This patch changes virtio devices to be multi-function devices whenever
possible.  This increases the number of virtio devices we can support now by
a factor of 8.

With this patch, I've been able to launch a guest with either 220 disks or 220
network adapters.

Since v1, I've changed the way virtio devices are allocated to be as follows:

 1) Always use a slot as long as they are available.  We can extend this to
    use a PCI when we get that working more reliably.

 2) When PCI slots are exhausted, fall back add device as an additional
    function on an existing slot

This way, hotplug continues to work just as well as it does now.  Once you
exceed the number of PCI slots, you need an OS that can do hotplug of
individual PCI functions if you care about doing hotplug.  I think this is a
pretty reasonable trade-off.

Signed-off-by: Anthony Liguori <[EMAIL PROTECTED]>

diff --git a/qemu/hw/pci.c b/qemu/hw/pci.c
index a23a466..5d5d1a5 100644
--- a/qemu/hw/pci.c
+++ b/qemu/hw/pci.c
@@ -146,6 +146,41 @@ int pci_device_load(PCIDevice *s, QEMUFile *f)
     return 0;
 }
 
+/* Search the bus for a multifunction device with a free function that
+ * matches vendor_id_filter and device_id_filter.  -1 can be passed as
+ * a filter value to accept any id.
+ */
+int pci_bus_find_device_function(PCIBus *bus, int vendor_id_filter,
+                                int device_id_filter)
+{
+    int devfn;
+
+    for (devfn = bus->devfn_min; devfn < 256; devfn += 8) {
+       int vendor_id, device_id;
+       PCIDevice *pci_dev;
+
+       if (!bus->devices[devfn])
+           continue;
+
+       pci_dev = bus->devices[devfn];
+       vendor_id = pci_dev->config[0x01] << 8 | pci_dev->config[0x00];
+       device_id = pci_dev->config[0x03] << 8 | pci_dev->config[0x02];
+
+       if ((vendor_id_filter == -1 || vendor_id_filter == vendor_id) &&
+           (device_id_filter == -1 || device_id_filter == device_id) &&
+           ((pci_dev->config[0x0e] & 0x80) == 0x80)) {
+           int i;
+
+           for (i = 1; i < 8; i++) {
+               if (!bus->devices[devfn + i])
+                   return devfn + i;
+           }
+       }
+    }
+
+    return -1;
+}
+
 /* -1 for devfn means auto assign */
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
diff --git a/qemu/hw/pci.h b/qemu/hw/pci.h
index 60e4094..84d6a29 100644
--- a/qemu/hw/pci.h
+++ b/qemu/hw/pci.h
@@ -33,7 +33,7 @@ typedef struct PCIIORegion {
 #define PCI_ROM_SLOT 6
 #define PCI_NUM_REGIONS 7
 
-#define PCI_DEVICES_MAX 64
+#define PCI_DEVICES_MAX 256
 
 #define PCI_VENDOR_ID          0x00    /* 16 bits */
 #define PCI_DEVICE_ID          0x02    /* 16 bits */
@@ -105,6 +105,9 @@ void pci_info(void);
 PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
                         pci_map_irq_fn map_irq, const char *name);
 
+int pci_bus_find_device_function(PCIBus *bus, int vendor_id_filter,
+                                int device_id_filter);
+
 /* lsi53c895a.c */
 #define LSI_MAX_DEVS 7
 void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id);
diff --git a/qemu/hw/virtio.c b/qemu/hw/virtio.c
index 6a50001..361455d 100644
--- a/qemu/hw/virtio.c
+++ b/qemu/hw/virtio.c
@@ -405,12 +405,22 @@ VirtIODevice *virtio_init_pci(PCIBus *bus, const char 
*name,
     PCIDevice *pci_dev;
     uint8_t *config;
     uint32_t size;
+    int devfn = -1;
 
-    pci_dev = pci_register_device(bus, name, struct_size,
-                                 -1, NULL, NULL);
-    if (!pci_dev)
+    pci_dev = pci_register_device(bus, name, struct_size, -1, NULL, NULL);
+
+    if (pci_dev == NULL) {
+       devfn = pci_bus_find_device_function(bus, vendor, -1);
+       if (devfn != -1)
+           pci_dev = pci_register_device(bus, name, struct_size,
+                                         devfn, NULL, NULL);
+    }
+
+    if (pci_dev == NULL)
        return NULL;
 
+    devfn = pci_dev->devfn;
+
     vdev = to_virtio_device(pci_dev);
 
     vdev->status = 0;
@@ -438,6 +448,10 @@ VirtIODevice *virtio_init_pci(PCIBus *bus, const char 
*name,
 
     config[0x3d] = 1;
 
+    /* Mark device as multi-function */
+    if ((devfn % 8) == 0)
+       config[0x0e] |= 0x80;
+
     vdev->name = name;
     vdev->config_len = config_size;
     if (vdev->config_len)
diff --git a/qemu/net.h b/qemu/net.h
index 13daa27..3bada75 100644
--- a/qemu/net.h
+++ b/qemu/net.h
@@ -42,7 +42,7 @@ void net_client_uninit(NICInfo *nd);
 
 /* NIC info */
 
-#define MAX_NICS 8
+#define MAX_NICS 256
 
 struct NICInfo {
     uint8_t macaddr[6];
diff --git a/qemu/sysemu.h b/qemu/sysemu.h
index c60072d..4385802 100644
--- a/qemu/sysemu.h
+++ b/qemu/sysemu.h
@@ -149,7 +149,7 @@ typedef struct DriveInfo {
 
 #define MAX_IDE_DEVS   2
 #define MAX_SCSI_DEVS  7
-#define MAX_DRIVES 32
+#define MAX_DRIVES 256
 
 int nb_drives;
 DriveInfo drives_table[MAX_DRIVES+1];
diff --git a/qemu/vl.c b/qemu/vl.c
index 74be059..824e331 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -8717,7 +8717,7 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type)
 }
 #endif
 
-#define MAX_NET_CLIENTS 32
+#define MAX_NET_CLIENTS 512
 
 static int saved_argc;
 static char **saved_argv;

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to