[PATCH] shpchp: event handling rework
[sfrench/cifs-2.6.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/module.h>
31 #include <linux/kernel.h>
32 #include <linux/types.h>
33 #include <linux/smp_lock.h>
34 #include <linux/pci.h>
35 #include <linux/workqueue.h>
36 #include "../pci.h"
37 #include "shpchp.h"
38
39 static void interrupt_event_handler(void *data);
40
41 static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
42 {
43         struct event_info *info;
44
45         info = kmalloc(sizeof(*info), GFP_ATOMIC);
46         if (!info)
47                 return -ENOMEM;
48
49         info->event_type = event_type;
50         info->p_slot = p_slot;
51         INIT_WORK(&info->work, interrupt_event_handler, info);
52
53         queue_work(shpchp_wq, &info->work);
54
55         return 0;
56 }
57
58 u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
59 {
60         struct controller *ctrl = (struct controller *) inst_id;
61         struct slot *p_slot;
62         u32 event_type;
63
64         /* Attention Button Change */
65         dbg("shpchp:  Attention button interrupt received.\n");
66         
67         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
68         p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
69
70         /*
71          *  Button pressed - See if need to TAKE ACTION!!!
72          */
73         info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
74         event_type = INT_BUTTON_PRESS;
75
76         if ((p_slot->state == BLINKINGON_STATE)
77             || (p_slot->state == BLINKINGOFF_STATE)) {
78                 /* Cancel if we are still blinking; this means that we press the
79                  * attention again before the 5 sec. limit expires to cancel hot-add
80                  * or hot-remove
81                  */
82                 event_type = INT_BUTTON_CANCEL;
83                 info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
84         } else if ((p_slot->state == POWERON_STATE)
85                    || (p_slot->state == POWEROFF_STATE)) {
86                 /* Ignore if the slot is on power-on or power-off state; this 
87                  * means that the previous attention button action to hot-add or
88                  * hot-remove is undergoing
89                  */
90                 event_type = INT_BUTTON_IGNORE;
91                 info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
92         }
93
94         queue_interrupt_event(p_slot, event_type);
95
96         return 0;
97
98 }
99
100 u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
101 {
102         struct controller *ctrl = (struct controller *) inst_id;
103         struct slot *p_slot;
104         u8 getstatus;
105         u32 event_type;
106
107         /* Switch Change */
108         dbg("shpchp:  Switch interrupt received.\n");
109
110         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
111         p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
112         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
113         dbg("%s: Card present %x Power status %x\n", __FUNCTION__,
114                 p_slot->presence_save, p_slot->pwr_save);
115
116         if (getstatus) {
117                 /*
118                  * Switch opened
119                  */
120                 info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
121                 event_type = INT_SWITCH_OPEN;
122                 if (p_slot->pwr_save && p_slot->presence_save) {
123                         event_type = INT_POWER_FAULT;
124                         err("Surprise Removal of card\n");
125                 }
126         } else {
127                 /*
128                  *  Switch closed
129                  */
130                 info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
131                 event_type = INT_SWITCH_CLOSE;
132         }
133
134         queue_interrupt_event(p_slot, event_type);
135
136         return 1;
137 }
138
139 u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
140 {
141         struct controller *ctrl = (struct controller *) inst_id;
142         struct slot *p_slot;
143         u32 event_type;
144
145         /* Presence Change */
146         dbg("shpchp:  Presence/Notify input change.\n");
147
148         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
149
150         /* 
151          * Save the presence state
152          */
153         p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
154         if (p_slot->presence_save) {
155                 /*
156                  * Card Present
157                  */
158                 info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
159                 event_type = INT_PRESENCE_ON;
160         } else {
161                 /*
162                  * Not Present
163                  */
164                 info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
165                 event_type = INT_PRESENCE_OFF;
166         }
167
168         queue_interrupt_event(p_slot, event_type);
169
170         return 1;
171 }
172
173 u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
174 {
175         struct controller *ctrl = (struct controller *) inst_id;
176         struct slot *p_slot;
177         u32 event_type;
178
179         /* Power fault */
180         dbg("shpchp:  Power fault interrupt received.\n");
181
182         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
183
184         if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
185                 /*
186                  * Power fault Cleared
187                  */
188                 info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
189                 p_slot->status = 0x00;
190                 event_type = INT_POWER_FAULT_CLEAR;
191         } else {
192                 /*
193                  *   Power fault
194                  */
195                 info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
196                 event_type = INT_POWER_FAULT;
197                 /* set power fault status for this board */
198                 p_slot->status = 0xFF;
199                 info("power fault bit %x set\n", hp_slot);
200         }
201
202         queue_interrupt_event(p_slot, event_type);
203
204         return 1;
205 }
206
207 /* The following routines constitute the bulk of the 
208    hotplug controller logic
209  */
210 static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
211                 enum pci_bus_speed speed)
212
213         int rc = 0;
214
215         dbg("%s: change to speed %d\n", __FUNCTION__, speed);
216         if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
217                 err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
218                 return WRONG_BUS_FREQUENCY;
219         }
220         return rc;
221 }
222
223 static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
224                 u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
225                 enum pci_bus_speed msp)
226
227         int rc = 0;
228         
229         if (flag != 0) { /* Other slots on the same bus are occupied */
230                 if ( asp < bsp ) {
231                         err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bsp, asp);
232                         return WRONG_BUS_FREQUENCY;
233                 }
234         } else {
235                 /* Other slots on the same bus are empty */
236                 if (msp == bsp) {
237                 /* if adapter_speed >= bus_speed, do nothing */
238                         if (asp < bsp) {
239                                 /* 
240                                 * Try to lower bus speed to accommodate the adapter if other slots 
241                                 * on the same controller are empty
242                                 */
243                                 if ((rc = change_bus_speed(ctrl, pslot, asp)))
244                                         return rc;
245                         } 
246                 } else {
247                         if (asp < msp) {
248                                 if ((rc = change_bus_speed(ctrl, pslot, asp)))
249                                         return rc;
250                         } else {
251                                 if ((rc = change_bus_speed(ctrl, pslot, msp)))
252                                         return rc;
253                         }
254                 }
255         }
256         return rc;
257 }
258
259 /**
260  * board_added - Called after a board has been added to the system.
261  *
262  * Turns power on for the board
263  * Configures board
264  *
265  */
266 static int board_added(struct slot *p_slot)
267 {
268         u8 hp_slot;
269         u8 slots_not_empty = 0;
270         int rc = 0;
271         enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed;
272         u8 pi, mode;
273         struct controller *ctrl = p_slot->ctrl;
274
275         hp_slot = p_slot->device - ctrl->slot_device_offset;
276
277         dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n",
278                         __FUNCTION__, p_slot->device,
279                         ctrl->slot_device_offset, hp_slot);
280
281         /* Power on slot without connecting to bus */
282         rc = p_slot->hpc_ops->power_on_slot(p_slot);
283         if (rc) {
284                 err("%s: Failed to power on slot\n", __FUNCTION__);
285                 return -1;
286         }
287         
288         if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
289                 if (slots_not_empty)
290                         return WRONG_BUS_FREQUENCY;
291                 
292                 if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
293                         err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
294                         return WRONG_BUS_FREQUENCY;
295                 }
296                 
297                 /* turn on board, blink green LED, turn off Amber LED */
298                 if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
299                         err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
300                         return rc;
301                 }
302         }
303  
304         rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
305         /* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */
306         /* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC,  0xa = PCI-X 133 Mhz 266, */
307         /* 0xd = PCI-X 133 Mhz 533 */
308         /* This encoding is different from the one used in cur_bus_speed & */
309         /* max_bus_speed */
310
311         if (rc  || adapter_speed == PCI_SPEED_UNKNOWN) {
312                 err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
313                 return WRONG_BUS_FREQUENCY;
314         }
315
316         rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed);
317         if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
318                 err("%s: Can't get bus operation speed\n", __FUNCTION__);
319                 return WRONG_BUS_FREQUENCY;
320         }
321
322         rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed);
323         if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
324                 err("%s: Can't get max bus operation speed\n", __FUNCTION__);
325                 max_bus_speed = bus_speed;
326         }
327
328         if ((rc  = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) {
329                 err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
330                 pi = 1;
331         }
332
333         /* Check if there are other slots or devices on the same bus */
334         if (!list_empty(&ctrl->pci_dev->subordinate->devices))
335                 slots_not_empty = 1;
336
337         dbg("%s: slots_not_empty %d, pi %d\n", __FUNCTION__, 
338                 slots_not_empty, pi);
339         dbg("adapter_speed %d, bus_speed %d, max_bus_speed %d\n", 
340                 adapter_speed, bus_speed, max_bus_speed);
341
342         if (pi == 2) {
343                 dbg("%s: In PI = %d\n", __FUNCTION__, pi);
344                 if ((rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode))) {
345                         err("%s: Can't get Mode1_ECC, set mode to 0\n", __FUNCTION__);
346                         mode = 0;
347                 }
348
349                 switch (adapter_speed) {
350                 case PCI_SPEED_133MHz_PCIX_533:
351                 case PCI_SPEED_133MHz_PCIX_266:
352                         if ((bus_speed != adapter_speed) &&
353                            ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
354                                 return rc;
355                         break;  
356                 case PCI_SPEED_133MHz_PCIX_ECC:
357                 case PCI_SPEED_133MHz_PCIX:
358                         if (mode) { /* Bus - Mode 1 ECC */
359                                 if ((bus_speed != 0x7) &&
360                                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
361                                         return rc;
362                         } else {
363                                 if ((bus_speed != 0x4) &&
364                                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
365                                         return rc;
366                         }
367                         break;
368                 case PCI_SPEED_66MHz_PCIX_ECC:
369                 case PCI_SPEED_66MHz_PCIX:
370                         if (mode) { /* Bus - Mode 1 ECC */
371                                 if ((bus_speed != 0x5) &&
372                                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
373                                         return rc;
374                         } else {
375                                 if ((bus_speed != 0x2) &&
376                                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
377                                         return rc;
378                         }
379                         break;
380                 case PCI_SPEED_66MHz:
381                         if ((bus_speed != 0x1) &&
382                            ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
383                                 return rc;
384                         break;  
385                 case PCI_SPEED_33MHz:
386                         if (bus_speed > 0x0) {
387                                 if (slots_not_empty == 0) {
388                                         if ((rc = change_bus_speed(ctrl, p_slot, adapter_speed)))
389                                                 return rc;
390                                 } else {
391                                         err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
392                                         return WRONG_BUS_FREQUENCY;
393                                 }
394                         }
395                         break;
396                 default:
397                         err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
398                         return WRONG_BUS_FREQUENCY;
399                 }
400         } else {
401                 /* If adpater_speed == bus_speed, nothing to do here */
402                 dbg("%s: In PI = %d\n", __FUNCTION__, pi);
403                 if ((adapter_speed != bus_speed) &&
404                    ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
405                                 return rc;
406         }
407
408         /* turn on board, blink green LED, turn off Amber LED */
409         if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
410                 err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
411                 return rc;
412         }
413
414         /* Wait for ~1 second */
415         msleep(1000);
416
417         dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status);
418         /* Check for a power fault */
419         if (p_slot->status == 0xFF) {
420                 /* power fault occurred, but it was benign */
421                 dbg("%s: power fault\n", __FUNCTION__);
422                 rc = POWER_FAILURE;
423                 p_slot->status = 0;
424                 goto err_exit;
425         }
426
427         if (shpchp_configure_device(p_slot)) {
428                 err("Cannot add device at 0x%x:0x%x\n", p_slot->bus,
429                                 p_slot->device);
430                 goto err_exit;
431         }
432
433         p_slot->status = 0;
434         p_slot->is_a_board = 0x01;
435         p_slot->pwr_save = 1;
436
437         p_slot->hpc_ops->green_led_on(p_slot);
438
439         return 0;
440
441 err_exit:
442         /* turn off slot, turn on Amber LED, turn off Green LED */
443         rc = p_slot->hpc_ops->slot_disable(p_slot);
444         if (rc) {
445                 err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
446                 return rc;
447         }
448
449         return(rc);
450 }
451
452
453 /**
454  * remove_board - Turns off slot and LED's
455  *
456  */
457 static int remove_board(struct slot *p_slot)
458 {
459         struct controller *ctrl = p_slot->ctrl;
460         u8 hp_slot;
461         int rc;
462
463         if (shpchp_unconfigure_device(p_slot))
464                 return(1);
465
466         hp_slot = p_slot->device - ctrl->slot_device_offset;
467         p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
468
469         dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
470
471         /* Change status to shutdown */
472         if (p_slot->is_a_board)
473                 p_slot->status = 0x01;
474
475         /* turn off slot, turn on Amber LED, turn off Green LED */
476         rc = p_slot->hpc_ops->slot_disable(p_slot);
477         if (rc) {
478                 err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
479                 return rc;
480         }
481         
482         rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
483         if (rc) {
484                 err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
485                 return rc;
486         }
487
488         p_slot->pwr_save = 0;
489         p_slot->is_a_board = 0;
490
491         return 0;
492 }
493
494
495 /**
496  * shpchp_pushbutton_thread
497  *
498  * Scheduled procedure to handle blocking stuff for the pushbuttons
499  * Handles all pending events and exits.
500  *
501  */
502 void shpchp_pushbutton_thread(void *data)
503 {
504         struct slot *p_slot = data;
505         u8 getstatus;
506
507         p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
508         if (getstatus) {
509                 p_slot->state = POWEROFF_STATE;
510                 shpchp_disable_slot(p_slot);
511                 p_slot->state = STATIC_STATE;
512         } else {
513                 p_slot->state = POWERON_STATE;
514                 if (shpchp_enable_slot(p_slot))
515                         p_slot->hpc_ops->green_led_off(p_slot);
516                 p_slot->state = STATIC_STATE;
517         }
518 }
519
520 static int update_slot_info (struct slot *slot)
521 {
522         struct hotplug_slot_info *info;
523         int result;
524
525         info = kmalloc(sizeof(*info), GFP_KERNEL);
526         if (!info)
527                 return -ENOMEM;
528
529         slot->hpc_ops->get_power_status(slot, &(info->power_status));
530         slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
531         slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
532         slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
533
534         result = pci_hp_change_slot_info(slot->hotplug_slot, info);
535         kfree (info);
536         return result;
537 }
538
539 static void interrupt_event_handler(void *data)
540 {
541         struct event_info *info = data;
542         struct slot *p_slot = info->p_slot;
543         u8 getstatus;
544
545         switch (info->event_type) {
546         case INT_BUTTON_CANCEL:
547                 dbg("%s: button cancel\n", __FUNCTION__);
548                 cancel_delayed_work(&p_slot->work);
549                 switch (p_slot->state) {
550                 case BLINKINGOFF_STATE:
551                         p_slot->hpc_ops->green_led_on(p_slot);
552                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
553                         break;
554                 case BLINKINGON_STATE:
555                         p_slot->hpc_ops->green_led_off(p_slot);
556                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
557                         break;
558                 default:
559                         warn("Not a valid state\n");
560                         return;
561                 }
562                 info(msg_button_cancel, p_slot->number);
563                 p_slot->state = STATIC_STATE;
564                 break;
565         case INT_BUTTON_PRESS:
566                 dbg("%s: Button pressed\n", __FUNCTION__);
567                 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
568                 if (getstatus) {
569                         p_slot->state = BLINKINGOFF_STATE;
570                         info(msg_button_off, p_slot->number);
571                 } else {
572                         p_slot->state = BLINKINGON_STATE;
573                         info(msg_button_on, p_slot->number);
574                 }
575                 /* blink green LED and turn off amber */
576                 p_slot->hpc_ops->green_led_blink(p_slot);
577                 p_slot->hpc_ops->set_attention_status(p_slot, 0);
578
579                 queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ);
580                 break;
581         case INT_POWER_FAULT:
582                 dbg("%s: power fault\n", __FUNCTION__);
583                 p_slot->hpc_ops->set_attention_status(p_slot, 1);
584                 p_slot->hpc_ops->green_led_off(p_slot);
585                 break;
586         default:
587                 update_slot_info(p_slot);
588                 break;
589         }
590
591         kfree(info);
592 }
593
594
595 int shpchp_enable_slot (struct slot *p_slot)
596 {
597         u8 getstatus = 0;
598         int rc, retval = -ENODEV;
599
600         /* Check to see if (latch closed, card present, power off) */
601         mutex_lock(&p_slot->ctrl->crit_sect);
602         rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
603         if (rc || !getstatus) {
604                 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
605                 goto out;
606         }
607         rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
608         if (rc || getstatus) {
609                 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
610                 goto out;
611         }
612         rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
613         if (rc || getstatus) {
614                 info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
615                 goto out;
616         }
617
618         p_slot->is_a_board = 1;
619
620         /* We have to save the presence info for these slots */
621         p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
622         p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save));
623         dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save);
624         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
625
626         if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
627             (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
628              && p_slot->ctrl->num_slots == 1) {
629                 /* handle amd pogo errata; this must be done before enable  */
630                 amd_pogo_errata_save_misc_reg(p_slot);
631                 retval = board_added(p_slot);
632                 /* handle amd pogo errata; this must be done after enable  */
633                 amd_pogo_errata_restore_misc_reg(p_slot);
634         } else
635                 retval = board_added(p_slot);
636
637         if (retval) {
638                 p_slot->hpc_ops->get_adapter_status(p_slot,
639                                 &(p_slot->presence_save));
640                 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
641         }
642
643         update_slot_info(p_slot);
644  out:
645         mutex_unlock(&p_slot->ctrl->crit_sect);
646         return retval;
647 }
648
649
650 int shpchp_disable_slot (struct slot *p_slot)
651 {
652         u8 getstatus = 0;
653         int rc, retval = -ENODEV;
654
655         if (!p_slot->ctrl)
656                 return -ENODEV;
657
658         /* Check to see if (latch closed, card present, power on) */
659         mutex_lock(&p_slot->ctrl->crit_sect);
660
661         rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
662         if (rc || !getstatus) {
663                 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
664                 goto out;
665         }
666         rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
667         if (rc || getstatus) {
668                 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
669                 goto out;
670         }
671         rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
672         if (rc || !getstatus) {
673                 info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
674                 goto out;
675         }
676
677         retval = remove_board(p_slot);
678         update_slot_info(p_slot);
679  out:
680         mutex_unlock(&p_slot->ctrl->crit_sect);
681         return retval;
682 }
683