diff options
Diffstat (limited to 'drivers/pci/hotplug/fakephp.c')
| -rw-r--r-- | drivers/pci/hotplug/fakephp.c | 86 |
1 files changed, 30 insertions, 56 deletions
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 7e9a827c2687..40337a06c18a 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c | |||
| @@ -66,6 +66,7 @@ struct dummy_slot { | |||
| 66 | struct pci_dev *dev; | 66 | struct pci_dev *dev; |
| 67 | struct work_struct remove_work; | 67 | struct work_struct remove_work; |
| 68 | unsigned long removed; | 68 | unsigned long removed; |
| 69 | char name[8]; | ||
| 69 | }; | 70 | }; |
| 70 | 71 | ||
| 71 | static int debug; | 72 | static int debug; |
| @@ -100,6 +101,7 @@ static int add_slot(struct pci_dev *dev) | |||
| 100 | struct dummy_slot *dslot; | 101 | struct dummy_slot *dslot; |
| 101 | struct hotplug_slot *slot; | 102 | struct hotplug_slot *slot; |
| 102 | int retval = -ENOMEM; | 103 | int retval = -ENOMEM; |
| 104 | static int count = 1; | ||
| 103 | 105 | ||
| 104 | slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); | 106 | slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); |
| 105 | if (!slot) | 107 | if (!slot) |
| @@ -113,18 +115,18 @@ static int add_slot(struct pci_dev *dev) | |||
| 113 | slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; | 115 | slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; |
| 114 | slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; | 116 | slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; |
| 115 | 117 | ||
| 116 | slot->name = &dev->dev.bus_id[0]; | ||
| 117 | dbg("slot->name = %s\n", slot->name); | ||
| 118 | |||
| 119 | dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); | 118 | dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); |
| 120 | if (!dslot) | 119 | if (!dslot) |
| 121 | goto error_info; | 120 | goto error_info; |
| 122 | 121 | ||
| 122 | slot->name = dslot->name; | ||
| 123 | snprintf(slot->name, sizeof(dslot->name), "fake%d", count++); | ||
| 124 | dbg("slot->name = %s\n", slot->name); | ||
| 123 | slot->ops = &dummy_hotplug_slot_ops; | 125 | slot->ops = &dummy_hotplug_slot_ops; |
| 124 | slot->release = &dummy_release; | 126 | slot->release = &dummy_release; |
| 125 | slot->private = dslot; | 127 | slot->private = dslot; |
| 126 | 128 | ||
| 127 | retval = pci_hp_register(slot); | 129 | retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn)); |
| 128 | if (retval) { | 130 | if (retval) { |
| 129 | err("pci_hp_register failed with error %d\n", retval); | 131 | err("pci_hp_register failed with error %d\n", retval); |
| 130 | goto error_dslot; | 132 | goto error_dslot; |
| @@ -148,17 +150,17 @@ error: | |||
| 148 | static int __init pci_scan_buses(void) | 150 | static int __init pci_scan_buses(void) |
| 149 | { | 151 | { |
| 150 | struct pci_dev *dev = NULL; | 152 | struct pci_dev *dev = NULL; |
| 151 | int retval = 0; | 153 | int lastslot = 0; |
| 152 | 154 | ||
| 153 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | 155 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { |
| 154 | retval = add_slot(dev); | 156 | if (PCI_FUNC(dev->devfn) > 0 && |
| 155 | if (retval) { | 157 | lastslot == PCI_SLOT(dev->devfn)) |
| 156 | pci_dev_put(dev); | 158 | continue; |
| 157 | break; | 159 | lastslot = PCI_SLOT(dev->devfn); |
| 158 | } | 160 | add_slot(dev); |
| 159 | } | 161 | } |
| 160 | 162 | ||
| 161 | return retval; | 163 | return 0; |
| 162 | } | 164 | } |
| 163 | 165 | ||
| 164 | static void remove_slot(struct dummy_slot *dslot) | 166 | static void remove_slot(struct dummy_slot *dslot) |
| @@ -296,23 +298,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) | |||
| 296 | return 0; | 298 | return 0; |
| 297 | } | 299 | } |
| 298 | 300 | ||
| 299 | /* find the hotplug_slot for the pci_dev */ | ||
| 300 | static struct hotplug_slot *get_slot_from_dev(struct pci_dev *dev) | ||
| 301 | { | ||
| 302 | struct dummy_slot *dslot; | ||
| 303 | |||
| 304 | list_for_each_entry(dslot, &slot_list, node) { | ||
| 305 | if (dslot->dev == dev) | ||
| 306 | return dslot->slot; | ||
| 307 | } | ||
| 308 | return NULL; | ||
| 309 | } | ||
| 310 | |||
| 311 | |||
| 312 | static int disable_slot(struct hotplug_slot *slot) | 301 | static int disable_slot(struct hotplug_slot *slot) |
| 313 | { | 302 | { |
| 314 | struct dummy_slot *dslot; | 303 | struct dummy_slot *dslot; |
| 315 | struct hotplug_slot *hslot; | ||
| 316 | struct pci_dev *dev; | 304 | struct pci_dev *dev; |
| 317 | int func; | 305 | int func; |
| 318 | 306 | ||
| @@ -322,41 +310,27 @@ static int disable_slot(struct hotplug_slot *slot) | |||
| 322 | 310 | ||
| 323 | dbg("%s - physical_slot = %s\n", __func__, slot->name); | 311 | dbg("%s - physical_slot = %s\n", __func__, slot->name); |
| 324 | 312 | ||
| 325 | /* don't disable bridged devices just yet, we can't handle them easily... */ | 313 | for (func = 7; func >= 0; func--) { |
| 326 | if (dslot->dev->subordinate) { | 314 | dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func); |
| 327 | err("Can't remove PCI devices with other PCI devices behind it yet.\n"); | 315 | if (!dev) |
| 328 | return -ENODEV; | 316 | continue; |
| 329 | } | 317 | |
| 330 | if (test_and_set_bit(0, &dslot->removed)) { | 318 | if (test_and_set_bit(0, &dslot->removed)) { |
| 331 | dbg("Slot already scheduled for removal\n"); | 319 | dbg("Slot already scheduled for removal\n"); |
| 332 | return -ENODEV; | 320 | return -ENODEV; |
| 333 | } | ||
| 334 | /* search for subfunctions and disable them first */ | ||
| 335 | if (!(dslot->dev->devfn & 7)) { | ||
| 336 | for (func = 1; func < 8; func++) { | ||
| 337 | dev = pci_get_slot(dslot->dev->bus, | ||
| 338 | dslot->dev->devfn + func); | ||
| 339 | if (dev) { | ||
| 340 | hslot = get_slot_from_dev(dev); | ||
| 341 | if (hslot) | ||
| 342 | disable_slot(hslot); | ||
| 343 | else { | ||
| 344 | err("Hotplug slot not found for subfunction of PCI device\n"); | ||
| 345 | return -ENODEV; | ||
| 346 | } | ||
| 347 | pci_dev_put(dev); | ||
| 348 | } else | ||
| 349 | dbg("No device in slot found\n"); | ||
| 350 | } | 321 | } |
| 351 | } | ||
| 352 | 322 | ||
| 353 | /* remove the device from the pci core */ | 323 | /* queue work item to blow away this sysfs entry and other |
| 354 | pci_remove_bus_device(dslot->dev); | 324 | * parts. |
| 325 | */ | ||
| 326 | INIT_WORK(&dslot->remove_work, remove_slot_worker); | ||
| 327 | queue_work(dummyphp_wq, &dslot->remove_work); | ||
| 355 | 328 | ||
| 356 | /* queue work item to blow away this sysfs entry and other parts. */ | 329 | /* blow away this sysfs entry and other parts. */ |
| 357 | INIT_WORK(&dslot->remove_work, remove_slot_worker); | 330 | remove_slot(dslot); |
| 358 | queue_work(dummyphp_wq, &dslot->remove_work); | ||
| 359 | 331 | ||
| 332 | pci_dev_put(dev); | ||
| 333 | } | ||
| 360 | return 0; | 334 | return 0; |
| 361 | } | 335 | } |
| 362 | 336 | ||
