LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Mike Turquette @ 2013-08-22  7:19 UTC (permalink / raw)
  To: Tomasz Figa, Mark Rutland
  Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org,
	lars@metafoo.de, ian.campbell@citrix.com, Pawel Moll,
	swarren@wwwdotorg.org, festevam@gmail.com, Sascha Hauer,
	Nicolin Chen, timur@tabi.org, rob.herring@calxeda.com,
	broonie@kernel.org, p.zabel@pengutronix.de, galak@codeaurora.org,
	shawn.guo@linaro.org, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <2207416.NJhrdSqkEZ@flatron>

Quoting Tomasz Figa (2013-08-21 14:34:55)
> On Wednesday 21 of August 2013 09:50:15 Mark Rutland wrote:
> > On Tue, Aug 20, 2013 at 01:06:25AM +0100, Mike Turquette wrote:
> > > Quoting Mark Rutland (2013-08-19 02:35:43)
> > > =

> > > > On Sat, Aug 17, 2013 at 04:17:18PM +0100, Tomasz Figa wrote:
> > > > > On Saturday 17 of August 2013 16:53:16 Sascha Hauer wrote:
> > > > > > On Sat, Aug 17, 2013 at 02:28:04PM +0200, Tomasz Figa wrote:
> > > > > > > > > > Also I would make this option required. Use a dummy
> > > > > > > > > > clock for
> > > > > > > > > > mux
> > > > > > > > > > inputs that are grounded for a specific SoC.
> > > > > > > > > =

> > > > > > > > > Some clocks are not from CCM and we haven't defined in
> > > > > > > > > imx6q-clk.txt,
> > > > > > > > > so in most cases we can't provide a phandle for them, eg:
> > > > > > > > > spdif_ext.
> > > > > > > > > I think it's a bit hard to force it to be 'required'. An
> > > > > > > > > 'optional'
> > > > > > > > > looks more flexible to me and a default one is ensured
> > > > > > > > > even if
> > > > > > > > > it's
> > > > > > > > > missing.
> > > > > > > > =

> > > > > > > > <&clks 0> is the dummy clock. This can be used for all input
> > > > > > > > clocks
> > > > > > > > not
> > > > > > > > defined by the SoC.
> > > > > > > =

> > > > > > > Where does this assumption come from? Is it documented
> > > > > > > anywhere?
> > > > > > =

> > > > > > This is how all i.MX clock bindings currently are. See
> > > > > > Documentation/devicetree/bindings/clock/imx*-clock.txt
> > > > > =

> > > > > OK, thanks.
> > > > > =

> > > > > I guess we need some discussion on dummy clocks vs skipped clocks.
> > > > > I think we want some consistency on this, don't we?
> > > > > =

> > > > > If we really need a dummy clock, then we might also want a generic
> > > > > way to specify it.
> > > > =

> > > > What do we actually mean by a "dummy clock"? We already have
> > > > bindings
> > > > for "fixed-clock" and co friends describe relatively simple
> > > > preconfigured clocks.
> > > =

> > > Some platforms have a fake clock which defines noops callbacks and
> > > basically doesn't do anything. This is analogous to the dummy
> > > regulator
> > > implementation. A central one could be registered by the clock core,
> > > as
> > > is done by the regulator core.
> > =

> > When you say some platforms, you presumably mean the platform code in
> > Linux? A dummy clock sounds like a completely Linux-specific abstraction
> > rather than a description of the hardware, and I don't see why we need
> > that in the DT:
> > =

> > * If a clock is wired up and running (as presumably the dummy clock is),
> > then surely it's a fixed-clock (it's running, we and we have no control
> > over it, but we presumably know its rate) and can be described as such?
> > =

> > * If no clock is wired up, then we should be able to describe that. If a
> > driver believes that a clock is required when it isn't (for some level
> > of functionality), then that driver should be fixed up to support the
> > clock as being optional.
> > =

> > Am I missing something?
> =

> I second that.
> =

> Moreover, I don't think that device tree should deal with dummy anything. =

> It should be able to describe hardware that is available on given system, =

> not list what hardware is not available.

I wasn't clear. The dummy clock IS a completely Linux-specific
abstraction.

I'm not advocating a dummy clock in DT. I am advocating consolidation of
the implementation of a clock that does nothing into the clock core.
This code could easily live in drivers/clk/clk.c instead of having
everyone open-code it.

As far as specifying a dummy clock in DT? I dunno. DT should describe
real hardware so there isn't much use for a dummy clock.

I'm guessing one of the reasons for such a clock are drivers do not
honor the clk.h api and they freak out when clk_get gives them a NULL
pointer?

Regards,
Mike

> =

> Best regards,
> Tomasz

^ permalink raw reply

* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver.
From: Deepthi Dharwar @ 2013-08-22  6:41 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Wood Scott-B07421, Wang Dongsheng-B40534,
	daniel.lezcano@linaro.org, Scott Wood, preeti@linux.vnet.ibm.com,
	linux-pm@lists.linux-foundation.org,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1377151097.25016.287.camel@pasglop>

On 08/22/2013 11:28 AM, Benjamin Herrenschmidt wrote:
> On Thu, 2013-08-22 at 11:20 +0530, Deepthi Dharwar wrote:
>> But if having cpuidle backend-driver separately for other powerpc arcs
>> makes sense such that each one have their own state information etc
>> then it makes sense to name the files as cpuidle-power.c,
>> cpuilde-ppc32.c and so on.
> 
> If by "power" you mean IBM POWER machines/CPUs, then make it
> cpuidle-ibm-power or cpuidle-book3s64 maybe to clarify what families it
> affects.

Sure. Thanks :)

Regards,
Deepthi


> Cheers
> Ben.
> 
> 
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
> 
> 

^ permalink raw reply

* Re: [PATCH v4 03/19] powerpc: refactor of_get_cpu_node to support other architectures
From: Benjamin Herrenschmidt @ 2013-08-22  6:15 UTC (permalink / raw)
  To: Sudeep KarkadaNagesha
  Cc: Jonas Bonn, devicetree, Michal Simek, linux-pm, Viresh Kumar,
	linux-kernel, Rob Herring, Rafael J. Wysocki, Greg Kroah-Hartman,
	Grant Likely, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1376991021-12160-4-git-send-email-Sudeep.KarkadaNagesha@arm.com>

On Tue, 2013-08-20 at 10:30 +0100, Sudeep KarkadaNagesha wrote:
> From: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> 
> Currently different drivers requiring to access cpu device node are
> parsing the device tree themselves. Since the ordering in the DT need
> not match the logical cpu ordering, the parsing logic needs to consider
> that. However, this has resulted in lots of code duplication and in some
> cases even incorrect logic.
> 
> It's better to consolidate them by adding support for getting cpu
> device node for a given logical cpu index in DT core library. However
> logical to physical index mapping can be architecture specific.
> 
> PowerPC has it's own implementation to get the cpu node for a given
> logical index.
> 
> This patch refactors the current implementation of of_get_cpu_node.
> This in preparation to move the implementation to DT core library.
> It separates out the logical to physical mapping so that a default
> matching of the physical id to the logical cpu index can be added
> when moved to common code. Architecture specific code can override it.

So the patch unfortunately collides with other changes in powerpc -next,
though it's not a huge deal and not hard to fixup, but expect Linus
to tick unless we sort it out some other way.

Appart from that, it's fine, builds on all my test configs and doesn't
seem to negatively impact things as far as I can tell so far...

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> Cc: Rob Herring <rob.herring@calxeda.com>
> Cc: Grant Likely <grant.likely@linaro.org>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> ---
>  arch/powerpc/kernel/prom.c | 76 ++++++++++++++++++++++++++++------------------
>  1 file changed, 47 insertions(+), 29 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
> index eb23ac9..f7b8c0b 100644
> --- a/arch/powerpc/kernel/prom.c
> +++ b/arch/powerpc/kernel/prom.c
> @@ -865,45 +865,63 @@ static int __init prom_reconfig_setup(void)
>  __initcall(prom_reconfig_setup);
>  #endif
>  
> +bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
> +{
> +	return (int)phys_id == get_hard_smp_processor_id(cpu);
> +}
> +
> +static bool __of_find_n_match_cpu_property(struct device_node *cpun,
> +			const char *prop_name, int cpu, unsigned int *thread)
> +{
> +	const __be32 *cell;
> +	int ac, prop_len, tid;
> +	u64 hwid;
> +
> +	ac = of_n_addr_cells(cpun);
> +	cell = of_get_property(cpun, prop_name, &prop_len);
> +	if (!cell)
> +		return false;
> +	prop_len /= sizeof(*cell);
> +	for (tid = 0; tid < prop_len; tid++) {
> +		hwid = of_read_number(cell, ac);
> +		if (arch_match_cpu_phys_id(cpu, hwid)) {
> +			if (thread)
> +				*thread = tid;
> +			return true;
> +		}
> +		cell += ac;
> +	}
> +	return false;
> +}
> +
>  /* Find the device node for a given logical cpu number, also returns the cpu
>   * local thread number (index in ibm,interrupt-server#s) if relevant and
>   * asked for (non NULL)
>   */
>  struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
>  {
> -	int hardid;
> -	struct device_node *np;
> +	struct device_node *cpun, *cpus;
>  
> -	hardid = get_hard_smp_processor_id(cpu);
> +	cpus = of_find_node_by_path("/cpus");
> +	if (!cpus) {
> +		pr_warn("Missing cpus node, bailing out\n");
> +		return NULL;
> +	}
>  
> -	for_each_node_by_type(np, "cpu") {
> -		const u32 *intserv;
> -		unsigned int plen, t;
> +	for_each_child_of_node(cpus, cpun) {
> +		if (of_node_cmp(cpun->type, "cpu"))
> +			continue;
>  
> -		/* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
> -		 * fallback to "reg" property and assume no threads
> +		/* Check for non-standard "ibm,ppc-interrupt-server#s" property
> +		 * for thread ids on PowerPC. If it doesn't exist fallback to
> +		 * standard "reg" property.
>  		 */
> -		intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
> -				&plen);
> -		if (intserv == NULL) {
> -			const u32 *reg = of_get_property(np, "reg", NULL);
> -			if (reg == NULL)
> -				continue;
> -			if (*reg == hardid) {
> -				if (thread)
> -					*thread = 0;
> -				return np;
> -			}
> -		} else {
> -			plen /= sizeof(u32);
> -			for (t = 0; t < plen; t++) {
> -				if (hardid == intserv[t]) {
> -					if (thread)
> -						*thread = t;
> -					return np;
> -				}
> -			}
> -		}
> +		if (__of_find_n_match_cpu_property(cpun,
> +				"ibm,ppc-interrupt-server#s", cpu, thread))
> +			return cpun;
> +
> +		if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread))
> +			return cpun;
>  	}
>  	return NULL;
>  }

^ permalink raw reply

* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver.
From: Benjamin Herrenschmidt @ 2013-08-22  5:58 UTC (permalink / raw)
  To: Deepthi Dharwar
  Cc: Wood Scott-B07421, daniel.lezcano@linaro.org,
	Wang Dongsheng-B40534, preeti@linux.vnet.ibm.com, Scott Wood,
	linux-pm@lists.linux-foundation.org,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <5215A69F.4090904@linux.vnet.ibm.com>

On Thu, 2013-08-22 at 11:20 +0530, Deepthi Dharwar wrote:
> But if having cpuidle backend-driver separately for other powerpc arcs
> makes sense such that each one have their own state information etc
> then it makes sense to name the files as cpuidle-power.c,
> cpuilde-ppc32.c and so on.

If by "power" you mean IBM POWER machines/CPUs, then make it
cpuidle-ibm-power or cpuidle-book3s64 maybe to clarify what families it
affects.

Cheers
Ben.

^ permalink raw reply

* Re: [RFC V2 PATCH 2/6] powerpc: Implement broadcast timer interrupt as an IPI message
From: Preeti U Murthy @ 2013-08-22  5:49 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: fweisbec, paul.gortmaker, paulus, shangw, rjw, paulmck, arnd,
	linux-pm, rostedt, john.stultz, tglx, chenhui.zhao, deepthi,
	r58472, geoff, linux-kernel, srivatsa.bhat, schwidefsky,
	linuxppc-dev
In-Reply-To: <1377141057.25016.265.camel@pasglop>

Hi Ben

On 08/22/2013 08:40 AM, Benjamin Herrenschmidt wrote:
> On Wed, 2013-08-14 at 17:26 +0530, Preeti U Murthy wrote:
>> -static irqreturn_t unused_action(int irq, void *data)
>> +static irqreturn_t timer_action(int irq, void *data)
>>  {
>> -       /* This slot is unused and hence available for use, if needed
>> */
>> +       timer_interrupt();
>>         return IRQ_HANDLED;
>>  }
>>  
> 
> That means we'll do irq_enter/irq_exit twice no ? And things like
> may_hard_irq_enable() are also already done by do_IRQ so you
> don't need timer_interrupt() to do it again.
> 
> We probably are better off breaking timer_interrupt in two:
> 
> void __timer_interrupt(struct pt_regs * regs)
> 
> Does the current stuff between irq_enter and irq_exit, timer_interrupt
> does the remaining around it and calls __timer_interrupt.
> 
> Then from timer_action, you call __timer_interrupt()

We actually tried out this approach. The implementation was have a
set_dec(0) in the timer_action(). This would ensure that we actually do
get a timer interrupt.

But the problem with either this approach or the one that you
suggest,i.e. calling __timer_interrupt is in the following flow.

do_IRQ() -> irq_exit() -> tick_irq_exit() -> tick_nohz_irq_exit()
-> tick_nohz_stop_sched_tick()

The problem lies in the function tick_nohz_stop_sched_tick(). This
function checks for the next timer interrupt pending on this cpu, and
programs the decrementer_next_event to the time of the next event, which
is of course > now.

As a result when in the timer_action() above, we do call
__timer_interrupt() or try to trigger a timer interrupt through
set_dec(0), the condition  if(now >= *next_tb) in timer_interrupt() or
__timer_interrupt() will fail, and will not call the timer interrupt
event handler.

---> if (now >= *next_tb) {
             *next_tb = ~(u64)0;
             if (evt->event_handler)
                evt->event_handler(evt);
      } else {

The broadcast IPI , is meant to make the target CPU of this IPI believe
that it woke up from a timer interrupt, and not from an IPI. (The reason
for this I will explain in the reply to the next patch). The target CPU
should then ideally do what it would have done had it received a real
timer interrupt, call the timer interrupt event handler.

But due to the above code flow this does  not happen.
Hence as the next patch PATCH 3/6 shows, we simply call the event
handler of a timer interrupt without this explicit now >= *next_tb check.

This problem arises only in the implementation of this patchset, because
a timer interrupt is pseudo triggered from an IPI. So the effects of the
IPI handler will be felt on the timer interrupt handler triggered from
this IPI, like above.

Regards
Preeti U Murthy

^ permalink raw reply

* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver.
From: Deepthi Dharwar @ 2013-08-22  5:50 UTC (permalink / raw)
  To: Scott Wood
  Cc: Wood Scott-B07421, Wang Dongsheng-B40534,
	daniel.lezcano@linaro.org, preeti@linux.vnet.ibm.com,
	linux-pm@lists.linux-foundation.org,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1377115703.5029.14.camel@snotra.buserror.net>

On 08/22/2013 01:38 AM, Scott Wood wrote:
> On Wed, 2013-08-21 at 10:23 +0530, Deepthi Dharwar wrote:
>> On 08/19/2013 11:47 PM, Scott Wood wrote:
>>> On Mon, 2013-08-19 at 15:48 +0530, Deepthi Dharwar wrote:
>>>> Hi Dongsheng,
>>>>
>>>> On 08/19/2013 11:22 AM, Wang Dongsheng-B40534 wrote:
>>>>> I think we should move the states and handle function to arch/power/platform*
>>>>> The states and handle function is belong to backend driver, not for this, different platform have different state.
>>>>> Different platforms to make their own deal with these states.
>>>>>
>>>>> I think we cannot put all the status of different platforms and handler in this driver.
>>>>
>>>> The idea here is a single powerpc back-end driver, which does a runtime
>>>> detection of the platform it is running and choose the right
>>>> idle states table. This was one of outcome of V2 discussion.
>>>
>>> I see a lot more in there than just detecting a platform and choosing a
>>> driver.
>>>
>>>> I feel there is no harm in keeping the state information in the same
>>>> file. We do have x86, which has all its variants information in one
>>>> file. One place will have all the idle consolidated information of
>>>> all the platform variants. If community does feel, we need to
>>>> have just the states information in arch specific file, we can do so.
>>>
>>> What actual functionality is common to all powerpc but not common to
>>> other arches?
> 

The functionality here is idle states on powerpc  like the snooze loop
that is common.
Also, the basic registration of the driver, hotplug notifier etc for
powerpc.

> 
>>>>>> +config CPU_IDLE_POWERPC
>>>>>> +	bool "CPU Idle driver for POWERPC platforms"
>>>>>> +	depends on PPC64
>>>>>
>>>>> Why not PPC?
>>>>
>>>> PPC64 seems to a good place to began the consolidation work. This
>>>> patch-set has not been tested for PPC32 currently.
>>>
>>> PPC64 is a bad place to start if you want it to be generic, because it
>>> means you'll end up growing dependencies on other things that are PPC64
>>> only.  There are too many arbitrary 32/64 differences as is.
>>
>> Hi Scott,
>>
>> From my understanding, PPC64 includes BOOK3E and BOOK3S archs.
>> PPC includes PPC32 and PPC64.
>>
>> It seemed logical to start consolidating at PPC64 as
>> one does not want to get into 32/64 bit differences.
> 
> I don't want to "get into" a file that claims to be generic PPC but is
> loaded with 64-bit dependencies.
> 
>> From your comments above,  I just wanted to clarify if PPC or PPC64 is
>> bad place to start. If PPC64 is bad place to start, then whats the way
>> forward ?  Can you please throw some more light on it.
> 
> The way forward is to give this file a more appropriate name based on
> the hardware that it actually targets -- and to refactor it so that the
> answer to that question is not complicated.

Sure, thanks.
Our idea was to have POWER archs idle states merged at the first go.
Only that is what is enabled in the current version (V4 posted out)
( Code is enabled for PSERIES and POWERNV only)
If needed, other POWERPC archs might benefit by extending the same
driver, that is why it is named cpuidle-powerpc.c

But if having cpuidle backend-driver separately for other powerpc arcs
makes sense such that each one have their own state information etc
then it makes sense to name the files as cpuidle-power.c,
cpuilde-ppc32.c and so on.

Regards,
Deepthi


> 
> -Scott
> 
> 
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
> 
> 

^ permalink raw reply

* [PATCH V4 5/5] powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework.
From: Deepthi Dharwar @ 2013-08-22  5:30 UTC (permalink / raw)
  To: linux-pm, linuxppc-dev, linux-kernel
  Cc: rjw, daniel.lezcano, dongsheng.wang, preeti, srivatsa.bhat,
	scottwood
In-Reply-To: <20130822052938.23277.67621.stgit@deepthi.in.ibm.com>

This patch enables idle cpu on the powernv platform  to hook on to the cpuidle
framework, if available, else call on to default idle platform
code.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/setup.c |   14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 84438af..fc62f21 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -25,6 +25,7 @@
 #include <linux/of.h>
 #include <linux/interrupt.h>
 #include <linux/bug.h>
+#include <linux/cpuidle.h>
 
 #include <asm/machdep.h>
 #include <asm/firmware.h>
@@ -175,6 +176,17 @@ static void __init pnv_setup_machdep_rtas(void)
 }
 #endif /* CONFIG_PPC_POWERNV_RTAS */
 
+void powernv_idle(void)
+{
+	/* Hook to cpuidle framework if available, else
+	 * call on default platform idle code
+	 */
+	if (cpuidle_idle_call()) {
+		HMT_low();
+		HMT_very_low();
+	}
+}
+
 static int __init pnv_probe(void)
 {
 	unsigned long root = of_get_flat_dt_root();
@@ -205,7 +217,7 @@ define_machine(powernv) {
 	.show_cpuinfo		= pnv_show_cpuinfo,
 	.progress		= pnv_progress,
 	.machine_shutdown	= pnv_shutdown,
-	.power_save             = power7_idle,
+	.power_save             = powernv_idle,
 	.calibrate_decr		= generic_calibrate_decr,
 #ifdef CONFIG_KEXEC
 	.kexec_cpu_down		= pnv_kexec_cpu_down,

^ permalink raw reply related

* [PATCH V4 4/5] powerpc/cpuidle: Enable powernv cpuidle support.
From: Deepthi Dharwar @ 2013-08-22  5:30 UTC (permalink / raw)
  To: linux-pm, linuxppc-dev, linux-kernel
  Cc: rjw, daniel.lezcano, dongsheng.wang, preeti, srivatsa.bhat,
	scottwood
In-Reply-To: <20130822052938.23277.67621.stgit@deepthi.in.ibm.com>

The following patch extends the current powerpc backend
idle driver to the powernv platform.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
 drivers/cpuidle/cpuidle-powerpc.c |   35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/drivers/cpuidle/cpuidle-powerpc.c b/drivers/cpuidle/cpuidle-powerpc.c
index 3662aba..973de6a 100644
--- a/drivers/cpuidle/cpuidle-powerpc.c
+++ b/drivers/cpuidle/cpuidle-powerpc.c
@@ -52,7 +52,9 @@ static int snooze_loop(struct cpuidle_device *dev,
 {
 	unsigned long in_purr;
 
-	idle_loop_prolog(&in_purr);
+	if (firmware_has_feature(FW_FEATURE_SPLPAR))
+		idle_loop_prolog(&in_purr);
+
 	local_irq_enable();
 	set_thread_flag(TIF_POLLING_NRFLAG);
 
@@ -66,7 +68,8 @@ static int snooze_loop(struct cpuidle_device *dev,
 	clear_thread_flag(TIF_POLLING_NRFLAG);
 	smp_mb();
 
-	idle_loop_epilog(in_purr);
+	if (firmware_has_feature(FW_FEATURE_SPLPAR))
+		idle_loop_epilog(in_purr);
 
 	return index;
 }
@@ -129,6 +132,15 @@ static int shared_cede_loop(struct cpuidle_device *dev,
 	return index;
 }
 
+static int nap_loop(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
+			int index)
+{
+	ppc64_runlatch_off();
+	power7_idle();
+	return index;
+}
+
 /*
  * States for dedicated partition case.
  */
@@ -162,6 +174,23 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
 		.enter = &shared_cede_loop },
 };
 
+static struct cpuidle_state powernv_states[MAX_IDLE_STATE_COUNT] = {
+	{ /* Snooze */
+		.name = "snooze",
+		.desc = "snooze",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = &snooze_loop },
+	{ /* NAP */
+		.name = "NAP",
+		.desc = "NAP",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 10,
+		.target_residency = 100,
+		.enter = &nap_loop },
+};
+
 void update_smt_snooze_delay(int cpu, int residency)
 {
 	struct cpuidle_driver *drv = cpuidle_get_driver();
@@ -261,6 +290,8 @@ static int powerpc_idle_probe(void)
 			cpuidle_state_table = shared_states;
 		else if (get_lppaca_is_shared_proc() == 0)
 			cpuidle_state_table = dedicated_states;
+	} else if (firmware_has_feature(FW_FEATURE_OPALv3)) {
+			cpuidle_state_table = powernv_states;
 	} else
 		return -ENODEV;
 

^ permalink raw reply related

* [PATCH V4 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver.
From: Deepthi Dharwar @ 2013-08-22  5:30 UTC (permalink / raw)
  To: linux-pm, linuxppc-dev, linux-kernel
  Cc: rjw, daniel.lezcano, dongsheng.wang, preeti, srivatsa.bhat,
	scottwood
In-Reply-To: <20130822052938.23277.67621.stgit@deepthi.in.ibm.com>

This patch involves moving the current pseries_idle backend driver code
from pseries/processor_idle.c to drivers/cpuidle/cpuidle-powerpc.c,
and making the backend code generic enough to be able to extend this
driver code for both powernv and pseries.

It enables the support for pseries platform, such that going forward the same code
with minimal efforts can be re-used for a common driver on powernv
and can be further extended to support cpuidle idle state mgmt for the rest
of the powerpc platforms in the future. This removes a lot of code duplicacy,
making the code elegant.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/paca.h                 |   23 +
 arch/powerpc/include/asm/processor.h            |    2 
 arch/powerpc/platforms/pseries/Kconfig          |    9 -
 arch/powerpc/platforms/pseries/Makefile         |    1 
 arch/powerpc/platforms/pseries/processor_idle.c |  360 -----------------------
 drivers/cpuidle/Kconfig                         |    7 
 drivers/cpuidle/Makefile                        |    2 
 drivers/cpuidle/cpuidle-powerpc.c               |  304 +++++++++++++++++++
 8 files changed, 337 insertions(+), 371 deletions(-)
 delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c
 create mode 100644 drivers/cpuidle/cpuidle-powerpc.c

diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 77c91e7..7bd83ff 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -175,6 +175,29 @@ extern void setup_paca(struct paca_struct *new_paca);
 extern void allocate_pacas(void);
 extern void free_unused_pacas(void);
 
+#ifdef CONFIG_PPC_BOOK3S
+#define get_lppaca_is_shared_proc()  get_paca()->lppaca_ptr->shared_proc
+static inline void set_lppaca_idle(u8  idle)
+{
+	get_paca()->lppaca_ptr->idle = idle;
+}
+
+static inline void add_lppaca_wait_state(u64 cycles)
+{
+	get_paca()->lppaca_ptr->wait_state_cycles += cycles;
+}
+
+static inline void set_lppaca_donate_dedicated_cpu(u8 value)
+{
+	get_paca()->lppaca_ptr->donate_dedicated_cpu = value;
+}
+#else
+#define get_lppaca_is_shared_proc()	-1
+static inline void set_lppaca_idle(u8 idle) { }
+static inline void  add_lppaca_wait_state(u64 cycles) { }
+static inline void  set_lppaca_donate_dedicated_cpu(u8 value) { }
+#endif
+
 #else /* CONFIG_PPC64 */
 
 static inline void allocate_pacas(void) { };
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index e378ccc..5f57c56 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -430,7 +430,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
 extern int powersave_nap;	/* set if nap mode can be used in idle loop */
 extern void power7_nap(void);
 
-#ifdef CONFIG_PSERIES_IDLE
+#ifdef CONFIG_CPU_IDLE_POWERPC
 extern void update_smt_snooze_delay(int cpu, int residency);
 #else
 static inline void update_smt_snooze_delay(int cpu, int residency) {}
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 62b4f80..bb59bb0 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -119,12 +119,3 @@ config DTL
 	  which are accessible through a debugfs file.
 
 	  Say N if you are unsure.
-
-config PSERIES_IDLE
-	bool "Cpuidle driver for pSeries platforms"
-	depends on CPU_IDLE
-	depends on PPC_PSERIES
-	default y
-	help
-	  Select this option to enable processor idle state management
-	  through cpuidle subsystem.
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 8ae0103..4b22379 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o
 obj-$(CONFIG_CMM)		+= cmm.o
 obj-$(CONFIG_DTL)		+= dtl.o
 obj-$(CONFIG_IO_EVENT_IRQ)	+= io_event_irq.o
-obj-$(CONFIG_PSERIES_IDLE)	+= processor_idle.o
 
 ifeq ($(CONFIG_PPC_PSERIES),y)
 obj-$(CONFIG_SUSPEND)		+= suspend.o
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
deleted file mode 100644
index c905b99..0000000
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- *  processor_idle - idle state cpuidle driver.
- *  Adapted from drivers/idle/intel_idle.c and
- *  drivers/acpi/processor_idle.c
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/cpuidle.h>
-#include <linux/cpu.h>
-#include <linux/notifier.h>
-
-#include <asm/paca.h>
-#include <asm/reg.h>
-#include <asm/machdep.h>
-#include <asm/firmware.h>
-#include <asm/runlatch.h>
-#include <asm/plpar_wrappers.h>
-
-struct cpuidle_driver pseries_idle_driver = {
-	.name             = "pseries_idle",
-	.owner            = THIS_MODULE,
-};
-
-#define MAX_IDLE_STATE_COUNT	2
-
-static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
-static struct cpuidle_device __percpu *pseries_cpuidle_devices;
-static struct cpuidle_state *cpuidle_state_table;
-
-static inline void idle_loop_prolog(unsigned long *in_purr)
-{
-	*in_purr = mfspr(SPRN_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;
-}
-
-static inline void idle_loop_epilog(unsigned long in_purr)
-{
-	get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr;
-	get_lppaca()->idle = 0;
-}
-
-static int snooze_loop(struct cpuidle_device *dev,
-			struct cpuidle_driver *drv,
-			int index)
-{
-	unsigned long in_purr;
-	int cpu = dev->cpu;
-
-	idle_loop_prolog(&in_purr);
-	local_irq_enable();
-	set_thread_flag(TIF_POLLING_NRFLAG);
-
-	while ((!need_resched()) && cpu_online(cpu)) {
-		ppc64_runlatch_off();
-		HMT_low();
-		HMT_very_low();
-	}
-
-	HMT_medium();
-	clear_thread_flag(TIF_POLLING_NRFLAG);
-	smp_mb();
-
-	idle_loop_epilog(in_purr);
-
-	return index;
-}
-
-static void check_and_cede_processor(void)
-{
-	/*
-	 * Ensure our interrupt state is properly tracked,
-	 * also checks if no interrupt has occurred while we
-	 * were soft-disabled
-	 */
-	if (prep_irq_for_idle()) {
-		cede_processor();
-#ifdef CONFIG_TRACE_IRQFLAGS
-		/* Ensure that H_CEDE returns with IRQs on */
-		if (WARN_ON(!(mfmsr() & MSR_EE)))
-			__hard_irq_enable();
-#endif
-	}
-}
-
-static int dedicated_cede_loop(struct cpuidle_device *dev,
-				struct cpuidle_driver *drv,
-				int index)
-{
-	unsigned long in_purr;
-
-	idle_loop_prolog(&in_purr);
-	get_lppaca()->donate_dedicated_cpu = 1;
-
-	ppc64_runlatch_off();
-	HMT_medium();
-	check_and_cede_processor();
-
-	get_lppaca()->donate_dedicated_cpu = 0;
-
-	idle_loop_epilog(in_purr);
-
-	return index;
-}
-
-static int shared_cede_loop(struct cpuidle_device *dev,
-			struct cpuidle_driver *drv,
-			int index)
-{
-	unsigned long in_purr;
-
-	idle_loop_prolog(&in_purr);
-
-	/*
-	 * 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.
-	 */
-	check_and_cede_processor();
-
-	idle_loop_epilog(in_purr);
-
-	return index;
-}
-
-/*
- * States for dedicated partition case.
- */
-static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
-	{ /* Snooze */
-		.name = "snooze",
-		.desc = "snooze",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
-		.exit_latency = 0,
-		.target_residency = 0,
-		.enter = &snooze_loop },
-	{ /* CEDE */
-		.name = "CEDE",
-		.desc = "CEDE",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
-		.exit_latency = 10,
-		.target_residency = 100,
-		.enter = &dedicated_cede_loop },
-};
-
-/*
- * States for shared partition case.
- */
-static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
-	{ /* Shared Cede */
-		.name = "Shared Cede",
-		.desc = "Shared Cede",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
-		.exit_latency = 0,
-		.target_residency = 0,
-		.enter = &shared_cede_loop },
-};
-
-void update_smt_snooze_delay(int cpu, int residency)
-{
-	struct cpuidle_driver *drv = cpuidle_get_driver();
-	struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
-
-	if (cpuidle_state_table != dedicated_states)
-		return;
-
-	if (residency < 0) {
-		/* Disable the Nap state on that cpu */
-		if (dev)
-			dev->states_usage[1].disable = 1;
-	} else
-		if (drv)
-			drv->states[1].target_residency = residency;
-}
-
-static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
-			unsigned long action, void *hcpu)
-{
-	int hotcpu = (unsigned long)hcpu;
-	struct cpuidle_device *dev =
-			per_cpu_ptr(pseries_cpuidle_devices, hotcpu);
-
-	if (dev && cpuidle_get_driver()) {
-		switch (action) {
-		case CPU_ONLINE:
-		case CPU_ONLINE_FROZEN:
-			cpuidle_pause_and_lock();
-			cpuidle_enable_device(dev);
-			cpuidle_resume_and_unlock();
-			break;
-
-		case CPU_DEAD:
-		case CPU_DEAD_FROZEN:
-			cpuidle_pause_and_lock();
-			cpuidle_disable_device(dev);
-			cpuidle_resume_and_unlock();
-			break;
-
-		default:
-			return NOTIFY_DONE;
-		}
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block setup_hotplug_notifier = {
-	.notifier_call = pseries_cpuidle_add_cpu_notifier,
-};
-
-/*
- * pseries_cpuidle_driver_init()
- */
-static int pseries_cpuidle_driver_init(void)
-{
-	int idle_state;
-	struct cpuidle_driver *drv = &pseries_idle_driver;
-
-	drv->state_count = 0;
-
-	for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
-
-		if (idle_state > max_idle_state)
-			break;
-
-		/* is the state not enabled? */
-		if (cpuidle_state_table[idle_state].enter == NULL)
-			continue;
-
-		drv->states[drv->state_count] =	/* structure copy */
-			cpuidle_state_table[idle_state];
-
-		drv->state_count += 1;
-	}
-
-	return 0;
-}
-
-/* pseries_idle_devices_uninit(void)
- * unregister cpuidle devices and de-allocate memory
- */
-static void pseries_idle_devices_uninit(void)
-{
-	int i;
-	struct cpuidle_device *dev;
-
-	for_each_possible_cpu(i) {
-		dev = per_cpu_ptr(pseries_cpuidle_devices, i);
-		cpuidle_unregister_device(dev);
-	}
-
-	free_percpu(pseries_cpuidle_devices);
-	return;
-}
-
-/* pseries_idle_devices_init()
- * allocate, initialize and register cpuidle device
- */
-static int pseries_idle_devices_init(void)
-{
-	int i;
-	struct cpuidle_driver *drv = &pseries_idle_driver;
-	struct cpuidle_device *dev;
-
-	pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device);
-	if (pseries_cpuidle_devices == NULL)
-		return -ENOMEM;
-
-	for_each_possible_cpu(i) {
-		dev = per_cpu_ptr(pseries_cpuidle_devices, i);
-		dev->state_count = drv->state_count;
-		dev->cpu = i;
-		if (cpuidle_register_device(dev)) {
-			printk(KERN_DEBUG \
-				"cpuidle_register_device %d failed!\n", i);
-			return -EIO;
-		}
-	}
-
-	return 0;
-}
-
-/*
- * pseries_idle_probe()
- * Choose state table for shared versus dedicated partition
- */
-static int pseries_idle_probe(void)
-{
-
-	if (!firmware_has_feature(FW_FEATURE_SPLPAR))
-		return -ENODEV;
-
-	if (cpuidle_disable != IDLE_NO_OVERRIDE)
-		return -ENODEV;
-
-	if (max_idle_state == 0) {
-		printk(KERN_DEBUG "pseries processor idle disabled.\n");
-		return -EPERM;
-	}
-
-	if (get_lppaca()->shared_proc)
-		cpuidle_state_table = shared_states;
-	else
-		cpuidle_state_table = dedicated_states;
-
-	return 0;
-}
-
-static int __init pseries_processor_idle_init(void)
-{
-	int retval;
-
-	retval = pseries_idle_probe();
-	if (retval)
-		return retval;
-
-	pseries_cpuidle_driver_init();
-	retval = cpuidle_register_driver(&pseries_idle_driver);
-	if (retval) {
-		printk(KERN_DEBUG "Registration of pseries driver failed.\n");
-		return retval;
-	}
-
-	retval = pseries_idle_devices_init();
-	if (retval) {
-		pseries_idle_devices_uninit();
-		cpuidle_unregister_driver(&pseries_idle_driver);
-		return retval;
-	}
-
-	register_cpu_notifier(&setup_hotplug_notifier);
-	printk(KERN_DEBUG "pseries_idle_driver registered\n");
-
-	return 0;
-}
-
-static void __exit pseries_processor_idle_exit(void)
-{
-
-	unregister_cpu_notifier(&setup_hotplug_notifier);
-	pseries_idle_devices_uninit();
-	cpuidle_unregister_driver(&pseries_idle_driver);
-
-	return;
-}
-
-module_init(pseries_processor_idle_init);
-module_exit(pseries_processor_idle_exit);
-
-MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
-MODULE_DESCRIPTION("Cpuidle driver for POWER");
-MODULE_LICENSE("GPL");
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 0e2cd5c..53ce03d 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -42,6 +42,13 @@ config CPU_IDLE_ZYNQ
 	help
 	  Select this to enable cpuidle on Xilinx Zynq processors.
 
+config CPU_IDLE_POWERPC
+	bool "CPU Idle driver for POWERPC platforms"
+	depends on PPC_PSERIES || PPC_POWERNV
+	default y
+        help
+          Select this option to enable processor idle state management
+	  for POWERPC platform.
 endif
 
 config ARCH_NEEDS_CPU_IDLE_COUPLED
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 8767a7b..d12e205 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -8,3 +8,5 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
 obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
 obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
 obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o
+
+obj-$(CONFIG_CPU_IDLE_POWERPC) += cpuidle-powerpc.o
diff --git a/drivers/cpuidle/cpuidle-powerpc.c b/drivers/cpuidle/cpuidle-powerpc.c
new file mode 100644
index 0000000..3662aba
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-powerpc.c
@@ -0,0 +1,304 @@
+/*
+ *  processor_idle - idle state cpuidle driver.
+ *  Adapted from drivers/idle/intel_idle.c and
+ *  drivers/acpi/processor_idle.c
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
+
+#include <asm/paca.h>
+#include <asm/reg.h>
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+#include <asm/runlatch.h>
+#include <asm/plpar_wrappers.h>
+
+struct cpuidle_driver powerpc_idle_driver = {
+	.name             = "powerpc_idle",
+	.owner            = THIS_MODULE,
+};
+
+#define MAX_IDLE_STATE_COUNT	2
+
+static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
+static struct cpuidle_state *cpuidle_state_table;
+
+static inline void idle_loop_prolog(unsigned long *in_purr)
+{
+	*in_purr = mfspr(SPRN_PURR);
+	/*
+	 * Indicate to the HV that we are idle. Now would be
+	 * a good time to find other work to dispatch.
+	 */
+	set_lppaca_idle(1);
+}
+
+static inline void idle_loop_epilog(unsigned long in_purr)
+{
+	add_lppaca_wait_state(mfspr(SPRN_PURR) - in_purr);
+	set_lppaca_idle(0);
+}
+
+static int snooze_loop(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
+			int index)
+{
+	unsigned long in_purr;
+
+	idle_loop_prolog(&in_purr);
+	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();
+
+	idle_loop_epilog(in_purr);
+
+	return index;
+}
+
+static void check_and_cede_processor(void)
+{
+	/*
+	 * Ensure our interrupt state is properly tracked,
+	 * also checks if no interrupt has occurred while we
+	 * were soft-disabled
+	 */
+	if (prep_irq_for_idle()) {
+		cede_processor();
+#ifdef CONFIG_TRACE_IRQFLAGS
+		/* Ensure that H_CEDE returns with IRQs on */
+		if (WARN_ON(!(mfmsr() & MSR_EE)))
+			__hard_irq_enable();
+#endif
+	}
+}
+
+static int dedicated_cede_loop(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+				int index)
+{
+	unsigned long in_purr;
+
+	idle_loop_prolog(&in_purr);
+	set_lppaca_donate_dedicated_cpu(1);
+
+	ppc64_runlatch_off();
+	HMT_medium();
+	check_and_cede_processor();
+
+	set_lppaca_donate_dedicated_cpu(0);
+	idle_loop_epilog(in_purr);
+
+	return index;
+}
+
+static int shared_cede_loop(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv,
+			int index)
+{
+	unsigned long in_purr;
+
+	idle_loop_prolog(&in_purr);
+
+	/*
+	 * 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.
+	 */
+	check_and_cede_processor();
+
+	idle_loop_epilog(in_purr);
+
+	return index;
+}
+
+/*
+ * States for dedicated partition case.
+ */
+static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
+	{ /* Snooze */
+		.name = "snooze",
+		.desc = "snooze",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = &snooze_loop },
+	{ /* CEDE */
+		.name = "CEDE",
+		.desc = "CEDE",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 10,
+		.target_residency = 100,
+		.enter = &dedicated_cede_loop },
+};
+
+/*
+ * States for shared partition case.
+ */
+static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
+	{ /* Shared Cede */
+		.name = "Shared Cede",
+		.desc = "Shared Cede",
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 0,
+		.target_residency = 0,
+		.enter = &shared_cede_loop },
+};
+
+void update_smt_snooze_delay(int cpu, int residency)
+{
+	struct cpuidle_driver *drv = cpuidle_get_driver();
+	struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
+
+	if (cpuidle_state_table != dedicated_states)
+		return;
+
+	if (residency < 0) {
+		/* Disable the Nap state on that cpu */
+		if (dev)
+			dev->states_usage[1].disable = 1;
+	} else
+		if (drv)
+			drv->states[1].target_residency = residency;
+}
+
+static int powerpc_cpuidle_add_cpu_notifier(struct notifier_block *n,
+			unsigned long action, void *hcpu)
+{
+	int hotcpu = (unsigned long)hcpu;
+	struct cpuidle_device *dev =
+			per_cpu_ptr(cpuidle_devices, hotcpu);
+
+	if (dev && cpuidle_get_driver()) {
+		switch (action) {
+		case CPU_ONLINE:
+		case CPU_ONLINE_FROZEN:
+			cpuidle_pause_and_lock();
+			cpuidle_enable_device(dev);
+			cpuidle_resume_and_unlock();
+			break;
+
+		case CPU_DEAD:
+		case CPU_DEAD_FROZEN:
+			cpuidle_pause_and_lock();
+			cpuidle_disable_device(dev);
+			cpuidle_resume_and_unlock();
+			break;
+
+		default:
+			return NOTIFY_DONE;
+		}
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block setup_hotplug_notifier = {
+	.notifier_call = powerpc_cpuidle_add_cpu_notifier,
+};
+
+/*
+ * powerpc_cpuidle_driver_init()
+ */
+static int powerpc_cpuidle_driver_init(void)
+{
+	int idle_state;
+	struct cpuidle_driver *drv = &powerpc_idle_driver;
+
+	drv->state_count = 0;
+
+	for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
+
+		if (idle_state > max_idle_state)
+			break;
+
+		/* is the state not enabled? */
+		if (cpuidle_state_table[idle_state].enter == NULL)
+			continue;
+
+		drv->states[drv->state_count] =	/* structure copy */
+			cpuidle_state_table[idle_state];
+
+		drv->state_count += 1;
+	}
+
+	return 0;
+}
+
+/*
+ * powerpc_idle_probe()
+ * Choose state table for shared versus dedicated partition
+ */
+static int powerpc_idle_probe(void)
+{
+
+	if (cpuidle_disable != IDLE_NO_OVERRIDE)
+		return -ENODEV;
+
+	if (max_idle_state == 0) {
+		printk(KERN_DEBUG "powerpc processor idle disabled.\n");
+		return -EPERM;
+	}
+
+	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+		if (get_lppaca_is_shared_proc() == 1)
+			cpuidle_state_table = shared_states;
+		else if (get_lppaca_is_shared_proc() == 0)
+			cpuidle_state_table = dedicated_states;
+	} else
+		return -ENODEV;
+
+	return 0;
+}
+
+static int __init powerpc_processor_idle_init(void)
+{
+	int retval;
+
+	retval = powerpc_idle_probe();
+	if (retval)
+		return retval;
+
+	powerpc_cpuidle_driver_init();
+	retval = cpuidle_register(&powerpc_idle_driver, NULL);
+	if (retval) {
+		printk(KERN_DEBUG "Registration of powerpc driver failed.\n");
+		return retval;
+	}
+
+	register_cpu_notifier(&setup_hotplug_notifier);
+	printk(KERN_DEBUG "powerpc_idle_driver registered\n");
+
+	return 0;
+}
+
+static void __exit powerpc_processor_idle_exit(void)
+{
+
+	unregister_cpu_notifier(&setup_hotplug_notifier);
+	cpuidle_unregister(&powerpc_idle_driver);
+	return;
+}
+
+module_init(powerpc_processor_idle_init);
+module_exit(powerpc_processor_idle_exit);
+
+MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("Cpuidle driver for powerpc");
+MODULE_LICENSE("GPL");

^ permalink raw reply related

* [PATCH V4 2/5] pseries: Move plpar_wrapper.h to powerpc common include/asm location.
From: Deepthi Dharwar @ 2013-08-22  5:30 UTC (permalink / raw)
  To: linux-pm, linuxppc-dev, linux-kernel
  Cc: rjw, daniel.lezcano, dongsheng.wang, preeti, srivatsa.bhat,
	scottwood
In-Reply-To: <20130822052938.23277.67621.stgit@deepthi.in.ibm.com>

As a part of pseries_idle backend driver cleanup to make
the code common to both pseries and powernv platforms, it
is necessary to move the backend-driver code to drivers/cpuidle.

As a pre-requisite for that, it is essential to move plpar_wrapper.h
to include/asm.

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/plpar_wrappers.h       |  325 +++++++++++++++++++++++
 arch/powerpc/platforms/pseries/cmm.c            |    3 
 arch/powerpc/platforms/pseries/dtl.c            |    3 
 arch/powerpc/platforms/pseries/hotplug-cpu.c    |    3 
 arch/powerpc/platforms/pseries/hvconsole.c      |    2 
 arch/powerpc/platforms/pseries/iommu.c          |    3 
 arch/powerpc/platforms/pseries/kexec.c          |    2 
 arch/powerpc/platforms/pseries/lpar.c           |    2 
 arch/powerpc/platforms/pseries/plpar_wrappers.h |  324 -----------------------
 arch/powerpc/platforms/pseries/processor_idle.c |    3 
 arch/powerpc/platforms/pseries/setup.c          |    2 
 arch/powerpc/platforms/pseries/smp.c            |    2 
 12 files changed, 336 insertions(+), 338 deletions(-)
 create mode 100644 arch/powerpc/include/asm/plpar_wrappers.h
 delete mode 100644 arch/powerpc/platforms/pseries/plpar_wrappers.h

diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h
new file mode 100644
index 0000000..e2f84d6
--- /dev/null
+++ b/arch/powerpc/include/asm/plpar_wrappers.h
@@ -0,0 +1,325 @@
+#ifndef _PSERIES_PLPAR_WRAPPERS_H
+#define _PSERIES_PLPAR_WRAPPERS_H
+
+#include <linux/string.h>
+#include <linux/irqflags.h>
+
+#include <asm/hvcall.h>
+#include <asm/paca.h>
+#include <asm/page.h>
+
+/* Get state of physical CPU from query_cpu_stopped */
+int smp_query_cpu_stopped(unsigned int pcpu);
+#define QCSS_STOPPED 0
+#define QCSS_STOPPING 1
+#define QCSS_NOT_STOPPED 2
+#define QCSS_HARDWARE_ERROR -1
+#define QCSS_HARDWARE_BUSY -2
+
+static inline long poll_pending(void)
+{
+	return plpar_hcall_norets(H_POLL_PENDING);
+}
+
+static inline u8 get_cede_latency_hint(void)
+{
+	return get_lppaca()->cede_latency_hint;
+}
+
+static inline void set_cede_latency_hint(u8 latency_hint)
+{
+	get_lppaca()->cede_latency_hint = latency_hint;
+}
+
+static inline long cede_processor(void)
+{
+	return plpar_hcall_norets(H_CEDE);
+}
+
+static inline long extended_cede_processor(unsigned long latency_hint)
+{
+	long rc;
+	u8 old_latency_hint = get_cede_latency_hint();
+
+	set_cede_latency_hint(latency_hint);
+
+	rc = cede_processor();
+#ifdef CONFIG_TRACE_IRQFLAGS
+		/* Ensure that H_CEDE returns with IRQs on */
+		if (WARN_ON(!(mfmsr() & MSR_EE)))
+			__hard_irq_enable();
+#endif
+
+	set_cede_latency_hint(old_latency_hint);
+
+	return rc;
+}
+
+static inline long vpa_call(unsigned long flags, unsigned long cpu,
+		unsigned long vpa)
+{
+	flags = flags << H_VPA_FUNC_SHIFT;
+
+	return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa);
+}
+
+static inline long unregister_vpa(unsigned long cpu)
+{
+	return vpa_call(H_VPA_DEREG_VPA, cpu, 0);
+}
+
+static inline long register_vpa(unsigned long cpu, unsigned long vpa)
+{
+	return vpa_call(H_VPA_REG_VPA, cpu, vpa);
+}
+
+static inline long unregister_slb_shadow(unsigned long cpu)
+{
+	return vpa_call(H_VPA_DEREG_SLB, cpu, 0);
+}
+
+static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
+{
+	return vpa_call(H_VPA_REG_SLB, cpu, vpa);
+}
+
+static inline long unregister_dtl(unsigned long cpu)
+{
+	return vpa_call(H_VPA_DEREG_DTL, cpu, 0);
+}
+
+static inline long register_dtl(unsigned long cpu, unsigned long vpa)
+{
+	return vpa_call(H_VPA_REG_DTL, cpu, vpa);
+}
+
+static inline long plpar_page_set_loaned(unsigned long vpa)
+{
+	unsigned long cmo_page_sz = cmo_get_page_size();
+	long rc = 0;
+	int i;
+
+	for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz)
+		rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED, vpa + i, 0);
+
+	for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz)
+		plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE,
+				   vpa + i - cmo_page_sz, 0);
+
+	return rc;
+}
+
+static inline long plpar_page_set_active(unsigned long vpa)
+{
+	unsigned long cmo_page_sz = cmo_get_page_size();
+	long rc = 0;
+	int i;
+
+	for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz)
+		rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE, vpa + i, 0);
+
+	for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz)
+		plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED,
+				   vpa + i - cmo_page_sz, 0);
+
+	return rc;
+}
+
+extern void vpa_init(int cpu);
+
+static inline long plpar_pte_enter(unsigned long flags,
+		unsigned long hpte_group, unsigned long hpte_v,
+		unsigned long hpte_r, unsigned long *slot)
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r);
+
+	*slot = retbuf[0];
+
+	return rc;
+}
+
+static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex,
+		unsigned long avpn, unsigned long *old_pteh_ret,
+		unsigned long *old_ptel_ret)
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn);
+
+	*old_pteh_ret = retbuf[0];
+	*old_ptel_ret = retbuf[1];
+
+	return rc;
+}
+
+/* plpar_pte_remove_raw can be called in real mode. It calls plpar_hcall_raw */
+static inline long plpar_pte_remove_raw(unsigned long flags, unsigned long ptex,
+		unsigned long avpn, unsigned long *old_pteh_ret,
+		unsigned long *old_ptel_ret)
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall_raw(H_REMOVE, retbuf, flags, ptex, avpn);
+
+	*old_pteh_ret = retbuf[0];
+	*old_ptel_ret = retbuf[1];
+
+	return rc;
+}
+
+static inline long plpar_pte_read(unsigned long flags, unsigned long ptex,
+		unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall(H_READ, retbuf, flags, ptex);
+
+	*old_pteh_ret = retbuf[0];
+	*old_ptel_ret = retbuf[1];
+
+	return rc;
+}
+
+/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */
+static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex,
+		unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex);
+
+	*old_pteh_ret = retbuf[0];
+	*old_ptel_ret = retbuf[1];
+
+	return rc;
+}
+
+/*
+ * plpar_pte_read_4_raw can be called in real mode.
+ * ptes must be 8*sizeof(unsigned long)
+ */
+static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex,
+					unsigned long *ptes)
+
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+
+	rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex);
+
+	memcpy(ptes, retbuf, 8*sizeof(unsigned long));
+
+	return rc;
+}
+
+static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
+		unsigned long avpn)
+{
+	return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);
+}
+
+static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba,
+		unsigned long *tce_ret)
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba);
+
+	*tce_ret = retbuf[0];
+
+	return rc;
+}
+
+static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba,
+		unsigned long tceval)
+{
+	return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval);
+}
+
+static inline long plpar_tce_put_indirect(unsigned long liobn,
+		unsigned long ioba, unsigned long page, unsigned long count)
+{
+	return plpar_hcall_norets(H_PUT_TCE_INDIRECT, liobn, ioba, page, count);
+}
+
+static inline long plpar_tce_stuff(unsigned long liobn, unsigned long ioba,
+		unsigned long tceval, unsigned long count)
+{
+	return plpar_hcall_norets(H_STUFF_TCE, liobn, ioba, tceval, count);
+}
+
+static inline long plpar_get_term_char(unsigned long termno,
+		unsigned long *len_ret, char *buf_ret)
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+	unsigned long *lbuf = (unsigned long *)buf_ret;	/* TODO: alignment? */
+
+	rc = plpar_hcall(H_GET_TERM_CHAR, retbuf, termno);
+
+	*len_ret = retbuf[0];
+	lbuf[0] = retbuf[1];
+	lbuf[1] = retbuf[2];
+
+	return rc;
+}
+
+static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
+		const char *buffer)
+{
+	unsigned long *lbuf = (unsigned long *)buffer;	/* TODO: alignment? */
+	return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0],
+			lbuf[1]);
+}
+
+/* Set various resource mode parameters */
+static inline long plpar_set_mode(unsigned long mflags, unsigned long resource,
+		unsigned long value1, unsigned long value2)
+{
+	return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2);
+}
+
+/*
+ * Enable relocation on exceptions on this partition
+ *
+ * Note: this call has a partition wide scope and can take a while to complete.
+ * If it returns H_LONG_BUSY_* it should be retried periodically until it
+ * returns H_SUCCESS.
+ */
+static inline long enable_reloc_on_exceptions(void)
+{
+	/* mflags = 3: Exceptions at 0xC000000000004000 */
+	return plpar_set_mode(3, 3, 0, 0);
+}
+
+/*
+ * Disable relocation on exceptions on this partition
+ *
+ * Note: this call has a partition wide scope and can take a while to complete.
+ * If it returns H_LONG_BUSY_* it should be retried periodically until it
+ * returns H_SUCCESS.
+ */
+static inline long disable_reloc_on_exceptions(void)
+{
+	return plpar_set_mode(0, 3, 0, 0);
+}
+
+static inline long plapr_set_ciabr(unsigned long ciabr)
+{
+	return plpar_set_mode(0, 1, ciabr, 0);
+}
+
+static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0)
+{
+	return plpar_set_mode(0, 2, dawr0, dawrx0);
+}
+
+#endif /* _PSERIES_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c
index c638535..1e561be 100644
--- a/arch/powerpc/platforms/pseries/cmm.c
+++ b/arch/powerpc/platforms/pseries/cmm.c
@@ -40,8 +40,7 @@
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <linux/memory.h>
-
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
 
 #define CMM_DRIVER_VERSION	"1.0.0"
 #define CMM_DEFAULT_DELAY	1
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index 0cc0ac0..f6cb051 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -29,8 +29,7 @@
 #include <asm/firmware.h>
 #include <asm/lppaca.h>
 #include <asm/debug.h>
-
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
 
 struct dtl {
 	struct dtl_entry	*buf;
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 217ca5c..a8ef932 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -30,7 +30,8 @@
 #include <asm/machdep.h>
 #include <asm/vdso_datapage.h>
 #include <asm/xics.h>
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
+
 #include "offline_states.h"
 
 /* This version can't take the spinlock, because it never returns */
diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index b344f94..f3f108b 100644
--- a/arch/powerpc/platforms/pseries/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
@@ -28,7 +28,7 @@
 #include <linux/errno.h>
 #include <asm/hvcall.h>
 #include <asm/hvconsole.h>
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
 
 /**
  * hvc_get_chars - retrieve characters from firmware for denoted vterm adatper
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 23fc1dc..4821933 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -48,8 +48,7 @@
 #include <asm/ppc-pci.h>
 #include <asm/udbg.h>
 #include <asm/mmzone.h>
-
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
 
 
 static void tce_invalidate_pSeries_sw(struct iommu_table *tbl,
diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c
index 7d94bdc..13fa95b3 100644
--- a/arch/powerpc/platforms/pseries/kexec.c
+++ b/arch/powerpc/platforms/pseries/kexec.c
@@ -17,9 +17,9 @@
 #include <asm/mpic.h>
 #include <asm/xics.h>
 #include <asm/smp.h>
+#include <asm/plpar_wrappers.h>
 
 #include "pseries.h"
-#include "plpar_wrappers.h"
 
 static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
 {
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 8bad880..e1873bc 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -41,8 +41,8 @@
 #include <asm/smp.h>
 #include <asm/trace.h>
 #include <asm/firmware.h>
+#include <asm/plpar_wrappers.h>
 
-#include "plpar_wrappers.h"
 #include "pseries.h"
 
 /* Flag bits for H_BULK_REMOVE */
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
deleted file mode 100644
index f35787b..0000000
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ /dev/null
@@ -1,324 +0,0 @@
-#ifndef _PSERIES_PLPAR_WRAPPERS_H
-#define _PSERIES_PLPAR_WRAPPERS_H
-
-#include <linux/string.h>
-#include <linux/irqflags.h>
-
-#include <asm/hvcall.h>
-#include <asm/paca.h>
-#include <asm/page.h>
-
-/* Get state of physical CPU from query_cpu_stopped */
-int smp_query_cpu_stopped(unsigned int pcpu);
-#define QCSS_STOPPED 0
-#define QCSS_STOPPING 1
-#define QCSS_NOT_STOPPED 2
-#define QCSS_HARDWARE_ERROR -1
-#define QCSS_HARDWARE_BUSY -2
-
-static inline long poll_pending(void)
-{
-	return plpar_hcall_norets(H_POLL_PENDING);
-}
-
-static inline u8 get_cede_latency_hint(void)
-{
-	return get_lppaca()->cede_latency_hint;
-}
-
-static inline void set_cede_latency_hint(u8 latency_hint)
-{
-	get_lppaca()->cede_latency_hint = latency_hint;
-}
-
-static inline long cede_processor(void)
-{
-	return plpar_hcall_norets(H_CEDE);
-}
-
-static inline long extended_cede_processor(unsigned long latency_hint)
-{
-	long rc;
-	u8 old_latency_hint = get_cede_latency_hint();
-
-	set_cede_latency_hint(latency_hint);
-
-	rc = cede_processor();
-#ifdef CONFIG_TRACE_IRQFLAGS
-		/* Ensure that H_CEDE returns with IRQs on */
-		if (WARN_ON(!(mfmsr() & MSR_EE)))
-			__hard_irq_enable();
-#endif
-
-	set_cede_latency_hint(old_latency_hint);
-
-	return rc;
-}
-
-static inline long vpa_call(unsigned long flags, unsigned long cpu,
-		unsigned long vpa)
-{
-	flags = flags << H_VPA_FUNC_SHIFT;
-
-	return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa);
-}
-
-static inline long unregister_vpa(unsigned long cpu)
-{
-	return vpa_call(H_VPA_DEREG_VPA, cpu, 0);
-}
-
-static inline long register_vpa(unsigned long cpu, unsigned long vpa)
-{
-	return vpa_call(H_VPA_REG_VPA, cpu, vpa);
-}
-
-static inline long unregister_slb_shadow(unsigned long cpu)
-{
-	return vpa_call(H_VPA_DEREG_SLB, cpu, 0);
-}
-
-static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
-{
-	return vpa_call(H_VPA_REG_SLB, cpu, vpa);
-}
-
-static inline long unregister_dtl(unsigned long cpu)
-{
-	return vpa_call(H_VPA_DEREG_DTL, cpu, 0);
-}
-
-static inline long register_dtl(unsigned long cpu, unsigned long vpa)
-{
-	return vpa_call(H_VPA_REG_DTL, cpu, vpa);
-}
-
-static inline long plpar_page_set_loaned(unsigned long vpa)
-{
-	unsigned long cmo_page_sz = cmo_get_page_size();
-	long rc = 0;
-	int i;
-
-	for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz)
-		rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED, vpa + i, 0);
-
-	for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz)
-		plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE,
-				   vpa + i - cmo_page_sz, 0);
-
-	return rc;
-}
-
-static inline long plpar_page_set_active(unsigned long vpa)
-{
-	unsigned long cmo_page_sz = cmo_get_page_size();
-	long rc = 0;
-	int i;
-
-	for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz)
-		rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE, vpa + i, 0);
-
-	for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz)
-		plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED,
-				   vpa + i - cmo_page_sz, 0);
-
-	return rc;
-}
-
-extern void vpa_init(int cpu);
-
-static inline long plpar_pte_enter(unsigned long flags,
-		unsigned long hpte_group, unsigned long hpte_v,
-		unsigned long hpte_r, unsigned long *slot)
-{
-	long rc;
-	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-	rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r);
-
-	*slot = retbuf[0];
-
-	return rc;
-}
-
-static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex,
-		unsigned long avpn, unsigned long *old_pteh_ret,
-		unsigned long *old_ptel_ret)
-{
-	long rc;
-	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-	rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn);
-
-	*old_pteh_ret = retbuf[0];
-	*old_ptel_ret = retbuf[1];
-
-	return rc;
-}
-
-/* plpar_pte_remove_raw can be called in real mode. It calls plpar_hcall_raw */
-static inline long plpar_pte_remove_raw(unsigned long flags, unsigned long ptex,
-		unsigned long avpn, unsigned long *old_pteh_ret,
-		unsigned long *old_ptel_ret)
-{
-	long rc;
-	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-	rc = plpar_hcall_raw(H_REMOVE, retbuf, flags, ptex, avpn);
-
-	*old_pteh_ret = retbuf[0];
-	*old_ptel_ret = retbuf[1];
-
-	return rc;
-}
-
-static inline long plpar_pte_read(unsigned long flags, unsigned long ptex,
-		unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
-	long rc;
-	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-	rc = plpar_hcall(H_READ, retbuf, flags, ptex);
-
-	*old_pteh_ret = retbuf[0];
-	*old_ptel_ret = retbuf[1];
-
-	return rc;
-}
-
-/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */
-static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex,
-		unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
-	long rc;
-	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-	rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex);
-
-	*old_pteh_ret = retbuf[0];
-	*old_ptel_ret = retbuf[1];
-
-	return rc;
-}
-
-/*
- * plpar_pte_read_4_raw can be called in real mode.
- * ptes must be 8*sizeof(unsigned long)
- */
-static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex,
-					unsigned long *ptes)
-
-{
-	long rc;
-	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
-
-	rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex);
-
-	memcpy(ptes, retbuf, 8*sizeof(unsigned long));
-
-	return rc;
-}
-
-static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
-		unsigned long avpn)
-{
-	return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);
-}
-
-static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba,
-		unsigned long *tce_ret)
-{
-	long rc;
-	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-	rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba);
-
-	*tce_ret = retbuf[0];
-
-	return rc;
-}
-
-static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba,
-		unsigned long tceval)
-{
-	return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval);
-}
-
-static inline long plpar_tce_put_indirect(unsigned long liobn,
-		unsigned long ioba, unsigned long page, unsigned long count)
-{
-	return plpar_hcall_norets(H_PUT_TCE_INDIRECT, liobn, ioba, page, count);
-}
-
-static inline long plpar_tce_stuff(unsigned long liobn, unsigned long ioba,
-		unsigned long tceval, unsigned long count)
-{
-	return plpar_hcall_norets(H_STUFF_TCE, liobn, ioba, tceval, count);
-}
-
-static inline long plpar_get_term_char(unsigned long termno,
-		unsigned long *len_ret, char *buf_ret)
-{
-	long rc;
-	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-	unsigned long *lbuf = (unsigned long *)buf_ret;	/* TODO: alignment? */
-
-	rc = plpar_hcall(H_GET_TERM_CHAR, retbuf, termno);
-
-	*len_ret = retbuf[0];
-	lbuf[0] = retbuf[1];
-	lbuf[1] = retbuf[2];
-
-	return rc;
-}
-
-static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
-		const char *buffer)
-{
-	unsigned long *lbuf = (unsigned long *)buffer;	/* TODO: alignment? */
-	return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0],
-			lbuf[1]);
-}
-
-/* Set various resource mode parameters */
-static inline long plpar_set_mode(unsigned long mflags, unsigned long resource,
-		unsigned long value1, unsigned long value2)
-{
-	return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2);
-}
-
-/*
- * Enable relocation on exceptions on this partition
- *
- * Note: this call has a partition wide scope and can take a while to complete.
- * If it returns H_LONG_BUSY_* it should be retried periodically until it
- * returns H_SUCCESS.
- */
-static inline long enable_reloc_on_exceptions(void)
-{
-	/* mflags = 3: Exceptions at 0xC000000000004000 */
-	return plpar_set_mode(3, 3, 0, 0);
-}
-
-/*
- * Disable relocation on exceptions on this partition
- *
- * Note: this call has a partition wide scope and can take a while to complete.
- * If it returns H_LONG_BUSY_* it should be retried periodically until it
- * returns H_SUCCESS.
- */
-static inline long disable_reloc_on_exceptions(void) {
-	return plpar_set_mode(0, 3, 0, 0);
-}
-
-static inline long plapr_set_ciabr(unsigned long ciabr)
-{
-	return plpar_set_mode(0, 1, ciabr, 0);
-}
-
-static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0)
-{
-	return plpar_set_mode(0, 2, dawr0, dawrx0);
-}
-
-#endif /* _PSERIES_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
index ca70279..c905b99 100644
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ b/arch/powerpc/platforms/pseries/processor_idle.c
@@ -18,8 +18,7 @@
 #include <asm/machdep.h>
 #include <asm/firmware.h>
 #include <asm/runlatch.h>
-
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
 
 struct cpuidle_driver pseries_idle_driver = {
 	.name             = "pseries_idle",
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index c11c823..4291589 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -66,8 +66,8 @@
 #include <asm/firmware.h>
 #include <asm/eeh.h>
 #include <asm/reg.h>
+#include <asm/plpar_wrappers.h>
 
-#include "plpar_wrappers.h"
 #include "pseries.h"
 
 int CMO_PrPSP = -1;
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 306643c..1c79af7 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -43,8 +43,8 @@
 #include <asm/cputhreads.h>
 #include <asm/xics.h>
 #include <asm/dbell.h>
+#include <asm/plpar_wrappers.h>
 
-#include "plpar_wrappers.h"
 #include "pseries.h"
 #include "offline_states.h"
 

^ permalink raw reply related

* [PATCH V4 1/5] pseries/cpuidle: Remove dependency of pseries.h file
From: Deepthi Dharwar @ 2013-08-22  5:30 UTC (permalink / raw)
  To: linux-pm, linuxppc-dev, linux-kernel
  Cc: rjw, daniel.lezcano, dongsheng.wang, preeti, srivatsa.bhat,
	scottwood
In-Reply-To: <20130822052938.23277.67621.stgit@deepthi.in.ibm.com>

As a part of pseries_idle cleanup to make the backend driver
code common to both pseries and powernv.
Remove non-essential smt_snooze_delay declaration in pseries.h
header file and pseries.h file inclusion in
pseries/processor_idle.c

Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/pseries/processor_idle.c |    1 -
 arch/powerpc/platforms/pseries/pseries.h        |    3 ---
 2 files changed, 4 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
index 4644efa0..ca70279 100644
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ b/arch/powerpc/platforms/pseries/processor_idle.c
@@ -20,7 +20,6 @@
 #include <asm/runlatch.h>
 
 #include "plpar_wrappers.h"
-#include "pseries.h"
 
 struct cpuidle_driver pseries_idle_driver = {
 	.name             = "pseries_idle",
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index c2a3a25..d1b07e6 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -60,9 +60,6 @@ extern struct device_node *dlpar_configure_connector(u32);
 extern int dlpar_attach_node(struct device_node *);
 extern int dlpar_detach_node(struct device_node *);
 
-/* Snooze Delay, pseries_idle */
-DECLARE_PER_CPU(long, smt_snooze_delay);
-
 /* PCI root bridge prepare function override for pseries */
 struct pci_host_bridge;
 int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);

^ permalink raw reply related

* [PATCH V4 0/5] powerpc/cpuidle: Generic POWERPC cpuidle driver enabled for POWER and POWERNV platforms
From: Deepthi Dharwar @ 2013-08-22  5:29 UTC (permalink / raw)
  To: linux-pm, linuxppc-dev, linux-kernel
  Cc: rjw, daniel.lezcano, dongsheng.wang, preeti, srivatsa.bhat,
	scottwood

This patch series consolidates the backend cpuidle driver for pSeries
and powernv platforms with minimal code duplication.

Current existing backend driver for pseries has been moved to drivers/cpuidle 
and has been extended to accommodate powernv idle power mgmt states. 
As seen in V1 of this patch series, having a separate powernv backend driver 
results in too much code duplication, which is less elegant and can pose 
maintenance problems going further.

Using the cpuidle framework to exploit platform low power idle states
management can take advantage of advanced heuristics, tunables and features 
provided by framework. The statistics and tracing infrastructure provided 
by the cpuidle framework also helps in enabling power management 
related tools and help tune the system and applications.

Earlier in 3.3 kernel, pSeries idle state management was modified to 
exploit the cpuidle framework and the end goal of this patch is to have powernv
platform also to hook its idle states into cpuidle framework with minimal 
code duplication between both platforms. This result is a generic powerpc 
backend driver currently enabled for pseries and powernv platforms and which
can be extended to accommodate other powerpc archs as well in the future.

This series aims to maintain compatibility and functionality to existing pseries 
and powernv idle cpu management code. There are no new functions or idle 
states added as part of this series. This can be extended by adding more 
states to this existing framework.

With this patch series, the powernv cpuidle functionalities are on-par with 
pSeries idle management.  

V1 -> http://lkml.org/lkml/2013/7/23/143
V2 -> https://lkml.org/lkml/2013/7/30/872
V3 -> http://comments.gmane.org/gmane.linux.ports.ppc.embedded/63093 

Changes in V4:
=============

* This patch series includes generic backend driver cpuidle cleanups 
  including, replacing the driver and device initialisation
  routines with cpuidle_register function.

* Enable CPUIDLE framework only for POWER and POWERNV platforms.

Changes in V3:
=============

* This patch series does not include smt-snooze-delay fixes. 
  This will be taken up later on.

* Integrated POWERPC driver in drivers/cpuidle.  Enabled for all of 
  POWERPC platform.  Currently has PSERIES and POWERNV support.
  No compile time flags in .c file. This  will be one consolidated 
  binary that does a run time detection based on platform and take 
  decisions accordingly.

* Enabled CPUIDLE framwork for all of PPC64.

Changes in V2:
=============

* Merged the backend driver posted out for powernv in V1 with
  pSeries to create a single powerpc driver but this had compile
  time flags.

 Deepthi Dharwar (5):
      pseries/cpuidle: Remove dependency of pseries.h file
      pseries: Move plpar_wrapper.h to powerpc common include/asm location.
      powerpc/cpuidle: Generic powerpc backend cpuidle driver.
      powerpc/cpuidle: Enable powernv cpuidle support.
      powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework.


 arch/powerpc/include/asm/paca.h                 |   23 +
 arch/powerpc/include/asm/plpar_wrappers.h       |  325 +++++++++++++++++++++
 arch/powerpc/include/asm/processor.h            |    2 
 arch/powerpc/platforms/powernv/setup.c          |   14 +
 arch/powerpc/platforms/pseries/Kconfig          |    9 -
 arch/powerpc/platforms/pseries/Makefile         |    1 
 arch/powerpc/platforms/pseries/cmm.c            |    3 
 arch/powerpc/platforms/pseries/dtl.c            |    3 
 arch/powerpc/platforms/pseries/hotplug-cpu.c    |    3 
 arch/powerpc/platforms/pseries/hvconsole.c      |    2 
 arch/powerpc/platforms/pseries/iommu.c          |    3 
 arch/powerpc/platforms/pseries/kexec.c          |    2 
 arch/powerpc/platforms/pseries/lpar.c           |    2 
 arch/powerpc/platforms/pseries/plpar_wrappers.h |  324 ---------------------
 arch/powerpc/platforms/pseries/processor_idle.c |  362 -----------------------
 arch/powerpc/platforms/pseries/pseries.h        |    3 
 arch/powerpc/platforms/pseries/setup.c          |    2 
 arch/powerpc/platforms/pseries/smp.c            |    2 
 drivers/cpuidle/Kconfig                         |    7 
 drivers/cpuidle/Makefile                        |    2 
 drivers/cpuidle/cpuidle-powerpc.c               |  335 +++++++++++++++++++++
 21 files changed, 716 insertions(+), 713 deletions(-)
 create mode 100644 arch/powerpc/include/asm/plpar_wrappers.h
 delete mode 100644 arch/powerpc/platforms/pseries/plpar_wrappers.h
 delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c
 create mode 100644 drivers/cpuidle/cpuidle-powerpc.c


-- Deepthi

^ permalink raw reply

* [PATCH] powerpc/p1010rdb: update phy node in dts
From: Shengzhou Liu @ 2013-08-22  4:06 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Shengzhou Liu

Update phy node according to new P1010RDB-PB board.

Signed-off-by: Shengzhou Liu <Shengzhou.Liu@freescale.com>
---
 arch/powerpc/boot/dts/p1010rdb.dtsi |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/boot/dts/p1010rdb.dtsi b/arch/powerpc/boot/dts/p1010rdb.dtsi
index ec7c27a..da24b2d 100644
--- a/arch/powerpc/boot/dts/p1010rdb.dtsi
+++ b/arch/powerpc/boot/dts/p1010rdb.dtsi
@@ -193,17 +193,17 @@
 
 	mdio@24000 {
 		phy0: ethernet-phy@0 {
-			interrupts = <3 1 0 0>;
+			interrupts = <0 1>;
 			reg = <0x1>;
 		};
 
 		phy1: ethernet-phy@1 {
-			interrupts = <2 1 0 0>;
+			interrupts = <2 1>;
 			reg = <0x0>;
 		};
 
 		phy2: ethernet-phy@2 {
-			interrupts = <2 1 0 0>;
+			interrupts = <1 1>;
 			reg = <0x2>;
 		};
 
-- 
1.7.0.4

^ permalink raw reply related

* Re: [RFC V2 PATCH 4/6] cpuidle/ppc: Add longnap state to the idle states on powernv
From: Benjamin Herrenschmidt @ 2013-08-22  3:28 UTC (permalink / raw)
  To: Preeti U Murthy
  Cc: fweisbec, paul.gortmaker, paulus, shangw, rjw, paulmck, arnd,
	linux-pm, rostedt, john.stultz, tglx, chenhui.zhao, deepthi,
	r58472, geoff, linux-kernel, srivatsa.bhat, schwidefsky,
	linuxppc-dev
In-Reply-To: <20130814115623.5193.36974.stgit@preeti.in.ibm.com>

On Wed, 2013-08-14 at 17:26 +0530, Preeti U Murthy wrote:
> This patch hooks into the existing broadcast framework along with the support
> that this patchset introduces for ppc, and the cpuidle driver backend
> for powernv(posted out by Deepthi Dharwar:https://lkml.org/lkml/2013/7/23/128)
> to add sleep state as one of the deep idle states, in which the decrementer
> is switched off.
> 
> However in this patch, we only emulate sleep by going into a state which does
> a nap with the decrementer interrupts disabled, termed as longnap. This enables
> focus on the timer broadcast framework for ppc in this series of patches ,
> which is required as a first step to enable sleep on ppc.

This is only for debug / proof of concept right ? We should use a real
sleep here.

If we need to know whether the FW supports it (PORE etc...) we shall add
a device-tree property from the FW to indicate that fact.

Cheers,
Ben.

> Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com>
> ---
> 
>  arch/powerpc/platforms/powernv/processor_idle.c |   48 +++++++++++++++++++++++
>  1 file changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/powerpc/platforms/powernv/processor_idle.c b/arch/powerpc/platforms/powernv/processor_idle.c
> index f43ad91a..9aca502 100644
> --- a/arch/powerpc/platforms/powernv/processor_idle.c
> +++ b/arch/powerpc/platforms/powernv/processor_idle.c
> @@ -9,16 +9,18 @@
>  #include <linux/cpuidle.h>
>  #include <linux/cpu.h>
>  #include <linux/notifier.h>
> +#include <linux/clockchips.h>
>  
>  #include <asm/machdep.h>
>  #include <asm/runlatch.h>
> +#include <asm/time.h>
>  
>  struct cpuidle_driver powernv_idle_driver = {
>  	.name =		"powernv_idle",
>  	.owner =	THIS_MODULE,
>  };
>  
> -#define MAX_IDLE_STATE_COUNT	2
> +#define MAX_IDLE_STATE_COUNT	3
>  
>  static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
>  static struct cpuidle_device __percpu *powernv_cpuidle_devices;
> @@ -54,6 +56,43 @@ static int nap_loop(struct cpuidle_device *dev,
>  	return index;
>  }
>  
> +/* Emulate sleep, with long nap.
> + * During sleep, the core does not receive decrementer interrupts.
> + * Emulate sleep using long nap with decrementers interrupts disabled.
> + * This is an initial prototype to test the timer offload framework for ppc.
> + * We will eventually introduce the sleep state once the timer offload framework
> + * for ppc is stable.
> + */
> +static int longnap_loop(struct cpuidle_device *dev,
> +				struct cpuidle_driver *drv,
> +				int index)
> +{
> +	int cpu = dev->cpu;
> +
> +	unsigned long lpcr = mfspr(SPRN_LPCR);
> +
> +	lpcr &= ~(LPCR_MER | LPCR_PECE); /* lpcr[mer] must be 0 */
> +
> +	/* exit powersave upon external interrupt, but not decrementer
> +	 * interrupt, Emulate sleep.
> +	 */
> +	lpcr |= LPCR_PECE0;
> +
> +	if (cpu != bc_cpu) {
> +		mtspr(SPRN_LPCR, lpcr);
> +		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
> +		power7_nap();
> +		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
> +	} else {
> +		/* Wakeup on a decrementer interrupt, Do a nap */
> +		lpcr |= LPCR_PECE1;
> +		mtspr(SPRN_LPCR, lpcr);
> +		power7_nap();
> +	}
> +
> +	return index;
> +}
> +
>  /*
>   * States for dedicated partition case.
>   */
> @@ -72,6 +111,13 @@ static struct cpuidle_state powernv_states[MAX_IDLE_STATE_COUNT] = {
>  		.exit_latency = 10,
>  		.target_residency = 100,
>  		.enter = &nap_loop },
> +	 { /* LongNap */
> +		.name = "LongNap",
> +		.desc = "LongNap",
> +		.flags = CPUIDLE_FLAG_TIME_VALID,
> +		.exit_latency = 10,
> +		.target_residency = 100,
> +		.enter = &longnap_loop },
>  };
>  
>  static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,

^ permalink raw reply

* Re: [RFC V2 PATCH 3/6] cpuidle/ppc: Add timer offload framework to support deep idle states
From: Benjamin Herrenschmidt @ 2013-08-22  3:27 UTC (permalink / raw)
  To: Preeti U Murthy
  Cc: fweisbec, paul.gortmaker, paulus, shangw, rjw, paulmck, arnd,
	linux-pm, rostedt, john.stultz, tglx, chenhui.zhao, deepthi,
	r58472, geoff, linux-kernel, srivatsa.bhat, schwidefsky,
	linuxppc-dev
In-Reply-To: <20130814115613.5193.43161.stgit@preeti.in.ibm.com>

On Wed, 2013-08-14 at 17:26 +0530, Preeti U Murthy wrote:

>  static irqreturn_t timer_action(int irq, void *data)
>  {
> -	timer_interrupt();
> +	decrementer_timer_interrupt();
>  	return IRQ_HANDLED;
>  }

I don't completely understand what you are doing here, but ...

> @@ -223,7 +223,7 @@ irqreturn_t smp_ipi_demux(void)
>  
>  #ifdef __BIG_ENDIAN
>  		if (all & (1 << (24 - 8 * PPC_MSG_TIMER)))
> -			timer_interrupt();
> +			decrementer_timer_interrupt();

Why call this decrementer_* since it's specifically *not* the
decrementer ?

Makes more sense to be called broadcast_timer_interrupt() no ?

>  		if (all & (1 << (24 - 8 * PPC_MSG_RESCHEDULE)))
>  			scheduler_ipi();
>  		if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNC_SINGLE)))
> diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
> index 65ab9e9..7e858e1 100644
> --- a/arch/powerpc/kernel/time.c
> +++ b/arch/powerpc/kernel/time.c
> @@ -42,6 +42,7 @@
>  #include <linux/timex.h>
>  #include <linux/kernel_stat.h>
>  #include <linux/time.h>
> +#include <linux/timer.h>
>  #include <linux/init.h>
>  #include <linux/profile.h>
>  #include <linux/cpu.h>
> @@ -97,8 +98,11 @@ static struct clocksource clocksource_timebase = {
>  
>  static int decrementer_set_next_event(unsigned long evt,
>  				      struct clock_event_device *dev);
> +static int broadcast_set_next_event(unsigned long evt,
> +				      struct clock_event_device *dev);
>  static void decrementer_set_mode(enum clock_event_mode mode,
>  				 struct clock_event_device *dev);
> +static void decrementer_timer_broadcast(const struct cpumask *mask);
>  
>  struct clock_event_device decrementer_clockevent = {
>  	.name           = "decrementer",
> @@ -106,13 +110,26 @@ struct clock_event_device decrementer_clockevent = {
>  	.irq            = 0,
>  	.set_next_event = decrementer_set_next_event,
>  	.set_mode       = decrementer_set_mode,
> -	.features       = CLOCK_EVT_FEAT_ONESHOT,
> +	.broadcast	= decrementer_timer_broadcast,
> +	.features       = CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_ONESHOT,
>  };
>  EXPORT_SYMBOL(decrementer_clockevent);
>  
> +struct clock_event_device broadcast_clockevent = {
> +	.name           = "broadcast",
> +	.rating         = 200,
> +	.irq            = 0,
> +	.set_next_event = broadcast_set_next_event,
> +	.set_mode       = decrementer_set_mode,

Same here, why "decrementer" ? This event device is *not* the
decrementer right ?

Also, pardon my ignorance, by why do we need a separate
clock_event_device ? Ie what does that do ? I am not familiar with the
broadcast scheme and what .broadcast do in the "decrementer" one, so
you need to provide me at least with better explanations.

> +	.features       = CLOCK_EVT_FEAT_ONESHOT,
> +};
> +EXPORT_SYMBOL(broadcast_clockevent);
> +
>  DEFINE_PER_CPU(u64, decrementers_next_tb);
>  static DEFINE_PER_CPU(struct clock_event_device, decrementers);
> +static DEFINE_PER_CPU(struct clock_event_device, bc_timer);

Do we really need an additional per CPU here ? What does the bc_timer
actually represent ? The sender (broadcaster) or receiver ? In the
latter case, why does it have to differ from the decrementer ?

> +int bc_cpu;

A global with that name ? Exported ? That's gross...

>  #define XSEC_PER_SEC (1024*1024)
>  
>  #ifdef CONFIG_PPC64
> @@ -487,6 +504,8 @@ void timer_interrupt(struct pt_regs * regs)
>  	struct pt_regs *old_regs;
>  	u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
>  	struct clock_event_device *evt = &__get_cpu_var(decrementers);
> +	struct clock_event_device *bc_evt = &__get_cpu_var(bc_timer);
> +	int cpu = smp_processor_id();
>  	u64 now;
>  
>  	/* Ensure a positive value is written to the decrementer, or else
> @@ -532,6 +551,10 @@ void timer_interrupt(struct pt_regs * regs)
>  		*next_tb = ~(u64)0;
>  		if (evt->event_handler)
>  			evt->event_handler(evt);
> +		if (cpu == bc_cpu && bc_evt->event_handler) {
> +			bc_evt->event_handler(bc_evt);
> +		}
> +

So here, on a CPU that happens to be "bc_cpu", we call an additional
"event_handler" on every timer interrupt ? What does that handler
actually do ? How does it relate to the "broadcast" field in the
original clock source ?

>  	} else {
>  		now = *next_tb - now;
>  		if (now <= DECREMENTER_MAX)
> @@ -806,6 +829,20 @@ static int decrementer_set_next_event(unsigned long evt,
>  	return 0;
>  }
>  
> +/*
> + * We cannot program the decrementer of a remote CPU. Hence CPUs going into
> + * deep idle states need to send IPIs to the broadcast CPU to program its
> + * decrementer for their next local event so as to receive a broadcast IPI
> + * for the same. In order to avoid the overhead of multiple CPUs from sending
> + * IPIs, this function is a nop. Instead the broadcast CPU will handle the
> + * wakeup of CPUs in deep idle states in each of its local timer interrupts.
> + */
> +static int broadcast_set_next_event(unsigned long evt,
> +					struct clock_event_device *dev)
> +{
> +	return 0;
> +}
> +
>  static void decrementer_set_mode(enum clock_event_mode mode,
>  				 struct clock_event_device *dev)
>  {
> @@ -813,6 +850,20 @@ static void decrementer_set_mode(enum clock_event_mode mode,
>  		decrementer_set_next_event(DECREMENTER_MAX, dev);
>  }
>  
> +void decrementer_timer_interrupt(void)
> +{
> +	struct clock_event_device *evt;
> +	evt = &per_cpu(decrementers, smp_processor_id());
> +
> +	if (evt->event_handler)
> +		evt->event_handler(evt);
> +}

So that's what happens when we receive the broadcast... it might need
some stats ... and it's using the normal "decrementer" clock source,
so I still have a problem understanding why you need another one.

> +static void decrementer_timer_broadcast(const struct cpumask *mask)
> +{
> +	arch_send_tick_broadcast(mask);
> +}

Ok, so far so good. But that's also hooked into the normal clock
source...

>  static void register_decrementer_clockevent(int cpu)
>  {
>  	struct clock_event_device *dec = &per_cpu(decrementers, cpu);
> @@ -826,6 +877,20 @@ static void register_decrementer_clockevent(int cpu)
>  	clockevents_register_device(dec);
>  }
>  
> +static void register_broadcast_clockevent(int cpu)
> +{
> +	struct clock_event_device *bc_evt = &per_cpu(bc_timer, cpu);
> +
> +	*bc_evt = broadcast_clockevent;
> +	bc_evt->cpumask = cpumask_of(cpu);
> +
> +	printk_once(KERN_DEBUG "clockevent: %s mult[%x] shift[%d] cpu[%d]\n",
> +		    bc_evt->name, bc_evt->mult, bc_evt->shift, cpu);
> +
> +	clockevents_register_device(bc_evt);
> +	bc_cpu = cpu;
> +}
> +
>  static void __init init_decrementer_clockevent(void)
>  {
>  	int cpu = smp_processor_id();
> @@ -840,6 +905,19 @@ static void __init init_decrementer_clockevent(void)
>  	register_decrementer_clockevent(cpu);
>  }
>  
> +static void __init init_broadcast_clockevent(void)
> +{
> +	int cpu = smp_processor_id();
> +
> +	clockevents_calc_mult_shift(&broadcast_clockevent, ppc_tb_freq, 4);
> +
> +	broadcast_clockevent.max_delta_ns =
> +		clockevent_delta2ns(DECREMENTER_MAX, &broadcast_clockevent);
> +	broadcast_clockevent.min_delta_ns =
> +		clockevent_delta2ns(2, &broadcast_clockevent);
> +	register_broadcast_clockevent(cpu);
> +}
> +
>  void secondary_cpu_time_init(void)
>  {
>  	/* Start the decrementer on CPUs that have manual control
> @@ -916,6 +994,7 @@ void __init time_init(void)
>  	clocksource_init();
>  
>  	init_decrementer_clockevent();
> +	init_broadcast_clockevent();
>  }
>  
> 
> diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig
> index ace2d22..e1a96eb 100644
> --- a/arch/powerpc/platforms/powernv/Kconfig
> +++ b/arch/powerpc/platforms/powernv/Kconfig
> @@ -6,6 +6,7 @@ config PPC_POWERNV
>  	select PPC_ICP_NATIVE
>  	select PPC_P7_NAP
>  	select PPC_PCI_CHOICE if EMBEDDED
> +	select GENERIC_CLOCKEVENTS_BROADCAST
>  	select EPAPR_BOOT
>  	default y
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* RE: [PATCH 1/2] powerpc/85xx: add hardware automatically enter altivec idle state
From: Wang Dongsheng-B40534 @ 2013-08-22  3:13 UTC (permalink / raw)
  To: Wood Scott-B07421, Kumar Gala
  Cc: linuxppc-dev@lists.ozlabs.org, Zhao Chenhui-B35336
In-Reply-To: <1376959116.31636.392.camel@snotra.buserror.net>

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogV29vZCBTY290dC1CMDc0
MjENCj4gU2VudDogVHVlc2RheSwgQXVndXN0IDIwLCAyMDEzIDg6MzkgQU0NCj4gVG86IFdhbmcg
RG9uZ3NoZW5nLUI0MDUzNA0KPiBDYzogV29vZCBTY290dC1CMDc0MjE7IEt1bWFyIEdhbGE7IGxp
bnV4cHBjLWRldkBsaXN0cy5vemxhYnMub3JnDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggMS8yXSBw
b3dlcnBjLzg1eHg6IGFkZCBoYXJkd2FyZSBhdXRvbWF0aWNhbGx5IGVudGVyDQo+IGFsdGl2ZWMg
aWRsZSBzdGF0ZQ0KPiANCj4gT24gU3VuLCAyMDEzLTA4LTE4IGF0IDIxOjUzIC0wNTAwLCBXYW5n
IERvbmdzaGVuZy1CNDA1MzQgd3JvdGU6DQo+ID4gVGhhbmtzIGZvciB5b3VyIGZlZWRiYWNrLg0K
PiA+DQo+ID4gPiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiA+ID4gRnJvbTogV29vZCBT
Y290dC1CMDc0MjENCj4gPiA+IFNlbnQ6IFNhdHVyZGF5LCBBdWd1c3QgMTcsIDIwMTMgMTI6NTEg
QU0NCj4gPiA+IFRvOiBLdW1hciBHYWxhDQo+ID4gPiBDYzogV2FuZyBEb25nc2hlbmctQjQwNTM0
OyBsaW51eHBwYy1kZXZAbGlzdHMub3psYWJzLm9yZw0KPiA+ID4gU3ViamVjdDogUmU6IFtQQVRD
SCAxLzJdIHBvd2VycGMvODV4eDogYWRkIGhhcmR3YXJlIGF1dG9tYXRpY2FsbHkNCj4gZW50ZXIN
Cj4gPiA+IGFsdGl2ZWMgaWRsZSBzdGF0ZQ0KPiA+ID4NCj4gPiA+IE9uIEZyaSwgMjAxMy0wOC0x
NiBhdCAwNjowMiAtMDUwMCwgS3VtYXIgR2FsYSB3cm90ZToNCj4gPiA+ID4gT24gQXVnIDE2LCAy
MDEzLCBhdCAyOjIzIEFNLCBEb25nc2hlbmcgV2FuZyB3cm90ZToNCj4gPiA+ID4NCj4gPiA+ID4g
PiBGcm9tOiBXYW5nIERvbmdzaGVuZyA8ZG9uZ3NoZW5nLndhbmdAZnJlZXNjYWxlLmNvbT4NCj4g
PiA+ID4gPg0KPiA+ID4gPiA+IEVhY2ggY29yZSdzIEFsdGlWZWMgdW5pdCBtYXkgYmUgcGxhY2Vk
IGludG8gYSBwb3dlciBzYXZpbmdzIG1vZGUNCj4gPiA+ID4gPiBieSB0dXJuaW5nIG9mZiBwb3dl
ciB0byB0aGUgdW5pdC4gQ29yZSBoYXJkd2FyZSB3aWxsDQo+IGF1dG9tYXRpY2FsbHkNCj4gPiA+
ID4gPiBwb3dlciBkb3duIHRoZSBBbHRpVmVjIHVuaXQgYWZ0ZXIgbm8gQWx0aVZlYyBpbnN0cnVj
dGlvbnMgaGF2ZQ0KPiA+ID4gPiA+IGV4ZWN1dGVkIGluIE4gY3ljbGVzLiBUaGUgQWx0aVZlYyBw
b3dlci1jb250cm9sIGlzIHRyaWdnZXJlZCBieQ0KPiA+ID4gaGFyZHdhcmUuDQo+ID4gPiA+ID4N
Cj4gPiA+ID4gPiBTaWduZWQtb2ZmLWJ5OiBXYW5nIERvbmdzaGVuZyA8ZG9uZ3NoZW5nLndhbmdA
ZnJlZXNjYWxlLmNvbT4NCj4gPiA+ID4NCj4gPiA+ID4gV2h5IHRyZWF0IHRoaXMgYXMgYSBpZGxl
IEhXIGdvdmVybm9yIHZzIGp1c3Qgc29tZSBvbmUgdGltZSBzZXR1cCBhdA0KPiA+ID4gYm9vdCBv
ZiB0aGUgdGltZSBkZWxheT8NCj4gPiA+DQo+ID4gPiBJdCBpcyBiZWluZyBkb25lIGFzIG9uZS10
aW1lIHNldHVwLCBkZXNwaXRlIHRoZSBmdW5jdGlvbiBuYW1lLg0KPiA+ID4NCj4gPiA+IE1heWJl
IGl0IHNob3VsZCBiZSBtb3ZlZCBpbnRvIF9fc2V0dXAvcmVzdG9yZV9jcHVfZTY1MDAgKEJUVywg
d2UNCj4gcmVhbGx5DQo+ID4gPiBzaG91bGQgcmVmYWN0b3IgdGhvc2UgdG8gcmVkdWNlIGR1cGxp
Y2F0aW9uKSB3aXRoIHRoZSB0aW1lYmFzZSBiaXQNCj4gPiA+IG51bWJlciBoYXJkY29kZWQgcmF0
aGVyIHRoYW4gYSB0aW1lIGluIHVzLg0KPiA+ID4NCj4gPiBUaGUgZnJlcXVlbmN5IG9mIHRoZSBk
aWZmZXJlbnQgcGxhdGZvcm1zIHRpbWViYXNlIGlzIG5vdCB0aGUgc2FtZS4NCj4gDQo+IEl0J3Mg
Y2xvc2UgZW5vdWdoLiAgUmVtZW1iZXIsIHRoaXMgbnVtYmVyIGlzIGEgdmFndWUgaW5pdGlhbCBn
dWVzcywgbm90DQo+IHNvbWV0aGluZyB0aGF0J3MgYmVlbiBjYXJlZnVsbHkgY2FsaWJyYXRlZC4g
IFRob3VnaCwgaXQgd291bGQgbWFrZSBpdA0KPiBoYXJkZXIgdG8gc3Vic3RpdHV0ZSB0aGUgbnVt
YmVyIHdpdGggb25lIHRoYXQncyBiZWVuIG1vcmUgY2FyZWZ1bGx5DQo+IGNhbGlicmF0ZWQuLi4g
IGJ1dCB3b3VsZG4ndCBkaWZmZXJlbnQgY2hpcHMgcG9zc2libHkgaGF2ZSBkaWZmZXJlbnQNCj4g
b3B0aW1hbCBkZWxheXMgYW55d2F5Pw0KPiANCj4gPiBJZiB3ZSB1c2UgaXQsIHdlIG5lZWQgdG8g
c2V0IGRpZmZlcmVudCB0aW1lYmFzZSBiaXQgb24gZWFjaCBwbGF0Zm9ybS4NCj4gPiBUaGF0IGlz
IHdoeSBJIGRpZCBub3QgcHV0IHRoZSBjb2RlIGluIF9fc2V0dXAvcmVzdG9yZV9jcHVfZTY1MDAs
IEkgbmVlZA0KPiA+IHVzZSB0Yl90aWNrc19wZXJfdXNlYyB0byBnZXQgdGltZWJhc2UgYml0LiBT
byB3ZSBvbmx5IG5lZWQgdG8gc2V0IGENCj4gdGltZQ0KPiA+IGZvciBlYWNoIHBsYXRmb3JtLCBh
bmQgbm90IHNldCBkaWZmZXJlbnQgdGltZWJhc2UgYml0Lg0KPiANCj4gSXQganVzdCBzZWVtcyB3
cm9uZyB0byBoYXZlIGFuIGFkLWhvYyBtZWNoYW5pc20gZm9yIHJ1bm5pbmcNCj4gY29yZS1zcGVj
aWZpYyBjb2RlIHdoZW4gd2UgaGF2ZSBjcHV0YWJsZS4uLiAgSWYgd2UgcmVhbGx5IG5lZWQgdGhp
cywNCj4gbWF5YmUgd2Ugc2hvdWxkIGFkZCBhICJjcHVfc2V0dXBfbGF0ZSIgZnVuY3Rpb24gcG9p
bnRlci4NCj4gDQo+IFdpdGggeW91ciBwYXRjaCwgd2hlbiBkb2VzIHRoZSBwb3dlciBtYW5hZ2Vt
ZW50IHJlZ2lzdGVyIGdldCBzZXQgd2hlbg0KPiBob3QgcGx1Z2dpbmcgYSBjcHU/DQo+IA0KVW0u
LiBJIGRvbid0IGRlYWwgd2l0aCB0aGlzIHNpdHVhdGlvbi4gSSB3aWxsIGZpeCBpdC4NCl9fc2V0
dXAvcmVzdG9yZV9jcHVfZTY1MDAgbG9va3MgZ29vZC4gQnV0IG9ubHkgYm9vdGNwdSBjYWxsIF9f
c2V0dXBfY3B1X2U2NTAwLCBub3Qgb24gZWFjaCBjcHUuDQpJIHRoaW5rIHRoaXMgaXMgYSBidWcu
DQoNCkZpeCBjb2RlOg0KDQpkaWZmIC0tZ2l0IGEvYXJjaC9wb3dlcnBjL2tlcm5lbC9oZWFkXzY0
LlMgYi9hcmNoL3Bvd2VycGMva2VybmVsL2hlYWRfNjQuUw0KaW5kZXggMmNmZWQ5ZS4uMmE5YTcx
OCAxMDA2NDQNCi0tLSBhL2FyY2gvcG93ZXJwYy9rZXJuZWwvaGVhZF82NC5TDQorKysgYi9hcmNo
L3Bvd2VycGMva2VybmVsL2hlYWRfNjQuUw0KQEAgLTYwMyw2ICs2MDMsOSBAQCBfX3NlY29uZGFy
eV9zdGFydDoNCiAgICAgICAgLyogU2V0IHRocmVhZCBwcmlvcml0eSB0byBNRURJVU0gKi8NCiAg
ICAgICAgSE1UX01FRElVTQ0KDQorI2lmZGVmIENPTkZJR19QUENfQk9PSzNFDQorICAgICAgIGJs
ICAgICAgY2FsbF9zZXR1cF9jcHUgICAgICAgICAgLyogQ2FsbCBzZXR1cF9jcHUgZm9yIHRoaXMg
Q1BVICovDQorI2VuZGlmDQogICAgICAgIC8qIEluaXRpYWxpemUgdGhlIGtlcm5lbCBzdGFjayAq
Lw0KICAgICAgICBMT0FEX1JFR19BRERSKHIzLCBjdXJyZW50X3NldCkNCiAgICAgICAgc2xkaSAg
ICByMjgscjI0LDMgICAgICAgICAgICAgICAvKiBnZXQgY3VycmVudF9zZXRbY3B1I10gICAgICAg
ICAqLw0KZGlmZiAtLWdpdCBhL2FyY2gvcG93ZXJwYy9rZXJuZWwvbWlzY182NC5TIGIvYXJjaC9w
b3dlcnBjL2tlcm5lbC9taXNjXzY0LlMNCmluZGV4IGI4NjNiODcuLjdkODRiZjQgMTAwNjQ0DQot
LS0gYS9hcmNoL3Bvd2VycGMva2VybmVsL21pc2NfNjQuUw0KKysrIGIvYXJjaC9wb3dlcnBjL2tl
cm5lbC9taXNjXzY0LlMNCkBAIC01NSw2ICs1NSwxNyBAQCBfR0xPQkFMKGNhbGxfaGFuZGxlX2ly
cSkNCiAgICAgICAgbXRsciAgICByMA0KICAgICAgICBibHINCg0KK19HTE9CQUwoY2FsbF9zZXR1
cF9jcHUpDQorICAgICAgIExPQURfUkVHX0FERFIocjQsIGN1cl9jcHVfc3BlYykNCisgICAgICAg
bGQgICAgICByNCwgMChyNCkNCisgICAgICAgbGQgICAgICByNSwgQ1BVX1NQRUNfU0VUVVAocjQp
DQorDQorICAgICAgIGNtcHdpICAgMCwgcjUsIDANCisgICAgICAgYmVxbHINCisgICAgICAgbGQg
ICAgICByNSwgMChyNSkNCisgICAgICAgbXRjdHIgICByNQ0KKyAgICAgICBiY3RyDQorDQogICAg
ICAgIC5zZWN0aW9uICAgICAgICAiLnRvYyIsImF3Ig0KIFBQQzY0X0NBQ0hFUzoNCiAgICAgICAg
LnRjICAgICAgICAgICAgIHBwYzY0X2NhY2hlc1tUQ10scHBjNjRfY2FjaGVzDQoNCj4gPiA+IEFz
IGZvciB0aGUgUFZSIGNoZWNrLCB0aGUgdXBzdHJlYW0ga2VybmVsIGRvZXNuJ3QgbmVlZCB0byBj
YXJlIGFib3V0DQo+ID4gPiByZXYxLCBzbyBrbm93aW5nIGl0J3MgYW4gZTY1MDAgaXMgZ29vZCBl
bm91Z2guDQo+ID4gPg0KPiA+IEJ1dCBBbHRpVmVjIGlkbGUgJiBQVzIwIGNhbm5vdCB3b3JrIG9u
IHJldjEgcGxhdGZvcm0uDQo+ID4gV2UgZGlkbid0IGhhdmUgdG8gZGVhbCB3aXRoIGl0Pw0KPiAN
Cj4gVXBzdHJlYW0gZG9lcyBub3QgcnVuIG9uIHJldjEuDQo+IA0KOiksIEJ1dCBhbHJlYWR5IGhh
dmUgY3VzdG9tZXJzIGluIHRoZSB1c2Ugb2YgcmV2MS4NCldoeSB3ZSBkb24ndCBuZWVkIHRvIGNh
cmUgYWJvdXQgdGhhdD8NCg==

^ permalink raw reply

* Re: [RFC V2 PATCH 2/6] powerpc: Implement broadcast timer interrupt as an IPI message
From: Benjamin Herrenschmidt @ 2013-08-22  3:10 UTC (permalink / raw)
  To: Preeti U Murthy
  Cc: fweisbec, paul.gortmaker, paulus, shangw, rjw, paulmck, arnd,
	linux-pm, rostedt, john.stultz, tglx, chenhui.zhao, deepthi,
	r58472, geoff, linux-kernel, srivatsa.bhat, schwidefsky,
	linuxppc-dev
In-Reply-To: <20130814115602.5193.60835.stgit@preeti.in.ibm.com>

On Wed, 2013-08-14 at 17:26 +0530, Preeti U Murthy wrote:
> -static irqreturn_t unused_action(int irq, void *data)
> +static irqreturn_t timer_action(int irq, void *data)
>  {
> -       /* This slot is unused and hence available for use, if needed
> */
> +       timer_interrupt();
>         return IRQ_HANDLED;
>  }
>  

That means we'll do irq_enter/irq_exit twice no ? And things like
may_hard_irq_enable() are also already done by do_IRQ so you
don't need timer_interrupt() to do it again.

We probably are better off breaking timer_interrupt in two:

void __timer_interrupt(struct pt_regs * regs)

Does the current stuff between irq_enter and irq_exit, timer_interrupt
does the remaining around it and calls __timer_interrupt.

Then from timer_action, you call __timer_interrupt()

Cheers,
Ben.

^ permalink raw reply

* [PATCH v2] powerpc: purge all the prefetched instructions for the coherent icache flush
From: Kevin Hao @ 2013-08-22  1:30 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc
In-Reply-To: <20130821114915.GC32546@pek-khao-d1.corp.ad.wrs.com>

As Benjamin Herrenschmidt has indicated, we still need a dummy icbi to
purge all the prefetched instructions from the ifetch buffers for the
snooping icache. We also need a sync before the icbi to order the
actual stores to memory that might have modified instructions with
the icbi.

Signed-off-by: Kevin Hao <haokexin@gmail.com>
---
 arch/powerpc/include/asm/cache.h | 14 +++++++++++++-
 arch/powerpc/kernel/misc_32.S    |  4 +++-
 arch/powerpc/kernel/misc_64.S    |  3 ++-
 3 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
index 9e495c9..ed0afc1 100644
--- a/arch/powerpc/include/asm/cache.h
+++ b/arch/powerpc/include/asm/cache.h
@@ -41,8 +41,20 @@ struct ppc64_caches {
 extern struct ppc64_caches ppc64_caches;
 #endif /* __powerpc64__ && ! __ASSEMBLY__ */
 
-#if !defined(__ASSEMBLY__)
+#if defined(__ASSEMBLY__)
+/*
+ * For a snooping icache, we still need a dummy icbi to purge all the
+ * prefetched instructions from the ifetch buffers. We also need a sync
+ * before the icbi to order the the actual stores to memory that might
+ * have modified instructions with the icbi.
+ */
+#define PURGE_PREFETCHED_INS	\
+	sync;			\
+	icbi	0,r3;		\
+	sync;			\
+	isync
 
+#else
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 #ifdef CONFIG_6xx
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 777d999..d1e819b 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -329,7 +329,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE)
  */
 _KPROBE(flush_icache_range)
 BEGIN_FTR_SECTION
-	isync
+	PURGE_PREFETCHED_INS
 	blr				/* for 601, do nothing */
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 	li	r5,L1_CACHE_BYTES-1
@@ -433,6 +433,7 @@ _GLOBAL(invalidate_dcache_range)
  */
 _GLOBAL(__flush_dcache_icache)
 BEGIN_FTR_SECTION
+	PURGE_PREFETCHED_INS
 	blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
@@ -474,6 +475,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x)
  */
 _GLOBAL(__flush_dcache_icache_phys)
 BEGIN_FTR_SECTION
+	PURGE_PREFETCHED_INS
 	blr					/* for 601, do nothing */
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 	mfmsr	r10
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 992a78e..f9e8770 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -69,6 +69,7 @@ PPC64_CACHES:
 
 _KPROBE(flush_icache_range)
 BEGIN_FTR_SECTION
+	PURGE_PREFETCHED_INS
 	blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 /*
@@ -208,7 +209,7 @@ _GLOBAL(flush_inval_dcache_range)
  */
 _GLOBAL(__flush_dcache_icache)
 BEGIN_FTR_SECTION
-	isync
+	PURGE_PREFETCHED_INS
 	blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 /*
-- 
1.8.3.1

^ permalink raw reply related

* Re: [RFC PATCH 1/1] powerpc/embedded6xx: Add support for Motorola/Emerson MVME5100.
From: Stephen N Chivers @ 2013-08-22  0:58 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, Stephen N Chivers, paulus, Chris Proctor
In-Reply-To: <1377040803.3370.88.camel@snotra.buserror.net>

Scott Wood <scottwood@freescale.com> wrote on 08/21/2013 09:20:03 AM:

> From: Scott Wood <scottwood@freescale.com>
> To: Stephen N Chivers <schivers@csc.com.au>
> Cc: <benh@kernel.crashing.org>, Chris Proctor <cproctor@csc.com.au>,
> <linuxppc-dev@lists.ozlabs.org>, <paulus@samba.org>
> Date: 08/21/2013 09:20 AM
> Subject: Re: [RFC PATCH 1/1] powerpc/embedded6xx: Add support for 
> Motorola/Emerson MVME5100.
> 
> On Tue, 2013-08-20 at 13:28 +1100, Stephen N Chivers wrote:
> > Scott Wood <scottwood@freescale.com> wrote on 08/09/2013 11:35:20 AM:
> > 
> > > From: Scott Wood <scottwood@freescale.com>
> > > To: Stephen N Chivers <schivers@csc.com.au>
> > > Cc: <benh@kernel.crashing.org>, <paulus@samba.org>, Chris Proctor 
> > > <cproctor@csc.com.au>, <linuxppc-dev@lists.ozlabs.org>
> > > Date: 08/09/2013 11:36 AM
> > > Subject: Re: [RFC PATCH 1/1] powerpc/embedded6xx: Add support for 
> > > Motorola/Emerson MVME5100.
> > > 
> > > simple-bus may be applicable here (in addition to a specific
> > > compatible).
> > >
> > The HAWK ASIC is a difficult beast. I still cannot get a positive
> > identification as to what it is (Motorola/Freescale part number
> > unknown, not even the part number on the chip on the board helps....).
> > The best I can come up with is that it is a tsi108 without
> > the ethenets.
> > So device_type will be tsi-bridge and compatible will be
> > tsi108-bridge.
> 
> Don't use device_type.  compatible should include "hawk" in the name
> (especially if you're not sure what's really in it), and/or the part
> number on the chip.  If you're convinced it's fully compatible with
> tsi108-bridge you can add that as a second compatible value, though
> given the uncertainty it's probably better to just teach Linux to look
> for the new compatible.
> 
> If devices on the bus can be used without any special bus setup or
> knowledge, then you can add a compatible of "simple-bus" to the end.
> 
> > > Why not just look for a chrp,iic node directly?
> > >
> > I was following the model used in other places, like chrp/setup.c.
> 
> Not all examples are good examples. :-)
> 
> > > > +       if ((np = of_find_compatible_node(NULL, "pci", 
"mpc10x-pci"))) 
> > {
> > > 
> > > Why insist on the device_type?
> > >
> > Following the model in the linkstation (kurobox) platform support. 
> 
> Drop the device_type check.
> 
> > > > +static void
> > > > +mvme5100_restart(char *cmd)
> > > > +{
> > > > +       volatile ulong          i = 10000000;
> > > > +
> > > > +
> > > > +       local_irq_disable();
> > > > +       _nmask_and_or_msr(0, MSR_IP);
> > > 
> > > Does "mtmsr(mfmsr() | MSR_IP)" not work?
> > >
> > Don't know. Is from the original code by Matt Porter.
> 
> It actually appears that there are no callers remaining that use the
> "and" portion of the functionality.  In fact there are no callers that
> use it for anything other than setting MSR_IP. :-P
> 
> > > > +       out_8((u_char *) BOARD_MODRST_REG, 0x01);
> > > > +
> > > > +       while (i-- > 0);
> > > 
> > > Do not use a loop to implement a delay.
> > >
> > Taken from the original code. But at this point the board
> > is going to reset and reboot via firmware, as /sbin/reboot
> > or /sbin/halt has been invoked.
> 
> Still, it's just a bad idea.  What's wrong with udelay()?
> 
> Or just use an infinite loop.  How much value is there really in timing
> out here?
> 
> > > > +static void __init
> > > > +mvme5100_set_bat(void)
> > > > +{
> > > > +
> > > > +
> > > > +       mb();
> > > > +       mtspr(SPRN_DBAT1U, 0xf0001ffe);
> > > > +       mtspr(SPRN_DBAT1L, 0xf000002a);
> > > > +       mb();
> > > > +       setbat(1, 0xfe000000, 0xfe000000, 0x02000000, 
> > PAGE_KERNEL_NCG);
> > > > +}
> > > 
> > > It is no longer allowed to squat on random virtual address space 
like
> > > this.  If you really need a BAT you'll have to allocate the virtual
> > > address properly.
> > >
> > Yes. I found that this was an anathema when researching the port in
> > 2010 but I couldn't find any practical solution at the time.
> > The code is called early to ensure that the hawk registers are 
available.
> > sysdev/cpm_common.c does the same thing.
> 
> > What is the correct solution?
> 
> ioremap() has special code to function early (using ioremap_bot).
> 
> If you still need to use a BAT that early, reserve the space with
> asm/fixmap.h or by adding a function to the early ioremap code to just
> reserve the space.  Or better, improve the ioremap code to be capable of
> creating a BAT (or equivalent) when requested.
>
It is really interesting. Given that the UART implementation on the
HAWK is such that legacy_serial will not set up an early console it
is very likely that the address translation set up by the bat is not
required.
I can probably replace the physical addresses used in:

        setup_indirec_pci(hose, 0, 0xfe000cf8, 0xfe000cfc, 0);

with remapped equivalents. But, with the setbat eliminated, the
line:

        pcibios_alloc_controller(dev);

silently (remember no early console, due to UART reg-shift) panics.
It is happening at the point where the newly allocated PHB
structure is being added to the "hose_list" in pci-common.c.

So, I think there is some side effect due to the call to the setbat with 
the
PAGE_KERNEL_NCG parameter that I do not yet understand.
 
> -Scott
> 
> 
> 

^ permalink raw reply

* Re: [PATCH v7 2/3] DMA: Freescale: Add new 8-channel DMA engine device tree nodes
From: Timur Tabi @ 2013-08-22  0:27 UTC (permalink / raw)
  To: Scott Wood
  Cc: devicetree, Stephen Warren, hongbo.zhang, lkml,
	vinod.koul@intel.com, djbw, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1377127873.5029.72.camel@snotra.buserror.net>

On Wed, Aug 21, 2013 at 6:31 PM, Scott Wood <scottwood@freescale.com> wrote:
>
>> > Other than "this is how the existing binding works and we're not going
>> > to break compatibility", it allows the OS more flexibility to choose
>> > whether to bind to controllers or directly to the channels.  Sometimes a
>> > channel will be labelled with a different compatible if it has a fixed
>> > purpose such as being connected to audio hardware (e.g. mpc8610_hpcd.dts
>> > where some channels are "fsl,ssi-dma-channel").
>>
>> That sounds terribly like encoding policy into DT rather than it being a
>> HW description.
>
> It is hardware description.  Those DMA channels are physically wired
> into the audio hardware.  Other DMA channels in the same system aren't.

Well, not quite.  Technically the DMA channel can be dynamically
assigned to the SSI, but there are limits.  At the time the code was
written, there was no way to reserve a DMA channel from the generic
DMA driver, and I didn't want to have to depend on that driver either.
 Using the device tree forced a specific pair of channels to be
assigned to each SSI.  The audio driver has code to program the SoC to
route whichever DMA channels are assigned, but it assumes that the
device tree has a valid assignment.

I believe the generic DMA driver can now accept DMA channel
reservations, but I don't think it works both ways.  That is, if the
audio driver loads first, I don't think there's a clean way to tell
the DMA driver which channels have already been taken by the audio
driver.

^ permalink raw reply

* Re: [PATCH v7 1/3] DMA: Freescale: revise device tree binding document
From: Scott Wood @ 2013-08-21 23:33 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, hongbo.zhang, linux-kernel, vinod.koul, djbw,
	linuxppc-dev
In-Reply-To: <52154976.2010204@wwwdotorg.org>

On Wed, 2013-08-21 at 17:12 -0600, Stephen Warren wrote:
> OK, if there's some alternative run-time way of enabling chip-specific
> quirking, it's probably fine to remove the extra compatible values.
> 
> Now, that does rather assume that this DMA IP block will only ever be
> used within SoCs that have that SVR concept, but perhaps if that's ever
> not the case, we can simply go back to requiring extra compatible values
> in those specific cases?

The only situation I can see where SVR would be absent is if we were to
integrate this device into an ARM chip, in which case I'd expect there
to be some equivalent way to find the SoC identification.  If the driver
knows what SoC version it expects, it will know the way that that SoC
advertises its version.

-Scott

^ permalink raw reply

* Re: [PATCH v7 2/3] DMA: Freescale: Add new 8-channel DMA engine device tree nodes
From: Scott Wood @ 2013-08-21 23:31 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, hongbo.zhang, linux-kernel, vinod.koul, djbw,
	linuxppc-dev
In-Reply-To: <52154A22.4090809@wwwdotorg.org>

On Wed, 2013-08-21 at 17:15 -0600, Stephen Warren wrote:
> On 08/21/2013 04:57 PM, Scott Wood wrote:
> > On Wed, 2013-08-21 at 16:40 -0600, Stephen Warren wrote:
> >> On 07/29/2013 04:49 AM, hongbo.zhang@freescale.com wrote:
> 
> >>> +- ranges            : describes the mapping between the address space of the
> >>> +                      DMA channels and the address space of the DMA controller
> >>
> >> Oh, so looking at the example, this is simply about being able to write
> >> the reg value in the child nodes more easily without having to write out
> >> the full based address of the controller in each child node.
> >>
> >> I don't think the binding document should require this;
> > 
> > It doesn't.  It just requires that there be a mapping; it doesn't have
> > to be any particular mapping.
> > 
> >> all the binding document should care about is that the child nodes have a valid reg
> >> value. Whether that reg value is <0x100100 0x80> without a ranges in the
> >> top-level DMA
> > 
> > Without a ranges property there is no translation and the registers
> > would not be memory mappable.  Linux may treat the absence of ranges as
> > an identity mapping for compatibility with some broken OF trees, but
> > it's not standard.
> 
> I would argue that missing ranges meaning 1:1 translation is now a
> standard, given that it must be true to support some DTs, it therefore
> can now be assumed?

"Some broken tree does it therefore it's fine for everyone to do it" is
awful.  We have standards documents for a reason.

Plus, not all OSes need to run on hardware with that broken firmware.
For example, the Freescale Embedded Hypervisor will not accept a missing
ranges in that way.  U-Boot does accept it, but only because the code
was copied from Linux (including the comment that says it's not supposed
to work that way).

If anything, we should remove the hack from U-Boot, and fix Linux to
only apply it in situations where it's known to be needed.

> >> Why do the channel nodes even need a compatible value? Presumably the
> >> driver for the top-level DMA node will scan these dma-channel nodes to
> >> extract the information it needs and will simply assume that all these
> >> nodes are DMA channel nodes rather than something else? I suppose this
> >> doesn't hurt, it just seems unnecessary unless you foresee other child
> >> nodes types existing in the future and hence a need to differentiate
> >> different types of nodes.
> > 
> > Other than "this is how the existing binding works and we're not going
> > to break compatibility", it allows the OS more flexibility to choose
> > whether to bind to controllers or directly to the channels.  Sometimes a
> > channel will be labelled with a different compatible if it has a fixed
> > purpose such as being connected to audio hardware (e.g. mpc8610_hpcd.dts
> > where some channels are "fsl,ssi-dma-channel").
> 
> That sounds terribly like encoding policy into DT rather than it being a
> HW description.

It is hardware description.  Those DMA channels are physically wired
into the audio hardware.  Other DMA channels in the same system aren't.

The only thing that's even slightly policy is that it assumes you aren't
going to ignore the audio device altogether, and use it as an extra
generic DMA channel.  I'm not sure that it's worthwhile to care in this
case.  If you want to be 100% policy-free then we shouldn't be
specifying a lot of the addresses we currently do, since that's actually
just how U-Boot configured things.  Sometimes simplifying assumptions
get made, when what the hardware people actually came up with is too
awkward to be worth describing directly.  In any case, this is not new,
nor is it relevant to the hardware we're currently adding support for,
and we're not going to break compatibility now.

-Scott

^ permalink raw reply

* Re: [PATCH v7 2/3] DMA: Freescale: Add new 8-channel DMA engine device tree nodes
From: Stephen Warren @ 2013-08-21 23:16 UTC (permalink / raw)
  To: Scott Wood
  Cc: devicetree, hongbo.zhang, linux-kernel, vinod.koul, djbw,
	linuxppc-dev
In-Reply-To: <1377126028.5029.52.camel@snotra.buserror.net>

On 08/21/2013 05:00 PM, Scott Wood wrote:
> On Wed, 2013-08-21 at 16:40 -0600, Stephen Warren wrote:
>> On 07/29/2013 04:49 AM, hongbo.zhang@freescale.com wrote:
>>> +        - reg               : <registers mapping for channel>
>>> +        - interrupts        : <interrupt mapping for DMA channel IRQ>
>>
>> s/interrupts/specifier/
> 
> Do you mean s/interrupt mapping/interrupt specifier/?
> 
> And probably s/registers mapping/register specifier/ as well.

Yup.

^ permalink raw reply

* Re: [PATCH v7 2/3] DMA: Freescale: Add new 8-channel DMA engine device tree nodes
From: Stephen Warren @ 2013-08-21 23:15 UTC (permalink / raw)
  To: Scott Wood
  Cc: devicetree, hongbo.zhang, linux-kernel, vinod.koul, djbw,
	linuxppc-dev
In-Reply-To: <1377125827.5029.50.camel@snotra.buserror.net>

On 08/21/2013 04:57 PM, Scott Wood wrote:
> On Wed, 2013-08-21 at 16:40 -0600, Stephen Warren wrote:
>> On 07/29/2013 04:49 AM, hongbo.zhang@freescale.com wrote:

>>> +- ranges            : describes the mapping between the address space of the
>>> +                      DMA channels and the address space of the DMA controller
>>
>> Oh, so looking at the example, this is simply about being able to write
>> the reg value in the child nodes more easily without having to write out
>> the full based address of the controller in each child node.
>>
>> I don't think the binding document should require this;
> 
> It doesn't.  It just requires that there be a mapping; it doesn't have
> to be any particular mapping.
> 
>> all the binding document should care about is that the child nodes have a valid reg
>> value. Whether that reg value is <0x100100 0x80> without a ranges in the
>> top-level DMA
> 
> Without a ranges property there is no translation and the registers
> would not be memory mappable.  Linux may treat the absence of ranges as
> an identity mapping for compatibility with some broken OF trees, but
> it's not standard.

I would argue that missing ranges meaning 1:1 translation is now a
standard, given that it must be true to support some DTs, it therefore
can now be assumed?

>> nor or whether that reg value is <0x0 0x80> with a ranges
>> value in the top-level DMA node isn't something that the binding should
>> specify. Either way will work equally without affecting a driver for the
>> DMA controller; the parsing of reg with/without a ranges property is
>> more of a core part of DT than anything to do with this binding.
>>
>>> +- DMA channel nodes:
>>> +        - compatible        : must include "fsl,eloplus-dma-channel"
>>
>> Why do the channel nodes even need a compatible value? Presumably the
>> driver for the top-level DMA node will scan these dma-channel nodes to
>> extract the information it needs and will simply assume that all these
>> nodes are DMA channel nodes rather than something else? I suppose this
>> doesn't hurt, it just seems unnecessary unless you foresee other child
>> nodes types existing in the future and hence a need to differentiate
>> different types of nodes.
> 
> Other than "this is how the existing binding works and we're not going
> to break compatibility", it allows the OS more flexibility to choose
> whether to bind to controllers or directly to the channels.  Sometimes a
> channel will be labelled with a different compatible if it has a fixed
> purpose such as being connected to audio hardware (e.g. mpc8610_hpcd.dts
> where some channels are "fsl,ssi-dma-channel").

That sounds terribly like encoding policy into DT rather than it being a
HW description.

^ permalink raw reply

* Re: [PATCH v7 1/3] DMA: Freescale: revise device tree binding document
From: Stephen Warren @ 2013-08-21 23:12 UTC (permalink / raw)
  To: Scott Wood
  Cc: devicetree, hongbo.zhang, linux-kernel, vinod.koul, djbw,
	linuxppc-dev
In-Reply-To: <1377125156.5029.40.camel@snotra.buserror.net>

On 08/21/2013 04:45 PM, Scott Wood wrote:
> On Wed, 2013-08-21 at 16:33 -0600, Stephen Warren wrote:
>> On 07/29/2013 04:49 AM, hongbo.zhang@freescale.com wrote:
>>> From: Hongbo Zhang <hongbo.zhang@freescale.com>
>>>
>>> This patch updates the discription of each type of DMA controller and its
>>> channels, it is preparation for adding another new DMA controller binding, it
>>> also fixes some defects of indent for text alignment at the same time.
>>
>>> diff --git a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
>>
>>> -- compatible        : compatible list, contains 2 entries, first is
>>> -		 "fsl,CHIP-dma", where CHIP is the processor
>>> -		 (mpc8349, mpc8360, etc.) and the second is
>>> -		 "fsl,elo-dma"
>>> +- compatible        : must include "fsl,elo-dma"
>>
>> Why remove the list of supported compatible values. Lately it seems that
>> we're moving towards listing more/all the values rather than removing
>> their documentation...
> 
> Previous versions had language that required fsl,CHIP-dma for 83xx (and
> maybe 85xx?) but not the new chip.  I asked for it to be consistent.
> The reason that 83xx still has fsl,CHIP-dma is not because of anything
> special to 83xx, but that most other chips with this device have been
> converted to dtsi and it's much more of a pain to specify the specific
> SoC in that context.  The existing language does not match actual device
> trees when it comes to 85xx.
> 
> Plus, the exact SoC name is of dubious value for integrated devices.  It
> doesn't uniquely identify the hardware because different versions of the
> SoC could have different versions of the subdevice.  As such, on our
> chips we've been moving away from including a compatible that specifies
> the exact SoC.  If it turns out we made a mistake in naming different
> versions of the device, or if there are errata, the exact SoC can still
> be determined at runtime using SVR.

OK, if there's some alternative run-time way of enabling chip-specific
quirking, it's probably fine to remove the extra compatible values.

Now, that does rather assume that this DMA IP block will only ever be
used within SoCs that have that SVR concept, but perhaps if that's ever
not the case, we can simply go back to requiring extra compatible values
in those specific cases?

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox