diff --git a/arch/sw_64/Makefile b/arch/sw_64/Makefile index a853a138bab242f1c503eb9bb2ca0775e4cefd9c..560d57ba2d6b6a10a86f2515db436344bfe80ee1 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) diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index 0e9ad8f5d464a5c2458fc88606f7390d3b84a088..8e93c76fe6d1665c6e2bcc9e1d8810a031ac7f90 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>; @@ -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/arch/sw_64/boot/dts/chip_vt.dts b/arch/sw_64/boot/dts/chip_vt.dts index 9889fcae7a5cf9476805807718cb7cd20151f01c..5f2ec68cb1d0fbb6152f8f7e8f80e3d787adb184 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/arch/sw_64/boot/dts/junzhang.dts b/arch/sw_64/boot/dts/junzhang.dts index 4e8cd655c798e2a4d85410198659aee00e32fd43..8712678a66e897540d1558f5f29cb77836105fab 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/arch/sw_64/include/asm/csr.h b/arch/sw_64/include/asm/csr.h index ea7b92e080111b4e4ac561bf93f59317aa7f85c2..9a089f9d4ad016ecdc8872aaf7dad6ec7b28a5ba 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/include/asm/fpu.h b/arch/sw_64/include/asm/fpu.h index 1d5e9b0efecc64df0c35c74c2185a08ca23660d2..763d763c04771162ebf65d15e7d7b9f60a340d61 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; } diff --git a/arch/sw_64/include/asm/hmcall.h b/arch/sw_64/include/asm/hmcall.h index f998a781ea2af37458612a9a48059f11a7b714fc..ae52b220fa38ae4b50be13bb13fafe5947b36e85 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/include/asm/kvm.h b/arch/sw_64/include/asm/kvm.h index 127d5b910d7497ac4590109ded6703185ca5bd16..9242d58352f0cf788057711673a233541137e210 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 diff --git a/arch/sw_64/include/asm/pci.h b/arch/sw_64/include/asm/pci.h index 8851c077964751d8534ce9e79def8819e8a32e0c..f3d8a25190f0b21d3236f9e607eb03edb74f694e 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/pgtable.h b/arch/sw_64/include/asm/pgtable.h index 102da6a411fe755d198421fe032b1208300341cd..9cfc23d83337ff5f9d344b4cfa43bbddf95e89af 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/include/asm/platform.h b/arch/sw_64/include/asm/platform.h index 7374f2087f90d0275d94aacb35df55e5f4464127..4f93d9532f9a6726b5768e06e3a466d94d6f92ea 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/include/asm/processor.h b/arch/sw_64/include/asm/processor.h index 26394854071f1897ba859fc802bf4ce6873b8bff..baed1c70bcfccb5b95db0c626bb2b1bd789834dd 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 diff --git a/arch/sw_64/include/asm/ptrace.h b/arch/sw_64/include/asm/ptrace.h index 3dcdd806f1c532d35eea3658939c2bac5e3cde6c..83d9a256b0a98ab8775e0d1ab1c5f5fbf8d773b0 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/include/asm/setup.h b/arch/sw_64/include/asm/setup.h index a22e79095fb40ef097dcf659390b26b784be9393..0a2edf9af3caa1ec805a20e1bbdfc65e47be5faf 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/include/asm/uncore_io_junzhang.h b/arch/sw_64/include/asm/uncore_io_junzhang.h index c0f759bbe74036055a19651371de708433fcacd0..2f745fe353658e2c838cf616a40ca5008f26b5d0 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 aeaadec5be16378e0944490319f6225b57d418be..695ce68dded9c32ca14704a4f15155125a02f5a0 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/kernel/acpi.c b/arch/sw_64/kernel/acpi.c index 7a423c917d43a37088180f7df2c009c9829ed569..0aa21e4d98a64170b320db32377914cb0217dbd4 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(); diff --git a/arch/sw_64/kernel/early_init.c b/arch/sw_64/kernel/early_init.c index 3d7b9c4325a9bae03cf0e2e934cdee287a307564..2ec7a3e994436034ec5d507858d9588d0f3ed6c0 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 db4af8f9366b8d0f123319091285ba88593231ba..15265fa4a0ea316121c5fd10ebebf464b275c172 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) diff --git a/arch/sw_64/kernel/hibernate.c b/arch/sw_64/kernel/hibernate.c index 644ea85043136066c1129b059735d3feb7dc9f71..e84f93762f13ef0f433444188331cd4eb8207132 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 ebba57b8bd8beb39c210abae4d23c1985b761429..0655efc59a252f34fbe019503b84f7cc2d84ef70 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 diff --git a/arch/sw_64/kernel/machine_kexec.c b/arch/sw_64/kernel/machine_kexec.c index d6758d48dc267c67e41eb6db4726fc0f0b8cfb51..dc1b2b4f5949ff10a7ddca5f9168b4fafedf079c 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 f427ffefda3b83490f5d654fb0b76a026dcb4969..ede5473c384d14cc38370d6e026649dce0d355ed 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; } +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/arch/sw_64/kernel/signal.c b/arch/sw_64/kernel/signal.c index 9ba151bb82d3993d6908d8ded38799bd0adb94cc..bc368d20c718750f1fff54ea59ba728428ad1c11 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 diff --git a/arch/sw_64/kernel/sys_sw64.c b/arch/sw_64/kernel/sys_sw64.c index 46e6197dce7654f6ffdbe9c86785272b6422a4d8..31e6a8d65cf91411054d1c6f00d6a376d01cc791 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 35d108b49a61ca7ac1058272e89dc2ecacf61923..1890bf129ddb0f531097adb461fc4422cc0f032c 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 diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index 9460ddb176b6d50a4ff1e930d52d2276ae2b1711..c0d0a442fda46c0c8cda8d83052b1a4b2616eb29 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" diff --git a/arch/sw_64/kvm/entry_core4.S b/arch/sw_64/kvm/entry_core4.S index fb6757425f76c188937f6225902df5f2035dd39f..46036abc696ce874d1ce2b0ee671fb7f792a2a35 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 96f053da84caf9edae5b8f8b6264a171339140fc..1646f191c9e3e1d431ba8cf134c7e12f5b792a8e 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/mmu.c b/arch/sw_64/kvm/mmu.c index f32b7383af454d0fb3b4ae5f75d3fbac3ba3223f..737d57406e79cfb3c516ca9392fa22630c756f4c 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 diff --git a/arch/sw_64/kvm/sw64.c b/arch/sw_64/kvm/sw64.c index 88785541cf33b051c5bd3dcba0e46a043ac2b933..fa249289918cb597e50c60c0c47a8b4822a213b4 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; diff --git a/arch/sw_64/pci/pci-legacy.c b/arch/sw_64/pci/pci-legacy.c index e0d515540e01e1f5fce77a08661da0528d922b23..228f58031626f5416ce8c37d51ef0b53ce947947 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/acpi_apd.c b/drivers/acpi/acpi_apd.c index 2a3d15c11ce16586b54144c922d2a459844065cb..46833bf3174eff9040ff5b645287ce9344de4f10 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/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index 7be2da09de2a25ccb419dc322a0ecc5eb6374b66..b45ab4f89bf1e37347e2caaf6af00ab0d7362e22 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/clocksource/timer-sw64.c b/drivers/clocksource/timer-sw64.c index 2b1670426b8a99c2acfb399909ab07a06182887c..72a5b05d496a0ffab25ae745ce3104c70cf0c880 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; diff --git a/drivers/gpio/gpio-sunway.c b/drivers/gpio/gpio-sunway.c index 5feafc3bdd457cfcc15580657e4f603b70ce72b3..8db99635d97081f7114d82d1c6ca6017c31be582 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 29098bc1f6450cd80cc00a9693c2eb04d5ce5f2a..52382f90f9301fe4dcdc0f8e877131137d443571 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 06af708ea86cab2c83bea76fe566d5388ccc3495..02b214b595bc7fe8fd2c5bf326a81aa39bc14ae7 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/iommu/sw64/Kconfig b/drivers/iommu/sw64/Kconfig index dbb6e75a84cb67b4402ab3d84aa3b0a5a914601e..4cc96bdcd233642f1d578454e0de4b46aab969c1 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 ad037e5a219b8797f5eb7fc10d2fc9ecdac1bc47..c0822d41b4469863a098d52e0870b07a456245aa 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 7fff0ae16336c85263af757765b1c5a59b76394e..5e37ac28d9345059a4c404c5b50632fd8ed5fc0c 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 d2a7e96657e9ae7f0a48cfefec776a599924c41e..ac09db0100bbc43c26b1b4f9f23e3a0c50b0e45d 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/drivers/irqchip/irq-sunway-lpc-intc.c b/drivers/irqchip/irq-sunway-lpc-intc.c index db10f363323af48da5381053c9843f633680c100..80442dae812f469b4593641613356578b8651f25 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 55ea830e26de09e0a9b53734aa0ded368f4ee93e..ca89a01316a3676bcfc6452a6a4358d4403478c0 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 diff --git a/drivers/mfd/lpc_sunway.c b/drivers/mfd/lpc_sunway.c index b36029a79d3b65c1b2e34492e189fa4daeef00bb..f39675f6f035e68acd6ef5d63e88ebda1181bd20 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/pci/controller/pci-sunway.c b/drivers/pci/controller/pci-sunway.c index 11df69dae968bef0b3583cdf943228524ee46fc4..f84f61fae96be9157eec0a58344f095dc5665f82 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); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b60c64e8037cff704ac9e2df2d867776bc184b8f..ad62cf203ea5831d1ae888f43de21c6c2e9640f1 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 b7cff3eda85b09d96deb3aa521a623c0c85e3d20..719367f636182a0a2dd9c554f62c391b21f197d8 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 45% rename from drivers/spi/spi-chip3-mmio.c rename to drivers/spi/spi-sunway-mmio.c index 1a1a9feaffa99a52f5c44f39a343f5770ba32664..7c8ba0a61ffb42a477967e70587a1060982db714 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 @@ -17,63 +17,65 @@ #include #include #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 +95,62 @@ 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); + + dev_info(&pdev->dev, "SPI(MMIO) probe succeed\n"); 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); + +#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 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, + .acpi_match_table = ACPI_PTR(chip_spi_mmio_acpi_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 568bcc65845d5a75a48611030393cd36abc098d6..6133173ea09aefa1d91c9744ecf70f191b54950a 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 88e49a9091a5d6bb8265fd0b8dc513d8e582b582..5f44050001d3536b6089100fd6757fa6c06ad45d 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 */ diff --git a/drivers/tty/serial/8250/8250_sunway.c b/drivers/tty/serial/8250/8250_sunway.c index 7cac6f63dab7f2ce987ebb5a06eb57035756fb1e..af6fed308b332bccc4557454af2eb0962c75376d 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); diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index e3080d643c2caba10394eca79ed678519706a64b..42038496419434a226b582ab72f2f0b46fa3a470 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