aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/pciehp_ctrl.c
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2007-03-06 18:02:26 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-05-02 22:02:34 -0400
commit5d386e1ac4025b4bcc6bad6811e771cb76064dfe (patch)
treed673b9686ed60aa43c1c0f43abc8bc54d19b6649 /drivers/pci/hotplug/pciehp_ctrl.c
parentf7bdd12d234d9064bd0aa1b5610508959120a9b4 (diff)
pciehp: Event handling rework
The event handler of PCIEHP driver is unnecessarily very complex. In addition, current event handler can only a fixed number of events at the same time, and some of events would be lost if several number of events happened at the same time. This patch simplify the event handler using 'work queue', and it also fix the above-mentioned issue. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug/pciehp_ctrl.c')
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c616
1 files changed, 282 insertions, 334 deletions
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 4283ef56dbd9..91441e5ae631 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -32,92 +32,61 @@
32#include <linux/types.h> 32#include <linux/types.h>
33#include <linux/smp_lock.h> 33#include <linux/smp_lock.h>
34#include <linux/pci.h> 34#include <linux/pci.h>
35#include <linux/workqueue.h>
35#include "../pci.h" 36#include "../pci.h"
36#include "pciehp.h" 37#include "pciehp.h"
37 38
38static void interrupt_event_handler(struct controller *ctrl); 39static void interrupt_event_handler(struct work_struct *work);
40static int pciehp_enable_slot(struct slot *p_slot);
41static int pciehp_disable_slot(struct slot *p_slot);
39 42
40static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ 43static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
41static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */
42static int event_finished;
43static unsigned long pushbutton_pending; /* = 0 */
44static unsigned long surprise_rm_pending; /* = 0 */
45
46static inline char *slot_name(struct slot *p_slot)
47{ 44{
48 return p_slot->hotplug_slot->name; 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;
49} 58}
50 59
51u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) 60u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
52{ 61{
53 struct slot *p_slot; 62 struct slot *p_slot;
54 u8 rc = 0; 63 u32 event_type;
55 u8 getstatus;
56 struct event_info *taskInfo;
57 64
58 /* Attention Button Change */ 65 /* Attention Button Change */
59 dbg("pciehp: Attention button interrupt received.\n"); 66 dbg("pciehp: Attention button interrupt received.\n");
60
61 /* This is the structure that tells the worker thread what to do */
62 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
63 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
64
65 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
66
67 ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
68 taskInfo->hp_slot = hp_slot;
69 67
70 rc++; 68 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
71 69
72 /* 70 /*
73 * Button pressed - See if need to TAKE ACTION!!! 71 * Button pressed - See if need to TAKE ACTION!!!
74 */ 72 */
75 info("Button pressed on Slot(%s)\n", slot_name(p_slot)); 73 info("Button pressed on Slot(%s)\n", p_slot->name);
76 taskInfo->event_type = INT_BUTTON_PRESS; 74 event_type = INT_BUTTON_PRESS;
77
78 if ((p_slot->state == BLINKINGON_STATE)
79 || (p_slot->state == BLINKINGOFF_STATE)) {
80 /* Cancel if we are still blinking; this means that we press the
81 * attention again before the 5 sec. limit expires to cancel hot-add
82 * or hot-remove
83 */
84 taskInfo->event_type = INT_BUTTON_CANCEL;
85 info("Button cancel on Slot(%s)\n", slot_name(p_slot));
86 } else if ((p_slot->state == POWERON_STATE)
87 || (p_slot->state == POWEROFF_STATE)) {
88 /* Ignore if the slot is on power-on or power-off state; this
89 * means that the previous attention button action to hot-add or
90 * hot-remove is undergoing
91 */
92 taskInfo->event_type = INT_BUTTON_IGNORE;
93 info("Button ignore on Slot(%s)\n", slot_name(p_slot));
94 }
95 75
96 if (rc) 76 queue_interrupt_event(p_slot, event_type);
97 up(&event_semaphore); /* signal event thread that new event is posted */
98 77
99 return 0; 78 return 0;
100
101} 79}
102 80
103u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) 81u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
104{ 82{
105 struct slot *p_slot; 83 struct slot *p_slot;
106 u8 rc = 0;
107 u8 getstatus; 84 u8 getstatus;
108 struct event_info *taskInfo; 85 u32 event_type;
109 86
110 /* Switch Change */ 87 /* Switch Change */
111 dbg("pciehp: Switch interrupt received.\n"); 88 dbg("pciehp: Switch interrupt received.\n");
112 89
113 /* This is the structure that tells the worker thread
114 * what to do
115 */
116 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
117 ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
118 taskInfo->hp_slot = hp_slot;
119
120 rc++;
121 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 90 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
122 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 91 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
123 92
@@ -125,39 +94,30 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
125 /* 94 /*
126 * Switch opened 95 * Switch opened
127 */ 96 */
128 info("Latch open on Slot(%s)\n", slot_name(p_slot)); 97 info("Latch open on Slot(%s)\n", p_slot->name);
129 taskInfo->event_type = INT_SWITCH_OPEN; 98 event_type = INT_SWITCH_OPEN;
130 } else { 99 } else {
131 /* 100 /*
132 * Switch closed 101 * Switch closed
133 */ 102 */
134 info("Latch close on Slot(%s)\n", slot_name(p_slot)); 103 info("Latch close on Slot(%s)\n", p_slot->name);
135 taskInfo->event_type = INT_SWITCH_CLOSE; 104 event_type = INT_SWITCH_CLOSE;
136 } 105 }
137 106
138 if (rc) 107 queue_interrupt_event(p_slot, event_type);
139 up(&event_semaphore); /* signal event thread that new event is posted */
140 108
141 return rc; 109 return 1;
142} 110}
143 111
144u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) 112u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
145{ 113{
146 struct slot *p_slot; 114 struct slot *p_slot;
147 u8 presence_save, rc = 0; 115 u32 event_type;
148 struct event_info *taskInfo; 116 u8 presence_save;
149 117
150 /* Presence Change */ 118 /* Presence Change */
151 dbg("pciehp: Presence/Notify input change.\n"); 119 dbg("pciehp: Presence/Notify input change.\n");
152 120
153 /* This is the structure that tells the worker thread
154 * what to do
155 */
156 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
157 ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
158 taskInfo->hp_slot = hp_slot;
159
160 rc++;
161 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 121 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
162 122
163 /* Switch is open, assume a presence change 123 /* Switch is open, assume a presence change
@@ -168,59 +128,49 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
168 /* 128 /*
169 * Card Present 129 * Card Present
170 */ 130 */
171 info("Card present on Slot(%s)\n", slot_name(p_slot)); 131 info("Card present on Slot(%s)\n", p_slot->name);
172 taskInfo->event_type = INT_PRESENCE_ON; 132 event_type = INT_PRESENCE_ON;
173 } else { 133 } else {
174 /* 134 /*
175 * Not Present 135 * Not Present
176 */ 136 */
177 info("Card not present on Slot(%s)\n", slot_name(p_slot)); 137 info("Card not present on Slot(%s)\n", p_slot->name);
178 taskInfo->event_type = INT_PRESENCE_OFF; 138 event_type = INT_PRESENCE_OFF;
179 } 139 }
180 140
181 if (rc) 141 queue_interrupt_event(p_slot, event_type);
182 up(&event_semaphore); /* signal event thread that new event is posted */
183 142
184 return rc; 143 return 1;
185} 144}
186 145
187u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) 146u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
188{ 147{
189 struct slot *p_slot; 148 struct slot *p_slot;
190 u8 rc = 0; 149 u32 event_type;
191 struct event_info *taskInfo;
192 150
193 /* power fault */ 151 /* power fault */
194 dbg("pciehp: Power fault interrupt received.\n"); 152 dbg("pciehp: Power fault interrupt received.\n");
195 153
196 /* this is the structure that tells the worker thread
197 * what to do
198 */
199 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
200 ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
201 taskInfo->hp_slot = hp_slot;
202
203 rc++;
204 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 154 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
205 155
206 if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { 156 if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
207 /* 157 /*
208 * power fault Cleared 158 * power fault Cleared
209 */ 159 */
210 info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); 160 info("Power fault cleared on Slot(%s)\n", p_slot->name);
211 taskInfo->event_type = INT_POWER_FAULT_CLEAR; 161 event_type = INT_POWER_FAULT_CLEAR;
212 } else { 162 } else {
213 /* 163 /*
214 * power fault 164 * power fault
215 */ 165 */
216 info("Power fault on Slot(%s)\n", slot_name(p_slot)); 166 info("Power fault on Slot(%s)\n", p_slot->name);
217 taskInfo->event_type = INT_POWER_FAULT; 167 event_type = INT_POWER_FAULT;
218 info("power fault bit %x set\n", hp_slot); 168 info("power fault bit %x set\n", hp_slot);
219 } 169 }
220 if (rc)
221 up(&event_semaphore); /* signal event thread that new event is posted */
222 170
223 return rc; 171 queue_interrupt_event(p_slot, event_type);
172
173 return 1;
224} 174}
225 175
226/* The following routines constitute the bulk of the 176/* The following routines constitute the bulk of the
@@ -357,13 +307,10 @@ static int remove_board(struct slot *p_slot)
357 return 0; 307 return 0;
358} 308}
359 309
360 310struct power_work_info {
361static void pushbutton_helper_thread(unsigned long data) 311 struct slot *p_slot;
362{ 312 struct work_struct work;
363 pushbutton_pending = data; 313};
364
365 up(&event_semaphore);
366}
367 314
368/** 315/**
369 * pciehp_pushbutton_thread 316 * pciehp_pushbutton_thread
@@ -372,276 +319,214 @@ static void pushbutton_helper_thread(unsigned long data)
372 * Handles all pending events and exits. 319 * Handles all pending events and exits.
373 * 320 *
374 */ 321 */
375static void pciehp_pushbutton_thread(unsigned long slot) 322static void pciehp_power_thread(struct work_struct *work)
376{ 323{
377 struct slot *p_slot = (struct slot *) slot; 324 struct power_work_info *info =
378 u8 getstatus; 325 container_of(work, struct power_work_info, work);
379 326 struct slot *p_slot = info->p_slot;
380 pushbutton_pending = 0; 327
381 328 mutex_lock(&p_slot->lock);
382 if (!p_slot) { 329 switch (p_slot->state) {
383 dbg("%s: Error! slot NULL\n", __FUNCTION__); 330 case POWEROFF_STATE:
384 return; 331 mutex_unlock(&p_slot->lock);
385 } 332 dbg("%s: disabling bus:device(%x:%x)\n",
386 333 __FUNCTION__, p_slot->bus, p_slot->device);
387 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
388 if (getstatus) {
389 p_slot->state = POWEROFF_STATE;
390 dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__,
391 p_slot->bus, p_slot->device);
392
393 pciehp_disable_slot(p_slot); 334 pciehp_disable_slot(p_slot);
335 mutex_lock(&p_slot->lock);
394 p_slot->state = STATIC_STATE; 336 p_slot->state = STATIC_STATE;
395 } else { 337 break;
396 p_slot->state = POWERON_STATE; 338 case POWERON_STATE:
397 dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__, 339 mutex_unlock(&p_slot->lock);
398 p_slot->bus, p_slot->device);
399
400 if (pciehp_enable_slot(p_slot) && 340 if (pciehp_enable_slot(p_slot) &&
401 PWR_LED(p_slot->ctrl->ctrlcap)) 341 PWR_LED(p_slot->ctrl->ctrlcap))
402 p_slot->hpc_ops->green_led_off(p_slot); 342 p_slot->hpc_ops->green_led_off(p_slot);
403 343 mutex_lock(&p_slot->lock);
404 p_slot->state = STATIC_STATE; 344 p_slot->state = STATIC_STATE;
345 break;
346 default:
347 break;
405 } 348 }
349 mutex_unlock(&p_slot->lock);
406 350
407 return; 351 kfree(info);
408} 352}
409 353
410/** 354void queue_pushbutton_work(struct work_struct *work)
411 * pciehp_surprise_rm_thread
412 *
413 * Scheduled procedure to handle blocking stuff for the surprise removal
414 * Handles all pending events and exits.
415 *
416 */
417static void pciehp_surprise_rm_thread(unsigned long slot)
418{ 355{
419 struct slot *p_slot = (struct slot *) slot; 356 struct slot *p_slot = container_of(work, struct slot, work.work);
420 u8 getstatus; 357 struct power_work_info *info;
421
422 surprise_rm_pending = 0;
423 358
424 if (!p_slot) { 359 info = kmalloc(sizeof(*info), GFP_KERNEL);
425 dbg("%s: Error! slot NULL\n", __FUNCTION__); 360 if (!info) {
361 err("%s: Cannot allocate memory\n", __FUNCTION__);
426 return; 362 return;
427 } 363 }
364 info->p_slot = p_slot;
365 INIT_WORK(&info->work, pciehp_power_thread);
428 366
429 p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 367 mutex_lock(&p_slot->lock);
430 if (!getstatus) { 368 switch (p_slot->state) {
369 case BLINKINGOFF_STATE:
431 p_slot->state = POWEROFF_STATE; 370 p_slot->state = POWEROFF_STATE;
432 dbg("%s: removing bus:device(%x:%x)\n", 371 break;
433 __FUNCTION__, p_slot->bus, p_slot->device); 372 case BLINKINGON_STATE:
434
435 pciehp_disable_slot(p_slot);
436 p_slot->state = STATIC_STATE;
437 } else {
438 p_slot->state = POWERON_STATE; 373 p_slot->state = POWERON_STATE;
439 dbg("%s: adding bus:device(%x:%x)\n", 374 break;
440 __FUNCTION__, p_slot->bus, p_slot->device); 375 default:
441 376 goto out;
442 if (pciehp_enable_slot(p_slot) &&
443 PWR_LED(p_slot->ctrl->ctrlcap))
444 p_slot->hpc_ops->green_led_off(p_slot);
445
446 p_slot->state = STATIC_STATE;
447 } 377 }
448 378 queue_work(pciehp_wq, &info->work);
449 return; 379 out:
380 mutex_unlock(&p_slot->lock);
450} 381}
451 382
452
453
454/* this is the main worker thread */
455static int event_thread(void* data)
456{
457 struct controller *ctrl;
458 lock_kernel();
459 daemonize("pciehpd_event");
460
461 unlock_kernel();
462
463 while (1) {
464 dbg("!!!!event_thread sleeping\n");
465 down_interruptible (&event_semaphore);
466 dbg("event_thread woken finished = %d\n", event_finished);
467 if (event_finished || signal_pending(current))
468 break;
469 /* Do stuff here */
470 if (pushbutton_pending)
471 pciehp_pushbutton_thread(pushbutton_pending);
472 else if (surprise_rm_pending)
473 pciehp_surprise_rm_thread(surprise_rm_pending);
474 else
475 for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
476 interrupt_event_handler(ctrl);
477 }
478 dbg("event_thread signals exit\n");
479 up(&event_exit);
480 return 0;
481}
482
483int pciehp_event_start_thread(void)
484{
485 int pid;
486
487 /* initialize our semaphores */
488 init_MUTEX_LOCKED(&event_exit);
489 event_finished=0;
490
491 init_MUTEX_LOCKED(&event_semaphore);
492 pid = kernel_thread(event_thread, NULL, 0);
493
494 if (pid < 0) {
495 err ("Can't start up our event thread\n");
496 return -1;
497 }
498 return 0;
499}
500
501
502void pciehp_event_stop_thread(void)
503{
504 event_finished = 1;
505 up(&event_semaphore);
506 down(&event_exit);
507}
508
509
510static int update_slot_info(struct slot *slot) 383static int update_slot_info(struct slot *slot)
511{ 384{
512 struct hotplug_slot_info *info; 385 struct hotplug_slot_info *info;
513 /* char buffer[SLOT_NAME_SIZE]; */
514 int result; 386 int result;
515 387
516 info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); 388 info = kmalloc(sizeof(*info), GFP_KERNEL);
517 if (!info) 389 if (!info)
518 return -ENOMEM; 390 return -ENOMEM;
519 391
520 /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */
521
522 slot->hpc_ops->get_power_status(slot, &(info->power_status)); 392 slot->hpc_ops->get_power_status(slot, &(info->power_status));
523 slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); 393 slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
524 slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); 394 slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
525 slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); 395 slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
526 396
527 /* result = pci_hp_change_slot_info(buffer, info); */
528 result = pci_hp_change_slot_info(slot->hotplug_slot, info); 397 result = pci_hp_change_slot_info(slot->hotplug_slot, info);
529 kfree (info); 398 kfree (info);
530 return result; 399 return result;
531} 400}
532 401
533static void interrupt_event_handler(struct controller *ctrl) 402/*
403 * Note: This function must be called with slot->lock held
404 */
405static void handle_button_press_event(struct slot *p_slot)
534{ 406{
535 int loop = 0; 407 struct controller *ctrl = p_slot->ctrl;
536 int change = 1;
537 u8 hp_slot;
538 u8 getstatus; 408 u8 getstatus;
539 struct slot *p_slot;
540 409
541 while (change) { 410 switch (p_slot->state) {
542 change = 0; 411 case STATIC_STATE:
543 412 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
544 for (loop = 0; loop < MAX_EVENTS; loop++) { 413 if (getstatus) {
545 if (ctrl->event_queue[loop].event_type != 0) { 414 p_slot->state = BLINKINGOFF_STATE;
546 hp_slot = ctrl->event_queue[loop].hp_slot; 415 info("PCI slot #%s - powering off due to button "
547 416 "press.\n", p_slot->name);
548 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 417 } else {
549 418 p_slot->state = BLINKINGON_STATE;
550 if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { 419 info("PCI slot #%s - powering on due to button "
551 dbg("button cancel\n"); 420 "press.\n", p_slot->name);
552 del_timer(&p_slot->task_event); 421 }
553 422 /* blink green LED and turn off amber */
554 switch (p_slot->state) { 423 if (PWR_LED(ctrl->ctrlcap))
555 case BLINKINGOFF_STATE: 424 p_slot->hpc_ops->green_led_blink(p_slot);
556 if (PWR_LED(ctrl->ctrlcap)) 425 if (ATTN_LED(ctrl->ctrlcap))
557 p_slot->hpc_ops->green_led_on(p_slot); 426 p_slot->hpc_ops->set_attention_status(p_slot, 0);
558 427
559 if (ATTN_LED(ctrl->ctrlcap)) 428 schedule_delayed_work(&p_slot->work, 5*HZ);
560 p_slot->hpc_ops->set_attention_status(p_slot, 0); 429 break;
561 break; 430 case BLINKINGOFF_STATE:
562 case BLINKINGON_STATE: 431 case BLINKINGON_STATE:
563 if (PWR_LED(ctrl->ctrlcap)) 432 /*
564 p_slot->hpc_ops->green_led_off(p_slot); 433 * Cancel if we are still blinking; this means that we
565 434 * press the attention again before the 5 sec. limit
566 if (ATTN_LED(ctrl->ctrlcap)) 435 * expires to cancel hot-add or hot-remove
567 p_slot->hpc_ops->set_attention_status(p_slot, 0); 436 */
568 break; 437 info("Button cancel on Slot(%s)\n", p_slot->name);
569 default: 438 dbg("%s: button cancel\n", __FUNCTION__);
570 warn("Not a valid state\n"); 439 cancel_delayed_work(&p_slot->work);
571 return; 440 if (p_slot->state == BLINKINGOFF_STATE) {
572 } 441 if (PWR_LED(ctrl->ctrlcap))
573 info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot)); 442 p_slot->hpc_ops->green_led_on(p_slot);
574 p_slot->state = STATIC_STATE; 443 } else {
575 } 444 if (PWR_LED(ctrl->ctrlcap))
576 /* ***********Button Pressed (No action on 1st press...) */ 445 p_slot->hpc_ops->green_led_off(p_slot);
577 else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { 446 }
578 447 if (ATTN_LED(ctrl->ctrlcap))
579 if (ATTN_BUTTN(ctrl->ctrlcap)) { 448 p_slot->hpc_ops->set_attention_status(p_slot, 0);
580 dbg("Button pressed\n"); 449 info("PCI slot #%s - action canceled due to button press\n",
581 p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 450 p_slot->name);
582 if (getstatus) { 451 p_slot->state = STATIC_STATE;
583 /* slot is on */ 452 break;
584 dbg("slot is on\n"); 453 case POWEROFF_STATE:
585 p_slot->state = BLINKINGOFF_STATE; 454 case POWERON_STATE:
586 info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot)); 455 /*
587 } else { 456 * Ignore if the slot is on power-on or power-off state;
588 /* slot is off */ 457 * this means that the previous attention button action
589 dbg("slot is off\n"); 458 * to hot-add or hot-remove is undergoing
590 p_slot->state = BLINKINGON_STATE; 459 */
591 info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot)); 460 info("Button ignore on Slot(%s)\n", p_slot->name);
592 } 461 update_slot_info(p_slot);
593 462 break;
594 /* blink green LED and turn off amber */ 463 default:
595 if (PWR_LED(ctrl->ctrlcap)) 464 warn("Not a valid state\n");
596 p_slot->hpc_ops->green_led_blink(p_slot); 465 break;
597
598 if (ATTN_LED(ctrl->ctrlcap))
599 p_slot->hpc_ops->set_attention_status(p_slot, 0);
600
601 init_timer(&p_slot->task_event);
602 p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
603 p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
604 p_slot->task_event.data = (unsigned long) p_slot;
605
606 add_timer(&p_slot->task_event);
607 }
608 }
609 /***********POWER FAULT********************/
610 else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
611 if (POWER_CTRL(ctrl->ctrlcap)) {
612 dbg("power fault\n");
613 if (ATTN_LED(ctrl->ctrlcap))
614 p_slot->hpc_ops->set_attention_status(p_slot, 1);
615
616 if (PWR_LED(ctrl->ctrlcap))
617 p_slot->hpc_ops->green_led_off(p_slot);
618 }
619 }
620 /***********SURPRISE REMOVAL********************/
621 else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) ||
622 (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
623 if (HP_SUPR_RM(ctrl->ctrlcap)) {
624 dbg("Surprise Removal\n");
625 if (p_slot) {
626 surprise_rm_pending = (unsigned long) p_slot;
627 up(&event_semaphore);
628 update_slot_info(p_slot);
629 }
630 }
631 } else {
632 /* refresh notification */
633 if (p_slot)
634 update_slot_info(p_slot);
635 }
636
637 ctrl->event_queue[loop].event_type = 0;
638
639 change = 1;
640 }
641 } /* End of FOR loop */
642 } 466 }
643} 467}
644 468
469/*
470 * Note: This function must be called with slot->lock held
471 */
472static 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
494static 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
645int pciehp_enable_slot(struct slot *p_slot) 530int pciehp_enable_slot(struct slot *p_slot)
646{ 531{
647 u8 getstatus = 0; 532 u8 getstatus = 0;
@@ -653,7 +538,7 @@ int pciehp_enable_slot(struct slot *p_slot)
653 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 538 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
654 if (rc || !getstatus) { 539 if (rc || !getstatus) {
655 info("%s: no adapter on slot(%s)\n", __FUNCTION__, 540 info("%s: no adapter on slot(%s)\n", __FUNCTION__,
656 slot_name(p_slot)); 541 p_slot->name);
657 mutex_unlock(&p_slot->ctrl->crit_sect); 542 mutex_unlock(&p_slot->ctrl->crit_sect);
658 return -ENODEV; 543 return -ENODEV;
659 } 544 }
@@ -661,7 +546,7 @@ int pciehp_enable_slot(struct slot *p_slot)
661 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 546 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
662 if (rc || getstatus) { 547 if (rc || getstatus) {
663 info("%s: latch open on slot(%s)\n", __FUNCTION__, 548 info("%s: latch open on slot(%s)\n", __FUNCTION__,
664 slot_name(p_slot)); 549 p_slot->name);
665 mutex_unlock(&p_slot->ctrl->crit_sect); 550 mutex_unlock(&p_slot->ctrl->crit_sect);
666 return -ENODEV; 551 return -ENODEV;
667 } 552 }
@@ -671,7 +556,7 @@ int pciehp_enable_slot(struct slot *p_slot)
671 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 556 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
672 if (rc || getstatus) { 557 if (rc || getstatus) {
673 info("%s: already enabled on slot(%s)\n", __FUNCTION__, 558 info("%s: already enabled on slot(%s)\n", __FUNCTION__,
674 slot_name(p_slot)); 559 p_slot->name);
675 mutex_unlock(&p_slot->ctrl->crit_sect); 560 mutex_unlock(&p_slot->ctrl->crit_sect);
676 return -EINVAL; 561 return -EINVAL;
677 } 562 }
@@ -706,7 +591,7 @@ int pciehp_disable_slot(struct slot *p_slot)
706 ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 591 ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
707 if (ret || !getstatus) { 592 if (ret || !getstatus) {
708 info("%s: no adapter on slot(%s)\n", __FUNCTION__, 593 info("%s: no adapter on slot(%s)\n", __FUNCTION__,
709 slot_name(p_slot)); 594 p_slot->name);
710 mutex_unlock(&p_slot->ctrl->crit_sect); 595 mutex_unlock(&p_slot->ctrl->crit_sect);
711 return -ENODEV; 596 return -ENODEV;
712 } 597 }
@@ -716,7 +601,7 @@ int pciehp_disable_slot(struct slot *p_slot)
716 ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 601 ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
717 if (ret || getstatus) { 602 if (ret || getstatus) {
718 info("%s: latch open on slot(%s)\n", __FUNCTION__, 603 info("%s: latch open on slot(%s)\n", __FUNCTION__,
719 slot_name(p_slot)); 604 p_slot->name);
720 mutex_unlock(&p_slot->ctrl->crit_sect); 605 mutex_unlock(&p_slot->ctrl->crit_sect);
721 return -ENODEV; 606 return -ENODEV;
722 } 607 }
@@ -726,7 +611,7 @@ int pciehp_disable_slot(struct slot *p_slot)
726 ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 611 ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
727 if (ret || !getstatus) { 612 if (ret || !getstatus) {
728 info("%s: already disabled slot(%s)\n", __FUNCTION__, 613 info("%s: already disabled slot(%s)\n", __FUNCTION__,
729 slot_name(p_slot)); 614 p_slot->name);
730 mutex_unlock(&p_slot->ctrl->crit_sect); 615 mutex_unlock(&p_slot->ctrl->crit_sect);
731 return -EINVAL; 616 return -EINVAL;
732 } 617 }
@@ -739,3 +624,66 @@ int pciehp_disable_slot(struct slot *p_slot)
739 return ret; 624 return ret;
740} 625}
741 626
627int 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
659int 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}