]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/pci/hotplug/shpchp_ctrl.c
[PATCH] shpchp: use the PCI core for hotplug resource management
[mv-sheeva.git] / drivers / pci / hotplug / shpchp_ctrl.c
1 /*
2  * Standard Hot Plug Controller Driver
3  *
4  * Copyright (C) 1995,2001 Compaq Computer Corporation
5  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6  * Copyright (C) 2001 IBM Corp.
7  * Copyright (C) 2003-2004 Intel Corporation
8  *
9  * All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or (at
14  * your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
19  * NON INFRINGEMENT.  See the GNU General Public License for more
20  * details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
27  *
28  */
29
30 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/types.h>
34 #include <linux/slab.h>
35 #include <linux/workqueue.h>
36 #include <linux/interrupt.h>
37 #include <linux/delay.h>
38 #include <linux/wait.h>
39 #include <linux/smp_lock.h>
40 #include <linux/pci.h>
41 #include "../pci.h"
42 #include "shpchp.h"
43 #include "shpchprm.h"
44
45 static void interrupt_event_handler(struct controller *ctrl);
46
47 static struct semaphore event_semaphore;        /* mutex for process loop (up if something to process) */
48 static struct semaphore event_exit;             /* guard ensure thread has exited before calling it quits */
49 static int event_finished;
50 static unsigned long pushbutton_pending;        /* = 0 */
51
52 u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
53 {
54         struct controller *ctrl = (struct controller *) inst_id;
55         struct slot *p_slot;
56         u8 rc = 0;
57         u8 getstatus;
58         struct pci_func *func;
59         struct event_info *taskInfo;
60
61         /* Attention Button Change */
62         dbg("shpchp:  Attention button interrupt received.\n");
63         
64         func = shpchp_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 */
67         taskInfo = &(ctrl->event_queue[ctrl->next_event]);
68         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
69
70         p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
71         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
72         
73         ctrl->next_event = (ctrl->next_event + 1) % 10;
74         taskInfo->hp_slot = hp_slot;
75
76         rc++;
77
78         /*
79          *  Button pressed - See if need to TAKE ACTION!!!
80          */
81         info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
82         taskInfo->event_type = INT_BUTTON_PRESS;
83
84         if ((p_slot->state == BLINKINGON_STATE)
85             || (p_slot->state == BLINKINGOFF_STATE)) {
86                 /* Cancel if we are still blinking; this means that we press the
87                  * attention again before the 5 sec. limit expires to cancel hot-add
88                  * or hot-remove
89                  */
90                 taskInfo->event_type = INT_BUTTON_CANCEL;
91                 info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
92         } else if ((p_slot->state == POWERON_STATE)
93                    || (p_slot->state == POWEROFF_STATE)) {
94                 /* Ignore if the slot is on power-on or power-off state; this 
95                  * means that the previous attention button action to hot-add or
96                  * hot-remove is undergoing
97                  */
98                 taskInfo->event_type = INT_BUTTON_IGNORE;
99                 info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
100         }
101
102         if (rc)
103                 up(&event_semaphore);   /* signal event thread that new event is posted */
104
105         return 0;
106
107 }
108
109 u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
110 {
111         struct controller *ctrl = (struct controller *) inst_id;
112         struct slot *p_slot;
113         u8 rc = 0;
114         u8 getstatus;
115         struct pci_func *func;
116         struct event_info *taskInfo;
117
118         /* Switch Change */
119         dbg("shpchp:  Switch interrupt received.\n");
120
121         func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
122
123         /* This is the structure that tells the worker thread
124          * what to do
125          */
126         taskInfo = &(ctrl->event_queue[ctrl->next_event]);
127         ctrl->next_event = (ctrl->next_event + 1) % 10;
128         taskInfo->hp_slot = hp_slot;
129
130         rc++;
131         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
132         p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
133         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
134         dbg("%s: Card present %x Power status %x\n", __FUNCTION__,
135                 func->presence_save, func->pwr_save);
136
137         if (getstatus) {
138                 /*
139                  * Switch opened
140                  */
141                 info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
142                 func->switch_save = 0;
143                 taskInfo->event_type = INT_SWITCH_OPEN;
144                 if (func->pwr_save && func->presence_save) {
145                         taskInfo->event_type = INT_POWER_FAULT;
146                         err("Surprise Removal of card\n");
147                 }
148         } else {
149                 /*
150                  *  Switch closed
151                  */
152                 info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
153                 func->switch_save = 0x10;
154                 taskInfo->event_type = INT_SWITCH_CLOSE;
155         }
156
157         if (rc)
158                 up(&event_semaphore);   /* signal event thread that new event is posted */
159
160         return rc;
161 }
162
163 u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
164 {
165         struct controller *ctrl = (struct controller *) inst_id;
166         struct slot *p_slot;
167         u8 rc = 0;
168         /*u8 temp_byte;*/
169         struct pci_func *func;
170         struct event_info *taskInfo;
171
172         /* Presence Change */
173         dbg("shpchp:  Presence/Notify input change.\n");
174
175         func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
176
177         /* This is the structure that tells the worker thread
178          * what to do
179          */
180         taskInfo = &(ctrl->event_queue[ctrl->next_event]);
181         ctrl->next_event = (ctrl->next_event + 1) % 10;
182         taskInfo->hp_slot = hp_slot;
183
184         rc++;
185         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
186
187         /* 
188          * Save the presence state
189          */
190         p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
191         if (func->presence_save) {
192                 /*
193                  * Card Present
194                  */
195                 info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
196                 taskInfo->event_type = INT_PRESENCE_ON;
197         } else {
198                 /*
199                  * Not Present
200                  */
201                 info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
202                 taskInfo->event_type = INT_PRESENCE_OFF;
203         }
204
205         if (rc)
206                 up(&event_semaphore);   /* signal event thread that new event is posted */
207
208         return rc;
209 }
210
211 u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
212 {
213         struct controller *ctrl = (struct controller *) inst_id;
214         struct slot *p_slot;
215         u8 rc = 0;
216         struct pci_func *func;
217         struct event_info *taskInfo;
218
219         /* Power fault */
220         dbg("shpchp:  Power fault interrupt received.\n");
221
222         func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
223
224         /* This is the structure that tells the worker thread
225          * what to do
226          */
227         taskInfo = &(ctrl->event_queue[ctrl->next_event]);
228         ctrl->next_event = (ctrl->next_event + 1) % 10;
229         taskInfo->hp_slot = hp_slot;
230
231         rc++;
232         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
233
234         if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
235                 /*
236                  * Power fault Cleared
237                  */
238                 info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
239                 func->status = 0x00;
240                 taskInfo->event_type = INT_POWER_FAULT_CLEAR;
241         } else {
242                 /*
243                  *   Power fault
244                  */
245                 info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
246                 taskInfo->event_type = INT_POWER_FAULT;
247                 /* set power fault status for this board */
248                 func->status = 0xFF;
249                 info("power fault bit %x set\n", hp_slot);
250         }
251         if (rc)
252                 up(&event_semaphore);   /* signal event thread that new event is posted */
253
254         return rc;
255 }
256
257 /**
258  * shpchp_slot_create - Creates a node and adds it to the proper bus.
259  * @busnumber - bus where new node is to be located
260  *
261  * Returns pointer to the new node or NULL if unsuccessful
262  */
263 struct pci_func *shpchp_slot_create(u8 busnumber)
264 {
265         struct pci_func *new_slot;
266         struct pci_func *next;
267
268         new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
269
270         if (new_slot == NULL) {
271                 return(new_slot);
272         }
273
274         memset(new_slot, 0, sizeof(struct pci_func));
275
276         new_slot->next = NULL;
277         new_slot->configured = 1;
278
279         if (shpchp_slot_list[busnumber] == NULL) {
280                 shpchp_slot_list[busnumber] = new_slot;
281         } else {
282                 next = shpchp_slot_list[busnumber];
283                 while (next->next != NULL)
284                         next = next->next;
285                 next->next = new_slot;
286         }
287         return(new_slot);
288 }
289
290
291 /*
292  * slot_remove - Removes a node from the linked list of slots.
293  * @old_slot: slot to remove
294  *
295  * Returns 0 if successful, !0 otherwise.
296  */
297 static int slot_remove(struct pci_func * old_slot)
298 {
299         struct pci_func *next;
300
301         if (old_slot == NULL)
302                 return(1);
303
304         next = shpchp_slot_list[old_slot->bus];
305
306         if (next == NULL) {
307                 return(1);
308         }
309
310         if (next == old_slot) {
311                 shpchp_slot_list[old_slot->bus] = old_slot->next;
312                 kfree(old_slot);
313                 return(0);
314         }
315
316         while ((next->next != old_slot) && (next->next != NULL)) {
317                 next = next->next;
318         }
319
320         if (next->next == old_slot) {
321                 next->next = old_slot->next;
322                 kfree(old_slot);
323                 return(0);
324         } else
325                 return(2);
326 }
327
328
329 /**
330  * bridge_slot_remove - Removes a node from the linked list of slots.
331  * @bridge: bridge to remove
332  *
333  * Returns 0 if successful, !0 otherwise.
334  */
335 static int bridge_slot_remove(struct pci_func *bridge)
336 {
337         u8 subordinateBus, secondaryBus;
338         u8 tempBus;
339         struct pci_func *next;
340
341         if (bridge == NULL)
342                 return(1);
343
344         secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
345         subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
346
347         for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
348                 next = shpchp_slot_list[tempBus];
349
350                 while (!slot_remove(next)) {
351                         next = shpchp_slot_list[tempBus];
352                 }
353         }
354
355         next = shpchp_slot_list[bridge->bus];
356
357         if (next == NULL) {
358                 return(1);
359         }
360
361         if (next == bridge) {
362                 shpchp_slot_list[bridge->bus] = bridge->next;
363                 kfree(bridge);
364                 return(0);
365         }
366
367         while ((next->next != bridge) && (next->next != NULL)) {
368                 next = next->next;
369         }
370
371         if (next->next == bridge) {
372                 next->next = bridge->next;
373                 kfree(bridge);
374                 return(0);
375         } else
376                 return(2);
377 }
378
379
380 /**
381  * shpchp_slot_find - Looks for a node by bus, and device, multiple functions accessed
382  * @bus: bus to find
383  * @device: device to find
384  * @index: is 0 for first function found, 1 for the second...
385  *
386  * Returns pointer to the node if successful, %NULL otherwise.
387  */
388 struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index)
389 {
390         int found = -1;
391         struct pci_func *func;
392
393         func = shpchp_slot_list[bus];
394
395         if ((func == NULL) || ((func->device == device) && (index == 0)))
396                 return(func);
397
398         if (func->device == device)
399                 found++;
400
401         while (func->next != NULL) {
402                 func = func->next;
403
404                 if (func->device == device)
405                         found++;
406
407                 if (found == index)
408                         return(func);
409         }
410
411         return(NULL);
412 }
413
414 static int is_bridge(struct pci_func * func)
415 {
416         /* Check the header type */
417         if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01)
418                 return 1;
419         else
420                 return 0;
421 }
422
423
424 /* The following routines constitute the bulk of the 
425    hotplug controller logic
426  */
427 static u32 change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum pci_bus_speed speed)
428
429         u32 rc = 0;
430
431         dbg("%s: change to speed %d\n", __FUNCTION__, speed);
432         down(&ctrl->crit_sect);
433         if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
434                 err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
435                 up(&ctrl->crit_sect);
436                 return WRONG_BUS_FREQUENCY;
437         }
438         wait_for_ctrl_irq (ctrl);
439                 
440         if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
441                 err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
442                           __FUNCTION__);
443                 err("%s: Error code (%d)\n", __FUNCTION__, rc);
444                 up(&ctrl->crit_sect);
445                 return WRONG_BUS_FREQUENCY;
446         }
447         up(&ctrl->crit_sect);
448         return rc;
449 }
450
451 static u32 fix_bus_speed(struct controller *ctrl, struct slot *pslot, u8 flag, 
452 enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp)
453
454         u32 rc = 0;
455         
456         if (flag != 0) { /* Other slots on the same bus are occupied */
457                 if ( asp < bsp ) {
458                         err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bsp, asp);
459                         return WRONG_BUS_FREQUENCY;
460                 }
461         } else {
462                 /* Other slots on the same bus are empty */
463                 if (msp == bsp) {
464                 /* if adapter_speed >= bus_speed, do nothing */
465                         if (asp < bsp) {
466                                 /* 
467                                 * Try to lower bus speed to accommodate the adapter if other slots 
468                                 * on the same controller are empty
469                                 */
470                                 if ((rc = change_bus_speed(ctrl, pslot, asp)))
471                                         return rc;
472                         } 
473                 } else {
474                         if (asp < msp) {
475                                 if ((rc = change_bus_speed(ctrl, pslot, asp)))
476                                         return rc;
477                         } else {
478                                 if ((rc = change_bus_speed(ctrl, pslot, msp)))
479                                         return rc;
480                         }
481                 }
482         }
483         return rc;
484 }
485
486 /**
487  * board_added - Called after a board has been added to the system.
488  *
489  * Turns power on for the board
490  * Configures board
491  *
492  */
493 static u32 board_added(struct pci_func * func, struct controller * ctrl)
494 {
495         u8 hp_slot;
496         u8 slots_not_empty = 0;
497         u32 rc = 0;
498         struct slot *p_slot;
499         enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed;
500         u8 pi, mode;
501
502         p_slot = shpchp_find_slot(ctrl, func->device);
503         hp_slot = func->device - ctrl->slot_device_offset;
504
505         dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
506
507         /* Wait for exclusive access to hardware */
508         down(&ctrl->crit_sect);
509
510         /* Power on slot without connecting to bus */
511         rc = p_slot->hpc_ops->power_on_slot(p_slot);
512         if (rc) {
513                 err("%s: Failed to power on slot\n", __FUNCTION__);
514                 /* Done with exclusive hardware access */
515                 up(&ctrl->crit_sect);
516                 return -1;
517         }
518                         
519         /* Wait for the command to complete */
520         wait_for_ctrl_irq (ctrl);
521         
522         rc = p_slot->hpc_ops->check_cmd_status(ctrl);
523         if (rc) {
524                 err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
525                 /* Done with exclusive hardware access */
526                 up(&ctrl->crit_sect);
527                 return -1;
528         }
529
530         
531         if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
532                 if (slots_not_empty)
533                         return WRONG_BUS_FREQUENCY;
534                 
535                 if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
536                         err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
537                         up(&ctrl->crit_sect);
538                         return WRONG_BUS_FREQUENCY;
539                 }
540                 wait_for_ctrl_irq (ctrl);
541                 
542                 if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
543                         err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
544                                   __FUNCTION__);
545                         err("%s: Error code (%d)\n", __FUNCTION__, rc);
546                         up(&ctrl->crit_sect);
547                         return WRONG_BUS_FREQUENCY;
548                 }
549                 /* turn on board, blink green LED, turn off Amber LED */
550                 if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
551                         err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
552                         up(&ctrl->crit_sect);
553                         return rc;
554                 }
555                 wait_for_ctrl_irq (ctrl);
556
557                 if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
558                         err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
559                         up(&ctrl->crit_sect);
560                         return rc;  
561                 }
562         }
563  
564         rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
565         /* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */
566         /* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC,  0xa = PCI-X 133 Mhz 266, */
567         /* 0xd = PCI-X 133 Mhz 533 */
568         /* This encoding is different from the one used in cur_bus_speed & */
569         /* max_bus_speed */
570
571         if (rc  || adapter_speed == PCI_SPEED_UNKNOWN) {
572                 err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
573                 /* Done with exclusive hardware access */
574                 up(&ctrl->crit_sect);
575                 return WRONG_BUS_FREQUENCY;
576         }
577
578         rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed);
579         if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
580                 err("%s: Can't get bus operation speed\n", __FUNCTION__);
581                 /* Done with exclusive hardware access */
582                 up(&ctrl->crit_sect);
583                 return WRONG_BUS_FREQUENCY;
584         }
585
586         rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed);
587         if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
588                 err("%s: Can't get max bus operation speed\n", __FUNCTION__);
589                 max_bus_speed = bus_speed;
590         }
591
592         /* Done with exclusive hardware access */
593         up(&ctrl->crit_sect);
594
595         if ((rc  = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) {
596                 err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
597                 pi = 1;
598         }
599
600         /* Check if there are other slots or devices on the same bus */
601         if (!list_empty(&ctrl->pci_dev->subordinate->devices))
602                 slots_not_empty = 1;
603
604         dbg("%s: slots_not_empty %d, pi %d\n", __FUNCTION__, 
605                 slots_not_empty, pi);
606         dbg("adapter_speed %d, bus_speed %d, max_bus_speed %d\n", 
607                 adapter_speed, bus_speed, max_bus_speed);
608
609         if (pi == 2) {
610                 dbg("%s: In PI = %d\n", __FUNCTION__, pi);
611                 if ((rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode))) {
612                         err("%s: Can't get Mode1_ECC, set mode to 0\n", __FUNCTION__);
613                         mode = 0;
614                 }
615
616                 switch (adapter_speed) {
617                 case PCI_SPEED_133MHz_PCIX_533:
618                 case PCI_SPEED_133MHz_PCIX_266:
619                         if ((bus_speed != adapter_speed) &&
620                            ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
621                                 return rc;
622                         break;  
623                 case PCI_SPEED_133MHz_PCIX_ECC:
624                 case PCI_SPEED_133MHz_PCIX:
625                         if (mode) { /* Bus - Mode 1 ECC */
626                                 if ((bus_speed != 0x7) &&
627                                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
628                                         return rc;
629                         } else {
630                                 if ((bus_speed != 0x4) &&
631                                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
632                                         return rc;
633                         }
634                         break;
635                 case PCI_SPEED_66MHz_PCIX_ECC:
636                 case PCI_SPEED_66MHz_PCIX:
637                         if (mode) { /* Bus - Mode 1 ECC */
638                                 if ((bus_speed != 0x5) &&
639                                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
640                                         return rc;
641                         } else {
642                                 if ((bus_speed != 0x2) &&
643                                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
644                                         return rc;
645                         }
646                         break;
647                 case PCI_SPEED_66MHz:
648                         if ((bus_speed != 0x1) &&
649                            ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
650                                 return rc;
651                         break;  
652                 case PCI_SPEED_33MHz:
653                         if (bus_speed > 0x0) {
654                                 if (slots_not_empty == 0) {
655                                         if ((rc = change_bus_speed(ctrl, p_slot, adapter_speed)))
656                                                 return rc;
657                                 } else {
658                                         err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
659                                         return WRONG_BUS_FREQUENCY;
660                                 }
661                         }
662                         break;
663                 default:
664                         err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
665                         return WRONG_BUS_FREQUENCY;
666                 }
667         } else {
668                 /* If adpater_speed == bus_speed, nothing to do here */
669                 dbg("%s: In PI = %d\n", __FUNCTION__, pi);
670                 if ((adapter_speed != bus_speed) &&
671                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
672                                 return rc;
673         }
674
675         down(&ctrl->crit_sect);
676         /* turn on board, blink green LED, turn off Amber LED */
677         if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
678                 err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
679                 up(&ctrl->crit_sect);
680                 return rc;
681         }
682         wait_for_ctrl_irq (ctrl);
683
684         if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
685                 err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
686                 up(&ctrl->crit_sect);
687                 return rc;  
688         }
689
690         up(&ctrl->crit_sect);
691
692         /* Wait for ~1 second */
693         dbg("%s: before long_delay\n", __FUNCTION__);
694         wait_for_ctrl_irq (ctrl);
695         dbg("%s: after long_delay\n", __FUNCTION__);
696
697         dbg("%s: func status = %x\n", __FUNCTION__, func->status);
698         /* Check for a power fault */
699         if (func->status == 0xFF) {
700                 /* power fault occurred, but it was benign */
701                 dbg("%s: power fault\n", __FUNCTION__);
702                 rc = POWER_FAILURE;
703                 func->status = 0;
704                 goto err_exit;
705         }
706
707         if (shpchp_configure_device(p_slot)) {
708                 err("Cannot add device at 0x%x:0x%x\n", p_slot->bus,
709                                 p_slot->device);
710                 goto err_exit;
711         }
712
713         shpchp_save_slot_config(ctrl, func);
714
715         func->status = 0;
716         func->switch_save = 0x10;
717         func->is_a_board = 0x01;
718         func->pwr_save = 1;
719
720         /* Wait for exclusive access to hardware */
721         down(&ctrl->crit_sect);
722
723         p_slot->hpc_ops->green_led_on(p_slot);
724
725         /* Wait for the command to complete */
726         wait_for_ctrl_irq (ctrl);
727
728         /* Done with exclusive hardware access */
729         up(&ctrl->crit_sect);
730
731         return 0;
732
733 err_exit:
734         /* Wait for exclusive access to hardware */
735         down(&ctrl->crit_sect);
736
737         /* turn off slot, turn on Amber LED, turn off Green LED */
738         rc = p_slot->hpc_ops->slot_disable(p_slot);
739         if (rc) {
740                 err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
741                 /* Done with exclusive hardware access */
742                 up(&ctrl->crit_sect);
743                 return rc;
744         }
745         /* Wait for the command to complete */
746         wait_for_ctrl_irq (ctrl);
747
748         rc = p_slot->hpc_ops->check_cmd_status(ctrl);
749         if (rc) {
750                 err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
751                 /* Done with exclusive hardware access */
752                 up(&ctrl->crit_sect);
753                 return rc;
754         }
755
756         /* Done with exclusive hardware access */
757         up(&ctrl->crit_sect);
758
759         return(rc);
760 }
761
762
763 /**
764  * remove_board - Turns off slot and LED's
765  *
766  */
767 static u32 remove_board(struct pci_func *func, struct controller *ctrl)
768 {
769         u8 device;
770         u8 hp_slot;
771         u32 rc;
772         struct slot *p_slot;
773
774         if (func == NULL)
775                 return(1);
776
777         if (shpchp_unconfigure_device(func))
778                 return(1);
779
780         device = func->device;
781
782         hp_slot = func->device - ctrl->slot_device_offset;
783         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
784
785         dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
786
787         /* Change status to shutdown */
788         if (func->is_a_board)
789                 func->status = 0x01;
790         func->configured = 0;
791
792         /* Wait for exclusive access to hardware */
793         down(&ctrl->crit_sect);
794
795         /* turn off slot, turn on Amber LED, turn off Green LED */
796         rc = p_slot->hpc_ops->slot_disable(p_slot);
797         if (rc) {
798                 err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
799                 /* Done with exclusive hardware access */
800                 up(&ctrl->crit_sect);
801                 return rc;
802         }
803         /* Wait for the command to complete */
804         wait_for_ctrl_irq (ctrl);
805
806         rc = p_slot->hpc_ops->check_cmd_status(ctrl);
807         if (rc) {
808                 err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
809                 /* Done with exclusive hardware access */
810                 up(&ctrl->crit_sect);
811                 return rc;  
812         }
813         
814         rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
815         if (rc) {
816                 err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
817                 /* Done with exclusive hardware access */
818                 up(&ctrl->crit_sect);
819                 return rc;
820         }
821         /* Wait for the command to complete */
822         wait_for_ctrl_irq (ctrl);
823
824         /* Done with exclusive hardware access */
825         up(&ctrl->crit_sect);
826
827         if (ctrl->add_support) {
828                 while (func) {
829                         if (is_bridge(func)) {
830                                 dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, 
831                                         func->device, func->function);
832                                 bridge_slot_remove(func);
833                         } else
834                                 dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, 
835                                         func->device, func->function);
836                                 slot_remove(func);
837
838                         func = shpchp_slot_find(ctrl->slot_bus, device, 0);
839                 }
840
841                 /* Setup slot structure with entry for empty slot */
842                 func = shpchp_slot_create(ctrl->slot_bus);
843
844                 if (func == NULL) {
845                         return(1);
846                 }
847
848                 func->bus = ctrl->slot_bus;
849                 func->device = device;
850                 func->function = 0;
851                 func->configured = 0;
852                 func->switch_save = 0x10;
853                 func->pwr_save = 0;
854                 func->is_a_board = 0;
855         }
856
857         return 0;
858 }
859
860
861 static void pushbutton_helper_thread (unsigned long data)
862 {
863         pushbutton_pending = data;
864
865         up(&event_semaphore);
866 }
867
868
869 /**
870  * shpchp_pushbutton_thread
871  *
872  * Scheduled procedure to handle blocking stuff for the pushbuttons
873  * Handles all pending events and exits.
874  *
875  */
876 static void shpchp_pushbutton_thread (unsigned long slot)
877 {
878         struct slot *p_slot = (struct slot *) slot;
879         u8 getstatus;
880         
881         pushbutton_pending = 0;
882
883         if (!p_slot) {
884                 dbg("%s: Error! slot NULL\n", __FUNCTION__);
885                 return;
886         }
887
888         p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
889         if (getstatus) {
890                 p_slot->state = POWEROFF_STATE;
891                 dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
892
893                 shpchp_disable_slot(p_slot);
894                 p_slot->state = STATIC_STATE;
895         } else {
896                 p_slot->state = POWERON_STATE;
897                 dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
898
899                 if (shpchp_enable_slot(p_slot)) {
900                         /* Wait for exclusive access to hardware */
901                         down(&p_slot->ctrl->crit_sect);
902
903                         p_slot->hpc_ops->green_led_off(p_slot);
904
905                         /* Wait for the command to complete */
906                         wait_for_ctrl_irq (p_slot->ctrl);
907
908                         /* Done with exclusive hardware access */
909                         up(&p_slot->ctrl->crit_sect);
910                 }
911                 p_slot->state = STATIC_STATE;
912         }
913
914         return;
915 }
916
917
918 /* this is the main worker thread */
919 static int event_thread(void* data)
920 {
921         struct controller *ctrl;
922         lock_kernel();
923         daemonize("shpchpd_event");
924         unlock_kernel();
925
926         while (1) {
927                 dbg("!!!!event_thread sleeping\n");
928                 down_interruptible (&event_semaphore);
929                 dbg("event_thread woken finished = %d\n", event_finished);
930                 if (event_finished || signal_pending(current))
931                         break;
932                 /* Do stuff here */
933                 if (pushbutton_pending)
934                         shpchp_pushbutton_thread(pushbutton_pending);
935                 else
936                         for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next)
937                                 interrupt_event_handler(ctrl);
938         }
939         dbg("event_thread signals exit\n");
940         up(&event_exit);
941         return 0;
942 }
943
944 int shpchp_event_start_thread (void)
945 {
946         int pid;
947
948         /* initialize our semaphores */
949         init_MUTEX_LOCKED(&event_exit);
950         event_finished=0;
951
952         init_MUTEX_LOCKED(&event_semaphore);
953         pid = kernel_thread(event_thread, NULL, 0);
954
955         if (pid < 0) {
956                 err ("Can't start up our event thread\n");
957                 return -1;
958         }
959         dbg("Our event thread pid = %d\n", pid);
960         return 0;
961 }
962
963
964 void shpchp_event_stop_thread (void)
965 {
966         event_finished = 1;
967         dbg("event_thread finish command given\n");
968         up(&event_semaphore);
969         dbg("wait for event_thread to exit\n");
970         down(&event_exit);
971 }
972
973
974 static int update_slot_info (struct slot *slot)
975 {
976         struct hotplug_slot_info *info;
977         int result;
978
979         info = kmalloc(sizeof(*info), GFP_KERNEL);
980         if (!info)
981                 return -ENOMEM;
982
983         slot->hpc_ops->get_power_status(slot, &(info->power_status));
984         slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
985         slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
986         slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
987
988         result = pci_hp_change_slot_info(slot->hotplug_slot, info);
989         kfree (info);
990         return result;
991 }
992
993 static void interrupt_event_handler(struct controller *ctrl)
994 {
995         int loop = 0;
996         int change = 1;
997         struct pci_func *func;
998         u8 hp_slot;
999         u8 getstatus;
1000         struct slot *p_slot;
1001
1002         dbg("%s:\n", __FUNCTION__);
1003         while (change) {
1004                 change = 0;
1005
1006                 for (loop = 0; loop < 10; loop++) {
1007                         if (ctrl->event_queue[loop].event_type != 0) {
1008                                 dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop, 
1009                                         ctrl->event_queue[loop].event_type);
1010                                 hp_slot = ctrl->event_queue[loop].hp_slot;
1011
1012                                 func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
1013
1014                                 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
1015
1016                                 dbg("%s: hp_slot %d, func %p, p_slot %p\n", __FUNCTION__, hp_slot, func, p_slot);
1017
1018                                 if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
1019                                         dbg("%s: button cancel\n", __FUNCTION__);
1020                                         del_timer(&p_slot->task_event);
1021
1022                                         switch (p_slot->state) {
1023                                         case BLINKINGOFF_STATE:
1024                                                 /* Wait for exclusive access to hardware */
1025                                                 down(&ctrl->crit_sect);
1026
1027                                                 p_slot->hpc_ops->green_led_on(p_slot);
1028                                                 /* Wait for the command to complete */
1029                                                 wait_for_ctrl_irq (ctrl);
1030
1031                                                 p_slot->hpc_ops->set_attention_status(p_slot, 0);
1032
1033                                                 /* Wait for the command to complete */
1034                                                 wait_for_ctrl_irq (ctrl);
1035
1036                                                 /* Done with exclusive hardware access */
1037                                                 up(&ctrl->crit_sect);
1038                                                 break;
1039                                         case BLINKINGON_STATE:
1040                                                 /* Wait for exclusive access to hardware */
1041                                                 down(&ctrl->crit_sect);
1042
1043                                                 p_slot->hpc_ops->green_led_off(p_slot);
1044                                                 /* Wait for the command to complete */
1045                                                 wait_for_ctrl_irq (ctrl);
1046
1047                                                 p_slot->hpc_ops->set_attention_status(p_slot, 0);
1048                                                 /* Wait for the command to complete */
1049                                                 wait_for_ctrl_irq (ctrl);
1050
1051                                                 /* Done with exclusive hardware access */
1052                                                 up(&ctrl->crit_sect);
1053
1054                                                 break;
1055                                         default:
1056                                                 warn("Not a valid state\n");
1057                                                 return;
1058                                         }
1059                                         info(msg_button_cancel, p_slot->number);
1060                                         p_slot->state = STATIC_STATE;
1061                                 } else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
1062                                         /* Button Pressed (No action on 1st press...) */
1063                                         dbg("%s: Button pressed\n", __FUNCTION__);
1064
1065                                         p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
1066                                         if (getstatus) {
1067                                                 /* slot is on */
1068                                                 dbg("%s: slot is on\n", __FUNCTION__);
1069                                                 p_slot->state = BLINKINGOFF_STATE;
1070                                                 info(msg_button_off, p_slot->number);
1071                                         } else {
1072                                                 /* slot is off */
1073                                                 dbg("%s: slot is off\n", __FUNCTION__);
1074                                                 p_slot->state = BLINKINGON_STATE;
1075                                                 info(msg_button_on, p_slot->number);
1076                                         }
1077
1078                                         /* Wait for exclusive access to hardware */
1079                                         down(&ctrl->crit_sect);
1080
1081                                         /* blink green LED and turn off amber */
1082                                         p_slot->hpc_ops->green_led_blink(p_slot);
1083                                         /* Wait for the command to complete */
1084                                         wait_for_ctrl_irq (ctrl);
1085                                         
1086                                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
1087
1088                                         /* Wait for the command to complete */
1089                                         wait_for_ctrl_irq (ctrl);
1090
1091                                         /* Done with exclusive hardware access */
1092                                         up(&ctrl->crit_sect);
1093
1094                                         init_timer(&p_slot->task_event);
1095                                         p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
1096                                         p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
1097                                         p_slot->task_event.data = (unsigned long) p_slot;
1098
1099                                         dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot);
1100                                         add_timer(&p_slot->task_event);
1101                                 } else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
1102                                         /***********POWER FAULT********************/
1103                                         dbg("%s: power fault\n", __FUNCTION__);
1104                                         /* Wait for exclusive access to hardware */
1105                                         down(&ctrl->crit_sect);
1106
1107                                         p_slot->hpc_ops->set_attention_status(p_slot, 1);
1108                                         /* Wait for the command to complete */
1109                                         wait_for_ctrl_irq (ctrl);
1110                                         
1111                                         p_slot->hpc_ops->green_led_off(p_slot);
1112                                         /* Wait for the command to complete */
1113                                         wait_for_ctrl_irq (ctrl);
1114
1115                                         /* Done with exclusive hardware access */
1116                                         up(&ctrl->crit_sect);
1117                                 } else {
1118                                         /* refresh notification */
1119                                         if (p_slot)
1120                                                 update_slot_info(p_slot);
1121                                 }
1122
1123                                 ctrl->event_queue[loop].event_type = 0;
1124
1125                                 change = 1;
1126                         }
1127                 }               /* End of FOR loop */
1128         }
1129
1130         return;
1131 }
1132
1133
1134 int shpchp_enable_slot (struct slot *p_slot)
1135 {
1136         u8 getstatus = 0;
1137         int rc;
1138         struct pci_func *func;
1139
1140         func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
1141         if (!func) {
1142                 dbg("%s: Error! slot NULL\n", __FUNCTION__);
1143                 return -ENODEV;
1144         }
1145
1146         /* Check to see if (latch closed, card present, power off) */
1147         down(&p_slot->ctrl->crit_sect);
1148         rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
1149         if (rc || !getstatus) {
1150                 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
1151                 up(&p_slot->ctrl->crit_sect);
1152                 return -ENODEV;
1153         }
1154         rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
1155         if (rc || getstatus) {
1156                 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
1157                 up(&p_slot->ctrl->crit_sect);
1158                 return -ENODEV;
1159         }
1160         rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
1161         if (rc || getstatus) {
1162                 info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
1163                 up(&p_slot->ctrl->crit_sect);
1164                 return -ENODEV;
1165         }
1166         up(&p_slot->ctrl->crit_sect);
1167
1168         slot_remove(func);
1169
1170         func = shpchp_slot_create(p_slot->bus);
1171         if (func == NULL)
1172                 return -ENOMEM;
1173
1174         func->bus = p_slot->bus;
1175         func->device = p_slot->device;
1176         func->function = 0;
1177         func->configured = 0;
1178         func->is_a_board = 1;
1179
1180         /* We have to save the presence info for these slots */
1181         p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
1182         p_slot->hpc_ops->get_power_status(p_slot, &(func->pwr_save));
1183         dbg("%s: func->pwr_save %x\n", __FUNCTION__, func->pwr_save);
1184         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
1185         func->switch_save = !getstatus? 0x10:0;
1186
1187         rc = board_added(func, p_slot->ctrl);
1188         if (rc) {
1189                 if (is_bridge(func))
1190                         bridge_slot_remove(func);
1191                 else
1192                         slot_remove(func);
1193
1194                 /* Setup slot structure with entry for empty slot */
1195                 func = shpchp_slot_create(p_slot->bus);
1196                 if (func == NULL)
1197                         return -ENOMEM; /* Out of memory */
1198
1199                 func->bus = p_slot->bus;
1200                 func->device = p_slot->device;
1201                 func->function = 0;
1202                 func->configured = 0;
1203                 func->is_a_board = 1;
1204
1205                 /* We have to save the presence info for these slots */
1206                 p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
1207                 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
1208                 func->switch_save = !getstatus? 0x10:0;
1209         }
1210
1211         if (p_slot)
1212                 update_slot_info(p_slot);
1213
1214         return rc;
1215 }
1216
1217
1218 int shpchp_disable_slot (struct slot *p_slot)
1219 {
1220         u8 class_code, header_type, BCR;
1221         u8 index = 0;
1222         u8 getstatus = 0;
1223         u32 rc = 0;
1224         int ret = 0;
1225         unsigned int devfn;
1226         struct pci_bus *pci_bus;
1227         struct pci_func *func;
1228
1229         if (!p_slot->ctrl)
1230                 return -ENODEV;
1231
1232         pci_bus = p_slot->ctrl->pci_dev->subordinate;
1233
1234         /* Check to see if (latch closed, card present, power on) */
1235         down(&p_slot->ctrl->crit_sect);
1236
1237         ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
1238         if (ret || !getstatus) {
1239                 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
1240                 up(&p_slot->ctrl->crit_sect);
1241                 return -ENODEV;
1242         }
1243         ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
1244         if (ret || getstatus) {
1245                 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
1246                 up(&p_slot->ctrl->crit_sect);
1247                 return -ENODEV;
1248         }
1249         ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
1250         if (ret || !getstatus) {
1251                 info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
1252                 up(&p_slot->ctrl->crit_sect);
1253                 return -ENODEV;
1254         }
1255         up(&p_slot->ctrl->crit_sect);
1256
1257         func = shpchp_slot_find(p_slot->bus, p_slot->device, index++);
1258
1259         /* Make sure there are no video controllers here
1260          * for all func of p_slot
1261          */
1262         while (func && !rc) {
1263                 pci_bus->number = func->bus;
1264                 devfn = PCI_DEVFN(func->device, func->function);
1265
1266                 /* Check the Class Code */
1267                 rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
1268                 if (rc)
1269                         return -ENODEV;
1270
1271                 if (class_code == PCI_BASE_CLASS_DISPLAY) {
1272                         /* Display/Video adapter (not supported) */
1273                         rc = REMOVE_NOT_SUPPORTED;
1274                 } else {
1275                         /* See if it's a bridge */
1276                         rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
1277                         if (rc)
1278                                 return -ENODEV;
1279
1280                         /* If it's a bridge, check the VGA Enable bit */
1281                         if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
1282                                 rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
1283                                 if (rc)
1284                                         return -ENODEV;
1285
1286                                 /* If the VGA Enable bit is set, remove isn't supported */
1287                                 if (BCR & PCI_BRIDGE_CTL_VGA) {
1288                                         rc = REMOVE_NOT_SUPPORTED;
1289                                 }
1290                         }
1291                 }
1292
1293                 func = shpchp_slot_find(p_slot->bus, p_slot->device, index++);
1294         }
1295
1296         func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
1297         if ((func != NULL) && !rc) {
1298                 rc = remove_board(func, p_slot->ctrl);
1299         } else if (!rc)
1300                 rc = -ENODEV;
1301
1302         if (p_slot)
1303                 update_slot_info(p_slot);
1304
1305         return rc;
1306 }
1307