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

pciehp: Event handling rework

The event handler of PCIEHP 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 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 f7bdd12d
...@@ -43,6 +43,7 @@ extern int pciehp_poll_mode; ...@@ -43,6 +43,7 @@ extern int pciehp_poll_mode;
extern int pciehp_poll_time; extern int pciehp_poll_time;
extern int pciehp_debug; extern int pciehp_debug;
extern int pciehp_force; extern int pciehp_force;
extern struct workqueue_struct *pciehp_wq;
#define dbg(format, arg...) \ #define dbg(format, arg...) \
do { \ do { \
...@@ -70,14 +71,16 @@ struct slot { ...@@ -70,14 +71,16 @@ struct slot {
struct list_head slot_list; struct list_head slot_list;
char name[SLOT_NAME_SIZE]; char name[SLOT_NAME_SIZE];
unsigned long last_emi_toggle; unsigned long last_emi_toggle;
struct delayed_work work; /* work for button event */
struct mutex lock;
}; };
struct event_info { struct event_info {
u32 event_type; u32 event_type;
u8 hp_slot; struct slot *p_slot;
struct work_struct work;
}; };
#define MAX_EVENTS 10
struct controller { struct controller {
struct controller *next; struct controller *next;
struct mutex crit_sect; /* critical section mutex */ struct mutex crit_sect; /* critical section mutex */
...@@ -86,11 +89,9 @@ struct controller { ...@@ -86,11 +89,9 @@ struct controller {
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 list_head slot_list; struct list_head slot_list;
struct event_info event_queue[MAX_EVENTS];
struct slot *slot; struct slot *slot;
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;
...@@ -149,16 +150,15 @@ struct controller { ...@@ -149,16 +150,15 @@ struct controller {
#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) #define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP)
#define EMI(cap) (cap & EMI_PRSN) #define EMI(cap) (cap & EMI_PRSN)
extern int pciehp_event_start_thread(void); extern int pciehp_sysfs_enable_slot(struct slot *slot);
extern void pciehp_event_stop_thread(void); extern int pciehp_sysfs_disable_slot(struct slot *slot);
extern int pciehp_enable_slot(struct slot *slot);
extern int pciehp_disable_slot(struct slot *slot);
extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
extern int pciehp_configure_device(struct slot *p_slot); extern int pciehp_configure_device(struct slot *p_slot);
extern int pciehp_unconfigure_device(struct slot *p_slot); extern int pciehp_unconfigure_device(struct slot *p_slot);
extern void queue_pushbutton_work(struct work_struct *work);
int pcie_init(struct controller *ctrl, struct pcie_device *dev); int pcie_init(struct controller *ctrl, struct pcie_device *dev);
/* Global variables */ /* Global variables */
......
...@@ -41,6 +41,7 @@ int pciehp_debug; ...@@ -41,6 +41,7 @@ int pciehp_debug;
int pciehp_poll_mode; int pciehp_poll_mode;
int pciehp_poll_time; int pciehp_poll_time;
int pciehp_force; int pciehp_force;
struct workqueue_struct *pciehp_wq;
struct controller *pciehp_ctrl_list; struct controller *pciehp_ctrl_list;
#define DRIVER_VERSION "0.4" #define DRIVER_VERSION "0.4"
...@@ -62,7 +63,6 @@ MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing" ...@@ -62,7 +63,6 @@ MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"
#define PCIE_MODULE_NAME "pciehp" #define PCIE_MODULE_NAME "pciehp"
static int pcie_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);
...@@ -229,6 +229,8 @@ static int init_slots(struct controller *ctrl) ...@@ -229,6 +229,8 @@ static int init_slots(struct controller *ctrl)
slot->device = ctrl->slot_device_offset + i; slot->device = ctrl->slot_device_offset + i;
slot->hpc_ops = ctrl->hpc_ops; slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot; slot->number = ctrl->first_slot;
mutex_init(&slot->lock);
INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work);
/* register this slot with the hotplug pci core */ /* register this slot with the hotplug pci core */
hotplug_slot->private = slot; hotplug_slot->private = slot;
...@@ -286,6 +288,9 @@ static void cleanup_slots(struct controller *ctrl) ...@@ -286,6 +288,9 @@ static void cleanup_slots(struct controller *ctrl)
if (EMI(ctrl->ctrlcap)) if (EMI(ctrl->ctrlcap))
sysfs_remove_file(&slot->hotplug_slot->kobj, sysfs_remove_file(&slot->hotplug_slot->kobj,
&hotplug_slot_attr_lock.attr); &hotplug_slot_attr_lock.attr);
cancel_delayed_work(&slot->work);
flush_scheduled_work();
flush_workqueue(pciehp_wq);
pci_hp_deregister(slot->hotplug_slot); pci_hp_deregister(slot->hotplug_slot);
} }
} }
...@@ -314,7 +319,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) ...@@ -314,7 +319,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
return pciehp_enable_slot(slot); return pciehp_sysfs_enable_slot(slot);
} }
...@@ -324,7 +329,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) ...@@ -324,7 +329,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
return pciehp_disable_slot(slot); return pciehp_sysfs_disable_slot(slot);
} }
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
...@@ -466,9 +471,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ ...@@ -466,9 +471,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
/* Finish setting up the hot plug ctrl device */
ctrl->next_event = 0;
if (!pciehp_ctrl_list) { if (!pciehp_ctrl_list) {
pciehp_ctrl_list = ctrl; pciehp_ctrl_list = ctrl;
ctrl->next = NULL; ctrl->next = NULL;
...@@ -496,22 +498,6 @@ err_out_none: ...@@ -496,22 +498,6 @@ err_out_none:
return -ENODEV; return -ENODEV;
} }
static int pcie_start_thread(void)
{
int retval = 0;
dbg("Initialize + Start the notification/polling mechanism \n");
retval = pciehp_event_start_thread();
if (retval) {
dbg("pciehp_event_start_thread() failed\n");
return retval;
}
return retval;
}
static void __exit unload_pciehpd(void) static void __exit unload_pciehpd(void)
{ {
struct controller *ctrl; struct controller *ctrl;
...@@ -529,10 +515,6 @@ static void __exit unload_pciehpd(void) ...@@ -529,10 +515,6 @@ static void __exit unload_pciehpd(void)
kfree(tctrl); kfree(tctrl);
} }
/* Stop the notification mechanism */
pciehp_event_stop_thread();
} }
static void pciehp_remove (struct pcie_device *device) static void pciehp_remove (struct pcie_device *device)
...@@ -585,21 +567,11 @@ static int __init pcied_init(void) ...@@ -585,21 +567,11 @@ static int __init pcied_init(void)
pciehp_poll_mode = 1; pciehp_poll_mode = 1;
#endif #endif
retval = pcie_start_thread();
if (retval)
goto error_hpc_init;
retval = pcie_port_service_register(&hpdriver_portdrv); retval = pcie_port_service_register(&hpdriver_portdrv);
dbg("pcie_port_service_register = %d\n", retval); dbg("pcie_port_service_register = %d\n", retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
if (retval) if (retval)
dbg("%s: Failure to register service\n", __FUNCTION__); dbg("%s: Failure to register service\n", __FUNCTION__);
error_hpc_init:
if (retval) {
pciehp_event_stop_thread();
};
return retval; return retval;
} }
......
This diff is collapsed.
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
#define DBG_LEAVE_ROUTINE #define DBG_LEAVE_ROUTINE
#endif /* DEBUG */ #endif /* DEBUG */
static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
struct ctrl_reg { struct ctrl_reg {
u8 cap_id; u8 cap_id;
u8 nxt_ptr; u8 nxt_ptr;
...@@ -219,10 +221,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) ...@@ -219,10 +221,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
#define EMI_STATE 0x0080 #define EMI_STATE 0x0080
#define EMI_STATUS_BIT 7 #define EMI_STATUS_BIT 7
static spinlock_t hpc_event_lock;
DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
static int ctlr_seq_num = 0; /* Controller sequence # */
static irqreturn_t pcie_isr(int irq, void *dev_id); static irqreturn_t pcie_isr(int irq, void *dev_id);
static void start_int_poll_timer(struct controller *ctrl, int sec); static void start_int_poll_timer(struct controller *ctrl, int sec);
...@@ -656,6 +655,13 @@ static void hpc_release_ctlr(struct controller *ctrl) ...@@ -656,6 +655,13 @@ static void hpc_release_ctlr(struct controller *ctrl)
else else
free_irq(ctrl->pci_dev->irq, ctrl); free_irq(ctrl->pci_dev->irq, ctrl);
/*
* If this is the last controller to be released, destroy the
* pciehp work queue
*/
if (atomic_dec_and_test(&pciehp_num_controllers))
destroy_workqueue(pciehp_wq);
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
} }
...@@ -1152,7 +1158,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) ...@@ -1152,7 +1158,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
int pcie_init(struct controller * ctrl, struct pcie_device *dev) int pcie_init(struct controller * ctrl, struct pcie_device *dev)
{ {
int rc; int rc;
static int first = 1;
u16 temp_word; u16 temp_word;
u16 cap_reg; u16 cap_reg;
u16 intr_enable = 0; u16 intr_enable = 0;
...@@ -1221,11 +1226,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ...@@ -1221,11 +1226,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
if (first) {
spin_lock_init(&hpc_event_lock);
first = 0;
}
for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
if (pci_resource_len(pdev, rc) > 0) if (pci_resource_len(pdev, rc) > 0)
dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
...@@ -1286,7 +1286,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ...@@ -1286,7 +1286,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
MY_NAME, (void *)ctrl); MY_NAME, (void *)ctrl);
dbg("%s: request_irq %d for hpc%d (returns %d)\n", dbg("%s: request_irq %d for hpc%d (returns %d)\n",
__FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc); __FUNCTION__, ctrl->pci_dev->irq,
atomic_read(&pciehp_num_controllers), rc);
if (rc) { if (rc) {
err("Can't get irq %d for the hotplug controller\n", err("Can't get irq %d for the hotplug controller\n",
ctrl->pci_dev->irq); ctrl->pci_dev->irq);
...@@ -1296,6 +1297,18 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ...@@ -1296,6 +1297,18 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
/*
* If this is the first controller to be initialized,
* initialize the pciehp work queue
*/
if (atomic_add_return(1, &pciehp_num_controllers) == 1) {
pciehp_wq = create_singlethread_workqueue("pciehpd");
if (!pciehp_wq) {
rc = -ENOMEM;
goto abort_free_irq;
}
}
rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) { if (rc) {
err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
...@@ -1349,7 +1362,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ...@@ -1349,7 +1362,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_disable_intr; goto abort_disable_intr;
} }
ctlr_seq_num++;
ctrl->hpc_ops = &pciehp_hpc_ops; ctrl->hpc_ops = &pciehp_hpc_ops;
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
......
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