|
@@ -665,3 +665,176 @@ do { \
|
|
|
: "r" (val), "i" (counter)); \
|
|
|
} while (0)
|
|
|
|
|
|
+
|
|
|
+/*
|
|
|
+ * Macros to access the system control coprocessor
|
|
|
+ */
|
|
|
+
|
|
|
+#define __read_32bit_c0_register(source, sel) \
|
|
|
+({ int __res; \
|
|
|
+ if (sel == 0) \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ "mfc0\t%0, " #source "\n\t" \
|
|
|
+ : "=r" (__res)); \
|
|
|
+ else \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips32\n\t" \
|
|
|
+ "mfc0\t%0, " #source ", " #sel "\n\t" \
|
|
|
+ ".set\tmips0\n\t" \
|
|
|
+ : "=r" (__res)); \
|
|
|
+ __res; \
|
|
|
+})
|
|
|
+
|
|
|
+#define __read_64bit_c0_register(source, sel) \
|
|
|
+({ unsigned long long __res; \
|
|
|
+ if (sizeof(unsigned long) == 4) \
|
|
|
+ __res = __read_64bit_c0_split(source, sel); \
|
|
|
+ else if (sel == 0) \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips3\n\t" \
|
|
|
+ "dmfc0\t%0, " #source "\n\t" \
|
|
|
+ ".set\tmips0" \
|
|
|
+ : "=r" (__res)); \
|
|
|
+ else \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips64\n\t" \
|
|
|
+ "dmfc0\t%0, " #source ", " #sel "\n\t" \
|
|
|
+ ".set\tmips0" \
|
|
|
+ : "=r" (__res)); \
|
|
|
+ __res; \
|
|
|
+})
|
|
|
+
|
|
|
+#define __write_32bit_c0_register(register, sel, value) \
|
|
|
+do { \
|
|
|
+ if (sel == 0) \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ "mtc0\t%z0, " #register "\n\t" \
|
|
|
+ : : "Jr" ((unsigned int)(value))); \
|
|
|
+ else \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips32\n\t" \
|
|
|
+ "mtc0\t%z0, " #register ", " #sel "\n\t" \
|
|
|
+ ".set\tmips0" \
|
|
|
+ : : "Jr" ((unsigned int)(value))); \
|
|
|
+} while (0)
|
|
|
+
|
|
|
+#define __write_64bit_c0_register(register, sel, value) \
|
|
|
+do { \
|
|
|
+ if (sizeof(unsigned long) == 4) \
|
|
|
+ __write_64bit_c0_split(register, sel, value); \
|
|
|
+ else if (sel == 0) \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips3\n\t" \
|
|
|
+ "dmtc0\t%z0, " #register "\n\t" \
|
|
|
+ ".set\tmips0" \
|
|
|
+ : : "Jr" (value)); \
|
|
|
+ else \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips64\n\t" \
|
|
|
+ "dmtc0\t%z0, " #register ", " #sel "\n\t" \
|
|
|
+ ".set\tmips0" \
|
|
|
+ : : "Jr" (value)); \
|
|
|
+} while (0)
|
|
|
+
|
|
|
+#define __read_ulong_c0_register(reg, sel) \
|
|
|
+ ((sizeof(unsigned long) == 4) ? \
|
|
|
+ (unsigned long) __read_32bit_c0_register(reg, sel) : \
|
|
|
+ (unsigned long) __read_64bit_c0_register(reg, sel))
|
|
|
+
|
|
|
+#define __write_ulong_c0_register(reg, sel, val) \
|
|
|
+do { \
|
|
|
+ if (sizeof(unsigned long) == 4) \
|
|
|
+ __write_32bit_c0_register(reg, sel, val); \
|
|
|
+ else \
|
|
|
+ __write_64bit_c0_register(reg, sel, val); \
|
|
|
+} while (0)
|
|
|
+
|
|
|
+/*
|
|
|
+ * On RM7000/RM9000 these are uses to access cop0 set 1 registers
|
|
|
+ */
|
|
|
+#define __read_32bit_c0_ctrl_register(source) \
|
|
|
+({ int __res; \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ "cfc0\t%0, " #source "\n\t" \
|
|
|
+ : "=r" (__res)); \
|
|
|
+ __res; \
|
|
|
+})
|
|
|
+
|
|
|
+#define __write_32bit_c0_ctrl_register(register, value) \
|
|
|
+do { \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ "ctc0\t%z0, " #register "\n\t" \
|
|
|
+ : : "Jr" ((unsigned int)(value))); \
|
|
|
+} while (0)
|
|
|
+
|
|
|
+/*
|
|
|
+ * These versions are only needed for systems with more than 38 bits of
|
|
|
+ * physical address space running the 32-bit kernel. That's none atm :-)
|
|
|
+ */
|
|
|
+#define __read_64bit_c0_split(source, sel) \
|
|
|
+({ \
|
|
|
+ unsigned long long __val; \
|
|
|
+ unsigned long __flags; \
|
|
|
+ \
|
|
|
+ local_irq_save(__flags); \
|
|
|
+ if (sel == 0) \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips64\n\t" \
|
|
|
+ "dmfc0\t%M0, " #source "\n\t" \
|
|
|
+ "dsll\t%L0, %M0, 32\n\t" \
|
|
|
+ "dsra\t%M0, %M0, 32\n\t" \
|
|
|
+ "dsra\t%L0, %L0, 32\n\t" \
|
|
|
+ ".set\tmips0" \
|
|
|
+ : "=r" (__val)); \
|
|
|
+ else \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips64\n\t" \
|
|
|
+ "dmfc0\t%M0, " #source ", " #sel "\n\t" \
|
|
|
+ "dsll\t%L0, %M0, 32\n\t" \
|
|
|
+ "dsra\t%M0, %M0, 32\n\t" \
|
|
|
+ "dsra\t%L0, %L0, 32\n\t" \
|
|
|
+ ".set\tmips0" \
|
|
|
+ : "=r" (__val)); \
|
|
|
+ local_irq_restore(__flags); \
|
|
|
+ \
|
|
|
+ __val; \
|
|
|
+})
|
|
|
+
|
|
|
+#define __write_64bit_c0_split(source, sel, val) \
|
|
|
+do { \
|
|
|
+ unsigned long __flags; \
|
|
|
+ \
|
|
|
+ local_irq_save(__flags); \
|
|
|
+ if (sel == 0) \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips64\n\t" \
|
|
|
+ "dsll\t%L0, %L0, 32\n\t" \
|
|
|
+ "dsrl\t%L0, %L0, 32\n\t" \
|
|
|
+ "dsll\t%M0, %M0, 32\n\t" \
|
|
|
+ "or\t%L0, %L0, %M0\n\t" \
|
|
|
+ "dmtc0\t%L0, " #source "\n\t" \
|
|
|
+ ".set\tmips0" \
|
|
|
+ : : "r" (val)); \
|
|
|
+ else \
|
|
|
+ __asm__ __volatile__( \
|
|
|
+ ".set\tmips64\n\t" \
|
|
|
+ "dsll\t%L0, %L0, 32\n\t" \
|
|
|
+ "dsrl\t%L0, %L0, 32\n\t" \
|
|
|
+ "dsll\t%M0, %M0, 32\n\t" \
|
|
|
+ "or\t%L0, %L0, %M0\n\t" \
|
|
|
+ "dmtc0\t%L0, " #source ", " #sel "\n\t" \
|
|
|
+ ".set\tmips0" \
|
|
|
+ : : "r" (val)); \
|
|
|
+ local_irq_restore(__flags); \
|
|
|
+} while (0)
|
|
|
+
|
|
|
+#define read_c0_index() __read_32bit_c0_register($0, 0)
|
|
|
+#define write_c0_index(val) __write_32bit_c0_register($0, 0, val)
|
|
|
+
|
|
|
+#define read_c0_random() __read_32bit_c0_register($1, 0)
|
|
|
+#define write_c0_random(val) __write_32bit_c0_register($1, 0, val)
|
|
|
+
|
|
|
+#define read_c0_entrylo0() __read_ulong_c0_register($2, 0)
|
|
|
+#define write_c0_entrylo0(val) __write_ulong_c0_register($2, 0, val)
|
|
|
+
|
|
|
+#define read_c0_entrylo1() __read_ulong_c0_register($3, 0)
|