aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
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
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')
-rw-r--r--drivers/pci/hotplug/shpchp.h13
-rw-r--r--drivers/pci/hotplug/shpchp_core.c49
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c313
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c10
4 files changed, 119 insertions, 266 deletions
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 6e1fb1bdc243..87db07cfebdf 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -46,6 +46,7 @@
46extern int shpchp_poll_mode; 46extern int shpchp_poll_mode;
47extern int shpchp_poll_time; 47extern int shpchp_poll_time;
48extern int shpchp_debug; 48extern int shpchp_debug;
49extern struct workqueue_struct *shpchp_wq;
49 50
50/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ 51/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
51#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0) 52#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
@@ -70,11 +71,13 @@ struct slot {
70 struct hotplug_slot *hotplug_slot; 71 struct hotplug_slot *hotplug_slot;
71 struct list_head slot_list; 72 struct list_head slot_list;
72 char name[SLOT_NAME_SIZE]; 73 char name[SLOT_NAME_SIZE];
74 struct work_struct work; /* work for button event */
73}; 75};
74 76
75struct event_info { 77struct event_info {
76 u32 event_type; 78 u32 event_type;
77 u8 hp_slot; 79 struct slot *p_slot;
80 struct work_struct work;
78}; 81};
79 82
80struct controller { 83struct controller {
@@ -85,11 +88,9 @@ struct controller {
85 int num_slots; /* Number of slots on ctlr */ 88 int num_slots; /* Number of slots on ctlr */
86 int slot_num_inc; /* 1 or -1 */ 89 int slot_num_inc; /* 1 or -1 */
87 struct pci_dev *pci_dev; 90 struct pci_dev *pci_dev;
88 struct event_info event_queue[10];
89 struct list_head slot_list; 91 struct list_head slot_list;
90 struct hpc_ops *hpc_ops; 92 struct hpc_ops *hpc_ops;
91 wait_queue_head_t queue; /* sleep & wake process */ 93 wait_queue_head_t queue; /* sleep & wake process */
92 u8 next_event;
93 u8 bus; 94 u8 bus;
94 u8 device; 95 u8 device;
95 u8 function; 96 u8 function;
@@ -180,9 +181,6 @@ struct hotplug_params {
180/* sysfs functions for the hotplug controller info */ 181/* sysfs functions for the hotplug controller info */
181extern void shpchp_create_ctrl_files (struct controller *ctrl); 182extern void shpchp_create_ctrl_files (struct controller *ctrl);
182 183
183/* controller functions */
184extern int shpchp_event_start_thread(void);
185extern void shpchp_event_stop_thread(void);
186extern int shpchp_enable_slot(struct slot *slot); 184extern int shpchp_enable_slot(struct slot *slot);
187extern int shpchp_disable_slot(struct slot *slot); 185extern int shpchp_disable_slot(struct slot *slot);
188 186
@@ -201,7 +199,8 @@ extern void get_hp_params_from_firmware(struct pci_dev *dev,
201extern int shpchprm_get_physical_slot_number(struct controller *ctrl, 199extern int shpchprm_get_physical_slot_number(struct controller *ctrl,
202 u32 *sun, u8 busnum, u8 devnum); 200 u32 *sun, u8 busnum, u8 devnum);
203extern void shpchp_remove_ctrl_files(struct controller *ctrl); 201extern void shpchp_remove_ctrl_files(struct controller *ctrl);
204 202extern void cleanup_slots(struct controller *ctrl);
203extern void shpchp_pushbutton_thread(void *data);
205 204
206/* Global variables */ 205/* Global variables */
207extern struct list_head shpchp_ctrl_list; 206extern struct list_head shpchp_ctrl_list;
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 8b21fc206712..5de659d23d1a 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -32,6 +32,7 @@
32#include <linux/kernel.h> 32#include <linux/kernel.h>
33#include <linux/types.h> 33#include <linux/types.h>
34#include <linux/pci.h> 34#include <linux/pci.h>
35#include <linux/workqueue.h>
35#include "shpchp.h" 36#include "shpchp.h"
36 37
37/* Global variables */ 38/* Global variables */
@@ -39,6 +40,7 @@ int shpchp_debug;
39int shpchp_poll_mode; 40int shpchp_poll_mode;
40int shpchp_poll_time; 41int shpchp_poll_time;
41LIST_HEAD(shpchp_ctrl_list); 42LIST_HEAD(shpchp_ctrl_list);
43struct workqueue_struct *shpchp_wq;
42 44
43#define DRIVER_VERSION "0.4" 45#define DRIVER_VERSION "0.4"
44#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" 46#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@@ -57,7 +59,6 @@ MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
57 59
58#define SHPC_MODULE_NAME "shpchp" 60#define SHPC_MODULE_NAME "shpchp"
59 61
60static int shpc_start_thread (void);
61static int set_attention_status (struct hotplug_slot *slot, u8 value); 62static int set_attention_status (struct hotplug_slot *slot, u8 value);
62static int enable_slot (struct hotplug_slot *slot); 63static int enable_slot (struct hotplug_slot *slot);
63static int disable_slot (struct hotplug_slot *slot); 64static int disable_slot (struct hotplug_slot *slot);
@@ -141,6 +142,7 @@ static int init_slots(struct controller *ctrl)
141 goto error_info; 142 goto error_info;
142 143
143 slot->number = sun; 144 slot->number = sun;
145 INIT_WORK(&slot->work, shpchp_pushbutton_thread, slot);
144 146
145 /* register this slot with the hotplug pci core */ 147 /* register this slot with the hotplug pci core */
146 hotplug_slot->private = slot; 148 hotplug_slot->private = slot;
@@ -176,7 +178,7 @@ error:
176 return retval; 178 return retval;
177} 179}
178 180
179static void cleanup_slots(struct controller *ctrl) 181void cleanup_slots(struct controller *ctrl)
180{ 182{
181 struct list_head *tmp; 183 struct list_head *tmp;
182 struct list_head *next; 184 struct list_head *next;
@@ -185,6 +187,8 @@ static void cleanup_slots(struct controller *ctrl)
185 list_for_each_safe(tmp, next, &ctrl->slot_list) { 187 list_for_each_safe(tmp, next, &ctrl->slot_list) {
186 slot = list_entry(tmp, struct slot, slot_list); 188 slot = list_entry(tmp, struct slot, slot_list);
187 list_del(&slot->slot_list); 189 list_del(&slot->slot_list);
190 cancel_delayed_work(&slot->work);
191 flush_workqueue(shpchp_wq);
188 pci_hp_deregister(slot->hotplug_slot); 192 pci_hp_deregister(slot->hotplug_slot);
189 } 193 }
190} 194}
@@ -400,7 +404,7 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
400 rc = get_ctlr_slot_config(ctrl); 404 rc = get_ctlr_slot_config(ctrl);
401 if (rc) { 405 if (rc) {
402 err(msg_initialization_err, rc); 406 err(msg_initialization_err, rc);
403 goto err_out_unmap_mmio_region; 407 goto err_out_release_ctlr;
404 } 408 }
405 first_device_num = ctrl->slot_device_offset; 409 first_device_num = ctrl->slot_device_offset;
406 num_ctlr_slots = ctrl->num_slots; 410 num_ctlr_slots = ctrl->num_slots;
@@ -411,7 +415,7 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
411 rc = init_slots(ctrl); 415 rc = init_slots(ctrl);
412 if (rc) { 416 if (rc) {
413 err(msg_initialization_err, 6); 417 err(msg_initialization_err, 6);
414 goto err_out_free_ctrl_slot; 418 goto err_out_release_ctlr;
415 } 419 }
416 420
417 /* Now hpc_functions (slot->hpc_ops->functions) are ready */ 421 /* Now hpc_functions (slot->hpc_ops->functions) are ready */
@@ -427,18 +431,13 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
427 ctrl->speed = PCI_SPEED_33MHz; 431 ctrl->speed = PCI_SPEED_33MHz;
428 } 432 }
429 433
430 /* Finish setting up the hot plug ctrl device */
431 ctrl->next_event = 0;
432
433 list_add(&ctrl->ctrl_list, &shpchp_ctrl_list); 434 list_add(&ctrl->ctrl_list, &shpchp_ctrl_list);
434 435
435 shpchp_create_ctrl_files(ctrl); 436 shpchp_create_ctrl_files(ctrl);
436 437
437 return 0; 438 return 0;
438 439
439err_out_free_ctrl_slot: 440err_out_release_ctlr:
440 cleanup_slots(ctrl);
441err_out_unmap_mmio_region:
442 ctrl->hpc_ops->release_ctlr(ctrl); 441 ctrl->hpc_ops->release_ctlr(ctrl);
443err_out_free_ctrl: 442err_out_free_ctrl:
444 kfree(ctrl); 443 kfree(ctrl);
@@ -446,21 +445,6 @@ err_out_none:
446 return -ENODEV; 445 return -ENODEV;
447} 446}
448 447
449static int shpc_start_thread(void)
450{
451 int retval = 0;
452
453 dbg("Initialize + Start the notification/polling mechanism \n");
454
455 retval = shpchp_event_start_thread();
456 if (retval) {
457 dbg("shpchp_event_start_thread() failed\n");
458 return retval;
459 }
460
461 return retval;
462}
463
464static void __exit unload_shpchpd(void) 448static void __exit unload_shpchpd(void)
465{ 449{
466 struct list_head *tmp; 450 struct list_head *tmp;
@@ -470,14 +454,11 @@ static void __exit unload_shpchpd(void)
470 list_for_each_safe(tmp, next, &shpchp_ctrl_list) { 454 list_for_each_safe(tmp, next, &shpchp_ctrl_list) {
471 ctrl = list_entry(tmp, struct controller, ctrl_list); 455 ctrl = list_entry(tmp, struct controller, ctrl_list);
472 shpchp_remove_ctrl_files(ctrl); 456 shpchp_remove_ctrl_files(ctrl);
473 cleanup_slots(ctrl);
474 ctrl->hpc_ops->release_ctlr(ctrl); 457 ctrl->hpc_ops->release_ctlr(ctrl);
475 kfree(ctrl); 458 kfree(ctrl);
476 } 459 }
477 460
478 /* Stop the notification mechanism */ 461 destroy_workqueue(shpchp_wq);
479 shpchp_event_stop_thread();
480
481} 462}
482 463
483static struct pci_device_id shpcd_pci_tbl[] = { 464static struct pci_device_id shpcd_pci_tbl[] = {
@@ -501,17 +482,15 @@ static int __init shpcd_init(void)
501 shpchp_poll_mode = 1; 482 shpchp_poll_mode = 1;
502#endif 483#endif
503 484
504 retval = shpc_start_thread(); 485 shpchp_wq = create_singlethread_workqueue("shpchpd");
505 if (retval) 486 if (!shpchp_wq)
506 goto error_hpc_init; 487 return -ENOMEM;
507 488
508 retval = pci_register_driver(&shpc_driver); 489 retval = pci_register_driver(&shpc_driver);
509 dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); 490 dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
510 info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); 491 info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
511
512error_hpc_init:
513 if (retval) { 492 if (retval) {
514 shpchp_event_stop_thread(); 493 destroy_workqueue(shpchp_wq);
515 } 494 }
516 return retval; 495 return retval;
517} 496}
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
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 943ed2b4dabe..b392606a905a 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -813,6 +813,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
813{ 813{
814 struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; 814 struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
815 struct php_ctlr_state_s *p, *p_prev; 815 struct php_ctlr_state_s *p, *p_prev;
816 int i;
816 817
817 DBG_ENTER_ROUTINE 818 DBG_ENTER_ROUTINE
818 819
@@ -821,6 +822,14 @@ static void hpc_release_ctlr(struct controller *ctrl)
821 return ; 822 return ;
822 } 823 }
823 824
825 /*
826 * Mask all slot event interrupts
827 */
828 for (i = 0; i < ctrl->num_slots; i++)
829 writel(0xffff3fff, php_ctlr->creg + SLOT1 + (4 * i));
830
831 cleanup_slots(ctrl);
832
824 if (shpchp_poll_mode) { 833 if (shpchp_poll_mode) {
825 del_timer(&php_ctlr->int_poll_timer); 834 del_timer(&php_ctlr->int_poll_timer);
826 } else { 835 } else {
@@ -830,6 +839,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
830 pci_disable_msi(php_ctlr->pci_dev); 839 pci_disable_msi(php_ctlr->pci_dev);
831 } 840 }
832 } 841 }
842
833 if (php_ctlr->pci_dev) { 843 if (php_ctlr->pci_dev) {
834 iounmap(php_ctlr->creg); 844 iounmap(php_ctlr->creg);
835 release_mem_region(ctrl->mmio_base, ctrl->mmio_size); 845 release_mem_region(ctrl->mmio_base, ctrl->mmio_size);