diff mbox

[RFC,08/16] kvm tools: add generic device registration mechanism

Message ID 1352721450-11340-9-git-send-email-will.deacon@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Will Deacon Nov. 12, 2012, 11:57 a.m. UTC
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

Comments

Sasha Levin Nov. 13, 2012, 4:29 a.m. UTC | #1
On 11/12/2012 06:57 AM, Will Deacon wrote:
> 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
> 
> diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
> index c105de1..5da416f 100644
> --- a/tools/kvm/Makefile
> +++ b/tools/kvm/Makefile
> @@ -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
> diff --git a/tools/kvm/devices.c b/tools/kvm/devices.c
> new file mode 100644
> index 0000000..f9666b9
> --- /dev/null
> +++ b/tools/kvm/devices.c
> @@ -0,0 +1,24 @@
> +#include "kvm/devices.h"
> +#include "kvm/kvm.h"
> +
> +#include <linux/err.h>
> +
> +static struct device_header *devices[KVM_MAX_DEVICES];

Does it really have a hard limit at KVM_MAX_DEVICES? Or can we turn it into
something more dynamic (list/tree/whatever)?


Thanks,
Sasha
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Will Deacon Nov. 13, 2012, 10:24 a.m. UTC | #2
Hi Sasha,

On Tue, Nov 13, 2012 at 04:29:33AM +0000, Sasha Levin wrote:
> On 11/12/2012 06:57 AM, Will Deacon wrote:
> > diff --git a/tools/kvm/devices.c b/tools/kvm/devices.c
> > new file mode 100644
> > index 0000000..f9666b9
> > --- /dev/null
> > +++ b/tools/kvm/devices.c
> > @@ -0,0 +1,24 @@
> > +#include "kvm/devices.h"
> > +#include "kvm/kvm.h"
> > +
> > +#include <linux/err.h>
> > +
> > +static struct device_header *devices[KVM_MAX_DEVICES];
> 
> Does it really have a hard limit at KVM_MAX_DEVICES? Or can we turn it into
> something more dynamic (list/tree/whatever)?

Sure, I'm happy to change the datatype to something more appropriate. Matt
also suggested trying to split up PCI devices from MMIO devices so that they
have their own ID namespaces, so I'll need to have a play.

Cheers,

Will

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index c105de1..5da416f 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -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
diff --git a/tools/kvm/devices.c b/tools/kvm/devices.c
new file mode 100644
index 0000000..f9666b9
--- /dev/null
+++ b/tools/kvm/devices.c
@@ -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];
+}
diff --git a/tools/kvm/hw/pci-shmem.c b/tools/kvm/hw/pci-shmem.c
index 4161335..f06c013 100644
--- a/tools/kvm/hw/pci-shmem.c
+++ b/tools/kvm/hw/pci-shmem.c
@@ -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,
diff --git a/tools/kvm/hw/vesa.c b/tools/kvm/hw/vesa.c
index a211491..630d8c9 100644
--- a/tools/kvm/hw/vesa.c
+++ b/tools/kvm/hw/vesa.c
@@ -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)
diff --git a/tools/kvm/include/kvm/devices.h b/tools/kvm/include/kvm/devices.h
new file mode 100644
index 0000000..3546904
--- /dev/null
+++ b/tools/kvm/include/kvm/devices.h
@@ -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 */
diff --git a/tools/kvm/include/kvm/pci.h b/tools/kvm/include/kvm/pci.h
index 26639b5..3da3811 100644
--- a/tools/kvm/include/kvm/pci.h
+++ b/tools/kvm/include/kvm/pci.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);
diff --git a/tools/kvm/include/kvm/virtio-mmio.h b/tools/kvm/include/kvm/virtio-mmio.h
index e0ede3c..983c8fc 100644
--- a/tools/kvm/include/kvm/virtio-mmio.h
+++ b/tools/kvm/include/kvm/virtio-mmio.h
@@ -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];
 };
 
diff --git a/tools/kvm/include/kvm/virtio-pci.h b/tools/kvm/include/kvm/virtio-pci.h
index 44130e0c..6d9a558 100644
--- a/tools/kvm/include/kvm/virtio-pci.h
+++ b/tools/kvm/include/kvm/virtio-pci.h
@@ -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;
diff --git a/tools/kvm/pci.c b/tools/kvm/pci.c
index c77d3cc..0c70343 100644
--- a/tools/kvm/pci.c
+++ b/tools/kvm/pci.c
@@ -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)
diff --git a/tools/kvm/powerpc/irq.c b/tools/kvm/powerpc/irq.c
index e89fa3b..af239fb 100644
--- a/tools/kvm/powerpc/irq.c
+++ b/tools/kvm/powerpc/irq.c
@@ -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++;
diff --git a/tools/kvm/powerpc/spapr_pci.c b/tools/kvm/powerpc/spapr_pci.c
index b74790e..5bfcec1 100644
--- a/tools/kvm/powerpc/spapr_pci.c
+++ b/tools/kvm/powerpc/spapr_pci.c
@@ -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);
 
diff --git a/tools/kvm/virtio/mmio.c b/tools/kvm/virtio/mmio.c
index 6ec33ec..2d538b8 100644
--- a/tools/kvm/virtio/mmio.c
+++ b/tools/kvm/virtio/mmio.c
@@ -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
diff --git a/tools/kvm/virtio/pci.c b/tools/kvm/virtio/pci.c
index adc8efc..e3cfb0a 100644
--- a/tools/kvm/virtio/pci.c
+++ b/tools/kvm/virtio/pci.c
@@ -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;