diff options
Diffstat (limited to 'drivers/pci/hotplug/pciehp_core.c')
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 127 |
1 files changed, 33 insertions, 94 deletions
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 48a2ed378914..3677495c4f91 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -72,7 +72,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); | |||
72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
73 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 73 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
74 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 74 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
75 | static int get_address (struct hotplug_slot *slot, u32 *value); | ||
76 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 75 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
77 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 76 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
78 | 77 | ||
@@ -85,7 +84,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { | |||
85 | .get_attention_status = get_attention_status, | 84 | .get_attention_status = get_attention_status, |
86 | .get_latch_status = get_latch_status, | 85 | .get_latch_status = get_latch_status, |
87 | .get_adapter_status = get_adapter_status, | 86 | .get_adapter_status = get_adapter_status, |
88 | .get_address = get_address, | ||
89 | .get_max_bus_speed = get_max_bus_speed, | 87 | .get_max_bus_speed = get_max_bus_speed, |
90 | .get_cur_bus_speed = get_cur_bus_speed, | 88 | .get_cur_bus_speed = get_cur_bus_speed, |
91 | }; | 89 | }; |
@@ -185,23 +183,10 @@ static struct hotplug_slot_attribute hotplug_slot_attr_lock = { | |||
185 | */ | 183 | */ |
186 | static void release_slot(struct hotplug_slot *hotplug_slot) | 184 | static void release_slot(struct hotplug_slot *hotplug_slot) |
187 | { | 185 | { |
188 | struct slot *slot = hotplug_slot->private; | ||
189 | |||
190 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); | 186 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); |
191 | 187 | ||
192 | kfree(slot->hotplug_slot->info); | 188 | kfree(hotplug_slot->info); |
193 | kfree(slot->hotplug_slot); | 189 | kfree(hotplug_slot); |
194 | kfree(slot); | ||
195 | } | ||
196 | |||
197 | static void make_slot_name(struct slot *slot) | ||
198 | { | ||
199 | if (pciehp_slot_with_bus) | ||
200 | snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", | ||
201 | slot->bus, slot->number); | ||
202 | else | ||
203 | snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", | ||
204 | slot->number); | ||
205 | } | 190 | } |
206 | 191 | ||
207 | static int init_slots(struct controller *ctrl) | 192 | static int init_slots(struct controller *ctrl) |
@@ -210,49 +195,34 @@ static int init_slots(struct controller *ctrl) | |||
210 | struct hotplug_slot *hotplug_slot; | 195 | struct hotplug_slot *hotplug_slot; |
211 | struct hotplug_slot_info *info; | 196 | struct hotplug_slot_info *info; |
212 | int retval = -ENOMEM; | 197 | int retval = -ENOMEM; |
213 | int i; | ||
214 | |||
215 | for (i = 0; i < ctrl->num_slots; i++) { | ||
216 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
217 | if (!slot) | ||
218 | goto error; | ||
219 | 198 | ||
199 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) { | ||
220 | hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); | 200 | hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); |
221 | if (!hotplug_slot) | 201 | if (!hotplug_slot) |
222 | goto error_slot; | 202 | goto error; |
223 | slot->hotplug_slot = hotplug_slot; | ||
224 | 203 | ||
225 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 204 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
226 | if (!info) | 205 | if (!info) |
227 | goto error_hpslot; | 206 | goto error_hpslot; |
228 | hotplug_slot->info = info; | ||
229 | |||
230 | hotplug_slot->name = slot->name; | ||
231 | |||
232 | slot->hp_slot = i; | ||
233 | slot->ctrl = ctrl; | ||
234 | slot->bus = ctrl->pci_dev->subordinate->number; | ||
235 | slot->device = ctrl->slot_device_offset + i; | ||
236 | slot->hpc_ops = ctrl->hpc_ops; | ||
237 | slot->number = ctrl->first_slot; | ||
238 | mutex_init(&slot->lock); | ||
239 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); | ||
240 | 207 | ||
241 | /* register this slot with the hotplug pci core */ | 208 | /* register this slot with the hotplug pci core */ |
209 | hotplug_slot->info = info; | ||
210 | hotplug_slot->name = slot->name; | ||
242 | hotplug_slot->private = slot; | 211 | hotplug_slot->private = slot; |
243 | hotplug_slot->release = &release_slot; | 212 | hotplug_slot->release = &release_slot; |
244 | make_slot_name(slot); | ||
245 | hotplug_slot->ops = &pciehp_hotplug_slot_ops; | 213 | hotplug_slot->ops = &pciehp_hotplug_slot_ops; |
246 | |||
247 | get_power_status(hotplug_slot, &info->power_status); | 214 | get_power_status(hotplug_slot, &info->power_status); |
248 | get_attention_status(hotplug_slot, &info->attention_status); | 215 | get_attention_status(hotplug_slot, &info->attention_status); |
249 | get_latch_status(hotplug_slot, &info->latch_status); | 216 | get_latch_status(hotplug_slot, &info->latch_status); |
250 | get_adapter_status(hotplug_slot, &info->adapter_status); | 217 | get_adapter_status(hotplug_slot, &info->adapter_status); |
218 | slot->hotplug_slot = hotplug_slot; | ||
251 | 219 | ||
252 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " | 220 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " |
253 | "slot_device_offset=%x\n", slot->bus, slot->device, | 221 | "slot_device_offset=%x\n", slot->bus, slot->device, |
254 | slot->hp_slot, slot->number, ctrl->slot_device_offset); | 222 | slot->hp_slot, slot->number, ctrl->slot_device_offset); |
255 | retval = pci_hp_register(hotplug_slot); | 223 | retval = pci_hp_register(hotplug_slot, |
224 | ctrl->pci_dev->subordinate, | ||
225 | slot->device); | ||
256 | if (retval) { | 226 | if (retval) { |
257 | err("pci_hp_register failed with error %d\n", retval); | 227 | err("pci_hp_register failed with error %d\n", retval); |
258 | if (retval == -EEXIST) | 228 | if (retval == -EEXIST) |
@@ -263,7 +233,7 @@ static int init_slots(struct controller *ctrl) | |||
263 | } | 233 | } |
264 | /* create additional sysfs entries */ | 234 | /* create additional sysfs entries */ |
265 | if (EMI(ctrl)) { | 235 | if (EMI(ctrl)) { |
266 | retval = sysfs_create_file(&hotplug_slot->kobj, | 236 | retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj, |
267 | &hotplug_slot_attr_lock.attr); | 237 | &hotplug_slot_attr_lock.attr); |
268 | if (retval) { | 238 | if (retval) { |
269 | pci_hp_deregister(hotplug_slot); | 239 | pci_hp_deregister(hotplug_slot); |
@@ -271,8 +241,6 @@ static int init_slots(struct controller *ctrl) | |||
271 | goto error_info; | 241 | goto error_info; |
272 | } | 242 | } |
273 | } | 243 | } |
274 | |||
275 | list_add(&slot->slot_list, &ctrl->slot_list); | ||
276 | } | 244 | } |
277 | 245 | ||
278 | return 0; | 246 | return 0; |
@@ -280,27 +248,18 @@ error_info: | |||
280 | kfree(info); | 248 | kfree(info); |
281 | error_hpslot: | 249 | error_hpslot: |
282 | kfree(hotplug_slot); | 250 | kfree(hotplug_slot); |
283 | error_slot: | ||
284 | kfree(slot); | ||
285 | error: | 251 | error: |
286 | return retval; | 252 | return retval; |
287 | } | 253 | } |
288 | 254 | ||
289 | static void cleanup_slots(struct controller *ctrl) | 255 | static void cleanup_slots(struct controller *ctrl) |
290 | { | 256 | { |
291 | struct list_head *tmp; | ||
292 | struct list_head *next; | ||
293 | struct slot *slot; | 257 | struct slot *slot; |
294 | 258 | ||
295 | list_for_each_safe(tmp, next, &ctrl->slot_list) { | 259 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) { |
296 | slot = list_entry(tmp, struct slot, slot_list); | ||
297 | list_del(&slot->slot_list); | ||
298 | if (EMI(ctrl)) | 260 | if (EMI(ctrl)) |
299 | sysfs_remove_file(&slot->hotplug_slot->kobj, | 261 | sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj, |
300 | &hotplug_slot_attr_lock.attr); | 262 | &hotplug_slot_attr_lock.attr); |
301 | cancel_delayed_work(&slot->work); | ||
302 | flush_scheduled_work(); | ||
303 | flush_workqueue(pciehp_wq); | ||
304 | pci_hp_deregister(slot->hotplug_slot); | 263 | pci_hp_deregister(slot->hotplug_slot); |
305 | } | 264 | } |
306 | } | 265 | } |
@@ -398,19 +357,8 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) | |||
398 | return 0; | 357 | return 0; |
399 | } | 358 | } |
400 | 359 | ||
401 | static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) | 360 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, |
402 | { | 361 | enum pci_bus_speed *value) |
403 | struct slot *slot = hotplug_slot->private; | ||
404 | struct pci_bus *bus = slot->ctrl->pci_dev->subordinate; | ||
405 | |||
406 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); | ||
407 | |||
408 | *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device; | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) | ||
414 | { | 362 | { |
415 | struct slot *slot = hotplug_slot->private; | 363 | struct slot *slot = hotplug_slot->private; |
416 | int retval; | 364 | int retval; |
@@ -444,34 +392,30 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
444 | struct controller *ctrl; | 392 | struct controller *ctrl; |
445 | struct slot *t_slot; | 393 | struct slot *t_slot; |
446 | u8 value; | 394 | u8 value; |
447 | struct pci_dev *pdev; | 395 | struct pci_dev *pdev = dev->port; |
448 | 396 | ||
449 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | 397 | if (pciehp_force) |
450 | if (!ctrl) { | 398 | dbg("Bypassing BIOS check for pciehp use on %s\n", |
451 | err("%s : out of memory\n", __func__); | 399 | pci_name(pdev)); |
400 | else if (pciehp_get_hp_hw_control_from_firmware(pdev)) | ||
452 | goto err_out_none; | 401 | goto err_out_none; |
453 | } | ||
454 | INIT_LIST_HEAD(&ctrl->slot_list); | ||
455 | |||
456 | pdev = dev->port; | ||
457 | ctrl->pci_dev = pdev; | ||
458 | 402 | ||
459 | rc = pcie_init(ctrl, dev); | 403 | ctrl = pcie_init(dev); |
460 | if (rc) { | 404 | if (!ctrl) { |
461 | dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME); | 405 | dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME); |
462 | goto err_out_free_ctrl; | 406 | goto err_out_none; |
463 | } | 407 | } |
464 | 408 | set_service_data(dev, ctrl); | |
465 | pci_set_drvdata(pdev, ctrl); | ||
466 | |||
467 | dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", | ||
468 | __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), | ||
469 | PCI_FUNC(pdev->devfn), pdev->irq); | ||
470 | 409 | ||
471 | /* Setup the slot information structures */ | 410 | /* Setup the slot information structures */ |
472 | rc = init_slots(ctrl); | 411 | rc = init_slots(ctrl); |
473 | if (rc) { | 412 | if (rc) { |
474 | err("%s: slot initialization failed\n", PCIE_MODULE_NAME); | 413 | if (rc == -EBUSY) |
414 | warn("%s: slot already registered by another " | ||
415 | "hotplug driver\n", PCIE_MODULE_NAME); | ||
416 | else | ||
417 | err("%s: slot initialization failed\n", | ||
418 | PCIE_MODULE_NAME); | ||
475 | goto err_out_release_ctlr; | 419 | goto err_out_release_ctlr; |
476 | } | 420 | } |
477 | 421 | ||
@@ -495,20 +439,16 @@ err_out_free_ctrl_slot: | |||
495 | cleanup_slots(ctrl); | 439 | cleanup_slots(ctrl); |
496 | err_out_release_ctlr: | 440 | err_out_release_ctlr: |
497 | ctrl->hpc_ops->release_ctlr(ctrl); | 441 | ctrl->hpc_ops->release_ctlr(ctrl); |
498 | err_out_free_ctrl: | ||
499 | kfree(ctrl); | ||
500 | err_out_none: | 442 | err_out_none: |
501 | return -ENODEV; | 443 | return -ENODEV; |
502 | } | 444 | } |
503 | 445 | ||
504 | static void pciehp_remove (struct pcie_device *dev) | 446 | static void pciehp_remove (struct pcie_device *dev) |
505 | { | 447 | { |
506 | struct pci_dev *pdev = dev->port; | 448 | struct controller *ctrl = get_service_data(dev); |
507 | struct controller *ctrl = pci_get_drvdata(pdev); | ||
508 | 449 | ||
509 | cleanup_slots(ctrl); | 450 | cleanup_slots(ctrl); |
510 | ctrl->hpc_ops->release_ctlr(ctrl); | 451 | ctrl->hpc_ops->release_ctlr(ctrl); |
511 | kfree(ctrl); | ||
512 | } | 452 | } |
513 | 453 | ||
514 | #ifdef CONFIG_PM | 454 | #ifdef CONFIG_PM |
@@ -522,13 +462,12 @@ static int pciehp_resume (struct pcie_device *dev) | |||
522 | { | 462 | { |
523 | printk("%s ENTRY\n", __func__); | 463 | printk("%s ENTRY\n", __func__); |
524 | if (pciehp_force) { | 464 | if (pciehp_force) { |
525 | struct pci_dev *pdev = dev->port; | 465 | struct controller *ctrl = get_service_data(dev); |
526 | struct controller *ctrl = pci_get_drvdata(pdev); | ||
527 | struct slot *t_slot; | 466 | struct slot *t_slot; |
528 | u8 status; | 467 | u8 status; |
529 | 468 | ||
530 | /* reinitialize the chipset's event detection logic */ | 469 | /* reinitialize the chipset's event detection logic */ |
531 | pcie_init_hardware_part2(ctrl, dev); | 470 | pcie_enable_notification(ctrl); |
532 | 471 | ||
533 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 472 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); |
534 | 473 | ||