aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorAmos Kong <akong@redhat.com>2011-11-25 02:03:07 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2012-02-14 11:44:47 -0500
commitf382a086f3129edc152b8044b69ccc6682e637bb (patch)
treef479e5fba237c3a2dcc4b8b7967298dc83448071 /drivers/pci
parent6535943fbf25c8e9419a6b20ca992633baa0bf99 (diff)
PCI: Can continually add funcs after adding func0
Boot up a KVM guest, and hotplug multifunction devices(func1,func2,func0,func3) to guest. for i in 1 2 0 3;do qemu-img create /tmp/resize$i.qcow2 1G -f qcow2 (qemu) drive_add 0x11.$i id=drv11$i,if=none,file=/tmp/resize$i.qcow2 (qemu) device_add virtio-blk-pci,id=dev11$i,drive=drv11$i,addr=0x11.$i,multifunction=on done In linux kernel, when func0 of the slot is hot-added, the whole slot will be marked as 'enabled', then driver will ignore other new hotadded funcs. But in Win7 & WinXP, we can continaully add other funcs after adding func0, all funcs will be added in guest. drivers/pci/hotplug/acpiphp_glue.c: static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) { .... for (slot = bridge->slots; slot; slot = slot->next) { if (slot->flags & SLOT_ENABLED) { acpiphp_disable_slot() else acpiphp_enable_slot() .... | } v enable_device() | v //only don't enable slot if func0 is not added list_for_each_entry(func, &slot->funcs, sibling) { ... } slot->flags |= SLOT_ENABLED; //mark slot to 'enabled' This patch just make pci driver can continaully add funcs after adding func 0. Only mark slot to 'enabled' when all funcs are added. For pci multifunction hotplug, we can add functions one by one(func 0 is necessary), and all functions will be removed in one time. Signed-off-by: Amos Kong <akong@redhat.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c29
1 files changed, 13 insertions, 16 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 9ddf69e3bbef..12d070ca7674 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -800,20 +800,10 @@ static int __ref enable_device(struct acpiphp_slot *slot)
800 if (slot->flags & SLOT_ENABLED) 800 if (slot->flags & SLOT_ENABLED)
801 goto err_exit; 801 goto err_exit;
802 802
803 /* sanity check: dev should be NULL when hot-plugged in */
804 dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
805 if (dev) {
806 /* This case shouldn't happen */
807 err("pci_dev structure already exists.\n");
808 pci_dev_put(dev);
809 retval = -1;
810 goto err_exit;
811 }
812
813 num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); 803 num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
814 if (num == 0) { 804 if (num == 0) {
815 err("No new device found\n"); 805 /* Maybe only part of funcs are added. */
816 retval = -1; 806 dbg("No new device found\n");
817 goto err_exit; 807 goto err_exit;
818 } 808 }
819 809
@@ -848,11 +838,16 @@ static int __ref enable_device(struct acpiphp_slot *slot)
848 838
849 pci_bus_add_devices(bus); 839 pci_bus_add_devices(bus);
850 840
841 slot->flags |= SLOT_ENABLED;
851 list_for_each_entry(func, &slot->funcs, sibling) { 842 list_for_each_entry(func, &slot->funcs, sibling) {
852 dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 843 dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
853 func->function)); 844 func->function));
854 if (!dev) 845 if (!dev) {
846 /* Do not set SLOT_ENABLED flag if some funcs
847 are not added. */
848 slot->flags &= (~SLOT_ENABLED);
855 continue; 849 continue;
850 }
856 851
857 if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE && 852 if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
858 dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) { 853 dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
@@ -867,7 +862,6 @@ static int __ref enable_device(struct acpiphp_slot *slot)
867 pci_dev_put(dev); 862 pci_dev_put(dev);
868 } 863 }
869 864
870 slot->flags |= SLOT_ENABLED;
871 865
872 err_exit: 866 err_exit:
873 return retval; 867 return retval;
@@ -892,9 +886,12 @@ static int disable_device(struct acpiphp_slot *slot)
892{ 886{
893 struct acpiphp_func *func; 887 struct acpiphp_func *func;
894 struct pci_dev *pdev; 888 struct pci_dev *pdev;
889 struct pci_bus *bus = slot->bridge->pci_bus;
895 890
896 /* is this slot already disabled? */ 891 /* The slot will be enabled when func 0 is added, so check
897 if (!(slot->flags & SLOT_ENABLED)) 892 func 0 before disable the slot. */
893 pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
894 if (!pdev)
898 goto err_exit; 895 goto err_exit;
899 896
900 list_for_each_entry(func, &slot->funcs, sibling) { 897 list_for_each_entry(func, &slot->funcs, sibling) {