* [v9 PATCH 1/9]: cpuidle: Design documentation patch
From: Arun R Bharadwaj @ 2009-10-16 9:40 UTC (permalink / raw)
To: Peter Zijlstra, Benjamin Herrenschmidt, Ingo Molnar,
Vaidyanathan Srinivasan, Dipankar Sarma, Balbir Singh, Andi Kleen,
Arun Bharadwaj
Cc: linux-arch, linux-acpi, linuxppc-dev, linux-kernel
In-Reply-To: <20091016093850.GB27350@linux.vnet.ibm.com>
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-10-16 15:08:50]:
This patch adds a little information about the redesigned cpuidle
infrastructure in Documentation/cpuidle/core.txt
Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
Documentation/cpuidle/core.txt | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
Index: linux.trees.git/Documentation/cpuidle/core.txt
===================================================================
--- linux.trees.git.orig/Documentation/cpuidle/core.txt
+++ linux.trees.git/Documentation/cpuidle/core.txt
@@ -21,3 +21,38 @@ which can be used to switch governors at
is meant for developer testing only. In normal usage, kernel picks the
best governor based on governor ratings.
SEE ALSO: sysfs.txt in this directory.
+
+Design:
+
+Cpuidle allows for registration of multiple sets of idle routines.
+The latest registered set is used by cpuidle governors as the current
+active set to choose the right idle state. This set is managed as a
+list and each time the newly registered set is added to the head of the
+list and made the current active set.
+
+An example of how this would work on x86 is shown below.
+
+----------------- -----------------
+| | | |
+| choose b/w | mwait is chosen | mwait |
+| mwait, poll, |-------------------------------------> |(current active|
+| default, c1e | register to cpuidle | set) |
+| | with mwait as the idle routine | |
+----------------- -----------------
+
+
+----------------- -----------------
+| | | c1, c2, c3 |
+| ACPI | register to cpuidle | (current) |
+| discovery |-------------------------------------> |---------------|
+| | with c1, c2, c3 | mwait |
+| | as set of idle routines | |
+----------------- -----------------
+
+With this mechanism, a module can register and unregister its set of
+idle routines at run time in a clean manner.
+
+The main idle routine called inside cpu_idle() of every arch is defined in
+driver/cpuidle/cpuidle.c which would in turn call the idle routine selected
+by the governor. If the CONFIG_CPU_IDLE is disabled, the arch needs to
+provide an alternate definition for cpuidle_idle_call().
^ permalink raw reply
* [v9 PATCH 2/9]: cpuidle: cleanup drivers/cpuidle/cpuidle.c
From: Arun R Bharadwaj @ 2009-10-16 9:41 UTC (permalink / raw)
To: Peter Zijlstra, Benjamin Herrenschmidt, Ingo Molnar,
Vaidyanathan Srinivasan, Dipankar Sarma, Balbir Singh, Andi Kleen,
Arun Bharadwaj
Cc: linux-arch, linux-acpi, linuxppc-dev, linux-kernel
In-Reply-To: <20091016093850.GB27350@linux.vnet.ibm.com>
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-10-16 15:08:50]:
This patch cleans up drivers/cpuidle/cpuidle.c
Earlier cpuidle assumed pm_idle as the default idle loop. Break that
assumption and make it more generic. cpuidle_idle_call() which is the
main idle loop of cpuidle is to be called by architectures which have
registered to cpuidle.
Remove routines cpuidle_install/uninstall_idle_handler() and
cpuidle_kick_cpus() which are not needed anymore.
Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
drivers/cpuidle/cpuidle.c | 63 ++++++---------------------------------------
drivers/cpuidle/cpuidle.h | 6 +---
drivers/cpuidle/driver.c | 4 --
drivers/cpuidle/governor.c | 13 +++------
drivers/cpuidle/sysfs.c | 34 +++++++++++++-----------
include/linux/cpuidle.h | 4 ++
6 files changed, 38 insertions(+), 86 deletions(-)
Index: linux.trees.git/drivers/cpuidle/cpuidle.c
===================================================================
--- linux.trees.git.orig/drivers/cpuidle/cpuidle.c
+++ linux.trees.git/drivers/cpuidle/cpuidle.c
@@ -24,10 +24,6 @@
DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
DEFINE_MUTEX(cpuidle_lock);
-LIST_HEAD(cpuidle_detected_devices);
-static void (*pm_idle_old)(void);
-
-static int enabled_devices;
#if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT)
static void cpuidle_kick_cpus(void)
@@ -47,7 +43,7 @@ static int __cpuidle_register_device(str
*
* NOTE: no locks or semaphores should be used here
*/
-static void cpuidle_idle_call(void)
+void cpuidle_idle_call(void)
{
struct cpuidle_device *dev = __get_cpu_var(cpuidle_devices);
struct cpuidle_state *target_state;
@@ -55,13 +51,10 @@ static void cpuidle_idle_call(void)
/* check if the device is ready */
if (!dev || !dev->enabled) {
- if (pm_idle_old)
- pm_idle_old();
- else
#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE)
- default_idle();
+ default_idle();
#else
- local_irq_enable();
+ local_irq_enable();
#endif
return;
}
@@ -75,7 +68,11 @@ static void cpuidle_idle_call(void)
hrtimer_peek_ahead_timers();
#endif
/* ask the governor for the next state */
- next_state = cpuidle_curr_governor->select(dev);
+ if (dev->state_count > 1)
+ next_state = cpuidle_curr_governor->select(dev);
+ else
+ next_state = 0;
+
if (need_resched())
return;
target_state = &dev->states[next_state];
@@ -96,35 +93,12 @@ static void cpuidle_idle_call(void)
}
/**
- * cpuidle_install_idle_handler - installs the cpuidle idle loop handler
- */
-void cpuidle_install_idle_handler(void)
-{
- if (enabled_devices && (pm_idle != cpuidle_idle_call)) {
- /* Make sure all changes finished before we switch to new idle */
- smp_wmb();
- pm_idle = cpuidle_idle_call;
- }
-}
-
-/**
- * cpuidle_uninstall_idle_handler - uninstalls the cpuidle idle loop handler
- */
-void cpuidle_uninstall_idle_handler(void)
-{
- if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) {
- pm_idle = pm_idle_old;
- cpuidle_kick_cpus();
- }
-}
-
-/**
* cpuidle_pause_and_lock - temporarily disables CPUIDLE
*/
void cpuidle_pause_and_lock(void)
{
mutex_lock(&cpuidle_lock);
- cpuidle_uninstall_idle_handler();
+ cpuidle_kick_cpus();
}
EXPORT_SYMBOL_GPL(cpuidle_pause_and_lock);
@@ -134,7 +108,6 @@ EXPORT_SYMBOL_GPL(cpuidle_pause_and_lock
*/
void cpuidle_resume_and_unlock(void)
{
- cpuidle_install_idle_handler();
mutex_unlock(&cpuidle_lock);
}
@@ -182,7 +155,6 @@ int cpuidle_enable_device(struct cpuidle
dev->enabled = 1;
- enabled_devices++;
return 0;
fail_sysfs:
@@ -213,7 +185,6 @@ void cpuidle_disable_device(struct cpuid
cpuidle_curr_governor->disable(dev);
cpuidle_remove_state_sysfs(dev);
- enabled_devices--;
}
EXPORT_SYMBOL_GPL(cpuidle_disable_device);
@@ -266,7 +237,6 @@ static void poll_idle_init(struct cpuidl
*/
static int __cpuidle_register_device(struct cpuidle_device *dev)
{
- int ret;
struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
if (!sys_dev)
@@ -274,16 +244,9 @@ static int __cpuidle_register_device(str
if (!try_module_get(cpuidle_curr_driver->owner))
return -EINVAL;
- init_completion(&dev->kobj_unregister);
-
poll_idle_init(dev);
per_cpu(cpuidle_devices, dev->cpu) = dev;
- list_add(&dev->device_list, &cpuidle_detected_devices);
- if ((ret = cpuidle_add_sysfs(sys_dev))) {
- module_put(cpuidle_curr_driver->owner);
- return ret;
- }
dev->registered = 1;
return 0;
@@ -305,7 +268,6 @@ int cpuidle_register_device(struct cpuid
}
cpuidle_enable_device(dev);
- cpuidle_install_idle_handler();
mutex_unlock(&cpuidle_lock);
@@ -321,8 +283,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register_devic
*/
void cpuidle_unregister_device(struct cpuidle_device *dev)
{
- struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
-
if (dev->registered == 0)
return;
@@ -330,9 +290,6 @@ void cpuidle_unregister_device(struct cp
cpuidle_disable_device(dev);
- cpuidle_remove_sysfs(sys_dev);
- list_del(&dev->device_list);
- wait_for_completion(&dev->kobj_unregister);
per_cpu(cpuidle_devices, dev->cpu) = NULL;
cpuidle_resume_and_unlock();
@@ -384,8 +341,6 @@ static int __init cpuidle_init(void)
{
int ret;
- pm_idle_old = pm_idle;
-
ret = cpuidle_add_class_sysfs(&cpu_sysdev_class);
if (ret)
return ret;
Index: linux.trees.git/drivers/cpuidle/governor.c
===================================================================
--- linux.trees.git.orig/drivers/cpuidle/governor.c
+++ linux.trees.git/drivers/cpuidle/governor.c
@@ -43,16 +43,14 @@ static struct cpuidle_governor * __cpuid
*/
int cpuidle_switch_governor(struct cpuidle_governor *gov)
{
- struct cpuidle_device *dev;
+ int cpu;
if (gov == cpuidle_curr_governor)
return 0;
- cpuidle_uninstall_idle_handler();
-
if (cpuidle_curr_governor) {
- list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
- cpuidle_disable_device(dev);
+ for_each_online_cpu(cpu)
+ cpuidle_disable_device(per_cpu(cpuidle_devices, cpu));
module_put(cpuidle_curr_governor->owner);
}
@@ -61,9 +59,8 @@ int cpuidle_switch_governor(struct cpuid
if (gov) {
if (!try_module_get(cpuidle_curr_governor->owner))
return -EINVAL;
- list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
- cpuidle_enable_device(dev);
- cpuidle_install_idle_handler();
+ for_each_online_cpu(cpu)
+ cpuidle_enable_device(per_cpu(cpuidle_devices, cpu));
printk(KERN_INFO "cpuidle: using governor %s\n", gov->name);
}
Index: linux.trees.git/include/linux/cpuidle.h
===================================================================
--- linux.trees.git.orig/include/linux/cpuidle.h
+++ linux.trees.git/include/linux/cpuidle.h
@@ -92,7 +92,6 @@ struct cpuidle_device {
struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
struct cpuidle_state *last_state;
- struct list_head device_list;
struct kobject kobj;
struct completion kobj_unregister;
void *governor_data;
@@ -112,6 +111,9 @@ static inline int cpuidle_get_last_resid
return dev->last_residency;
}
+extern struct cpuidle_driver *cpuidle_curr_driver;
+extern void cpuidle_idle_call(void);
+
/****************************
* CPUIDLE DRIVER INTERFACE *
Index: linux.trees.git/drivers/cpuidle/cpuidle.h
===================================================================
--- linux.trees.git.orig/drivers/cpuidle/cpuidle.h
+++ linux.trees.git/drivers/cpuidle/cpuidle.h
@@ -9,9 +9,7 @@
/* For internal use only */
extern struct cpuidle_governor *cpuidle_curr_governor;
-extern struct cpuidle_driver *cpuidle_curr_driver;
extern struct list_head cpuidle_governors;
-extern struct list_head cpuidle_detected_devices;
extern struct mutex cpuidle_lock;
extern spinlock_t cpuidle_driver_lock;
@@ -27,7 +25,7 @@ extern int cpuidle_add_class_sysfs(struc
extern void cpuidle_remove_class_sysfs(struct sysdev_class *cls);
extern int cpuidle_add_state_sysfs(struct cpuidle_device *device);
extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device);
-extern int cpuidle_add_sysfs(struct sys_device *sysdev);
-extern void cpuidle_remove_sysfs(struct sys_device *sysdev);
+extern int cpuidle_add_sysfs(struct cpuidle_device *device);
+extern void cpuidle_remove_sysfs(struct cpuidle_device *device);
#endif /* __DRIVER_CPUIDLE_H */
Index: linux.trees.git/drivers/cpuidle/sysfs.c
===================================================================
--- linux.trees.git.orig/drivers/cpuidle/sysfs.c
+++ linux.trees.git/drivers/cpuidle/sysfs.c
@@ -311,6 +311,13 @@ int cpuidle_add_state_sysfs(struct cpuid
int i, ret = -ENOMEM;
struct cpuidle_state_kobj *kobj;
+ init_completion(&device->kobj_unregister);
+
+ ret = cpuidle_add_sysfs(device);
+ if (ret) {
+ module_put(cpuidle_curr_driver->owner);
+ return ret;
+ }
/* state statistics */
for (i = 0; i < device->state_count; i++) {
kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
@@ -347,35 +354,32 @@ void cpuidle_remove_state_sysfs(struct c
for (i = 0; i < device->state_count; i++)
cpuidle_free_state_kobj(device, i);
+
+ cpuidle_remove_sysfs(device);
}
/**
* cpuidle_add_sysfs - creates a sysfs instance for the target device
- * @sysdev: the target device
+ * @device: the target device
*/
-int cpuidle_add_sysfs(struct sys_device *sysdev)
+int cpuidle_add_sysfs(struct cpuidle_device *device)
{
- int cpu = sysdev->id;
- struct cpuidle_device *dev;
int error;
+ struct sys_device *sysdev = get_cpu_sysdev((unsigned long)device->cpu);
- dev = per_cpu(cpuidle_devices, cpu);
- error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &sysdev->kobj,
- "cpuidle");
+ error = kobject_init_and_add(&device->kobj, &ktype_cpuidle,
+ &sysdev->kobj, "cpuidle");
if (!error)
- kobject_uevent(&dev->kobj, KOBJ_ADD);
+ kobject_uevent(&device->kobj, KOBJ_ADD);
return error;
}
/**
* cpuidle_remove_sysfs - deletes a sysfs instance on the target device
- * @sysdev: the target device
+ * @device: the target device
*/
-void cpuidle_remove_sysfs(struct sys_device *sysdev)
+void cpuidle_remove_sysfs(struct cpuidle_device *device)
{
- int cpu = sysdev->id;
- struct cpuidle_device *dev;
-
- dev = per_cpu(cpuidle_devices, cpu);
- kobject_put(&dev->kobj);
+ kobject_put(&device->kobj);
+ wait_for_completion(&device->kobj_unregister);
}
Index: linux.trees.git/drivers/cpuidle/driver.c
===================================================================
--- linux.trees.git.orig/drivers/cpuidle/driver.c
+++ linux.trees.git/drivers/cpuidle/driver.c
@@ -27,10 +27,6 @@ int cpuidle_register_driver(struct cpuid
return -EINVAL;
spin_lock(&cpuidle_driver_lock);
- if (cpuidle_curr_driver) {
- spin_unlock(&cpuidle_driver_lock);
- return -EBUSY;
- }
cpuidle_curr_driver = drv;
spin_unlock(&cpuidle_driver_lock);
^ permalink raw reply
* [v9 PATCH 3/9]: cpuidle: implement a list based approach to register a set of idle routines.
From: Arun R Bharadwaj @ 2009-10-16 9:42 UTC (permalink / raw)
To: Peter Zijlstra, Benjamin Herrenschmidt, Ingo Molnar,
Vaidyanathan Srinivasan, Dipankar Sarma, Balbir Singh, Andi Kleen,
Arun Bharadwaj
Cc: linux-arch, linux-acpi, linuxppc-dev, linux-kernel
In-Reply-To: <20091016093850.GB27350@linux.vnet.ibm.com>
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-10-16 15:08:50]:
Implement a list based registering mechanism for architectures which
have multiple sets of idle routines which are to be registered.
Currently, in x86 it is done by merely setting pm_idle = idle_routine
and managing this pm_idle pointer is messy.
To give an example of how this mechanism works:
In x86, initially, idle routine is selected from the set of poll/mwait/
c1e/default idle loops. So the selected idle loop is registered in cpuidle
as one idle state cpuidle devices. Once ACPI comes up, it registers
another set of idle states on top of this state. Again, suppose a module
registers another set of idle loops, it is added to this list.
This provides a clean way of registering and unregistering idle state
routines.
In the current implementation, pm_idle is set as the current idle routine
being used and the old idle routine has to be maintained and when a module
registers/unregisters an idle routine, confusion arises.
Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
drivers/cpuidle/cpuidle.c | 54 ++++++++++++++++++++++++++++++++++++++++------
include/linux/cpuidle.h | 1
2 files changed, 48 insertions(+), 7 deletions(-)
Index: linux.trees.git/drivers/cpuidle/cpuidle.c
===================================================================
--- linux.trees.git.orig/drivers/cpuidle/cpuidle.c
+++ linux.trees.git/drivers/cpuidle/cpuidle.c
@@ -22,6 +22,7 @@
#include "cpuidle.h"
DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
+DEFINE_PER_CPU(struct list_head, cpuidle_devices_list);
DEFINE_MUTEX(cpuidle_lock);
@@ -113,6 +114,45 @@ void cpuidle_resume_and_unlock(void)
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
+int cpuidle_add_to_list(struct cpuidle_device *dev)
+{
+ int ret, cpu = dev->cpu;
+ struct cpuidle_device *old_dev;
+
+ if (!list_empty(&per_cpu(cpuidle_devices_list, cpu))) {
+ old_dev = list_first_entry(&per_cpu(cpuidle_devices_list, cpu),
+ struct cpuidle_device, idle_list);
+ cpuidle_remove_state_sysfs(old_dev);
+ }
+
+ list_add(&dev->idle_list, &per_cpu(cpuidle_devices_list, cpu));
+ ret = cpuidle_add_state_sysfs(dev);
+ return ret;
+}
+
+void cpuidle_remove_from_list(struct cpuidle_device *dev)
+{
+ struct cpuidle_device *temp_dev;
+ struct list_head *pos;
+ int ret, cpu = dev->cpu;
+
+ list_for_each(pos, &per_cpu(cpuidle_devices_list, cpu)) {
+ temp_dev = container_of(pos, struct cpuidle_device, idle_list);
+ if (dev == temp_dev) {
+ list_del(&temp_dev->idle_list);
+ cpuidle_remove_state_sysfs(temp_dev);
+ break;
+ }
+ }
+
+ if (!list_empty(&per_cpu(cpuidle_devices_list, cpu))) {
+ temp_dev = list_first_entry(&per_cpu(cpuidle_devices_list, cpu),
+ struct cpuidle_device, idle_list);
+ ret = cpuidle_add_state_sysfs(temp_dev);
+ }
+ cpuidle_kick_cpus();
+}
+
/**
* cpuidle_enable_device - enables idle PM for a CPU
* @dev: the CPU
@@ -137,9 +177,6 @@ int cpuidle_enable_device(struct cpuidle
return ret;
}
- if ((ret = cpuidle_add_state_sysfs(dev)))
- return ret;
-
if (cpuidle_curr_governor->enable &&
(ret = cpuidle_curr_governor->enable(dev)))
goto fail_sysfs;
@@ -158,7 +195,7 @@ int cpuidle_enable_device(struct cpuidle
return 0;
fail_sysfs:
- cpuidle_remove_state_sysfs(dev);
+ cpuidle_remove_from_list(dev);
return ret;
}
@@ -183,8 +220,6 @@ void cpuidle_disable_device(struct cpuid
if (cpuidle_curr_governor->disable)
cpuidle_curr_governor->disable(dev);
-
- cpuidle_remove_state_sysfs(dev);
}
EXPORT_SYMBOL_GPL(cpuidle_disable_device);
@@ -268,6 +303,7 @@ int cpuidle_register_device(struct cpuid
}
cpuidle_enable_device(dev);
+ cpuidle_add_to_list(dev);
mutex_unlock(&cpuidle_lock);
@@ -289,6 +325,7 @@ void cpuidle_unregister_device(struct cp
cpuidle_pause_and_lock();
cpuidle_disable_device(dev);
+ cpuidle_remove_from_list(dev);
per_cpu(cpuidle_devices, dev->cpu) = NULL;
@@ -339,12 +376,15 @@ static inline void latency_notifier_init
*/
static int __init cpuidle_init(void)
{
- int ret;
+ int ret, cpu;
ret = cpuidle_add_class_sysfs(&cpu_sysdev_class);
if (ret)
return ret;
+ for_each_possible_cpu(cpu)
+ INIT_LIST_HEAD(&per_cpu(cpuidle_devices_list, cpu));
+
latency_notifier_init(&cpuidle_latency_notifier);
return 0;
Index: linux.trees.git/include/linux/cpuidle.h
===================================================================
--- linux.trees.git.orig/include/linux/cpuidle.h
+++ linux.trees.git/include/linux/cpuidle.h
@@ -92,6 +92,7 @@ struct cpuidle_device {
struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
struct cpuidle_state *last_state;
+ struct list_head idle_list;
struct kobject kobj;
struct completion kobj_unregister;
void *governor_data;
^ permalink raw reply
* [v9 PATCH 4/9]: x86: refactor x86 idle power management code and remove all instances of pm_idle.
From: Arun R Bharadwaj @ 2009-10-16 9:43 UTC (permalink / raw)
To: Peter Zijlstra, Benjamin Herrenschmidt, Ingo Molnar,
Vaidyanathan Srinivasan, Dipankar Sarma, Balbir Singh, Andi Kleen,
Arun Bharadwaj
Cc: linux-arch, linux-acpi, linuxppc-dev, linux-kernel
In-Reply-To: <20091016093850.GB27350@linux.vnet.ibm.com>
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-10-16 15:08:50]:
This patch cleans up x86 of all instances of pm_idle.
pm_idle which was earlier called from cpu_idle() idle loop
is replaced by cpuidle_idle_call.
x86 also registers to cpuidle when the idle routine is selected,
by populating the cpuidle_device data structure for each cpu.
This is replicated for apm module and for xen, which also used pm_idle.
Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
arch/x86/kernel/apm_32.c | 55 ++++++++++++++++++++++++-
arch/x86/kernel/process.c | 90 ++++++++++++++++++++++++++++++++----------
arch/x86/kernel/process_32.c | 3 -
arch/x86/kernel/process_64.c | 3 -
arch/x86/xen/setup.c | 40 ++++++++++++++++++
drivers/acpi/processor_core.c | 9 ++--
drivers/cpuidle/cpuidle.c | 16 +++++--
7 files changed, 182 insertions(+), 34 deletions(-)
Index: linux.trees.git/arch/x86/kernel/process.c
===================================================================
--- linux.trees.git.orig/arch/x86/kernel/process.c
+++ linux.trees.git/arch/x86/kernel/process.c
@@ -10,6 +10,7 @@
#include <linux/clockchips.h>
#include <linux/random.h>
#include <linux/user-return-notifier.h>
+#include <linux/cpuidle.h>
#include <trace/events/power.h>
#include <asm/system.h>
#include <asm/apic.h>
@@ -246,12 +247,6 @@ int sys_vfork(struct pt_regs *regs)
unsigned long boot_option_idle_override = 0;
EXPORT_SYMBOL(boot_option_idle_override);
-/*
- * Powermanagement idle function, if any..
- */
-void (*pm_idle)(void);
-EXPORT_SYMBOL(pm_idle);
-
#ifdef CONFIG_X86_32
/*
* This halt magic was a workaround for ancient floppy DMA
@@ -331,17 +326,15 @@ static void do_nothing(void *unused)
}
/*
- * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
- * pm_idle and update to new pm_idle value. Required while changing pm_idle
- * handler on SMP systems.
+ * cpu_idle_wait - Required while changing idle routine handler on SMP systems.
*
- * Caller must have changed pm_idle to the new value before the call. Old
- * pm_idle value will not be used by any CPU after the return of this function.
+ * Caller must have changed idle routine to the new value before the call. Old
+ * value will not be used by any CPU after the return of this function.
*/
void cpu_idle_wait(void)
{
smp_mb();
- /* kick all the CPUs so that they exit out of pm_idle */
+ /* kick all the CPUs so that they exit out of idle loop */
smp_call_function(do_nothing, NULL, 1);
}
EXPORT_SYMBOL_GPL(cpu_idle_wait);
@@ -520,15 +513,70 @@ static void c1e_idle(void)
default_idle();
}
+static void (*local_idle)(void);
+
+#ifndef CONFIG_CPU_IDLE
+void cpuidle_idle_call(void)
+{
+ if (local_idle)
+ local_idle();
+ else
+ default_idle();
+}
+#endif
+
+DEFINE_PER_CPU(struct cpuidle_device, idle_devices);
+
+struct cpuidle_driver cpuidle_default_driver = {
+ .name = "cpuidle_default",
+};
+
+static int local_idle_loop(struct cpuidle_device *dev, struct cpuidle_state *st)
+{
+ ktime_t t1, t2;
+ s64 diff;
+ int ret;
+
+ t1 = ktime_get();
+ local_idle();
+ t2 = ktime_get();
+
+ diff = ktime_to_us(ktime_sub(t2, t1));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+ ret = (int) diff;
+
+ return ret;
+}
+
+static int setup_cpuidle_simple(void)
+{
+ struct cpuidle_device *dev;
+ int cpu;
+
+ if (!cpuidle_curr_driver)
+ cpuidle_register_driver(&cpuidle_default_driver);
+
+ for_each_online_cpu(cpu) {
+ dev = &per_cpu(idle_devices, cpu);
+ dev->cpu = cpu;
+ dev->states[0].enter = local_idle_loop;
+ dev->state_count = 1;
+ cpuidle_register_device(dev);
+ }
+ return 0;
+}
+device_initcall(setup_cpuidle_simple);
+
void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
{
#ifdef CONFIG_SMP
- if (pm_idle == poll_idle && smp_num_siblings > 1) {
+ if (local_idle == poll_idle && smp_num_siblings > 1) {
printk(KERN_WARNING "WARNING: polling idle and HT enabled,"
" performance may degrade.\n");
}
#endif
- if (pm_idle)
+ if (local_idle)
return;
if (cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)) {
@@ -536,18 +584,20 @@ void __cpuinit select_idle_routine(const
* One CPU supports mwait => All CPUs supports mwait
*/
printk(KERN_INFO "using mwait in idle threads.\n");
- pm_idle = mwait_idle;
+ local_idle = mwait_idle;
} else if (check_c1e_idle(c)) {
printk(KERN_INFO "using C1E aware idle routine\n");
- pm_idle = c1e_idle;
+ local_idle = c1e_idle;
} else
- pm_idle = default_idle;
+ local_idle = default_idle;
+
+ return;
}
void __init init_c1e_mask(void)
{
/* If we're using c1e_idle, we need to allocate c1e_mask. */
- if (pm_idle == c1e_idle)
+ if (local_idle == c1e_idle)
zalloc_cpumask_var(&c1e_mask, GFP_KERNEL);
}
@@ -558,7 +608,7 @@ static int __init idle_setup(char *str)
if (!strcmp(str, "poll")) {
printk("using polling idle threads.\n");
- pm_idle = poll_idle;
+ local_idle = poll_idle;
} else if (!strcmp(str, "mwait"))
force_mwait = 1;
else if (!strcmp(str, "halt")) {
@@ -569,7 +619,7 @@ static int __init idle_setup(char *str)
* To continue to load the CPU idle driver, don't touch
* the boot_option_idle_override.
*/
- pm_idle = default_idle;
+ local_idle = default_idle;
idle_halt = 1;
return 0;
} else if (!strcmp(str, "nomwait")) {
Index: linux.trees.git/arch/x86/kernel/process_32.c
===================================================================
--- linux.trees.git.orig/arch/x86/kernel/process_32.c
+++ linux.trees.git/arch/x86/kernel/process_32.c
@@ -40,6 +40,7 @@
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/kdebug.h>
+#include <linux/cpuidle.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -113,7 +114,7 @@ void cpu_idle(void)
local_irq_disable();
/* Don't trace irqs off for idle */
stop_critical_timings();
- pm_idle();
+ cpuidle_idle_call();
start_critical_timings();
}
tick_nohz_restart_sched_tick();
Index: linux.trees.git/arch/x86/kernel/process_64.c
===================================================================
--- linux.trees.git.orig/arch/x86/kernel/process_64.c
+++ linux.trees.git/arch/x86/kernel/process_64.c
@@ -39,6 +39,7 @@
#include <linux/io.h>
#include <linux/ftrace.h>
#include <linux/dmi.h>
+#include <linux/cpuidle.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -142,7 +143,7 @@ void cpu_idle(void)
enter_idle();
/* Don't trace irqs off for idle */
stop_critical_timings();
- pm_idle();
+ cpuidle_idle_call();
start_critical_timings();
/* In many cases the interrupt that ended idle
has already called exit_idle. But some idle
Index: linux.trees.git/arch/x86/kernel/apm_32.c
===================================================================
--- linux.trees.git.orig/arch/x86/kernel/apm_32.c
+++ linux.trees.git/arch/x86/kernel/apm_32.c
@@ -2255,6 +2255,56 @@ static struct dmi_system_id __initdata a
{ }
};
+DEFINE_PER_CPU(struct cpuidle_device, apm_idle_devices);
+
+struct cpuidle_driver cpuidle_apm_driver = {
+ .name = "cpuidle_apm",
+};
+
+static int apm_idle_loop(struct cpuidle_device *dev, struct cpuidle_state *st)
+{
+ ktime_t t1, t2;
+ s64 diff;
+ int ret;
+
+ t1 = ktime_get();
+ apm_cpu_idle();
+ t2 = ktime_get();
+
+ diff = ktime_to_us(ktime_sub(t2, t1));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+ ret = (int) diff;
+
+ return ret;
+}
+
+void __cpuinit setup_cpuidle_apm(void)
+{
+ struct cpuidle_device *dev;
+
+ if (!cpuidle_curr_driver)
+ cpuidle_register_driver(&cpuidle_apm_driver);
+
+ dev = &per_cpu(apm_idle_devices, smp_processor_id());
+ dev->cpu = smp_processor_id();
+ dev->states[0].enter = apm_idle_loop;
+ dev->state_count = 1;
+ cpuidle_register_device(dev);
+}
+
+void exit_cpuidle_apm(void)
+{
+ struct cpuidle_device *dev;
+ int cpu;
+
+ for_each_online_cpu(cpu) {
+ dev = &per_cpu(apm_idle_devices, cpu);
+ cpuidle_unregister_device(dev);
+ }
+}
+
+
/*
* Just start the APM thread. We do NOT want to do APM BIOS
* calls from anything but the APM thread, if for no other reason
@@ -2392,8 +2442,7 @@ static int __init apm_init(void)
if (HZ != 100)
idle_period = (idle_period * HZ) / 100;
if (idle_threshold < 100) {
- original_pm_idle = pm_idle;
- pm_idle = apm_cpu_idle;
+ setup_cpuidle_apm();
set_pm_idle = 1;
}
@@ -2405,7 +2454,7 @@ static void __exit apm_exit(void)
int error;
if (set_pm_idle) {
- pm_idle = original_pm_idle;
+ exit_cpuidle_apm();
/*
* We are about to unload the current idle thread pm callback
* (pm_idle), Wait for all processors to update cached/local
Index: linux.trees.git/arch/x86/xen/setup.c
===================================================================
--- linux.trees.git.orig/arch/x86/xen/setup.c
+++ linux.trees.git/arch/x86/xen/setup.c
@@ -8,6 +8,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/pm.h>
+#include <linux/cpuidle.h>
#include <asm/elf.h>
#include <asm/vdso.h>
@@ -151,6 +152,43 @@ void __cpuinit xen_enable_syscall(void)
#endif /* CONFIG_X86_64 */
}
+DEFINE_PER_CPU(struct cpuidle_device, xen_idle_devices);
+struct cpuidle_driver cpuidle_xen_driver = {
+ .name = "cpuidle_xen",
+};
+
+static int xen_idle_loop(struct cpuidle_device *dev, struct cpuidle_state *st)
+{
+ ktime_t t1, t2;
+ s64 diff;
+ int ret;
+
+ t1 = ktime_get();
+ xen_idle();
+ t2 = ktime_get();
+
+ diff = ktime_to_us(ktime_sub(t2, t1));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+ ret = (int) diff;
+
+ return ret;
+}
+
+void __cpuinit setup_cpuidle_xen(void)
+{
+ struct cpuidle_device *dev;
+
+ if (!cpuidle_curr_driver)
+ cpuidle_register_driver(&cpuidle_xen_driver);
+
+ dev = &per_cpu(xen_idle_devices, smp_processor_id());
+ dev->cpu = smp_processor_id();
+ dev->states[0].enter = xen_idle_loop;
+ dev->state_count = 1;
+ cpuidle_register_device(dev);
+}
+
void __init xen_arch_setup(void)
{
struct physdev_set_iopl set_iopl;
@@ -186,7 +224,7 @@ void __init xen_arch_setup(void)
MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ?
COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
- pm_idle = xen_idle;
+ setup_cpuidle_xen();
paravirt_disable_iospace();
Index: linux.trees.git/drivers/acpi/processor_core.c
===================================================================
--- linux.trees.git.orig/drivers/acpi/processor_core.c
+++ linux.trees.git/drivers/acpi/processor_core.c
@@ -1150,9 +1150,12 @@ static int __init acpi_processor_init(vo
* should not use mwait for CPU-states.
*/
dmi_check_system(processor_idle_dmi_table);
- result = cpuidle_register_driver(&acpi_idle_driver);
- if (result < 0)
- goto out_proc;
+
+ if (!boot_option_idle_override) {
+ result = cpuidle_register_driver(&acpi_idle_driver);
+ if (result < 0)
+ goto out_proc;
+ }
result = acpi_bus_register_driver(&acpi_processor_driver);
if (result < 0)
Index: linux.trees.git/drivers/cpuidle/cpuidle.c
===================================================================
--- linux.trees.git.orig/drivers/cpuidle/cpuidle.c
+++ linux.trees.git/drivers/cpuidle/cpuidle.c
@@ -225,16 +225,22 @@ void cpuidle_disable_device(struct cpuid
EXPORT_SYMBOL_GPL(cpuidle_disable_device);
#ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
+static void poll_idle(void)
+{
+ local_irq_enable();
+ while (!need_resched())
+ cpu_relax();
+}
+
+static int poll_idle_loop(struct cpuidle_device *dev, struct cpuidle_state *st)
{
ktime_t t1, t2;
s64 diff;
int ret;
t1 = ktime_get();
- local_irq_enable();
- while (!need_resched())
- cpu_relax();
+
+ poll_idle();
t2 = ktime_get();
diff = ktime_to_us(ktime_sub(t2, t1));
@@ -257,7 +263,7 @@ static void poll_idle_init(struct cpuidl
state->target_residency = 0;
state->power_usage = -1;
state->flags = CPUIDLE_FLAG_POLL;
- state->enter = poll_idle;
+ state->enter = poll_idle_loop;
}
#else
static void poll_idle_init(struct cpuidle_device *dev) {}
^ permalink raw reply
* [v9 PATCH 5/9]: POWER: enable cpuidle for POWER.
From: Arun R Bharadwaj @ 2009-10-16 9:44 UTC (permalink / raw)
To: Peter Zijlstra, Benjamin Herrenschmidt, Ingo Molnar,
Vaidyanathan Srinivasan, Dipankar Sarma, Balbir Singh, Andi Kleen,
Arun Bharadwaj
Cc: linux-arch, linux-acpi, linuxppc-dev, linux-kernel
In-Reply-To: <20091016093850.GB27350@linux.vnet.ibm.com>
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-10-16 15:08:50]:
This patch enables the cpuidle option in Kconfig for pSeries.
Currently cpuidle infrastructure is enabled only for x86 and ARM.
This code is almost completely borrowed from x86 to enable
cpuidle for pSeries.
Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
arch/powerpc/Kconfig | 17 +++++++++++++++++
arch/powerpc/include/asm/system.h | 2 ++
arch/powerpc/kernel/idle.c | 19 +++++++++++++++++++
3 files changed, 38 insertions(+)
Index: linux.trees.git/arch/powerpc/Kconfig
===================================================================
--- linux.trees.git.orig/arch/powerpc/Kconfig
+++ linux.trees.git/arch/powerpc/Kconfig
@@ -91,6 +91,9 @@ config ARCH_HAS_ILOG2_U64
bool
default y if 64BIT
+config ARCH_HAS_CPU_IDLE_WAIT
+ def_bool y
+
config GENERIC_HWEIGHT
bool
default y
@@ -247,6 +250,20 @@ source "kernel/Kconfig.freezer"
source "arch/powerpc/sysdev/Kconfig"
source "arch/powerpc/platforms/Kconfig"
+menu "Power management options"
+
+source "drivers/cpuidle/Kconfig"
+
+config PSERIES_PROCESSOR_IDLE
+ bool "Idle Power Management Support for pSeries"
+ depends on PPC_PSERIES && CPU_IDLE
+ default y
+ help
+ Idle Power Management Support for pSeries. This hooks onto cpuidle
+ infrastructure to help in idle cpu power management.
+
+endmenu
+
menu "Kernel options"
config HIGHMEM
Index: linux.trees.git/arch/powerpc/include/asm/system.h
===================================================================
--- linux.trees.git.orig/arch/powerpc/include/asm/system.h
+++ linux.trees.git/arch/powerpc/include/asm/system.h
@@ -546,5 +546,7 @@ extern void account_system_vtime(struct
extern struct dentry *powerpc_debugfs_root;
+void cpu_idle_wait(void);
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_SYSTEM_H */
Index: linux.trees.git/arch/powerpc/kernel/idle.c
===================================================================
--- linux.trees.git.orig/arch/powerpc/kernel/idle.c
+++ linux.trees.git/arch/powerpc/kernel/idle.c
@@ -102,6 +102,25 @@ void cpu_idle(void)
}
}
+static void do_nothing(void *unused)
+{
+}
+
+/*
+ * cpu_idle_wait - Used to ensure that all the CPUs come out of the old
+ * idle loop and start using the new idle loop.
+ * Required while changing idle handler on SMP systems.
+ * Caller must have changed idle handler to the new value before the call.
+ */
+void cpu_idle_wait(void)
+{
+ /* Ensure that new value of idle is set */
+ smp_mb();
+ /* kick all the CPUs so that they exit out of old idle routine */
+ smp_call_function(do_nothing, NULL, 1);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
+
int powersave_nap;
#ifdef CONFIG_SYSCTL
^ permalink raw reply
* [v9 PATCH 6/9]: pSeries/cpuidle: refactor pseries idle loops
From: Arun R Bharadwaj @ 2009-10-16 9:45 UTC (permalink / raw)
To: Peter Zijlstra, Benjamin Herrenschmidt, Ingo Molnar,
Vaidyanathan Srinivasan, Dipankar Sarma, Balbir Singh, Andi Kleen,
Arun Bharadwaj
Cc: linux-arch, linux-acpi, linuxppc-dev, linux-kernel
In-Reply-To: <20091016093850.GB27350@linux.vnet.ibm.com>
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-10-16 15:08:50]:
This patch removes the routines, pseries_shared_idle_sleep and
pseries_dedicated_idle_sleep, since this is implemented as a part
of arch/powerpc/platform/pseries/processor_idle.c
Also, similar to x86, call cpuidle_idle_call from cpu_idle() idle
loop instead of ppc_md.power_save.
Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
arch/powerpc/kernel/idle.c | 58 ++++++++++-----------
arch/powerpc/platforms/pseries/setup.c | 89 ---------------------------------
2 files changed, 30 insertions(+), 117 deletions(-)
Index: linux.trees.git/arch/powerpc/platforms/pseries/setup.c
===================================================================
--- linux.trees.git.orig/arch/powerpc/platforms/pseries/setup.c
+++ linux.trees.git/arch/powerpc/platforms/pseries/setup.c
@@ -75,9 +75,6 @@ EXPORT_SYMBOL(CMO_PageSize);
int fwnmi_active; /* TRUE if an FWNMI handler is present */
-static void pseries_shared_idle_sleep(void);
-static void pseries_dedicated_idle_sleep(void);
-
static struct device_node *pSeries_mpic_node;
static void pSeries_show_cpuinfo(struct seq_file *m)
@@ -297,18 +294,8 @@ static void __init pSeries_setup_arch(vo
pSeries_nvram_init();
/* Choose an idle loop */
- if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+ if (firmware_has_feature(FW_FEATURE_SPLPAR))
vpa_init(boot_cpuid);
- if (get_lppaca()->shared_proc) {
- printk(KERN_DEBUG "Using shared processor idle loop\n");
- ppc_md.power_save = pseries_shared_idle_sleep;
- } else {
- printk(KERN_DEBUG "Using dedicated idle loop\n");
- ppc_md.power_save = pseries_dedicated_idle_sleep;
- }
- } else {
- printk(KERN_DEBUG "Using default idle loop\n");
- }
if (firmware_has_feature(FW_FEATURE_LPAR))
ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
@@ -496,80 +483,6 @@ static int __init pSeries_probe(void)
return 1;
}
-
-DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
-
-static void pseries_dedicated_idle_sleep(void)
-{
- unsigned int cpu = smp_processor_id();
- unsigned long start_snooze;
- unsigned long in_purr, out_purr;
-
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- get_lppaca()->idle = 1;
- get_lppaca()->donate_dedicated_cpu = 1;
- in_purr = mfspr(SPRN_PURR);
-
- /*
- * We come in with interrupts disabled, and need_resched()
- * has been checked recently. If we should poll for a little
- * while, do so.
- */
- if (__get_cpu_var(smt_snooze_delay)) {
- start_snooze = get_tb() +
- __get_cpu_var(smt_snooze_delay) * tb_ticks_per_usec;
- local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while (get_tb() < start_snooze) {
- if (need_resched() || cpu_is_offline(cpu))
- goto out;
- ppc64_runlatch_off();
- HMT_low();
- HMT_very_low();
- }
-
- HMT_medium();
- clear_thread_flag(TIF_POLLING_NRFLAG);
- smp_mb();
- local_irq_disable();
- if (need_resched() || cpu_is_offline(cpu))
- goto out;
- }
-
- cede_processor();
-
-out:
- HMT_medium();
- out_purr = mfspr(SPRN_PURR);
- get_lppaca()->wait_state_cycles += out_purr - in_purr;
- get_lppaca()->donate_dedicated_cpu = 0;
- get_lppaca()->idle = 0;
-}
-
-static void pseries_shared_idle_sleep(void)
-{
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- get_lppaca()->idle = 1;
-
- /*
- * Yield the processor to the hypervisor. We return if
- * an external interrupt occurs (which are driven prior
- * to returning here) or if a prod occurs from another
- * processor. When returning here, external interrupts
- * are enabled.
- */
- cede_processor();
-
- get_lppaca()->idle = 0;
-}
-
static int pSeries_pci_probe_mode(struct pci_bus *bus)
{
if (firmware_has_feature(FW_FEATURE_LPAR))
Index: linux.trees.git/arch/powerpc/kernel/idle.c
===================================================================
--- linux.trees.git.orig/arch/powerpc/kernel/idle.c
+++ linux.trees.git/arch/powerpc/kernel/idle.c
@@ -25,6 +25,7 @@
#include <linux/cpu.h>
#include <linux/sysctl.h>
#include <linux/tick.h>
+#include <linux/cpuidle.h>
#include <asm/system.h>
#include <asm/processor.h>
@@ -46,6 +47,14 @@ static int __init powersave_off(char *ar
}
__setup("powersave=off", powersave_off);
+#ifndef CONFIG_CPU_IDLE
+void cpuidle_idle_call(void)
+{
+ local_irq_enable();
+ cpu_relax();
+}
+#endif
+
/*
* The body of the idle task.
*/
@@ -60,35 +69,26 @@ void cpu_idle(void)
while (!need_resched() && !cpu_should_die()) {
ppc64_runlatch_off();
- if (ppc_md.power_save) {
- clear_thread_flag(TIF_POLLING_NRFLAG);
- /*
- * smp_mb is so clearing of TIF_POLLING_NRFLAG
- * is ordered w.r.t. need_resched() test.
- */
- smp_mb();
- local_irq_disable();
-
- /* Don't trace irqs off for idle */
- stop_critical_timings();
-
- /* check again after disabling irqs */
- if (!need_resched() && !cpu_should_die())
- ppc_md.power_save();
-
- start_critical_timings();
-
- local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- } else {
- /*
- * Go into low thread priority and possibly
- * low power mode.
- */
- HMT_low();
- HMT_very_low();
- }
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ /*
+ * smp_mb is so clearing of TIF_POLLING_NRFLAG
+ * is ordered w.r.t. need_resched() test.
+ */
+ smp_mb();
+ local_irq_disable();
+
+ /* Don't trace irqs off for idle */
+ stop_critical_timings();
+
+ /* check again after disabling irqs */
+ if (!need_resched() && !cpu_should_die())
+ cpuidle_idle_call();
+
+ start_critical_timings();
+
+ local_irq_enable();
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
}
HMT_medium();
^ permalink raw reply
* [v9 PATCH 7/9]: POWER: add a default_idle idle loop for POWER.
From: Arun R Bharadwaj @ 2009-10-16 9:46 UTC (permalink / raw)
To: Peter Zijlstra, Benjamin Herrenschmidt, Ingo Molnar,
Vaidyanathan Srinivasan, Dipankar Sarma, Balbir Singh, Andi Kleen,
Arun Bharadwaj
Cc: linux-arch, linux-acpi, linuxppc-dev, linux-kernel
In-Reply-To: <20091016093850.GB27350@linux.vnet.ibm.com>
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-10-16 15:08:50]:
In arch/powerpc/kernel/idle.c create a default_idle() routine by moving
the failover condition of the cpu_idle() idle loop. This is needed by
cpuidle infrastructure to call default_idle when other idle routines
are not yet registered. Functionality remains the same, but the code is
slightly moved around.
Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
arch/powerpc/Kconfig | 3 +++
arch/powerpc/include/asm/system.h | 1 +
arch/powerpc/kernel/idle.c | 6 ++++++
3 files changed, 10 insertions(+)
Index: linux.trees.git/arch/powerpc/Kconfig
===================================================================
--- linux.trees.git.orig/arch/powerpc/Kconfig
+++ linux.trees.git/arch/powerpc/Kconfig
@@ -94,6 +94,9 @@ config ARCH_HAS_ILOG2_U64
config ARCH_HAS_CPU_IDLE_WAIT
def_bool y
+config ARCH_HAS_DEFAULT_IDLE
+ def_bool y
+
config GENERIC_HWEIGHT
bool
default y
Index: linux.trees.git/arch/powerpc/include/asm/system.h
===================================================================
--- linux.trees.git.orig/arch/powerpc/include/asm/system.h
+++ linux.trees.git/arch/powerpc/include/asm/system.h
@@ -218,6 +218,7 @@ extern unsigned long klimit;
extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
+extern void default_idle(void);
extern int powersave_nap; /* set if nap mode can be used in idle loop */
/*
Index: linux.trees.git/arch/powerpc/kernel/idle.c
===================================================================
--- linux.trees.git.orig/arch/powerpc/kernel/idle.c
+++ linux.trees.git/arch/powerpc/kernel/idle.c
@@ -121,6 +121,12 @@ void cpu_idle_wait(void)
}
EXPORT_SYMBOL_GPL(cpu_idle_wait);
+void default_idle(void)
+{
+ HMT_low();
+ HMT_very_low();
+}
+
int powersave_nap;
#ifdef CONFIG_SYSCTL
^ permalink raw reply
* [v9 PATCH 8/9]: pSeries: implement pSeries processor idle module.
From: Arun R Bharadwaj @ 2009-10-16 9:47 UTC (permalink / raw)
To: Peter Zijlstra, Benjamin Herrenschmidt, Ingo Molnar,
Vaidyanathan Srinivasan, Dipankar Sarma, Balbir Singh, Andi Kleen,
Arun Bharadwaj
Cc: linux-arch, linux-acpi, linuxppc-dev, linux-kernel
In-Reply-To: <20091016093850.GB27350@linux.vnet.ibm.com>
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-10-16 15:08:50]:
This patch creates arch/powerpc/platforms/pseries/processor_idle.c,
which implements the cpuidle infrastructure for pseries.
It implements a pseries_cpuidle_loop() which would be the main idle loop
called from cpu_idle(). It makes decision of entering either
dedicated_snooze_loop or dedicated_cede_loop for dedicated lpar and
shared_cede_loop for shared lpar processor based on the
decision taken by the cpuidle governor.
Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/system.h | 1
arch/powerpc/kernel/sysfs.c | 2
arch/powerpc/platforms/pseries/Makefile | 1
arch/powerpc/platforms/pseries/processor_idle.c | 210 ++++++++++++++++++++++++
arch/powerpc/platforms/pseries/pseries.h | 8
5 files changed, 222 insertions(+)
Index: linux.trees.git/arch/powerpc/platforms/pseries/Makefile
===================================================================
--- linux.trees.git.orig/arch/powerpc/platforms/pseries/Makefile
+++ linux.trees.git/arch/powerpc/platforms/pseries/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst
obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o
obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_DTL) += dtl.o
+obj-$(CONFIG_PSERIES_PROCESSOR_IDLE) += processor_idle.o
Index: linux.trees.git/arch/powerpc/platforms/pseries/pseries.h
===================================================================
--- linux.trees.git.orig/arch/powerpc/platforms/pseries/pseries.h
+++ linux.trees.git/arch/powerpc/platforms/pseries/pseries.h
@@ -10,6 +10,8 @@
#ifndef _PSERIES_PSERIES_H
#define _PSERIES_PSERIES_H
+#include <linux/cpuidle.h>
+
extern void __init fw_feature_init(const char *hypertas, unsigned long len);
struct pt_regs;
@@ -40,4 +42,10 @@ extern unsigned long rtas_poweron_auto;
extern void find_udbg_vterm(void);
+DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
+
+#ifdef CONFIG_PSERIES_PROCESSOR_IDLE
+extern struct cpuidle_driver pseries_idle_driver;
+#endif
+
#endif /* _PSERIES_PSERIES_H */
Index: linux.trees.git/arch/powerpc/platforms/pseries/processor_idle.c
===================================================================
--- /dev/null
+++ linux.trees.git/arch/powerpc/platforms/pseries/processor_idle.c
@@ -0,0 +1,210 @@
+/*
+ * processor_idle - idle state cpuidle driver.
+ * Adapted from drivers/acpi/processor_idle.c
+ *
+ * Arun R Bharadwaj <arun@linux.vnet.ibm.com>
+ *
+ * Copyright (C) 2009 IBM Corporation.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
+
+#include <asm/paca.h>
+#include <asm/reg.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+
+#include "plpar_wrappers.h"
+#include "pseries.h"
+
+MODULE_AUTHOR("Arun R Bharadwaj");
+MODULE_DESCRIPTION("pSeries Idle State Driver");
+MODULE_LICENSE("GPL");
+
+struct cpuidle_driver pseries_idle_driver = {
+ .name = "pseries_idle",
+ .owner = THIS_MODULE,
+};
+
+DEFINE_PER_CPU(struct cpuidle_device, pseries_dev);
+
+#define IDLE_STATE_COUNT 2
+
+/* pSeries Idle state Flags */
+#define PSERIES_DEDICATED_SNOOZE (0x01)
+#define PSERIES_DEDICATED_CEDE (0x02)
+#define PSERIES_SHARED_CEDE (0x03)
+
+static int pseries_idle_init(struct cpuidle_device *dev)
+{
+ return cpuidle_register_device(dev);
+}
+
+static void shared_cede_loop(void)
+{
+ get_lppaca()->idle = 1;
+ cede_processor();
+ get_lppaca()->idle = 0;
+}
+
+static void dedicated_snooze_loop(void)
+{
+ local_irq_enable();
+ set_thread_flag(TIF_POLLING_NRFLAG);
+ while (!need_resched()) {
+ ppc64_runlatch_off();
+ HMT_low();
+ HMT_very_low();
+ }
+ HMT_medium();
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ smp_mb();
+ local_irq_disable();
+}
+
+static void dedicated_cede_loop(void)
+{
+ ppc64_runlatch_off();
+ HMT_medium();
+ cede_processor();
+}
+
+static int pseries_cpuidle_loop(struct cpuidle_device *dev,
+ struct cpuidle_state *st)
+{
+ ktime_t t1, t2;
+ s64 diff;
+ int ret;
+ unsigned long in_purr, out_purr;
+
+ get_lppaca()->idle = 1;
+ get_lppaca()->donate_dedicated_cpu = 1;
+ in_purr = mfspr(SPRN_PURR);
+
+ t1 = ktime_get();
+
+ if (st->flags & PSERIES_SHARED_CEDE)
+ shared_cede_loop();
+ else if (st->flags & PSERIES_DEDICATED_SNOOZE)
+ dedicated_snooze_loop();
+ else
+ dedicated_cede_loop();
+
+ t2 = ktime_get();
+ diff = ktime_to_us(ktime_sub(t2, t1));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ ret = (int) diff;
+
+ out_purr = mfspr(SPRN_PURR);
+ get_lppaca()->wait_state_cycles += out_purr - in_purr;
+ get_lppaca()->donate_dedicated_cpu = 0;
+ get_lppaca()->idle = 0;
+
+ return ret;
+}
+
+static int pseries_setup_cpuidle(struct cpuidle_device *dev, int cpu)
+{
+ int i;
+ struct cpuidle_state *state;
+
+ dev->cpu = cpu;
+
+ if (get_lppaca()->shared_proc) {
+ state = &dev->states[0];
+ snprintf(state->name, CPUIDLE_NAME_LEN, "IDLE");
+ state->enter = pseries_cpuidle_loop;
+ strncpy(state->desc, "shared_cede", CPUIDLE_DESC_LEN);
+ state->flags = PSERIES_SHARED_CEDE;
+ state->exit_latency = 0;
+ state->target_residency = 0;
+ return 0;
+ }
+
+ for (i = 0; i < IDLE_STATE_COUNT; i++) {
+ state = &dev->states[i];
+
+ snprintf(state->name, CPUIDLE_NAME_LEN, "CEDE%d", i);
+ state->enter = pseries_cpuidle_loop;
+
+ switch (i) {
+ case 0:
+ strncpy(state->desc, "snooze", CPUIDLE_DESC_LEN);
+ state->flags = PSERIES_DEDICATED_SNOOZE;
+ state->exit_latency = 0;
+ state->target_residency = 0;
+ break;
+
+ case 1:
+ strncpy(state->desc, "cede", CPUIDLE_DESC_LEN);
+ state->flags = PSERIES_DEDICATED_CEDE;
+ state->exit_latency = 1;
+ state->target_residency =
+ __get_cpu_var(smt_snooze_delay);
+ break;
+ }
+ }
+ dev->state_count = IDLE_STATE_COUNT;
+
+ return 0;
+}
+
+void update_smt_snooze_delay(int snooze)
+{
+ int cpu;
+ for_each_online_cpu(cpu)
+ per_cpu(pseries_dev, cpu).states[0].target_residency = snooze;
+}
+
+static int __init pseries_processor_idle_init(void)
+{
+ int cpu;
+ int result;
+
+ result = cpuidle_register_driver(&pseries_idle_driver);
+
+ if (result < 0)
+ return result;
+
+ printk(KERN_DEBUG "pSeries idle driver registered\n");
+
+ if (!firmware_has_feature(FW_FEATURE_SPLPAR)) {
+ printk(KERN_DEBUG "Using default idle\n");
+ return 0;
+ }
+
+ for_each_online_cpu(cpu) {
+ pseries_setup_cpuidle(&per_cpu(pseries_dev, cpu), cpu);
+ pseries_idle_init(&per_cpu(pseries_dev, cpu));
+ }
+
+ printk(KERN_DEBUG "Using cpuidle idle loop\n");
+
+ return 0;
+}
+
+device_initcall(pseries_processor_idle_init);
Index: linux.trees.git/arch/powerpc/include/asm/system.h
===================================================================
--- linux.trees.git.orig/arch/powerpc/include/asm/system.h
+++ linux.trees.git/arch/powerpc/include/asm/system.h
@@ -548,6 +548,7 @@ extern void account_system_vtime(struct
extern struct dentry *powerpc_debugfs_root;
void cpu_idle_wait(void);
+extern void update_smt_snooze_delay(int snooze);
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_SYSTEM_H */
Index: linux.trees.git/arch/powerpc/kernel/sysfs.c
===================================================================
--- linux.trees.git.orig/arch/powerpc/kernel/sysfs.c
+++ linux.trees.git/arch/powerpc/kernel/sysfs.c
@@ -18,6 +18,7 @@
#include <asm/machdep.h>
#include <asm/smp.h>
#include <asm/pmc.h>
+#include <asm/system.h>
#include "cacheinfo.h"
@@ -51,6 +52,7 @@ static ssize_t store_smt_snooze_delay(st
return -EINVAL;
per_cpu(smt_snooze_delay, cpu->sysdev.id) = snooze;
+ update_smt_snooze_delay(snooze);
return count;
}
^ permalink raw reply
* [v9 PATCH 9/9]: POWER: Enable default_idle when power_save=off.
From: Arun R Bharadwaj @ 2009-10-16 9:48 UTC (permalink / raw)
To: Peter Zijlstra, Benjamin Herrenschmidt, Ingo Molnar,
Vaidyanathan Srinivasan, Dipankar Sarma, Balbir Singh, Andi Kleen,
Arun Bharadwaj
Cc: linux-arch, linux-acpi, linuxppc-dev, linux-kernel
In-Reply-To: <20091016093850.GB27350@linux.vnet.ibm.com>
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-10-16 15:08:50]:
This patch enables default_idle when power_save=off kernel boot
option is specified.
Earlier, this was done by setting ppc_md.power_save = NULL and hence
HMT_low() and HMT_very_low() was called. Now this is defined under
default_idle() and hence by setting boot_option_idle_override = 1,
the cpuidle registration stuff does not happen and hence default_idle
is chosen in cpuidle_idle_call.
Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/processor.h | 2 ++
arch/powerpc/kernel/idle.c | 4 +++-
arch/powerpc/platforms/pseries/processor_idle.c | 5 +++++
3 files changed, 10 insertions(+), 1 deletion(-)
Index: linux.trees.git/arch/powerpc/include/asm/processor.h
===================================================================
--- linux.trees.git.orig/arch/powerpc/include/asm/processor.h
+++ linux.trees.git/arch/powerpc/include/asm/processor.h
@@ -332,6 +332,8 @@ static inline unsigned long get_clean_sp
}
#endif
+extern int boot_option_idle_override;
+
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_PROCESSOR_H */
Index: linux.trees.git/arch/powerpc/kernel/idle.c
===================================================================
--- linux.trees.git.orig/arch/powerpc/kernel/idle.c
+++ linux.trees.git/arch/powerpc/kernel/idle.c
@@ -40,9 +40,11 @@
#define cpu_should_die() 0
#endif
+int boot_option_idle_override = 0;
+
static int __init powersave_off(char *arg)
{
- ppc_md.power_save = NULL;
+ boot_option_idle_override = 1;
return 0;
}
__setup("powersave=off", powersave_off);
Index: linux.trees.git/arch/powerpc/platforms/pseries/processor_idle.c
===================================================================
--- linux.trees.git.orig/arch/powerpc/platforms/pseries/processor_idle.c
+++ linux.trees.git/arch/powerpc/platforms/pseries/processor_idle.c
@@ -185,6 +185,11 @@ static int __init pseries_processor_idle
int cpu;
int result;
+ if (boot_option_idle_override) {
+ printk(KERN_DEBUG "Using default idle\n");
+ return 0;
+ }
+
result = cpuidle_register_driver(&pseries_idle_driver);
if (result < 0)
^ permalink raw reply
* [PATCH] Found skb leak in mpc5200 fec on rxfifo error
From: Asier Llano Palacios @ 2009-10-16 11:51 UTC (permalink / raw)
To: linuxppc-dev, Grant Likely; +Cc: a.arzuaga
Hi all,
I finally found why in my mpc5200 based system (and in the lite5200) I
had leaks of skbs when receiving ethernet traffic at 100 Mbit/s so that
we generated an rxfifo error (to be able to get it I even reduced the
speed of the CPU using the PLL jumpers).
The problem was:
The reception packets are handled in the interrupt handler:
mpc52xx_fec_rx_interrupt. So this interrupt is being handled all the
time because we are receiving packets continuously.
The reception fifo errors are handled in the interrupt handler:
mpc52xx_fec_interrupt. This interruption is being handled very often
because we are receiving more packets that what we can handle, and that
generates a fifo reception error.
So it is very usual that the mpc52xx_fec_interrupt handler is executed
at the middle of the mpc52xx_fec_rx_interrupt handler. And I think that
it is not designed for that purpose.
The mpc52xx_fec_rx_interrupt uses bcom_retrieve_buffer and
bcom_submit_next_buffer. The mpc52xx_fec_interrupt calls to
mpc52xx_fec_reset which calls to mpc52xx_fec_free_rx_buffers and
mpc52xx_fec_alloc_rx_buffers, which at the end call bcom_retrieve_buffer
and bcom_submit_next_buffer.
Then we have two problems because of the same origin:
- bcom_retrieve_buffer and bcom_submit_next_buffer doesn't seem to be
atomic, so they cannot be called from one interrupt nested from
another one being executing those functions.
- Even if they were atomic, the mpc52xx_fec_rx_interrupt and the
mpc52xx_fec_reset functions are not intended to be called at the
same time.
Patch I managed to do:
I've managed to perform a patch that avoids the leak disabling the
irqs, but I have a remaining problem: The last packet to be transmited
is waiting for a packet to be received in order to egress (I don't know
why but I detected it experimentaly).
=20
Anyone with more experience can tell me what's wrong in this patch?
Thank you in advance,
Asier
Signed-off-by: Asier Llano <a.llano@ziv.es>
---
drivers/net/fec_mpc52xx.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff -urpN linux-2.6.31.2/drivers/net/fec_mpc52xx.c
linux-2.6.31.2-fec_mpc52xx_skb_leak/drivers/net/fec_mpc52xx.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- linux-2.6.31.2/drivers/net/fec_mpc52xx.c
+++ linux-2.6.31.2-fec_mpc52xx_skb_leak/drivers/net/fec_mpc52xx.c
@@ -85,13 +85,20 @@ MODULE_PARM_DESC(debug, "debugging messa
=20
static void mpc52xx_fec_tx_timeout(struct net_device *dev)
{
+ struct mpc52xx_fec_priv *priv =3D netdev_priv(dev);
+ unsigned long flags;
+
dev_warn(&dev->dev, "transmit timed out\n");
=20
+ spin_lock_irqsave(&priv->lock, flags);
+
mpc52xx_fec_reset(dev);
=20
dev->stats.tx_errors++;
=20
netif_wake_queue(dev);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
}
=20
static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
@@ -359,8 +366,9 @@ static irqreturn_t mpc52xx_fec_tx_interr
{
struct net_device *dev =3D dev_id;
struct mpc52xx_fec_priv *priv =3D netdev_priv(dev);
+ unsigned long flags;
=20
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
=20
while (bcom_buffer_done(priv->tx_dmatsk)) {
struct sk_buff *skb;
@@ -375,7 +383,7 @@ static irqreturn_t mpc52xx_fec_tx_interr
=20
netif_wake_queue(dev);
=20
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
=20
return IRQ_HANDLED;
}
@@ -384,6 +392,9 @@ static irqreturn_t mpc52xx_fec_rx_interr
{
struct net_device *dev =3D dev_id;
struct mpc52xx_fec_priv *priv =3D netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
=20
while (bcom_buffer_done(priv->rx_dmatsk)) {
struct sk_buff *skb;
@@ -445,6 +456,8 @@ static irqreturn_t mpc52xx_fec_rx_interr
bcom_submit_next_buffer(priv->rx_dmatsk, skb);
}
=20
+ spin_unlock_irqrestore(&priv->lock, flags);
+
return IRQ_HANDLED;
}
=20
@@ -454,6 +467,7 @@ static irqreturn_t mpc52xx_fec_interrupt
struct mpc52xx_fec_priv *priv =3D netdev_priv(dev);
struct mpc52xx_fec __iomem *fec =3D priv->fec;
u32 ievent;
+ unsigned long flags;
=20
ievent =3D in_be32(&fec->ievent);
=20
@@ -471,9 +485,14 @@ static irqreturn_t mpc52xx_fec_interrupt
if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
=20
+ spin_lock_irqsave(&priv->lock, flags);
+
mpc52xx_fec_reset(dev);
=20
netif_wake_queue(dev);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
return IRQ_HANDLED;
}=20
=20
----------------------------------------- PLEASE NOTE =
-------------------------------------------
This message, along with any attachments, may be confidential or legally =
privileged.=20
It is intended only for the named person(s), who is/are the only =
authorized recipients.
If this message has reached you in error, kindly destroy it without =
review and notify the sender immediately.
Thank you for your help.
ZIV uses virus scanning software but excludes any liability for viruses =
contained in any attachment.
=20
------------------------------------ ROGAMOS LEA ESTE TEXTO =
-------------------------------
Este mensaje y sus anexos pueden contener informaci=F3n confidencial y/o =
con derecho legal.=20
Est=E1 dirigido =FAnicamente a la/s persona/s o entidad/es rese=F1adas =
como =FAnico destinatario autorizado.
Si este mensaje le hubiera llegado por error, por favor elim=EDnelo sin =
revisarlo ni reenviarlo y notif=EDquelo inmediatamente al remitente. =
Gracias por su colaboraci=F3n. =20
ZIV utiliza software antivirus, pero no se hace responsable de los virus =
contenidos en los ficheros anexos.
^ permalink raw reply
* [PATCH] Found skb leak in mpc5200 fec on rxfifo error
From: Asier Llano Palacios @ 2009-10-16 12:01 UTC (permalink / raw)
To: linuxppc-dev, Grant Likely; +Cc: a.arzuaga
(I'm sorry about my previous message with a legal notice, this time
I resent it with another mail server that doesn't include the legal
notice for me)
Hi all,
I finally found why in my mpc5200 based system (and in the lite5200) I
had leaks of skbs when receiving ethernet traffic at 100 Mbit/s so that
we generated an rxfifo error (to be able to get it I even reduced the
speed of the CPU using the PLL jumpers).
The problem was:
The reception packets are handled in the interrupt handler:
mpc52xx_fec_rx_interrupt. So this interrupt is being handled all the
time because we are receiving packets continuously.
The reception fifo errors are handled in the interrupt handler:
mpc52xx_fec_interrupt. This interruption is being handled very often
because we are receiving more packets that what we can handle, and that
generates a fifo reception error.
So it is very usual that the mpc52xx_fec_interrupt handler is executed
at the middle of the mpc52xx_fec_rx_interrupt handler. And I think that
it is not designed for that purpose.
The mpc52xx_fec_rx_interrupt uses bcom_retrieve_buffer and
bcom_submit_next_buffer. The mpc52xx_fec_interrupt calls to
mpc52xx_fec_reset which calls to mpc52xx_fec_free_rx_buffers and
mpc52xx_fec_alloc_rx_buffers, which at the end call bcom_retrieve_buffer
and bcom_submit_next_buffer.
Then we have two problems because of the same origin:
- bcom_retrieve_buffer and bcom_submit_next_buffer doesn't seem to be
atomic, so they cannot be called from one interrupt nested from
another one being executing those functions.
- Even if they were atomic, the mpc52xx_fec_rx_interrupt and the
mpc52xx_fec_reset functions are not intended to be called at the
same time.
Patch I managed to do:
I've managed to perform a patch that avoids the leak disabling the
irqs, but I have a remaining problem: The last packet to be transmited
is waiting for a packet to be received in order to egress (I don't know
why but I detected it experimentaly).
Anyone with more experience can tell me what's wrong in this patch?
Thank you in advance,
Asier
Signed-off-by: Asier Llano <a.llano@ziv.es>
---
drivers/net/fec_mpc52xx.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff -urpN linux-2.6.31.2/drivers/net/fec_mpc52xx.c
linux-2.6.31.2-fec_mpc52xx_skb_leak/drivers/net/fec_mpc52xx.c
================================================================
--- linux-2.6.31.2/drivers/net/fec_mpc52xx.c
+++ linux-2.6.31.2-fec_mpc52xx_skb_leak/drivers/net/fec_mpc52xx.c
@@ -85,13 +85,20 @@ MODULE_PARM_DESC(debug, "debugging messa
static void mpc52xx_fec_tx_timeout(struct net_device *dev)
{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
dev_warn(&dev->dev, "transmit timed out\n");
+ spin_lock_irqsave(&priv->lock, flags);
+
mpc52xx_fec_reset(dev);
dev->stats.tx_errors++;
netif_wake_queue(dev);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
}
static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
@@ -359,8 +366,9 @@ static irqreturn_t mpc52xx_fec_tx_interr
{
struct net_device *dev = dev_id;
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ unsigned long flags;
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
while (bcom_buffer_done(priv->tx_dmatsk)) {
struct sk_buff *skb;
@@ -375,7 +383,7 @@ static irqreturn_t mpc52xx_fec_tx_interr
netif_wake_queue(dev);
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
return IRQ_HANDLED;
}
@@ -384,6 +392,9 @@ static irqreturn_t mpc52xx_fec_rx_interr
{
struct net_device *dev = dev_id;
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
while (bcom_buffer_done(priv->rx_dmatsk)) {
struct sk_buff *skb;
@@ -445,6 +456,8 @@ static irqreturn_t mpc52xx_fec_rx_interr
bcom_submit_next_buffer(priv->rx_dmatsk, skb);
}
+ spin_unlock_irqrestore(&priv->lock, flags);
+
return IRQ_HANDLED;
}
@@ -454,6 +467,7 @@ static irqreturn_t mpc52xx_fec_interrupt
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
struct mpc52xx_fec __iomem *fec = priv->fec;
u32 ievent;
+ unsigned long flags;
ievent = in_be32(&fec->ievent);
@@ -471,9 +485,14 @@ static irqreturn_t mpc52xx_fec_interrupt
if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
+ spin_lock_irqsave(&priv->lock, flags);
+
mpc52xx_fec_reset(dev);
netif_wake_queue(dev);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
return IRQ_HANDLED;
}
^ permalink raw reply
* Re: MPC5121 CAN and USB
From: Kári Davíðsson @ 2009-10-16 13:53 UTC (permalink / raw)
To: Wolfgang Denk; +Cc: linuxppc-dev@ozlabs.org, paul.gibson2074@gmail.com
In-Reply-To: <20091015183039.A577EECA6BE@gemini.denx.de>
Hello,
Wolfgang Denk wrote:
> Dear =?ISO-8859-1?Q?K=E1ri_Dav=ED=F0sson?=,
>
> In message <4AD70927.3030401@marel.com> you wrote:
>> The kernel from the BSP on Freescale site is crashing on the CAN in my case
>> (might be a hardware bug).
>
> I don;t think so. There are some problems in this code, for example
> the clocks seem to be wrong. Not toi menthin that the whole code is
> hoplessly old and without chance of ever being merged into mainline.
Indeed. I had to disable the follwing clock stuff to prevent crashing. I am
running on Rev 3 chip.
diff --git a/drivers/net/can/mscan/mpc52xx_can.c b/drivers/net/can/mscan/mpc52xx_can.c
index e1d78b9..55def57 100644
--- a/drivers/net/can/mscan/mpc52xx_can.c
+++ b/drivers/net/can/mscan/mpc52xx_can.c
@@ -104,8 +104,8 @@ static int __devinit mpc52xx_can_probe(struct platform_device *pdev)
port_clk = clk_get(NULL, clk_name);
/* update clock rate for mpc5121e rev2 chip */
- if (port_clk)
- pdata->clock_frq = clk_get_rate(port_clk);
+// if (port_clk)
+// pdata->clock_frq = clk_get_rate(port_clk);
/* enable clock for mscan module */
clk_enable(mscan_clk);
>
>> I could not find the source for the kernel in the BSP or on the freescale site.
>
> Extracting just the sources from LTIB (without actually building all
> of it) is indeed not exactly easy.
>
>> I had not looked at http://git.denx.de/?p=linux-2.6-denx.git;a=shortlog;h=refs/heads/ltib-mpc5121ads-20090602
>
> Be careful. There are several branches that are intended for reference
> only, or reflect work in progress. These are usually not intended for
> use real use in a project:
>
> The "ltib-mpc5121ads-20090602" branch reflects the exact state of the
> kernel contained in the LTIB with this name (dated July 2009, despite
> the name; based at 2.6.24.6, i. e. 7+ kernel versions behind).
Yes this I found it odd that the mpc5121 work is so far behind.
We have two other mpc5200 based boards that I am running with 2.6.29.
They are running well.
>
> The "mpc512x" branch contains a much smaller subset of drivers, but is
> based on a more recent kernel tree (2.6.31-rc5) and is the base of our
> (currently dozing) attempts to push this code into mainline.
>
>> I am now in the progress of cloning the linux-mpc512x git from denx and building from it.
>> Hopefully that will help me.
>
> Do not do this. This old repository was intended for co-operation
> with John Rigby, when he was still working for Freescale. It is a
> dead end and totally unsupported. Guess I should remove it. Indeed.
> Removed now. Sorry for the confusion.
Already done it and I got it to compile but as you hint I am having other problems.
Serial ports and ethernet works though :)
>
> Best regards,
>
> Wolfgang Denk
>
rg
kd
^ permalink raw reply related
* Re: UBIFS problem on MPC8536DS
From: Scott Wood @ 2009-10-16 15:31 UTC (permalink / raw)
To: Felix Radensky
Cc: linuxppc-dev@ozlabs.org, linux-mtd@lists.infradead.org,
Adrian Hunter
In-Reply-To: <4AD7FE37.1060705@embedded-sol.com>
On Fri, Oct 16, 2009 at 07:01:43AM +0200, Felix Radensky wrote:
> Thanks for confirmation. So the real problem is eLBC ?
> What happens if I access other devices on eLBC (e.g. FPGA)
> simultaneously with NAND or NOR ?
AFAICT, the problem is NAND being accessed simultaneously with anything else
on the eLBC (at least GPCM -- not sure about UPM). Instead of delaying the
memory-like transaction until the NAND special operation has completed, it
seems to just abort the NAND operation.
eLBC can't really tell the difference whether you've got NOR or FPGA hooked
up to a GPCM chip select, so the problem should still apply.
-Scott
^ permalink raw reply
* Re: [PATCH] hvc_console: returning 0 from put_chars is not an error
From: Scott Wood @ 2009-10-16 15:33 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev, Linux Kernel Mailing List, Christian Borntraeger,
brueckner, Timur Tabi, Alan Cox
In-Reply-To: <1255668405.19032.13.camel@pasglop>
On Fri, Oct 16, 2009 at 03:46:45PM +1100, Benjamin Herrenschmidt wrote:
> On Thu, 2009-10-15 at 13:57 -0500, Scott Wood wrote:
> > I'd say the dropping approach is quite undesirable (significant
> > potential for output loss unless the buffer is huge), unless there's
> > simply no way to safely spin. Hopefully there are no such backends, but
> > if there are perhaps we can have them return some special code to
> > indicate that.
>
> Should never spin.
Why is a hypervisor console different than a serial port in this regard?
> Best is to keep a copy in the upper layer of the pending data and throttle
> (not accept further data from tty layer) until we have managed to flush
> out that "pending" buffer.
The data isn't coming from the tty layer -- we're talking about printk. How
do you throttle that without spinning?
I agree that it shouldn't spin when handling tty I/O.
-Scott
^ permalink raw reply
* Re: Support for S29JL064 in MPC8272ADS?
From: Roberto Guerra @ 2009-10-16 15:37 UTC (permalink / raw)
To: Scott Wood, linuxppc-dev
In-Reply-To: <4AD6454C.60705@freescale.com>
In the last few days, I made this progress (<snip> indicates where I
cropped the file to the relevant sections):
$ cat myboard.dts
<snip>
localbus@f0010100 {
compatible =3D "fsl,mpc8280-localbus",
"fsl,pq2-localbus";
#address-cells =3D <2>;
#size-cells =3D <1>;
reg =3D <f0010100 60>;
ranges =3D <0 0 ffe00000 00800000>;
flash@0,0 {
compatible =3D "cfi-flash";
reg =3D <0 0 800000>;
bank-width =3D <2>;
device-width =3D <2>;
};
};
<snip>
$ cat linux/.config
<snip>
#
# Generic Driver Options
#
CONFIG_MTD=3Dy
CONFIG_MTD_DEBUG=3Dy
CONFIG_MTD_DEBUG_VERBOSE=3D3
# CONFIG_MTD_CONCAT is not set
CONFIG_MTD_PARTITIONS=3Dy
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=3Dy
# CONFIG_MTD_OF_PARTS is not set
#
# User Modules And Translation Layers
#
# CONFIG_MTD_CHAR is not set
# CONFIG_MTD_BLKDEVS is not set
# CONFIG_MTD_BLOCK is not set
# CONFIG_MTD_BLOCK_RO is not set
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
# CONFIG_MTD_OOPS is not set
#
# RAM/ROM/Flash chip drivers
#
CONFIG_MTD_CFI=3Dy
# CONFIG_MTD_JEDECPROBE is not set
CONFIG_MTD_GEN_PROBE=3Dy
CONFIG_MTD_CFI_ADV_OPTIONS=3Dy
# CONFIG_MTD_CFI_NOSWAP is not set
# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
CONFIG_MTD_CFI_LE_BYTE_SWAP=3Dy
CONFIG_MTD_CFI_GEOMETRY=3Dy
# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
CONFIG_MTD_MAP_BANK_WIDTH_2=3Dy
# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
CONFIG_MTD_CFI_I1=3Dy
# CONFIG_MTD_CFI_I2 is not set
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
# CONFIG_MTD_OTP is not set
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CFI_AMDSTD=3Dy
# CONFIG_MTD_CFI_STAA is not set
CONFIG_MTD_CFI_UTIL=3Dy
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
CONFIG_MTD_PHYSMAP=3Dy
CONFIG_MTD_PHYSMAP_START=3D0xff800000
CONFIG_MTD_PHYSMAP_LEN=3D0x800000
CONFIG_MTD_PHYSMAP_BANKWIDTH=3D2
# CONFIG_MTD_PHYSMAP_OF is not set
# CONFIG_MTD_INTEL_VR_NOR is not set
# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
#
# CONFIG_MTD_PMC551 is not set
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_BLOCK2MTD is not set
<snip>
=3D> tftpboot 200000 uImage
=3D> tftpboot 400000 myboard.dtb
=3D> echo $bootargs
console=3DttyCPM0,115200 root=3D/dev/mtdblock1 rw
mtdparts=3Dphys:1600K(ROM)ro,6M(root),512K(U-Boot)ro,512K(unused)
rootfstype=3Djffs2
=3D> bootm 200000 - 400000
<snip>
physmap platform flash device: 00800000 at ff800000
physmap-flash.0: Found 1 x16 devices at 0x0 in 16-bit bank
Amd/Fujitsu Extended Query Table at 0x0040
physmap-flash.0: CFI does not contain boot bank location. Assuming
top.
number of CFI chips: 1
cfi_cmdset_0002: Disabling erase-suspend-program due to code
brokenness.
RedBoot partition parsing not available
mtd: Giving out device 0 to physmap-flash.0
mice: PS/2 mouse device common for all mice
TCP cubic registered
NET: Registered protocol family 1
NET: Registered protocol family 17
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
Root-NFS: No NFS server available, giving up.
VFS: Unable to mount root fs via NFS, trying floppy.
MTDSB: dev_name "/dev/root"
MTDSB: path_lookup() returned 0, inode c1400aa0
List of all partitions:
0100 4096 ram0 (driver?)
0101 4096 ram1 (driver?)
0102 4096 ram2 (driver?)
0103 4096 ram3 (driver?)
0104 4096 ram4 (driver?)
0105 4096 ram5 (driver?)
0106 4096 ram6 (driver?)
0107 4096 ram7 (driver?)
0108 4096 ram8 (driver?)
0109 4096 ram9 (driver?)
010a 4096 ram10 (driver?)
010b 4096 ram11 (driver?)
010c 4096 ram12 (driver?)
010d 4096 ram13 (driver?)
010e 4096 ram14 (driver?)
010f 4096 ram15 (driver?)
No filesystem could mount root, tried: jffs2
Kernel panic - not syncing: VFS: Unable to mount root fs on
unknown-block(2,0)
Rebooting in 180 seconds..
The key change in my kernel config was the BIG_ENDIAN=3DY.
The kernel probes the AMD chip, but it can't see the partitions.
I guess now I will have to define my mtd partitions in either FDT or
in the kernel arguments.
Which is the best way to define them? If the partitions are defined in
both FDT and bootargs, which one takes precedence?
-Roberto
On Wed, Oct 14, 2009 at 5:40 PM, Scott Wood <scottwood@freescale.com> wrote=
:
> Roberto Guerra wrote:
>>
>> I've been learning how to modify the dts from
>>
>> http://www.mjmwired.net/kernel/Documentation/powerpc/dts-bindings/mtd-ph=
ysmap.txt#49
>> The original mpc8272ads.dts represents four 8-bit JEDEC Sharp flash
>> chips in 1 SIMM module:
>> [snip] =A0 =A0 =A0 =A0localbus@f0010100 {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "fsl,mpc8280-localbus",
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "fsl,pq2-localbu=
s";
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0#address-cells =3D <2>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0#size-cells =3D <1>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <f0010100 60>;
>>
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ranges =3D <0 0 fe000000 00800000
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A01 0 f4500000 00008000
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A08 0 f8200000 00008000=
>;
>>
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flash@0,0 {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "jedec-fla=
sh";
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <0 0 800000>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bank-width =3D <4>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0device-width =3D <1>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0};
>> [snip]
>> My board (based on the PQ2FADS, using the MPC8272ADS BSP)
>
> Don't base anything on the BSPs, unless there's something in them that yo=
u
> really need that isn't upstream. =A0There is pq2fads support in current
> upstream kernels.
>
>> uses one
>> 16-bit Spansion (AMD) CFI chip at addresses FF800000 through FFFFFFFF.
>> It probably needs to be represented this way (I've only made changes
>> to the "flash" section.
>> [snip]
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flash@0,0 {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "amd, s29j=
l064h", "cfi-flash";
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <0 0 800000>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bank-width =3D <2>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0device-width =3D <2>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0};
>> [snip]
>> However, I don't know what would be the correct addresses to type
>> after "localbus", "flash" and "reg". Is this enough information to
>> define my dts?
>
> The flash node looks good, other than that there shouldn't be a space aft=
er
> "amd,".
>
> In the localbus node, change fe000000 to ff800000. =A0Remove or change th=
e
> other ranges entries if they don't describe your board's chipselects.
>
> If your IMMR is somewhere other than 0xf0000000, update the f0010100 to
> match.
>
> -Scott
>
>
^ permalink raw reply
* Re: Support for S29JL064 in MPC8272ADS?
From: Roberto Guerra @ 2009-10-16 15:55 UTC (permalink / raw)
To: Scott Wood, linuxppc-dev
In-Reply-To: <7c4144600910160837y3d70ccd2yeeeb220da7e556c3@mail.gmail.com>
Sorry I made a typo: LITTLE endian byte swap is enabled for Flash Chip driv=
ers:
CONFIG_MTD_CFI_LE_BYTE_SWAP=3Dy
On Fri, Oct 16, 2009 at 11:37 AM, Roberto Guerra
<roberto.j.guerra@gmail.com> wrote:
> In the last few days, I made this progress (<snip> indicates where I
> cropped the file to the relevant sections):
>
> $ cat myboard.dts
> <snip>
> =A0 =A0 =A0 =A0localbus@f0010100 {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "fsl,mpc8280-localbus",
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "fsl,pq2-localbus=
";
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0#address-cells =3D <2>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0#size-cells =3D <1>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <f0010100 60>;
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ranges =3D <0 0 ffe00000 00800000>;
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flash@0,0 {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "cfi-flash"=
;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <0 0 800000>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bank-width =3D <2>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0device-width =3D <2>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0};
> =A0 =A0 =A0 =A0};
> <snip>
>
> $ cat linux/.config
> <snip>
> #
> # Generic Driver Options
> #
> CONFIG_MTD=3Dy
> CONFIG_MTD_DEBUG=3Dy
> CONFIG_MTD_DEBUG_VERBOSE=3D3
> # CONFIG_MTD_CONCAT is not set
> CONFIG_MTD_PARTITIONS=3Dy
> # CONFIG_MTD_REDBOOT_PARTS is not set
> CONFIG_MTD_CMDLINE_PARTS=3Dy
> # CONFIG_MTD_OF_PARTS is not set
> #
> # User Modules And Translation Layers
> #
> # CONFIG_MTD_CHAR is not set
> # CONFIG_MTD_BLKDEVS is not set
> # CONFIG_MTD_BLOCK is not set
> # CONFIG_MTD_BLOCK_RO is not set
> # CONFIG_FTL is not set
> # CONFIG_NFTL is not set
> # CONFIG_INFTL is not set
> # CONFIG_RFD_FTL is not set
> # CONFIG_SSFDC is not set
> # CONFIG_MTD_OOPS is not set
> #
> # RAM/ROM/Flash chip drivers
> #
> CONFIG_MTD_CFI=3Dy
> # CONFIG_MTD_JEDECPROBE is not set
> CONFIG_MTD_GEN_PROBE=3Dy
> CONFIG_MTD_CFI_ADV_OPTIONS=3Dy
> # CONFIG_MTD_CFI_NOSWAP is not set
> # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
> CONFIG_MTD_CFI_LE_BYTE_SWAP=3Dy
> CONFIG_MTD_CFI_GEOMETRY=3Dy
> # CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
> CONFIG_MTD_MAP_BANK_WIDTH_2=3Dy
> # CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
> # CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
> # CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
> # CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
> CONFIG_MTD_CFI_I1=3Dy
> # CONFIG_MTD_CFI_I2 is not set
> # CONFIG_MTD_CFI_I4 is not set
> # CONFIG_MTD_CFI_I8 is not set
> # CONFIG_MTD_OTP is not set
> # CONFIG_MTD_CFI_INTELEXT is not set
> CONFIG_MTD_CFI_AMDSTD=3Dy
> # CONFIG_MTD_CFI_STAA is not set
> CONFIG_MTD_CFI_UTIL=3Dy
> # CONFIG_MTD_RAM is not set
> # CONFIG_MTD_ROM is not set
> # CONFIG_MTD_ABSENT is not set
> #
> # Mapping drivers for chip access
> #
> # CONFIG_MTD_COMPLEX_MAPPINGS is not set
> CONFIG_MTD_PHYSMAP=3Dy
> CONFIG_MTD_PHYSMAP_START=3D0xff800000
> CONFIG_MTD_PHYSMAP_LEN=3D0x800000
> CONFIG_MTD_PHYSMAP_BANKWIDTH=3D2
> # CONFIG_MTD_PHYSMAP_OF is not set
> # CONFIG_MTD_INTEL_VR_NOR is not set
> # CONFIG_MTD_PLATRAM is not set
> #
> # Self-contained MTD device drivers
> #
> # CONFIG_MTD_PMC551 is not set
> # CONFIG_MTD_SLRAM is not set
> # CONFIG_MTD_PHRAM is not set
> # CONFIG_MTD_MTDRAM is not set
> # CONFIG_MTD_BLOCK2MTD is not set
> <snip>
>
> =3D> tftpboot 200000 uImage
> =3D> tftpboot 400000 myboard.dtb
> =3D> echo $bootargs
> console=3DttyCPM0,115200 root=3D/dev/mtdblock1 rw
> mtdparts=3Dphys:1600K(ROM)ro,6M(root),512K(U-Boot)ro,512K(unused)
> rootfstype=3Djffs2
> =3D> bootm 200000 - 400000
> <snip>
> physmap platform flash device: 00800000 at ff800000
> physmap-flash.0: Found 1 x16 devices at 0x0 in 16-bit bank
> =A0Amd/Fujitsu Extended Query Table at 0x0040
> physmap-flash.0: CFI does not contain boot bank location. Assuming
> top.
> number of CFI chips: 1
> cfi_cmdset_0002: Disabling erase-suspend-program due to code
> brokenness.
> RedBoot partition parsing not available
> mtd: Giving out device 0 to physmap-flash.0
> mice: PS/2 mouse device common for all mice
> TCP cubic registered
> NET: Registered protocol family 1
> NET: Registered protocol family 17
> RPC: Registered udp transport module.
> RPC: Registered tcp transport module.
> Root-NFS: No NFS server available, giving up.
> VFS: Unable to mount root fs via NFS, trying floppy.
> MTDSB: dev_name "/dev/root"
> MTDSB: path_lookup() returned 0, inode c1400aa0
> List of all partitions:
> 0100 =A0 =A0 =A0 4096 ram0 (driver?)
> 0101 =A0 =A0 =A0 4096 ram1 (driver?)
> 0102 =A0 =A0 =A0 4096 ram2 (driver?)
> 0103 =A0 =A0 =A0 4096 ram3 (driver?)
> 0104 =A0 =A0 =A0 4096 ram4 (driver?)
> 0105 =A0 =A0 =A0 4096 ram5 (driver?)
> 0106 =A0 =A0 =A0 4096 ram6 (driver?)
> 0107 =A0 =A0 =A0 4096 ram7 (driver?)
> 0108 =A0 =A0 =A0 4096 ram8 (driver?)
> 0109 =A0 =A0 =A0 4096 ram9 (driver?)
> 010a =A0 =A0 =A0 4096 ram10 (driver?)
> 010b =A0 =A0 =A0 4096 ram11 (driver?)
> 010c =A0 =A0 =A0 4096 ram12 (driver?)
> 010d =A0 =A0 =A0 4096 ram13 (driver?)
> 010e =A0 =A0 =A0 4096 ram14 (driver?)
> 010f =A0 =A0 =A0 4096 ram15 (driver?)
> No filesystem could mount root, tried: =A0jffs2
> Kernel panic - not syncing: VFS: Unable to mount root fs on
> unknown-block(2,0)
> Rebooting in 180 seconds..
>
> The key change in my kernel config was the BIG_ENDIAN=3DY.
> The kernel probes the AMD chip, but it can't see the partitions.
> I guess now I will have to define my mtd partitions in either FDT or
> in the kernel arguments.
> Which is the best way to define them? If the partitions are defined in
> both FDT and bootargs, which one takes precedence?
>
> -Roberto
>
>
> On Wed, Oct 14, 2009 at 5:40 PM, Scott Wood <scottwood@freescale.com> wro=
te:
>> Roberto Guerra wrote:
>>>
>>> I've been learning how to modify the dts from
>>>
>>> http://www.mjmwired.net/kernel/Documentation/powerpc/dts-bindings/mtd-p=
hysmap.txt#49
>>> The original mpc8272ads.dts represents four 8-bit JEDEC Sharp flash
>>> chips in 1 SIMM module:
>>> [snip] =A0 =A0 =A0 =A0localbus@f0010100 {
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "fsl,mpc8280-localbus",
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "fsl,pq2-localb=
us";
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0#address-cells =3D <2>;
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0#size-cells =3D <1>;
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <f0010100 60>;
>>>
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ranges =3D <0 0 fe000000 00800000
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A01 0 f4500000 0000800=
0
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A08 0 f8200000 0000800=
0>;
>>>
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flash@0,0 {
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "jedec-fl=
ash";
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <0 0 800000>;
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bank-width =3D <4>;
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0device-width =3D <1>;
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0};
>>> [snip]
>>> My board (based on the PQ2FADS, using the MPC8272ADS BSP)
>>
>> Don't base anything on the BSPs, unless there's something in them that y=
ou
>> really need that isn't upstream. =A0There is pq2fads support in current
>> upstream kernels.
>>
>>> uses one
>>> 16-bit Spansion (AMD) CFI chip at addresses FF800000 through FFFFFFFF.
>>> It probably needs to be represented this way (I've only made changes
>>> to the "flash" section.
>>> [snip]
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flash@0,0 {
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "amd, s29=
jl064h", "cfi-flash";
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <0 0 800000>;
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bank-width =3D <2>;
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0device-width =3D <2>;
>>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0};
>>> [snip]
>>> However, I don't know what would be the correct addresses to type
>>> after "localbus", "flash" and "reg". Is this enough information to
>>> define my dts?
>>
>> The flash node looks good, other than that there shouldn't be a space af=
ter
>> "amd,".
>>
>> In the localbus node, change fe000000 to ff800000. =A0Remove or change t=
he
>> other ranges entries if they don't describe your board's chipselects.
>>
>> If your IMMR is somewhere other than 0xf0000000, update the f0010100 to
>> match.
>>
>> -Scott
>>
>>
>
^ permalink raw reply
* Re: [PATCH v0 1/2] DMA: fsldma: Disable DMA_INTERRUPT when Async_tx enabled
From: Ira W. Snyder @ 2009-10-16 15:33 UTC (permalink / raw)
To: Dan Williams
Cc: herbert, linux-kernel, linux-raid, linuxppc-dev, Vishnu Suresh,
linux-crypto, Timur Tabi
In-Reply-To: <e9c3a7c20910151825o67cd2712id91aead70f84987c@mail.gmail.com>
On Thu, Oct 15, 2009 at 06:25:14PM -0700, Dan Williams wrote:
> [ added Leo and Timur to the Cc ]
>
> On Wed, Oct 14, 2009 at 11:41 PM, Vishnu Suresh <Vishnu@freescale.com> wrote:
> > This patch disables the use of DMA_INTERRUPT capability with Async_tx
> >
> > The fsldma produces a null transfer with DMA_INTERRUPT
> > capability when used with Async_tx. When RAID devices queue
> > a transaction via Async_tx, this results in a hang.
> >
> > Signed-off-by: Vishnu Suresh <Vishnu@freescale.com>
> > ---
> > drivers/dma/fsldma.c | 6 ++++++
> > 1 files changed, 6 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
> > index 296f9e7..66d9b39 100644
> > --- a/drivers/dma/fsldma.c
> > +++ b/drivers/dma/fsldma.c
> > @@ -1200,7 +1200,13 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
> > - fdev->reg.start + 1);
> >
> > dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
> > +#ifndef CONFIG_ASYNC_CORE
> > + /*
> > + * The DMA_INTERRUPT async_tx is a NULL transfer, which will
> > + * triger a PE interrupt.
> > + */
> > dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
> > +#endif
> > dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
> > fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
> > fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
>
> You are basically saying that fsl_dma_prep_interrupt() is buggy. Can
> that routine be fixed rather than this piecemeal solution? If it
> cannot be fixed (i.e. hardware issue) then fsl_dma_prep_interrupt()
> should just be disabled/deleted altogether.
>
For what it's worth, I've used the following code in the recent past,
without any issues. This was on an 83xx, within the last few kernel
releases. I haven't tried it on the latest -rc.
Using device_prep_dma_memcpy() can trigger a callback as well, so the
interrupt feature isn't strictly needed. Just attach the callback to the
last memcpy operation.
static dma_cookie_t dma_async_interrupt(struct dma_chan *chan,
dma_async_tx_callback callback,
void *data)
{
struct dma_device *dev = chan->device;
struct dma_async_tx_descriptor *tx;
/* Set up the DMA */
tx = dev->device_prep_dma_interrupt(chan, DMA_PREP_INTERRUPT);
if (!tx)
return -ENOMEM;
tx->callback = callback;
tx->callback_param = data;
return tx->tx_submit(tx);
}
Ira
^ permalink raw reply
* Re: [PATCH] * mpc8313erdb.dts: Fixed eTSEC interrupt assignment.
From: Scott Wood @ 2009-10-16 16:01 UTC (permalink / raw)
To: Richard Cochran; +Cc: 'linuxppc-dev@lists.ozlabs.org'
In-Reply-To: <95DC1AA8EC908B48939B72CF375AA5E30E2AE800@alice.at.omicron.at>
On Fri, Oct 16, 2009 at 08:31:19AM +0200, Richard Cochran wrote:
> > -----Original Message-----
> > From: Scott Wood [mailto:scottwood@freescale.com]
> > Subject: Re: [PATCH] * mpc8313erdb.dts: Fixed eTSEC interrupt assignment.
> >
> > On Thu, Oct 15, 2009 at 02:19:30PM +0200, Richard Cochran wrote:
> > > 2. Having only one dts for his board, but Ethernet doesn't work.
> >
> > The point is to fix u-boot so that it *does* work with only one dts. If
> > people not upgrading u-boot is your concern, we could put the fixup in the
> > Linux platform code instead.
>
> Yes, I was thinking that upgrading u-boot can be problematic for
> people who don't have a JTAG flash tool, in case things go wrong.
Right, so we could put a fixup in Linux as well to handle that case (make
sure not to blindly reverse, though, in case u-boot has already fixed it
up).
> But I thought the whole point of the device tree was, that it is easy
> to produce a dts that exactly matches a particular physical board
> design.
It's the dtb that the kernel sees (possibly after platform fixups, though
that's not the ideal case) that is supposed to exactly match the hardware.
The dts is just one source (albeit the most significant one) of the data
that goes into the final dtb.
There are boards that have several orthogonal configuration options that
can't be probed -- we'd have to provide dozens (or worse) of .dts files in
order to cover all of them without any runtime fixup. Not to mention things
like memory size and clock frequency...
> If MPC8313-ERDB REVC has a different IRQ routing, then doesn't
> it deserve its own dts?
I'm inclined to say no, though I wouldn't object too hard in this case if
people really want it. But we should still put in a u-boot fixup so that if
you have a new u-boot it doesn't matter which dts you use.
> Or do only *some* of the REVC boards have this
> routing?
They should all have it.
> > And feel free to ask through official Freescale support channels why the
> > U-Boot that shipped on these boards does not have such a fixup (or why they
> > decided it was better to make late-rev 8313's interrupt assignments match
> > other 83xx than for all revs of the same part number to have the same
> > interrupt assignments).
>
> It sounds like you are not overly satisfied with Freescale's handling
> of their BSPs ;)
:-)
Things are slowly getting better, but it'd be good for the BSP teams to hear
from customers (and not just other internal groups) saying they want more
up-to-date software that doesn't diverge as much from mainline.
And getting u-boot right before shipping it on a board is particularly
important.
> To be fair, I am happy that Freescale appears to take Linux support
> seriously, but I do think they drop the ball once a BSP is
> published. For example, the MPC8313-ERDB ships with kernel 2.6.23
> (with the old style dts) and a fair number of non-mainstream
> patches. It is not so easy to get a recent kernel booting on that
> board.
What problems have you been having with upstream kernels on mpc8313erdb,
other than this IRQ issue? It should work, though the BSP may have extra
features that haven't been pushed upstream.
> I have the LITE5200B, MPC8313-ERDB, MPC8572DS, and the P2020DS in
> house, and it is really the same, sad story with each of
> them. Wouldn't it be grand if the development boards would boot "out
> of the box" when compiling the most recent kernel with default config?
That's what the group I'm in tries to make sure happens (for the
mpc8xxx/qoriq chips) -- but we're outnumbered by the BSP developers, so some
BSP features tend to be missing. Basic board support should be there,
though.
I just booted 2.6.32-rc4 straight from Linus on an mpc8572ds yesterday.
I've booted various upstream kernels on mpc8313erdb (typically an older rev,
though).
-Scott
^ permalink raw reply
* Re: [PATCH] Found skb leak in mpc5200 fec on rxfifo error
From: Asier Llano Palacios @ 2009-10-16 16:10 UTC (permalink / raw)
To: linuxppc-dev; +Cc: a.arzuaga
In-Reply-To: <1255694497.4683.163.camel@allano>
Sorry, but it seems that the patch did already do the work. The other
problems were hardware problems and are not related to this patch (it
even happened without applying it). So it seems that the skb leak may be
solved with the provided patch.
Kind regards,
Asier
El vie, 16-10-2009 a las 14:01 +0200, Asier Llano Palacios escribi=F3:
> (I'm sorry about my previous message with a legal notice, this time
> I resent it with another mail server that doesn't include the legal
> notice for me)
>=20
> Hi all,
>=20
> I finally found why in my mpc5200 based system (and in the lite5200) I
> had leaks of skbs when receiving ethernet traffic at 100 Mbit/s so =
that
> we generated an rxfifo error (to be able to get it I even reduced the
> speed of the CPU using the PLL jumpers).
>=20
> The problem was:
>=20
> The reception packets are handled in the interrupt handler:
> mpc52xx_fec_rx_interrupt. So this interrupt is being handled all the
> time because we are receiving packets continuously.
>=20
> The reception fifo errors are handled in the interrupt handler:
> mpc52xx_fec_interrupt. This interruption is being handled very often
> because we are receiving more packets that what we can handle, and =
that
> generates a fifo reception error.
>=20
> So it is very usual that the mpc52xx_fec_interrupt handler is executed
> at the middle of the mpc52xx_fec_rx_interrupt handler. And I think =
that
> it is not designed for that purpose.
>=20
> The mpc52xx_fec_rx_interrupt uses bcom_retrieve_buffer and
> bcom_submit_next_buffer. The mpc52xx_fec_interrupt calls to
> mpc52xx_fec_reset which calls to mpc52xx_fec_free_rx_buffers and
> mpc52xx_fec_alloc_rx_buffers, which at the end call =
bcom_retrieve_buffer
> and bcom_submit_next_buffer.
>=20
> Then we have two problems because of the same origin:
> - bcom_retrieve_buffer and bcom_submit_next_buffer doesn't seem to be
> atomic, so they cannot be called from one interrupt nested from
> another one being executing those functions.
> - Even if they were atomic, the mpc52xx_fec_rx_interrupt and the
> mpc52xx_fec_reset functions are not intended to be called at the
> same time.
>=20
> Patch I managed to do:
> I've managed to perform a patch that avoids the leak disabling the
> irqs, but I have a remaining problem: The last packet to be =
transmited
> is waiting for a packet to be received in order to egress (I don't =
know
> why but I detected it experimentaly).
> =20
> Anyone with more experience can tell me what's wrong in this patch?
>=20
> Thank you in advance,
> Asier
>=20
> Signed-off-by: Asier Llano <a.llano@ziv.es>
> ---
> drivers/net/fec_mpc52xx.c | 23 +++++++++++++++++++++--
> 1 file changed, 21 insertions(+), 2 deletions(-)
>=20
> diff -urpN linux-2.6.31.2/drivers/net/fec_mpc52xx.c
> linux-2.6.31.2-fec_mpc52xx_skb_leak/drivers/net/fec_mpc52xx.c
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- linux-2.6.31.2/drivers/net/fec_mpc52xx.c
> +++ linux-2.6.31.2-fec_mpc52xx_skb_leak/drivers/net/fec_mpc52xx.c
> @@ -85,13 +85,20 @@ MODULE_PARM_DESC(debug, "debugging messa
> =20
> static void mpc52xx_fec_tx_timeout(struct net_device *dev)
> {
> + struct mpc52xx_fec_priv *priv =3D netdev_priv(dev);
> + unsigned long flags;
> +
> dev_warn(&dev->dev, "transmit timed out\n");
> =20
> + spin_lock_irqsave(&priv->lock, flags);
> +
> mpc52xx_fec_reset(dev);
> =20
> dev->stats.tx_errors++;
> =20
> netif_wake_queue(dev);
> +
> + spin_unlock_irqrestore(&priv->lock, flags);
> }
> =20
> static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
> @@ -359,8 +366,9 @@ static irqreturn_t mpc52xx_fec_tx_interr
> {
> struct net_device *dev =3D dev_id;
> struct mpc52xx_fec_priv *priv =3D netdev_priv(dev);
> + unsigned long flags;
> =20
> - spin_lock(&priv->lock);
> + spin_lock_irqsave(&priv->lock, flags);
> =20
> while (bcom_buffer_done(priv->tx_dmatsk)) {
> struct sk_buff *skb;
> @@ -375,7 +383,7 @@ static irqreturn_t mpc52xx_fec_tx_interr
> =20
> netif_wake_queue(dev);
> =20
> - spin_unlock(&priv->lock);
> + spin_unlock_irqrestore(&priv->lock, flags);
> =20
> return IRQ_HANDLED;
> }
> @@ -384,6 +392,9 @@ static irqreturn_t mpc52xx_fec_rx_interr
> {
> struct net_device *dev =3D dev_id;
> struct mpc52xx_fec_priv *priv =3D netdev_priv(dev);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> =20
> while (bcom_buffer_done(priv->rx_dmatsk)) {
> struct sk_buff *skb;
> @@ -445,6 +456,8 @@ static irqreturn_t mpc52xx_fec_rx_interr
> bcom_submit_next_buffer(priv->rx_dmatsk, skb);
> }
> =20
> + spin_unlock_irqrestore(&priv->lock, flags);
> +
> return IRQ_HANDLED;
> }
> =20
> @@ -454,6 +467,7 @@ static irqreturn_t mpc52xx_fec_interrupt
> struct mpc52xx_fec_priv *priv =3D netdev_priv(dev);
> struct mpc52xx_fec __iomem *fec =3D priv->fec;
> u32 ievent;
> + unsigned long flags;
> =20
> ievent =3D in_be32(&fec->ievent);
> =20
> @@ -471,9 +485,14 @@ static irqreturn_t mpc52xx_fec_interrupt
> if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
> dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
> =20
> + spin_lock_irqsave(&priv->lock, flags);
> +
> mpc52xx_fec_reset(dev);
> =20
> netif_wake_queue(dev);
> +
> + spin_unlock_irqrestore(&priv->lock, flags);
> +
> return IRQ_HANDLED;
> }
> =20
>=20
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev=20
=20
----------------------------------------- PLEASE NOTE =
-------------------------------------------
This message, along with any attachments, may be confidential or legally =
privileged.=20
It is intended only for the named person(s), who is/are the only =
authorized recipients.
If this message has reached you in error, kindly destroy it without =
review and notify the sender immediately.
Thank you for your help.
ZIV uses virus scanning software but excludes any liability for viruses =
contained in any attachment.
=20
------------------------------------ ROGAMOS LEA ESTE TEXTO =
-------------------------------
Este mensaje y sus anexos pueden contener informaci=F3n confidencial y/o =
con derecho legal.=20
Est=E1 dirigido =FAnicamente a la/s persona/s o entidad/es rese=F1adas =
como =FAnico destinatario autorizado.
Si este mensaje le hubiera llegado por error, por favor elim=EDnelo sin =
revisarlo ni reenviarlo y notif=EDquelo inmediatamente al remitente. =
Gracias por su colaboraci=F3n. =20
ZIV utiliza software antivirus, pero no se hace responsable de los virus =
contenidos en los ficheros anexos.
^ permalink raw reply
* Re: Support for S29JL064 in MPC8272ADS?
From: Scott Wood @ 2009-10-16 16:18 UTC (permalink / raw)
To: Roberto Guerra; +Cc: linuxppc-dev
In-Reply-To: <7c4144600910160837y3d70ccd2yeeeb220da7e556c3@mail.gmail.com>
Roberto Guerra wrote:
> mtdparts=phys:1600K(ROM)ro,6M(root),512K(U-Boot)ro,512K(unused)
> rootfstype=jffs2
> => bootm 200000 - 400000
> <snip>
> physmap platform flash device: 00800000 at ff800000
> physmap-flash.0: Found 1 x16 devices at 0x0 in 16-bit bank
> Amd/Fujitsu Extended Query Table at 0x0040
> physmap-flash.0: CFI does not contain boot bank location. Assuming
> top.
Hmm, you seem to be using physmap rather than physmap_of -- so it won't
even be looking at your device tree node.
> List of all partitions:
> 0100 4096 ram0 (driver?)
> 0101 4096 ram1 (driver?)
> 0102 4096 ram2 (driver?)
> 0103 4096 ram3 (driver?)
> 0104 4096 ram4 (driver?)
> 0105 4096 ram5 (driver?)
> 0106 4096 ram6 (driver?)
> 0107 4096 ram7 (driver?)
> 0108 4096 ram8 (driver?)
> 0109 4096 ram9 (driver?)
> 010a 4096 ram10 (driver?)
> 010b 4096 ram11 (driver?)
> 010c 4096 ram12 (driver?)
> 010d 4096 ram13 (driver?)
> 010e 4096 ram14 (driver?)
> 010f 4096 ram15 (driver?)
Where are all these coming from?
> The key change in my kernel config was the BIG_ENDIAN=Y.
> The kernel probes the AMD chip, but it can't see the partitions.
Even without partiitons, you should see the whole flash device...
> I guess now I will have to define my mtd partitions in either FDT or
> in the kernel arguments.
> Which is the best way to define them?
If you're defining a standard layout for the platform that's unlikely to
change, I'd go with the device tree. Otherwise, I'd go with whatever's
most convenient.
> If the partitions are defined in
> both FDT and bootargs, which one takes precedence?
The command line takes precedence.
-Scott
^ permalink raw reply
* Re: [PATCH] * mpc8313erdb.dts: Fixed eTSEC interrupt assignment.
From: Kumar Gala @ 2009-10-16 16:30 UTC (permalink / raw)
To: Richard Cochran; +Cc: Scott Wood, linuxppc-dev
In-Reply-To: <20091016160125.GC11838@loki.buserror.net>
On Oct 16, 2009, at 11:01 AM, Scott Wood wrote:
>>
>> I have the LITE5200B, MPC8313-ERDB, MPC8572DS, and the P2020DS in
>> house, and it is really the same, sad story with each of
>> them. Wouldn't it be grand if the development boards would boot "out
>> of the box" when compiling the most recent kernel with default
>> config?
>
> That's what the group I'm in tries to make sure happens (for the
> mpc8xxx/qoriq chips) -- but we're outnumbered by the BSP developers,
> so some
> BSP features tend to be missing. Basic board support should be there,
> though.
>
> I just booted 2.6.32-rc4 straight from Linus on an mpc8572ds
> yesterday.
> I've booted various upstream kernels on mpc8313erdb (typically an
> older rev,
> though).
Also, if they don't boot out of the box report an issue on this list.
That is part of the community testing aspect of open source.
- k
^ permalink raw reply
* [PATCH] sata_fsl: Split hard and soft reset
From: Anton Vorontsov @ 2009-10-16 16:44 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linuxppc-dev, Jiang Yutang, Ashish Kalra, linux-ide
From: Jiang Yutang <b14898@freescale.com>
Split sata_fsl_softreset() into hard and soft resets to make
error-handling more efficient & device and PMP detection more
reliable.
Also includes fix for PMP support, driver tested with Sil3726,
Sil4726 & Exar PMP controllers.
[AV: Also fixes resuming from deep sleep on MPC8315 CPUs]
Signed-off-by: Jiang Yutang <b14898@freescale.com>
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/ata/sata_fsl.c | 84 +++++++++++++++++++++++++-----------------------
1 files changed, 44 insertions(+), 40 deletions(-)
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index d344db4..172b57e 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -707,34 +707,17 @@ static unsigned int sata_fsl_dev_classify(struct ata_port *ap)
return ata_dev_classify(&tf);
}
-static int sata_fsl_prereset(struct ata_link *link, unsigned long deadline)
-{
- /* FIXME: Never skip softreset, sata_fsl_softreset() is
- * combination of soft and hard resets. sata_fsl_softreset()
- * needs to be splitted into soft and hard resets.
- */
- return 0;
-}
-
-static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
+static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
- struct sata_fsl_port_priv *pp = ap->private_data;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
- int pmp = sata_srst_pmp(link);
u32 temp;
- struct ata_taskfile tf;
- u8 *cfis;
- u32 Serror;
int i = 0;
unsigned long start_jiffies;
- DPRINTK("in xx_softreset\n");
-
- if (pmp != SATA_PMP_CTRL_PORT)
- goto issue_srst;
+ DPRINTK("in xx_hardreset\n");
try_offline_again:
/*
@@ -749,7 +732,7 @@ try_offline_again:
if (temp & ONLINE) {
ata_port_printk(ap, KERN_ERR,
- "Softreset failed, not off-lined %d\n", i);
+ "Hardreset failed, not off-lined %d\n", i);
/*
* Try to offline controller atleast twice
@@ -761,7 +744,7 @@ try_offline_again:
goto try_offline_again;
}
- DPRINTK("softreset, controller off-lined\n");
+ DPRINTK("hardreset, controller off-lined\n");
VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
@@ -786,11 +769,11 @@ try_offline_again:
if (!(temp & ONLINE)) {
ata_port_printk(ap, KERN_ERR,
- "Softreset failed, not on-lined\n");
+ "Hardreset failed, not on-lined\n");
goto err;
}
- DPRINTK("softreset, controller off-lined & on-lined\n");
+ DPRINTK("hardreset, controller off-lined & on-lined\n");
VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
@@ -806,7 +789,7 @@ try_offline_again:
"No Device OR PHYRDY change,Hstatus = 0x%x\n",
ioread32(hcr_base + HSTATUS));
*class = ATA_DEV_NONE;
- goto out;
+ return 0;
}
/*
@@ -819,11 +802,44 @@ try_offline_again:
if ((temp & 0xFF) != 0x18) {
ata_port_printk(ap, KERN_WARNING, "No Signature Update\n");
*class = ATA_DEV_NONE;
- goto out;
+ goto do_followup_srst;
} else {
ata_port_printk(ap, KERN_INFO,
"Signature Update detected @ %d msecs\n",
jiffies_to_msecs(jiffies - start_jiffies));
+ *class = sata_fsl_dev_classify(ap);
+ return 0;
+ }
+
+do_followup_srst:
+ /*
+ * request libATA to perform follow-up softreset
+ */
+ return -EAGAIN;
+
+err:
+ return -EIO;
+}
+
+static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct sata_fsl_port_priv *pp = ap->private_data;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ int pmp = sata_srst_pmp(link);
+ u32 temp;
+ struct ata_taskfile tf;
+ u8 *cfis;
+ u32 Serror;
+
+ DPRINTK("in xx_softreset\n");
+
+ if (ata_link_offline(link)) {
+ DPRINTK("PHY reports no device\n");
+ *class = ATA_DEV_NONE;
+ return 0;
}
/*
@@ -834,7 +850,6 @@ try_offline_again:
* reached here, we can send a command to the target device
*/
-issue_srst:
DPRINTK("Sending SRST/device reset\n");
ata_tf_init(link->device, &tf);
@@ -860,6 +875,8 @@ issue_srst:
ioread32(CA + hcr_base), ioread32(CC + hcr_base));
iowrite32(0xFFFF, CC + hcr_base);
+ if (pmp != SATA_PMP_CTRL_PORT)
+ iowrite32(pmp, CQPMP + hcr_base);
iowrite32(1, CQ + hcr_base);
temp = ata_wait_register(CQ + hcr_base, 0x1, 0x1, 1, 5000);
@@ -926,7 +943,6 @@ issue_srst:
VPRINTK("cereg = 0x%x\n", ioread32(hcr_base + CE));
}
-out:
return 0;
err:
@@ -988,18 +1004,6 @@ static void sata_fsl_error_intr(struct ata_port *ap)
ehi->err_mask |= AC_ERR_ATA_BUS;
ehi->action |= ATA_EH_SOFTRESET;
- /*
- * Ignore serror in case of fatal errors as we always want
- * to do a soft-reset of the FSL SATA controller. Analyzing
- * serror may cause libata to schedule a hard-reset action,
- * and hard-reset currently does not do controller
- * offline/online, causing command timeouts and leads to an
- * un-recoverable state, hence make libATA ignore
- * autopsy in case of fatal errors.
- */
-
- ehi->flags |= ATA_EHI_NO_AUTOPSY;
-
freeze = 1;
}
@@ -1267,8 +1271,8 @@ static struct ata_port_operations sata_fsl_ops = {
.freeze = sata_fsl_freeze,
.thaw = sata_fsl_thaw,
- .prereset = sata_fsl_prereset,
.softreset = sata_fsl_softreset,
+ .hardreset = sata_fsl_hardreset,
.pmp_softreset = sata_fsl_softreset,
.error_handler = sata_fsl_error_handler,
.post_internal_cmd = sata_fsl_post_internal_cmd,
--
1.6.3.3
^ permalink raw reply related
* [PATCH] powerpc/83xx: Fix u-boot partion size for MPC8377E-WLAN boards
From: Anton Vorontsov @ 2009-10-16 16:47 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
u-boot partition size should be 0x80000 (512 KB), not 0x8000 (32 KB).
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
arch/powerpc/boot/dts/mpc8377_wlan.dts | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc8377_wlan.dts b/arch/powerpc/boot/dts/mpc8377_wlan.dts
index 9a60369..9ea7830 100644
--- a/arch/powerpc/boot/dts/mpc8377_wlan.dts
+++ b/arch/powerpc/boot/dts/mpc8377_wlan.dts
@@ -67,7 +67,7 @@
device-width = <1>;
partition@0 {
- reg = <0 0x8000>;
+ reg = <0 0x80000>;
label = "u-boot";
read-only;
};
--
1.6.3.3
^ permalink raw reply related
* [PATCH] powerpc/85xx: Fix USB GPIOs for MPC8569E-MDS boards
From: Anton Vorontsov @ 2009-10-16 16:50 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, Liu Yu
This patch fixes USB GPIOs numbers for MPC8569E-MDS boards, plus
according to the latest HW Getting Started Guide (rev 3.3, pilot
boards), USB "POWER" GPIO polarity has changed, it is no longer
inverted.
This patch makes USB Host somewhat work on pilot boards, though
there are still some problems with determining devices speed and
long bulk transfers.
Reported-by: Liu Yu <Yu.Liu@freescale.com>
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
arch/powerpc/boot/dts/mpc8569mds.dts | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc8569mds.dts b/arch/powerpc/boot/dts/mpc8569mds.dts
index 06332d6..1e3ec8f 100644
--- a/arch/powerpc/boot/dts/mpc8569mds.dts
+++ b/arch/powerpc/boot/dts/mpc8569mds.dts
@@ -487,8 +487,8 @@
&qe_pio_f 5 0 /* USBTN */
&qe_pio_f 6 0 /* USBRP */
&qe_pio_f 8 0 /* USBRN */
- &bcsr17 6 0 /* SPEED */
- &bcsr17 5 1>; /* POWER */
+ &bcsr17 1 0 /* SPEED */
+ &bcsr17 2 0>; /* POWER */
};
enet0: ucc@2000 {
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH 2/2][v2] powerpc: Make the CMM memory hotplug aware
From: Christoph Lameter @ 2009-10-16 16:48 UTC (permalink / raw)
To: gerald.schaefer
Cc: Nick Piggin, linuxppc-dev, Mel Gorman, linux-kernel, linux-mm,
Badari Pulavarty, Brian King, Paul Mackerras, Ingo Molnar,
Martin Schwidefsky, KAMEZAWA Hiroyuki
In-Reply-To: <4AD7681C.7060800@linux.vnet.ibm.com>
On Thu, 15 Oct 2009, Gerald Schaefer wrote:
> > The pages allocated as __GFP_MOVABLE are used to store the list of pages
> > allocated by the balloon. They reference virtual addresses and it would
> > be fine for the kernel to migrate the physical pages for those, the
> > balloon would not notice this.
>
> Does page migration really work for kernel pages that were allocated
> with __get_free_page()? I was wondering if we can do this on s390, where
> we have a 1:1 mapping of kernel virtual to physical addresses, but
> looking at migrate_pages() and friends, it seems that kernel pages
> w/o mapping and rmap should not be migrateable at all. Any thoughts from
> the memory migration experts?
page migration only works for pages where we have some way of accounting
for all the references to a page. This usually mean using reverse mappings
(anon list, radix trees and page tables).
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox