static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,

                                uint32_t token, uint32_t nargs,

                                target_ulong args, uint32_t nret,

                                target_ulong rets)

{

    uint32_t config_addr = rtas_ld(args, 0);

    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);

    unsigned int func = rtas_ld(args, 3);

    unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */

    unsigned int seq_num = rtas_ld(args, 5);

    unsigned int ret_intr_type;

    unsigned int irq, max_irqs = 0, num = 0;

    sPAPRPHBState *phb = NULL;

    PCIDevice *pdev = NULL;

    spapr_pci_msi *msi;

    int *config_addr_key;



    switch (func) {

    case RTAS_CHANGE_MSI_FN:

    case RTAS_CHANGE_FN:

        ret_intr_type = RTAS_TYPE_MSI;

        break;

    case RTAS_CHANGE_MSIX_FN:

        ret_intr_type = RTAS_TYPE_MSIX;

        break;

    default:

        error_report("rtas_ibm_change_msi(%u) is not implemented", func);

        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);

        return;

    }



    /* Fins sPAPRPHBState */

    phb = find_phb(spapr, buid);

    if (phb) {

        pdev = find_dev(spapr, buid, config_addr);

    }

    if (!phb || !pdev) {

        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);

        return;

    }



    /* Releasing MSIs */

    if (!req_num) {

        msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);

        if (!msi) {

            trace_spapr_pci_msi("Releasing wrong config", config_addr);

            rtas_st(rets, 0, RTAS_OUT_HW_ERROR);

            return;

        }



        xics_free(spapr->icp, msi->first_irq, msi->num);

        if (msi_present(pdev)) {

            spapr_msi_setmsg(pdev, 0, false, 0, num);

        }

        if (msix_present(pdev)) {

            spapr_msi_setmsg(pdev, 0, true, 0, num);

        }

        g_hash_table_remove(phb->msi, &config_addr);



        trace_spapr_pci_msi("Released MSIs", config_addr);

        rtas_st(rets, 0, RTAS_OUT_SUCCESS);

        rtas_st(rets, 1, 0);

        return;

    }



    /* Enabling MSI */



    /* Check if the device supports as many IRQs as requested */

    if (ret_intr_type == RTAS_TYPE_MSI) {

        max_irqs = msi_nr_vectors_allocated(pdev);

    } else if (ret_intr_type == RTAS_TYPE_MSIX) {

        max_irqs = pdev->msix_entries_nr;

    }

    if (!max_irqs) {

        error_report("Requested interrupt type %d is not enabled for device %x",

                     ret_intr_type, config_addr);

        rtas_st(rets, 0, -1); /* Hardware error */

        return;

    }

    /* Correct the number if the guest asked for too many */

    if (req_num > max_irqs) {

        trace_spapr_pci_msi_retry(config_addr, req_num, max_irqs);

        req_num = max_irqs;

        irq = 0; /* to avoid misleading trace */

        goto out;

    }



    /* Allocate MSIs */

    irq = xics_alloc_block(spapr->icp, 0, req_num, false,

                           ret_intr_type == RTAS_TYPE_MSI);

    if (!irq) {

        error_report("Cannot allocate MSIs for device %x", config_addr);

        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);

        return;

    }



    /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */

    spapr_msi_setmsg(pdev, SPAPR_PCI_MSI_WINDOW, ret_intr_type == RTAS_TYPE_MSIX,

                     irq, req_num);



    /* Add MSI device to cache */

    msi = g_new(spapr_pci_msi, 1);

    msi->first_irq = irq;

    msi->num = req_num;

    config_addr_key = g_new(int, 1);

    *config_addr_key = config_addr;

    g_hash_table_insert(phb->msi, config_addr_key, msi);



out:

    rtas_st(rets, 0, RTAS_OUT_SUCCESS);

    rtas_st(rets, 1, req_num);

    rtas_st(rets, 2, ++seq_num);

    rtas_st(rets, 3, ret_intr_type);



    trace_spapr_pci_rtas_ibm_change_msi(config_addr, func, req_num, irq);

}

static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,

                                uint32_t token, uint32_t nargs,

                                target_ulong args, uint32_t nret,

                                target_ulong rets)

{

    uint32_t config_addr = rtas_ld(args, 0);

    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);

    unsigned int func = rtas_ld(args, 3);

    unsigned int req_num = rtas_ld(args, 4); 

    unsigned int seq_num = rtas_ld(args, 5);

    unsigned int ret_intr_type;

    unsigned int irq, max_irqs = 0, num = 0;

    sPAPRPHBState *phb = NULL;

    PCIDevice *pdev = NULL;

    spapr_pci_msi *msi;

    int *config_addr_key;



    switch (func) {

    case RTAS_CHANGE_MSI_FN:

    case RTAS_CHANGE_FN:

        ret_intr_type = RTAS_TYPE_MSI;

        break;

    case RTAS_CHANGE_MSIX_FN:

        ret_intr_type = RTAS_TYPE_MSIX;

        break;

    default:

        error_report("rtas_ibm_change_msi(%u) is not implemented", func);

        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);

        return;

    }



    

    phb = find_phb(spapr, buid);

    if (phb) {

        pdev = find_dev(spapr, buid, config_addr);

    }

    if (!phb || !pdev) {

        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);

        return;

    }



    

    if (!req_num) {

        msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);

        if (!msi) {

            trace_spapr_pci_msi("Releasing wrong config", config_addr);

            rtas_st(rets, 0, RTAS_OUT_HW_ERROR);

            return;

        }



        xics_free(spapr->icp, msi->first_irq, msi->num);

        if (msi_present(pdev)) {

            spapr_msi_setmsg(pdev, 0, false, 0, num);

        }

        if (msix_present(pdev)) {

            spapr_msi_setmsg(pdev, 0, true, 0, num);

        }

        g_hash_table_remove(phb->msi, &config_addr);



        trace_spapr_pci_msi("Released MSIs", config_addr);

        rtas_st(rets, 0, RTAS_OUT_SUCCESS);

        rtas_st(rets, 1, 0);

        return;

    }



    



    

    if (ret_intr_type == RTAS_TYPE_MSI) {

        max_irqs = msi_nr_vectors_allocated(pdev);

    } else if (ret_intr_type == RTAS_TYPE_MSIX) {

        max_irqs = pdev->msix_entries_nr;

    }

    if (!max_irqs) {

        error_report("Requested interrupt type %d is not enabled for device %x",

                     ret_intr_type, config_addr);

        rtas_st(rets, 0, -1); 

        return;

    }

    

    if (req_num > max_irqs) {

        trace_spapr_pci_msi_retry(config_addr, req_num, max_irqs);

        req_num = max_irqs;

        irq = 0; 

        goto out;

    }



    

    irq = xics_alloc_block(spapr->icp, 0, req_num, false,

                           ret_intr_type == RTAS_TYPE_MSI);

    if (!irq) {

        error_report("Cannot allocate MSIs for device %x", config_addr);

        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);

        return;

    }



    

    spapr_msi_setmsg(pdev, SPAPR_PCI_MSI_WINDOW, ret_intr_type == RTAS_TYPE_MSIX,

                     irq, req_num);



    

    msi = g_new(spapr_pci_msi, 1);

    msi->first_irq = irq;

    msi->num = req_num;

    config_addr_key = g_new(int, 1);

    *config_addr_key = config_addr;

    g_hash_table_insert(phb->msi, config_addr_key, msi);



out:

    rtas_st(rets, 0, RTAS_OUT_SUCCESS);

    rtas_st(rets, 1, req_num);

    rtas_st(rets, 2, ++seq_num);

    rtas_st(rets, 3, ret_intr_type);



    trace_spapr_pci_rtas_ibm_change_msi(config_addr, func, req_num, irq);

}

static void FUNC_0(PowerPCCPU *VAR_0, sPAPREnvironment *VAR_1,

                                uint32_t VAR_2, uint32_t VAR_3,

                                target_ulong VAR_4, uint32_t VAR_5,

                                target_ulong VAR_6)

{

    uint32_t config_addr = rtas_ld(VAR_4, 0);

    uint64_t buid = ((uint64_t)rtas_ld(VAR_4, 1) << 32) | rtas_ld(VAR_4, 2);

    unsigned int VAR_7 = rtas_ld(VAR_4, 3);

    unsigned int VAR_8 = rtas_ld(VAR_4, 4); 

    unsigned int VAR_9 = rtas_ld(VAR_4, 5);

    unsigned int VAR_10;

    unsigned int VAR_11, VAR_12 = 0, VAR_13 = 0;

    sPAPRPHBState *phb = NULL;

    PCIDevice *pdev = NULL;

    spapr_pci_msi *msi;

    int *VAR_14;



    switch (VAR_7) {

    case RTAS_CHANGE_MSI_FN:

    case RTAS_CHANGE_FN:

        VAR_10 = RTAS_TYPE_MSI;

        break;

    case RTAS_CHANGE_MSIX_FN:

        VAR_10 = RTAS_TYPE_MSIX;

        break;

    default:

        error_report("FUNC_0(%u) is not implemented", VAR_7);

        rtas_st(VAR_6, 0, RTAS_OUT_PARAM_ERROR);

        return;

    }



    

    phb = find_phb(VAR_1, buid);

    if (phb) {

        pdev = find_dev(VAR_1, buid, config_addr);

    }

    if (!phb || !pdev) {

        rtas_st(VAR_6, 0, RTAS_OUT_PARAM_ERROR);

        return;

    }



    

    if (!VAR_8) {

        msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);

        if (!msi) {

            trace_spapr_pci_msi("Releasing wrong config", config_addr);

            rtas_st(VAR_6, 0, RTAS_OUT_HW_ERROR);

            return;

        }



        xics_free(VAR_1->icp, msi->first_irq, msi->VAR_13);

        if (msi_present(pdev)) {

            spapr_msi_setmsg(pdev, 0, false, 0, VAR_13);

        }

        if (msix_present(pdev)) {

            spapr_msi_setmsg(pdev, 0, true, 0, VAR_13);

        }

        g_hash_table_remove(phb->msi, &config_addr);



        trace_spapr_pci_msi("Released MSIs", config_addr);

        rtas_st(VAR_6, 0, RTAS_OUT_SUCCESS);

        rtas_st(VAR_6, 1, 0);

        return;

    }



    



    

    if (VAR_10 == RTAS_TYPE_MSI) {

        VAR_12 = msi_nr_vectors_allocated(pdev);

    } else if (VAR_10 == RTAS_TYPE_MSIX) {

        VAR_12 = pdev->msix_entries_nr;

    }

    if (!VAR_12) {

        error_report("Requested interrupt type %d is not enabled for device %x",

                     VAR_10, config_addr);

        rtas_st(VAR_6, 0, -1); 

        return;

    }

    

    if (VAR_8 > VAR_12) {

        trace_spapr_pci_msi_retry(config_addr, VAR_8, VAR_12);

        VAR_8 = VAR_12;

        VAR_11 = 0; 

        goto out;

    }



    

    VAR_11 = xics_alloc_block(VAR_1->icp, 0, VAR_8, false,

                           VAR_10 == RTAS_TYPE_MSI);

    if (!VAR_11) {

        error_report("Cannot allocate MSIs for device %x", config_addr);

        rtas_st(VAR_6, 0, RTAS_OUT_HW_ERROR);

        return;

    }



    

    spapr_msi_setmsg(pdev, SPAPR_PCI_MSI_WINDOW, VAR_10 == RTAS_TYPE_MSIX,

                     VAR_11, VAR_8);



    

    msi = g_new(spapr_pci_msi, 1);

    msi->first_irq = VAR_11;

    msi->VAR_13 = VAR_8;

    VAR_14 = g_new(int, 1);

    *VAR_14 = config_addr;

    g_hash_table_insert(phb->msi, VAR_14, msi);



out:

    rtas_st(VAR_6, 0, RTAS_OUT_SUCCESS);

    rtas_st(VAR_6, 1, VAR_8);

    rtas_st(VAR_6, 2, ++VAR_9);

    rtas_st(VAR_6, 3, VAR_10);



    trace_spapr_pci_rtas_ibm_change_msi(config_addr, VAR_7, VAR_8, VAR_11);

}

static void FUNC_0(PowerPCCPU *VAR_0, sPAPREnvironment *VAR_1,
uint32_t VAR_2, uint32_t VAR_3,
target_ulong VAR_4, uint32_t VAR_5,
target_ulong VAR_6)
{ uint32_t config_addr = rtas_ld(VAR_4, 0); uint64_t buid = ((uint64_t)rtas_ld(VAR_4, 1) << 32) | rtas_ld(VAR_4, 2); unsigned int VAR_7 = rtas_ld(VAR_4, 3); unsigned int VAR_8 = rtas_ld(VAR_4, 4); unsigned int VAR_9 = rtas_ld(VAR_4, 5); unsigned int VAR_10; unsigned int VAR_11, VAR_12 = 0, VAR_13 = 0; sPAPRPHBState *phb = NULL; PCIDevice *pdev = NULL; spapr_pci_msi *msi; int *VAR_14; switch (VAR_7) { case RTAS_CHANGE_MSI_FN:
case RTAS_CHANGE_FN:
VAR_10 = RTAS_TYPE_MSI; break; case RTAS_CHANGE_MSIX_FN:
VAR_10 = RTAS_TYPE_MSIX; break; default:
error_report("FUNC_0(%u) is not implemented", VAR_7); rtas_st(VAR_6, 0, RTAS_OUT_PARAM_ERROR); return; } phb = find_phb(VAR_1, buid); if (phb) { pdev = find_dev(VAR_1, buid, config_addr); } if (!phb || !pdev) { rtas_st(VAR_6, 0, RTAS_OUT_PARAM_ERROR); return; } if (!VAR_8) { msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr); if (!msi) { trace_spapr_pci_msi("Releasing wrong config", config_addr); rtas_st(VAR_6, 0, RTAS_OUT_HW_ERROR); return; } xics_free(VAR_1->icp, msi->first_irq, msi->VAR_13); if (msi_present(pdev)) { spapr_msi_setmsg(pdev, 0, false, 0, VAR_13); } if (msix_present(pdev)) { spapr_msi_setmsg(pdev, 0, true, 0, VAR_13); } g_hash_table_remove(phb->msi, &config_addr); trace_spapr_pci_msi("Released MSIs", config_addr); rtas_st(VAR_6, 0, RTAS_OUT_SUCCESS); rtas_st(VAR_6, 1, 0); return; } if (VAR_10 == RTAS_TYPE_MSI) { VAR_12 = msi_nr_vectors_allocated(pdev); } else if (VAR_10 == RTAS_TYPE_MSIX) { VAR_12 = pdev->msix_entries_nr; } if (!VAR_12) { error_report("Requested interrupt type %d is not enabled for device %x",
VAR_10, config_addr); rtas_st(VAR_6, 0, -1); return; } if (VAR_8 > VAR_12) { trace_spapr_pci_msi_retry(config_addr, VAR_8, VAR_12); VAR_8 = VAR_12; VAR_11 = 0; goto out; } VAR_11 = xics_alloc_block(VAR_1->icp, 0, VAR_8, false,
VAR_10 == RTAS_TYPE_MSI); if (!VAR_11) { error_report("Cannot allocate MSIs for device %x", config_addr); rtas_st(VAR_6, 0, RTAS_OUT_HW_ERROR); return; } spapr_msi_setmsg(pdev, SPAPR_PCI_MSI_WINDOW, VAR_10 == RTAS_TYPE_MSIX,
VAR_11, VAR_8); msi = g_new(spapr_pci_msi, 1); msi->first_irq = VAR_11; msi->VAR_13 = VAR_8; VAR_14 = g_new(int, 1); *VAR_14 = config_addr; g_hash_table_insert(phb->msi, VAR_14, msi); out:
rtas_st(VAR_6, 0, RTAS_OUT_SUCCESS); rtas_st(VAR_6, 1, VAR_8); rtas_st(VAR_6, 2, ++VAR_9); rtas_st(VAR_6, 3, VAR_10); trace_spapr_pci_rtas_ibm_change_msi(config_addr, VAR_7, VAR_8, VAR_11); }