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
|