Commit f7391f53 authored by Kenji Kaneshige's avatar Kenji Kaneshige Committed by Greg Kroah-Hartman

[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: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarKristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 68c0b671
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
extern int shpchp_poll_mode; extern int shpchp_poll_mode;
extern int shpchp_poll_time; extern int shpchp_poll_time;
extern int shpchp_debug; extern int shpchp_debug;
extern struct workqueue_struct *shpchp_wq;
/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ /*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0) #define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
...@@ -70,11 +71,13 @@ struct slot { ...@@ -70,11 +71,13 @@ struct slot {
struct hotplug_slot *hotplug_slot; struct hotplug_slot *hotplug_slot;
struct list_head slot_list; struct list_head slot_list;
char name[SLOT_NAME_SIZE]; char name[SLOT_NAME_SIZE];
struct work_struct work; /* work for button event */
}; };
struct event_info { struct event_info {
u32 event_type; u32 event_type;
u8 hp_slot; struct slot *p_slot;
struct work_struct work;
}; };
struct controller { struct controller {
...@@ -85,11 +88,9 @@ struct controller { ...@@ -85,11 +88,9 @@ struct controller {
int num_slots; /* Number of slots on ctlr */ int num_slots; /* Number of slots on ctlr */
int slot_num_inc; /* 1 or -1 */ int slot_num_inc; /* 1 or -1 */
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
struct event_info event_queue[10];
struct list_head slot_list; struct list_head slot_list;
struct hpc_ops *hpc_ops; struct hpc_ops *hpc_ops;
wait_queue_head_t queue; /* sleep & wake process */ wait_queue_head_t queue; /* sleep & wake process */
u8 next_event;
u8 bus; u8 bus;
u8 device; u8 device;
u8 function; u8 function;
...@@ -180,9 +181,6 @@ struct hotplug_params { ...@@ -180,9 +181,6 @@ struct hotplug_params {
/* sysfs functions for the hotplug controller info */ /* sysfs functions for the hotplug controller info */
extern void shpchp_create_ctrl_files (struct controller *ctrl); extern void shpchp_create_ctrl_files (struct controller *ctrl);
/* controller functions */
extern int shpchp_event_start_thread(void);
extern void shpchp_event_stop_thread(void);
extern int shpchp_enable_slot(struct slot *slot); extern int shpchp_enable_slot(struct slot *slot);
extern int shpchp_disable_slot(struct slot *slot); extern int shpchp_disable_slot(struct slot *slot);
...@@ -201,7 +199,8 @@ extern void get_hp_params_from_firmware(struct pci_dev *dev, ...@@ -201,7 +199,8 @@ extern void get_hp_params_from_firmware(struct pci_dev *dev,
extern int shpchprm_get_physical_slot_number(struct controller *ctrl, extern int shpchprm_get_physical_slot_number(struct controller *ctrl,
u32 *sun, u8 busnum, u8 devnum); u32 *sun, u8 busnum, u8 devnum);
extern void shpchp_remove_ctrl_files(struct controller *ctrl); extern void shpchp_remove_ctrl_files(struct controller *ctrl);
extern void cleanup_slots(struct controller *ctrl);
extern void shpchp_pushbutton_thread(void *data);
/* Global variables */ /* Global variables */
extern struct list_head shpchp_ctrl_list; extern struct list_head shpchp_ctrl_list;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/workqueue.h>
#include "shpchp.h" #include "shpchp.h"
/* Global variables */ /* Global variables */
...@@ -39,6 +40,7 @@ int shpchp_debug; ...@@ -39,6 +40,7 @@ int shpchp_debug;
int shpchp_poll_mode; int shpchp_poll_mode;
int shpchp_poll_time; int shpchp_poll_time;
LIST_HEAD(shpchp_ctrl_list); LIST_HEAD(shpchp_ctrl_list);
struct workqueue_struct *shpchp_wq;
#define DRIVER_VERSION "0.4" #define DRIVER_VERSION "0.4"
#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" #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,7 +59,6 @@ MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
#define SHPC_MODULE_NAME "shpchp" #define SHPC_MODULE_NAME "shpchp"
static int shpc_start_thread (void);
static int set_attention_status (struct hotplug_slot *slot, u8 value); static int set_attention_status (struct hotplug_slot *slot, u8 value);
static int enable_slot (struct hotplug_slot *slot); static int enable_slot (struct hotplug_slot *slot);
static int disable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot);
...@@ -141,6 +142,7 @@ static int init_slots(struct controller *ctrl) ...@@ -141,6 +142,7 @@ static int init_slots(struct controller *ctrl)
goto error_info; goto error_info;
slot->number = sun; slot->number = sun;
INIT_WORK(&slot->work, shpchp_pushbutton_thread, slot);
/* register this slot with the hotplug pci core */ /* register this slot with the hotplug pci core */
hotplug_slot->private = slot; hotplug_slot->private = slot;
...@@ -176,7 +178,7 @@ static int init_slots(struct controller *ctrl) ...@@ -176,7 +178,7 @@ static int init_slots(struct controller *ctrl)
return retval; return retval;
} }
static void cleanup_slots(struct controller *ctrl) void cleanup_slots(struct controller *ctrl)
{ {
struct list_head *tmp; struct list_head *tmp;
struct list_head *next; struct list_head *next;
...@@ -185,6 +187,8 @@ static void cleanup_slots(struct controller *ctrl) ...@@ -185,6 +187,8 @@ static void cleanup_slots(struct controller *ctrl)
list_for_each_safe(tmp, next, &ctrl->slot_list) { list_for_each_safe(tmp, next, &ctrl->slot_list) {
slot = list_entry(tmp, struct slot, slot_list); slot = list_entry(tmp, struct slot, slot_list);
list_del(&slot->slot_list); list_del(&slot->slot_list);
cancel_delayed_work(&slot->work);
flush_workqueue(shpchp_wq);
pci_hp_deregister(slot->hotplug_slot); pci_hp_deregister(slot->hotplug_slot);
} }
} }
...@@ -400,7 +404,7 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -400,7 +404,7 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = get_ctlr_slot_config(ctrl); rc = get_ctlr_slot_config(ctrl);
if (rc) { if (rc) {
err(msg_initialization_err, rc); err(msg_initialization_err, rc);
goto err_out_unmap_mmio_region; goto err_out_release_ctlr;
} }
first_device_num = ctrl->slot_device_offset; first_device_num = ctrl->slot_device_offset;
num_ctlr_slots = ctrl->num_slots; 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,7 +415,7 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = init_slots(ctrl); rc = init_slots(ctrl);
if (rc) { if (rc) {
err(msg_initialization_err, 6); err(msg_initialization_err, 6);
goto err_out_free_ctrl_slot; goto err_out_release_ctlr;
} }
/* Now hpc_functions (slot->hpc_ops->functions) are ready */ /* 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,18 +431,13 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ctrl->speed = PCI_SPEED_33MHz; ctrl->speed = PCI_SPEED_33MHz;
} }
/* Finish setting up the hot plug ctrl device */
ctrl->next_event = 0;
list_add(&ctrl->ctrl_list, &shpchp_ctrl_list); list_add(&ctrl->ctrl_list, &shpchp_ctrl_list);
shpchp_create_ctrl_files(ctrl); shpchp_create_ctrl_files(ctrl);
return 0; return 0;
err_out_free_ctrl_slot: err_out_release_ctlr:
cleanup_slots(ctrl);
err_out_unmap_mmio_region:
ctrl->hpc_ops->release_ctlr(ctrl); ctrl->hpc_ops->release_ctlr(ctrl);
err_out_free_ctrl: err_out_free_ctrl:
kfree(ctrl); kfree(ctrl);
...@@ -446,21 +445,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -446,21 +445,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV; return -ENODEV;
} }
static int shpc_start_thread(void)
{
int retval = 0;
dbg("Initialize + Start the notification/polling mechanism \n");
retval = shpchp_event_start_thread();
if (retval) {
dbg("shpchp_event_start_thread() failed\n");
return retval;
}
return retval;
}
static void __exit unload_shpchpd(void) static void __exit unload_shpchpd(void)
{ {
struct list_head *tmp; struct list_head *tmp;
...@@ -470,14 +454,11 @@ static void __exit unload_shpchpd(void) ...@@ -470,14 +454,11 @@ static void __exit unload_shpchpd(void)
list_for_each_safe(tmp, next, &shpchp_ctrl_list) { list_for_each_safe(tmp, next, &shpchp_ctrl_list) {
ctrl = list_entry(tmp, struct controller, ctrl_list); ctrl = list_entry(tmp, struct controller, ctrl_list);
shpchp_remove_ctrl_files(ctrl); shpchp_remove_ctrl_files(ctrl);
cleanup_slots(ctrl);
ctrl->hpc_ops->release_ctlr(ctrl); ctrl->hpc_ops->release_ctlr(ctrl);
kfree(ctrl); kfree(ctrl);
} }
/* Stop the notification mechanism */ destroy_workqueue(shpchp_wq);
shpchp_event_stop_thread();
} }
static struct pci_device_id shpcd_pci_tbl[] = { static struct pci_device_id shpcd_pci_tbl[] = {
...@@ -501,17 +482,15 @@ static int __init shpcd_init(void) ...@@ -501,17 +482,15 @@ static int __init shpcd_init(void)
shpchp_poll_mode = 1; shpchp_poll_mode = 1;
#endif #endif
retval = shpc_start_thread(); shpchp_wq = create_singlethread_workqueue("shpchpd");
if (retval) if (!shpchp_wq)
goto error_hpc_init; return -ENOMEM;
retval = pci_register_driver(&shpc_driver); retval = pci_register_driver(&shpc_driver);
dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
error_hpc_init:
if (retval) { if (retval) {
shpchp_event_stop_thread(); destroy_workqueue(shpchp_wq);
} }
return retval; return retval;
} }
......
This diff is collapsed.
...@@ -813,6 +813,7 @@ static void hpc_release_ctlr(struct controller *ctrl) ...@@ -813,6 +813,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
{ {
struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
struct php_ctlr_state_s *p, *p_prev; struct php_ctlr_state_s *p, *p_prev;
int i;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
...@@ -821,6 +822,14 @@ static void hpc_release_ctlr(struct controller *ctrl) ...@@ -821,6 +822,14 @@ static void hpc_release_ctlr(struct controller *ctrl)
return ; return ;
} }
/*
* Mask all slot event interrupts
*/
for (i = 0; i < ctrl->num_slots; i++)
writel(0xffff3fff, php_ctlr->creg + SLOT1 + (4 * i));
cleanup_slots(ctrl);
if (shpchp_poll_mode) { if (shpchp_poll_mode) {
del_timer(&php_ctlr->int_poll_timer); del_timer(&php_ctlr->int_poll_timer);
} else { } else {
...@@ -830,6 +839,7 @@ static void hpc_release_ctlr(struct controller *ctrl) ...@@ -830,6 +839,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
pci_disable_msi(php_ctlr->pci_dev); pci_disable_msi(php_ctlr->pci_dev);
} }
} }
if (php_ctlr->pci_dev) { if (php_ctlr->pci_dev) {
iounmap(php_ctlr->creg); iounmap(php_ctlr->creg);
release_mem_region(ctrl->mmio_base, ctrl->mmio_size); release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment