(2011/09/14 13:55), Amos Kong wrote:
'slot->funcs' is initialized in acpiphp_glue.c:register_slot() before hotpluging device, and only one entry(func 0) is added to it, no new entry will be added to the list when hotpluging devices to the slot.
I guess your hotplug slot has only one device object (for func#0) in ACPI Namespace (DSDT), and guess this is why there is only one entry in the 'slot->funcs'. If so, what about adding device objects for function 1-7 to ACPI Namespace? I think most of bare-metal environments have such definition in ACPI Namespace. For example: Device (P2P) { // PCI to PCI bridge Name (_ADR, ...) // PCI address Name (_HPP, ...) // Hot Plug parameter ... Device (S0F0) { // For function 0 Name (_ADR, ...) Name (_SUN, ...) Method (_EJ0, ...) } Device (S0F1) { // For function 1 ... } ... Device (S0F7) { // For function 7 ... } } Regards, Kenji Kaneshige
When we release the whole device, there is only one entry in the list, this causes func1~7 could not be released. I try to add entries for all hotpluged device in enable_device(), but it doesn't work, because 'slot->funcs' is used in many place which we only need to process func 0. This patch just try to clean all funcs in disable_device(). drivers/pci/hotplug/acpiphp_glue.c: static int disable_device(struct acpiphp_slot *slot) { list_for_each_entry(func,&slot->funcs, sibling) { pdev = pci_get_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, func->function)); ..clean code.. // those code can only be executed one time(func 0) pci_remove_bus_device(pdev); --- pci_bus_add_device() is called for each func device in acpiphp_glue.c:enable_device(). pci_remove_bus_device(pdev) is only called for func 0 in acpiphp_glue.c:disable_device(). Boot up a KVM guest, hotplug a multifunc device(8 funcs), we can find it in the guest. @ ls /dev/vd* vda vdb vdc vde vdf vdg vdh @ lspci 00:06.0 SCSI storage controller: Red Hat, Inc Virtio block device ... 00:06.7 SCSI storage controller: Red Hat, Inc Virtio block device But func 1~7 still exist in guest after hot-removing the multifunc device through qemu monitor. @ lspci (00:06.0 disappeared) 00:06.1 SCSI storage controller: Red Hat, Inc Virtio block device (rev ff) ... 00:06.7 SCSI storage controller: Red Hat, Inc Virtio block device (rev ff) ^^^^^^^^ @ ls /dev/vd* vdb vdc vde vdf vdg vdh @ mkfs /dev/vdb INFO: task mkfs.ext2:1784 blocked for more than 120 seconds. (task hung) Hotpluging multifunc of WinXp is fine. Signed-off-by: Amos Kong<akong@xxxxxxxxxx> --- drivers/pci/hotplug/acpiphp_glue.c | 27 ++++++++++++++++++--------- 1 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a70fa89..3b86d1a 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -880,6 +880,8 @@ static int disable_device(struct acpiphp_slot *slot) { struct acpiphp_func *func; struct pci_dev *pdev; + struct pci_bus *bus = slot->bridge->pci_bus; + int i, num = 1; /* is this slot already disabled? */ if (!(slot->flags& SLOT_ENABLED)) @@ -893,16 +895,23 @@ static int disable_device(struct acpiphp_slot *slot) func->bridge = NULL; } - pdev = pci_get_slot(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, func->function)); - if (pdev) { - pci_stop_bus_device(pdev); - if (pdev->subordinate) { - disable_bridges(pdev->subordinate); - pci_disable_device(pdev); + pdev = pci_scan_single_device(bus, + PCI_DEVFN(slot->device, 0)); + if (!pdev) + goto err_exit; + if (pdev->multifunction == 1) + num = 8; + for (i=0; i<num; i++) { + pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, i)); + if (pdev) { + pci_stop_bus_device(pdev); + if (pdev->subordinate) { + disable_bridges(pdev->subordinate); + pci_disable_device(pdev); + } + pci_remove_bus_device(pdev); + pci_dev_put(pdev); } - pci_remove_bus_device(pdev); - pci_dev_put(pdev); } }
-- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html