diff options
author | Paul Mackerras <paulus@samba.org> | 2007-05-07 23:37:51 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-05-07 23:37:51 -0400 |
commit | 02bbc0f09c90cefdb2837605c96a66c5ce4ba2e1 (patch) | |
tree | 04ef573cd4de095c500c9fc3477f4278c0b36300 /drivers/pci/hotplug | |
parent | 7487a2245b8841c77ba9db406cf99a483b9334e9 (diff) | |
parent | 5b94f675f57e4ff16c8fda09088d7480a84dcd91 (diff) |
Merge branch 'linux-2.6'
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r-- | drivers/pci/hotplug/Kconfig | 25 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_ibm.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpcihp_zt5550.c | 6 | ||||
-rw-r--r-- | drivers/pci/hotplug/fakephp.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/pci_hotplug_core.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 19 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 82 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 616 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 34 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpadlpar_core.c | 27 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp.h | 8 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp_core.c | 200 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp_pci.c | 167 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp_slot.c | 49 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp.h | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 2 |
17 files changed, 514 insertions, 735 deletions
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index be92695a7833..63d62752fb91 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig | |||
@@ -2,9 +2,7 @@ | |||
2 | # PCI Hotplug support | 2 | # PCI Hotplug support |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "PCI Hotplug Support" | 5 | menuconfig HOTPLUG_PCI |
6 | |||
7 | config HOTPLUG_PCI | ||
8 | tristate "Support for PCI Hotplug (EXPERIMENTAL)" | 6 | tristate "Support for PCI Hotplug (EXPERIMENTAL)" |
9 | depends on PCI && EXPERIMENTAL && HOTPLUG | 7 | depends on PCI && EXPERIMENTAL && HOTPLUG |
10 | ---help--- | 8 | ---help--- |
@@ -17,9 +15,10 @@ config HOTPLUG_PCI | |||
17 | 15 | ||
18 | When in doubt, say N. | 16 | When in doubt, say N. |
19 | 17 | ||
18 | if HOTPLUG_PCI | ||
19 | |||
20 | config HOTPLUG_PCI_FAKE | 20 | config HOTPLUG_PCI_FAKE |
21 | tristate "Fake PCI Hotplug driver" | 21 | tristate "Fake PCI Hotplug driver" |
22 | depends on HOTPLUG_PCI | ||
23 | help | 22 | help |
24 | Say Y here if you want to use the fake PCI hotplug driver. It can | 23 | Say Y here if you want to use the fake PCI hotplug driver. It can |
25 | be used to simulate PCI hotplug events if even if your system is | 24 | be used to simulate PCI hotplug events if even if your system is |
@@ -42,7 +41,7 @@ config HOTPLUG_PCI_FAKE | |||
42 | 41 | ||
43 | config HOTPLUG_PCI_COMPAQ | 42 | config HOTPLUG_PCI_COMPAQ |
44 | tristate "Compaq PCI Hotplug driver" | 43 | tristate "Compaq PCI Hotplug driver" |
45 | depends on HOTPLUG_PCI && X86 && PCI_BIOS | 44 | depends on X86 && PCI_BIOS |
46 | help | 45 | help |
47 | Say Y here if you have a motherboard with a Compaq PCI Hotplug | 46 | Say Y here if you have a motherboard with a Compaq PCI Hotplug |
48 | controller. | 47 | controller. |
@@ -64,7 +63,7 @@ config HOTPLUG_PCI_COMPAQ_NVRAM | |||
64 | 63 | ||
65 | config HOTPLUG_PCI_IBM | 64 | config HOTPLUG_PCI_IBM |
66 | tristate "IBM PCI Hotplug driver" | 65 | tristate "IBM PCI Hotplug driver" |
67 | depends on HOTPLUG_PCI && X86_IO_APIC && X86 && PCI_BIOS | 66 | depends on X86_IO_APIC && X86 && PCI_BIOS |
68 | help | 67 | help |
69 | Say Y here if you have a motherboard with a IBM PCI Hotplug | 68 | Say Y here if you have a motherboard with a IBM PCI Hotplug |
70 | controller. | 69 | controller. |
@@ -76,7 +75,6 @@ config HOTPLUG_PCI_IBM | |||
76 | 75 | ||
77 | config HOTPLUG_PCI_ACPI | 76 | config HOTPLUG_PCI_ACPI |
78 | tristate "ACPI PCI Hotplug driver" | 77 | tristate "ACPI PCI Hotplug driver" |
79 | depends on HOTPLUG_PCI | ||
80 | depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK) | 78 | depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK) |
81 | help | 79 | help |
82 | Say Y here if you have a system that supports PCI Hotplug using | 80 | Say Y here if you have a system that supports PCI Hotplug using |
@@ -101,7 +99,6 @@ config HOTPLUG_PCI_ACPI_IBM | |||
101 | 99 | ||
102 | config HOTPLUG_PCI_CPCI | 100 | config HOTPLUG_PCI_CPCI |
103 | bool "CompactPCI Hotplug driver" | 101 | bool "CompactPCI Hotplug driver" |
104 | depends on HOTPLUG_PCI | ||
105 | help | 102 | help |
106 | Say Y here if you have a CompactPCI system card with CompactPCI | 103 | Say Y here if you have a CompactPCI system card with CompactPCI |
107 | hotswap support per the PICMG 2.1 specification. | 104 | hotswap support per the PICMG 2.1 specification. |
@@ -110,7 +107,7 @@ config HOTPLUG_PCI_CPCI | |||
110 | 107 | ||
111 | config HOTPLUG_PCI_CPCI_ZT5550 | 108 | config HOTPLUG_PCI_CPCI_ZT5550 |
112 | tristate "Ziatech ZT5550 CompactPCI Hotplug driver" | 109 | tristate "Ziatech ZT5550 CompactPCI Hotplug driver" |
113 | depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 | 110 | depends on HOTPLUG_PCI_CPCI && X86 |
114 | help | 111 | help |
115 | Say Y here if you have an Performance Technologies (formerly Intel, | 112 | Say Y here if you have an Performance Technologies (formerly Intel, |
116 | formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. | 113 | formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. |
@@ -122,7 +119,7 @@ config HOTPLUG_PCI_CPCI_ZT5550 | |||
122 | 119 | ||
123 | config HOTPLUG_PCI_CPCI_GENERIC | 120 | config HOTPLUG_PCI_CPCI_GENERIC |
124 | tristate "Generic port I/O CompactPCI Hotplug driver" | 121 | tristate "Generic port I/O CompactPCI Hotplug driver" |
125 | depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 | 122 | depends on HOTPLUG_PCI_CPCI && X86 |
126 | help | 123 | help |
127 | Say Y here if you have a CompactPCI system card that exposes the #ENUM | 124 | Say Y here if you have a CompactPCI system card that exposes the #ENUM |
128 | hotswap signal as a bit in a system register that can be read through | 125 | hotswap signal as a bit in a system register that can be read through |
@@ -135,7 +132,6 @@ config HOTPLUG_PCI_CPCI_GENERIC | |||
135 | 132 | ||
136 | config HOTPLUG_PCI_SHPC | 133 | config HOTPLUG_PCI_SHPC |
137 | tristate "SHPC PCI Hotplug driver" | 134 | tristate "SHPC PCI Hotplug driver" |
138 | depends on HOTPLUG_PCI | ||
139 | help | 135 | help |
140 | Say Y here if you have a motherboard with a SHPC PCI Hotplug | 136 | Say Y here if you have a motherboard with a SHPC PCI Hotplug |
141 | controller. | 137 | controller. |
@@ -147,7 +143,7 @@ config HOTPLUG_PCI_SHPC | |||
147 | 143 | ||
148 | config HOTPLUG_PCI_RPA | 144 | config HOTPLUG_PCI_RPA |
149 | tristate "RPA PCI Hotplug driver" | 145 | tristate "RPA PCI Hotplug driver" |
150 | depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE | 146 | depends on PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE |
151 | help | 147 | help |
152 | Say Y here if you have a RPA system that supports PCI Hotplug. | 148 | Say Y here if you have a RPA system that supports PCI Hotplug. |
153 | 149 | ||
@@ -170,12 +166,11 @@ config HOTPLUG_PCI_RPA_DLPAR | |||
170 | 166 | ||
171 | config HOTPLUG_PCI_SGI | 167 | config HOTPLUG_PCI_SGI |
172 | tristate "SGI PCI Hotplug Support" | 168 | tristate "SGI PCI Hotplug Support" |
173 | depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC) | 169 | depends on IA64_SGI_SN2 || IA64_GENERIC |
174 | help | 170 | help |
175 | Say Y here if you want to use the SGI Altix Hotplug | 171 | Say Y here if you want to use the SGI Altix Hotplug |
176 | Driver for PCI devices. | 172 | Driver for PCI devices. |
177 | 173 | ||
178 | When in doubt, say N. | 174 | When in doubt, say N. |
179 | 175 | ||
180 | endmenu | 176 | endif # HOTPLUG_PCI |
181 | |||
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index 7f03881a8b68..e7322c25d377 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c | |||
@@ -424,7 +424,7 @@ static int __init ibm_acpiphp_init(void) | |||
424 | int retval = 0; | 424 | int retval = 0; |
425 | acpi_status status; | 425 | acpi_status status; |
426 | struct acpi_device *device; | 426 | struct acpi_device *device; |
427 | struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; | 427 | struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj; |
428 | 428 | ||
429 | dbg("%s\n", __FUNCTION__); | 429 | dbg("%s\n", __FUNCTION__); |
430 | 430 | ||
@@ -471,7 +471,7 @@ init_return: | |||
471 | static void __exit ibm_acpiphp_exit(void) | 471 | static void __exit ibm_acpiphp_exit(void) |
472 | { | 472 | { |
473 | acpi_status status; | 473 | acpi_status status; |
474 | struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; | 474 | struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj; |
475 | 475 | ||
476 | dbg("%s\n", __FUNCTION__); | 476 | dbg("%s\n", __FUNCTION__); |
477 | 477 | ||
diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index 1c12e9171097..41f6a8d79c81 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c | |||
@@ -296,13 +296,17 @@ static struct pci_driver zt5550_hc_driver = { | |||
296 | static int __init zt5550_init(void) | 296 | static int __init zt5550_init(void) |
297 | { | 297 | { |
298 | struct resource* r; | 298 | struct resource* r; |
299 | int rc; | ||
299 | 300 | ||
300 | info(DRIVER_DESC " version: " DRIVER_VERSION); | 301 | info(DRIVER_DESC " version: " DRIVER_VERSION); |
301 | r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); | 302 | r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); |
302 | if(!r) | 303 | if(!r) |
303 | return -EBUSY; | 304 | return -EBUSY; |
304 | 305 | ||
305 | return pci_register_driver(&zt5550_hc_driver); | 306 | rc = pci_register_driver(&zt5550_hc_driver); |
307 | if(rc < 0) | ||
308 | release_region(ENUM_PORT, 1); | ||
309 | return rc; | ||
306 | } | 310 | } |
307 | 311 | ||
308 | static void __exit | 312 | static void __exit |
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index e27907c91d92..027f6865d7e3 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c | |||
@@ -238,7 +238,7 @@ static void pci_rescan_bus(const struct pci_bus *bus) | |||
238 | { | 238 | { |
239 | unsigned int devfn; | 239 | unsigned int devfn; |
240 | struct pci_dev *dev; | 240 | struct pci_dev *dev; |
241 | dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); | 241 | dev = alloc_pci_dev(); |
242 | if (!dev) | 242 | if (!dev) |
243 | return; | 243 | return; |
244 | 244 | ||
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index f5d632e72323..63f3bd1eecc4 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c | |||
@@ -62,7 +62,7 @@ static int debug; | |||
62 | 62 | ||
63 | static LIST_HEAD(pci_hotplug_slot_list); | 63 | static LIST_HEAD(pci_hotplug_slot_list); |
64 | 64 | ||
65 | struct subsystem pci_hotplug_slots_subsys; | 65 | struct kset pci_hotplug_slots_subsys; |
66 | 66 | ||
67 | static ssize_t hotplug_slot_attr_show(struct kobject *kobj, | 67 | static ssize_t hotplug_slot_attr_show(struct kobject *kobj, |
68 | struct attribute *attr, char *buf) | 68 | struct attribute *attr, char *buf) |
@@ -764,7 +764,7 @@ static int __init pci_hotplug_init (void) | |||
764 | { | 764 | { |
765 | int result; | 765 | int result; |
766 | 766 | ||
767 | kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys); | 767 | kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys); |
768 | result = subsystem_register(&pci_hotplug_slots_subsys); | 768 | result = subsystem_register(&pci_hotplug_slots_subsys); |
769 | if (result) { | 769 | if (result) { |
770 | err("Register subsys with error %d\n", result); | 770 | err("Register subsys with error %d\n", result); |
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index d19fcae8a7c0..ccc57627201e 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -43,6 +43,7 @@ extern int pciehp_poll_mode; | |||
43 | extern int pciehp_poll_time; | 43 | extern int pciehp_poll_time; |
44 | extern int pciehp_debug; | 44 | extern int pciehp_debug; |
45 | extern int pciehp_force; | 45 | extern int pciehp_force; |
46 | extern struct workqueue_struct *pciehp_wq; | ||
46 | 47 | ||
47 | #define dbg(format, arg...) \ | 48 | #define dbg(format, arg...) \ |
48 | do { \ | 49 | do { \ |
@@ -70,14 +71,16 @@ struct slot { | |||
70 | struct list_head slot_list; | 71 | struct list_head slot_list; |
71 | char name[SLOT_NAME_SIZE]; | 72 | char name[SLOT_NAME_SIZE]; |
72 | unsigned long last_emi_toggle; | 73 | unsigned long last_emi_toggle; |
74 | struct delayed_work work; /* work for button event */ | ||
75 | struct mutex lock; | ||
73 | }; | 76 | }; |
74 | 77 | ||
75 | struct event_info { | 78 | struct event_info { |
76 | u32 event_type; | 79 | u32 event_type; |
77 | u8 hp_slot; | 80 | struct slot *p_slot; |
81 | struct work_struct work; | ||
78 | }; | 82 | }; |
79 | 83 | ||
80 | #define MAX_EVENTS 10 | ||
81 | struct controller { | 84 | struct controller { |
82 | struct controller *next; | 85 | struct controller *next; |
83 | struct mutex crit_sect; /* critical section mutex */ | 86 | struct mutex crit_sect; /* critical section mutex */ |
@@ -86,11 +89,9 @@ struct controller { | |||
86 | int slot_num_inc; /* 1 or -1 */ | 89 | int slot_num_inc; /* 1 or -1 */ |
87 | struct pci_dev *pci_dev; | 90 | struct pci_dev *pci_dev; |
88 | struct list_head slot_list; | 91 | struct list_head slot_list; |
89 | struct event_info event_queue[MAX_EVENTS]; | ||
90 | struct slot *slot; | 92 | struct slot *slot; |
91 | struct hpc_ops *hpc_ops; | 93 | struct hpc_ops *hpc_ops; |
92 | wait_queue_head_t queue; /* sleep & wake process */ | 94 | wait_queue_head_t queue; /* sleep & wake process */ |
93 | u8 next_event; | ||
94 | u8 bus; | 95 | u8 bus; |
95 | u8 device; | 96 | u8 device; |
96 | u8 function; | 97 | u8 function; |
@@ -149,21 +150,17 @@ struct controller { | |||
149 | #define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) | 150 | #define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) |
150 | #define EMI(cap) (cap & EMI_PRSN) | 151 | #define EMI(cap) (cap & EMI_PRSN) |
151 | 152 | ||
152 | extern int pciehp_event_start_thread(void); | 153 | extern int pciehp_sysfs_enable_slot(struct slot *slot); |
153 | extern void pciehp_event_stop_thread(void); | 154 | extern int pciehp_sysfs_disable_slot(struct slot *slot); |
154 | extern int pciehp_enable_slot(struct slot *slot); | ||
155 | extern int pciehp_disable_slot(struct slot *slot); | ||
156 | extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); | 155 | extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); |
157 | extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); | 156 | extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); |
158 | extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); | 157 | extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); |
159 | extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); | 158 | extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); |
160 | extern int pciehp_configure_device(struct slot *p_slot); | 159 | extern int pciehp_configure_device(struct slot *p_slot); |
161 | extern int pciehp_unconfigure_device(struct slot *p_slot); | 160 | extern int pciehp_unconfigure_device(struct slot *p_slot); |
161 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); | ||
162 | int pcie_init(struct controller *ctrl, struct pcie_device *dev); | 162 | int pcie_init(struct controller *ctrl, struct pcie_device *dev); |
163 | 163 | ||
164 | /* Global variables */ | ||
165 | extern struct controller *pciehp_ctrl_list; | ||
166 | |||
167 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) | 164 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) |
168 | { | 165 | { |
169 | struct slot *slot; | 166 | struct slot *slot; |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index a92eda6e02f6..e5d3f0b4f45a 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -41,7 +41,7 @@ int pciehp_debug; | |||
41 | int pciehp_poll_mode; | 41 | int pciehp_poll_mode; |
42 | int pciehp_poll_time; | 42 | int pciehp_poll_time; |
43 | int pciehp_force; | 43 | int pciehp_force; |
44 | struct controller *pciehp_ctrl_list; | 44 | struct workqueue_struct *pciehp_wq; |
45 | 45 | ||
46 | #define DRIVER_VERSION "0.4" | 46 | #define DRIVER_VERSION "0.4" |
47 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" | 47 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" |
@@ -62,7 +62,6 @@ MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing" | |||
62 | 62 | ||
63 | #define PCIE_MODULE_NAME "pciehp" | 63 | #define PCIE_MODULE_NAME "pciehp" |
64 | 64 | ||
65 | static int pcie_start_thread (void); | ||
66 | static int set_attention_status (struct hotplug_slot *slot, u8 value); | 65 | static int set_attention_status (struct hotplug_slot *slot, u8 value); |
67 | static int enable_slot (struct hotplug_slot *slot); | 66 | static int enable_slot (struct hotplug_slot *slot); |
68 | static int disable_slot (struct hotplug_slot *slot); | 67 | static int disable_slot (struct hotplug_slot *slot); |
@@ -229,6 +228,8 @@ static int init_slots(struct controller *ctrl) | |||
229 | slot->device = ctrl->slot_device_offset + i; | 228 | slot->device = ctrl->slot_device_offset + i; |
230 | slot->hpc_ops = ctrl->hpc_ops; | 229 | slot->hpc_ops = ctrl->hpc_ops; |
231 | slot->number = ctrl->first_slot; | 230 | slot->number = ctrl->first_slot; |
231 | mutex_init(&slot->lock); | ||
232 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); | ||
232 | 233 | ||
233 | /* register this slot with the hotplug pci core */ | 234 | /* register this slot with the hotplug pci core */ |
234 | hotplug_slot->private = slot; | 235 | hotplug_slot->private = slot; |
@@ -286,6 +287,9 @@ static void cleanup_slots(struct controller *ctrl) | |||
286 | if (EMI(ctrl->ctrlcap)) | 287 | if (EMI(ctrl->ctrlcap)) |
287 | sysfs_remove_file(&slot->hotplug_slot->kobj, | 288 | sysfs_remove_file(&slot->hotplug_slot->kobj, |
288 | &hotplug_slot_attr_lock.attr); | 289 | &hotplug_slot_attr_lock.attr); |
290 | cancel_delayed_work(&slot->work); | ||
291 | flush_scheduled_work(); | ||
292 | flush_workqueue(pciehp_wq); | ||
289 | pci_hp_deregister(slot->hotplug_slot); | 293 | pci_hp_deregister(slot->hotplug_slot); |
290 | } | 294 | } |
291 | } | 295 | } |
@@ -314,7 +318,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) | |||
314 | 318 | ||
315 | dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); | 319 | dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); |
316 | 320 | ||
317 | return pciehp_enable_slot(slot); | 321 | return pciehp_sysfs_enable_slot(slot); |
318 | } | 322 | } |
319 | 323 | ||
320 | 324 | ||
@@ -324,7 +328,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) | |||
324 | 328 | ||
325 | dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); | 329 | dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); |
326 | 330 | ||
327 | return pciehp_disable_slot(slot); | 331 | return pciehp_sysfs_disable_slot(slot); |
328 | } | 332 | } |
329 | 333 | ||
330 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) | 334 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) |
@@ -466,17 +470,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
466 | 470 | ||
467 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 471 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); |
468 | 472 | ||
469 | /* Finish setting up the hot plug ctrl device */ | ||
470 | ctrl->next_event = 0; | ||
471 | |||
472 | if (!pciehp_ctrl_list) { | ||
473 | pciehp_ctrl_list = ctrl; | ||
474 | ctrl->next = NULL; | ||
475 | } else { | ||
476 | ctrl->next = pciehp_ctrl_list; | ||
477 | pciehp_ctrl_list = ctrl; | ||
478 | } | ||
479 | |||
480 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ | 473 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ |
481 | if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { | 474 | if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { |
482 | rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ | 475 | rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ |
@@ -496,48 +489,14 @@ err_out_none: | |||
496 | return -ENODEV; | 489 | return -ENODEV; |
497 | } | 490 | } |
498 | 491 | ||
499 | 492 | static void pciehp_remove (struct pcie_device *dev) | |
500 | static int pcie_start_thread(void) | ||
501 | { | 493 | { |
502 | int retval = 0; | 494 | struct pci_dev *pdev = dev->port; |
503 | 495 | struct controller *ctrl = pci_get_drvdata(pdev); | |
504 | dbg("Initialize + Start the notification/polling mechanism \n"); | ||
505 | |||
506 | retval = pciehp_event_start_thread(); | ||
507 | if (retval) { | ||
508 | dbg("pciehp_event_start_thread() failed\n"); | ||
509 | return retval; | ||
510 | } | ||
511 | |||
512 | return retval; | ||
513 | } | ||
514 | |||
515 | static void __exit unload_pciehpd(void) | ||
516 | { | ||
517 | struct controller *ctrl; | ||
518 | struct controller *tctrl; | ||
519 | |||
520 | ctrl = pciehp_ctrl_list; | ||
521 | |||
522 | while (ctrl) { | ||
523 | cleanup_slots(ctrl); | ||
524 | 496 | ||
525 | ctrl->hpc_ops->release_ctlr(ctrl); | 497 | cleanup_slots(ctrl); |
526 | 498 | ctrl->hpc_ops->release_ctlr(ctrl); | |
527 | tctrl = ctrl; | 499 | kfree(ctrl); |
528 | ctrl = ctrl->next; | ||
529 | |||
530 | kfree(tctrl); | ||
531 | } | ||
532 | |||
533 | /* Stop the notification mechanism */ | ||
534 | pciehp_event_stop_thread(); | ||
535 | |||
536 | } | ||
537 | |||
538 | static void pciehp_remove (struct pcie_device *device) | ||
539 | { | ||
540 | /* XXX - Needs to be adapted to device driver model */ | ||
541 | } | 500 | } |
542 | 501 | ||
543 | #ifdef CONFIG_PM | 502 | #ifdef CONFIG_PM |
@@ -585,31 +544,18 @@ static int __init pcied_init(void) | |||
585 | pciehp_poll_mode = 1; | 544 | pciehp_poll_mode = 1; |
586 | #endif | 545 | #endif |
587 | 546 | ||
588 | retval = pcie_start_thread(); | ||
589 | if (retval) | ||
590 | goto error_hpc_init; | ||
591 | |||
592 | retval = pcie_port_service_register(&hpdriver_portdrv); | 547 | retval = pcie_port_service_register(&hpdriver_portdrv); |
593 | dbg("pcie_port_service_register = %d\n", retval); | 548 | dbg("pcie_port_service_register = %d\n", retval); |
594 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 549 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
595 | if (retval) | 550 | if (retval) |
596 | dbg("%s: Failure to register service\n", __FUNCTION__); | 551 | dbg("%s: Failure to register service\n", __FUNCTION__); |
597 | |||
598 | error_hpc_init: | ||
599 | if (retval) { | ||
600 | pciehp_event_stop_thread(); | ||
601 | }; | ||
602 | |||
603 | return retval; | 552 | return retval; |
604 | } | 553 | } |
605 | 554 | ||
606 | static void __exit pcied_cleanup(void) | 555 | static void __exit pcied_cleanup(void) |
607 | { | 556 | { |
608 | dbg("unload_pciehpd()\n"); | 557 | dbg("unload_pciehpd()\n"); |
609 | unload_pciehpd(); | ||
610 | |||
611 | pcie_port_service_unregister(&hpdriver_portdrv); | 558 | pcie_port_service_unregister(&hpdriver_portdrv); |
612 | |||
613 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); | 559 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); |
614 | } | 560 | } |
615 | 561 | ||
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 4283ef56dbd9..7f22caa70178 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c | |||
@@ -32,92 +32,61 @@ | |||
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/smp_lock.h> | 33 | #include <linux/smp_lock.h> |
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #include <linux/workqueue.h> | ||
35 | #include "../pci.h" | 36 | #include "../pci.h" |
36 | #include "pciehp.h" | 37 | #include "pciehp.h" |
37 | 38 | ||
38 | static void interrupt_event_handler(struct controller *ctrl); | 39 | static void interrupt_event_handler(struct work_struct *work); |
40 | static int pciehp_enable_slot(struct slot *p_slot); | ||
41 | static int pciehp_disable_slot(struct slot *p_slot); | ||
39 | 42 | ||
40 | static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ | 43 | static int queue_interrupt_event(struct slot *p_slot, u32 event_type) |
41 | static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ | ||
42 | static int event_finished; | ||
43 | static unsigned long pushbutton_pending; /* = 0 */ | ||
44 | static unsigned long surprise_rm_pending; /* = 0 */ | ||
45 | |||
46 | static inline char *slot_name(struct slot *p_slot) | ||
47 | { | 44 | { |
48 | return p_slot->hotplug_slot->name; | 45 | struct event_info *info; |
46 | |||
47 | info = kmalloc(sizeof(*info), GFP_ATOMIC); | ||
48 | if (!info) | ||
49 | return -ENOMEM; | ||
50 | |||
51 | info->event_type = event_type; | ||
52 | info->p_slot = p_slot; | ||
53 | INIT_WORK(&info->work, interrupt_event_handler); | ||
54 | |||
55 | schedule_work(&info->work); | ||
56 | |||
57 | return 0; | ||
49 | } | 58 | } |
50 | 59 | ||
51 | u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) | 60 | u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) |
52 | { | 61 | { |
53 | struct slot *p_slot; | 62 | struct slot *p_slot; |
54 | u8 rc = 0; | 63 | u32 event_type; |
55 | u8 getstatus; | ||
56 | struct event_info *taskInfo; | ||
57 | 64 | ||
58 | /* Attention Button Change */ | 65 | /* Attention Button Change */ |
59 | dbg("pciehp: Attention button interrupt received.\n"); | 66 | dbg("pciehp: Attention button interrupt received.\n"); |
60 | |||
61 | /* This is the structure that tells the worker thread what to do */ | ||
62 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
63 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | ||
64 | |||
65 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | ||
66 | |||
67 | ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; | ||
68 | taskInfo->hp_slot = hp_slot; | ||
69 | 67 | ||
70 | rc++; | 68 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
71 | 69 | ||
72 | /* | 70 | /* |
73 | * Button pressed - See if need to TAKE ACTION!!! | 71 | * Button pressed - See if need to TAKE ACTION!!! |
74 | */ | 72 | */ |
75 | info("Button pressed on Slot(%s)\n", slot_name(p_slot)); | 73 | info("Button pressed on Slot(%s)\n", p_slot->name); |
76 | taskInfo->event_type = INT_BUTTON_PRESS; | 74 | event_type = INT_BUTTON_PRESS; |
77 | |||
78 | if ((p_slot->state == BLINKINGON_STATE) | ||
79 | || (p_slot->state == BLINKINGOFF_STATE)) { | ||
80 | /* Cancel if we are still blinking; this means that we press the | ||
81 | * attention again before the 5 sec. limit expires to cancel hot-add | ||
82 | * or hot-remove | ||
83 | */ | ||
84 | taskInfo->event_type = INT_BUTTON_CANCEL; | ||
85 | info("Button cancel on Slot(%s)\n", slot_name(p_slot)); | ||
86 | } else if ((p_slot->state == POWERON_STATE) | ||
87 | || (p_slot->state == POWEROFF_STATE)) { | ||
88 | /* Ignore if the slot is on power-on or power-off state; this | ||
89 | * means that the previous attention button action to hot-add or | ||
90 | * hot-remove is undergoing | ||
91 | */ | ||
92 | taskInfo->event_type = INT_BUTTON_IGNORE; | ||
93 | info("Button ignore on Slot(%s)\n", slot_name(p_slot)); | ||
94 | } | ||
95 | 75 | ||
96 | if (rc) | 76 | queue_interrupt_event(p_slot, event_type); |
97 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
98 | 77 | ||
99 | return 0; | 78 | return 0; |
100 | |||
101 | } | 79 | } |
102 | 80 | ||
103 | u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) | 81 | u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) |
104 | { | 82 | { |
105 | struct slot *p_slot; | 83 | struct slot *p_slot; |
106 | u8 rc = 0; | ||
107 | u8 getstatus; | 84 | u8 getstatus; |
108 | struct event_info *taskInfo; | 85 | u32 event_type; |
109 | 86 | ||
110 | /* Switch Change */ | 87 | /* Switch Change */ |
111 | dbg("pciehp: Switch interrupt received.\n"); | 88 | dbg("pciehp: Switch interrupt received.\n"); |
112 | 89 | ||
113 | /* This is the structure that tells the worker thread | ||
114 | * what to do | ||
115 | */ | ||
116 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
117 | ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; | ||
118 | taskInfo->hp_slot = hp_slot; | ||
119 | |||
120 | rc++; | ||
121 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 90 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
122 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 91 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
123 | 92 | ||
@@ -125,39 +94,30 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) | |||
125 | /* | 94 | /* |
126 | * Switch opened | 95 | * Switch opened |
127 | */ | 96 | */ |
128 | info("Latch open on Slot(%s)\n", slot_name(p_slot)); | 97 | info("Latch open on Slot(%s)\n", p_slot->name); |
129 | taskInfo->event_type = INT_SWITCH_OPEN; | 98 | event_type = INT_SWITCH_OPEN; |
130 | } else { | 99 | } else { |
131 | /* | 100 | /* |
132 | * Switch closed | 101 | * Switch closed |
133 | */ | 102 | */ |
134 | info("Latch close on Slot(%s)\n", slot_name(p_slot)); | 103 | info("Latch close on Slot(%s)\n", p_slot->name); |
135 | taskInfo->event_type = INT_SWITCH_CLOSE; | 104 | event_type = INT_SWITCH_CLOSE; |
136 | } | 105 | } |
137 | 106 | ||
138 | if (rc) | 107 | queue_interrupt_event(p_slot, event_type); |
139 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
140 | 108 | ||
141 | return rc; | 109 | return 1; |
142 | } | 110 | } |
143 | 111 | ||
144 | u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) | 112 | u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) |
145 | { | 113 | { |
146 | struct slot *p_slot; | 114 | struct slot *p_slot; |
147 | u8 presence_save, rc = 0; | 115 | u32 event_type; |
148 | struct event_info *taskInfo; | 116 | u8 presence_save; |
149 | 117 | ||
150 | /* Presence Change */ | 118 | /* Presence Change */ |
151 | dbg("pciehp: Presence/Notify input change.\n"); | 119 | dbg("pciehp: Presence/Notify input change.\n"); |
152 | 120 | ||
153 | /* This is the structure that tells the worker thread | ||
154 | * what to do | ||
155 | */ | ||
156 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
157 | ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; | ||
158 | taskInfo->hp_slot = hp_slot; | ||
159 | |||
160 | rc++; | ||
161 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 121 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
162 | 122 | ||
163 | /* Switch is open, assume a presence change | 123 | /* Switch is open, assume a presence change |
@@ -168,59 +128,49 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) | |||
168 | /* | 128 | /* |
169 | * Card Present | 129 | * Card Present |
170 | */ | 130 | */ |
171 | info("Card present on Slot(%s)\n", slot_name(p_slot)); | 131 | info("Card present on Slot(%s)\n", p_slot->name); |
172 | taskInfo->event_type = INT_PRESENCE_ON; | 132 | event_type = INT_PRESENCE_ON; |
173 | } else { | 133 | } else { |
174 | /* | 134 | /* |
175 | * Not Present | 135 | * Not Present |
176 | */ | 136 | */ |
177 | info("Card not present on Slot(%s)\n", slot_name(p_slot)); | 137 | info("Card not present on Slot(%s)\n", p_slot->name); |
178 | taskInfo->event_type = INT_PRESENCE_OFF; | 138 | event_type = INT_PRESENCE_OFF; |
179 | } | 139 | } |
180 | 140 | ||
181 | if (rc) | 141 | queue_interrupt_event(p_slot, event_type); |
182 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
183 | 142 | ||
184 | return rc; | 143 | return 1; |
185 | } | 144 | } |
186 | 145 | ||
187 | u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) | 146 | u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) |
188 | { | 147 | { |
189 | struct slot *p_slot; | 148 | struct slot *p_slot; |
190 | u8 rc = 0; | 149 | u32 event_type; |
191 | struct event_info *taskInfo; | ||
192 | 150 | ||
193 | /* power fault */ | 151 | /* power fault */ |
194 | dbg("pciehp: Power fault interrupt received.\n"); | 152 | dbg("pciehp: Power fault interrupt received.\n"); |
195 | 153 | ||
196 | /* this is the structure that tells the worker thread | ||
197 | * what to do | ||
198 | */ | ||
199 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | ||
200 | ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; | ||
201 | taskInfo->hp_slot = hp_slot; | ||
202 | |||
203 | rc++; | ||
204 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 154 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
205 | 155 | ||
206 | if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { | 156 | if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { |
207 | /* | 157 | /* |
208 | * power fault Cleared | 158 | * power fault Cleared |
209 | */ | 159 | */ |
210 | info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); | 160 | info("Power fault cleared on Slot(%s)\n", p_slot->name); |
211 | taskInfo->event_type = INT_POWER_FAULT_CLEAR; | 161 | event_type = INT_POWER_FAULT_CLEAR; |
212 | } else { | 162 | } else { |
213 | /* | 163 | /* |
214 | * power fault | 164 | * power fault |
215 | */ | 165 | */ |
216 | info("Power fault on Slot(%s)\n", slot_name(p_slot)); | 166 | info("Power fault on Slot(%s)\n", p_slot->name); |
217 | taskInfo->event_type = INT_POWER_FAULT; | 167 | event_type = INT_POWER_FAULT; |
218 | info("power fault bit %x set\n", hp_slot); | 168 | info("power fault bit %x set\n", hp_slot); |
219 | } | 169 | } |
220 | if (rc) | ||
221 | up(&event_semaphore); /* signal event thread that new event is posted */ | ||
222 | 170 | ||
223 | return rc; | 171 | queue_interrupt_event(p_slot, event_type); |
172 | |||
173 | return 1; | ||
224 | } | 174 | } |
225 | 175 | ||
226 | /* The following routines constitute the bulk of the | 176 | /* The following routines constitute the bulk of the |
@@ -357,13 +307,10 @@ static int remove_board(struct slot *p_slot) | |||
357 | return 0; | 307 | return 0; |
358 | } | 308 | } |
359 | 309 | ||
360 | 310 | struct power_work_info { | |
361 | static void pushbutton_helper_thread(unsigned long data) | 311 | struct slot *p_slot; |
362 | { | 312 | struct work_struct work; |
363 | pushbutton_pending = data; | 313 | }; |
364 | |||
365 | up(&event_semaphore); | ||
366 | } | ||
367 | 314 | ||
368 | /** | 315 | /** |
369 | * pciehp_pushbutton_thread | 316 | * pciehp_pushbutton_thread |
@@ -372,276 +319,214 @@ static void pushbutton_helper_thread(unsigned long data) | |||
372 | * Handles all pending events and exits. | 319 | * Handles all pending events and exits. |
373 | * | 320 | * |
374 | */ | 321 | */ |
375 | static void pciehp_pushbutton_thread(unsigned long slot) | 322 | static void pciehp_power_thread(struct work_struct *work) |
376 | { | 323 | { |
377 | struct slot *p_slot = (struct slot *) slot; | 324 | struct power_work_info *info = |
378 | u8 getstatus; | 325 | container_of(work, struct power_work_info, work); |
379 | 326 | struct slot *p_slot = info->p_slot; | |
380 | pushbutton_pending = 0; | 327 | |
381 | 328 | mutex_lock(&p_slot->lock); | |
382 | if (!p_slot) { | 329 | switch (p_slot->state) { |
383 | dbg("%s: Error! slot NULL\n", __FUNCTION__); | 330 | case POWEROFF_STATE: |
384 | return; | 331 | mutex_unlock(&p_slot->lock); |
385 | } | 332 | dbg("%s: disabling bus:device(%x:%x)\n", |
386 | 333 | __FUNCTION__, p_slot->bus, p_slot->device); | |
387 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | ||
388 | if (getstatus) { | ||
389 | p_slot->state = POWEROFF_STATE; | ||
390 | dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__, | ||
391 | p_slot->bus, p_slot->device); | ||
392 | |||
393 | pciehp_disable_slot(p_slot); | 334 | pciehp_disable_slot(p_slot); |
335 | mutex_lock(&p_slot->lock); | ||
394 | p_slot->state = STATIC_STATE; | 336 | p_slot->state = STATIC_STATE; |
395 | } else { | 337 | break; |
396 | p_slot->state = POWERON_STATE; | 338 | case POWERON_STATE: |
397 | dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__, | 339 | mutex_unlock(&p_slot->lock); |
398 | p_slot->bus, p_slot->device); | ||
399 | |||
400 | if (pciehp_enable_slot(p_slot) && | 340 | if (pciehp_enable_slot(p_slot) && |
401 | PWR_LED(p_slot->ctrl->ctrlcap)) | 341 | PWR_LED(p_slot->ctrl->ctrlcap)) |
402 | p_slot->hpc_ops->green_led_off(p_slot); | 342 | p_slot->hpc_ops->green_led_off(p_slot); |
403 | 343 | mutex_lock(&p_slot->lock); | |
404 | p_slot->state = STATIC_STATE; | 344 | p_slot->state = STATIC_STATE; |
345 | break; | ||
346 | default: | ||
347 | break; | ||
405 | } | 348 | } |
349 | mutex_unlock(&p_slot->lock); | ||
406 | 350 | ||
407 | return; | 351 | kfree(info); |
408 | } | 352 | } |
409 | 353 | ||
410 | /** | 354 | void pciehp_queue_pushbutton_work(struct work_struct *work) |
411 | * pciehp_surprise_rm_thread | ||
412 | * | ||
413 | * Scheduled procedure to handle blocking stuff for the surprise removal | ||
414 | * Handles all pending events and exits. | ||
415 | * | ||
416 | */ | ||
417 | static void pciehp_surprise_rm_thread(unsigned long slot) | ||
418 | { | 355 | { |
419 | struct slot *p_slot = (struct slot *) slot; | 356 | struct slot *p_slot = container_of(work, struct slot, work.work); |
420 | u8 getstatus; | 357 | struct power_work_info *info; |
421 | |||
422 | surprise_rm_pending = 0; | ||
423 | 358 | ||
424 | if (!p_slot) { | 359 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
425 | dbg("%s: Error! slot NULL\n", __FUNCTION__); | 360 | if (!info) { |
361 | err("%s: Cannot allocate memory\n", __FUNCTION__); | ||
426 | return; | 362 | return; |
427 | } | 363 | } |
364 | info->p_slot = p_slot; | ||
365 | INIT_WORK(&info->work, pciehp_power_thread); | ||
428 | 366 | ||
429 | p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 367 | mutex_lock(&p_slot->lock); |
430 | if (!getstatus) { | 368 | switch (p_slot->state) { |
369 | case BLINKINGOFF_STATE: | ||
431 | p_slot->state = POWEROFF_STATE; | 370 | p_slot->state = POWEROFF_STATE; |
432 | dbg("%s: removing bus:device(%x:%x)\n", | 371 | break; |
433 | __FUNCTION__, p_slot->bus, p_slot->device); | 372 | case BLINKINGON_STATE: |
434 | |||
435 | pciehp_disable_slot(p_slot); | ||
436 | p_slot->state = STATIC_STATE; | ||
437 | } else { | ||
438 | p_slot->state = POWERON_STATE; | 373 | p_slot->state = POWERON_STATE; |
439 | dbg("%s: adding bus:device(%x:%x)\n", | 374 | break; |
440 | __FUNCTION__, p_slot->bus, p_slot->device); | 375 | default: |
441 | 376 | goto out; | |
442 | if (pciehp_enable_slot(p_slot) && | ||
443 | PWR_LED(p_slot->ctrl->ctrlcap)) | ||
444 | p_slot->hpc_ops->green_led_off(p_slot); | ||
445 | |||
446 | p_slot->state = STATIC_STATE; | ||
447 | } | 377 | } |
448 | 378 | queue_work(pciehp_wq, &info->work); | |
449 | return; | 379 | out: |
380 | mutex_unlock(&p_slot->lock); | ||
450 | } | 381 | } |
451 | 382 | ||
452 | |||
453 | |||
454 | /* this is the main worker thread */ | ||
455 | static int event_thread(void* data) | ||
456 | { | ||
457 | struct controller *ctrl; | ||
458 | lock_kernel(); | ||
459 | daemonize("pciehpd_event"); | ||
460 | |||
461 | unlock_kernel(); | ||
462 | |||
463 | while (1) { | ||
464 | dbg("!!!!event_thread sleeping\n"); | ||
465 | down_interruptible (&event_semaphore); | ||
466 | dbg("event_thread woken finished = %d\n", event_finished); | ||
467 | if (event_finished || signal_pending(current)) | ||
468 | break; | ||
469 | /* Do stuff here */ | ||
470 | if (pushbutton_pending) | ||
471 | pciehp_pushbutton_thread(pushbutton_pending); | ||
472 | else if (surprise_rm_pending) | ||
473 | pciehp_surprise_rm_thread(surprise_rm_pending); | ||
474 | else | ||
475 | for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next) | ||
476 | interrupt_event_handler(ctrl); | ||
477 | } | ||
478 | dbg("event_thread signals exit\n"); | ||
479 | up(&event_exit); | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | int pciehp_event_start_thread(void) | ||
484 | { | ||
485 | int pid; | ||
486 | |||
487 | /* initialize our semaphores */ | ||
488 | init_MUTEX_LOCKED(&event_exit); | ||
489 | event_finished=0; | ||
490 | |||
491 | init_MUTEX_LOCKED(&event_semaphore); | ||
492 | pid = kernel_thread(event_thread, NULL, 0); | ||
493 | |||
494 | if (pid < 0) { | ||
495 | err ("Can't start up our event thread\n"); | ||
496 | return -1; | ||
497 | } | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | |||
502 | void pciehp_event_stop_thread(void) | ||
503 | { | ||
504 | event_finished = 1; | ||
505 | up(&event_semaphore); | ||
506 | down(&event_exit); | ||
507 | } | ||
508 | |||
509 | |||
510 | static int update_slot_info(struct slot *slot) | 383 | static int update_slot_info(struct slot *slot) |
511 | { | 384 | { |
512 | struct hotplug_slot_info *info; | 385 | struct hotplug_slot_info *info; |
513 | /* char buffer[SLOT_NAME_SIZE]; */ | ||
514 | int result; | 386 | int result; |
515 | 387 | ||
516 | info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); | 388 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
517 | if (!info) | 389 | if (!info) |
518 | return -ENOMEM; | 390 | return -ENOMEM; |
519 | 391 | ||
520 | /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */ | ||
521 | |||
522 | slot->hpc_ops->get_power_status(slot, &(info->power_status)); | 392 | slot->hpc_ops->get_power_status(slot, &(info->power_status)); |
523 | slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); | 393 | slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); |
524 | slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); | 394 | slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); |
525 | slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); | 395 | slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); |
526 | 396 | ||
527 | /* result = pci_hp_change_slot_info(buffer, info); */ | ||
528 | result = pci_hp_change_slot_info(slot->hotplug_slot, info); | 397 | result = pci_hp_change_slot_info(slot->hotplug_slot, info); |
529 | kfree (info); | 398 | kfree (info); |
530 | return result; | 399 | return result; |
531 | } | 400 | } |
532 | 401 | ||
533 | static void interrupt_event_handler(struct controller *ctrl) | 402 | /* |
403 | * Note: This function must be called with slot->lock held | ||
404 | */ | ||
405 | static void handle_button_press_event(struct slot *p_slot) | ||
534 | { | 406 | { |
535 | int loop = 0; | 407 | struct controller *ctrl = p_slot->ctrl; |
536 | int change = 1; | ||
537 | u8 hp_slot; | ||
538 | u8 getstatus; | 408 | u8 getstatus; |
539 | struct slot *p_slot; | ||
540 | 409 | ||
541 | while (change) { | 410 | switch (p_slot->state) { |
542 | change = 0; | 411 | case STATIC_STATE: |
543 | 412 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | |
544 | for (loop = 0; loop < MAX_EVENTS; loop++) { | 413 | if (getstatus) { |
545 | if (ctrl->event_queue[loop].event_type != 0) { | 414 | p_slot->state = BLINKINGOFF_STATE; |
546 | hp_slot = ctrl->event_queue[loop].hp_slot; | 415 | info("PCI slot #%s - powering off due to button " |
547 | 416 | "press.\n", p_slot->name); | |
548 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 417 | } else { |
549 | 418 | p_slot->state = BLINKINGON_STATE; | |
550 | if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { | 419 | info("PCI slot #%s - powering on due to button " |
551 | dbg("button cancel\n"); | 420 | "press.\n", p_slot->name); |
552 | del_timer(&p_slot->task_event); | 421 | } |
553 | 422 | /* blink green LED and turn off amber */ | |
554 | switch (p_slot->state) { | 423 | if (PWR_LED(ctrl->ctrlcap)) |
555 | case BLINKINGOFF_STATE: | 424 | p_slot->hpc_ops->green_led_blink(p_slot); |
556 | if (PWR_LED(ctrl->ctrlcap)) | 425 | if (ATTN_LED(ctrl->ctrlcap)) |
557 | p_slot->hpc_ops->green_led_on(p_slot); | 426 | p_slot->hpc_ops->set_attention_status(p_slot, 0); |
558 | 427 | ||
559 | if (ATTN_LED(ctrl->ctrlcap)) | 428 | schedule_delayed_work(&p_slot->work, 5*HZ); |
560 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | 429 | break; |
561 | break; | 430 | case BLINKINGOFF_STATE: |
562 | case BLINKINGON_STATE: | 431 | case BLINKINGON_STATE: |
563 | if (PWR_LED(ctrl->ctrlcap)) | 432 | /* |
564 | p_slot->hpc_ops->green_led_off(p_slot); | 433 | * Cancel if we are still blinking; this means that we |
565 | 434 | * press the attention again before the 5 sec. limit | |
566 | if (ATTN_LED(ctrl->ctrlcap)) | 435 | * expires to cancel hot-add or hot-remove |
567 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | 436 | */ |
568 | break; | 437 | info("Button cancel on Slot(%s)\n", p_slot->name); |
569 | default: | 438 | dbg("%s: button cancel\n", __FUNCTION__); |
570 | warn("Not a valid state\n"); | 439 | cancel_delayed_work(&p_slot->work); |
571 | return; | 440 | if (p_slot->state == BLINKINGOFF_STATE) { |
572 | } | 441 | if (PWR_LED(ctrl->ctrlcap)) |
573 | info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot)); | 442 | p_slot->hpc_ops->green_led_on(p_slot); |
574 | p_slot->state = STATIC_STATE; | 443 | } else { |
575 | } | 444 | if (PWR_LED(ctrl->ctrlcap)) |
576 | /* ***********Button Pressed (No action on 1st press...) */ | 445 | p_slot->hpc_ops->green_led_off(p_slot); |
577 | else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { | 446 | } |
578 | 447 | if (ATTN_LED(ctrl->ctrlcap)) | |
579 | if (ATTN_BUTTN(ctrl->ctrlcap)) { | 448 | p_slot->hpc_ops->set_attention_status(p_slot, 0); |
580 | dbg("Button pressed\n"); | 449 | info("PCI slot #%s - action canceled due to button press\n", |
581 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 450 | p_slot->name); |
582 | if (getstatus) { | 451 | p_slot->state = STATIC_STATE; |
583 | /* slot is on */ | 452 | break; |
584 | dbg("slot is on\n"); | 453 | case POWEROFF_STATE: |
585 | p_slot->state = BLINKINGOFF_STATE; | 454 | case POWERON_STATE: |
586 | info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot)); | 455 | /* |
587 | } else { | 456 | * Ignore if the slot is on power-on or power-off state; |
588 | /* slot is off */ | 457 | * this means that the previous attention button action |
589 | dbg("slot is off\n"); | 458 | * to hot-add or hot-remove is undergoing |
590 | p_slot->state = BLINKINGON_STATE; | 459 | */ |
591 | info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot)); | 460 | info("Button ignore on Slot(%s)\n", p_slot->name); |
592 | } | 461 | update_slot_info(p_slot); |
593 | 462 | break; | |
594 | /* blink green LED and turn off amber */ | 463 | default: |
595 | if (PWR_LED(ctrl->ctrlcap)) | 464 | warn("Not a valid state\n"); |
596 | p_slot->hpc_ops->green_led_blink(p_slot); | 465 | break; |
597 | |||
598 | if (ATTN_LED(ctrl->ctrlcap)) | ||
599 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | ||
600 | |||
601 | init_timer(&p_slot->task_event); | ||
602 | p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ | ||
603 | p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; | ||
604 | p_slot->task_event.data = (unsigned long) p_slot; | ||
605 | |||
606 | add_timer(&p_slot->task_event); | ||
607 | } | ||
608 | } | ||
609 | /***********POWER FAULT********************/ | ||
610 | else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { | ||
611 | if (POWER_CTRL(ctrl->ctrlcap)) { | ||
612 | dbg("power fault\n"); | ||
613 | if (ATTN_LED(ctrl->ctrlcap)) | ||
614 | p_slot->hpc_ops->set_attention_status(p_slot, 1); | ||
615 | |||
616 | if (PWR_LED(ctrl->ctrlcap)) | ||
617 | p_slot->hpc_ops->green_led_off(p_slot); | ||
618 | } | ||
619 | } | ||
620 | /***********SURPRISE REMOVAL********************/ | ||
621 | else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || | ||
622 | (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) { | ||
623 | if (HP_SUPR_RM(ctrl->ctrlcap)) { | ||
624 | dbg("Surprise Removal\n"); | ||
625 | if (p_slot) { | ||
626 | surprise_rm_pending = (unsigned long) p_slot; | ||
627 | up(&event_semaphore); | ||
628 | update_slot_info(p_slot); | ||
629 | } | ||
630 | } | ||
631 | } else { | ||
632 | /* refresh notification */ | ||
633 | if (p_slot) | ||
634 | update_slot_info(p_slot); | ||
635 | } | ||
636 | |||
637 | ctrl->event_queue[loop].event_type = 0; | ||
638 | |||
639 | change = 1; | ||
640 | } | ||
641 | } /* End of FOR loop */ | ||
642 | } | 466 | } |
643 | } | 467 | } |
644 | 468 | ||
469 | /* | ||
470 | * Note: This function must be called with slot->lock held | ||
471 | */ | ||
472 | static void handle_surprise_event(struct slot *p_slot) | ||
473 | { | ||
474 | u8 getstatus; | ||
475 | struct power_work_info *info; | ||
476 | |||
477 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
478 | if (!info) { | ||
479 | err("%s: Cannot allocate memory\n", __FUNCTION__); | ||
480 | return; | ||
481 | } | ||
482 | info->p_slot = p_slot; | ||
483 | INIT_WORK(&info->work, pciehp_power_thread); | ||
484 | |||
485 | p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | ||
486 | if (!getstatus) | ||
487 | p_slot->state = POWEROFF_STATE; | ||
488 | else | ||
489 | p_slot->state = POWERON_STATE; | ||
490 | |||
491 | queue_work(pciehp_wq, &info->work); | ||
492 | } | ||
493 | |||
494 | static void interrupt_event_handler(struct work_struct *work) | ||
495 | { | ||
496 | struct event_info *info = container_of(work, struct event_info, work); | ||
497 | struct slot *p_slot = info->p_slot; | ||
498 | struct controller *ctrl = p_slot->ctrl; | ||
499 | |||
500 | mutex_lock(&p_slot->lock); | ||
501 | switch (info->event_type) { | ||
502 | case INT_BUTTON_PRESS: | ||
503 | handle_button_press_event(p_slot); | ||
504 | break; | ||
505 | case INT_POWER_FAULT: | ||
506 | if (!POWER_CTRL(ctrl->ctrlcap)) | ||
507 | break; | ||
508 | if (ATTN_LED(ctrl->ctrlcap)) | ||
509 | p_slot->hpc_ops->set_attention_status(p_slot, 1); | ||
510 | if (PWR_LED(ctrl->ctrlcap)) | ||
511 | p_slot->hpc_ops->green_led_off(p_slot); | ||
512 | break; | ||
513 | case INT_PRESENCE_ON: | ||
514 | case INT_PRESENCE_OFF: | ||
515 | if (!HP_SUPR_RM(ctrl->ctrlcap)) | ||
516 | break; | ||
517 | dbg("Surprise Removal\n"); | ||
518 | update_slot_info(p_slot); | ||
519 | handle_surprise_event(p_slot); | ||
520 | break; | ||
521 | default: | ||
522 | update_slot_info(p_slot); | ||
523 | break; | ||
524 | } | ||
525 | mutex_unlock(&p_slot->lock); | ||
526 | |||
527 | kfree(info); | ||
528 | } | ||
529 | |||
645 | int pciehp_enable_slot(struct slot *p_slot) | 530 | int pciehp_enable_slot(struct slot *p_slot) |
646 | { | 531 | { |
647 | u8 getstatus = 0; | 532 | u8 getstatus = 0; |
@@ -653,7 +538,7 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
653 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 538 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
654 | if (rc || !getstatus) { | 539 | if (rc || !getstatus) { |
655 | info("%s: no adapter on slot(%s)\n", __FUNCTION__, | 540 | info("%s: no adapter on slot(%s)\n", __FUNCTION__, |
656 | slot_name(p_slot)); | 541 | p_slot->name); |
657 | mutex_unlock(&p_slot->ctrl->crit_sect); | 542 | mutex_unlock(&p_slot->ctrl->crit_sect); |
658 | return -ENODEV; | 543 | return -ENODEV; |
659 | } | 544 | } |
@@ -661,7 +546,7 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
661 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 546 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
662 | if (rc || getstatus) { | 547 | if (rc || getstatus) { |
663 | info("%s: latch open on slot(%s)\n", __FUNCTION__, | 548 | info("%s: latch open on slot(%s)\n", __FUNCTION__, |
664 | slot_name(p_slot)); | 549 | p_slot->name); |
665 | mutex_unlock(&p_slot->ctrl->crit_sect); | 550 | mutex_unlock(&p_slot->ctrl->crit_sect); |
666 | return -ENODEV; | 551 | return -ENODEV; |
667 | } | 552 | } |
@@ -671,7 +556,7 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
671 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 556 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
672 | if (rc || getstatus) { | 557 | if (rc || getstatus) { |
673 | info("%s: already enabled on slot(%s)\n", __FUNCTION__, | 558 | info("%s: already enabled on slot(%s)\n", __FUNCTION__, |
674 | slot_name(p_slot)); | 559 | p_slot->name); |
675 | mutex_unlock(&p_slot->ctrl->crit_sect); | 560 | mutex_unlock(&p_slot->ctrl->crit_sect); |
676 | return -EINVAL; | 561 | return -EINVAL; |
677 | } | 562 | } |
@@ -706,7 +591,7 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
706 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 591 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
707 | if (ret || !getstatus) { | 592 | if (ret || !getstatus) { |
708 | info("%s: no adapter on slot(%s)\n", __FUNCTION__, | 593 | info("%s: no adapter on slot(%s)\n", __FUNCTION__, |
709 | slot_name(p_slot)); | 594 | p_slot->name); |
710 | mutex_unlock(&p_slot->ctrl->crit_sect); | 595 | mutex_unlock(&p_slot->ctrl->crit_sect); |
711 | return -ENODEV; | 596 | return -ENODEV; |
712 | } | 597 | } |
@@ -716,7 +601,7 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
716 | ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 601 | ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
717 | if (ret || getstatus) { | 602 | if (ret || getstatus) { |
718 | info("%s: latch open on slot(%s)\n", __FUNCTION__, | 603 | info("%s: latch open on slot(%s)\n", __FUNCTION__, |
719 | slot_name(p_slot)); | 604 | p_slot->name); |
720 | mutex_unlock(&p_slot->ctrl->crit_sect); | 605 | mutex_unlock(&p_slot->ctrl->crit_sect); |
721 | return -ENODEV; | 606 | return -ENODEV; |
722 | } | 607 | } |
@@ -726,7 +611,7 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
726 | ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 611 | ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
727 | if (ret || !getstatus) { | 612 | if (ret || !getstatus) { |
728 | info("%s: already disabled slot(%s)\n", __FUNCTION__, | 613 | info("%s: already disabled slot(%s)\n", __FUNCTION__, |
729 | slot_name(p_slot)); | 614 | p_slot->name); |
730 | mutex_unlock(&p_slot->ctrl->crit_sect); | 615 | mutex_unlock(&p_slot->ctrl->crit_sect); |
731 | return -EINVAL; | 616 | return -EINVAL; |
732 | } | 617 | } |
@@ -739,3 +624,66 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
739 | return ret; | 624 | return ret; |
740 | } | 625 | } |
741 | 626 | ||
627 | int pciehp_sysfs_enable_slot(struct slot *p_slot) | ||
628 | { | ||
629 | int retval = -ENODEV; | ||
630 | |||
631 | mutex_lock(&p_slot->lock); | ||
632 | switch (p_slot->state) { | ||
633 | case BLINKINGON_STATE: | ||
634 | cancel_delayed_work(&p_slot->work); | ||
635 | case STATIC_STATE: | ||
636 | p_slot->state = POWERON_STATE; | ||
637 | mutex_unlock(&p_slot->lock); | ||
638 | retval = pciehp_enable_slot(p_slot); | ||
639 | mutex_lock(&p_slot->lock); | ||
640 | p_slot->state = STATIC_STATE; | ||
641 | break; | ||
642 | case POWERON_STATE: | ||
643 | info("Slot %s is already in powering on state\n", | ||
644 | p_slot->name); | ||
645 | break; | ||
646 | case BLINKINGOFF_STATE: | ||
647 | case POWEROFF_STATE: | ||
648 | info("Already enabled on slot %s\n", p_slot->name); | ||
649 | break; | ||
650 | default: | ||
651 | err("Not a valid state on slot %s\n", p_slot->name); | ||
652 | break; | ||
653 | } | ||
654 | mutex_unlock(&p_slot->lock); | ||
655 | |||
656 | return retval; | ||
657 | } | ||
658 | |||
659 | int pciehp_sysfs_disable_slot(struct slot *p_slot) | ||
660 | { | ||
661 | int retval = -ENODEV; | ||
662 | |||
663 | mutex_lock(&p_slot->lock); | ||
664 | switch (p_slot->state) { | ||
665 | case BLINKINGOFF_STATE: | ||
666 | cancel_delayed_work(&p_slot->work); | ||
667 | case STATIC_STATE: | ||
668 | p_slot->state = POWEROFF_STATE; | ||
669 | mutex_unlock(&p_slot->lock); | ||
670 | retval = pciehp_disable_slot(p_slot); | ||
671 | mutex_lock(&p_slot->lock); | ||
672 | p_slot->state = STATIC_STATE; | ||
673 | break; | ||
674 | case POWEROFF_STATE: | ||
675 | info("Slot %s is already in powering off state\n", | ||
676 | p_slot->name); | ||
677 | break; | ||
678 | case BLINKINGON_STATE: | ||
679 | case POWERON_STATE: | ||
680 | info("Already disabled on slot %s\n", p_slot->name); | ||
681 | break; | ||
682 | default: | ||
683 | err("Not a valid state on slot %s\n", p_slot->name); | ||
684 | break; | ||
685 | } | ||
686 | mutex_unlock(&p_slot->lock); | ||
687 | |||
688 | return retval; | ||
689 | } | ||
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index fbc64aa2dd68..9aac6a87eb53 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -71,6 +71,8 @@ | |||
71 | #define DBG_LEAVE_ROUTINE | 71 | #define DBG_LEAVE_ROUTINE |
72 | #endif /* DEBUG */ | 72 | #endif /* DEBUG */ |
73 | 73 | ||
74 | static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); | ||
75 | |||
74 | struct ctrl_reg { | 76 | struct ctrl_reg { |
75 | u8 cap_id; | 77 | u8 cap_id; |
76 | u8 nxt_ptr; | 78 | u8 nxt_ptr; |
@@ -219,10 +221,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) | |||
219 | #define EMI_STATE 0x0080 | 221 | #define EMI_STATE 0x0080 |
220 | #define EMI_STATUS_BIT 7 | 222 | #define EMI_STATUS_BIT 7 |
221 | 223 | ||
222 | static spinlock_t hpc_event_lock; | ||
223 | |||
224 | DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ | 224 | DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ |
225 | static int ctlr_seq_num = 0; /* Controller sequence # */ | ||
226 | 225 | ||
227 | static irqreturn_t pcie_isr(int irq, void *dev_id); | 226 | static irqreturn_t pcie_isr(int irq, void *dev_id); |
228 | static void start_int_poll_timer(struct controller *ctrl, int sec); | 227 | static void start_int_poll_timer(struct controller *ctrl, int sec); |
@@ -656,6 +655,13 @@ static void hpc_release_ctlr(struct controller *ctrl) | |||
656 | else | 655 | else |
657 | free_irq(ctrl->pci_dev->irq, ctrl); | 656 | free_irq(ctrl->pci_dev->irq, ctrl); |
658 | 657 | ||
658 | /* | ||
659 | * If this is the last controller to be released, destroy the | ||
660 | * pciehp work queue | ||
661 | */ | ||
662 | if (atomic_dec_and_test(&pciehp_num_controllers)) | ||
663 | destroy_workqueue(pciehp_wq); | ||
664 | |||
659 | DBG_LEAVE_ROUTINE | 665 | DBG_LEAVE_ROUTINE |
660 | } | 666 | } |
661 | 667 | ||
@@ -1152,7 +1158,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | |||
1152 | int pcie_init(struct controller * ctrl, struct pcie_device *dev) | 1158 | int pcie_init(struct controller * ctrl, struct pcie_device *dev) |
1153 | { | 1159 | { |
1154 | int rc; | 1160 | int rc; |
1155 | static int first = 1; | ||
1156 | u16 temp_word; | 1161 | u16 temp_word; |
1157 | u16 cap_reg; | 1162 | u16 cap_reg; |
1158 | u16 intr_enable = 0; | 1163 | u16 intr_enable = 0; |
@@ -1221,11 +1226,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1221 | dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", | 1226 | dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", |
1222 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); | 1227 | __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); |
1223 | 1228 | ||
1224 | if (first) { | ||
1225 | spin_lock_init(&hpc_event_lock); | ||
1226 | first = 0; | ||
1227 | } | ||
1228 | |||
1229 | for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) | 1229 | for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) |
1230 | if (pci_resource_len(pdev, rc) > 0) | 1230 | if (pci_resource_len(pdev, rc) > 0) |
1231 | dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, | 1231 | dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, |
@@ -1286,7 +1286,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1286 | rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, | 1286 | rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, |
1287 | MY_NAME, (void *)ctrl); | 1287 | MY_NAME, (void *)ctrl); |
1288 | dbg("%s: request_irq %d for hpc%d (returns %d)\n", | 1288 | dbg("%s: request_irq %d for hpc%d (returns %d)\n", |
1289 | __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc); | 1289 | __FUNCTION__, ctrl->pci_dev->irq, |
1290 | atomic_read(&pciehp_num_controllers), rc); | ||
1290 | if (rc) { | 1291 | if (rc) { |
1291 | err("Can't get irq %d for the hotplug controller\n", | 1292 | err("Can't get irq %d for the hotplug controller\n", |
1292 | ctrl->pci_dev->irq); | 1293 | ctrl->pci_dev->irq); |
@@ -1296,6 +1297,18 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1296 | dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, | 1297 | dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, |
1297 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); | 1298 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); |
1298 | 1299 | ||
1300 | /* | ||
1301 | * If this is the first controller to be initialized, | ||
1302 | * initialize the pciehp work queue | ||
1303 | */ | ||
1304 | if (atomic_add_return(1, &pciehp_num_controllers) == 1) { | ||
1305 | pciehp_wq = create_singlethread_workqueue("pciehpd"); | ||
1306 | if (!pciehp_wq) { | ||
1307 | rc = -ENOMEM; | ||
1308 | goto abort_free_irq; | ||
1309 | } | ||
1310 | } | ||
1311 | |||
1299 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); | 1312 | rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); |
1300 | if (rc) { | 1313 | if (rc) { |
1301 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); | 1314 | err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); |
@@ -1349,7 +1362,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1349 | goto abort_disable_intr; | 1362 | goto abort_disable_intr; |
1350 | } | 1363 | } |
1351 | 1364 | ||
1352 | ctlr_seq_num++; | ||
1353 | ctrl->hpc_ops = &pciehp_hpc_ops; | 1365 | ctrl->hpc_ops = &pciehp_hpc_ops; |
1354 | 1366 | ||
1355 | DBG_LEAVE_ROUTINE | 1367 | DBG_LEAVE_ROUTINE |
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index 72383467a0d5..bb3c101c2c5a 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c | |||
@@ -98,7 +98,15 @@ static struct device_node *find_dlpar_node(char *drc_name, int *node_type) | |||
98 | return NULL; | 98 | return NULL; |
99 | } | 99 | } |
100 | 100 | ||
101 | static struct slot *find_slot(struct device_node *dn) | 101 | /** |
102 | * find_php_slot - return hotplug slot structure for device node | ||
103 | * | ||
104 | * This routine will return the hotplug slot structure | ||
105 | * for a given device node. Note that built-in PCI slots | ||
106 | * may be dlpar-able, but not hot-pluggable, so this routine | ||
107 | * will return NULL for built-in PCI slots. | ||
108 | */ | ||
109 | static struct slot *find_php_slot(struct device_node *dn) | ||
102 | { | 110 | { |
103 | struct list_head *tmp, *n; | 111 | struct list_head *tmp, *n; |
104 | struct slot *slot; | 112 | struct slot *slot; |
@@ -224,9 +232,9 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn) | |||
224 | if (!pcibios_find_pci_bus(dn)) | 232 | if (!pcibios_find_pci_bus(dn)) |
225 | return -EINVAL; | 233 | return -EINVAL; |
226 | 234 | ||
227 | slot = find_slot(dn); | 235 | /* If pci slot is hotplugable, use hotplug to remove it */ |
236 | slot = find_php_slot(dn); | ||
228 | if (slot) { | 237 | if (slot) { |
229 | /* Remove hotplug slot */ | ||
230 | if (rpaphp_deregister_slot(slot)) { | 238 | if (rpaphp_deregister_slot(slot)) { |
231 | printk(KERN_ERR | 239 | printk(KERN_ERR |
232 | "%s: unable to remove hotplug slot %s\n", | 240 | "%s: unable to remove hotplug slot %s\n", |
@@ -370,22 +378,17 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) | |||
370 | if (!bus) | 378 | if (!bus) |
371 | return -EINVAL; | 379 | return -EINVAL; |
372 | 380 | ||
373 | slot = find_slot(dn); | 381 | /* If pci slot is hotplugable, use hotplug to remove it */ |
382 | slot = find_php_slot(dn); | ||
374 | if (slot) { | 383 | if (slot) { |
375 | /* Remove hotplug slot */ | ||
376 | if (rpaphp_deregister_slot(slot)) { | 384 | if (rpaphp_deregister_slot(slot)) { |
377 | printk(KERN_ERR | 385 | printk(KERN_ERR |
378 | "%s: unable to remove hotplug slot %s\n", | 386 | "%s: unable to remove hotplug slot %s\n", |
379 | __FUNCTION__, drc_name); | 387 | __FUNCTION__, drc_name); |
380 | return -EIO; | 388 | return -EIO; |
381 | } | 389 | } |
382 | } else { | 390 | } else |
383 | struct pci_dev *dev, *tmp; | 391 | pcibios_remove_pci_devices(bus); |
384 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { | ||
385 | eeh_remove_bus_device(dev); | ||
386 | pci_remove_bus_device(dev); | ||
387 | } | ||
388 | } | ||
389 | 392 | ||
390 | if (unmap_bus_range(bus)) { | 393 | if (unmap_bus_range(bus)) { |
391 | printk(KERN_ERR "%s: failed to unmap bus range\n", | 394 | printk(KERN_ERR "%s: failed to unmap bus range\n", |
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 2e7accf0f734..c822a779653f 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h | |||
@@ -83,19 +83,15 @@ struct slot { | |||
83 | 83 | ||
84 | extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops; | 84 | extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops; |
85 | extern struct list_head rpaphp_slot_head; | 85 | extern struct list_head rpaphp_slot_head; |
86 | extern int num_slots; | ||
87 | 86 | ||
88 | /* function prototypes */ | 87 | /* function prototypes */ |
89 | 88 | ||
90 | /* rpaphp_pci.c */ | 89 | /* rpaphp_pci.c */ |
91 | extern int rpaphp_enable_pci_slot(struct slot *slot); | 90 | extern int rpaphp_enable_slot(struct slot *slot); |
92 | extern int rpaphp_register_pci_slot(struct slot *slot); | ||
93 | extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); | ||
94 | extern int rpaphp_get_sensor_state(struct slot *slot, int *state); | 91 | extern int rpaphp_get_sensor_state(struct slot *slot, int *state); |
95 | 92 | ||
96 | /* rpaphp_core.c */ | 93 | /* rpaphp_core.c */ |
97 | extern int rpaphp_add_slot(struct device_node *dn); | 94 | extern int rpaphp_add_slot(struct device_node *dn); |
98 | extern int rpaphp_remove_slot(struct slot *slot); | ||
99 | extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, | 95 | extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, |
100 | char **drc_name, char **drc_type, int *drc_power_domain); | 96 | char **drc_name, char **drc_type, int *drc_power_domain); |
101 | 97 | ||
@@ -104,7 +100,5 @@ extern void dealloc_slot_struct(struct slot *slot); | |||
104 | extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain); | 100 | extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain); |
105 | extern int rpaphp_register_slot(struct slot *slot); | 101 | extern int rpaphp_register_slot(struct slot *slot); |
106 | extern int rpaphp_deregister_slot(struct slot *slot); | 102 | extern int rpaphp_deregister_slot(struct slot *slot); |
107 | extern int rpaphp_get_power_status(struct slot *slot, u8 * value); | ||
108 | extern int rpaphp_set_attention_status(struct slot *slot, u8 status); | ||
109 | 103 | ||
110 | #endif /* _PPC64PHP_H */ | 104 | #endif /* _PPC64PHP_H */ |
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 353da5b296ef..899eed002748 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c | |||
@@ -39,9 +39,7 @@ | |||
39 | #include "rpaphp.h" | 39 | #include "rpaphp.h" |
40 | 40 | ||
41 | int debug; | 41 | int debug; |
42 | static struct semaphore rpaphp_sem; | ||
43 | LIST_HEAD(rpaphp_slot_head); | 42 | LIST_HEAD(rpaphp_slot_head); |
44 | int num_slots; | ||
45 | 43 | ||
46 | #define DRIVER_VERSION "0.1" | 44 | #define DRIVER_VERSION "0.1" |
47 | #define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>" | 45 | #define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>" |
@@ -55,11 +53,6 @@ MODULE_LICENSE("GPL"); | |||
55 | 53 | ||
56 | module_param(debug, bool, 0644); | 54 | module_param(debug, bool, 0644); |
57 | 55 | ||
58 | static int rpaphp_get_attention_status(struct slot *slot) | ||
59 | { | ||
60 | return slot->hotplug_slot->info->attention_status; | ||
61 | } | ||
62 | |||
63 | /** | 56 | /** |
64 | * set_attention_status - set attention LED | 57 | * set_attention_status - set attention LED |
65 | * echo 0 > attention -- set LED OFF | 58 | * echo 0 > attention -- set LED OFF |
@@ -69,79 +62,75 @@ static int rpaphp_get_attention_status(struct slot *slot) | |||
69 | */ | 62 | */ |
70 | static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) | 63 | static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) |
71 | { | 64 | { |
72 | int retval = 0; | 65 | int rc; |
73 | struct slot *slot = (struct slot *)hotplug_slot->private; | 66 | struct slot *slot = (struct slot *)hotplug_slot->private; |
74 | 67 | ||
75 | down(&rpaphp_sem); | ||
76 | switch (value) { | 68 | switch (value) { |
77 | case 0: | 69 | case 0: |
78 | retval = rpaphp_set_attention_status(slot, LED_OFF); | ||
79 | hotplug_slot->info->attention_status = 0; | ||
80 | break; | ||
81 | case 1: | 70 | case 1: |
82 | default: | ||
83 | retval = rpaphp_set_attention_status(slot, LED_ON); | ||
84 | hotplug_slot->info->attention_status = 1; | ||
85 | break; | ||
86 | case 2: | 71 | case 2: |
87 | retval = rpaphp_set_attention_status(slot, LED_ID); | 72 | break; |
88 | hotplug_slot->info->attention_status = 2; | 73 | default: |
74 | value = 1; | ||
89 | break; | 75 | break; |
90 | } | 76 | } |
91 | up(&rpaphp_sem); | 77 | |
92 | return retval; | 78 | rc = rtas_set_indicator(DR_INDICATOR, slot->index, value); |
79 | if (!rc) | ||
80 | hotplug_slot->info->attention_status = value; | ||
81 | |||
82 | return rc; | ||
93 | } | 83 | } |
94 | 84 | ||
95 | /** | 85 | /** |
96 | * get_power_status - get power status of a slot | 86 | * get_power_status - get power status of a slot |
97 | * @hotplug_slot: slot to get status | 87 | * @hotplug_slot: slot to get status |
98 | * @value: pointer to store status | 88 | * @value: pointer to store status |
99 | * | ||
100 | * | ||
101 | */ | 89 | */ |
102 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) | 90 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) |
103 | { | 91 | { |
104 | int retval; | 92 | int retval, level; |
105 | struct slot *slot = (struct slot *)hotplug_slot->private; | 93 | struct slot *slot = (struct slot *)hotplug_slot->private; |
106 | 94 | ||
107 | down(&rpaphp_sem); | 95 | retval = rtas_get_power_level (slot->power_domain, &level); |
108 | retval = rpaphp_get_power_status(slot, value); | 96 | if (!retval) |
109 | up(&rpaphp_sem); | 97 | *value = level; |
110 | return retval; | 98 | return retval; |
111 | } | 99 | } |
112 | 100 | ||
113 | /** | 101 | /** |
114 | * get_attention_status - get attention LED status | 102 | * get_attention_status - get attention LED status |
115 | * | ||
116 | * | ||
117 | */ | 103 | */ |
118 | static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) | 104 | static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) |
119 | { | 105 | { |
120 | int retval = 0; | ||
121 | struct slot *slot = (struct slot *)hotplug_slot->private; | 106 | struct slot *slot = (struct slot *)hotplug_slot->private; |
122 | 107 | *value = slot->hotplug_slot->info->attention_status; | |
123 | down(&rpaphp_sem); | 108 | return 0; |
124 | *value = rpaphp_get_attention_status(slot); | ||
125 | up(&rpaphp_sem); | ||
126 | return retval; | ||
127 | } | 109 | } |
128 | 110 | ||
129 | static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) | 111 | static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) |
130 | { | 112 | { |
131 | struct slot *slot = (struct slot *)hotplug_slot->private; | 113 | struct slot *slot = (struct slot *)hotplug_slot->private; |
132 | int retval = 0; | 114 | int rc, state; |
133 | 115 | ||
134 | down(&rpaphp_sem); | 116 | rc = rpaphp_get_sensor_state(slot, &state); |
135 | retval = rpaphp_get_pci_adapter_status(slot, 0, value); | 117 | |
136 | up(&rpaphp_sem); | 118 | *value = NOT_VALID; |
137 | return retval; | 119 | if (rc) |
120 | return rc; | ||
121 | |||
122 | if (state == EMPTY) | ||
123 | *value = EMPTY; | ||
124 | else if (state == PRESENT) | ||
125 | *value = slot->state; | ||
126 | |||
127 | return 0; | ||
138 | } | 128 | } |
139 | 129 | ||
140 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) | 130 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) |
141 | { | 131 | { |
142 | struct slot *slot = (struct slot *)hotplug_slot->private; | 132 | struct slot *slot = (struct slot *)hotplug_slot->private; |
143 | 133 | ||
144 | down(&rpaphp_sem); | ||
145 | switch (slot->type) { | 134 | switch (slot->type) { |
146 | case 1: | 135 | case 1: |
147 | case 2: | 136 | case 2: |
@@ -172,7 +161,6 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe | |||
172 | break; | 161 | break; |
173 | 162 | ||
174 | } | 163 | } |
175 | up(&rpaphp_sem); | ||
176 | return 0; | 164 | return 0; |
177 | } | 165 | } |
178 | 166 | ||
@@ -265,6 +253,14 @@ static int is_php_type(char *drc_type) | |||
265 | return 1; | 253 | return 1; |
266 | } | 254 | } |
267 | 255 | ||
256 | /** | ||
257 | * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0 | ||
258 | * | ||
259 | * This routine will return true only if the device node is | ||
260 | * a hotpluggable slot. This routine will return false | ||
261 | * for built-in pci slots (even when the built-in slots are | ||
262 | * dlparable.) | ||
263 | */ | ||
268 | static int is_php_dn(struct device_node *dn, const int **indexes, | 264 | static int is_php_dn(struct device_node *dn, const int **indexes, |
269 | const int **names, const int **types, const int **power_domains) | 265 | const int **names, const int **types, const int **power_domains) |
270 | { | 266 | { |
@@ -272,24 +268,31 @@ static int is_php_dn(struct device_node *dn, const int **indexes, | |||
272 | int rc; | 268 | int rc; |
273 | 269 | ||
274 | rc = get_children_props(dn, indexes, names, &drc_types, power_domains); | 270 | rc = get_children_props(dn, indexes, names, &drc_types, power_domains); |
275 | if (rc >= 0) { | 271 | if (rc < 0) |
276 | if (is_php_type((char *) &drc_types[1])) { | 272 | return 0; |
277 | *types = drc_types; | ||
278 | return 1; | ||
279 | } | ||
280 | } | ||
281 | 273 | ||
282 | return 0; | 274 | if (!is_php_type((char *) &drc_types[1])) |
275 | return 0; | ||
276 | |||
277 | *types = drc_types; | ||
278 | return 1; | ||
283 | } | 279 | } |
284 | 280 | ||
285 | /** | 281 | /** |
286 | * rpaphp_add_slot -- add hotplug or dlpar slot | 282 | * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem. |
283 | * @dn device node of slot | ||
284 | * | ||
285 | * This subroutine will register a hotplugable slot with the | ||
286 | * PCI hotplug infrastructure. This routine is typicaly called | ||
287 | * during boot time, if the hotplug slots are present at boot time, | ||
288 | * or is called later, by the dlpar add code, if the slot is | ||
289 | * being dynamically added during runtime. | ||
290 | * | ||
291 | * If the device node points at an embedded (built-in) slot, this | ||
292 | * routine will just return without doing anything, since embedded | ||
293 | * slots cannot be hotplugged. | ||
287 | * | 294 | * |
288 | * rpaphp not only registers PCI hotplug slots(HOTPLUG), | 295 | * To remove a slot, it suffices to call rpaphp_deregister_slot() |
289 | * but also logical DR slots(EMBEDDED). | ||
290 | * HOTPLUG slot: An adapter can be physically added/removed. | ||
291 | * EMBEDDED slot: An adapter can be logically removed/added | ||
292 | * from/to a partition with the slot. | ||
293 | */ | 296 | */ |
294 | int rpaphp_add_slot(struct device_node *dn) | 297 | int rpaphp_add_slot(struct device_node *dn) |
295 | { | 298 | { |
@@ -299,34 +302,42 @@ int rpaphp_add_slot(struct device_node *dn) | |||
299 | const int *indexes, *names, *types, *power_domains; | 302 | const int *indexes, *names, *types, *power_domains; |
300 | char *name, *type; | 303 | char *name, *type; |
301 | 304 | ||
305 | if (!dn->name || strcmp(dn->name, "pci")) | ||
306 | return 0; | ||
307 | |||
308 | /* If this is not a hotplug slot, return without doing anything. */ | ||
309 | if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) | ||
310 | return 0; | ||
311 | |||
302 | dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name); | 312 | dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name); |
303 | 313 | ||
304 | /* register PCI devices */ | 314 | /* register PCI devices */ |
305 | if (dn->name != 0 && strcmp(dn->name, "pci") == 0) { | 315 | name = (char *) &names[1]; |
306 | if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) | 316 | type = (char *) &types[1]; |
307 | goto exit; | 317 | for (i = 0; i < indexes[0]; i++) { |
308 | 318 | ||
309 | name = (char *) &names[1]; | 319 | slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]); |
310 | type = (char *) &types[1]; | 320 | if (!slot) |
311 | for (i = 0; i < indexes[0]; i++, | 321 | return -ENOMEM; |
312 | name += (strlen(name) + 1), type += (strlen(type) + 1)) { | 322 | |
313 | 323 | slot->type = simple_strtoul(type, NULL, 10); | |
314 | if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name, | ||
315 | power_domains[i + 1]))) { | ||
316 | retval = -ENOMEM; | ||
317 | goto exit; | ||
318 | } | ||
319 | slot->type = simple_strtoul(type, NULL, 10); | ||
320 | 324 | ||
321 | dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", | 325 | dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", |
322 | indexes[i + 1], name, type); | 326 | indexes[i + 1], name, type); |
323 | 327 | ||
324 | retval = rpaphp_register_pci_slot(slot); | 328 | retval = rpaphp_enable_slot(slot); |
325 | } | 329 | if (!retval) |
330 | retval = rpaphp_register_slot(slot); | ||
331 | |||
332 | if (retval) | ||
333 | dealloc_slot_struct(slot); | ||
334 | |||
335 | name += strlen(name) + 1; | ||
336 | type += strlen(type) + 1; | ||
326 | } | 337 | } |
327 | exit: | 338 | dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); |
328 | dbg("%s - Exit: num_slots=%d rc[%d]\n", | 339 | |
329 | __FUNCTION__, num_slots, retval); | 340 | /* XXX FIXME: reports a failure only if last entry in loop failed */ |
330 | return retval; | 341 | return retval; |
331 | } | 342 | } |
332 | 343 | ||
@@ -354,7 +365,6 @@ static int __init rpaphp_init(void) | |||
354 | struct device_node *dn = NULL; | 365 | struct device_node *dn = NULL; |
355 | 366 | ||
356 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 367 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
357 | init_MUTEX(&rpaphp_sem); | ||
358 | 368 | ||
359 | while ((dn = of_find_node_by_name(dn, "pci"))) | 369 | while ((dn = of_find_node_by_name(dn, "pci"))) |
360 | rpaphp_add_slot(dn); | 370 | rpaphp_add_slot(dn); |
@@ -367,8 +377,9 @@ static void __exit rpaphp_exit(void) | |||
367 | cleanup_slots(); | 377 | cleanup_slots(); |
368 | } | 378 | } |
369 | 379 | ||
370 | static int __enable_slot(struct slot *slot) | 380 | static int enable_slot(struct hotplug_slot *hotplug_slot) |
371 | { | 381 | { |
382 | struct slot *slot = (struct slot *)hotplug_slot->private; | ||
372 | int state; | 383 | int state; |
373 | int retval; | 384 | int retval; |
374 | 385 | ||
@@ -392,46 +403,17 @@ static int __enable_slot(struct slot *slot) | |||
392 | return 0; | 403 | return 0; |
393 | } | 404 | } |
394 | 405 | ||
395 | static int enable_slot(struct hotplug_slot *hotplug_slot) | 406 | static int disable_slot(struct hotplug_slot *hotplug_slot) |
396 | { | 407 | { |
397 | int retval; | ||
398 | struct slot *slot = (struct slot *)hotplug_slot->private; | 408 | struct slot *slot = (struct slot *)hotplug_slot->private; |
399 | |||
400 | down(&rpaphp_sem); | ||
401 | retval = __enable_slot(slot); | ||
402 | up(&rpaphp_sem); | ||
403 | |||
404 | return retval; | ||
405 | } | ||
406 | |||
407 | static int __disable_slot(struct slot *slot) | ||
408 | { | ||
409 | struct pci_dev *dev, *tmp; | ||
410 | |||
411 | if (slot->state == NOT_CONFIGURED) | 409 | if (slot->state == NOT_CONFIGURED) |
412 | return -EINVAL; | 410 | return -EINVAL; |
413 | 411 | ||
414 | list_for_each_entry_safe(dev, tmp, &slot->bus->devices, bus_list) { | 412 | pcibios_remove_pci_devices(slot->bus); |
415 | eeh_remove_bus_device(dev); | ||
416 | pci_remove_bus_device(dev); | ||
417 | } | ||
418 | |||
419 | slot->state = NOT_CONFIGURED; | 413 | slot->state = NOT_CONFIGURED; |
420 | return 0; | 414 | return 0; |
421 | } | 415 | } |
422 | 416 | ||
423 | static int disable_slot(struct hotplug_slot *hotplug_slot) | ||
424 | { | ||
425 | struct slot *slot = (struct slot *)hotplug_slot->private; | ||
426 | int retval; | ||
427 | |||
428 | down(&rpaphp_sem); | ||
429 | retval = __disable_slot (slot); | ||
430 | up(&rpaphp_sem); | ||
431 | |||
432 | return retval; | ||
433 | } | ||
434 | |||
435 | struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { | 417 | struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { |
436 | .owner = THIS_MODULE, | 418 | .owner = THIS_MODULE, |
437 | .enable_slot = enable_slot, | 419 | .enable_slot = enable_slot, |
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 6f6cbede5135..54ca8650d511 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c | |||
@@ -64,75 +64,6 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state) | |||
64 | return rc; | 64 | return rc; |
65 | } | 65 | } |
66 | 66 | ||
67 | /** | ||
68 | * get_pci_adapter_status - get the status of a slot | ||
69 | * | ||
70 | * 0-- slot is empty | ||
71 | * 1-- adapter is configured | ||
72 | * 2-- adapter is not configured | ||
73 | * 3-- not valid | ||
74 | */ | ||
75 | int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value) | ||
76 | { | ||
77 | struct pci_bus *bus; | ||
78 | int state, rc; | ||
79 | |||
80 | *value = NOT_VALID; | ||
81 | rc = rpaphp_get_sensor_state(slot, &state); | ||
82 | if (rc) | ||
83 | goto exit; | ||
84 | |||
85 | if (state == EMPTY) | ||
86 | *value = EMPTY; | ||
87 | else if (state == PRESENT) { | ||
88 | if (!is_init) { | ||
89 | /* at run-time slot->state can be changed by */ | ||
90 | /* config/unconfig adapter */ | ||
91 | *value = slot->state; | ||
92 | } else { | ||
93 | bus = pcibios_find_pci_bus(slot->dn); | ||
94 | if (bus && !list_empty(&bus->devices)) | ||
95 | *value = CONFIGURED; | ||
96 | else | ||
97 | *value = NOT_CONFIGURED; | ||
98 | } | ||
99 | } | ||
100 | exit: | ||
101 | return rc; | ||
102 | } | ||
103 | |||
104 | static void print_slot_pci_funcs(struct pci_bus *bus) | ||
105 | { | ||
106 | struct device_node *dn; | ||
107 | struct pci_dev *dev; | ||
108 | |||
109 | dn = pci_bus_to_OF_node(bus); | ||
110 | if (!dn) | ||
111 | return; | ||
112 | |||
113 | dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name); | ||
114 | list_for_each_entry (dev, &bus->devices, bus_list) | ||
115 | dbg("\t%s\n", pci_name(dev)); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | static int setup_pci_hotplug_slot_info(struct slot *slot) | ||
120 | { | ||
121 | struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info; | ||
122 | |||
123 | dbg("%s Initilize the PCI slot's hotplug->info structure ...\n", | ||
124 | __FUNCTION__); | ||
125 | rpaphp_get_power_status(slot, &hotplug_slot_info->power_status); | ||
126 | rpaphp_get_pci_adapter_status(slot, 1, | ||
127 | &hotplug_slot_info->adapter_status); | ||
128 | if (hotplug_slot_info->adapter_status == NOT_VALID) { | ||
129 | err("%s: NOT_VALID: skip dn->full_name=%s\n", | ||
130 | __FUNCTION__, slot->dn->full_name); | ||
131 | return -EINVAL; | ||
132 | } | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static void set_slot_name(struct slot *slot) | 67 | static void set_slot_name(struct slot *slot) |
137 | { | 68 | { |
138 | struct pci_bus *bus = slot->bus; | 69 | struct pci_bus *bus = slot->bus; |
@@ -146,69 +77,73 @@ static void set_slot_name(struct slot *slot) | |||
146 | bus->number); | 77 | bus->number); |
147 | } | 78 | } |
148 | 79 | ||
149 | static int setup_pci_slot(struct slot *slot) | 80 | /** |
81 | * rpaphp_enable_slot - record slot state, config pci device | ||
82 | * | ||
83 | * Initialize values in the slot, and the hotplug_slot info | ||
84 | * structures to indicate if there is a pci card plugged into | ||
85 | * the slot. If the slot is not empty, run the pcibios routine | ||
86 | * to get pcibios stuff correctly set up. | ||
87 | */ | ||
88 | int rpaphp_enable_slot(struct slot *slot) | ||
150 | { | 89 | { |
151 | struct device_node *dn = slot->dn; | 90 | int rc, level, state; |
152 | struct pci_bus *bus; | 91 | struct pci_bus *bus; |
92 | struct hotplug_slot_info *info = slot->hotplug_slot->info; | ||
93 | |||
94 | info->adapter_status = NOT_VALID; | ||
95 | slot->state = EMPTY; | ||
96 | |||
97 | /* Find out if the power is turned on for the slot */ | ||
98 | rc = rtas_get_power_level(slot->power_domain, &level); | ||
99 | if (rc) | ||
100 | return rc; | ||
101 | info->power_status = level; | ||
102 | |||
103 | /* Figure out if there is an adapter in the slot */ | ||
104 | rc = rpaphp_get_sensor_state(slot, &state); | ||
105 | if (rc) | ||
106 | return rc; | ||
153 | 107 | ||
154 | BUG_ON(!dn); | 108 | bus = pcibios_find_pci_bus(slot->dn); |
155 | bus = pcibios_find_pci_bus(dn); | ||
156 | if (!bus) { | 109 | if (!bus) { |
157 | err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name); | 110 | err("%s: no pci_bus for dn %s\n", __FUNCTION__, slot->dn->full_name); |
158 | goto exit_rc; | 111 | return -EINVAL; |
159 | } | 112 | } |
160 | 113 | ||
114 | info->adapter_status = EMPTY; | ||
161 | slot->bus = bus; | 115 | slot->bus = bus; |
162 | slot->pci_devs = &bus->devices; | 116 | slot->pci_devs = &bus->devices; |
163 | set_slot_name(slot); | 117 | set_slot_name(slot); |
164 | 118 | ||
165 | /* find slot's pci_dev if it's not empty */ | 119 | /* if there's an adapter in the slot, go add the pci devices */ |
166 | if (slot->hotplug_slot->info->adapter_status == EMPTY) { | 120 | if (state == PRESENT) { |
167 | slot->state = EMPTY; /* slot is empty */ | 121 | info->adapter_status = NOT_CONFIGURED; |
168 | } else { | 122 | slot->state = NOT_CONFIGURED; |
169 | /* slot is occupied */ | 123 | |
170 | if (!dn->child) { | 124 | /* non-empty slot has to have child */ |
171 | /* non-empty slot has to have child */ | 125 | if (!slot->dn->child) { |
172 | err("%s: slot[%s]'s device_node doesn't have child for adapter\n", | 126 | err("%s: slot[%s]'s device_node doesn't have child for adapter\n", |
173 | __FUNCTION__, slot->name); | 127 | __FUNCTION__, slot->name); |
174 | goto exit_rc; | 128 | return -EINVAL; |
175 | } | 129 | } |
176 | 130 | ||
177 | if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) { | 131 | if (list_empty(&bus->devices)) |
178 | dbg("%s CONFIGURING pci adapter in slot[%s]\n", | 132 | pcibios_add_pci_devices(bus); |
179 | __FUNCTION__, slot->name); | ||
180 | pcibios_add_pci_devices(slot->bus); | ||
181 | 133 | ||
182 | } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) { | 134 | if (!list_empty(&bus->devices)) { |
183 | err("%s: slot[%s]'s adapter_status is NOT_VALID.\n", | 135 | info->adapter_status = CONFIGURED; |
184 | __FUNCTION__, slot->name); | ||
185 | goto exit_rc; | ||
186 | } | ||
187 | print_slot_pci_funcs(slot->bus); | ||
188 | if (!list_empty(slot->pci_devs)) { | ||
189 | slot->state = CONFIGURED; | 136 | slot->state = CONFIGURED; |
190 | } else { | 137 | } |
191 | /* DLPAR add as opposed to | 138 | |
192 | * boot time */ | 139 | if (debug) { |
193 | slot->state = NOT_CONFIGURED; | 140 | struct pci_dev *dev; |
141 | dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, slot->dn->full_name); | ||
142 | list_for_each_entry (dev, &bus->devices, bus_list) | ||
143 | dbg("\t%s\n", pci_name(dev)); | ||
194 | } | 144 | } |
195 | } | 145 | } |
196 | return 0; | ||
197 | exit_rc: | ||
198 | dealloc_slot_struct(slot); | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | 146 | ||
202 | int rpaphp_register_pci_slot(struct slot *slot) | 147 | return 0; |
203 | { | ||
204 | int rc = -EINVAL; | ||
205 | |||
206 | if (setup_pci_hotplug_slot_info(slot)) | ||
207 | goto exit_rc; | ||
208 | if (setup_pci_slot(slot)) | ||
209 | goto exit_rc; | ||
210 | rc = rpaphp_register_slot(slot); | ||
211 | exit_rc: | ||
212 | return rc; | ||
213 | } | 148 | } |
214 | 149 | ||
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 3009193f0058..d4ee8723fcb3 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c | |||
@@ -56,7 +56,6 @@ static struct hotplug_slot_attribute php_attr_location = { | |||
56 | static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) | 56 | static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) |
57 | { | 57 | { |
58 | struct slot *slot = (struct slot *) hotplug_slot->private; | 58 | struct slot *slot = (struct slot *) hotplug_slot->private; |
59 | |||
60 | dealloc_slot_struct(slot); | 59 | dealloc_slot_struct(slot); |
61 | } | 60 | } |
62 | 61 | ||
@@ -65,12 +64,12 @@ void dealloc_slot_struct(struct slot *slot) | |||
65 | kfree(slot->hotplug_slot->info); | 64 | kfree(slot->hotplug_slot->info); |
66 | kfree(slot->hotplug_slot->name); | 65 | kfree(slot->hotplug_slot->name); |
67 | kfree(slot->hotplug_slot); | 66 | kfree(slot->hotplug_slot); |
67 | kfree(slot->location); | ||
68 | kfree(slot); | 68 | kfree(slot); |
69 | return; | ||
70 | } | 69 | } |
71 | 70 | ||
72 | struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, | 71 | struct slot *alloc_slot_struct(struct device_node *dn, |
73 | int power_domain) | 72 | int drc_index, char *drc_name, int power_domain) |
74 | { | 73 | { |
75 | struct slot *slot; | 74 | struct slot *slot; |
76 | 75 | ||
@@ -115,7 +114,7 @@ error_nomem: | |||
115 | 114 | ||
116 | static int is_registered(struct slot *slot) | 115 | static int is_registered(struct slot *slot) |
117 | { | 116 | { |
118 | struct slot *tmp_slot; | 117 | struct slot *tmp_slot; |
119 | 118 | ||
120 | list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) { | 119 | list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) { |
121 | if (!strcmp(tmp_slot->name, slot->name)) | 120 | if (!strcmp(tmp_slot->name, slot->name)) |
@@ -140,8 +139,6 @@ int rpaphp_deregister_slot(struct slot *slot) | |||
140 | retval = pci_hp_deregister(php_slot); | 139 | retval = pci_hp_deregister(php_slot); |
141 | if (retval) | 140 | if (retval) |
142 | err("Problem unregistering a slot %s\n", slot->name); | 141 | err("Problem unregistering a slot %s\n", slot->name); |
143 | else | ||
144 | num_slots--; | ||
145 | 142 | ||
146 | dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); | 143 | dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); |
147 | return retval; | 144 | return retval; |
@@ -160,14 +157,13 @@ int rpaphp_register_slot(struct slot *slot) | |||
160 | /* should not try to register the same slot twice */ | 157 | /* should not try to register the same slot twice */ |
161 | if (is_registered(slot)) { | 158 | if (is_registered(slot)) { |
162 | err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name); | 159 | err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name); |
163 | retval = -EAGAIN; | 160 | return -EAGAIN; |
164 | goto register_fail; | ||
165 | } | 161 | } |
166 | 162 | ||
167 | retval = pci_hp_register(php_slot); | 163 | retval = pci_hp_register(php_slot); |
168 | if (retval) { | 164 | if (retval) { |
169 | err("pci_hp_register failed with error %d\n", retval); | 165 | err("pci_hp_register failed with error %d\n", retval); |
170 | goto register_fail; | 166 | return retval; |
171 | } | 167 | } |
172 | 168 | ||
173 | /* create "phy_location" file */ | 169 | /* create "phy_location" file */ |
@@ -181,43 +177,10 @@ int rpaphp_register_slot(struct slot *slot) | |||
181 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); | 177 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); |
182 | info("Slot [%s](PCI location=%s) registered\n", slot->name, | 178 | info("Slot [%s](PCI location=%s) registered\n", slot->name, |
183 | slot->location); | 179 | slot->location); |
184 | num_slots++; | ||
185 | return 0; | 180 | return 0; |
186 | 181 | ||
187 | sysfs_fail: | 182 | sysfs_fail: |
188 | pci_hp_deregister(php_slot); | 183 | pci_hp_deregister(php_slot); |
189 | register_fail: | ||
190 | rpaphp_release_slot(php_slot); | ||
191 | return retval; | 184 | return retval; |
192 | } | 185 | } |
193 | 186 | ||
194 | int rpaphp_get_power_status(struct slot *slot, u8 * value) | ||
195 | { | ||
196 | int rc = 0, level; | ||
197 | |||
198 | rc = rtas_get_power_level(slot->power_domain, &level); | ||
199 | if (rc < 0) { | ||
200 | err("failed to get power-level for slot(%s), rc=0x%x\n", | ||
201 | slot->location, rc); | ||
202 | return rc; | ||
203 | } | ||
204 | |||
205 | dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n", | ||
206 | __FUNCTION__, slot->name, slot->power_domain, level); | ||
207 | *value = level; | ||
208 | |||
209 | return rc; | ||
210 | } | ||
211 | |||
212 | int rpaphp_set_attention_status(struct slot *slot, u8 status) | ||
213 | { | ||
214 | int rc; | ||
215 | |||
216 | /* status: LED_OFF or LED_ON */ | ||
217 | rc = rtas_set_indicator(DR_INDICATOR, slot->index, status); | ||
218 | if (rc < 0) | ||
219 | err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n", | ||
220 | slot->name, slot->location, slot->index, status, rc); | ||
221 | |||
222 | return rc; | ||
223 | } | ||
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 01d31a1f697c..37ed0884b972 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h | |||
@@ -166,7 +166,7 @@ extern u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl); | |||
166 | extern int shpchp_configure_device(struct slot *p_slot); | 166 | extern int shpchp_configure_device(struct slot *p_slot); |
167 | extern int shpchp_unconfigure_device(struct slot *p_slot); | 167 | extern int shpchp_unconfigure_device(struct slot *p_slot); |
168 | extern void cleanup_slots(struct controller *ctrl); | 168 | extern void cleanup_slots(struct controller *ctrl); |
169 | extern void queue_pushbutton_work(struct work_struct *work); | 169 | extern void shpchp_queue_pushbutton_work(struct work_struct *work); |
170 | extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); | 170 | extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); |
171 | 171 | ||
172 | #ifdef CONFIG_ACPI | 172 | #ifdef CONFIG_ACPI |
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 5f4bc08a633a..80dec9796b31 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
@@ -136,7 +136,7 @@ static int init_slots(struct controller *ctrl) | |||
136 | slot->hpc_ops = ctrl->hpc_ops; | 136 | slot->hpc_ops = ctrl->hpc_ops; |
137 | slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); | 137 | slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); |
138 | mutex_init(&slot->lock); | 138 | mutex_init(&slot->lock); |
139 | INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work); | 139 | INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work); |
140 | 140 | ||
141 | /* register this slot with the hotplug pci core */ | 141 | /* register this slot with the hotplug pci core */ |
142 | hotplug_slot->private = slot; | 142 | hotplug_slot->private = slot; |
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index b746bd265bc6..2c94d44279a3 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
@@ -433,7 +433,7 @@ static void shpchp_pushbutton_thread(struct work_struct *work) | |||
433 | kfree(info); | 433 | kfree(info); |
434 | } | 434 | } |
435 | 435 | ||
436 | void queue_pushbutton_work(struct work_struct *work) | 436 | void shpchp_queue_pushbutton_work(struct work_struct *work) |
437 | { | 437 | { |
438 | struct slot *p_slot = container_of(work, struct slot, work.work); | 438 | struct slot *p_slot = container_of(work, struct slot, work.work); |
439 | struct pushbutton_work_info *info; | 439 | struct pushbutton_work_info *info; |