2 * PCI HotPlug Controller Core
4 * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
5 * Copyright (C) 2001-2002 IBM Corp.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
17 * NON INFRINGEMENT. See the GNU General Public License for more
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Send feedback to <kristen.c.accardi@intel.com>
28 #include <linux/module.h>
29 #include <linux/moduleparam.h>
30 #include <linux/kernel.h>
31 #include <linux/types.h>
32 #include <linux/list.h>
33 #include <linux/kobject.h>
34 #include <linux/sysfs.h>
35 #include <linux/pagemap.h>
36 #include <linux/slab.h>
37 #include <linux/init.h>
38 #include <linux/mount.h>
39 #include <linux/namei.h>
40 #include <linux/mutex.h>
41 #include <linux/pci.h>
42 #include <linux/pci_hotplug.h>
43 #include <asm/uaccess.h>
46 #define MY_NAME "pci_hotplug"
48 #define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __func__ , ## arg); } while (0)
49 #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
50 #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
51 #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
57 #define DRIVER_VERSION "0.5"
58 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>"
59 #define DRIVER_DESC "PCI Hot Plug PCI Core"
62 //////////////////////////////////////////////////////////////////
64 static LIST_HEAD(pci_hotplug_slot_list
);
65 static DEFINE_MUTEX(pci_hp_mutex
);
67 /* these strings match up with the values in pci_bus_speed */
68 static char *pci_bus_speed_strings
[] = {
69 "33 MHz PCI", /* 0x00 */
70 "66 MHz PCI", /* 0x01 */
71 "66 MHz PCIX", /* 0x02 */
72 "100 MHz PCIX", /* 0x03 */
73 "133 MHz PCIX", /* 0x04 */
78 "66 MHz PCIX 266", /* 0x09 */
79 "100 MHz PCIX 266", /* 0x0a */
80 "133 MHz PCIX 266", /* 0x0b */
86 "66 MHz PCIX 533", /* 0x11 */
87 "100 MHz PCIX 533", /* 0x12 */
88 "133 MHz PCIX 533", /* 0x13 */
89 "25 GBps PCI-E", /* 0x14 */
92 #ifdef CONFIG_HOTPLUG_PCI_CPCI
93 extern int cpci_hotplug_init(int debug
);
94 extern void cpci_hotplug_exit(void);
96 static inline int cpci_hotplug_init(int debug
) { return 0; }
97 static inline void cpci_hotplug_exit(void) { }
100 /* Weee, fun with macros... */
101 #define GET_STATUS(name,type) \
102 static int get_##name (struct hotplug_slot *slot, type *value) \
104 struct hotplug_slot_ops *ops = slot->ops; \
106 if (!try_module_get(ops->owner)) \
108 if (ops->get_##name) \
109 retval = ops->get_##name(slot, value); \
111 *value = slot->info->name; \
112 module_put(ops->owner); \
116 GET_STATUS(power_status
, u8
)
117 GET_STATUS(attention_status
, u8
)
118 GET_STATUS(latch_status
, u8
)
119 GET_STATUS(adapter_status
, u8
)
120 GET_STATUS(max_bus_speed
, enum pci_bus_speed
)
121 GET_STATUS(cur_bus_speed
, enum pci_bus_speed
)
123 static ssize_t
power_read_file(struct pci_slot
*slot
, char *buf
)
128 retval
= get_power_status(slot
->hotplug
, &value
);
131 retval
= sprintf (buf
, "%d\n", value
);
136 static ssize_t
power_write_file(struct pci_slot
*pci_slot
, const char *buf
,
139 struct hotplug_slot
*slot
= pci_slot
->hotplug
;
140 unsigned long lpower
;
144 lpower
= simple_strtoul (buf
, NULL
, 10);
145 power
= (u8
)(lpower
& 0xff);
146 dbg ("power = %d\n", power
);
148 if (!try_module_get(slot
->ops
->owner
)) {
154 if (slot
->ops
->disable_slot
)
155 retval
= slot
->ops
->disable_slot(slot
);
159 if (slot
->ops
->enable_slot
)
160 retval
= slot
->ops
->enable_slot(slot
);
164 err ("Illegal value specified for power\n");
167 module_put(slot
->ops
->owner
);
175 static struct pci_slot_attribute hotplug_slot_attr_power
= {
176 .attr
= {.name
= "power", .mode
= S_IFREG
| S_IRUGO
| S_IWUSR
},
177 .show
= power_read_file
,
178 .store
= power_write_file
181 static ssize_t
attention_read_file(struct pci_slot
*slot
, char *buf
)
186 retval
= get_attention_status(slot
->hotplug
, &value
);
189 retval
= sprintf(buf
, "%d\n", value
);
195 static ssize_t
attention_write_file(struct pci_slot
*slot
, const char *buf
,
198 struct hotplug_slot_ops
*ops
= slot
->hotplug
->ops
;
199 unsigned long lattention
;
203 lattention
= simple_strtoul (buf
, NULL
, 10);
204 attention
= (u8
)(lattention
& 0xff);
205 dbg (" - attention = %d\n", attention
);
207 if (!try_module_get(ops
->owner
)) {
211 if (ops
->set_attention_status
)
212 retval
= ops
->set_attention_status(slot
->hotplug
, attention
);
213 module_put(ops
->owner
);
221 static struct pci_slot_attribute hotplug_slot_attr_attention
= {
222 .attr
= {.name
= "attention", .mode
= S_IFREG
| S_IRUGO
| S_IWUSR
},
223 .show
= attention_read_file
,
224 .store
= attention_write_file
227 static ssize_t
latch_read_file(struct pci_slot
*slot
, char *buf
)
232 retval
= get_latch_status(slot
->hotplug
, &value
);
235 retval
= sprintf (buf
, "%d\n", value
);
241 static struct pci_slot_attribute hotplug_slot_attr_latch
= {
242 .attr
= {.name
= "latch", .mode
= S_IFREG
| S_IRUGO
},
243 .show
= latch_read_file
,
246 static ssize_t
presence_read_file(struct pci_slot
*slot
, char *buf
)
251 retval
= get_adapter_status(slot
->hotplug
, &value
);
254 retval
= sprintf (buf
, "%d\n", value
);
260 static struct pci_slot_attribute hotplug_slot_attr_presence
= {
261 .attr
= {.name
= "adapter", .mode
= S_IFREG
| S_IRUGO
},
262 .show
= presence_read_file
,
265 static char *unknown_speed
= "Unknown bus speed";
267 static ssize_t
max_bus_speed_read_file(struct pci_slot
*slot
, char *buf
)
271 enum pci_bus_speed value
;
273 retval
= get_max_bus_speed(slot
->hotplug
, &value
);
277 if (value
== PCI_SPEED_UNKNOWN
)
278 speed_string
= unknown_speed
;
280 speed_string
= pci_bus_speed_strings
[value
];
282 retval
= sprintf (buf
, "%s\n", speed_string
);
288 static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed
= {
289 .attr
= {.name
= "max_bus_speed", .mode
= S_IFREG
| S_IRUGO
},
290 .show
= max_bus_speed_read_file
,
293 static ssize_t
cur_bus_speed_read_file(struct pci_slot
*slot
, char *buf
)
297 enum pci_bus_speed value
;
299 retval
= get_cur_bus_speed(slot
->hotplug
, &value
);
303 if (value
== PCI_SPEED_UNKNOWN
)
304 speed_string
= unknown_speed
;
306 speed_string
= pci_bus_speed_strings
[value
];
308 retval
= sprintf (buf
, "%s\n", speed_string
);
314 static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed
= {
315 .attr
= {.name
= "cur_bus_speed", .mode
= S_IFREG
| S_IRUGO
},
316 .show
= cur_bus_speed_read_file
,
319 static ssize_t
test_write_file(struct pci_slot
*pci_slot
, const char *buf
,
322 struct hotplug_slot
*slot
= pci_slot
->hotplug
;
327 ltest
= simple_strtoul (buf
, NULL
, 10);
328 test
= (u32
)(ltest
& 0xffffffff);
329 dbg ("test = %d\n", test
);
331 if (!try_module_get(slot
->ops
->owner
)) {
335 if (slot
->ops
->hardware_test
)
336 retval
= slot
->ops
->hardware_test(slot
, test
);
337 module_put(slot
->ops
->owner
);
345 static struct pci_slot_attribute hotplug_slot_attr_test
= {
346 .attr
= {.name
= "test", .mode
= S_IFREG
| S_IRUGO
| S_IWUSR
},
347 .store
= test_write_file
350 static bool has_power_file(struct pci_slot
*pci_slot
)
352 struct hotplug_slot
*slot
= pci_slot
->hotplug
;
353 if ((!slot
) || (!slot
->ops
))
355 if ((slot
->ops
->enable_slot
) ||
356 (slot
->ops
->disable_slot
) ||
357 (slot
->ops
->get_power_status
))
362 static bool has_attention_file(struct pci_slot
*pci_slot
)
364 struct hotplug_slot
*slot
= pci_slot
->hotplug
;
365 if ((!slot
) || (!slot
->ops
))
367 if ((slot
->ops
->set_attention_status
) ||
368 (slot
->ops
->get_attention_status
))
373 static bool has_latch_file(struct pci_slot
*pci_slot
)
375 struct hotplug_slot
*slot
= pci_slot
->hotplug
;
376 if ((!slot
) || (!slot
->ops
))
378 if (slot
->ops
->get_latch_status
)
383 static bool has_adapter_file(struct pci_slot
*pci_slot
)
385 struct hotplug_slot
*slot
= pci_slot
->hotplug
;
386 if ((!slot
) || (!slot
->ops
))
388 if (slot
->ops
->get_adapter_status
)
393 static bool has_max_bus_speed_file(struct pci_slot
*pci_slot
)
395 struct hotplug_slot
*slot
= pci_slot
->hotplug
;
396 if ((!slot
) || (!slot
->ops
))
398 if (slot
->ops
->get_max_bus_speed
)
403 static bool has_cur_bus_speed_file(struct pci_slot
*pci_slot
)
405 struct hotplug_slot
*slot
= pci_slot
->hotplug
;
406 if ((!slot
) || (!slot
->ops
))
408 if (slot
->ops
->get_cur_bus_speed
)
413 static bool has_test_file(struct pci_slot
*pci_slot
)
415 struct hotplug_slot
*slot
= pci_slot
->hotplug
;
416 if ((!slot
) || (!slot
->ops
))
418 if (slot
->ops
->hardware_test
)
423 static int fs_add_slot(struct pci_slot
*slot
)
427 /* Create symbolic link to the hotplug driver module */
428 pci_hp_create_module_link(slot
);
430 if (has_power_file(slot
)) {
431 retval
= sysfs_create_file(&slot
->kobj
,
432 &hotplug_slot_attr_power
.attr
);
437 if (has_attention_file(slot
)) {
438 retval
= sysfs_create_file(&slot
->kobj
,
439 &hotplug_slot_attr_attention
.attr
);
444 if (has_latch_file(slot
)) {
445 retval
= sysfs_create_file(&slot
->kobj
,
446 &hotplug_slot_attr_latch
.attr
);
451 if (has_adapter_file(slot
)) {
452 retval
= sysfs_create_file(&slot
->kobj
,
453 &hotplug_slot_attr_presence
.attr
);
458 if (has_max_bus_speed_file(slot
)) {
459 retval
= sysfs_create_file(&slot
->kobj
,
460 &hotplug_slot_attr_max_bus_speed
.attr
);
465 if (has_cur_bus_speed_file(slot
)) {
466 retval
= sysfs_create_file(&slot
->kobj
,
467 &hotplug_slot_attr_cur_bus_speed
.attr
);
472 if (has_test_file(slot
)) {
473 retval
= sysfs_create_file(&slot
->kobj
,
474 &hotplug_slot_attr_test
.attr
);
482 if (has_cur_bus_speed_file(slot
))
483 sysfs_remove_file(&slot
->kobj
,
484 &hotplug_slot_attr_cur_bus_speed
.attr
);
486 if (has_max_bus_speed_file(slot
))
487 sysfs_remove_file(&slot
->kobj
,
488 &hotplug_slot_attr_max_bus_speed
.attr
);
490 if (has_adapter_file(slot
))
491 sysfs_remove_file(&slot
->kobj
,
492 &hotplug_slot_attr_presence
.attr
);
494 if (has_latch_file(slot
))
495 sysfs_remove_file(&slot
->kobj
, &hotplug_slot_attr_latch
.attr
);
497 if (has_attention_file(slot
))
498 sysfs_remove_file(&slot
->kobj
,
499 &hotplug_slot_attr_attention
.attr
);
501 if (has_power_file(slot
))
502 sysfs_remove_file(&slot
->kobj
, &hotplug_slot_attr_power
.attr
);
504 pci_hp_remove_module_link(slot
);
509 static void fs_remove_slot(struct pci_slot
*slot
)
511 if (has_power_file(slot
))
512 sysfs_remove_file(&slot
->kobj
, &hotplug_slot_attr_power
.attr
);
514 if (has_attention_file(slot
))
515 sysfs_remove_file(&slot
->kobj
,
516 &hotplug_slot_attr_attention
.attr
);
518 if (has_latch_file(slot
))
519 sysfs_remove_file(&slot
->kobj
, &hotplug_slot_attr_latch
.attr
);
521 if (has_adapter_file(slot
))
522 sysfs_remove_file(&slot
->kobj
,
523 &hotplug_slot_attr_presence
.attr
);
525 if (has_max_bus_speed_file(slot
))
526 sysfs_remove_file(&slot
->kobj
,
527 &hotplug_slot_attr_max_bus_speed
.attr
);
529 if (has_cur_bus_speed_file(slot
))
530 sysfs_remove_file(&slot
->kobj
,
531 &hotplug_slot_attr_cur_bus_speed
.attr
);
533 if (has_test_file(slot
))
534 sysfs_remove_file(&slot
->kobj
, &hotplug_slot_attr_test
.attr
);
536 pci_hp_remove_module_link(slot
);
539 static struct hotplug_slot
*get_slot_from_name (const char *name
)
541 struct hotplug_slot
*slot
;
542 struct list_head
*tmp
;
544 list_for_each (tmp
, &pci_hotplug_slot_list
) {
545 slot
= list_entry (tmp
, struct hotplug_slot
, slot_list
);
546 if (strcmp(hotplug_slot_name(slot
), name
) == 0)
553 * __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
554 * @bus: bus this slot is on
555 * @slot: pointer to the &struct hotplug_slot to register
556 * @devnr: device number
557 * @name: name registered with kobject core
558 * @owner: caller module owner
559 * @mod_name: caller module name
561 * Registers a hotplug slot with the pci hotplug subsystem, which will allow
562 * userspace interaction to the slot.
564 * Returns 0 if successful, anything else for an error.
566 int __pci_hp_register(struct hotplug_slot
*slot
, struct pci_bus
*bus
,
567 int devnr
, const char *name
,
568 struct module
*owner
, const char *mod_name
)
571 struct pci_slot
*pci_slot
;
575 if ((slot
->info
== NULL
) || (slot
->ops
== NULL
))
577 if (slot
->release
== NULL
) {
578 dbg("Why are you trying to register a hotplug slot "
579 "without a proper release function?\n");
583 slot
->ops
->owner
= owner
;
584 slot
->ops
->mod_name
= mod_name
;
586 mutex_lock(&pci_hp_mutex
);
588 * No problems if we call this interface from both ACPI_PCI_SLOT
589 * driver and call it here again. If we've already created the
590 * pci_slot, the interface will simply bump the refcount.
592 pci_slot
= pci_create_slot(bus
, devnr
, name
, slot
);
593 if (IS_ERR(pci_slot
)) {
594 result
= PTR_ERR(pci_slot
);
598 slot
->pci_slot
= pci_slot
;
599 pci_slot
->hotplug
= slot
;
601 list_add(&slot
->slot_list
, &pci_hotplug_slot_list
);
603 result
= fs_add_slot(pci_slot
);
604 kobject_uevent(&pci_slot
->kobj
, KOBJ_ADD
);
605 dbg("Added slot %s to the list\n", name
);
607 mutex_unlock(&pci_hp_mutex
);
612 * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
613 * @hotplug: pointer to the &struct hotplug_slot to deregister
615 * The @slot must have been registered with the pci hotplug subsystem
616 * previously with a call to pci_hp_register().
618 * Returns 0 if successful, anything else for an error.
620 int pci_hp_deregister(struct hotplug_slot
*hotplug
)
622 struct hotplug_slot
*temp
;
623 struct pci_slot
*slot
;
628 mutex_lock(&pci_hp_mutex
);
629 temp
= get_slot_from_name(hotplug_slot_name(hotplug
));
630 if (temp
!= hotplug
) {
631 mutex_unlock(&pci_hp_mutex
);
635 list_del(&hotplug
->slot_list
);
637 slot
= hotplug
->pci_slot
;
638 fs_remove_slot(slot
);
639 dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug
));
641 hotplug
->release(hotplug
);
642 slot
->hotplug
= NULL
;
643 pci_destroy_slot(slot
);
644 mutex_unlock(&pci_hp_mutex
);
650 * pci_hp_change_slot_info - changes the slot's information structure in the core
651 * @hotplug: pointer to the slot whose info has changed
652 * @info: pointer to the info copy into the slot's info structure
654 * @slot must have been registered with the pci
655 * hotplug subsystem previously with a call to pci_hp_register().
657 * Returns 0 if successful, anything else for an error.
659 int __must_check
pci_hp_change_slot_info(struct hotplug_slot
*hotplug
,
660 struct hotplug_slot_info
*info
)
662 struct pci_slot
*slot
;
663 if (!hotplug
|| !info
)
665 slot
= hotplug
->pci_slot
;
667 memcpy(hotplug
->info
, info
, sizeof(struct hotplug_slot_info
));
672 static int __init
pci_hotplug_init (void)
676 result
= cpci_hotplug_init(debug
);
678 err ("cpci_hotplug_init with error %d\n", result
);
682 info (DRIVER_DESC
" version: " DRIVER_VERSION
"\n");
688 static void __exit
pci_hotplug_exit (void)
693 module_init(pci_hotplug_init
);
694 module_exit(pci_hotplug_exit
);
696 MODULE_AUTHOR(DRIVER_AUTHOR
);
697 MODULE_DESCRIPTION(DRIVER_DESC
);
698 MODULE_LICENSE("GPL");
699 module_param(debug
, bool, 0644);
700 MODULE_PARM_DESC(debug
, "Debugging mode enabled or not");
702 EXPORT_SYMBOL_GPL(__pci_hp_register
);
703 EXPORT_SYMBOL_GPL(pci_hp_deregister
);
704 EXPORT_SYMBOL_GPL(pci_hp_change_slot_info
);