diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-02-22 15:02:34 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-02-22 15:02:34 -0800 |
commit | eb6b406dcc7096974eec722b436e0f05eca353a4 (patch) | |
tree | 0fa607d200cd276b6774f0f863e317a0741fc493 /pci | |
parent | 4fffec22d6b7a52d17e144280ea226114c92e0a0 (diff) | |
download | patches-eb6b406dcc7096974eec722b436e0f05eca353a4.tar.gz |
usb, pci, and driver patches added
Diffstat (limited to 'pci')
-rw-r--r-- | pci/pci-add-pci_device_shutdown-to-pci_bus_type.patch | 44 | ||||
-rw-r--r-- | pci/pci-make-msi-quirk-inheritable-from-the-pci-bus.patch | 83 | ||||
-rw-r--r-- | pci/pci-pci-quirk-for-asus-a8v-and-a8v-deluxe-motherboards.patch | 67 | ||||
-rw-r--r-- | pci/pci-smbus-unhide-on-hp-compaq-nx6110.patch | 32 | ||||
-rw-r--r-- | pci/shpchp-adapt-to-pci-driver-model.patch | 107 | ||||
-rw-r--r-- | pci/shpchp-event-handling-rework.patch | 754 | ||||
-rw-r--r-- | pci/shpchp-fix-slot-state-handling.patch | 455 | ||||
-rw-r--r-- | pci/shpchp-remove-unused-pci_bus-member-from-controller-structure.patch | 76 | ||||
-rw-r--r-- | pci/shpchp-remove-unused-wait_for_ctrl_irq.patch | 63 |
9 files changed, 1681 insertions, 0 deletions
diff --git a/pci/pci-add-pci_device_shutdown-to-pci_bus_type.patch b/pci/pci-add-pci_device_shutdown-to-pci_bus_type.patch new file mode 100644 index 0000000000000..300373569faf8 --- /dev/null +++ b/pci/pci-add-pci_device_shutdown-to-pci_bus_type.patch @@ -0,0 +1,44 @@ +From bgerst@didntduck.org Sun Feb 19 13:05:20 2006 +Message-ID: <43F8DDB0.6030700@didntduck.org> +Date: Sun, 19 Feb 2006 16:05:52 -0500 +From: Brian Gerst <bgerst@didntduck.org> +To: Greg KH <greg@kroah.com> +CC: <rmk+lkml@arm.linux.org.uk> +Subject: PCI: Add pci_device_shutdown to pci_bus_type + +The extra compatability code is not necessary. Any code still using +the old shutdown method will trigger the warning in driver_register() +instead. + +Signed-off-by: Brian Gerst <bgerst@didntduck.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/pci/pci-driver.c | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +--- gregkh-2.6.orig/drivers/pci/pci-driver.c ++++ gregkh-2.6/drivers/pci/pci-driver.c +@@ -380,14 +380,6 @@ int __pci_register_driver(struct pci_dri + /* initialize common driver fields */ + drv->driver.name = drv->name; + drv->driver.bus = &pci_bus_type; +- /* FIXME, once all of the existing PCI drivers have been fixed to set +- * the pci shutdown function, this test can go away. */ +- if (!drv->driver.shutdown) +- drv->driver.shutdown = pci_device_shutdown; +- else +- printk(KERN_WARNING "Warning: PCI driver %s has a struct " +- "device_driver shutdown method, please update!\n", +- drv->name); + drv->driver.owner = owner; + drv->driver.kobj.ktype = &pci_driver_kobj_type; + +@@ -514,6 +506,7 @@ struct bus_type pci_bus_type = { + .probe = pci_device_probe, + .remove = pci_device_remove, + .suspend = pci_device_suspend, ++ .shutdown = pci_device_shutdown, + .resume = pci_device_resume, + .dev_attrs = pci_dev_attrs, + }; diff --git a/pci/pci-make-msi-quirk-inheritable-from-the-pci-bus.patch b/pci/pci-make-msi-quirk-inheritable-from-the-pci-bus.patch new file mode 100644 index 0000000000000..54c013ce7e6d0 --- /dev/null +++ b/pci/pci-make-msi-quirk-inheritable-from-the-pci-bus.patch @@ -0,0 +1,83 @@ +From mst@mellanox.co.il Tue Feb 14 08:51:01 2006 +Date: Tue, 14 Feb 2006 18:52:22 +0200 +From: "Michael S. Tsirkin" <mst@mellanox.co.il> +To: Roland Dreier <rolandd@cisco.com> +Subject: PCI: make MSI quirk inheritable from the pci bus +Message-ID: <20060214165222.GC12974@mellanox.co.il> +Content-Disposition: inline + + +It turns out AMD 8131 quirk only affects MSI for devices behind the 8131 bridge. +Handle this by adding a flags field in pci_bus, inherited from parent to child. + +Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/pci/msi.c | 3 +++ + drivers/pci/probe.c | 1 + + drivers/pci/quirks.c | 7 +++++-- + include/linux/pci.h | 7 ++++++- + 4 files changed, 15 insertions(+), 3 deletions(-) + +--- gregkh-2.6.orig/drivers/pci/msi.c ++++ gregkh-2.6/drivers/pci/msi.c +@@ -723,6 +723,9 @@ int pci_enable_msi(struct pci_dev* dev) + if (dev->no_msi) + return status; + ++ if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) ++ return -EINVAL; ++ + temp = dev->irq; + + status = msi_init(); +--- gregkh-2.6.orig/drivers/pci/probe.c ++++ gregkh-2.6/drivers/pci/probe.c +@@ -347,6 +347,7 @@ pci_alloc_child_bus(struct pci_bus *pare + child->parent = parent; + child->ops = parent->ops; + child->sysdata = parent->sysdata; ++ child->bus_flags = parent->bus_flags; + child->bridge = get_device(&bridge->dev); + + child->class_dev.class = &pcibus_class; +--- gregkh-2.6.orig/drivers/pci/quirks.c ++++ gregkh-2.6/drivers/pci/quirks.c +@@ -575,8 +575,11 @@ static void __init quirk_amd_8131_ioapic + { + unsigned char revid, tmp; + +- pci_msi_quirk = 1; +- printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n"); ++ if (dev->subordinate) { ++ printk(KERN_WARNING "PCI: MSI quirk detected. " ++ "PCI_BUS_FLAGS_NO_MSI set for subordinate bus.\n"); ++ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; ++ } + + if (nr_ioapics == 0) + return; +--- gregkh-2.6.orig/include/linux/pci.h ++++ gregkh-2.6/include/linux/pci.h +@@ -95,6 +95,11 @@ enum pci_channel_state { + pci_channel_io_perm_failure = (__force pci_channel_state_t) 3, + }; + ++typedef unsigned short __bitwise pci_bus_flags_t; ++enum pci_bus_flags { ++ PCI_BUS_FLAGS_NO_MSI = (pci_bus_flags_t) 1, ++}; ++ + /* + * The pci_dev structure is used to describe PCI devices. + */ +@@ -203,7 +208,7 @@ struct pci_bus { + char name[48]; + + unsigned short bridge_ctl; /* manage NO_ISA/FBB/et al behaviors */ +- unsigned short pad2; ++ pci_bus_flags_t bus_flags; /* Inherited by child busses */ + struct device *bridge; + struct class_device class_dev; + struct bin_attribute *legacy_io; /* legacy I/O for this bus */ diff --git a/pci/pci-pci-quirk-for-asus-a8v-and-a8v-deluxe-motherboards.patch b/pci/pci-pci-quirk-for-asus-a8v-and-a8v-deluxe-motherboards.patch new file mode 100644 index 0000000000000..c7534f09f7371 --- /dev/null +++ b/pci/pci-pci-quirk-for-asus-a8v-and-a8v-deluxe-motherboards.patch @@ -0,0 +1,67 @@ +From root@skyscraper.xs4all.nl Sat Feb 11 18:22:21 2006 +Date: Sun, 12 Feb 2006 03:22:18 +0100 +From: bjd <bjdouma@xs4all.nl> +To: Greg Kroah-Hartman <gregkh@suse.de> +Subject: PCI: PCI quirk for Asus A8V and A8V Deluxe motherboards +Message-ID: <20060212022218.GA3847@skyscraper.unix9.prv> +Content-Disposition: inline + +From: Bauke Jan Douma <bjdouma@xs4all.nl> + +On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller +and MC97 modem controller are deactivated when a second PCI soundcard +is present. This patch enables them. + +Signed-off-by: Bauke Jan Douma <bjdouma@xs4all.nl> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- gregkh-2.6.orig/drivers/pci/quirks.c ++++ gregkh-2.6/drivers/pci/quirks.c +@@ -1080,6 +1080,42 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); + ++/* ++ * On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller ++ * and MC97 modem controller are disabled when a second PCI soundcard is ++ * present. This patch, tweaking the VT8237 ISA bridge, enables them. ++ * -- bjd ++ */ ++static int __initdata asus_hides_ac97 = 0; ++ ++static void __init asus_hides_ac97_device(struct pci_dev *dev) ++{ ++ if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) { ++ if (dev->device == PCI_DEVICE_ID_VIA_8237) ++ asus_hides_ac97 = 1; ++ } ++} ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_device ); ++ ++static void __init asus_hides_ac97_lpc(struct pci_dev *dev) ++{ ++ u8 val; ++ ++ if (likely(!asus_hides_ac97)) ++ return; ++ ++ pci_read_config_byte(dev, 0x50, &val); ++ if (val & 0xc0) { ++ pci_write_config_byte(dev, 0x50, val & (~0xc0)); ++ pci_read_config_byte(dev, 0x50, &val); ++ if (val & 0xc0) ++ printk(KERN_INFO "PCI: onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val); ++ else ++ printk(KERN_INFO "PCI: enabled onboard AC97/MC97 devices\n"); ++ } ++} ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); ++ + #ifdef CONFIG_X86_IO_APIC + static void __init quirk_alder_ioapic(struct pci_dev *pdev) + { diff --git a/pci/pci-smbus-unhide-on-hp-compaq-nx6110.patch b/pci/pci-smbus-unhide-on-hp-compaq-nx6110.patch new file mode 100644 index 0000000000000..31689a08dfb90 --- /dev/null +++ b/pci/pci-smbus-unhide-on-hp-compaq-nx6110.patch @@ -0,0 +1,32 @@ +From tomek@koprowski.org Sun Feb 19 09:01:51 2006 +From: Tomek Koprowski <tomek@koprowski.org>(by way of Tomek Koprowski <tomek@koprowski.org>) +Date: Sun, 19 Feb 2006 18:03:24 +0100 +To: gregkh@suse.de +Subject: PCI: SMBus unhide on HP Compaq nx6110 +Message-Id: <200602191803.24639.tomek@koprowski.org> + +I attach a trivial patch for 2.6.15.4 that unhides SMBus controller +on an HP Compaq nx6110 notebook. + +Signed-off-by: Tomasz Koprowski <tomek@koprowski.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/pci/quirks.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- gregkh-2.6.orig/drivers/pci/quirks.c ++++ gregkh-2.6/drivers/pci/quirks.c +@@ -934,6 +934,12 @@ static void __init asus_hides_smbus_host + case 0x12bd: /* HP D530 */ + asus_hides_smbus = 1; + } ++ if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { ++ switch (dev->subsystem_device) { ++ case 0x099c: /* HP Compaq nx6110 */ ++ asus_hides_smbus = 1; ++ } ++ } + } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) { + if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) + switch(dev->subsystem_device) { diff --git a/pci/shpchp-adapt-to-pci-driver-model.patch b/pci/shpchp-adapt-to-pci-driver-model.patch new file mode 100644 index 0000000000000..3671816a6379f --- /dev/null +++ b/pci/shpchp-adapt-to-pci-driver-model.patch @@ -0,0 +1,107 @@ +From pcihpd-discuss-admin@lists.sourceforge.net Tue Feb 21 15:41:04 2006 +From: Kristen Accardi <kristen.c.accardi@intel.com> +To: Greg KH <greg@kroah.com> +Cc: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>, Kristen Accardi <kristen.c.accardi@intel.com> +Message-Id: <1140565551.24286.23.camel@whizzy> +Subject: shpchp: adapt to pci driver model +Date: Tue, 21 Feb 2006 15:45:50 -0800 + +From: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> + +This patch adapts SHPCHP driver to the PCI device driver model. + +Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> +Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/pci/hotplug/shpchp.h | 4 ---- + drivers/pci/hotplug/shpchp_core.c | 26 +++++++------------------- + 2 files changed, 7 insertions(+), 23 deletions(-) + +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp.h ++++ gregkh-2.6/drivers/pci/hotplug/shpchp.h +@@ -82,7 +82,6 @@ struct event_info { + }; + + struct controller { +- struct list_head ctrl_list; + struct mutex crit_sect; /* critical section mutex */ + struct mutex cmd_lock; /* command lock */ + struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ +@@ -203,9 +202,6 @@ extern void shpchp_remove_ctrl_files(str + extern void cleanup_slots(struct controller *ctrl); + extern void queue_pushbutton_work(void *data); + +-/* Global variables */ +-extern struct list_head shpchp_ctrl_list; +- + struct ctrl_reg { + volatile u32 base_offset; + volatile u32 slot_avail1; +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_core.c ++++ gregkh-2.6/drivers/pci/hotplug/shpchp_core.c +@@ -39,7 +39,6 @@ + int shpchp_debug; + int shpchp_poll_mode; + int shpchp_poll_time; +-LIST_HEAD(shpchp_ctrl_list); + struct workqueue_struct *shpchp_wq; + + #define DRIVER_VERSION "0.4" +@@ -433,8 +432,6 @@ static int shpc_probe(struct pci_dev *pd + ctrl->speed = PCI_SPEED_33MHz; + } + +- list_add(&ctrl->ctrl_list, &shpchp_ctrl_list); +- + shpchp_create_ctrl_files(ctrl); + + return 0; +@@ -447,20 +444,13 @@ err_out_none: + return -ENODEV; + } + +-static void __exit unload_shpchpd(void) ++static void shpc_remove(struct pci_dev *dev) + { +- struct list_head *tmp; +- struct list_head *next; +- struct controller *ctrl; +- +- list_for_each_safe(tmp, next, &shpchp_ctrl_list) { +- ctrl = list_entry(tmp, struct controller, ctrl_list); +- shpchp_remove_ctrl_files(ctrl); +- ctrl->hpc_ops->release_ctlr(ctrl); +- kfree(ctrl); +- } ++ struct controller *ctrl = pci_get_drvdata(dev); + +- destroy_workqueue(shpchp_wq); ++ shpchp_remove_ctrl_files(ctrl); ++ ctrl->hpc_ops->release_ctlr(ctrl); ++ kfree(ctrl); + } + + static struct pci_device_id shpcd_pci_tbl[] = { +@@ -473,7 +463,7 @@ static struct pci_driver shpc_driver = { + .name = SHPC_MODULE_NAME, + .id_table = shpcd_pci_tbl, + .probe = shpc_probe, +- /* remove: shpc_remove_one, */ ++ .remove = shpc_remove, + }; + + static int __init shpcd_init(void) +@@ -500,10 +490,8 @@ static int __init shpcd_init(void) + static void __exit shpcd_cleanup(void) + { + dbg("unload_shpchpd()\n"); +- unload_shpchpd(); +- + pci_unregister_driver(&shpc_driver); +- ++ destroy_workqueue(shpchp_wq); + info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); + } + diff --git a/pci/shpchp-event-handling-rework.patch b/pci/shpchp-event-handling-rework.patch new file mode 100644 index 0000000000000..c0668a6de18ed --- /dev/null +++ b/pci/shpchp-event-handling-rework.patch @@ -0,0 +1,754 @@ +From pcihpd-discuss-admin@lists.sourceforge.net Tue Feb 21 15:41:04 2006 +From: Kristen Accardi <kristen.c.accardi@intel.com> +To: Greg KH <greg@kroah.com> +Cc: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>, Kristen Accardi <kristen.c.accardi@intel.com> +Message-Id: <1140565545.24286.21.camel@whizzy> +Subject: shpchp: event handling rework +Date: Tue, 21 Feb 2006 15:45:45 -0800 + +From: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> + +The event handler of SHPCHP driver is unnecessarily very complex. In +addition, current event handler can only a fixed number of events at +the same time, and some of events would be lost if several number of +events happened at the same time. + +This patch simplify the event handler by using 'work queue', and it +also fix the above-mentioned issue. + +Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> +Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/pci/hotplug/shpchp.h | 13 - + drivers/pci/hotplug/shpchp_core.c | 49 +---- + drivers/pci/hotplug/shpchp_ctrl.c | 315 ++++++++++---------------------------- + drivers/pci/hotplug/shpchp_hpc.c | 10 + + 4 files changed, 120 insertions(+), 267 deletions(-) + +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_ctrl.c ++++ gregkh-2.6/drivers/pci/hotplug/shpchp_ctrl.c +@@ -32,44 +32,46 @@ + #include <linux/types.h> + #include <linux/smp_lock.h> + #include <linux/pci.h> ++#include <linux/workqueue.h> + #include "../pci.h" + #include "shpchp.h" + +-static void interrupt_event_handler(struct controller *ctrl); ++static void interrupt_event_handler(void *data); + +-static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +-static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ +-static int event_finished; +-static unsigned long pushbutton_pending; /* = 0 */ ++static int queue_interrupt_event(struct slot *p_slot, u32 event_type) ++{ ++ struct event_info *info; ++ ++ info = kmalloc(sizeof(*info), GFP_ATOMIC); ++ if (!info) ++ return -ENOMEM; ++ ++ info->event_type = event_type; ++ info->p_slot = p_slot; ++ INIT_WORK(&info->work, interrupt_event_handler, info); ++ ++ queue_work(shpchp_wq, &info->work); ++ ++ return 0; ++} + + u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) + { + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; +- u8 rc = 0; +- u8 getstatus; +- struct event_info *taskInfo; ++ u32 event_type; + + /* Attention Button Change */ + dbg("shpchp: Attention button interrupt received.\n"); + +- /* This is the structure that tells the worker thread what to do */ +- taskInfo = &(ctrl->event_queue[ctrl->next_event]); + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); +- + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); +- p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); +- +- ctrl->next_event = (ctrl->next_event + 1) % 10; +- taskInfo->hp_slot = hp_slot; +- +- rc++; + + /* + * Button pressed - See if need to TAKE ACTION!!! + */ + info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); +- taskInfo->event_type = INT_BUTTON_PRESS; ++ event_type = INT_BUTTON_PRESS; + + if ((p_slot->state == BLINKINGON_STATE) + || (p_slot->state == BLINKINGOFF_STATE)) { +@@ -77,7 +79,7 @@ u8 shpchp_handle_attention_button(u8 hp_ + * attention again before the 5 sec. limit expires to cancel hot-add + * or hot-remove + */ +- taskInfo->event_type = INT_BUTTON_CANCEL; ++ event_type = INT_BUTTON_CANCEL; + info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); + } else if ((p_slot->state == POWERON_STATE) + || (p_slot->state == POWEROFF_STATE)) { +@@ -85,12 +87,11 @@ u8 shpchp_handle_attention_button(u8 hp_ + * means that the previous attention button action to hot-add or + * hot-remove is undergoing + */ +- taskInfo->event_type = INT_BUTTON_IGNORE; ++ event_type = INT_BUTTON_IGNORE; + info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); + } + +- if (rc) +- up(&event_semaphore); /* signal event thread that new event is posted */ ++ queue_interrupt_event(p_slot, event_type); + + return 0; + +@@ -100,21 +101,12 @@ u8 shpchp_handle_switch_change(u8 hp_slo + { + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; +- u8 rc = 0; + u8 getstatus; +- struct event_info *taskInfo; ++ u32 event_type; + + /* Switch Change */ + dbg("shpchp: Switch interrupt received.\n"); + +- /* This is the structure that tells the worker thread +- * what to do +- */ +- taskInfo = &(ctrl->event_queue[ctrl->next_event]); +- ctrl->next_event = (ctrl->next_event + 1) % 10; +- taskInfo->hp_slot = hp_slot; +- +- rc++; + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); +@@ -126,9 +118,9 @@ u8 shpchp_handle_switch_change(u8 hp_slo + * Switch opened + */ + info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); +- taskInfo->event_type = INT_SWITCH_OPEN; ++ event_type = INT_SWITCH_OPEN; + if (p_slot->pwr_save && p_slot->presence_save) { +- taskInfo->event_type = INT_POWER_FAULT; ++ event_type = INT_POWER_FAULT; + err("Surprise Removal of card\n"); + } + } else { +@@ -136,34 +128,23 @@ u8 shpchp_handle_switch_change(u8 hp_slo + * Switch closed + */ + info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); +- taskInfo->event_type = INT_SWITCH_CLOSE; ++ event_type = INT_SWITCH_CLOSE; + } + +- if (rc) +- up(&event_semaphore); /* signal event thread that new event is posted */ ++ queue_interrupt_event(p_slot, event_type); + +- return rc; ++ return 1; + } + + u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) + { + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; +- u8 rc = 0; +- /*u8 temp_byte;*/ +- struct event_info *taskInfo; ++ u32 event_type; + + /* Presence Change */ + dbg("shpchp: Presence/Notify input change.\n"); + +- /* This is the structure that tells the worker thread +- * what to do +- */ +- taskInfo = &(ctrl->event_queue[ctrl->next_event]); +- ctrl->next_event = (ctrl->next_event + 1) % 10; +- taskInfo->hp_slot = hp_slot; +- +- rc++; + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + /* +@@ -175,39 +156,29 @@ u8 shpchp_handle_presence_change(u8 hp_s + * Card Present + */ + info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); +- taskInfo->event_type = INT_PRESENCE_ON; ++ event_type = INT_PRESENCE_ON; + } else { + /* + * Not Present + */ + info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); +- taskInfo->event_type = INT_PRESENCE_OFF; ++ event_type = INT_PRESENCE_OFF; + } + +- if (rc) +- up(&event_semaphore); /* signal event thread that new event is posted */ ++ queue_interrupt_event(p_slot, event_type); + +- return rc; ++ return 1; + } + + u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) + { + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; +- u8 rc = 0; +- struct event_info *taskInfo; ++ u32 event_type; + + /* Power fault */ + dbg("shpchp: Power fault interrupt received.\n"); + +- /* This is the structure that tells the worker thread +- * what to do +- */ +- taskInfo = &(ctrl->event_queue[ctrl->next_event]); +- ctrl->next_event = (ctrl->next_event + 1) % 10; +- taskInfo->hp_slot = hp_slot; +- +- rc++; + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { +@@ -216,21 +187,21 @@ u8 shpchp_handle_power_fault(u8 hp_slot, + */ + info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); + p_slot->status = 0x00; +- taskInfo->event_type = INT_POWER_FAULT_CLEAR; ++ event_type = INT_POWER_FAULT_CLEAR; + } else { + /* + * Power fault + */ + info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); +- taskInfo->event_type = INT_POWER_FAULT; ++ event_type = INT_POWER_FAULT; + /* set power fault status for this board */ + p_slot->status = 0xFF; + info("power fault bit %x set\n", hp_slot); + } +- if (rc) +- up(&event_semaphore); /* signal event thread that new event is posted */ + +- return rc; ++ queue_interrupt_event(p_slot, event_type); ++ ++ return 1; + } + + /* The following routines constitute the bulk of the +@@ -521,14 +492,6 @@ static int remove_board(struct slot *p_s + } + + +-static void pushbutton_helper_thread (unsigned long data) +-{ +- pushbutton_pending = data; +- +- up(&event_semaphore); +-} +- +- + /** + * shpchp_pushbutton_thread + * +@@ -536,90 +499,24 @@ static void pushbutton_helper_thread (un + * Handles all pending events and exits. + * + */ +-static void shpchp_pushbutton_thread (unsigned long slot) ++void shpchp_pushbutton_thread(void *data) + { +- struct slot *p_slot = (struct slot *) slot; ++ struct slot *p_slot = data; + u8 getstatus; +- +- pushbutton_pending = 0; +- +- if (!p_slot) { +- dbg("%s: Error! slot NULL\n", __FUNCTION__); +- return; +- } + + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + p_slot->state = POWEROFF_STATE; +- + shpchp_disable_slot(p_slot); + p_slot->state = STATIC_STATE; + } else { + p_slot->state = POWERON_STATE; +- + if (shpchp_enable_slot(p_slot)) + p_slot->hpc_ops->green_led_off(p_slot); +- + p_slot->state = STATIC_STATE; + } +- +- return; + } + +- +-/* this is the main worker thread */ +-static int event_thread(void* data) +-{ +- struct controller *ctrl; +- lock_kernel(); +- daemonize("shpchpd_event"); +- unlock_kernel(); +- +- while (1) { +- dbg("!!!!event_thread sleeping\n"); +- down_interruptible (&event_semaphore); +- dbg("event_thread woken finished = %d\n", event_finished); +- if (event_finished || signal_pending(current)) +- break; +- /* Do stuff here */ +- if (pushbutton_pending) +- shpchp_pushbutton_thread(pushbutton_pending); +- else +- list_for_each_entry(ctrl, &shpchp_ctrl_list, ctrl_list) +- interrupt_event_handler(ctrl); +- } +- dbg("event_thread signals exit\n"); +- up(&event_exit); +- return 0; +-} +- +-int shpchp_event_start_thread (void) +-{ +- int pid; +- +- /* initialize our semaphores */ +- init_MUTEX_LOCKED(&event_exit); +- event_finished=0; +- +- init_MUTEX_LOCKED(&event_semaphore); +- pid = kernel_thread(event_thread, NULL, 0); +- +- if (pid < 0) { +- err ("Can't start up our event thread\n"); +- return -1; +- } +- return 0; +-} +- +- +-void shpchp_event_stop_thread (void) +-{ +- event_finished = 1; +- up(&event_semaphore); +- down(&event_exit); +-} +- +- + static int update_slot_info (struct slot *slot) + { + struct hotplug_slot_info *info; +@@ -639,91 +536,59 @@ static int update_slot_info (struct slot + return result; + } + +-static void interrupt_event_handler(struct controller *ctrl) ++static void interrupt_event_handler(void *data) + { +- int loop = 0; +- int change = 1; +- u8 hp_slot; ++ struct event_info *info = data; ++ struct slot *p_slot = info->p_slot; + u8 getstatus; +- struct slot *p_slot; + +- while (change) { +- change = 0; +- +- for (loop = 0; loop < 10; loop++) { +- if (ctrl->event_queue[loop].event_type != 0) { +- dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop, +- ctrl->event_queue[loop].event_type); +- hp_slot = ctrl->event_queue[loop].hp_slot; +- +- p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); +- +- if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { +- dbg("%s: button cancel\n", __FUNCTION__); +- del_timer(&p_slot->task_event); +- +- switch (p_slot->state) { +- case BLINKINGOFF_STATE: +- p_slot->hpc_ops->green_led_on(p_slot); +- p_slot->hpc_ops->set_attention_status(p_slot, 0); +- break; +- case BLINKINGON_STATE: +- p_slot->hpc_ops->green_led_off(p_slot); +- p_slot->hpc_ops->set_attention_status(p_slot, 0); +- break; +- default: +- warn("Not a valid state\n"); +- return; +- } +- info(msg_button_cancel, p_slot->number); +- p_slot->state = STATIC_STATE; +- } else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { +- /* Button Pressed (No action on 1st press...) */ +- dbg("%s: Button pressed\n", __FUNCTION__); +- +- p_slot->hpc_ops->get_power_status(p_slot, &getstatus); +- if (getstatus) { +- /* slot is on */ +- dbg("%s: slot is on\n", __FUNCTION__); +- p_slot->state = BLINKINGOFF_STATE; +- info(msg_button_off, p_slot->number); +- } else { +- /* slot is off */ +- dbg("%s: slot is off\n", __FUNCTION__); +- p_slot->state = BLINKINGON_STATE; +- info(msg_button_on, p_slot->number); +- } +- +- /* blink green LED and turn off amber */ +- p_slot->hpc_ops->green_led_blink(p_slot); +- p_slot->hpc_ops->set_attention_status(p_slot, 0); +- +- init_timer(&p_slot->task_event); +- p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ +- p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; +- p_slot->task_event.data = (unsigned long) p_slot; +- +- dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot); +- add_timer(&p_slot->task_event); +- } else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { +- /***********POWER FAULT********************/ +- dbg("%s: power fault\n", __FUNCTION__); +- p_slot->hpc_ops->set_attention_status(p_slot, 1); +- p_slot->hpc_ops->green_led_off(p_slot); +- } else { +- /* refresh notification */ +- if (p_slot) +- update_slot_info(p_slot); +- } +- +- ctrl->event_queue[loop].event_type = 0; +- +- change = 1; +- } +- } /* End of FOR loop */ ++ switch (info->event_type) { ++ case INT_BUTTON_CANCEL: ++ dbg("%s: button cancel\n", __FUNCTION__); ++ cancel_delayed_work(&p_slot->work); ++ switch (p_slot->state) { ++ case BLINKINGOFF_STATE: ++ p_slot->hpc_ops->green_led_on(p_slot); ++ p_slot->hpc_ops->set_attention_status(p_slot, 0); ++ break; ++ case BLINKINGON_STATE: ++ p_slot->hpc_ops->green_led_off(p_slot); ++ p_slot->hpc_ops->set_attention_status(p_slot, 0); ++ break; ++ default: ++ warn("Not a valid state\n"); ++ return; ++ } ++ info(msg_button_cancel, p_slot->number); ++ p_slot->state = STATIC_STATE; ++ break; ++ case INT_BUTTON_PRESS: ++ dbg("%s: Button pressed\n", __FUNCTION__); ++ p_slot->hpc_ops->get_power_status(p_slot, &getstatus); ++ if (getstatus) { ++ p_slot->state = BLINKINGOFF_STATE; ++ info(msg_button_off, p_slot->number); ++ } else { ++ p_slot->state = BLINKINGON_STATE; ++ info(msg_button_on, p_slot->number); ++ } ++ /* blink green LED and turn off amber */ ++ p_slot->hpc_ops->green_led_blink(p_slot); ++ p_slot->hpc_ops->set_attention_status(p_slot, 0); ++ ++ queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ); ++ break; ++ case INT_POWER_FAULT: ++ dbg("%s: power fault\n", __FUNCTION__); ++ p_slot->hpc_ops->set_attention_status(p_slot, 1); ++ p_slot->hpc_ops->green_led_off(p_slot); ++ break; ++ default: ++ update_slot_info(p_slot); ++ break; + } + +- return; ++ kfree(info); + } + + +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp.h ++++ gregkh-2.6/drivers/pci/hotplug/shpchp.h +@@ -46,6 +46,7 @@ + extern int shpchp_poll_mode; + extern int shpchp_poll_time; + 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("%s: " format, MY_NAME , ## arg); } while (0) +@@ -70,11 +71,13 @@ struct slot { + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; + char name[SLOT_NAME_SIZE]; ++ struct work_struct work; /* work for button event */ + }; + + struct event_info { + u32 event_type; +- u8 hp_slot; ++ struct slot *p_slot; ++ struct work_struct work; + }; + + struct controller { +@@ -85,11 +88,9 @@ struct controller { + int num_slots; /* Number of slots on ctlr */ + int slot_num_inc; /* 1 or -1 */ + struct pci_dev *pci_dev; +- struct event_info event_queue[10]; + struct list_head slot_list; + struct hpc_ops *hpc_ops; + wait_queue_head_t queue; /* sleep & wake process */ +- u8 next_event; + u8 bus; + u8 device; + u8 function; +@@ -180,9 +181,6 @@ struct hotplug_params { + /* sysfs functions for the hotplug controller info */ + 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_disable_slot(struct slot *slot); + +@@ -201,7 +199,8 @@ extern void get_hp_params_from_firmware( + extern int shpchprm_get_physical_slot_number(struct controller *ctrl, + u32 *sun, u8 busnum, u8 devnum); + 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 */ + extern struct list_head shpchp_ctrl_list; +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_core.c ++++ gregkh-2.6/drivers/pci/hotplug/shpchp_core.c +@@ -32,6 +32,7 @@ + #include <linux/kernel.h> + #include <linux/types.h> + #include <linux/pci.h> ++#include <linux/workqueue.h> + #include "shpchp.h" + + /* Global variables */ +@@ -39,6 +40,7 @@ int shpchp_debug; + int shpchp_poll_mode; + int shpchp_poll_time; + LIST_HEAD(shpchp_ctrl_list); ++struct workqueue_struct *shpchp_wq; + + #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>" +@@ -57,7 +59,6 @@ MODULE_PARM_DESC(shpchp_poll_time, "Poll + + #define SHPC_MODULE_NAME "shpchp" + +-static int shpc_start_thread (void); + static int set_attention_status (struct hotplug_slot *slot, u8 value); + static int enable_slot (struct hotplug_slot *slot); + static int disable_slot (struct hotplug_slot *slot); +@@ -141,6 +142,7 @@ static int init_slots(struct controller + goto error_info; + + slot->number = sun; ++ INIT_WORK(&slot->work, shpchp_pushbutton_thread, slot); + + /* register this slot with the hotplug pci core */ + hotplug_slot->private = slot; +@@ -176,7 +178,7 @@ error: + return retval; + } + +-static void cleanup_slots(struct controller *ctrl) ++void cleanup_slots(struct controller *ctrl) + { + struct list_head *tmp; + struct list_head *next; +@@ -185,6 +187,8 @@ static void cleanup_slots(struct control + list_for_each_safe(tmp, next, &ctrl->slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + list_del(&slot->slot_list); ++ cancel_delayed_work(&slot->work); ++ flush_workqueue(shpchp_wq); + pci_hp_deregister(slot->hotplug_slot); + } + } +@@ -400,7 +404,7 @@ static int shpc_probe(struct pci_dev *pd + rc = get_ctlr_slot_config(ctrl); + if (rc) { + err(msg_initialization_err, rc); +- goto err_out_unmap_mmio_region; ++ goto err_out_release_ctlr; + } + first_device_num = ctrl->slot_device_offset; + num_ctlr_slots = ctrl->num_slots; +@@ -411,7 +415,7 @@ static int shpc_probe(struct pci_dev *pd + rc = init_slots(ctrl); + if (rc) { + 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 */ +@@ -427,18 +431,13 @@ static int shpc_probe(struct pci_dev *pd + 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); + + shpchp_create_ctrl_files(ctrl); + + return 0; + +-err_out_free_ctrl_slot: +- cleanup_slots(ctrl); +-err_out_unmap_mmio_region: ++err_out_release_ctlr: + ctrl->hpc_ops->release_ctlr(ctrl); + err_out_free_ctrl: + kfree(ctrl); +@@ -446,21 +445,6 @@ err_out_none: + 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) + { + struct list_head *tmp; +@@ -470,14 +454,11 @@ static void __exit unload_shpchpd(void) + list_for_each_safe(tmp, next, &shpchp_ctrl_list) { + ctrl = list_entry(tmp, struct controller, ctrl_list); + shpchp_remove_ctrl_files(ctrl); +- cleanup_slots(ctrl); + ctrl->hpc_ops->release_ctlr(ctrl); + kfree(ctrl); + } + +- /* Stop the notification mechanism */ +- shpchp_event_stop_thread(); +- ++ destroy_workqueue(shpchp_wq); + } + + static struct pci_device_id shpcd_pci_tbl[] = { +@@ -501,17 +482,15 @@ static int __init shpcd_init(void) + shpchp_poll_mode = 1; + #endif + +- retval = shpc_start_thread(); +- if (retval) +- goto error_hpc_init; ++ shpchp_wq = create_singlethread_workqueue("shpchpd"); ++ if (!shpchp_wq) ++ return -ENOMEM; + + retval = pci_register_driver(&shpc_driver); + dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); +- +-error_hpc_init: + if (retval) { +- shpchp_event_stop_thread(); ++ destroy_workqueue(shpchp_wq); + } + return retval; + } +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_hpc.c ++++ gregkh-2.6/drivers/pci/hotplug/shpchp_hpc.c +@@ -813,6 +813,7 @@ static void hpc_release_ctlr(struct cont + { + struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *p, *p_prev; ++ int i; + + DBG_ENTER_ROUTINE + +@@ -821,6 +822,14 @@ static void hpc_release_ctlr(struct cont + 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) { + del_timer(&php_ctlr->int_poll_timer); + } else { +@@ -830,6 +839,7 @@ static void hpc_release_ctlr(struct cont + pci_disable_msi(php_ctlr->pci_dev); + } + } ++ + if (php_ctlr->pci_dev) { + iounmap(php_ctlr->creg); + release_mem_region(ctrl->mmio_base, ctrl->mmio_size); diff --git a/pci/shpchp-fix-slot-state-handling.patch b/pci/shpchp-fix-slot-state-handling.patch new file mode 100644 index 0000000000000..b625579014607 --- /dev/null +++ b/pci/shpchp-fix-slot-state-handling.patch @@ -0,0 +1,455 @@ +From pcihpd-discuss-admin@lists.sourceforge.net Tue Feb 21 15:42:10 2006 +From: Kristen Accardi <kristen.c.accardi@intel.com> +To: Greg KH <greg@kroah.com> +Cc: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>, Kristen Accardi <kristen.c.accardi@intel.com> +Message-Id: <1140565548.24286.22.camel@whizzy> +Subject: shpchp: Fix slot state handling +Date: Tue, 21 Feb 2006 15:45:48 -0800 + +From: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> + +Current SHPCHP driver doesn't care about the confliction between +hotplug operation via sysfs and hotplug operation via attention +button. So if those ware conflicted, slot could be an unexpected +state. + +This patch changes SHPCHP driver to handle slot state properly. With +this patch, slot events are handled according to the current slot +state as shown at the Table below. + + Table. Slot States and Event Handling +========================================================================= +Slot State Event and Action +========================================================================= +STATIC - Go to POWERON state if user initiates +(Slot enabled, insertion request via sysfs + Slot disabled) - Go to POWEROFF state if user initiates removal + request via sysfs + - Go to BLINKINGON state if user presses + attention button when the slot is disabled + - Go to BLINKINGOFF state if user presses + attention button when the slot is enabled +------------------------------------------------------------------------- +POWERON - Ignore insertion requests via sysfs +(Enabling slot) - Ignore removal requests via sysfs + - Ignore attention button press + - Go to STATIC state when slot has been enabled + - Go to STATIC state if any error happened while + enabling slot +------------------------------------------------------------------------- +POWEROFF - Ignore insertion requests via sysfs +(Disabling slot) - Ignore removal requests via sysfs + - Ignore attention button press + - Go to STATIC state when slot has been disabled +------------------------------------------------------------------------- +BLINKINGON - Go to POWERON state if user initiates insertion +(Waiting for >5 sec. request via sysfs + for canceling - Ignore removal request via sysfs + insertion request - Go to STATIC state if user presses attention + initiated via button + attention button) - Go to POWERON state after waiting for >5 sec. +------------------------------------------------------------------------- +BLINKINGOFF - Ignore insertion request via sysfs +(Waiting for >5 sec. - Go to POWEROFF state if user initiates removal + for canceling removal request via sysfs + request initiated via - Go to STATIC state if user presses attention + attention button) button + - Go to POWEROFF state after waiting for >5 sec. +------------------------------------------------------------------------- + +Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> +Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/pci/hotplug/shpchp.h | 7 - + drivers/pci/hotplug/shpchp_core.c | 8 - + drivers/pci/hotplug/shpchp_ctrl.c | 227 ++++++++++++++++++++++++++++---------- + 3 files changed, 181 insertions(+), 61 deletions(-) + +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp.h ++++ gregkh-2.6/drivers/pci/hotplug/shpchp.h +@@ -72,6 +72,7 @@ struct slot { + struct list_head slot_list; + char name[SLOT_NAME_SIZE]; + struct work_struct work; /* work for button event */ ++ struct mutex lock; + }; + + struct event_info { +@@ -181,8 +182,8 @@ struct hotplug_params { + /* sysfs functions for the hotplug controller info */ + extern void shpchp_create_ctrl_files (struct controller *ctrl); + +-extern int shpchp_enable_slot(struct slot *slot); +-extern int shpchp_disable_slot(struct slot *slot); ++extern int shpchp_sysfs_enable_slot(struct slot *slot); ++extern int shpchp_sysfs_disable_slot(struct slot *slot); + + extern u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id); + extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id); +@@ -200,7 +201,7 @@ extern int shpchprm_get_physical_slot_nu + u32 *sun, u8 busnum, u8 devnum); + extern void shpchp_remove_ctrl_files(struct controller *ctrl); + extern void cleanup_slots(struct controller *ctrl); +-extern void shpchp_pushbutton_thread(void *data); ++extern void queue_pushbutton_work(void *data); + + /* Global variables */ + extern struct list_head shpchp_ctrl_list; +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_core.c ++++ gregkh-2.6/drivers/pci/hotplug/shpchp_core.c +@@ -136,13 +136,14 @@ static int init_slots(struct controller + slot->bus = ctrl->slot_bus; + slot->device = ctrl->slot_device_offset + i; + slot->hpc_ops = ctrl->hpc_ops; ++ mutex_init(&slot->lock); + + if (shpchprm_get_physical_slot_number(ctrl, &sun, + slot->bus, slot->device)) + goto error_info; + + slot->number = sun; +- INIT_WORK(&slot->work, shpchp_pushbutton_thread, slot); ++ INIT_WORK(&slot->work, queue_pushbutton_work, slot); + + /* register this slot with the hotplug pci core */ + hotplug_slot->private = slot; +@@ -188,6 +189,7 @@ void cleanup_slots(struct controller *ct + slot = list_entry(tmp, struct slot, slot_list); + list_del(&slot->slot_list); + cancel_delayed_work(&slot->work); ++ flush_scheduled_work(); + flush_workqueue(shpchp_wq); + pci_hp_deregister(slot->hotplug_slot); + } +@@ -244,7 +246,7 @@ static int enable_slot (struct hotplug_s + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + +- return shpchp_enable_slot(slot); ++ return shpchp_sysfs_enable_slot(slot); + } + + static int disable_slot (struct hotplug_slot *hotplug_slot) +@@ -253,7 +255,7 @@ static int disable_slot (struct hotplug_ + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + +- return shpchp_disable_slot(slot); ++ return shpchp_sysfs_disable_slot(slot); + } + + static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_ctrl.c ++++ gregkh-2.6/drivers/pci/hotplug/shpchp_ctrl.c +@@ -37,6 +37,8 @@ + #include "shpchp.h" + + static void interrupt_event_handler(void *data); ++static int shpchp_enable_slot(struct slot *p_slot); ++static int shpchp_disable_slot(struct slot *p_slot); + + static int queue_interrupt_event(struct slot *p_slot, u32 event_type) + { +@@ -50,7 +52,7 @@ static int queue_interrupt_event(struct + info->p_slot = p_slot; + INIT_WORK(&info->work, interrupt_event_handler, info); + +- queue_work(shpchp_wq, &info->work); ++ schedule_work(&info->work); + + return 0; + } +@@ -73,24 +75,6 @@ u8 shpchp_handle_attention_button(u8 hp_ + info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); + event_type = INT_BUTTON_PRESS; + +- if ((p_slot->state == BLINKINGON_STATE) +- || (p_slot->state == BLINKINGOFF_STATE)) { +- /* Cancel if we are still blinking; this means that we press the +- * attention again before the 5 sec. limit expires to cancel hot-add +- * or hot-remove +- */ +- event_type = INT_BUTTON_CANCEL; +- info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); +- } else if ((p_slot->state == POWERON_STATE) +- || (p_slot->state == POWEROFF_STATE)) { +- /* Ignore if the slot is on power-on or power-off state; this +- * means that the previous attention button action to hot-add or +- * hot-remove is undergoing +- */ +- event_type = INT_BUTTON_IGNORE; +- info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); +- } +- + queue_interrupt_event(p_slot, event_type); + + return 0; +@@ -492,6 +476,11 @@ static int remove_board(struct slot *p_s + } + + ++struct pushbutton_work_info { ++ struct slot *p_slot; ++ struct work_struct work; ++}; ++ + /** + * shpchp_pushbutton_thread + * +@@ -499,22 +488,61 @@ static int remove_board(struct slot *p_s + * Handles all pending events and exits. + * + */ +-void shpchp_pushbutton_thread(void *data) ++static void shpchp_pushbutton_thread(void *data) + { +- struct slot *p_slot = data; +- u8 getstatus; ++ struct pushbutton_work_info *info = data; ++ struct slot *p_slot = info->p_slot; + +- p_slot->hpc_ops->get_power_status(p_slot, &getstatus); +- if (getstatus) { +- p_slot->state = POWEROFF_STATE; ++ mutex_lock(&p_slot->lock); ++ switch (p_slot->state) { ++ case POWEROFF_STATE: ++ mutex_unlock(&p_slot->lock); + shpchp_disable_slot(p_slot); ++ mutex_lock(&p_slot->lock); + p_slot->state = STATIC_STATE; +- } else { +- p_slot->state = POWERON_STATE; ++ break; ++ case POWERON_STATE: ++ mutex_unlock(&p_slot->lock); + if (shpchp_enable_slot(p_slot)) + p_slot->hpc_ops->green_led_off(p_slot); ++ mutex_lock(&p_slot->lock); + p_slot->state = STATIC_STATE; ++ break; ++ default: ++ break; ++ } ++ mutex_unlock(&p_slot->lock); ++ ++ kfree(info); ++} ++ ++void queue_pushbutton_work(void *data) ++{ ++ struct slot *p_slot = data; ++ struct pushbutton_work_info *info; ++ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) { ++ err("%s: Cannot allocate memory\n", __FUNCTION__); ++ return; ++ } ++ info->p_slot = p_slot; ++ INIT_WORK(&info->work, shpchp_pushbutton_thread, info); ++ ++ mutex_lock(&p_slot->lock); ++ switch (p_slot->state) { ++ case BLINKINGOFF_STATE: ++ p_slot->state = POWEROFF_STATE; ++ break; ++ case BLINKINGON_STATE: ++ p_slot->state = POWERON_STATE; ++ break; ++ default: ++ goto out; + } ++ queue_work(shpchp_wq, &info->work); ++ out: ++ mutex_unlock(&p_slot->lock); + } + + static int update_slot_info (struct slot *slot) +@@ -536,34 +564,15 @@ static int update_slot_info (struct slot + return result; + } + +-static void interrupt_event_handler(void *data) ++/* ++ * Note: This function must be called with slot->lock held ++ */ ++static void handle_button_press_event(struct slot *p_slot) + { +- struct event_info *info = data; +- struct slot *p_slot = info->p_slot; + u8 getstatus; + +- switch (info->event_type) { +- case INT_BUTTON_CANCEL: +- dbg("%s: button cancel\n", __FUNCTION__); +- cancel_delayed_work(&p_slot->work); +- switch (p_slot->state) { +- case BLINKINGOFF_STATE: +- p_slot->hpc_ops->green_led_on(p_slot); +- p_slot->hpc_ops->set_attention_status(p_slot, 0); +- break; +- case BLINKINGON_STATE: +- p_slot->hpc_ops->green_led_off(p_slot); +- p_slot->hpc_ops->set_attention_status(p_slot, 0); +- break; +- default: +- warn("Not a valid state\n"); +- return; +- } +- info(msg_button_cancel, p_slot->number); +- p_slot->state = STATIC_STATE; +- break; +- case INT_BUTTON_PRESS: +- dbg("%s: Button pressed\n", __FUNCTION__); ++ switch (p_slot->state) { ++ case STATIC_STATE: + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + p_slot->state = BLINKINGOFF_STATE; +@@ -576,7 +585,51 @@ static void interrupt_event_handler(void + p_slot->hpc_ops->green_led_blink(p_slot); + p_slot->hpc_ops->set_attention_status(p_slot, 0); + +- queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ); ++ schedule_delayed_work(&p_slot->work, 5*HZ); ++ break; ++ case BLINKINGOFF_STATE: ++ case BLINKINGON_STATE: ++ /* ++ * Cancel if we are still blinking; this means that we ++ * press the attention again before the 5 sec. limit ++ * expires to cancel hot-add or hot-remove ++ */ ++ info("Button cancel on Slot(%s)\n", p_slot->name); ++ dbg("%s: button cancel\n", __FUNCTION__); ++ cancel_delayed_work(&p_slot->work); ++ if (p_slot->state == BLINKINGOFF_STATE) ++ p_slot->hpc_ops->green_led_on(p_slot); ++ else ++ p_slot->hpc_ops->green_led_off(p_slot); ++ p_slot->hpc_ops->set_attention_status(p_slot, 0); ++ info(msg_button_cancel, p_slot->number); ++ p_slot->state = STATIC_STATE; ++ break; ++ case POWEROFF_STATE: ++ case POWERON_STATE: ++ /* ++ * Ignore if the slot is on power-on or power-off state; ++ * this means that the previous attention button action ++ * to hot-add or hot-remove is undergoing ++ */ ++ info("Button ignore on Slot(%s)\n", p_slot->name); ++ update_slot_info(p_slot); ++ break; ++ default: ++ warn("Not a valid state\n"); ++ break; ++ } ++} ++ ++static void interrupt_event_handler(void *data) ++{ ++ struct event_info *info = data; ++ struct slot *p_slot = info->p_slot; ++ ++ mutex_lock(&p_slot->lock); ++ switch (info->event_type) { ++ case INT_BUTTON_PRESS: ++ handle_button_press_event(p_slot); + break; + case INT_POWER_FAULT: + dbg("%s: power fault\n", __FUNCTION__); +@@ -587,12 +640,13 @@ static void interrupt_event_handler(void + update_slot_info(p_slot); + break; + } ++ mutex_unlock(&p_slot->lock); + + kfree(info); + } + + +-int shpchp_enable_slot (struct slot *p_slot) ++static int shpchp_enable_slot (struct slot *p_slot) + { + u8 getstatus = 0; + int rc, retval = -ENODEV; +@@ -647,7 +701,7 @@ int shpchp_enable_slot (struct slot *p_s + } + + +-int shpchp_disable_slot (struct slot *p_slot) ++static int shpchp_disable_slot (struct slot *p_slot) + { + u8 getstatus = 0; + int rc, retval = -ENODEV; +@@ -681,3 +735,66 @@ int shpchp_disable_slot (struct slot *p_ + return retval; + } + ++int shpchp_sysfs_enable_slot(struct slot *p_slot) ++{ ++ int retval = -ENODEV; ++ ++ mutex_lock(&p_slot->lock); ++ switch (p_slot->state) { ++ case BLINKINGON_STATE: ++ cancel_delayed_work(&p_slot->work); ++ case STATIC_STATE: ++ p_slot->state = POWERON_STATE; ++ mutex_unlock(&p_slot->lock); ++ retval = shpchp_enable_slot(p_slot); ++ mutex_lock(&p_slot->lock); ++ p_slot->state = STATIC_STATE; ++ break; ++ case POWERON_STATE: ++ info("Slot %s is already in powering on state\n", ++ p_slot->name); ++ break; ++ case BLINKINGOFF_STATE: ++ case POWEROFF_STATE: ++ info("Already enabled on slot %s\n", p_slot->name); ++ break; ++ default: ++ err("Not a valid state on slot %s\n", p_slot->name); ++ break; ++ } ++ mutex_unlock(&p_slot->lock); ++ ++ return retval; ++} ++ ++int shpchp_sysfs_disable_slot(struct slot *p_slot) ++{ ++ int retval = -ENODEV; ++ ++ mutex_lock(&p_slot->lock); ++ switch (p_slot->state) { ++ case BLINKINGOFF_STATE: ++ cancel_delayed_work(&p_slot->work); ++ case STATIC_STATE: ++ p_slot->state = POWEROFF_STATE; ++ mutex_unlock(&p_slot->lock); ++ retval = shpchp_disable_slot(p_slot); ++ mutex_lock(&p_slot->lock); ++ p_slot->state = STATIC_STATE; ++ break; ++ case POWEROFF_STATE: ++ info("Slot %s is already in powering off state\n", ++ p_slot->name); ++ break; ++ case BLINKINGON_STATE: ++ case POWERON_STATE: ++ info("Already disabled on slot %s\n", p_slot->name); ++ break; ++ default: ++ err("Not a valid state on slot %s\n", p_slot->name); ++ break; ++ } ++ mutex_unlock(&p_slot->lock); ++ ++ return retval; ++} diff --git a/pci/shpchp-remove-unused-pci_bus-member-from-controller-structure.patch b/pci/shpchp-remove-unused-pci_bus-member-from-controller-structure.patch new file mode 100644 index 0000000000000..21e1fffcc7ea9 --- /dev/null +++ b/pci/shpchp-remove-unused-pci_bus-member-from-controller-structure.patch @@ -0,0 +1,76 @@ +From pcihpd-discuss-admin@lists.sourceforge.net Tue Feb 21 15:41:15 2006 +From: Kristen Accardi <kristen.c.accardi@intel.com> +To: Greg KH <greg@kroah.com> +Cc: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>, Kristen Accardi <kristen.c.accardi@intel.com> +Message-Id: <1140565538.24286.19.camel@whizzy> +Subject: shpchp: Remove unused pci_bus member from controller structure +Date: Tue, 21 Feb 2006 15:45:38 -0800 + +From: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> + +This patch removes unused 'pci_bus' member from controller structure. +This patch have no functional change. + +Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> +Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/pci/hotplug/shpchp.h | 1 - + drivers/pci/hotplug/shpchp_core.c | 13 +------------ + 2 files changed, 1 insertion(+), 13 deletions(-) + +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp.h ++++ gregkh-2.6/drivers/pci/hotplug/shpchp.h +@@ -85,7 +85,6 @@ struct controller { + int num_slots; /* Number of slots on ctlr */ + int slot_num_inc; /* 1 or -1 */ + struct pci_dev *pci_dev; +- struct pci_bus *pci_bus; + struct event_info event_queue[10]; + struct list_head slot_list; + struct hpc_ops *hpc_ops; +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_core.c ++++ gregkh-2.6/drivers/pci/hotplug/shpchp_core.c +@@ -386,14 +386,6 @@ static int shpc_probe(struct pci_dev *pd + + pci_set_drvdata(pdev, ctrl); + +- ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL); +- if (!ctrl->pci_bus) { +- err("out of memory\n"); +- rc = -ENOMEM; +- goto err_out_unmap_mmio_region; +- } +- +- memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); + ctrl->bus = pdev->bus->number; + ctrl->slot_bus = pdev->subordinate->number; + ctrl->device = PCI_SLOT(pdev->devfn); +@@ -408,7 +400,7 @@ static int shpc_probe(struct pci_dev *pd + rc = get_ctlr_slot_config(ctrl); + if (rc) { + err(msg_initialization_err, rc); +- goto err_out_free_ctrl_bus; ++ goto err_out_unmap_mmio_region; + } + first_device_num = ctrl->slot_device_offset; + num_ctlr_slots = ctrl->num_slots; +@@ -446,8 +438,6 @@ static int shpc_probe(struct pci_dev *pd + + err_out_free_ctrl_slot: + cleanup_slots(ctrl); +-err_out_free_ctrl_bus: +- kfree(ctrl->pci_bus); + err_out_unmap_mmio_region: + ctrl->hpc_ops->release_ctlr(ctrl); + err_out_free_ctrl: +@@ -481,7 +471,6 @@ static void __exit unload_shpchpd(void) + ctrl = list_entry(tmp, struct controller, ctrl_list); + shpchp_remove_ctrl_files(ctrl); + cleanup_slots(ctrl); +- kfree (ctrl->pci_bus); + ctrl->hpc_ops->release_ctlr(ctrl); + kfree(ctrl); + } diff --git a/pci/shpchp-remove-unused-wait_for_ctrl_irq.patch b/pci/shpchp-remove-unused-wait_for_ctrl_irq.patch new file mode 100644 index 0000000000000..ba58261356d67 --- /dev/null +++ b/pci/shpchp-remove-unused-wait_for_ctrl_irq.patch @@ -0,0 +1,63 @@ +From pcihpd-discuss-admin@lists.sourceforge.net Tue Feb 21 15:41:04 2006 +From: Kristen Accardi <kristen.c.accardi@intel.com> +To: Greg KH <greg@kroah.com> +Cc: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>, Kristen Accardi <kristen.c.accardi@intel.com> +Message-Id: <1140565542.24286.20.camel@whizzy> +Subject: shpchp: Remove unused wait_for_ctrl_irq +Date: Tue, 21 Feb 2006 15:45:42 -0800 + +From: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> + +The wait_for_ctrl_irq() function in SHPCHP driver is no longer needed. +This patch removes that. This patch has no functional change. + +Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> +Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/pci/hotplug/shpchp.h | 21 --------------------- + drivers/pci/hotplug/shpchp_ctrl.c | 2 +- + 2 files changed, 1 insertion(+), 22 deletions(-) + +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp.h ++++ gregkh-2.6/drivers/pci/hotplug/shpchp.h +@@ -325,27 +325,6 @@ static inline struct slot *shpchp_find_s + return NULL; + } + +-static inline int wait_for_ctrl_irq (struct controller *ctrl) +-{ +- DECLARE_WAITQUEUE(wait, current); +- int retval = 0; +- +- add_wait_queue(&ctrl->queue, &wait); +- +- if (!shpchp_poll_mode) { +- /* Sleep for up to 1 second */ +- msleep_interruptible(1000); +- } else { +- /* Sleep for up to 2 seconds */ +- msleep_interruptible(2000); +- } +- remove_wait_queue(&ctrl->queue, &wait); +- if (signal_pending(current)) +- retval = -EINTR; +- +- return retval; +-} +- + static inline void amd_pogo_errata_save_misc_reg(struct slot *p_slot) + { + u32 pcix_misc2_temp; +--- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_ctrl.c ++++ gregkh-2.6/drivers/pci/hotplug/shpchp_ctrl.c +@@ -441,7 +441,7 @@ static int board_added(struct slot *p_sl + } + + /* Wait for ~1 second */ +- wait_for_ctrl_irq (ctrl); ++ msleep(1000); + + dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); + /* Check for a power fault */ |