diff options
| -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); |
