- patches.apparmor/remove_suid_new_case_in_2.6.22.diff: Merge fix.
[linux-flexiantxendom0-3.2.10.git] / 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 }
202
203 /**
204  * board_added - Called after a board has been added to the system.
205  *
206  * Turns power on for the board
207  * Configures board
208  *
209  */
210 static int board_added(struct slot *p_slot)
211 {
212         u8 hp_slot;
213         int retval = 0;
214         struct controller *ctrl = p_slot->ctrl;
215
216         hp_slot = p_slot->device - ctrl->slot_device_offset;
217
218         dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
219                         __FUNCTION__, p_slot->device,
220                         ctrl->slot_device_offset, hp_slot);
221
222         if (POWER_CTRL(ctrl->ctrlcap)) {
223                 /* Power on slot */
224                 retval = p_slot->hpc_ops->power_on_slot(p_slot);
225                 if (retval)
226                         return retval;
227         }
228         
229         if (PWR_LED(ctrl->ctrlcap))
230                 p_slot->hpc_ops->green_led_blink(p_slot);
231
232         /* Wait for ~1 second */
233         msleep(1000);
234
235         /* Check link training status */
236         retval = p_slot->hpc_ops->check_lnk_status(ctrl);
237         if (retval) {
238                 err("%s: Failed to check link status\n", __FUNCTION__);
239                 set_slot_off(ctrl, p_slot);
240                 return retval;
241         }
242
243         /* Check for a power fault */
244         if (p_slot->hpc_ops->query_power_fault(p_slot)) {
245                 dbg("%s: power fault detected\n", __FUNCTION__);
246                 retval = POWER_FAILURE;
247                 goto err_exit;
248         }
249
250         retval = pciehp_configure_device(p_slot);
251         if (retval) {
252                 err("Cannot add device 0x%x:%x\n", p_slot->bus,
253                     p_slot->device);
254                 goto err_exit;
255         }
256
257         /*
258          * Some PCI Express root ports require fixup after hot-plug operation.
259          */
260         if (pcie_mch_quirk)
261                 pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
262         if (PWR_LED(ctrl->ctrlcap))
263                 p_slot->hpc_ops->green_led_on(p_slot);
264
265         return 0;
266
267 err_exit:
268         set_slot_off(ctrl, p_slot);
269         return retval;
270 }
271
272 /**
273  * remove_board - Turns off slot and LED's
274  *
275  */
276 static int remove_board(struct slot *p_slot)
277 {
278         u8 device;
279         u8 hp_slot;
280         int retval = 0;
281         struct controller *ctrl = p_slot->ctrl;
282
283         retval = pciehp_unconfigure_device(p_slot);
284         if (retval)
285                 return retval;
286
287         device = p_slot->device;
288         hp_slot = p_slot->device - ctrl->slot_device_offset;
289         p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
290
291         dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
292
293         if (POWER_CTRL(ctrl->ctrlcap)) {
294                 /* power off slot */
295                 retval = p_slot->hpc_ops->power_off_slot(p_slot);
296                 if (retval) {
297                         err("%s: Issue of Slot Disable command failed\n",
298                             __FUNCTION__);
299                         return retval;
300                 }
301         }
302
303         if (PWR_LED(ctrl->ctrlcap))
304                 /* turn off Green LED */
305                 p_slot->hpc_ops->green_led_off(p_slot);
306
307         return 0;
308 }
309
310 struct power_work_info {
311         struct slot *p_slot;
312         struct work_struct work;
313 };
314
315 /**
316  * pciehp_pushbutton_thread
317  *
318  * Scheduled procedure to handle blocking stuff for the pushbuttons
319  * Handles all pending events and exits.
320  *
321  */
322 static void pciehp_power_thread(struct work_struct *work)
323 {
324         struct power_work_info *info =
325                 container_of(work, struct power_work_info, work);
326         struct slot *p_slot = info->p_slot;
327
328         mutex_lock(&p_slot->lock);
329         switch (p_slot->state) {
330         case POWEROFF_STATE:
331                 mutex_unlock(&p_slot->lock);
332                 dbg("%s: disabling bus:device(%x:%x)\n",
333                     __FUNCTION__, p_slot->bus, p_slot->device);
334                 pciehp_disable_slot(p_slot);
335                 mutex_lock(&p_slot->lock);
336                 p_slot->state = STATIC_STATE;
337                 break;
338         case POWERON_STATE:
339                 mutex_unlock(&p_slot->lock);
340                 if (pciehp_enable_slot(p_slot) &&
341                     PWR_LED(p_slot->ctrl->ctrlcap))
342                         p_slot->hpc_ops->green_led_off(p_slot);
343                 mutex_lock(&p_slot->lock);
344                 p_slot->state = STATIC_STATE;
345                 break;
346         default:
347                 break;
348         }
349         mutex_unlock(&p_slot->lock);
350
351         kfree(info);
352 }
353
354 void pciehp_queue_pushbutton_work(struct work_struct *work)
355 {
356         struct slot *p_slot = container_of(work, struct slot, work.work);
357         struct power_work_info *info;
358
359         info = kmalloc(sizeof(*info), GFP_KERNEL);
360         if (!info) {
361                 err("%s: Cannot allocate memory\n", __FUNCTION__);
362                 return;
363         }
364         info->p_slot = p_slot;
365         INIT_WORK(&info->work, pciehp_power_thread);
366
367         mutex_lock(&p_slot->lock);
368         switch (p_slot->state) {
369         case BLINKINGOFF_STATE:
370                 p_slot->state = POWEROFF_STATE;
371                 break;
372         case BLINKINGON_STATE:
373                 p_slot->state = POWERON_STATE;
374                 break;
375         default:
376                 goto out;
377         }
378         queue_work(pciehp_wq, &info->work);
379  out:
380         mutex_unlock(&p_slot->lock);
381 }
382
383 static int update_slot_info(struct slot *slot)
384 {
385         struct hotplug_slot_info *info;
386         int result;
387
388         info = kmalloc(sizeof(*info), GFP_KERNEL);
389         if (!info)
390                 return -ENOMEM;
391
392         slot->hpc_ops->get_power_status(slot, &(info->power_status));
393         slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
394         slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
395         slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
396
397         result = pci_hp_change_slot_info(slot->hotplug_slot, info);
398         kfree (info);
399         return result;
400 }
401
402 /*
403  * Note: This function must be called with slot->lock held
404  */
405 static void handle_button_press_event(struct slot *p_slot)
406 {
407         struct controller *ctrl = p_slot->ctrl;
408         u8 getstatus;
409
410         switch (p_slot->state) {
411         case STATIC_STATE:
412                 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
413                 if (getstatus) {
414                         p_slot->state = BLINKINGOFF_STATE;
415                         info("PCI slot #%s - powering off due to button "
416                              "press.\n", p_slot->name);
417                 } else {
418                         p_slot->state = BLINKINGON_STATE;
419                         info("PCI slot #%s - powering on due to button "
420                              "press.\n", p_slot->name);
421                 }
422                 /* blink green LED and turn off amber */
423                 if (PWR_LED(ctrl->ctrlcap))
424                         p_slot->hpc_ops->green_led_blink(p_slot);
425                 if (ATTN_LED(ctrl->ctrlcap))
426                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
427
428                 schedule_delayed_work(&p_slot->work, 5*HZ);
429                 break;
430         case BLINKINGOFF_STATE:
431         case BLINKINGON_STATE:
432                 /*
433                  * Cancel if we are still blinking; this means that we
434                  * press the attention again before the 5 sec. limit
435                  * expires to cancel hot-add or hot-remove
436                  */
437                 info("Button cancel on Slot(%s)\n", p_slot->name);
438                 dbg("%s: button cancel\n", __FUNCTION__);
439                 cancel_delayed_work(&p_slot->work);
440                 if (p_slot->state == BLINKINGOFF_STATE) {
441                         if (PWR_LED(ctrl->ctrlcap))
442                                 p_slot->hpc_ops->green_led_on(p_slot);
443                 } else {
444                         if (PWR_LED(ctrl->ctrlcap))
445                                 p_slot->hpc_ops->green_led_off(p_slot);
446                 }
447                 if (ATTN_LED(ctrl->ctrlcap))
448                         p_slot->hpc_ops->set_attention_status(p_slot, 0);
449                 info("PCI slot #%s - action canceled due to button press\n",
450                      p_slot->name);
451                 p_slot->state = STATIC_STATE;
452                 break;
453         case POWEROFF_STATE:
454         case POWERON_STATE:
455                 /*
456                  * Ignore if the slot is on power-on or power-off state;
457                  * this means that the previous attention button action
458                  * to hot-add or hot-remove is undergoing
459                  */
460                 info("Button ignore on Slot(%s)\n", p_slot->name);
461                 update_slot_info(p_slot);
462                 break;
463         default:
464                 warn("Not a valid state\n");
465                 break;
466         }
467 }
468
469 /*
470  * Note: This function must be called with slot->lock held
471  */
472 static void handle_surprise_event(struct slot *p_slot)
473 {
474         u8 getstatus;
475         struct power_work_info *info;
476
477         info = kmalloc(sizeof(*info), GFP_KERNEL);
478         if (!info) {
479                 err("%s: Cannot allocate memory\n", __FUNCTION__);
480                 return;
481         }
482         info->p_slot = p_slot;
483         INIT_WORK(&info->work, pciehp_power_thread);
484
485         p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
486         if (!getstatus)
487                 p_slot->state = POWEROFF_STATE;
488         else
489                 p_slot->state = POWERON_STATE;
490
491         queue_work(pciehp_wq, &info->work);
492 }
493
494 static void interrupt_event_handler(struct work_struct *work)
495 {
496         struct event_info *info = container_of(work, struct event_info, work);
497         struct slot *p_slot = info->p_slot;
498         struct controller *ctrl = p_slot->ctrl;
499
500         mutex_lock(&p_slot->lock);
501         switch (info->event_type) {
502         case INT_BUTTON_PRESS:
503                 handle_button_press_event(p_slot);
504                 break;
505         case INT_POWER_FAULT:
506                 if (!POWER_CTRL(ctrl->ctrlcap))
507                         break;
508                 if (ATTN_LED(ctrl->ctrlcap))
509                         p_slot->hpc_ops->set_attention_status(p_slot, 1);
510                 if (PWR_LED(ctrl->ctrlcap))
511                         p_slot->hpc_ops->green_led_off(p_slot);
512                 break;
513         case INT_PRESENCE_ON:
514         case INT_PRESENCE_OFF:
515                 if (!HP_SUPR_RM(ctrl->ctrlcap))
516                         break;
517                 dbg("Surprise Removal\n");
518                 update_slot_info(p_slot);
519                 handle_surprise_event(p_slot);
520                 break;
521         default:
522                 update_slot_info(p_slot);
523                 break;
524         }
525         mutex_unlock(&p_slot->lock);
526
527         kfree(info);
528 }
529
530 int pciehp_enable_slot(struct slot *p_slot)
531 {
532         u8 getstatus = 0;
533         int rc;
534
535         /* Check to see if (latch closed, card present, power off) */
536         mutex_lock(&p_slot->ctrl->crit_sect);
537
538         rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
539         if (rc || !getstatus) {
540                 info("%s: no adapter on slot(%s)\n", __FUNCTION__,
541                      p_slot->name);
542                 mutex_unlock(&p_slot->ctrl->crit_sect);
543                 return -ENODEV;
544         }
545         if (MRL_SENS(p_slot->ctrl->ctrlcap)) {  
546                 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
547                 if (rc || getstatus) {
548                         info("%s: latch open on slot(%s)\n", __FUNCTION__,
549                              p_slot->name);
550                         mutex_unlock(&p_slot->ctrl->crit_sect);
551                         return -ENODEV;
552                 }
553         }
554         
555         if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {        
556                 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
557                 if (rc || getstatus) {
558                         info("%s: already enabled on slot(%s)\n", __FUNCTION__,
559                              p_slot->name);
560                         mutex_unlock(&p_slot->ctrl->crit_sect);
561                         return -EINVAL;
562                 }
563         }
564
565         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
566
567         rc = board_added(p_slot);
568         if (rc) {
569                 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
570         }
571
572         update_slot_info(p_slot);
573
574         mutex_unlock(&p_slot->ctrl->crit_sect);
575         return rc;
576 }
577
578
579 int pciehp_disable_slot(struct slot *p_slot)
580 {
581         u8 getstatus = 0;
582         int ret = 0;
583
584         if (!p_slot->ctrl)
585                 return 1;
586
587         /* Check to see if (latch closed, card present, power on) */
588         mutex_lock(&p_slot->ctrl->crit_sect);
589
590         if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {       
591                 ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
592                 if (ret || !getstatus) {
593                         info("%s: no adapter on slot(%s)\n", __FUNCTION__,
594                              p_slot->name);
595                         mutex_unlock(&p_slot->ctrl->crit_sect);
596                         return -ENODEV;
597                 }
598         }
599
600         if (MRL_SENS(p_slot->ctrl->ctrlcap)) {  
601                 ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
602                 if (ret || getstatus) {
603                         info("%s: latch open on slot(%s)\n", __FUNCTION__,
604                              p_slot->name);
605                         mutex_unlock(&p_slot->ctrl->crit_sect);
606                         return -ENODEV;
607                 }
608         }
609
610         if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {        
611                 ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
612                 if (ret || !getstatus) {
613                         info("%s: already disabled slot(%s)\n", __FUNCTION__,
614                              p_slot->name);
615                         mutex_unlock(&p_slot->ctrl->crit_sect);
616                         return -EINVAL;
617                 }
618         }
619
620         ret = remove_board(p_slot);
621         update_slot_info(p_slot);
622
623         mutex_unlock(&p_slot->ctrl->crit_sect);
624         return ret;
625 }
626
627 int pciehp_sysfs_enable_slot(struct slot *p_slot)
628 {
629         int retval = -ENODEV;
630
631         mutex_lock(&p_slot->lock);
632         switch (p_slot->state) {
633         case BLINKINGON_STATE:
634                 cancel_delayed_work(&p_slot->work);
635         case STATIC_STATE:
636                 p_slot->state = POWERON_STATE;
637                 mutex_unlock(&p_slot->lock);
638                 retval = pciehp_enable_slot(p_slot);
639                 mutex_lock(&p_slot->lock);
640                 p_slot->state = STATIC_STATE;
641                 break;
642         case POWERON_STATE:
643                 info("Slot %s is already in powering on state\n",
644                      p_slot->name);
645                 break;
646         case BLINKINGOFF_STATE:
647         case POWEROFF_STATE:
648                 info("Already enabled on slot %s\n", p_slot->name);
649                 break;
650         default:
651                 err("Not a valid state on slot %s\n", p_slot->name);
652                 break;
653         }
654         mutex_unlock(&p_slot->lock);
655
656         return retval;
657 }
658
659 int pciehp_sysfs_disable_slot(struct slot *p_slot)
660 {
661         int retval = -ENODEV;
662
663         mutex_lock(&p_slot->lock);
664         switch (p_slot->state) {
665         case BLINKINGOFF_STATE:
666                 cancel_delayed_work(&p_slot->work);
667         case STATIC_STATE:
668                 p_slot->state = POWEROFF_STATE;
669                 mutex_unlock(&p_slot->lock);
670                 retval = pciehp_disable_slot(p_slot);
671                 mutex_lock(&p_slot->lock);
672                 p_slot->state = STATIC_STATE;
673                 break;
674         case POWEROFF_STATE:
675                 info("Slot %s is already in powering off state\n",
676                      p_slot->name);
677                 break;
678         case BLINKINGON_STATE:
679         case POWERON_STATE:
680                 info("Already disabled on slot %s\n", p_slot->name);
681                 break;
682         default:
683                 err("Not a valid state on slot %s\n", p_slot->name);
684                 break;
685         }
686         mutex_unlock(&p_slot->lock);
687
688         return retval;
689 }