[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [rfc 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 | 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |