aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/shpchp_ctrl.c
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2006-02-21 18:45:45 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-03-23 17:35:13 -0500
commitf7391f5325ea744f0632f7ef39a90085162743ac (patch)
treea7368b2ca639211743ba7fbc0dab7a9efaea02b7 /drivers/pci/hotplug/shpchp_ctrl.c
parent68c0b671491088d79611fa965bbf94b3bc0024a4 (diff)
[PATCH] shpchp: event handling rework
The event handler of SHPCHP 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 by 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/shpchp_ctrl.c')
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c313
1 files changed, 89 insertions, 224 deletions
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index b709328a4145..2411f3bd08da 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -32,44 +32,46 @@
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 "shpchp.h" 37#include "shpchp.h"
37 38
38static void interrupt_event_handler(struct controller *ctrl); 39static void interrupt_event_handler(void *data);
39 40
40static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ 41static 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 */ 42{
42static int event_finished; 43 struct event_info *info;
43static unsigned long pushbutton_pending; /* = 0 */ 44
45 info = kmalloc(sizeof(*info), GFP_ATOMIC);
46 if (!info)
47 return -ENOMEM;
48
49 info->event_type = event_type;
50 info->p_slot = p_slot;
51 INIT_WORK(&info->work, interrupt_event_handler, info);
52
53 queue_work(shpchp_wq, &info->work);
54
55 return 0;
56}
44 57
45u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) 58u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
46{ 59{
47 struct controller *ctrl = (struct controller *) inst_id; 60 struct controller *ctrl = (struct controller *) inst_id;
48 struct slot *p_slot; 61 struct slot *p_slot;
49 u8 rc = 0; 62 u32 event_type;
50 u8 getstatus;
51 struct event_info *taskInfo;
52 63
53 /* Attention Button Change */ 64 /* Attention Button Change */
54 dbg("shpchp: Attention button interrupt received.\n"); 65 dbg("shpchp: Attention button interrupt received.\n");
55 66
56 /* This is the structure that tells the worker thread what to do */
57 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
58 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 67 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
59
60 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 68 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
61 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
62
63 ctrl->next_event = (ctrl->next_event + 1) % 10;
64 taskInfo->hp_slot = hp_slot;
65
66 rc++;
67 69
68 /* 70 /*
69 * Button pressed - See if need to TAKE ACTION!!! 71 * Button pressed - See if need to TAKE ACTION!!!
70 */ 72 */
71 info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); 73 info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
72 taskInfo->event_type = INT_BUTTON_PRESS; 74 event_type = INT_BUTTON_PRESS;
73 75
74 if ((p_slot->state == BLINKINGON_STATE) 76 if ((p_slot->state == BLINKINGON_STATE)
75 || (p_slot->state == BLINKINGOFF_STATE)) { 77 || (p_slot->state == BLINKINGOFF_STATE)) {
@@ -77,7 +79,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
77 * attention again before the 5 sec. limit expires to cancel hot-add 79 * attention again before the 5 sec. limit expires to cancel hot-add
78 * or hot-remove 80 * or hot-remove
79 */ 81 */
80 taskInfo->event_type = INT_BUTTON_CANCEL; 82 event_type = INT_BUTTON_CANCEL;
81 info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); 83 info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
82 } else if ((p_slot->state == POWERON_STATE) 84 } else if ((p_slot->state == POWERON_STATE)
83 || (p_slot->state == POWEROFF_STATE)) { 85 || (p_slot->state == POWEROFF_STATE)) {
@@ -85,12 +87,11 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
85 * means that the previous attention button action to hot-add or 87 * means that the previous attention button action to hot-add or
86 * hot-remove is undergoing 88 * hot-remove is undergoing
87 */ 89 */
88 taskInfo->event_type = INT_BUTTON_IGNORE; 90 event_type = INT_BUTTON_IGNORE;
89 info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); 91 info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
90 } 92 }
91 93
92 if (rc) 94 queue_interrupt_event(p_slot, event_type);
93 up(&event_semaphore); /* signal event thread that new event is posted */
94 95
95 return 0; 96 return 0;
96 97
@@ -100,21 +101,12 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
100{ 101{
101 struct controller *ctrl = (struct controller *) inst_id; 102 struct controller *ctrl = (struct controller *) inst_id;
102 struct slot *p_slot; 103 struct slot *p_slot;
103 u8 rc = 0;
104 u8 getstatus; 104 u8 getstatus;
105 struct event_info *taskInfo; 105 u32 event_type;
106 106
107 /* Switch Change */ 107 /* Switch Change */
108 dbg("shpchp: Switch interrupt received.\n"); 108 dbg("shpchp: Switch interrupt received.\n");
109 109
110 /* This is the structure that tells the worker thread
111 * what to do
112 */
113 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
114 ctrl->next_event = (ctrl->next_event + 1) % 10;
115 taskInfo->hp_slot = hp_slot;
116
117 rc++;
118 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 110 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
119 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 111 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
120 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 112 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
@@ -126,9 +118,9 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
126 * Switch opened 118 * Switch opened
127 */ 119 */
128 info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); 120 info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
129 taskInfo->event_type = INT_SWITCH_OPEN; 121 event_type = INT_SWITCH_OPEN;
130 if (p_slot->pwr_save && p_slot->presence_save) { 122 if (p_slot->pwr_save && p_slot->presence_save) {
131 taskInfo->event_type = INT_POWER_FAULT; 123 event_type = INT_POWER_FAULT;
132 err("Surprise Removal of card\n"); 124 err("Surprise Removal of card\n");
133 } 125 }
134 } else { 126 } else {
@@ -136,34 +128,23 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
136 * Switch closed 128 * Switch closed
137 */ 129 */
138 info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); 130 info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
139 taskInfo->event_type = INT_SWITCH_CLOSE; 131 event_type = INT_SWITCH_CLOSE;
140 } 132 }
141 133
142 if (rc) 134 queue_interrupt_event(p_slot, event_type);
143 up(&event_semaphore); /* signal event thread that new event is posted */
144 135
145 return rc; 136 return 1;
146} 137}
147 138
148u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) 139u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
149{ 140{
150 struct controller *ctrl = (struct controller *) inst_id; 141 struct controller *ctrl = (struct controller *) inst_id;
151 struct slot *p_slot; 142 struct slot *p_slot;
152 u8 rc = 0; 143 u32 event_type;
153 /*u8 temp_byte;*/
154 struct event_info *taskInfo;
155 144
156 /* Presence Change */ 145 /* Presence Change */
157 dbg("shpchp: Presence/Notify input change.\n"); 146 dbg("shpchp: Presence/Notify input change.\n");
158 147
159 /* This is the structure that tells the worker thread
160 * what to do
161 */
162 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
163 ctrl->next_event = (ctrl->next_event + 1) % 10;
164 taskInfo->hp_slot = hp_slot;
165
166 rc++;
167 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 148 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
168 149
169 /* 150 /*
@@ -175,39 +156,29 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
175 * Card Present 156 * Card Present
176 */ 157 */
177 info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); 158 info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
178 taskInfo->event_type = INT_PRESENCE_ON; 159 event_type = INT_PRESENCE_ON;
179 } else { 160 } else {
180 /* 161 /*
181 * Not Present 162 * Not Present
182 */ 163 */
183 info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); 164 info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
184 taskInfo->event_type = INT_PRESENCE_OFF; 165 event_type = INT_PRESENCE_OFF;
185 } 166 }
186 167
187 if (rc) 168 queue_interrupt_event(p_slot, event_type);
188 up(&event_semaphore); /* signal event thread that new event is posted */
189 169
190 return rc; 170 return 1;
191} 171}
192 172
193u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) 173u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
194{ 174{
195 struct controller *ctrl = (struct controller *) inst_id; 175 struct controller *ctrl = (struct controller *) inst_id;
196 struct slot *p_slot; 176 struct slot *p_slot;
197 u8 rc = 0; 177 u32 event_type;
198 struct event_info *taskInfo;
199 178
200 /* Power fault */ 179 /* Power fault */
201 dbg("shpchp: Power fault interrupt received.\n"); 180 dbg("shpchp: Power fault interrupt received.\n");
202 181
203 /* This is the structure that tells the worker thread
204 * what to do
205 */
206 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
207 ctrl->next_event = (ctrl->next_event + 1) % 10;
208 taskInfo->hp_slot = hp_slot;
209
210 rc++;
211 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 182 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
212 183
213 if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { 184 if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
@@ -216,21 +187,21 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
216 */ 187 */
217 info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); 188 info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
218 p_slot->status = 0x00; 189 p_slot->status = 0x00;
219 taskInfo->event_type = INT_POWER_FAULT_CLEAR; 190 event_type = INT_POWER_FAULT_CLEAR;
220 } else { 191 } else {
221 /* 192 /*
222 * Power fault 193 * Power fault
223 */ 194 */
224 info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); 195 info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
225 taskInfo->event_type = INT_POWER_FAULT; 196 event_type = INT_POWER_FAULT;
226 /* set power fault status for this board */ 197 /* set power fault status for this board */
227 p_slot->status = 0xFF; 198 p_slot->status = 0xFF;
228 info("power fault bit %x set\n", hp_slot); 199 info("power fault bit %x set\n", hp_slot);
229 } 200 }
230 if (rc)
231 up(&event_semaphore); /* signal event thread that new event is posted */
232 201
233 return rc; 202 queue_interrupt_event(p_slot, event_type);
203
204 return 1;
234} 205}
235 206
236/* The following routines constitute the bulk of the 207/* The following routines constitute the bulk of the
@@ -521,14 +492,6 @@ static int remove_board(struct slot *p_slot)
521} 492}
522 493
523 494
524static void pushbutton_helper_thread (unsigned long data)
525{
526 pushbutton_pending = data;
527
528 up(&event_semaphore);
529}
530
531
532/** 495/**
533 * shpchp_pushbutton_thread 496 * shpchp_pushbutton_thread
534 * 497 *
@@ -536,90 +499,24 @@ static void pushbutton_helper_thread (unsigned long data)
536 * Handles all pending events and exits. 499 * Handles all pending events and exits.
537 * 500 *
538 */ 501 */
539static void shpchp_pushbutton_thread (unsigned long slot) 502void shpchp_pushbutton_thread(void *data)
540{ 503{
541 struct slot *p_slot = (struct slot *) slot; 504 struct slot *p_slot = data;
542 u8 getstatus; 505 u8 getstatus;
543
544 pushbutton_pending = 0;
545
546 if (!p_slot) {
547 dbg("%s: Error! slot NULL\n", __FUNCTION__);
548 return;
549 }
550 506
551 p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 507 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
552 if (getstatus) { 508 if (getstatus) {
553 p_slot->state = POWEROFF_STATE; 509 p_slot->state = POWEROFF_STATE;
554
555 shpchp_disable_slot(p_slot); 510 shpchp_disable_slot(p_slot);
556 p_slot->state = STATIC_STATE; 511 p_slot->state = STATIC_STATE;
557 } else { 512 } else {
558 p_slot->state = POWERON_STATE; 513 p_slot->state = POWERON_STATE;
559
560 if (shpchp_enable_slot(p_slot)) 514 if (shpchp_enable_slot(p_slot))
561 p_slot->hpc_ops->green_led_off(p_slot); 515 p_slot->hpc_ops->green_led_off(p_slot);
562
563 p_slot->state = STATIC_STATE; 516 p_slot->state = STATIC_STATE;
564 } 517 }
565
566 return;
567}
568
569
570/* this is the main worker thread */
571static int event_thread(void* data)
572{
573 struct controller *ctrl;
574 lock_kernel();
575 daemonize("shpchpd_event");
576 unlock_kernel();
577
578 while (1) {
579 dbg("!!!!event_thread sleeping\n");
580 down_interruptible (&event_semaphore);
581 dbg("event_thread woken finished = %d\n", event_finished);
582 if (event_finished || signal_pending(current))
583 break;
584 /* Do stuff here */
585 if (pushbutton_pending)
586 shpchp_pushbutton_thread(pushbutton_pending);
587 else
588 list_for_each_entry(ctrl, &shpchp_ctrl_list, ctrl_list)
589 interrupt_event_handler(ctrl);
590 }
591 dbg("event_thread signals exit\n");
592 up(&event_exit);
593 return 0;
594}
595
596int shpchp_event_start_thread (void)
597{
598 int pid;
599
600 /* initialize our semaphores */
601 init_MUTEX_LOCKED(&event_exit);
602 event_finished=0;
603
604 init_MUTEX_LOCKED(&event_semaphore);
605 pid = kernel_thread(event_thread, NULL, 0);
606
607 if (pid < 0) {
608 err ("Can't start up our event thread\n");
609 return -1;
610 }
611 return 0;
612}
613
614
615void shpchp_event_stop_thread (void)
616{
617 event_finished = 1;
618 up(&event_semaphore);
619 down(&event_exit);
620} 518}
621 519
622
623static int update_slot_info (struct slot *slot) 520static int update_slot_info (struct slot *slot)
624{ 521{
625 struct hotplug_slot_info *info; 522 struct hotplug_slot_info *info;
@@ -639,91 +536,59 @@ static int update_slot_info (struct slot *slot)
639 return result; 536 return result;
640} 537}
641 538
642static void interrupt_event_handler(struct controller *ctrl) 539static void interrupt_event_handler(void *data)
643{ 540{
644 int loop = 0; 541 struct event_info *info = data;
645 int change = 1; 542 struct slot *p_slot = info->p_slot;
646 u8 hp_slot;
647 u8 getstatus; 543 u8 getstatus;
648 struct slot *p_slot;
649 544
650 while (change) { 545 switch (info->event_type) {
651 change = 0; 546 case INT_BUTTON_CANCEL:
652 547 dbg("%s: button cancel\n", __FUNCTION__);
653 for (loop = 0; loop < 10; loop++) { 548 cancel_delayed_work(&p_slot->work);
654 if (ctrl->event_queue[loop].event_type != 0) { 549 switch (p_slot->state) {
655 dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop, 550 case BLINKINGOFF_STATE:
656 ctrl->event_queue[loop].event_type); 551 p_slot->hpc_ops->green_led_on(p_slot);
657 hp_slot = ctrl->event_queue[loop].hp_slot; 552 p_slot->hpc_ops->set_attention_status(p_slot, 0);
658 553 break;
659 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 554 case BLINKINGON_STATE:
660 555 p_slot->hpc_ops->green_led_off(p_slot);
661 if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { 556 p_slot->hpc_ops->set_attention_status(p_slot, 0);
662 dbg("%s: button cancel\n", __FUNCTION__); 557 break;
663 del_timer(&p_slot->task_event); 558 default:
664 559 warn("Not a valid state\n");
665 switch (p_slot->state) { 560 return;
666 case BLINKINGOFF_STATE: 561 }
667 p_slot->hpc_ops->green_led_on(p_slot); 562 info(msg_button_cancel, p_slot->number);
668 p_slot->hpc_ops->set_attention_status(p_slot, 0); 563 p_slot->state = STATIC_STATE;
669 break; 564 break;
670 case BLINKINGON_STATE: 565 case INT_BUTTON_PRESS:
671 p_slot->hpc_ops->green_led_off(p_slot); 566 dbg("%s: Button pressed\n", __FUNCTION__);
672 p_slot->hpc_ops->set_attention_status(p_slot, 0); 567 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
673 break; 568 if (getstatus) {
674 default: 569 p_slot->state = BLINKINGOFF_STATE;
675 warn("Not a valid state\n"); 570 info(msg_button_off, p_slot->number);
676 return; 571 } else {
677 } 572 p_slot->state = BLINKINGON_STATE;
678 info(msg_button_cancel, p_slot->number); 573 info(msg_button_on, p_slot->number);
679 p_slot->state = STATIC_STATE; 574 }
680 } else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { 575 /* blink green LED and turn off amber */
681 /* Button Pressed (No action on 1st press...) */ 576 p_slot->hpc_ops->green_led_blink(p_slot);
682 dbg("%s: Button pressed\n", __FUNCTION__); 577 p_slot->hpc_ops->set_attention_status(p_slot, 0);
683
684 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
685 if (getstatus) {
686 /* slot is on */
687 dbg("%s: slot is on\n", __FUNCTION__);
688 p_slot->state = BLINKINGOFF_STATE;
689 info(msg_button_off, p_slot->number);
690 } else {
691 /* slot is off */
692 dbg("%s: slot is off\n", __FUNCTION__);
693 p_slot->state = BLINKINGON_STATE;
694 info(msg_button_on, p_slot->number);
695 }
696
697 /* blink green LED and turn off amber */
698 p_slot->hpc_ops->green_led_blink(p_slot);
699 p_slot->hpc_ops->set_attention_status(p_slot, 0);
700
701 init_timer(&p_slot->task_event);
702 p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
703 p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
704 p_slot->task_event.data = (unsigned long) p_slot;
705
706 dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot);
707 add_timer(&p_slot->task_event);
708 } else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
709 /***********POWER FAULT********************/
710 dbg("%s: power fault\n", __FUNCTION__);
711 p_slot->hpc_ops->set_attention_status(p_slot, 1);
712 p_slot->hpc_ops->green_led_off(p_slot);
713 } else {
714 /* refresh notification */
715 if (p_slot)
716 update_slot_info(p_slot);
717 }
718
719 ctrl->event_queue[loop].event_type = 0;
720 578
721 change = 1; 579 queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ);
722 } 580 break;
723 } /* End of FOR loop */ 581 case INT_POWER_FAULT:
582 dbg("%s: power fault\n", __FUNCTION__);
583 p_slot->hpc_ops->set_attention_status(p_slot, 1);
584 p_slot->hpc_ops->green_led_off(p_slot);
585 break;
586 default:
587 update_slot_info(p_slot);
588 break;
724 } 589 }
725 590
726 return; 591 kfree(info);
727} 592}
728 593
729 594