Ejemplo n.º 1
0
void msix_reset(PCIDevice *dev)
{
    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
        return;
    msix_free_irq_entries(dev);
    dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
	    ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
    memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE);
    msix_mask_all(dev, dev->msix_entries_nr);
}
Ejemplo n.º 2
0
void msix_reset(PCIDevice *dev)
{
    if (!msix_present(dev)) {
        return;
    }
    msix_clear_all_vectors(dev);
    dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
	    ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
    memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE);
    memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8);
    msix_mask_all(dev, dev->msix_entries_nr);
}
Ejemplo n.º 3
0
/* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is
 * modified, it should be retrieved with msix_bar_size. */
int msix_init(struct PCIDevice *dev, unsigned short nentries,
              MemoryRegion *bar,
              unsigned bar_nr, unsigned bar_size)
{
    int ret;
    /* Nothing to do if MSI is not supported by interrupt controller */
    if (!msix_supported ||
        (kvm_enabled() && kvm_irqchip_in_kernel() && !kvm_has_gsi_routing())) {
        return -ENOTSUP;
    }

    if (nentries > MSIX_MAX_ENTRIES)
        return -EINVAL;

    dev->msix_mask_notifier = NULL;
    dev->msix_entry_used = g_malloc0(MSIX_MAX_ENTRIES *
                                        sizeof *dev->msix_entry_used);

    dev->msix_table_page = g_malloc0(MSIX_PAGE_SIZE);
    msix_mask_all(dev, nentries);

    memory_region_init_io(&dev->msix_mmio, &msix_mmio_ops, dev,
                          "msix", MSIX_PAGE_SIZE);

    dev->msix_entries_nr = nentries;
    ret = msix_add_config(dev, nentries, bar_nr, bar_size);
    if (ret)
        goto err_config;

    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
        dev->msix_irq_entries = g_malloc(nentries *
                                         sizeof *dev->msix_irq_entries);
    }

    dev->cap_present |= QEMU_PCI_CAP_MSIX;
    msix_mmio_setup(dev, bar);
    return 0;

err_config:
    dev->msix_entries_nr = 0;
    memory_region_destroy(&dev->msix_mmio);
    g_free(dev->msix_table_page);
    dev->msix_table_page = NULL;
    g_free(dev->msix_entry_used);
    dev->msix_entry_used = NULL;
    return ret;
}
Ejemplo n.º 4
0
/* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is
 * modified, it should be retrieved with msix_bar_size. */
int msix_init(struct PCIDevice *dev, unsigned short nentries,
              unsigned bar_nr, unsigned bar_size)
{
    int ret;
    /* Nothing to do if MSI is not supported by interrupt controller */
    if (!msix_supported)
        return -ENOTSUP;

    if (nentries > MSIX_MAX_ENTRIES)
        return -EINVAL;

    dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
                                        sizeof *dev->msix_entry_used);

    dev->msix_table_page = qemu_mallocz(MSIX_PAGE_SIZE);
    msix_mask_all(dev, nentries);

    dev->msix_mmio_index = cpu_register_io_memory(msix_mmio_read,
                                                  msix_mmio_write, dev,
                                                  DEVICE_NATIVE_ENDIAN);
    if (dev->msix_mmio_index == -1) {
        ret = -EBUSY;
        goto err_index;
    }

    dev->msix_entries_nr = nentries;
    ret = msix_add_config(dev, nentries, bar_nr, bar_size);
    if (ret)
        goto err_config;

    dev->cap_present |= QEMU_PCI_CAP_MSIX;
    return 0;

err_config:
    dev->msix_entries_nr = 0;
    cpu_unregister_io_memory(dev->msix_mmio_index);
err_index:
    qemu_free(dev->msix_table_page);
    dev->msix_table_page = NULL;
    qemu_free(dev->msix_entry_used);
    dev->msix_entry_used = NULL;
    return ret;
}
Ejemplo n.º 5
0
/* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is
 * modified, it should be retrieved with msix_bar_size. */
int msix_init(struct PCIDevice *dev, unsigned short nentries,
              MemoryRegion *bar,
              unsigned bar_nr, unsigned bar_size)
{
    int ret;
    /* Nothing to do if MSI is not supported by interrupt controller */
    if (!msix_supported)
        return -ENOTSUP;

    if (nentries > MSIX_MAX_ENTRIES)
        return -EINVAL;

    dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
                                        sizeof *dev->msix_entry_used);

    dev->msix_table_page = qemu_mallocz(MSIX_PAGE_SIZE);
    msix_mask_all(dev, nentries);

    memory_region_init_io(&dev->msix_mmio, &msix_mmio_ops, dev,
                          "msix", MSIX_PAGE_SIZE);

    dev->msix_entries_nr = nentries;
    ret = msix_add_config(dev, nentries, bar_nr, bar_size);
    if (ret)
        goto err_config;

    dev->cap_present |= QEMU_PCI_CAP_MSIX;
    msix_mmio_setup(dev, bar);
    return 0;

err_config:
    dev->msix_entries_nr = 0;
    memory_region_destroy(&dev->msix_mmio);
    qemu_free(dev->msix_table_page);
    dev->msix_table_page = NULL;
    qemu_free(dev->msix_entry_used);
    dev->msix_entry_used = NULL;
    return ret;
}
Ejemplo n.º 6
0
/* Initialize the MSI-X structures */
int msix_init(struct PCIDevice *dev, unsigned short nentries,
              MemoryRegion *table_bar, uint8_t table_bar_nr,
              unsigned table_offset, MemoryRegion *pba_bar,
              uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos)
{
    int cap;
    unsigned table_size, pba_size;
    uint8_t *config;

    /* Nothing to do if MSI is not supported by interrupt controller */
    if (!msi_supported) {
        return -ENOTSUP;
    }

    if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) {
        return -EINVAL;
    }

    table_size = nentries * PCI_MSIX_ENTRY_SIZE;
    pba_size = QEMU_ALIGN_UP(nentries, 64) / 8;

    /* Sanity test: table & pba don't overlap, fit within BARs, min aligned */
    if ((table_bar_nr == pba_bar_nr &&
         ranges_overlap(table_offset, table_size, pba_offset, pba_size)) ||
        table_offset + table_size > memory_region_size(table_bar) ||
        pba_offset + pba_size > memory_region_size(pba_bar) ||
        (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) {
        return -EINVAL;
    }

    cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH);
    if (cap < 0) {
        return cap;
    }

    dev->msix_cap = cap;
    dev->cap_present |= QEMU_PCI_CAP_MSIX;
    config = dev->config + cap;

    pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
    dev->msix_entries_nr = nentries;
    dev->msix_function_masked = true;

    pci_set_long(config + PCI_MSIX_TABLE, table_offset | table_bar_nr);
    pci_set_long(config + PCI_MSIX_PBA, pba_offset | pba_bar_nr);

    /* Make flags bit writable. */
    dev->wmask[cap + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
                                             MSIX_MASKALL_MASK;

    dev->msix_table = g_malloc0(table_size);
    dev->msix_pba = g_malloc0(pba_size);
    dev->msix_entry_used = g_malloc0(nentries * sizeof *dev->msix_entry_used);

    msix_mask_all(dev, nentries);

    memory_region_init_io(&dev->msix_table_mmio, OBJECT(dev), &msix_table_mmio_ops, dev,
                          "msix-table", table_size);
    memory_region_add_subregion(table_bar, table_offset, &dev->msix_table_mmio);
    memory_region_init_io(&dev->msix_pba_mmio, OBJECT(dev), &msix_pba_mmio_ops, dev,
                          "msix-pba", pba_size);
    memory_region_add_subregion(pba_bar, pba_offset, &dev->msix_pba_mmio);

    return 0;
}