LoongArch: Add writecombine support for DMW-based ioremap()
authorHuacai Chen <chenhuacai@loongson.cn>
Sat, 20 Jul 2024 14:40:59 +0000 (22:40 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Sat, 20 Jul 2024 14:40:59 +0000 (22:40 +0800)
Currently, only TLB-based ioremap() support writecombine, so add the
counterpart for DMW-based ioremap() with help of DMW2. The base address
(WRITECOMBINE_BASE) is configured as 0xa000000000000000.

DMW3 is unused by kernel now, however firmware may leave garbage in them
and interfere kernel's address mapping. So clear it as necessary.

BTW, centralize the DMW configuration to macro SETUP_DMWINS.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/include/asm/addrspace.h
arch/loongarch/include/asm/io.h
arch/loongarch/include/asm/loongarch.h
arch/loongarch/include/asm/stackframe.h
arch/loongarch/kernel/head.S
arch/loongarch/power/suspend_asm.S
drivers/firmware/efi/libstub/loongarch.c

index 7bd47d65bf7a048fda5183ed6844d5dbc129b232..fe198b473f849062a349cf7cfdd20eb02bdc4d36 100644 (file)
@@ -37,6 +37,10 @@ extern unsigned long vm_map_base;
 #define UNCACHE_BASE           CSR_DMW0_BASE
 #endif
 
+#ifndef WRITECOMBINE_BASE
+#define WRITECOMBINE_BASE      CSR_DMW2_BASE
+#endif
+
 #define DMW_PABITS     48
 #define TO_PHYS_MASK   ((1ULL << DMW_PABITS) - 1)
 
index c2f9979b2979e5e92e791e3f8304975db9e929c9..5e95a60df1808aa294b791f12a8bfe3826059116 100644 (file)
@@ -25,10 +25,16 @@ extern void __init early_iounmap(void __iomem *addr, unsigned long size);
 static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
                                         unsigned long prot_val)
 {
-       if (prot_val & _CACHE_CC)
+       switch (prot_val & _CACHE_MASK) {
+       case _CACHE_CC:
                return (void __iomem *)(unsigned long)(CACHE_BASE + offset);
-       else
+       case _CACHE_SUC:
                return (void __iomem *)(unsigned long)(UNCACHE_BASE + offset);
+       case _CACHE_WUC:
+               return (void __iomem *)(unsigned long)(WRITECOMBINE_BASE + offset);
+       default:
+               return NULL;
+       }
 }
 
 #define ioremap(offset, size)          \
index eb09adda54b7c855eb56232b4442b79fadd09d46..c430df59537654c699f36e2d19d96e6e216d2d61 100644 (file)
 #define LOONGARCH_CSR_DMWIN2           0x182   /* 64 direct map win2: MEM */
 #define LOONGARCH_CSR_DMWIN3           0x183   /* 64 direct map win3: MEM */
 
-/* Direct Map window 0/1 */
+/* Direct Map window 0/1/2/3 */
 #define CSR_DMW0_PLV0          _CONST64_(1 << 0)
 #define CSR_DMW0_VSEG          _CONST64_(0x8000)
 #define CSR_DMW0_BASE          (CSR_DMW0_VSEG << DMW_PABITS)
 #define CSR_DMW1_BASE          (CSR_DMW1_VSEG << DMW_PABITS)
 #define CSR_DMW1_INIT          (CSR_DMW1_BASE | CSR_DMW1_MAT | CSR_DMW1_PLV0)
 
+#define CSR_DMW2_PLV0          _CONST64_(1 << 0)
+#define CSR_DMW2_MAT           _CONST64_(2 << 4)
+#define CSR_DMW2_VSEG          _CONST64_(0xa000)
+#define CSR_DMW2_BASE          (CSR_DMW2_VSEG << DMW_PABITS)
+#define CSR_DMW2_INIT          (CSR_DMW2_BASE | CSR_DMW2_MAT | CSR_DMW2_PLV0)
+
+#define CSR_DMW3_INIT          0x0
+
 /* Performance Counter registers */
 #define LOONGARCH_CSR_PERFCTRL0                0x200   /* 32 perf event 0 config */
 #define LOONGARCH_CSR_PERFCNTR0                0x201   /* 64 perf event 0 count value */
index d9eafd3ee3d1e848675f54f033163ecc66e07d72..66736837085b61cd7c6d62461e5beb237e982fec 100644 (file)
        cfi_restore \reg \offset \docfi
        .endm
 
+       .macro SETUP_DMWINS temp
+       li.d    \temp, CSR_DMW0_INIT    # WUC, PLV0, 0x8000 xxxx xxxx xxxx
+       csrwr   \temp, LOONGARCH_CSR_DMWIN0
+       li.d    \temp, CSR_DMW1_INIT    # CAC, PLV0, 0x9000 xxxx xxxx xxxx
+       csrwr   \temp, LOONGARCH_CSR_DMWIN1
+       li.d    \temp, CSR_DMW2_INIT    # WUC, PLV0, 0xa000 xxxx xxxx xxxx
+       csrwr   \temp, LOONGARCH_CSR_DMWIN2
+       li.d    \temp, CSR_DMW3_INIT    # 0x0, unused
+       csrwr   \temp, LOONGARCH_CSR_DMWIN3
+       .endm
+
 /* Jump to the runtime virtual address. */
        .macro JUMP_VIRT_ADDR temp1 temp2
        li.d    \temp1, CACHE_BASE
index 4677ea8fa8e98cad8b11b5ea89d7811500be738e..506a99a5bbc74f412084f7ea2ce275f72651c7c1 100644 (file)
@@ -44,11 +44,7 @@ SYM_DATA(kernel_fsize, .long _kernel_fsize);
 SYM_CODE_START(kernel_entry)                   # kernel entry point
 
        /* Config direct window and set PG */
-       li.d            t0, CSR_DMW0_INIT       # UC, PLV0, 0x8000 xxxx xxxx xxxx
-       csrwr           t0, LOONGARCH_CSR_DMWIN0
-       li.d            t0, CSR_DMW1_INIT       # CA, PLV0, 0x9000 xxxx xxxx xxxx
-       csrwr           t0, LOONGARCH_CSR_DMWIN1
-
+       SETUP_DMWINS    t0
        JUMP_VIRT_ADDR  t0, t1
 
        /* Enable PG */
@@ -124,11 +120,8 @@ SYM_CODE_END(kernel_entry)
  * function after setting up the stack and tp registers.
  */
 SYM_CODE_START(smpboot_entry)
-       li.d            t0, CSR_DMW0_INIT       # UC, PLV0
-       csrwr           t0, LOONGARCH_CSR_DMWIN0
-       li.d            t0, CSR_DMW1_INIT       # CA, PLV0
-       csrwr           t0, LOONGARCH_CSR_DMWIN1
 
+       SETUP_DMWINS    t0
        JUMP_VIRT_ADDR  t0, t1
 
 #ifdef CONFIG_PAGE_SIZE_4KB
index e2fc3b4e31f0019164f57de05c05324cc2bb391d..c28ad52b7bafba21fdaaae3e9aa42df36c0c0351 100644 (file)
@@ -73,11 +73,7 @@ SYM_FUNC_START(loongarch_suspend_enter)
         * Reload all of the registers and return.
         */
 SYM_INNER_LABEL(loongarch_wakeup_start, SYM_L_GLOBAL)
-       li.d            t0, CSR_DMW0_INIT       # UC, PLV0
-       csrwr           t0, LOONGARCH_CSR_DMWIN0
-       li.d            t0, CSR_DMW1_INIT       # CA, PLV0
-       csrwr           t0, LOONGARCH_CSR_DMWIN1
-
+       SETUP_DMWINS    t0
        JUMP_VIRT_ADDR  t0, t1
 
        /* Enable PG */
index d0ef93551c44f64affb5a152b277a8b0c4e827fb..3782d0a187d1f50d91a803ccd5a57094204314ca 100644 (file)
@@ -74,6 +74,8 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
        /* Config Direct Mapping */
        csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
        csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
+       csr_write64(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2);
+       csr_write64(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3);
 
        real_kernel_entry = (void *)kernel_entry_address(kernel_addr, image);