]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
LoongArch: Make WriteCombine configurable for ioremap()
authorHuacai Chen <chenhuacai@loongson.cn>
Tue, 18 Apr 2023 11:38:58 +0000 (19:38 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Apr 2023 12:30:07 +0000 (14:30 +0200)
commit 16c52e503043aed1e2a2ce38d9249de5936c1f6b upstream.

LoongArch maintains cache coherency in hardware, but when paired with
LS7A chipsets the WUC attribute (Weak-ordered UnCached, which is similar
to WriteCombine) is out of the scope of cache coherency machanism for
PCIe devices (this is a PCIe protocol violation, which may be fixed in
newer chipsets).

This means WUC can only used for write-only memory regions now, so this
option is disabled by default, making WUC silently fallback to SUC for
ioremap(). You can enable this option if the kernel is ensured to run on
hardware without this bug.

Kernel parameter writecombine=on/off can be used to override the Kconfig
option.

Cc: stable@vger.kernel.org
Suggested-by: WANG Xuerui <kernel@xen0n.name>
Reviewed-by: WANG Xuerui <kernel@xen0n.name>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/admin-guide/kernel-parameters.rst
Documentation/admin-guide/kernel-parameters.txt
arch/loongarch/Kconfig
arch/loongarch/include/asm/io.h
arch/loongarch/kernel/setup.c

index 959f73a327126f2de649fa1e25eeacdade0aacc1..426440f5d79f2952da98a990d839dc38dc82d3ed 100644 (file)
@@ -128,6 +128,7 @@ parameter is applicable::
        KVM     Kernel Virtual Machine support is enabled.
        LIBATA  Libata driver is enabled
        LP      Printer support is enabled.
+       LOONGARCH LoongArch architecture is enabled.
        LOOP    Loopback device support is enabled.
        M68k    M68k architecture is enabled.
                        These options have more detailed description inside of
index 6cfa6e3996cf75ee6bb1e8b399daa4d5701ab92b..8cf1595545ac263bad5ee68e488aee60a8578a13 100644 (file)
                        When enabled, memory and cache locality will be
                        impacted.
 
+       writecombine=   [LOONGARCH] Control the MAT (Memory Access Type) of
+                       ioremap_wc().
+
+                       on   - Enable writecombine, use WUC for ioremap_wc()
+                       off  - Disable writecombine, use SUC for ioremap_wc()
+
        x2apic_phys     [X86-64,APIC] Use x2apic physical mode instead of
                        default x2apic cluster mode on platforms
                        supporting x2apic.
index 0c1c6063cc66175a4d448f38d4a1b1974b506c71..e349cc9e3c228e7506aa74e8db025a5ae1f2384c 100644 (file)
@@ -442,6 +442,22 @@ config ARCH_IOREMAP
          protection support. However, you can enable LoongArch DMW-based
          ioremap() for better performance.
 
+config ARCH_WRITECOMBINE
+       bool "Enable WriteCombine (WUC) for ioremap()"
+       help
+         LoongArch maintains cache coherency in hardware, but when paired
+         with LS7A chipsets the WUC attribute (Weak-ordered UnCached, which
+         is similar to WriteCombine) is out of the scope of cache coherency
+         machanism for PCIe devices (this is a PCIe protocol violation, which
+         may be fixed in newer chipsets).
+
+         This means WUC can only used for write-only memory regions now, so
+         this option is disabled by default, making WUC silently fallback to
+         SUC for ioremap(). You can enable this option if the kernel is ensured
+         to run on hardware without this bug.
+
+         You can override this setting via writecombine=on/off boot parameter.
+
 config ARCH_STRICT_ALIGN
        bool "Enable -mstrict-align to prevent unaligned accesses" if EXPERT
        default y
index 402a7d9e3a53eafed41c4170de5627f673d142f4..545e2708fbf7042f6a61f29c1423be1f11de7a7e 100644 (file)
@@ -54,8 +54,10 @@ static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
  * @offset:    bus address of the memory
  * @size:      size of the resource to map
  */
+extern pgprot_t pgprot_wc;
+
 #define ioremap_wc(offset, size)       \
-       ioremap_prot((offset), (size), pgprot_val(PAGE_KERNEL_WUC))
+       ioremap_prot((offset), (size), pgprot_val(pgprot_wc))
 
 #define ioremap_cache(offset, size)    \
        ioremap_prot((offset), (size), pgprot_val(PAGE_KERNEL))
index 4344502c0b31780677a84cd5bb117004336df712..7ac1aecc76870930fb4c72f336a4a18f81ff4928 100644 (file)
@@ -160,6 +160,27 @@ static void __init smbios_parse(void)
        dmi_walk(find_tokens, NULL);
 }
 
+#ifdef CONFIG_ARCH_WRITECOMBINE
+pgprot_t pgprot_wc = PAGE_KERNEL_WUC;
+#else
+pgprot_t pgprot_wc = PAGE_KERNEL_SUC;
+#endif
+
+EXPORT_SYMBOL(pgprot_wc);
+
+static int __init setup_writecombine(char *p)
+{
+       if (!strcmp(p, "on"))
+               pgprot_wc = PAGE_KERNEL_WUC;
+       else if (!strcmp(p, "off"))
+               pgprot_wc = PAGE_KERNEL_SUC;
+       else
+               pr_warn("Unknown writecombine setting \"%s\".\n", p);
+
+       return 0;
+}
+early_param("writecombine", setup_writecombine);
+
 static int usermem __initdata;
 
 static int __init early_parse_mem(char *p)