|
@@ -1,6 +1,41 @@
|
|
|
#include <linux/export.h>
|
|
|
#include <linux/types.h>
|
|
|
#include <linux/io.h>
|
|
|
+#include <linux/spinlock.h>
|
|
|
+
|
|
|
+static DEFINE_RAW_SPINLOCK(__io_lock);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Generic atomic MMIO modify.
|
|
|
+ *
|
|
|
+ * Allows thread-safe access to registers shared by unrelated subsystems.
|
|
|
+ * The access is protected by a single MMIO-wide lock.
|
|
|
+ */
|
|
|
+void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ u32 value;
|
|
|
+
|
|
|
+ raw_spin_lock_irqsave(&__io_lock, flags);
|
|
|
+ value = readl_relaxed(reg) & ~mask;
|
|
|
+ value |= (set & mask);
|
|
|
+ writel_relaxed(value, reg);
|
|
|
+ raw_spin_unlock_irqrestore(&__io_lock, flags);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(atomic_io_modify_relaxed);
|
|
|
+
|
|
|
+void atomic_io_modify(void __iomem *reg, u32 mask, u32 set)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ u32 value;
|
|
|
+
|
|
|
+ raw_spin_lock_irqsave(&__io_lock, flags);
|
|
|
+ value = readl_relaxed(reg) & ~mask;
|
|
|
+ value |= (set & mask);
|
|
|
+ writel(value, reg);
|
|
|
+ raw_spin_unlock_irqrestore(&__io_lock, flags);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(atomic_io_modify);
|
|
|
|
|
|
/*
|
|
|
* Copy data from IO memory space to "real" memory space.
|