diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-bus-pci | 7 | ||||
-rw-r--r-- | drivers/pci/hotplug/pci_hotplug_core.c | 23 | ||||
-rw-r--r-- | drivers/pci/slot.c | 39 | ||||
-rw-r--r-- | include/linux/pci.h | 5 | ||||
-rw-r--r-- | include/linux/pci_hotplug.h | 15 |
5 files changed, 80 insertions, 9 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 97ad190e13af..6bf68053e4b8 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci | |||
@@ -122,3 +122,10 @@ Description: | |||
122 | This symbolic link appears when a device is a Virtual Function. | 122 | This symbolic link appears when a device is a Virtual Function. |
123 | The symbolic link points to the PCI device sysfs entry of the | 123 | The symbolic link points to the PCI device sysfs entry of the |
124 | Physical Function this device associates with. | 124 | Physical Function this device associates with. |
125 | |||
126 | What: /sys/bus/pci/slots/.../module | ||
127 | Date: June 2009 | ||
128 | Contact: linux-pci@vger.kernel.org | ||
129 | Description: | ||
130 | This symbolic link points to the PCI hotplug controller driver | ||
131 | module that manages the hotplug slot. | ||
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index ff32c6b4ae13..844580489d4d 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c | |||
@@ -424,6 +424,9 @@ static int fs_add_slot(struct pci_slot *slot) | |||
424 | { | 424 | { |
425 | int retval = 0; | 425 | int retval = 0; |
426 | 426 | ||
427 | /* Create symbolic link to the hotplug driver module */ | ||
428 | pci_hp_create_module_link(slot); | ||
429 | |||
427 | if (has_power_file(slot)) { | 430 | if (has_power_file(slot)) { |
428 | retval = sysfs_create_file(&slot->kobj, | 431 | retval = sysfs_create_file(&slot->kobj, |
429 | &hotplug_slot_attr_power.attr); | 432 | &hotplug_slot_attr_power.attr); |
@@ -498,6 +501,7 @@ exit_attention: | |||
498 | if (has_power_file(slot)) | 501 | if (has_power_file(slot)) |
499 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); | 502 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); |
500 | exit_power: | 503 | exit_power: |
504 | pci_hp_remove_module_link(slot); | ||
501 | exit: | 505 | exit: |
502 | return retval; | 506 | return retval; |
503 | } | 507 | } |
@@ -528,6 +532,8 @@ static void fs_remove_slot(struct pci_slot *slot) | |||
528 | 532 | ||
529 | if (has_test_file(slot)) | 533 | if (has_test_file(slot)) |
530 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); | 534 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); |
535 | |||
536 | pci_hp_remove_module_link(slot); | ||
531 | } | 537 | } |
532 | 538 | ||
533 | static struct hotplug_slot *get_slot_from_name (const char *name) | 539 | static struct hotplug_slot *get_slot_from_name (const char *name) |
@@ -544,10 +550,10 @@ static struct hotplug_slot *get_slot_from_name (const char *name) | |||
544 | } | 550 | } |
545 | 551 | ||
546 | /** | 552 | /** |
547 | * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem | 553 | * __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem |
548 | * @bus: bus this slot is on | 554 | * @bus: bus this slot is on |
549 | * @slot: pointer to the &struct hotplug_slot to register | 555 | * @slot: pointer to the &struct hotplug_slot to register |
550 | * @slot_nr: slot number | 556 | * @devnr: device number |
551 | * @name: name registered with kobject core | 557 | * @name: name registered with kobject core |
552 | * | 558 | * |
553 | * Registers a hotplug slot with the pci hotplug subsystem, which will allow | 559 | * Registers a hotplug slot with the pci hotplug subsystem, which will allow |
@@ -555,8 +561,9 @@ static struct hotplug_slot *get_slot_from_name (const char *name) | |||
555 | * | 561 | * |
556 | * Returns 0 if successful, anything else for an error. | 562 | * Returns 0 if successful, anything else for an error. |
557 | */ | 563 | */ |
558 | int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr, | 564 | int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, |
559 | const char *name) | 565 | int devnr, const char *name, |
566 | struct module *owner, const char *mod_name) | ||
560 | { | 567 | { |
561 | int result; | 568 | int result; |
562 | struct pci_slot *pci_slot; | 569 | struct pci_slot *pci_slot; |
@@ -571,14 +578,16 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr, | |||
571 | return -EINVAL; | 578 | return -EINVAL; |
572 | } | 579 | } |
573 | 580 | ||
574 | mutex_lock(&pci_hp_mutex); | 581 | slot->ops->owner = owner; |
582 | slot->ops->mod_name = mod_name; | ||
575 | 583 | ||
584 | mutex_lock(&pci_hp_mutex); | ||
576 | /* | 585 | /* |
577 | * No problems if we call this interface from both ACPI_PCI_SLOT | 586 | * No problems if we call this interface from both ACPI_PCI_SLOT |
578 | * driver and call it here again. If we've already created the | 587 | * driver and call it here again. If we've already created the |
579 | * pci_slot, the interface will simply bump the refcount. | 588 | * pci_slot, the interface will simply bump the refcount. |
580 | */ | 589 | */ |
581 | pci_slot = pci_create_slot(bus, slot_nr, name, slot); | 590 | pci_slot = pci_create_slot(bus, devnr, name, slot); |
582 | if (IS_ERR(pci_slot)) { | 591 | if (IS_ERR(pci_slot)) { |
583 | result = PTR_ERR(pci_slot); | 592 | result = PTR_ERR(pci_slot); |
584 | goto out; | 593 | goto out; |
@@ -688,6 +697,6 @@ MODULE_LICENSE("GPL"); | |||
688 | module_param(debug, bool, 0644); | 697 | module_param(debug, bool, 0644); |
689 | MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); | 698 | MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); |
690 | 699 | ||
691 | EXPORT_SYMBOL_GPL(pci_hp_register); | 700 | EXPORT_SYMBOL_GPL(__pci_hp_register); |
692 | EXPORT_SYMBOL_GPL(pci_hp_deregister); | 701 | EXPORT_SYMBOL_GPL(pci_hp_deregister); |
693 | EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); | 702 | EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); |
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index fe95ce20bcbd..eddb0748b0ea 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c | |||
@@ -307,6 +307,45 @@ void pci_destroy_slot(struct pci_slot *slot) | |||
307 | } | 307 | } |
308 | EXPORT_SYMBOL_GPL(pci_destroy_slot); | 308 | EXPORT_SYMBOL_GPL(pci_destroy_slot); |
309 | 309 | ||
310 | #if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE) | ||
311 | #include <linux/pci_hotplug.h> | ||
312 | /** | ||
313 | * pci_hp_create_link - create symbolic link to the hotplug driver module. | ||
314 | * @slot: struct pci_slot | ||
315 | * | ||
316 | * Helper function for pci_hotplug_core.c to create symbolic link to | ||
317 | * the hotplug driver module. | ||
318 | */ | ||
319 | void pci_hp_create_module_link(struct pci_slot *pci_slot) | ||
320 | { | ||
321 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
322 | struct kobject *kobj = NULL; | ||
323 | int no_warn; | ||
324 | |||
325 | if (!slot || !slot->ops) | ||
326 | return; | ||
327 | kobj = kset_find_obj(module_kset, slot->ops->mod_name); | ||
328 | if (!kobj) | ||
329 | return; | ||
330 | no_warn = sysfs_create_link(&pci_slot->kobj, kobj, "module"); | ||
331 | kobject_put(kobj); | ||
332 | } | ||
333 | EXPORT_SYMBOL_GPL(pci_hp_create_module_link); | ||
334 | |||
335 | /** | ||
336 | * pci_hp_remove_link - remove symbolic link to the hotplug driver module. | ||
337 | * @slot: struct pci_slot | ||
338 | * | ||
339 | * Helper function for pci_hotplug_core.c to remove symbolic link to | ||
340 | * the hotplug driver module. | ||
341 | */ | ||
342 | void pci_hp_remove_module_link(struct pci_slot *pci_slot) | ||
343 | { | ||
344 | sysfs_remove_link(&pci_slot->kobj, "module"); | ||
345 | } | ||
346 | EXPORT_SYMBOL_GPL(pci_hp_remove_module_link); | ||
347 | #endif | ||
348 | |||
310 | static int pci_slot_init(void) | 349 | static int pci_slot_init(void) |
311 | { | 350 | { |
312 | struct kset *pci_bus_kset; | 351 | struct kset *pci_bus_kset; |
diff --git a/include/linux/pci.h b/include/linux/pci.h index ea2a153a9126..6a1800ecd95d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -1261,5 +1261,10 @@ static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev) | |||
1261 | } | 1261 | } |
1262 | #endif | 1262 | #endif |
1263 | 1263 | ||
1264 | #if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE) | ||
1265 | extern void pci_hp_create_module_link(struct pci_slot *pci_slot); | ||
1266 | extern void pci_hp_remove_module_link(struct pci_slot *pci_slot); | ||
1267 | #endif | ||
1268 | |||
1264 | #endif /* __KERNEL__ */ | 1269 | #endif /* __KERNEL__ */ |
1265 | #endif /* LINUX_PCI_H */ | 1270 | #endif /* LINUX_PCI_H */ |
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 11936fd0b56d..b3646cd7fd5a 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h | |||
@@ -69,6 +69,7 @@ enum pcie_link_speed { | |||
69 | /** | 69 | /** |
70 | * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use | 70 | * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use |
71 | * @owner: The module owner of this structure | 71 | * @owner: The module owner of this structure |
72 | * @mod_name: The module name (KBUILD_MODNAME) of this structure | ||
72 | * @enable_slot: Called when the user wants to enable a specific pci slot | 73 | * @enable_slot: Called when the user wants to enable a specific pci slot |
73 | * @disable_slot: Called when the user wants to disable a specific pci slot | 74 | * @disable_slot: Called when the user wants to disable a specific pci slot |
74 | * @set_attention_status: Called to set the specific slot's attention LED to | 75 | * @set_attention_status: Called to set the specific slot's attention LED to |
@@ -101,6 +102,7 @@ enum pcie_link_speed { | |||
101 | */ | 102 | */ |
102 | struct hotplug_slot_ops { | 103 | struct hotplug_slot_ops { |
103 | struct module *owner; | 104 | struct module *owner; |
105 | const char *mod_name; | ||
104 | int (*enable_slot) (struct hotplug_slot *slot); | 106 | int (*enable_slot) (struct hotplug_slot *slot); |
105 | int (*disable_slot) (struct hotplug_slot *slot); | 107 | int (*disable_slot) (struct hotplug_slot *slot); |
106 | int (*set_attention_status) (struct hotplug_slot *slot, u8 value); | 108 | int (*set_attention_status) (struct hotplug_slot *slot, u8 value); |
@@ -159,12 +161,21 @@ static inline const char *hotplug_slot_name(const struct hotplug_slot *slot) | |||
159 | return pci_slot_name(slot->pci_slot); | 161 | return pci_slot_name(slot->pci_slot); |
160 | } | 162 | } |
161 | 163 | ||
162 | extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr, | 164 | extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus, |
163 | const char *name); | 165 | int nr, const char *name, |
166 | struct module *owner, const char *mod_name); | ||
164 | extern int pci_hp_deregister(struct hotplug_slot *slot); | 167 | extern int pci_hp_deregister(struct hotplug_slot *slot); |
165 | extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, | 168 | extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, |
166 | struct hotplug_slot_info *info); | 169 | struct hotplug_slot_info *info); |
167 | 170 | ||
171 | static inline int pci_hp_register(struct hotplug_slot *slot, | ||
172 | struct pci_bus *pbus, | ||
173 | int devnr, const char *name) | ||
174 | { | ||
175 | return __pci_hp_register(slot, pbus, devnr, name, | ||
176 | THIS_MODULE, KBUILD_MODNAME); | ||
177 | } | ||
178 | |||
168 | /* PCI Setting Record (Type 0) */ | 179 | /* PCI Setting Record (Type 0) */ |
169 | struct hpp_type0 { | 180 | struct hpp_type0 { |
170 | u32 revision; | 181 | u32 revision; |