From cf9610f9116d55c5a66ef9f1faecacabd93a9322 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 24 Aug 2026 08:46:03 -0700 Subject: Merge tag 'pinctrl-v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl Pull pin control updates from Linus Walleij: "Core changes: - Use the non-blocking mux_state_try_select() in the generic MUX pin control back-end - Free pin maps on pinctrl_generic_to_map() failure in the core helpers New hardware pin control: - Qualcomm Maili TLMM SoC, PMG1110 PMIC, and Eliza LPASS LPI TLMM SoC (this is for the low power audio, LPASS = Low Power Audio SubSystem portions) - Upboard support on top of the Intel pin controller - Apple T6030 and T6031 support (just compatible strings) - Samsung Exynos 8855 SoC - Mediatek MT6858 SoC - Rockchip RK3308B and RV1106 SoCs - Airoha EN7523 and AN7563 SoCs Improvements: - Qualcomm TLMM GPIOs are unconditionally marked as wakeup capable - Qualcomm improvements on top of the Qualcomm PDC (power domain controller) irqchip improvements from tglx:s tree - Qualcomm IPQ806x and IPQ9650 non-urgent pin grop fixups - The NPCM8xx driver has been put into shape fixing many pin and group definitions - Some non-urgent Tegra 264 pin assignments are fixed up - Some non-urgent fixups to Airoha AN7581 and AN7583 registers and pin assignments, missing features etc" * tag 'pinctrl-v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (130 commits) dt-bindings: pinctrl: Convert TI DA850 pupd to DT schema pinctrl: meson: sync some modify from A4 pinctrl: meson: a4: Add input enable pin configuration pinctrl: realtek: rtd1625: remove unused group name spdif_sel pinctrl: realtek: rtd1625: fix base_bit for VE4 GPIO 13 dt-bindings: pinctrl: microchip,pic32mzda-pinctrl: Convert to DT schema Revert "Merge branch 'ib-rsk7204' into devel" pinctrl: rockchip: Add RV1106 pinctrl support dt-bindings: pinctrl: rockchip: Add RV1106 compatible pinctrl: rockchip: Decode drive strength in the get function pinctrl: fix PINCTRL_GENERIC_MUX not always being selectable pinctrl: airoha: add support of an7563 SoC dt-bindings: pinctrl: airoha: add support of an7563 pin controller pinctrl: airoha: try to find chip scu node by phandle first pinctrl: airoha: add support of en7523 SoC dt-bindings: pinctrl: airoha: add support of en7523 pin controller pinctrl: airoha: an7583: add support for olt pinmux pinctrl: airoha: an7583: add support for pon_alt pinmux pinctrl: airoha: an7583: add support for npu_uart pinmux dt-bindings: pinctrl: airoha: an7583: add missed features ... --- lib/atomic64.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 lib/atomic64.c (limited to 'lib/atomic64.c') diff --git a/lib/atomic64.c b/lib/atomic64.c new file mode 100644 index 000000000..1a72bba36 --- /dev/null +++ b/lib/atomic64.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Generic implementation of 64-bit atomics using spinlocks, + * useful on processors that don't have 64-bit atomic instructions. + * + * Copyright © 2009 Paul Mackerras, IBM Corp. + */ +#include +#include +#include +#include +#include +#include + +/* + * We use a hashed array of spinlocks to provide exclusive access + * to each atomic64_t variable. Since this is expected to used on + * systems with small numbers of CPUs (<= 4 or so), we use a + * relatively small array of 16 spinlocks to avoid wasting too much + * memory on the spinlock array. + */ +#define NR_LOCKS 16 + +/* + * Ensure each lock is in a separate cacheline. + */ +static union { + arch_spinlock_t lock; + char pad[L1_CACHE_BYTES]; +} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp = { + [0 ... (NR_LOCKS - 1)] = { + .lock = __ARCH_SPIN_LOCK_UNLOCKED, + }, +}; + +static inline arch_spinlock_t *lock_addr(const atomic64_t *v) +{ + unsigned long addr = (unsigned long) v; + + addr >>= L1_CACHE_SHIFT; + addr ^= (addr >> 8) ^ (addr >> 16); + return &atomic64_lock[addr & (NR_LOCKS - 1)].lock; +} + +s64 generic_atomic64_read(const atomic64_t *v) +{ + unsigned long flags; + arch_spinlock_t *lock = lock_addr(v); + s64 val; + + local_irq_save(flags); + arch_spin_lock(lock); + val = v->counter; + arch_spin_unlock(lock); + local_irq_restore(flags); + return val; +} +EXPORT_SYMBOL(generic_atomic64_read); + +void generic_atomic64_set(atomic64_t *v, s64 i) +{ + unsigned long flags; + arch_spinlock_t *lock = lock_addr(v); + + local_irq_save(flags); + arch_spin_lock(lock); + v->counter = i; + arch_spin_unlock(lock); + local_irq_restore(flags); +} +EXPORT_SYMBOL(generic_atomic64_set); + +#define ATOMIC64_OP(op, c_op) \ +void generic_atomic64_##op(s64 a, atomic64_t *v) \ +{ \ + unsigned long flags; \ + arch_spinlock_t *lock = lock_addr(v); \ + \ + local_irq_save(flags); \ + arch_spin_lock(lock); \ + v->counter c_op a; \ + arch_spin_unlock(lock); \ + local_irq_restore(flags); \ +} \ +EXPORT_SYMBOL(generic_atomic64_##op); + +#define ATOMIC64_OP_RETURN(op, c_op) \ +s64 generic_atomic64_##op##_return(s64 a, atomic64_t *v) \ +{ \ + unsigned long flags; \ + arch_spinlock_t *lock = lock_addr(v); \ + s64 val; \ + \ + local_irq_save(flags); \ + arch_spin_lock(lock); \ + val = (v->counter c_op a); \ + arch_spin_unlock(lock); \ + local_irq_restore(flags); \ + return val; \ +} \ +EXPORT_SYMBOL(generic_atomic64_##op##_return); + +#define ATOMIC64_FETCH_OP(op, c_op) \ +s64 generic_atomic64_fetch_##op(s64 a, atomic64_t *v) \ +{ \ + unsigned long flags; \ + arch_spinlock_t *lock = lock_addr(v); \ + s64 val; \ + \ + local_irq_save(flags); \ + arch_spin_lock(lock); \ + val = v->counter; \ + v->counter c_op a; \ + arch_spin_unlock(lock); \ + local_irq_restore(flags); \ + return val; \ +} \ +EXPORT_SYMBOL(generic_atomic64_fetch_##op); + +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op, c_op) \ + ATOMIC64_OP_RETURN(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) + +ATOMIC64_OPS(add, +=) +ATOMIC64_OPS(sub, -=) + +#undef ATOMIC64_OPS +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) + +ATOMIC64_OPS(and, &=) +ATOMIC64_OPS(or, |=) +ATOMIC64_OPS(xor, ^=) + +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP +#undef ATOMIC64_OP + +s64 generic_atomic64_dec_if_positive(atomic64_t *v) +{ + unsigned long flags; + arch_spinlock_t *lock = lock_addr(v); + s64 val; + + local_irq_save(flags); + arch_spin_lock(lock); + val = v->counter - 1; + if (val >= 0) + v->counter = val; + arch_spin_unlock(lock); + local_irq_restore(flags); + return val; +} +EXPORT_SYMBOL(generic_atomic64_dec_if_positive); + +s64 generic_atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n) +{ + unsigned long flags; + arch_spinlock_t *lock = lock_addr(v); + s64 val; + + local_irq_save(flags); + arch_spin_lock(lock); + val = v->counter; + if (val == o) + v->counter = n; + arch_spin_unlock(lock); + local_irq_restore(flags); + return val; +} +EXPORT_SYMBOL(generic_atomic64_cmpxchg); + +s64 generic_atomic64_xchg(atomic64_t *v, s64 new) +{ + unsigned long flags; + arch_spinlock_t *lock = lock_addr(v); + s64 val; + + local_irq_save(flags); + arch_spin_lock(lock); + val = v->counter; + v->counter = new; + arch_spin_unlock(lock); + local_irq_restore(flags); + return val; +} +EXPORT_SYMBOL(generic_atomic64_xchg); + +s64 generic_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u) +{ + unsigned long flags; + arch_spinlock_t *lock = lock_addr(v); + s64 val; + + local_irq_save(flags); + arch_spin_lock(lock); + val = v->counter; + if (val != u) + v->counter += a; + arch_spin_unlock(lock); + local_irq_restore(flags); + + return val; +} +EXPORT_SYMBOL(generic_atomic64_fetch_add_unless); -- cgit v1.3.1