mirror of https://github.com/xemu-project/xemu.git
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: Richard Henderson <rth@twiddle.net> Reviewed-by: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
de00982e9e
commit
95524ae8dc
|
@ -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) {
|
||||||
|
|
||||||
/* 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");
|
||||||
|
|
64
hw/msix.c
64
hw/msix.c
|
@ -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)
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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[] = {
|
static void msix_mmio_setup(PCIDevice *d, MemoryRegion *bar)
|
||||||
msix_mmio_read_unallowed, msix_mmio_read_unallowed, msix_mmio_readl
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Should be called from device's map method. */
|
|
||||||
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)
|
||||||
/* 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,
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
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 @@
|
||||||
#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);
|
||||||
|
|
2
hw/pci.h
2
hw/pci.h
|
@ -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)
|
||||||
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)
|
||||||
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 {
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue