----------------------
.. kernel-doc:: include/linux/rcupdate.h
- :external:
.. kernel-doc:: include/linux/rcupdate_wait.h
- :external:
.. kernel-doc:: include/linux/rcutree.h
- :external:
.. kernel-doc:: kernel/rcu/tree.c
- :external:
.. kernel-doc:: kernel/rcu/tree_plugin.h
- :external:
.. kernel-doc:: kernel/rcu/tree_exp.h
- :external:
.. kernel-doc:: kernel/rcu/update.c
- :external:
.. kernel-doc:: include/linux/srcu.h
- :external:
.. kernel-doc:: kernel/rcu/srcutree.c
- :external:
.. kernel-doc:: include/linux/rculist_bl.h
- :external:
.. kernel-doc:: include/linux/rculist.h
- :external:
.. kernel-doc:: include/linux/rculist_nulls.h
- :external:
.. kernel-doc:: include/linux/rcu_sync.h
- :external:
.. kernel-doc:: kernel/rcu/sync.c
- :external:
EXPORT_SYMBOL(__xchg8);
EXPORT_SYMBOL(__xchg32);
EXPORT_SYMBOL(__cmpxchg_u32);
+EXPORT_SYMBOL(__cmpxchg_u64);
#ifdef CONFIG_SMP
EXPORT_SYMBOL(__atomic_hash);
#endif
#ifdef CONFIG_64BIT
EXPORT_SYMBOL(__xchg64);
-EXPORT_SYMBOL(__cmpxchg_u64);
#endif
#include <linux/uaccess.h>
10: ldd 0(%r25), %r25
11: ldd 0(%r24), %r24
#else
- /* Load new value into r22/r23 - high/low */
+ /* Load old value into r22/r23 - high/low */
10: ldw 0(%r25), %r22
11: ldw 4(%r25), %r23
/* Load new value into fr4 for atomic store later */
copy %r0, %r28
#else
/* Compare first word */
-19: ldw,ma 0(%r26), %r29
+19: ldw 0(%r26), %r29
sub,= %r29, %r22, %r0
b,n cas2_end
/* Compare second word */
-20: ldw,ma 4(%r26), %r29
+20: ldw 4(%r26), %r29
sub,= %r29, %r23, %r0
b,n cas2_end
/* Perform the store */
cpu0_loc = per_cpu(cpu_data, 0).cpu_loc;
for_each_online_cpu(cpu) {
- if (cpu0_loc == per_cpu(cpu_data, cpu).cpu_loc)
+ if (cpu == 0)
+ continue;
+ if ((cpu0_loc != 0) &&
+ (cpu0_loc == per_cpu(cpu_data, cpu).cpu_loc))
continue;
clocksource_cr16.name = "cr16_unstable";
/* execve succeeded */
current->fs->in_exec = 0;
current->in_execve = 0;
+ membarrier_execve(current);
acct_update_integrals(current);
task_numa_free(current);
free_bprm(bprm);
unsigned long flags; /* Must use atomic bitops to access the bits */
struct core_state *core_state; /* coredumping support */
+#ifdef CONFIG_MEMBARRIER
+ atomic_t membarrier_state;
+#endif
#ifdef CONFIG_AIO
spinlock_t ioctx_lock;
struct kioctx_table __rcu *ioctx_table;
#define list_entry_rcu(ptr, type, member) \
container_of(lockless_dereference(ptr), type, member)
-/**
+/*
* Where are list_empty_rcu() and list_first_entry_rcu()?
*
* Implementing those functions following their counterparts list_empty() and
* Return the value of the specified RCU-protected pointer, but omit
* both the smp_read_barrier_depends() and the READ_ONCE(). This
* is useful in cases where update-side locks prevent the value of the
- * pointer from changing. Please note that this primitive does -not-
+ * pointer from changing. Please note that this primitive does *not*
* prevent the compiler from repeating this reference or combining it
* with other references, so it should not be used without protection
* of appropriate locks.
* is handed off from RCU to some other synchronization mechanism, for
* example, reference counting or locking. In C11, it would map to
* kill_dependency(). It could be used as follows:
- *
+ * ``
* rcu_read_lock();
* p = rcu_dereference(gp);
* long_lived = is_long_lived(p);
* p = rcu_pointer_handoff(p);
* }
* rcu_read_unlock();
+ *``
*/
#define rcu_pointer_handoff(p) (p)
/**
* RCU_INIT_POINTER() - initialize an RCU protected pointer
+ * @p: The pointer to be initialized.
+ * @v: The value to initialized the pointer to.
*
* Initialize an RCU-protected pointer in special cases where readers
* do not need ordering constraints on the CPU or the compiler. These
* special cases are:
*
- * 1. This use of RCU_INIT_POINTER() is NULLing out the pointer -or-
+ * 1. This use of RCU_INIT_POINTER() is NULLing out the pointer *or*
* 2. The caller has taken whatever steps are required to prevent
- * RCU readers from concurrently accessing this pointer -or-
+ * RCU readers from concurrently accessing this pointer *or*
* 3. The referenced data structure has already been exposed to
- * readers either at compile time or via rcu_assign_pointer() -and-
- * a. You have not made -any- reader-visible changes to
- * this structure since then -or-
+ * readers either at compile time or via rcu_assign_pointer() *and*
+ *
+ * a. You have not made *any* reader-visible changes to
+ * this structure since then *or*
* b. It is OK for readers accessing this structure from its
* new location to see the old state of the structure. (For
* example, the changes were to statistical counters or to
* by a single external-to-structure RCU-protected pointer, then you may
* use RCU_INIT_POINTER() to initialize the internal RCU-protected
* pointers, but you must use rcu_assign_pointer() to initialize the
- * external-to-structure pointer -after- you have completely initialized
+ * external-to-structure pointer *after* you have completely initialized
* the reader-accessible portions of the linked structure.
*
* Note that unlike rcu_assign_pointer(), RCU_INIT_POINTER() provides no
/**
* RCU_POINTER_INITIALIZER() - statically initialize an RCU protected pointer
+ * @p: The pointer to be initialized.
+ * @v: The value to initialized the pointer to.
*
* GCC-style initialization for an RCU-protected pointer in a structure field.
*/
current->flags = (current->flags & ~PF_MEMALLOC) | flags;
}
+#ifdef CONFIG_MEMBARRIER
+enum {
+ MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY = (1U << 0),
+ MEMBARRIER_STATE_SWITCH_MM = (1U << 1),
+};
+
+static inline void membarrier_execve(struct task_struct *t)
+{
+ atomic_set(&t->mm->membarrier_state, 0);
+}
+#else
+static inline void membarrier_execve(struct task_struct *t)
+{
+}
+#endif
+
#endif /* _LINUX_SCHED_MM_H */
/**
* srcu_read_lock_held - might we be in SRCU read-side critical section?
+ * @sp: The srcu_struct structure to check
*
* If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an SRCU
* read-side critical section. In absence of CONFIG_DEBUG_LOCK_ALLOC,
void *private_data);
void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only);
#define snd_ctl_sync_vmaster_hook(kctl) snd_ctl_sync_vmaster(kctl, true)
+int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl,
+ int (*func)(struct snd_kcontrol *, void *),
+ void *arg);
/*
* Helper functions for jack-detection controls
* (non-running threads are de facto in such a
* state). This only covers threads from the
* same processes as the caller thread. This
- * command returns 0. The "expedited" commands
- * complete faster than the non-expedited ones,
- * they never block, but have the downside of
- * causing extra overhead.
+ * command returns 0 on success. The
+ * "expedited" commands complete faster than
+ * the non-expedited ones, they never block,
+ * but have the downside of causing extra
+ * overhead. A process needs to register its
+ * intent to use the private expedited command
+ * prior to using it, otherwise this command
+ * returns -EPERM.
+ * @MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED:
+ * Register the process intent to use
+ * MEMBARRIER_CMD_PRIVATE_EXPEDITED. Always
+ * returns 0.
*
* Command to be passed to the membarrier system call. The commands need to
* be a single bit each, except for MEMBARRIER_CMD_QUERY which is assigned to
* the value 0.
*/
enum membarrier_cmd {
- MEMBARRIER_CMD_QUERY = 0,
- MEMBARRIER_CMD_SHARED = (1 << 0),
+ MEMBARRIER_CMD_QUERY = 0,
+ MEMBARRIER_CMD_SHARED = (1 << 0),
/* reserved for MEMBARRIER_CMD_SHARED_EXPEDITED (1 << 1) */
/* reserved for MEMBARRIER_CMD_PRIVATE (1 << 2) */
- MEMBARRIER_CMD_PRIVATE_EXPEDITED = (1 << 3),
+ MEMBARRIER_CMD_PRIVATE_EXPEDITED = (1 << 3),
+ MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = (1 << 4),
};
#endif /* _UAPI_LINUX_MEMBARRIER_H */
/**
* call_srcu() - Queue a callback for invocation after an SRCU grace period
* @sp: srcu_struct in queue the callback
- * @head: structure to be used for queueing the SRCU callback.
+ * @rhp: structure to be used for queueing the SRCU callback.
* @func: function to be invoked after the SRCU grace period
*
* The callback function will be invoked some time after a full SRCU
}
/**
+ * rcu_sync_enter_start - Force readers onto slow path for multiple updates
+ * @rsp: Pointer to rcu_sync structure to use for synchronization
+ *
* Must be called after rcu_sync_init() and before first use.
*
* Ensures rcu_sync_is_idle() returns false and rcu_sync_{enter,exit}()
/**
* rcu_sync_func() - Callback function managing reader access to fastpath
- * @rsp: Pointer to rcu_sync structure to use for synchronization
+ * @rhp: Pointer to rcu_head in rcu_sync structure to use for synchronization
*
* This function is passed to one of the call_rcu() functions by
* rcu_sync_exit(), so that it is invoked after a grace period following the
* rcu_sync_exit(). Otherwise, set all state back to idle so that readers
* can again use their fastpaths.
*/
-static void rcu_sync_func(struct rcu_head *rcu)
+static void rcu_sync_func(struct rcu_head *rhp)
{
- struct rcu_sync *rsp = container_of(rcu, struct rcu_sync, cb_head);
+ struct rcu_sync *rsp = container_of(rhp, struct rcu_sync, cb_head);
unsigned long flags;
BUG_ON(rsp->gp_state != GP_PASSED);
* read-side critical sections have completed. call_rcu_sched() assumes
* that the read-side critical sections end on enabling of preemption
* or on voluntary preemption.
- * RCU read-side critical sections are delimited by :
- * - rcu_read_lock_sched() and rcu_read_unlock_sched(), OR
- * - anything that disables preemption.
+ * RCU read-side critical sections are delimited by:
+ *
+ * - rcu_read_lock_sched() and rcu_read_unlock_sched(), OR
+ * - anything that disables preemption.
*
* These may be nested.
*
* handler. This means that read-side critical sections in process
* context must not be interrupted by softirqs. This interface is to be
* used when most of the read-side critical sections are in softirq context.
- * RCU read-side critical sections are delimited by :
- * - rcu_read_lock() and rcu_read_unlock(), if in interrupt context.
- * OR
- * - rcu_read_lock_bh() and rcu_read_unlock_bh(), if in process context.
- * These may be nested.
+ * RCU read-side critical sections are delimited by:
+ *
+ * - rcu_read_lock() and rcu_read_unlock(), if in interrupt context, OR
+ * - rcu_read_lock_bh() and rcu_read_unlock_bh(), if in process context.
+ *
+ * These may be nested.
*
* See the description of call_rcu() for more detailed information on
* memory ordering guarantees.
#include <linux/membarrier.h>
#include <linux/tick.h>
#include <linux/cpumask.h>
+#include <linux/atomic.h>
#include "sched.h" /* for cpu_rq(). */
* except MEMBARRIER_CMD_QUERY.
*/
#define MEMBARRIER_CMD_BITMASK \
- (MEMBARRIER_CMD_SHARED | MEMBARRIER_CMD_PRIVATE_EXPEDITED)
+ (MEMBARRIER_CMD_SHARED | MEMBARRIER_CMD_PRIVATE_EXPEDITED \
+ | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED)
static void ipi_mb(void *info)
{
smp_mb(); /* IPIs should be serializing but paranoid. */
}
-static void membarrier_private_expedited(void)
+static int membarrier_private_expedited(void)
{
int cpu;
bool fallback = false;
cpumask_var_t tmpmask;
+ if (!(atomic_read(¤t->mm->membarrier_state)
+ & MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY))
+ return -EPERM;
+
if (num_online_cpus() == 1)
- return;
+ return 0;
/*
* Matches memory barriers around rq->curr modification in
* rq->curr modification in scheduler.
*/
smp_mb(); /* exit from system call is not a mb */
+ return 0;
+}
+
+static void membarrier_register_private_expedited(void)
+{
+ struct task_struct *p = current;
+ struct mm_struct *mm = p->mm;
+
+ /*
+ * We need to consider threads belonging to different thread
+ * groups, which use the same mm. (CLONE_VM but not
+ * CLONE_THREAD).
+ */
+ if (atomic_read(&mm->membarrier_state)
+ & MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY)
+ return;
+ atomic_or(MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY,
+ &mm->membarrier_state);
}
/**
synchronize_sched();
return 0;
case MEMBARRIER_CMD_PRIVATE_EXPEDITED:
- membarrier_private_expedited();
+ return membarrier_private_expedited();
+ case MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED:
+ membarrier_register_private_expedited();
return 0;
default:
return -EINVAL;
#include <sound/core.h>
#include "seq_lock.h"
-#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
-
/* wait until all locks are released */
void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
{
}
}
EXPORT_SYMBOL(snd_use_lock_sync_helper);
-
-#endif
#include <linux/sched.h>
-#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
-
typedef atomic_t snd_use_lock_t;
/* initialize lock */
void snd_use_lock_sync_helper(snd_use_lock_t *lock, const char *file, int line);
#define snd_use_lock_sync(lockp) snd_use_lock_sync_helper(lockp, __BASE_FILE__, __LINE__)
-#else /* SMP || CONFIG_SND_DEBUG */
-
-typedef spinlock_t snd_use_lock_t; /* dummy */
-#define snd_use_lock_init(lockp) /**/
-#define snd_use_lock_use(lockp) /**/
-#define snd_use_lock_free(lockp) /**/
-#define snd_use_lock_sync(lockp) /**/
-
-#endif /* SMP || CONFIG_SND_DEBUG */
-
#endif /* __SND_SEQ_LOCK_H */
master->hook(master->hook_private_data, master->val);
}
EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
+
+/**
+ * snd_ctl_apply_vmaster_slaves - Apply function to each vmaster slave
+ * @kctl: vmaster kctl element
+ * @func: function to apply
+ * @arg: optional function argument
+ *
+ * Apply the function @func to each slave kctl of the given vmaster kctl.
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl,
+ int (*func)(struct snd_kcontrol *, void *),
+ void *arg)
+{
+ struct link_master *master;
+ struct link_slave *slave;
+ int err;
+
+ master = snd_kcontrol_chip(kctl);
+ err = master_init(master);
+ if (err < 0)
+ return err;
+ list_for_each_entry(slave, &master->slaves, list) {
+ err = func(&slave->slave, arg);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_apply_vmaster_slaves);
dev_dbg(bus->dev, "HDA capability ID: 0x%x\n",
(cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF);
+ if (cur_cap == -1) {
+ dev_dbg(bus->dev, "Invalid capability reg read\n");
+ break;
+ }
+
switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) {
case AZX_ML_CAP_ID:
dev_dbg(bus->dev, "Found ML capability\n");
return 1;
}
-/* guess the value corresponding to 0dB */
-static int get_kctl_0dB_offset(struct hda_codec *codec,
- struct snd_kcontrol *kctl, int *step_to_check)
-{
- int _tlv[4];
- const int *tlv = NULL;
- int val = -1;
-
- if ((kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) &&
- kctl->tlv.c == snd_hda_mixer_amp_tlv) {
- get_ctl_amp_tlv(kctl, _tlv);
- tlv = _tlv;
- } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ)
- tlv = kctl->tlv.p;
- if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) {
- int step = tlv[3];
- step &= ~TLV_DB_SCALE_MUTE;
- if (!step)
- return -1;
- if (*step_to_check && *step_to_check != step) {
- codec_err(codec, "Mismatching dB step for vmaster slave (%d!=%d)\n",
-- *step_to_check, step);
- return -1;
- }
- *step_to_check = step;
- val = -tlv[2] / step;
- }
- return val;
-}
-
/* call kctl->put with the given value(s) */
static int put_kctl_with_value(struct snd_kcontrol *kctl, int val)
{
return 0;
}
-/* initialize the slave volume with 0dB */
-static int init_slave_0dB(struct hda_codec *codec,
- void *data, struct snd_kcontrol *slave)
+struct slave_init_arg {
+ struct hda_codec *codec;
+ int step;
+};
+
+/* initialize the slave volume with 0dB via snd_ctl_apply_vmaster_slaves() */
+static int init_slave_0dB(struct snd_kcontrol *kctl, void *_arg)
{
- int offset = get_kctl_0dB_offset(codec, slave, data);
- if (offset > 0)
- put_kctl_with_value(slave, offset);
+ struct slave_init_arg *arg = _arg;
+ int _tlv[4];
+ const int *tlv = NULL;
+ int step;
+ int val;
+
+ if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+ if (kctl->tlv.c != snd_hda_mixer_amp_tlv) {
+ codec_err(arg->codec,
+ "Unexpected TLV callback for slave %s:%d\n",
+ kctl->id.name, kctl->id.index);
+ return 0; /* ignore */
+ }
+ get_ctl_amp_tlv(kctl, _tlv);
+ tlv = _tlv;
+ } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ)
+ tlv = kctl->tlv.p;
+
+ if (!tlv || tlv[0] != SNDRV_CTL_TLVT_DB_SCALE)
+ return 0;
+
+ step = tlv[3];
+ step &= ~TLV_DB_SCALE_MUTE;
+ if (!step)
+ return 0;
+ if (arg->step && arg->step != step) {
+ codec_err(arg->codec,
+ "Mismatching dB step for vmaster slave (%d!=%d)\n",
+ arg->step, step);
+ return 0;
+ }
+
+ arg->step = step;
+ val = -tlv[2] / step;
+ if (val > 0) {
+ put_kctl_with_value(kctl, val);
+ return val;
+ }
+
return 0;
}
-/* unmute the slave */
-static int init_slave_unmute(struct hda_codec *codec,
- void *data, struct snd_kcontrol *slave)
+/* unmute the slave via snd_ctl_apply_vmaster_slaves() */
+static int init_slave_unmute(struct snd_kcontrol *slave, void *_arg)
{
return put_kctl_with_value(slave, 1);
}
/* init with master mute & zero volume */
put_kctl_with_value(kctl, 0);
if (init_slave_vol) {
- int step = 0;
- map_slaves(codec, slaves, suffix,
- tlv ? init_slave_0dB : init_slave_unmute, &step);
+ struct slave_init_arg arg = {
+ .codec = codec,
+ .step = 0,
+ };
+ snd_ctl_apply_vmaster_slaves(kctl,
+ tlv ? init_slave_0dB : init_slave_unmute,
+ &arg);
}
if (ctl_ret)
case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */
case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */
case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */
+ case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */
if (fp->altsetting == 2)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
unsigned int crystal_hz;
unsigned long long tsc_hz;
int base_cpu;
-int do_migrate;
double discover_bclk(unsigned int family, unsigned int model);
unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */
/* IA32_HWP_REQUEST, IA32_HWP_STATUS */
int cpu_migrate(int cpu)
{
- if (!do_migrate)
- return 0;
-
CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set);
if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1)
{"hide", required_argument, 0, 'H'}, // meh, -h taken by --help
{"Joules", no_argument, 0, 'J'},
{"list", no_argument, 0, 'l'},
- {"migrate", no_argument, 0, 'm'},
{"out", required_argument, 0, 'o'},
{"quiet", no_argument, 0, 'q'},
{"show", required_argument, 0, 's'},
progname = argv[0];
- while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:Jmo:qST:v",
+ while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:JM:m:o:qST:v",
long_options, &option_index)) != -1) {
switch (opt) {
case 'a':
list_header_only++;
quiet++;
break;
- case 'm':
- do_migrate = 1;
- break;
case 'o':
outf = fopen_or_die(optarg, "w");
break;