WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [rfc 2/2] ioemu: Allow any unused PCI device to be used for

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [rfc 2/2] ioemu: Allow any unused PCI device to be used for pass-through
From: Simon Horman <horms@xxxxxxxxxxxx>
Date: Fri, 13 Mar 2009 18:07:36 +1100
Delivery-date: Fri, 13 Mar 2009 00:23:08 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <20090313070734.348651100@xxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: quilt/0.46-1
Allow any unused PCI device to be used for pass-through.
This includes allowing these devices to be used for hotplug.

There are companion xend and hvmloader patches.

Signed-off-by: Simon Horman <horms@xxxxxxxxxxxx>

--- 

 hw/pass-through.c |  113 ++++++++++++++++++++++-------------------------------
 hw/pci.c          |    8 ++-
 hw/pci.h          |   12 +----
 hw/piix4acpi.c    |   68 ++++++++++++++++++-------------
 4 files changed, 96 insertions(+), 105 deletions(-)

Index: ioemu-remote/hw/pass-through.c
===================================================================
--- ioemu-remote.orig/hw/pass-through.c 2009-03-13 17:51:06.000000000 +1100
+++ ioemu-remote/hw/pass-through.c      2009-03-13 17:55:51.000000000 +1100
@@ -39,7 +39,7 @@ struct php_dev {
 };
 struct dpci_infos {
 
-    struct php_dev php_devs[PHP_SLOT_LEN];
+    struct php_dev php_devs[NR_PCI_DEV];
 
     PCIBus *e_bus;
     struct pci_access *pci_access;
@@ -819,51 +819,41 @@ static int get_next_keyval(char **option
 }
 
 /* Insert a new pass-through device into a specific pci slot.
- * input  dom:bus:dev.func@slot, chose free one if slot == 0
- * return -1: required slot not available
- *         0: no free hotplug slots, but normal slot should okay
- *        >0: the new hotplug slot
+ * input  dom:bus:dev.func@slot, chose free one if slot == AUTO_PHP_SLOT
+ * return -2: requested slot not available
+ *        -1: no free slots
+ *        >=0: the new hotplug slot
  */
 static int __insert_to_pci_slot(int bus, int dev, int func, int slot,
                                 char *opt)
 {
-    int i, php_slot;
+    PCIBus *e_bus = dpci_infos.e_bus;
 
     /* preferred virt pci slot */
-    if ( slot >= PHP_SLOT_START && slot < PHP_SLOT_END )
+    if ( slot != AUTO_PHP_SLOT)
     {
-        php_slot = PCI_TO_PHP_SLOT(slot);
-        if ( !test_pci_slot(slot) )
-        {
+        if ( !test_pci_slot(slot) && !pci_devfn_in_use(e_bus, slot << 3) )
             goto found;
-        }
-        else
-            return -1;
+        return -2;
     }
 
-    if ( slot != 0 )
-        return -1;
-
     /* slot == 0, pick up a free one */
-    for ( i = 0; i < PHP_SLOT_LEN; i++ )
+    for ( slot = 0; slot < NR_PCI_DEV; slot++ )
     {
-        if ( !test_pci_slot(PHP_TO_PCI_SLOT(i)) )
-        {
-            php_slot = i;
+        if ( !test_pci_slot(slot) && !pci_devfn_in_use(e_bus, slot << 3) )
             goto found;
-        }
     }
 
     /* not found */
-    return 0;
+    return -1;
 
 found:
-    dpci_infos.php_devs[php_slot].valid  = 1;
-    dpci_infos.php_devs[php_slot].r_bus  = bus;
-    dpci_infos.php_devs[php_slot].r_dev  = dev;
-    dpci_infos.php_devs[php_slot].r_func = func;
-    dpci_infos.php_devs[php_slot].opt = opt;
-    return PHP_TO_PCI_SLOT(php_slot);
+    dpci_infos.php_devs[slot].valid  = 1;
+    dpci_infos.php_devs[slot].r_bus  = bus;
+    dpci_infos.php_devs[slot].r_dev  = dev;
+    dpci_infos.php_devs[slot].r_func = func;
+    dpci_infos.php_devs[slot].opt = opt;
+    return slot;
 }
 
 /* Insert a new pass-through device into a specific pci slot.
@@ -872,7 +862,7 @@ found:
 int insert_to_pci_slot(char *bdf_slt)
 {
     int seg, bus, dev, func, slot;
-    char *bdf_str, *slt_str, *opt;
+    char *bdf_str, *slt_str, *opt, *endptr;
     const char *delim="@";
 
     bdf_str = strsep(&bdf_slt, delim);
@@ -888,23 +878,20 @@ int insert_to_pci_slot(char *bdf_slt)
 
 }
 
-/* Test if a pci slot has a device
+/* Test if a pci slot has a PHP device
  * 1:  present
  * 0:  not present
- * -1: invalide pci slot input
+ * -1: invalid pci slot input
  */
 int test_pci_slot(int slot)
 {
-    int php_slot;
-
-    if ( slot < PHP_SLOT_START || slot >= PHP_SLOT_END )
+    if ( slot < 0 || slot >= NR_PCI_DEV )
         return -1;
 
-    php_slot = PCI_TO_PHP_SLOT(slot);
-    if ( dpci_infos.php_devs[php_slot].valid )
+    if ( dpci_infos.php_devs[slot].valid )
         return 1;
-    else
-        return 0;
+
+    return 0;
 }
 
 /* find the pci slot for pass-through dev with specified BDF */
@@ -919,15 +906,13 @@ int bdf_to_slot(char *bdf_str)
     }
 
     /* locate the virtual pci slot for this VTd device */
-    for ( i = 0; i < PHP_SLOT_LEN; i++ )
+    for ( i = 0; i < NR_PCI_DEV; i++ )
     {
         if ( dpci_infos.php_devs[i].valid &&
            dpci_infos.php_devs[i].r_bus == bus &&
            dpci_infos.php_devs[i].r_dev  == dev &&
            dpci_infos.php_devs[i].r_func == func )
-        {
-            return PHP_TO_PCI_SLOT(i);
-        }
+            return i;
     }
 
     return -1;
@@ -3562,7 +3547,7 @@ struct pt_dev * register_real_device(PCI
     struct pci_dev *pci_dev;
     uint8_t e_device, e_intx;
     struct pci_config_cf8 machine_bdf;
-    int free_pci_slot = -1;
+    int free_slot = -1;
     char *key, *val;
     int msi_translate;
 
@@ -3587,13 +3572,13 @@ struct pt_dev * register_real_device(PCI
 
     if ( e_devfn == PT_VIRT_DEVFN_AUTO ) {
         /*indicate a static assignment(not hotplug), so find a free PCI hot 
plug slot */
-        free_pci_slot = __insert_to_pci_slot(r_bus, r_dev, r_func, 0, NULL);
-        if ( free_pci_slot > 0 )
-            e_devfn = free_pci_slot  << 3;
-        else {
+        free_slot = __insert_to_pci_slot(r_bus, r_dev, r_func,
+                                         AUTO_PHP_SLOT, NULL);
+        if ( free_slot < 0 ) {
             PT_LOG("Error: no free virtual PCI hot plug slot, thus no live 
migration.\n");
             return NULL;
         }
+        e_devfn = free_slot << 3;
     }
 
     msi_translate = direct_pci_msitranslate;
@@ -3634,8 +3619,8 @@ struct pt_dev * register_real_device(PCI
         return NULL;
     }
 
-    if ( free_pci_slot > 0 )
-        dpci_infos.php_devs[PCI_TO_PHP_SLOT(free_pci_slot)].pt_dev = 
assigned_device;
+    if ( free_slot > 0 )
+        dpci_infos.php_devs[free_slot].pt_dev = assigned_device;
 
     assigned_device->pci_dev = pci_dev;
     assigned_device->msi_trans_cap = msi_translate;
@@ -3718,7 +3703,7 @@ out:
     return assigned_device;
 }
 
-int unregister_real_device(int php_slot)
+int unregister_real_device(int slot)
 {
     struct php_dev *php_dev;
     struct pci_dev *pci_dev;
@@ -3728,10 +3713,10 @@ int unregister_real_device(int php_slot)
     uint32_t bdf = 0;
     int rc = -1;
 
-    if ( test_pci_slot(PHP_TO_PCI_SLOT(php_slot)) != 1 )
+    if ( test_pci_slot(slot) != 1 )
        return -1;
 
-    php_dev = &dpci_infos.php_devs[php_slot];
+    php_dev = &dpci_infos.php_devs[slot];
     assigned_device = php_dev->pt_dev;
 
     if ( !assigned_device )
@@ -3789,15 +3774,14 @@ int unregister_real_device(int php_slot)
     return 0;
 }
 
-int power_on_php_slot(int php_slot)
+int power_on_php_slot(int slot)
 {
-    struct php_dev *php_dev = &dpci_infos.php_devs[php_slot];
-    int pci_slot = php_slot + PHP_SLOT_START;
+    struct php_dev *php_dev = &dpci_infos.php_devs[slot];
     struct pt_dev *pt_dev;
     pt_dev =
         register_real_device(dpci_infos.e_bus,
             "DIRECT PCI",
-            pci_slot << 3,
+            slot << 3,
             php_dev->r_bus,
             php_dev->r_dev,
             php_dev->r_func,
@@ -3820,7 +3804,7 @@ int power_off_php_slot(int php_slot)
 
 int pt_init(PCIBus *e_bus, const char *direct_pci)
 {
-    int seg, b, d, f, php_slot = 0, status = -1;
+    int seg, b, d, f, slot, status = -1;
     struct pt_dev *pt_dev;
     struct pci_access *pci_access;
     char *vslots;
@@ -3856,7 +3840,9 @@ int pt_init(PCIBus *e_bus, const char *d
     vslots = qemu_mallocz ( strlen(direct_pci) / 3 );
 
     /* Assign given devices to guest */
-    while ( next_bdf(&direct_pci_p, &seg, &b, &d, &f, &opt) )
+    for ( slot = 0;
+          slot < NR_PCI_DEV && next_bdf(&direct_pci_p, &seg, &b, &d, &f, &opt);
+          slot++ )
     {
         /* Register real device with the emulated bus */
         pt_dev = register_real_device(e_bus, "DIRECT PCI", PT_VIRT_DEVFN_AUTO,
@@ -3868,16 +3854,11 @@ int pt_init(PCIBus *e_bus, const char *d
         }
 
         /* Record the virtual slot info */
-        if ( php_slot < PHP_SLOT_LEN &&
-              dpci_infos.php_devs[php_slot].pt_dev == pt_dev )
-        {
-            sprintf(slot_str, "0x%x;", PHP_TO_PCI_SLOT(php_slot));
-        }
-        else
-            sprintf(slot_str, "0x%x;", 0);
+        sprintf(slot_str, "0x%02x;",
+                dpci_infos.php_devs[slot].pt_dev == pt_dev ? slot :
+                AUTO_PHP_SLOT);
 
         strcat(vslots, slot_str);
-        php_slot++;
     }
 
     /* Write virtual slots info to xenstore for Control panel use */
Index: ioemu-remote/hw/pci.c
===================================================================
--- ioemu-remote.orig/hw/pci.c  2009-03-13 17:49:44.000000000 +1100
+++ ioemu-remote/hw/pci.c       2009-03-13 17:54:59.000000000 +1100
@@ -130,6 +130,11 @@ int pci_device_load(PCIDevice *s, QEMUFi
     return 0;
 }
 
+int pci_devfn_in_use(PCIBus *bus, int devfn)
+{
+        return bus->devices[devfn] ? 1 : 0;
+}
+
 /* -1 for devfn means auto assign */
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
@@ -140,8 +145,7 @@ PCIDevice *pci_register_device(PCIBus *b
 
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) {
-            if ( !bus->devices[devfn] &&
-                 !( devfn >= PHP_DEVFN_START && devfn < PHP_DEVFN_END ) )
+            if ( !pci_devfn_in_use(bus, devfn) )
                 goto found;
         }
         return NULL;
Index: ioemu-remote/hw/pci.h
===================================================================
--- ioemu-remote.orig/hw/pci.h  2009-03-13 17:49:44.000000000 +1100
+++ ioemu-remote/hw/pci.h       2009-03-13 17:54:59.000000000 +1100
@@ -66,6 +66,8 @@ struct PCIDevice {
 extern char direct_pci_str[];
 extern int direct_pci_msitranslate;
 
+int pci_devfn_in_use(PCIBus *bus, int devfn);
+
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
                                PCIConfigReadFunc *config_read,
@@ -101,14 +103,8 @@ void pci_info(void);
 PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
                         pci_map_irq_fn map_irq, const char *name);
 
-/* PCI slot 6~7 support ACPI PCI hot plug */
-#define PHP_SLOT_START  (6)
-#define PHP_SLOT_END    (8)
-#define PHP_SLOT_LEN    (PHP_SLOT_END - PHP_SLOT_START)
-#define PHP_TO_PCI_SLOT(x) (x + PHP_SLOT_START)
-#define PCI_TO_PHP_SLOT(x) (x - PHP_SLOT_START)
-#define PHP_DEVFN_START (PHP_SLOT_START << 3)
-#define PHP_DEVFN_END   (PHP_SLOT_END << 3)
+#define NR_PCI_DEV 32
+#define AUTO_PHP_SLOT NR_PCI_DEV
 
 int insert_to_pci_slot(char*);
 int test_pci_slot(int);
Index: ioemu-remote/hw/piix4acpi.c
===================================================================
--- ioemu-remote.orig/hw/piix4acpi.c    2009-03-13 17:49:44.000000000 +1100
+++ ioemu-remote/hw/piix4acpi.c 2009-03-13 17:54:59.000000000 +1100
@@ -75,8 +75,11 @@ typedef struct GPEState {
 GPEState gpe_state;
 
 typedef struct PHPSlots {
-    uint8_t status[PHP_SLOT_LEN]; /* Apaptor stats */
-    uint8_t plug_evt;      /* slot|event slot:0-no event;1-1st. 
event:0-remove;1-add */
+    uint8_t status[NR_PCI_DEV]; /* Apaptor stats */
+    uint8_t plug_evt;           /* PHP_EVT_ADD or PHP_EVT_REMOVE
+                                 * PSTA in ASL */
+    uint8_t plug_slot;          /* Slot number
+                                 * PSTB in ASL */
 } PHPSlots;
 
 PHPSlots php_slots;
@@ -234,8 +237,11 @@ static uint32_t acpi_php_readb(void *opa
     case ACPI_PHP_IO_ADDR:
         val = hotplug_slots->plug_evt;
         break;
+    case ACPI_PHP_IO_ADDR + 1:
+        val = hotplug_slots->plug_slot;
+        break;
     default:
-        num = addr - ACPI_PHP_IO_ADDR - 1;
+        num = addr - ACPI_PHP_IO_ADDR - 2;
         val = hotplug_slots->status[num];
     }
 
@@ -248,7 +254,7 @@ static uint32_t acpi_php_readb(void *opa
 static void acpi_php_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
     PHPSlots *hotplug_slots = opaque;
-    int php_slot;
+    int slot;
 
     fprintf(logfile, "ACPI PCI hotplug: write addr=0x%x, val=0x%x.\n",
             addr, val);
@@ -256,18 +262,20 @@ static void acpi_php_writeb(void *opaque
     switch (addr)
     {
     case ACPI_PHP_IO_ADDR:
+    case ACPI_PHP_IO_ADDR + 1:
         break;
     default:
-        php_slot = addr - ACPI_PHP_IO_ADDR - 1;
+        slot = addr - ACPI_PHP_IO_ADDR - 2;
         if ( val == 0x1 ) { /* Eject command */
             /* make _STA of the slot 0 */
-            hotplug_slots->status[php_slot] = 0;
+            hotplug_slots->status[slot] = 0;
 
             /* clear the hotplug event */
             hotplug_slots->plug_evt = 0;
+            hotplug_slots->plug_slot = 0;
 
             /* power off the slot */
-            power_off_php_slot(php_slot);
+            power_off_php_slot(slot);
 
             /* signal the CP ACPI hot remove done. */
             xenstore_record_dm_state("pci-removed");
@@ -279,10 +287,11 @@ static void pcislots_save(QEMUFile* f, v
 {
     PHPSlots *hotplug_slots = opaque;
     int i;
-    for ( i = 0; i < PHP_SLOT_LEN; i++ ) {
+    for ( i = 0; i < NR_PCI_DEV; i++ ) {
         qemu_put_8s( f, &hotplug_slots->status[i]);
     }
     qemu_put_8s(f, &hotplug_slots->plug_evt);
+    qemu_put_8s(f, &hotplug_slots->plug_slot);
 }
 
 static int pcislots_load(QEMUFile* f, void* opaque, int version_id)
@@ -291,10 +300,11 @@ static int pcislots_load(QEMUFile* f, vo
     int i;
     if (version_id != 1)
         return -EINVAL;
-    for ( i = 0; i < PHP_SLOT_LEN; i++ ) {
+    for ( i = 0; i < NR_PCI_DEV; i++ ) {
         qemu_get_8s( f, &hotplug_slots->status[i]);
     }
     qemu_get_8s(f, &hotplug_slots->plug_evt);
+    qemu_get_8s(f, &hotplug_slots->plug_slot);
     return 0;
 }
 
@@ -304,16 +314,15 @@ static void php_slots_init(void)
     memset(&php_slots, 0, sizeof(PHPSlots));
 
     /* update the pci slot status */
-    for ( i = 0; i < PHP_SLOT_LEN; i++ ) {
-        if ( test_pci_slot( PHP_TO_PCI_SLOT(i) ) == 1 )
+    for ( i = 0; i < NR_PCI_DEV; i++ ) {
+        if ( test_pci_slot(i) )
             php_slots.status[i] = 0xf;
     }
 
-
     /* ACPI PCI hotplug controller */
-    register_ioport_read(ACPI_PHP_IO_ADDR, PHP_SLOT_LEN + 1, 1,
+    register_ioport_read(ACPI_PHP_IO_ADDR, NR_PCI_DEV, 1,
                          acpi_php_readb, &php_slots);
-    register_ioport_write(ACPI_PHP_IO_ADDR, PHP_SLOT_LEN + 1, 1,
+    register_ioport_write(ACPI_PHP_IO_ADDR, NR_PCI_DEV, 1,
                           acpi_php_writeb, &php_slots);
     register_savevm("pcislots", 0, 1, pcislots_save, pcislots_load,
                     &php_slots);
@@ -449,36 +458,36 @@ static void acpi_sci_intr(GPEState *s)
     }
 }
 
-void acpi_php_del(int pci_slot)
+void acpi_php_del(int slot)
 {
     GPEState *s = &gpe_state;
-    int php_slot = PCI_TO_PHP_SLOT(pci_slot);
 
-    if ( test_pci_slot(pci_slot) < 0 ) {
-        fprintf(logfile, "not find the pci slot %d when hot remove.\n", 
pci_slot);
+    if ( test_pci_slot(slot) < 0 ) {
+        fprintf(logfile, "hot remove: pci slot %d "
+                "is not used by a hotplug device.\n", slot);
 
         return;
     }
 
     /* update the php controller status */
-    php_slots.plug_evt = (((php_slot+1) << 4) | PHP_EVT_REMOVE);
+    php_slots.plug_evt = PHP_EVT_REMOVE;
+    php_slots.plug_slot = slot;
 
     /* generate a SCI interrupt */
     acpi_sci_intr(s);
 }
 
-void acpi_php_add(int pci_slot)
+void acpi_php_add(int slot)
 {
     GPEState *s = &gpe_state;
-    int php_slot = PCI_TO_PHP_SLOT(pci_slot);
     char ret_str[30];
 
-    if ( pci_slot < PHP_SLOT_START || pci_slot >= PHP_SLOT_END ) {
-        fprintf(logfile, "hot add pci slot %d exceed.\n", pci_slot);
+    if ( slot < 0 ) {
+        fprintf(logfile, "hot add pci slot %d exceed.\n", slot);
 
-        if ( pci_slot == 0 )
+        if ( slot == -1 )
             sprintf(ret_str, "no free hotplug slots");
-        else if ( pci_slot == -1 )
+        else if ( slot == -2 )
             sprintf(ret_str, "wrong bdf or vslot");
 
         if ( strlen(ret_str) > 0 )
@@ -488,16 +497,17 @@ void acpi_php_add(int pci_slot)
     }
 
     /* update the php controller status */
-    php_slots.plug_evt = (((php_slot+1) << 4) | PHP_EVT_ADD);
+    php_slots.plug_evt = PHP_EVT_ADD;
+    php_slots.plug_slot = slot;
 
     /* update the slot status as present */
-    php_slots.status[php_slot]= 0xf;
+    php_slots.status[slot] = 0xf;
 
     /* power on the slot */
-    power_on_php_slot(php_slot);
+    power_on_php_slot(slot);
 
     /* tell Control panel which slot for the new pass-throgh dev */
-    sprintf(ret_str, "0x%x", pci_slot);
+    sprintf(ret_str, "0x%x", slot);
     xenstore_record_dm("parameter", ret_str);
 
     /* signal the CP ACPI hot insert done */

-- 

-- 
Simon Horman
  VA Linux Systems Japan K.K., Sydney, Australia Satellite Office
  H: www.vergenet.net/~horms/             W: www.valinux.co.jp/en


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel