diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/shpchp.h | 35 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 20 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 405 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_pci.c | 27 |
4 files changed, 63 insertions, 424 deletions
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 5e99260987e8..052c11f14a79 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h | |||
@@ -52,34 +52,18 @@ extern int shpchp_debug; | |||
52 | #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) | 52 | #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) |
53 | #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) | 53 | #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) |
54 | 54 | ||
55 | struct pci_func { | ||
56 | struct pci_func *next; | ||
57 | u8 bus; | ||
58 | u8 device; | ||
59 | u8 function; | ||
60 | u8 is_a_board; | ||
61 | u16 status; | ||
62 | u8 configured; | ||
63 | u8 switch_save; | ||
64 | u8 presence_save; | ||
65 | u8 pwr_save; | ||
66 | struct pci_dev* pci_dev; | ||
67 | }; | ||
68 | |||
69 | #define SLOT_MAGIC 0x67267321 | 55 | #define SLOT_MAGIC 0x67267321 |
70 | struct slot { | 56 | struct slot { |
71 | u32 magic; | 57 | u32 magic; |
72 | struct slot *next; | 58 | struct slot *next; |
73 | u8 bus; | 59 | u8 bus; |
74 | u8 device; | 60 | u8 device; |
61 | u16 status; | ||
75 | u32 number; | 62 | u32 number; |
76 | u8 is_a_board; | 63 | u8 is_a_board; |
77 | u8 configured; | ||
78 | u8 state; | 64 | u8 state; |
79 | u8 switch_save; | ||
80 | u8 presence_save; | 65 | u8 presence_save; |
81 | u32 capabilities; | 66 | u8 pwr_save; |
82 | u16 reserved2; | ||
83 | struct timer_list task_event; | 67 | struct timer_list task_event; |
84 | u8 hp_slot; | 68 | u8 hp_slot; |
85 | struct controller *ctrl; | 69 | struct controller *ctrl; |
@@ -106,19 +90,14 @@ struct controller { | |||
106 | struct hpc_ops *hpc_ops; | 90 | struct hpc_ops *hpc_ops; |
107 | wait_queue_head_t queue; /* sleep & wake process */ | 91 | wait_queue_head_t queue; /* sleep & wake process */ |
108 | u8 next_event; | 92 | u8 next_event; |
109 | u8 seg; | ||
110 | u8 bus; | 93 | u8 bus; |
111 | u8 device; | 94 | u8 device; |
112 | u8 function; | 95 | u8 function; |
113 | u8 rev; | ||
114 | u8 slot_device_offset; | 96 | u8 slot_device_offset; |
115 | u8 add_support; | 97 | u8 add_support; |
116 | enum pci_bus_speed speed; | 98 | enum pci_bus_speed speed; |
117 | u32 first_slot; /* First physical slot number */ | 99 | u32 first_slot; /* First physical slot number */ |
118 | u8 slot_bus; /* Bus where the slots handled by this controller sit */ | 100 | u8 slot_bus; /* Bus where the slots handled by this controller sit */ |
119 | u8 push_flag; | ||
120 | u16 ctlrcap; | ||
121 | u16 vendor_id; | ||
122 | }; | 101 | }; |
123 | 102 | ||
124 | struct hotplug_params { | 103 | struct hotplug_params { |
@@ -169,13 +148,9 @@ struct hotplug_params { | |||
169 | * error Messages | 148 | * error Messages |
170 | */ | 149 | */ |
171 | #define msg_initialization_err "Initialization failure, error=%d\n" | 150 | #define msg_initialization_err "Initialization failure, error=%d\n" |
172 | #define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" | ||
173 | #define msg_HPC_non_shpc "The PCI hot plug controller is not supported by this driver.\n" | ||
174 | #define msg_HPC_not_supported "This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n" | ||
175 | #define msg_button_on "PCI slot #%d - powering on due to button press.\n" | 151 | #define msg_button_on "PCI slot #%d - powering on due to button press.\n" |
176 | #define msg_button_off "PCI slot #%d - powering off due to button press.\n" | 152 | #define msg_button_off "PCI slot #%d - powering off due to button press.\n" |
177 | #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" | 153 | #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" |
178 | #define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" | ||
179 | 154 | ||
180 | /* sysfs functions for the hotplug controller info */ | 155 | /* sysfs functions for the hotplug controller info */ |
181 | extern void shpchp_create_ctrl_files (struct controller *ctrl); | 156 | extern void shpchp_create_ctrl_files (struct controller *ctrl); |
@@ -183,8 +158,6 @@ extern void shpchp_create_ctrl_files (struct controller *ctrl); | |||
183 | /* controller functions */ | 158 | /* controller functions */ |
184 | extern int shpchp_event_start_thread(void); | 159 | extern int shpchp_event_start_thread(void); |
185 | extern void shpchp_event_stop_thread(void); | 160 | extern void shpchp_event_stop_thread(void); |
186 | extern struct pci_func *shpchp_slot_create(unsigned char busnumber); | ||
187 | extern struct pci_func *shpchp_slot_find(unsigned char bus, unsigned char device, unsigned char index); | ||
188 | extern int shpchp_enable_slot(struct slot *slot); | 161 | extern int shpchp_enable_slot(struct slot *slot); |
189 | extern int shpchp_disable_slot(struct slot *slot); | 162 | extern int shpchp_disable_slot(struct slot *slot); |
190 | 163 | ||
@@ -195,9 +168,8 @@ extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id); | |||
195 | 168 | ||
196 | /* pci functions */ | 169 | /* pci functions */ |
197 | extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); | 170 | extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); |
198 | extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); | ||
199 | extern int shpchp_configure_device(struct slot *p_slot); | 171 | extern int shpchp_configure_device(struct slot *p_slot); |
200 | extern int shpchp_unconfigure_device(struct pci_func* func); | 172 | extern int shpchp_unconfigure_device(struct slot *p_slot); |
201 | extern void get_hp_hw_control_from_firmware(struct pci_dev *dev); | 173 | extern void get_hp_hw_control_from_firmware(struct pci_dev *dev); |
202 | extern void get_hp_params_from_firmware(struct pci_dev *dev, | 174 | extern void get_hp_params_from_firmware(struct pci_dev *dev, |
203 | struct hotplug_params *hpp); | 175 | struct hotplug_params *hpp); |
@@ -207,7 +179,6 @@ extern int shpchprm_get_physical_slot_number(struct controller *ctrl, | |||
207 | 179 | ||
208 | /* Global variables */ | 180 | /* Global variables */ |
209 | extern struct controller *shpchp_ctrl_list; | 181 | extern struct controller *shpchp_ctrl_list; |
210 | extern struct pci_func *shpchp_slot_list[256]; | ||
211 | 182 | ||
212 | struct ctrl_reg { | 183 | struct ctrl_reg { |
213 | volatile u32 base_offset; | 184 | volatile u32 base_offset; |
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 5d4fc28969d0..b54edccbf2cc 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
@@ -45,7 +45,6 @@ int shpchp_debug; | |||
45 | int shpchp_poll_mode; | 45 | int shpchp_poll_mode; |
46 | int shpchp_poll_time; | 46 | int shpchp_poll_time; |
47 | struct controller *shpchp_ctrl_list; /* = NULL */ | 47 | struct controller *shpchp_ctrl_list; /* = NULL */ |
48 | struct pci_func *shpchp_slot_list[256]; | ||
49 | 48 | ||
50 | #define DRIVER_VERSION "0.4" | 49 | #define DRIVER_VERSION "0.4" |
51 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" | 50 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" |
@@ -475,7 +474,6 @@ err_out_none: | |||
475 | 474 | ||
476 | static int shpc_start_thread(void) | 475 | static int shpc_start_thread(void) |
477 | { | 476 | { |
478 | int loop; | ||
479 | int retval = 0; | 477 | int retval = 0; |
480 | 478 | ||
481 | dbg("Initialize + Start the notification/polling mechanism \n"); | 479 | dbg("Initialize + Start the notification/polling mechanism \n"); |
@@ -486,20 +484,11 @@ static int shpc_start_thread(void) | |||
486 | return retval; | 484 | return retval; |
487 | } | 485 | } |
488 | 486 | ||
489 | dbg("Initialize slot lists\n"); | ||
490 | /* One slot list for each bus in the system */ | ||
491 | for (loop = 0; loop < 256; loop++) { | ||
492 | shpchp_slot_list[loop] = NULL; | ||
493 | } | ||
494 | |||
495 | return retval; | 487 | return retval; |
496 | } | 488 | } |
497 | 489 | ||
498 | static void __exit unload_shpchpd(void) | 490 | static void __exit unload_shpchpd(void) |
499 | { | 491 | { |
500 | struct pci_func *next; | ||
501 | struct pci_func *TempSlot; | ||
502 | int loop; | ||
503 | struct controller *ctrl; | 492 | struct controller *ctrl; |
504 | struct controller *tctrl; | 493 | struct controller *tctrl; |
505 | 494 | ||
@@ -519,15 +508,6 @@ static void __exit unload_shpchpd(void) | |||
519 | kfree(tctrl); | 508 | kfree(tctrl); |
520 | } | 509 | } |
521 | 510 | ||
522 | for (loop = 0; loop < 256; loop++) { | ||
523 | next = shpchp_slot_list[loop]; | ||
524 | while (next != NULL) { | ||
525 | TempSlot = next; | ||
526 | next = next->next; | ||
527 | kfree(TempSlot); | ||
528 | } | ||
529 | } | ||
530 | |||
531 | /* Stop the notification mechanism */ | 511 | /* Stop the notification mechanism */ |
532 | shpchp_event_stop_thread(); | 512 | shpchp_event_stop_thread(); |
533 | 513 | ||
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index c55103f3cebd..b6fde3565e55 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
@@ -54,19 +54,16 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) | |||
54 | struct slot *p_slot; | 54 | struct slot *p_slot; |
55 | u8 rc = 0; | 55 | u8 rc = 0; |
56 | u8 getstatus; | 56 | u8 getstatus; |
57 | struct pci_func *func; | ||
58 | struct event_info *taskInfo; | 57 | struct event_info *taskInfo; |
59 | 58 | ||
60 | /* Attention Button Change */ | 59 | /* Attention Button Change */ |
61 | dbg("shpchp: Attention button interrupt received.\n"); | 60 | dbg("shpchp: Attention button interrupt received.\n"); |
62 | 61 | ||
63 | func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
64 | |||
65 | /* This is the structure that tells the worker thread what to do */ | 62 | /* This is the structure that tells the worker thread what to do */ |
66 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); | 63 | taskInfo = &(ctrl->event_queue[ctrl->next_event]); |
67 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 64 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
68 | 65 | ||
69 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | 66 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
70 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 67 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
71 | 68 | ||
72 | ctrl->next_event = (ctrl->next_event + 1) % 10; | 69 | ctrl->next_event = (ctrl->next_event + 1) % 10; |
@@ -111,14 +108,11 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
111 | struct slot *p_slot; | 108 | struct slot *p_slot; |
112 | u8 rc = 0; | 109 | u8 rc = 0; |
113 | u8 getstatus; | 110 | u8 getstatus; |
114 | struct pci_func *func; | ||
115 | struct event_info *taskInfo; | 111 | struct event_info *taskInfo; |
116 | 112 | ||
117 | /* Switch Change */ | 113 | /* Switch Change */ |
118 | dbg("shpchp: Switch interrupt received.\n"); | 114 | dbg("shpchp: Switch interrupt received.\n"); |
119 | 115 | ||
120 | func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
121 | |||
122 | /* This is the structure that tells the worker thread | 116 | /* This is the structure that tells the worker thread |
123 | * what to do | 117 | * what to do |
124 | */ | 118 | */ |
@@ -128,19 +122,18 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
128 | 122 | ||
129 | rc++; | 123 | rc++; |
130 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 124 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
131 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | 125 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
132 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 126 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
133 | dbg("%s: Card present %x Power status %x\n", __FUNCTION__, | 127 | dbg("%s: Card present %x Power status %x\n", __FUNCTION__, |
134 | func->presence_save, func->pwr_save); | 128 | p_slot->presence_save, p_slot->pwr_save); |
135 | 129 | ||
136 | if (getstatus) { | 130 | if (getstatus) { |
137 | /* | 131 | /* |
138 | * Switch opened | 132 | * Switch opened |
139 | */ | 133 | */ |
140 | info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); | 134 | info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); |
141 | func->switch_save = 0; | ||
142 | taskInfo->event_type = INT_SWITCH_OPEN; | 135 | taskInfo->event_type = INT_SWITCH_OPEN; |
143 | if (func->pwr_save && func->presence_save) { | 136 | if (p_slot->pwr_save && p_slot->presence_save) { |
144 | taskInfo->event_type = INT_POWER_FAULT; | 137 | taskInfo->event_type = INT_POWER_FAULT; |
145 | err("Surprise Removal of card\n"); | 138 | err("Surprise Removal of card\n"); |
146 | } | 139 | } |
@@ -149,7 +142,6 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
149 | * Switch closed | 142 | * Switch closed |
150 | */ | 143 | */ |
151 | info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); | 144 | info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); |
152 | func->switch_save = 0x10; | ||
153 | taskInfo->event_type = INT_SWITCH_CLOSE; | 145 | taskInfo->event_type = INT_SWITCH_CLOSE; |
154 | } | 146 | } |
155 | 147 | ||
@@ -165,14 +157,11 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) | |||
165 | struct slot *p_slot; | 157 | struct slot *p_slot; |
166 | u8 rc = 0; | 158 | u8 rc = 0; |
167 | /*u8 temp_byte;*/ | 159 | /*u8 temp_byte;*/ |
168 | struct pci_func *func; | ||
169 | struct event_info *taskInfo; | 160 | struct event_info *taskInfo; |
170 | 161 | ||
171 | /* Presence Change */ | 162 | /* Presence Change */ |
172 | dbg("shpchp: Presence/Notify input change.\n"); | 163 | dbg("shpchp: Presence/Notify input change.\n"); |
173 | 164 | ||
174 | func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
175 | |||
176 | /* This is the structure that tells the worker thread | 165 | /* This is the structure that tells the worker thread |
177 | * what to do | 166 | * what to do |
178 | */ | 167 | */ |
@@ -186,8 +175,8 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) | |||
186 | /* | 175 | /* |
187 | * Save the presence state | 176 | * Save the presence state |
188 | */ | 177 | */ |
189 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | 178 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
190 | if (func->presence_save) { | 179 | if (p_slot->presence_save) { |
191 | /* | 180 | /* |
192 | * Card Present | 181 | * Card Present |
193 | */ | 182 | */ |
@@ -212,14 +201,11 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
212 | struct controller *ctrl = (struct controller *) inst_id; | 201 | struct controller *ctrl = (struct controller *) inst_id; |
213 | struct slot *p_slot; | 202 | struct slot *p_slot; |
214 | u8 rc = 0; | 203 | u8 rc = 0; |
215 | struct pci_func *func; | ||
216 | struct event_info *taskInfo; | 204 | struct event_info *taskInfo; |
217 | 205 | ||
218 | /* Power fault */ | 206 | /* Power fault */ |
219 | dbg("shpchp: Power fault interrupt received.\n"); | 207 | dbg("shpchp: Power fault interrupt received.\n"); |
220 | 208 | ||
221 | func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
222 | |||
223 | /* This is the structure that tells the worker thread | 209 | /* This is the structure that tells the worker thread |
224 | * what to do | 210 | * what to do |
225 | */ | 211 | */ |
@@ -235,7 +221,7 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
235 | * Power fault Cleared | 221 | * Power fault Cleared |
236 | */ | 222 | */ |
237 | info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); | 223 | info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); |
238 | func->status = 0x00; | 224 | p_slot->status = 0x00; |
239 | taskInfo->event_type = INT_POWER_FAULT_CLEAR; | 225 | taskInfo->event_type = INT_POWER_FAULT_CLEAR; |
240 | } else { | 226 | } else { |
241 | /* | 227 | /* |
@@ -244,7 +230,7 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
244 | info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); | 230 | info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); |
245 | taskInfo->event_type = INT_POWER_FAULT; | 231 | taskInfo->event_type = INT_POWER_FAULT; |
246 | /* set power fault status for this board */ | 232 | /* set power fault status for this board */ |
247 | func->status = 0xFF; | 233 | p_slot->status = 0xFF; |
248 | info("power fault bit %x set\n", hp_slot); | 234 | info("power fault bit %x set\n", hp_slot); |
249 | } | 235 | } |
250 | if (rc) | 236 | if (rc) |
@@ -253,179 +239,6 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
253 | return rc; | 239 | return rc; |
254 | } | 240 | } |
255 | 241 | ||
256 | /** | ||
257 | * shpchp_slot_create - Creates a node and adds it to the proper bus. | ||
258 | * @busnumber - bus where new node is to be located | ||
259 | * | ||
260 | * Returns pointer to the new node or NULL if unsuccessful | ||
261 | */ | ||
262 | struct pci_func *shpchp_slot_create(u8 busnumber) | ||
263 | { | ||
264 | struct pci_func *new_slot; | ||
265 | struct pci_func *next; | ||
266 | |||
267 | new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); | ||
268 | |||
269 | if (new_slot == NULL) { | ||
270 | return(new_slot); | ||
271 | } | ||
272 | |||
273 | memset(new_slot, 0, sizeof(struct pci_func)); | ||
274 | |||
275 | new_slot->next = NULL; | ||
276 | new_slot->configured = 1; | ||
277 | |||
278 | if (shpchp_slot_list[busnumber] == NULL) { | ||
279 | shpchp_slot_list[busnumber] = new_slot; | ||
280 | } else { | ||
281 | next = shpchp_slot_list[busnumber]; | ||
282 | while (next->next != NULL) | ||
283 | next = next->next; | ||
284 | next->next = new_slot; | ||
285 | } | ||
286 | return(new_slot); | ||
287 | } | ||
288 | |||
289 | |||
290 | /* | ||
291 | * slot_remove - Removes a node from the linked list of slots. | ||
292 | * @old_slot: slot to remove | ||
293 | * | ||
294 | * Returns 0 if successful, !0 otherwise. | ||
295 | */ | ||
296 | static int slot_remove(struct pci_func * old_slot) | ||
297 | { | ||
298 | struct pci_func *next; | ||
299 | |||
300 | if (old_slot == NULL) | ||
301 | return(1); | ||
302 | |||
303 | next = shpchp_slot_list[old_slot->bus]; | ||
304 | |||
305 | if (next == NULL) { | ||
306 | return(1); | ||
307 | } | ||
308 | |||
309 | if (next == old_slot) { | ||
310 | shpchp_slot_list[old_slot->bus] = old_slot->next; | ||
311 | kfree(old_slot); | ||
312 | return(0); | ||
313 | } | ||
314 | |||
315 | while ((next->next != old_slot) && (next->next != NULL)) { | ||
316 | next = next->next; | ||
317 | } | ||
318 | |||
319 | if (next->next == old_slot) { | ||
320 | next->next = old_slot->next; | ||
321 | kfree(old_slot); | ||
322 | return(0); | ||
323 | } else | ||
324 | return(2); | ||
325 | } | ||
326 | |||
327 | |||
328 | /** | ||
329 | * bridge_slot_remove - Removes a node from the linked list of slots. | ||
330 | * @bridge: bridge to remove | ||
331 | * @secondaryBus: secondary PCI bus number for bridge being removed | ||
332 | * @subordinateBus: subordinate PCI bus number for bridge being removed | ||
333 | * | ||
334 | * Returns 0 if successful, !0 otherwise. | ||
335 | */ | ||
336 | static int bridge_slot_remove(struct pci_func *bridge, u8 secondaryBus, | ||
337 | u8 subordinateBus) | ||
338 | { | ||
339 | u8 tempBus; | ||
340 | struct pci_func *next; | ||
341 | |||
342 | if (bridge == NULL) | ||
343 | return(1); | ||
344 | |||
345 | for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { | ||
346 | next = shpchp_slot_list[tempBus]; | ||
347 | |||
348 | while (!slot_remove(next)) { | ||
349 | next = shpchp_slot_list[tempBus]; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | next = shpchp_slot_list[bridge->bus]; | ||
354 | |||
355 | if (next == NULL) { | ||
356 | return(1); | ||
357 | } | ||
358 | |||
359 | if (next == bridge) { | ||
360 | shpchp_slot_list[bridge->bus] = bridge->next; | ||
361 | kfree(bridge); | ||
362 | return(0); | ||
363 | } | ||
364 | |||
365 | while ((next->next != bridge) && (next->next != NULL)) { | ||
366 | next = next->next; | ||
367 | } | ||
368 | |||
369 | if (next->next == bridge) { | ||
370 | next->next = bridge->next; | ||
371 | kfree(bridge); | ||
372 | return(0); | ||
373 | } else | ||
374 | return(2); | ||
375 | } | ||
376 | |||
377 | |||
378 | /** | ||
379 | * shpchp_slot_find - Looks for a node by bus, and device, multiple functions accessed | ||
380 | * @bus: bus to find | ||
381 | * @device: device to find | ||
382 | * @index: is 0 for first function found, 1 for the second... | ||
383 | * | ||
384 | * Returns pointer to the node if successful, %NULL otherwise. | ||
385 | */ | ||
386 | struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index) | ||
387 | { | ||
388 | int found = -1; | ||
389 | struct pci_func *func; | ||
390 | |||
391 | func = shpchp_slot_list[bus]; | ||
392 | |||
393 | if ((func == NULL) || ((func->device == device) && (index == 0))) | ||
394 | return(func); | ||
395 | |||
396 | if (func->device == device) | ||
397 | found++; | ||
398 | |||
399 | while (func->next != NULL) { | ||
400 | func = func->next; | ||
401 | |||
402 | if (func->device == device) | ||
403 | found++; | ||
404 | |||
405 | if (found == index) | ||
406 | return(func); | ||
407 | } | ||
408 | |||
409 | return(NULL); | ||
410 | } | ||
411 | |||
412 | static int is_bridge(struct pci_func *func, struct controller *ctrl) | ||
413 | { | ||
414 | u8 hdr_type; | ||
415 | struct pci_bus *bus = ctrl->pci_dev->subordinate; | ||
416 | |||
417 | /* | ||
418 | * Note: device may have just been hot-added and not yet scanned | ||
419 | * by the pci core, so its pci_dev structure may not exist yet | ||
420 | */ | ||
421 | pci_bus_read_config_byte(bus, PCI_DEVFN(func->device, func->function), | ||
422 | PCI_HEADER_TYPE, &hdr_type); | ||
423 | if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) | ||
424 | return 1; | ||
425 | else | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | /* The following routines constitute the bulk of the | 242 | /* The following routines constitute the bulk of the |
430 | hotplug controller logic | 243 | hotplug controller logic |
431 | */ | 244 | */ |
@@ -495,19 +308,20 @@ enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) | |||
495 | * Configures board | 308 | * Configures board |
496 | * | 309 | * |
497 | */ | 310 | */ |
498 | static u32 board_added(struct pci_func * func, struct controller * ctrl) | 311 | static u32 board_added(struct slot *p_slot) |
499 | { | 312 | { |
500 | u8 hp_slot; | 313 | u8 hp_slot; |
501 | u8 slots_not_empty = 0; | 314 | u8 slots_not_empty = 0; |
502 | u32 rc = 0; | 315 | u32 rc = 0; |
503 | struct slot *p_slot; | ||
504 | enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; | 316 | enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; |
505 | u8 pi, mode; | 317 | u8 pi, mode; |
318 | struct controller *ctrl = p_slot->ctrl; | ||
506 | 319 | ||
507 | p_slot = shpchp_find_slot(ctrl, func->device); | 320 | hp_slot = p_slot->device - ctrl->slot_device_offset; |
508 | hp_slot = func->device - ctrl->slot_device_offset; | ||
509 | 321 | ||
510 | dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); | 322 | dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", |
323 | __FUNCTION__, p_slot->device, | ||
324 | ctrl->slot_device_offset, hp_slot); | ||
511 | 325 | ||
512 | /* Wait for exclusive access to hardware */ | 326 | /* Wait for exclusive access to hardware */ |
513 | down(&ctrl->crit_sect); | 327 | down(&ctrl->crit_sect); |
@@ -699,13 +513,13 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) | |||
699 | wait_for_ctrl_irq (ctrl); | 513 | wait_for_ctrl_irq (ctrl); |
700 | dbg("%s: after long_delay\n", __FUNCTION__); | 514 | dbg("%s: after long_delay\n", __FUNCTION__); |
701 | 515 | ||
702 | dbg("%s: func status = %x\n", __FUNCTION__, func->status); | 516 | dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); |
703 | /* Check for a power fault */ | 517 | /* Check for a power fault */ |
704 | if (func->status == 0xFF) { | 518 | if (p_slot->status == 0xFF) { |
705 | /* power fault occurred, but it was benign */ | 519 | /* power fault occurred, but it was benign */ |
706 | dbg("%s: power fault\n", __FUNCTION__); | 520 | dbg("%s: power fault\n", __FUNCTION__); |
707 | rc = POWER_FAILURE; | 521 | rc = POWER_FAILURE; |
708 | func->status = 0; | 522 | p_slot->status = 0; |
709 | goto err_exit; | 523 | goto err_exit; |
710 | } | 524 | } |
711 | 525 | ||
@@ -715,10 +529,9 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) | |||
715 | goto err_exit; | 529 | goto err_exit; |
716 | } | 530 | } |
717 | 531 | ||
718 | func->status = 0; | 532 | p_slot->status = 0; |
719 | func->switch_save = 0x10; | 533 | p_slot->is_a_board = 0x01; |
720 | func->is_a_board = 0x01; | 534 | p_slot->pwr_save = 1; |
721 | func->pwr_save = 1; | ||
722 | 535 | ||
723 | /* Wait for exclusive access to hardware */ | 536 | /* Wait for exclusive access to hardware */ |
724 | down(&ctrl->crit_sect); | 537 | down(&ctrl->crit_sect); |
@@ -767,38 +580,23 @@ err_exit: | |||
767 | * remove_board - Turns off slot and LED's | 580 | * remove_board - Turns off slot and LED's |
768 | * | 581 | * |
769 | */ | 582 | */ |
770 | static u32 remove_board(struct pci_func *func, struct controller *ctrl) | 583 | static u32 remove_board(struct slot *p_slot) |
771 | { | 584 | { |
772 | u8 device; | 585 | struct controller *ctrl = p_slot->ctrl; |
773 | u8 hp_slot; | 586 | u8 hp_slot; |
774 | u32 rc; | 587 | u32 rc; |
775 | struct slot *p_slot; | ||
776 | u8 secondary = 0, subordinate = 0; | ||
777 | int remove_bridge; | ||
778 | |||
779 | if (func == NULL) | ||
780 | return(1); | ||
781 | |||
782 | if ((remove_bridge = is_bridge(func, ctrl))) { | ||
783 | /* Stash away bus information before we destroy it */ | ||
784 | secondary = func->pci_dev->subordinate->secondary; | ||
785 | subordinate = func->pci_dev->subordinate->subordinate; | ||
786 | } | ||
787 | 588 | ||
788 | if (shpchp_unconfigure_device(func)) | 589 | if (shpchp_unconfigure_device(p_slot)) |
789 | return(1); | 590 | return(1); |
790 | 591 | ||
791 | device = func->device; | 592 | hp_slot = p_slot->device - ctrl->slot_device_offset; |
792 | |||
793 | hp_slot = func->device - ctrl->slot_device_offset; | ||
794 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 593 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
795 | 594 | ||
796 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); | 595 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); |
797 | 596 | ||
798 | /* Change status to shutdown */ | 597 | /* Change status to shutdown */ |
799 | if (func->is_a_board) | 598 | if (p_slot->is_a_board) |
800 | func->status = 0x01; | 599 | p_slot->status = 0x01; |
801 | func->configured = 0; | ||
802 | 600 | ||
803 | /* Wait for exclusive access to hardware */ | 601 | /* Wait for exclusive access to hardware */ |
804 | down(&ctrl->crit_sect); | 602 | down(&ctrl->crit_sect); |
@@ -835,36 +633,8 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) | |||
835 | /* Done with exclusive hardware access */ | 633 | /* Done with exclusive hardware access */ |
836 | up(&ctrl->crit_sect); | 634 | up(&ctrl->crit_sect); |
837 | 635 | ||
838 | if (ctrl->add_support) { | 636 | p_slot->pwr_save = 0; |
839 | while (func) { | 637 | p_slot->is_a_board = 0; |
840 | if (remove_bridge) { | ||
841 | dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, | ||
842 | func->device, func->function); | ||
843 | bridge_slot_remove(func, secondary, | ||
844 | subordinate); | ||
845 | } else | ||
846 | dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, | ||
847 | func->device, func->function); | ||
848 | slot_remove(func); | ||
849 | |||
850 | func = shpchp_slot_find(ctrl->slot_bus, device, 0); | ||
851 | } | ||
852 | |||
853 | /* Setup slot structure with entry for empty slot */ | ||
854 | func = shpchp_slot_create(ctrl->slot_bus); | ||
855 | |||
856 | if (func == NULL) { | ||
857 | return(1); | ||
858 | } | ||
859 | |||
860 | func->bus = ctrl->slot_bus; | ||
861 | func->device = device; | ||
862 | func->function = 0; | ||
863 | func->configured = 0; | ||
864 | func->switch_save = 0x10; | ||
865 | func->pwr_save = 0; | ||
866 | func->is_a_board = 0; | ||
867 | } | ||
868 | 638 | ||
869 | return 0; | 639 | return 0; |
870 | } | 640 | } |
@@ -1006,7 +776,6 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
1006 | { | 776 | { |
1007 | int loop = 0; | 777 | int loop = 0; |
1008 | int change = 1; | 778 | int change = 1; |
1009 | struct pci_func *func; | ||
1010 | u8 hp_slot; | 779 | u8 hp_slot; |
1011 | u8 getstatus; | 780 | u8 getstatus; |
1012 | struct slot *p_slot; | 781 | struct slot *p_slot; |
@@ -1021,11 +790,10 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
1021 | ctrl->event_queue[loop].event_type); | 790 | ctrl->event_queue[loop].event_type); |
1022 | hp_slot = ctrl->event_queue[loop].hp_slot; | 791 | hp_slot = ctrl->event_queue[loop].hp_slot; |
1023 | 792 | ||
1024 | func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); | ||
1025 | |||
1026 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | 793 | p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); |
1027 | 794 | ||
1028 | dbg("%s: hp_slot %d, func %p, p_slot %p\n", __FUNCTION__, hp_slot, func, p_slot); | 795 | dbg("%s: hp_slot %d, p_slot %p\n", |
796 | __FUNCTION__, hp_slot, p_slot); | ||
1029 | 797 | ||
1030 | if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { | 798 | if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { |
1031 | dbg("%s: button cancel\n", __FUNCTION__); | 799 | dbg("%s: button cancel\n", __FUNCTION__); |
@@ -1147,13 +915,6 @@ int shpchp_enable_slot (struct slot *p_slot) | |||
1147 | { | 915 | { |
1148 | u8 getstatus = 0; | 916 | u8 getstatus = 0; |
1149 | int rc; | 917 | int rc; |
1150 | struct pci_func *func; | ||
1151 | |||
1152 | func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); | ||
1153 | if (!func) { | ||
1154 | dbg("%s: Error! slot NULL\n", __FUNCTION__); | ||
1155 | return -ENODEV; | ||
1156 | } | ||
1157 | 918 | ||
1158 | /* Check to see if (latch closed, card present, power off) */ | 919 | /* Check to see if (latch closed, card present, power off) */ |
1159 | down(&p_slot->ctrl->crit_sect); | 920 | down(&p_slot->ctrl->crit_sect); |
@@ -1177,75 +938,35 @@ int shpchp_enable_slot (struct slot *p_slot) | |||
1177 | } | 938 | } |
1178 | up(&p_slot->ctrl->crit_sect); | 939 | up(&p_slot->ctrl->crit_sect); |
1179 | 940 | ||
1180 | slot_remove(func); | 941 | p_slot->is_a_board = 1; |
1181 | |||
1182 | func = shpchp_slot_create(p_slot->bus); | ||
1183 | if (func == NULL) | ||
1184 | return -ENOMEM; | ||
1185 | |||
1186 | func->bus = p_slot->bus; | ||
1187 | func->device = p_slot->device; | ||
1188 | func->function = 0; | ||
1189 | func->configured = 0; | ||
1190 | func->is_a_board = 1; | ||
1191 | 942 | ||
1192 | /* We have to save the presence info for these slots */ | 943 | /* We have to save the presence info for these slots */ |
1193 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | 944 | p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); |
1194 | p_slot->hpc_ops->get_power_status(p_slot, &(func->pwr_save)); | 945 | p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save)); |
1195 | dbg("%s: func->pwr_save %x\n", __FUNCTION__, func->pwr_save); | 946 | dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save); |
1196 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 947 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
1197 | func->switch_save = !getstatus? 0x10:0; | ||
1198 | 948 | ||
1199 | rc = board_added(func, p_slot->ctrl); | 949 | rc = board_added(p_slot); |
1200 | if (rc) { | 950 | if (rc) { |
1201 | if (is_bridge(func, p_slot->ctrl)) { | 951 | p_slot->hpc_ops->get_adapter_status(p_slot, |
1202 | u8 secondary = func->pci_dev->subordinate->secondary; | 952 | &(p_slot->presence_save)); |
1203 | u8 subordinate = | ||
1204 | func->pci_dev->subordinate->subordinate; | ||
1205 | bridge_slot_remove(func, secondary, subordinate); | ||
1206 | } else | ||
1207 | slot_remove(func); | ||
1208 | |||
1209 | /* Setup slot structure with entry for empty slot */ | ||
1210 | func = shpchp_slot_create(p_slot->bus); | ||
1211 | if (func == NULL) | ||
1212 | return -ENOMEM; /* Out of memory */ | ||
1213 | |||
1214 | func->bus = p_slot->bus; | ||
1215 | func->device = p_slot->device; | ||
1216 | func->function = 0; | ||
1217 | func->configured = 0; | ||
1218 | func->is_a_board = 1; | ||
1219 | |||
1220 | /* We have to save the presence info for these slots */ | ||
1221 | p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); | ||
1222 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 953 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
1223 | func->switch_save = !getstatus? 0x10:0; | ||
1224 | } | 954 | } |
1225 | 955 | ||
1226 | if (p_slot) | 956 | update_slot_info(p_slot); |
1227 | update_slot_info(p_slot); | ||
1228 | |||
1229 | return rc; | 957 | return rc; |
1230 | } | 958 | } |
1231 | 959 | ||
1232 | 960 | ||
1233 | int shpchp_disable_slot (struct slot *p_slot) | 961 | int shpchp_disable_slot (struct slot *p_slot) |
1234 | { | 962 | { |
1235 | u8 class_code, header_type, BCR; | ||
1236 | u8 index = 0; | ||
1237 | u8 getstatus = 0; | 963 | u8 getstatus = 0; |
1238 | u32 rc = 0; | 964 | u32 rc = 0; |
1239 | int ret = 0; | 965 | int ret = 0; |
1240 | unsigned int devfn; | ||
1241 | struct pci_bus *pci_bus; | ||
1242 | struct pci_func *func; | ||
1243 | 966 | ||
1244 | if (!p_slot->ctrl) | 967 | if (!p_slot->ctrl) |
1245 | return -ENODEV; | 968 | return -ENODEV; |
1246 | 969 | ||
1247 | pci_bus = p_slot->ctrl->pci_dev->subordinate; | ||
1248 | |||
1249 | /* Check to see if (latch closed, card present, power on) */ | 970 | /* Check to see if (latch closed, card present, power on) */ |
1250 | down(&p_slot->ctrl->crit_sect); | 971 | down(&p_slot->ctrl->crit_sect); |
1251 | 972 | ||
@@ -1269,54 +990,8 @@ int shpchp_disable_slot (struct slot *p_slot) | |||
1269 | } | 990 | } |
1270 | up(&p_slot->ctrl->crit_sect); | 991 | up(&p_slot->ctrl->crit_sect); |
1271 | 992 | ||
1272 | func = shpchp_slot_find(p_slot->bus, p_slot->device, index++); | 993 | rc = remove_board(p_slot); |
1273 | 994 | update_slot_info(p_slot); | |
1274 | /* Make sure there are no video controllers here | ||
1275 | * for all func of p_slot | ||
1276 | */ | ||
1277 | while (func && !rc) { | ||
1278 | pci_bus->number = func->bus; | ||
1279 | devfn = PCI_DEVFN(func->device, func->function); | ||
1280 | |||
1281 | /* Check the Class Code */ | ||
1282 | rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); | ||
1283 | if (rc) | ||
1284 | return -ENODEV; | ||
1285 | |||
1286 | if (class_code == PCI_BASE_CLASS_DISPLAY) { | ||
1287 | /* Display/Video adapter (not supported) */ | ||
1288 | rc = REMOVE_NOT_SUPPORTED; | ||
1289 | } else { | ||
1290 | /* See if it's a bridge */ | ||
1291 | rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); | ||
1292 | if (rc) | ||
1293 | return -ENODEV; | ||
1294 | |||
1295 | /* If it's a bridge, check the VGA Enable bit */ | ||
1296 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { | ||
1297 | rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); | ||
1298 | if (rc) | ||
1299 | return -ENODEV; | ||
1300 | |||
1301 | /* If the VGA Enable bit is set, remove isn't supported */ | ||
1302 | if (BCR & PCI_BRIDGE_CTL_VGA) { | ||
1303 | rc = REMOVE_NOT_SUPPORTED; | ||
1304 | } | ||
1305 | } | ||
1306 | } | ||
1307 | |||
1308 | func = shpchp_slot_find(p_slot->bus, p_slot->device, index++); | ||
1309 | } | ||
1310 | |||
1311 | func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); | ||
1312 | if ((func != NULL) && !rc) { | ||
1313 | rc = remove_board(func, p_slot->ctrl); | ||
1314 | } else if (!rc) | ||
1315 | rc = -ENODEV; | ||
1316 | |||
1317 | if (p_slot) | ||
1318 | update_slot_info(p_slot); | ||
1319 | |||
1320 | return rc; | 995 | return rc; |
1321 | } | 996 | } |
1322 | 997 | ||
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index f51a97d7611f..8f0a1667f2e6 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c | |||
@@ -148,20 +148,33 @@ int shpchp_configure_device(struct slot *p_slot) | |||
148 | return 0; | 148 | return 0; |
149 | } | 149 | } |
150 | 150 | ||
151 | int shpchp_unconfigure_device(struct pci_func* func) | 151 | int shpchp_unconfigure_device(struct slot *p_slot) |
152 | { | 152 | { |
153 | int rc = 0; | 153 | int rc = 0; |
154 | int j; | 154 | int j; |
155 | u8 bctl = 0; | ||
155 | 156 | ||
156 | dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, | 157 | dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device); |
157 | func->device, func->function); | ||
158 | 158 | ||
159 | for (j=0; j<8 ; j++) { | 159 | for (j=0; j<8 ; j++) { |
160 | struct pci_dev* temp = pci_find_slot(func->bus, | 160 | struct pci_dev* temp = pci_find_slot(p_slot->bus, |
161 | (func->device << 3) | j); | 161 | (p_slot->device << 3) | j); |
162 | if (temp) { | 162 | if (!temp) |
163 | pci_remove_bus_device(temp); | 163 | continue; |
164 | if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { | ||
165 | err("Cannot remove display device %s\n", | ||
166 | pci_name(temp)); | ||
167 | continue; | ||
168 | } | ||
169 | if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
170 | pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); | ||
171 | if (bctl & PCI_BRIDGE_CTL_VGA) { | ||
172 | err("Cannot remove display device %s\n", | ||
173 | pci_name(temp)); | ||
174 | continue; | ||
175 | } | ||
164 | } | 176 | } |
177 | pci_remove_bus_device(temp); | ||
165 | } | 178 | } |
166 | return rc; | 179 | return rc; |
167 | } | 180 | } |