aboutsummaryrefslogtreecommitdiffstats
path: root/pci
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-02-22 15:02:34 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2006-02-22 15:02:34 -0800
commiteb6b406dcc7096974eec722b436e0f05eca353a4 (patch)
tree0fa607d200cd276b6774f0f863e317a0741fc493 /pci
parent4fffec22d6b7a52d17e144280ea226114c92e0a0 (diff)
downloadpatches-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.patch44
-rw-r--r--pci/pci-make-msi-quirk-inheritable-from-the-pci-bus.patch83
-rw-r--r--pci/pci-pci-quirk-for-asus-a8v-and-a8v-deluxe-motherboards.patch67
-rw-r--r--pci/pci-smbus-unhide-on-hp-compaq-nx6110.patch32
-rw-r--r--pci/shpchp-adapt-to-pci-driver-model.patch107
-rw-r--r--pci/shpchp-event-handling-rework.patch754
-rw-r--r--pci/shpchp-fix-slot-state-handling.patch455
-rw-r--r--pci/shpchp-remove-unused-pci_bus-member-from-controller-structure.patch76
-rw-r--r--pci/shpchp-remove-unused-wait_for_ctrl_irq.patch63
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 */