aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve French <sfrench@hera.kernel.org>2005-05-19 12:26:57 -0700
committerSteve French <sfrench@hera.kernel.org>2005-05-19 12:26:57 -0700
commit7e2987503dda95a5f80290bb8c06279009c2419e (patch)
treee841944c911ada8d2b806e13d2c7b7320adaeb2f
parentb1a45695bde0204597957e448923f09ce271ca80 (diff)
parent49a43876b935c811cfd29d8fe998a6912a1cc5c4 (diff)
Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
-rw-r--r--Documentation/filesystems/sysfs-pci.txt6
-rw-r--r--Documentation/power/devices.txt21
-rw-r--r--Documentation/powerpc/hvcs.txt4
-rw-r--r--drivers/base/Makefile2
-rw-r--r--drivers/base/bus.c1
-rw-r--r--drivers/base/core.c3
-rw-r--r--drivers/base/interface.c51
-rw-r--r--drivers/base/power/power.h11
-rw-r--r--drivers/base/power/resume.c11
-rw-r--r--drivers/base/power/shutdown.c23
-rw-r--r--drivers/base/power/suspend.c17
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/pci/hotplug.c119
-rw-r--r--drivers/pci/hotplug/cpci_hotplug.h2
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c169
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c352
-rw-r--r--drivers/pci/hotplug/pciehp.h1
-rw-r--r--drivers/pci/hotplug/pciehp_core.c2
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c156
-rw-r--r--drivers/pci/hotplug/shpchp_core.c2
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c30
-rw-r--r--drivers/pci/pci-sysfs.c12
-rw-r--r--drivers/pci/pci.h27
-rw-r--r--drivers/pci/pcie/portdrv_bus.c3
-rw-r--r--fs/ext3/super.c10
-rw-r--r--include/linux/device.h3
-rw-r--r--kernel/power/main.c6
-rw-r--r--mm/mmap.c4
28 files changed, 282 insertions, 768 deletions
diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt
index e97d024eae7..988a62fae11 100644
--- a/Documentation/filesystems/sysfs-pci.txt
+++ b/Documentation/filesystems/sysfs-pci.txt
@@ -7,7 +7,6 @@ that support it. For example, a given bus might look like this:
|-- 0000:17:00.0
| |-- class
| |-- config
- | |-- detach_state
| |-- device
| |-- irq
| |-- local_cpus
@@ -19,7 +18,7 @@ that support it. For example, a given bus might look like this:
| |-- subsystem_device
| |-- subsystem_vendor
| `-- vendor
- `-- detach_state
+ `-- ...
The topmost element describes the PCI domain and bus number. In this case,
the domain number is 0000 and the bus number is 17 (both values are in hex).
@@ -31,7 +30,6 @@ files, each with their own function.
---- --------
class PCI class (ascii, ro)
config PCI config space (binary, rw)
- detach_state connection status (bool, rw)
device PCI device (ascii, ro)
irq IRQ number (ascii, ro)
local_cpus nearby CPU mask (cpumask, ro)
@@ -85,4 +83,4 @@ useful return codes should be provided.
Legacy resources are protected by the HAVE_PCI_LEGACY define. Platforms
wishing to support legacy functionality should define it and provide
-pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions. \ No newline at end of file
+pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions.
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index 5d4ae9a39f1..f987afe43e2 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -207,27 +207,6 @@ SYSTEM_SHUTDOWN, I do not understand this one too much. probably event
#READY_AFTER_RESUME
#
-Driver Detach Power Management
-
-The kernel now supports the ability to place a device in a low-power
-state when it is detached from its driver, which happens when its
-module is removed.
-
-Each device contains a 'detach_state' file in its sysfs directory
-which can be used to control this state. Reading from this file
-displays what the current detach state is set to. This is 0 (On) by
-default. A user may write a positive integer value to this file in the
-range of 1-4 inclusive.
-
-A value of 1-3 will indicate the device should be placed in that
-low-power state, which will cause ->suspend() to be called for that
-device. A value of 4 indicates that the device should be shutdown, so
-->shutdown() will be called for that device.
-
-The driver is responsible for reinitializing the device when the
-module is re-inserted during it's ->probe() (or equivalent) method.
-The driver core will not call any extra functions when binding the
-device to the driver.
pm_message_t meaning
diff --git a/Documentation/powerpc/hvcs.txt b/Documentation/powerpc/hvcs.txt
index c0a62e116e6..dca75cbda6f 100644
--- a/Documentation/powerpc/hvcs.txt
+++ b/Documentation/powerpc/hvcs.txt
@@ -347,8 +347,8 @@ address that is created by firmware. An example vty-server sysfs entry
looks like the following:
Pow5:/sys/bus/vio/drivers/hvcs/30000004 # ls
- . current_vty devspec name partner_vtys
- .. detach_state index partner_clcs vterm_state
+ . current_vty devspec name partner_vtys
+ .. index partner_clcs vterm_state
Each entry is provided, by default with a "name" attribute. Reading the
"name" attribute will reveal the device type as shown in the following
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 6662b545e0a..a47928a2e57 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -1,6 +1,6 @@
# Makefile for the Linux device tree
-obj-y := core.o sys.o interface.o bus.o \
+obj-y := core.o sys.o bus.o \
driver.o class.o class_simple.o platform.o \
cpu.o firmware.o init.o map.o dmapool.o \
attribute_container.o transport_class.o
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 2b3902c867d..3cb04bb04c2 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -390,7 +390,6 @@ void device_release_driver(struct device * dev)
sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
sysfs_remove_link(&dev->kobj, "driver");
list_del_init(&dev->driver_list);
- device_detach_shutdown(dev);
if (drv->remove)
drv->remove(dev);
dev->driver = NULL;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 268a9c8d168..d21eb774449 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -31,8 +31,6 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
-extern struct attribute * dev_default_attrs[];
-
static ssize_t
dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{
@@ -89,7 +87,6 @@ static void device_release(struct kobject * kobj)
static struct kobj_type ktype_device = {
.release = device_release,
.sysfs_ops = &dev_sysfs_ops,
- .default_attrs = dev_default_attrs,
};
diff --git a/drivers/base/interface.c b/drivers/base/interface.c
deleted file mode 100644
index bd515843a0c..00000000000
--- a/drivers/base/interface.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * drivers/base/interface.c - common driverfs interface that's exported to
- * the world for all devices.
- *
- * Copyright (c) 2002-3 Patrick Mochel
- * Copyright (c) 2002-3 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-
-/**
- * detach_state - control the default power state for the device.
- *
- * This is the state the device enters when it's driver module is
- * unloaded. The value is an unsigned integer, in the range of 0-4.
- * '0' indicates 'On', so no action will be taken when the driver is
- * unloaded. This is the default behavior.
- * '4' indicates 'Off', meaning the driver core will call the driver's
- * shutdown method to quiesce the device.
- * 1-3 indicate a low-power state for the device to enter via the
- * driver's suspend method.
- */
-
-static ssize_t detach_show(struct device * dev, char * buf)
-{
- return sprintf(buf, "%u\n", dev->detach_state);
-}
-
-static ssize_t detach_store(struct device * dev, const char * buf, size_t n)
-{
- u32 state;
- state = simple_strtoul(buf, NULL, 10);
- if (state > 4)
- return -EINVAL;
- dev->detach_state = state;
- return n;
-}
-
-static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store);
-
-
-struct attribute * dev_default_attrs[] = {
- &dev_attr_detach_state.attr,
- NULL,
-};
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index e5eda746f2a..2e700d795cf 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -1,18 +1,7 @@
-
-
-enum {
- DEVICE_PM_ON,
- DEVICE_PM1,
- DEVICE_PM2,
- DEVICE_PM3,
- DEVICE_PM_OFF,
-};
-
/*
* shutdown.c
*/
-extern int device_detach_shutdown(struct device *);
extern void device_shutdown(void);
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
index f8f5055754d..26468971ef5 100644
--- a/drivers/base/power/resume.c
+++ b/drivers/base/power/resume.c
@@ -22,8 +22,17 @@ extern int sysdev_resume(void);
int resume_device(struct device * dev)
{
- if (dev->bus && dev->bus->resume)
+ if (dev->power.pm_parent
+ && dev->power.pm_parent->power.power_state) {
+ dev_err(dev, "PM: resume from %d, parent %s still %d\n",
+ dev->power.power_state,
+ dev->power.pm_parent->bus_id,
+ dev->power.pm_parent->power.power_state);
+ }
+ if (dev->bus && dev->bus->resume) {
+ dev_dbg(dev,"resuming\n");
return dev->bus->resume(dev);
+ }
return 0;
}
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
index d1e023fbe16..f50a08be424 100644
--- a/drivers/base/power/shutdown.c
+++ b/drivers/base/power/shutdown.c
@@ -19,20 +19,6 @@
extern struct subsystem devices_subsys;
-int device_detach_shutdown(struct device * dev)
-{
- if (!dev->detach_state)
- return 0;
-
- if (dev->detach_state == DEVICE_PM_OFF) {
- if (dev->driver && dev->driver->shutdown)
- dev->driver->shutdown(dev);
- return 0;
- }
- return dpm_runtime_suspend(dev, dev->detach_state);
-}
-
-
/**
* We handle system devices differently - we suspend and shut them
* down last and resume them first. That way, we don't do anything stupid like
@@ -52,13 +38,12 @@ void device_shutdown(void)
struct device * dev;
down_write(&devices_subsys.rwsem);
- list_for_each_entry_reverse(dev, &devices_subsys.kset.list, kobj.entry) {
- pr_debug("shutting down %s: ", dev->bus_id);
+ list_for_each_entry_reverse(dev, &devices_subsys.kset.list,
+ kobj.entry) {
if (dev->driver && dev->driver->shutdown) {
- pr_debug("Ok\n");
+ dev_dbg(dev, "shutdown\n");
dev->driver->shutdown(dev);
- } else
- pr_debug("Ignored.\n");
+ }
}
up_write(&devices_subsys.rwsem);
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
index a0b5cf689e6..0ec44ef840b 100644
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -39,12 +39,25 @@ int suspend_device(struct device * dev, pm_message_t state)
{
int error = 0;
- dev_dbg(dev, "suspending\n");
+ if (dev->power.power_state) {
+ dev_dbg(dev, "PM: suspend %d-->%d\n",
+ dev->power.power_state, state);
+ }
+ if (dev->power.pm_parent
+ && dev->power.pm_parent->power.power_state) {
+ dev_err(dev,
+ "PM: suspend %d->%d, parent %s already %d\n",
+ dev->power.power_state, state,
+ dev->power.pm_parent->bus_id,
+ dev->power.pm_parent->power.power_state);
+ }
dev->power.prev_state = dev->power.power_state;
- if (dev->bus && dev->bus->suspend && !dev->power.power_state)
+ if (dev->bus && dev->bus->suspend && !dev->power.power_state) {
+ dev_dbg(dev, "suspending\n");
error = dev->bus->suspend(dev, state);
+ }
return error;
}
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 131465e8de5..ca5f42bcaad 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp,
{
struct block_device *bdev = filp->private_data;
- return blkdev_ioctl(bdev->bd_inode, filp, command, arg);
+ return blkdev_ioctl(bdev->bd_inode, NULL, command, arg);
}
static void bind_device(struct raw_config_request *rq)
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
index 021d0f76bc4..3903f8c559b 100644
--- a/drivers/pci/hotplug.c
+++ b/drivers/pci/hotplug.c
@@ -52,116 +52,17 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp,
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
+ envp[i++] = scratch;
+ length += scnprintf (scratch, buffer_size - length,
+ "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",
+ pdev->vendor, pdev->device,
+ pdev->subsystem_vendor, pdev->subsystem_device,
+ (u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
+ (u8)(pdev->class));
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ return -ENOMEM;
+
envp[i] = NULL;
return 0;
}
-
-static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
-{
- struct list_head *ln;
- struct pci_dev *dev;
- struct pci_dev_wrapped wrapped_dev;
- int result = 0;
-
- pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(wrapped_bus->bus),
- wrapped_bus->bus->number);
-
- if (fn->pre_visit_pci_bus) {
- result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
- if (result)
- return result;
- }
-
- ln = wrapped_bus->bus->devices.next;
- while (ln != &wrapped_bus->bus->devices) {
- dev = pci_dev_b(ln);
- ln = ln->next;
-
- memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
- wrapped_dev.dev = dev;
-
- result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
- if (result)
- return result;
- }
-
- if (fn->post_visit_pci_bus)
- result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
-
- return result;
-}
-
-static int pci_visit_bridge (struct pci_visit * fn,
- struct pci_dev_wrapped *wrapped_dev,
- struct pci_bus_wrapped *wrapped_parent)
-{
- struct pci_bus *bus;
- struct pci_bus_wrapped wrapped_bus;
- int result = 0;
-
- pr_debug("PCI: Scanning bridge %s\n", pci_name(wrapped_dev->dev));
-
- if (fn->visit_pci_dev) {
- result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
- if (result)
- return result;
- }
-
- bus = wrapped_dev->dev->subordinate;
- if (bus) {
- memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
- wrapped_bus.bus = bus;
-
- result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
- }
- return result;
-}
-
-/**
- * pci_visit_dev - scans the pci buses.
- * @fn: callback functions that are called while visiting
- * @wrapped_dev: the device to scan
- * @wrapped_parent: the bus where @wrapped_dev is connected to
- *
- * Every bus and every function is presented to a custom
- * function that can act upon it.
- */
-int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
- struct pci_bus_wrapped *wrapped_parent)
-{
- struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
- int result = 0;
-
- if (!dev)
- return 0;
-
- if (fn->pre_visit_pci_dev) {
- result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
- if (result)
- return result;
- }
-
- switch (dev->class >> 8) {
- case PCI_CLASS_BRIDGE_PCI:
- result = pci_visit_bridge(fn, wrapped_dev,
- wrapped_parent);
- if (result)
- return result;
- break;
- default:
- pr_debug("PCI: Scanning device %s\n", pci_name(dev));
- if (fn->visit_pci_dev) {
- result = fn->visit_pci_dev (wrapped_dev,
- wrapped_parent);
- if (result)
- return result;
- }
- }
-
- if (fn->post_visit_pci_dev)
- result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
-
- return result;
-}
-EXPORT_SYMBOL(pci_visit_dev);
diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
index 3ddd75937a4..d9769b30be9 100644
--- a/drivers/pci/hotplug/cpci_hotplug.h
+++ b/drivers/pci/hotplug/cpci_hotplug.h
@@ -31,7 +31,7 @@
#include <linux/types.h>
#include <linux/pci.h>
-/* PICMG 2.12 R2.0 HS CSR bits: */
+/* PICMG 2.1 R2.0 HS CSR bits: */
#define HS_CSR_INS 0x0080
#define HS_CSR_EXT 0x0040
#define HS_CSR_PI 0x0030
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index ed243605dc7..9e9dab7fe86 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -33,11 +33,11 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
+#include <asm/atomic.h>
#include <linux/delay.h>
#include "pci_hotplug.h"
#include "cpci_hotplug.h"
-#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
#define DRIVER_DESC "CompactPCI Hot Plug Core"
@@ -54,9 +54,10 @@
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
/* local variables */
-static spinlock_t list_lock;
+static DECLARE_RWSEM(list_rwsem);
static LIST_HEAD(slot_list);
static int slots;
+static atomic_t extracting;
int cpci_debug;
static struct cpci_hp_controller *controller;
static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
@@ -68,6 +69,8 @@ static int disable_slot(struct hotplug_slot *slot);
static int set_attention_status(struct hotplug_slot *slot, u8 value);
static int get_power_status(struct hotplug_slot *slot, u8 * value);
static int get_attention_status(struct hotplug_slot *slot, u8 * value);
+static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
+static int get_latch_status(struct hotplug_slot *slot, u8 * value);
static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
.owner = THIS_MODULE,
@@ -76,6 +79,8 @@ static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
.set_attention_status = set_attention_status,
.get_power_status = get_power_status,
.get_attention_status = get_attention_status,
+ .get_adapter_status = get_adapter_status,
+ .get_latch_status = get_latch_status,
};
static int
@@ -148,8 +153,10 @@ disable_slot(struct hotplug_slot *hotplug_slot)
warn("failure to update adapter file");
}
- slot->extracting = 0;
-
+ if(slot->extracting) {
+ slot->extracting = 0;
+ atomic_dec(&extracting);
+ }
return retval;
}
@@ -188,6 +195,20 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
return cpci_set_attention_status(hotplug_slot->private, status);
}
+static int
+get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+ *value = hotplug_slot->info->adapter_status;
+ return 0;
+}
+
+static int
+get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+ *value = hotplug_slot->info->latch_status;
+ return 0;
+}
+
static void release_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
@@ -273,10 +294,10 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
}
/* Add slot to our internal list */
- spin_lock(&list_lock);
+ down_write(&list_rwsem);
list_add(&slot->slot_list, &slot_list);
slots++;
- spin_unlock(&list_lock);
+ up_write(&list_rwsem);
}
return 0;
error_name:
@@ -299,9 +320,9 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
struct list_head *next;
int status;
- spin_lock(&list_lock);
+ down_write(&list_rwsem);
if(!slots) {
- spin_unlock(&list_lock);
+ up_write(&list_rwsem);
return -1;
}
list_for_each_safe(tmp, next, &slot_list) {
@@ -319,7 +340,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
slots--;
}
}
- spin_unlock(&list_lock);
+ up_write(&list_rwsem);
return 0;
}
@@ -347,7 +368,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
}
/*
- * According to PICMG 2.12 R2.0, section 6.3.2, upon
+ * According to PICMG 2.1 R2.0, section 6.3.2, upon
* initialization, the system driver shall clear the
* INS bits of the cold-inserted devices.
*/
@@ -359,9 +380,9 @@ init_slots(void)
struct pci_dev* dev;
dbg("%s - enter", __FUNCTION__);
- spin_lock(&list_lock);
+ down_read(&list_rwsem);
if(!slots) {
- spin_unlock(&list_lock);
+ up_read(&list_rwsem);
return -1;
}
list_for_each(tmp, &slot_list) {
@@ -386,7 +407,7 @@ init_slots(void)
}
}
}
- spin_unlock(&list_lock);
+ up_read(&list_rwsem);
dbg("%s - exit", __FUNCTION__);
return 0;
}
@@ -398,10 +419,11 @@ check_slots(void)
struct list_head *tmp;
int extracted;
int inserted;
+ u16 hs_csr;
- spin_lock(&list_lock);
+ down_read(&list_rwsem);
if(!slots) {
- spin_unlock(&list_lock);
+ up_read(&list_rwsem);
err("no slots registered, shutting down");
return -1;
}
@@ -411,8 +433,6 @@ check_slots(void)
dbg("%s - looking at slot %s",
__FUNCTION__, slot->hotplug_slot->name);
if(cpci_check_and_clear_ins(slot)) {
- u16 hs_csr;
-
/* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
if(slot->dev) {
warn("slot %s already inserted", slot->hotplug_slot->name);
@@ -462,8 +482,6 @@ check_slots(void)
inserted++;
} else if(cpci_check_ext(slot)) {
- u16 hs_csr;
-
/* Process extraction request */
dbg("%s - slot %s extracted",
__FUNCTION__, slot->hotplug_slot->name);
@@ -476,20 +494,40 @@ check_slots(void)
if(!slot->extracting) {
if(update_latch_status(slot->hotplug_slot, 0)) {
warn("failure to update latch file");
+
}
+ atomic_inc(&extracting);
slot->extracting = 1;
}
extracted++;
+ } else if(slot->extracting) {
+ hs_csr = cpci_get_hs_csr(slot);
+ if(hs_csr == 0xffff) {
+ /*
+ * Hmmm, we're likely hosed at this point, should we
+ * bother trying to tell the driver or not?
+ */
+ err("card in slot %s was improperly removed",
+ slot->hotplug_slot->name);
+ if(update_adapter_status(slot->hotplug_slot, 0)) {
+ warn("failure to update adapter file");
+ }
+ slot->extracting = 0;
+ atomic_dec(&extracting);
+ }
}
}
- spin_unlock(&list_lock);
+ up_read(&list_rwsem);
+ dbg("inserted=%d, extracted=%d, extracting=%d",
+ inserted, extracted, atomic_read(&extracting));
if(inserted || extracted) {
return extracted;
}
- else {
+ else if(!atomic_read(&extracting)) {
err("cannot find ENUM# source, shutting down");
return -1;
}
+ return 0;
}
/* This is the interrupt mode worker thread body */
@@ -497,8 +535,6 @@ static int
event_thread(void *data)
{
int rc;
- struct slot *slot;
- struct list_head *tmp;
lock_kernel();
daemonize("cpci_hp_eventd");
@@ -512,39 +548,22 @@ event_thread(void *data)
thread_finished);
if(thread_finished || signal_pending(current))
break;
- while(controller->ops->query_enum()) {
+ do {
rc = check_slots();
- if (rc > 0)
+ if (rc > 0) {
/* Give userspace a chance to handle extraction */
msleep(500);
- else if (rc < 0) {
+ } else if (rc < 0) {
dbg("%s - error checking slots", __FUNCTION__);
thread_finished = 1;
break;
}
- }
- /* Check for someone yanking out a board */
- list_for_each(tmp, &slot_list) {
- slot = list_entry(tmp, struct slot, slot_list);
- if(slot->extracting) {
- /*
- * Hmmm, we're likely hosed at this point, should we
- * bother trying to tell the driver or not?
- */
- err("card in slot %s was improperly removed",
- slot->hotplug_slot->name);
- if(update_adapter_status(slot->hotplug_slot, 0)) {
- warn("failure to update adapter file");
- }
- slot->extracting = 0;
- }
- }
+ } while(atomic_read(&extracting) != 0);
/* Re-enable ENUM# interrupt */
dbg("%s - re-enabling irq", __FUNCTION__);
controller->ops->enable_irq();
}
-
dbg("%s - event thread signals exit", __FUNCTION__);
up(&thread_exit);
return 0;
@@ -555,8 +574,6 @@ static int
poll_thread(void *data)
{
int rc;
- struct slot *slot;
- struct list_head *tmp;
lock_kernel();
daemonize("cpci_hp_polld");
@@ -565,35 +582,19 @@ poll_thread(void *data)
while(1) {
if(thread_finished || signal_pending(current))
break;
-
- while(controller->ops->query_enum()) {
- rc = check_slots();
- if(rc > 0)
- /* Give userspace a chance to handle extraction */
- msleep(500);
- else if (rc < 0) {
- dbg("%s - error checking slots", __FUNCTION__);
- thread_finished = 1;
- break;
- }
- }
- /* Check for someone yanking out a board */
- list_for_each(tmp, &slot_list) {
- slot = list_entry(tmp, struct slot, slot_list);
- if(slot->extracting) {
- /*
- * Hmmm, we're likely hosed at this point, should we
- * bother trying to tell the driver or not?
- */
- err("card in slot %s was improperly removed",
- slot->hotplug_slot->name);
- if(update_adapter_status(slot->hotplug_slot, 0)) {
- warn("failure to update adapter file");
+ if(controller->ops->query_enum()) {
+ do {
+ rc = check_slots();
+ if(rc > 0) {
+ /* Give userspace a chance to handle extraction */
+ msleep(500);
+ } else if(rc < 0) {
+ dbg("%s - error checking slots", __FUNCTION__);
+ thread_finished = 1;
+ break;
}
- slot->extracting = 0;
- }
+ } while(atomic_read(&extracting) != 0);
}
-
msleep(100);
}
dbg("poll thread signals exit");
@@ -667,6 +668,9 @@ cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
int status = 0;
if(controller) {
+ if(atomic_read(&extracting) != 0) {
+ return -EBUSY;
+ }
if(!thread_finished) {
cpci_stop_thread();
}
@@ -691,12 +695,12 @@ cpci_hp_start(void)
return -ENODEV;
}
- spin_lock(&list_lock);
- if(!slots) {
- spin_unlock(&list_lock);
+ down_read(&list_rwsem);
+ if(list_empty(&slot_list)) {
+ up_read(&list_rwsem);
return -ENODEV;
}
- spin_unlock(&list_lock);
+ up_read(&list_rwsem);
if(first) {
status = init_slots();
@@ -727,7 +731,9 @@ cpci_hp_stop(void)
if(!controller) {
return -ENODEV;
}
-
+ if(atomic_read(&extracting) != 0) {
+ return -EBUSY;
+ }
if(controller->irq) {
/* Stop enum interrupt processing */
dbg("%s - disabling irq", __FUNCTION__);
@@ -747,7 +753,7 @@ cleanup_slots(void)
* Unregister all of our slots with the pci_hotplug subsystem,
* and free up all memory that we had allocated.
*/
- spin_lock(&list_lock);
+ down_write(&list_rwsem);
if(!slots) {
goto null_cleanup;
}
@@ -761,17 +767,14 @@ cleanup_slots(void)
kfree(slot);
}
null_cleanup:
- spin_unlock(&list_lock);
+ up_write(&list_rwsem);
return;
}
int __init
cpci_hotplug_init(int debug)
{
- spin_lock_init(&list_lock);
cpci_debug = debug;
-
- info(DRIVER_DESC " version: " DRIVER_VERSION);
return 0;
}
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 2e969616f29..69eb4fc54f2 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -32,11 +32,7 @@
#include "pci_hotplug.h"
#include "cpci_hotplug.h"
-#if !defined(MODULE)
#define MY_NAME "cpci_hotplug"
-#else