<feed xmlns='http://www.w3.org/2005/Atom'>
<title>kernel.git/arch/powerpc/include/asm/spinlock.h, branch linux-3.12.y</title>
<subtitle>Hosts the 0x221E linux distro kernel.
</subtitle>
<id>https://git.0xinfinity.dev/distro/kernel.git/atom?h=linux-3.12.y</id>
<link rel='self' href='https://git.0xinfinity.dev/distro/kernel.git/atom?h=linux-3.12.y'/>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/'/>
<updated>2014-10-31T14:11:33Z</updated>
<entry>
<title>powerpc: Add smp_mb() to arch_spin_is_locked()</title>
<updated>2014-10-31T14:11:33Z</updated>
<author>
<name>Michael Ellerman</name>
</author>
<published>2014-10-14T01:07:18Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=5aaee42d255a81d3b010432265254353946d88b3'/>
<id>urn:sha1:5aaee42d255a81d3b010432265254353946d88b3</id>
<content type='text'>
commit 51d7d5205d3389a32859f9939f1093f267409929 upstream.

The kernel defines the function spin_is_locked(), which can be used to
check if a spinlock is currently locked.

Using spin_is_locked() on a lock you don't hold is obviously racy. That
is, even though you may observe that the lock is unlocked, it may become
locked at any time.

There is (at least) one exception to that, which is if two locks are
used as a pair, and the holder of each checks the status of the other
before doing any update.

Assuming *A and *B are two locks, and *COUNTER is a shared non-atomic
value:

The first CPU does:

	spin_lock(*A)

	if spin_is_locked(*B)
		# nothing
	else
		smp_mb()
		LOAD r = *COUNTER
		r++
		STORE *COUNTER = r

	spin_unlock(*A)

And the second CPU does:

	spin_lock(*B)

	if spin_is_locked(*A)
		# nothing
	else
		smp_mb()
		LOAD r = *COUNTER
		r++
		STORE *COUNTER = r

	spin_unlock(*B)

Although this is a strange locking construct, it should work.

It seems to be understood, but not documented, that spin_is_locked() is
not a memory barrier, so in the examples above and below the caller
inserts its own memory barrier before acting on the result of
spin_is_locked().

For now we assume spin_is_locked() is implemented as below, and we break
it out in our examples:

	bool spin_is_locked(*LOCK) {
		LOAD l = *LOCK
		return l.locked
	}

Our intuition is that there should be no problem even if the two code
sequences run simultaneously such as:

	CPU 0			CPU 1
	==================================================
	spin_lock(*A)		spin_lock(*B)
	LOAD b = *B		LOAD a = *A
	if b.locked # true	if a.locked # true
	# nothing		# nothing
	spin_unlock(*A)		spin_unlock(*B)

If one CPU gets the lock before the other then it will do the update and
the other CPU will back off:

	CPU 0			CPU 1
	==================================================
	spin_lock(*A)
	LOAD b = *B
				spin_lock(*B)
	if b.locked # false	LOAD a = *A
	else			if a.locked # true
	smp_mb()		# nothing
	LOAD r1 = *COUNTER	spin_unlock(*B)
	r1++
	STORE *COUNTER = r1
	spin_unlock(*A)

However in reality spin_lock() itself is not indivisible. On powerpc we
implement it as a load-and-reserve and store-conditional.

Ignoring the retry logic for the lost reservation case, it boils down to:
	spin_lock(*LOCK) {
		LOAD l = *LOCK
		l.locked = true
		STORE *LOCK = l
		ACQUIRE_BARRIER
	}

The ACQUIRE_BARRIER is required to give spin_lock() ACQUIRE semantics as
defined in memory-barriers.txt:

     This acts as a one-way permeable barrier.  It guarantees that all
     memory operations after the ACQUIRE operation will appear to happen
     after the ACQUIRE operation with respect to the other components of
     the system.

On modern powerpc systems we use lwsync for ACQUIRE_BARRIER. lwsync is
also know as "lightweight sync", or "sync 1".

As described in Power ISA v2.07 section B.2.1.1, in this scenario the
lwsync is not the barrier itself. It instead causes the LOAD of *LOCK to
act as the barrier, preventing any loads or stores in the locked region
from occurring prior to the load of *LOCK.

Whether this behaviour is in accordance with the definition of ACQUIRE
semantics in memory-barriers.txt is open to discussion, we may switch to
a different barrier in future.

What this means in practice is that the following can occur:

	CPU 0			CPU 1
	==================================================
	LOAD a = *A 		LOAD b = *B
	a.locked = true		b.locked = true
	LOAD b = *B		LOAD a = *A
	STORE *A = a		STORE *B = b
	if b.locked # false	if a.locked # false
	else			else
	smp_mb()		smp_mb()
	LOAD r1 = *COUNTER	LOAD r2 = *COUNTER
	r1++			r2++
	STORE *COUNTER = r1
				STORE *COUNTER = r2	# Lost update
	spin_unlock(*A)		spin_unlock(*B)

That is, the load of *B can occur prior to the store that makes *A
visibly locked. And similarly for CPU 1. The result is both CPUs hold
their lock and believe the other lock is unlocked.

The easiest fix for this is to add a full memory barrier to the start of
spin_is_locked(), so adding to our previous definition would give us:

	bool spin_is_locked(*LOCK) {
		smp_mb()
		LOAD l = *LOCK
		return l.locked
	}

The new barrier orders the store to the lock we are locking vs the load
of the other lock:

	CPU 0			CPU 1
	==================================================
	LOAD a = *A 		LOAD b = *B
	a.locked = true		b.locked = true
	STORE *A = a		STORE *B = b
	smp_mb()		smp_mb()
	LOAD b = *B		LOAD a = *A
	if b.locked # true	if a.locked # true
	# nothing		# nothing
	spin_unlock(*A)		spin_unlock(*B)

Although the above example is theoretical, there is code similar to this
example in sem_lock() in ipc/sem.c. This commit in addition to the next
commit appears to be a fix for crashes we are seeing in that code where
we believe this race happens in practice.

Signed-off-by: Michael Ellerman &lt;mpe@ellerman.id.au&gt;
Signed-off-by: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;
Signed-off-by: Jiri Slaby &lt;jslaby@suse.cz&gt;
</content>
</entry>
<entry>
<title>powerpc: Make rwlocks endian safe</title>
<updated>2013-08-14T05:33:40Z</updated>
<author>
<name>Anton Blanchard</name>
</author>
<published>2013-08-06T16:01:51Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=54bb7f4bda0ee49f39dc593c2d73fe6053a99dbb'/>
<id>urn:sha1:54bb7f4bda0ee49f39dc593c2d73fe6053a99dbb</id>
<content type='text'>
Our ppc64 spinlocks and rwlocks use a trick where a lock token and
the paca index are placed in the lock with a single store. Since we
are using two u16s they need adjusting for little endian.

Signed-off-by: Anton Blanchard &lt;anton@samba.org&gt;
Signed-off-by: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;
</content>
</entry>
<entry>
<title>powerpc: Stop using non-architected shared_proc field in lppaca</title>
<updated>2013-08-14T01:50:26Z</updated>
<author>
<name>Anton Blanchard</name>
</author>
<published>2013-08-06T16:01:26Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=f13c13a005127b5dc5daaca190277a062d946e63'/>
<id>urn:sha1:f13c13a005127b5dc5daaca190277a062d946e63</id>
<content type='text'>
Although the shared_proc field in the lppaca works today, it is
not architected. A shared processor partition will always have a non
zero yield_count so use that instead. Create a wrapper so users
don't have to know about the details.

In order for older kernels to continue to work on KVM we need
to set the shared_proc bit. While here, remove the ugly bitfield.

Signed-off-by: Anton Blanchard &lt;anton@samba.org&gt;
Signed-off-by: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;
</content>
</entry>
<entry>
<title>powerpc: Avoid debug_smp_processor_id() check in SHARED_PROCESSOR</title>
<updated>2013-01-29T00:35:06Z</updated>
<author>
<name>Li Zhong</name>
</author>
<published>2013-01-24T21:51:13Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=94c95cfbfe784eca5f4b96955e41bda1318605bc'/>
<id>urn:sha1:94c95cfbfe784eca5f4b96955e41bda1318605bc</id>
<content type='text'>
Use local_paca directly in macro SHARED_PROCESSOR, as all processors
have the same value for the field shared_proc, so we don't need care
racy here.

Reported-by: Paul E. McKenney &lt;paulmck@linux.vnet.ibm.com&gt;
Signed-off-by: Li Zhong &lt;zhong@linux.vnet.ibm.com&gt;
Signed-off-by: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;
</content>
</entry>
<entry>
<title>powerpc: Remove the remaining CONFIG_PPC_ISERIES pieces</title>
<updated>2012-03-21T00:16:12Z</updated>
<author>
<name>Stephen Rothwell</name>
</author>
<published>2012-03-15T18:20:13Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=1b041885ae1d9938440fc2cf6a444b70ec0a86c9'/>
<id>urn:sha1:1b041885ae1d9938440fc2cf6a444b70ec0a86c9</id>
<content type='text'>
Signed-off-by: Stephen Rothwell &lt;sfr@canb.auug.org.au&gt;
Signed-off-by: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;
</content>
</entry>
<entry>
<title>powerpc: Rename LWSYNC_ON_SMP to PPC_RELEASE_BARRIER, ISYNC_ON_SMP to PPC_ACQUIRE_BARRIER</title>
<updated>2010-02-17T03:03:15Z</updated>
<author>
<name>Anton Blanchard</name>
</author>
<published>2010-02-10T01:04:06Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=f10e2e5b4b4c9937de596f96ffe028be3a565598'/>
<id>urn:sha1:f10e2e5b4b4c9937de596f96ffe028be3a565598</id>
<content type='text'>
For performance reasons we are about to change ISYNC_ON_SMP to sometimes be
lwsync. Now that the macro name doesn't make sense, change it and LWSYNC_ON_SMP
to better explain what the barriers are doing.

Signed-off-by: Anton Blanchard &lt;anton@samba.org&gt;
Signed-off-by: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;
</content>
</entry>
<entry>
<title>powerpc: Use lwarx hint in spinlocks</title>
<updated>2010-02-17T03:03:14Z</updated>
<author>
<name>Anton Blanchard</name>
</author>
<published>2010-02-10T00:57:28Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=4e14a4d17a8cd66ccab180d32c977091922cfbed'/>
<id>urn:sha1:4e14a4d17a8cd66ccab180d32c977091922cfbed</id>
<content type='text'>
Recent versions of the PowerPC architecture added a hint bit to the larx
instructions to differentiate between an atomic operation and a lock operation:

&gt; 0 Other programs might attempt to modify the word in storage addressed by EA
&gt; even if the subsequent Store Conditional succeeds.
&gt;
&gt; 1 Other programs will not attempt to modify the word in storage addressed by
&gt; EA until the program that has acquired the lock performs a subsequent store
&gt; releasing the lock.

To avoid a binutils dependency this patch create macros for the extended lwarx
format and uses it in the spinlock code. To test this change I used a simple
test case that acquires and releases a global pthread mutex:

	pthread_mutex_lock(&amp;mutex);
	pthread_mutex_unlock(&amp;mutex);

On a 32 core POWER6, running 32 test threads we spend almost all our time in
the futex spinlock code:

    94.37%     perf  [kernel]                     [k] ._raw_spin_lock
               |
               |--99.95%-- ._raw_spin_lock
               |          |
               |          |--63.29%-- .futex_wake
               |          |
               |          |--36.64%-- .futex_wait_setup

Which is a good test for this patch. The results (in lock/unlock operations per
second) are:

before: 1538203 ops/sec
after:  2189219 ops/sec

An improvement of 42%

A 32 core POWER7 improves even more:

before: 1279529 ops/sec
after:  2282076 ops/sec

An improvement of 78%

Signed-off-by: Anton Blanchard &lt;anton@samba.org&gt;
Signed-off-by: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;
</content>
</entry>
<entry>
<title>locking: Convert raw_rwlock functions to arch_rwlock</title>
<updated>2009-12-14T22:55:32Z</updated>
<author>
<name>Thomas Gleixner</name>
</author>
<published>2009-12-03T19:08:46Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=e5931943d02bf751b1ec849c0d2ade23d76a8d41'/>
<id>urn:sha1:e5931943d02bf751b1ec849c0d2ade23d76a8d41</id>
<content type='text'>
Name space cleanup for rwlock functions. No functional change.

Signed-off-by: Thomas Gleixner &lt;tglx@linutronix.de&gt;
Acked-by: Peter Zijlstra &lt;peterz@infradead.org&gt;
Acked-by: David S. Miller &lt;davem@davemloft.net&gt;
Acked-by: Ingo Molnar &lt;mingo@elte.hu&gt;
Cc: linux-arch@vger.kernel.org
</content>
</entry>
<entry>
<title>locking: Convert raw_rwlock to arch_rwlock</title>
<updated>2009-12-14T22:55:32Z</updated>
<author>
<name>Thomas Gleixner</name>
</author>
<published>2009-12-03T19:01:19Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=fb3a6bbc912b12347614e5742c7c61416cdb0ca0'/>
<id>urn:sha1:fb3a6bbc912b12347614e5742c7c61416cdb0ca0</id>
<content type='text'>
Not strictly necessary for -rt as -rt does not have non sleeping
rwlocks, but it's odd to not have a consistent naming convention.

No functional change.

Signed-off-by: Thomas Gleixner &lt;tglx@linutronix.de&gt;
Acked-by: Peter Zijlstra &lt;peterz@infradead.org&gt;
Acked-by: David S. Miller &lt;davem@davemloft.net&gt;
Acked-by: Ingo Molnar &lt;mingo@elte.hu&gt;
Cc: linux-arch@vger.kernel.org

</content>
</entry>
<entry>
<title>locking: Convert __raw_spin* functions to arch_spin*</title>
<updated>2009-12-14T22:55:32Z</updated>
<author>
<name>Thomas Gleixner</name>
</author>
<published>2009-12-02T19:01:25Z</published>
<link rel='alternate' type='text/html' href='https://git.0xinfinity.dev/distro/kernel.git/commit/?id=0199c4e68d1f02894bdefe4b5d9e9ee4aedd8d62'/>
<id>urn:sha1:0199c4e68d1f02894bdefe4b5d9e9ee4aedd8d62</id>
<content type='text'>
Name space cleanup. No functional change.

Signed-off-by: Thomas Gleixner &lt;tglx@linutronix.de&gt;
Acked-by: Peter Zijlstra &lt;peterz@infradead.org&gt;
Acked-by: David S. Miller &lt;davem@davemloft.net&gt;
Acked-by: Ingo Molnar &lt;mingo@elte.hu&gt;
Cc: linux-arch@vger.kernel.org
</content>
</entry>
</feed>
