[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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



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    |   77 ++++++++++++++++++++----------------
 4 files changed, 99 insertions(+), 111 deletions(-)

* Fri, 13 Mar 2009 18:07:36 +1100
  Initial public release

* Mon, 16 Mar 2009 12:55:39 +1100
  Update the description of acpi_php_readb to match the changes made to it

* Mon, 16 Mar 2009 18:04:07 +1100
  Pass NR_PCI_SLOTS + 2 instead of NR_PCI_SLOTS as length parameter of
  register_ioport_read() and register_ioport_write()

* Fri, 20 Mar 2009 11:36:36 +1100
  Fixed a regression in the way that it treats vslots in pt_init.

  pt_init() iterates through the PHP slots independantly of
  the assignment that occurs inside __insert_to_pci_slot
  which is called by register_real_device(). It assumes
  that vslots are assigned in order sarting at PHP_SLOT_START.

  This was valid before my change, although why it didn't take
  the simpler option of just checking what value had been
  assigned to pt_dev->dev.devfn in register_real_device()
  is a mystery to me. Its also a mystery to what valid circumstance
  could lead to pt_init() using 0 (a.k.a. unknown?) as the vslot.


  My patch made one the assumptions that pt_init() made about slot numbers
  invalid. That is, they don't start at PHP_SLOT_START, they start
  wherever there is a free device.

  A simple solution seems to be to use the value assigned to
  pt_dev->dev.devfn in register_real_device().

Index: ioemu-remote/hw/pass-through.c
===================================================================
--- ioemu-remote.orig/hw/pass-through.c 2009-03-20 11:05:58.000000000 +1100
+++ ioemu-remote/hw/pass-through.c      2009-03-20 11:34:56.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++ )
+    /* slot == AUTO_PHP_SLOT, pick up a free one */
+    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 pass-through 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,
@@ -3813,14 +3797,14 @@ int power_on_php_slot(int php_slot)
 
 }
 
-int power_off_php_slot(int php_slot)
+int power_off_php_slot(int slot)
 {
-    return unregister_real_device(php_slot);
+    return unregister_real_device(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, status = -1;
     struct pt_dev *pt_dev;
     struct pci_access *pci_access;
     char *vslots;
@@ -3868,16 +3852,9 @@ 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;", PCI_SLOT(pt_dev->dev.devfn));
 
         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-20 11:01:51.000000000 +1100
+++ ioemu-remote/hw/pci.c       2009-03-20 11:05:58.000000000 +1100
@@ -143,6 +143,11 @@ static int pci_set_default_subsystem_id(
     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,
@@ -153,8 +158,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-20 11:01:51.000000000 +1100
+++ ioemu-remote/hw/pci.h       2009-03-20 11:05:58.000000000 +1100
@@ -196,6 +196,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,
@@ -232,14 +234,8 @@ void pci_info(void);
 PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
                         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-20 11:05:58.000000000 +1100
+++ ioemu-remote/hw/piix4acpi.c 2009-03-20 11:05:58.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;
@@ -218,10 +221,11 @@ static void acpi_dbg_writel(void *opaque
 /*
  * simple PCI hotplug controller IO 
  * ACPI_PHP_IO_ADDR + :
- * 0 - the hotplug description: slot(|event(remove/add); 
- * 1 - 1st php slot ctr/sts reg
- * 2 - 2nd php slot ctr/sts reg
- * ......
+ * 0 - the hotplug event:
+ * 1 - the hotplug slot that has an event:
+ * 2 - 1st php slot ctr/sts reg
+ * 3 - 2nd php slot ctr/sts reg
+ * ...
  */
 static uint32_t acpi_php_readb(void *opaque, uint32_t addr)
 {
@@ -234,8 +238,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 +255,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 +263,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 +288,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 +301,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 +315,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 + 2, 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 + 2, 1,
                           acpi_php_writeb, &php_slots);
     register_savevm("pcislots", 0, 1, pcislots_save, pcislots_load,
                     &php_slots);
@@ -449,36 +459,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 +498,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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.