OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [pci/] [hotplug/] [shpchp_ctrl.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.