diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/hotplug/shpchp.h | 13 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 49 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 313 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_hpc.c | 10 |
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 @@ | |||
46 | extern int shpchp_poll_mode; | 46 | extern int shpchp_poll_mode; |
47 | extern int shpchp_poll_time; | 47 | extern int shpchp_poll_time; |
48 | extern int shpchp_debug; | 48 | extern int shpchp_debug; |
49 | extern 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 | ||
75 | struct event_info { | 77 | struct 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 | ||
80 | struct controller { | 83 | struct 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 */ |
181 | extern void shpchp_create_ctrl_files (struct controller *ctrl); | 182 | extern void shpchp_create_ctrl_files (struct controller *ctrl); |
182 | 183 | ||
183 | /* controller functions */ | ||
184 | extern int shpchp_event_start_thread(void); | ||
185 | extern void shpchp_event_stop_thread(void); | ||
186 | extern int shpchp_enable_slot(struct slot *slot); | 184 | extern int shpchp_enable_slot(struct slot *slot); |
187 | extern int shpchp_disable_slot(struct slot *slot); | 185 | extern int shpchp_disable_slot(struct slot *slot); |
188 | 186 | ||
@@ -201,7 +199,8 @@ extern void get_hp_params_from_firmware(struct pci_dev *dev, | |||
201 | extern int shpchprm_get_physical_slot_number(struct controller *ctrl, | 199 | extern int shpchprm_get_physical_slot_number(struct controller *ctrl, |
202 | u32 *sun, u8 busnum, u8 devnum); | 200 | u32 *sun, u8 busnum, u8 devnum); |
203 | extern void shpchp_remove_ctrl_files(struct controller *ctrl); | 201 | extern void shpchp_remove_ctrl_files(struct controller *ctrl); |
204 | 202 | extern void cleanup_slots(struct controller *ctrl); | |
203 | extern void shpchp_pushbutton_thread(void *data); | ||
205 | 204 | ||
206 | /* Global variables */ | 205 | /* Global variables */ |
207 | extern struct list_head shpchp_ctrl_list; | 206 | extern 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; | |||
39 | int shpchp_poll_mode; | 40 | int shpchp_poll_mode; |
40 | int shpchp_poll_time; | 41 | int shpchp_poll_time; |
41 | LIST_HEAD(shpchp_ctrl_list); | 42 | LIST_HEAD(shpchp_ctrl_list); |
43 | struct 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 | ||
60 | static int shpc_start_thread (void); | ||
61 | static int set_attention_status (struct hotplug_slot *slot, u8 value); | 62 | static int set_attention_status (struct hotplug_slot *slot, u8 value); |
62 | static int enable_slot (struct hotplug_slot *slot); | 63 | static int enable_slot (struct hotplug_slot *slot); |
63 | static int disable_slot (struct hotplug_slot *slot); | 64 | static 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 | ||
179 | static void cleanup_slots(struct controller *ctrl) | 181 | void 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 | ||
439 | err_out_free_ctrl_slot: | 440 | err_out_release_ctlr: |
440 | cleanup_slots(ctrl); | ||
441 | err_out_unmap_mmio_region: | ||
442 | ctrl->hpc_ops->release_ctlr(ctrl); | 441 | ctrl->hpc_ops->release_ctlr(ctrl); |
443 | err_out_free_ctrl: | 442 | err_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 | ||
449 | static 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 | |||
464 | static void __exit unload_shpchpd(void) | 448 | static 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 | ||
483 | static struct pci_device_id shpcd_pci_tbl[] = { | 464 | static 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 | |||
512 | error_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 | ||
38 | static void interrupt_event_handler(struct controller *ctrl); | 39 | static void interrupt_event_handler(void *data); |
39 | 40 | ||
40 | static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ | 41 | static int queue_interrupt_event(struct slot *p_slot, u32 event_type) |
41 | static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ | 42 | { |
42 | static int event_finished; | 43 | struct event_info *info; |
43 | static 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 | ||
45 | u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) | 58 | u8 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 | ||
148 | u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) | 139 | u8 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 | ||
193 | u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) | 173 | u8 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 | ||
524 | static 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 | */ |
539 | static void shpchp_pushbutton_thread (unsigned long slot) | 502 | void 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 */ | ||
571 | static 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 | |||
596 | int 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 | |||
615 | void shpchp_event_stop_thread (void) | ||
616 | { | ||
617 | event_finished = 1; | ||
618 | up(&event_semaphore); | ||
619 | down(&event_exit); | ||
620 | } | 518 | } |
621 | 519 | ||
622 | |||
623 | static int update_slot_info (struct slot *slot) | 520 | static 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 | ||
642 | static void interrupt_event_handler(struct controller *ctrl) | 539 | static 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); |