From 35d1f0bc182c4353bd5be0cbe7e3c20b0b95efb2 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Tue, 9 Apr 2024 19:45:57 +0800 Subject: [PATCH 01/19] anolis: sw64: acpi: disable ACPI for xuelang ANBZ: #4688 Enabling ACPI on xuelang platform requires the latest firmware, otherwise kernel may fail to boot. To avoid potential risks, disable ACPI for xuelang platform. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/acpi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/sw_64/kernel/acpi.c b/arch/sw_64/kernel/acpi.c index 7a423c917d43..0aa21e4d98a6 100644 --- a/arch/sw_64/kernel/acpi.c +++ b/arch/sw_64/kernel/acpi.c @@ -358,6 +358,12 @@ static int __init acpi_process_madt_sw_cintc(void) void __init acpi_boot_table_init(void) { + if (IS_ENABLED(CONFIG_SUBARCH_C3B)) { + pr_info(PREFIX "Current platform does not support ACPI\n"); + disable_acpi(); + return; + } + /** * ACPI is disabled by default. * ACPI is only enabled when firmware passes ACPI table @@ -372,7 +378,6 @@ void __init acpi_boot_table_init(void) if (acpi_disabled) return; - pr_warn("Currently, ACPI is an experimental feature!\n"); if (acpi_table_init()) { pr_err("Failed to init ACPI tables\n"); disable_acpi(); -- Gitee From 40db1e8627ed44f3cce299efd93b474f42857f14 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 3 Apr 2024 09:30:21 +0800 Subject: [PATCH 02/19] anolis: sw64: get mclk and external clk from firmware ANBZ: #4688 Starting from junzhang, kernel will not directly access Motherboard Configuration Tables to get mclk and external clk. Instead, kernel get mclk and external clk from firmware. This commit will not break backward compatibility. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/setup.h | 10 +++++- arch/sw_64/kernel/setup.c | 61 +++++++++++++++++++++++++++++--- drivers/clocksource/timer-sw64.c | 7 +++- 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/arch/sw_64/include/asm/setup.h b/arch/sw_64/include/asm/setup.h index a22e79095fb4..0a2edf9af3ca 100644 --- a/arch/sw_64/include/asm/setup.h +++ b/arch/sw_64/include/asm/setup.h @@ -38,7 +38,13 @@ #define INITRD_START_OFF (0x10000UL - 0xA100UL) #define INITRD_SIZE_OFF (0x10000UL - 0xA108UL) -/* Motherboard Configuration Tables */ +/** + * Motherboard Configuration Tables + * + * Starting from junzhang, we will not directly access Motherboard + * Configuration Tables in kernel. These macros and related code can + * be removed when kernel no longer support C3B(xuelang). + */ #define MB_CONFIG_START 0x908000 #define MB_MCLK (MB_CONFIG_START + 0x1) #define MB_EXTCLK (MB_CONFIG_START + 0x11) @@ -46,6 +52,8 @@ #ifndef __ASSEMBLY__ #include extern struct boot_params *sunway_boot_params; +extern u64 sunway_mclk_hz; +extern u64 sunway_extclk_hz; #endif #endif /* _ASM_SW64_SETUP_H */ diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index f427ffefda3b..06540e4d3095 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -24,6 +24,7 @@ #endif #include #include +#include #include #include #include @@ -135,6 +136,9 @@ EXPORT_SYMBOL(sunway_boot_magic); unsigned long sunway_dtb_address; EXPORT_SYMBOL(sunway_dtb_address); +u64 sunway_mclk_hz; +u64 sunway_extclk_hz; + /* * The format of "screen_info" is strange, and due to early * i386-setup code. This is just enough to make the console @@ -557,6 +561,34 @@ static bool __init arch_dtb_verify(void *dt_virt, bool from_firmware) return true; } +static void early_parse_fdt_property(const void *fdt, const char *path, + const char *prop_name, u64 *property, int size) +{ + int node, prop_len; + const __be32 *prop; + + if (!path || !prop_name) + return; + + node = fdt_path_offset(fdt, path); + if (node < 0) { + pr_err("Failed to get node [%s]\n", path); + return; + } + + prop = fdt_getprop(initial_boot_params, node, prop_name, &prop_len); + if (!prop) { + pr_err("Failed to get property [%s]\n", prop_name); + return; + } + + if (prop_len != size) + pr_warn("Expect [%s] %d bytes, but %d bytes\n", + prop_name, size, prop_len); + + *property = of_read_number(prop, size / 4); +} + static void __init setup_firmware_fdt(void) { void *dt_virt; @@ -587,6 +619,18 @@ static void __init setup_firmware_fdt(void) cpu_relax(); } + if (sunway_boot_magic == 0xDEED2024UL) { + /* Parse MCLK(Hz) from firmware DTB */ + early_parse_fdt_property(dt_virt, "/soc/clocks/mclk", + "clock-frequency", &sunway_mclk_hz, sizeof(u32)); + pr_info("MCLK: %llu Hz\n", sunway_mclk_hz); + + /* Parse EXTCLK(Hz) from firmware DTB */ + early_parse_fdt_property(dt_virt, "/soc/clocks/extclk", + "clock-frequency", &sunway_extclk_hz, sizeof(u32)); + pr_info("EXTCLK: %llu Hz\n", sunway_extclk_hz); + } + name = of_flat_dt_get_machine_name(); if (name) pr_info("DTB(from firmware): Machine model: %s\n", name); @@ -1030,16 +1074,23 @@ arch_initcall(debugfs_sw64); static int __init debugfs_mclk_init(void) { - static u64 mclk; + struct dentry *dir = sw64_debugfs_dir; + static u64 mclk_mhz, mclk_hz; - if (!sw64_debugfs_dir) + if (!dir) return -ENODEV; - mclk = *((unsigned char *)__va(MB_MCLK)); - debugfs_create_u64("mclk", 0644, sw64_debugfs_dir, &mclk); + if (sunway_boot_magic != 0xDEED2024UL) { + mclk_mhz = *((unsigned char *)__va(MB_MCLK)); + mclk_hz = mclk_mhz * 1000000; + debugfs_create_u64("mclk", 0644, dir, &mclk_mhz); + debugfs_create_u64("mclk_hz", 0644, dir, &mclk_hz); + } else { + mclk_hz = sunway_mclk_hz; + debugfs_create_u64("mclk_hz", 0644, dir, &mclk_hz); + } return 0; - } late_initcall(debugfs_mclk_init); #endif diff --git a/drivers/clocksource/timer-sw64.c b/drivers/clocksource/timer-sw64.c index 2b1670426b8a..72a5b05d496a 100644 --- a/drivers/clocksource/timer-sw64.c +++ b/drivers/clocksource/timer-sw64.c @@ -47,7 +47,12 @@ early_param("mclk_khz", setup_mclk); void __init sw64_setup_clocksource(void) { - unsigned long mclk_khz = *((unsigned char *)__va(MB_MCLK)) * 1000; + unsigned long mclk_khz; + + if (sunway_mclk_hz) + mclk_khz = sunway_mclk_hz / 1000; + else + mclk_khz = *((unsigned char *)__va(MB_MCLK)) * 1000; if (override_mclk_khz) { mclk_khz = override_mclk_khz; -- Gitee From a4c8c908ab1eb72da92b01180a11fc54159394ee Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 10 Apr 2024 10:29:28 +0800 Subject: [PATCH 03/19] anolis: sw64: pci: adjust the maximum number of RC per node ANBZ: #4688 Adjust the maximum number of RC per node from 6 to 12, since the upcoming hardware platform supports 12 RC per node. This commit also update the OEM table ID of MCFG. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/pci.h | 3 ++ arch/sw_64/include/asm/uncore_io_junzhang.h | 3 -- arch/sw_64/include/asm/uncore_io_xuelang.h | 3 -- arch/sw_64/pci/pci-legacy.c | 6 +-- drivers/acpi/pci_mcfg.c | 46 ++++++++++----------- drivers/pci/controller/pci-sunway.c | 13 ++++-- 6 files changed, 39 insertions(+), 35 deletions(-) diff --git a/arch/sw_64/include/asm/pci.h b/arch/sw_64/include/asm/pci.h index 8851c0779647..f3d8a25190f0 100644 --- a/arch/sw_64/include/asm/pci.h +++ b/arch/sw_64/include/asm/pci.h @@ -110,6 +110,7 @@ extern int sw64_pcie_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); extern void pci_mark_rc_linkup(unsigned long node, unsigned long index); +extern void pci_clear_rc_linkup(unsigned long node, unsigned long index); extern int pci_get_rc_linkup(unsigned long node, unsigned long index); #ifdef CONFIG_PCI_DOMAINS @@ -174,4 +175,6 @@ extern int chip_pcie_configure(struct pci_controller *hose); #define PCITODMA_OFFSET 0x0 /*0 offset*/ +#define MAX_NR_RCS_PER_NODE 12 + #endif /* _ASM_SW64_PCI_H */ diff --git a/arch/sw_64/include/asm/uncore_io_junzhang.h b/arch/sw_64/include/asm/uncore_io_junzhang.h index c0f759bbe740..2f745fe35365 100644 --- a/arch/sw_64/include/asm/uncore_io_junzhang.h +++ b/arch/sw_64/include/asm/uncore_io_junzhang.h @@ -48,9 +48,6 @@ #define SW64_PCI0_BUS 0 #define PCI0_BUS SW64_PCI0_BUS -#define MAX_NR_NODES 0x2 -#define MAX_NR_RCS 0x6 - #define SPBU_BASE (0x3UL << 36) #define INTPU_BASE (0x3aUL << 32) #define IIC0_BASE (0x31UL << 32) diff --git a/arch/sw_64/include/asm/uncore_io_xuelang.h b/arch/sw_64/include/asm/uncore_io_xuelang.h index aeaadec5be16..695ce68dded9 100644 --- a/arch/sw_64/include/asm/uncore_io_xuelang.h +++ b/arch/sw_64/include/asm/uncore_io_xuelang.h @@ -47,9 +47,6 @@ #define SW64_PCI0_BUS 0 #define PCI0_BUS SW64_PCI0_BUS -#define MAX_NR_NODES 0x2 -#define MAX_NR_RCS 0x6 - #define MCU_BASE (0x3UL << 36) #define CAB0_BASE (0x10UL << 32) #define INTPU_BASE (0x2aUL << 32) diff --git a/arch/sw_64/pci/pci-legacy.c b/arch/sw_64/pci/pci-legacy.c index e0d515540e01..228f58031626 100644 --- a/arch/sw_64/pci/pci-legacy.c +++ b/arch/sw_64/pci/pci-legacy.c @@ -244,7 +244,7 @@ static bool __init is_any_rc_linkup_one_node(unsigned long node) { int i; - for (i = 0; i < 8; ++i) { + for (i = 0; i < MAX_NR_RCS_PER_NODE; ++i) { if (pci_get_rc_linkup(node, i)) return true; } @@ -279,14 +279,14 @@ void __init sw64_init_arch(void) printk("PCIe is disabled on node %ld\n", node); continue; } - for (i = 0; i < MAX_NR_RCS; i++) { + for (i = 0; i < MAX_NR_RCS_PER_NODE; i++) { if ((rc_enable >> i) & 0x1) sw64_init_host(node, i); } if (is_any_rc_linkup_one_node(node)) { memset(msg, 0, 64); sprintf(msg, "Node %ld: RC [ ", node); - for (i = 0; i < MAX_NR_RCS; i++) { + for (i = 0; i < MAX_NR_RCS_PER_NODE; i++) { if (pci_get_rc_linkup(node, i)) { memset(id, 0, 8); sprintf(id, "%d ", i); diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index 7be2da09de2a..b45ab4f89bf1 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -176,29 +176,29 @@ static struct mcfg_fixup mcfg_quirks[] = { #endif /* LOONGARCH */ #ifdef CONFIG_SW64 -#define _SW64_ECAM_QUIRK(rev, seg) \ - { "SUNWAY", "MCFG", rev, seg, MCFG_BUS_ANY, &sw64_pci_ecam_ops } -#define SW64_ECAM_QUIRK(rev, node) _SW64_ECAM_QUIRK(rev, node * 8 + 0),\ - _SW64_ECAM_QUIRK(rev, node * 8 + 1),\ - _SW64_ECAM_QUIRK(rev, node * 8 + 2),\ - _SW64_ECAM_QUIRK(rev, node * 8 + 3),\ - _SW64_ECAM_QUIRK(rev, node * 8 + 4),\ - _SW64_ECAM_QUIRK(rev, node * 8 + 5),\ - _SW64_ECAM_QUIRK(rev, node * 8 + 6),\ - _SW64_ECAM_QUIRK(rev, node * 8 + 7) - - /** - * According to the address space of sw64, up to 8 nodes supported - * with a maximum of 8 pcie controllers per node - */ - SW64_ECAM_QUIRK(1, 0x00), - SW64_ECAM_QUIRK(1, 0x01), - SW64_ECAM_QUIRK(1, 0x02), - SW64_ECAM_QUIRK(1, 0x03), - SW64_ECAM_QUIRK(1, 0x04), - SW64_ECAM_QUIRK(1, 0x05), - SW64_ECAM_QUIRK(1, 0x06), - SW64_ECAM_QUIRK(1, 0x07), +#define SW64_ECAM_QUIRK(table_id, rev, node, ops) \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 0), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 1), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 2), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 3), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 4), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 5), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 6), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 7), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 8), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 9), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 10), MCFG_BUS_ANY, ops }, \ + { "SUNWAY", table_id, rev, ((node) * MAX_NR_RCS_PER_NODE + 11), MCFG_BUS_ANY, ops } \ + + /* up to 8 nodes for SW64 series */ + SW64_ECAM_QUIRK("SUNWAY ", 1, 0x00, &sw64_pci_ecam_ops), + SW64_ECAM_QUIRK("SUNWAY ", 1, 0x01, &sw64_pci_ecam_ops), + SW64_ECAM_QUIRK("SUNWAY ", 1, 0x02, &sw64_pci_ecam_ops), + SW64_ECAM_QUIRK("SUNWAY ", 1, 0x03, &sw64_pci_ecam_ops), + SW64_ECAM_QUIRK("SUNWAY ", 1, 0x04, &sw64_pci_ecam_ops), + SW64_ECAM_QUIRK("SUNWAY ", 1, 0x05, &sw64_pci_ecam_ops), + SW64_ECAM_QUIRK("SUNWAY ", 1, 0x06, &sw64_pci_ecam_ops), + SW64_ECAM_QUIRK("SUNWAY ", 1, 0x07, &sw64_pci_ecam_ops), #endif /* SW64 */ }; diff --git a/drivers/pci/controller/pci-sunway.c b/drivers/pci/controller/pci-sunway.c index 11df69dae968..f84f61fae96b 100644 --- a/drivers/pci/controller/pci-sunway.c +++ b/drivers/pci/controller/pci-sunway.c @@ -346,18 +346,25 @@ void __init setup_chip_pci_ops(void) sw64_chip_init->pci_init = chip_pci_init_ops; } -static unsigned long rc_linkup; static struct pci_controller *head, **tail = &head; +static DECLARE_BITMAP(rc_linkup, (MAX_NUMNODES * MAX_NR_RCS_PER_NODE)); + void pci_mark_rc_linkup(unsigned long node, unsigned long index) { - set_bit(node * 8 + index, &rc_linkup); + set_bit(node * MAX_NR_RCS_PER_NODE + index, rc_linkup); } EXPORT_SYMBOL(pci_mark_rc_linkup); +void pci_clear_rc_linkup(unsigned long node, unsigned long index) +{ + clear_bit(node * MAX_NR_RCS_PER_NODE + index, rc_linkup); +} +EXPORT_SYMBOL(pci_clear_rc_linkup); + int pci_get_rc_linkup(unsigned long node, unsigned long index) { - return test_bit(node * 8 + index, &rc_linkup); + return test_bit(node * MAX_NR_RCS_PER_NODE + index, rc_linkup); } EXPORT_SYMBOL(pci_get_rc_linkup); -- Gitee From a45960f51d80c7e544fe8270bc93829b04ff8043 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Fri, 12 Apr 2024 09:15:58 +0800 Subject: [PATCH 04/19] anolis: sw64: fix compile error of efi.systab ANBZ: #4688 The systab field has been removed from struct efi. To get systab, we can parse it from the DTB provided by firmware. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/platform.h | 2 ++ arch/sw_64/kernel/machine_kexec.c | 7 ++++--- arch/sw_64/kernel/setup.c | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/sw_64/include/asm/platform.h b/arch/sw_64/include/asm/platform.h index 7374f2087f90..4f93d9532f9a 100644 --- a/arch/sw_64/include/asm/platform.h +++ b/arch/sw_64/include/asm/platform.h @@ -30,5 +30,7 @@ extern void (*pm_halt)(void); extern int i2c_set_adapter(void); extern void cpld_write(uint8_t slave_addr, uint8_t reg, uint8_t data); extern void fix_jm585_reset(void); +extern void early_parse_fdt_property(const void *fdt, const char *path, + const char *prop_name, u64 *property, int size); #endif /* _ASM_SW64_PLATFORM_H */ diff --git a/arch/sw_64/kernel/machine_kexec.c b/arch/sw_64/kernel/machine_kexec.c index d6758d48dc26..dc1b2b4f5949 100644 --- a/arch/sw_64/kernel/machine_kexec.c +++ b/arch/sw_64/kernel/machine_kexec.c @@ -289,11 +289,10 @@ static void update_boot_params(void) params.dtb_start = (unsigned long)arch_kexec_alloc_and_setup_fdt( params.initrd_start, params.initrd_size, (const char *)params.cmdline); - /* update dtb base address */ - sunway_dtb_address = params.dtb_start; #ifdef CONFIG_EFI - params.efi_systab = virt_to_phys((void *)efi.systab); + early_parse_fdt_property((void *)sunway_dtb_address, "/chosen", + "linux,uefi-system-table", ¶ms.efi_systab, sizeof(u64)); params.efi_memmap = efi.memmap.phys_map; params.efi_memmap_size = efi.memmap.map_end - efi.memmap.map; params.efi_memdesc_size = efi.memmap.desc_size; @@ -312,6 +311,8 @@ static void update_boot_params(void) if (update_efi_properties(¶ms)) pr_err("Note: failed to update efi properties\n"); #endif + /* update dtb base address */ + sunway_dtb_address = params.dtb_start; } pr_info("initrd_start = %#llx, initrd_size = %#llx\n" diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index 06540e4d3095..ede5473c384d 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -561,7 +561,7 @@ static bool __init arch_dtb_verify(void *dt_virt, bool from_firmware) return true; } -static void early_parse_fdt_property(const void *fdt, const char *path, +void early_parse_fdt_property(const void *fdt, const char *path, const char *prop_name, u64 *property, int size) { int node, prop_len; -- Gitee From 3dc7dc1914a84fa9fb0328e41c439673c7f1bbf1 Mon Sep 17 00:00:00 2001 From: Wang Yuanheng Date: Mon, 8 Apr 2024 18:36:14 +0800 Subject: [PATCH 05/19] anolis: sw64: kvm: fix size of struct kvm_regs for C3B ANBZ: #4688 The size of struct kvm_regs passed by Qemu is fixed and checked in kernel. Since Qemu has extended the struct kvm_regs, this patch adds some padding bytes to ensure that the size of struct kvm_regs is the same on both C3B and C4. Signed-off-by: Wang Yuanheng Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/kvm.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/sw_64/include/asm/kvm.h b/arch/sw_64/include/asm/kvm.h index 127d5b910d74..9242d58352f0 100644 --- a/arch/sw_64/include/asm/kvm.h +++ b/arch/sw_64/include/asm/kvm.h @@ -49,7 +49,7 @@ struct kvm_regs { unsigned long r27; unsigned long r28; - unsigned long __padding0; + unsigned long reserved; unsigned long fpcr; unsigned long fp[124]; @@ -60,6 +60,7 @@ struct kvm_regs { unsigned long r16; unsigned long r17; unsigned long r18; + unsigned long __padding[6]; }; #elif CONFIG_SUBARCH_C4 -- Gitee From f214843f23e4c32bf655c13a488ae6dec981b419 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Tue, 9 Apr 2024 17:07:31 +0800 Subject: [PATCH 06/19] anolis: sw64: define cpu_relax() as imb() ANBZ: #4688 Use imb() to implement cpu_relax() which pause the cpu for a very short period of time until all instructions in pipelines are committed. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/processor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/include/asm/processor.h b/arch/sw_64/include/asm/processor.h index 26394854071f..baed1c70bcfc 100644 --- a/arch/sw_64/include/asm/processor.h +++ b/arch/sw_64/include/asm/processor.h @@ -67,7 +67,7 @@ unsigned long get_wchan(struct task_struct *p); #define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[30]) -#define cpu_relax() barrier() +#define cpu_relax() imemb() #define ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCHW -- Gitee From dc760a9070f321774106552ab79ac14e3da89f7a Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Thu, 11 Apr 2024 18:31:08 +0800 Subject: [PATCH 07/19] anolis: sw64: add -fno-sw-unalign-byte to cflags for C4 ANBZ: #4688 This ensures that kernel does not throw an unalign exception. Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/Makefile b/arch/sw_64/Makefile index a853a138bab2..560d57ba2d6b 100644 --- a/arch/sw_64/Makefile +++ b/arch/sw_64/Makefile @@ -27,7 +27,7 @@ endif CHECKFLAGS += -D__sw__ cflags-y := -pipe -ffixed-8 -mno-fp-regs #-msmall-data ifeq ($(CONFIG_SUBARCH_C4),y) - cflags-y += -fsw-rev + cflags-y += -fsw-rev -fno-sw-unalign-byte endif cflags-y += $(call cc-option, -fno-jump-tables) -- Gitee From fc7763498609fa3eb4aea689ac647b5c4ac1a0fa Mon Sep 17 00:00:00 2001 From: Lei Yilong Date: Thu, 11 Apr 2024 14:39:59 +0800 Subject: [PATCH 08/19] anolis: sw64: kvm: fix pmd_trans_cont ANBZ: #4688 If CONFIG_TRANSPARENT_HUGEPAGE=n, it fails to complie because pmd_trans_cont() is undefined. Signed-off-by: Lei Yilong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/pgtable.h | 10 +++++----- arch/sw_64/kvm/mmu.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/sw_64/include/asm/pgtable.h b/arch/sw_64/include/asm/pgtable.h index 102da6a411fe..9cfc23d83337 100644 --- a/arch/sw_64/include/asm/pgtable.h +++ b/arch/sw_64/include/asm/pgtable.h @@ -634,6 +634,11 @@ static inline int pte_devmap(pte_t a) } #endif +static inline int pmd_cont(pmd_t pmd) +{ + return !!(pmd_val(pmd) & _PAGE_CONT); +} + #ifdef CONFIG_TRANSPARENT_HUGEPAGE /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/ @@ -644,11 +649,6 @@ static inline int pmd_trans_splitting(pmd_t pmd) return !!(pmd_val(pmd) & _PAGE_SPLITTING); } -static inline int pmd_trans_cont(pmd_t pmd) -{ - return !!(pmd_val(pmd) & _PAGE_CONT); -} - static inline int pmd_trans_huge(pmd_t pmd) { return !!(pmd_val(pmd) & _PAGE_LEAF); diff --git a/arch/sw_64/kvm/mmu.c b/arch/sw_64/kvm/mmu.c index f32b7383af45..737d57406e79 100644 --- a/arch/sw_64/kvm/mmu.c +++ b/arch/sw_64/kvm/mmu.c @@ -73,7 +73,7 @@ static void apt_dissolve_pmd(struct kvm *kvm, phys_addr_t addr, pmd_t *pmd) if (!pmd_trans_huge(*pmd)) return; - if (pmd_trans_cont(*pmd)) { + if (pmd_cont(*pmd)) { for (i = 0; i < CONT_PMDS; i++, pmd++) pmd_clear(pmd); } else @@ -178,7 +178,7 @@ static void unmap_apt_pmds(struct kvm *kvm, pud_t *pud, next = pmd_addr_end(addr, end); if (!pmd_none(*pmd)) { if (pmd_trans_huge(*pmd)) { - if (pmd_trans_cont(*pmd)) { + if (pmd_cont(*pmd)) { for (i = 0; i < CONT_PMDS; i++, pmd++) pmd_clear(pmd); } else -- Gitee From 0ce251e0706d93f2d36733694ea0a192efc4bd06 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Tue, 9 Apr 2024 14:50:54 +0800 Subject: [PATCH 09/19] anolis: sw64: irqchip: fix compatibility with old dts ANBZ: #4688 'commit a48a35ef3030 ("anolis: sw64: dts: improve properties for LPC-INTC")' and 'commit f5f17442764a ("anolis: sw64: dts: improve properties for PINTC")' break the compatibility of old dts. This commit fixes the compatibility issue so that the latest kernel can work with old firmware. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip3.dts | 2 +- arch/sw_64/boot/dts/chip_vt.dts | 2 +- drivers/irqchip/irq-sunway-lpc-intc.c | 15 ++++++----- drivers/irqchip/irq-sunway-pintc.c | 39 +++++++++++++++++---------- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index 0e9ad8f5d464..920519566c58 100644 --- a/arch/sw_64/boot/dts/chip3.dts +++ b/arch/sw_64/boot/dts/chip3.dts @@ -36,7 +36,7 @@ spiclk: spiclk { }; pintc: interrupt-controller { - compatible = "sw64,pintc"; + compatible = "sw64,pintc", "sw64,sw6_irq_controller"; interrupt-controller; sw64,node = <0>; sw64,irq-num = <8>; diff --git a/arch/sw_64/boot/dts/chip_vt.dts b/arch/sw_64/boot/dts/chip_vt.dts index 9889fcae7a5c..5f2ec68cb1d0 100644 --- a/arch/sw_64/boot/dts/chip_vt.dts +++ b/arch/sw_64/boot/dts/chip_vt.dts @@ -20,7 +20,7 @@ soc { ranges; pintc: interrupt-controller { - compatible = "sw64,pintc_vt"; + compatible = "sw64,pintc_vt", "sw64,sw6_irq_vt_controller"; interrupt-controller; sw64,node = <0>; sw64,irq-num = <16>; diff --git a/drivers/irqchip/irq-sunway-lpc-intc.c b/drivers/irqchip/irq-sunway-lpc-intc.c index db10f363323a..80442dae812f 100644 --- a/drivers/irqchip/irq-sunway-lpc-intc.c +++ b/drivers/irqchip/irq-sunway-lpc-intc.c @@ -187,20 +187,23 @@ static int __init lpc_intc_of_init(struct device_node *np, ret = of_property_read_u32(np, "sw64,node", &node); if (ret) { - pr_err(PREFIX "\"sw64,node\" not found\n"); - return -EINVAL; + node = 0; + pr_warn(PREFIX "\"sw64,node\" fallback to %u\n", + node); } ret = of_property_read_u32(np, "sw64,irq-num", &nr_irqs); if (ret) { - pr_err(PREFIX "\"sw64,irq-num\" not found\n"); - return -EINVAL; + nr_irqs = 16; + pr_warn(PREFIX "\"sw64,irq-num\" fallback to %u\n", + nr_irqs); } ret = of_property_read_u32(np, "sw64,ver", &version); if (ret) { - pr_err(PREFIX "\"sw64,ver\" not found\n"); - return -EINVAL; + version = 1; + pr_warn(PREFIX "\"sw64,ver\" fallback to %u\n", + version); } base = of_iomap(np, 0); diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c index 55ea830e26de..ca89a01316a3 100644 --- a/drivers/irqchip/irq-sunway-pintc.c +++ b/drivers/irqchip/irq-sunway-pintc.c @@ -49,6 +49,12 @@ #define SW_PINTC_MCU_GSI_BASE 64 +#define INTPU_BASE_V1 0x802a00000000 +#define INTPU_SIZE_V1 0x1680 + +#define MCU_BASE_V1 0x803000000000 +#define MCU_SIZE_V1 0x8f00 + struct pintc_chip_data { bool vt; /* virtual pintc */ u32 node; /* node ID */ @@ -354,39 +360,43 @@ pintc_of_init_common(struct device_node *pintc, ret = of_property_read_u32(pintc, "sw64,node", &node); if (ret) { - pr_err(PREFIX "\"sw64,node\" not found\n"); - return -EINVAL; + node = 0; + pr_warn(PREFIX "\"sw64,node\" fallback to %u\n", + node); } ret = of_property_read_u32(pintc, "sw64,irq-num", &nr_irqs); if (ret) { - pr_err(PREFIX "\"sw64,irq-num\" not found\n"); - return -EINVAL; + nr_irqs = vt ? 16 : 8; + pr_err(PREFIX "\"sw64,irq-num\" fallback to %u\n", + nr_irqs); } ret = of_property_read_u32(pintc, "sw64,ver", &version); if (ret) { - pr_err(PREFIX "\"sw64,ver\" not found\n"); - return -EINVAL; + version = 1; + pr_err(PREFIX "\"sw64,ver\" fallback to %u\n", + version); } pintc_base = of_iomap(pintc, 0); if (!vt && !pintc_base) { - pr_err(PREFIX "failed to map pintc base address\n"); - return -ENXIO; + pintc_base = ioremap(INTPU_BASE_V1, INTPU_SIZE_V1); + pr_warn(PREFIX "pintc base address fallback to 0x%lx\n", + INTPU_BASE_V1); } mcu_base = of_iomap(pintc, 1); if (!vt && !mcu_base) { - pr_err(PREFIX "failed to map mcu base address\n"); - ret = -ENXIO; - goto out_unmap0; + mcu_base = ioremap(MCU_BASE_V1, MCU_SIZE_V1); + pr_warn(PREFIX "mcu base address fallback to 0x%lx\n", + MCU_BASE_V1); } chip_data = kzalloc_node(sizeof(*chip_data), GFP_KERNEL, node); if (!chip_data) { ret = -ENOMEM; - goto out_unmap1; + goto out_unmap; } chip_data->vt = vt; @@ -404,9 +414,8 @@ pintc_of_init_common(struct device_node *pintc, out_free_mem: kfree(chip_data); -out_unmap1: +out_unmap: iounmap(mcu_base); -out_unmap0: iounmap(pintc_base); return ret; } @@ -418,6 +427,7 @@ pintc_of_init(struct device_node *pintc, struct device_node *parent) } IRQCHIP_DECLARE(sw64_pintc, "sw64,pintc", pintc_of_init); +IRQCHIP_DECLARE(sw64_pintc_legacy, "sw64,sw6_irq_controller", pintc_of_init); static int __init pintc_vt_of_init(struct device_node *pintc, struct device_node *parent) @@ -426,6 +436,7 @@ pintc_vt_of_init(struct device_node *pintc, struct device_node *parent) } IRQCHIP_DECLARE(sw64_pintc_vt, "sw64,pintc_vt", pintc_vt_of_init); +IRQCHIP_DECLARE(sw64_pintc_vt_legacy, "sw64,sw6_irq_vt_controller", pintc_vt_of_init); #endif #ifdef CONFIG_ACPI -- Gitee From 40500f3045d772bc5ca8a98c0114d0eabaadc328 Mon Sep 17 00:00:00 2001 From: Xu Chenjiao Date: Tue, 16 Apr 2024 15:07:03 +0000 Subject: [PATCH 10/19] anolis: sw64: spi: update spi controller driver ANBZ: #4688 Update spi controller driver. It should be noted as follows: - The m25p80 driver has been removed in commit b35b9a10362d ("mtd: spi-nor: Move m25p80 code in spi-nor.c"). - The data structures used by spi memory driver have changed. Signed-off-by: Xu Chenjiao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/junzhang.dts | 4 +- drivers/spi/Kconfig | 22 +- drivers/spi/Makefile | 3 +- .../{spi-chip3-mmio.c => spi-sunway-mmio.c} | 85 +++--- drivers/spi/{spi-chip3.c => spi-sunway.c} | 247 +++++++++--------- drivers/spi/{spi-chip3.h => spi-sunway.h} | 162 +++++++----- 6 files changed, 279 insertions(+), 244 deletions(-) rename drivers/spi/{spi-chip3-mmio.c => spi-sunway-mmio.c} (49%) rename drivers/spi/{spi-chip3.c => spi-sunway.c} (44%) rename drivers/spi/{spi-chip3.h => spi-sunway.h} (49%) diff --git a/arch/sw_64/boot/dts/junzhang.dts b/arch/sw_64/boot/dts/junzhang.dts index 4e8cd655c798..8712678a66e8 100644 --- a/arch/sw_64/boot/dts/junzhang.dts +++ b/arch/sw_64/boot/dts/junzhang.dts @@ -160,7 +160,7 @@ partitions { partition@0 { label = "test"; - reg = <0 0x400000>; + reg = <0 0x800000>; }; }; }; @@ -178,7 +178,7 @@ partitions { partition@0 { label = "test"; - reg = <0 0x400000>; + reg = <0 0x800000>; }; }; }; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b60c64e8037c..ad62cf203ea5 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -282,6 +282,21 @@ config SPI_DW_BT1_DIRMAP endif +config SPI_SUNWAY + tristate "Sunway SPI controller support" + depends on SW64 + imply SPI_MEM + help + general driver for Sunway SPI controller + +if SPI_SUNWAY + +config SPI_SUNWAY_MMIO + tristate "Memory-mapped io interface driver for Sunway SPI controller" + depends on HAS_IOMEM + +endif + config SPI_DLN2 tristate "Diolan DLN-2 USB SPI adapter" depends on MFD_DLN2 @@ -995,13 +1010,6 @@ config SPI_AMD # # Add new SPI master controllers in alphabetical order above this line # -config SPI_CHIP3 - tristate "Memory-mapped io interface driver for SUNWAY CHIP3 SPI core" - depends on UNCORE_XUELANG - help - general driver for SPI controller core from DesignWare - - comment "SPI Multiplexer support" config SPI_MUX diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b7cff3eda85b..719367f63618 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -41,8 +41,9 @@ spi-dw-y := spi-dw-core.o spi-dw-$(CONFIG_SPI_DW_DMA) += spi-dw-dma.o obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1.o obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o -obj-$(CONFIG_SPI_CHIP3) += spi-chip3.o spi-chip3-mmio.o obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o +obj-$(CONFIG_SPI_SUNWAY) += spi-sunway.o +obj-$(CONFIG_SPI_SUNWAY_MMIO) += spi-sunway-mmio.o obj-$(CONFIG_SPI_EFM32) += spi-efm32.o obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o obj-$(CONFIG_SPI_FALCON) += spi-falcon.o diff --git a/drivers/spi/spi-chip3-mmio.c b/drivers/spi/spi-sunway-mmio.c similarity index 49% rename from drivers/spi/spi-chip3-mmio.c rename to drivers/spi/spi-sunway-mmio.c index 1a1a9feaffa9..b170207cd104 100644 --- a/drivers/spi/spi-chip3-mmio.c +++ b/drivers/spi/spi-sunway-mmio.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Memory-mapped interface driver for SUNWAY CHIP3 SPI Core + * Memory-mapped interface driver for SUNWAY CHIP SPI Core */ #include @@ -18,62 +18,63 @@ #include #include -#include "spi-chip3.h" +#include "spi-sunway.h" -#define DRIVER_NAME "sunway_chip3_spi" -struct chip3_spi_mmio { - struct chip3_spi dws; +#define DRIVER_NAME "sunway_chip_spi" + +struct chip_spi_mmio { + struct spi_chip spi_chip; struct clk *clk; void *priv; }; -static int chip3_spi_mmio_probe(struct platform_device *pdev) +static int chip_spi_mmio_probe(struct platform_device *pdev) { int (*init_func)(struct platform_device *pdev, - struct chip3_spi_mmio *dwsmmio); - struct chip3_spi_mmio *dwsmmio; - struct chip3_spi *dws; + struct chip_spi_mmio *spimmio); + struct chip_spi_mmio *spimmio; + struct spi_chip *spi_chip; struct resource *mem; int ret; int num_cs; - dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct chip3_spi_mmio), + spimmio = devm_kzalloc(&pdev->dev, sizeof(struct chip_spi_mmio), GFP_KERNEL); - if (!dwsmmio) + if (!spimmio) return -ENOMEM; - dws = &dwsmmio->dws; + spi_chip = &spimmio->spi_chip; /* Get basic io resource and map it */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dws->regs = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(dws->regs)) { + spi_chip->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(spi_chip->regs)) { dev_err(&pdev->dev, "SPI region map failed\n"); - return PTR_ERR(dws->regs); + return PTR_ERR(spi_chip->regs); } - dwsmmio->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(dwsmmio->clk)) - return PTR_ERR(dwsmmio->clk); - ret = clk_prepare_enable(dwsmmio->clk); + spimmio->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(spimmio->clk)) + return PTR_ERR(spimmio->clk); + ret = clk_prepare_enable(spimmio->clk); if (ret) return ret; - dws->bus_num = pdev->id; - dws->max_freq = clk_get_rate(dwsmmio->clk); + spi_chip->bus_num = pdev->id; + spi_chip->max_freq = clk_get_rate(spimmio->clk); device_property_read_u32(&pdev->dev, "reg-io-width", - &dws->reg_io_width); + &spi_chip->reg_io_width); num_cs = 4; device_property_read_u32(&pdev->dev, "num-cs", &num_cs); - dws->num_cs = num_cs; + spi_chip->num_cs = num_cs; if (pdev->dev.of_node) { int i; - for (i = 0; i < dws->num_cs; i++) { + for (i = 0; i < spi_chip->num_cs; i++) { int cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i); @@ -93,49 +94,51 @@ static int chip3_spi_mmio_probe(struct platform_device *pdev) init_func = device_get_match_data(&pdev->dev); if (init_func) { - ret = init_func(pdev, dwsmmio); + ret = init_func(pdev, spimmio); if (ret) goto out; } - ret = chip3_spi_add_host(&pdev->dev, dws); + spi_chip->flags = SPI_PLAT; + + ret = spi_chip_add_host(&pdev->dev, spi_chip); if (ret) goto out; - platform_set_drvdata(pdev, dwsmmio); + platform_set_drvdata(pdev, spimmio); return 0; out: - clk_disable_unprepare(dwsmmio->clk); + clk_disable_unprepare(spimmio->clk); return ret; } -static int chip3_spi_mmio_remove(struct platform_device *pdev) +static int chip_spi_mmio_remove(struct platform_device *pdev) { - struct chip3_spi_mmio *dwsmmio = platform_get_drvdata(pdev); + struct chip_spi_mmio *spimmio = platform_get_drvdata(pdev); - chip3_spi_remove_host(&dwsmmio->dws); - clk_disable_unprepare(dwsmmio->clk); + spi_chip_remove_host(&spimmio->spi_chip); + clk_disable_unprepare(spimmio->clk); return 0; } -static const struct of_device_id chip3_spi_mmio_of_match[] = { - { .compatible = "sunway,chip3-spi", }, +static const struct of_device_id chip_spi_mmio_of_match[] = { + { .compatible = "sunway,chip-spi",}, { /* end of table */} }; -MODULE_DEVICE_TABLE(of, chip3_spi_mmio_of_match); +MODULE_DEVICE_TABLE(of, chip_spi_mmio_of_match); -static struct platform_driver chip3_spi_mmio_driver = { - .probe = chip3_spi_mmio_probe, - .remove = chip3_spi_mmio_remove, +static struct platform_driver chip_spi_mmio_driver = { + .probe = chip_spi_mmio_probe, + .remove = chip_spi_mmio_remove, .driver = { .name = DRIVER_NAME, - .of_match_table = chip3_spi_mmio_of_match, + .of_match_table = chip_spi_mmio_of_match, }, }; -module_platform_driver(chip3_spi_mmio_driver); +module_platform_driver(chip_spi_mmio_driver); MODULE_AUTHOR("Platform@wiat.com"); -MODULE_DESCRIPTION("Memory-mapped I/O interface driver for Sunway CHIP3"); +MODULE_DESCRIPTION("Memory-mapped I/O interface driver for Sunway CHIP"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-chip3.c b/drivers/spi/spi-sunway.c similarity index 44% rename from drivers/spi/spi-chip3.c rename to drivers/spi/spi-sunway.c index 568bcc65845d..6133173ea09a 100644 --- a/drivers/spi/spi-chip3.c +++ b/drivers/spi/spi-sunway.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * SUNWAY CHIP3 SPI core controller driver + * SPI core controller driver */ #include @@ -16,7 +16,7 @@ #include #include -#include "spi-chip3.h" +#include "spi-sunway.h" /* Slave spi_dev related */ struct chip_data { @@ -30,25 +30,25 @@ struct chip_data { void (*cs_control)(u32 command); }; -static void chip3_spi_handle_err(struct spi_controller *master, +static void spi_chip_handle_err(struct spi_controller *master, struct spi_message *msg) { - struct chip3_spi *dws = spi_controller_get_devdata(master); + struct spi_chip *spi_chip = spi_controller_get_devdata(master); - spi_reset_chip(dws); + spi_reset_chip(spi_chip); } -static size_t chip3_spi_max_length(struct spi_device *spi) +static size_t spi_chip_max_length(struct spi_device *spi) { - struct chip3_spi *dws = spi_controller_get_devdata(spi->master); + struct spi_chip *spi_chip = spi_controller_get_devdata(spi->master); - return dws->fifo_len; + return spi_chip->fifo_len; } -static int chip3_spi_transfer_one_message(struct spi_controller *master, +static int spi_chip_transfer_one_message(struct spi_controller *master, struct spi_message *m) { - struct chip3_spi *dws = spi_controller_get_devdata(master); + struct spi_chip *spi_chip = spi_controller_get_devdata(master); struct spi_transfer *t = NULL; u16 clk_div; u32 freq; @@ -58,31 +58,31 @@ static int chip3_spi_transfer_one_message(struct spi_controller *master, int ret = 0; int i = 0; - spi_enable_chip(dws, 0); + spi_enable_chip(spi_chip, 0); /* Handle per transfer options for bpw and speed. */ - freq = clamp(m->spi->max_speed_hz, 0U, dws->max_freq); - clk_div = (DIV_ROUND_UP(dws->max_freq, freq) + 1) & 0xfffe; - speed_hz = dws->max_freq / clk_div; + freq = clamp(m->spi->max_speed_hz, 0U, spi_chip->max_freq); + clk_div = (DIV_ROUND_UP(spi_chip->max_freq, freq) + 1) & 0xfffe; + speed_hz = spi_chip->max_freq / clk_div; - if (dws->current_freq != speed_hz) { - spi_set_clk(dws, clk_div); - dws->current_freq = speed_hz; + if (spi_chip->current_freq != speed_hz) { + spi_set_clk(spi_chip, clk_div); + spi_chip->current_freq = speed_hz; } - dws->n_bytes = 1; + spi_chip->n_bytes = 1; /* For poll mode just disable all interrupts */ - spi_mask_intr(dws, 0xff); + spi_mask_intr(spi_chip, 0xff); - chip3_writel(dws, CHIP3_SPI_CTRL0, SPI_TRANSMIT_RECEIVE); + spi_writel(spi_chip, SPI_CHIP_CTRL0, SPI_TRANSMIT_RECEIVE); - spi_enable_chip(dws, 1); + spi_enable_chip(spi_chip, 1); list_for_each_entry(t, &m->transfers, transfer_list) { len += t->len; /* Judge if data is overflow */ - if (len > dws->fifo_len) { + if (len > spi_chip->fifo_len) { pr_err("SPI transfer overflow.\n"); m->actual_length = 0; m->status = -EIO; @@ -91,27 +91,28 @@ static int chip3_spi_transfer_one_message(struct spi_controller *master, } if (t->tx_buf) - memcpy(&dws->buf[len], t->tx_buf, t->len); + memcpy(&spi_chip->buf[len], t->tx_buf, t->len); else - memset(&dws->buf[len], 0, t->len); + memset(&spi_chip->buf[len], 0, t->len); } - chip3_writel(dws, CHIP3_SPI_SER, 0x0); + spi_writel(spi_chip, SPI_CHIP_SER, 0x0); for (i = 0; i < len; i++) - chip3_writel(dws, CHIP3_SPI_DR, dws->buf[i]); - chip3_writel(dws, CHIP3_SPI_SER, BIT(m->spi->chip_select)); + spi_writel(spi_chip, SPI_CHIP_DR, spi_chip->buf[i]); + spi_writel(spi_chip, SPI_CHIP_SER, BIT(m->spi->chip_select)); do { - status = chip3_readl(dws, CHIP3_SPI_SR); + status = spi_readl(spi_chip, SPI_CHIP_SR); } while (status & SR_BUSY); list_for_each_entry(t, &m->transfers, transfer_list) { if (t->rx_buf) { for (i = 0; i < t->len; i++, t->rx_buf += 1) - *(u8 *)t->rx_buf = chip3_readl(dws, CHIP3_SPI_DR); + *(u8 *)t->rx_buf = spi_readl(spi_chip, + SPI_CHIP_DR); } else { for (i = 0; i < t->len; i++) - chip3_readl(dws, CHIP3_SPI_DR); + spi_readl(spi_chip, SPI_CHIP_DR); } } @@ -123,32 +124,34 @@ static int chip3_spi_transfer_one_message(struct spi_controller *master, return ret; } -static int chip3_spi_adjust_mem_op_size(struct spi_mem *mem, - struct spi_mem_op *op) +static int spi_chip_adjust_mem_op_size(struct spi_mem *mem, + struct spi_mem_op *op) { - struct chip3_spi *dws = spi_controller_get_devdata(mem->spi->controller); + struct spi_chip *spi_chip = spi_controller_get_devdata( + mem->spi->controller); size_t len; len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; - op->data.nbytes = min((size_t)op->data.nbytes, (dws->fifo_len - len)); + op->data.nbytes = min((size_t)op->data.nbytes, + (spi_chip->fifo_len - len)); if (!op->data.nbytes) return -EINVAL; return 0; } -static int chip3_spi_init_mem_buf(struct chip3_spi *dws, +static int spi_chip_init_mem_buf(struct spi_chip *spi_chip, const struct spi_mem_op *op) { int ret = 0; int i, j, len; /* Calculate the total length of the transfer. */ - len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; + len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; /* Judge if data is overflow */ - if (len + op->data.nbytes > dws->fifo_len) { + if (len + op->data.nbytes > spi_chip->fifo_len) { ret = -EIO; goto way_out; } @@ -158,36 +161,37 @@ static int chip3_spi_init_mem_buf(struct chip3_spi *dws, * buffer. If it's a transfer with data to be sent, also copy it into * the single buffer. */ - for (i = 0; i < sizeof(op->cmd.opcode); i++) - dws->buf[i] = op->cmd.opcode; + for (i = 0; i < op->cmd.nbytes; i++) + spi_chip->buf[i] = op->cmd.opcode; for (j = 0; j < op->addr.nbytes; i++, j++) - dws->buf[i] = op->addr.val >> (8 * (op->addr.nbytes - i)); + spi_chip->buf[i] = op->addr.val >> (8 * (op->addr.nbytes - i)); for (j = 0; j < op->dummy.nbytes; i++, j++) - dws->buf[i] = 0xff; + spi_chip->buf[i] = 0xff; if (op->data.dir == SPI_MEM_DATA_OUT) { - memcpy(&dws->buf[i], op->data.buf.out, op->data.nbytes); + memcpy(&spi_chip->buf[i], op->data.buf.out, op->data.nbytes); len += op->data.nbytes; } - dws->tx_len = len; + spi_chip->tx_len = len; if (op->data.dir == SPI_MEM_DATA_IN) { - dws->rx = op->data.buf.in; - dws->rx_len = op->data.nbytes; + spi_chip->rx = op->data.buf.in; + spi_chip->rx_len = op->data.nbytes; } else { - dws->rx = NULL; - dws->rx_len = 0; + spi_chip->rx = NULL; + spi_chip->rx_len = 0; } way_out: return ret; } -static int chip3_spi_exec_mem_op(struct spi_mem *mem, - const struct spi_mem_op *op) +static int spi_chip_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) { - struct chip3_spi *dws = spi_controller_get_devdata(mem->spi->controller); + struct spi_chip *spi_chip = spi_controller_get_devdata( + mem->spi->controller); u16 clk_div; int ret = 0; int i; @@ -195,55 +199,55 @@ static int chip3_spi_exec_mem_op(struct spi_mem *mem, u32 freq; u32 speed_hz; - ret = chip3_spi_init_mem_buf(dws, op); + ret = spi_chip_init_mem_buf(spi_chip, op); if (ret) return ret; - spi_enable_chip(dws, 0); + spi_enable_chip(spi_chip, 0); /* Handle per transfer options for bpw and speed. */ - freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_freq); - clk_div = (DIV_ROUND_UP(dws->max_freq, freq) + 1) & 0xfffe; - speed_hz = dws->max_freq / clk_div; + freq = clamp(mem->spi->max_speed_hz, 0U, spi_chip->max_freq); + clk_div = (DIV_ROUND_UP(spi_chip->max_freq, freq) + 1) & 0xfffe; + speed_hz = spi_chip->max_freq / clk_div; - if (dws->current_freq != speed_hz) { - spi_set_clk(dws, clk_div); - dws->current_freq = speed_hz; + if (spi_chip->current_freq != speed_hz) { + spi_set_clk(spi_chip, clk_div); + spi_chip->current_freq = speed_hz; } - dws->n_bytes = 1; + spi_chip->n_bytes = 1; /* For poll mode just disable all interrupts */ - spi_mask_intr(dws, 0xff); + spi_mask_intr(spi_chip, 0xff); - if ((dws->tx_len != 0) && (dws->rx_len != 0)) { - chip3_writel(dws, CHIP3_SPI_CTRL0, SPI_EEPROM_READ); - chip3_writel(dws, CHIP3_SPI_CTRL1, (dws->rx_len - 1)); + if ((spi_chip->tx_len != 0) && (spi_chip->rx_len != 0)) { + spi_writel(spi_chip, SPI_CHIP_CTRL0, SPI_EEPROM_READ); + spi_writel(spi_chip, SPI_CHIP_CTRL1, (spi_chip->rx_len - 1)); } else { - chip3_writel(dws, CHIP3_SPI_CTRL0, SPI_TRANSMIT_ONLY); + spi_writel(spi_chip, SPI_CHIP_CTRL0, SPI_TRANSMIT_ONLY); } - spi_enable_chip(dws, 1); + spi_enable_chip(spi_chip, 1); - chip3_writel(dws, CHIP3_SPI_SER, 0x0); - for (i = 0; i < dws->tx_len; i++) - chip3_writel(dws, CHIP3_SPI_DR, dws->buf[i]); - chip3_writel(dws, CHIP3_SPI_SER, BIT(mem->spi->chip_select)); + spi_writel(spi_chip, SPI_CHIP_SER, 0x0); + for (i = 0; i < spi_chip->tx_len; i++) + spi_writel(spi_chip, SPI_CHIP_DR, spi_chip->buf[i]); + spi_writel(spi_chip, SPI_CHIP_SER, BIT(mem->spi->chip_select)); - value = chip3_readl(dws, CHIP3_SPI_SR); + value = spi_readl(spi_chip, SPI_CHIP_SR); while (value & SR_BUSY) - value = chip3_readl(dws, CHIP3_SPI_SR); + value = spi_readl(spi_chip, SPI_CHIP_SR); - for (i = 0; i < dws->rx_len; dws->rx += dws->n_bytes, i++) - *(u8 *)dws->rx = chip3_readl(dws, CHIP3_SPI_DR); + for (i = 0; i < spi_chip->rx_len; spi_chip->rx += spi_chip->n_bytes, i++) + *(u8 *)spi_chip->rx = spi_readl(spi_chip, SPI_CHIP_DR); return ret; } /* This may be called twice for each spi dev */ -static int chip3_spi_setup(struct spi_device *spi) +static int spi_chip_setup(struct spi_device *spi) { - struct chip3_spi_chip *chip_info = NULL; + struct spi_chip_info *chip_info = NULL; struct chip_data *chip; u32 poll_mode = 0; struct device_node *np = spi->dev.of_node; @@ -282,7 +286,7 @@ static int chip3_spi_setup(struct spi_device *spi) return 0; } -static void chip3_spi_cleanup(struct spi_device *spi) +static void spi_chip_cleanup(struct spi_device *spi) { struct chip_data *chip = spi_get_ctldata(spi); @@ -291,114 +295,115 @@ static void chip3_spi_cleanup(struct spi_device *spi) } /* Restart the controller, disable all interrupts, clean rx fifo */ -static void spi_hw_init(struct device *dev, struct chip3_spi *dws) +static void spi_hw_init(struct device *dev, struct spi_chip *spi_chip) { - spi_reset_chip(dws); + spi_reset_chip(spi_chip); /* * Try to detect the FIFO depth if not set by interface driver, * the depth could be from 2 to 256 from HW spec */ - if (!dws->fifo_len) { + if (!spi_chip->fifo_len) { u32 fifo; for (fifo = 1; fifo < 256; fifo++) { - chip3_writel(dws, CHIP3_SPI_TXFLTR, fifo); - if (fifo != chip3_readl(dws, CHIP3_SPI_TXFLTR)) + spi_writel(spi_chip, SPI_CHIP_TXFLTR, fifo); + if (fifo != spi_readl(spi_chip, SPI_CHIP_TXFLTR)) break; } - chip3_writel(dws, CHIP3_SPI_TXFLTR, 0); + spi_writel(spi_chip, SPI_CHIP_TXFLTR, 0); - dws->fifo_len = (fifo == 1) ? 0 : fifo; - dev_info(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len); + spi_chip->fifo_len = (fifo == 1) ? 0 : fifo; + dev_info(dev, "Detected FIFO size: %u bytes\n", + spi_chip->fifo_len); } } -static const struct spi_controller_mem_ops chip3_mem_ops = { - .adjust_op_size = chip3_spi_adjust_mem_op_size, - .exec_op = chip3_spi_exec_mem_op, +static const struct spi_controller_mem_ops spi_mem_ops = { + .adjust_op_size = spi_chip_adjust_mem_op_size, + .exec_op = spi_chip_exec_mem_op, }; - -int chip3_spi_add_host(struct device *dev, struct chip3_spi *dws) +int spi_chip_add_host(struct device *dev, struct spi_chip *spi_chip) { struct spi_controller *master; int ret; - BUG_ON(dws == NULL); + WARN_ON(spi_chip == NULL); master = spi_alloc_master(dev, 0); if (!master) return -ENOMEM; - dws->master = master; - dws->type = SSI_MOTO_SPI; + spi_chip->master = master; + spi_chip->type = SSI_MOTO_SPI; - spi_controller_set_devdata(master, dws); + spi_controller_set_devdata(master, spi_chip); master->mode_bits = SPI_CPOL | SPI_CPHA; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); - master->bus_num = dws->bus_num; - master->num_chipselect = dws->num_cs; - master->setup = chip3_spi_setup; - master->cleanup = chip3_spi_cleanup; - master->transfer_one_message = chip3_spi_transfer_one_message; - master->handle_err = chip3_spi_handle_err; - master->max_speed_hz = dws->max_freq; + master->bus_num = spi_chip->bus_num; + master->num_chipselect = spi_chip->num_cs; + master->setup = spi_chip_setup; + master->cleanup = spi_chip_cleanup; + master->transfer_one_message = spi_chip_transfer_one_message; + master->handle_err = spi_chip_handle_err; + master->max_speed_hz = spi_chip->max_freq; master->dev.of_node = dev->of_node; master->flags = SPI_MASTER_GPIO_SS; - master->max_transfer_size = chip3_spi_max_length; - master->max_message_size = chip3_spi_max_length; + master->max_transfer_size = spi_chip_max_length; + master->max_message_size = spi_chip_max_length; - master->mem_ops = &chip3_mem_ops; + master->mem_ops = &spi_mem_ops; /* Basic HW init */ - spi_hw_init(dev, dws); + spi_hw_init(dev, spi_chip); ret = devm_spi_register_controller(dev, master); if (ret) { dev_err(&master->dev, "problem registering spi master\n"); - spi_enable_chip(dws, 0); - free_irq(dws->irq, master); + spi_enable_chip(spi_chip, 0); + free_irq(spi_chip->irq, master); } return 0; } -EXPORT_SYMBOL_GPL(chip3_spi_add_host); +EXPORT_SYMBOL_GPL(spi_chip_add_host); -void chip3_spi_remove_host(struct chip3_spi *dws) +void spi_chip_remove_host(struct spi_chip *spi_chip) { - spi_shutdown_chip(dws); + spi_shutdown_chip(spi_chip); - free_irq(dws->irq, dws->master); + free_irq(spi_chip->irq, spi_chip->master); } -EXPORT_SYMBOL_GPL(chip3_spi_remove_host); +EXPORT_SYMBOL_GPL(spi_chip_remove_host); -int chip3_spi_suspend_host(struct chip3_spi *dws) +int spi_chip_suspend_host(struct spi_chip *spi_chip) { int ret; - ret = spi_controller_suspend(dws->master); + ret = spi_controller_suspend(spi_chip->master); if (ret) return ret; - spi_shutdown_chip(dws); + spi_shutdown_chip(spi_chip); return 0; } -EXPORT_SYMBOL_GPL(chip3_spi_suspend_host); +EXPORT_SYMBOL_GPL(spi_chip_suspend_host); -int chip3_spi_resume_host(struct chip3_spi *dws) +int spi_chip_resume_host(struct spi_chip *spi_chip) { int ret; - spi_hw_init(&dws->master->dev, dws); - ret = spi_controller_resume(dws->master); + spi_hw_init(&spi_chip->master->dev, spi_chip); + ret = spi_controller_resume(spi_chip->master); if (ret) - dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); + dev_err(&spi_chip->master->dev, "fail to start queue (%d)\n", + ret); return ret; } -EXPORT_SYMBOL_GPL(chip3_spi_resume_host); +EXPORT_SYMBOL_GPL(spi_chip_resume_host); MODULE_AUTHOR("Platform@wiat.com"); -MODULE_DESCRIPTION("Driver for Sunway CHIP3 SPI controller core"); +MODULE_DESCRIPTION("Driver for SPI controller core"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-chip3.h b/drivers/spi/spi-sunway.h similarity index 49% rename from drivers/spi/spi-chip3.h rename to drivers/spi/spi-sunway.h index 88e49a9091a5..5f44050001d3 100644 --- a/drivers/spi/spi-chip3.h +++ b/drivers/spi/spi-sunway.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef CHIP3_SPI_HEADER_H -#define CHIP3_SPI_HEADER_H +#ifndef SPI_CHIP_HEADER_H +#define SPI_CHIP_HEADER_H #include #include @@ -8,31 +8,31 @@ #include /* Register offsets */ -#define CHIP3_SPI_CTRL0 (0x00<<7) -#define CHIP3_SPI_CTRL1 (0x04<<7) -#define CHIP3_SPI_SSIENR (0x08<<7) -#define CHIP3_SPI_MWCR (0x0c<<7) -#define CHIP3_SPI_SER (0x10<<7) -#define CHIP3_SPI_BAUDR (0x14<<7) -#define CHIP3_SPI_TXFLTR (0x18<<7) -#define CHIP3_SPI_RXFLTR (0x1c<<7) -#define CHIP3_SPI_TXFLR (0x20<<7) -#define CHIP3_SPI_RXFLR (0x24<<7) -#define CHIP3_SPI_SR (0x28<<7) -#define CHIP3_SPI_IMR (0x2c<<7) -#define CHIP3_SPI_ISR (0x30<<7) -#define CHIP3_SPI_RISR (0x34<<7) -#define CHIP3_SPI_TXOICR (0x38<<7) -#define CHIP3_SPI_RXOICR (0x3c<<7) -#define CHIP3_SPI_RXUICR (0x40<<7) -#define CHIP3_SPI_MSTICR (0x44<<7) -#define CHIP3_SPI_ICR (0x48<<7) -#define CHIP3_SPI_DMACR (0x4c<<7) -#define CHIP3_SPI_DMATDLR (0x50<<7) -#define CHIP3_SPI_DMARDLR (0x54<<7) -#define CHIP3_SPI_IDR (0x58<<7) -#define CHIP3_SPI_VERSION (0x5c<<7) -#define CHIP3_SPI_DR (0x60<<7) +#define SPI_CHIP_CTRL0 0x00 +#define SPI_CHIP_CTRL1 0x04 +#define SPI_CHIP_SSIENR 0x08 +#define SPI_CHIP_MWCR 0x0c +#define SPI_CHIP_SER 0x10 +#define SPI_CHIP_BAUDR 0x14 +#define SPI_CHIP_TXFLTR 0x18 +#define SPI_CHIP_RXFLTR 0x1c +#define SPI_CHIP_TXFLR 0x20 +#define SPI_CHIP_RXFLR 0x24 +#define SPI_CHIP_SR 0x28 +#define SPI_CHIP_IMR 0x2c +#define SPI_CHIP_ISR 0x30 +#define SPI_CHIP_RISR 0x34 +#define SPI_CHIP_TXOICR 0x38 +#define SPI_CHIP_RXOICR 0x3c +#define SPI_CHIP_RXUICR 0x40 +#define SPI_CHIP_MSTICR 0x44 +#define SPI_CHIP_ICR 0x48 +#define SPI_CHIP_DMACR 0x4c +#define SPI_CHIP_DMATDLR 0x50 +#define SPI_CHIP_DMARDLR 0x54 +#define SPI_CHIP_IDR 0x58 +#define SPI_CHIP_VERSION 0x5c +#define SPI_CHIP_DR 0x60 /* Bit fields in CTRLR0 */ #define SPI_DFS_OFFSET 0 @@ -91,17 +91,21 @@ #define SPI_EEPROM_READ 0x3c7 #define SPI_TRANSMIT_ONLY 0x1c7 -enum chip3_ssi_type { +#define SPI_PLAT 0x1 +#define SPI_PCI 0x2 + +enum spi_ssi_type { SSI_MOTO_SPI = 0, SSI_TI_SSP, SSI_NS_MICROWIRE, }; -struct chip3_spi; -struct chip3_spi { +struct spi_chip; + +struct spi_chip { struct spi_controller *master; - enum chip3_ssi_type type; + enum spi_ssi_type type; void __iomem *regs; unsigned long paddr; @@ -122,6 +126,7 @@ struct chip3_spi { unsigned int rx_len; u8 n_bytes; /* current is a 1/2 bytes op */ u32 current_freq; /* frequency in hz */ + int flags; u8 buf[MAX_LEN]; @@ -132,76 +137,89 @@ struct chip3_spi { #endif }; -static inline u32 chip3_readl(struct chip3_spi *dws, u32 offset) +static inline u32 spi_readl(struct spi_chip *spi_chip, u32 offset) { - return __raw_readl(dws->regs + offset); + if (spi_chip->flags & SPI_PLAT) + offset <<= 7; + + return __raw_readl(spi_chip->regs + offset); } -static inline u16 chip3_readw(struct chip3_spi *dws, u32 offset) +static inline u16 spi_readw(struct spi_chip *spi_chip, u32 offset) { - return __raw_readw(dws->regs + offset); + if (spi_chip->flags & SPI_PLAT) + offset <<= 7; + + return __raw_readw(spi_chip->regs + offset); } -static inline void chip3_writel(struct chip3_spi *dws, u32 offset, u32 val) +static inline void spi_writel(struct spi_chip *spi_chip, u32 offset, u32 val) { - __raw_writel(val, dws->regs + offset); + if (spi_chip->flags & SPI_PLAT) + offset <<= 7; + + __raw_writel(val, spi_chip->regs + offset); } -static inline void chip3_writew(struct chip3_spi *dws, u32 offset, u16 val) +static inline void spi_writew(struct spi_chip *spi_chip, u32 offset, u16 val) { - __raw_writew(val, dws->regs + offset); + if (spi_chip->flags & SPI_PLAT) + offset <<= 7; + + __raw_writew(val, spi_chip->regs + offset); } -static inline u32 chip3_read_io_reg(struct chip3_spi *dws, u32 offset) +static inline u32 spi_read_io_reg(struct spi_chip *spi_chip, u32 offset) { - switch (dws->reg_io_width) { + switch (spi_chip->reg_io_width) { case 2: - return chip3_readw(dws, offset); + return spi_readw(spi_chip, offset); case 4: default: - return chip3_readl(dws, offset); + return spi_readl(spi_chip, offset); } } -static inline void chip3_write_io_reg(struct chip3_spi *dws, u32 offset, u32 val) +static inline void spi_write_io_reg(struct spi_chip *spi_chip, u32 offset, + u32 val) { - switch (dws->reg_io_width) { + switch (spi_chip->reg_io_width) { case 2: - chip3_writew(dws, offset, val); + spi_writew(spi_chip, offset, val); break; case 4: default: - chip3_writel(dws, offset, val); + spi_writel(spi_chip, offset, val); break; } } -static inline void spi_enable_chip(struct chip3_spi *dws, int enable) +static inline void spi_enable_chip(struct spi_chip *spi_chip, int enable) { - chip3_writel(dws, CHIP3_SPI_SSIENR, (enable ? 1 : 0)); + spi_writel(spi_chip, SPI_CHIP_SSIENR, (enable ? 1 : 0)); } -static inline void spi_set_clk(struct chip3_spi *dws, u16 div) +static inline void spi_set_clk(struct spi_chip *spi_chip, u16 div) { - chip3_writel(dws, CHIP3_SPI_BAUDR, div); + spi_writel(spi_chip, SPI_CHIP_BAUDR, div); } /* Disable IRQ bits */ -static inline void spi_mask_intr(struct chip3_spi *dws, u32 mask) +static inline void spi_mask_intr(struct spi_chip *spi_chip, u32 mask) { u32 new_mask; - new_mask = chip3_readl(dws, CHIP3_SPI_IMR) & ~mask; - chip3_writel(dws, CHIP3_SPI_IMR, new_mask); + new_mask = spi_readl(spi_chip, SPI_CHIP_IMR) & ~mask; + spi_writel(spi_chip, SPI_CHIP_IMR, new_mask); } /* Enable IRQ bits */ -static inline void spi_umask_intr(struct chip3_spi *dws, u32 mask) +static inline void spi_umask_intr(struct spi_chip *spi_chip, u32 mask) { u32 new_mask; - new_mask = chip3_readl(dws, CHIP3_SPI_IMR) | mask; - chip3_writel(dws, CHIP3_SPI_IMR, new_mask); + new_mask = spi_readl(spi_chip, SPI_CHIP_IMR) | mask; + spi_writel(spi_chip, SPI_CHIP_IMR, new_mask); } /* @@ -209,37 +227,37 @@ static inline void spi_umask_intr(struct chip3_spi *dws, u32 mask) * controller back. Transmit and receive FIFO buffers are cleared when the * device is disabled. */ -static inline void spi_reset_chip(struct chip3_spi *dws) +static inline void spi_reset_chip(struct spi_chip *spi_chip) { - spi_enable_chip(dws, 0); - spi_mask_intr(dws, 0xff); - spi_enable_chip(dws, 1); + spi_enable_chip(spi_chip, 0); + spi_mask_intr(spi_chip, 0xff); + spi_enable_chip(spi_chip, 1); } -static inline void spi_shutdown_chip(struct chip3_spi *dws) +static inline void spi_shutdown_chip(struct spi_chip *spi_chip) { - spi_enable_chip(dws, 0); - spi_set_clk(dws, 0); + spi_enable_chip(spi_chip, 0); + spi_set_clk(spi_chip, 0); } /* - * Each SPI slave device to work with chip3_api controller should + * Each SPI slave device to work with spi_api controller should * has such a structure claiming its working mode (poll or PIO/DMA), * which can be save in the "controller_data" member of the * struct spi_device. */ -struct chip3_spi_chip { +struct spi_chip_info { u8 poll_mode; /* 1 for controller polling mode */ u8 type; /* SPI/SSP/MicroWire */ u8 chip_select; void (*cs_control)(u32 command); }; -extern int chip3_spi_add_host(struct device *dev, struct chip3_spi *dws); -extern void chip3_spi_remove_host(struct chip3_spi *dws); -extern int chip3_spi_suspend_host(struct chip3_spi *dws); -extern int chip3_spi_resume_host(struct chip3_spi *dws); +extern int spi_chip_add_host(struct device *dev, struct spi_chip *spi_chip); +extern void spi_chip_remove_host(struct spi_chip *spi_chip); +extern int spi_chip_suspend_host(struct spi_chip *spi_chip); +extern int spi_chip_resume_host(struct spi_chip *spi_chip); /* platform related setup */ -extern int chip3_spi_mid_init(struct chip3_spi *dws); /* Intel MID platforms */ -#endif /* CHIP3_SPI_HEADER_H */ +extern int spi_ich_init(struct spi_chip *spi_chip); +#endif /* SPI_CHIP_HEADER_H */ -- Gitee From 8cacf9f312b1e5df08667bb7cae41509d4674da1 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Mon, 8 Apr 2024 10:33:56 +0800 Subject: [PATCH 11/19] anolis: sw64: force kernel stack to be 16 bytes aligned ANBZ: #4688 Make struct pt_regs and struct rt_sigframe 16 bytes aligned to make sure the kernel stack is always 16 bytes aligned. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/ptrace.h | 2 +- arch/sw_64/kernel/signal.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/include/asm/ptrace.h b/arch/sw_64/include/asm/ptrace.h index 3dcdd806f1c5..83d9a256b0a9 100644 --- a/arch/sw_64/include/asm/ptrace.h +++ b/arch/sw_64/include/asm/ptrace.h @@ -34,7 +34,7 @@ struct pt_regs { unsigned long earg0; unsigned long earg1; unsigned long earg2; -}; +} __aligned(16); #define arch_has_single_step() (1) #define user_mode(regs) (((regs)->ps & 8) != 0) diff --git a/arch/sw_64/kernel/signal.c b/arch/sw_64/kernel/signal.c index 9ba151bb82d3..bc368d20c718 100644 --- a/arch/sw_64/kernel/signal.c +++ b/arch/sw_64/kernel/signal.c @@ -82,7 +82,7 @@ SYSCALL_DEFINE3(odd_sigaction, int, sig, struct rt_sigframe { struct siginfo info; struct ucontext uc; -}; +} __aligned(16); /* * If this changes, userland unwinders that Know Things about our signal -- Gitee From 10f05f900a3747f93d2fdfeb0c2deff4013434b8 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Tue, 9 Apr 2024 09:17:34 +0800 Subject: [PATCH 12/19] anolis: sw64: fix broken rdfpcr() ANBZ: #4688 The memory output is used again after the register output is written, so the register of the register output constraint cannot be reused to store the memory address. Add the necessary constraint modifier to avoid this register reuse. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/fpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/include/asm/fpu.h b/arch/sw_64/include/asm/fpu.h index 1d5e9b0efecc..763d763c0477 100644 --- a/arch/sw_64/include/asm/fpu.h +++ b/arch/sw_64/include/asm/fpu.h @@ -100,7 +100,7 @@ rdfpcr(void) " rfpcr $f0\n\t" " fimovd $f0, %1\n\t" " vldd $f0, %0\n\t" - : "=m"(*fp), "=r"(ret)); + : "=m"(*fp), "=&r"(ret)); return ret; } -- Gitee From 14c4812caacbfc34117a9a2dd128147090ed2379 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Wed, 28 Feb 2024 09:38:22 +0800 Subject: [PATCH 13/19] anolis: sw64: add syscall pfh_ops ANBZ: #4688 Add a new syscall pfh_ops which allows system administrators to modify hardware cache prefetch configuration. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/csr.h | 2 + arch/sw_64/kernel/sys_sw64.c | 61 ++++++++++++++++++++++++++ arch/sw_64/kernel/syscalls/syscall.tbl | 2 +- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/arch/sw_64/include/asm/csr.h b/arch/sw_64/include/asm/csr.h index ea7b92e08011..9a089f9d4ad0 100644 --- a/arch/sw_64/include/asm/csr.h +++ b/arch/sw_64/include/asm/csr.h @@ -20,8 +20,10 @@ #define CSR_EXC_PC 0xe #define CSR_AS_INFO 0x3c #define CSR_DS_STAT 0x48 +#define CSR_PFH_CTL 0x4f #define CSR_SOFTCID 0xc9 #define CSR_DVA 0x54 +#define CSR_PFH_CNT 0x5c #define CSR_BRRETC 0x5e #define CSR_BRFAILC 0x5f #define CSR_PTBR_SYS 0x68 diff --git a/arch/sw_64/kernel/sys_sw64.c b/arch/sw_64/kernel/sys_sw64.c index 46e6197dce76..31e6a8d65cf9 100644 --- a/arch/sw_64/kernel/sys_sw64.c +++ b/arch/sw_64/kernel/sys_sw64.c @@ -151,3 +151,64 @@ SYSCALL_DEFINE0(sw64_pipe) } return res; } + +#ifdef CONFIG_SUBARCH_C4 + +struct pfh_val { + unsigned long pfh_ctl; + unsigned long pfh_cnt; +}; + +static void local_set_pfh(void *info) +{ + struct pfh_val *kbuf = info; + + if (kbuf->pfh_ctl) + sw64_write_csr(kbuf->pfh_ctl, CSR_PFH_CTL); + if (kbuf->pfh_cnt) + sw64_write_csr(kbuf->pfh_cnt, CSR_PFH_CNT); +} + +SYSCALL_DEFINE3(pfh_ops, unsigned long, op, + unsigned long __user *, pfh_ctl_p, + unsigned long __user *, pfh_cnt_p) +{ + struct pfh_val kbuf = {0, 0}; + long error = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (op) { // op != 0, set + if (pfh_ctl_p) + error |= get_user(kbuf.pfh_ctl, pfh_ctl_p); + if (pfh_cnt_p) + error |= get_user(kbuf.pfh_cnt, pfh_cnt_p); + + if (!error && (kbuf.pfh_ctl || kbuf.pfh_cnt)) { + smp_call_function(local_set_pfh, &kbuf, 1); + local_set_pfh(&kbuf); + } + } else { // op == 0, get + if (pfh_ctl_p) { + kbuf.pfh_ctl = sw64_read_csr(CSR_PFH_CTL); + error |= put_user(kbuf.pfh_ctl, pfh_ctl_p); + } + + if (pfh_cnt_p) { + kbuf.pfh_cnt = sw64_read_csr(CSR_PFH_CNT); + error |= put_user(kbuf.pfh_cnt, pfh_cnt_p); + } + } + + return error; +} + +#else + +SYSCALL_DEFINE0(pfh_ops) +{ + return -ENOSYS; +} + +#endif /* CONFIG_SUBARCH_C4 */ diff --git a/arch/sw_64/kernel/syscalls/syscall.tbl b/arch/sw_64/kernel/syscalls/syscall.tbl index 35d108b49a61..1890bf129ddb 100644 --- a/arch/sw_64/kernel/syscalls/syscall.tbl +++ b/arch/sw_64/kernel/syscalls/syscall.tbl @@ -117,7 +117,7 @@ #107 is unused #108 is unused #109 is unused -#110 is unused +110 common pfh_ops sys_pfh_ops 111 common sigsuspend sys_sigsuspend #112 is unused 113 common recvmsg sys_recvmsg -- Gitee From 021f8e4d5b1dfb2b5fdd8691b07f10152f8ce3aa Mon Sep 17 00:00:00 2001 From: Xu Yiwei Date: Tue, 16 Apr 2024 08:55:26 +0000 Subject: [PATCH 14/19] anolis: sw64: iommu: support acpi init ANBZ: #4688 Introduces ACPI DMAR table for sunway IOMMU description and add support for sunway IOMMU ACPI initialization. The old iommu command line parameter is also changed according to the new initialization strategy. Software should use sunway_iommu=on/off to turn on/off all IOMMUs on device now. Signed-off-by: Xu Yiwei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/iommu/sw64/Kconfig | 4 +- drivers/iommu/sw64/iommu.c | 332 ++++++++++++-------- drivers/iommu/sw64/iommu_v2.c | 500 +++++++++++++++++++++++------- drivers/iommu/sw64/sunway_iommu.h | 10 +- include/acpi/actbl1.h | 28 ++ 5 files changed, 623 insertions(+), 251 deletions(-) diff --git a/drivers/iommu/sw64/Kconfig b/drivers/iommu/sw64/Kconfig index dbb6e75a84cb..4cc96bdcd233 100644 --- a/drivers/iommu/sw64/Kconfig +++ b/drivers/iommu/sw64/Kconfig @@ -8,7 +8,7 @@ config SUNWAY_IOMMU depends on SW64 && PCI && SUBARCH_C3B help Support for IOMMU on SW64 platform. It can enable or bypass specific device by - adding boot param "iommu_enable" and "iommu.passthrough". + adding boot param "sunway_iommu" and "iommu.passthrough". # SW64 IOMMU V2 SUPPORT config SUNWAY_IOMMU_V2 @@ -19,4 +19,4 @@ config SUNWAY_IOMMU_V2 depends on SW64 && PCI && SUBARCH_C4 help Support for IOMMU V2 on SW64 platform. It can enable or bypass specific device by - adding boot param "iommu_enable" and "iommu.passthrough". + adding boot param "sunway_iommu" and "iommu.passthrough". diff --git a/drivers/iommu/sw64/iommu.c b/drivers/iommu/sw64/iommu.c index ad037e5a219b..c0822d41b446 100644 --- a/drivers/iommu/sw64/iommu.c +++ b/drivers/iommu/sw64/iommu.c @@ -39,9 +39,6 @@ #define SW64_DMA_LIMIT (0xe0000000 - 1) #define SW64_BAR_ADDRESS (IO_BASE | PCI_BASE) -#define SW64_IOMMU_LEVEL1_OFFSET 0x1ff -#define SW64_IOMMU_LEVEL2_OFFSET 0x3ff - #define SW64_IOMMU_GRN_8K ((0UL) << 4) /* page size as 8KB */ #define SW64_IOMMU_GRN_8M ((0x2UL) << 4) /* page size as 8MB */ #define SW64_IOMMU_PGSIZES (((1ULL) << PAGE_SHIFT) | ((1ULL) << PAGE_8M_SHIFT)) @@ -49,6 +46,10 @@ #define IDENTMAP_ALL ((1U) << 0) #define DMA_MASK64 ((1U) << 1) +#define MAX_NR_IOMMU_PER_NODE 8 + +LIST_HEAD(iommu_list); + /* IOMMU Exceptional Status */ enum exceptype { DTE_LEVEL1 = 0x0, @@ -63,7 +64,7 @@ enum exceptype { PTE_LEVEL2_VAL, }; -u64 iommu_enable_cmd; /* default IOMMU boot param: 0 */ +DECLARE_BITMAP(iommu_bitmap, 32); unsigned long *sunway_iommu_domain_bitmap; @@ -98,59 +99,77 @@ static int get_alias(struct pci_dev *pdev) } /* flush helpers */ -static void piu_flush_all(struct pci_controller *hose) +static void piu_flush_all(struct sunway_iommu *iommu) { - write_piu_ior0(hose->node, hose->index, DTLB_FLUSHALL, 0); - write_piu_ior0(hose->node, hose->index, PTLB_FLUSHALL, 0); - write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHALL, 0); + void __iomem *base; + + base = iommu->reg_base_addr; + if (!base) + return; + + writeq(0, base + DTLB_FLUSHALL); + writeq(0, base + PTLB_FLUSHALL); + writeq(0, base + PCACHE_FLUSHALL); } -void dev_flush_dtlb(struct sunway_iommu_domain *sdomain, - struct sunway_iommu_dev *sdev_data) +static void do_pcache_flush(struct sunway_iommu *iommu, + unsigned long flush_addr) { - struct pci_controller *hose; - int devid; + void __iomem *base; - list_for_each_entry(sdev_data, &sdomain->dev_list, list) { - hose = pci_bus_to_pci_controller(sdev_data->pdev->bus); - devid = sdev_data->devid; + base = iommu->reg_base_addr; + if (!base) + return; - write_piu_ior0(hose->node, hose->index, DTLB_FLUSHDEV, devid); - } + writeq(flush_addr, base + PCACHE_FLUSHPADDR); } void flush_pcache_by_addr(struct sunway_iommu_domain *sdomain, unsigned long flush_addr) { struct pci_controller *hose; + struct sunway_iommu *iommu; struct sunway_iommu_dev *sdev_data; list_for_each_entry(sdev_data, &sdomain->dev_list, list) { hose = pci_bus_to_pci_controller(sdev_data->pdev->bus); + iommu = hose->pci_iommu; flush_addr = __pa(flush_addr); - write_piu_ior0(hose->node, hose->index, - PCACHE_FLUSHPADDR, flush_addr); + do_pcache_flush(iommu, flush_addr); } } +static void do_ptlb_flush(struct sunway_iommu *iommu, + unsigned long flush_addr) +{ + void __iomem *base; + + base = iommu->reg_base_addr; + if (!base) + return; + + writeq(flush_addr, base + PTLB_FLUSHVADDR); +} + void flush_ptlb_by_addr(struct sunway_iommu_domain *sdomain, unsigned long flush_addr) { struct pci_controller *hose; struct pci_dev *pdev; struct sunway_iommu_dev *sdev_data; + struct sunway_iommu *iommu; unsigned long address; u16 alias, bus_number, devfn; list_for_each_entry(sdev_data, &sdomain->dev_list, list) { pdev = sdev_data->pdev; hose = pci_bus_to_pci_controller(pdev->bus); + iommu = hose->pci_iommu; address = (pdev->bus->number << 8) | pdev->devfn | (flush_addr << 16); - write_piu_ior0(hose->node, hose->index, - PTLB_FLUSHVADDR, flush_addr); + do_ptlb_flush(iommu, address); if (sdev_data->alias != sdev_data->devid) { alias = sdev_data->alias; @@ -159,8 +178,7 @@ void flush_ptlb_by_addr(struct sunway_iommu_domain *sdomain, address = (bus_number << 8) | devfn | (flush_addr << 16); - write_piu_ior0(hose->node, hose->index, - PTLB_FLUSHVADDR, flush_addr); + do_ptlb_flush(iommu, address); } } } @@ -275,7 +293,7 @@ static int sunway_domain_init(struct sunway_iommu_domain *sdomain) return -ENOMEM; INIT_LIST_HEAD(&sdomain->dev_list); - return 1; + return 0; } static struct sunway_iommu_domain *sunway_domain_alloc(void) @@ -286,7 +304,7 @@ static struct sunway_iommu_domain *sunway_domain_alloc(void) if (!sdomain) return NULL; - if (!sunway_domain_init(sdomain)) { + if (sunway_domain_init(sdomain)) { kfree(sdomain); return NULL; } @@ -299,22 +317,49 @@ static struct dma_domain *dma_domain_alloc(void) { struct dma_domain *dma_dom; struct page; + int ret; dma_dom = kzalloc(sizeof(struct dma_domain), GFP_KERNEL); if (!dma_dom) return NULL; - sunway_domain_init(&dma_dom->sdomain); + ret = sunway_domain_init(&dma_dom->sdomain); + if (ret) + return ERR_PTR(ret); + dma_dom->sdomain.type = IOMMU_DOMAIN_DMA; init_iova_domain(&dma_dom->iovad, PAGE_SIZE, IOVA_PFN(SW64_DMA_START)); dma_dom->sdomain.pt_root = (void *)get_zeroed_page(GFP_KERNEL); + if (!dma_dom->sdomain.pt_root) { + pr_err("Failed to allocate a new DMA Domain.\n"); + dma_domain_free(dma_dom); + return ERR_PTR(-ENOMEM); + } add_domain_to_list(&dma_dom->sdomain); return dma_dom; } +static void do_flush_dev(struct pci_controller *hose, u16 devid) +{ + struct sunway_iommu *iommu; + void __iomem *base; + + iommu = hose->pci_iommu; + if (!iommu) + return; + + base = iommu->reg_base_addr; + if (!base) + return; + + writeq(devid, base + DTLB_FLUSHDEV); + writeq(devid, base + PTLB_FLUSHDEV); + writeq(devid, base + PCACHE_FLUSHDEV); +} + static void device_flush_all(struct sunway_iommu_dev *sdata) { struct pci_controller *hose = pci_bus_to_pci_controller(sdata->pdev->bus); @@ -322,19 +367,14 @@ static void device_flush_all(struct sunway_iommu_dev *sdata) if (hose == NULL) return; - write_piu_ior0(hose->node, hose->index, DTLB_FLUSHDEV, sdata->devid); - write_piu_ior0(hose->node, hose->index, PTLB_FLUSHDEV, sdata->devid); - write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHDEV, sdata->devid); + do_flush_dev(hose, sdata->devid); - if (sdata->devid != sdata->alias) { - write_piu_ior0(hose->node, hose->index, DTLB_FLUSHDEV, sdata->alias); - write_piu_ior0(hose->node, hose->index, PTLB_FLUSHDEV, sdata->alias); - write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHDEV, sdata->alias); - } + if (sdata->devid != sdata->alias) + do_flush_dev(hose, sdata->alias); } /* iommu_ops device attach/unattach helpers */ -static bool +static int set_entry_by_devid(u16 devid, struct sunway_iommu_domain *sdomain, struct sunway_iommu *iommu) @@ -343,6 +383,7 @@ set_entry_by_devid(u16 devid, unsigned long *dte_l1, *dte_l2; unsigned long dte_l1_val, dte_l2_base, dte_l2_val; u16 bus_number, devfn; + int node; bus_number = PCI_BUS_NUM(devid); devfn = PCI_SLOT(devid) | PCI_FUNC(devid); @@ -350,35 +391,37 @@ set_entry_by_devid(u16 devid, dte_l1 = iommu->iommu_dtbr + bus_number; dte_l1_val = *dte_l1; + node = node_online(iommu->node) ? iommu->node : NUMA_NO_NODE; if (!dte_l1_val) { /* Alloc a new level-2 device table page */ - dt_page = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO, + dt_page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, get_order(PAGE_SIZE)); + if (!dt_page) + return -ENOMEM; - WARN_ON(!dt_page); dte_l2_base = (unsigned long)page_address(dt_page); dte_l1_val = (__pa(dte_l2_base) & PAGE_MASK) | SW64_IOMMU_ENTRY_VALID; *dte_l1 = dte_l1_val; } if (!sdomain->pt_root) { - pt_page = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO, 0); - WARN_ON(!pt_page); + pt_page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0); + if (!pt_page) + return -ENOMEM; + sdomain->pt_root = page_address(pt_page); } dte_l2 = __va(dte_l1_val & ~(SW64_IOMMU_ENTRY_VALID) & PAGE_MASK) + (devfn << 3); dte_l2_val = (__pa(sdomain->pt_root) & PAGE_MASK) | SW64_IOMMU_ENTRY_VALID; - if (sdomain->type == IOMMU_DOMAIN_IDENTITY) { + + if (sdomain->type == IOMMU_DOMAIN_IDENTITY) dte_l2_val |= 0x1; - *dte_l2 = dte_l2_val; - return true; - } *dte_l2 = dte_l2_val; pr_debug("iommu: device with id %d added to domain: %d\n", devid, sdomain->id); - return false; + return 0; } static void @@ -386,18 +429,17 @@ set_dte_entry(struct sunway_iommu_dev *sdev, struct sunway_iommu_domain *sdomain { struct sunway_iommu *iommu; struct pci_dev *pdev; - bool is_identity; pdev = sdev->pdev; if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) return; iommu = sdev->iommu; - is_identity = set_entry_by_devid(sdev->devid, sdomain, iommu); + set_entry_by_devid(sdev->devid, sdomain, iommu); if (sdev->devid != sdev->alias) - is_identity = set_entry_by_devid(sdev->alias, sdomain, iommu); + set_entry_by_devid(sdev->alias, sdomain, iommu); - if (is_identity) + if (sdomain->type == IOMMU_DOMAIN_IDENTITY) sdev->passthrough = IDENTMAP_ALL; device_flush_all(sdev); @@ -516,37 +558,6 @@ static struct sunway_iommu_dev *search_dev_data(u16 devid) * **********************************************************************/ -static struct sunway_iommu *sunway_iommu_early_init(struct pci_controller *hose) -{ - struct sunway_iommu *iommu; - struct page *page; - unsigned long base; - - hose->pci_iommu = kzalloc(sizeof(struct sunway_iommu), GFP_KERNEL); - if (!hose->pci_iommu) - return 0; - - iommu = hose->pci_iommu; - spin_lock_init(&iommu->dt_lock); - - iommu->node = hose->node; - if (!node_online(hose->node)) - iommu->node = -1; - - page = alloc_pages_node(iommu->node, __GFP_ZERO, get_order(PAGE_SIZE)); - iommu->iommu_dtbr = page_address(page); - - iommu->hose_pt = hose; - iommu->index = hose->index; - - iommu->enabled = true; - - base = __pa(iommu->iommu_dtbr) & PAGE_MASK; - write_piu_ior0(hose->node, hose->index, DTBASEADDR, base); - - return iommu; -} - unsigned long fetch_dte(struct sunway_iommu *iommu, unsigned long devid, enum exceptype type) { @@ -621,11 +632,13 @@ irqreturn_t iommu_interrupt(int irq, void *dev) struct pci_controller *hose = (struct pci_controller *)dev; struct sunway_iommu_domain *sdomain; struct sunway_iommu_dev *sdev; + struct sunway_iommu *iommu; unsigned long iommu_status; unsigned long type; unsigned long devid, dva; - iommu_status = read_piu_ior0(hose->node, hose->index, IOMMUEXCPT_STATUS); + iommu = hose->pci_iommu; + iommu_status = readq(iommu->reg_base_addr + IOMMUEXCPT_STATUS); if (!(iommu_status >> 63)) return IRQ_NONE; @@ -640,8 +653,7 @@ irqreturn_t iommu_interrupt(int irq, void *dev) pr_info("no such dev!!!\n"); iommu_status &= ~(1UL << 62); - write_piu_ior0(hose->node, hose->index, - IOMMUEXCPT_STATUS, iommu_status); + writeq(iommu_status, iommu->reg_base_addr + IOMMUEXCPT_STATUS); return IRQ_HANDLED; } @@ -650,13 +662,13 @@ irqreturn_t iommu_interrupt(int irq, void *dev) switch (type) { case DTE_LEVEL1: pr_info("invalid level1 dte, addr:%#lx, val:%#lx\n", - fetch_dte(hose->pci_iommu, devid, DTE_LEVEL1), - fetch_dte(hose->pci_iommu, devid, DTE_LEVEL1_VAL)); + fetch_dte(iommu, devid, DTE_LEVEL1), + fetch_dte(iommu, devid, DTE_LEVEL1_VAL)); break; case DTE_LEVEL2: pr_info("invalid level2 dte, addr:%#lx, val:%#lx\n", - fetch_dte(hose->pci_iommu, devid, DTE_LEVEL2), - fetch_dte(hose->pci_iommu, devid, DTE_LEVEL2_VAL)); + fetch_dte(iommu, devid, DTE_LEVEL2), + fetch_dte(iommu, devid, DTE_LEVEL2_VAL)); break; case PTE_LEVEL1: pr_info("invalid level1 pte, addr: %#lx, val:%#lx\n", @@ -669,8 +681,7 @@ irqreturn_t iommu_interrupt(int irq, void *dev) fetch_pte(sdomain, dva, PTE_LEVEL2_VAL)); iommu_status &= ~(1UL << 62); - write_piu_ior0(hose->node, hose->index, - IOMMUEXCPT_STATUS, iommu_status); + writeq(iommu_status, iommu->reg_base_addr + IOMMUEXCPT_STATUS); break; case UNAUTHORIZED_ACCESS: @@ -695,6 +706,7 @@ struct irqaction iommu_irqaction = { void sunway_enable_iommu_func(struct pci_controller *hose) { + struct sunway_iommu *iommu; unsigned int iommu_irq, err; unsigned long iommu_conf, iommu_ctrl; @@ -706,28 +718,18 @@ void sunway_enable_iommu_func(struct pci_controller *hose) if (err < 0) pr_info("sw iommu request irq failed!\n"); + iommu = hose->pci_iommu; iommu_ctrl = (1UL << 63) | (0x100UL << 10); - write_piu_ior0(hose->node, hose->index, IOMMUEXCPT_CTRL, iommu_ctrl); - iommu_conf = read_piu_ior0(hose->node, hose->index, PIUCONFIG0); + writeq(iommu_ctrl, iommu->reg_base_addr + IOMMUEXCPT_CTRL); + iommu_conf = readq(iommu->reg_base_addr + PIUCONFIG0); iommu_conf = iommu_conf | (0x3 << 7); - write_piu_ior0(hose->node, hose->index, PIUCONFIG0, iommu_conf); - write_piu_ior0(hose->node, hose->index, TIMEOUT_CONFIG, 0xf); - iommu_conf = read_piu_ior0(hose->node, hose->index, PIUCONFIG0); + writeq(iommu_conf, iommu->reg_base_addr + PIUCONFIG0); + writeq(0xf, iommu->reg_base_addr + TIMEOUT_CONFIG); + iommu_conf = readq(iommu->reg_base_addr + PIUCONFIG0); pr_debug("SW arch configure node %ld hose-%ld iommu_conf = %#lx\n", hose->node, hose->index, iommu_conf); } -static bool is_iommu_enable(struct pci_controller *hose) -{ - u64 rc_mask = 0x1; - - rc_mask <<= (8 * hose->node + hose->index); - if (iommu_enable_cmd & rc_mask) - return true; - - return false; -} - /* iommu cpu syscore ops */ static int iommu_cpu_suspend(void) { @@ -746,12 +748,54 @@ struct syscore_ops iommu_cpu_syscore_ops = { static struct iommu_domain *sunway_iommu_domain_alloc(unsigned type); +/* Init functions */ +static struct sunway_iommu *sunway_iommu_early_init(struct pci_controller *hose) +{ + struct sunway_iommu *iommu; + struct page *page; + unsigned long base; + int ret = 0, node; + + iommu = kzalloc(sizeof(struct sunway_iommu), GFP_KERNEL); + if (!iommu) { + ret = -ENOMEM; + return 0; + } + + spin_lock_init(&iommu->dt_lock); + + iommu->node = hose->node; + iommu->index = hose->index; + + node = node_online(iommu->node) ? iommu->node : NUMA_NO_NODE; + page = alloc_pages_node(node, __GFP_ZERO, get_order(PAGE_SIZE)); + if (!page) { + ret = -ENOMEM; + goto free_iommu; + } + + iommu->iommu_dtbr = page_address(page); + base = __pa(iommu->iommu_dtbr) & PAGE_MASK; + iommu->reg_base_addr = __va(MK_PIU_IOR0(iommu->node, iommu->index)); + writeq(base, iommu->reg_base_addr + DTBASEADDR); + + hose->pci_iommu = iommu; + iommu->enabled = true; + return iommu; + +free_iommu: + kfree(iommu); + + return ERR_PTR(ret); +} + static int sunway_iommu_init(void) { struct pci_controller *hose; struct sunway_iommu *iommu; - int ret; + unsigned long rc_mask; int iommu_index = 0; + int ret; sunway_iommu_domain_bitmap = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, @@ -762,19 +806,24 @@ static int sunway_iommu_init(void) /* Do the loop */ for (hose = hose_head; hose; hose = hose->next) { - if (!is_iommu_enable(hose)) { + rc_mask = MAX_NR_IOMMU_PER_NODE * hose->node + hose->index; + if (!test_bit(rc_mask, iommu_bitmap)) { hose->iommu_enable = false; continue; } iommu = sunway_iommu_early_init(hose); - iommu_device_sysfs_add(&iommu->iommu, NULL, NULL, "%d", - iommu_index); + + iommu_device_sysfs_add(&iommu->iommu, + NULL, NULL, "%d", iommu_index); iommu_device_set_ops(&iommu->iommu, &sunway_iommu_ops); iommu_device_register(&iommu->iommu); - iommu_index++; + sunway_enable_iommu_func(hose); hose->iommu_enable = true; + piu_flush_all(iommu); + + iommu_index++; } ret = iova_cache_get(); @@ -785,13 +834,9 @@ static int sunway_iommu_init(void) if (ret) return ret; - for (hose = hose_head; hose; hose = hose->next) - if (hose->iommu_enable) - piu_flush_all(hose); - register_syscore_ops(&iommu_cpu_syscore_ops); - return 1; + return 0; } subsys_initcall_sync(sunway_iommu_init); @@ -819,7 +864,6 @@ sunway_iommu_unmap_page(struct sunway_iommu_domain *sunway_domain, unsigned long *pte_l2, unmapped; pr_debug("%s iova %#lx, page_size %#lx\n", __func__, iova, page_size); - BUG_ON(!is_power_of_2(page_size)); unmapped = 0; while (unmapped < page_size) { @@ -838,7 +882,7 @@ sunway_iommu_unmap_page(struct sunway_iommu_domain *sunway_domain, int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, unsigned long bus_addr, unsigned long paddr, - size_t page_size) + size_t page_size, int iommu_prot) { /* * pde: page table entry @@ -851,6 +895,7 @@ int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, unsigned long pdebaseaddr; u64 *ptebasecond, ptebaseaddr; u64 pte_root = (__pa(sunway_domain->pt_root) & PAGE_MASK); + int node; iova_pfn = (unsigned long)(bus_addr >> PAGE_SHIFT); @@ -869,7 +914,9 @@ int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, iommu = get_first_iommu_from_domain(sunway_domain); if (!iommu) return -1; - page = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, 0); + + node = node_online(iommu->node) ? iommu->node : NUMA_NO_NODE; + page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0); if (!page) { pr_err("Allocating pages failed.\n"); return -1; @@ -904,7 +951,12 @@ int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, } pte = (paddr & PAGE_MASK) | SW64_IOMMU_ENTRY_VALID - | SW64_IOMMU_GRN_8K | SW64_IOMMU_ENABLE; + | SW64_IOMMU_GRN_8K; + + pte |= PTE_READE; + if (iommu_prot & IOMMU_WRITE) + pte |= PTE_WRITEE; + *(volatile u64 *)ptebaseaddr = pte; flush_pcache_by_addr(sunway_domain, ptebaseaddr); /* case 8M */ @@ -917,7 +969,11 @@ int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, ptes_one_cache = L1_CACHE_BYTES/sizeof(pte); pte = (paddr & PAGE_MASK) | SW64_IOMMU_ENTRY_VALID - | SW64_IOMMU_GRN_8M | SW64_IOMMU_ENABLE; + | SW64_IOMMU_GRN_8M; + + pte |= PTE_READE; + if (iommu_prot & IOMMU_WRITE) + pte |= PTE_WRITEE; for (i = 0; i < ptes_one_page; i++) { if (*ptr) { @@ -959,6 +1015,10 @@ static struct iommu_domain *sunway_iommu_domain_alloc(unsigned type) } sdomain->pt_root = (void *)get_zeroed_page(GFP_KERNEL); + if (!sdomain->pt_root) { + sunway_domain_free(sdomain); + return NULL; + } sdomain->domain.geometry.aperture_start = 0ULL; sdomain->domain.geometry.aperture_end = (~0ULL); @@ -986,6 +1046,7 @@ static struct iommu_domain *sunway_iommu_domain_alloc(unsigned type) sdomain->pt_root = (void *)get_zeroed_page(GFP_KERNEL); if (!sdomain->pt_root) { pr_err("Allocating pt_root failed!\n"); + sunway_domain_free(sdomain); return NULL; } @@ -1010,7 +1071,6 @@ static void clean_domain(struct sunway_iommu_domain *sdomain) entry = list_first_entry(&sdomain->dev_list, struct sunway_iommu_dev, list); - BUG_ON(!entry->domain); __detach_device(entry); } @@ -1027,8 +1087,6 @@ static void sunway_iommu_domain_free(struct iommu_domain *dom) if (sdomain->dev_cnt > 0) clean_domain(sdomain); - BUG_ON(sdomain->dev_cnt != 0); - if (!dom) return; @@ -1136,7 +1194,7 @@ sunway_iommu_map(struct iommu_domain *dom, unsigned long iova, if (iova >= SW64_BAR_ADDRESS) return 0; - ret = sunway_iommu_map_page(sdomain, iova, paddr, page_size); + ret = sunway_iommu_map_page(sdomain, iova, paddr, page_size, iommu_prot); return ret; } @@ -1316,13 +1374,35 @@ const struct iommu_ops sunway_iommu_ops = { * rc0 for cpu node 1. * *****************************************************************************/ +static int __init sunway_iommu_setup(char *str) +{ + unsigned long rc_val; + int ret; + + bitmap_zero(iommu_bitmap, 64); + + if (!strncmp(str, "on", 2)) { + bitmap_fill(iommu_bitmap, 64); + } else if (!strncmp(str, "off", 3)) { + bitmap_zero(iommu_bitmap, 64); + } else { + ret = kstrtoul(str, 16, &rc_val); + bitmap_from_u64(iommu_bitmap, rc_val); + } + + return ret; +} +__setup("sunway_iommu=", sunway_iommu_setup); + static int __init iommu_enable_setup(char *str) { + unsigned long rc_val; int ret; - unsigned long rc_bitmap = 0xffffffffUL; - ret = kstrtoul(str, 16, &rc_bitmap); - iommu_enable_cmd = rc_bitmap; + bitmap_zero(iommu_bitmap, 64); + + ret = kstrtoul(str, 16, &rc_val); + bitmap_from_u64(iommu_bitmap, rc_val); return ret; } diff --git a/drivers/iommu/sw64/iommu_v2.c b/drivers/iommu/sw64/iommu_v2.c index 7fff0ae16336..5e37ac28d934 100644 --- a/drivers/iommu/sw64/iommu_v2.c +++ b/drivers/iommu/sw64/iommu_v2.c @@ -2,7 +2,7 @@ /* * iommu.c: Generic sw64 IOMMU support * - * This is designed and tested for 3231. If there are no changes in hardware + * This is designed and tested for 6432. If there are no changes in hardware * in later chips, then it should work just as well. * */ @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,7 @@ #define MAX_DOMAIN_NUM 65536 #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT) #define SW64_32BIT_DMA_LIMIT (0xe0000000 - 1) -#define SW64_64BIT_DMA_LIMIT ((1UL << 41) - 1) +#define SW64_64BIT_DMA_LIMIT ((1UL << 42) - 1) #define SW64_BAR_ADDRESS (IO_BASE | PCI_BASE) #define SW64_IOMMU_PGSIZES (((1ULL) << PAGE_SHIFT) \ @@ -63,6 +64,13 @@ #define PAGE_8M_OFFSET_MASK ((1UL << PAGE_8M_SHIFT) - 1) #define MAX_IOVA_WIDTH (1UL << 42) +#define for_each_iommu(iommu) \ + list_for_each_entry(iommu, &iommu_list, list) + +#define MAX_NR_IOMMU_PER_NODE 16 + +LIST_HEAD(iommu_list); + /* IOMMU Exceptional Status */ enum exceptype { DTE_LEVEL1 = 0x0, @@ -79,7 +87,7 @@ enum exceptype { PTE_LEVEL3_VAL, }; -u64 iommu_enable_cmd; /* default IOMMU boot param: 0 */ +DECLARE_BITMAP(iommu_bitmap, 64); unsigned long *sunway_iommu_domain_bitmap; @@ -90,6 +98,8 @@ spinlock_t sunway_domain_lock; static LLIST_HEAD(dev_data_list); LIST_HEAD(sunway_domain_list); +struct acpi_table_header *dmar_tbl; + struct dma_domain { struct sunway_iommu_domain sdomain; struct iova_domain iovad; @@ -113,31 +123,63 @@ static int get_alias(struct pci_dev *pdev) } /* flush helpers */ -static void piu_flush_all(struct pci_controller *hose) +static void piu_flush_all(struct sunway_iommu *iommu) { - write_piu_ior0(hose->node, hose->index, DTLB_FLUSHALL, 0); - write_piu_ior0(hose->node, hose->index, PTLB_FLUSHALL, 0); - write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHALL, 0); + void __iomem *base; + + base = iommu->reg_base_addr; + if (!base) + return; + + writeq(0, base + DTLB_FLUSHALL); + writeq(0, base + PTLB_FLUSHALL); + writeq(0, base + PCACHE_FLUSHALL); +} + +static void do_pcache_flush(struct sunway_iommu *iommu, + unsigned long flush_addr) +{ + void __iomem *base; + + base = iommu->reg_base_addr; + if (!base) + return; + + writeq(flush_addr, base + PCACHE_FLUSHPADDR); } void flush_pcache_by_addr(struct sunway_iommu_domain *sdomain, unsigned long flush_addr) { struct pci_controller *hose; struct sunway_iommu_dev *sdev; + struct sunway_iommu *iommu; list_for_each_entry(sdev, &sdomain->dev_list, list) { hose = pci_bus_to_pci_controller(sdev->pdev->bus); + iommu = hose->pci_iommu; flush_addr = __pa(flush_addr); - write_piu_ior0(hose->node, hose->index, - PCACHE_FLUSHPADDR, flush_addr); + do_pcache_flush(iommu, flush_addr); } } +static void do_ptlb_flush(struct sunway_iommu *iommu, + unsigned long flush_addr) +{ + void __iomem *base; + + base = iommu->reg_base_addr; + if (!base) + return; + + writeq(flush_addr, base + PTLB_FLUSHVADDR); +} + void flush_ptlb_by_addr(struct sunway_iommu_domain *sdomain, unsigned long flush_addr) { struct pci_controller *hose; struct sunway_iommu_dev *sdev; + struct sunway_iommu *iommu; struct pci_dev *pdev; unsigned long address; u16 alias, bus_number, devfn; @@ -145,11 +187,11 @@ void flush_ptlb_by_addr(struct sunway_iommu_domain *sdomain, unsigned long flush list_for_each_entry(sdev, &sdomain->dev_list, list) { pdev = sdev->pdev; hose = pci_bus_to_pci_controller(pdev->bus); + iommu = hose->pci_iommu; address = (pdev->bus->number << 8) | pdev->devfn | (flush_addr << 16); - write_piu_ior0(hose->node, hose->index, - PTLB_FLUSHVADDR, address); + do_ptlb_flush(iommu, address); if (sdev->alias != sdev->devid) { alias = sdev->alias; @@ -158,8 +200,7 @@ void flush_ptlb_by_addr(struct sunway_iommu_domain *sdomain, unsigned long flush address = (bus_number << 8) | devfn | (flush_addr << 16); - write_piu_ior0(hose->node, hose->index, - PTLB_FLUSHVADDR, address); + do_ptlb_flush(iommu, address); } } } @@ -285,18 +326,20 @@ static int sunway_domain_init(struct sunway_iommu_domain *sdomain) return -ENOMEM; INIT_LIST_HEAD(&sdomain->dev_list); - return 1; + return 0; } static struct sunway_iommu_domain *sunway_domain_alloc(void) { struct sunway_iommu_domain *sdomain; + int ret; sdomain = kzalloc(sizeof(struct sunway_iommu_domain), GFP_KERNEL); if (!sdomain) return NULL; - if (!sunway_domain_init(sdomain)) { + ret = sunway_domain_init(sdomain); + if (ret) { kfree(sdomain); return NULL; } @@ -324,6 +367,24 @@ static struct dma_domain *dma_domain_alloc(void) return dma_dom; } +static void do_flush_dev(struct pci_controller *hose, u16 devid) +{ + struct sunway_iommu *iommu; + void __iomem *base; + + iommu = hose->pci_iommu; + if (!iommu) + return; + + base = iommu->reg_base_addr; + if (!base) + return; + + writeq(devid, base + DTLB_FLUSHDEV); + writeq(devid, base + PTLB_FLUSHDEV); + writeq(devid, base + PCACHE_FLUSHDEV); +} + static void device_flush_all(struct sunway_iommu_dev *sdata) { struct pci_controller *hose = pci_bus_to_pci_controller(sdata->pdev->bus); @@ -331,20 +392,15 @@ static void device_flush_all(struct sunway_iommu_dev *sdata) if (hose == NULL) return; - write_piu_ior0(hose->node, hose->index, DTLB_FLUSHDEV, sdata->devid); - write_piu_ior0(hose->node, hose->index, PTLB_FLUSHDEV, sdata->devid); - write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHDEV, sdata->devid); + do_flush_dev(hose, sdata->devid); - if (sdata->devid != sdata->alias) { - write_piu_ior0(hose->node, hose->index, DTLB_FLUSHDEV, sdata->alias); - write_piu_ior0(hose->node, hose->index, PTLB_FLUSHDEV, sdata->alias); - write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHDEV, sdata->alias); - } + if (sdata->devid != sdata->alias) + do_flush_dev(hose, sdata->alias); } /* iommu_ops device attach/unattach helpers */ -static bool set_entry_by_devid(u16 devid, +static int set_entry_by_devid(u16 devid, struct sunway_iommu_domain *sdomain, struct sunway_iommu *iommu) { @@ -352,6 +408,7 @@ static bool set_entry_by_devid(u16 devid, unsigned long *dte_l1, *dte_l2; unsigned long dte_l1_val, dte_l2_base, dte_l2_val; u16 bus_number, devfn; + int node; bus_number = PCI_BUS_NUM(devid); devfn = PCI_SLOT(devid) | PCI_FUNC(devid); @@ -360,34 +417,36 @@ static bool set_entry_by_devid(u16 devid, dte_l1_val = *dte_l1; if (!dte_l1_val) { + node = node_online(iommu->node) ? iommu->node : NUMA_NO_NODE; /* Alloc a new level-2 device table page */ - dt_page = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO, + dt_page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, get_order(PAGE_SIZE)); + if (!dt_page) + return -ENOMEM; - WARN_ON(!dt_page); dte_l2_base = (unsigned long)page_address(dt_page); dte_l1_val = (__pa(dte_l2_base) & PAGE_MASK) | SW64_IOMMU_ENTRY_VALID; *dte_l1 = dte_l1_val; } if (!sdomain->pt_root) { - pt_page = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO, 0); - WARN_ON(!pt_page); + node = node_online(iommu->node) ? iommu->node : NUMA_NO_NODE; + pt_page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0); + if (!pt_page) + return -ENOMEM; + sdomain->pt_root = page_address(pt_page); } dte_l2 = __va(dte_l1_val & ~(SW64_IOMMU_ENTRY_VALID) & PAGE_MASK) + (devfn << 3); dte_l2_val = (__pa(sdomain->pt_root) & PAGE_MASK) | SW64_IOMMU_ENTRY_VALID; - if (sdomain->type == IOMMU_DOMAIN_IDENTITY) { + if (sdomain->type == IOMMU_DOMAIN_IDENTITY) dte_l2_val |= 0x1; - *dte_l2 = dte_l2_val; - return true; - } *dte_l2 = dte_l2_val; pr_debug("iommu: device with id %d added to domain: %d\n", devid, sdomain->id); - return false; + return 0; } static void @@ -395,18 +454,17 @@ set_dte_entry(struct sunway_iommu_dev *sdev, struct sunway_iommu_domain *sdomain { struct sunway_iommu *iommu; struct pci_dev *pdev; - bool is_identity; pdev = sdev->pdev; if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) return; iommu = sdev->iommu; - is_identity = set_entry_by_devid(sdev->devid, sdomain, iommu); + set_entry_by_devid(sdev->devid, sdomain, iommu); if (sdev->devid != sdev->alias) - is_identity = set_entry_by_devid(sdev->alias, sdomain, iommu); + set_entry_by_devid(sdev->alias, sdomain, iommu); - if (is_identity) + if (sdomain->type == IOMMU_DOMAIN_IDENTITY) sdev->passthrough = IDENTMAP_ALL; device_flush_all(sdev); @@ -441,15 +499,15 @@ static void do_detach(struct sunway_iommu_dev *sdev_data) static int __attach_device(struct sunway_iommu_dev *sdev_data, struct sunway_iommu_domain *sdomain) { - int ret; + int ret = 0; spin_lock(&sdomain->lock); - ret = -EBUSY; - if (sdev_data->domain != NULL) + if (sdev_data->domain != NULL) { + ret = -EBUSY; goto out_unlock; + } do_attach(sdev_data, sdomain); - ret = 0; out_unlock: spin_unlock(&sdomain->lock); @@ -491,7 +549,7 @@ static void detach_device(struct device *dev) sdev = dev_iommu_priv_get(dev); sunway_domain = sdev->domain; - if (WARN_ON(!sdev->domain)) + if (!sdev->domain) return; spin_lock_irqsave(&sunway_iommu_device_table_lock, flags); @@ -530,30 +588,41 @@ static struct sunway_iommu *sunway_iommu_early_init(struct pci_controller *hose) struct sunway_iommu *iommu; struct page *page; unsigned long base; + int ret = 0; + int node; - hose->pci_iommu = kzalloc(sizeof(struct sunway_iommu), GFP_KERNEL); - if (!hose->pci_iommu) - return 0; + iommu = kzalloc(sizeof(struct sunway_iommu), GFP_KERNEL); + if (!iommu) { + ret = -ENOMEM; + goto out; + } - iommu = hose->pci_iommu; spin_lock_init(&iommu->dt_lock); iommu->node = hose->node; - if (!node_online(hose->node)) - iommu->node = -1; - - page = alloc_pages_node(iommu->node, __GFP_ZERO, get_order(PAGE_SIZE)); - iommu->iommu_dtbr = page_address(page); - - iommu->hose_pt = hose; iommu->index = hose->index; - iommu->enabled = true; + node = node_online(iommu->node) ? iommu->node : NUMA_NO_NODE; + page = alloc_pages_node(node, __GFP_ZERO, get_order(PAGE_SIZE)); + if (!page) { + ret = -ENOMEM; + goto free_iommu; + } + iommu->iommu_dtbr = page_address(page); base = __pa(iommu->iommu_dtbr) & PAGE_MASK; - write_piu_ior0(hose->node, hose->index, DTBASEADDR, base); + iommu->reg_base_addr = __va(MK_PIU_IOR0(iommu->node, iommu->index)); + writeq(base, iommu->reg_base_addr + DTBASEADDR); + + hose->pci_iommu = iommu; + iommu->enabled = true; return iommu; + +free_iommu: + kfree(iommu); +out: + return ERR_PTR(ret); } unsigned long fetch_dte(struct sunway_iommu *iommu, unsigned long devid, @@ -641,12 +710,14 @@ irqreturn_t iommu_interrupt(int irq, void *dev) { struct pci_controller *hose = (struct pci_controller *)dev; struct sunway_iommu_domain *sdomain; + struct sunway_iommu *iommu; struct sunway_iommu_dev *sdev; unsigned long iommu_status; unsigned long type; unsigned long devid, dva; - iommu_status = read_piu_ior0(hose->node, hose->index, IOMMUEXCPT_STATUS); + iommu = hose->pci_iommu; + iommu_status = readq(iommu->reg_base_addr + IOMMUEXCPT_STATUS); if (!(iommu_status >> 63)) return IRQ_NONE; @@ -661,8 +732,7 @@ irqreturn_t iommu_interrupt(int irq, void *dev) pr_info("no such dev!!!\n"); iommu_status &= ~(1UL << 62); - write_piu_ior0(hose->node, hose->index, - IOMMUEXCPT_STATUS, iommu_status); + writeq(iommu_status, iommu->reg_base_addr + IOMMUEXCPT_STATUS); return IRQ_HANDLED; } @@ -671,13 +741,13 @@ irqreturn_t iommu_interrupt(int irq, void *dev) switch (type) { case DTE_LEVEL1: pr_info("invalid level1 dte, addr:%#lx, val:%#lx\n", - fetch_dte(hose->pci_iommu, devid, DTE_LEVEL1), - fetch_dte(hose->pci_iommu, devid, DTE_LEVEL1_VAL)); + fetch_dte(iommu, devid, DTE_LEVEL1), + fetch_dte(iommu, devid, DTE_LEVEL1_VAL)); break; case DTE_LEVEL2: pr_info("invalid level2 dte, addr:%#lx, val:%#lx\n", - fetch_dte(hose->pci_iommu, devid, DTE_LEVEL2), - fetch_dte(hose->pci_iommu, devid, DTE_LEVEL2_VAL)); + fetch_dte(iommu, devid, DTE_LEVEL2), + fetch_dte(iommu, devid, DTE_LEVEL2_VAL)); break; case PTE_LEVEL1: pr_info("invalid level1 pte, addr: %#lx, val:%#lx\n", @@ -685,8 +755,7 @@ irqreturn_t iommu_interrupt(int irq, void *dev) fetch_pte(sdomain, dva, PTE_LEVEL1_VAL)); iommu_status &= ~(1UL << 62); - write_piu_ior0(hose->node, hose->index, - IOMMUEXCPT_STATUS, iommu_status); + writeq(iommu_status, iommu->reg_base_addr + IOMMUEXCPT_STATUS); break; case PTE_LEVEL2: pr_info("invalid level2 pte, addr: %#lx, val: %#lx\n", @@ -694,8 +763,7 @@ irqreturn_t iommu_interrupt(int irq, void *dev) fetch_pte(sdomain, dva, PTE_LEVEL2_VAL)); iommu_status &= ~(1UL << 62); - write_piu_ior0(hose->node, hose->index, - IOMMUEXCPT_STATUS, iommu_status); + writeq(iommu_status, iommu->reg_base_addr + IOMMUEXCPT_STATUS); break; case PTE_LEVEL3: @@ -704,8 +772,7 @@ irqreturn_t iommu_interrupt(int irq, void *dev) fetch_pte(sdomain, dva, PTE_LEVEL3_VAL)); iommu_status &= ~(1UL << 62); - write_piu_ior0(hose->node, hose->index, - IOMMUEXCPT_STATUS, iommu_status); + writeq(iommu_status, iommu->reg_base_addr + IOMMUEXCPT_STATUS); break; default: pr_info("iommu exception type %ld\n", type); @@ -723,6 +790,7 @@ struct irqaction iommu_irqaction = { void sunway_enable_iommu_func(struct pci_controller *hose) { + struct sunway_iommu *iommu; unsigned int iommu_irq, err; unsigned long iommu_conf, iommu_ctrl; @@ -734,28 +802,18 @@ void sunway_enable_iommu_func(struct pci_controller *hose) if (err < 0) pr_info("sw iommu request irq failed!\n"); + iommu = hose->pci_iommu; iommu_ctrl = (1UL << 63) | (0x100UL << 10); - write_piu_ior0(hose->node, hose->index, IOMMUEXCPT_CTRL, iommu_ctrl); - iommu_conf = read_piu_ior0(hose->node, hose->index, PIUCONFIG0); + writeq(iommu_ctrl, iommu->reg_base_addr + IOMMUEXCPT_CTRL); + iommu_conf = readq(iommu->reg_base_addr + PIUCONFIG0); iommu_conf = iommu_conf | (0x3 << 7); - write_piu_ior0(hose->node, hose->index, PIUCONFIG0, iommu_conf); - write_piu_ior0(hose->node, hose->index, TIMEOUT_CONFIG, 0xf); - iommu_conf = read_piu_ior0(hose->node, hose->index, PIUCONFIG0); + writeq(iommu_conf, iommu->reg_base_addr + PIUCONFIG0); + writeq(0xf, iommu->reg_base_addr + TIMEOUT_CONFIG); + iommu_conf = readq(iommu->reg_base_addr + PIUCONFIG0); pr_debug("SW arch configure node %ld hose-%ld iommu_conf = %#lx\n", hose->node, hose->index, iommu_conf); } -static bool is_iommu_enable(struct pci_controller *hose) -{ - u64 rc_mask = 0x1; - - rc_mask <<= (8 * hose->node + hose->index); - if (iommu_enable_cmd & rc_mask) - return true; - - return false; -} - /* iommu cpu syscore ops */ static int iommu_cpu_suspend(void) { @@ -774,23 +832,204 @@ struct syscore_ops iommu_cpu_syscore_ops = { static struct iommu_domain *sunway_iommu_domain_alloc(unsigned int type); -static int sunway_iommu_init(void) +/* Init functions */ +static int do_detect(void) +{ + acpi_status status = AE_OK; + + status = acpi_get_table(ACPI_SIG_DMAR, 0, &dmar_tbl); + + if (ACPI_SUCCESS(status) && !dmar_tbl) { + pr_warn("No DMAR found!\n"); + status = AE_NOT_FOUND; + } + + return ACPI_SUCCESS(status) ? 0 : -ENOENT; +} + +static struct pci_controller *find_hose_by_rcid(int node, int index) { struct pci_controller *hose; + + for (hose = hose_head; hose; hose = hose->next) + if (hose->node == node && hose->index == index) + return hose; + + return NULL; +} + +static int parse_one_drhd_unit(struct acpi_sw_dmar_header *header) +{ + struct acpi_dmar_sw_hardware_unit *drhd; struct sunway_iommu *iommu; + struct pci_controller *hose; + struct page *page; + unsigned long base; + int cmdline_enabled; + int rc_mask, ret, node; + int rc_node, rc_index; + + drhd = (struct acpi_dmar_sw_hardware_unit *)header; + if (!drhd->enable) + return 0; + + rc_node = (drhd->index >> 8) & 0xff; + rc_index = drhd->index & 0xff; + + hose = find_hose_by_rcid(rc_node, rc_index); + if (!hose) + return 0; + + iommu = kzalloc(sizeof(struct sunway_iommu), GFP_KERNEL); + if (!iommu) + return -ENOMEM; + + iommu->node = rc_node; + iommu->index = rc_index; + iommu->reg_base_addr = ioremap(drhd->address, drhd->size); + + rc_mask = MAX_NR_IOMMU_PER_NODE * iommu->node + iommu->index; + cmdline_enabled = test_bit(rc_mask, iommu_bitmap); + if (!cmdline_enabled) { + iommu->enabled = false; + ret = 0; + goto free_iommu; + } + + node = node_online(iommu->node) ? iommu->node : NUMA_NO_NODE; + page = alloc_pages_node(node, __GFP_ZERO, get_order(PAGE_SIZE)); + if (!page) { + ret = -ENOMEM; + goto free_iommu; + } + + iommu->iommu_dtbr = page_address(page); + base = __pa(iommu->iommu_dtbr) & PAGE_MASK; + writeq(base, iommu->reg_base_addr + DTBASEADDR); + + list_add(&iommu->list, &iommu_list); + iommu->enabled = true; + + hose->pci_iommu = iommu; + + pr_info("iommu: node: %ld index: %ld IOMMU enabled!\n", + iommu->node, iommu->index); + return 0; + +free_iommu: + kfree(iommu); + return ret; +} + +static int parse_drhd_units(struct acpi_table_sw_dmar *dmar) +{ + struct acpi_sw_dmar_header *iter, *start, *next, *end; + size_t len = dmar->header.length - sizeof(*dmar); + int ret, count = 0; + + /* Skip DMAR table, point to first DRHD table. */ + start = (struct acpi_sw_dmar_header *)(dmar + 1); + end = ((void *)start) + len; + + for (iter = start; iter < end; iter = next) { + next = (void *)iter + iter->length; + if (iter->length == 0) { + pr_warn(FW_BUG "Invalid 0-length structure\n"); + break; + } else if (next > end) { + pr_warn(FW_BUG "Record passes table end\n"); + return -EINVAL; + } + + if (iter->type >= ACPI_SW_DMAR_TYPE_RESERVED) { + pr_info("Unknown DMAR structure type %d\n", + iter->type); + } else if (iter->type == 0) { + ret = parse_one_drhd_unit(iter); + if (ret) + return ret; + } + count++; + } + + return 0; +} + +static int sunway_iommu_acpi_early_init(void) +{ int ret; + + struct acpi_table_sw_dmar *dmar; + + ret = do_detect(); + if (ret) + return ret; + + dmar = (struct acpi_table_sw_dmar *)dmar_tbl; + if (!dmar) + return -ENODEV; + + if (dmar->width < 42) { + pr_warn("Invalid DMAR haw\n"); + return -EINVAL; + } + pr_info("Host address width: %d\n", dmar->width); + + ret = parse_drhd_units(dmar); + + return ret; +} + +static int sunway_iommu_acpi_init(void) +{ + struct sunway_iommu *iommu; + struct pci_controller *hose; int iommu_index = 0; + int ret; - sunway_iommu_domain_bitmap = - (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(MAX_DOMAIN_NUM / 8)); - if (sunway_iommu_domain_bitmap == NULL) - return 0; - __set_bit(0, sunway_iommu_domain_bitmap); + ret = sunway_iommu_acpi_early_init(); + if (ret) + return ret; + + for_each_iommu(iommu) { + if (!iommu->enabled) + continue; + iommu_device_sysfs_add(&iommu->iommu, NULL, NULL, "%d", + iommu_index); + iommu_device_set_ops(&iommu->iommu, &sunway_iommu_ops); + iommu_device_register(&iommu->iommu); + iommu_index++; + hose = find_hose_by_rcid(iommu->node, iommu->index); + sunway_enable_iommu_func(hose); + hose->iommu_enable = true; + piu_flush_all(iommu); + } + + ret = iova_cache_get(); + if (ret) + return ret; + + ret = bus_set_iommu(&pci_bus_type, &sunway_iommu_ops); + if (ret) + return ret; + + register_syscore_ops(&iommu_cpu_syscore_ops); + + return 0; +} + +static int sunway_iommu_legacy_init(void) +{ + struct pci_controller *hose; + struct sunway_iommu *iommu; + unsigned long rc_mask; + int iommu_index = 0; + int ret; /* Do the loop */ for (hose = hose_head; hose; hose = hose->next) { - if (!is_iommu_enable(hose)) { + rc_mask = MAX_NR_IOMMU_PER_NODE * hose->node + hose->index; + if (!test_bit(rc_mask, iommu_bitmap)) { hose->iommu_enable = false; continue; } @@ -803,6 +1042,7 @@ static int sunway_iommu_init(void) iommu_index++; sunway_enable_iommu_func(hose); hose->iommu_enable = true; + piu_flush_all(iommu); } ret = iova_cache_get(); @@ -813,13 +1053,28 @@ static int sunway_iommu_init(void) if (ret) return ret; - for (hose = hose_head; hose; hose = hose->next) - if (hose->iommu_enable) - piu_flush_all(hose); - register_syscore_ops(&iommu_cpu_syscore_ops); - return 1; + return 0; +} + +static int sunway_iommu_init(void) +{ + int ret; + + sunway_iommu_domain_bitmap = + (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(MAX_DOMAIN_NUM / 8)); + if (!sunway_iommu_domain_bitmap) + return 0; + __set_bit(0, sunway_iommu_domain_bitmap); + + if (!acpi_disabled) + ret = sunway_iommu_acpi_init(); + else + ret = sunway_iommu_legacy_init(); + + return ret; } subsys_initcall_sync(sunway_iommu_init); @@ -829,7 +1084,8 @@ subsys_initcall_sync(sunway_iommu_init); * ******************************************************************************/ -struct sunway_iommu *get_first_iommu_from_domain(struct sunway_iommu_domain *sdomain) +struct sunway_iommu * +get_first_iommu_from_domain(struct sunway_iommu_domain *sdomain) { struct sunway_iommu *iommu; struct sunway_iommu_dev *entry; @@ -851,7 +1107,6 @@ sunway_iommu_unmap_page(struct sunway_iommu_domain *sunway_domain, int tmp = 1; pr_debug("%s iova %#lx, page_size %#lx\n", __func__, iova, page_size); - BUG_ON(!is_power_of_2(page_size)); switch (page_size) { case (1UL << 33): @@ -877,6 +1132,7 @@ sunway_iommu_unmap_page(struct sunway_iommu_domain *sunway_domain, current_level = 1; while (current_level <= level) { pte = &pte_base[offset]; + if (current_level == level) { if (grn == PTE_GRN_512M) { int i; @@ -904,7 +1160,7 @@ sunway_iommu_unmap_page(struct sunway_iommu_domain *sunway_domain, int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, unsigned long bus_addr, unsigned long paddr, - size_t page_size) + size_t page_size, int iommu_prot) { struct page *page; struct sunway_iommu *iommu; @@ -912,7 +1168,7 @@ int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, unsigned long *pte_base, *pte; unsigned long offset, grn = 0; int level = 0, current_level; - int tmp = 1; + int tmp = 1, node; iommu = get_first_iommu_from_domain(sunway_domain); if (!iommu) @@ -920,6 +1176,8 @@ int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, iova_pfn = bus_addr >> PAGE_SHIFT; pte_base = sunway_domain->pt_root; + node = node_online(iommu->node) ? iommu->node : NUMA_NO_NODE; + switch (page_size) { case (1UL << 33): level = 1; @@ -944,12 +1202,12 @@ int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, pte = &pte_base[offset]; if (!(*pte) || (current_level == level)) { - pte_val = PTE_VALID | PTE_RWE | grn; + pte_val = PTE_VALID | grn; if (current_level == level) { *(volatile u64 *)(pte) = 0; pte_val |= ((paddr & PAGE_MASK) | LAST_STAGE); } else { - page = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, 0); + page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0); if (!page) { pr_err("Allocating level%d page table pages failed.\n", (level + 1)); return -ENOMEM; @@ -958,6 +1216,10 @@ int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, pte_val |= (page_to_phys(page) & PAGE_MASK); } + pte_val |= PTE_READE; + if (iommu_prot & IOMMU_WRITE) + pte_val |= PTE_WRITEE; + if ((grn == PTE_GRN_512M) && (current_level == 2)) { int i; @@ -1044,7 +1306,6 @@ static void clean_domain(struct sunway_iommu_domain *sdomain) entry = list_first_entry(&sdomain->dev_list, struct sunway_iommu_dev, list); - BUG_ON(!entry->domain); __detach_device(entry); } @@ -1061,8 +1322,6 @@ static void sunway_iommu_domain_free(struct iommu_domain *dom) if (sdomain->dev_cnt > 0) clean_domain(sdomain); - BUG_ON(sdomain->dev_cnt != 0); - if (!dom) return; @@ -1206,7 +1465,7 @@ sunway_iommu_map(struct iommu_domain *dom, unsigned long iova, return -EFAULT; } - ret = sunway_iommu_map_page(sdomain, iova, paddr, page_size); + ret = sunway_iommu_map_page(sdomain, iova, paddr, page_size, iommu_prot); return ret; } @@ -1312,10 +1571,7 @@ static struct iommu_device *sunway_iommu_probe_device(struct device *dev) return ERR_PTR(-ENODEV); hose = pci_bus_to_pci_controller(pdev->bus); - if (!hose) - return ERR_PTR(-ENODEV); - - if (!hose->iommu_enable) + if (!hose || !hose->iommu_enable) return ERR_PTR(-ENODEV); if (dev_iommu_priv_get(dev)) { @@ -1387,19 +1643,25 @@ const struct iommu_ops sunway_iommu_ops = { /***************************************************************************** * * Boot param handle - * Each bit of iommu_enable bitmap represents an rc enable, and every 8 bits - * represents one cpu node. For example, iommu_enable=0x0100 means enabling - * rc0 for cpu node 1. * *****************************************************************************/ -static int __init iommu_enable_setup(char *str) +static int __init sunway_iommu_setup(char *str) { + unsigned long rc_val; int ret; - unsigned long rc_bitmap = 0xffffffffUL; - ret = kstrtoul(str, 16, &rc_bitmap); - iommu_enable_cmd = rc_bitmap; + /* IOMMU should be disabled by default. */ + bitmap_zero(iommu_bitmap, 64); + + if (!strncmp(str, "on", 2)) { + bitmap_fill(iommu_bitmap, 64); + } else if (!strncmp(str, "off", 3)) { + bitmap_zero(iommu_bitmap, 64); + } else { + ret = kstrtoul(str, 16, &rc_val); + bitmap_from_u64(iommu_bitmap, rc_val); + } return ret; } -__setup("iommu_enable=", iommu_enable_setup); +__setup("sunway_iommu=", sunway_iommu_setup); diff --git a/drivers/iommu/sw64/sunway_iommu.h b/drivers/iommu/sw64/sunway_iommu.h index d2a7e96657e9..ac09db0100bb 100644 --- a/drivers/iommu/sw64/sunway_iommu.h +++ b/drivers/iommu/sw64/sunway_iommu.h @@ -14,14 +14,16 @@ struct sunway_iommu_bypass_id { }; struct sunway_iommu { - int index; + unsigned long index; bool enabled; unsigned long *iommu_dtbr; spinlock_t dt_lock; /* Device Table Lock */ - int node; /* NUMA node */ + unsigned long node; /* NUMA node */ + void __iomem *reg_base_addr; struct pci_controller *hose_pt; struct iommu_device iommu; /* IOMMU core code handle */ + struct list_head list; }; struct sunway_iommu_dev { @@ -65,8 +67,8 @@ struct sunway_iommu_group { #define PAGE_8M_SHIFT 23 #define PAGE_512M_SHIFT 29 #define PAGE_8G_SHIFT 33 -#define SW64_IOMMU_ENABLE 3 -#define SW64_IOMMU_DISABLE 0 +#define PTE_WRITEE 0x2UL +#define PTE_READE 0x1UL #define SW64_IOMMU_LEVEL1_OFFSET 0x1ff #define SW64_IOMMU_LEVEL2_OFFSET 0x3ff #define SW64_IOMMU_LEVEL3_OFFSET 0x3ff diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index e3080d643c2c..420384964194 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -616,6 +616,34 @@ struct acpi_dmar_satc { u8 reserved; u16 segment; }; + +#ifdef CONFIG_SW64 +struct acpi_table_sw_dmar { + struct acpi_table_header header; /* Common ACPI table header*/ + u8 version; /* IOMMU version */ + u8 width; /* Host Address Width */ + u8 flags; +}; + +struct acpi_sw_dmar_header { + u8 type; + u8 length; +}; + +enum acpi_sw_dmar_type { + ACPI_SW_DMAR_TYPE_HARDWARE_UNIT = 0, + ACPI_SW_DMAR_TYPE_RESERVED = 1 +}; + +struct acpi_dmar_sw_hardware_unit { + struct acpi_sw_dmar_header header; + u16 index; + u32 size; + u8 enable; + u64 address; +}; +#endif + /******************************************************************************* * * DRTM - Dynamic Root of Trust for Measurement table -- Gitee From 362cb6403baf7a3765e87b3a97626ac5c8d34d79 Mon Sep 17 00:00:00 2001 From: Xu Yiwei Date: Fri, 19 Apr 2024 14:17:17 +0000 Subject: [PATCH 15/19] anolis: sw64: match platform device by acpi method ANBZ: #4688 Signed-off-by: Xu Yiwei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip3.dts | 6 +++--- drivers/acpi/acpi_apd.c | 4 ++-- drivers/gpio/gpio-sunway.c | 5 +++++ drivers/hwmon/sw64_pvt.c | 11 +++++++++++ drivers/i2c/busses/i2c-designware-platdrv.c | 1 + drivers/mfd/lpc_sunway.c | 10 +++++++++- drivers/spi/spi-sunway-mmio.c | 12 ++++++++++++ drivers/tty/serial/8250/8250_sunway.c | 1 + 8 files changed, 44 insertions(+), 6 deletions(-) diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index 920519566c58..8e93c76fe6d1 100644 --- a/arch/sw_64/boot/dts/chip3.dts +++ b/arch/sw_64/boot/dts/chip3.dts @@ -86,7 +86,7 @@ serial1@9033 { i2c0@0x8031 { #address-cells = <2>; #size-cells = <2>; - compatible = "snps,designware-i2c"; + compatible = "sunway,suntai-i2c", "snps,designware-i2c"; reg = <0x8031 0x0 0x0 0x8000>; clock-frequency = <100000>; clocks = <&i2cclk>; @@ -98,7 +98,7 @@ i2c0@0x8031 { i2c1@0x8034 { #address-cells = <1>; #size-cells = <0>; - compatible = "snps,designware-i2c"; + compatible = "sunway,suntai-i2c", "snps,designware-i2c"; reg = <0x8034 0x0 0x0 0x8000>; clock-frequency = <100000>; clocks = <&i2cclk>; @@ -110,7 +110,7 @@ i2c1@0x8034 { i2c2@0x8035 { #address-cells = <1>; #size-cells = <0>; - compatible = "snps,designware-i2c"; + compatible = "sunway,suntai-i2c", "snps,designware-i2c"; reg = <0x8035 0x0 0x0 0x8000>; clock-frequency = <100000>; clocks = <&i2cclk>; diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 2a3d15c11ce1..46833bf3174e 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -275,8 +275,8 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { { "BABA8030", APD_ADDR(baba_spi_desc)}, #endif #ifdef CONFIG_SW64 - { "HISI02A1", APD_ADDR(sunway_i2c_desc) }, - { "HISI0173", APD_ADDR(sunway_spi_desc) }, + { "SUNW0005", APD_ADDR(sunway_i2c_desc) }, + { "SUNW0008", APD_ADDR(sunway_spi_desc) }, #endif { } }; diff --git a/drivers/gpio/gpio-sunway.c b/drivers/gpio/gpio-sunway.c index 5feafc3bdd45..8db99635d970 100644 --- a/drivers/gpio/gpio-sunway.c +++ b/drivers/gpio/gpio-sunway.c @@ -648,13 +648,16 @@ static const struct of_device_id sunway_of_match[] = { }; MODULE_DEVICE_TABLE(of, sunway_of_match); +#ifdef CONFIG_ACPI static const struct acpi_device_id sunway_acpi_match[] = { {"HISI0181", 0}, {"APMC0D07", 0}, {"APMC0D81", GPIO_REG_OFFSET_V2}, + {"SUNW0002", 0}, { } }; MODULE_DEVICE_TABLE(acpi, sunway_acpi_match); +#endif static int sunway_gpio_probe(struct platform_device *pdev) { @@ -727,6 +730,8 @@ static int sunway_gpio_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, gpio); + def_info(&pdev->dev, "GPIO probe succeed\n"); + return 0; out_unregister: diff --git a/drivers/hwmon/sw64_pvt.c b/drivers/hwmon/sw64_pvt.c index 29098bc1f645..52382f90f930 100644 --- a/drivers/hwmon/sw64_pvt.c +++ b/drivers/hwmon/sw64_pvt.c @@ -184,6 +184,8 @@ static int pvt_vol_plat_probe(struct platform_device *pdev) return false; } + dev_info(&pdev->dev, "PVT probe succeed\n"); + return 0; err: @@ -199,11 +201,20 @@ static const struct of_device_id pvt_vol_of_match[] = { MODULE_DEVICE_TABLE(of, pvt_vol_of_match); #endif +#ifdef CONFIG_ACPI +static const struct acpi_device_id pvt_vol_acpi_match[] = { + { "SUNW0007", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, pvt_vol_acpi_match); +#endif + static struct platform_driver pvt_vol_driver = { .probe = pvt_vol_plat_probe, .driver = { .name = "pvt-sw64", .of_match_table = of_match_ptr(pvt_vol_of_match), + .acpi_match_table = ACPI_PTR(pvt_vol_acpi_match), }, }; diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 06af708ea86c..02b214b595bc 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -58,6 +58,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { { "HYGO0010", ACCESS_INTR_MASK }, { "BABA8000", 0 }, { "PHYT0003", 0 }, + { "SUNW0005", MODEL_SUNWAY }, { } }; MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); diff --git a/drivers/mfd/lpc_sunway.c b/drivers/mfd/lpc_sunway.c index b36029a79d3b..f39675f6f035 100644 --- a/drivers/mfd/lpc_sunway.c +++ b/drivers/mfd/lpc_sunway.c @@ -249,9 +249,16 @@ static const struct of_device_id chip3_lpc_of_match[] = { { .compatible = "sunway,chip3_lpc", }, { /* end of table */ } }; - MODULE_DEVICE_TABLE(of, chip3_lpc_of_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id chip3_lpc_acpi_match[] = { + { "SUNW0006", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, chip3_lpc_acpi_match); +#endif + #ifdef CONFIG_PM_SLEEP unsigned int lpc_irq_ctrl_value; unsigned int lpc_irq_irq_value; @@ -300,6 +307,7 @@ static struct platform_driver chip3_lpc_platform_driver = { .driver = { .name = "chip3_lpc", .of_match_table = chip3_lpc_of_match, + .acpi_match_table = ACPI_PTR(chip3_lpc_acpi_match), #ifdef CONFIG_PM_SLEEP .pm = &chip3_lpc_pm_ops, #endif diff --git a/drivers/spi/spi-sunway-mmio.c b/drivers/spi/spi-sunway-mmio.c index b170207cd104..7c8ba0a61ffb 100644 --- a/drivers/spi/spi-sunway-mmio.c +++ b/drivers/spi/spi-sunway-mmio.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "spi-sunway.h" @@ -107,6 +108,8 @@ static int chip_spi_mmio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, spimmio); + dev_info(&pdev->dev, "SPI(MMIO) probe succeed\n"); + return 0; out: clk_disable_unprepare(spimmio->clk); @@ -129,12 +132,21 @@ static const struct of_device_id chip_spi_mmio_of_match[] = { }; MODULE_DEVICE_TABLE(of, chip_spi_mmio_of_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id chip_spi_mmio_acpi_match[] = { + { "SUNW0008", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, chip_spi_mmio_acpi_match); +#endif + static struct platform_driver chip_spi_mmio_driver = { .probe = chip_spi_mmio_probe, .remove = chip_spi_mmio_remove, .driver = { .name = DRIVER_NAME, .of_match_table = chip_spi_mmio_of_match, + .acpi_match_table = ACPI_PTR(chip_spi_mmio_acpi_match), }, }; module_platform_driver(chip_spi_mmio_driver); diff --git a/drivers/tty/serial/8250/8250_sunway.c b/drivers/tty/serial/8250/8250_sunway.c index 7cac6f63dab7..af6fed308b33 100644 --- a/drivers/tty/serial/8250/8250_sunway.c +++ b/drivers/tty/serial/8250/8250_sunway.c @@ -762,6 +762,7 @@ static const struct acpi_device_id sunway8250_acpi_match[] = { { "AMDI0020", 0 }, { "BRCM2032", 0 }, { "HISI0031", 0 }, + { "SUNW0009", 0}, { }, }; MODULE_DEVICE_TABLE(acpi, sunway8250_acpi_match); -- Gitee From c1d71e88c76dd9a6dc2847305ae1f9cfa4ba46a2 Mon Sep 17 00:00:00 2001 From: Wang Yuanheng Date: Fri, 12 Apr 2024 17:25:34 +0800 Subject: [PATCH 16/19] anolis: sw64: kvm: remove some unused codes ANBZ: #4688 Signed-off-by: Wang Yuanheng Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kvm/entry_core4.S | 2 -- arch/sw_64/kvm/kvm_core4.c | 2 -- arch/sw_64/kvm/sw64.c | 3 --- 3 files changed, 7 deletions(-) diff --git a/arch/sw_64/kvm/entry_core4.S b/arch/sw_64/kvm/entry_core4.S index fb6757425f76..46036abc696c 100644 --- a/arch/sw_64/kvm/entry_core4.S +++ b/arch/sw_64/kvm/entry_core4.S @@ -219,8 +219,6 @@ $g_setfpec_over: ldl $15, PT_REGS_R15(sp) ldl $26, PT_REGS_R26(sp) ldl $29, PT_REGS_GP(sp) - csrr $2, CSR_PS - stl $2, PT_REGS_PS(sp) ldi sp, PT_REGS_SIZE(sp) /* restore host fpregs */ diff --git a/arch/sw_64/kvm/kvm_core4.c b/arch/sw_64/kvm/kvm_core4.c index 96f053da84ca..1646f191c9e3 100644 --- a/arch/sw_64/kvm/kvm_core4.c +++ b/arch/sw_64/kvm/kvm_core4.c @@ -63,8 +63,6 @@ int kvm_sw64_vcpu_reset(struct kvm_vcpu *vcpu) apt_unmap_vm(vcpu->kvm); hrtimer_cancel(&vcpu->arch.hrt); - vcpu->arch.vcb.soft_cid = vcpu->vcpu_id; - vcpu->arch.vcb.vcpu_irq_disabled = 1; vcpu->arch.pcpu_id = -1; /* force flush tlb for the first time */ vcpu->arch.power_off = 0; memset(&vcpu->arch.irqs_pending, 0, sizeof(vcpu->arch.irqs_pending)); diff --git a/arch/sw_64/kvm/sw64.c b/arch/sw_64/kvm/sw64.c index 88785541cf33..fa249289918c 100644 --- a/arch/sw_64/kvm/sw64.c +++ b/arch/sw_64/kvm/sw64.c @@ -277,9 +277,6 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) hrtimer_init(&vcpu->arch.hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); vcpu->arch.hrt.function = clockdev_fn; vcpu->arch.tsk = current; - - vcpu->arch.vcb.soft_cid = vcpu->vcpu_id; - vcpu->arch.vcb.vcpu_irq_disabled = 1; vcpu->arch.pcpu_id = -1; /* force flush tlb for the first time */ return 0; -- Gitee From 25c224a02e4c5f27dd4da1cf082a3ef1fe50c83f Mon Sep 17 00:00:00 2001 From: Tang Jinyang Date: Mon, 15 Apr 2024 17:22:18 +0800 Subject: [PATCH 17/19] anolis: sw64: fix PTBR save/restore for hibernation ANBZ: #4688 For C4, both CSR:PTBR_USR and CSR:PTBR_SYS have to be saved/restored to make hibernation work. Signed-off-by: Tang Jinyang Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/hibernate.c | 10 ++++++++++ arch/sw_64/kernel/hibernate_asm.S | 1 + 2 files changed, 11 insertions(+) diff --git a/arch/sw_64/kernel/hibernate.c b/arch/sw_64/kernel/hibernate.c index 644ea8504313..e84f93762f13 100644 --- a/arch/sw_64/kernel/hibernate.c +++ b/arch/sw_64/kernel/hibernate.c @@ -15,7 +15,12 @@ void save_processor_state(void) vcb->ksp = rdksp(); vcb->usp = rdusp(); vcb->soft_tid = rtid(); +#if defined(CONFIG_SUBARCH_C3B) vcb->ptbr = rdptbr(); +#elif defined(CONFIG_SUBARCH_C4) + vcb->ptbr_usr = sw64_read_csr(CSR_PTBR_USR); + vcb->ptbr_sys = sw64_read_csr(CSR_PTBR_SYS); +#endif } void restore_processor_state(void) @@ -25,7 +30,12 @@ void restore_processor_state(void) wrksp(vcb->ksp); wrusp(vcb->usp); wrtp(vcb->soft_tid); +#if defined(CONFIG_SUBARCH_C3B) wrptbr(vcb->ptbr); +#elif defined(CONFIG_SUBARCH_C4) + sw64_write_csr_imb(vcb->ptbr_usr, CSR_PTBR_USR); + sw64_write_csr_imb(vcb->ptbr_sys, CSR_PTBR_SYS); +#endif sflush(); tbiv(); } diff --git a/arch/sw_64/kernel/hibernate_asm.S b/arch/sw_64/kernel/hibernate_asm.S index ebba57b8bd8b..0655efc59a25 100644 --- a/arch/sw_64/kernel/hibernate_asm.S +++ b/arch/sw_64/kernel/hibernate_asm.S @@ -3,6 +3,7 @@ #include #include #include +#include .macro SAVE_KTP #ifdef CONFIG_SUBARCH_C3B -- Gitee From 3cc019ef57678a919614046e0d33aaf000d2a740 Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Thu, 18 Apr 2024 10:34:54 +0800 Subject: [PATCH 18/19] anolis: sw64: fix save_ktp compatibility for C3 ANBZ: #4688 Commit 6cac472dcc7e ("anolis: sw64: introduce new entry framework for C4") moves save_ktp() to head.S, and breaks compatibility with old firmware because hmcall_wrktp was not implemented. To fix it, save_ktp() should come after fixup_hmcall(). Fixes: 6cac472dcc7e ("anolis: sw64: introduce new entry framework for C4") Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hmcall.h | 9 +++++++-- arch/sw_64/kernel/early_init.c | 1 + arch/sw_64/kernel/head.S | 1 - 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/sw_64/include/asm/hmcall.h b/arch/sw_64/include/asm/hmcall.h index f998a781ea2a..ae52b220fa38 100644 --- a/arch/sw_64/include/asm/hmcall.h +++ b/arch/sw_64/include/asm/hmcall.h @@ -230,13 +230,18 @@ __CALL_HMC_W1(wrtp, unsigned long); /* Invalidate all user TLB with current UPN and VPN */ #define tbiu() __tbi(4, /* no second argument */) -#ifndef CONFIG_SUBARCH_C3B +#if defined(CONFIG_SUBARCH_C4) __CALL_HMC_W2(wrap_asid, unsigned long, unsigned long); -#else +static inline void save_ktp(void) +{ + __asm__ __volatile__("csrw $8, 0xef"); +} +#elif defined(CONFIG_SUBARCH_C3B) static inline void wrap_asid(unsigned long asid, unsigned long ptbr) { tbivp(); } +#define save_ktp() wrktp() #endif #endif /* !__ASSEMBLY__ */ diff --git a/arch/sw_64/kernel/early_init.c b/arch/sw_64/kernel/early_init.c index 3d7b9c4325a9..2ec7a3e99443 100644 --- a/arch/sw_64/kernel/early_init.c +++ b/arch/sw_64/kernel/early_init.c @@ -6,5 +6,6 @@ asmlinkage __visible void __init sw64_start_kernel(void) { fixup_hmcall(); + save_ktp(); start_kernel(); } diff --git a/arch/sw_64/kernel/head.S b/arch/sw_64/kernel/head.S index db4af8f9366b..15265fa4a0ea 100644 --- a/arch/sw_64/kernel/head.S +++ b/arch/sw_64/kernel/head.S @@ -32,7 +32,6 @@ __start: 1: ldgp $29, 0($27) /* We need to get current_task_info loaded up... */ ldi $8, init_task - SAVE_KTP ldl $30, TASK_STACK($8) /* ... and find our stack ... */ ldi $30, ASM_THREAD_SIZE($30) -- Gitee From d477169c6ae7e6d4ecf94ddd76e5174cda69fcbd Mon Sep 17 00:00:00 2001 From: He Chuyue Date: Mon, 22 Apr 2024 14:51:36 +0800 Subject: [PATCH 19/19] anolis: sw64: fix compile warning of do_entUna() ANBZ: #4688 Fix the following warnings: arch/sw_64/kernel/traps.c: In function 'do_entUna': arch/sw_64/kernel/traps.c:411:3: warning: this statement may fall through [-Wimplicit-fallthrough=] switch (fncode) { ^~~~~~ arch/sw_64/kernel/traps.c:585:2: note: here case 0x21: ^~~~ Fixes: effb2c5cb240 ("anolis: sw64: add unaligned access support for C4 new instructions") Signed-off-by: He Chuyue Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/traps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index 9460ddb176b6..c0d0a442fda4 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -582,6 +582,8 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, regs->regs[rb] = regs->regs[rb] + disp; return; } + return; + case 0x21: __asm__ __volatile__( "1: ldl_u %1, 0(%3)\n" -- Gitee