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