diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2008-03-13 13:54:38 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-03-13 13:54:38 -0700 |
| commit | 9abc65f8c4c95fd809f8d9e8c911d2e077c449bf (patch) | |
| tree | 92a9798dc7f63e0098740574f953426b1e1e3731 | |
| parent | 1e68a850ab158ff9d4886402ab3d76f21c4ac27a (diff) | |
| download | patches-9abc65f8c4c95fd809f8d9e8c911d2e077c449bf.tar.gz | |
more patch fun
17 files changed, 3997 insertions, 25 deletions
diff --git a/driver-core/driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch b/driver-core/driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch new file mode 100644 index 00000000000000..683a99f79ff106 --- /dev/null +++ b/driver-core/driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch @@ -0,0 +1,75 @@ +From rjw@sisk.pl Thu Mar 13 13:45:38 2008 +From: "Rafael J. Wysocki" <rjw@sisk.pl> +Date: Wed, 12 Mar 2008 00:59:38 +0100 +Subject: Driver core: Call device_pm_add() after bus_add_device() in device_add() +To: Greg KH <greg@kroah.com> +Cc: Alan Stern <stern@rowland.harvard.edu>, Andrew Morton <akpm@linux-foundation.org>, David Brownell <david-b@pacbell.net>, LKML <linux-kernel@vger.kernel.org>, Pavel Machek <pavel@ucw.cz>, pm list <linux-pm@lists.linux-foundation.org> +Message-ID: <200803120059.39902.rjw@sisk.pl> +Content-Disposition: inline + + +From: Rafael J. Wysocki <rjw@sisk.pl> + +Include dpm_sysfs_add() into device_pm_add(), in analogy with +device_pm_remove(), and modify device_add() to call the latter after +bus_add_device(), to avoid situations in which the PM core may +attempt to suspend a device the registration of which has not been +successful. + +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +Acked-by: Pavel Machek <pavel@ucw.cz> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/base/core.c | 15 +++++---------- + drivers/base/power/main.c | 4 +++- + 2 files changed, 8 insertions(+), 11 deletions(-) + +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -817,17 +817,12 @@ int device_add(struct device *dev) + error = device_add_attrs(dev); + if (error) + goto AttrsError; +- error = dpm_sysfs_add(dev); +- if (error) +- goto PMError; +- error = device_pm_add(dev); +- if (error) { +- dpm_sysfs_remove(dev); +- goto PMError; +- } + error = bus_add_device(dev); + if (error) + goto BusError; ++ error = device_pm_add(dev); ++ if (error) ++ goto PMError; + kobject_uevent(&dev->kobj, KOBJ_ADD); + bus_attach_device(dev); + if (parent) +@@ -847,9 +842,9 @@ int device_add(struct device *dev) + Done: + put_device(dev); + return error; +- BusError: +- device_pm_remove(dev); + PMError: ++ bus_remove_device(dev); ++ BusError: + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, + BUS_NOTIFY_DEL_DEVICE, dev); +--- a/drivers/base/power/main.c ++++ b/drivers/base/power/main.c +@@ -81,7 +81,9 @@ int device_pm_add(struct device *dev) + WARN_ON(true); + error = -EBUSY; + } else { +- list_add_tail(&dev->power.entry, &dpm_active); ++ error = dpm_sysfs_add(dev); ++ if (!error) ++ list_add_tail(&dev->power.entry, &dpm_active); + } + mutex_unlock(&dpm_list_mtx); + return error; diff --git a/driver-core/driver-core-replace-remaining-__function__-occurrences.patch b/driver-core/driver-core-replace-remaining-__function__-occurrences.patch index 7377a431bd29b1..47c94fe68c98da 100644 --- a/driver-core/driver-core-replace-remaining-__function__-occurrences.patch +++ b/driver-core/driver-core-replace-remaining-__function__-occurrences.patch @@ -130,7 +130,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> parent = get_device(dev->parent); setup_parent(dev, parent); -@@ -981,7 +981,7 @@ void device_del(struct device *dev) +@@ -980,7 +980,7 @@ void device_del(struct device *dev) */ void device_unregister(struct device *dev) { @@ -139,7 +139,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> device_del(dev); put_device(dev); } -@@ -1076,7 +1076,7 @@ EXPORT_SYMBOL_GPL(device_remove_file); +@@ -1075,7 +1075,7 @@ EXPORT_SYMBOL_GPL(device_remove_file); static void device_create_release(struct device *dev) { @@ -148,7 +148,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> kfree(dev); } -@@ -1210,7 +1210,7 @@ int device_rename(struct device *dev, ch +@@ -1209,7 +1209,7 @@ int device_rename(struct device *dev, ch return -EINVAL; pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id, @@ -157,7 +157,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> #ifdef CONFIG_SYSFS_DEPRECATED if ((dev->class) && (dev->parent)) -@@ -1249,7 +1249,7 @@ int device_rename(struct device *dev, ch +@@ -1248,7 +1248,7 @@ int device_rename(struct device *dev, ch dev->bus_id); if (error) { dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n", @@ -166,7 +166,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } } #endif -@@ -1325,7 +1325,7 @@ int device_move(struct device *dev, stru +@@ -1324,7 +1324,7 @@ int device_move(struct device *dev, stru new_parent_kobj = get_device_parent(dev, new_parent); pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id, @@ -336,7 +336,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> } --- a/drivers/base/sys.c +++ b/drivers/base/sys.c -@@ -183,7 +183,7 @@ int sysdev_driver_register(struct sysdev +@@ -195,7 +195,7 @@ int sysdev_driver_register(struct sysdev } } else { err = -EINVAL; diff --git a/driver-core/ib-rename-dev-to-srp_dev-in-srp_host-structure.patch b/driver-core/ib-rename-dev-to-srp_dev-in-srp_host-structure.patch index cd0cac0b7e50a3..87be800e815ed3 100644 --- a/driver-core/ib-rename-dev-to-srp_dev-in-srp_host-structure.patch +++ b/driver-core/ib-rename-dev-to-srp_dev-in-srp_host-structure.patch @@ -12,7 +12,7 @@ by Greg. Signed-off-by: Tony Jones <tonyj@suse.de> Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> -Cc: Roland Dreier <rolandd@cisco.com> +Reviewed-by: Roland Dreier <rolandd@cisco.com> Cc: Sean Hefty <sean.hefty@intel.com> Cc: Hal Rosenstock <hal.rosenstock@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff --git a/driver-core/pm-handle-device-registrations-during-suspend-resume.patch b/driver-core/pm-handle-device-registrations-during-suspend-resume.patch new file mode 100644 index 00000000000000..c0eb9685a1d61b --- /dev/null +++ b/driver-core/pm-handle-device-registrations-during-suspend-resume.patch @@ -0,0 +1,253 @@ +From rjw@sisk.pl Thu Mar 13 13:44:50 2008 +From: "Rafael J. Wysocki" <rjw@sisk.pl> +Date: Wed, 12 Mar 2008 00:57:22 +0100 +Subject: PM: Handle device registrations during suspend/resume +To: Greg KH <greg@kroah.com> +Cc: Alan Stern <stern@rowland.harvard.edu>, Andrew Morton <akpm@linux-foundation.org>, David Brownell <david-b@pacbell.net>, LKML <linux-kernel@vger.kernel.org>, Pavel Machek <pavel@ucw.cz>, pm list <linux-pm@lists.linux-foundation.org> +Message-ID: <200803120057.23101.rjw@sisk.pl> +Content-Disposition: inline + + +From: Rafael J. Wysocki <rjw@sisk.pl> + +Modify the PM core to protect its data structures, specifically the +dpm_active list, from being corrupted if a child of the currently +suspending device is registered concurrently with its ->suspend() +callback. In that case, since the new device (the child) is added +to dpm_active after its parent, the PM core will attempt to +suspend it after the parent, which is wrong. + +Introduce a new member of struct dev_pm_info, called 'sleeping', +and use it to check if the parent of the device being added to +dpm_active has been suspended, in which case the device registration +fails. Also, use 'sleeping' for checking if the ordering of devices +on dpm_active is correct. + +Introduce variable 'all_sleeping' that will be set to 'true' once all +devices have been suspended and make new device registrations fail +until 'all_sleeping' is reset to 'false', in order to avoid having +unsuspended devices around while the system is going into a sleep state. + +Remove pm_sleep_rwsem which is not necessary any more. + +Special thanks to Alan Stern for discussions and suggestions that +lead to the creation of this patch. + +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +Acked-by: Pavel Machek <pavel@ucw.cz> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + Documentation/power/devices.txt | 5 +++ + drivers/base/core.c | 6 +++- + drivers/base/power/main.c | 57 ++++++++++++++++++---------------------- + drivers/base/power/power.h | 23 ++-------------- + include/linux/pm.h | 1 + 5 files changed, 40 insertions(+), 52 deletions(-) + +--- a/Documentation/power/devices.txt ++++ b/Documentation/power/devices.txt +@@ -196,6 +196,11 @@ its parent; and can't be removed or susp + + The policy is that the device tree should match hardware bus topology. + (Or at least the control bus, for devices which use multiple busses.) ++In particular, this means that a device registration may fail if the parent of ++the device is suspending (ie. has been chosen by the PM core as the next ++device to suspend) or has already suspended, as well as after all of the other ++devices have been suspended. Device drivers must be prepared to cope with such ++situations. + + + Suspending Devices +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -820,7 +820,11 @@ int device_add(struct device *dev) + error = dpm_sysfs_add(dev); + if (error) + goto PMError; +- device_pm_add(dev); ++ error = device_pm_add(dev); ++ if (error) { ++ dpm_sysfs_remove(dev); ++ goto PMError; ++ } + error = bus_add_device(dev); + if (error) + goto BusError; +--- a/drivers/base/power/main.c ++++ b/drivers/base/power/main.c +@@ -54,7 +54,8 @@ static LIST_HEAD(dpm_destroy); + + static DEFINE_MUTEX(dpm_list_mtx); + +-static DECLARE_RWSEM(pm_sleep_rwsem); ++/* 'true' if all devices have been suspended, protected by dpm_list_mtx */ ++static bool all_sleeping; + + int (*platform_enable_wakeup)(struct device *dev, int is_on); + +@@ -62,14 +63,28 @@ int (*platform_enable_wakeup)(struct dev + * device_pm_add - add a device to the list of active devices + * @dev: Device to be added to the list + */ +-void device_pm_add(struct device *dev) ++int device_pm_add(struct device *dev) + { ++ int error = 0; ++ + pr_debug("PM: Adding info for %s:%s\n", + dev->bus ? dev->bus->name : "No Bus", + kobject_name(&dev->kobj)); + mutex_lock(&dpm_list_mtx); +- list_add_tail(&dev->power.entry, &dpm_active); ++ if ((dev->parent && dev->parent->power.sleeping) || all_sleeping) { ++ if (dev->parent->power.sleeping) ++ dev_warn(dev, ++ "parent %s is sleeping, will not add\n", ++ dev->parent->bus_id); ++ else ++ dev_warn(dev, "devices are sleeping, will not add\n"); ++ WARN_ON(true); ++ error = -EBUSY; ++ } else { ++ list_add_tail(&dev->power.entry, &dpm_active); ++ } + mutex_unlock(&dpm_list_mtx); ++ return error; + } + + /** +@@ -107,32 +122,6 @@ void device_pm_schedule_removal(struct d + } + EXPORT_SYMBOL_GPL(device_pm_schedule_removal); + +-/** +- * pm_sleep_lock - mutual exclusion for registration and suspend +- * +- * Returns 0 if no suspend is underway and device registration +- * may proceed, otherwise -EBUSY. +- */ +-int pm_sleep_lock(void) +-{ +- if (down_read_trylock(&pm_sleep_rwsem)) +- return 0; +- +- return -EBUSY; +-} +- +-/** +- * pm_sleep_unlock - mutual exclusion for registration and suspend +- * +- * This routine undoes the effect of device_pm_add_lock +- * when a device's registration is complete. +- */ +-void pm_sleep_unlock(void) +-{ +- up_read(&pm_sleep_rwsem); +-} +- +- + /*------------------------- Resume routines -------------------------*/ + + /** +@@ -242,11 +231,13 @@ static int resume_device(struct device * + static void dpm_resume(void) + { + mutex_lock(&dpm_list_mtx); ++ all_sleeping = false; + while(!list_empty(&dpm_off)) { + struct list_head *entry = dpm_off.next; + struct device *dev = to_device(entry); + + list_move_tail(entry, &dpm_active); ++ dev->power.sleeping = false; + mutex_unlock(&dpm_list_mtx); + resume_device(dev); + mutex_lock(&dpm_list_mtx); +@@ -285,7 +276,6 @@ void device_resume(void) + might_sleep(); + dpm_resume(); + unregister_dropped_devices(); +- up_write(&pm_sleep_rwsem); + } + EXPORT_SYMBOL_GPL(device_resume); + +@@ -421,6 +411,9 @@ static int dpm_suspend(pm_message_t stat + struct list_head *entry = dpm_active.prev; + struct device *dev = to_device(entry); + ++ WARN_ON(dev->parent && dev->parent->power.sleeping); ++ ++ dev->power.sleeping = true; + mutex_unlock(&dpm_list_mtx); + error = suspend_device(dev, state); + mutex_lock(&dpm_list_mtx); +@@ -432,11 +425,14 @@ static int dpm_suspend(pm_message_t stat + (error == -EAGAIN ? + " (please convert to suspend_late)" : + "")); ++ dev->power.sleeping = false; + break; + } + if (!list_empty(&dev->power.entry)) + list_move(&dev->power.entry, &dpm_off); + } ++ if (!error) ++ all_sleeping = true; + mutex_unlock(&dpm_list_mtx); + + return error; +@@ -454,7 +450,6 @@ int device_suspend(pm_message_t state) + int error; + + might_sleep(); +- down_write(&pm_sleep_rwsem); + error = dpm_suspend(state); + if (error) + device_resume(); +--- a/drivers/base/power/power.h ++++ b/drivers/base/power/power.h +@@ -11,30 +11,13 @@ static inline struct device *to_device(s + return container_of(entry, struct device, power.entry); + } + +-extern void device_pm_add(struct device *); ++extern int device_pm_add(struct device *); + extern void device_pm_remove(struct device *); +-extern int pm_sleep_lock(void); +-extern void pm_sleep_unlock(void); + + #else /* CONFIG_PM_SLEEP */ + +- +-static inline void device_pm_add(struct device *dev) +-{ +-} +- +-static inline void device_pm_remove(struct device *dev) +-{ +-} +- +-static inline int pm_sleep_lock(void) +-{ +- return 0; +-} +- +-static inline void pm_sleep_unlock(void) +-{ +-} ++static inline int device_pm_add(struct device *dev) { return 0; } ++static inline void device_pm_remove(struct device *dev) {} + + #endif + +--- a/include/linux/pm.h ++++ b/include/linux/pm.h +@@ -183,6 +183,7 @@ typedef struct pm_message { + struct dev_pm_info { + pm_message_t power_state; + unsigned can_wakeup:1; ++ bool sleeping:1; /* Owned by the PM core */ + #ifdef CONFIG_PM_SLEEP + unsigned should_wakeup:1; + struct list_head entry; diff --git a/driver-core/pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch b/driver-core/pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch new file mode 100644 index 00000000000000..fb1621b0727261 --- /dev/null +++ b/driver-core/pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch @@ -0,0 +1,156 @@ +From rjw@sisk.pl Thu Mar 13 13:46:04 2008 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Wed, 12 Mar 2008 01:01:47 +0100 +Subject: PM: make wakeup flags available whenever CONFIG_PM is set +To: Greg KH <greg@kroah.com> +Cc: Alan Stern <stern@rowland.harvard.edu>, Andrew Morton <akpm@linux-foundation.org>, David Brownell <david-b@pacbell.net>, LKML <linux-kernel@vger.kernel.org>, Pavel Machek <pavel@ucw.cz>, pm list <linux-pm@lists.linux-foundation.org> +Message-ID: <200803120101.48805.rjw@sisk.pl> +Content-Disposition: inline + +From: Alan Stern <stern@rowland.harvard.edu> + +The various wakeup flags and their accessor macros in struct +dev_pm_info should be available whenever CONFIG_PM is enabled, not +just when CONFIG_PM_SLEEP is on. Otherwise remote wakeup won't always +be configurable for runtime power management. This patch (as1056) +fixes the oversight. + +[rjw: rebased the patch on top of the previous two.] + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +CC: David Brownell <david-b@pacbell.net> +Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> +Acked-by: Pavel Machek <pavel@ucw.cz> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/base/power/main.c | 2 - + drivers/base/power/sysfs.c | 2 + + include/linux/pm.h | 64 +++++++++++++++++++++++++-------------------- + 3 files changed, 38 insertions(+), 30 deletions(-) + +--- a/drivers/base/power/main.c ++++ b/drivers/base/power/main.c +@@ -57,8 +57,6 @@ static DEFINE_MUTEX(dpm_list_mtx); + /* 'true' if all devices have been suspended, protected by dpm_list_mtx */ + static bool all_sleeping; + +-int (*platform_enable_wakeup)(struct device *dev, int is_on); +- + /** + * device_pm_add - add a device to the list of active devices + * @dev: Device to be added to the list +--- a/drivers/base/power/sysfs.c ++++ b/drivers/base/power/sysfs.c +@@ -6,6 +6,8 @@ + #include <linux/string.h> + #include "power.h" + ++int (*platform_enable_wakeup)(struct device *dev, int is_on); ++ + + /* + * wakeup - Report/change current wakeup option for device +--- a/include/linux/pm.h ++++ b/include/linux/pm.h +@@ -183,9 +183,9 @@ typedef struct pm_message { + struct dev_pm_info { + pm_message_t power_state; + unsigned can_wakeup:1; ++ unsigned should_wakeup:1; + bool sleeping:1; /* Owned by the PM core */ + #ifdef CONFIG_PM_SLEEP +- unsigned should_wakeup:1; + struct list_head entry; + #endif + }; +@@ -198,11 +198,6 @@ extern void device_resume(void); + extern int device_suspend(pm_message_t state); + extern int device_prepare_suspend(pm_message_t state); + +-#define device_set_wakeup_enable(dev,val) \ +- ((dev)->power.should_wakeup = !!(val)) +-#define device_may_wakeup(dev) \ +- (device_can_wakeup(dev) && (dev)->power.should_wakeup) +- + extern void __suspend_report_result(const char *function, void *fn, int ret); + + #define suspend_report_result(fn, ret) \ +@@ -210,6 +205,35 @@ extern void __suspend_report_result(cons + __suspend_report_result(__FUNCTION__, fn, ret); \ + } while (0) + ++#else /* !CONFIG_PM_SLEEP */ ++ ++static inline int device_suspend(pm_message_t state) ++{ ++ return 0; ++} ++ ++#define suspend_report_result(fn, ret) do {} while (0) ++ ++#endif /* !CONFIG_PM_SLEEP */ ++ ++#ifdef CONFIG_PM ++ ++/* changes to device_may_wakeup take effect on the next pm state change. ++ * by default, devices should wakeup if they can. ++ */ ++#define device_can_wakeup(dev) \ ++ ((dev)->power.can_wakeup) ++#define device_init_wakeup(dev,val) \ ++ do { \ ++ device_can_wakeup(dev) = !!(val); \ ++ device_set_wakeup_enable(dev,val); \ ++ } while(0) ++ ++#define device_set_wakeup_enable(dev,val) \ ++ ((dev)->power.should_wakeup = !!(val)) ++#define device_may_wakeup(dev) \ ++ (device_can_wakeup(dev) && (dev)->power.should_wakeup) ++ + /* + * Platform hook to activate device wakeup capability, if that's not already + * handled by enable_irq_wake() etc. +@@ -224,35 +248,19 @@ static inline int call_platform_enable_w + return 0; + } + +-#else /* !CONFIG_PM_SLEEP */ +- +-static inline int device_suspend(pm_message_t state) +-{ +- return 0; +-} +- +-#define device_set_wakeup_enable(dev,val) do{}while(0) +-#define device_may_wakeup(dev) (0) ++#else /* !CONFIG_PM */ + +-#define suspend_report_result(fn, ret) do { } while (0) ++#define device_can_wakeup(dev) 0 ++#define device_init_wakeup(dev,val) do {} while (0) ++#define device_set_wakeup_enable(dev,val) do {} while (0) ++#define device_may_wakeup(dev) 0 + + static inline int call_platform_enable_wakeup(struct device *dev, int is_on) + { + return 0; + } + +-#endif /* !CONFIG_PM_SLEEP */ +- +-/* changes to device_may_wakeup take effect on the next pm state change. +- * by default, devices should wakeup if they can. +- */ +-#define device_can_wakeup(dev) \ +- ((dev)->power.can_wakeup) +-#define device_init_wakeup(dev,val) \ +- do { \ +- device_can_wakeup(dev) = !!(val); \ +- device_set_wakeup_enable(dev,val); \ +- } while(0) ++#endif /* !CONFIG_PM */ + + /* + * Global Power Management flags diff --git a/driver-core/sysdev-detect-multiple-driver-registrations.patch b/driver-core/sysdev-detect-multiple-driver-registrations.patch index 45d19a57be0f5a..9175c37e30c022 100644 --- a/driver-core/sysdev-detect-multiple-driver-registrations.patch +++ b/driver-core/sysdev-detect-multiple-driver-registrations.patch @@ -23,18 +23,30 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- - drivers/base/sys.c | 4 ++++ - 1 file changed, 4 insertions(+) + drivers/base/sys.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) --- a/drivers/base/sys.c +++ b/drivers/base/sys.c -@@ -167,6 +167,10 @@ int sysdev_driver_register(struct sysdev +@@ -167,6 +167,22 @@ int sysdev_driver_register(struct sysdev { int err = 0; ++ if (!cls) { ++ printk(KERN_WARNING "sysdev: invalid class passed to " ++ "sysdev_driver_register!\n"); ++ WARN_ON(1); ++ return -EINVAL; ++ } ++ + /* Check whether this driver has already been added to a class. */ -+ WARN_ON(drv->entry.next != drv->entry.prev); -+ WARN_ON(drv->entry.next != NULL); ++ if ((drv->entry.next != drv->entry.prev) || ++ (drv->entry.next != NULL)) { ++ printk(KERN_WARNING "sysdev: class %s: driver (%p) has already" ++ " been registered to a class, something is wrong, but " ++ "will forge on!\n", cls->name, drv); ++ WARN_ON(1); ++ } + mutex_lock(&sysdev_drivers_lock); if (cls && kset_get(&cls->kset)) { diff --git a/driver-core/uio-implement-a-uio-interface-for-the-smx-cryptengine.patch b/driver-core/uio-implement-a-uio-interface-for-the-smx-cryptengine.patch new file mode 100644 index 00000000000000..cccd500a6475c4 --- /dev/null +++ b/driver-core/uio-implement-a-uio-interface-for-the-smx-cryptengine.patch @@ -0,0 +1,227 @@ +From bn@niasdigital.com Thu Mar 13 13:40:45 2008 +From: Ben Nizette <bn@niasdigital.com> +Date: Thu, 13 Mar 2008 22:27:30 +1100 +Subject: UIO: Implement a UIO interface for the SMX Cryptengine +To: Hans-J�rgen Koch <hjk@linutronix.de> +Cc: Paul Mundt <lethal@linux-sh.org>, gregkh <gregkh@suse.de>, linux-kernel <linux-kernel@vger.kernel.org> +Message-ID: <1205407650.3735.19.camel@moss.renham> + +From: Ben Nizette <bn@niasdigital.com> + +This patch implements a UIO interface for the SMX Cryptengine. + +The Cryptengine found on the Nias Digital SMX board is best suited +for a UIO interface. It is not wired in to the cryptographic API +as the engine handles it's own keys, algorithms, everything. All +that we know about is that if there's room in the buffer, you can +write data to it and when there's data ready, you read it out again. + +There isn't necessarily even any direct correlation between data +going in and data coming out again, the engine may consume or +generate data all on its own. + +This driver is for proprietary hardware but we're always told to +submit the drivers anyway; here you are. :-) + +This is version 4 of this patch and addresses all issues raised by +Hans-Jürgen Koch and Paul Mundt in their reviews. Slightly altered +is Paul's suggestion to use DRV_NAME and DRV_VERSION as the UIO +version and name. While at the moment they are the same, there +is no reason for them to stay that way. Nevertheless we now at +least provide a MODULE_VERSION macro to keep modinfo happy. + +Signed-off-by: Ben Nizette <bn@niasdigital.com> +Acked-by: Paul Mundt <lethal@linux-sh.org> +Signed-off-by: Hans J Koch <hjk@linutronix.de> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + MAINTAINERS | 5 + + drivers/uio/Kconfig | 13 ++++ + drivers/uio/Makefile | 1 + drivers/uio/uio_smx.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 159 insertions(+) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3583,6 +3583,11 @@ M: mhoffman@lightlink.com + L: lm-sensors@lm-sensors.org + S: Maintained + ++SMX UIO Interface ++P: Ben Nizette ++M: bn@niasdigital.com ++S: Maintained ++ + SOFTMAC LAYER (IEEE 802.11) + P: Daniel Drake + M: dsd@gentoo.org +--- a/drivers/uio/Kconfig ++++ b/drivers/uio/Kconfig +@@ -26,4 +26,17 @@ config UIO_CIF + To compile this driver as a module, choose M here: the module + will be called uio_cif. + ++config UIO_SMX ++ tristate "SMX cryptengine UIO interface" ++ depends on UIO ++ default n ++ help ++ Userspace IO interface to the Cryptography engine found on the ++ Nias Digital SMX boards. These will be available from Q4 2008 ++ from http://www.niasdigital.com. The userspace part of this ++ driver will be released under the GPL at the same time as the ++ hardware and will be able to be downloaded from the same site. ++ ++ If you compile this as a module, it will be called uio_smx. ++ + endif +--- a/drivers/uio/Makefile ++++ b/drivers/uio/Makefile +@@ -1,2 +1,3 @@ + obj-$(CONFIG_UIO) += uio.o + obj-$(CONFIG_UIO_CIF) += uio_cif.o ++obj-$(CONFIG_UIO_SMX) += uio_smx.o +--- /dev/null ++++ b/drivers/uio/uio_smx.c +@@ -0,0 +1,140 @@ ++/* ++ * UIO SMX Cryptengine driver. ++ * ++ * (C) 2008 Nias Digital P/L <bn@niasdigital.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/device.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/uio_driver.h> ++#include <linux/io.h> ++ ++#define DRV_NAME "smx-ce" ++#define DRV_VERSION "0.03" ++ ++#define SMX_CSR 0x00000000 ++#define SMX_EnD 0x00000001 ++#define SMX_RUN 0x00000002 ++#define SMX_DRDY 0x00000004 ++#define SMX_ERR 0x00000008 ++ ++static irqreturn_t smx_handler(int irq, struct uio_info *dev_info) ++{ ++ void __iomem *csr = dev_info->mem[0].internal_addr + SMX_CSR; ++ ++ u32 status = ioread32(csr); ++ ++ if (!(status & SMX_DRDY)) ++ return IRQ_NONE; ++ ++ /* Disable interrupt */ ++ iowrite32(status & ~SMX_DRDY, csr); ++ return IRQ_HANDLED; ++} ++ ++static int __devinit smx_ce_probe(struct platform_device *dev) ++{ ++ ++ int ret = -ENODEV; ++ struct uio_info *info; ++ struct resource *regs; ++ ++ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ regs = platform_get_resource(dev, IORESOURCE_MEM, 0); ++ if (!regs) { ++ dev_err(&dev->dev, "No memory resource specified\n"); ++ goto out_free; ++ } ++ ++ info->mem[0].addr = regs->start; ++ if (!info->mem[0].addr) { ++ dev_err(&dev->dev, "Invalid memory resource\n"); ++ goto out_free; ++ } ++ ++ info->mem[0].size = regs->end - regs->start + 1; ++ info->mem[0].internal_addr = ioremap(regs->start, info->mem[0].size); ++ ++ if (!info->mem[0].internal_addr) { ++ dev_err(&dev->dev, "Can't remap memory address range\n"); ++ goto out_free; ++ } ++ ++ info->mem[0].memtype = UIO_MEM_PHYS; ++ ++ info->name = "smx-ce"; ++ info->version = "0.03"; ++ ++ info->irq = platform_get_irq(dev, 0); ++ if (info->irq < 0) { ++ ret = info->irq; ++ dev_err(&dev->dev, "No (or invalid) IRQ resource specified\n"); ++ goto out_unmap; ++ } ++ ++ info->irq_flags = IRQF_SHARED; ++ info->handler = smx_handler; ++ ++ platform_set_drvdata(dev, info); ++ ++ ret = uio_register_device(&dev->dev, info); ++ ++ if (ret) ++ goto out_unmap; ++ ++ return 0; ++ ++out_unmap: ++ iounmap(info->mem[0].internal_addr); ++out_free: ++ kfree(info); ++ ++ return ret; ++} ++ ++static int __devexit smx_ce_remove(struct platform_device *dev) ++{ ++ struct uio_info *info = platform_get_drvdata(dev); ++ ++ uio_unregister_device(info); ++ platform_set_drvdata(dev, NULL); ++ iounmap(info->mem[0].internal_addr); ++ ++ kfree(info); ++ ++ return 0; ++} ++ ++static struct platform_driver smx_ce_driver = { ++ .probe = smx_ce_probe, ++ .remove = __devexit_p(smx_ce_remove), ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init smx_ce_init_module(void) ++{ ++ return platform_driver_register(&smx_ce_driver); ++} ++module_init(smx_ce_init_module); ++ ++static void __exit smx_ce_exit_module(void) ++{ ++ platform_driver_unregister(&smx_ce_driver); ++} ++module_exit(smx_ce_exit_module); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION(DRV_VERSION); ++MODULE_AUTHOR("Ben Nizette <bn@niasdigital.com>"); diff --git a/pci/pci-arm-use-generic-pci_enable_resources.patch b/pci/pci-arm-use-generic-pci_enable_resources.patch index 114b59af23cd85..31ac7c920c6566 100644 --- a/pci/pci-arm-use-generic-pci_enable_resources.patch +++ b/pci/pci-arm-use-generic-pci_enable_resources.patch @@ -26,6 +26,7 @@ Unlike this arch-specific code, the generic version: - checks for resource collisions with "!r->parent" Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> +Acked-by: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- diff --git a/pci/pci-doc-pci-create-documentation-pci-and-move-files-into-it.patch b/pci/pci-doc-pci-create-documentation-pci-and-move-files-into-it.patch new file mode 100644 index 00000000000000..10658a220d9ba5 --- /dev/null +++ b/pci/pci-doc-pci-create-documentation-pci-and-move-files-into-it.patch @@ -0,0 +1,3141 @@ +From randy.dunlap@oracle.com Thu Mar 13 13:47:45 2008 +From: Randy Dunlap <randy.dunlap@oracle.com> +Date: Mon, 10 Mar 2008 17:16:32 -0700 +Subject: PCI: doc/pci: create Documentation/PCI/ and move files into it +To: Jesse Barnes <jbarnes@virtuousgeek.org>, gregkh <greg@kroah.com> +Cc: linux-pci@atrey.karlin.mff.cuni.cz +Message-ID: <20080310171632.cd4c9c31.randy.dunlap@oracle.com> + +From: Randy Dunlap <randy.dunlap@oracle.com> + +Create Documentation/PCI/ and move PCI-related files to it. +Fix a few instances of trailing whitespace. +Update references to the new file locations. + +Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> +Cc: Jesse Barnes <jbarnes@virtuousgeek.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + Documentation/00-INDEX | 10 + Documentation/PCI/00-INDEX | 12 + Documentation/PCI/PCIEBUS-HOWTO.txt | 217 ++++++++++ + Documentation/PCI/pci-error-recovery.txt | 396 +++++++++++++++++++ + Documentation/PCI/pci.txt | 646 +++++++++++++++++++++++++++++++ + Documentation/PCI/pcieaer-howto.txt | 253 ++++++++++++ + Documentation/PCIEBUS-HOWTO.txt | 217 ---------- + Documentation/memory-barriers.txt | 4 + Documentation/pci-error-recovery.txt | 396 ------------------- + Documentation/pci.txt | 646 ------------------------------- + Documentation/pcieaer-howto.txt | 253 ------------ + 11 files changed, 1526 insertions(+), 1524 deletions(-) + +--- a/Documentation/00-INDEX ++++ b/Documentation/00-INDEX +@@ -25,8 +25,6 @@ DMA-API.txt + - DMA API, pci_ API & extensions for non-consistent memory machines. + DMA-ISA-LPC.txt + - How to do DMA with ISA (and LPC) devices. +-DMA-mapping.txt +- - info for PCI drivers using DMA portably across all platforms. + DocBook/ + - directory with DocBook templates etc. for kernel documentation. + HOWTO +@@ -43,8 +41,6 @@ ManagementStyle + - how to (attempt to) manage kernel hackers. + MSI-HOWTO.txt + - the Message Signaled Interrupts (MSI) Driver Guide HOWTO and FAQ. +-PCIEBUS-HOWTO.txt +- - a guide describing the PCI Express Port Bus driver. + RCU/ + - directory with info on RCU (read-copy update). + README.DAC960 +@@ -291,12 +287,6 @@ parport.txt + - how to use the parallel-port driver. + parport-lowlevel.txt + - description and usage of the low level parallel port functions. +-pci-error-recovery.txt +- - info on PCI error recovery. +-pci.txt +- - info on the PCI subsystem for device driver authors. +-pcieaer-howto.txt +- - the PCI Express Advanced Error Reporting Driver Guide HOWTO. + pcmcia/ + - info on the Linux PCMCIA driver. + pi-futex.txt +--- /dev/null ++++ b/Documentation/PCI/00-INDEX +@@ -0,0 +1,12 @@ ++00-INDEX ++ - this file ++PCI-DMA-mapping.txt ++ - info for PCI drivers using DMA portably across all platforms ++PCIEBUS-HOWTO.txt ++ - a guide describing the PCI Express Port Bus driver ++pci-error-recovery.txt ++ - info on PCI error recovery ++pci.txt ++ - info on the PCI subsystem for device driver authors ++pcieaer-howto.txt ++ - the PCI Express Advanced Error Reporting Driver Guide HOWTO +--- /dev/null ++++ b/Documentation/PCI/PCIEBUS-HOWTO.txt +@@ -0,0 +1,217 @@ ++ The PCI Express Port Bus Driver Guide HOWTO ++ Tom L Nguyen tom.l.nguyen@intel.com ++ 11/03/2004 ++ ++1. About this guide ++ ++This guide describes the basics of the PCI Express Port Bus driver ++and provides information on how to enable the service drivers to ++register/unregister with the PCI Express Port Bus Driver. ++ ++2. Copyright 2004 Intel Corporation ++ ++3. What is the PCI Express Port Bus Driver ++ ++A PCI Express Port is a logical PCI-PCI Bridge structure. There ++are two types of PCI Express Port: the Root Port and the Switch ++Port. The Root Port originates a PCI Express link from a PCI Express ++Root Complex and the Switch Port connects PCI Express links to ++internal logical PCI buses. The Switch Port, which has its secondary ++bus representing the switch's internal routing logic, is called the ++switch's Upstream Port. The switch's Downstream Port is bridging from ++switch's internal routing bus to a bus representing the downstream ++PCI Express link from the PCI Express Switch. ++ ++A PCI Express Port can provide up to four distinct functions, ++referred to in this document as services, depending on its port type. ++PCI Express Port's services include native hotplug support (HP), ++power management event support (PME), advanced error reporting ++support (AER), and virtual channel support (VC). These services may ++be handled by a single complex driver or be individually distributed ++and handled by corresponding service drivers. ++ ++4. Why use the PCI Express Port Bus Driver? ++ ++In existing Linux kernels, the Linux Device Driver Model allows a ++physical device to be handled by only a single driver. The PCI ++Express Port is a PCI-PCI Bridge device with multiple distinct ++services. To maintain a clean and simple solution each service ++may have its own software service driver. In this case several ++service drivers will compete for a single PCI-PCI Bridge device. ++For example, if the PCI Express Root Port native hotplug service ++driver is loaded first, it claims a PCI-PCI Bridge Root Port. The ++kernel therefore does not load other service drivers for that Root ++Port. In other words, it is impossible to have multiple service ++drivers load and run on a PCI-PCI Bridge device simultaneously ++using the current driver model. ++ ++To enable multiple service drivers running simultaneously requires ++having a PCI Express Port Bus driver, which manages all populated ++PCI Express Ports and distributes all provided service requests ++to the corresponding service drivers as required. Some key ++advantages of using the PCI Express Port Bus driver are listed below: ++ ++ - Allow multiple service drivers to run simultaneously on ++ a PCI-PCI Bridge Port device. ++ ++ - Allow service drivers implemented in an independent ++ staged approach. ++ ++ - Allow one service driver to run on multiple PCI-PCI Bridge ++ Port devices. ++ ++ - Manage and distribute resources of a PCI-PCI Bridge Port ++ device to requested service drivers. ++ ++5. Configuring the PCI Express Port Bus Driver vs. Service Drivers ++ ++5.1 Including the PCI Express Port Bus Driver Support into the Kernel ++ ++Including the PCI Express Port Bus driver depends on whether the PCI ++Express support is included in the kernel config. The kernel will ++automatically include the PCI Express Port Bus driver as a kernel ++driver when the PCI Express support is enabled in the kernel. ++ ++5.2 Enabling Service Driver Support ++ ++PCI device drivers are implemented based on Linux Device Driver Model. ++All service drivers are PCI device drivers. As discussed above, it is ++impossible to load any service driver once the kernel has loaded the ++PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver ++Model requires some minimal changes on existing service drivers that ++imposes no impact on the functionality of existing service drivers. ++ ++A service driver is required to use the two APIs shown below to ++register its service with the PCI Express Port Bus driver (see ++section 5.2.1 & 5.2.2). It is important that a service driver ++initializes the pcie_port_service_driver data structure, included in ++header file /include/linux/pcieport_if.h, before calling these APIs. ++Failure to do so will result an identity mismatch, which prevents ++the PCI Express Port Bus driver from loading a service driver. ++ ++5.2.1 pcie_port_service_register ++ ++int pcie_port_service_register(struct pcie_port_service_driver *new) ++ ++This API replaces the Linux Driver Model's pci_module_init API. A ++service driver should always calls pcie_port_service_register at ++module init. Note that after service driver being loaded, calls ++such as pci_enable_device(dev) and pci_set_master(dev) are no longer ++necessary since these calls are executed by the PCI Port Bus driver. ++ ++5.2.2 pcie_port_service_unregister ++ ++void pcie_port_service_unregister(struct pcie_port_service_driver *new) ++ ++pcie_port_service_unregister replaces the Linux Driver Model's ++pci_unregister_driver. It's always called by service driver when a ++module exits. ++ ++5.2.3 Sample Code ++ ++Below is sample service driver code to initialize the port service ++driver data structure. ++ ++static struct pcie_port_service_id service_id[] = { { ++ .vendor = PCI_ANY_ID, ++ .device = PCI_ANY_ID, ++ .port_type = PCIE_RC_PORT, ++ .service_type = PCIE_PORT_SERVICE_AER, ++ }, { /* end: all zeroes */ } ++}; ++ ++static struct pcie_port_service_driver root_aerdrv = { ++ .name = (char *)device_name, ++ .id_table = &service_id[0], ++ ++ .probe = aerdrv_load, ++ .remove = aerdrv_unload, ++ ++ .suspend = aerdrv_suspend, ++ .resume = aerdrv_resume, ++}; ++ ++Below is a sample code for registering/unregistering a service ++driver. ++ ++static int __init aerdrv_service_init(void) ++{ ++ int retval = 0; ++ ++ retval = pcie_port_service_register(&root_aerdrv); ++ if (!retval) { ++ /* ++ * FIX ME ++ */ ++ } ++ return retval; ++} ++ ++static void __exit aerdrv_service_exit(void) ++{ ++ pcie_port_service_unregister(&root_aerdrv); ++} ++ ++module_init(aerdrv_service_init); ++module_exit(aerdrv_service_exit); ++ ++6. Possible Resource Conflicts ++ ++Since all service drivers of a PCI-PCI Bridge Port device are ++allowed to run simultaneously, below lists a few of possible resource ++conflicts with proposed solutions. ++ ++6.1 MSI Vector Resource ++ ++The MSI capability structure enables a device software driver to call ++pci_enable_msi to request MSI based interrupts. Once MSI interrupts ++are enabled on a device, it stays in this mode until a device driver ++calls pci_disable_msi to disable MSI interrupts and revert back to ++INTx emulation mode. Since service drivers of the same PCI-PCI Bridge ++port share the same physical device, if an individual service driver ++calls pci_enable_msi/pci_disable_msi it may result unpredictable ++behavior. For example, two service drivers run simultaneously on the ++same physical Root Port. Both service drivers call pci_enable_msi to ++request MSI based interrupts. A service driver may not know whether ++any other service drivers have run on this Root Port. If either one ++of them calls pci_disable_msi, it puts the other service driver ++in a wrong interrupt mode. ++ ++To avoid this situation all service drivers are not permitted to ++switch interrupt mode on its device. The PCI Express Port Bus driver ++is responsible for determining the interrupt mode and this should be ++transparent to service drivers. Service drivers need to know only ++the vector IRQ assigned to the field irq of struct pcie_device, which ++is passed in when the PCI Express Port Bus driver probes each service ++driver. Service drivers should use (struct pcie_device*)dev->irq to ++call request_irq/free_irq. In addition, the interrupt mode is stored ++in the field interrupt_mode of struct pcie_device. ++ ++6.2 MSI-X Vector Resources ++ ++Similar to the MSI a device driver for an MSI-X capable device can ++call pci_enable_msix to request MSI-X interrupts. All service drivers ++are not permitted to switch interrupt mode on its device. The PCI ++Express Port Bus driver is responsible for determining the interrupt ++mode and this should be transparent to service drivers. Any attempt ++by service driver to call pci_enable_msix/pci_disable_msix may ++result unpredictable behavior. Service drivers should use ++(struct pcie_device*)dev->irq and call request_irq/free_irq. ++ ++6.3 PCI Memory/IO Mapped Regions ++ ++Service drivers for PCI Express Power Management (PME), Advanced ++Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access ++PCI configuration space on the PCI Express port. In all cases the ++registers accessed are independent of each other. This patch assumes ++that all service drivers will be well behaved and not overwrite ++other service driver's configuration settings. ++ ++6.4 PCI Config Registers ++ ++Each service driver runs its PCI config operations on its own ++capability structure except the PCI Express capability structure, in ++which Root Control register and Device Control register are shared ++between PME and AER. This patch assumes that all service drivers ++will be well behaved and not overwrite other service driver's ++configuration settings. +--- /dev/null ++++ b/Documentation/PCI/pci-error-recovery.txt +@@ -0,0 +1,396 @@ ++ ++ PCI Error Recovery ++ ------------------ ++ February 2, 2006 ++ ++ Current document maintainer: ++ Linas Vepstas <linas@austin.ibm.com> ++ ++ ++Many PCI bus controllers are able to detect a variety of hardware ++PCI errors on the bus, such as parity errors on the data and address ++busses, as well as SERR and PERR errors. Some of the more advanced ++chipsets are able to deal with these errors; these include PCI-E chipsets, ++and the PCI-host bridges found on IBM Power4 and Power5-based pSeries ++boxes. A typical action taken is to disconnect the affected device, ++halting all I/O to it. The goal of a disconnection is to avoid system ++corruption; for example, to halt system memory corruption due to DMA's ++to "wild" addresses. Typically, a reconnection mechanism is also ++offered, so that the affected PCI device(s) are reset and put back ++into working condition. The reset phase requires coordination ++between the affected device drivers and the PCI controller chip. ++This document describes a generic API for notifying device drivers ++of a bus disconnection, and then performing error recovery. ++This API is currently implemented in the 2.6.16 and later kernels. ++ ++Reporting and recovery is performed in several steps. First, when ++a PCI hardware error has resulted in a bus disconnect, that event ++is reported as soon as possible to all affected device drivers, ++including multiple instances of a device driver on multi-function ++cards. This allows device drivers to avoid deadlocking in spinloops, ++waiting for some i/o-space register to change, when it never will. ++It also gives the drivers a chance to defer incoming I/O as ++needed. ++ ++Next, recovery is performed in several stages. Most of the complexity ++is forced by the need to handle multi-function devices, that is, ++devices that have multiple device drivers associated with them. ++In the first stage, each driver is allowed to indicate what type ++of reset it desires, the choices being a simple re-enabling of I/O ++or requesting a hard reset (a full electrical #RST of the PCI card). ++If any driver requests a full reset, that is what will be done. ++ ++After a full reset and/or a re-enabling of I/O, all drivers are ++again notified, so that they may then perform any device setup/config ++that may be required. After these have all completed, a final ++"resume normal operations" event is sent out. ++ ++The biggest reason for choosing a kernel-based implementation rather ++than a user-space implementation was the need to deal with bus ++disconnects of PCI devices attached to storage media, and, in particular, ++disconnects from devices holding the root file system. If the root ++file system is disconnected, a user-space mechanism would have to go ++through a large number of contortions to complete recovery. Almost all ++of the current Linux file systems are not tolerant of disconnection ++from/reconnection to their underlying block device. By contrast, ++bus errors are easy to manage in the device driver. Indeed, most ++device drivers already handle very similar recovery procedures; ++for example, the SCSI-generic layer already provides significant ++mechanisms for dealing with SCSI bus errors and SCSI bus resets. ++ ++ ++Detailed Design ++--------------- ++Design and implementation details below, based on a chain of ++public email discussions with Ben Herrenschmidt, circa 5 April 2005. ++ ++The error recovery API support is exposed to the driver in the form of ++a structure of function pointers pointed to by a new field in struct ++pci_driver. A driver that fails to provide the structure is "non-aware", ++and the actual recovery steps taken are platform dependent. The ++arch/powerpc implementation will simulate a PCI hotplug remove/add. ++ ++This structure has the form: ++struct pci_error_handlers ++{ ++ int (*error_detected)(struct pci_dev *dev, enum pci_channel_state); ++ int (*mmio_enabled)(struct pci_dev *dev); ++ int (*link_reset)(struct pci_dev *dev); ++ int (*slot_reset)(struct pci_dev *dev); ++ void (*resume)(struct pci_dev *dev); ++}; ++ ++The possible channel states are: ++enum pci_channel_state { ++ pci_channel_io_normal, /* I/O channel is in normal state */ ++ pci_channel_io_frozen, /* I/O to channel is blocked */ ++ pci_channel_io_perm_failure, /* PCI card is dead */ ++}; ++ ++Possible return values are: ++enum pci_ers_result { ++ PCI_ERS_RESULT_NONE, /* no result/none/not supported in device driver */ ++ PCI_ERS_RESULT_CAN_RECOVER, /* Device driver can recover without slot reset */ ++ PCI_ERS_RESULT_NEED_RESET, /* Device driver wants slot to be reset. */ ++ PCI_ERS_RESULT_DISCONNECT, /* Device has completely failed, is unrecoverable */ ++ PCI_ERS_RESULT_RECOVERED, /* Device driver is fully recovered and operational */ ++}; ++ ++A driver does not have to implement all of these callbacks; however, ++if it implements any, it must implement error_detected(). If a callback ++is not implemented, the corresponding feature is considered unsupported. ++For example, if mmio_enabled() and resume() aren't there, then it ++is assumed that the driver is not doing any direct recovery and requires ++a reset. If link_reset() is not implemented, the card is assumed as ++not care about link resets. Typically a driver will want to know about ++a slot_reset(). ++ ++The actual steps taken by a platform to recover from a PCI error ++event will be platform-dependent, but will follow the general ++sequence described below. ++ ++STEP 0: Error Event ++------------------- ++PCI bus error is detect by the PCI hardware. On powerpc, the slot ++is isolated, in that all I/O is blocked: all reads return 0xffffffff, ++all writes are ignored. ++ ++ ++STEP 1: Notification ++-------------------- ++Platform calls the error_detected() callback on every instance of ++every driver affected by the error. ++ ++At this point, the device might not be accessible anymore, depending on ++the platform (the slot will be isolated on powerpc). The driver may ++already have "noticed" the error because of a failing I/O, but this ++is the proper "synchronization point", that is, it gives the driver ++a chance to cleanup, waiting for pending stuff (timers, whatever, etc...) ++to complete; it can take semaphores, schedule, etc... everything but ++touch the device. Within this function and after it returns, the driver ++shouldn't do any new IOs. Called in task context. This is sort of a ++"quiesce" point. See note about interrupts at the end of this doc. ++ ++All drivers participating in this system must implement this call. ++The driver must return one of the following result codes: ++ - PCI_ERS_RESULT_CAN_RECOVER: ++ Driver returns this if it thinks it might be able to recover ++ the HW by just banging IOs or if it wants to be given ++ a chance to extract some diagnostic information (see ++ mmio_enable, below). ++ - PCI_ERS_RESULT_NEED_RESET: ++ Driver returns this if it can't recover without a hard ++ slot reset. ++ - PCI_ERS_RESULT_DISCONNECT: ++ Driver returns this if it doesn't want to recover at all. ++ ++The next step taken will depend on the result codes returned by the ++drivers. ++ ++If all drivers on the segment/slot return PCI_ERS_RESULT_CAN_RECOVER, ++then the platform should re-enable IOs on the slot (or do nothing in ++particular, if the platform doesn't isolate slots), and recovery ++proceeds to STEP 2 (MMIO Enable). ++ ++If any driver requested a slot reset (by returning PCI_ERS_RESULT_NEED_RESET), ++then recovery proceeds to STEP 4 (Slot Reset). ++ ++If the platform is unable to recover the slot, the next step ++is STEP 6 (Permanent Failure). ++ ++>>> The current powerpc implementation assumes that a device driver will ++>>> *not* schedule or semaphore in this routine; the current powerpc ++>>> implementation uses one kernel thread to notify all devices; ++>>> thus, if one device sleeps/schedules, all devices are affected. ++>>> Doing better requires complex multi-threaded logic in the error ++>>> recovery implementation (e.g. waiting for all notification threads ++>>> to "join" before proceeding with recovery.) This seems excessively ++>>> complex and not worth implementing. ++ ++>>> The current powerpc implementation doesn't much care if the device ++>>> attempts I/O at this point, or not. I/O's will fail, returning ++>>> a value of 0xff on read, and writes will be dropped. If the device ++>>> driver attempts more than 10K I/O's to a frozen adapter, it will ++>>> assume that the device driver has gone into an infinite loop, and ++>>> it will panic the kernel. There doesn't seem to be any other ++>>> way of stopping a device driver that insists on spinning on I/O. ++ ++STEP 2: MMIO Enabled ++------------------- ++The platform re-enables MMIO to the device (but typically not the ++DMA), and then calls the mmio_enabled() callback on all affected ++device drivers. ++ ++This is the "early recovery" call. IOs are allowed again, but DMA is ++not (hrm... to be discussed, I prefer not), with some restrictions. This ++is NOT a callback for the driver to start operations again, only to ++peek/poke at the device, extract diagnostic information, if any, and ++eventually do things like trigger a device local reset or some such, ++but not restart operations. This is callback is made if all drivers on ++a segment agree that they can try to recover and if no automatic link reset ++was performed by the HW. If the platform can't just re-enable IOs without ++a slot reset or a link reset, it wont call this callback, and instead ++will have gone directly to STEP 3 (Link Reset) or STEP 4 (Slot Reset) ++ ++>>> The following is proposed; no platform implements this yet: ++>>> Proposal: All I/O's should be done _synchronously_ from within ++>>> this callback, errors triggered by them will be returned via ++>>> the normal pci_check_whatever() API, no new error_detected() ++>>> callback will be issued due to an error happening here. However, ++>>> such an error might cause IOs to be re-blocked for the whole ++>>> segment, and thus invalidate the recovery that other devices ++>>> on the same segment might have done, forcing the whole segment ++>>> into one of the next states, that is, link reset or slot reset. ++ ++The driver should return one of the following result codes: ++ - PCI_ERS_RESULT_RECOVERED ++ Driver returns this if it thinks the device is fully ++ functional and thinks it is ready to start ++ normal driver operations again. There is no ++ guarantee that the driver will actually be ++ allowed to proceed, as another driver on the ++ same segment might have failed and thus triggered a ++ slot reset on platforms that support it. ++ ++ - PCI_ERS_RESULT_NEED_RESET ++ Driver returns this if it thinks the device is not ++ recoverable in it's current state and it needs a slot ++ reset to proceed. ++ ++ - PCI_ERS_RESULT_DISCONNECT ++ Same as above. Total failure, no recovery even after ++ reset driver dead. (To be defined more precisely) ++ ++The next step taken depends on the results returned by the drivers. ++If all drivers returned PCI_ERS_RESULT_RECOVERED, then the platform ++proceeds to either STEP3 (Link Reset) or to STEP 5 (Resume Operations). ++ ++If any driver returned PCI_ERS_RESULT_NEED_RESET, then the platform ++proceeds to STEP 4 (Slot Reset) ++ ++>>> The current powerpc implementation does not implement this callback. ++ ++ ++STEP 3: Link Reset ++------------------ ++The platform resets the link, and then calls the link_reset() callback ++on all affected device drivers. This is a PCI-Express specific state ++and is done whenever a non-fatal error has been detected that can be ++"solved" by resetting the link. This call informs the driver of the ++reset and the driver should check to see if the device appears to be ++in working condition. ++ ++The driver is not supposed to restart normal driver I/O operations ++at this point. It should limit itself to "probing" the device to ++check it's recoverability status. If all is right, then the platform ++will call resume() once all drivers have ack'd link_reset(). ++ ++ Result codes: ++ (identical to STEP 3 (MMIO Enabled) ++ ++The platform then proceeds to either STEP 4 (Slot Reset) or STEP 5 ++(Resume Operations). ++ ++>>> The current powerpc implementation does not implement this callback. ++ ++ ++STEP 4: Slot Reset ++------------------ ++The platform performs a soft or hard reset of the device, and then ++calls the slot_reset() callback. ++ ++A soft reset consists of asserting the adapter #RST line and then ++restoring the PCI BAR's and PCI configuration header to a state ++that is equivalent to what it would be after a fresh system ++power-on followed by power-on BIOS/system firmware initialization. ++If the platform supports PCI hotplug, then the reset might be ++performed by toggling the slot electrical power off/on. ++ ++It is important for the platform to restore the PCI config space ++to the "fresh poweron" state, rather than the "last state". After ++a slot reset, the device driver will almost always use its standard ++device initialization routines, and an unusual config space setup ++may result in hung devices, kernel panics, or silent data corruption. ++ ++This call gives drivers the chance to re-initialize the hardware ++(re-download firmware, etc.). At this point, the driver may assume ++that he card is in a fresh state and is fully functional. In ++particular, interrupt generation should work normally. ++ ++Drivers should not yet restart normal I/O processing operations ++at this point. If all device drivers report success on this ++callback, the platform will call resume() to complete the sequence, ++and let the driver restart normal I/O processing. ++ ++A driver can still return a critical failure for this function if ++it can't get the device operational after reset. If the platform ++previously tried a soft reset, it might now try a hard reset (power ++cycle) and then call slot_reset() again. It the device still can't ++be recovered, there is nothing more that can be done; the platform ++will typically report a "permanent failure" in such a case. The ++device will be considered "dead" in this case. ++ ++Drivers for multi-function cards will need to coordinate among ++themselves as to which driver instance will perform any "one-shot" ++or global device initialization. For example, the Symbios sym53cxx2 ++driver performs device init only from PCI function 0: ++ +++ if (PCI_FUNC(pdev->devfn) == 0) +++ sym_reset_scsi_bus(np, 0); ++ ++ Result codes: ++ - PCI_ERS_RESULT_DISCONNECT ++ Same as above. ++ ++Platform proceeds either to STEP 5 (Resume Operations) or STEP 6 (Permanent ++Failure). ++ ++>>> The current powerpc implementation does not currently try a ++>>> power-cycle reset if the driver returned PCI_ERS_RESULT_DISCONNECT. ++>>> However, it probably should. ++ ++ ++STEP 5: Resume Operations ++------------------------- ++The platform will call the resume() callback on all affected device ++drivers if all drivers on the segment have returned ++PCI_ERS_RESULT_RECOVERED from one of the 3 previous callbacks. ++The goal of this callback is to tell the driver to restart activity, ++that everything is back and running. This callback does not return ++a result code. ++ ++At this point, if a new error happens, the platform will restart ++a new error recovery sequence. ++ ++STEP 6: Permanent Failure ++------------------------- ++A "permanent failure" has occurred, and the platform cannot recover ++the device. The platform will call error_detected() with a ++pci_channel_state value of pci_channel_io_perm_failure. ++ ++The device driver should, at this point, assume the worst. It should ++cancel all pending I/O, refuse all new I/O, returning -EIO to ++higher layers. The device driver should then clean up all of its ++memory and remove itself from kernel operations, much as it would ++during system shutdown. ++ ++The platform will typically notify the system operator of the ++permanent failure in some way. If the device is hotplug-capable, ++the operator will probably want to remove and replace the device. ++Note, however, not all failures are truly "permanent". Some are ++caused by over-heating, some by a poorly seated card. Many ++PCI error events are caused by software bugs, e.g. DMA's to ++wild addresses or bogus split transactions due to programming ++errors. See the discussion in powerpc/eeh-pci-error-recovery.txt ++for additional detail on real-life experience of the causes of ++software errors. ++ ++ ++Conclusion; General Remarks ++--------------------------- ++The way those callbacks are called is platform policy. A platform with ++no slot reset capability may want to just "ignore" drivers that can't ++recover (disconnect them) and try to let other cards on the same segment ++recover. Keep in mind that in most real life cases, though, there will ++be only one driver per segment. ++ ++Now, a note about interrupts. If you get an interrupt and your ++device is dead or has been isolated, there is a problem :) ++The current policy is to turn this into a platform policy. ++That is, the recovery API only requires that: ++ ++ - There is no guarantee that interrupt delivery can proceed from any ++device on the segment starting from the error detection and until the ++resume callback is sent, at which point interrupts are expected to be ++fully operational. ++ ++ - There is no guarantee that interrupt delivery is stopped, that is, ++a driver that gets an interrupt after detecting an error, or that detects ++an error within the interrupt handler such that it prevents proper ++ack'ing of the interrupt (and thus removal of the source) should just ++return IRQ_NOTHANDLED. It's up to the platform to deal with that ++condition, typically by masking the IRQ source during the duration of ++the error handling. It is expected that the platform "knows" which ++interrupts are routed to error-management capable slots and can deal ++with temporarily disabling that IRQ number during error processing (this ++isn't terribly complex). That means some IRQ latency for other devices ++sharing the interrupt, but there is simply no other way. High end ++platforms aren't supposed to share interrupts between many devices ++anyway :) ++ ++>>> Implementation details for the powerpc platform are discussed in ++>>> the file Documentation/powerpc/eeh-pci-error-recovery.txt ++ ++>>> As of this writing, there are six device drivers with patches ++>>> implementing error recovery. Not all of these patches are in ++>>> mainline yet. These may be used as "examples": ++>>> ++>>> drivers/scsi/ipr.c ++>>> drivers/scsi/sym53cxx_2 ++>>> drivers/next/e100.c ++>>> drivers/net/e1000 ++>>> drivers/net/ixgb ++>>> drivers/net/s2io.c ++ ++The End ++------- +--- /dev/null ++++ b/Documentation/PCI/pci.txt +@@ -0,0 +1,646 @@ ++ ++ How To Write Linux PCI Drivers ++ ++ by Martin Mares <mj@ucw.cz> on 07-Feb-2000 ++ updated by Grant Grundler <grundler@parisc-linux.org> on 23-Dec-2006 ++ ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++The world of PCI is vast and full of (mostly unpleasant) surprises. ++Since each CPU architecture implements different chip-sets and PCI devices ++have different requirements (erm, "features"), the result is the PCI support ++in the Linux kernel is not as trivial as one would wish. This short paper ++tries to introduce all potential driver authors to Linux APIs for ++PCI device drivers. ++ ++A more complete resource is the third edition of "Linux Device Drivers" ++by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman. ++LDD3 is available for free (under Creative Commons License) from: ++ ++ http://lwn.net/Kernel/LDD3/ ++ ++However, keep in mind that all documents are subject to "bit rot". ++Refer to the source code if things are not working as described here. ++ ++Please send questions/comments/patches about Linux PCI API to the ++"Linux PCI" <linux-pci@atrey.karlin.mff.cuni.cz> mailing list. ++ ++ ++ ++0. Structure of PCI drivers ++~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++PCI drivers "discover" PCI devices in a system via pci_register_driver(). ++Actually, it's the other way around. When the PCI generic code discovers ++a new device, the driver with a matching "description" will be notified. ++Details on this below. ++ ++pci_register_driver() leaves most of the probing for devices to ++the PCI layer and supports online insertion/removal of devices [thus ++supporting hot-pluggable PCI, CardBus, and Express-Card in a single driver]. ++pci_register_driver() call requires passing in a table of function ++pointers and thus dictates the high level structure of a driver. ++ ++Once the driver knows about a PCI device and takes ownership, the ++driver generally needs to perform the following initialization: ++ ++ Enable the device ++ Request MMIO/IOP resources ++ Set the DMA mask size (for both coherent and streaming DMA) ++ Allocate and initialize shared control data (pci_allocate_coherent()) ++ Access device configuration space (if needed) ++ Register IRQ handler (request_irq()) ++ Initialize non-PCI (i.e. LAN/SCSI/etc parts of the chip) ++ Enable DMA/processing engines ++ ++When done using the device, and perhaps the module needs to be unloaded, ++the driver needs to take the follow steps: ++ Disable the device from generating IRQs ++ Release the IRQ (free_irq()) ++ Stop all DMA activity ++ Release DMA buffers (both streaming and coherent) ++ Unregister from other subsystems (e.g. scsi or netdev) ++ Release MMIO/IOP resources ++ Disable the device ++ ++Most of these topics are covered in the following sections. ++For the rest look at LDD3 or <linux/pci.h> . ++ ++If the PCI subsystem is not configured (CONFIG_PCI is not set), most of ++the PCI functions described below are defined as inline functions either ++completely empty or just returning an appropriate error codes to avoid ++lots of ifdefs in the drivers. ++ ++ ++ ++1. pci_register_driver() call ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++PCI device drivers call pci_register_driver() during their ++initialization with a pointer to a structure describing the driver ++(struct pci_driver): ++ ++ field name Description ++ ---------- ------------------------------------------------------ ++ id_table Pointer to table of device ID's the driver is ++ interested in. Most drivers should export this ++ table using MODULE_DEVICE_TABLE(pci,...). ++ ++ probe This probing function gets called (during execution ++ of pci_register_driver() for already existing ++ devices or later if a new device gets inserted) for ++ all PCI devices which match the ID table and are not ++ "owned" by the other drivers yet. This function gets ++ passed a "struct pci_dev *" for each device whose ++ entry in the ID table matches the device. The probe ++ function returns zero when the driver chooses to ++ take "ownership" of the device or an error code ++ (negative number) otherwise. ++ The probe function always gets called from process ++ context, so it can sleep. ++ ++ remove The remove() function gets called whenever a device ++ being handled by this driver is removed (either during ++ deregistration of the driver or when it's manually ++ pulled out of a hot-pluggable slot). ++ The remove function always gets called from process ++ context, so it can sleep. ++ ++ suspend Put device into low power state. ++ suspend_late Put device into low power state. ++ ++ resume_early Wake device from low power state. ++ resume Wake device from low power state. ++ ++ (Please see Documentation/power/pci.txt for descriptions ++ of PCI Power Management and the related functions.) ++ ++ shutdown Hook into reboot_notifier_list (kernel/sys.c). ++ Intended to stop any idling DMA operations. ++ Useful for enabling wake-on-lan (NIC) or changing ++ the power state of a device before reboot. ++ e.g. drivers/net/e100.c. ++ ++ err_handler See Documentation/PCI/pci-error-recovery.txt ++ ++ ++The ID table is an array of struct pci_device_id entries ending with an ++all-zero entry; use of the macro DEFINE_PCI_DEVICE_TABLE is the preferred ++method of declaring the table. Each entry consists of: ++ ++ vendor,device Vendor and device ID to match (or PCI_ANY_ID) ++ ++ subvendor, Subsystem vendor and device ID to match (or PCI_ANY_ID) ++ subdevice, ++ ++ class Device class, subclass, and "interface" to match. ++ See Appendix D of the PCI Local Bus Spec or ++ include/linux/pci_ids.h for a full list of classes. ++ Most drivers do not need to specify class/class_mask ++ as vendor/device is normally sufficient. ++ ++ class_mask limit which sub-fields of the class field are compared. ++ See drivers/scsi/sym53c8xx_2/ for example of usage. ++ ++ driver_data Data private to the driver. ++ Most drivers don't need to use driver_data field. ++ Best practice is to use driver_data as an index ++ into a static list of equivalent device types, ++ instead of using it as a pointer. ++ ++ ++Most drivers only need PCI_DEVICE() or PCI_DEVICE_CLASS() to set up ++a pci_device_id table. ++ ++New PCI IDs may be added to a device driver pci_ids table at runtime ++as shown below: ++ ++echo "vendor device subvendor subdevice class class_mask driver_data" > \ ++/sys/bus/pci/drivers/{driver}/new_id ++ ++All fields are passed in as hexadecimal values (no leading 0x). ++The vendor and device fields are mandatory, the others are optional. Users ++need pass only as many optional fields as necessary: ++ o subvendor and subdevice fields default to PCI_ANY_ID (FFFFFFFF) ++ o class and classmask fields default to 0 ++ o driver_data defaults to 0UL. ++ ++Once added, the driver probe routine will be invoked for any unclaimed ++PCI devices listed in its (newly updated) pci_ids list. ++ ++When the driver exits, it just calls pci_unregister_driver() and the PCI layer ++automatically calls the remove hook for all devices handled by the driver. ++ ++ ++1.1 "Attributes" for driver functions/data ++ ++Please mark the initialization and cleanup functions where appropriate ++(the corresponding macros are defined in <linux/init.h>): ++ ++ __init Initialization code. Thrown away after the driver ++ initializes. ++ __exit Exit code. Ignored for non-modular drivers. ++ ++ ++ __devinit Device initialization code. ++ Identical to __init if the kernel is not compiled ++ with CONFIG_HOTPLUG, normal function otherwise. ++ __devexit The same for __exit. ++ ++Tips on when/where to use the above attributes: ++ o The module_init()/module_exit() functions (and all ++ initialization functions called _only_ from these) ++ should be marked __init/__exit. ++ ++ o Do not mark the struct pci_driver. ++ ++ o The ID table array should be marked __devinitconst; this is done ++ automatically if the table is declared with DEFINE_PCI_DEVICE_TABLE(). ++ ++ o The probe() and remove() functions should be marked __devinit ++ and __devexit respectively. All initialization functions ++ exclusively called by the probe() routine, can be marked __devinit. ++ Ditto for remove() and __devexit. ++ ++ o If mydriver_remove() is marked with __devexit(), then all address ++ references to mydriver_remove must use __devexit_p(mydriver_remove) ++ (in the struct pci_driver declaration for example). ++ __devexit_p() will generate the function name _or_ NULL if the ++ function will be discarded. For an example, see drivers/net/tg3.c. ++ ++ o Do NOT mark a function if you are not sure which mark to use. ++ Better to not mark the function than mark the function wrong. ++ ++ ++ ++2. How to find PCI devices manually ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++PCI drivers should have a really good reason for not using the ++pci_register_driver() interface to search for PCI devices. ++The main reason PCI devices are controlled by multiple drivers ++is because one PCI device implements several different HW services. ++E.g. combined serial/parallel port/floppy controller. ++ ++A manual search may be performed using the following constructs: ++ ++Searching by vendor and device ID: ++ ++ struct pci_dev *dev = NULL; ++ while (dev = pci_get_device(VENDOR_ID, DEVICE_ID, dev)) ++ configure_device(dev); ++ ++Searching by class ID (iterate in a similar way): ++ ++ pci_get_class(CLASS_ID, dev) ++ ++Searching by both vendor/device and subsystem vendor/device ID: ++ ++ pci_get_subsys(VENDOR_ID,DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev). ++ ++You can use the constant PCI_ANY_ID as a wildcard replacement for ++VENDOR_ID or DEVICE_ID. This allows searching for any device from a ++specific vendor, for example. ++ ++These functions are hotplug-safe. They increment the reference count on ++the pci_dev that they return. You must eventually (possibly at module unload) ++decrement the reference count on these devices by calling pci_dev_put(). ++ ++ ++ ++3. Device Initialization Steps ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++As noted in the introduction, most PCI drivers need the following steps ++for device initialization: ++ ++ Enable the device ++ Request MMIO/IOP resources ++ Set the DMA mask size (for both coherent and streaming DMA) ++ Allocate and initialize shared control data (pci_allocate_coherent()) ++ Access device configuration space (if needed) ++ Register IRQ handler (request_irq()) ++ Initialize non-PCI (i.e. LAN/SCSI/etc parts of the chip) ++ Enable DMA/processing engines. ++ ++The driver can access PCI config space registers at any time. ++(Well, almost. When running BIST, config space can go away...but ++that will just result in a PCI Bus Master Abort and config reads ++will return garbage). ++ ++ ++3.1 Enable the PCI device ++~~~~~~~~~~~~~~~~~~~~~~~~~ ++Before touching any device registers, the driver needs to enable ++the PCI device by calling pci_enable_device(). This will: ++ o wake up the device if it was in suspended state, ++ o allocate I/O and memory regions of the device (if BIOS did not), ++ o allocate an IRQ (if BIOS did not). ++ ++NOTE: pci_enable_device() can fail! Check the return value. ++ ++[ OS BUG: we don't check resource allocations before enabling those ++ resources. The sequence would make more sense if we called ++ pci_request_resources() before calling pci_enable_device(). ++ Currently, the device drivers can't detect the bug when when two ++ devices have been allocated the same range. This is not a common ++ problem and unlikely to get fixed soon. ++ ++ This has been discussed before but not changed as of 2.6.19: ++ http://lkml.org/lkml/2006/3/2/194 ++] ++ ++pci_set_master() will enable DMA by setting the bus master bit ++in the PCI_COMMAND register. It also fixes the latency timer value if ++it's set to something bogus by the BIOS. ++ ++If the PCI device can use the PCI Memory-Write-Invalidate transaction, ++call pci_set_mwi(). This enables the PCI_COMMAND bit for Mem-Wr-Inval ++and also ensures that the cache line size register is set correctly. ++Check the return value of pci_set_mwi() as not all architectures ++or chip-sets may support Memory-Write-Invalidate. Alternatively, ++if Mem-Wr-Inval would be nice to have but is not required, call ++pci_try_set_mwi() to have the system do its best effort at enabling ++Mem-Wr-Inval. ++ ++ ++3.2 Request MMIO/IOP resources ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Memory (MMIO), and I/O port addresses should NOT be read directly ++from the PCI device config space. Use the values in the pci_dev structure ++as the PCI "bus address" might have been remapped to a "host physical" ++address by the arch/chip-set specific kernel support. ++ ++See Documentation/IO-mapping.txt for how to access device registers ++or device memory. ++ ++The device driver needs to call pci_request_region() to verify ++no other device is already using the same address resource. ++Conversely, drivers should call pci_release_region() AFTER ++calling pci_disable_device(). ++The idea is to prevent two devices colliding on the same address range. ++ ++[ See OS BUG comment above. Currently (2.6.19), The driver can only ++ determine MMIO and IO Port resource availability _after_ calling ++ pci_enable_device(). ] ++ ++Generic flavors of pci_request_region() are request_mem_region() ++(for MMIO ranges) and request_region() (for IO Port ranges). ++Use these for address resources that are not described by "normal" PCI ++BARs. ++ ++Also see pci_request_selected_regions() below. ++ ++ ++3.3 Set the DMA mask size ++~~~~~~~~~~~~~~~~~~~~~~~~~ ++[ If anything below doesn't make sense, please refer to ++ Documentation/DMA-API.txt. This section is just a reminder that ++ drivers need to indicate DMA capabilities of the device and is not ++ an authoritative source for DMA interfaces. ] ++ ++While all drivers should explicitly indicate the DMA capability ++(e.g. 32 or 64 bit) of the PCI bus master, devices with more than ++32-bit bus master capability for streaming data need the driver ++to "register" this capability by calling pci_set_dma_mask() with ++appropriate parameters. In general this allows more efficient DMA ++on systems where System RAM exists above 4G _physical_ address. ++ ++Drivers for all PCI-X and PCIe compliant devices must call ++pci_set_dma_mask() as they are 64-bit DMA devices. ++ ++Similarly, drivers must also "register" this capability if the device ++can directly address "consistent memory" in System RAM above 4G physical ++address by calling pci_set_consistent_dma_mask(). ++Again, this includes drivers for all PCI-X and PCIe compliant devices. ++Many 64-bit "PCI" devices (before PCI-X) and some PCI-X devices are ++64-bit DMA capable for payload ("streaming") data but not control ++("consistent") data. ++ ++ ++3.4 Setup shared control data ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Once the DMA masks are set, the driver can allocate "consistent" (a.k.a. shared) ++memory. See Documentation/DMA-API.txt for a full description of ++the DMA APIs. This section is just a reminder that it needs to be done ++before enabling DMA on the device. ++ ++ ++3.5 Initialize device registers ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Some drivers will need specific "capability" fields programmed ++or other "vendor specific" register initialized or reset. ++E.g. clearing pending interrupts. ++ ++ ++3.6 Register IRQ handler ++~~~~~~~~~~~~~~~~~~~~~~~~ ++While calling request_irq() is the last step described here, ++this is often just another intermediate step to initialize a device. ++This step can often be deferred until the device is opened for use. ++ ++All interrupt handlers for IRQ lines should be registered with IRQF_SHARED ++and use the devid to map IRQs to devices (remember that all PCI IRQ lines ++can be shared). ++ ++request_irq() will associate an interrupt handler and device handle ++with an interrupt number. Historically interrupt numbers represent ++IRQ lines which run from the PCI device to the Interrupt controller. ++With MSI and MSI-X (more below) the interrupt number is a CPU "vector". ++ ++request_irq() also enables the interrupt. Make sure the device is ++quiesced and does not have any interrupts pending before registering ++the interrupt handler. ++ ++MSI and MSI-X are PCI capabilities. Both are "Message Signaled Interrupts" ++which deliver interrupts to the CPU via a DMA write to a Local APIC. ++The fundamental difference between MSI and MSI-X is how multiple ++"vectors" get allocated. MSI requires contiguous blocks of vectors ++while MSI-X can allocate several individual ones. ++ ++MSI capability can be enabled by calling pci_enable_msi() or ++pci_enable_msix() before calling request_irq(). This causes ++the PCI support to program CPU vector data into the PCI device ++capability registers. ++ ++If your PCI device supports both, try to enable MSI-X first. ++Only one can be enabled at a time. Many architectures, chip-sets, ++or BIOSes do NOT support MSI or MSI-X and the call to pci_enable_msi/msix ++will fail. This is important to note since many drivers have ++two (or more) interrupt handlers: one for MSI/MSI-X and another for IRQs. ++They choose which handler to register with request_irq() based on the ++return value from pci_enable_msi/msix(). ++ ++There are (at least) two really good reasons for using MSI: ++1) MSI is an exclusive interrupt vector by definition. ++ This means the interrupt handler doesn't have to verify ++ its device caused the interrupt. ++ ++2) MSI avoids DMA/IRQ race conditions. DMA to host memory is guaranteed ++ to be visible to the host CPU(s) when the MSI is delivered. This ++ is important for both data coherency and avoiding stale control data. ++ This guarantee allows the driver to omit MMIO reads to flush ++ the DMA stream. ++ ++See drivers/infiniband/hw/mthca/ or drivers/net/tg3.c for examples ++of MSI/MSI-X usage. ++ ++ ++ ++4. PCI device shutdown ++~~~~~~~~~~~~~~~~~~~~~~~ ++ ++When a PCI device driver is being unloaded, most of the following ++steps need to be performed: ++ ++ Disable the device from generating IRQs ++ Release the IRQ (free_irq()) ++ Stop all DMA activity ++ Release DMA buffers (both streaming and consistent) ++ Unregister from other subsystems (e.g. scsi or netdev) ++ Disable device from responding to MMIO/IO Port addresses ++ Release MMIO/IO Port resource(s) ++ ++ ++4.1 Stop IRQs on the device ++~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++How to do this is chip/device specific. If it's not done, it opens ++the possibility of a "screaming interrupt" if (and only if) ++the IRQ is shared with another device. ++ ++When the shared IRQ handler is "unhooked", the remaining devices ++using the same IRQ line will still need the IRQ enabled. Thus if the ++"unhooked" device asserts IRQ line, the system will respond assuming ++it was one of the remaining devices asserted the IRQ line. Since none ++of the other devices will handle the IRQ, the system will "hang" until ++it decides the IRQ isn't going to get handled and masks the IRQ (100,000 ++iterations later). Once the shared IRQ is masked, the remaining devices ++will stop functioning properly. Not a nice situation. ++ ++This is another reason to use MSI or MSI-X if it's available. ++MSI and MSI-X are defined to be exclusive interrupts and thus ++are not susceptible to the "screaming interrupt" problem. ++ ++ ++4.2 Release the IRQ ++~~~~~~~~~~~~~~~~~~~ ++Once the device is quiesced (no more IRQs), one can call free_irq(). ++This function will return control once any pending IRQs are handled, ++"unhook" the drivers IRQ handler from that IRQ, and finally release ++the IRQ if no one else is using it. ++ ++ ++4.3 Stop all DMA activity ++~~~~~~~~~~~~~~~~~~~~~~~~~ ++It's extremely important to stop all DMA operations BEFORE attempting ++to deallocate DMA control data. Failure to do so can result in memory ++corruption, hangs, and on some chip-sets a hard crash. ++ ++Stopping DMA after stopping the IRQs can avoid races where the ++IRQ handler might restart DMA engines. ++ ++While this step sounds obvious and trivial, several "mature" drivers ++didn't get this step right in the past. ++ ++ ++4.4 Release DMA buffers ++~~~~~~~~~~~~~~~~~~~~~~~ ++Once DMA is stopped, clean up streaming DMA first. ++I.e. unmap data buffers and return buffers to "upstream" ++owners if there is one. ++ ++Then clean up "consistent" buffers which contain the control data. ++ ++See Documentation/DMA-API.txt for details on unmapping interfaces. ++ ++ ++4.5 Unregister from other subsystems ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Most low level PCI device drivers support some other subsystem ++like USB, ALSA, SCSI, NetDev, Infiniband, etc. Make sure your ++driver isn't losing resources from that other subsystem. ++If this happens, typically the symptom is an Oops (panic) when ++the subsystem attempts to call into a driver that has been unloaded. ++ ++ ++4.6 Disable Device from responding to MMIO/IO Port addresses ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++io_unmap() MMIO or IO Port resources and then call pci_disable_device(). ++This is the symmetric opposite of pci_enable_device(). ++Do not access device registers after calling pci_disable_device(). ++ ++ ++4.7 Release MMIO/IO Port Resource(s) ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Call pci_release_region() to mark the MMIO or IO Port range as available. ++Failure to do so usually results in the inability to reload the driver. ++ ++ ++ ++5. How to access PCI config space ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++You can use pci_(read|write)_config_(byte|word|dword) to access the config ++space of a device represented by struct pci_dev *. All these functions return 0 ++when successful or an error code (PCIBIOS_...) which can be translated to a text ++string by pcibios_strerror. Most drivers expect that accesses to valid PCI ++devices don't fail. ++ ++If you don't have a struct pci_dev available, you can call ++pci_bus_(read|write)_config_(byte|word|dword) to access a given device ++and function on that bus. ++ ++If you access fields in the standard portion of the config header, please ++use symbolic names of locations and bits declared in <linux/pci.h>. ++ ++If you need to access Extended PCI Capability registers, just call ++pci_find_capability() for the particular capability and it will find the ++corresponding register block for you. ++ ++ ++ ++6. Other interesting functions ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++pci_find_slot() Find pci_dev corresponding to given bus and ++ slot numbers. ++pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3) ++pci_find_capability() Find specified capability in device's capability ++ list. ++pci_resource_start() Returns bus start address for a given PCI region ++pci_resource_end() Returns bus end address for a given PCI region ++pci_resource_len() Returns the byte length of a PCI region ++pci_set_drvdata() Set private driver data pointer for a pci_dev ++pci_get_drvdata() Return private driver data pointer for a pci_dev ++pci_set_mwi() Enable Memory-Write-Invalidate transactions. ++pci_clear_mwi() Disable Memory-Write-Invalidate transactions. ++ ++ ++ ++7. Miscellaneous hints ++~~~~~~~~~~~~~~~~~~~~~~ ++ ++When displaying PCI device names to the user (for example when a driver wants ++to tell the user what card has it found), please use pci_name(pci_dev). ++ ++Always refer to the PCI devices by a pointer to the pci_dev structure. ++All PCI layer functions use this identification and it's the only ++reasonable one. Don't use bus/slot/function numbers except for very ++special purposes -- on systems with multiple primary buses their semantics ++can be pretty complex. ++ ++Don't try to turn on Fast Back to Back writes in your driver. All devices ++on the bus need to be capable of doing it, so this is something which needs ++to be handled by platform and generic code, not individual drivers. ++ ++ ++ ++8. Vendor and device identifications ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++One is not not required to add new device ids to include/linux/pci_ids.h. ++Please add PCI_VENDOR_ID_xxx for vendors and a hex constant for device ids. ++ ++PCI_VENDOR_ID_xxx constants are re-used. The device ids are arbitrary ++hex numbers (vendor controlled) and normally used only in a single ++location, the pci_device_id table. ++ ++Please DO submit new vendor/device ids to pciids.sourceforge.net project. ++ ++ ++ ++9. Obsolete functions ++~~~~~~~~~~~~~~~~~~~~~ ++ ++There are several functions which you might come across when trying to ++port an old driver to the new PCI interface. They are no longer present ++in the kernel as they aren't compatible with hotplug or PCI domains or ++having sane locking. ++ ++pci_find_device() Superseded by pci_get_device() ++pci_find_subsys() Superseded by pci_get_subsys() ++pci_find_slot() Superseded by pci_get_slot() ++ ++ ++The alternative is the traditional PCI device driver that walks PCI ++device lists. This is still possible but discouraged. ++ ++ ++ ++10. MMIO Space and "Write Posting" ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++Converting a driver from using I/O Port space to using MMIO space ++often requires some additional changes. Specifically, "write posting" ++needs to be handled. Many drivers (e.g. tg3, acenic, sym53c8xx_2) ++already do this. I/O Port space guarantees write transactions reach the PCI ++device before the CPU can continue. Writes to MMIO space allow the CPU ++to continue before the transaction reaches the PCI device. HW weenies ++call this "Write Posting" because the write completion is "posted" to ++the CPU before the transaction has reached its destination. ++ ++Thus, timing sensitive code should add readl() where the CPU is ++expected to wait before doing other work. The classic "bit banging" ++sequence works fine for I/O Port space: ++ ++ for (i = 8; --i; val >>= 1) { ++ outb(val & 1, ioport_reg); /* write bit */ ++ udelay(10); ++ } ++ ++The same sequence for MMIO space should be: ++ ++ for (i = 8; --i; val >>= 1) { ++ writeb(val & 1, mmio_reg); /* write bit */ ++ readb(safe_mmio_reg); /* flush posted write */ ++ udelay(10); ++ } ++ ++It is important that "safe_mmio_reg" not have any side effects that ++interferes with the correct operation of the device. ++ ++Another case to watch out for is when resetting a PCI device. Use PCI ++Configuration space reads to flush the writel(). This will gracefully ++handle the PCI master abort on all platforms if the PCI device is ++expected to not respond to a readl(). Most x86 platforms will allow ++MMIO reads to master abort (a.k.a. "Soft Fail") and return garbage ++(e.g. ~0). But many RISC platforms will crash (a.k.a."Hard Fail"). ++ +--- /dev/null ++++ b/Documentation/PCI/pcieaer-howto.txt +@@ -0,0 +1,253 @@ ++ The PCI Express Advanced Error Reporting Driver Guide HOWTO ++ T. Long Nguyen <tom.l.nguyen@intel.com> ++ Yanmin Zhang <yanmin.zhang@intel.com> ++ 07/29/2006 ++ ++ ++1. Overview ++ ++1.1 About this guide ++ ++This guide describes the basics of the PCI Express Advanced Error ++Reporting (AER) driver and provides information on how to use it, as ++well as how to enable the drivers of endpoint devices to conform with ++PCI Express AER driver. ++ ++1.2 Copyright � Intel Corporation 2006. ++ ++1.3 What is the PCI Express AER Driver? ++ ++PCI Express error signaling can occur on the PCI Express link itself ++or on behalf of transactions initiated on the link. PCI Express ++defines two error reporting paradigms: the baseline capability and ++the Advanced Error Reporting capability. The baseline capability is ++required of all PCI Express components providing a minimum defined ++set of error reporting requirements. Advanced Error Reporting ++capability is implemented with a PCI Express advanced error reporting ++extended capability structure providing more robust error reporting. ++ ++The PCI Express AER driver provides the infrastructure to support PCI ++Express Advanced Error Reporting capability. The PCI Express AER ++driver provides three basic functions: ++ ++- Gathers the comprehensive error information if errors occurred. ++- Reports error to the users. ++- Performs error recovery actions. ++ ++AER driver only attaches root ports which support PCI-Express AER ++capability. ++ ++ ++2. User Guide ++ ++2.1 Include the PCI Express AER Root Driver into the Linux Kernel ++ ++The PCI Express AER Root driver is a Root Port service driver attached ++to the PCI Express Port Bus driver. If a user wants to use it, the driver ++has to be compiled. Option CONFIG_PCIEAER supports this capability. It ++depends on CONFIG_PCIEPORTBUS, so pls. set CONFIG_PCIEPORTBUS=y and ++CONFIG_PCIEAER = y. ++ ++2.2 Load PCI Express AER Root Driver ++There is a case where a system has AER support in BIOS. Enabling the AER ++Root driver and having AER support in BIOS may result unpredictable ++behavior. To avoid this conflict, a successful load of the AER Root driver ++requires ACPI _OSC support in the BIOS to allow the AER Root driver to ++request for native control of AER. See the PCI FW 3.0 Specification for ++details regarding OSC usage. Currently, lots of firmwares don't provide ++_OSC support while they use PCI Express. To support such firmwares, ++forceload, a parameter of type bool, could enable AER to continue to ++be initiated although firmwares have no _OSC support. To enable the ++walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line ++when booting kernel. Note that forceload=n by default. ++ ++2.3 AER error output ++When a PCI-E AER error is captured, an error message will be outputed to ++console. If it's a correctable error, it is outputed as a warning. ++Otherwise, it is printed as an error. So users could choose different ++log level to filter out correctable error messages. ++ ++Below shows an example. +++------ PCI-Express Device Error -----+ ++Error Severity : Uncorrected (Fatal) ++PCIE Bus Error type : Transaction Layer ++Unsupported Request : First ++Requester ID : 0500 ++VendorID=8086h, DeviceID=0329h, Bus=05h, Device=00h, Function=00h ++TLB Header: ++04000001 00200a03 05010000 00050100 ++ ++In the example, 'Requester ID' means the ID of the device who sends ++the error message to root port. Pls. refer to pci express specs for ++other fields. ++ ++ ++3. Developer Guide ++ ++To enable AER aware support requires a software driver to configure ++the AER capability structure within its device and to provide callbacks. ++ ++To support AER better, developers need understand how AER does work ++firstly. ++ ++PCI Express errors are classified into two types: correctable errors ++and uncorrectable errors. This classification is based on the impacts ++of those errors, which may result in degraded performance or function ++failure. ++ ++Correctable errors pose no impacts on the functionality of the ++interface. The PCI Express protocol can recover without any software ++intervention or any loss of data. These errors are detected and ++corrected by hardware. Unlike correctable errors, uncorrectable ++errors impact functionality of the interface. Uncorrectable errors ++can cause a particular transaction or a particular PCI Express link ++to be unreliable. Depending on those error conditions, uncorrectable ++errors are further classified into non-fatal errors and fatal errors. ++Non-fatal errors cause the particular transaction to be unreliable, ++but the PCI Express link itself is fully functional. Fatal errors, on ++the other hand, cause the link to be unreliable. ++ ++When AER is enabled, a PCI Express device will automatically send an ++error message to the PCIE root port above it when the device captures ++an error. The Root Port, upon receiving an error reporting message, ++internally processes and logs the error message in its PCI Express ++capability structure. Error information being logged includes storing ++the error reporting agent's requestor ID into the Error Source ++Identification Registers and setting the error bits of the Root Error ++Status Register accordingly. If AER error reporting is enabled in Root ++Error Command Register, the Root Port generates an interrupt if an ++error is detected. ++ ++Note that the errors as described above are related to the PCI Express ++hierarchy and links. These errors do not include any device specific ++errors because device specific errors will still get sent directly to ++the device driver. ++ ++3.1 Configure the AER capability structure ++ ++AER aware drivers of PCI Express component need change the device ++control registers to enable AER. They also could change AER registers, ++including mask and severity registers. Helper function ++pci_enable_pcie_error_reporting could be used to enable AER. See ++section 3.3. ++ ++3.2. Provide callbacks ++ ++3.2.1 callback reset_link to reset pci express link ++ ++This callback is used to reset the pci express physical link when a ++fatal error happens. The root port aer service driver provides a ++default reset_link function, but different upstream ports might ++have different specifications to reset pci express link, so all ++upstream ports should provide their own reset_link functions. ++ ++In struct pcie_port_service_driver, a new pointer, reset_link, is ++added. ++ ++pci_ers_result_t (*reset_link) (struct pci_dev *dev); ++ ++Section 3.2.2.2 provides more detailed info on when to call ++reset_link. ++ ++3.2.2 PCI error-recovery callbacks ++ ++The PCI Express AER Root driver uses error callbacks to coordinate ++with downstream device drivers associated with a hierarchy in question ++when performing error recovery actions. ++ ++Data struct pci_driver has a pointer, err_handler, to point to ++pci_error_handlers who consists of a couple of callback function ++pointers. AER driver follows the rules defined in ++pci-error-recovery.txt except pci express specific parts (e.g. ++reset_link). Pls. refer to pci-error-recovery.txt for detailed ++definitions of the callbacks. ++ ++Below sections specify when to call the error callback functions. ++ ++3.2.2.1 Correctable errors ++ ++Correctable errors pose no impacts on the functionality of ++the interface. The PCI Express protocol can recover without any ++software intervention or any loss of data. These errors do not ++require any recovery actions. The AER driver clears the device's ++correctable error status register accordingly and logs these errors. ++ ++3.2.2.2 Non-correctable (non-fatal and fatal) errors ++ ++If an error message indicates a non-fatal error, performing link reset ++at upstream is not required. The AER driver calls error_detected(dev, ++pci_channel_io_normal) to all drivers associated within a hierarchy in ++question. for example, ++EndPoint<==>DownstreamPort B<==>UpstreamPort A<==>RootPort. ++If Upstream port A captures an AER error, the hierarchy consists of ++Downstream port B and EndPoint. ++ ++A driver may return PCI_ERS_RESULT_CAN_RECOVER, ++PCI_ERS_RESULT_DISCONNECT, or PCI_ERS_RESULT_NEED_RESET, depending on ++whether it can recover or the AER driver calls mmio_enabled as next. ++ ++If an error message indicates a fatal error, kernel will broadcast ++error_detected(dev, pci_channel_io_frozen) to all drivers within ++a hierarchy in question. Then, performing link reset at upstream is ++necessary. As different kinds of devices might use different approaches ++to reset link, AER port service driver is required to provide the ++function to reset link. Firstly, kernel looks for if the upstream ++component has an aer driver. If it has, kernel uses the reset_link ++callback of the aer driver. If the upstream component has no aer driver ++and the port is downstream port, we will use the aer driver of the ++root port who reports the AER error. As for upstream ports, ++they should provide their own aer service drivers with reset_link ++function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and ++reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes ++to mmio_enabled. ++ ++3.3 helper functions ++ ++3.3.1 int pci_find_aer_capability(struct pci_dev *dev); ++pci_find_aer_capability locates the PCI Express AER capability ++in the device configuration space. If the device doesn't support ++PCI-Express AER, the function returns 0. ++ ++3.3.2 int pci_enable_pcie_error_reporting(struct pci_dev *dev); ++pci_enable_pcie_error_reporting enables the device to send error ++messages to root port when an error is detected. Note that devices ++don't enable the error reporting by default, so device drivers need ++call this function to enable it. ++ ++3.3.3 int pci_disable_pcie_error_reporting(struct pci_dev *dev); ++pci_disable_pcie_error_reporting disables the device to send error ++messages to root port when an error is detected. ++ ++3.3.4 int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev); ++pci_cleanup_aer_uncorrect_error_status cleanups the uncorrectable ++error status register. ++ ++3.4 Frequent Asked Questions ++ ++Q: What happens if a PCI Express device driver does not provide an ++error recovery handler (pci_driver->err_handler is equal to NULL)? ++ ++A: The devices attached with the driver won't be recovered. If the ++error is fatal, kernel will print out warning messages. Please refer ++to section 3 for more information. ++ ++Q: What happens if an upstream port service driver does not provide ++callback reset_link? ++ ++A: Fatal error recovery will fail if the errors are reported by the ++upstream ports who are attached by the service driver. ++ ++Q: How does this infrastructure deal with driver that is not PCI ++Express aware? ++ ++A: This infrastructure calls the error callback functions of the ++driver when an error happens. But if the driver is not aware of ++PCI Express, the device might not report its own errors to root ++port. ++ ++Q: What modifications will that driver need to make it compatible ++with the PCI Express AER Root driver? ++ ++A: It could call the helper functions to enable AER in devices and ++cleanup uncorrectable status register. Pls. refer to section 3.3. ++ +--- a/Documentation/PCIEBUS-HOWTO.txt ++++ /dev/null +@@ -1,217 +0,0 @@ +- The PCI Express Port Bus Driver Guide HOWTO +- Tom L Nguyen tom.l.nguyen@intel.com +- 11/03/2004 +- +-1. About this guide +- +-This guide describes the basics of the PCI Express Port Bus driver +-and provides information on how to enable the service drivers to +-register/unregister with the PCI Express Port Bus Driver. +- +-2. Copyright 2004 Intel Corporation +- +-3. What is the PCI Express Port Bus Driver +- +-A PCI Express Port is a logical PCI-PCI Bridge structure. There +-are two types of PCI Express Port: the Root Port and the Switch +-Port. The Root Port originates a PCI Express link from a PCI Express +-Root Complex and the Switch Port connects PCI Express links to +-internal logical PCI buses. The Switch Port, which has its secondary +-bus representing the switch's internal routing logic, is called the +-switch's Upstream Port. The switch's Downstream Port is bridging from +-switch's internal routing bus to a bus representing the downstream +-PCI Express link from the PCI Express Switch. +- +-A PCI Express Port can provide up to four distinct functions, +-referred to in this document as services, depending on its port type. +-PCI Express Port's services include native hotplug support (HP), +-power management event support (PME), advanced error reporting +-support (AER), and virtual channel support (VC). These services may +-be handled by a single complex driver or be individually distributed +-and handled by corresponding service drivers. +- +-4. Why use the PCI Express Port Bus Driver? +- +-In existing Linux kernels, the Linux Device Driver Model allows a +-physical device to be handled by only a single driver. The PCI +-Express Port is a PCI-PCI Bridge device with multiple distinct +-services. To maintain a clean and simple solution each service +-may have its own software service driver. In this case several +-service drivers will compete for a single PCI-PCI Bridge device. +-For example, if the PCI Express Root Port native hotplug service +-driver is loaded first, it claims a PCI-PCI Bridge Root Port. The +-kernel therefore does not load other service drivers for that Root +-Port. In other words, it is impossible to have multiple service +-drivers load and run on a PCI-PCI Bridge device simultaneously +-using the current driver model. +- +-To enable multiple service drivers running simultaneously requires +-having a PCI Express Port Bus driver, which manages all populated +-PCI Express Ports and distributes all provided service requests +-to the corresponding service drivers as required. Some key +-advantages of using the PCI Express Port Bus driver are listed below: +- +- - Allow multiple service drivers to run simultaneously on +- a PCI-PCI Bridge Port device. +- +- - Allow service drivers implemented in an independent +- staged approach. +- +- - Allow one service driver to run on multiple PCI-PCI Bridge +- Port devices. +- +- - Manage and distribute resources of a PCI-PCI Bridge Port +- device to requested service drivers. +- +-5. Configuring the PCI Express Port Bus Driver vs. Service Drivers +- +-5.1 Including the PCI Express Port Bus Driver Support into the Kernel +- +-Including the PCI Express Port Bus driver depends on whether the PCI +-Express support is included in the kernel config. The kernel will +-automatically include the PCI Express Port Bus driver as a kernel +-driver when the PCI Express support is enabled in the kernel. +- +-5.2 Enabling Service Driver Support +- +-PCI device drivers are implemented based on Linux Device Driver Model. +-All service drivers are PCI device drivers. As discussed above, it is +-impossible to load any service driver once the kernel has loaded the +-PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver +-Model requires some minimal changes on existing service drivers that +-imposes no impact on the functionality of existing service drivers. +- +-A service driver is required to use the two APIs shown below to +-register its service with the PCI Express Port Bus driver (see +-section 5.2.1 & 5.2.2). It is important that a service driver +-initializes the pcie_port_service_driver data structure, included in +-header file /include/linux/pcieport_if.h, before calling these APIs. +-Failure to do so will result an identity mismatch, which prevents +-the PCI Express Port Bus driver from loading a service driver. +- +-5.2.1 pcie_port_service_register +- +-int pcie_port_service_register(struct pcie_port_service_driver *new) +- +-This API replaces the Linux Driver Model's pci_module_init API. A +-service driver should always calls pcie_port_service_register at +-module init. Note that after service driver being loaded, calls +-such as pci_enable_device(dev) and pci_set_master(dev) are no longer +-necessary since these calls are executed by the PCI Port Bus driver. +- +-5.2.2 pcie_port_service_unregister +- +-void pcie_port_service_unregister(struct pcie_port_service_driver *new) +- +-pcie_port_service_unregister replaces the Linux Driver Model's +-pci_unregister_driver. It's always called by service driver when a +-module exits. +- +-5.2.3 Sample Code +- +-Below is sample service driver code to initialize the port service +-driver data structure. +- +-static struct pcie_port_service_id service_id[] = { { +- .vendor = PCI_ANY_ID, +- .device = PCI_ANY_ID, +- .port_type = PCIE_RC_PORT, +- .service_type = PCIE_PORT_SERVICE_AER, +- }, { /* end: all zeroes */ } +-}; +- +-static struct pcie_port_service_driver root_aerdrv = { +- .name = (char *)device_name, +- .id_table = &service_id[0], +- +- .probe = aerdrv_load, +- .remove = aerdrv_unload, +- +- .suspend = aerdrv_suspend, +- .resume = aerdrv_resume, +-}; +- +-Below is a sample code for registering/unregistering a service +-driver. +- +-static int __init aerdrv_service_init(void) +-{ +- int retval = 0; +- +- retval = pcie_port_service_register(&root_aerdrv); +- if (!retval) { +- /* +- * FIX ME +- */ +- } +- return retval; +-} +- +-static void __exit aerdrv_service_exit(void) +-{ +- pcie_port_service_unregister(&root_aerdrv); +-} +- +-module_init(aerdrv_service_init); +-module_exit(aerdrv_service_exit); +- +-6. Possible Resource Conflicts +- +-Since all service drivers of a PCI-PCI Bridge Port device are +-allowed to run simultaneously, below lists a few of possible resource +-conflicts with proposed solutions. +- +-6.1 MSI Vector Resource +- +-The MSI capability structure enables a device software driver to call +-pci_enable_msi to request MSI based interrupts. Once MSI interrupts +-are enabled on a device, it stays in this mode until a device driver +-calls pci_disable_msi to disable MSI interrupts and revert back to +-INTx emulation mode. Since service drivers of the same PCI-PCI Bridge +-port share the same physical device, if an individual service driver +-calls pci_enable_msi/pci_disable_msi it may result unpredictable +-behavior. For example, two service drivers run simultaneously on the +-same physical Root Port. Both service drivers call pci_enable_msi to +-request MSI based interrupts. A service driver may not know whether +-any other service drivers have run on this Root Port. If either one +-of them calls pci_disable_msi, it puts the other service driver +-in a wrong interrupt mode. +- +-To avoid this situation all service drivers are not permitted to +-switch interrupt mode on its device. The PCI Express Port Bus driver +-is responsible for determining the interrupt mode and this should be +-transparent to service drivers. Service drivers need to know only +-the vector IRQ assigned to the field irq of struct pcie_device, which +-is passed in when the PCI Express Port Bus driver probes each service +-driver. Service drivers should use (struct pcie_device*)dev->irq to +-call request_irq/free_irq. In addition, the interrupt mode is stored +-in the field interrupt_mode of struct pcie_device. +- +-6.2 MSI-X Vector Resources +- +-Similar to the MSI a device driver for an MSI-X capable device can +-call pci_enable_msix to request MSI-X interrupts. All service drivers +-are not permitted to switch interrupt mode on its device. The PCI +-Express Port Bus driver is responsible for determining the interrupt +-mode and this should be transparent to service drivers. Any attempt +-by service driver to call pci_enable_msix/pci_disable_msix may +-result unpredictable behavior. Service drivers should use +-(struct pcie_device*)dev->irq and call request_irq/free_irq. +- +-6.3 PCI Memory/IO Mapped Regions +- +-Service drivers for PCI Express Power Management (PME), Advanced +-Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access +-PCI configuration space on the PCI Express port. In all cases the +-registers accessed are independent of each other. This patch assumes +-that all service drivers will be well behaved and not overwrite +-other service driver's configuration settings. +- +-6.4 PCI Config Registers +- +-Each service driver runs its PCI config operations on its own +-capability structure except the PCI Express capability structure, in +-which Root Control register and Device Control register are shared +-between PME and AER. This patch assumes that all service drivers +-will be well behaved and not overwrite other service driver's +-configuration settings. +--- a/Documentation/memory-barriers.txt ++++ b/Documentation/memory-barriers.txt +@@ -430,8 +430,8 @@ There are certain things that the Linux + + [*] For information on bus mastering DMA and coherency please read: + +- Documentation/pci.txt +- Documentation/DMA-mapping.txt ++ Documentation/PCI/pci.txt ++ Documentation/PCI/PCI-DMA-mapping.txt + Documentation/DMA-API.txt + + +--- a/Documentation/pci-error-recovery.txt ++++ /dev/null +@@ -1,396 +0,0 @@ +- +- PCI Error Recovery +- ------------------ +- February 2, 2006 +- +- Current document maintainer: +- Linas Vepstas <linas@austin.ibm.com> +- +- +-Many PCI bus controllers are able to detect a variety of hardware +-PCI errors on the bus, such as parity errors on the data and address +-busses, as well as SERR and PERR errors. Some of the more advanced +-chipsets are able to deal with these errors; these include PCI-E chipsets, +-and the PCI-host bridges found on IBM Power4 and Power5-based pSeries +-boxes. A typical action taken is to disconnect the affected device, +-halting all I/O to it. The goal of a disconnection is to avoid system +-corruption; for example, to halt system memory corruption due to DMA's +-to "wild" addresses. Typically, a reconnection mechanism is also +-offered, so that the affected PCI device(s) are reset and put back +-into working condition. The reset phase requires coordination +-between the affected device drivers and the PCI controller chip. +-This document describes a generic API for notifying device drivers +-of a bus disconnection, and then performing error recovery. +-This API is currently implemented in the 2.6.16 and later kernels. +- +-Reporting and recovery is performed in several steps. First, when +-a PCI hardware error has resulted in a bus disconnect, that event +-is reported as soon as possible to all affected device drivers, +-including multiple instances of a device driver on multi-function +-cards. This allows device drivers to avoid deadlocking in spinloops, +-waiting for some i/o-space register to change, when it never will. +-It also gives the drivers a chance to defer incoming I/O as +-needed. +- +-Next, recovery is performed in several stages. Most of the complexity +-is forced by the need to handle multi-function devices, that is, +-devices that have multiple device drivers associated with them. +-In the first stage, each driver is allowed to indicate what type +-of reset it desires, the choices being a simple re-enabling of I/O +-or requesting a hard reset (a full electrical #RST of the PCI card). +-If any driver requests a full reset, that is what will be done. +- +-After a full reset and/or a re-enabling of I/O, all drivers are +-again notified, so that they may then perform any device setup/config +-that may be required. After these have all completed, a final +-"resume normal operations" event is sent out. +- +-The biggest reason for choosing a kernel-based implementation rather +-than a user-space implementation was the need to deal with bus +-disconnects of PCI devices attached to storage media, and, in particular, +-disconnects from devices holding the root file system. If the root +-file system is disconnected, a user-space mechanism would have to go +-through a large number of contortions to complete recovery. Almost all +-of the current Linux file systems are not tolerant of disconnection +-from/reconnection to their underlying block device. By contrast, +-bus errors are easy to manage in the device driver. Indeed, most +-device drivers already handle very similar recovery procedures; +-for example, the SCSI-generic layer already provides significant +-mechanisms for dealing with SCSI bus errors and SCSI bus resets. +- +- +-Detailed Design +---------------- +-Design and implementation details below, based on a chain of +-public email discussions with Ben Herrenschmidt, circa 5 April 2005. +- +-The error recovery API support is exposed to the driver in the form of +-a structure of function pointers pointed to by a new field in struct +-pci_driver. A driver that fails to provide the structure is "non-aware", +-and the actual recovery steps taken are platform dependent. The +-arch/powerpc implementation will simulate a PCI hotplug remove/add. +- +-This structure has the form: +-struct pci_error_handlers +-{ +- int (*error_detected)(struct pci_dev *dev, enum pci_channel_state); +- int (*mmio_enabled)(struct pci_dev *dev); +- int (*link_reset)(struct pci_dev *dev); +- int (*slot_reset)(struct pci_dev *dev); +- void (*resume)(struct pci_dev *dev); +-}; +- +-The possible channel states are: +-enum pci_channel_state { +- pci_channel_io_normal, /* I/O channel is in normal state */ +- pci_channel_io_frozen, /* I/O to channel is blocked */ +- pci_channel_io_perm_failure, /* PCI card is dead */ +-}; +- +-Possible return values are: +-enum pci_ers_result { +- PCI_ERS_RESULT_NONE, /* no result/none/not supported in device driver */ +- PCI_ERS_RESULT_CAN_RECOVER, /* Device driver can recover without slot reset */ +- PCI_ERS_RESULT_NEED_RESET, /* Device driver wants slot to be reset. */ +- PCI_ERS_RESULT_DISCONNECT, /* Device has completely failed, is unrecoverable */ +- PCI_ERS_RESULT_RECOVERED, /* Device driver is fully recovered and operational */ +-}; +- +-A driver does not have to implement all of these callbacks; however, +-if it implements any, it must implement error_detected(). If a callback +-is not implemented, the corresponding feature is considered unsupported. +-For example, if mmio_enabled() and resume() aren't there, then it +-is assumed that the driver is not doing any direct recovery and requires +-a reset. If link_reset() is not implemented, the card is assumed as +-not care about link resets. Typically a driver will want to know about +-a slot_reset(). +- +-The actual steps taken by a platform to recover from a PCI error +-event will be platform-dependent, but will follow the general +-sequence described below. +- +-STEP 0: Error Event +-------------------- +-PCI bus error is detect by the PCI hardware. On powerpc, the slot +-is isolated, in that all I/O is blocked: all reads return 0xffffffff, +-all writes are ignored. +- +- +-STEP 1: Notification +--------------------- +-Platform calls the error_detected() callback on every instance of +-every driver affected by the error. +- +-At this point, the device might not be accessible anymore, depending on +-the platform (the slot will be isolated on powerpc). The driver may +-already have "noticed" the error because of a failing I/O, but this +-is the proper "synchronization point", that is, it gives the driver +-a chance to cleanup, waiting for pending stuff (timers, whatever, etc...) +-to complete; it can take semaphores, schedule, etc... everything but +-touch the device. Within this function and after it returns, the driver +-shouldn't do any new IOs. Called in task context. This is sort of a +-"quiesce" point. See note about interrupts at the end of this doc. +- +-All drivers participating in this system must implement this call. +-The driver must return one of the following result codes: +- - PCI_ERS_RESULT_CAN_RECOVER: +- Driver returns this if it thinks it might be able to recover +- the HW by just banging IOs or if it wants to be given +- a chance to extract some diagnostic information (see +- mmio_enable, below). +- - PCI_ERS_RESULT_NEED_RESET: +- Driver returns this if it can't recover without a hard +- slot reset. +- - PCI_ERS_RESULT_DISCONNECT: +- Driver returns this if it doesn't want to recover at all. +- +-The next step taken will depend on the result codes returned by the +-drivers. +- +-If all drivers on the segment/slot return PCI_ERS_RESULT_CAN_RECOVER, +-then the platform should re-enable IOs on the slot (or do nothing in +-particular, if the platform doesn't isolate slots), and recovery +-proceeds to STEP 2 (MMIO Enable). +- +-If any driver requested a slot reset (by returning PCI_ERS_RESULT_NEED_RESET), +-then recovery proceeds to STEP 4 (Slot Reset). +- +-If the platform is unable to recover the slot, the next step +-is STEP 6 (Permanent Failure). +- +->>> The current powerpc implementation assumes that a device driver will +->>> *not* schedule or semaphore in this routine; the current powerpc +->>> implementation uses one kernel thread to notify all devices; +->>> thus, if one device sleeps/schedules, all devices are affected. +->>> Doing better requires complex multi-threaded logic in the error +->>> recovery implementation (e.g. waiting for all notification threads +->>> to "join" before proceeding with recovery.) This seems excessively +->>> complex and not worth implementing. +- +->>> The current powerpc implementation doesn't much care if the device +->>> attempts I/O at this point, or not. I/O's will fail, returning +->>> a value of 0xff on read, and writes will be dropped. If the device +->>> driver attempts more than 10K I/O's to a frozen adapter, it will +->>> assume that the device driver has gone into an infinite loop, and +->>> it will panic the kernel. There doesn't seem to be any other +->>> way of stopping a device driver that insists on spinning on I/O. +- +-STEP 2: MMIO Enabled +-------------------- +-The platform re-enables MMIO to the device (but typically not the +-DMA), and then calls the mmio_enabled() callback on all affected +-device drivers. +- +-This is the "early recovery" call. IOs are allowed again, but DMA is +-not (hrm... to be discussed, I prefer not), with some restrictions. This +-is NOT a callback for the driver to start operations again, only to +-peek/poke at the device, extract diagnostic information, if any, and +-eventually do things like trigger a device local reset or some such, +-but not restart operations. This is callback is made if all drivers on +-a segment agree that they can try to recover and if no automatic link reset +-was performed by the HW. If the platform can't just re-enable IOs without +-a slot reset or a link reset, it wont call this callback, and instead +-will have gone directly to STEP 3 (Link Reset) or STEP 4 (Slot Reset) +- +->>> The following is proposed; no platform implements this yet: +->>> Proposal: All I/O's should be done _synchronously_ from within +->>> this callback, errors triggered by them will be returned via +->>> the normal pci_check_whatever() API, no new error_detected() +->>> callback will be issued due to an error happening here. However, +->>> such an error might cause IOs to be re-blocked for the whole +->>> segment, and thus invalidate the recovery that other devices +->>> on the same segment might have done, forcing the whole segment +->>> into one of the next states, that is, link reset or slot reset. +- +-The driver should return one of the following result codes: +- - PCI_ERS_RESULT_RECOVERED +- Driver returns this if it thinks the device is fully +- functional and thinks it is ready to start +- normal driver operations again. There is no +- guarantee that the driver will actually be +- allowed to proceed, as another driver on the +- same segment might have failed and thus triggered a +- slot reset on platforms that support it. +- +- - PCI_ERS_RESULT_NEED_RESET +- Driver returns this if it thinks the device is not +- recoverable in it's current state and it needs a slot +- reset to proceed. +- +- - PCI_ERS_RESULT_DISCONNECT +- Same as above. Total failure, no recovery even after +- reset driver dead. (To be defined more precisely) +- +-The next step taken depends on the results returned by the drivers. +-If all drivers returned PCI_ERS_RESULT_RECOVERED, then the platform +-proceeds to either STEP3 (Link Reset) or to STEP 5 (Resume Operations). +- +-If any driver returned PCI_ERS_RESULT_NEED_RESET, then the platform +-proceeds to STEP 4 (Slot Reset) +- +->>> The current powerpc implementation does not implement this callback. +- +- +-STEP 3: Link Reset +------------------- +-The platform resets the link, and then calls the link_reset() callback +-on all affected device drivers. This is a PCI-Express specific state +-and is done whenever a non-fatal error has been detected that can be +-"solved" by resetting the link. This call informs the driver of the +-reset and the driver should check to see if the device appears to be +-in working condition. +- +-The driver is not supposed to restart normal driver I/O operations +-at this point. It should limit itself to "probing" the device to +-check it's recoverability status. If all is right, then the platform +-will call resume() once all drivers have ack'd link_reset(). +- +- Result codes: +- (identical to STEP 3 (MMIO Enabled) +- +-The platform then proceeds to either STEP 4 (Slot Reset) or STEP 5 +-(Resume Operations). +- +->>> The current powerpc implementation does not implement this callback. +- +- +-STEP 4: Slot Reset +------------------- +-The platform performs a soft or hard reset of the device, and then +-calls the slot_reset() callback. +- +-A soft reset consists of asserting the adapter #RST line and then +-restoring the PCI BAR's and PCI configuration header to a state +-that is equivalent to what it would be after a fresh system +-power-on followed by power-on BIOS/system firmware initialization. +-If the platform supports PCI hotplug, then the reset might be +-performed by toggling the slot electrical power off/on. +- +-It is important for the platform to restore the PCI config space +-to the "fresh poweron" state, rather than the "last state". After +-a slot reset, the device driver will almost always use its standard +-device initialization routines, and an unusual config space setup +-may result in hung devices, kernel panics, or silent data corruption. +- +-This call gives drivers the chance to re-initialize the hardware +-(re-download firmware, etc.). At this point, the driver may assume +-that he card is in a fresh state and is fully functional. In +-particular, interrupt generation should work normally. +- +-Drivers should not yet restart normal I/O processing operations +-at this point. If all device drivers report success on this +-callback, the platform will call resume() to complete the sequence, +-and let the driver restart normal I/O processing. +- +-A driver can still return a critical failure for this function if +-it can't get the device operational after reset. If the platform +-previously tried a soft reset, it might now try a hard reset (power +-cycle) and then call slot_reset() again. It the device still can't +-be recovered, there is nothing more that can be done; the platform +-will typically report a "permanent failure" in such a case. The +-device will be considered "dead" in this case. +- +-Drivers for multi-function cards will need to coordinate among +-themselves as to which driver instance will perform any "one-shot" +-or global device initialization. For example, the Symbios sym53cxx2 +-driver performs device init only from PCI function 0: +- +-+ if (PCI_FUNC(pdev->devfn) == 0) +-+ sym_reset_scsi_bus(np, 0); +- +- Result codes: +- - PCI_ERS_RESULT_DISCONNECT +- Same as above. +- +-Platform proceeds either to STEP 5 (Resume Operations) or STEP 6 (Permanent +-Failure). +- +->>> The current powerpc implementation does not currently try a +->>> power-cycle reset if the driver returned PCI_ERS_RESULT_DISCONNECT. +->>> However, it probably should. +- +- +-STEP 5: Resume Operations +-------------------------- +-The platform will call the resume() callback on all affected device +-drivers if all drivers on the segment have returned +-PCI_ERS_RESULT_RECOVERED from one of the 3 previous callbacks. +-The goal of this callback is to tell the driver to restart activity, +-that everything is back and running. This callback does not return +-a result code. +- +-At this point, if a new error happens, the platform will restart +-a new error recovery sequence. +- +-STEP 6: Permanent Failure +-------------------------- +-A "permanent failure" has occurred, and the platform cannot recover +-the device. The platform will call error_detected() with a +-pci_channel_state value of pci_channel_io_perm_failure. +- +-The device driver should, at this point, assume the worst. It should +-cancel all pending I/O, refuse all new I/O, returning -EIO to +-higher layers. The device driver should then clean up all of its +-memory and remove itself from kernel operations, much as it would +-during system shutdown. +- +-The platform will typically notify the system operator of the +-permanent failure in some way. If the device is hotplug-capable, +-the operator will probably want to remove and replace the device. +-Note, however, not all failures are truly "permanent". Some are +-caused by over-heating, some by a poorly seated card. Many +-PCI error events are caused by software bugs, e.g. DMA's to +-wild addresses or bogus split transactions due to programming +-errors. See the discussion in powerpc/eeh-pci-error-recovery.txt +-for additional detail on real-life experience of the causes of +-software errors. +- +- +-Conclusion; General Remarks +---------------------------- +-The way those callbacks are called is platform policy. A platform with +-no slot reset capability may want to just "ignore" drivers that can't +-recover (disconnect them) and try to let other cards on the same segment +-recover. Keep in mind that in most real life cases, though, there will +-be only one driver per segment. +- +-Now, a note about interrupts. If you get an interrupt and your +-device is dead or has been isolated, there is a problem :) +-The current policy is to turn this into a platform policy. +-That is, the recovery API only requires that: +- +- - There is no guarantee that interrupt delivery can proceed from any +-device on the segment starting from the error detection and until the +-resume callback is sent, at which point interrupts are expected to be +-fully operational. +- +- - There is no guarantee that interrupt delivery is stopped, that is, +-a driver that gets an interrupt after detecting an error, or that detects +-an error within the interrupt handler such that it prevents proper +-ack'ing of the interrupt (and thus removal of the source) should just +-return IRQ_NOTHANDLED. It's up to the platform to deal with that +-condition, typically by masking the IRQ source during the duration of +-the error handling. It is expected that the platform "knows" which +-interrupts are routed to error-management capable slots and can deal +-with temporarily disabling that IRQ number during error processing (this +-isn't terribly complex). That means some IRQ latency for other devices +-sharing the interrupt, but there is simply no other way. High end +-platforms aren't supposed to share interrupts between many devices +-anyway :) +- +->>> Implementation details for the powerpc platform are discussed in +->>> the file Documentation/powerpc/eeh-pci-error-recovery.txt +- +->>> As of this writing, there are six device drivers with patches +->>> implementing error recovery. Not all of these patches are in +->>> mainline yet. These may be used as "examples": +->>> +->>> drivers/scsi/ipr.c +->>> drivers/scsi/sym53cxx_2 +->>> drivers/next/e100.c +->>> drivers/net/e1000 +->>> drivers/net/ixgb +->>> drivers/net/s2io.c +- +-The End +-------- +--- a/Documentation/pci.txt ++++ /dev/null +@@ -1,646 +0,0 @@ +- +- How To Write Linux PCI Drivers +- +- by Martin Mares <mj@ucw.cz> on 07-Feb-2000 +- updated by Grant Grundler <grundler@parisc-linux.org> on 23-Dec-2006 +- +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-The world of PCI is vast and full of (mostly unpleasant) surprises. +-Since each CPU architecture implements different chip-sets and PCI devices +-have different requirements (erm, "features"), the result is the PCI support +-in the Linux kernel is not as trivial as one would wish. This short paper +-tries to introduce all potential driver authors to Linux APIs for +-PCI device drivers. +- +-A more complete resource is the third edition of "Linux Device Drivers" +-by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman. +-LDD3 is available for free (under Creative Commons License) from: +- +- http://lwn.net/Kernel/LDD3/ +- +-However, keep in mind that all documents are subject to "bit rot". +-Refer to the source code if things are not working as described here. +- +-Please send questions/comments/patches about Linux PCI API to the +-"Linux PCI" <linux-pci@atrey.karlin.mff.cuni.cz> mailing list. +- +- +- +-0. Structure of PCI drivers +-~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-PCI drivers "discover" PCI devices in a system via pci_register_driver(). +-Actually, it's the other way around. When the PCI generic code discovers +-a new device, the driver with a matching "description" will be notified. +-Details on this below. +- +-pci_register_driver() leaves most of the probing for devices to +-the PCI layer and supports online insertion/removal of devices [thus +-supporting hot-pluggable PCI, CardBus, and Express-Card in a single driver]. +-pci_register_driver() call requires passing in a table of function +-pointers and thus dictates the high level structure of a driver. +- +-Once the driver knows about a PCI device and takes ownership, the +-driver generally needs to perform the following initialization: +- +- Enable the device +- Request MMIO/IOP resources +- Set the DMA mask size (for both coherent and streaming DMA) +- Allocate and initialize shared control data (pci_allocate_coherent()) +- Access device configuration space (if needed) +- Register IRQ handler (request_irq()) +- Initialize non-PCI (i.e. LAN/SCSI/etc parts of the chip) +- Enable DMA/processing engines +- +-When done using the device, and perhaps the module needs to be unloaded, +-the driver needs to take the follow steps: +- Disable the device from generating IRQs +- Release the IRQ (free_irq()) +- Stop all DMA activity +- Release DMA buffers (both streaming and coherent) +- Unregister from other subsystems (e.g. scsi or netdev) +- Release MMIO/IOP resources +- Disable the device +- +-Most of these topics are covered in the following sections. +-For the rest look at LDD3 or <linux/pci.h> . +- +-If the PCI subsystem is not configured (CONFIG_PCI is not set), most of +-the PCI functions described below are defined as inline functions either +-completely empty or just returning an appropriate error codes to avoid +-lots of ifdefs in the drivers. +- +- +- +-1. pci_register_driver() call +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-PCI device drivers call pci_register_driver() during their +-initialization with a pointer to a structure describing the driver +-(struct pci_driver): +- +- field name Description +- ---------- ------------------------------------------------------ +- id_table Pointer to table of device ID's the driver is +- interested in. Most drivers should export this +- table using MODULE_DEVICE_TABLE(pci,...). +- +- probe This probing function gets called (during execution +- of pci_register_driver() for already existing +- devices or later if a new device gets inserted) for +- all PCI devices which match the ID table and are not +- "owned" by the other drivers yet. This function gets +- passed a "struct pci_dev *" for each device whose +- entry in the ID table matches the device. The probe +- function returns zero when the driver chooses to +- take "ownership" of the device or an error code +- (negative number) otherwise. +- The probe function always gets called from process +- context, so it can sleep. +- +- remove The remove() function gets called whenever a device +- being handled by this driver is removed (either during +- deregistration of the driver or when it's manually +- pulled out of a hot-pluggable slot). +- The remove function always gets called from process +- context, so it can sleep. +- +- suspend Put device into low power state. +- suspend_late Put device into low power state. +- +- resume_early Wake device from low power state. +- resume Wake device from low power state. +- +- (Please see Documentation/power/pci.txt for descriptions +- of PCI Power Management and the related functions.) +- +- shutdown Hook into reboot_notifier_list (kernel/sys.c). +- Intended to stop any idling DMA operations. +- Useful for enabling wake-on-lan (NIC) or changing +- the power state of a device before reboot. +- e.g. drivers/net/e100.c. +- +- err_handler See Documentation/pci-error-recovery.txt +- +- +-The ID table is an array of struct pci_device_id entries ending with an +-all-zero entry; use of the macro DEFINE_PCI_DEVICE_TABLE is the preferred +-method of declaring the table. Each entry consists of: +- +- vendor,device Vendor and device ID to match (or PCI_ANY_ID) +- +- subvendor, Subsystem vendor and device ID to match (or PCI_ANY_ID) +- subdevice, +- +- class Device class, subclass, and "interface" to match. +- See Appendix D of the PCI Local Bus Spec or +- include/linux/pci_ids.h for a full list of classes. +- Most drivers do not need to specify class/class_mask +- as vendor/device is normally sufficient. +- +- class_mask limit which sub-fields of the class field are compared. +- See drivers/scsi/sym53c8xx_2/ for example of usage. +- +- driver_data Data private to the driver. +- Most drivers don't need to use driver_data field. +- Best practice is to use driver_data as an index +- into a static list of equivalent device types, +- instead of using it as a pointer. +- +- +-Most drivers only need PCI_DEVICE() or PCI_DEVICE_CLASS() to set up +-a pci_device_id table. +- +-New PCI IDs may be added to a device driver pci_ids table at runtime +-as shown below: +- +-echo "vendor device subvendor subdevice class class_mask driver_data" > \ +-/sys/bus/pci/drivers/{driver}/new_id +- +-All fields are passed in as hexadecimal values (no leading 0x). +-The vendor and device fields are mandatory, the others are optional. Users +-need pass only as many optional fields as necessary: +- o subvendor and subdevice fields default to PCI_ANY_ID (FFFFFFFF) +- o class and classmask fields default to 0 +- o driver_data defaults to 0UL. +- +-Once added, the driver probe routine will be invoked for any unclaimed +-PCI devices listed in its (newly updated) pci_ids list. +- +-When the driver exits, it just calls pci_unregister_driver() and the PCI layer +-automatically calls the remove hook for all devices handled by the driver. +- +- +-1.1 "Attributes" for driver functions/data +- +-Please mark the initialization and cleanup functions where appropriate +-(the corresponding macros are defined in <linux/init.h>): +- +- __init Initialization code. Thrown away after the driver +- initializes. +- __exit Exit code. Ignored for non-modular drivers. +- +- +- __devinit Device initialization code. +- Identical to __init if the kernel is not compiled +- with CONFIG_HOTPLUG, normal function otherwise. +- __devexit The same for __exit. +- +-Tips on when/where to use the above attributes: +- o The module_init()/module_exit() functions (and all +- initialization functions called _only_ from these) +- should be marked __init/__exit. +- +- o Do not mark the struct pci_driver. +- +- o The ID table array should be marked __devinitconst; this is done +- automatically if the table is declared with DEFINE_PCI_DEVICE_TABLE(). +- +- o The probe() and remove() functions should be marked __devinit +- and __devexit respectively. All initialization functions +- exclusively called by the probe() routine, can be marked __devinit. +- Ditto for remove() and __devexit. +- +- o If mydriver_remove() is marked with __devexit(), then all address +- references to mydriver_remove must use __devexit_p(mydriver_remove) +- (in the struct pci_driver declaration for example). +- __devexit_p() will generate the function name _or_ NULL if the +- function will be discarded. For an example, see drivers/net/tg3.c. +- +- o Do NOT mark a function if you are not sure which mark to use. +- Better to not mark the function than mark the function wrong. +- +- +- +-2. How to find PCI devices manually +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-PCI drivers should have a really good reason for not using the +-pci_register_driver() interface to search for PCI devices. +-The main reason PCI devices are controlled by multiple drivers +-is because one PCI device implements several different HW services. +-E.g. combined serial/parallel port/floppy controller. +- +-A manual search may be performed using the following constructs: +- +-Searching by vendor and device ID: +- +- struct pci_dev *dev = NULL; +- while (dev = pci_get_device(VENDOR_ID, DEVICE_ID, dev)) +- configure_device(dev); +- +-Searching by class ID (iterate in a similar way): +- +- pci_get_class(CLASS_ID, dev) +- +-Searching by both vendor/device and subsystem vendor/device ID: +- +- pci_get_subsys(VENDOR_ID,DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev). +- +-You can use the constant PCI_ANY_ID as a wildcard replacement for +-VENDOR_ID or DEVICE_ID. This allows searching for any device from a +-specific vendor, for example. +- +-These functions are hotplug-safe. They increment the reference count on +-the pci_dev that they return. You must eventually (possibly at module unload) +-decrement the reference count on these devices by calling pci_dev_put(). +- +- +- +-3. Device Initialization Steps +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-As noted in the introduction, most PCI drivers need the following steps +-for device initialization: +- +- Enable the device +- Request MMIO/IOP resources +- Set the DMA mask size (for both coherent and streaming DMA) +- Allocate and initialize shared control data (pci_allocate_coherent()) +- Access device configuration space (if needed) +- Register IRQ handler (request_irq()) +- Initialize non-PCI (i.e. LAN/SCSI/etc parts of the chip) +- Enable DMA/processing engines. +- +-The driver can access PCI config space registers at any time. +-(Well, almost. When running BIST, config space can go away...but +-that will just result in a PCI Bus Master Abort and config reads +-will return garbage). +- +- +-3.1 Enable the PCI device +-~~~~~~~~~~~~~~~~~~~~~~~~~ +-Before touching any device registers, the driver needs to enable +-the PCI device by calling pci_enable_device(). This will: +- o wake up the device if it was in suspended state, +- o allocate I/O and memory regions of the device (if BIOS did not), +- o allocate an IRQ (if BIOS did not). +- +-NOTE: pci_enable_device() can fail! Check the return value. +- +-[ OS BUG: we don't check resource allocations before enabling those +- resources. The sequence would make more sense if we called +- pci_request_resources() before calling pci_enable_device(). +- Currently, the device drivers can't detect the bug when when two +- devices have been allocated the same range. This is not a common +- problem and unlikely to get fixed soon. +- +- This has been discussed before but not changed as of 2.6.19: +- http://lkml.org/lkml/2006/3/2/194 +-] +- +-pci_set_master() will enable DMA by setting the bus master bit +-in the PCI_COMMAND register. It also fixes the latency timer value if +-it's set to something bogus by the BIOS. +- +-If the PCI device can use the PCI Memory-Write-Invalidate transaction, +-call pci_set_mwi(). This enables the PCI_COMMAND bit for Mem-Wr-Inval +-and also ensures that the cache line size register is set correctly. +-Check the return value of pci_set_mwi() as not all architectures +-or chip-sets may support Memory-Write-Invalidate. Alternatively, +-if Mem-Wr-Inval would be nice to have but is not required, call +-pci_try_set_mwi() to have the system do its best effort at enabling +-Mem-Wr-Inval. +- +- +-3.2 Request MMIO/IOP resources +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-Memory (MMIO), and I/O port addresses should NOT be read directly +-from the PCI device config space. Use the values in the pci_dev structure +-as the PCI "bus address" might have been remapped to a "host physical" +-address by the arch/chip-set specific kernel support. +- +-See Documentation/IO-mapping.txt for how to access device registers +-or device memory. +- +-The device driver needs to call pci_request_region() to verify +-no other device is already using the same address resource. +-Conversely, drivers should call pci_release_region() AFTER +-calling pci_disable_device(). +-The idea is to prevent two devices colliding on the same address range. +- +-[ See OS BUG comment above. Currently (2.6.19), The driver can only +- determine MMIO and IO Port resource availability _after_ calling +- pci_enable_device(). ] +- +-Generic flavors of pci_request_region() are request_mem_region() +-(for MMIO ranges) and request_region() (for IO Port ranges). +-Use these for address resources that are not described by "normal" PCI +-BARs. +- +-Also see pci_request_selected_regions() below. +- +- +-3.3 Set the DMA mask size +-~~~~~~~~~~~~~~~~~~~~~~~~~ +-[ If anything below doesn't make sense, please refer to +- Documentation/DMA-API.txt. This section is just a reminder that +- drivers need to indicate DMA capabilities of the device and is not +- an authoritative source for DMA interfaces. ] +- +-While all drivers should explicitly indicate the DMA capability +-(e.g. 32 or 64 bit) of the PCI bus master, devices with more than +-32-bit bus master capability for streaming data need the driver +-to "register" this capability by calling pci_set_dma_mask() with +-appropriate parameters. In general this allows more efficient DMA +-on systems where System RAM exists above 4G _physical_ address. +- +-Drivers for all PCI-X and PCIe compliant devices must call +-pci_set_dma_mask() as they are 64-bit DMA devices. +- +-Similarly, drivers must also "register" this capability if the device +-can directly address "consistent memory" in System RAM above 4G physical +-address by calling pci_set_consistent_dma_mask(). +-Again, this includes drivers for all PCI-X and PCIe compliant devices. +-Many 64-bit "PCI" devices (before PCI-X) and some PCI-X devices are +-64-bit DMA capable for payload ("streaming") data but not control +-("consistent") data. +- +- +-3.4 Setup shared control data +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-Once the DMA masks are set, the driver can allocate "consistent" (a.k.a. shared) +-memory. See Documentation/DMA-API.txt for a full description of +-the DMA APIs. This section is just a reminder that it needs to be done +-before enabling DMA on the device. +- +- +-3.5 Initialize device registers +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-Some drivers will need specific "capability" fields programmed +-or other "vendor specific" register initialized or reset. +-E.g. clearing pending interrupts. +- +- +-3.6 Register IRQ handler +-~~~~~~~~~~~~~~~~~~~~~~~~ +-While calling request_irq() is the last step described here, +-this is often just another intermediate step to initialize a device. +-This step can often be deferred until the device is opened for use. +- +-All interrupt handlers for IRQ lines should be registered with IRQF_SHARED +-and use the devid to map IRQs to devices (remember that all PCI IRQ lines +-can be shared). +- +-request_irq() will associate an interrupt handler and device handle +-with an interrupt number. Historically interrupt numbers represent +-IRQ lines which run from the PCI device to the Interrupt controller. +-With MSI and MSI-X (more below) the interrupt number is a CPU "vector". +- +-request_irq() also enables the interrupt. Make sure the device is +-quiesced and does not have any interrupts pending before registering +-the interrupt handler. +- +-MSI and MSI-X are PCI capabilities. Both are "Message Signaled Interrupts" +-which deliver interrupts to the CPU via a DMA write to a Local APIC. +-The fundamental difference between MSI and MSI-X is how multiple +-"vectors" get allocated. MSI requires contiguous blocks of vectors +-while MSI-X can allocate several individual ones. +- +-MSI capability can be enabled by calling pci_enable_msi() or +-pci_enable_msix() before calling request_irq(). This causes +-the PCI support to program CPU vector data into the PCI device +-capability registers. +- +-If your PCI device supports both, try to enable MSI-X first. +-Only one can be enabled at a time. Many architectures, chip-sets, +-or BIOSes do NOT support MSI or MSI-X and the call to pci_enable_msi/msix +-will fail. This is important to note since many drivers have +-two (or more) interrupt handlers: one for MSI/MSI-X and another for IRQs. +-They choose which handler to register with request_irq() based on the +-return value from pci_enable_msi/msix(). +- +-There are (at least) two really good reasons for using MSI: +-1) MSI is an exclusive interrupt vector by definition. +- This means the interrupt handler doesn't have to verify +- its device caused the interrupt. +- +-2) MSI avoids DMA/IRQ race conditions. DMA to host memory is guaranteed +- to be visible to the host CPU(s) when the MSI is delivered. This +- is important for both data coherency and avoiding stale control data. +- This guarantee allows the driver to omit MMIO reads to flush +- the DMA stream. +- +-See drivers/infiniband/hw/mthca/ or drivers/net/tg3.c for examples +-of MSI/MSI-X usage. +- +- +- +-4. PCI device shutdown +-~~~~~~~~~~~~~~~~~~~~~~~ +- +-When a PCI device driver is being unloaded, most of the following +-steps need to be performed: +- +- Disable the device from generating IRQs +- Release the IRQ (free_irq()) +- Stop all DMA activity +- Release DMA buffers (both streaming and consistent) +- Unregister from other subsystems (e.g. scsi or netdev) +- Disable device from responding to MMIO/IO Port addresses +- Release MMIO/IO Port resource(s) +- +- +-4.1 Stop IRQs on the device +-~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-How to do this is chip/device specific. If it's not done, it opens +-the possibility of a "screaming interrupt" if (and only if) +-the IRQ is shared with another device. +- +-When the shared IRQ handler is "unhooked", the remaining devices +-using the same IRQ line will still need the IRQ enabled. Thus if the +-"unhooked" device asserts IRQ line, the system will respond assuming +-it was one of the remaining devices asserted the IRQ line. Since none +-of the other devices will handle the IRQ, the system will "hang" until +-it decides the IRQ isn't going to get handled and masks the IRQ (100,000 +-iterations later). Once the shared IRQ is masked, the remaining devices +-will stop functioning properly. Not a nice situation. +- +-This is another reason to use MSI or MSI-X if it's available. +-MSI and MSI-X are defined to be exclusive interrupts and thus +-are not susceptible to the "screaming interrupt" problem. +- +- +-4.2 Release the IRQ +-~~~~~~~~~~~~~~~~~~~ +-Once the device is quiesced (no more IRQs), one can call free_irq(). +-This function will return control once any pending IRQs are handled, +-"unhook" the drivers IRQ handler from that IRQ, and finally release +-the IRQ if no one else is using it. +- +- +-4.3 Stop all DMA activity +-~~~~~~~~~~~~~~~~~~~~~~~~~ +-It's extremely important to stop all DMA operations BEFORE attempting +-to deallocate DMA control data. Failure to do so can result in memory +-corruption, hangs, and on some chip-sets a hard crash. +- +-Stopping DMA after stopping the IRQs can avoid races where the +-IRQ handler might restart DMA engines. +- +-While this step sounds obvious and trivial, several "mature" drivers +-didn't get this step right in the past. +- +- +-4.4 Release DMA buffers +-~~~~~~~~~~~~~~~~~~~~~~~ +-Once DMA is stopped, clean up streaming DMA first. +-I.e. unmap data buffers and return buffers to "upstream" +-owners if there is one. +- +-Then clean up "consistent" buffers which contain the control data. +- +-See Documentation/DMA-API.txt for details on unmapping interfaces. +- +- +-4.5 Unregister from other subsystems +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-Most low level PCI device drivers support some other subsystem +-like USB, ALSA, SCSI, NetDev, Infiniband, etc. Make sure your +-driver isn't losing resources from that other subsystem. +-If this happens, typically the symptom is an Oops (panic) when +-the subsystem attempts to call into a driver that has been unloaded. +- +- +-4.6 Disable Device from responding to MMIO/IO Port addresses +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-io_unmap() MMIO or IO Port resources and then call pci_disable_device(). +-This is the symmetric opposite of pci_enable_device(). +-Do not access device registers after calling pci_disable_device(). +- +- +-4.7 Release MMIO/IO Port Resource(s) +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-Call pci_release_region() to mark the MMIO or IO Port range as available. +-Failure to do so usually results in the inability to reload the driver. +- +- +- +-5. How to access PCI config space +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-You can use pci_(read|write)_config_(byte|word|dword) to access the config +-space of a device represented by struct pci_dev *. All these functions return 0 +-when successful or an error code (PCIBIOS_...) which can be translated to a text +-string by pcibios_strerror. Most drivers expect that accesses to valid PCI +-devices don't fail. +- +-If you don't have a struct pci_dev available, you can call +-pci_bus_(read|write)_config_(byte|word|dword) to access a given device +-and function on that bus. +- +-If you access fields in the standard portion of the config header, please +-use symbolic names of locations and bits declared in <linux/pci.h>. +- +-If you need to access Extended PCI Capability registers, just call +-pci_find_capability() for the particular capability and it will find the +-corresponding register block for you. +- +- +- +-6. Other interesting functions +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-pci_find_slot() Find pci_dev corresponding to given bus and +- slot numbers. +-pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3) +-pci_find_capability() Find specified capability in device's capability +- list. +-pci_resource_start() Returns bus start address for a given PCI region +-pci_resource_end() Returns bus end address for a given PCI region +-pci_resource_len() Returns the byte length of a PCI region +-pci_set_drvdata() Set private driver data pointer for a pci_dev +-pci_get_drvdata() Return private driver data pointer for a pci_dev +-pci_set_mwi() Enable Memory-Write-Invalidate transactions. +-pci_clear_mwi() Disable Memory-Write-Invalidate transactions. +- +- +- +-7. Miscellaneous hints +-~~~~~~~~~~~~~~~~~~~~~~ +- +-When displaying PCI device names to the user (for example when a driver wants +-to tell the user what card has it found), please use pci_name(pci_dev). +- +-Always refer to the PCI devices by a pointer to the pci_dev structure. +-All PCI layer functions use this identification and it's the only +-reasonable one. Don't use bus/slot/function numbers except for very +-special purposes -- on systems with multiple primary buses their semantics +-can be pretty complex. +- +-Don't try to turn on Fast Back to Back writes in your driver. All devices +-on the bus need to be capable of doing it, so this is something which needs +-to be handled by platform and generic code, not individual drivers. +- +- +- +-8. Vendor and device identifications +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-One is not not required to add new device ids to include/linux/pci_ids.h. +-Please add PCI_VENDOR_ID_xxx for vendors and a hex constant for device ids. +- +-PCI_VENDOR_ID_xxx constants are re-used. The device ids are arbitrary +-hex numbers (vendor controlled) and normally used only in a single +-location, the pci_device_id table. +- +-Please DO submit new vendor/device ids to pciids.sourceforge.net project. +- +- +- +-9. Obsolete functions +-~~~~~~~~~~~~~~~~~~~~~ +- +-There are several functions which you might come across when trying to +-port an old driver to the new PCI interface. They are no longer present +-in the kernel as they aren't compatible with hotplug or PCI domains or +-having sane locking. +- +-pci_find_device() Superseded by pci_get_device() +-pci_find_subsys() Superseded by pci_get_subsys() +-pci_find_slot() Superseded by pci_get_slot() +- +- +-The alternative is the traditional PCI device driver that walks PCI +-device lists. This is still possible but discouraged. +- +- +- +-10. MMIO Space and "Write Posting" +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-Converting a driver from using I/O Port space to using MMIO space +-often requires some additional changes. Specifically, "write posting" +-needs to be handled. Many drivers (e.g. tg3, acenic, sym53c8xx_2) +-already do this. I/O Port space guarantees write transactions reach the PCI +-device before the CPU can continue. Writes to MMIO space allow the CPU +-to continue before the transaction reaches the PCI device. HW weenies +-call this "Write Posting" because the write completion is "posted" to +-the CPU before the transaction has reached its destination. +- +-Thus, timing sensitive code should add readl() where the CPU is +-expected to wait before doing other work. The classic "bit banging" +-sequence works fine for I/O Port space: +- +- for (i = 8; --i; val >>= 1) { +- outb(val & 1, ioport_reg); /* write bit */ +- udelay(10); +- } +- +-The same sequence for MMIO space should be: +- +- for (i = 8; --i; val >>= 1) { +- writeb(val & 1, mmio_reg); /* write bit */ +- readb(safe_mmio_reg); /* flush posted write */ +- udelay(10); +- } +- +-It is important that "safe_mmio_reg" not have any side effects that +-interferes with the correct operation of the device. +- +-Another case to watch out for is when resetting a PCI device. Use PCI +-Configuration space reads to flush the writel(). This will gracefully +-handle the PCI master abort on all platforms if the PCI device is +-expected to not respond to a readl(). Most x86 platforms will allow +-MMIO reads to master abort (a.k.a. "Soft Fail") and return garbage +-(e.g. ~0). But many RISC platforms will crash (a.k.a."Hard Fail"). +- +--- a/Documentation/pcieaer-howto.txt ++++ /dev/null +@@ -1,253 +0,0 @@ +- The PCI Express Advanced Error Reporting Driver Guide HOWTO +- T. Long Nguyen <tom.l.nguyen@intel.com> +- Yanmin Zhang <yanmin.zhang@intel.com> +- 07/29/2006 +- +- +-1. Overview +- +-1.1 About this guide +- +-This guide describes the basics of the PCI Express Advanced Error +-Reporting (AER) driver and provides information on how to use it, as +-well as how to enable the drivers of endpoint devices to conform with +-PCI Express AER driver. +- +-1.2 Copyright © Intel Corporation 2006. +- +-1.3 What is the PCI Express AER Driver? +- +-PCI Express error signaling can occur on the PCI Express link itself +-or on behalf of transactions initiated on the link. PCI Express +-defines two error reporting paradigms: the baseline capability and +-the Advanced Error Reporting capability. The baseline capability is +-required of all PCI Express components providing a minimum defined +-set of error reporting requirements. Advanced Error Reporting +-capability is implemented with a PCI Express advanced error reporting +-extended capability structure providing more robust error reporting. +- +-The PCI Express AER driver provides the infrastructure to support PCI +-Express Advanced Error Reporting capability. The PCI Express AER +-driver provides three basic functions: +- +-- Gathers the comprehensive error information if errors occurred. +-- Reports error to the users. +-- Performs error recovery actions. +- +-AER driver only attaches root ports which support PCI-Express AER +-capability. +- +- +-2. User Guide +- +-2.1 Include the PCI Express AER Root Driver into the Linux Kernel +- +-The PCI Express AER Root driver is a Root Port service driver attached +-to the PCI Express Port Bus driver. If a user wants to use it, the driver +-has to be compiled. Option CONFIG_PCIEAER supports this capability. It +-depends on CONFIG_PCIEPORTBUS, so pls. set CONFIG_PCIEPORTBUS=y and +-CONFIG_PCIEAER = y. +- +-2.2 Load PCI Express AER Root Driver +-There is a case where a system has AER support in BIOS. Enabling the AER +-Root driver and having AER support in BIOS may result unpredictable +-behavior. To avoid this conflict, a successful load of the AER Root driver +-requires ACPI _OSC support in the BIOS to allow the AER Root driver to +-request for native control of AER. See the PCI FW 3.0 Specification for +-details regarding OSC usage. Currently, lots of firmwares don't provide +-_OSC support while they use PCI Express. To support such firmwares, +-forceload, a parameter of type bool, could enable AER to continue to +-be initiated although firmwares have no _OSC support. To enable the +-walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line +-when booting kernel. Note that forceload=n by default. +- +-2.3 AER error output +-When a PCI-E AER error is captured, an error message will be outputed to +-console. If it's a correctable error, it is outputed as a warning. +-Otherwise, it is printed as an error. So users could choose different +-log level to filter out correctable error messages. +- +-Below shows an example. +-+------ PCI-Express Device Error -----+ +-Error Severity : Uncorrected (Fatal) +-PCIE Bus Error type : Transaction Layer +-Unsupported Request : First +-Requester ID : 0500 +-VendorID=8086h, DeviceID=0329h, Bus=05h, Device=00h, Function=00h +-TLB Header: +-04000001 00200a03 05010000 00050100 +- +-In the example, 'Requester ID' means the ID of the device who sends +-the error message to root port. Pls. refer to pci express specs for +-other fields. +- +- +-3. Developer Guide +- +-To enable AER aware support requires a software driver to configure +-the AER capability structure within its device and to provide callbacks. +- +-To support AER better, developers need understand how AER does work +-firstly. +- +-PCI Express errors are classified into two types: correctable errors +-and uncorrectable errors. This classification is based on the impacts +-of those errors, which may result in degraded performance or function +-failure. +- +-Correctable errors pose no impacts on the functionality of the +-interface. The PCI Express protocol can recover without any software +-intervention or any loss of data. These errors are detected and +-corrected by hardware. Unlike correctable errors, uncorrectable +-errors impact functionality of the interface. Uncorrectable errors +-can cause a particular transaction or a particular PCI Express link +-to be unreliable. Depending on those error conditions, uncorrectable +-errors are further classified into non-fatal errors and fatal errors. +-Non-fatal errors cause the particular transaction to be unreliable, +-but the PCI Express link itself is fully functional. Fatal errors, on +-the other hand, cause the link to be unreliable. +- +-When AER is enabled, a PCI Express device will automatically send an +-error message to the PCIE root port above it when the device captures +-an error. The Root Port, upon receiving an error reporting message, +-internally processes and logs the error message in its PCI Express +-capability structure. Error information being logged includes storing +-the error reporting agent's requestor ID into the Error Source +-Identification Registers and setting the error bits of the Root Error +-Status Register accordingly. If AER error reporting is enabled in Root +-Error Command Register, the Root Port generates an interrupt if an +-error is detected. +- +-Note that the errors as described above are related to the PCI Express +-hierarchy and links. These errors do not include any device specific +-errors because device specific errors will still get sent directly to +-the device driver. +- +-3.1 Configure the AER capability structure +- +-AER aware drivers of PCI Express component need change the device +-control registers to enable AER. They also could change AER registers, +-including mask and severity registers. Helper function +-pci_enable_pcie_error_reporting could be used to enable AER. See +-section 3.3. +- +-3.2. Provide callbacks +- +-3.2.1 callback reset_link to reset pci express link +- +-This callback is used to reset the pci express physical link when a +-fatal error happens. The root port aer service driver provides a +-default reset_link function, but different upstream ports might +-have different specifications to reset pci express link, so all +-upstream ports should provide their own reset_link functions. +- +-In struct pcie_port_service_driver, a new pointer, reset_link, is +-added. +- +-pci_ers_result_t (*reset_link) (struct pci_dev *dev); +- +-Section 3.2.2.2 provides more detailed info on when to call +-reset_link. +- +-3.2.2 PCI error-recovery callbacks +- +-The PCI Express AER Root driver uses error callbacks to coordinate +-with downstream device drivers associated with a hierarchy in question +-when performing error recovery actions. +- +-Data struct pci_driver has a pointer, err_handler, to point to +-pci_error_handlers who consists of a couple of callback function +-pointers. AER driver follows the rules defined in +-pci-error-recovery.txt except pci express specific parts (e.g. +-reset_link). Pls. refer to pci-error-recovery.txt for detailed +-definitions of the callbacks. +- +-Below sections specify when to call the error callback functions. +- +-3.2.2.1 Correctable errors +- +-Correctable errors pose no impacts on the functionality of +-the interface. The PCI Express protocol can recover without any +-software intervention or any loss of data. These errors do not +-require any recovery actions. The AER driver clears the device's +-correctable error status register accordingly and logs these errors. +- +-3.2.2.2 Non-correctable (non-fatal and fatal) errors +- +-If an error message indicates a non-fatal error, performing link reset +-at upstream is not required. The AER driver calls error_detected(dev, +-pci_channel_io_normal) to all drivers associated within a hierarchy in +-question. for example, +-EndPoint<==>DownstreamPort B<==>UpstreamPort A<==>RootPort. +-If Upstream port A captures an AER error, the hierarchy consists of +-Downstream port B and EndPoint. +- +-A driver may return PCI_ERS_RESULT_CAN_RECOVER, +-PCI_ERS_RESULT_DISCONNECT, or PCI_ERS_RESULT_NEED_RESET, depending on +-whether it can recover or the AER driver calls mmio_enabled as next. +- +-If an error message indicates a fatal error, kernel will broadcast +-error_detected(dev, pci_channel_io_frozen) to all drivers within +-a hierarchy in question. Then, performing link reset at upstream is +-necessary. As different kinds of devices might use different approaches +-to reset link, AER port service driver is required to provide the +-function to reset link. Firstly, kernel looks for if the upstream +-component has an aer driver. If it has, kernel uses the reset_link +-callback of the aer driver. If the upstream component has no aer driver +-and the port is downstream port, we will use the aer driver of the +-root port who reports the AER error. As for upstream ports, +-they should provide their own aer service drivers with reset_link +-function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and +-reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes +-to mmio_enabled. +- +-3.3 helper functions +- +-3.3.1 int pci_find_aer_capability(struct pci_dev *dev); +-pci_find_aer_capability locates the PCI Express AER capability +-in the device configuration space. If the device doesn't support +-PCI-Express AER, the function returns 0. +- +-3.3.2 int pci_enable_pcie_error_reporting(struct pci_dev *dev); +-pci_enable_pcie_error_reporting enables the device to send error +-messages to root port when an error is detected. Note that devices +-don't enable the error reporting by default, so device drivers need +-call this function to enable it. +- +-3.3.3 int pci_disable_pcie_error_reporting(struct pci_dev *dev); +-pci_disable_pcie_error_reporting disables the device to send error +-messages to root port when an error is detected. +- +-3.3.4 int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev); +-pci_cleanup_aer_uncorrect_error_status cleanups the uncorrectable +-error status register. +- +-3.4 Frequent Asked Questions +- +-Q: What happens if a PCI Express device driver does not provide an +-error recovery handler (pci_driver->err_handler is equal to NULL)? +- +-A: The devices attached with the driver won't be recovered. If the +-error is fatal, kernel will print out warning messages. Please refer +-to section 3 for more information. +- +-Q: What happens if an upstream port service driver does not provide +-callback reset_link? +- +-A: Fatal error recovery will fail if the errors are reported by the +-upstream ports who are attached by the service driver. +- +-Q: How does this infrastructure deal with driver that is not PCI +-Express aware? +- +-A: This infrastructure calls the error callback functions of the +-driver when an error happens. But if the driver is not aware of +-PCI Express, the device might not report its own errors to root +-port. +- +-Q: What modifications will that driver need to make it compatible +-with the PCI Express AER Root driver? +- +-A: It could call the helper functions to enable AER in devices and +-cleanup uncorrectable status register. Pls. refer to section 3.3. +- @@ -11,6 +11,7 @@ driver-core/uio-kconfig-improvements.patch driver-core/uio-mark-pci_device_id-hilscher_pci_ids-__devinitdata.patch driver-core/uio-arch-arm-kconfig-make-uio-available-on-arm-architecture.patch driver-core/uio-remove-needless-pci_device_id-definition-from-uio_cif.c.patch +driver-core/uio-implement-a-uio-interface-for-the-smx-cryptengine.patch driver-core/driver-core-memory-semaphore-to-mutex.patch driver-core/driver-core-register_memory-unregister_memory-clean-ups-and-bugfix.patch driver-core/sysfs-small-header-file-cleanup-for-sysfs-n.patch @@ -23,6 +24,9 @@ driver-core/driver-core-cpu-fix-section-mismatch-in-cpu.c-store_online.patch driver-core/sysdev-detect-multiple-driver-registrations.patch driver-core/driver-core-debug-for-bad-dev_attr_show-return-value.patch driver-core/block-send-disk-change-event-for-rescan_partitions.patch +driver-core/pm-handle-device-registrations-during-suspend-resume.patch +driver-core/driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch +driver-core/pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch driver-core/net-convert-the-phy_device-file-to-use-bus_find_device_by_name.patch @@ -46,6 +50,7 @@ driver-core/sysfs-crash-debugging.patch pci/pci-fix-issue-with-busses-registering-multiple-times-in-sysfs.patch # pci patches for after 2.6.25 is out +pci/pci-doc-pci-create-documentation-pci-and-move-files-into-it.patch pci/pci-if-0-pci_assign_resource_fixed.patch pci/pci-remove-pci_find_present.patch @@ -95,6 +100,7 @@ pci/pci-replace-remaining-__function__-occurrences.patch # usb patches queued for 2.6.25 (bugfixes, new ids, etc.) usb/usb-fix-gadgetfs-class-request-delegation.patch +usb/usb-new-quirk-flag-to-avoid-set-interface.patch # resume rework usb/usb-ehci-carry-out-port-handover-during-each-root-hub-resume.patch @@ -144,6 +150,7 @@ usb/usb-ipaq-fix-devices-having-more-than-one-endpoint.patch usb/usb-remove-dev-power.power_state.patch usb/usb-ehci-paranoia-reject-large-control-transfers.patch usb/usb-cypress_m8-speed-handling.patch +usb/drivers-usb-core-devio.c-suppress-warning-with-64k-page_size.patch usb/usb-add-usb-serial-spcp8x5-driver.patch @@ -172,6 +179,5 @@ driver-core/video-add-the-go7007-driver.patch #pending/greg-debugobjects-add-documentation.patch #pending/greg-debugobjects-add-timer-specific-object-debugging-code.patch - firmware-add-kconfig-and-makefile-to-build-the-firmware-samples.patch f2.patch diff --git a/usb/drivers-usb-core-devio.c-suppress-warning-with-64k-page_size.patch b/usb/drivers-usb-core-devio.c-suppress-warning-with-64k-page_size.patch new file mode 100644 index 00000000000000..025e06f603135c --- /dev/null +++ b/usb/drivers-usb-core-devio.c-suppress-warning-with-64k-page_size.patch @@ -0,0 +1,43 @@ +From akpm@linux-foundation.org Thu Mar 13 13:43:17 2008 +From: Andrew Morton <akpm@linux-foundation.org> +Date: Wed, 12 Mar 2008 13:32:24 -0700 +Subject: drivers/usb/core/devio.c: suppress warning with 64k PAGE_SIZE +To: mm-commits@vger.kernel.org +Cc: akpm@linux-foundation.org, gregkh@suse.de, oliver@neukum.org, stern@rowland.harvard.edu, zaitcev@redhat.com +Message-ID: <200803122041.m2CKfxNN012309@imap1.linux-foundation.org> + +From: Andrew Morton <akpm@linux-foundation.org> + +drivers/usb/core/devio.c: In function 'proc_control': +drivers/usb/core/devio.c:657: warning: comparison is always false due to limited range of data type + +Cc: Alan Stern <stern@rowland.harvard.edu> +Cc: Pete Zaitcev <zaitcev@redhat.com> +Cc: Oliver Neukum <oliver@neukum.org> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/devio.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -647,6 +647,7 @@ static int proc_control(struct dev_state + struct usbdevfs_ctrltransfer ctrl; + unsigned int tmo; + unsigned char *tbuf; ++ unsigned wLength; + int i, j, ret; + + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) +@@ -654,7 +655,8 @@ static int proc_control(struct dev_state + ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex); + if (ret) + return ret; +- if (ctrl.wLength > PAGE_SIZE) ++ wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ ++ if (wLength > PAGE_SIZE) + return -EINVAL; + tbuf = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!tbuf) diff --git a/usb/usb-add-usb-serial-spcp8x5-driver.patch b/usb/usb-add-usb-serial-spcp8x5-driver.patch index 422d8d48eea116..265ee94c4ed1c9 100644 --- a/usb/usb-add-usb-serial-spcp8x5-driver.patch +++ b/usb/usb-add-usb-serial-spcp8x5-driver.patch @@ -14,8 +14,8 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/serial/Kconfig | 10 drivers/usb/serial/Makefile | 3 - drivers/usb/serial/spcp8x5.c | 1076 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 1088 insertions(+), 1 deletion(-) + drivers/usb/serial/spcp8x5.c | 1075 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 1087 insertions(+), 1 deletion(-) --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -58,7 +58,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o --- /dev/null +++ b/drivers/usb/serial/spcp8x5.c -@@ -0,0 +1,1076 @@ +@@ -0,0 +1,1075 @@ +/* + * spcp8x5 USB to serial adaptor driver + * @@ -475,11 +475,10 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + GET_UART_STATUS, GET_UART_STATUS_TYPE, + 0, GET_UART_STATUS_MSR, status_buffer, 1, 100); + if (ret < 0) -+ dev_dbg(&dev->dev, "Get MSR = %#x failed (error = %d)", -+ (int)status_buffer, (int)ret); ++ dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)", ++ status_buffer, ret); + -+ dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - %x ", (int)ret, -+ (int)status_buffer); ++ dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - 0x%p ", ret, status_buffer); + status[0] = status_buffer[0]; + kfree(status_buffer); + diff --git a/usb/usb-enable-usb-persist-by-default.patch b/usb/usb-enable-usb-persist-by-default.patch index 28e8a1b898d192..17ca2b993444bf 100644 --- a/usb/usb-enable-usb-persist-by-default.patch +++ b/usb/usb-enable-usb-persist-by-default.patch @@ -29,7 +29,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c -@@ -95,12 +95,14 @@ void usb_detect_quirks(struct usb_device +@@ -98,12 +98,14 @@ void usb_detect_quirks(struct usb_device udev->autosuspend_disabled = 1; #endif diff --git a/usb/usb-new-quirk-flag-to-avoid-set-interface.patch b/usb/usb-new-quirk-flag-to-avoid-set-interface.patch new file mode 100644 index 00000000000000..426cfd25eef63a --- /dev/null +++ b/usb/usb-new-quirk-flag-to-avoid-set-interface.patch @@ -0,0 +1,59 @@ +From stern@rowland.harvard.edu Thu Mar 13 13:46:50 2008 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 11 Mar 2008 10:20:12 -0400 (EDT) +Subject: USB: new quirk flag to avoid Set-Interface +To: Greg KH <greg@kroah.com> +Cc: Graeme Gill <graeme2@argyllcms.com>, USB list <linux-usb@vger.kernel.org> +Message-ID: <Pine.LNX.4.44L0.0803111018560.3587-100000@iolanthe.rowland.org> + + +This patch (as1057) fixes a problem with the Gretag-Macbeth Huey display +colorimeter; the device crashes when it receives a Set-Interface +request. A new quirk (USB_QUIRK_NO_SET_INTF) is introduced and a +quirks entry is created for this device. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/message.c | 5 ++++- + drivers/usb/core/quirks.c | 3 +++ + include/linux/usb/quirks.h | 3 +++ + 3 files changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/usb/core/message.c ++++ b/drivers/usb/core/message.c +@@ -1206,7 +1206,10 @@ int usb_set_interface(struct usb_device + return -EINVAL; + } + +- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ++ if (dev->quirks & USB_QUIRK_NO_SET_INTF) ++ ret = -EPIPE; ++ else ++ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, + alternate, interface, NULL, 0, 5000); + +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -50,6 +50,9 @@ static const struct usb_device_id usb_qu + /* M-Systems Flash Disk Pioneers */ + { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, + ++ /* Gretag-Macbeth Huey display colorimeter */ ++ { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF }, ++ + /* Action Semiconductor flash disk */ + { USB_DEVICE(0x10d6, 0x2200), .driver_info = + USB_QUIRK_STRING_FETCH_255 }, +--- a/include/linux/usb/quirks.h ++++ b/include/linux/usb/quirks.h +@@ -9,3 +9,6 @@ + + /* device can't resume correctly so reset it instead */ + #define USB_QUIRK_RESET_RESUME 0x00000002 ++ ++/* device can't handle Set-Interface requests */ ++#define USB_QUIRK_NO_SET_INTF 0x00000004 diff --git a/usb/usb-remove-config_usb_persist-setting.patch b/usb/usb-remove-config_usb_persist-setting.patch index 59dbd1396b4af9..bfb11c6df8bb11 100644 --- a/usb/usb-remove-config_usb_persist-setting.patch +++ b/usb/usb-remove-config_usb_persist-setting.patch @@ -226,7 +226,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> { --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c -@@ -94,4 +94,16 @@ void usb_detect_quirks(struct usb_device +@@ -97,4 +97,16 @@ void usb_detect_quirks(struct usb_device if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) udev->autosuspend_disabled = 1; #endif diff --git a/usb/usb-remove-dev-power.power_state.patch b/usb/usb-remove-dev-power.power_state.patch index d5f5456c56616b..01697d71ffc730 100644 --- a/usb/usb-remove-dev-power.power_state.patch +++ b/usb/usb-remove-dev-power.power_state.patch @@ -16,7 +16,7 @@ Part of this patch was written by Pavel Machek. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: David Brownell <david-b@pacbell.net> -Cc: Pavel Machek <pavel@ucw.cz> +Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff --git a/usb/usb-replace-remaining-__function__-occurrences.patch b/usb/usb-replace-remaining-__function__-occurrences.patch index 85edaaefd0c92e..55321111be1d35 100644 --- a/usb/usb-replace-remaining-__function__-occurrences.patch +++ b/usb/usb-replace-remaining-__function__-occurrences.patch @@ -148,7 +148,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /* data interface returns incoming bytes, or we got unthrottled */ --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c -@@ -1509,60 +1509,60 @@ static int usbdev_ioctl(struct inode *in +@@ -1511,60 +1511,60 @@ static int usbdev_ioctl(struct inode *in switch (cmd) { case USBDEVFS_CONTROL: @@ -219,7 +219,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> ret = proc_submiturb(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; -@@ -1571,60 +1571,60 @@ static int usbdev_ioctl(struct inode *in +@@ -1573,60 +1573,60 @@ static int usbdev_ioctl(struct inode *in #ifdef CONFIG_COMPAT case USBDEVFS_SUBMITURB32: |
