aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/locking/qspinlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/locking/qspinlock.c')
-rw-r--r--kernel/locking/qspinlock.c68
1 files changed, 67 insertions, 1 deletions
diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
index fd31a474145d..38c49202d532 100644
--- a/kernel/locking/qspinlock.c
+++ b/kernel/locking/qspinlock.c
@@ -18,6 +18,9 @@
18 * Authors: Waiman Long <waiman.long@hp.com> 18 * Authors: Waiman Long <waiman.long@hp.com>
19 * Peter Zijlstra <peterz@infradead.org> 19 * Peter Zijlstra <peterz@infradead.org>
20 */ 20 */
21
22#ifndef _GEN_PV_LOCK_SLOWPATH
23
21#include <linux/smp.h> 24#include <linux/smp.h>
22#include <linux/bug.h> 25#include <linux/bug.h>
23#include <linux/cpumask.h> 26#include <linux/cpumask.h>
@@ -65,13 +68,21 @@
65 68
66#include "mcs_spinlock.h" 69#include "mcs_spinlock.h"
67 70
71#ifdef CONFIG_PARAVIRT_SPINLOCKS
72#define MAX_NODES 8
73#else
74#define MAX_NODES 4
75#endif
76
68/* 77/*
69 * Per-CPU queue node structures; we can never have more than 4 nested 78 * Per-CPU queue node structures; we can never have more than 4 nested
70 * contexts: task, softirq, hardirq, nmi. 79 * contexts: task, softirq, hardirq, nmi.
71 * 80 *
72 * Exactly fits one 64-byte cacheline on a 64-bit architecture. 81 * Exactly fits one 64-byte cacheline on a 64-bit architecture.
82 *
83 * PV doubles the storage and uses the second cacheline for PV state.
73 */ 84 */
74static DEFINE_PER_CPU_ALIGNED(struct mcs_spinlock, mcs_nodes[4]); 85static DEFINE_PER_CPU_ALIGNED(struct mcs_spinlock, mcs_nodes[MAX_NODES]);
75 86
76/* 87/*
77 * We must be able to distinguish between no-tail and the tail at 0:0, 88 * We must be able to distinguish between no-tail and the tail at 0:0,
@@ -220,6 +231,32 @@ static __always_inline void set_locked(struct qspinlock *lock)
220 WRITE_ONCE(l->locked, _Q_LOCKED_VAL); 231 WRITE_ONCE(l->locked, _Q_LOCKED_VAL);
221} 232}
222 233
234
235/*
236 * Generate the native code for queued_spin_unlock_slowpath(); provide NOPs for
237 * all the PV callbacks.
238 */
239
240static __always_inline void __pv_init_node(struct mcs_spinlock *node) { }
241static __always_inline void __pv_wait_node(struct mcs_spinlock *node) { }
242static __always_inline void __pv_kick_node(struct mcs_spinlock *node) { }
243
244static __always_inline void __pv_wait_head(struct qspinlock *lock,
245 struct mcs_spinlock *node) { }
246
247#define pv_enabled() false
248
249#define pv_init_node __pv_init_node
250#define pv_wait_node __pv_wait_node
251#define pv_kick_node __pv_kick_node
252#define pv_wait_head __pv_wait_head
253
254#ifdef CONFIG_PARAVIRT_SPINLOCKS
255#define queued_spin_lock_slowpath native_queued_spin_lock_slowpath
256#endif
257
258#endif /* _GEN_PV_LOCK_SLOWPATH */
259
223/** 260/**
224 * queued_spin_lock_slowpath - acquire the queued spinlock 261 * queued_spin_lock_slowpath - acquire the queued spinlock
225 * @lock: Pointer to queued spinlock structure 262 * @lock: Pointer to queued spinlock structure
@@ -249,6 +286,9 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
249 286
250 BUILD_BUG_ON(CONFIG_NR_CPUS >= (1U << _Q_TAIL_CPU_BITS)); 287 BUILD_BUG_ON(CONFIG_NR_CPUS >= (1U << _Q_TAIL_CPU_BITS));
251 288
289 if (pv_enabled())
290 goto queue;
291
252 if (virt_queued_spin_lock(lock)) 292 if (virt_queued_spin_lock(lock))
253 return; 293 return;
254 294
@@ -325,6 +365,7 @@ queue:
325 node += idx; 365 node += idx;
326 node->locked = 0; 366 node->locked = 0;
327 node->next = NULL; 367 node->next = NULL;
368 pv_init_node(node);
328 369
329 /* 370 /*
330 * We touched a (possibly) cold cacheline in the per-cpu queue node; 371 * We touched a (possibly) cold cacheline in the per-cpu queue node;
@@ -350,6 +391,7 @@ queue:
350 prev = decode_tail(old); 391 prev = decode_tail(old);
351 WRITE_ONCE(prev->next, node); 392 WRITE_ONCE(prev->next, node);
352 393
394 pv_wait_node(node);
353 arch_mcs_spin_lock_contended(&node->locked); 395 arch_mcs_spin_lock_contended(&node->locked);
354 } 396 }
355 397
@@ -365,6 +407,7 @@ queue:
365 * does not imply a full barrier. 407 * does not imply a full barrier.
366 * 408 *
367 */ 409 */
410 pv_wait_head(lock, node);
368 while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_PENDING_MASK) 411 while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_PENDING_MASK)
369 cpu_relax(); 412 cpu_relax();
370 413
@@ -397,6 +440,7 @@ queue:
397 cpu_relax(); 440 cpu_relax();
398 441
399 arch_mcs_spin_unlock_contended(&next->locked); 442 arch_mcs_spin_unlock_contended(&next->locked);
443 pv_kick_node(next);
400 444
401release: 445release:
402 /* 446 /*
@@ -405,3 +449,25 @@ release:
405 this_cpu_dec(mcs_nodes[0].count); 449 this_cpu_dec(mcs_nodes[0].count);
406} 450}
407EXPORT_SYMBOL(queued_spin_lock_slowpath); 451EXPORT_SYMBOL(queued_spin_lock_slowpath);
452
453/*
454 * Generate the paravirt code for queued_spin_unlock_slowpath().
455 */
456#if !defined(_GEN_PV_LOCK_SLOWPATH) && defined(CONFIG_PARAVIRT_SPINLOCKS)
457#define _GEN_PV_LOCK_SLOWPATH
458
459#undef pv_enabled
460#define pv_enabled() true
461
462#undef pv_init_node
463#undef pv_wait_node
464#undef pv_kick_node
465#undef pv_wait_head
466
467#undef queued_spin_lock_slowpath
468#define queued_spin_lock_slowpath __pv_queued_spin_lock_slowpath
469
470#include "qspinlock_paravirt.h"
471#include "qspinlock.c"
472
473#endif