@@ -50,6 +50,7 @@ OBJS += builtin-run.o
OBJS += builtin-setup.o
OBJS += builtin-stop.o
OBJS += builtin-version.o
+OBJS += devices.o
OBJS += disk/core.o
OBJS += framebuffer.o
OBJS += guest_compat.o
new file mode 100644
@@ -0,0 +1,24 @@
+#include "kvm/devices.h"
+#include "kvm/kvm.h"
+
+#include <linux/err.h>
+
+static struct device_header *devices[KVM_MAX_DEVICES];
+
+int device__register(struct device_header *dev, u8 dev_num)
+{
+ if (dev_num >= KVM_MAX_DEVICES)
+ return -ENOSPC;
+
+ devices[dev_num] = dev;
+
+ return 0;
+}
+
+struct device_header *device__find_dev(u8 dev_num)
+{
+ if (dev_num >= KVM_MAX_DEVICES)
+ return ERR_PTR(-EOVERFLOW);
+
+ return devices[dev_num];
+}
@@ -1,3 +1,4 @@
+#include "kvm/devices.h"
#include "kvm/pci-shmem.h"
#include "kvm/virtio-pci-dev.h"
#include "kvm/irq.h"
@@ -30,6 +31,11 @@ static struct pci_device_header pci_shmem_pci_device = {
.msix.pba_offset = cpu_to_le32(0x1001), /* Use BAR 1 */
};
+static struct device_header pci_shmem_device = {
+ .bus_type = DEVICE_BUS_PCI,
+ .data = &pci_shmem_pci_device,
+};
+
/* registers for the Inter-VM shared memory device */
enum ivshmem_registers {
INTRMASK = 0,
@@ -384,7 +390,7 @@ int pci_shmem__init(struct kvm *kvm)
pci_shmem_pci_device.bar[2] = cpu_to_le32(shmem_region->phys_addr | PCI_BASE_ADDRESS_SPACE_MEMORY);
pci_shmem_pci_device.bar_size[2] = shmem_region->size;
- pci__register(&pci_shmem_pci_device, dev);
+ device__register(&pci_shmem_device, dev);
/* Open shared memory and plug it into the guest */
mem = setup_shmem(shmem_region->handle, shmem_region->size,
@@ -1,5 +1,6 @@
#include "kvm/vesa.h"
+#include "kvm/devices.h"
#include "kvm/virtio-pci-dev.h"
#include "kvm/framebuffer.h"
#include "kvm/kvm-cpu.h"
@@ -44,6 +45,11 @@ static struct pci_device_header vesa_pci_device = {
.bar_size[1] = VESA_MEM_SIZE,
};
+static struct device_header vesa_device = {
+ .bus_type = DEVICE_BUS_PCI,
+ .data = &vesa_pci_device,
+};
+
static struct framebuffer vesafb;
struct framebuffer *vesa__init(struct kvm *kvm)
@@ -68,7 +74,7 @@ struct framebuffer *vesa__init(struct kvm *kvm)
vesa_pci_device.irq_line = line;
vesa_base_addr = (u16)r;
vesa_pci_device.bar[0] = cpu_to_le32(vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO);
- pci__register(&vesa_pci_device, dev);
+ device__register(&vesa_device, dev);
mem = mmap(NULL, VESA_MEM_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
if (mem == MAP_FAILED)
new file mode 100644
@@ -0,0 +1,21 @@
+#ifndef KVM__DEVICES_H
+#define KVM__DEVICES_H
+
+#include <linux/types.h>
+
+#define KVM_MAX_DEVICES 256
+
+enum device_bus_type {
+ DEVICE_BUS_PCI,
+ DEVICE_BUS_MMIO,
+};
+
+struct device_header {
+ enum device_bus_type bus_type;
+ void *data;
+};
+
+int device__register(struct device_header *dev, u8 dev_num);
+struct device_header *device__find_dev(u8 dev_num);
+
+#endif /* KVM__DEVICES_H */
@@ -9,7 +9,6 @@
#include "kvm/kvm.h"
#include "kvm/msi.h"
-#define PCI_MAX_DEVICES 256
/*
* PCI Configuration Mechanism #1 I/O ports. See Section 3.7.4.1.
* ("Configuration Mechanism #1") of the PCI Local Bus Specification 2.1 for
@@ -86,7 +85,6 @@ struct pci_device_header {
int pci__init(struct kvm *kvm);
int pci__exit(struct kvm *kvm);
-int pci__register(struct pci_device_header *dev, u8 dev_num);
struct pci_device_header *pci__find_dev(u8 dev_num);
u32 pci_get_io_space_block(u32 size);
void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size);
@@ -47,6 +47,7 @@ struct virtio_mmio {
struct kvm *kvm;
u8 irq;
struct virtio_mmio_hdr hdr;
+ struct device_header dev_hdr;
struct virtio_mmio_ioevent_param ioeventfds[VIRTIO_MMIO_MAX_VQ];
};
@@ -1,6 +1,7 @@
#ifndef KVM__VIRTIO_PCI_H
#define KVM__VIRTIO_PCI_H
+#include "kvm/devices.h"
#include "kvm/pci.h"
#include <linux/types.h>
@@ -19,6 +20,7 @@ struct virtio_pci_ioevent_param {
struct virtio_pci {
struct pci_device_header pci_hdr;
+ struct device_header dev_hdr;
void *dev;
u16 base_addr;
@@ -1,3 +1,4 @@
+#include "kvm/devices.h"
#include "kvm/pci.h"
#include "kvm/ioport.h"
#include "kvm/util.h"
@@ -8,8 +9,6 @@
#define PCI_BAR_OFFSET(b) (offsetof(struct pci_device_header, bar[b]))
-static struct pci_device_header *pci_devices[PCI_MAX_DEVICES];
-
static union pci_config_address pci_config_address;
/* This is within our PCI gap - in an unused area.
@@ -63,7 +62,7 @@ static struct ioport_operations pci_config_address_ops = {
static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_number)
{
- struct pci_device_header *dev;
+ struct device_header *dev;
if (pci_config_address.bus_number != bus_number)
return false;
@@ -71,12 +70,8 @@ static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_numbe
if (pci_config_address.function_number != function_number)
return false;
- if (device_number >= PCI_MAX_DEVICES)
- return false;
-
- dev = pci_devices[device_number];
-
- return dev != NULL;
+ dev = device__find_dev(device_number);
+ return !IS_ERR_OR_NULL(dev) && dev->bus_type == DEVICE_BUS_PCI;
}
static bool pci_config_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
@@ -121,12 +116,13 @@ void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data,
offset = addr.w & 0xff;
if (offset < sizeof(struct pci_device_header)) {
- void *p = pci_devices[dev_num];
+ void *p = device__find_dev(dev_num)->data;
+ struct pci_device_header *hdr = p;
u8 bar = (offset - PCI_BAR_OFFSET(0)) / (sizeof(u32));
u32 sz = PCI_IO_SIZE;
- if (bar < 6 && pci_devices[dev_num]->bar_size[bar])
- sz = pci_devices[dev_num]->bar_size[bar];
+ if (bar < 6 && hdr->bar_size[bar])
+ sz = hdr->bar_size[bar];
/*
* If the kernel masks the BAR it would expect to find the
@@ -158,7 +154,7 @@ void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data,
offset = addr.w & 0xff;
if (offset < sizeof(struct pci_device_header)) {
- void *p = pci_devices[dev_num];
+ void *p = device__find_dev(dev_num)->data;
memcpy(data, p + offset, size);
} else {
@@ -169,22 +165,14 @@ void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data,
}
}
-int pci__register(struct pci_device_header *dev, u8 dev_num)
-{
- if (dev_num >= PCI_MAX_DEVICES)
- return -ENOSPC;
-
- pci_devices[dev_num] = dev;
-
- return 0;
-}
-
struct pci_device_header *pci__find_dev(u8 dev_num)
{
- if (dev_num >= PCI_MAX_DEVICES)
- return ERR_PTR(-EOVERFLOW);
+ struct device_header *hdr = device__find_dev(dev_num);
+
+ if (IS_ERR(hdr) || hdr->bus_type != DEVICE_BUS_PCI)
+ return NULL;
- return pci_devices[dev_num];
+ return hdr->data;
}
int pci__init(struct kvm *kvm)
@@ -8,6 +8,7 @@
* by the Free Software Foundation.
*/
+#include "kvm/devices.h"
#include "kvm/irq.h"
#include "kvm/kvm.h"
#include "kvm/util.h"
@@ -35,7 +36,7 @@ static int pci_devs = 0;
int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
{
- if (pci_devs >= PCI_MAX_DEVICES)
+ if (pci_devs >= KVM_MAX_DEVICES)
die("Hit PCI device limit!\n");
*num = pci_devs++;
@@ -302,7 +302,7 @@ int spapr_populate_pci_devices(struct kvm *kvm,
/* Populate PCI devices and allocate IRQs */
devices = 0;
- for (devid = 0; devid < PCI_MAX_DEVICES; devid++) {
+ for (devid = 0; devid < KVM_MAX_DEVICES; devid++) {
uint32_t *irqmap = interrupt_map[devices];
struct pci_device_header *hdr = pci__find_dev(devid);
@@ -1,3 +1,4 @@
+#include "kvm/devices.h"
#include "kvm/virtio-mmio.h"
#include "kvm/ioeventfd.h"
#include "kvm/ioport.h"
@@ -238,6 +239,12 @@ int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
if (irq__register_device(subsys_id, &device, &pin, &line) < 0)
return -1;
vmmio->irq = line;
+ vmmio->dev_hdr = (struct device_header) {
+ .bus_type = DEVICE_BUS_MMIO,
+ .data = vmmio,
+ };
+
+ device__register(&vmmio->dev_hdr, device);
/*
* Instantiate guest virtio-mmio devices using kernel command line
@@ -343,6 +343,11 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
.bar_size[3] = PCI_IO_SIZE,
};
+ vpci->dev_hdr = (struct device_header) {
+ .bus_type = DEVICE_BUS_PCI,
+ .data = &vpci->pci_hdr,
+ };
+
vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
vpci->pci_hdr.msix.next = 0;
/*
@@ -375,7 +380,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
vpci->pci_hdr.irq_pin = pin;
vpci->pci_hdr.irq_line = line;
- r = pci__register(&vpci->pci_hdr, ndev);
+ r = device__register(&vpci->dev_hdr, ndev);
if (r < 0)
goto free_ioport;
PCI devices are currently registered into the pci_devices array via the pci__register function, which can then be indexed later by architecture code to construct device tree nodes. For MMIO devices, there is no such utility. Rather than invent a similar mechanism for MMIO, this patch creates a global device registration mechanism, which allows the device type to be specified when registered or indexing a device. Current users of the pci registration code are migrated to the new infrastructure and virtio MMIO devices are registered at init time. Signed-off-by: Will Deacon <will.deacon@arm.com> --- tools/kvm/Makefile | 1 + tools/kvm/devices.c | 24 +++++++++++++++++++++ tools/kvm/hw/pci-shmem.c | 8 ++++++- tools/kvm/hw/vesa.c | 8 ++++++- tools/kvm/include/kvm/devices.h | 21 ++++++++++++++++++ tools/kvm/include/kvm/pci.h | 2 - tools/kvm/include/kvm/virtio-mmio.h | 1 + tools/kvm/include/kvm/virtio-pci.h | 2 + tools/kvm/pci.c | 40 ++++++++++++---------------------- tools/kvm/powerpc/irq.c | 3 +- tools/kvm/powerpc/spapr_pci.c | 2 +- tools/kvm/virtio/mmio.c | 7 ++++++ tools/kvm/virtio/pci.c | 7 +++++- 13 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 tools/kvm/devices.c create mode 100644 tools/kvm/include/kvm/devices.h