* [PATCH v2 05/16] ARM: b.L: Add baremetal voting mutexes
From: Nicolas Pitre @ 2013-01-24 6:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359008879-9015-1-git-send-email-nicolas.pitre@linaro.org>
From: Dave Martin <dave.martin@linaro.org>
This patch adds a simple low-level voting mutex implementation
to be used to arbitrate during first man selection when no load/store
exclusive instructions are usable.
For want of a better name, these are called "vlocks". (I was
tempted to call them ballot locks, but "block" is way too confusing
an abbreviation...)
There is no function to wait for the lock to be released, and no
vlock_lock() function since we don't need these at the moment.
These could straightforwardly be added if vlocks get used for other
purposes.
For architectural correctness even Strongly-Ordered memory accesses
require barriers in order to guarantee that multiple CPUs have a
coherent view of the ordering of memory accesses. Whether or not
this matters depends on hardware implementation details of the
memory system. Since the purpose of this code is to provide a clean,
generic locking mechanism with no platform-specific dependencies the
barriers should be present to avoid unpleasant surprises on future
platforms.
Note:
* When taking the lock, we don't care about implicit background
memory operations and other signalling which may be pending,
because those are not part of the critical section anyway.
A DMB is sufficient to ensure correctly observed ordering if
the explicit memory accesses in vlock_trylock.
* No barrier is required after checking the election result,
because the result is determined by the store to
VLOCK_OWNER_OFFSET and is already globally observed due to the
barriers in voting_end. This means that global agreement on
the winner is guaranteed, even before the winner is known
locally.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
---
Documentation/arm/big.LITTLE/vlocks.txt | 211 ++++++++++++++++++++++++++++++++
arch/arm/common/vlock.S | 108 ++++++++++++++++
arch/arm/common/vlock.h | 28 +++++
3 files changed, 347 insertions(+)
create mode 100644 Documentation/arm/big.LITTLE/vlocks.txt
create mode 100644 arch/arm/common/vlock.S
create mode 100644 arch/arm/common/vlock.h
diff --git a/Documentation/arm/big.LITTLE/vlocks.txt b/Documentation/arm/big.LITTLE/vlocks.txt
new file mode 100644
index 0000000000..415960a9ba
--- /dev/null
+++ b/Documentation/arm/big.LITTLE/vlocks.txt
@@ -0,0 +1,211 @@
+vlocks for Bare-Metal Mutual Exclusion
+======================================
+
+Voting Locks, or "vlocks" provide a simple low-level mutual exclusion
+mechanism, with reasonable but minimal requirements on the memory
+system.
+
+These are intended to be used to coordinate critical activity among CPUs
+which are otherwise non-coherent, in situations where the hardware
+provides no other mechanism to support this and ordinary spinlocks
+cannot be used.
+
+
+vlocks make use of the atomicity provided by the memory system for
+writes to a single memory location. To arbitrate, every CPU "votes for
+itself", by storing a unique number to a common memory location. The
+final value seen in that memory location when all the votes have been
+cast identifies the winner.
+
+In order to make sure that the election produces an unambiguous result
+in finite time, a CPU will only enter the election in the first place if
+no winner has been chosen and the election does not appear to have
+started yet.
+
+
+Algorithm
+---------
+
+The easiest way to explain the vlocks algorithm is with some pseudo-code:
+
+
+ int currently_voting[NR_CPUS] = { 0, };
+ int last_vote = -1; /* no votes yet */
+
+ bool vlock_trylock(int this_cpu)
+ {
+ /* signal our desire to vote */
+ currently_voting[this_cpu] = 1;
+ if (last_vote != -1) {
+ /* someone already volunteered himself */
+ currently_voting[this_cpu] = 0;
+ return false; /* not ourself */
+ }
+
+ /* let's suggest ourself */
+ last_vote = this_cpu;
+ currently_voting[this_cpu] = 0;
+
+ /* then wait until everyone else is done voting */
+ for_each_cpu(i) {
+ while (currently_voting[i] != 0)
+ /* wait */;
+ }
+
+ /* result */
+ if (last_vote == this_cpu)
+ return true; /* we won */
+ return false;
+ }
+
+ bool vlock_unlock(void)
+ {
+ last_vote = -1;
+ }
+
+
+The currently_voting[] array provides a way for the CPUs to determine
+whether an election is in progress, and plays a role analogous to the
+"entering" array in Lamport's bakery algorithm [1].
+
+However, once the election has started, the underlying memory system
+atomicity is used to pick the winner. This avoids the need for a static
+priority rule to act as a tie-breaker, or any counters which could
+overflow.
+
+As long as the last_vote variable is globally visible to all CPUs, it
+will contain only one value that won't change once every CPU has cleared
+its currently_voting flag.
+
+
+Features and limitations
+------------------------
+
+ * vlocks are not intended to be fair. In the contended case, it is the
+ _last_ CPU which attempts to get the lock which will be most likely
+ to win.
+
+ vlocks are therefore best suited to situations where it is necessary
+ to pick a unique winner, but it does not matter which CPU actually
+ wins.
+
+ * Like other similar mechanisms, vlocks will not scale well to a large
+ number of CPUs.
+
+ vlocks can be cascaded in a voting hierarchy to permit better scaling
+ if necessary, as in the following hypothetical example for 4096 CPUs:
+
+ /* first level: local election */
+ my_town = towns[(this_cpu >> 4) & 0xf];
+ I_won = vlock_trylock(my_town, this_cpu & 0xf);
+ if (I_won) {
+ /* we won the town election, let's go for the state */
+ my_state = states[(this_cpu >> 8) & 0xf];
+ I_won = vlock_lock(my_state, this_cpu & 0xf));
+ if (I_won) {
+ /* and so on */
+ I_won = vlock_lock(the_whole_country, this_cpu & 0xf];
+ if (I_won) {
+ /* ... */
+ }
+ vlock_unlock(the_whole_country);
+ }
+ vlock_unlock(my_state);
+ }
+ vlock_unlock(my_town);
+
+
+ARM implementation
+------------------
+
+The current ARM implementation [2] contains some optimisations beyond
+the basic algorithm:
+
+ * By packing the members of the currently_voting array close together,
+ we can read the whole array in one transaction (providing the number
+ of CPUs potentially contending the lock is small enough). This
+ reduces the number of round-trips required to external memory.
+
+ In the ARM implementation, this means that we can use a single load
+ and comparison:
+
+ LDR Rt, [Rn]
+ CMP Rt, #0
+
+ ...in place of code equivalent to:
+
+ LDRB Rt, [Rn]
+ CMP Rt, #0
+ LDRBEQ Rt, [Rn, #1]
+ CMPEQ Rt, #0
+ LDRBEQ Rt, [Rn, #2]
+ CMPEQ Rt, #0
+ LDRBEQ Rt, [Rn, #3]
+ CMPEQ Rt, #0
+
+ This cuts down on the fast-path latency, as well as potentially
+ reducing bus contention in contended cases.
+
+ The optimisation relies on the fact that the ARM memory system
+ guarantees coherency between overlapping memory accesses of
+ different sizes, similarly to many other architectures. Note that
+ we do not care which element of currently_voting appears in which
+ bits of Rt, so there is no need to worry about endianness in this
+ optimisation.
+
+ If there are too many CPUs to read the currently_voting array in
+ one transaction then multiple transations are still required. The
+ implementation uses a simple loop of word-sized loads for this
+ case. The number of transactions is still fewer than would be
+ required if bytes were loaded individually.
+
+
+ In principle, we could aggregate further by using LDRD or LDM, but
+ to keep the code simple this was not attempted in the initial
+ implementation.
+
+
+ * vlocks are currently only used to coordinate between CPUs which are
+ unable to enable their caches yet. This means that the
+ implementation removes many of the barriers which would be required
+ when executing the algorithm in cached memory.
+
+ packing of the currently_voting array does not work with cached
+ memory unless all CPUs contending the lock are cache-coherent, due
+ to cache writebacks from one CPU clobbering values written by other
+ CPUs. (Though if all the CPUs are cache-coherent, you should be
+ probably be using proper spinlocks instead anyway).
+
+
+ * The "no votes yet" value used for the last_vote variable is 0 (not
+ -1 as in the pseudocode). This allows statically-allocated vlocks
+ to be implicitly initialised to an unlocked state simply by putting
+ them in .bss.
+
+ An offset is added to each CPU's ID for the purpose of setting this
+ variable, so that no CPU uses the value 0 for its ID.
+
+
+Colophon
+--------
+
+Originally created and documented by Dave Martin for Linaro Limited, for
+use in ARM-based big.LITTLE platforms, with review and input gratefully
+received from Nicolas Pitre and Achin Gupta. Thanks to Nicolas for
+grabbing most of this text out of the relevant mail thread and writing
+up the pseudocode.
+
+Copyright (C) 2012-2013 Linaro Limited
+Distributed under the terms of Version 2 of the GNU General Public
+License, as defined in linux/COPYING.
+
+
+References
+----------
+
+[1] Lamport, L. "A New Solution of Dijkstra's Concurrent Programming
+ Problem", Communications of the ACM 17, 8 (August 1974), 453-455.
+
+ http://en.wikipedia.org/wiki/Lamport%27s_bakery_algorithm
+
+[2] linux/arch/arm/common/vlock.S, www.kernel.org.
diff --git a/arch/arm/common/vlock.S b/arch/arm/common/vlock.S
new file mode 100644
index 0000000000..9109825606
--- /dev/null
+++ b/arch/arm/common/vlock.S
@@ -0,0 +1,108 @@
+/*
+ * vlock.S - simple voting lock implementation for ARM
+ *
+ * Created by: Dave Martin, 2012-08-16
+ * Copyright: (C) 2012-2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * This algorithm is described in more detail in
+ * Documentation/arm/big.LITTLE/vlocks.txt.
+ */
+
+#include <linux/linkage.h>
+#include "vlock.h"
+
+/* Select different code if voting flags can fit in a single word. */
+#if VLOCK_VOTING_SIZE > 4
+#define FEW(x...)
+#define MANY(x...) x
+#else
+#define FEW(x...) x
+#define MANY(x...)
+#endif
+
+@ voting lock for first-man coordination
+
+.macro voting_begin rbase:req, rcpu:req, rscratch:req
+ mov \rscratch, #1
+ strb \rscratch, [\rbase, \rcpu]
+ dmb
+.endm
+
+.macro voting_end rbase:req, rcpu:req, rscratch:req
+ dmb
+ mov \rscratch, #0
+ strb \rscratch, [\rbase, \rcpu]
+ dsb
+ sev
+.endm
+
+/*
+ * The vlock structure must reside in Strongly-Ordered or Device memory.
+ * This implementation deliberately eliminates most of the barriers which
+ * would be required for other memory types, and assumes that independent
+ * writes to neighbouring locations within a cacheline do not interfere
+ * with one another.
+ */
+
+@ r0: lock structure base
+@ r1: CPU ID (0-based index within cluster)
+ENTRY(vlock_trylock)
+ add r1, r1, #VLOCK_VOTING_OFFSET
+
+ voting_begin r0, r1, r2
+
+ ldrb r2, [r0, #VLOCK_OWNER_OFFSET] @ check whether lock is held
+ cmp r2, #VLOCK_OWNER_NONE
+ bne trylock_fail @ fail if so
+
+ @ Control dependency implies strb not observable before previous ldrb.
+
+ strb r1, [r0, #VLOCK_OWNER_OFFSET] @ submit my vote
+
+ voting_end r0, r1, r2 @ implies DMB
+
+ @ Wait for the current round of voting to finish:
+
+ MANY( mov r3, #VLOCK_VOTING_OFFSET )
+0:
+ MANY( ldr r2, [r0, r3] )
+ FEW( ldr r2, [r0, #VLOCK_VOTING_OFFSET] )
+ cmp r2, #0
+ wfene
+ bne 0b
+ MANY( add r3, r3, #4 )
+ MANY( cmp r3, #VLOCK_VOTING_OFFSET + VLOCK_VOTING_SIZE )
+ MANY( bne 0b )
+
+ @ Check who won:
+
+ dmb
+ ldrb r2, [r0, #VLOCK_OWNER_OFFSET]
+ eor r0, r1, r2 @ zero if I won, else nonzero
+ bx lr
+
+trylock_fail:
+ voting_end r0, r1, r2
+ mov r0, #1 @ nonzero indicates that I lost
+ bx lr
+ENDPROC(vlock_trylock)
+
+@ r0: lock structure base
+ENTRY(vlock_unlock)
+ dmb
+ mov r1, #VLOCK_OWNER_NONE
+ strb r1, [r0, #VLOCK_OWNER_OFFSET]
+ dsb
+ sev
+ bx lr
+ENDPROC(vlock_unlock)
diff --git a/arch/arm/common/vlock.h b/arch/arm/common/vlock.h
new file mode 100644
index 0000000000..bd4d649af2
--- /dev/null
+++ b/arch/arm/common/vlock.h
@@ -0,0 +1,28 @@
+/*
+ * vlock.h - simple voting lock implementation
+ *
+ * Created by: Dave Martin, 2012-08-16
+ * Copyright: (C) 2012-2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __VLOCK_H
+#define __VLOCK_H
+
+#include <asm/bL_entry.h>
+
+#define VLOCK_OWNER_OFFSET 0
+#define VLOCK_VOTING_OFFSET 4
+#define VLOCK_VOTING_SIZE ((BL_MAX_CPUS_PER_CLUSTER + 3) / 4 * 4)
+#define VLOCK_SIZE (VLOCK_VOTING_OFFSET + VLOCK_VOTING_SIZE)
+#define VLOCK_OWNER_NONE 0
+
+#endif /* ! __VLOCK_H */
--
1.8.0
^ permalink raw reply related
* [PATCH v2 04/16] ARM: b.L: introduce helpers for platform coherency exit/setup
From: Nicolas Pitre @ 2013-01-24 6:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359008879-9015-1-git-send-email-nicolas.pitre@linaro.org>
From: Dave Martin <dave.martin@linaro.org>
This provides helper methods to coordinate between CPUs coming down
and CPUs going up, as well as documentation on the used algorithms,
so that cluster teardown and setup
operations are not done for a cluster simultaneously.
For use in the power_down() implementation:
* __bL_cpu_going_down(unsigned int cluster, unsigned int cpu)
* __bL_outbound_enter_critical(unsigned int cluster)
* __bL_outbound_leave_critical(unsigned int cluster)
* __bL_cpu_down(unsigned int cluster, unsigned int cpu)
The power_up_setup() helper should do platform-specific setup in
preparation for turning the CPU on, such as invalidating local caches
or entering coherency. It must be assembler for now, since it must
run before the MMU can be switched on. It is passed the affinity level
which should be initialized.
Because the bL_cluster_sync_struct content is looked-up and modified
with the cache enabled or disabled depending on the code path, it is
crucial to always ensure proper cache maintenance to update main memory
right away. Therefore, any cached write must be followed by a cache
clean operation and any cached read must be preceded by a cache
invalidate operation (actually a cache flush i.e. clean+invalidate to
avoid discarding possible concurrent writes) on the accessed memory.
Also, in order to prevent a cached writer from interfering with an
adjacent non-cached writer, we ensure each state variable is located to
a separate cache line.
Thanks to Nicolas Pitre and Achin Gupta for the help with this
patch.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
---
.../arm/big.LITTLE/cluster-pm-race-avoidance.txt | 498 +++++++++++++++++++++
arch/arm/common/bL_entry.c | 197 ++++++++
arch/arm/common/bL_head.S | 106 ++++-
arch/arm/include/asm/bL_entry.h | 63 +++
4 files changed, 862 insertions(+), 2 deletions(-)
create mode 100644 Documentation/arm/big.LITTLE/cluster-pm-race-avoidance.txt
diff --git a/Documentation/arm/big.LITTLE/cluster-pm-race-avoidance.txt b/Documentation/arm/big.LITTLE/cluster-pm-race-avoidance.txt
new file mode 100644
index 0000000000..ba6dadb0d4
--- /dev/null
+++ b/Documentation/arm/big.LITTLE/cluster-pm-race-avoidance.txt
@@ -0,0 +1,498 @@
+Big.LITTLE cluster Power-up/power-down race avoidance algorithm
+===============================================================
+
+This file documents the algorithm which is used to coordinate CPU and
+cluster setup and teardown operations and to manage hardware coherency
+controls safely.
+
+The section "Rationale" explains what the algorithm is for and why it is
+needed. "Basic model" explains general concepts using a simplified view
+of the system. The other sections explain the actual details of the
+algorithm in use.
+
+
+Rationale
+---------
+
+In a system containing multiple CPUs, it is desirable to have the
+ability to turn off individual CPUs when the system is idle, reducing
+power consumption and thermal dissipation.
+
+In a system containing multiple clusters of CPUs, it is also desirable
+to have the ability to turn off entire clusters.
+
+Turning entire clusters off and on is a risky business, because it
+involves performing potentially destructive operations affecting a group
+of independently running CPUs, while the OS continues to run. This
+means that we need some coordination in order to ensure that critical
+cluster-level operations are only performed when it is truly safe to do
+so.
+
+Simple locking may not be sufficient to solve this problem, because
+mechanisms like Linux spinlocks may rely on coherency mechanisms which
+are not immediately enabled when a cluster powers up. Since enabling or
+disabling those mechanisms may itself be a non-atomic operation (such as
+writing some hardware registers and invalidating large caches), other
+methods of coordination are required in order to guarantee safe
+power-down and power-up at the cluster level.
+
+The mechanism presented in this document describes a coherent memory
+based protocol for performing the needed coordination. It aims to be as
+lightweight as possible, while providing the required safety properties.
+
+
+Basic model
+-----------
+
+Each cluster and CPU is assigned a state, as follows:
+
+ DOWN
+ COMING_UP
+ UP
+ GOING_DOWN
+
+ +---------> UP ----------+
+ | v
+
+ COMING_UP GOING_DOWN
+
+ ^ |
+ +--------- DOWN <--------+
+
+
+DOWN: The CPU or cluster is not coherent, and is either powered off or
+ suspended, or is ready to be powered off or suspended.
+
+COMING_UP: The CPU or cluster has committed to moving to the UP state.
+ It may be part way through the process of initialisation and
+ enabling coherency.
+
+UP: The CPU or cluster is active and coherent at the hardware
+ level. A CPU in this state is not necessarily being used
+ actively by the kernel.
+
+GOING_DOWN: The CPU or cluster has committed to moving to the DOWN
+ state. It may be part way through the process of teardown and
+ coherency exit.
+
+
+Each CPU has one of these states assigned to it at any point in time.
+The CPU states are described in the "CPU state" section, below.
+
+Each cluster is also assigned a state, but it is necessary to split the
+state value into two parts (the "cluster" state and "inbound" state) and
+to introduce additional states in order to avoid races between different
+CPUs in the cluster simultaneously modifying the state. The cluster-
+level states are described in the "Cluster state" section.
+
+To help distinguish the CPU states from cluster states in this
+discussion, the state names are given a CPU_ prefix for the CPU states,
+and a CLUSTER_ or INBOUND_ prefix for the cluster states.
+
+
+CPU state
+---------
+
+In this algorithm, each individual core in a multi-core processor is
+referred to as a "CPU". CPUs are assumed to be single-threaded:
+therefore, a CPU can only be doing one thing@a single point in time.
+
+This means that CPUs fit the basic model closely.
+
+The algorithm defines the following states for each CPU in the system:
+
+ CPU_DOWN
+ CPU_COMING_UP
+ CPU_UP
+ CPU_GOING_DOWN
+
+ cluster setup and
+ CPU setup complete policy decision
+ +-----------> CPU_UP ------------+
+ | v
+
+ CPU_COMING_UP CPU_GOING_DOWN
+
+ ^ |
+ +----------- CPU_DOWN <----------+
+ policy decision CPU teardown complete
+ or hardware event
+
+
+The definitions of the four states correspond closely to the states of
+the basic model.
+
+Transitions between states occur as follows.
+
+A trigger event (spontaneous) means that the CPU can transition to the
+next state as a result of making local progress only, with no
+requirement for any external event to happen.
+
+
+CPU_DOWN:
+
+ A CPU reaches the CPU_DOWN state when it is ready for
+ power-down. On reaching this state, the CPU will typically
+ power itself down or suspend itself, via a WFI instruction or a
+ firmware call.
+
+ Next state: CPU_COMING_UP
+ Conditions: none
+
+ Trigger events:
+
+ a) an explicit hardware power-up operation, resulting
+ from a policy decision on another CPU;
+
+ b) a hardware event, such as an interrupt.
+
+
+CPU_COMING_UP:
+
+ A CPU cannot start participating in hardware coherency until the
+ cluster is set up and coherent. If the cluster is not ready,
+ then the CPU will wait in the CPU_COMING_UP state until the
+ cluster has been set up.
+
+ Next state: CPU_UP
+ Conditions: The CPU's parent cluster must be in CLUSTER_UP.
+ Trigger events: Transition of the parent cluster to CLUSTER_UP.
+
+ Refer to the "Cluster state" section for a description of the
+ CLUSTER_UP state.
+
+
+CPU_UP:
+ When a CPU reaches the CPU_UP state, it is safe for the CPU to
+ start participating in local coherency.
+
+ This is done by jumping to the kernel's CPU resume code.
+
+ Note that the definition of this state is slightly different
+ from the basic model definition: CPU_UP does not mean that the
+ CPU is coherent yet, but it does mean that it is safe to resume
+ the kernel. The kernel handles the rest of the resume
+ procedure, so the remaining steps are not visible as part of the
+ race avoidance algorithm.
+
+ The CPU remains in this state until an explicit policy decision
+ is made to shut down or suspend the CPU.
+
+ Next state: CPU_GOING_DOWN
+ Conditions: none
+ Trigger events: explicit policy decision
+
+
+CPU_GOING_DOWN:
+
+ While in this state, the CPU exits coherency, including any
+ operations required to achieve this (such as cleaning data
+ caches).
+
+ Next state: CPU_DOWN
+ Conditions: local CPU teardown complete
+ Trigger events: (spontaneous)
+
+
+Cluster state
+-------------
+
+A cluster is a group of connected CPUs with some common resources.
+Because a cluster contains multiple CPUs, it can be doing multiple
+things@the same time. This has some implications. In particular, a
+CPU can start up while another CPU is tearing the cluster down.
+
+In this discussion, the "outbound side" is the view of the cluster state
+as seen by a CPU tearing the cluster down. The "inbound side" is the
+view of the cluster state as seen by a CPU setting the CPU up.
+
+In order to enable safe coordination in such situations, it is important
+that a CPU which is setting up the cluster can advertise its state
+independently of the CPU which is tearing down the cluster. For this
+reason, the cluster state is split into two parts:
+
+ "cluster" state: The global state of the cluster; or the state
+ on the outbound side:
+
+ CLUSTER_DOWN
+ CLUSTER_UP
+ CLUSTER_GOING_DOWN
+
+ "inbound" state: The state of the cluster on the inbound side.
+
+ INBOUND_NOT_COMING_UP
+ INBOUND_COMING_UP
+
+
+ The different pairings of these states results in six possible
+ states for the cluster as a whole:
+
+ CLUSTER_UP
+ +==========> INBOUND_NOT_COMING_UP -------------+
+ # |
+ |
+ CLUSTER_UP <----+ |
+ INBOUND_COMING_UP | v
+
+ ^ CLUSTER_GOING_DOWN CLUSTER_GOING_DOWN
+ # INBOUND_COMING_UP <=== INBOUND_NOT_COMING_UP
+
+ CLUSTER_DOWN | |
+ INBOUND_COMING_UP <----+ |
+ |
+ ^ |
+ +=========== CLUSTER_DOWN <------------+
+ INBOUND_NOT_COMING_UP
+
+ Transitions -----> can only be made by the outbound CPU, and
+ only involve changes to the "cluster" state.
+
+ Transitions ===##> can only be made by the inbound CPU, and only
+ involve changes to the "inbound" state, except where there is no
+ further transition possible on the outbound side (i.e., the
+ outbound CPU has put the cluster into the CLUSTER_DOWN state).
+
+ The race avoidance algorithm does not provide a way to determine
+ which exact CPUs within the cluster play these roles. This must
+ be decided in advance by some other means. Refer to the section
+ "Last man and first man selection" for more explanation.
+
+
+ CLUSTER_DOWN/INBOUND_NOT_COMING_UP is the only state where the
+ cluster can actually be powered down.
+
+ The parallelism of the inbound and outbound CPUs is observed by
+ the existence of two different paths from CLUSTER_GOING_DOWN/
+ INBOUND_NOT_COMING_UP (corresponding to GOING_DOWN in the basic
+ model) to CLUSTER_DOWN/INBOUND_COMING_UP (corresponding to
+ COMING_UP in the basic model). The second path avoids cluster
+ teardown completely.
+
+ CLUSTER_UP/INBOUND_COMING_UP is equivalent to UP in the basic
+ model. The final transition to CLUSTER_UP/INBOUND_NOT_COMING_UP
+ is trivial and merely resets the state machine ready for the
+ next cycle.
+
+ Details of the allowable transitions follow.
+
+ The next state in each case is notated
+
+ <cluster state>/<inbound state> (<transitioner>)
+
+ where the <transitioner> is the side on which the transition
+ can occur; either the inbound or the outbound side.
+
+
+CLUSTER_DOWN/INBOUND_NOT_COMING_UP:
+
+ Next state: CLUSTER_DOWN/INBOUND_COMING_UP (inbound)
+ Conditions: none
+ Trigger events:
+
+ a) an explicit hardware power-up operation, resulting
+ from a policy decision on another CPU;
+
+ b) a hardware event, such as an interrupt.
+
+
+CLUSTER_DOWN/INBOUND_COMING_UP:
+
+ In this state, an inbound CPU sets up the cluster, including
+ enabling of hardware coherency at the cluster level and any
+ other operations (such as cache invalidation) which are required
+ in order to achieve this.
+
+ The purpose of this state is to do sufficient cluster-level
+ setup to enable other CPUs in the cluster to enter coherency
+ safely.
+
+ Next state: CLUSTER_UP/INBOUND_COMING_UP (inbound)
+ Conditions: cluster-level setup and hardware coherency complete
+ Trigger events: (spontaneous)
+
+
+CLUSTER_UP/INBOUND_COMING_UP:
+
+ Cluster-level setup is complete and hardware coherency is
+ enabled for the cluster. Other CPUs in the cluster can safely
+ enter coherency.
+
+ This is a transient state, leading immediately to
+ CLUSTER_UP/INBOUND_NOT_COMING_UP. All other CPUs on the cluster
+ should consider treat these two states as equivalent.
+
+ Next state: CLUSTER_UP/INBOUND_NOT_COMING_UP (inbound)
+ Conditions: none
+ Trigger events: (spontaneous)
+
+
+CLUSTER_UP/INBOUND_NOT_COMING_UP:
+
+ Cluster-level setup is complete and hardware coherency is
+ enabled for the cluster. Other CPUs in the cluster can safely
+ enter coherency.
+
+ The cluster will remain in this state until a policy decision is
+ made to power the cluster down.
+
+ Next state: CLUSTER_GOING_DOWN/INBOUND_NOT_COMING_UP (outbound)
+ Conditions: none
+ Trigger events: policy decision to power down the cluster
+
+
+CLUSTER_GOING_DOWN/INBOUND_NOT_COMING_UP:
+
+ An outbound CPU is tearing the cluster down. The selected CPU
+ must wait in this state until all CPUs in the cluster are in the
+ CPU_DOWN state.
+
+ When all CPUs are in the CPU_DOWN state, the cluster can be torn
+ down, for example by cleaning data caches and exiting
+ cluster-level coherency.
+
+ To avoid wasteful unnecessary teardown operations, the outbound
+ should check the inbound cluster state for asynchronous
+ transitions to INBOUND_COMING_UP. Alternatively, individual
+ CPUs can be checked for entry into CPU_COMING_UP or CPU_UP.
+
+
+ Next states:
+
+ CLUSTER_DOWN/INBOUND_NOT_COMING_UP (outbound)
+ Conditions: cluster torn down and ready to power off
+ Trigger events: (spontaneous)
+
+ CLUSTER_GOING_DOWN/INBOUND_COMING_UP (inbound)
+ Conditions: none
+ Trigger events:
+
+ a) an explicit hardware power-up operation,
+ resulting from a policy decision on another
+ CPU;
+
+ b) a hardware event, such as an interrupt.
+
+
+CLUSTER_GOING_DOWN/INBOUND_COMING_UP:
+
+ The cluster is (or was) being torn down, but another CPU has
+ come online in the meantime and is trying to set up the cluster
+ again.
+
+ If the outbound CPU observes this state, it has two choices:
+
+ a) back out of teardown, restoring the cluster to the
+ CLUSTER_UP state;
+
+ b) finish tearing the cluster down and put the cluster
+ in the CLUSTER_DOWN state; the inbound CPU will
+ set up the cluster again from there.
+
+ Choice (a) permits the removal of some latency by avoiding
+ unnecessary teardown and setup operations in situations where
+ the cluster is not really going to be powered down.
+
+
+ Next states:
+
+ CLUSTER_UP/INBOUND_COMING_UP (outbound)
+ Conditions: cluster-level setup and hardware
+ coherency complete
+ Trigger events: (spontaneous)
+
+ CLUSTER_DOWN/INBOUND_COMING_UP (outbound)
+ Conditions: cluster torn down and ready to power off
+ Trigger events: (spontaneous)
+
+
+Last man and First man selection
+--------------------------------
+
+The CPU which performs cluster tear-down operations on the outbound side
+is commonly referred to as the "last man".
+
+The CPU which performs cluster setup on the inbound side is commonly
+referred to as the "first man".
+
+The race avoidance algorithm documented above does not provide a
+mechanism to choose which CPUs should play these roles.
+
+
+Last man:
+
+When shutting down the cluster, all the CPUs involved are initially
+executing Linux and hence coherent. Therefore, ordinary spinlocks can
+be used to select a last man safely, before the CPUs become
+non-coherent.
+
+
+First man:
+
+Because CPUs may power up asynchronously in response to external wake-up
+events, a dynamic mechanism is needed to make sure that only one CPU
+attempts to play the first man role and do the cluster-level
+initialisation: any other CPUs must wait for this to complete before
+proceeding.
+
+Cluster-level initialisation may involve actions such as configuring
+coherency controls in the bus fabric.
+
+The current implementation in bL_head.S uses a separate mutual exclusion
+mechanism to do this arbitration. This mechanism is documented in
+detail in vlocks.txt.
+
+
+Features and Limitations
+------------------------
+
+Implementation:
+
+ The current ARM-based implementation is split between
+ arch/arm/common/bL_head.S (low-level inbound CPU operations) and
+ arch/arm/common/bL_entry.c (everything else):
+
+ __bL_cpu_going_down() signals the transition of a CPU to the
+ CPU_GOING_DOWN state.
+
+ __bL_cpu_down() signals the transition of a CPU to the CPU_DOWN
+ state.
+
+ A CPU transitions to CPU_COMING_UP and then to CPU_UP via the
+ low-level power-up code in bL_head.S. This could
+ involve CPU-specific setup code, but in the current
+ implementation it does not.
+
+ __bL_outbound_enter_critical() and __bL_outbound_leave_critical()
+ handle transitions from CLUSTER_UP to CLUSTER_GOING_DOWN
+ and from there to CLUSTER_DOWN or back to CLUSTER_UP (in
+ the case of an aborted cluster power-down).
+
+ These functions are more complex than the __bL_cpu_*()
+ functions due to the extra inter-CPU coordination which
+ is needed for safe transitions at the cluster level.
+
+ A cluster transitions from CLUSTER_DOWN back to CLUSTER_UP via
+ the low-level power-up code in bL_head.S. This
+ typically involves platform-specific setup code,
+ provided by the platform-specific power_up_setup
+ function registered via bL_cluster_sync_init.
+
+Deep topologies:
+
+ As currently described and implemented, the algorithm does not
+ support CPU topologies involving more than two levels (i.e.,
+ clusters of clusters are not supported). The algorithm could be
+ extended by replicating the cluster-level states for the
+ additional topological levels, and modifying the transition
+ rules for the intermediate (non-outermost) cluster levels.
+
+
+Colophon
+--------
+
+Originally created and documented by Dave Martin for Linaro Limited, in
+collaboration with Nicolas Pitre and Achin Gupta.
+
+Copyright (C) 2012-2013 Linaro Limited
+Distributed under the terms of Version 2 of the GNU General Public
+License, as defined in linux/COPYING.
diff --git a/arch/arm/common/bL_entry.c b/arch/arm/common/bL_entry.c
index 54bf0e572f..14d72b97ad 100644
--- a/arch/arm/common/bL_entry.c
+++ b/arch/arm/common/bL_entry.c
@@ -18,6 +18,7 @@
#include <asm/proc-fns.h>
#include <asm/cacheflush.h>
#include <asm/idmap.h>
+#include <asm/cputype.h>
extern volatile unsigned long bL_entry_vectors[BL_MAX_CLUSTERS][BL_MAX_CPUS_PER_CLUSTER];
@@ -115,3 +116,199 @@ int bL_cpu_powered_up(void)
platform_ops->powered_up();
return 0;
}
+
+struct bL_sync_struct bL_sync;
+
+/*
+ * There is no __cpuc_clean_dcache_area but we use it anyway for
+ * code clarity, and alias it to __cpuc_flush_dcache_area.
+ */
+#define __cpuc_clean_dcache_area __cpuc_flush_dcache_area
+
+/*
+ * Ensure preceding writes to *p by this CPU are visible to
+ * subsequent reads by other CPUs:
+ */
+static void __sync_range_w(volatile void *p, size_t size)
+{
+ char *_p = (char *)p;
+
+ __cpuc_clean_dcache_area(_p, size);
+ outer_clean_range(__pa(_p), __pa(_p + size));
+}
+
+/*
+ * Ensure preceding writes to *p by other CPUs are visible to
+ * subsequent reads by this CPU. We must be careful not to
+ * discard data simultaneously written by another CPU, hence the
+ * usage of flush rather than invalidate operations.
+ */
+static void __sync_range_r(volatile void *p, size_t size)
+{
+ char *_p = (char *)p;
+
+#ifdef CONFIG_OUTER_CACHE
+ if (outer_cache.flush_range) {
+ /*
+ * Ensure dirty data migrated from other CPUs into our cache
+ * are cleaned out safely before the outer cache is cleaned:
+ */
+ __cpuc_clean_dcache_area(_p, size);
+
+ /* Clean and invalidate stale data for *p from outer ... */
+ outer_flush_range(__pa(_p), __pa(_p + size));
+ }
+#endif
+
+ /* ... and inner cache: */
+ __cpuc_flush_dcache_area(_p, size);
+}
+
+#define sync_w(ptr) __sync_range_w(ptr, sizeof *(ptr))
+#define sync_r(ptr) __sync_range_r(ptr, sizeof *(ptr))
+
+/*
+ * __bL_cpu_going_down: Indicates that the cpu is being torn down.
+ * This must be called at the point of committing to teardown of a CPU.
+ * The CPU cache (SCTRL.C bit) is expected to still be active.
+ */
+void __bL_cpu_going_down(unsigned int cpu, unsigned int cluster)
+{
+ bL_sync.clusters[cluster].cpus[cpu].cpu = CPU_GOING_DOWN;
+ sync_w(&bL_sync.clusters[cluster].cpus[cpu].cpu);
+}
+
+/*
+ * __bL_cpu_down: Indicates that cpu teardown is complete and that the
+ * cluster can be torn down without disrupting this CPU.
+ * To avoid deadlocks, this must be called before a CPU is powered down.
+ * The CPU cache (SCTRL.C bit) is expected to be off.
+ */
+void __bL_cpu_down(unsigned int cpu, unsigned int cluster)
+{
+ dmb();
+ bL_sync.clusters[cluster].cpus[cpu].cpu = CPU_DOWN;
+ sync_w(&bL_sync.clusters[cluster].cpus[cpu].cpu);
+ dsb_sev();
+}
+
+/*
+ * __bL_outbound_leave_critical: Leave the cluster teardown critical section.
+ * @state: the final state of the cluster:
+ * CLUSTER_UP: no destructive teardown was done and the cluster has been
+ * restored to the previous state (CPU cache still active); or
+ * CLUSTER_DOWN: the cluster has been torn-down, ready for power-off
+ * (CPU cache disabled).
+ */
+void __bL_outbound_leave_critical(unsigned int cluster, int state)
+{
+ dmb();
+ bL_sync.clusters[cluster].cluster = state;
+ sync_w(&bL_sync.clusters[cluster].cluster);
+ dsb_sev();
+}
+
+/*
+ * __bL_outbound_enter_critical: Enter the cluster teardown critical section.
+ * This function should be called by the last man, after local CPU teardown
+ * is complete. CPU cache expected to be active.
+ *
+ * Returns:
+ * false: the critical section was not entered because an inbound CPU was
+ * observed, or the cluster is already being set up;
+ * true: the critical section was entered: it is now safe to tear down the
+ * cluster.
+ */
+bool __bL_outbound_enter_critical(unsigned int cpu, unsigned int cluster)
+{
+ unsigned int i;
+ struct bL_cluster_sync_struct *c = &bL_sync.clusters[cluster];
+
+ /* Warn inbound CPUs that the cluster is being torn down: */
+ c->cluster = CLUSTER_GOING_DOWN;
+ sync_w(&c->cluster);
+
+ /* Back out if the inbound cluster is already in the critical region: */
+ sync_r(&c->inbound);
+ if (c->inbound == INBOUND_COMING_UP)
+ goto abort;
+
+ /*
+ * Wait for all CPUs to get out of the GOING_DOWN state, so that local
+ * teardown is complete on each CPU before tearing down the cluster.
+ *
+ * If any CPU has been woken up again from the DOWN state, then we
+ * shouldn't be taking the cluster down at all: abort in that case.
+ */
+ sync_r(&c->cpus);
+ for (i = 0; i < BL_MAX_CPUS_PER_CLUSTER; i++) {
+ int cpustate;
+
+ if (i == cpu)
+ continue;
+
+ while (1) {
+ cpustate = c->cpus[i].cpu;
+ if (cpustate != CPU_GOING_DOWN)
+ break;
+
+ wfe();
+ sync_r(&c->cpus[i].cpu);
+ }
+
+ switch (cpustate) {
+ case CPU_DOWN:
+ continue;
+
+ default:
+ goto abort;
+ }
+ }
+
+ return true;
+
+abort:
+ __bL_outbound_leave_critical(cluster, CLUSTER_UP);
+ return false;
+}
+
+int __bL_cluster_state(unsigned int cluster)
+{
+ sync_r(&bL_sync.clusters[cluster].cluster);
+ return bL_sync.clusters[cluster].cluster;
+}
+
+extern unsigned long bL_power_up_setup_phys;
+
+int __init bL_cluster_sync_init(
+ void (*power_up_setup)(unsigned int affinity_level))
+{
+ unsigned int i, j, mpidr, this_cluster;
+
+ BUILD_BUG_ON(BL_SYNC_CLUSTER_SIZE * BL_MAX_CLUSTERS != sizeof bL_sync);
+ BUG_ON((unsigned long)&bL_sync & (__CACHE_WRITEBACK_GRANULE - 1));
+
+ /*
+ * Set initial CPU and cluster states.
+ * Only one cluster is assumed to be active at this point.
+ */
+ for (i = 0; i < BL_MAX_CLUSTERS; i++) {
+ bL_sync.clusters[i].cluster = CLUSTER_DOWN;
+ bL_sync.clusters[i].inbound = INBOUND_NOT_COMING_UP;
+ for (j = 0; j < BL_MAX_CPUS_PER_CLUSTER; j++)
+ bL_sync.clusters[i].cpus[j].cpu = CPU_DOWN;
+ }
+ mpidr = read_cpuid_mpidr();
+ this_cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+ for_each_online_cpu(i)
+ bL_sync.clusters[this_cluster].cpus[i].cpu = CPU_UP;
+ bL_sync.clusters[this_cluster].cluster = CLUSTER_UP;
+ sync_w(&bL_sync);
+
+ if (power_up_setup) {
+ bL_power_up_setup_phys = virt_to_phys(power_up_setup);
+ sync_w(&bL_power_up_setup_phys);
+ }
+
+ return 0;
+}
diff --git a/arch/arm/common/bL_head.S b/arch/arm/common/bL_head.S
index 072a13da20..a226cdf4ce 100644
--- a/arch/arm/common/bL_head.S
+++ b/arch/arm/common/bL_head.S
@@ -7,11 +7,19 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
+ *
+ *
+ * Refer to Documentation/arm/big.LITTLE/cluster-pm-race-avoidance.txt
+ * for details of the synchronisation algorithms used here.
*/
#include <linux/linkage.h>
#include <asm/bL_entry.h>
+.if BL_SYNC_CLUSTER_CPUS
+.error "cpus must be the first member of struct bL_cluster_sync_struct"
+.endif
+
.macro pr_dbg cpu, string
#if defined(CONFIG_DEBUG_LL) && defined(DEBUG)
b 1901f
@@ -52,24 +60,114 @@ ENTRY(bL_entry_point)
2: pr_dbg r4, "kernel bL_entry_point\n"
/*
- * MMU is off so we need to get to bL_entry_vectors in a
+ * MMU is off so we need to get to various variables in a
* position independent way.
*/
adr r5, 3f
- ldr r6, [r5]
+ ldmia r5, {r6, r7, r8}
add r6, r5, r6 @ r6 = bL_entry_vectors
+ ldr r7, [r5, r7] @ r7 = bL_power_up_setup_phys
+ add r8, r5, r8 @ r8 = bL_sync
+
+ mov r0, #BL_SYNC_CLUSTER_SIZE
+ mla r8, r0, r10, r8 @ r8 = bL_sync cluster base
+
+ @ Signal that this CPU is coming UP:
+ mov r0, #CPU_COMING_UP
+ mov r5, #BL_SYNC_CPU_SIZE
+ mla r5, r9, r5, r8 @ r5 = bL_sync cpu address
+ strb r0, [r5]
+
+ @ At this point, the cluster cannot unexpectedly enter the GOING_DOWN
+ @ state, because there is at least one active CPU (this CPU).
+
+ @ Note: the following is racy as another CPU might be testing
+ @ the same flag at the same moment. That'll be fixed later.
+ ldrb r0, [r8, #BL_SYNC_CLUSTER_CLUSTER]
+ cmp r0, #CLUSTER_UP @ cluster already up?
+ bne cluster_setup @ if not, set up the cluster
+
+ @ Otherwise, skip setup:
+ b cluster_setup_complete
+
+cluster_setup:
+ @ Control dependency implies strb not observable before previous ldrb.
+
+ @ Signal that the cluster is being brought up:
+ mov r0, #INBOUND_COMING_UP
+ strb r0, [r8, #BL_SYNC_CLUSTER_INBOUND]
+ dmb
+
+ @ Any CPU trying to take the cluster into CLUSTER_GOING_DOWN from this
+ @ point onwards will observe INBOUND_COMING_UP and abort.
+
+ @ Wait for any previously-pending cluster teardown operations to abort
+ @ or complete:
+cluster_teardown_wait:
+ ldrb r0, [r8, #BL_SYNC_CLUSTER_CLUSTER]
+ cmp r0, #CLUSTER_GOING_DOWN
+ bne first_man_setup
+ wfe
+ b cluster_teardown_wait
+
+first_man_setup:
+ dmb
+
+ @ If the outbound gave up before teardown started, skip cluster setup:
+
+ cmp r0, #CLUSTER_UP
+ beq cluster_setup_leave
+
+ @ power_up_setup is now responsible for setting up the cluster:
+
+ cmp r7, #0
+ mov r0, #1 @ second (cluster) affinity level
+ blxne r7 @ Call power_up_setup if defined
+ dmb
+
+ mov r0, #CLUSTER_UP
+ strb r0, [r8, #BL_SYNC_CLUSTER_CLUSTER]
+ dmb
+
+cluster_setup_leave:
+ @ Leave the cluster setup critical section:
+
+ mov r0, #INBOUND_NOT_COMING_UP
+ strb r0, [r8, #BL_SYNC_CLUSTER_INBOUND]
+ dsb
+ sev
+
+cluster_setup_complete:
+ @ If a platform-specific CPU setup hook is needed, it is
+ @ called from here.
+
+ cmp r7, #0
+ mov r0, #0 @ first (CPU) affinity level
+ blxne r7 @ Call power_up_setup if defined
+ dmb
+
+ @ Mark the CPU as up:
+
+ mov r0, #CPU_UP
+ strb r0, [r5]
+
+ @ Observability order of CPU_UP and opening of the gate does not matter.
bL_entry_gated:
ldr r5, [r6, r4, lsl #2] @ r5 = CPU entry vector
cmp r5, #0
wfeeq
beq bL_entry_gated
+ dmb
+
pr_dbg r4, "released\n"
bx r5
.align 2
3: .word bL_entry_vectors - .
+ .word bL_power_up_setup_phys - 3b
+ .word bL_sync - 3b
ENDPROC(bL_entry_point)
@@ -79,3 +177,7 @@ ENDPROC(bL_entry_point)
.type bL_entry_vectors, #object
ENTRY(bL_entry_vectors)
.space 4 * BL_MAX_CLUSTERS * BL_MAX_CPUS_PER_CLUSTER
+
+ .type bL_power_up_setup_phys, #object
+ENTRY(bL_power_up_setup_phys)
+ .space 4 @ set by bL_cluster_sync_init()
diff --git a/arch/arm/include/asm/bL_entry.h b/arch/arm/include/asm/bL_entry.h
index adf8706c76..0736575783 100644
--- a/arch/arm/include/asm/bL_entry.h
+++ b/arch/arm/include/asm/bL_entry.h
@@ -15,8 +15,37 @@
#define BL_MAX_CPUS_PER_CLUSTER 4
#define BL_MAX_CLUSTERS 2
+/* Definitions for bL_cluster_sync_struct */
+#define CPU_DOWN 0x11
+#define CPU_COMING_UP 0x12
+#define CPU_UP 0x13
+#define CPU_GOING_DOWN 0x14
+
+#define CLUSTER_DOWN 0x21
+#define CLUSTER_UP 0x22
+#define CLUSTER_GOING_DOWN 0x23
+
+#define INBOUND_NOT_COMING_UP 0x31
+#define INBOUND_COMING_UP 0x32
+
+/* This is a complete guess. */
+#define __CACHE_WRITEBACK_ORDER 6
+#define __CACHE_WRITEBACK_GRANULE (1 << __CACHE_WRITEBACK_ORDER)
+
+/* Offsets for the bL_cluster_sync_struct members, for use in asm: */
+#define BL_SYNC_CLUSTER_CPUS 0
+#define BL_SYNC_CPU_SIZE __CACHE_WRITEBACK_GRANULE
+#define BL_SYNC_CLUSTER_CLUSTER \
+ (BL_SYNC_CLUSTER_CPUS + BL_SYNC_CPU_SIZE * BL_MAX_CPUS_PER_CLUSTER)
+#define BL_SYNC_CLUSTER_INBOUND \
+ (BL_SYNC_CLUSTER_CLUSTER + __CACHE_WRITEBACK_GRANULE)
+#define BL_SYNC_CLUSTER_SIZE \
+ (BL_SYNC_CLUSTER_INBOUND + __CACHE_WRITEBACK_GRANULE)
+
#ifndef __ASSEMBLY__
+#include <linux/types.h>
+
/*
* Platform specific code should use this symbol to set up secondary
* entry location for processors to use when released from reset.
@@ -123,5 +152,39 @@ struct bL_platform_power_ops {
*/
int __init bL_platform_power_register(const struct bL_platform_power_ops *ops);
+/* Synchronisation structures for coordinating safe cluster setup/teardown: */
+
+/*
+ * When modifying this structure, make sure you update the BL_SYNC_ defines
+ * to match.
+ */
+struct bL_cluster_sync_struct {
+ /* individual CPU states */
+ struct {
+ volatile s8 cpu __aligned(__CACHE_WRITEBACK_GRANULE);
+ } cpus[BL_MAX_CPUS_PER_CLUSTER];
+
+ /* cluster state */
+ volatile s8 cluster __aligned(__CACHE_WRITEBACK_GRANULE);
+
+ /* inbound-side state */
+ volatile s8 inbound __aligned(__CACHE_WRITEBACK_GRANULE);
+};
+
+struct bL_sync_struct {
+ struct bL_cluster_sync_struct clusters[BL_MAX_CLUSTERS];
+};
+
+extern unsigned long bL_sync_phys; /* physical address of *bL_sync */
+
+void __bL_cpu_going_down(unsigned int cpu, unsigned int cluster);
+void __bL_cpu_down(unsigned int cpu, unsigned int cluster);
+void __bL_outbound_leave_critical(unsigned int cluster, int state);
+bool __bL_outbound_enter_critical(unsigned int this_cpu, unsigned int cluster);
+int __bL_cluster_state(unsigned int cluster);
+
+int __init bL_cluster_sync_init(
+ void (*power_up_setup)(unsigned int affinity_level));
+
#endif /* ! __ASSEMBLY__ */
#endif
--
1.8.0
^ permalink raw reply related
* [PATCH v2 03/16] ARM: b.L: introduce the CPU/cluster power API
From: Nicolas Pitre @ 2013-01-24 6:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359008879-9015-1-git-send-email-nicolas.pitre@linaro.org>
This is the basic API used to handle the powering up/down of individual
CPUs in a big.LITTLE system. The platform specific backend implementation
has the responsibility to also handle the cluster level power as well when
the first/last CPU in a cluster is brought up/down.
Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
arch/arm/common/bL_entry.c | 88 +++++++++++++++++++++++++++++++++++++++
arch/arm/include/asm/bL_entry.h | 92 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 180 insertions(+)
diff --git a/arch/arm/common/bL_entry.c b/arch/arm/common/bL_entry.c
index 4e1044612d..54bf0e572f 100644
--- a/arch/arm/common/bL_entry.c
+++ b/arch/arm/common/bL_entry.c
@@ -11,11 +11,13 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/irqflags.h>
#include <asm/bL_entry.h>
#include <asm/barrier.h>
#include <asm/proc-fns.h>
#include <asm/cacheflush.h>
+#include <asm/idmap.h>
extern volatile unsigned long bL_entry_vectors[BL_MAX_CLUSTERS][BL_MAX_CPUS_PER_CLUSTER];
@@ -27,3 +29,89 @@ void bL_set_entry_vector(unsigned cpu, unsigned cluster, void *ptr)
outer_clean_range(__pa(&bL_entry_vectors[cluster][cpu]),
__pa(&bL_entry_vectors[cluster][cpu + 1]));
}
+
+static const struct bL_platform_power_ops *platform_ops;
+
+int __init bL_platform_power_register(const struct bL_platform_power_ops *ops)
+{
+ if (platform_ops)
+ return -EBUSY;
+ platform_ops = ops;
+ return 0;
+}
+
+int bL_cpu_power_up(unsigned int cpu, unsigned int cluster)
+{
+ if (!platform_ops)
+ return -EUNATCH;
+ might_sleep();
+ return platform_ops->power_up(cpu, cluster);
+}
+
+typedef void (*phys_reset_t)(unsigned long);
+
+void bL_cpu_power_down(void)
+{
+ phys_reset_t phys_reset;
+
+ BUG_ON(!platform_ops);
+ BUG_ON(!irqs_disabled());
+
+ /*
+ * Do this before calling into the power_down method,
+ * as it might not always be safe to do afterwards.
+ */
+ setup_mm_for_reboot();
+
+ platform_ops->power_down();
+
+ /*
+ * It is possible for a power_up request to happen concurrently
+ * with a power_down request for the same CPU. In this case the
+ * power_down method might not be able to actually enter a
+ * powered down state with the WFI instruction if the power_up
+ * method has removed the required reset condition. The
+ * power_down method is then allowed to return. We must perform
+ * a re-entry in the kernel as if the power_up method just had
+ * deasserted reset on the CPU.
+ *
+ * To simplify race issues, the platform specific implementation
+ * must accommodate for the possibility of unordered calls to
+ * power_down and power_up with a usage count. Therefore, if a
+ * call to power_up is issued for a CPU that is not down, then
+ * the next call to power_down must not attempt a full shutdown
+ * but only do the minimum (normally disabling L1 cache and CPU
+ * coherency) and return just as if a concurrent power_up request
+ * had happened as described above.
+ */
+
+ phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+ phys_reset(virt_to_phys(bL_entry_point));
+
+ /* should never get here */
+ BUG();
+}
+
+void bL_cpu_suspend(u64 expected_residency)
+{
+ phys_reset_t phys_reset;
+
+ BUG_ON(!platform_ops);
+ BUG_ON(!irqs_disabled());
+
+ /* Very similar to bL_cpu_power_down() */
+ setup_mm_for_reboot();
+ platform_ops->suspend(expected_residency);
+ phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+ phys_reset(virt_to_phys(bL_entry_point));
+ BUG();
+}
+
+int bL_cpu_powered_up(void)
+{
+ if (!platform_ops)
+ return -EUNATCH;
+ if (platform_ops->powered_up)
+ platform_ops->powered_up();
+ return 0;
+}
diff --git a/arch/arm/include/asm/bL_entry.h b/arch/arm/include/asm/bL_entry.h
index 7525614243..adf8706c76 100644
--- a/arch/arm/include/asm/bL_entry.h
+++ b/arch/arm/include/asm/bL_entry.h
@@ -31,5 +31,97 @@ extern void bL_entry_point(void);
*/
void bL_set_entry_vector(unsigned cpu, unsigned cluster, void *ptr);
+/*
+ * CPU/cluster power operations API for higher subsystems to use.
+ */
+
+/**
+ * bL_cpu_power_up - make given CPU in given cluster runable
+ *
+ * @cpu: CPU number within given cluster
+ * @cluster: cluster number for the CPU
+ *
+ * The identified CPU is brought out of reset. If the cluster was powered
+ * down then it is brought up as well, taking care not to let the other CPUs
+ * in the cluster run, and ensuring appropriate cluster setup.
+ *
+ * Caller must ensure the appropriate entry vector is initialized with
+ * bL_set_entry_vector() prior to calling this.
+ *
+ * This must be called in a sleepable context. However, the implementation
+ * is strongly encouraged to return early and let the operation happen
+ * asynchronously, especially when significant delays are expected.
+ *
+ * If the operation cannot be performed then an error code is returned.
+ */
+int bL_cpu_power_up(unsigned int cpu, unsigned int cluster);
+
+/**
+ * bL_cpu_power_down - power the calling CPU down
+ *
+ * The calling CPU is powered down.
+ *
+ * If this CPU is found to be the "last man standing" in the cluster
+ * then the cluster is prepared for power-down too.
+ *
+ * This must be called with interrupts disabled.
+ *
+ * This does not return. Re-entry in the kernel is expected via
+ * bL_entry_point.
+ */
+void bL_cpu_power_down(void);
+
+/**
+ * bL_cpu_suspend - bring the calling CPU in a suspended state
+ *
+ * @expected_residency: duration in microseconds the CPU is expected
+ * to remain suspended, or 0 if unknown/infinity.
+ *
+ * The calling CPU is suspended. The expected residency argument is used
+ * as a hint by the platform specific backend to implement the appropriate
+ * sleep state level according to the knowledge it has on wake-up latency
+ * for the given hardware.
+ *
+ * If this CPU is found to be the "last man standing" in the cluster
+ * then the cluster may be prepared for power-down too, if the expected
+ * residency makes it worthwhile.
+ *
+ * This must be called with interrupts disabled.
+ *
+ * This does not return. Re-entry in the kernel is expected via
+ * bL_entry_point.
+ */
+void bL_cpu_suspend(u64 expected_residency);
+
+/**
+ * bL_cpu_powered_up - housekeeping workafter a CPU has been powered up
+ *
+ * This lets the platform specific backend code perform needed housekeeping
+ * work. This must be called by the newly activated CPU as soon as it is
+ * fully operational in kernel space, before it enables interrupts.
+ *
+ * If the operation cannot be performed then an error code is returned.
+ */
+int bL_cpu_powered_up(void);
+
+/*
+ * Platform specific methods used in the implementation of the above API.
+ */
+struct bL_platform_power_ops {
+ int (*power_up)(unsigned int cpu, unsigned int cluster);
+ void (*power_down)(void);
+ void (*suspend)(u64);
+ void (*powered_up)(void);
+};
+
+/**
+ * bL_platform_power_register - register platform specific power methods
+ *
+ * @ops: bL_platform_power_ops structure to register
+ *
+ * An error is returned if the registration has been done previously.
+ */
+int __init bL_platform_power_register(const struct bL_platform_power_ops *ops);
+
#endif /* ! __ASSEMBLY__ */
#endif
--
1.8.0
^ permalink raw reply related
* [PATCH v2 02/16] ARM: b.L: secondary kernel entry code
From: Nicolas Pitre @ 2013-01-24 6:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359008879-9015-1-git-send-email-nicolas.pitre@linaro.org>
CPUs in a big.LITTLE systems have special needs when entering the kernel
due to a hotplug event, or when resuming from a deep sleep mode.
This is vectorized so multiple CPUs can enter the kernel in parallel
without serialization.
Only the basic structure is introduced here. This will be extended
later.
TODO: MPIDR based indexing should eventually be made runtime adjusted.
Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
arch/arm/Kconfig | 6 +++
arch/arm/common/Makefile | 1 +
arch/arm/common/bL_entry.c | 29 +++++++++++++++
arch/arm/common/bL_head.S | 81 +++++++++++++++++++++++++++++++++++++++++
arch/arm/include/asm/bL_entry.h | 35 ++++++++++++++++++
5 files changed, 152 insertions(+)
create mode 100644 arch/arm/common/bL_entry.c
create mode 100644 arch/arm/common/bL_head.S
create mode 100644 arch/arm/include/asm/bL_entry.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 67874b82a4..3dd5591c79 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1584,6 +1584,12 @@ config HAVE_ARM_TWD
help
This options enables support for the ARM timer and watchdog unit
+config BIG_LITTLE
+ bool "big.LITTLE support"
+ depends on CPU_V7 && SMP
+ help
+ This option enables support for the big.LITTLE architecture.
+
choice
prompt "Memory split"
default VMSPLIT_3G
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index e8a4e58f1b..8025899a20 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
obj-$(CONFIG_SHARP_SCOOP) += scoop.o
obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
+obj-$(CONFIG_BIG_LITTLE) += bL_head.o bL_entry.o
diff --git a/arch/arm/common/bL_entry.c b/arch/arm/common/bL_entry.c
new file mode 100644
index 0000000000..4e1044612d
--- /dev/null
+++ b/arch/arm/common/bL_entry.c
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/common/bL_entry.c -- big.LITTLE kernel re-entry point
+ *
+ * Created by: Nicolas Pitre, March 2012
+ * Copyright: (C) 2012-2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/bL_entry.h>
+#include <asm/barrier.h>
+#include <asm/proc-fns.h>
+#include <asm/cacheflush.h>
+
+extern volatile unsigned long bL_entry_vectors[BL_MAX_CLUSTERS][BL_MAX_CPUS_PER_CLUSTER];
+
+void bL_set_entry_vector(unsigned cpu, unsigned cluster, void *ptr)
+{
+ unsigned long val = ptr ? virt_to_phys(ptr) : 0;
+ bL_entry_vectors[cluster][cpu] = val;
+ __cpuc_flush_dcache_area((void *)&bL_entry_vectors[cluster][cpu], 4);
+ outer_clean_range(__pa(&bL_entry_vectors[cluster][cpu]),
+ __pa(&bL_entry_vectors[cluster][cpu + 1]));
+}
diff --git a/arch/arm/common/bL_head.S b/arch/arm/common/bL_head.S
new file mode 100644
index 0000000000..072a13da20
--- /dev/null
+++ b/arch/arm/common/bL_head.S
@@ -0,0 +1,81 @@
+/*
+ * arch/arm/common/bL_head.S -- big.LITTLE kernel re-entry point
+ *
+ * Created by: Nicolas Pitre, March 2012
+ * Copyright: (C) 2012-2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/bL_entry.h>
+
+ .macro pr_dbg cpu, string
+#if defined(CONFIG_DEBUG_LL) && defined(DEBUG)
+ b 1901f
+1902: .ascii "CPU 0: \0CPU 1: \0CPU 2: \0CPU 3: \0"
+ .ascii "CPU 4: \0CPU 5: \0CPU 6: \0CPU 7: \0"
+1903: .asciz "\string"
+ .align
+1901: adr r0, 1902b
+ add r0, r0, \cpu, lsl #3
+ bl printascii
+ adr r0, 1903b
+ bl printascii
+#endif
+ .endm
+
+ .arm
+ .align
+
+ENTRY(bL_entry_point)
+
+ THUMB( adr r12, BSYM(1f) )
+ THUMB( bx r12 )
+ THUMB( .thumb )
+1:
+ mrc p15, 0, r0, c0, c0, 5 @ MPIDR
+ ubfx r9, r0, #0, #4 @ r9 = cpu
+ ubfx r10, r0, #8, #4 @ r10 = cluster
+ mov r3, #BL_MAX_CPUS_PER_CLUSTER
+ mla r4, r3, r10, r9 @ r4 = canonical CPU index
+ cmp r4, #(BL_MAX_CPUS_PER_CLUSTER * BL_MAX_CLUSTERS)
+ blo 2f
+
+ /* We didn't expect this CPU. Try to cheaply make it quiet. */
+1: wfi
+ wfe
+ b 1b
+
+2: pr_dbg r4, "kernel bL_entry_point\n"
+
+ /*
+ * MMU is off so we need to get to bL_entry_vectors in a
+ * position independent way.
+ */
+ adr r5, 3f
+ ldr r6, [r5]
+ add r6, r5, r6 @ r6 = bL_entry_vectors
+
+bL_entry_gated:
+ ldr r5, [r6, r4, lsl #2] @ r5 = CPU entry vector
+ cmp r5, #0
+ wfeeq
+ beq bL_entry_gated
+ pr_dbg r4, "released\n"
+ bx r5
+
+ .align 2
+
+3: .word bL_entry_vectors - .
+
+ENDPROC(bL_entry_point)
+
+ .bss
+ .align 5
+
+ .type bL_entry_vectors, #object
+ENTRY(bL_entry_vectors)
+ .space 4 * BL_MAX_CLUSTERS * BL_MAX_CPUS_PER_CLUSTER
diff --git a/arch/arm/include/asm/bL_entry.h b/arch/arm/include/asm/bL_entry.h
new file mode 100644
index 0000000000..7525614243
--- /dev/null
+++ b/arch/arm/include/asm/bL_entry.h
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/include/asm/bL_entry.h
+ *
+ * Created by: Nicolas Pitre, April 2012
+ * Copyright: (C) 2012-2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef BL_ENTRY_H
+#define BL_ENTRY_H
+
+#define BL_MAX_CPUS_PER_CLUSTER 4
+#define BL_MAX_CLUSTERS 2
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Platform specific code should use this symbol to set up secondary
+ * entry location for processors to use when released from reset.
+ */
+extern void bL_entry_point(void);
+
+/*
+ * This is used to indicate where the given CPU from given cluster should
+ * branch once it is ready to re-enter the kernel using ptr, or NULL if it
+ * should be gated. A gated CPU is held in a WFE loop until its vector
+ * becomes non NULL.
+ */
+void bL_set_entry_vector(unsigned cpu, unsigned cluster, void *ptr);
+
+#endif /* ! __ASSEMBLY__ */
+#endif
--
1.8.0
^ permalink raw reply related
* [PATCH v2 01/16] ARM: introduce common set_auxcr/get_auxcr functions
From: Nicolas Pitre @ 2013-01-24 6:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359008879-9015-1-git-send-email-nicolas.pitre@linaro.org>
From: Rob Herring <rob.herring@calxeda.com>
Move the private set_auxcr/get_auxcr functions from
drivers/cpuidle/cpuidle-calxeda.c so they can be used across platforms.
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Russell King <linux@arm.linux.org.uk>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
arch/arm/include/asm/cp15.h | 14 ++++++++++++++
drivers/cpuidle/cpuidle-calxeda.c | 14 --------------
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h
index 5ef4d8015a..ef0094abf2 100644
--- a/arch/arm/include/asm/cp15.h
+++ b/arch/arm/include/asm/cp15.h
@@ -59,6 +59,20 @@ static inline void set_cr(unsigned int val)
isb();
}
+static inline unsigned int get_auxcr(void)
+{
+ unsigned int val;
+ asm("mrc p15, 0, %0, c1, c0, 1 @ get AUXCR" : "=r" (val) : : "cc");
+ return val;
+}
+
+static inline void set_auxcr(unsigned int val)
+{
+ asm volatile("mcr p15, 0, %0, c1, c0, 1 @ set AUXCR"
+ : : "r" (val) : "cc");
+ isb();
+}
+
#ifndef CONFIG_SMP
extern void adjust_cr(unsigned long mask, unsigned long set);
#endif
diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c
index e1aab38c5a..ece83d6e04 100644
--- a/drivers/cpuidle/cpuidle-calxeda.c
+++ b/drivers/cpuidle/cpuidle-calxeda.c
@@ -37,20 +37,6 @@ extern void *scu_base_addr;
static struct cpuidle_device __percpu *calxeda_idle_cpuidle_devices;
-static inline unsigned int get_auxcr(void)
-{
- unsigned int val;
- asm("mrc p15, 0, %0, c1, c0, 1 @ get AUXCR" : "=r" (val) : : "cc");
- return val;
-}
-
-static inline void set_auxcr(unsigned int val)
-{
- asm volatile("mcr p15, 0, %0, c1, c0, 1 @ set AUXCR"
- : : "r" (val) : "cc");
- isb();
-}
-
static noinline void calxeda_idle_restore(void)
{
set_cr(get_cr() | CR_C);
--
1.8.0
^ permalink raw reply related
* [PATCH v2 00/16] low-level CPU and cluster power management
From: Nicolas Pitre @ 2013-01-24 6:27 UTC (permalink / raw)
To: linux-arm-kernel
This is version 2 of the patch series required to safely power up
and down CPUs in a cluster as can be found in b.L systems.
Please refer to http://article.gmane.org/gmane.linux.ports.arm.kernel/208625
for the initial series and particularly the cover page blurb for this work.
Thanks to those who provided review comments.
Changes from v1:
- Pulled in Rob Herring's auxcr accessor patch and converted this series
to it.
- VMajor rework of various barriers (some DSBs demoted to DMBs, etc.)
- The sync_mem() macro is now split and enhanced to properly process the
cache for writers and readers in the cluster critical region helpers.
- BL_NR_CLUSTERS and BL_CPUS_PER_CLUSTER renamed to BL_MAX_CLUSTERS
and BL_MAX_CPUS_PER_CLUSTER.
- Removed unused C definitions and prototypes for vlocks.
- Simplified the vlock memory allocation.
- The vlock code is GPL v2.
- Replaced MPIDR inline asm by read_cpuid_mpidr().
- Use of MPIDR_AFFINITY_LEVEL() to replace explicit shifts and masks.
- Dropped gic_cpu_if_down().
- Added a DSB before SEV and WFI.
- Fixed power_up_setup helper prototype.
- Nuked smp_wmb() in bL_set_entry_vector().
- Moved the CCI driver to drivers/bus/.
- Dependency on CONFIG_EXPERIMENTAL removed.
- Leftover garbage in Makefile removed.
- Added/clarified various comments in the assembly code.
- Some documentation typos fixed.
- Copyright notices updated to 2013
Still not addressed yet in this series:
- The bL_ rename (will be trivial once I settle on an alternative).
- The CCI and DCSCB device tree binding descriptions.
The new diffstat is:
.../big.LITTLE/cluster-pm-race-avoidance.txt | 498 ++++++++++++++++++
Documentation/arm/big.LITTLE/vlocks.txt | 211 ++++++++
arch/arm/Kconfig | 6 +
arch/arm/common/Makefile | 1 +
arch/arm/common/bL_entry.c | 314 +++++++++++
arch/arm/common/bL_head.S | 214 ++++++++
arch/arm/common/bL_platsmp.c | 84 +++
arch/arm/common/vlock.S | 108 ++++
arch/arm/common/vlock.h | 28 +
arch/arm/include/asm/bL_entry.h | 190 +++++++
arch/arm/include/asm/cp15.h | 14 +
arch/arm/include/asm/mach/arch.h | 3 +
arch/arm/kernel/setup.c | 5 +-
arch/arm/mach-vexpress/Kconfig | 9 +
arch/arm/mach-vexpress/Makefile | 1 +
arch/arm/mach-vexpress/core.h | 2 +
arch/arm/mach-vexpress/dcscb.c | 249 +++++++++
arch/arm/mach-vexpress/dcscb_setup.S | 80 +++
arch/arm/mach-vexpress/platsmp.c | 12 +
arch/arm/mach-vexpress/v2m.c | 2 +-
drivers/bus/Kconfig | 5 +
drivers/bus/Makefile | 2 +
drivers/bus/arm-cci.c | 124 +++++
drivers/cpuidle/cpuidle-calxeda.c | 14 -
include/linux/arm-cci.h | 30 ++
25 files changed, 2190 insertions(+), 16 deletions(-)
Nicolas
^ permalink raw reply
* [RFC PATCH 6/6] ARM: kirkwood: consolidate mv643xx_eth init for DT
From: Andrew Lunn @ 2013-01-24 6:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130124013945.GX1758@titan.lakedaemon.net>
> > +static void kirkwood_gige_dt_init(void) {
> > + int i;
> > +
> > + for (i = 0; kw_dt_gige[i].compatible != NULL; i++) {
> > + if (of_machine_is_compatible(kw_dt_gige[i].compatible)) {
> > +
> > + if (kw_dt_gige[i].phy_addr00 != MV643XX_ETH_PHY_NONE) {
> > + struct mv643xx_eth_platform_data d = {
> > + .phy_addr = kw_dt_gige[i].phy_addr00,
> > + };
> > + kirkwood_ge00_init(&d);
> > + }
> > +
> > + if (kw_dt_gige[i].phy_addr01 != MV643XX_ETH_PHY_NONE) {
> > + struct mv643xx_eth_platform_data d = {
> > + .phy_addr = kw_dt_gige[i].phy_addr01,
> > + };
> > + kirkwood_ge01_init(&d);
> > + }
> > +
> > + break;
> > + }
>
> meh, hindsight is 50/50 :-) Much more readable this way, I think:
>
> if (of_machine_is_compatible(kw_dt_gige[i].compatible)) {
> struct mv643xx_eth_platform_data d;
>
> if (kw_dt_gige[i].phy_addr00 != MV643XX_ETH_PHY_NONE) {
> d.phy_addr = kw_dt_gige[i].phy_addr00,
> kirkwood_ge00_init(&d);
> }
>
> if (kw_dt_gige[i].phy_addr01 != MV643XX_ETH_PHY_NONE) {
> d.phy_addr = kw_dt_gige[i].phy_addr01,
> kirkwood_ge01_init(&d);
> }
>
> break;
> }
>
> thx,
>
> Jason.
Hi Jason
Might it be better still to implement something like:
const struct of_device_id *of_match_machine(const struct of_device_id *matches)
{
struct device_node *root;
const struct of_device_id *match;
if (!matches)
return NULL;
root = of_find_node_by_path("/");
if (!root)
return NULL;
match = of_match_node(matches, root);
of_node_put(root);
return match;
}
and then board-dt.c becomes
match = of_match_machine(ge00_matches);
if (match)
krikwood_ge00_init(match->data)
match = of_match_machine(ge01_matches);
if (match)
krikwood_ge01_init(match->data)
Andrew
^ permalink raw reply
* [PATCH] ARM: DTS: exynos5250-arndale: Add initial board support file
From: Tushar Behera @ 2013-01-24 6:16 UTC (permalink / raw)
To: linux-arm-kernel
From: Girish K S <ks.giri@samsung.com>
Arndale is a low cost board based on the Samsung Exynos5250 SoC. This
patch adds initial device tree support for this board.
Signed-off-by: Girish K S <ks.giri@samsung.com>
Signed-off-by: Tushar Behera <tushar.behera@linaro.org>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/exynos5250-arndale.dts | 124 ++++++++++++++++++++++++++++++
2 files changed, 125 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/boot/dts/exynos5250-arndale.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 5ebb44f..60a9e52 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -44,6 +44,7 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
exynos4210-trats.dtb \
exynos4412-smdk4412.dtb \
exynos5250-smdk5250.dtb \
+ exynos5250-arndale.dtb \
exynos5250-snow.dtb \
exynos5440-ssdk5440.dtb
dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
new file mode 100644
index 0000000..7504cf3
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -0,0 +1,124 @@
+/*
+ * Samsung's Exynos5250 based Arndale board device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/dts-v1/;
+/include/ "exynos5250.dtsi"
+
+/ {
+ model = "Insignal Arndale evaluation board based on EXYNOS5250";
+ compatible = "insignal,arndale", "samsung,exynos5250";
+
+ memory {
+ reg = <0x40000000 0x80000000>;
+ };
+
+ chosen {
+ bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
+ };
+
+ i2c at 12C60000 {
+ status = "disabled";
+ };
+
+ i2c at 12C70000 {
+ status = "disabled";
+ };
+
+ i2c at 12C80000 {
+ status = "disabled";
+ };
+
+ i2c at 12C90000 {
+ status = "disabled";
+ };
+
+ i2c at 12CA0000 {
+ status = "disabled";
+ };
+
+ i2c at 12CB0000 {
+ status = "disabled";
+ };
+
+ i2c at 12CC0000 {
+ status = "disabled";
+ };
+
+ i2c at 12CD0000 {
+ status = "disabled";
+ };
+
+ i2c at 121D0000 {
+ status = "disabled";
+ };
+
+ dwmmc_0: dwmmc0 at 12200000 {
+ num-slots = <1>;
+ supports-highspeed;
+ broken-cd;
+ fifo-depth = <0x80>;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+
+ slot at 0 {
+ reg = <0>;
+ bus-width = <8>;
+ gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
+ <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
+ <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
+ <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
+ <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
+ };
+ };
+
+ dwmmc_1: dwmmc1 at 12210000 {
+ status = "disabled";
+ };
+
+ dwmmc_2: dwmmc2 at 12220000 {
+ num-slots = <1>;
+ supports-highspeed;
+ fifo-depth = <0x80>;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+
+ slot at 0 {
+ reg = <0>;
+ bus-width = <4>;
+ samsung,cd-pinmux-gpio = <&gpc3 2 2 3 3>;
+ gpios = <&gpc3 0 2 0 3>, <&gpc3 1 2 0 3>,
+ <&gpc3 3 2 3 3>, <&gpc3 4 2 3 3>,
+ <&gpc3 5 2 3 3>, <&gpc3 6 2 3 3>,
+ <&gpc4 3 3 3 3>, <&gpc4 3 3 3 3>,
+ <&gpc4 5 3 3 3>, <&gpc4 6 3 3 3>;
+ };
+ };
+
+ dwmmc_3: dwmmc3 at 12230000 {
+ status = "disabled";
+ };
+
+ spi_0: spi at 12d20000 {
+ status = "disabled";
+ };
+
+ spi_1: spi at 12d30000 {
+ status = "disabled";
+ };
+
+ spi_2: spi at 12d40000 {
+ status = "disabled";
+ };
+};
--
1.7.4.1
^ permalink raw reply related
* [PATCH] ARM: mxs: dt: Add Crystalfontz CFA-10037 device tree support
From: Shawn Guo @ 2013-01-24 6:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358872551-14490-1-git-send-email-maxime.ripard@free-electrons.com>
On Tue, Jan 22, 2013 at 05:35:51PM +0100, Maxime Ripard wrote:
> The CFA-10037 is another expansion board for the CFA-10036 module, with
> only a USB Host, a Ethernet device and a lot of gpios.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
> arch/arm/boot/dts/imx28-cfa10037.dts | 77 ++++++++++++++++++++++++++++++++++
Please add the dtb target into arch/arm/boot/dts/Makfile.
Shawn
> arch/arm/mach-mxs/mach-mxs.c | 8 ++++
> 2 files changed, 85 insertions(+)
> create mode 100644 arch/arm/boot/dts/imx28-cfa10037.dts
^ permalink raw reply
* [v3 2/2] ARM: tegra: Skip scu_enable(scu_base) if not Cortex A9
From: Santosh Shilimkar @ 2013-01-24 5:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5100C0F7.9080101@wwwdotorg.org>
Stephen,
On Thursday 24 January 2013 10:34 AM, Stephen Warren wrote:
> On 01/23/2013 01:58 AM, Santosh Shilimkar wrote:
>> On Tuesday 22 January 2013 10:34 PM, Olof Johansson wrote:
>>> On Tue, Jan 22, 2013 at 8:57 AM, Stephen Warren
>>> <swarren@wwwdotorg.org> wrote:
>>>> On 01/21/2013 11:07 PM, Santosh Shilimkar wrote:
>>>>> On Tuesday 22 January 2013 11:22 AM, Hiroshi Doyu wrote:
>>>>>> Skip scu_enable(scu_base) if CPU is not Cortex A9 with SCU.
>>>>>>
>>>>>> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
>>>>>> ---
>>>>> Looks fine. I will also update OMAP code with the new
>>>>> interface. Thanks.
>>>>
>>>> OK, so patch 1/2 at least needs to get into a stable arm-soc branch
>>>> then. Unless there are violent objections, I'll forward patch 1/2 to
>>>> arm-soc and request it be added into a branch so that Tegra and OMAP can
>>>> both merge it into their branches as a dependency. I guess patch 2/2
>>>> could also be included; I don't think it has any complex dependencies
>>>> that'd prevent that, and would help to show how patch 1/2 gets used.
>>>>
>>>> Hiroshi, is this series the only dependency you need for your Tegra114
>>>> series? So, I could merge your Tegra114 series once this series is
>>>> applied?
>>>
>>> For something like this, it might make more sense for us to just apply
>>> the patches for OMAP on top, i.e. we'll pull the short branch from
>>> you, and then we can just apply patches (with maintainer acks) on top,
>>> instead of doing a bunch of single-patch pulls.
>>
>> In case you decide to apply patches, you can use patch in the end
>> of the email for OMAP. Attached the same in case mailer damages it.
>>
>> Btw, I noticed the build error with patch 1/1. Since I wasn't using
>> the first interface in OMAP code, I just bypassed it for testing.
>> I might be missing some dependent patch which added
>> read_cpuid_part_number().
>
> Thanks for the OMAP patch. I have pushed a couple of temporary and
> non-stable branches to:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra.git
>
> Branch scu-base-rework contains just the SCU base address patches. After
> the few things listed below, I'll rename this branch and send a pull
> request to arm-soc.
>
> 1) Olof asked that Russell Ack or otherwise OK Hiroshi's latest versions
> of the following two patches since he commented on previous versions:
>
> ARM: tegra: Skip scu_enable(scu_base) if not Cortex A9
> ARM: Add API to detect SCU base address from CP15
>
> 2) Lorenzo's last comment on "ARM: tegra: Use DT /cpu node to detect
> number of CPU core" was:
>
> Please add missing punctuation, reword the commit log to make it clearer.
>
> ... so that patch needs a reworded commit log.
>
> 3) This branch needs testing on both Tegra30 and OMAP (I'm away from the
> office at the moment and can only test on Tegra20 here),
>
Tested 'scu-base-rework' branch on OMAP and it works just fine. I
noticed that the OMAP patch subject got line wrapped. Can you
please fix that before sending pull request ?
Thanks for picking up the patch.
Regards,
Santosh
^ permalink raw reply
* [GIT PULL for v3.8-rc] DaVinci media fixes for v3.8
From: Prabhakar Lad @ 2013-01-24 5:52 UTC (permalink / raw)
To: linux-arm-kernel
Hi Mauro,
Please pull the following patches which fixes display on DA850 EVM . To
avoid conflicts I have included a arm patch, which has been Acked by
its maintainer.
Fixes :
- adv7343 encoder: fix configuring the encoder.
- da850: pass data for adv7343 encoder for required configuration.
Thank you!
Prabhakar
The following changes since commit 7d1f9aeff1ee4a20b1aeb377dd0f579fe9647619:
Linux 3.8-rc4 (2013-01-17 19:25:45 -0800)
are available in the git repository at:
git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git davinci_media
Lad, Prabhakar (2):
media: adv7343: accept configuration through platform data
ARM: davinci: da850 evm: pass platform data for adv7343 encoder
arch/arm/mach-davinci/board-da850-evm.c | 13 ++++++++
drivers/media/i2c/adv7343.c | 36 ++++++++++++++++++---
include/media/adv7343.h | 52 +++++++++++++++++++++++++++++++
3 files changed, 96 insertions(+), 5 deletions(-)
^ permalink raw reply
* [RFC PATCH 3/6] ARM: kirkwood: nsa310: cleanup includes and unneeded code
From: Andrew Lunn @ 2013-01-24 5:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <28ae8033afa32ea4ea298ba63e1d5b2a1f4e18f9.1358983578.git.jason@lakedaemon.net>
On Wed, Jan 23, 2013 at 11:34:21PM +0000, Jason Cooper wrote:
> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
> ---
> arch/arm/mach-kirkwood/board-nsa310.c | 9 +--------
> 1 file changed, 1 insertion(+), 8 deletions(-)
>
> diff --git a/arch/arm/mach-kirkwood/board-nsa310.c b/arch/arm/mach-kirkwood/board-nsa310.c
> index 1bd328d..0b99533 100644
> --- a/arch/arm/mach-kirkwood/board-nsa310.c
> +++ b/arch/arm/mach-kirkwood/board-nsa310.c
> @@ -10,11 +10,8 @@
>
> #include <linux/kernel.h>
> #include <linux/init.h>
> -#include <linux/i2c.h>
> -
> -#include <asm/mach-types.h>
> -#include <asm/mach/arch.h>
> #include <mach/kirkwood.h>
> +#include <linux/of.h>
> #include "common.h"
> #include "mpp.h"
>
> @@ -40,11 +37,7 @@ static unsigned int nsa310_mpp_config[] __initdata = {
>
> void __init nsa310_init(void)
> {
> - u32 dev, rev;
> -
> kirkwood_mpp_conf(nsa310_mpp_config);
> -
> - kirkwood_pcie_id(&dev, &rev);
> }
>
> static int __init nsa310_pci_init(void)
> --
> 1.8.1.1
>
Hi Jason, Tero
This board is rather unusual for a Kirkwood. It has no Ethernet
interfaces. Is this correct?
Thanks
Andrew
^ permalink raw reply
* [PATCH 4/4] irqchip: gic: Perform the gic_secondary_init() call via CPU notifier
From: Santosh Shilimkar @ 2013-01-24 5:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358963974-5496-5-git-send-email-catalin.marinas@arm.com>
On Wednesday 23 January 2013 11:29 PM, Catalin Marinas wrote:
> All the calls to gic_secondary_init() pass 0 as the first argument.
> Since this function is called on each CPU when starting, it can be done
> in a platform-independent way via a CPU notifier registered by the GIC
> code.
>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
[..]
> ---
>
Nice to see GIC is converted as well like timers. The trick
as you mentioned about higher priority of GIC than timer
is key for correct initialization of secondary CPUs.
For OMAP changes and the series,
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
^ permalink raw reply
* [PATCH 2/4] arm: Move chained_irq_(enter|exit) to a generic file
From: Santosh Shilimkar @ 2013-01-24 5:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358963974-5496-3-git-send-email-catalin.marinas@arm.com>
On Wednesday 23 January 2013 11:29 PM, Catalin Marinas wrote:
> These functions have been introduced by commit 10a8c383 (irq: introduce
> entry and exit functions for chained handlers) in asm/mach/irq.h. This
> patch moves them to linux/irqchip/chained_irq.h so that generic irqchip
> drivers do not rely on architecture specific header files.
>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Rob Herring <rob.herring@calxeda.com>
> ---
[..]
> diff --git a/include/linux/irqchip/chained_irq.h b/include/linux/irqchip/chained_irq.h
> new file mode 100644
> index 0000000..adf4c30
> --- /dev/null
> +++ b/include/linux/irqchip/chained_irq.h
> @@ -0,0 +1,52 @@
> +/*
> + * Chained IRQ handlers support.
> + *
> + * Copyright (C) 2011 ARM Ltd.
2013 now ;)
^ permalink raw reply
* [PATCH] ARM:plat-s3c24xx: for memcpy, reading more things out of boundary
From: Chen Gang @ 2013-01-24 5:27 UTC (permalink / raw)
To: linux-arm-kernel
the size is made by "plls_no + 1".
so when copy from original buffer, need dec 1, or reading out of boundary.
additional info:
plls_no is ARRARY_SIZE(plls).
Signed-off-by: Chen Gang <gang.chen@asianux.com>
---
arch/arm/plat-s3c24xx/cpu-freq.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/plat-s3c24xx/cpu-freq.c b/arch/arm/plat-s3c24xx/cpu-freq.c
index 4680799..df093b2 100644
--- a/arch/arm/plat-s3c24xx/cpu-freq.c
+++ b/arch/arm/plat-s3c24xx/cpu-freq.c
@@ -700,7 +700,8 @@ int __init s3c_plltab_register(struct cpufreq_frequency_table *plls,
vals = kmalloc(size, GFP_KERNEL);
if (vals) {
- memcpy(vals, plls, size);
+ memcpy(vals, plls,
+ size - sizeof(struct cpufreq_frequency_table));
pll_reg = vals;
/* write a terminating entry, we don't store it in the
--
1.7.10.4
^ permalink raw reply related
* [PATCH v5 00/14] DMA Engine support for AM33XX
From: Sekhar Nori @ 2013-01-24 5:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130123213736.GC5256@beef>
Matt,
On 1/24/2013 3:07 AM, Matt Porter wrote:
> On Wed, Jan 23, 2013 at 10:21:42AM +0800, Mark Brown wrote:
>> On Tue, Jan 22, 2013 at 09:26:34PM +0530, Sekhar Nori wrote:
>>> On 1/16/2013 2:02 AM, Matt Porter wrote:
>>
>>>> This series adds DMA Engine support for AM33xx, which uses
>>>> an EDMA DMAC. The EDMA DMAC has been previously supported by only
>>>> a private API implementation (much like the situation with OMAP
>>>> DMA) found on the DaVinci family of SoCs.
>>
>>> Will you take this series through the OMAP tree? Only 1/14 touches
>>> mach-davinci and I am mostly okay with it except some changes I just
>>> requested Matt to make in another thread.
>>
>> Is this series somewhere near actually getting merged then? It seemed
>> like there was lots of stuff going on.
>
> The issues raised by Sekhar and Santosh were reasonably minor and will
> be addressed. My major concern is that the dependency on some api to
> fetch dmaengine driver SG limitations is not resolved. That's being
> discussed in https://lkml.org/lkml/2013/1/10/432
It might be worth posting the patches which don't have dependencies and
are ready for acceptance as a separate series. That way at least some of
these patches have a good chance of getting into v3.9 if not the entire
series.
Thanks,
Sekhar
^ permalink raw reply
* [PATCH v5 00/14] DMA Engine support for AM33XX
From: Santosh Shilimkar @ 2013-01-24 5:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130123204917.GA5256@beef>
On Thursday 24 January 2013 02:19 AM, Matt Porter wrote:
> On Wed, Jan 23, 2013 at 04:37:55PM +0530, Santosh Shilimkar wrote:
>> Matt,
>>
>> On Wednesday 16 January 2013 02:02 AM, Matt Porter wrote:
>>
>> [..]
>>
>>> This series adds DMA Engine support for AM33xx, which uses
>>> an EDMA DMAC. The EDMA DMAC has been previously supported by only
>>> a private API implementation (much like the situation with OMAP
>>> DMA) found on the DaVinci family of SoCs.
>>>
>>> The series applies on top of 3.8-rc3 and the following patches:
>>>
>>> - TPS65910 REGMAP_IRQ build fix:
>>> https://patchwork.kernel.org/patch/1857701/
>>> - dmaengine DT support from Vinod's dmaengine_dt branch in
>>> git://git.infradead.org/users/vkoul/slave-dma.git since
>>> 027478851791df751176398be02a3b1c5f6aa824
>>> - edma dmaengine driver fix:
>>> https://patchwork.kernel.org/patch/1961521/
>>> - dmaengine dma_get_channel_caps v2:
>>> https://patchwork.kernel.org/patch/1961601/
>>> - dmaengine edma driver channel caps support v2:
>>> https://patchwork.kernel.org/patch/1961591/
>>>
>>> The approach taken is similar to how OMAP DMA is being converted to
>>> DMA Engine support. With the functional EDMA private API already
>>> existing in mach-davinci/dma.c, we first move that to an ARM common
>>> area so it can be shared. Adding DT and runtime PM support to the
>>> private EDMA API implementation allows it to run on AM33xx. AM33xx
>>> *only* boots using DT so we leverage Jon's generic DT DMA helpers to
>>> register EDMA DMAC with the of_dma framework and then add support
>>> for calling the dma_request_slave_channel() API to both the mmc
>>> and spi drivers.
>>>
>>> With this series both BeagleBone and the AM335x EVM have working
>>> MMC and SPI support.
>>>
>>> This is tested on BeagleBone with a SPI framebuffer driver and MMC
>>> rootfs. A trivial gpio DMA event misc driver was used to test the
>>> crossbar DMA event support. It is also tested on the AM335x EVM
>>> with the onboard SPI flash and MMC rootfs. The branch at
>>> https://github.com/ohporter/linux/tree/edma-dmaengine-am33xx-v4
>>> has the complete series, dependencies, and some test
>>> drivers/defconfigs.
>>>
>>> Regression testing was done on AM180x-EVM (which also makes use
>>> of the EDMA dmaengine driver and the EDMA private API) using SD,
>>> SPI flash, and the onboard audio supported by the ASoC Davinci
>>> driver. Regression testing was also done on a BeagleBoard xM
>>> booting from the legacy board file using MMC rootfs.
>>>
>>> Matt Porter (14):
>>> ARM: davinci: move private EDMA API to arm/common
>>> ARM: edma: remove unused transfer controller handlers
>>> ARM: edma: add AM33XX support to the private EDMA API
>>> dmaengine: edma: enable build for AM33XX
>>> dmaengine: edma: Add TI EDMA device tree binding
>>> ARM: dts: add AM33XX EDMA support
>>> dmaengine: add dma_request_slave_channel_compat()
>>> mmc: omap_hsmmc: convert to dma_request_slave_channel_compat()
>>> mmc: omap_hsmmc: set max_segs based on dma engine limitations
>>> mmc: omap_hsmmc: add generic DMA request support to the DT binding
>>> ARM: dts: add AM33XX MMC support
>>> spi: omap2-mcspi: convert to dma_request_slave_channel_compat()
>>> spi: omap2-mcspi: add generic DMA request support to the DT binding
>>> ARM: dts: add AM33XX SPI DMA support
>>>
>> While going through the series and testing it out, I observed an issue
>> with MMC driver. You need patch in the end of the email to avoid the
>> issue. Same is attached in case mailer damages it. Can you please
>> add it with your series if you agree ?
>
> Yes, by inspection this makes sense. As you noticed, we've been relying
> on the fact that DMA resources still don't come from DT, we only use our
> DT data in conjunction with the DMA OF helpers to do channel filtering.
> I was figuring we would address that separately later, but I see how
> even omap4 has this issue with DMA resources named with "tx1", for
> example. A good followup once this series is taken will be to only
> use hwmod resources on a !populated-dt platform like we do for other
> resources now. Baby steps. :)
>
We are already on it :-)
> Thanks for the catch, I'll add this in with your tested line as well for
> the series.
>
Thanks.
Regards,
Santosh
^ permalink raw reply
* [v3 2/2] ARM: tegra: Skip scu_enable(scu_base) if not Cortex A9
From: Stephen Warren @ 2013-01-24 5:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50FFA620.50008@ti.com>
On 01/23/2013 01:58 AM, Santosh Shilimkar wrote:
> On Tuesday 22 January 2013 10:34 PM, Olof Johansson wrote:
>> On Tue, Jan 22, 2013 at 8:57 AM, Stephen Warren
>> <swarren@wwwdotorg.org> wrote:
>>> On 01/21/2013 11:07 PM, Santosh Shilimkar wrote:
>>>> On Tuesday 22 January 2013 11:22 AM, Hiroshi Doyu wrote:
>>>>> Skip scu_enable(scu_base) if CPU is not Cortex A9 with SCU.
>>>>>
>>>>> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
>>>>> ---
>>>> Looks fine. I will also update OMAP code with the new
>>>> interface. Thanks.
>>>
>>> OK, so patch 1/2 at least needs to get into a stable arm-soc branch
>>> then. Unless there are violent objections, I'll forward patch 1/2 to
>>> arm-soc and request it be added into a branch so that Tegra and OMAP can
>>> both merge it into their branches as a dependency. I guess patch 2/2
>>> could also be included; I don't think it has any complex dependencies
>>> that'd prevent that, and would help to show how patch 1/2 gets used.
>>>
>>> Hiroshi, is this series the only dependency you need for your Tegra114
>>> series? So, I could merge your Tegra114 series once this series is
>>> applied?
>>
>> For something like this, it might make more sense for us to just apply
>> the patches for OMAP on top, i.e. we'll pull the short branch from
>> you, and then we can just apply patches (with maintainer acks) on top,
>> instead of doing a bunch of single-patch pulls.
>
> In case you decide to apply patches, you can use patch in the end
> of the email for OMAP. Attached the same in case mailer damages it.
>
> Btw, I noticed the build error with patch 1/1. Since I wasn't using
> the first interface in OMAP code, I just bypassed it for testing.
> I might be missing some dependent patch which added
> read_cpuid_part_number().
Thanks for the OMAP patch. I have pushed a couple of temporary and
non-stable branches to:
git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra.git
Branch scu-base-rework contains just the SCU base address patches. After
the few things listed below, I'll rename this branch and send a pull
request to arm-soc.
1) Olof asked that Russell Ack or otherwise OK Hiroshi's latest versions
of the following two patches since he commented on previous versions:
ARM: tegra: Skip scu_enable(scu_base) if not Cortex A9
ARM: Add API to detect SCU base address from CP15
2) Lorenzo's last comment on "ARM: tegra: Use DT /cpu node to detect
number of CPU core" was:
Please add missing punctuation, reword the commit log to make it clearer.
... so that patch needs a reworded commit log.
3) This branch needs testing on both Tegra30 and OMAP (I'm away from the
office at the moment and can only test on Tegra20 here),
Branch test-test-hdoyu-t114 contains the most recent version of the
Tegra114 series from Hiroshi, mainly for my local testing etc. Hiroshi
said he will repost an updated version based on the latest Tegra common
clock framework changes. For the record, what I plan to do when applying
this is:
1) Merge the renamed tmp/scu-base-rework into Tegra's for-3.9/soc.
2) Apply the new posting of the Tegra114 patch series.
^ permalink raw reply
* [GIT PULL] ARM: arm-soc fixes for 3.8-rc
From: Olof Johansson @ 2013-01-24 5:04 UTC (permalink / raw)
To: linux-arm-kernel
Hi Linus,
The following changes since commit 7d1f9aeff1ee4a20b1aeb377dd0f579fe9647619:
Linux 3.8-rc4 (2013-01-17 19:25:45 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git tags/fixes-for-linus
for you to fetch changes up to 4ad3041d3b76632c02b50aa384a8f21d7d15bac0:
Merge tag 'imx-fixes-3.8-3' of git://git.linaro.org/people/shawnguo/linux-2.6 into fixes (2013-01-23 20:35:02 -0800)
----------------------------------------------------------------
ARM: arm-soc fixes for 3.8
Here's a long-pending fixes pull request for arm-soc (I didn't send one
in the -rc4 cycle).
The largest delta is for a fixup of error paths in the mvsdio
driver. There's also a header file move for a driver that hadn't been
properly converted to multiplatform on i.MX, which was causing build
failures when included.
The rest are the normal mix of small fixes all over the place; sunxi,
omap, imx, mvebu, etc, etc.
----------------------------------------------------------------
Alim Akhtar (1):
ARM: dts: correct the dw-mshc timing properties as per binding
Andrew Lunn (1):
mmc: mvsdio: use devm_ API to simplify/correct error paths.
Cong Ding (1):
clk: mvebu/clk-cpu.c: fix memory leakage
Dimitris Papastamos (1):
ARM: S3C64XX: Fix up IRQ mapping for balblair on Cragganmore
Fabio Estevam (1):
video: imxfb: Do not crash on reboot
Gregory CLEMENT (1):
arm: mvebu: Fix memory size for Armada 370 DB
Gwenhael Goavec-Merou (2):
ARM: imx: platform-imx-fb: modifies platform device name
video: imxfb: fix imxfb_info configuration order
Jon Hunter (1):
ARM: OMAP2: Fix missing omap2xxx_clkt_vps_late_init function calls
Linus Walleij (1):
ARM: integrator: move syscon remap for AP PCIv3
Luciano Coelho (1):
ARM: OMAP2+: omap4-panda: add UART2 muxing for WiLink shared transport
Maxime Ripard (1):
ARM: sunxi: Use the Synosys APB UART instead of ns8250
Olof Johansson (8):
Merge tag 'mvebu_fixes_for_v3.8-rc3' of git://git.infradead.org/users/jcooper/linux into fixes
Merge tag 'imx-fixes-3.8-2' of git://git.linaro.org/people/shawnguo/linux-2.6 into fixes
Merge tag 'sunxi-fixes-for-3.8-rc4' of git://github.com/mripard/linux into fixes
Merge branch 'v3.8-samsung-fixes-3' of git://git.kernel.org/.../kgene/linux-samsung into fixes
Merge tag 'imx-fixes-rc' of git://git.pengutronix.de/git/imx/linux-2.6 into fixes
Merge tag 'omap-for-v3.8-rc4/fixes-signed' of git://git.kernel.org/.../tmlind/linux-omap into fixes
Merge tag 'mvebu_fixes_for_v3.8-rc5' of git://git.infradead.org/users/jcooper/linux into fixes
Merge tag 'imx-fixes-3.8-3' of git://git.linaro.org/people/shawnguo/linux-2.6 into fixes
Pantelis Antoniou (1):
ARM: OMAP2+: DT node Timer iteration fix
Peter Ujfalusi (2):
ARM: OMAP4: clock data: Lock ABE DPLL on all revisions
ARM: OMAP4: hwmod_data: Correct IDLEMODE for McPDM
Rob Clark (1):
ARM: OMAP2+: fix build break for omapdrm
Sascha Hauer (1):
[media] coda: Fix build due to iram.h rename
Sebastian Hesselbarth (2):
ARM: Dove: add Cubox sdhci card detect gpio
ARM: kirkwood: fix missing #interrupt-cells property
Shawn Guo (3):
ARM: imx: fix build error with !CONFIG_SMP
ARM: imx: disable cpu in .cpu_kill hook
ARM: imx: correct low-power mode setting
Simon Guinot (1):
ARM: Kirkwood: fix ns2 gpios by converting to pinctrl
Thomas Petazzoni (1):
arm: mvebu: use global interrupts for GPIOs on Armada XP
Tomasz Figa (1):
ARM: S3C64XX: Fix build error with CONFIG_S3C_DEV_FB disabled
Tony Lindgren (3):
arm: mvebu: Fix compile for multiplatform when ARMv6 is selected
Merge tag 'omap-fixes-b-for-v3.8-rc' of git://git.kernel.org/.../pjw/omap-pending into omap-for-v3.8-rc4/fixes
ARM: OMAP2+: Fix section warning for omap_init_ocp2scp()
Uwe Kleine-K?nig (1):
ARM: compile fix for DEBUG_LL=y && MMU=n
arch/arm/boot/dts/armada-370-db.dts | 2 +-
arch/arm/boot/dts/armada-xp-mv78230.dtsi | 14 ++--
arch/arm/boot/dts/armada-xp-mv78260.dtsi | 21 +++--
arch/arm/boot/dts/armada-xp-mv78460.dtsi | 21 +++--
arch/arm/boot/dts/cros5250-common.dtsi | 12 +--
arch/arm/boot/dts/dove-cubox.dts | 14 +++-
arch/arm/boot/dts/exynos5250-smdk5250.dts | 8 +-
arch/arm/boot/dts/kirkwood-ns2-common.dtsi | 16 ++++
arch/arm/boot/dts/kirkwood.dtsi | 2 +
arch/arm/boot/dts/sunxi.dtsi | 6 +-
arch/arm/kernel/debug.S | 2 +
arch/arm/mach-imx/Kconfig | 1 +
arch/arm/mach-imx/clk-imx6q.c | 3 +
arch/arm/mach-imx/common.h | 1 +
arch/arm/mach-imx/devices/platform-imx-fb.c | 2 +-
arch/arm/mach-imx/hotplug.c | 10 ++-
arch/arm/mach-imx/iram_alloc.c | 3 +-
arch/arm/mach-imx/platsmp.c | 1 +
arch/arm/mach-imx/pm-imx6q.c | 1 +
arch/arm/mach-integrator/pci_v3.c | 14 +++-
arch/arm/mach-kirkwood/board-ns2.c | 38 ---------
arch/arm/mach-mvebu/Makefile | 2 +
arch/arm/mach-omap2/board-omap4panda.c | 6 ++
arch/arm/mach-omap2/cclock2420_data.c | 2 +
arch/arm/mach-omap2/cclock2430_data.c | 2 +
arch/arm/mach-omap2/cclock44xx_data.c | 13 ++-
arch/arm/mach-omap2/devices.c | 2 +-
arch/arm/mach-omap2/drm.c | 3 +-
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 6 +-
arch/arm/mach-omap2/timer.c | 8 +-
arch/arm/mach-s3c64xx/mach-crag6410-module.c | 2 +-
arch/arm/mach-s3c64xx/pm.c | 2 +
drivers/clk/mvebu/clk-cpu.c | 9 ++-
drivers/media/platform/coda.c | 2 +-
drivers/mmc/host/mvsdio.c | 92 +++++++---------------
drivers/video/imxfb.c | 13 ++-
.../linux/platform_data/imx-iram.h | 0
37 files changed, 176 insertions(+), 180 deletions(-)
rename arch/arm/mach-imx/iram.h => include/linux/platform_data/imx-iram.h (100%)
^ permalink raw reply
* [GIT PULL][for 3.8] request from armsoc/fix branch in pxa git tree
From: Haojian Zhuang @ 2013-01-24 4:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOesGMjfJ6A37Ncek8221dsYNzf6pZNYYD-XOt4hoa9TD_VYAw@mail.gmail.com>
On Thu, Jan 24, 2013 at 12:33 PM, Olof Johansson <olof@lixom.net> wrote:
> Hi,
>
> On Wed, Jan 23, 2013 at 1:15 AM, Haojian Zhuang
> <haojian.zhuang@gmail.com> wrote:
>> Hi Arnd & Olof,
>>
>> Please help to pull armsoc/fix branch in pxa git tree.
>>
>> Regards
>> Haojian
>>
>> The following changes since commit 7d1f9aeff1ee4a20b1aeb377dd0f579fe9647619:
>>
>> Linux 3.8-rc4 (2013-01-17 19:25:45 -0800)
>>
>> are available in the git repository at:
>>
>> git://github.com/hzhuang1/linux.git armsoc/fix
>>
>> for you to fetch changes up to eea6e39b916dd282c7fa4629be8934b5ad60e62b:
>>
>> ARM: pxa: Minor naming fixes in spitz.c (2013-01-23 17:13:07 +0800)
>>
>> ----------------------------------------------------------------
>> Igor Grinberg (1):
>> ARM: PXA3xx: program the CSMSADRCFG register
>>
>> Marko Katic (1):
>> ARM: pxa: Minor naming fixes in spitz.c
>>
>> Mike Dunn (2):
>> ARM: palmtreo: fix lcd initilialization on treo680
>> ARM: palmtreo: fix #ifdefs for leds-gpio device
>
> I don't think some of those really are regressions, are they? I.e. the
> palmtreo fixes are for code that never in recent times worked I think?
>
> If so, I'd prefer to queue this for 3.9 as a fixes-non-critical
> instead, please let me know if that's ok.
>
> Thanks,
>
> -Olof
It's fine to me. You can queue all of them into 3.9 release cycle.
Thanks
Haojian
^ permalink raw reply
* [GIT PULL] imx fixes for 3.8, take 3
From: Olof Johansson @ 2013-01-24 4:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130122144358.GC2812@S2101-09.ap.freescale.net>
On Tue, Jan 22, 2013 at 6:44 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> git://git.linaro.org/people/shawnguo/linux-2.6.git tags/imx-fixes-3.8-3
Pulled, thanks.
-Olof
^ permalink raw reply
* [GIT PULL] ARM: mvebu fixes for v3.8-rc5
From: Olof Johansson @ 2013-01-24 4:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358904583.07bA7B0.11715@triton>
On Tue, Jan 22, 2013 at 5:29 PM, Jason Cooper <jason@lakedaemon.net> wrote:
> The following changes since commit 11d5993df2e1f65e3acfeb92a3febe88803b3e7f:
>
> arm: mvebu: Fix memory size for Armada 370 DB (2013-01-10 19:16:51 +0000)
>
> are available in the git repository at:
>
> git://git.infradead.org/users/jcooper/linux.git tags/mvebu_fixes_for_v3.8-rc5
Pulled, thanks. A little bigger than ideal at this point in the
release, but oh well.
-Olof
^ permalink raw reply
* [GIT PULL][for 3.8] request from armsoc/fix branch in pxa git tree
From: Olof Johansson @ 2013-01-24 4:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAN1soZzTnVhMwQfOz7=MyHm7b6n=OmNL=wEENJz-SFOPU6Wsjw@mail.gmail.com>
Hi,
On Wed, Jan 23, 2013 at 1:15 AM, Haojian Zhuang
<haojian.zhuang@gmail.com> wrote:
> Hi Arnd & Olof,
>
> Please help to pull armsoc/fix branch in pxa git tree.
>
> Regards
> Haojian
>
> The following changes since commit 7d1f9aeff1ee4a20b1aeb377dd0f579fe9647619:
>
> Linux 3.8-rc4 (2013-01-17 19:25:45 -0800)
>
> are available in the git repository at:
>
> git://github.com/hzhuang1/linux.git armsoc/fix
>
> for you to fetch changes up to eea6e39b916dd282c7fa4629be8934b5ad60e62b:
>
> ARM: pxa: Minor naming fixes in spitz.c (2013-01-23 17:13:07 +0800)
>
> ----------------------------------------------------------------
> Igor Grinberg (1):
> ARM: PXA3xx: program the CSMSADRCFG register
>
> Marko Katic (1):
> ARM: pxa: Minor naming fixes in spitz.c
>
> Mike Dunn (2):
> ARM: palmtreo: fix lcd initilialization on treo680
> ARM: palmtreo: fix #ifdefs for leds-gpio device
I don't think some of those really are regressions, are they? I.e. the
palmtreo fixes are for code that never in recent times worked I think?
If so, I'd prefer to queue this for 3.9 as a fixes-non-critical
instead, please let me know if that's ok.
Thanks,
-Olof
^ permalink raw reply
* [PATCH v5 04/45] percpu_rwlock: Implement the core design of Per-CPU Reader-Writer Locks
From: Srivatsa S. Bhat @ 2013-01-24 4:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130123195740.GI2373@mtj.dyndns.org>
On 01/24/2013 01:27 AM, Tejun Heo wrote:
> Hello, Srivatsa.
>
> On Thu, Jan 24, 2013 at 01:03:52AM +0530, Srivatsa S. Bhat wrote:
>> Hmm.. I split it up into steps to help explain the reasoning behind
>> the code sufficiently, rather than spring all of the intricacies at
>> one go (which would make it very hard to write the changelog/comments
>> also). The split made it easier for me to document it well in the
>> changelog, because I could deal with reasonable chunks of code/complexity
>> at a time. IMHO that helps people reading it for the first time to
>> understand the logic easily.
>
> I don't know. It's a judgement call I guess. I personally would much
> prefer having ample documentation as comments in the source itself or
> as a separate Documentation/ file as that's what most people are gonna
> be looking at to figure out what's going on. Maybe just compact it a
> bit and add more in-line documentation instead?
>
OK, I'll think about this.
>>> The only two options are either punishing writers or identifying and
>>> updating all such possible deadlocks. percpu_rwsem does the former,
>>> right? I don't know how feasible the latter would be.
>>
>> I don't think we can avoid looking into all the possible deadlocks,
>> as long as we use rwlocks inside get/put_online_cpus_atomic() (assuming
>> rwlocks are fair). Even with Oleg's idea of using synchronize_sched()
>> at the writer, we still need to take care of locking rules, because the
>> synchronize_sched() only helps avoid the memory barriers at the reader,
>> and doesn't help get rid of the rwlocks themselves.
>
> Well, percpu_rwlock don't have to use rwlock for the slow path. It
> can implement its own writer starving locking scheme. It's not like
> implementing slow path global rwlock logic is difficult.
>
Great idea! So probably I could use atomic ops or something similar in the
slow path to implement the scheme we need...
>> CPU 0 CPU 1
>>
>> read_lock(&rwlock)
>>
>> write_lock(&rwlock) //spins, because CPU 0
>> //has acquired the lock for read
>>
>> read_lock(&rwlock)
>> ^^^^^
>> What happens here? Does CPU 0 start spinning (and hence deadlock) or will
>> it continue realizing that it already holds the rwlock for read?
>
> I don't think rwlock allows nesting write lock inside read lock.
> read_lock(); write_lock() will always deadlock.
>
Sure, I understand that :-) My question was, what happens when *two* CPUs
are involved, as in, the read_lock() is invoked only on CPU 0 whereas the
write_lock() is invoked on CPU 1.
For example, the same scenario shown above, but with slightly different
timing, will NOT result in a deadlock:
Scenario 2:
CPU 0 CPU 1
read_lock(&rwlock)
read_lock(&rwlock) //doesn't spin
write_lock(&rwlock) //spins, because CPU 0
//has acquired the lock for read
So I was wondering whether the "fairness" logic of rwlocks would cause
the second read_lock() to spin (in the first scenario shown above) because
a writer is already waiting (and hence new readers should spin) and thus
cause a deadlock.
Regards,
Srivatsa S. Bhat
^ permalink raw reply
* [PATCH v5 01/45] percpu_rwlock: Introduce the global reader-writer lock backend
From: Michel Lespinasse @ 2013-01-24 4:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358883152.21576.55.camel@gandalf.local.home>
On Tue, Jan 22, 2013 at 11:32 AM, Steven Rostedt <rostedt@goodmis.org> wrote:
> On Tue, 2013-01-22 at 13:03 +0530, Srivatsa S. Bhat wrote:
>> A straight-forward (and obvious) algorithm to implement Per-CPU Reader-Writer
>> locks can also lead to too many deadlock possibilities which can make it very
>> hard/impossible to use. This is explained in the example below, which helps
>> justify the need for a different algorithm to implement flexible Per-CPU
>> Reader-Writer locks.
>>
>> We can use global rwlocks as shown below safely, without fear of deadlocks:
>>
>> Readers:
>>
>> CPU 0 CPU 1
>> ------ ------
>>
>> 1. spin_lock(&random_lock); read_lock(&my_rwlock);
>>
>>
>> 2. read_lock(&my_rwlock); spin_lock(&random_lock);
>>
>>
>> Writer:
>>
>> CPU 2:
>> ------
>>
>> write_lock(&my_rwlock);
>>
>
> I thought global locks are now fair. That is, a reader will block if a
> writer is waiting. Hence, the above should deadlock on the current
> rwlock_t types.
I believe you are mistaken here. struct rw_semaphore is fair (and
blocking), but rwlock_t is unfair. The reason we can't easily make
rwlock_t fair is because tasklist_lock currently depends on the
rwlock_t unfairness - tasklist_lock readers typically don't disable
local interrupts, and tasklist_lock may be acquired again from within
an interrupt, which would deadlock if rwlock_t was fair and a writer
was queued by the time the interrupt is processed.
> We need to fix those locations (or better yet, remove all rwlocks ;-)
tasklist_lock is the main remaining user. I'm not sure about removing
rwlock_t, but I would like to at least make it fair somehow :)
--
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox