diff options
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 30 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 29 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 391 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_pci.c | 349 |
4 files changed, 65 insertions, 734 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index e9c09566f851..3e17e3d4dd65 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -56,25 +56,11 @@ struct hotplug_params { | |||
56 | u8 enable_perr; | 56 | u8 enable_perr; |
57 | }; | 57 | }; |
58 | 58 | ||
59 | struct pci_func { | ||
60 | struct pci_func *next; | ||
61 | u8 bus; | ||
62 | u8 device; | ||
63 | u8 function; | ||
64 | u8 is_a_board; | ||
65 | u16 status; | ||
66 | u8 configured; | ||
67 | u8 switch_save; | ||
68 | u8 presence_save; | ||
69 | u16 reserved2; | ||
70 | u32 config_space[0x20]; | ||
71 | struct pci_dev* pci_dev; | ||
72 | }; | ||
73 | |||
74 | struct slot { | 59 | struct slot { |
75 | struct slot *next; | 60 | struct slot *next; |
76 | u8 bus; | 61 | u8 bus; |
77 | u8 device; | 62 | u8 device; |
63 | u16 status; | ||
78 | u32 number; | 64 | u32 number; |
79 | u8 is_a_board; | 65 | u8 is_a_board; |
80 | u8 configured; | 66 | u8 configured; |
@@ -177,9 +163,6 @@ struct controller { | |||
177 | * error Messages | 163 | * error Messages |
178 | */ | 164 | */ |
179 | #define msg_initialization_err "Initialization failure, error=%d\n" | 165 | #define msg_initialization_err "Initialization failure, error=%d\n" |
180 | #define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" | ||
181 | #define msg_HPC_non_pcie "The PCI hot plug controller is not supported by this driver.\n" | ||
182 | #define msg_HPC_not_supported "This system is not supported by this version of pciephd module. Upgrade to a newer version of pciehpd\n" | ||
183 | #define msg_button_on "PCI slot #%d - powering on due to button press.\n" | 166 | #define msg_button_on "PCI slot #%d - powering on due to button press.\n" |
184 | #define msg_button_off "PCI slot #%d - powering off due to button press.\n" | 167 | #define msg_button_off "PCI slot #%d - powering off due to button press.\n" |
185 | #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" | 168 | #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" |
@@ -188,8 +171,6 @@ struct controller { | |||
188 | /* controller functions */ | 171 | /* controller functions */ |
189 | extern int pciehp_event_start_thread (void); | 172 | extern int pciehp_event_start_thread (void); |
190 | extern void pciehp_event_stop_thread (void); | 173 | extern void pciehp_event_stop_thread (void); |
191 | extern struct pci_func *pciehp_slot_create (unsigned char busnumber); | ||
192 | extern struct pci_func *pciehp_slot_find (unsigned char bus, unsigned char device, unsigned char index); | ||
193 | extern int pciehp_enable_slot (struct slot *slot); | 174 | extern int pciehp_enable_slot (struct slot *slot); |
194 | extern int pciehp_disable_slot (struct slot *slot); | 175 | extern int pciehp_disable_slot (struct slot *slot); |
195 | 176 | ||
@@ -200,12 +181,8 @@ extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id); | |||
200 | /* extern void long_delay (int delay); */ | 181 | /* extern void long_delay (int delay); */ |
201 | 182 | ||
202 | /* pci functions */ | 183 | /* pci functions */ |
203 | extern int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); | 184 | extern int pciehp_configure_device (struct slot *p_slot); |
204 | /*extern int pciehp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/ | 185 | extern int pciehp_unconfigure_device (struct slot *p_slot); |
205 | extern int pciehp_save_config (struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); | ||
206 | extern int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); | ||
207 | extern int pciehp_configure_device (struct slot *ctrl); | ||
208 | extern int pciehp_unconfigure_device (struct pci_func* func); | ||
209 | extern int get_hp_hw_control_from_firmware(struct pci_dev *dev); | 186 | extern int get_hp_hw_control_from_firmware(struct pci_dev *dev); |
210 | extern void get_hp_params_from_firmware(struct pci_dev *dev, | 187 | extern void get_hp_params_from_firmware(struct pci_dev *dev, |
211 | struct hotplug_params *hpp); | 188 | struct hotplug_params *hpp); |
@@ -214,7 +191,6 @@ extern void get_hp_params_from_firmware(struct pci_dev *dev, | |||
214 | 191 | ||
215 | /* Global variables */ | 192 | /* Global variables */ |
216 | extern struct controller *pciehp_ctrl_list; | 193 | extern struct controller *pciehp_ctrl_list; |
217 | extern struct pci_func *pciehp_slot_list[256]; | ||
218 | 194 | ||
219 | /* Inline functions */ | 195 | /* Inline functions */ |
220 | 196 | ||
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index e20cf8e42bd9..be608563e8b6 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -46,7 +46,6 @@ int pciehp_debug; | |||
46 | int pciehp_poll_mode; | 46 | int pciehp_poll_mode; |
47 | int pciehp_poll_time; | 47 | int pciehp_poll_time; |
48 | struct controller *pciehp_ctrl_list; | 48 | struct controller *pciehp_ctrl_list; |
49 | struct pci_func *pciehp_slot_list[256]; | ||
50 | 49 | ||
51 | #define DRIVER_VERSION "0.4" | 50 | #define DRIVER_VERSION "0.4" |
52 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" | 51 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" |
@@ -422,15 +421,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
422 | first_device_num = ctrl->slot_device_offset; | 421 | first_device_num = ctrl->slot_device_offset; |
423 | num_ctlr_slots = ctrl->num_slots; | 422 | num_ctlr_slots = ctrl->num_slots; |
424 | 423 | ||
425 | /* Store PCI Config Space for all devices on this bus */ | ||
426 | dbg("%s: Before calling pciehp_save_config, ctrl->bus %x,ctrl->slot_bus %x\n", | ||
427 | __FUNCTION__,ctrl->bus, ctrl->slot_bus); | ||
428 | rc = pciehp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num); | ||
429 | if (rc) { | ||
430 | err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); | ||
431 | goto err_out_free_ctrl_bus; | ||
432 | } | ||
433 | |||
434 | ctrl->add_support = 1; | 424 | ctrl->add_support = 1; |
435 | 425 | ||
436 | /* Setup the slot information structures */ | 426 | /* Setup the slot information structures */ |
@@ -491,7 +481,6 @@ err_out_none: | |||
491 | 481 | ||
492 | static int pcie_start_thread(void) | 482 | static int pcie_start_thread(void) |
493 | { | 483 | { |
494 | int loop; | ||
495 | int retval = 0; | 484 | int retval = 0; |
496 | 485 | ||
497 | dbg("Initialize + Start the notification/polling mechanism \n"); | 486 | dbg("Initialize + Start the notification/polling mechanism \n"); |
@@ -502,20 +491,11 @@ static int pcie_start_thread(void) | |||
502 | return retval; | 491 | return retval; |
503 | } | 492 | } |
504 | 493 | ||
505 | dbg("Initialize slot lists\n"); | ||
506 | /* One slot list for each bus in the system */ | ||
507 | for (loop = 0; loop < 256; loop++) { | ||
508 | pciehp_slot_list[loop] = NULL; | ||
509 | } | ||
510 | |||
511 | return retval; | 494 | return retval; |
512 | } | 495 | } |
513 | 496 | ||
514 | static void __exit unload_pciehpd(void) | 497 | static void __exit unload_pciehpd(void) |
515 | { | 498 | { |
516 | struct pci_func *next; | ||
517 | struct pci_func *TempSlot; | ||
518 | int loop; | ||
519 | struct controller *ctrl; | 499 | struct controller *ctrl; |
520 | struct controller *tctrl; | 500 | struct controller *tctrl; |
521 | 501 | ||
@@ -534,15 +514,6 @@ static void __exit unload_pciehpd(void) | |||
534 | kfree(tctrl); | 514 | kfree(tctrl); |
535 | } | 515 | } |
536 | 516 | ||
537 | for (loop = 0; loop < 256; loop++) { | ||
538 | next = pciehp_slot_list[loop]; | ||
539 | while (next != NULL) { | ||
540 | TempSlot = next; | ||
541 | next = next->next; | ||
542 | kfree(TempSlot); | ||
543 | } | ||
544 | } | ||
545 | |||
546 | /* Stop the notification mechanism */ | 517 | /* Stop the notification mechanism */ |
547 | pciehp_event_stop_thread(); | 518 | pciehp_event_stop_thread(); |
548 | 519 | ||
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index d07d4194bc29..b60e4973289c 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c | |||
@@ -55,19 +55,16 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) | |||
55 | struct slot *p_slot; | 55 | struct slot *p_slot; |
56 | u8 rc = 0; | 56 | u8 rc = 0; |
57 | u8 getstatus; | 57 | u8 getstatus; |
58 | struct pci_func *func; | ||
59 | struct event_info *taskInfo; | 58 | struct event_info *taskInfo; |
60 | 59 | ||
61 | /* Attention Button Change */ | 60 | /* Attention Button Change */ |
62 | dbg("pciehp: Attention button interrupt received.\n"); | 61 | dbg("pciehp: Attention button interrupt received.\n"); |
63 | 62 | ||
64 | func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
65 | |||
66 | /* This is the structure that tells the worker thread what to do */ | 63 | /* This is the structure that tells the worker thread what to do */ |
67 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | 64 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); |
68 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 65 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
69 | 66 | ||
70 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | 67 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
71 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 68 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
72 | 69 | ||
73 | ctrl->next_event = (ctrl->next_event + 1) % 10; | 70 | ctrl->next_event = (ctrl->next_event + 1) % 10; |
@@ -112,14 +109,11 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
112 | struct slot *p_slot; | 109 | struct slot *p_slot; |
113 | u8 rc = 0; | 110 | u8 rc = 0; |
114 | u8 getstatus; | 111 | u8 getstatus; |
115 | struct pci_func *func; | ||
116 | struct event_info *taskInfo; | 112 | struct event_info *taskInfo; |
117 | 113 | ||
118 | /* Switch Change */ | 114 | /* Switch Change */ |
119 | dbg("pciehp: Switch interrupt received.\n"); | 115 | dbg("pciehp: Switch interrupt received.\n"); |
120 | 116 | ||
121 | func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
122 | |||
123 | /* This is the structure that tells the worker thread | 117 | /* This is the structure that tells the worker thread |
124 | * what to do | 118 | * what to do |
125 | */ | 119 | */ |
@@ -129,7 +123,7 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
129 | 123 | ||
130 | rc++; | 124 | rc++; |
131 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 125 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
132 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | 126 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
133 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 127 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
134 | 128 | ||
135 | if (getstatus) { | 129 | if (getstatus) { |
@@ -137,14 +131,14 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
137 | * Switch opened | 131 | * Switch opened |
138 | */ | 132 | */ |
139 | info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); | 133 | info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); |
140 | func->switch_save = 0; | 134 | p_slot->switch_save = 0; |
141 | taskInfo->event_type = INT_SWITCH_OPEN; | 135 | taskInfo->event_type = INT_SWITCH_OPEN; |
142 | } else { | 136 | } else { |
143 | /* | 137 | /* |
144 | * Switch closed | 138 | * Switch closed |
145 | */ | 139 | */ |
146 | info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); | 140 | info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); |
147 | func->switch_save = 0x10; | 141 | p_slot->switch_save = 0x10; |
148 | taskInfo->event_type = INT_SWITCH_CLOSE; | 142 | taskInfo->event_type = INT_SWITCH_CLOSE; |
149 | } | 143 | } |
150 | 144 | ||
@@ -159,14 +153,11 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) | |||
159 | struct controller *ctrl = (struct controller *) inst_id; | 153 | struct controller *ctrl = (struct controller *) inst_id; |
160 | struct slot *p_slot; | 154 | struct slot *p_slot; |
161 | u8 rc = 0; | 155 | u8 rc = 0; |
162 | struct pci_func *func; | ||
163 | struct event_info *taskInfo; | 156 | struct event_info *taskInfo; |
164 | 157 | ||
165 | /* Presence Change */ | 158 | /* Presence Change */ |
166 | dbg("pciehp: Presence/Notify input change.\n"); | 159 | dbg("pciehp: Presence/Notify input change.\n"); |
167 | 160 | ||
168 | func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
169 | |||
170 | /* This is the structure that tells the worker thread | 161 | /* This is the structure that tells the worker thread |
171 | * what to do | 162 | * what to do |
172 | */ | 163 | */ |
@@ -180,8 +171,8 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) | |||
180 | /* Switch is open, assume a presence change | 171 | /* Switch is open, assume a presence change |
181 | * Save the presence state | 172 | * Save the presence state |
182 | */ | 173 | */ |
183 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | 174 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
184 | if (func->presence_save) { | 175 | if (p_slot->presence_save) { |
185 | /* | 176 | /* |
186 | * Card Present | 177 | * Card Present |
187 | */ | 178 | */ |
@@ -206,14 +197,11 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
206 | struct controller *ctrl = (struct controller *) inst_id; | 197 | struct controller *ctrl = (struct controller *) inst_id; |
207 | struct slot *p_slot; | 198 | struct slot *p_slot; |
208 | u8 rc = 0; | 199 | u8 rc = 0; |
209 | struct pci_func *func; | ||
210 | struct event_info *taskInfo; | 200 | struct event_info *taskInfo; |
211 | 201 | ||
212 | /* power fault */ | 202 | /* power fault */ |
213 | dbg("pciehp: Power fault interrupt received.\n"); | 203 | dbg("pciehp: Power fault interrupt received.\n"); |
214 | 204 | ||
215 | func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
216 | |||
217 | /* this is the structure that tells the worker thread | 205 | /* this is the structure that tells the worker thread |
218 | * what to do | 206 | * what to do |
219 | */ | 207 | */ |
@@ -229,7 +217,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
229 | * power fault Cleared | 217 | * power fault Cleared |
230 | */ | 218 | */ |
231 | info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); | 219 | info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); |
232 | func->status = 0x00; | 220 | p_slot->status = 0x00; |
233 | taskInfo->event_type = INT_POWER_FAULT_CLEAR; | 221 | taskInfo->event_type = INT_POWER_FAULT_CLEAR; |
234 | } else { | 222 | } else { |
235 | /* | 223 | /* |
@@ -238,7 +226,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
238 | info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); | 226 | info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); |
239 | taskInfo->event_type = INT_POWER_FAULT; | 227 | taskInfo->event_type = INT_POWER_FAULT; |
240 | /* set power fault status for this board */ | 228 | /* set power fault status for this board */ |
241 | func->status = 0xFF; | 229 | p_slot->status = 0xFF; |
242 | info("power fault bit %x set\n", hp_slot); | 230 | info("power fault bit %x set\n", hp_slot); |
243 | } | 231 | } |
244 | if (rc) | 232 | if (rc) |
@@ -247,187 +235,6 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
247 | return rc; | 235 | return rc; |
248 | } | 236 | } |
249 | 237 | ||
250 | /** | ||
251 | * pciehp_slot_create - Creates a node and adds it to the proper bus. | ||
252 | * @busnumber - bus where new node is to be located | ||
253 | * | ||
254 | * Returns pointer to the new node or NULL if unsuccessful | ||
255 | */ | ||
256 | struct pci_func *pciehp_slot_create(u8 busnumber) | ||
257 | { | ||
258 | struct pci_func *new_slot; | ||
259 | struct pci_func *next; | ||
260 | dbg("%s: busnumber %x\n", __FUNCTION__, busnumber); | ||
261 | new_slot = kmalloc(sizeof(struct pci_func), GFP_KERNEL); | ||
262 | |||
263 | if (new_slot == NULL) | ||
264 | return new_slot; | ||
265 | |||
266 | memset(new_slot, 0, sizeof(struct pci_func)); | ||
267 | |||
268 | new_slot->next = NULL; | ||
269 | new_slot->configured = 1; | ||
270 | |||
271 | if (pciehp_slot_list[busnumber] == NULL) { | ||
272 | pciehp_slot_list[busnumber] = new_slot; | ||
273 | } else { | ||
274 | next = pciehp_slot_list[busnumber]; | ||
275 | while (next->next != NULL) | ||
276 | next = next->next; | ||
277 | next->next = new_slot; | ||
278 | } | ||
279 | return new_slot; | ||
280 | } | ||
281 | |||
282 | |||
283 | /** | ||
284 | * slot_remove - Removes a node from the linked list of slots. | ||
285 | * @old_slot: slot to remove | ||
286 | * | ||
287 | * Returns 0 if successful, !0 otherwise. | ||
288 | */ | ||
289 | static int slot_remove(struct pci_func * old_slot) | ||
290 | { | ||
291 | struct pci_func *next; | ||
292 | |||
293 | if (old_slot == NULL) | ||
294 | return 1; | ||
295 | |||
296 | next = pciehp_slot_list[old_slot->bus]; | ||
297 | |||
298 | if (next == NULL) | ||
299 | return 1; | ||
300 | |||
301 | if (next == old_slot) { | ||
302 | pciehp_slot_list[old_slot->bus] = old_slot->next; | ||
303 | kfree(old_slot); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | while ((next->next != old_slot) && (next->next != NULL)) { | ||
308 | next = next->next; | ||
309 | } | ||
310 | |||
311 | if (next->next == old_slot) { | ||
312 | next->next = old_slot->next; | ||
313 | kfree(old_slot); | ||
314 | return 0; | ||
315 | } else | ||
316 | return 2; | ||
317 | } | ||
318 | |||
319 | |||
320 | /** | ||
321 | * bridge_slot_remove - Removes a node from the linked list of slots. | ||
322 | * @bridge: bridge to remove | ||
323 | * | ||
324 | * Returns 0 if successful, !0 otherwise. | ||
325 | */ | ||
326 | static int bridge_slot_remove(struct pci_func *bridge) | ||
327 | { | ||
328 | u8 subordinateBus, secondaryBus; | ||
329 | u8 tempBus; | ||
330 | struct pci_func *next; | ||
331 | |||
332 | if (bridge == NULL) | ||
333 | return 1; | ||
334 | |||
335 | secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; | ||
336 | subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; | ||
337 | |||
338 | for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { | ||
339 | next = pciehp_slot_list[tempBus]; | ||
340 | |||
341 | while (!slot_remove(next)) { | ||
342 | next = pciehp_slot_list[tempBus]; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | next = pciehp_slot_list[bridge->bus]; | ||
347 | |||
348 | if (next == NULL) { | ||
349 | return 1; | ||
350 | } | ||
351 | |||
352 | if (next == bridge) { | ||
353 | pciehp_slot_list[bridge->bus] = bridge->next; | ||
354 | kfree(bridge); | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | while ((next->next != bridge) && (next->next != NULL)) { | ||
359 | next = next->next; | ||
360 | } | ||
361 | |||
362 | if (next->next == bridge) { | ||
363 | next->next = bridge->next; | ||
364 | kfree(bridge); | ||
365 | return 0; | ||
366 | } else | ||
367 | return 2; | ||
368 | } | ||
369 | |||
370 | |||
371 | /** | ||
372 | * pciehp_slot_find - Looks for a node by bus, and device, multiple functions accessed | ||
373 | * @bus: bus to find | ||
374 | * @device: device to find | ||
375 | * @index: is 0 for first function found, 1 for the second... | ||
376 | * | ||
377 | * Returns pointer to the node if successful, %NULL otherwise. | ||
378 | */ | ||
379 | struct pci_func *pciehp_slot_find(u8 bus, u8 device, u8 index) | ||
380 | { | ||
381 | int found = -1; | ||
382 | struct pci_func *func; | ||
383 | |||
384 | func = pciehp_slot_list[bus]; | ||
385 | dbg("%s: bus %x device %x index %x\n", | ||
386 | __FUNCTION__, bus, device, index); | ||
387 | if (func != NULL) { | ||
388 | dbg("%s: func-> bus %x device %x function %x pci_dev %p\n", | ||
389 | __FUNCTION__, func->bus, func->device, func->function, | ||
390 | func->pci_dev); | ||
391 | } else | ||
392 | dbg("%s: func == NULL\n", __FUNCTION__); | ||
393 | |||
394 | if ((func == NULL) || ((func->device == device) && (index == 0))) | ||
395 | return func; | ||
396 | |||
397 | if (func->device == device) | ||
398 | found++; | ||
399 | |||
400 | while (func->next != NULL) { | ||
401 | func = func->next; | ||
402 | |||
403 | dbg("%s: In while loop, func-> bus %x device %x function %x pci_dev %p\n", | ||
404 | __FUNCTION__, func->bus, func->device, func->function, | ||
405 | func->pci_dev); | ||
406 | if (func->device == device) | ||
407 | found++; | ||
408 | dbg("%s: while loop, found %d, index %d\n", __FUNCTION__, | ||
409 | found, index); | ||
410 | |||
411 | if ((found == index) || (func->function == index)) { | ||
412 | dbg("%s: Found bus %x dev %x func %x\n", __FUNCTION__, | ||
413 | func->bus, func->device, func->function); | ||
414 | return func; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | return NULL; | ||
419 | } | ||
420 | |||
421 | static int is_bridge(struct pci_func * func) | ||
422 | { | ||
423 | /* Check the header type */ | ||
424 | if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) | ||
425 | return 1; | ||
426 | else | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | |||
431 | /* The following routines constitute the bulk of the | 238 | /* The following routines constitute the bulk of the |
432 | hotplug controller logic | 239 | hotplug controller logic |
433 | */ | 240 | */ |
@@ -472,17 +279,16 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) | |||
472 | * Configures board | 279 | * Configures board |
473 | * | 280 | * |
474 | */ | 281 | */ |
475 | static u32 board_added(struct pci_func * func, struct controller * ctrl) | 282 | static u32 board_added(struct slot *p_slot) |
476 | { | 283 | { |
477 | u8 hp_slot; | 284 | u8 hp_slot; |
478 | u32 temp_register = 0xFFFFFFFF; | 285 | u32 temp_register = 0xFFFFFFFF; |
479 | u32 rc = 0; | 286 | u32 rc = 0; |
480 | struct slot *p_slot; | 287 | struct controller *ctrl = p_slot->ctrl; |
481 | 288 | ||
482 | p_slot = pciehp_find_slot(ctrl, func->device); | 289 | hp_slot = p_slot->device - ctrl->slot_device_offset; |
483 | hp_slot = func->device - ctrl->slot_device_offset; | ||
484 | 290 | ||
485 | dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); | 291 | dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, p_slot->device, ctrl->slot_device_offset, hp_slot); |
486 | 292 | ||
487 | /* Wait for exclusive access to hardware */ | 293 | /* Wait for exclusive access to hardware */ |
488 | down(&ctrl->crit_sect); | 294 | down(&ctrl->crit_sect); |
@@ -522,15 +328,15 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) | |||
522 | return rc; | 328 | return rc; |
523 | } | 329 | } |
524 | 330 | ||
525 | dbg("%s: func status = %x\n", __FUNCTION__, func->status); | 331 | dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); |
526 | 332 | ||
527 | /* Check for a power fault */ | 333 | /* Check for a power fault */ |
528 | if (func->status == 0xFF) { | 334 | if (p_slot->status == 0xFF) { |
529 | /* power fault occurred, but it was benign */ | 335 | /* power fault occurred, but it was benign */ |
530 | temp_register = 0xFFFFFFFF; | 336 | temp_register = 0xFFFFFFFF; |
531 | dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); | 337 | dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); |
532 | rc = POWER_FAILURE; | 338 | rc = POWER_FAILURE; |
533 | func->status = 0; | 339 | p_slot->status = 0; |
534 | goto err_exit; | 340 | goto err_exit; |
535 | } | 341 | } |
536 | 342 | ||
@@ -541,10 +347,9 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) | |||
541 | goto err_exit; | 347 | goto err_exit; |
542 | } | 348 | } |
543 | 349 | ||
544 | pciehp_save_slot_config(ctrl, func); | 350 | p_slot->status = 0; |
545 | func->status = 0; | 351 | p_slot->switch_save = 0x10; |
546 | func->switch_save = 0x10; | 352 | p_slot->is_a_board = 0x01; |
547 | func->is_a_board = 0x01; | ||
548 | 353 | ||
549 | /* | 354 | /* |
550 | * Some PCI Express root ports require fixup after hot-plug operation. | 355 | * Some PCI Express root ports require fixup after hot-plug operation. |
@@ -575,30 +380,27 @@ err_exit: | |||
575 | * remove_board - Turns off slot and LED's | 380 | * remove_board - Turns off slot and LED's |
576 | * | 381 | * |
577 | */ | 382 | */ |
578 | static u32 remove_board(struct pci_func *func, struct controller *ctrl) | 383 | static u32 remove_board(struct slot *p_slot) |
579 | { | 384 | { |
580 | u8 device; | 385 | u8 device; |
581 | u8 hp_slot; | 386 | u8 hp_slot; |
582 | u32 rc; | 387 | u32 rc; |
583 | struct slot *p_slot; | 388 | struct controller *ctrl = p_slot->ctrl; |
584 | |||
585 | if (func == NULL) | ||
586 | return 1; | ||
587 | 389 | ||
588 | if (pciehp_unconfigure_device(func)) | 390 | if (pciehp_unconfigure_device(p_slot)) |
589 | return 1; | 391 | return 1; |
590 | 392 | ||
591 | device = func->device; | 393 | device = p_slot->device; |
592 | 394 | ||
593 | hp_slot = func->device - ctrl->slot_device_offset; | 395 | hp_slot = p_slot->device - ctrl->slot_device_offset; |
594 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 396 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
595 | 397 | ||
596 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); | 398 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); |
597 | 399 | ||
598 | /* Change status to shutdown */ | 400 | /* Change status to shutdown */ |
599 | if (func->is_a_board) | 401 | if (p_slot->is_a_board) |
600 | func->status = 0x01; | 402 | p_slot->status = 0x01; |
601 | func->configured = 0; | 403 | p_slot->configured = 0; |
602 | 404 | ||
603 | /* Wait for exclusive access to hardware */ | 405 | /* Wait for exclusive access to hardware */ |
604 | down(&ctrl->crit_sect); | 406 | down(&ctrl->crit_sect); |
@@ -626,35 +428,8 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) | |||
626 | /* Done with exclusive hardware access */ | 428 | /* Done with exclusive hardware access */ |
627 | up(&ctrl->crit_sect); | 429 | up(&ctrl->crit_sect); |
628 | 430 | ||
629 | if (ctrl->add_support) { | 431 | p_slot->switch_save = 0x10; |
630 | while (func) { | 432 | p_slot->is_a_board = 0; |
631 | if (is_bridge(func)) { | ||
632 | dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", | ||
633 | ctrl->seg, func->bus, func->device, func->function); | ||
634 | bridge_slot_remove(func); | ||
635 | } else { | ||
636 | dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", | ||
637 | ctrl->seg, func->bus, func->device, func->function); | ||
638 | slot_remove(func); | ||
639 | } | ||
640 | |||
641 | func = pciehp_slot_find(ctrl->slot_bus, device, 0); | ||
642 | } | ||
643 | |||
644 | /* Setup slot structure with entry for empty slot */ | ||
645 | func = pciehp_slot_create(ctrl->slot_bus); | ||
646 | |||
647 | if (func == NULL) { | ||
648 | return 1; | ||
649 | } | ||
650 | |||
651 | func->bus = ctrl->slot_bus; | ||
652 | func->device = device; | ||
653 | func->function = 0; | ||
654 | func->configured = 0; | ||
655 | func->switch_save = 0x10; | ||
656 | func->is_a_board = 0; | ||
657 | } | ||
658 | 433 | ||
659 | return 0; | 434 | return 0; |
660 | } | 435 | } |
@@ -851,7 +626,6 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
851 | { | 626 | { |
852 | int loop = 0; | 627 | int loop = 0; |
853 | int change = 1; | 628 | int change = 1; |
854 | struct pci_func *func; | ||
855 | u8 hp_slot; | 629 | u8 hp_slot; |
856 | u8 getstatus; | 630 | u8 getstatus; |
857 | struct slot *p_slot; | 631 | struct slot *p_slot; |
@@ -863,11 +637,9 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
863 | if (ctrl->event_queue[loop].event_type != 0) { | 637 | if (ctrl->event_queue[loop].event_type != 0) { |
864 | hp_slot = ctrl->event_queue[loop].hp_slot; | 638 | hp_slot = ctrl->event_queue[loop].hp_slot; |
865 | 639 | ||
866 | func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
867 | |||
868 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 640 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
869 | 641 | ||
870 | dbg("hp_slot %d, func %p, p_slot %p\n", hp_slot, func, p_slot); | 642 | dbg("hp_slot %d, p_slot %p\n", hp_slot, p_slot); |
871 | 643 | ||
872 | if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { | 644 | if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { |
873 | dbg("button cancel\n"); | 645 | dbg("button cancel\n"); |
@@ -1015,13 +787,6 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
1015 | { | 787 | { |
1016 | u8 getstatus = 0; | 788 | u8 getstatus = 0; |
1017 | int rc; | 789 | int rc; |
1018 | struct pci_func *func; | ||
1019 | |||
1020 | func = pciehp_slot_find(p_slot->bus, p_slot->device, 0); | ||
1021 | if (!func) { | ||
1022 | dbg("%s: Error! slot NULL\n", __FUNCTION__); | ||
1023 | return 1; | ||
1024 | } | ||
1025 | 790 | ||
1026 | /* Check to see if (latch closed, card present, power off) */ | 791 | /* Check to see if (latch closed, card present, power off) */ |
1027 | down(&p_slot->ctrl->crit_sect); | 792 | down(&p_slot->ctrl->crit_sect); |
@@ -1051,45 +816,21 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
1051 | } | 816 | } |
1052 | up(&p_slot->ctrl->crit_sect); | 817 | up(&p_slot->ctrl->crit_sect); |
1053 | 818 | ||
1054 | slot_remove(func); | 819 | p_slot->configured = 0; |
1055 | 820 | p_slot->is_a_board = 1; | |
1056 | func = pciehp_slot_create(p_slot->bus); | ||
1057 | if (func == NULL) | ||
1058 | return 1; | ||
1059 | |||
1060 | func->bus = p_slot->bus; | ||
1061 | func->device = p_slot->device; | ||
1062 | func->function = 0; | ||
1063 | func->configured = 0; | ||
1064 | func->is_a_board = 1; | ||
1065 | 821 | ||
1066 | /* We have to save the presence info for these slots */ | 822 | /* We have to save the presence info for these slots */ |
1067 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | 823 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
1068 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 824 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
1069 | func->switch_save = !getstatus? 0x10:0; | 825 | p_slot->switch_save = !getstatus? 0x10:0; |
1070 | 826 | ||
1071 | rc = board_added(func, p_slot->ctrl); | 827 | rc = board_added(p_slot); |
1072 | if (rc) { | 828 | if (rc) { |
1073 | if (is_bridge(func)) | ||
1074 | bridge_slot_remove(func); | ||
1075 | else | ||
1076 | slot_remove(func); | ||
1077 | |||
1078 | /* Setup slot structure with entry for empty slot */ | ||
1079 | func = pciehp_slot_create(p_slot->bus); | ||
1080 | if (func == NULL) | ||
1081 | return 1; /* Out of memory */ | ||
1082 | |||
1083 | func->bus = p_slot->bus; | ||
1084 | func->device = p_slot->device; | ||
1085 | func->function = 0; | ||
1086 | func->configured = 0; | ||
1087 | func->is_a_board = 1; | ||
1088 | |||
1089 | /* We have to save the presence info for these slots */ | 829 | /* We have to save the presence info for these slots */ |
1090 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | 830 | p_slot->hpc_ops->get_adapter_status(p_slot, |
831 | &(p_slot->presence_save)); | ||
1091 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 832 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
1092 | func->switch_save = !getstatus? 0x10:0; | 833 | p_slot->switch_save = !getstatus? 0x10:0; |
1093 | } | 834 | } |
1094 | 835 | ||
1095 | if (p_slot) | 836 | if (p_slot) |
@@ -1101,14 +842,8 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
1101 | 842 | ||
1102 | int pciehp_disable_slot(struct slot *p_slot) | 843 | int pciehp_disable_slot(struct slot *p_slot) |
1103 | { | 844 | { |
1104 | u8 class_code, header_type, BCR; | ||
1105 | u8 index = 0; | ||
1106 | u8 getstatus = 0; | 845 | u8 getstatus = 0; |
1107 | u32 rc = 0; | ||
1108 | int ret = 0; | 846 | int ret = 0; |
1109 | unsigned int devfn; | ||
1110 | struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate; | ||
1111 | struct pci_func *func; | ||
1112 | 847 | ||
1113 | if (!p_slot->ctrl) | 848 | if (!p_slot->ctrl) |
1114 | return 1; | 849 | return 1; |
@@ -1145,54 +880,8 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
1145 | 880 | ||
1146 | up(&p_slot->ctrl->crit_sect); | 881 | up(&p_slot->ctrl->crit_sect); |
1147 | 882 | ||
1148 | func = pciehp_slot_find(p_slot->bus, p_slot->device, index++); | 883 | ret = remove_board(p_slot); |
1149 | 884 | update_slot_info(p_slot); | |
1150 | /* Make sure there are no video controllers here | 885 | return ret; |
1151 | * for all func of p_slot | ||
1152 | */ | ||
1153 | while (func && !rc) { | ||
1154 | pci_bus->number = func->bus; | ||
1155 | devfn = PCI_DEVFN(func->device, func->function); | ||
1156 | |||
1157 | /* Check the Class Code */ | ||
1158 | rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); | ||
1159 | if (rc) | ||
1160 | return rc; | ||
1161 | |||
1162 | if (class_code == PCI_BASE_CLASS_DISPLAY) { | ||
1163 | /* Display/Video adapter (not supported) */ | ||
1164 | rc = REMOVE_NOT_SUPPORTED; | ||
1165 | } else { | ||
1166 | /* See if it's a bridge */ | ||
1167 | rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); | ||
1168 | if (rc) | ||
1169 | return rc; | ||
1170 | |||
1171 | /* If it's a bridge, check the VGA Enable bit */ | ||
1172 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { | ||
1173 | rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); | ||
1174 | if (rc) | ||
1175 | return rc; | ||
1176 | |||
1177 | /* If the VGA Enable bit is set, remove isn't supported */ | ||
1178 | if (BCR & PCI_BRIDGE_CTL_VGA) { | ||
1179 | rc = REMOVE_NOT_SUPPORTED; | ||
1180 | } | ||
1181 | } | ||
1182 | } | ||
1183 | |||
1184 | func = pciehp_slot_find(p_slot->bus, p_slot->device, index++); | ||
1185 | } | ||
1186 | |||
1187 | func = pciehp_slot_find(p_slot->bus, p_slot->device, 0); | ||
1188 | if ((func != NULL) && !rc) { | ||
1189 | rc = remove_board(func, p_slot->ctrl); | ||
1190 | } else if (!rc) | ||
1191 | rc = 1; | ||
1192 | |||
1193 | if (p_slot) | ||
1194 | update_slot_info(p_slot); | ||
1195 | |||
1196 | return rc; | ||
1197 | } | 886 | } |
1198 | 887 | ||
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index db59a06ab0b4..1d185c1bc77a 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c | |||
@@ -101,346 +101,41 @@ int pciehp_configure_device(struct slot *p_slot) | |||
101 | return 0; | 101 | return 0; |
102 | } | 102 | } |
103 | 103 | ||
104 | int pciehp_unconfigure_device(struct pci_func* func) | 104 | int pciehp_unconfigure_device(struct slot *p_slot) |
105 | { | 105 | { |
106 | int rc = 0; | 106 | int rc = 0; |
107 | int j; | 107 | int j; |
108 | struct pci_bus *pbus; | 108 | u8 bctl = 0; |
109 | 109 | ||
110 | dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, | 110 | dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, |
111 | func->device, func->function); | 111 | p_slot->device); |
112 | pbus = func->pci_dev->bus; | ||
113 | 112 | ||
114 | for (j=0; j<8 ; j++) { | 113 | for (j=0; j<8 ; j++) { |
115 | struct pci_dev* temp = pci_find_slot(func->bus, | 114 | struct pci_dev* temp = pci_find_slot(p_slot->bus, |
116 | (func->device << 3) | j); | 115 | (p_slot->device << 3) | j); |
117 | if (temp) { | 116 | if (!temp) |
118 | pci_remove_bus_device(temp); | 117 | continue; |
118 | if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { | ||
119 | err("Cannot remove display device %s\n", | ||
120 | pci_name(temp)); | ||
121 | continue; | ||
122 | } | ||
123 | if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
124 | pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); | ||
125 | if (bctl & PCI_BRIDGE_CTL_VGA) { | ||
126 | err("Cannot remove display device %s\n", | ||
127 | pci_name(temp)); | ||
128 | continue; | ||
129 | } | ||
119 | } | 130 | } |
131 | pci_remove_bus_device(temp); | ||
120 | } | 132 | } |
121 | /* | 133 | /* |
122 | * Some PCI Express root ports require fixup after hot-plug operation. | 134 | * Some PCI Express root ports require fixup after hot-plug operation. |
123 | */ | 135 | */ |
124 | if (pcie_mch_quirk) | 136 | if (pcie_mch_quirk) |
125 | pci_fixup_device(pci_fixup_final, pbus->self); | 137 | pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev); |
126 | 138 | ||
127 | return rc; | 139 | return rc; |
128 | } | 140 | } |
129 | 141 | ||
130 | /* | ||
131 | * pciehp_save_config | ||
132 | * | ||
133 | * Reads configuration for all slots in a PCI bus and saves info. | ||
134 | * | ||
135 | * Note: For non-hot plug busses, the slot # saved is the device # | ||
136 | * | ||
137 | * returns 0 if success | ||
138 | */ | ||
139 | int pciehp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num) | ||
140 | { | ||
141 | int rc; | ||
142 | u8 class_code; | ||
143 | u8 header_type; | ||
144 | u32 ID; | ||
145 | u8 secondary_bus; | ||
146 | struct pci_func *new_slot; | ||
147 | int sub_bus; | ||
148 | int max_functions; | ||
149 | int function; | ||
150 | u8 DevError; | ||
151 | int device = 0; | ||
152 | int cloop = 0; | ||
153 | int stop_it; | ||
154 | int index; | ||
155 | int is_hot_plug = num_ctlr_slots || first_device_num; | ||
156 | struct pci_bus lpci_bus, *pci_bus; | ||
157 | int FirstSupported, LastSupported; | ||
158 | |||
159 | dbg("%s: Enter\n", __FUNCTION__); | ||
160 | |||
161 | memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); | ||
162 | pci_bus = &lpci_bus; | ||
163 | |||
164 | dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, | ||
165 | num_ctlr_slots, first_device_num); | ||
166 | |||
167 | /* Decide which slots are supported */ | ||
168 | if (is_hot_plug) { | ||
169 | /********************************* | ||
170 | * is_hot_plug is the slot mask | ||
171 | *********************************/ | ||
172 | FirstSupported = first_device_num; | ||
173 | LastSupported = FirstSupported + num_ctlr_slots - 1; | ||
174 | } else { | ||
175 | FirstSupported = 0; | ||
176 | LastSupported = 0x1F; | ||
177 | } | ||
178 | |||
179 | dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, | ||
180 | LastSupported); | ||
181 | |||
182 | /* Save PCI configuration space for all devices in supported slots */ | ||
183 | dbg("%s: pci_bus->number = %x\n", __FUNCTION__, pci_bus->number); | ||
184 | pci_bus->number = busnumber; | ||
185 | dbg("%s: bus = %x, dev = %x\n", __FUNCTION__, busnumber, device); | ||
186 | for (device = FirstSupported; device <= LastSupported; device++) { | ||
187 | ID = 0xFFFFFFFF; | ||
188 | rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), | ||
189 | PCI_VENDOR_ID, &ID); | ||
190 | |||
191 | if (ID != 0xFFFFFFFF) { /* device in slot */ | ||
192 | dbg("%s: ID = %x\n", __FUNCTION__, ID); | ||
193 | rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), | ||
194 | 0x0B, &class_code); | ||
195 | if (rc) | ||
196 | return rc; | ||
197 | |||
198 | rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), | ||
199 | PCI_HEADER_TYPE, &header_type); | ||
200 | if (rc) | ||
201 | return rc; | ||
202 | |||
203 | dbg("class_code = %x, header_type = %x\n", class_code, header_type); | ||
204 | |||
205 | /* If multi-function device, set max_functions to 8 */ | ||
206 | if (header_type & 0x80) | ||
207 | max_functions = 8; | ||
208 | else | ||
209 | max_functions = 1; | ||
210 | |||
211 | function = 0; | ||
212 | |||
213 | do { | ||
214 | DevError = 0; | ||
215 | dbg("%s: In do loop\n", __FUNCTION__); | ||
216 | |||
217 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* P-P Bridge */ | ||
218 | /* Recurse the subordinate bus | ||
219 | * get the subordinate bus number | ||
220 | */ | ||
221 | rc = pci_bus_read_config_byte(pci_bus, | ||
222 | PCI_DEVFN(device, function), | ||
223 | PCI_SECONDARY_BUS, &secondary_bus); | ||
224 | if (rc) { | ||
225 | return rc; | ||
226 | } else { | ||
227 | sub_bus = (int) secondary_bus; | ||
228 | |||
229 | /* Save secondary bus cfg spc with this recursive call. */ | ||
230 | rc = pciehp_save_config(ctrl, sub_bus, 0, 0); | ||
231 | if (rc) | ||
232 | return rc; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | index = 0; | ||
237 | new_slot = pciehp_slot_find(busnumber, device, index++); | ||
238 | |||
239 | dbg("%s: new_slot = %p bus %x dev %x fun %x\n", | ||
240 | __FUNCTION__, new_slot, busnumber, device, index-1); | ||
241 | |||
242 | while (new_slot && (new_slot->function != (u8) function)) { | ||
243 | new_slot = pciehp_slot_find(busnumber, device, index++); | ||
244 | dbg("%s: while loop, new_slot = %p bus %x dev %x fun %x\n", | ||
245 | __FUNCTION__, new_slot, busnumber, device, index-1); | ||
246 | } | ||
247 | if (!new_slot) { | ||
248 | /* Setup slot structure. */ | ||
249 | new_slot = pciehp_slot_create(busnumber); | ||
250 | dbg("%s: if, new_slot = %p bus %x dev %x fun %x\n", | ||
251 | __FUNCTION__, new_slot, busnumber, device, function); | ||
252 | |||
253 | if (new_slot == NULL) | ||
254 | return(1); | ||
255 | } | ||
256 | |||
257 | new_slot->bus = (u8) busnumber; | ||
258 | new_slot->device = (u8) device; | ||
259 | new_slot->function = (u8) function; | ||
260 | new_slot->is_a_board = 1; | ||
261 | new_slot->switch_save = 0x10; | ||
262 | /* In case of unsupported board */ | ||
263 | new_slot->status = DevError; | ||
264 | new_slot->pci_dev = pci_find_slot(new_slot->bus, | ||
265 | (new_slot->device << 3) | new_slot->function); | ||
266 | dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev); | ||
267 | |||
268 | for (cloop = 0; cloop < 0x20; cloop++) { | ||
269 | rc = pci_bus_read_config_dword(pci_bus, | ||
270 | PCI_DEVFN(device, function), | ||
271 | cloop << 2, | ||
272 | (u32 *) &(new_slot->config_space [cloop])); | ||
273 | /* dbg("new_slot->config_space[%x] = %x\n", | ||
274 | cloop, new_slot->config_space[cloop]); */ | ||
275 | if (rc) | ||
276 | return rc; | ||
277 | } | ||
278 | |||
279 | function++; | ||
280 | |||
281 | stop_it = 0; | ||
282 | |||
283 | /* this loop skips to the next present function | ||
284 | * reading in Class Code and Header type. | ||
285 | */ | ||
286 | |||
287 | while ((function < max_functions)&&(!stop_it)) { | ||
288 | dbg("%s: In while loop \n", __FUNCTION__); | ||
289 | rc = pci_bus_read_config_dword(pci_bus, | ||
290 | PCI_DEVFN(device, function), | ||
291 | PCI_VENDOR_ID, &ID); | ||
292 | |||
293 | if (ID == 0xFFFFFFFF) { /* nothing there. */ | ||
294 | function++; | ||
295 | dbg("Nothing there\n"); | ||
296 | } else { /* Something there */ | ||
297 | rc = pci_bus_read_config_byte(pci_bus, | ||
298 | PCI_DEVFN(device, function), | ||
299 | 0x0B, &class_code); | ||
300 | if (rc) | ||
301 | return rc; | ||
302 | |||
303 | rc = pci_bus_read_config_byte(pci_bus, | ||
304 | PCI_DEVFN(device, function), | ||
305 | PCI_HEADER_TYPE, &header_type); | ||
306 | if (rc) | ||
307 | return rc; | ||
308 | |||
309 | dbg("class_code = %x, header_type = %x\n", class_code, header_type); | ||
310 | stop_it++; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | } while (function < max_functions); | ||
315 | /* End of IF (device in slot?) */ | ||
316 | } else if (is_hot_plug) { | ||
317 | /* Setup slot structure with entry for empty slot */ | ||
318 | new_slot = pciehp_slot_create(busnumber); | ||
319 | |||
320 | if (new_slot == NULL) { | ||
321 | return(1); | ||
322 | } | ||
323 | dbg("new_slot = %p, bus = %x, dev = %x, fun = %x\n", new_slot, | ||
324 | new_slot->bus, new_slot->device, new_slot->function); | ||
325 | |||
326 | new_slot->bus = (u8) busnumber; | ||
327 | new_slot->device = (u8) device; | ||
328 | new_slot->function = 0; | ||
329 | new_slot->is_a_board = 0; | ||
330 | new_slot->presence_save = 0; | ||
331 | new_slot->switch_save = 0; | ||
332 | } | ||
333 | } /* End of FOR loop */ | ||
334 | |||
335 | dbg("%s: Exit\n", __FUNCTION__); | ||
336 | return(0); | ||
337 | } | ||
338 | |||
339 | |||
340 | /* | ||
341 | * pciehp_save_slot_config | ||
342 | * | ||
343 | * Saves configuration info for all PCI devices in a given slot | ||
344 | * including subordinate busses. | ||
345 | * | ||
346 | * returns 0 if success | ||
347 | */ | ||
348 | int pciehp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot) | ||
349 | { | ||
350 | int rc; | ||
351 | u8 class_code; | ||
352 | u8 header_type; | ||
353 | u32 ID; | ||
354 | u8 secondary_bus; | ||
355 | int sub_bus; | ||
356 | int max_functions; | ||
357 | int function; | ||
358 | int cloop = 0; | ||
359 | int stop_it; | ||
360 | struct pci_bus lpci_bus, *pci_bus; | ||
361 | memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); | ||
362 | pci_bus = &lpci_bus; | ||
363 | pci_bus->number = new_slot->bus; | ||
364 | |||
365 | ID = 0xFFFFFFFF; | ||
366 | |||
367 | pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), | ||
368 | PCI_VENDOR_ID, &ID); | ||
369 | |||
370 | if (ID != 0xFFFFFFFF) { /* device in slot */ | ||
371 | pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), | ||
372 | 0x0B, &class_code); | ||
373 | |||
374 | pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), | ||
375 | PCI_HEADER_TYPE, &header_type); | ||
376 | |||
377 | if (header_type & 0x80) /* Multi-function device */ | ||
378 | max_functions = 8; | ||
379 | else | ||
380 | max_functions = 1; | ||
381 | |||
382 | function = 0; | ||
383 | |||
384 | do { | ||
385 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ | ||
386 | /* Recurse the subordinate bus */ | ||
387 | pci_bus_read_config_byte(pci_bus, | ||
388 | PCI_DEVFN(new_slot->device, function), | ||
389 | PCI_SECONDARY_BUS, &secondary_bus); | ||
390 | |||
391 | sub_bus = (int) secondary_bus; | ||
392 | |||
393 | /* Save the config headers for the secondary bus. */ | ||
394 | rc = pciehp_save_config(ctrl, sub_bus, 0, 0); | ||
395 | |||
396 | if (rc) | ||
397 | return rc; | ||
398 | |||
399 | } /* End of IF */ | ||
400 | |||
401 | new_slot->status = 0; | ||
402 | |||
403 | for (cloop = 0; cloop < 0x20; cloop++) { | ||
404 | pci_bus_read_config_dword(pci_bus, | ||
405 | PCI_DEVFN(new_slot->device, function), | ||
406 | cloop << 2, | ||
407 | (u32 *) &(new_slot->config_space [cloop])); | ||
408 | } | ||
409 | |||
410 | function++; | ||
411 | |||
412 | stop_it = 0; | ||
413 | |||
414 | /* this loop skips to the next present function | ||
415 | * reading in the Class Code and the Header type. | ||
416 | */ | ||
417 | |||
418 | while ((function < max_functions) && (!stop_it)) { | ||
419 | pci_bus_read_config_dword(pci_bus, | ||
420 | PCI_DEVFN(new_slot->device, function), | ||
421 | PCI_VENDOR_ID, &ID); | ||
422 | |||
423 | if (ID == 0xFFFFFFFF) { /* nothing there. */ | ||
424 | function++; | ||
425 | } else { /* Something there */ | ||
426 | pci_bus_read_config_byte(pci_bus, | ||
427 | PCI_DEVFN(new_slot->device, function), | ||
428 | 0x0B, &class_code); | ||
429 | |||
430 | pci_bus_read_config_byte(pci_bus, | ||
431 | PCI_DEVFN(new_slot->device, function), | ||
432 | PCI_HEADER_TYPE, &header_type); | ||
433 | |||
434 | stop_it++; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | } while (function < max_functions); | ||
439 | } /* End of IF (device in slot?) */ | ||
440 | else { | ||
441 | return 2; | ||
442 | } | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||