提交 95524ae8 编写于 作者: A Avi Kivity 提交者: Anthony Liguori

msix: convert to memory API

The msix table is defined as a subregion, to allow for a BAR that
mixes device specific regions with the msix table.
Reviewed-by: NRichard Henderson <rth@twiddle.net>
Reviewed-by: NAnthony Liguori <aliguori@us.ibm.com>
Signed-off-by: NAvi Kivity <avi@redhat.com>
Signed-off-by: NAnthony Liguori <aliguori@us.ibm.com>
上级 de00982e
...@@ -65,6 +65,7 @@ typedef struct IVShmemState { ...@@ -65,6 +65,7 @@ typedef struct IVShmemState {
*/ */
MemoryRegion bar; MemoryRegion bar;
MemoryRegion ivshmem; MemoryRegion ivshmem;
MemoryRegion msix_bar;
uint64_t ivshmem_size; /* size of shared memory region */ uint64_t ivshmem_size; /* size of shared memory region */
int shm_fd; /* shared memory file descriptor */ int shm_fd; /* shared memory file descriptor */
...@@ -540,11 +541,11 @@ static void ivshmem_setup_msi(IVShmemState * s) { ...@@ -540,11 +541,11 @@ static void ivshmem_setup_msi(IVShmemState * s) {
/* allocate the MSI-X vectors */ /* allocate the MSI-X vectors */
if (!msix_init(&s->dev, s->vectors, 1, 0)) { memory_region_init(&s->msix_bar, "ivshmem-msix", 4096);
pci_register_bar(&s->dev, 1, if (!msix_init(&s->dev, s->vectors, &s->msix_bar, 1, 0)) {
msix_bar_size(&s->dev), pci_register_bar_region(&s->dev, 1,
PCI_BASE_ADDRESS_SPACE_MEMORY, PCI_BASE_ADDRESS_SPACE_MEMORY,
msix_mmio_map); &s->msix_bar);
IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors); IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
} else { } else {
IVSHMEM_DPRINTF("msix initialization failed\n"); IVSHMEM_DPRINTF("msix initialization failed\n");
......
...@@ -82,7 +82,8 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries, ...@@ -82,7 +82,8 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
return 0; return 0;
} }
static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr) static uint64_t msix_mmio_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{ {
PCIDevice *dev = opaque; PCIDevice *dev = opaque;
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3; unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
...@@ -91,12 +92,6 @@ static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr) ...@@ -91,12 +92,6 @@ static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
return pci_get_long(page + offset); return pci_get_long(page + offset);
} }
static uint32_t msix_mmio_read_unallowed(void *opaque, target_phys_addr_t addr)
{
fprintf(stderr, "MSI-X: only dword read is allowed!\n");
return 0;
}
static uint8_t msix_pending_mask(int vector) static uint8_t msix_pending_mask(int vector)
{ {
return 1 << (vector % 8); return 1 << (vector % 8);
...@@ -169,8 +164,8 @@ void msix_write_config(PCIDevice *dev, uint32_t addr, ...@@ -169,8 +164,8 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
} }
} }
static void msix_mmio_writel(void *opaque, target_phys_addr_t addr, static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
uint32_t val) uint64_t val, unsigned size)
{ {
PCIDevice *dev = opaque; PCIDevice *dev = opaque;
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3; unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
...@@ -179,37 +174,25 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr, ...@@ -179,37 +174,25 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
msix_handle_mask_update(dev, vector); msix_handle_mask_update(dev, vector);
} }
static void msix_mmio_write_unallowed(void *opaque, target_phys_addr_t addr, static const MemoryRegionOps msix_mmio_ops = {
uint32_t val) .read = msix_mmio_read,
{ .write = msix_mmio_write,
fprintf(stderr, "MSI-X: only dword write is allowed!\n"); .endianness = DEVICE_NATIVE_ENDIAN,
} .valid = {
.min_access_size = 4,
static CPUWriteMemoryFunc * const msix_mmio_write[] = { .max_access_size = 4,
msix_mmio_write_unallowed, msix_mmio_write_unallowed, msix_mmio_writel },
};
static CPUReadMemoryFunc * const msix_mmio_read[] = {
msix_mmio_read_unallowed, msix_mmio_read_unallowed, msix_mmio_readl
}; };
/* Should be called from device's map method. */ static void msix_mmio_setup(PCIDevice *d, MemoryRegion *bar)
void msix_mmio_map(PCIDevice *d, int region_num,
pcibus_t addr, pcibus_t size, int type)
{ {
uint8_t *config = d->config + d->msix_cap; uint8_t *config = d->config + d->msix_cap;
uint32_t table = pci_get_long(config + PCI_MSIX_TABLE); uint32_t table = pci_get_long(config + PCI_MSIX_TABLE);
uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1); uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1);
/* TODO: for assigned devices, we'll want to make it possible to map /* TODO: for assigned devices, we'll want to make it possible to map
* pending bits separately in case they are in a separate bar. */ * pending bits separately in case they are in a separate bar. */
int table_bir = table & PCI_MSIX_FLAGS_BIRMASK;
if (table_bir != region_num) memory_region_add_subregion(bar, offset, &d->msix_mmio);
return;
if (size <= offset)
return;
cpu_register_physical_memory(addr + offset, size - offset,
d->msix_mmio_index);
} }
static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
...@@ -225,6 +208,7 @@ static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) ...@@ -225,6 +208,7 @@ static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
/* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is /* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is
* modified, it should be retrieved with msix_bar_size. */ * modified, it should be retrieved with msix_bar_size. */
int msix_init(struct PCIDevice *dev, unsigned short nentries, int msix_init(struct PCIDevice *dev, unsigned short nentries,
MemoryRegion *bar,
unsigned bar_nr, unsigned bar_size) unsigned bar_nr, unsigned bar_size)
{ {
int ret; int ret;
...@@ -241,13 +225,8 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, ...@@ -241,13 +225,8 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
dev->msix_table_page = qemu_mallocz(MSIX_PAGE_SIZE); dev->msix_table_page = qemu_mallocz(MSIX_PAGE_SIZE);
msix_mask_all(dev, nentries); msix_mask_all(dev, nentries);
dev->msix_mmio_index = cpu_register_io_memory(msix_mmio_read, memory_region_init_io(&dev->msix_mmio, &msix_mmio_ops, dev,
msix_mmio_write, dev, "msix", MSIX_PAGE_SIZE);
DEVICE_NATIVE_ENDIAN);
if (dev->msix_mmio_index == -1) {
ret = -EBUSY;
goto err_index;
}
dev->msix_entries_nr = nentries; dev->msix_entries_nr = nentries;
ret = msix_add_config(dev, nentries, bar_nr, bar_size); ret = msix_add_config(dev, nentries, bar_nr, bar_size);
...@@ -255,12 +234,12 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, ...@@ -255,12 +234,12 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
goto err_config; goto err_config;
dev->cap_present |= QEMU_PCI_CAP_MSIX; dev->cap_present |= QEMU_PCI_CAP_MSIX;
msix_mmio_setup(dev, bar);
return 0; return 0;
err_config: err_config:
dev->msix_entries_nr = 0; dev->msix_entries_nr = 0;
cpu_unregister_io_memory(dev->msix_mmio_index); memory_region_destroy(&dev->msix_mmio);
err_index:
qemu_free(dev->msix_table_page); qemu_free(dev->msix_table_page);
dev->msix_table_page = NULL; dev->msix_table_page = NULL;
qemu_free(dev->msix_entry_used); qemu_free(dev->msix_entry_used);
...@@ -279,7 +258,7 @@ static void msix_free_irq_entries(PCIDevice *dev) ...@@ -279,7 +258,7 @@ static void msix_free_irq_entries(PCIDevice *dev)
} }
/* Clean up resources for the device. */ /* Clean up resources for the device. */
int msix_uninit(PCIDevice *dev) int msix_uninit(PCIDevice *dev, MemoryRegion *bar)
{ {
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
return 0; return 0;
...@@ -287,7 +266,8 @@ int msix_uninit(PCIDevice *dev) ...@@ -287,7 +266,8 @@ int msix_uninit(PCIDevice *dev)
dev->msix_cap = 0; dev->msix_cap = 0;
msix_free_irq_entries(dev); msix_free_irq_entries(dev);
dev->msix_entries_nr = 0; dev->msix_entries_nr = 0;
cpu_unregister_io_memory(dev->msix_mmio_index); memory_region_del_subregion(bar, &dev->msix_mmio);
memory_region_destroy(&dev->msix_mmio);
qemu_free(dev->msix_table_page); qemu_free(dev->msix_table_page);
dev->msix_table_page = NULL; dev->msix_table_page = NULL;
qemu_free(dev->msix_entry_used); qemu_free(dev->msix_entry_used);
......
...@@ -5,15 +5,13 @@ ...@@ -5,15 +5,13 @@
#include "pci.h" #include "pci.h"
int msix_init(PCIDevice *pdev, unsigned short nentries, int msix_init(PCIDevice *pdev, unsigned short nentries,
MemoryRegion *bar,
unsigned bar_nr, unsigned bar_size); unsigned bar_nr, unsigned bar_size);
void msix_write_config(PCIDevice *pci_dev, uint32_t address, void msix_write_config(PCIDevice *pci_dev, uint32_t address,
uint32_t val, int len); uint32_t val, int len);
void msix_mmio_map(PCIDevice *pci_dev, int region_num, int msix_uninit(PCIDevice *d, MemoryRegion *bar);
pcibus_t addr, pcibus_t size, int type);
int msix_uninit(PCIDevice *d);
void msix_save(PCIDevice *dev, QEMUFile *f); void msix_save(PCIDevice *dev, QEMUFile *f);
void msix_load(PCIDevice *dev, QEMUFile *f); void msix_load(PCIDevice *dev, QEMUFile *f);
......
...@@ -176,7 +176,7 @@ struct PCIDevice { ...@@ -176,7 +176,7 @@ struct PCIDevice {
/* Space to store MSIX table */ /* Space to store MSIX table */
uint8_t *msix_table_page; uint8_t *msix_table_page;
/* MMIO index used to map MSIX table and pending bit entries. */ /* MMIO index used to map MSIX table and pending bit entries. */
int msix_mmio_index; MemoryRegion msix_mmio;
/* Reference-count for entries actually in use by driver. */ /* Reference-count for entries actually in use by driver. */
unsigned *msix_entry_used; unsigned *msix_entry_used;
/* Region including the MSI-X table */ /* Region including the MSI-X table */
......
...@@ -641,11 +641,12 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev) ...@@ -641,11 +641,12 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
pci_set_word(config + 0x2e, vdev->device_id); pci_set_word(config + 0x2e, vdev->device_id);
config[0x3d] = 1; config[0x3d] = 1;
if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors, 1, 0)) { memory_region_init(&proxy->msix_bar, "virtio-msix", 4096);
pci_register_bar(&proxy->pci_dev, 1, if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors,
msix_bar_size(&proxy->pci_dev), &proxy->msix_bar, 1, 0)) {
pci_register_bar_region(&proxy->pci_dev, 1,
PCI_BASE_ADDRESS_SPACE_MEMORY, PCI_BASE_ADDRESS_SPACE_MEMORY,
msix_mmio_map); &proxy->msix_bar);
} else } else
vdev->nvectors = 0; vdev->nvectors = 0;
...@@ -694,9 +695,12 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev) ...@@ -694,9 +695,12 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
static int virtio_exit_pci(PCIDevice *pci_dev) static int virtio_exit_pci(PCIDevice *pci_dev)
{ {
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
int r;
memory_region_destroy(&proxy->bar); memory_region_destroy(&proxy->bar);
return msix_uninit(pci_dev); r = msix_uninit(pci_dev, &proxy->msix_bar);
memory_region_destroy(&proxy->msix_bar);
return r;
} }
static int virtio_blk_exit_pci(PCIDevice *pci_dev) static int virtio_blk_exit_pci(PCIDevice *pci_dev)
......
...@@ -22,6 +22,7 @@ typedef struct { ...@@ -22,6 +22,7 @@ typedef struct {
PCIDevice pci_dev; PCIDevice pci_dev;
VirtIODevice *vdev; VirtIODevice *vdev;
MemoryRegion bar; MemoryRegion bar;
MemoryRegion msix_bar;
uint32_t flags; uint32_t flags;
uint32_t class_code; uint32_t class_code;
uint32_t nvectors; uint32_t nvectors;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册