diff options
Diffstat (limited to 'arch')
565 files changed, 25193 insertions, 5211 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 81a3439a72bc..fcf9a41a4ef5 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1048,6 +1048,10 @@ config HAVE_NOINSTR_HACK config HAVE_NOINSTR_VALIDATION bool +config HAVE_UACCESS_VALIDATION + bool + select OBJTOOL + config HAVE_STACK_VALIDATION bool help diff --git a/arch/alpha/include/uapi/asm/termbits.h b/arch/alpha/include/uapi/asm/termbits.h index 4575ba34a0ea..f1290b22072b 100644 --- a/arch/alpha/include/uapi/asm/termbits.h +++ b/arch/alpha/include/uapi/asm/termbits.h @@ -2,10 +2,8 @@ #ifndef _ALPHA_TERMBITS_H #define _ALPHA_TERMBITS_H -#include <linux/posix_types.h> +#include <asm-generic/termbits-common.h> -typedef unsigned char cc_t; -typedef unsigned int speed_t; typedef unsigned int tcflag_t; /* @@ -53,76 +51,58 @@ struct ktermios { }; /* c_cc characters */ -#define VEOF 0 -#define VEOL 1 -#define VEOL2 2 -#define VERASE 3 -#define VWERASE 4 -#define VKILL 5 -#define VREPRINT 6 -#define VSWTC 7 -#define VINTR 8 -#define VQUIT 9 -#define VSUSP 10 -#define VSTART 12 -#define VSTOP 13 -#define VLNEXT 14 -#define VDISCARD 15 -#define VMIN 16 -#define VTIME 17 +#define VEOF 0 +#define VEOL 1 +#define VEOL2 2 +#define VERASE 3 +#define VWERASE 4 +#define VKILL 5 +#define VREPRINT 6 +#define VSWTC 7 +#define VINTR 8 +#define VQUIT 9 +#define VSUSP 10 +#define VSTART 12 +#define VSTOP 13 +#define VLNEXT 14 +#define VDISCARD 15 +#define VMIN 16 +#define VTIME 17 /* c_iflag bits */ -#define IGNBRK 0000001 -#define BRKINT 0000002 -#define IGNPAR 0000004 -#define PARMRK 0000010 -#define INPCK 0000020 -#define ISTRIP 0000040 -#define INLCR 0000100 -#define IGNCR 0000200 -#define ICRNL 0000400 -#define IXON 0001000 -#define IXOFF 0002000 -#define IXANY 0004000 -#define IUCLC 0010000 -#define IMAXBEL 0020000 -#define IUTF8 0040000 +#define IXON 0x0200 +#define IXOFF 0x0400 +#define IUCLC 0x1000 +#define IMAXBEL 0x2000 +#define IUTF8 0x4000 /* c_oflag bits */ -#define OPOST 0000001 -#define ONLCR 0000002 -#define OLCUC 0000004 - -#define OCRNL 0000010 -#define ONOCR 0000020 -#define ONLRET 0000040 - -#define OFILL 00000100 -#define OFDEL 00000200 -#define NLDLY 00001400 -#define NL0 00000000 -#define NL1 00000400 -#define NL2 00001000 -#define NL3 00001400 -#define TABDLY 00006000 -#define TAB0 00000000 -#define TAB1 00002000 -#define TAB2 00004000 -#define TAB3 00006000 -#define CRDLY 00030000 -#define CR0 00000000 -#define CR1 00010000 -#define CR2 00020000 -#define CR3 00030000 -#define FFDLY 00040000 -#define FF0 00000000 -#define FF1 00040000 -#define BSDLY 00100000 -#define BS0 00000000 -#define BS1 00100000 -#define VTDLY 00200000 -#define VT0 00000000 -#define VT1 00200000 +#define ONLCR 0x00002 +#define OLCUC 0x00004 +#define NLDLY 0x00300 +#define NL0 0x00000 +#define NL1 0x00100 +#define NL2 0x00200 +#define NL3 0x00300 +#define TABDLY 0x00c00 +#define TAB0 0x00000 +#define TAB1 0x00400 +#define TAB2 0x00800 +#define TAB3 0x00c00 +#define CRDLY 0x03000 +#define CR0 0x00000 +#define CR1 0x01000 +#define CR2 0x02000 +#define CR3 0x03000 +#define FFDLY 0x04000 +#define FF0 0x00000 +#define FF1 0x04000 +#define BSDLY 0x08000 +#define BS0 0x00000 +#define BS1 0x08000 +#define VTDLY 0x10000 +#define VT0 0x00000 +#define VT1 0x10000 /* * Should be equivalent to TAB3, see description of TAB3 in * POSIX.1-2008, Ch. 11.2.3 "Output Modes" @@ -130,61 +110,36 @@ struct ktermios { #define XTABS TAB3 /* c_cflag bit meaning */ -#define CBAUD 0000037 -#define B0 0000000 /* hang up */ -#define B50 0000001 -#define B75 0000002 -#define B110 0000003 -#define B134 0000004 -#define B150 0000005 -#define B200 0000006 -#define B300 0000007 -#define B600 0000010 -#define B1200 0000011 -#define B1800 0000012 -#define B2400 0000013 -#define B4800 0000014 -#define B9600 0000015 -#define B19200 0000016 -#define B38400 0000017 -#define EXTA B19200 -#define EXTB B38400 -#define CBAUDEX 0000000 -#define B57600 00020 -#define B115200 00021 -#define B230400 00022 -#define B460800 00023 -#define B500000 00024 -#define B576000 00025 -#define B921600 00026 -#define B1000000 00027 -#define B1152000 00030 -#define B1500000 00031 -#define B2000000 00032 -#define B2500000 00033 -#define B3000000 00034 -#define B3500000 00035 -#define B4000000 00036 -#define BOTHER 00037 - -#define CSIZE 00001400 -#define CS5 00000000 -#define CS6 00000400 -#define CS7 00001000 -#define CS8 00001400 - -#define CSTOPB 00002000 -#define CREAD 00004000 -#define PARENB 00010000 -#define PARODD 00020000 -#define HUPCL 00040000 - -#define CLOCAL 00100000 -#define CMSPAR 010000000000 /* mark or space (stick) parity */ -#define CRTSCTS 020000000000 /* flow control */ - -#define CIBAUD 07600000 -#define IBSHIFT 16 +#define CBAUD 0x0000001f +#define CBAUDEX 0x00000000 +#define BOTHER 0x0000001f +#define B57600 0x00000010 +#define B115200 0x00000011 +#define B230400 0x00000012 +#define B460800 0x00000013 +#define B500000 0x00000014 +#define B576000 0x00000015 +#define B921600 0x00000016 +#define B1000000 0x00000017 +#define B1152000 0x00000018 +#define B1500000 0x00000019 +#define B2000000 0x0000001a +#define B2500000 0x0000001b +#define B3000000 0x0000001c +#define B3500000 0x0000001d +#define B4000000 0x0000001e +#define CSIZE 0x00000300 +#define CS5 0x00000000 +#define CS6 0x00000100 +#define CS7 0x00000200 +#define CS8 0x00000300 +#define CSTOPB 0x00000400 +#define CREAD 0x00000800 +#define PARENB 0x00001000 +#define PARODD 0x00002000 +#define HUPCL 0x00004000 +#define CLOCAL 0x00008000 +#define CIBAUD 0x001f0000 /* c_lflag bits */ #define ISIG 0x00000080 @@ -204,17 +159,6 @@ struct ktermios { #define IEXTEN 0x00000400 #define EXTPROC 0x10000000 -/* Values for the ACTION argument to `tcflow'. */ -#define TCOOFF 0 -#define TCOON 1 -#define TCIOFF 2 -#define TCION 3 - -/* Values for the QUEUE_SELECTOR argument to `tcflush'. */ -#define TCIFLUSH 0 -#define TCOFLUSH 1 -#define TCIOFLUSH 2 - /* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'. */ #define TCSANOW 0 #define TCSADRAIN 1 diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 8bbeebb73cf0..d257293401e2 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -36,6 +36,7 @@ #include <linux/types.h> #include <linux/ipc.h> #include <linux/namei.h> +#include <linux/mount.h> #include <linux/uio.h> #include <linux/vfs.h> #include <linux/rcupdate.h> diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 5f8527081da9..e2e25f8b5e76 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -125,7 +125,7 @@ common_shutdown_1(void *generic_ptr) /* Wait for the secondaries to halt. */ set_cpu_present(boot_cpuid, false); set_cpu_possible(boot_cpuid, false); - while (cpumask_weight(cpu_present_mask)) + while (!cpumask_empty(cpu_present_mask)) barrier(); #endif @@ -233,10 +233,11 @@ release_thread(struct task_struct *dead_task) /* * Copy architecture-specific thread state */ -int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long kthread_arg, struct task_struct *p, - unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; extern void ret_from_fork(void); extern void ret_from_kernel_thread(void); @@ -249,13 +250,13 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, childti->pcb.ksp = (unsigned long) childstack; childti->pcb.flags = 1; /* set FEN, clear everything else */ - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { /* kernel thread */ memset(childstack, 0, sizeof(struct switch_stack) + sizeof(struct pt_regs)); childstack->r26 = (unsigned long) ret_from_kernel_thread; - childstack->r9 = usp; /* function */ - childstack->r10 = kthread_arg; + childstack->r9 = (unsigned long) args->fn; + childstack->r10 = (unsigned long) args->fn_arg; childregs->hae = alpha_mv.hae_cache; childti->pcb.usp = 0; return 0; diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index 5f7f5aab361f..3369f0700702 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -162,10 +162,11 @@ asmlinkage void ret_from_fork(void); * | user_r25 | * ------------------ <===== END of PAGE */ -int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long kthread_arg, struct task_struct *p, - unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct pt_regs *c_regs; /* child's pt_regs */ unsigned long *childksp; /* to unwind out of __switch_to() */ struct callee_regs *c_callee; /* child's callee regs */ @@ -191,11 +192,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, childksp[0] = 0; /* fp */ childksp[1] = (unsigned long)ret_from_fork; /* blink */ - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { memset(c_regs, 0, sizeof(struct pt_regs)); - c_callee->r13 = kthread_arg; - c_callee->r14 = usp; /* function */ + c_callee->r13 = (unsigned long)args->fn_arg; + c_callee->r14 = (unsigned long)args->fn; return 0; } diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 903165a400a7..7630ba9cb6cc 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -357,25 +357,6 @@ config ARCH_FOOTBRIDGE Support for systems based on the DC21285 companion chip ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder. -config ARCH_PXA - bool "PXA2xx/PXA3xx-based" - depends on CPU_LITTLE_ENDIAN - select ARCH_MTD_XIP - select ARM_CPU_SUSPEND if PM - select AUTO_ZRELADDR - select COMMON_CLK - select CLKSRC_PXA - select CLKSRC_MMIO - select TIMER_OF - select CPU_XSCALE if !CPU_XSC3 - select GPIO_PXA - select GPIOLIB - select IRQ_DOMAIN - select PLAT_PXA - select SPARSE_IRQ - help - Support for Intel/Marvell's PXA2xx/PXA3xx processor line. - config ARCH_RPC bool "RiscPC" depends on !CC_IS_CLANG && GCC_VERSION < 90100 && GCC_VERSION >= 60000 @@ -415,19 +396,6 @@ config ARCH_SA1100 help Support for StrongARM 11x0 based boards. -config ARCH_OMAP1 - bool "TI OMAP1" - depends on CPU_LITTLE_ENDIAN - select CLKSRC_MMIO - select FORCE_PCI if PCCARD - select GENERIC_IRQ_CHIP - select GPIOLIB - select HAVE_LEGACY_CLK - select IRQ_DOMAIN - select SPARSE_IRQ - help - Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx) - endchoice menu "Multiple platform selection" @@ -550,6 +518,8 @@ source "arch/arm/mach-highbank/Kconfig" source "arch/arm/mach-hisi/Kconfig" +source "arch/arm/mach-hpe/Kconfig" + source "arch/arm/mach-imx/Kconfig" source "arch/arm/mach-iop32x/Kconfig" @@ -593,7 +563,6 @@ source "arch/arm/mach-orion5x/Kconfig" source "arch/arm/mach-oxnas/Kconfig" source "arch/arm/mach-pxa/Kconfig" -source "arch/arm/plat-pxa/Kconfig" source "arch/arm/mach-qcom/Kconfig" @@ -672,9 +641,6 @@ config PLAT_ORION_LEGACY bool select PLAT_ORION -config PLAT_PXA - bool - config PLAT_VERSATILE bool diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 954ec707d182..c8e3633f5434 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -179,6 +179,7 @@ machine-$(CONFIG_ARCH_FOOTBRIDGE) += footbridge machine-$(CONFIG_ARCH_GEMINI) += gemini machine-$(CONFIG_ARCH_HIGHBANK) += highbank machine-$(CONFIG_ARCH_HISI) += hisi +machine-$(CONFIG_ARCH_HPE) += hpe machine-$(CONFIG_ARCH_IOP32X) += iop32x machine-$(CONFIG_ARCH_IXP4XX) += ixp4xx machine-$(CONFIG_ARCH_KEYSTONE) += keystone @@ -225,7 +226,6 @@ machine-$(CONFIG_PLAT_SPEAR) += spear # Platform directory name. This list is sorted alphanumerically # by CONFIG_* macro name. plat-$(CONFIG_PLAT_ORION) += orion -plat-$(CONFIG_PLAT_PXA) += pxa # The byte offset of the kernel image in RAM from the start of RAM. TEXT_OFFSET := $(textofs-y) diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index edfbedaa6168..184899808ee7 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -259,6 +259,8 @@ dtb-$(CONFIG_ARCH_HISI) += \ hi3519-demb.dtb dtb-$(CONFIG_ARCH_HIX5HD2) += \ hisi-x5hd2-dkb.dtb +dtb-$(CONFIG_ARCH_HPE_GXP) += \ + hpe-bmc-dl360gen10.dtb dtb-$(CONFIG_ARCH_INTEGRATOR) += \ integratorap.dtb \ integratorap-im-pd1.dtb \ @@ -1584,6 +1586,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-lenovo-hr630.dtb \ aspeed-bmc-lenovo-hr855xg2.dtb \ aspeed-bmc-microsoft-olympus.dtb \ + aspeed-bmc-nuvia-dc-scm.dtb \ aspeed-bmc-opp-lanyang.dtb \ aspeed-bmc-opp-mihawk.dtb \ aspeed-bmc-opp-mowgli.dtb \ diff --git a/arch/arm/boot/dts/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed-ast2600-evb.dts index b7eb552640cb..5a6063bd4508 100644 --- a/arch/arm/boot/dts/aspeed-ast2600-evb.dts +++ b/arch/arm/boot/dts/aspeed-ast2600-evb.dts @@ -23,6 +23,26 @@ reg = <0x80000000 0x80000000>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + video_engine_memory: video { + size = <0x04000000>; + alignment = <0x01000000>; + compatible = "shared-dma-pool"; + reusable; + }; + + gfx_memory: framebuffer { + size = <0x01000000>; + alignment = <0x01000000>; + compatible = "shared-dma-pool"; + reusable; + }; + }; + vcc_sdhci0: regulator-vcc-sdhci0 { compatible = "regulator-fixed"; regulator-name = "SDHCI0 Vcc"; @@ -103,7 +123,7 @@ &mac0 { status = "okay"; - phy-mode = "rgmii"; + phy-mode = "rgmii-rxid"; phy-handle = <ðphy0>; pinctrl-names = "default"; @@ -114,7 +134,7 @@ &mac1 { status = "okay"; - phy-mode = "rgmii"; + phy-mode = "rgmii-rxid"; phy-handle = <ðphy1>; pinctrl-names = "default"; @@ -300,3 +320,18 @@ vqmmc-supply = <&vccq_sdhci1>; clk-phase-sd-hs = <7>, <200>; }; + +&vhub { + status = "okay"; + pinctrl-names = "default"; +}; + +&video { + status = "okay"; + memory-region = <&video_engine_memory>; +}; + +&gfx { + status = "okay"; + memory-region = <&gfx_memory>; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-bletchley.dts index eaf1bc261ee3..41d2b1535d9a 100644 --- a/arch/arm/boot/dts/aspeed-bmc-facebook-bletchley.dts +++ b/arch/arm/boot/dts/aspeed-bmc-facebook-bletchley.dts @@ -51,26 +51,6 @@ }; }; - spi2_gpio: spi2-gpio { - compatible = "spi-gpio"; - #address-cells = <1>; - #size-cells = <0>; - - gpio-sck = <&gpio0 ASPEED_GPIO(X, 3) GPIO_ACTIVE_HIGH>; - gpio-mosi = <&gpio0 ASPEED_GPIO(X, 4) GPIO_ACTIVE_HIGH>; - gpio-miso = <&gpio0 ASPEED_GPIO(X, 5) GPIO_ACTIVE_HIGH>; - num-chipselects = <1>; - cs-gpios = <&gpio0 ASPEED_GPIO(X, 0) GPIO_ACTIVE_LOW>; - - flash@0 { - reg = <0>; - compatible = "jedec,spi-nor"; - m25p,fast-read; - label = "pnor"; - spi-max-frequency = <100000000>; - }; - }; - switchphy: ethernet-phy@0 { // Fixed link }; @@ -242,6 +222,19 @@ }; }; +&spi2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi2_default>; + + flash@0 { + status = "okay"; + m25p,fast-read; + label = "pnor"; + spi-max-frequency = <50000000>; + }; +}; + &i2c0 { status = "okay"; ina230@45 { @@ -260,6 +253,17 @@ reg = <0x4f>; }; + sled1_ioexp41: pca9536@41 { + compatible = "nxp,pca9536"; + reg = <0x41>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "SLED1_SWD_MUX", "SLED1_XRES_SWD_N", + "SLED1_CLKREQ_N", "SLED1_PCIE_PWR_EN"; + }; + sled1_ioexp: pca9539@76 { compatible = "nxp,pca9539"; reg = <0x76>; @@ -310,6 +314,11 @@ op-sink-microwatt = <10000000>; }; }; + + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + }; }; &i2c1 { @@ -330,6 +339,17 @@ reg = <0x4f>; }; + sled2_ioexp41: pca9536@41 { + compatible = "nxp,pca9536"; + reg = <0x41>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "SLED2_SWD_MUX", "SLED2_XRES_SWD_N", + "SLED2_CLKREQ_N", "SLED2_PCIE_PWR_EN"; + }; + sled2_ioexp: pca9539@76 { compatible = "nxp,pca9539"; reg = <0x76>; @@ -380,6 +400,11 @@ op-sink-microwatt = <10000000>; }; }; + + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + }; }; &i2c2 { @@ -400,6 +425,17 @@ reg = <0x4f>; }; + sled3_ioexp41: pca9536@41 { + compatible = "nxp,pca9536"; + reg = <0x41>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "SLED3_SWD_MUX", "SLED3_XRES_SWD_N", + "SLED3_CLKREQ_N", "SLED3_PCIE_PWR_EN"; + }; + sled3_ioexp: pca9539@76 { compatible = "nxp,pca9539"; reg = <0x76>; @@ -450,6 +486,11 @@ op-sink-microwatt = <10000000>; }; }; + + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + }; }; &i2c3 { @@ -470,6 +511,17 @@ reg = <0x4f>; }; + sled4_ioexp41: pca9536@41 { + compatible = "nxp,pca9536"; + reg = <0x41>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "SLED4_SWD_MUX", "SLED4_XRES_SWD_N", + "SLED4_CLKREQ_N", "SLED4_PCIE_PWR_EN"; + }; + sled4_ioexp: pca9539@76 { compatible = "nxp,pca9539"; reg = <0x76>; @@ -520,6 +572,11 @@ op-sink-microwatt = <10000000>; }; }; + + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + }; }; &i2c4 { @@ -540,6 +597,17 @@ reg = <0x4f>; }; + sled5_ioexp41: pca9536@41 { + compatible = "nxp,pca9536"; + reg = <0x41>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "SLED5_SWD_MUX", "SLED5_XRES_SWD_N", + "SLED5_CLKREQ_N", "SLED5_PCIE_PWR_EN"; + }; + sled5_ioexp: pca9539@76 { compatible = "nxp,pca9539"; reg = <0x76>; @@ -590,6 +658,11 @@ op-sink-microwatt = <10000000>; }; }; + + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + }; }; &i2c5 { @@ -610,6 +683,17 @@ reg = <0x4f>; }; + sled6_ioexp41: pca9536@41 { + compatible = "nxp,pca9536"; + reg = <0x41>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "SLED6_SWD_MUX", "SLED6_XRES_SWD_N", + "SLED6_CLKREQ_N", "SLED6_PCIE_PWR_EN"; + }; + sled6_ioexp: pca9539@76 { compatible = "nxp,pca9539"; reg = <0x76>; @@ -660,6 +744,11 @@ op-sink-microwatt = <10000000>; }; }; + + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + }; }; &i2c6 { @@ -732,6 +821,8 @@ compatible = "adi,adm1278"; reg = <0x11>; shunt-resistor-micro-ohms = <300>; + adi,volt-curr-sample-average = <128>; + adi,power-sample-average = <128>; }; tmp421@4c { @@ -771,43 +862,55 @@ &gpio0 { gpio-line-names = /*A0-A7*/ "","","","","","","","", - /*B0-B7*/ "","","SEL_SPI2_MUX","SPI2_MUX1", - "SPI2_MUX2","SPI2_MUX3","","", + /*B0-B7*/ "FUSB302_SLED1_INT_N","FUSB302_SLED2_INT_N", + "SEL_SPI2_MUX","SPI2_MUX1", + "SPI2_MUX2","SPI2_MUX3", + "","FUSB302_SLED3_INT_N", /*C0-C7*/ "","","","","","","","", /*D0-D7*/ "","","","","","","","", /*E0-E7*/ "","","","","","","","", - /*F0-F7*/ "","","","","","","","", - /*G0-G7*/ "BSM_FRU_WP","SWITCH_FRU_MUX","","", + /*F0-F7*/ "BMC_SLED1_STCK","BMC_SLED2_STCK", + "BMC_SLED3_STCK","BMC_SLED4_STCK", + "BMC_SLED5_STCK","BMC_SLED6_STCK", + "","", + /*G0-G7*/ "BSM_FRU_WP","SWITCH_FRU_MUX","","FM_SOL_UART_CH_SEL", "PWRGD_P1V05_VDDCORE","PWRGD_P1V5_VDD","","", /*H0-H7*/ "presence-riser1","presence-riser2", "presence-sled1","presence-sled2", "presence-sled3","presence-sled4", "presence-sled5","presence-sled6", - /*I0-I7*/ "REV_ID0","","REV_ID1","REV_ID2", - "","BSM_FLASH_WP_STATUS","BMC_TPM_PRES","", + /*I0-I7*/ "REV_ID0","", + "REV_ID1","REV_ID2", + "","BSM_FLASH_WP_STATUS", + "BMC_TPM_PRES_N","FUSB302_SLED6_INT_N", /*J0-J7*/ "","","","","","","","", /*K0-K7*/ "","","","","","","","", /*L0-L7*/ "","","","","","BMC_RTC_INT","","", - /*M0-M7*/ "ALERT_SLED1","ALERT_SLED2", - "ALERT_SLED3","ALERT_SLED4", - "ALERT_SLED5","ALERT_SLED6", - "P12V_AUX_ALERT1","", - /*N0-N7*/ "","","","","","","","", + /*M0-M7*/ "ALERT_SLED1_N","ALERT_SLED2_N", + "ALERT_SLED3_N","ALERT_SLED4_N", + "ALERT_SLED5_N","ALERT_SLED6_N", + "","", + /*N0-N7*/ "LED_POSTCODE_0","LED_POSTCODE_1", + "LED_POSTCODE_2","LED_POSTCODE_3", + "LED_POSTCODE_4","LED_POSTCODE_5", + "LED_POSTCODE_5","LED_POSTCODE_7", /*O0-O7*/ "","","","", "","BOARD_ID0","BOARD_ID1","BOARD_ID2", /*P0-P7*/ "","","","","","","","BMC_HEARTBEAT", /*Q0-Q7*/ "","","","","","","","", /*R0-R7*/ "","","","","","","","", /*S0-S7*/ "","","","BAT_DETECT", - "BMC_BT_WP0","BMC_BT_WP1","","", + "BMC_BT_WP0_N","BMC_BT_WP1_N","","FUSB302_SLED4_INT_N", /*T0-T7*/ "","","","","","","","", /*U0-U7*/ "","","","","","","","", - /*V0-V7*/ "PWRGD_CNS_PSU","RST_BMC_MVL","","PSU_PRSNT", + /*V0-V7*/ "PWRGD_CNS_PSU","RST_BMC_MVL_N", + "P12V_AUX_ALERT1_N","PSU_PRSNT", "USB2_SEL0_A","USB2_SEL1_A", "USB2_SEL0_B","USB2_SEL1_B", - /*W0-W7*/ "RST_FRONT_IOEXP","","","","","","","", + /*W0-W7*/ "RST_FRONT_IOEXP_N","","","","","","","", /*X0-X7*/ "","","","","","","","", - /*Y0-Y7*/ "BMC_SELF_HW_RST","BSM_PRSNT","BSM_FLASH_LATCH","", + /*Y0-Y7*/ "BMC_SELF_HW_RST","BSM_PRSNT_N", + "BSM_FLASH_LATCH_N","FUSB302_SLED5_INT_N", "","","","", /*Z0-Z7*/ "","","","","","","",""; }; @@ -834,7 +937,16 @@ &pinctrl_adc14_default &pinctrl_adc15_default>; }; +&mdio0 { + status = "okay"; + /* TODO: Add Marvell 88E6191X */ +}; + &mdio3 { status = "okay"; /* TODO: Add Marvell 88X3310 */ }; + +&ehci0 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts index 578f9e2fc7ed..382da7934eaa 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts @@ -283,7 +283,7 @@ /*P0-P7*/ "","","","","led-pcieslot-power","","","", /*Q0-Q7*/ "","","regulator-standby-faulted","","","","","", /*R0-R7*/ "bmc-tpm-reset","power-chassis-control","power-chassis-good","","","I2C_FLASH_MICRO_N","","", - /*S0-S7*/ "","","","","","","","", + /*S0-S7*/ "","","","","power-ffs-sync-history","","","", /*T0-T7*/ "","","","","","","","", /*U0-U7*/ "","","","","","","","", /*V0-V7*/ "","BMC_3RESTART_ATTEMPT_P","","","","","","", diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts index 528b49e2c0f8..7213434695bf 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts @@ -265,7 +265,7 @@ /*Q0-Q7*/ "cfam-reset","","regulator-standby-faulted","","","","","", /*R0-R7*/ "bmc-tpm-reset","power-chassis-control","power-chassis-good","","","","","", /*S0-S7*/ "presence-ps0","presence-ps1","presence-ps2","presence-ps3", - "","","","", + "power-ffs-sync-history","","","", /*T0-T7*/ "","","","","","","","", /*U0-U7*/ "","","","","","","","", /*V0-V7*/ "","","","","","","","", diff --git a/arch/arm/boot/dts/aspeed-bmc-nuvia-dc-scm.dts b/arch/arm/boot/dts/aspeed-bmc-nuvia-dc-scm.dts new file mode 100644 index 000000000000..f4a97cfb0f23 --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-nuvia-dc-scm.dts @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + +/dts-v1/; + +#include "aspeed-g6.dtsi" + +/ { + model = "Nuvia DC-SCM BMC"; + compatible = "nuvia,dc-scm-bmc", "aspeed,ast2600"; + + aliases { + serial4 = &uart5; + }; + + chosen { + stdout-path = &uart5; + bootargs = "console=ttyS4,115200n8"; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x40000000>; + }; +}; + +&mdio3 { + status = "okay"; + + ethphy3: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; +}; + +&mac2 { + status = "okay"; + + /* Bootloader sets up the MAC to insert delay */ + phy-mode = "rgmii"; + phy-handle = <ðphy3>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii3_default>; +}; + +&mac3 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii4_default>; + + use-ncsi; +}; + +&rtc { + status = "okay"; +}; + +&fmc { + status = "okay"; + + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + spi-max-frequency = <133000000>; +#include "openbmc-flash-layout-64.dtsi" + }; + + flash@1 { + status = "okay"; + m25p,fast-read; + label = "alt-bmc"; + spi-max-frequency = <133000000>; +#include "openbmc-flash-layout-64-alt.dtsi" + }; +}; + +&spi1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1_default>; + + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bios"; + spi-max-frequency = <133000000>; + }; +}; + +&gpio0 { + gpio-line-names = + /*A0-A7*/ "","","","","","","","", + /*B0-B7*/ "BMC_FLASH_MUX_SEL","","","","","","","", + /*C0-C7*/ "","","","","","","","", + /*D0-D7*/ "","","","","","","","", + /*E0-E7*/ "","","","","","","","", + /*F0-F7*/ "","","","","","","","", + /*G0-G7*/ "","","","","","","","", + /*H0-H7*/ "","","","","","","","", + /*I0-I7*/ "","","","","","","","", + /*J0-J7*/ "","","","","","","","", + /*K0-K7*/ "","","","","","","","", + /*L0-L7*/ "","","","","","","","", + /*M0-M7*/ "","","","","","","","", + /*N0-N7*/ "BMC_FWSPI_RST_N","","GPIO_1_BMC_3V3","","","","","", + /*O0-O7*/ "JTAG_MUX_A","JTAG_MUX_B","","","","","","", + /*P0-P7*/ "","","","","","","","", + /*Q0-Q7*/ "","","","","","","","", + /*R0-R7*/ "","","","","","","","", + /*S0-S7*/ "","","","","","","","", + /*T0-T7*/ "","","","","","","","", + /*U0-U7*/ "","","","","","","","", + /*V0-V7*/ "","","","SCMFPGA_SPARE_GPIO1_3V3", + "SCMFPGA_SPARE_GPIO2_3V3","SCMFPGA_SPARE_GPIO3_3V3", + "SCMFPGA_SPARE_GPIO4_3V3","SCMFPGA_SPARE_GPIO5_3V3", + /*W0-W7*/ "","","","","","","","", + /*X0-X7*/ "","","","","","","","", + /*Y0-Y7*/ "","","","","","","","", + /*Z0-Z7*/ "","","","","","","","", + /*AA0-AA7*/ "","","","","","","","", + /*AB0-AB7*/ "","","","","","","","", + /*AC0-AC7*/ "","","","","","","",""; +}; + +&gpio1 { + gpio-line-names = + /*A0-A7*/ "GPI_1_BMC_1V8","","","","","", + "SCMFPGA_SPARE_GPIO1_1V8","SCMFPGA_SPARE_GPIO2_1V8", + /*B0-B7*/ "SCMFPGA_SPARE_GPIO3_1V8","SCMFPGA_SPARE_GPIO4_1V8", + "SCMFPGA_SPARE_GPIO5_1V8","","","","","", + /*C0-C7*/ "","","","","","","","", + /*D0-D7*/ "","BMC_SPI1_RST_N","BIOS_FLASH_MUX_SEL","", + "","TPM2_PIRQ_N","TPM2_RST_N","", + /*E0-E7*/ "","","","","","","",""; +}; + +&i2c2 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c8 { + status = "okay"; +}; + +&i2c9 { + status = "okay"; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; +}; + +&i2c14 { + status = "okay"; +}; + +&i2c15 { + status = "okay"; +}; + +&vhub { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi index fa8b581c3d6c..530491ae5eb2 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi @@ -54,8 +54,7 @@ ranges; fmc: spi@1e620000 { - reg = < 0x1e620000 0x94 - 0x20000000 0x10000000 >; + reg = <0x1e620000 0x94>, <0x20000000 0x10000000>; #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2400-fmc"; @@ -65,34 +64,42 @@ flash@0 { reg = < 0 >; compatible = "jedec,spi-nor"; + spi-rx-bus-width = <2>; spi-max-frequency = <50000000>; status = "disabled"; }; flash@1 { reg = < 1 >; compatible = "jedec,spi-nor"; + spi-rx-bus-width = <2>; + spi-max-frequency = <50000000>; status = "disabled"; }; flash@2 { reg = < 2 >; compatible = "jedec,spi-nor"; + spi-rx-bus-width = <2>; + spi-max-frequency = <50000000>; status = "disabled"; }; flash@3 { reg = < 3 >; compatible = "jedec,spi-nor"; + spi-rx-bus-width = <2>; + spi-max-frequency = <50000000>; status = "disabled"; }; flash@4 { reg = < 4 >; compatible = "jedec,spi-nor"; + spi-rx-bus-width = <2>; + spi-max-frequency = <50000000>; status = "disabled"; }; }; spi: spi@1e630000 { - reg = < 0x1e630000 0x18 - 0x30000000 0x10000000 >; + reg = <0x1e630000 0x18>, <0x30000000 0x10000000>; #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2400-spi"; @@ -102,6 +109,7 @@ reg = < 0 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index 4147b397c883..c89092c3905b 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -55,8 +55,7 @@ ranges; fmc: spi@1e620000 { - reg = < 0x1e620000 0xc4 - 0x20000000 0x10000000 >; + reg = <0x1e620000 0xc4>, <0x20000000 0x10000000>; #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2500-fmc"; @@ -67,25 +66,27 @@ reg = < 0 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; flash@1 { reg = < 1 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; flash@2 { reg = < 2 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; }; spi1: spi@1e630000 { - reg = < 0x1e630000 0xc4 - 0x30000000 0x08000000 >; + reg = <0x1e630000 0xc4>, <0x30000000 0x08000000>; #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2500-spi"; @@ -95,19 +96,20 @@ reg = < 0 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; flash@1 { reg = < 1 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; }; spi2: spi@1e631000 { - reg = < 0x1e631000 0xc4 - 0x38000000 0x08000000 >; + reg = <0x1e631000 0xc4>, <0x38000000 0x08000000>; #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2500-spi"; @@ -117,12 +119,14 @@ reg = < 0 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; flash@1 { reg = < 1 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi index 3c1011678ce6..6660564855ff 100644 --- a/arch/arm/boot/dts/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed-g6.dtsi @@ -95,8 +95,7 @@ }; fmc: spi@1e620000 { - reg = < 0x1e620000 0xc4 - 0x20000000 0x10000000 >; + reg = <0x1e620000 0xc4>, <0x20000000 0x10000000>; #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2600-fmc"; @@ -107,25 +106,27 @@ reg = < 0 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; flash@1 { reg = < 1 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; flash@2 { reg = < 2 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; }; spi1: spi@1e630000 { - reg = < 0x1e630000 0xc4 - 0x30000000 0x10000000 >; + reg = <0x1e630000 0xc4>, <0x30000000 0x10000000>; #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2600-spi"; @@ -135,19 +136,20 @@ reg = < 0 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; flash@1 { reg = < 1 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; }; spi2: spi@1e631000 { - reg = < 0x1e631000 0xc4 - 0x50000000 0x10000000 >; + reg = <0x1e631000 0xc4>, <0x50000000 0x10000000>; #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2600-spi"; @@ -157,18 +159,21 @@ reg = < 0 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; flash@1 { reg = < 1 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; flash@2 { reg = < 2 >; compatible = "jedec,spi-nor"; spi-max-frequency = <50000000>; + spi-rx-bus-width = <2>; status = "disabled"; }; }; @@ -302,6 +307,16 @@ status = "disabled"; }; + udc: usb@1e6a2000 { + compatible = "aspeed,ast2600-udc"; + reg = <0x1e6a2000 0x300>; + interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb2bd_default>; + status = "disabled"; + }; + apb { compatible = "simple-bus"; #address-cells = <1>; @@ -355,6 +370,17 @@ quality = <100>; }; + gfx: display@1e6e6000 { + compatible = "aspeed,ast2600-gfx", "syscon"; + reg = <0x1e6e6000 0x1000>; + reg-io-width = <4>; + clocks = <&syscon ASPEED_CLK_GATE_D1CLK>; + resets = <&syscon ASPEED_RESET_GRAPHICS>; + syscon = <&syscon>; + status = "disabled"; + interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; + }; + xdma: xdma@1e6e7000 { compatible = "aspeed,ast2600-xdma"; reg = <0x1e6e7000 0x100>; diff --git a/arch/arm/boot/dts/at91-sama7g5ek.dts b/arch/arm/boot/dts/at91-sama7g5ek.dts index d83f76a6cd6a..103544620fd7 100644 --- a/arch/arm/boot/dts/at91-sama7g5ek.dts +++ b/arch/arm/boot/dts/at91-sama7g5ek.dts @@ -14,6 +14,7 @@ #include <dt-bindings/mfd/atmel-flexcom.h> #include <dt-bindings/input/input.h> #include <dt-bindings/pinctrl/at91.h> +#include <dt-bindings/sound/microchip,pdmc.h> / { model = "Microchip SAMA7G5-EK"; @@ -456,7 +457,7 @@ &pinctrl_gmac1_mdio_default &pinctrl_gmac1_phy_irq>; phy-mode = "rmii"; - status = "okay"; + status = "okay"; /* Conflict with pdmc0. */ ethernet-phy@0 { reg = <0x0>; @@ -470,6 +471,17 @@ pinctrl-0 = <&pinctrl_i2s0_default>; }; +&pdmc0 { + #sound-dai-cells = <0>; + microchip,mic-pos = <MCHP_PDMC_DS0 MCHP_PDMC_CLK_NEGATIVE>, /* MIC 1 */ + <MCHP_PDMC_DS1 MCHP_PDMC_CLK_NEGATIVE>, /* MIC 2 */ + <MCHP_PDMC_DS0 MCHP_PDMC_CLK_POSITIVE>, /* MIC 3 */ + <MCHP_PDMC_DS1 MCHP_PDMC_CLK_POSITIVE>; /* MIC 4 */ + status = "disabled"; /* Conflict with gmac1. */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pdmc0_default>; +}; + &pioA { pinctrl_can0_default: can0_default { @@ -639,6 +651,13 @@ bias-disable; }; + pinctrl_pdmc0_default: pdmc0_default { + pinmux = <PIN_PD23__PDMC0_DS0>, + <PIN_PD24__PDMC0_DS1>, + <PIN_PD22__PDMC0_CLK>; + bias_disable; + }; + pinctrl_qspi: qspi { pinmux = <PIN_PB12__QSPI0_IO0>, <PIN_PB11__QSPI0_IO1>, diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts index 8f11c0b7d76d..6fb4fe49cf1c 100644 --- a/arch/arm/boot/dts/at91sam9261ek.dts +++ b/arch/arm/boot/dts/at91sam9261ek.dts @@ -178,6 +178,10 @@ status = "okay"; }; + rtc@fffffd20 { + atmel,rtt-rtc-time-reg = <&gpbr 0x0>; + }; + watchdog@fffffd40 { status = "okay"; }; diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts index 42e734020235..e732565913a4 100644 --- a/arch/arm/boot/dts/at91sam9263ek.dts +++ b/arch/arm/boot/dts/at91sam9263ek.dts @@ -102,6 +102,10 @@ }; }; + rtc@fffffd20 { + atmel,rtt-rtc-time-reg = <&gpbr 0x0>; + }; + watchdog@fffffd40 { status = "okay"; }; diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts index d74b8d9d84aa..ddaadfec6751 100644 --- a/arch/arm/boot/dts/at91sam9rlek.dts +++ b/arch/arm/boot/dts/at91sam9rlek.dts @@ -212,6 +212,10 @@ status = "okay"; }; + rtc@fffffd20 { + atmel,rtt-rtc-time-reg = <&gpbr 0x0>; + }; + rtc@fffffe00 { status = "okay"; }; diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi index c3942b4e82ad..0386376fa486 100644 --- a/arch/arm/boot/dts/da850.dtsi +++ b/arch/arm/boot/dts/da850.dtsi @@ -679,7 +679,9 @@ "scheduler", "queuemgr"; interrupts = <58>; #dma-cells = <2>; + /* For backwards compatibility: */ #dma-channels = <4>; + dma-channels = <4>; power-domains = <&psc1 1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/hpe-bmc-dl360gen10.dts b/arch/arm/boot/dts/hpe-bmc-dl360gen10.dts new file mode 100644 index 000000000000..3a7382ce40ef --- /dev/null +++ b/arch/arm/boot/dts/hpe-bmc-dl360gen10.dts @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for HPE DL360Gen10 + */ + +/include/ "hpe-gxp.dtsi" + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "hpe,gxp-dl360gen10", "hpe,gxp"; + model = "Hewlett Packard Enterprise ProLiant dl360 Gen10"; + + aliases { + serial0 = &uartc; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x40000000 0x20000000>; + }; +}; diff --git a/arch/arm/boot/dts/hpe-gxp.dtsi b/arch/arm/boot/dts/hpe-gxp.dtsi new file mode 100644 index 000000000000..cf735b3c4f35 --- /dev/null +++ b/arch/arm/boot/dts/hpe-gxp.dtsi @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for HPE GXP + */ + +/dts-v1/; +/ { + model = "Hewlett Packard Enterprise GXP BMC"; + compatible = "hpe,gxp"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + device_type = "cpu"; + next-level-cache = <&L2>; + }; + }; + + clocks { + pll: clock-0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1600000000>; + }; + + iopclk: clock-1 { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clock-div = <4>; + clock-mult = <1>; + clocks = <&pll>; + }; + }; + + axi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + dma-ranges; + + L2: cache-controller@b0040000 { + compatible = "arm,pl310-cache"; + reg = <0xb0040000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + ahb@c0000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xc0000000 0x30000000>; + dma-ranges; + + vic0: interrupt-controller@eff0000 { + compatible = "arm,pl192-vic"; + reg = <0xeff0000 0x1000>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + vic1: interrupt-controller@80f00000 { + compatible = "arm,pl192-vic"; + reg = <0x80f00000 0x1000>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + uarta: serial@e0 { + compatible = "ns16550a"; + reg = <0xe0 0x8>; + interrupts = <17>; + interrupt-parent = <&vic0>; + clock-frequency = <1846153>; + reg-shift = <0>; + }; + + uartb: serial@e8 { + compatible = "ns16550a"; + reg = <0xe8 0x8>; + interrupts = <18>; + interrupt-parent = <&vic0>; + clock-frequency = <1846153>; + reg-shift = <0>; + }; + + uartc: serial@f0 { + compatible = "ns16550a"; + reg = <0xf0 0x8>; + interrupts = <19>; + interrupt-parent = <&vic0>; + clock-frequency = <1846153>; + reg-shift = <0>; + }; + + usb0: usb@efe0000 { + compatible = "hpe,gxp-ehci", "generic-ehci"; + reg = <0xefe0000 0x100>; + interrupts = <7>; + interrupt-parent = <&vic0>; + }; + + st: timer@80 { + compatible = "hpe,gxp-timer"; + reg = <0x80 0x16>; + interrupts = <0>; + interrupt-parent = <&vic0>; + clocks = <&iopclk>; + clock-names = "iop"; + }; + + usb1: usb@efe0100 { + compatible = "hpe,gxp-ohci", "generic-ohci"; + reg = <0xefe0100 0x110>; + interrupts = <6>; + interrupt-parent = <&vic0>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/mmp2.dtsi b/arch/arm/boot/dts/mmp2.dtsi index 46984d4c5224..987d792f67ea 100644 --- a/arch/arm/boot/dts/mmp2.dtsi +++ b/arch/arm/boot/dts/mmp2.dtsi @@ -275,7 +275,9 @@ compatible = "marvell,pdma-1.0"; reg = <0xd4000000 0x10000>; interrupts = <48>; + /* For backwards compatibility: */ #dma-channels = <16>; + dma-channels = <16>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/pxa25x.dtsi b/arch/arm/boot/dts/pxa25x.dtsi index a248bf038033..5f8300e356ad 100644 --- a/arch/arm/boot/dts/pxa25x.dtsi +++ b/arch/arm/boot/dts/pxa25x.dtsi @@ -38,9 +38,12 @@ compatible = "marvell,pdma-1.0"; reg = <0x40000000 0x10000>; interrupts = <25>; - #dma-channels = <16>; #dma-cells = <2>; + /* For backwards compatibility: */ + #dma-channels = <16>; + dma-channels = <16>; #dma-requests = <40>; + dma-requests = <40>; status = "okay"; }; diff --git a/arch/arm/boot/dts/pxa27x.dtsi b/arch/arm/boot/dts/pxa27x.dtsi index ccbecad9c5c7..a2cbfb3be609 100644 --- a/arch/arm/boot/dts/pxa27x.dtsi +++ b/arch/arm/boot/dts/pxa27x.dtsi @@ -12,9 +12,12 @@ compatible = "marvell,pdma-1.0"; reg = <0x40000000 0x10000>; interrupts = <25>; - #dma-channels = <32>; #dma-cells = <2>; + /* For backwards compatibility: */ + #dma-channels = <32>; + dma-channels = <32>; #dma-requests = <75>; + dma-requests = <75>; status = "okay"; }; diff --git a/arch/arm/boot/dts/pxa3xx.dtsi b/arch/arm/boot/dts/pxa3xx.dtsi index d19674812cd2..f9c216f91865 100644 --- a/arch/arm/boot/dts/pxa3xx.dtsi +++ b/arch/arm/boot/dts/pxa3xx.dtsi @@ -122,9 +122,12 @@ compatible = "marvell,pdma-1.0"; reg = <0x40000000 0x10000>; interrupts = <25>; - #dma-channels = <32>; #dma-cells = <2>; + /* For backwards compatibility: */ + #dma-channels = <32>; + dma-channels = <32>; #dma-requests = <100>; + dma-requests = <100>; status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi index 9d5e934f2272..c5da723f7674 100644 --- a/arch/arm/boot/dts/qcom-ipq4019.dtsi +++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi @@ -646,7 +646,7 @@ clocks = <&gcc GCC_USB3_MASTER_CLK>, <&gcc GCC_USB3_SLEEP_CLK>, <&gcc GCC_USB3_MOCK_UTMI_CLK>; - clock-names = "master", "sleep", "mock_utmi"; + clock-names = "core", "sleep", "mock_utmi"; ranges; status = "disabled"; diff --git a/arch/arm/boot/dts/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom-sdx55.dtsi index 123390721b7f..1c2b208a5670 100644 --- a/arch/arm/boot/dts/qcom-sdx55.dtsi +++ b/arch/arm/boot/dts/qcom-sdx55.dtsi @@ -483,10 +483,13 @@ clocks = <&gcc GCC_USB30_SLV_AHB_CLK>, <&gcc GCC_USB30_MASTER_CLK>, <&gcc GCC_USB30_MSTR_AXI_CLK>, - <&gcc GCC_USB30_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep"; + <&gcc GCC_USB30_SLEEP_CLK>, + <&gcc GCC_USB30_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, <&gcc GCC_USB30_MASTER_CLK>; diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index 242ce42fbd87..9b0f0497567d 100644 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -330,6 +330,8 @@ cru: clock-controller@20000000 { compatible = "rockchip,rk3036-cru"; reg = <0x20000000 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; rockchip,grf = <&grf>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi index c25b9695db4b..de9915d946f7 100644 --- a/arch/arm/boot/dts/rk3066a.dtsi +++ b/arch/arm/boot/dts/rk3066a.dtsi @@ -202,8 +202,9 @@ cru: clock-controller@20000000 { compatible = "rockchip,rk3066a-cru"; reg = <0x20000000 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; rockchip,grf = <&grf>; - #clock-cells = <1>; #reset-cells = <1>; assigned-clocks = <&cru PLL_CPLL>, <&cru PLL_GPLL>, diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi index a94321e90014..cdd4a0bd5133 100644 --- a/arch/arm/boot/dts/rk3188.dtsi +++ b/arch/arm/boot/dts/rk3188.dtsi @@ -195,8 +195,9 @@ cru: clock-controller@20000000 { compatible = "rockchip,rk3188-cru"; reg = <0x20000000 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; rockchip,grf = <&grf>; - #clock-cells = <1>; #reset-cells = <1>; }; diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi index 6513ffcaac92..ffc16d6b97e1 100644 --- a/arch/arm/boot/dts/rk322x.dtsi +++ b/arch/arm/boot/dts/rk322x.dtsi @@ -484,6 +484,8 @@ cru: clock-controller@110e0000 { compatible = "rockchip,rk3228-cru"; reg = <0x110e0000 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; rockchip,grf = <&grf>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 26b9bbe310af..487b0e03d4b4 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -862,6 +862,8 @@ cru: clock-controller@ff760000 { compatible = "rockchip,rk3288-cru"; reg = <0x0 0xff760000 0x0 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; rockchip,grf = <&grf>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi index 448254906452..c158a7ea86ec 100644 --- a/arch/arm/boot/dts/rv1108.dtsi +++ b/arch/arm/boot/dts/rv1108.dtsi @@ -85,24 +85,6 @@ #clock-cells = <0>; }; - amba: bus { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - pdma: pdma@102a0000 { - compatible = "arm,pl330", "arm,primecell"; - reg = <0x102a0000 0x4000>; - interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; - #dma-cells = <1>; - arm,pl330-broken-no-flushp; - arm,pl330-periph-burst; - clocks = <&cru ACLK_DMAC>; - clock-names = "apb_pclk"; - }; - }; - bus_intmem: sram@10080000 { compatible = "mmio-sram"; reg = <0x10080000 0x2000>; @@ -259,6 +241,17 @@ status = "disabled"; }; + pdma: dma-controller@102a0000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x102a0000 0x4000>; + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; + arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + }; + grf: syscon@10300000 { compatible = "rockchip,rv1108-grf", "syscon", "simple-mfd"; reg = <0x10300000 0x1000>; @@ -456,6 +449,8 @@ cru: clock-controller@20200000 { compatible = "rockchip,rv1108-cru"; reg = <0x20200000 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; rockchip,grf = <&grf>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/arch/arm/boot/dts/sam9x60.dtsi b/arch/arm/boot/dts/sam9x60.dtsi index 998629a3c34f..c328b67bea0c 100644 --- a/arch/arm/boot/dts/sam9x60.dtsi +++ b/arch/arm/boot/dts/sam9x60.dtsi @@ -684,7 +684,7 @@ status = "disabled"; }; - rtt: rtt@fffffe20 { + rtt: rtc@fffffe20 { compatible = "microchip,sam9x60-rtt", "atmel,at91sam9260-rtt"; reg = <0xfffffe20 0x20>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; diff --git a/arch/arm/boot/dts/sama7g5.dtsi b/arch/arm/boot/dts/sama7g5.dtsi index b63263129692..a37e3a80392d 100644 --- a/arch/arm/boot/dts/sama7g5.dtsi +++ b/arch/arm/boot/dts/sama7g5.dtsi @@ -209,7 +209,7 @@ status = "disabled"; }; - rtt: rtt@e001d020 { + rtt: rtc@e001d020 { compatible = "microchip,sama7g5-rtt", "microchip,sam9x60-rtt", "atmel,at91sam9260-rtt"; reg = <0xe001d020 0x30>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; @@ -463,6 +463,30 @@ status = "disabled"; }; + pdmc0: sound@e1608000 { + compatible = "microchip,sama7g5-pdmc"; + reg = <0xe1608000 0x1000>; + interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; + #sound-dai-cells = <0>; + dmas = <&dma0 AT91_XDMAC_DT_PERID(37)>; + dma-names = "rx"; + clocks = <&pmc PMC_TYPE_PERIPHERAL 68>, <&pmc PMC_TYPE_GCK 68>; + clock-names = "pclk", "gclk"; + status = "disabled"; + }; + + pdmc1: sound@e160c000 { + compatible = "microchip,sama7g5-pdmc"; + reg = <0xe160c000 0x1000>; + interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; + #sound-dai-cells = <0>; + dmas = <&dma0 AT91_XDMAC_DT_PERID(38)>; + dma-names = "rx"; + clocks = <&pmc PMC_TYPE_PERIPHERAL 69>, <&pmc PMC_TYPE_GCK 69>; + clock-names = "pclk", "gclk"; + status = "disabled"; + }; + spdifrx: spdifrx@e1614000 { #sound-dai-cells = <0>; compatible = "microchip,sama7g5-spdifrx"; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts index 2a745522404d..11ccdc6c2dc6 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts @@ -9,7 +9,7 @@ &qspi { status = "okay"; - flash0: n25q00@0 { + flash0: flash@0 { #address-cells = <1>; #size-cells = <1>; compatible = "micron,mt25qu02g", "jedec,spi-nor"; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts index 253ef139181d..b2241205c7a9 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts @@ -121,7 +121,7 @@ &qspi { status = "okay"; - flash0: n25q00@0 { + flash0: flash@0 { #address-cells = <1>; #size-cells = <1>; compatible = "micron,mt25qu02g", "jedec,spi-nor"; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts index b0003f350e65..2564671fc1c6 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts @@ -113,7 +113,7 @@ &qspi { status = "okay"; - flash0: n25q512a@0 { + flash0: flash@0 { #address-cells = <1>; #size-cells = <1>; compatible = "micron,n25q512a", "jedec,spi-nor"; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts index 25874e1b9c82..f24f17c2f5ee 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts @@ -221,7 +221,7 @@ &qspi { status = "okay"; - n25q128@0 { + flash@0 { #address-cells = <1>; #size-cells = <1>; compatible = "micron,n25q128", "jedec,spi-nor"; @@ -238,7 +238,7 @@ cdns,tslch-ns = <4>; }; - n25q00@1 { + flash@1 { #address-cells = <1>; #size-cells = <1>; compatible = "micron,mt25qu02g", "jedec,spi-nor"; diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 24d21ba63030..da30a4d4f35c 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -23,7 +23,6 @@ #include <linux/spinlock.h> #include <linux/io.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <asm/mach/irq.h> diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 5367f03beb46..2343e2b6214d 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -26,13 +26,16 @@ #include <linux/clk.h> #include <linux/io.h> -#include <mach/hardware.h> #include <asm/mach/irq.h> #include <asm/mach-types.h> #include <linux/sizes.h> #include <asm/hardware/sa1111.h> +#ifdef CONFIG_ARCH_SA1100 +#include <mach/hardware.h> +#endif + /* SA1111 IRQs */ #define IRQ_GPAIN0 (0) #define IRQ_GPAIN1 (1) diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig index 4e49d6cb2f62..9252ce0e722b 100644 --- a/arch/arm/configs/am200epdkit_defconfig +++ b/arch/arm/configs/am200epdkit_defconfig @@ -10,6 +10,7 @@ CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_ARCH_GUMSTIX=y CONFIG_PCCARD=y diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig index 45769d0ddd4e..bb0fcd82d2a7 100644 --- a/arch/arm/configs/cm_x300_defconfig +++ b/arch/arm/configs/cm_x300_defconfig @@ -10,6 +10,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_GPIO_PCA953X=y CONFIG_MACH_CM_X300=y diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig index 52bad9a544a0..b29898fd6a12 100644 --- a/arch/arm/configs/colibri_pxa270_defconfig +++ b/arch/arm/configs/colibri_pxa270_defconfig @@ -16,6 +16,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_COLIBRI=y CONFIG_PREEMPT=y diff --git a/arch/arm/configs/colibri_pxa300_defconfig b/arch/arm/configs/colibri_pxa300_defconfig index 26e5a67f8e2d..f9d110294644 100644 --- a/arch/arm/configs/colibri_pxa300_defconfig +++ b/arch/arm/configs/colibri_pxa300_defconfig @@ -1,6 +1,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_COLIBRI300=y CONFIG_AEABI=y diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig index 15b749f6996d..96c677c98bc7 100644 --- a/arch/arm/configs/corgi_defconfig +++ b/arch/arm/configs/corgi_defconfig @@ -9,6 +9,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_PXA_SHARPSL=y CONFIG_MACH_POODLE=y diff --git a/arch/arm/configs/eseries_pxa_defconfig b/arch/arm/configs/eseries_pxa_defconfig index 046f4dc2e18e..2146adc1825e 100644 --- a/arch/arm/configs/eseries_pxa_defconfig +++ b/arch/arm/configs/eseries_pxa_defconfig @@ -9,6 +9,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_ARCH_PXA_ESERIES=y # CONFIG_ARM_THUMB is not set diff --git a/arch/arm/configs/ezx_defconfig b/arch/arm/configs/ezx_defconfig index 0788a892e160..5d000c8be44e 100644 --- a/arch/arm/configs/ezx_defconfig +++ b/arch/arm/configs/ezx_defconfig @@ -14,6 +14,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_PXA_EZX=y CONFIG_NO_HZ=y diff --git a/arch/arm/configs/h5000_defconfig b/arch/arm/configs/h5000_defconfig index f5a338fefda8..a67d6020aee5 100644 --- a/arch/arm/configs/h5000_defconfig +++ b/arch/arm/configs/h5000_defconfig @@ -10,6 +10,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_H5000=y CONFIG_AEABI=y diff --git a/arch/arm/configs/lpd270_defconfig b/arch/arm/configs/lpd270_defconfig index 3a4d0e64cd6e..5c0a671ed294 100644 --- a/arch/arm/configs/lpd270_defconfig +++ b/arch/arm/configs/lpd270_defconfig @@ -2,6 +2,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SLAB=y CONFIG_MODULES=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_LOGICPD_PXA270=y # CONFIG_ARM_THUMB is not set diff --git a/arch/arm/configs/lubbock_defconfig b/arch/arm/configs/lubbock_defconfig index 4ce2da2e76fa..cf49dc1629a7 100644 --- a/arch/arm/configs/lubbock_defconfig +++ b/arch/arm/configs/lubbock_defconfig @@ -1,6 +1,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_MODULES=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_ARCH_LUBBOCK=y # CONFIG_ARM_THUMB is not set diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index abde1fb23b20..13da808ffa13 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -9,6 +9,7 @@ CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_H4700=y CONFIG_MACH_MAGICIAN=y diff --git a/arch/arm/configs/mainstone_defconfig b/arch/arm/configs/mainstone_defconfig index 26499b697f9f..03b4c61bdadd 100644 --- a/arch/arm/configs/mainstone_defconfig +++ b/arch/arm/configs/mainstone_defconfig @@ -1,6 +1,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_MODULES=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_MAINSTONE=y # CONFIG_ARM_THUMB is not set diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 547918170f1f..ce9826bce29b 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -17,6 +17,7 @@ CONFIG_SOC_SAMA5D2=y CONFIG_SOC_SAMA5D3=y CONFIG_SOC_SAMA5D4=y CONFIG_SOC_SAMA7G5=y +CONFIG_SOC_LAN966=y CONFIG_ARCH_BCM=y CONFIG_ARCH_BCM_CYGNUS=y CONFIG_ARCH_BCM_HR2=y @@ -43,6 +44,8 @@ CONFIG_ARCH_HI3xxx=y CONFIG_ARCH_HIP01=y CONFIG_ARCH_HIP04=y CONFIG_ARCH_HIX5HD2=y +CONFIG_ARCH_HPE=y +CONFIG_ARCH_HPE_GXP=y CONFIG_ARCH_MXC=y CONFIG_SOC_IMX50=y CONFIG_SOC_IMX51=y @@ -277,6 +280,7 @@ CONFIG_MV643XX_ETH=y CONFIG_MVNETA=y CONFIG_PXA168_ETH=m CONFIG_KS8851=y +CONFIG_LAN966X_SWITCH=m CONFIG_R8169=y CONFIG_SH_ETH=y CONFIG_SMSC911X=y @@ -287,6 +291,7 @@ CONFIG_TI_CPSW=y CONFIG_TI_CPSW_SWITCHDEV=y CONFIG_TI_CPTS=y CONFIG_XILINX_EMACLITE=y +CONFIG_SFP=m CONFIG_BROADCOM_PHY=y CONFIG_ICPLUS_PHY=y CONFIG_MARVELL_PHY=y @@ -294,6 +299,7 @@ CONFIG_AT803X_PHY=y CONFIG_ROCKCHIP_PHY=y CONFIG_DP83867_PHY=y CONFIG_USB_BRCMSTB=m +CONFIG_MDIO_MSCC_MIIM=m CONFIG_USB_PEGASUS=y CONFIG_USB_RTL8152=m CONFIG_USB_LAN78XX=m @@ -430,6 +436,7 @@ CONFIG_I2C_CROS_EC_TUNNEL=m CONFIG_I2C_SLAVE_EEPROM=y CONFIG_SPI=y CONFIG_SPI_ATMEL=m +CONFIG_SPI_ATMEL_QUADSPI=m CONFIG_SPI_BCM2835=y CONFIG_SPI_BCM2835AUX=y CONFIG_SPI_CADENCE=y @@ -459,6 +466,8 @@ CONFIG_SPMI=y CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_AS3722=y CONFIG_PINCTRL_STMFX=y +CONFIG_PINCTRL_MICROCHIP_SGPIO=y +CONFIG_PINCTRL_OCELOT=y CONFIG_PINCTRL_PALMAS=y CONFIG_PINCTRL_OWL=y CONFIG_PINCTRL_S500=y @@ -517,6 +526,7 @@ CONFIG_CHARGER_TPS65090=y CONFIG_SENSORS_ARM_SCMI=y CONFIG_SENSORS_ASPEED=m CONFIG_SENSORS_IIO_HWMON=y +CONFIG_SENSORS_LAN966X=m CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM95245=y CONFIG_SENSORS_NTC_THERMISTOR=m @@ -563,6 +573,7 @@ CONFIG_BCM47XX_WDT=y CONFIG_BCM2835_WDT=y CONFIG_BCM_KONA_WDT=y CONFIG_BCM7038_WDT=m +CONFIG_GXP_WATCHDOG=y CONFIG_BCMA_HOST_SOC=y CONFIG_BCMA_DRIVER_GMAC_CMN=y CONFIG_BCMA_DRIVER_GPIO=y @@ -767,6 +778,8 @@ CONFIG_SND_ATMEL_SOC_WM8904=m CONFIG_SND_ATMEL_SOC_PDMIC=m CONFIG_SND_ATMEL_SOC_I2S=m CONFIG_SND_BCM2835_SOC_I2S=m +CONFIG_SND_IMX_SOC=m +CONFIG_SND_SOC_FSL_ASOC_CARD=m CONFIG_SND_SOC_FSL_SAI=m CONFIG_SND_PXA_SOC_SSP=m CONFIG_SND_MMP_SOC_SSPA=m @@ -1018,6 +1031,7 @@ CONFIG_CROS_EC_SPI=m CONFIG_COMMON_CLK_MAX77686=y CONFIG_COMMON_CLK_RK808=m CONFIG_COMMON_CLK_SCMI=y +CONFIG_COMMON_CLK_LAN966X=y CONFIG_COMMON_CLK_S2MPS11=m CONFIG_CLK_RASPBERRYPI=y CONFIG_COMMON_CLK_QCOM=y @@ -1145,6 +1159,7 @@ CONFIG_PWM_SUN4I=y CONFIG_PWM_TEGRA=y CONFIG_PWM_VT8500=y CONFIG_KEYSTONE_IRQ=y +CONFIG_RESET_MCHP_SPARX5=y CONFIG_PHY_SUN4I_USB=y CONFIG_PHY_SUN9I_USB=y CONFIG_PHY_HIX5HD2_SATA=y @@ -1152,6 +1167,7 @@ CONFIG_PHY_BERLIN_SATA=y CONFIG_PHY_BERLIN_USB=y CONFIG_PHY_BRCM_USB=m CONFIG_PHY_MMP3_USB=m +CONFIG_PHY_LAN966X_SERDES=m CONFIG_PHY_CPCAP_USB=m CONFIG_PHY_QCOM_APQ8064_SATA=m CONFIG_PHY_QCOM_USB_HS=y diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index 3148567b66b6..14c17a218ec5 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig @@ -17,6 +17,9 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_ARCH_MULTI_V4T=y +CONFIG_ARCH_MULTI_V5=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_OMAP=y CONFIG_ARCH_OMAP1=y CONFIG_OMAP_RESET_CLOCKS=y diff --git a/arch/arm/configs/palmz72_defconfig b/arch/arm/configs/palmz72_defconfig index b47c8abe85bc..e6acb1d588e2 100644 --- a/arch/arm/configs/palmz72_defconfig +++ b/arch/arm/configs/palmz72_defconfig @@ -7,6 +7,7 @@ CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_ARCH_PXA_PALM=y # CONFIG_MACH_PALMTX is not set diff --git a/arch/arm/configs/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig index e97a158081fc..106d5bef48e2 100644 --- a/arch/arm/configs/pcm027_defconfig +++ b/arch/arm/configs/pcm027_defconfig @@ -13,6 +13,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_PCM027=y CONFIG_MACH_PCM990_BASEBOARD=y diff --git a/arch/arm/configs/pxa255-idp_defconfig b/arch/arm/configs/pxa255-idp_defconfig index 4a383afa5e87..5663245e9534 100644 --- a/arch/arm/configs/pxa255-idp_defconfig +++ b/arch/arm/configs/pxa255-idp_defconfig @@ -1,6 +1,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_MODULES=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_ARCH_PXA_IDP=y # CONFIG_ARM_THUMB is not set diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_defconfig index f0c34017f2aa..228d4271748b 100644 --- a/arch/arm/configs/pxa3xx_defconfig +++ b/arch/arm/configs/pxa3xx_defconfig @@ -6,6 +6,7 @@ CONFIG_KALLSYMS_ALL=y CONFIG_SLAB=y CONFIG_MODULES=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_LITTLETON=y CONFIG_MACH_TAVOREVB=y diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index 29b1f192afbb..1db70dfd32d2 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -23,6 +23,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_PARTITION_ADVANCED=y CONFIG_LDM_PARTITION=y CONFIG_CMDLINE_PARTITION=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_ARCH_LUBBOCK=y CONFIG_MACH_MAINSTONE=y diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig index f42c7a502b6e..43d079ee342a 100644 --- a/arch/arm/configs/spitz_defconfig +++ b/arch/arm/configs/spitz_defconfig @@ -9,6 +9,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_PXA_SHARPSL=y CONFIG_MACH_AKITA=y diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig index d66f0c287d41..baeba4667e9b 100644 --- a/arch/arm/configs/trizeps4_defconfig +++ b/arch/arm/configs/trizeps4_defconfig @@ -14,6 +14,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_TRIZEPS_PXA=y CONFIG_MACH_TRIZEPS4=y diff --git a/arch/arm/configs/viper_defconfig b/arch/arm/configs/viper_defconfig index c28539bfd128..7c1029716ea5 100644 --- a/arch/arm/configs/viper_defconfig +++ b/arch/arm/configs/viper_defconfig @@ -9,6 +9,7 @@ CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_ARCH_VIPER=y CONFIG_IWMMXT=y diff --git a/arch/arm/configs/xcep_defconfig b/arch/arm/configs/xcep_defconfig index 4d8e7f2eaef7..3752672f980e 100644 --- a/arch/arm/configs/xcep_defconfig +++ b/arch/arm/configs/xcep_defconfig @@ -19,6 +19,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLOCK is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_XCEP=y CONFIG_IWMMXT=y diff --git a/arch/arm/configs/zeus_defconfig b/arch/arm/configs/zeus_defconfig index 25bb6995f105..03a12fb51259 100644 --- a/arch/arm/configs/zeus_defconfig +++ b/arch/arm/configs/zeus_defconfig @@ -4,6 +4,7 @@ CONFIG_LOG_BUF_SHIFT=13 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_MACH_ARCOM_ZEUS=y CONFIG_PCCARD=m diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h index 2e70db6f22ea..d8c6f8a99dfa 100644 --- a/arch/arm/include/asm/hardware/sa1111.h +++ b/arch/arm/include/asm/hardware/sa1111.h @@ -13,8 +13,6 @@ #ifndef _ASM_ARCH_SA1111 #define _ASM_ARCH_SA1111 -#include <mach/bitfield.h> - /* * Don't ask the (SAC) DMA engines to move less than this amount. */ diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 2a0739a2350b..eba7cbc93b86 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -174,7 +174,7 @@ static inline void __iomem *__typesafe_io(unsigned long addr) #define PCI_IO_VIRT_BASE 0xfee00000 #define PCI_IOBASE ((void __iomem *)PCI_IO_VIRT_BASE) -#if defined(CONFIG_PCI) +#if defined(CONFIG_PCI) || IS_ENABLED(CONFIG_PCMCIA) void pci_ioremap_set_mem_type(int mem_type); #else static inline void pci_ioremap_set_mem_type(int mem_type) {} @@ -200,32 +200,13 @@ void __iomem *pci_remap_cfgspace(resource_size_t res_cookie, size_t size); */ #ifdef CONFIG_NEED_MACH_IO_H #include <mach/io.h> -#elif defined(CONFIG_PCI) -#define IO_SPACE_LIMIT ((resource_size_t)0xfffff) -#define __io(a) __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT)) #else -#define __io(a) __typesafe_io((a) & IO_SPACE_LIMIT) -#endif - -/* - * This is the limit of PC card/PCI/ISA IO space, which is by default - * 64K if we have PC card, PCI or ISA support. Otherwise, default to - * zero to prevent ISA/PCI drivers claiming IO space (and potentially - * oopsing.) - * - * Only set this larger if you really need inb() et.al. to operate over - * a larger address space. Note that SOC_COMMON ioremaps each sockets - * IO space area, and so inb() et.al. must be defined to operate as per - * readb() et.al. on such platforms. - */ -#ifndef IO_SPACE_LIMIT -#if defined(CONFIG_PCMCIA_SOC_COMMON) || defined(CONFIG_PCMCIA_SOC_COMMON_MODULE) -#define IO_SPACE_LIMIT ((resource_size_t)0xffffffff) -#elif defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD) -#define IO_SPACE_LIMIT ((resource_size_t)0xffff) +#if IS_ENABLED(CONFIG_PCMCIA) || defined(CONFIG_PCI) +#define IO_SPACE_LIMIT ((resource_size_t)0xfffff) #else #define IO_SPACE_LIMIT ((resource_size_t)0) #endif +#define __io(a) __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT)) #endif /* diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 0617af11377f..3d9cace63884 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -238,9 +238,11 @@ void release_thread(struct task_struct *dead_task) asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); -int copy_thread(unsigned long clone_flags, unsigned long stack_start, - unsigned long stk_sz, struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long stack_start = args->stack; + unsigned long tls = args->tls; struct thread_info *thread = task_thread_info(p); struct pt_regs *childregs = task_pt_regs(p); @@ -256,15 +258,15 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, thread->cpu_domain = get_domain(); #endif - if (likely(!(p->flags & (PF_KTHREAD | PF_IO_WORKER)))) { + if (likely(!args->fn)) { *childregs = *current_pt_regs(); childregs->ARM_r0 = 0; if (stack_start) childregs->ARM_sp = stack_start; } else { memset(childregs, 0, sizeof(struct pt_regs)); - thread->cpu_context.r4 = stk_sz; - thread->cpu_context.r5 = stack_start; + thread->cpu_context.r4 = (unsigned long)args->fn_arg; + thread->cpu_context.r5 = (unsigned long)args->fn; childregs->ARM_cpsr = SVC_MODE; } thread->cpu_context.pc = (unsigned long)ret_from_fork; diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 3d7e66976206..3dd9e718661b 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -219,7 +219,7 @@ config SOC_SAMA5 select SRAM if PM config ATMEL_PM - bool "Atmel PM support" + bool config ATMEL_SECURE_PM bool "Atmel Secure PM support" diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 4fa6ea5461b7..85a496ddc619 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -345,9 +345,10 @@ static struct clk_hw *clk_hw_register_ddiv(const char *name, psc->hw.init = &init; clk = clk_register(NULL, &psc->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { kfree(psc); - + return ERR_CAST(clk); + } return &psc->hw; } @@ -452,9 +453,10 @@ static struct clk_hw *clk_hw_register_div(const char *name, psc->hw.init = &init; clk = clk_register(NULL, &psc->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { kfree(psc); - + return ERR_CAST(clk); + } return &psc->hw; } diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index e70bac011407..d3de7283ecb3 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -150,7 +150,7 @@ static struct platform_device ts72xx_nand_flash = { .num_resources = ARRAY_SIZE(ts72xx_nand_resource), }; -void __init ts72xx_register_flash(struct mtd_partition *parts, int n, +static void __init ts72xx_register_flash(struct mtd_partition *parts, int n, resource_size_t start) { /* diff --git a/arch/arm/mach-hpe/Kconfig b/arch/arm/mach-hpe/Kconfig new file mode 100644 index 000000000000..3372bbf38d38 --- /dev/null +++ b/arch/arm/mach-hpe/Kconfig @@ -0,0 +1,23 @@ +menuconfig ARCH_HPE + bool "HPE SoC support" + depends on ARCH_MULTI_V7 + help + This enables support for HPE ARM based BMC chips. +if ARCH_HPE + +config ARCH_HPE_GXP + bool "HPE GXP SoC" + depends on ARCH_MULTI_V7 + select ARM_VIC + select GENERIC_IRQ_CHIP + select CLKSRC_MMIO + help + HPE GXP is the name of the HPE Soc. This SoC is used to implement many + BMC features at HPE. It supports ARMv7 architecture based on the Cortex + A9 core. It is capable of using an AXI bus to which a memory controller + is attached. It has multiple SPI interfaces to connect boot flash and + BIOS flash. It uses a 10/100/1000 MAC for network connectivity. It + has multiple i2c engines to drive connectivity with a host + infrastructure. + +endif diff --git a/arch/arm/mach-hpe/Makefile b/arch/arm/mach-hpe/Makefile new file mode 100644 index 000000000000..8b0a91234df4 --- /dev/null +++ b/arch/arm/mach-hpe/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARCH_HPE_GXP) += gxp.o diff --git a/arch/arm/mach-hpe/gxp.c b/arch/arm/mach-hpe/gxp.c new file mode 100644 index 000000000000..ef3341373006 --- /dev/null +++ b/arch/arm/mach-hpe/gxp.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */ + +#include <linux/of_platform.h> +#include <asm/mach/arch.h> + +static const char * const gxp_board_dt_compat[] = { + "hpe,gxp", + NULL, +}; + +DT_MACHINE_START(GXP_DT, "HPE GXP") + .dt_compat = gxp_board_dt_compat, + .l2c_aux_val = 0, + .l2c_aux_mask = ~0, +MACHINE_END diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig index 9642e6663a52..333229c65b28 100644 --- a/arch/arm/mach-mmp/Kconfig +++ b/arch/arm/mach-mmp/Kconfig @@ -39,16 +39,8 @@ config MACH_AVENGERS_LITE Say 'Y' here if you want to support the Marvell PXA168-based Avengers Lite Development Board. -config MACH_TAVOREVB - bool "Marvell's PXA910 TavorEVB Development Board" - depends on ARCH_MULTI_V5 - select CPU_PXA910 - help - Say 'Y' here if you want to support the Marvell PXA910-based - TavorEVB Development Board. - config MACH_TTC_DKB - bool "Marvell's PXA910 TavorEVB Development Board" + bool "Marvell's PXA910 TavorEVB/TTC_DKB Development Board" depends on ARCH_MULTI_V5 select CPU_PXA910 help diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile index e3758f7e1fe7..539d750aaf10 100644 --- a/arch/arm/mach-mmp/Makefile +++ b/arch/arm/mach-mmp/Makefile @@ -2,8 +2,6 @@ # # Makefile for Marvell's PXA168 processors line # -ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-pxa/include - obj-y += common.o devices.o time.o # SoC support @@ -24,7 +22,6 @@ endif obj-$(CONFIG_MACH_ASPENITE) += aspenite.o obj-$(CONFIG_MACH_ZYLONITE2) += aspenite.o obj-$(CONFIG_MACH_AVENGERS_LITE)+= avengers_lite.o -obj-$(CONFIG_MACH_TAVOREVB) += tavorevb.o obj-$(CONFIG_MACH_TTC_DKB) += ttc_dkb.o obj-$(CONFIG_MACH_BROWNSTONE) += brownstone.o obj-$(CONFIG_MACH_FLINT) += flint.o diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c index 18bee66a671f..79f4a2aa5475 100644 --- a/arch/arm/mach-mmp/devices.c +++ b/arch/arm/mach-mmp/devices.c @@ -14,7 +14,7 @@ #include <linux/soc/mmp/cputype.h> #include "regs-usb.h" -int __init pxa_register_device(struct pxa_device_desc *desc, +int __init mmp_register_device(struct mmp_device_desc *desc, void *data, size_t size) { struct platform_device *pdev; diff --git a/arch/arm/mach-mmp/devices.h b/arch/arm/mach-mmp/devices.h index 4df596c5c201..d4920ebfebc5 100644 --- a/arch/arm/mach-mmp/devices.h +++ b/arch/arm/mach-mmp/devices.h @@ -7,7 +7,7 @@ #define MAX_RESOURCE_DMA 2 /* structure for describing the on-chip devices */ -struct pxa_device_desc { +struct mmp_device_desc { const char *dev_name; const char *drv_name; int id; @@ -18,7 +18,7 @@ struct pxa_device_desc { }; #define PXA168_DEVICE(_name, _drv, _id, _irq, _start, _size, _dma...) \ -struct pxa_device_desc pxa168_device_##_name __initdata = { \ +struct mmp_device_desc pxa168_device_##_name __initdata = { \ .dev_name = "pxa168-" #_name, \ .drv_name = _drv, \ .id = _id, \ @@ -29,7 +29,7 @@ struct pxa_device_desc pxa168_device_##_name __initdata = { \ }; #define PXA910_DEVICE(_name, _drv, _id, _irq, _start, _size, _dma...) \ -struct pxa_device_desc pxa910_device_##_name __initdata = { \ +struct mmp_device_desc pxa910_device_##_name __initdata = { \ .dev_name = "pxa910-" #_name, \ .drv_name = _drv, \ .id = _id, \ @@ -40,7 +40,7 @@ struct pxa_device_desc pxa910_device_##_name __initdata = { \ }; #define MMP2_DEVICE(_name, _drv, _id, _irq, _start, _size, _dma...) \ -struct pxa_device_desc mmp2_device_##_name __initdata = { \ +struct mmp_device_desc mmp2_device_##_name __initdata = { \ .dev_name = "mmp2-" #_name, \ .drv_name = _drv, \ .id = _id, \ @@ -50,7 +50,7 @@ struct pxa_device_desc mmp2_device_##_name __initdata = { \ .dma = { _dma }, \ } -extern int pxa_register_device(struct pxa_device_desc *, void *, size_t); +extern int mmp_register_device(struct mmp_device_desc *, void *, size_t); extern int pxa_usb_phy_init(void __iomem *phy_reg); extern void pxa_usb_phy_deinit(void __iomem *phy_reg); diff --git a/arch/arm/mach-mmp/mfp.h b/arch/arm/mach-mmp/mfp.h index 75a4acb33b1b..6f3057987756 100644 --- a/arch/arm/mach-mmp/mfp.h +++ b/arch/arm/mach-mmp/mfp.h @@ -2,7 +2,7 @@ #ifndef __ASM_MACH_MFP_H #define __ASM_MACH_MFP_H -#include <plat/mfp.h> +#include <linux/soc/pxa/mfp.h> /* * NOTE: the MFPR register bit definitions on PXA168 processor lines are a diff --git a/arch/arm/mach-mmp/mmp2.h b/arch/arm/mach-mmp/mmp2.h index adafc4fba8f4..3ebc1bb13f71 100644 --- a/arch/arm/mach-mmp/mmp2.h +++ b/arch/arm/mach-mmp/mmp2.h @@ -15,28 +15,28 @@ extern void mmp2_clear_pmic_int(void); #include "devices.h" -extern struct pxa_device_desc mmp2_device_uart1; -extern struct pxa_device_desc mmp2_device_uart2; -extern struct pxa_device_desc mmp2_device_uart3; -extern struct pxa_device_desc mmp2_device_uart4; -extern struct pxa_device_desc mmp2_device_twsi1; -extern struct pxa_device_desc mmp2_device_twsi2; -extern struct pxa_device_desc mmp2_device_twsi3; -extern struct pxa_device_desc mmp2_device_twsi4; -extern struct pxa_device_desc mmp2_device_twsi5; -extern struct pxa_device_desc mmp2_device_twsi6; -extern struct pxa_device_desc mmp2_device_sdh0; -extern struct pxa_device_desc mmp2_device_sdh1; -extern struct pxa_device_desc mmp2_device_sdh2; -extern struct pxa_device_desc mmp2_device_sdh3; -extern struct pxa_device_desc mmp2_device_asram; -extern struct pxa_device_desc mmp2_device_isram; +extern struct mmp_device_desc mmp2_device_uart1; +extern struct mmp_device_desc mmp2_device_uart2; +extern struct mmp_device_desc mmp2_device_uart3; +extern struct mmp_device_desc mmp2_device_uart4; +extern struct mmp_device_desc mmp2_device_twsi1; +extern struct mmp_device_desc mmp2_device_twsi2; +extern struct mmp_device_desc mmp2_device_twsi3; +extern struct mmp_device_desc mmp2_device_twsi4; +extern struct mmp_device_desc mmp2_device_twsi5; +extern struct mmp_device_desc mmp2_device_twsi6; +extern struct mmp_device_desc mmp2_device_sdh0; +extern struct mmp_device_desc mmp2_device_sdh1; +extern struct mmp_device_desc mmp2_device_sdh2; +extern struct mmp_device_desc mmp2_device_sdh3; +extern struct mmp_device_desc mmp2_device_asram; +extern struct mmp_device_desc mmp2_device_isram; extern struct platform_device mmp2_device_gpio; static inline int mmp2_add_uart(int id) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; switch (id) { case 1: d = &mmp2_device_uart1; break; @@ -47,13 +47,13 @@ static inline int mmp2_add_uart(int id) return -EINVAL; } - return pxa_register_device(d, NULL, 0); + return mmp_register_device(d, NULL, 0); } static inline int mmp2_add_twsi(int id, struct i2c_pxa_platform_data *data, struct i2c_board_info *info, unsigned size) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; int ret; switch (id) { @@ -71,12 +71,12 @@ static inline int mmp2_add_twsi(int id, struct i2c_pxa_platform_data *data, if (ret) return ret; - return pxa_register_device(d, data, sizeof(*data)); + return mmp_register_device(d, data, sizeof(*data)); } static inline int mmp2_add_sdhost(int id, struct sdhci_pxa_platdata *data) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; switch (id) { case 0: d = &mmp2_device_sdh0; break; @@ -87,17 +87,17 @@ static inline int mmp2_add_sdhost(int id, struct sdhci_pxa_platdata *data) return -EINVAL; } - return pxa_register_device(d, data, sizeof(*data)); + return mmp_register_device(d, data, sizeof(*data)); } static inline int mmp2_add_asram(struct sram_platdata *data) { - return pxa_register_device(&mmp2_device_asram, data, sizeof(*data)); + return mmp_register_device(&mmp2_device_asram, data, sizeof(*data)); } static inline int mmp2_add_isram(struct sram_platdata *data) { - return pxa_register_device(&mmp2_device_isram, data, sizeof(*data)); + return mmp_register_device(&mmp2_device_isram, data, sizeof(*data)); } #endif /* __ASM_MACH_MMP2_H */ diff --git a/arch/arm/mach-mmp/pxa168.h b/arch/arm/mach-mmp/pxa168.h index dff651b9f252..34f907cd165a 100644 --- a/arch/arm/mach-mmp/pxa168.h +++ b/arch/arm/mach-mmp/pxa168.h @@ -21,24 +21,24 @@ extern void pxa168_clear_keypad_wakeup(void); #include "devices.h" -extern struct pxa_device_desc pxa168_device_uart1; -extern struct pxa_device_desc pxa168_device_uart2; -extern struct pxa_device_desc pxa168_device_uart3; -extern struct pxa_device_desc pxa168_device_twsi0; -extern struct pxa_device_desc pxa168_device_twsi1; -extern struct pxa_device_desc pxa168_device_pwm1; -extern struct pxa_device_desc pxa168_device_pwm2; -extern struct pxa_device_desc pxa168_device_pwm3; -extern struct pxa_device_desc pxa168_device_pwm4; -extern struct pxa_device_desc pxa168_device_ssp1; -extern struct pxa_device_desc pxa168_device_ssp2; -extern struct pxa_device_desc pxa168_device_ssp3; -extern struct pxa_device_desc pxa168_device_ssp4; -extern struct pxa_device_desc pxa168_device_ssp5; -extern struct pxa_device_desc pxa168_device_nand; -extern struct pxa_device_desc pxa168_device_fb; -extern struct pxa_device_desc pxa168_device_keypad; -extern struct pxa_device_desc pxa168_device_eth; +extern struct mmp_device_desc pxa168_device_uart1; +extern struct mmp_device_desc pxa168_device_uart2; +extern struct mmp_device_desc pxa168_device_uart3; +extern struct mmp_device_desc pxa168_device_twsi0; +extern struct mmp_device_desc pxa168_device_twsi1; +extern struct mmp_device_desc pxa168_device_pwm1; +extern struct mmp_device_desc pxa168_device_pwm2; +extern struct mmp_device_desc pxa168_device_pwm3; +extern struct mmp_device_desc pxa168_device_pwm4; +extern struct mmp_device_desc pxa168_device_ssp1; +extern struct mmp_device_desc pxa168_device_ssp2; +extern struct mmp_device_desc pxa168_device_ssp3; +extern struct mmp_device_desc pxa168_device_ssp4; +extern struct mmp_device_desc pxa168_device_ssp5; +extern struct mmp_device_desc pxa168_device_nand; +extern struct mmp_device_desc pxa168_device_fb; +extern struct mmp_device_desc pxa168_device_keypad; +extern struct mmp_device_desc pxa168_device_eth; /* pdata can be NULL */ extern int __init pxa168_add_usb_host(struct mv_usb_platform_data *pdata); @@ -48,7 +48,7 @@ extern struct platform_device pxa168_device_gpio; static inline int pxa168_add_uart(int id) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; switch (id) { case 1: d = &pxa168_device_uart1; break; @@ -59,13 +59,13 @@ static inline int pxa168_add_uart(int id) if (d == NULL) return -EINVAL; - return pxa_register_device(d, NULL, 0); + return mmp_register_device(d, NULL, 0); } static inline int pxa168_add_twsi(int id, struct i2c_pxa_platform_data *data, struct i2c_board_info *info, unsigned size) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; int ret; switch (id) { @@ -79,12 +79,12 @@ static inline int pxa168_add_twsi(int id, struct i2c_pxa_platform_data *data, if (ret) return ret; - return pxa_register_device(d, data, sizeof(*data)); + return mmp_register_device(d, data, sizeof(*data)); } static inline int pxa168_add_pwm(int id) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; switch (id) { case 1: d = &pxa168_device_pwm1; break; @@ -95,12 +95,12 @@ static inline int pxa168_add_pwm(int id) return -EINVAL; } - return pxa_register_device(d, NULL, 0); + return mmp_register_device(d, NULL, 0); } static inline int pxa168_add_ssp(int id) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; switch (id) { case 1: d = &pxa168_device_ssp1; break; @@ -111,17 +111,17 @@ static inline int pxa168_add_ssp(int id) default: return -EINVAL; } - return pxa_register_device(d, NULL, 0); + return mmp_register_device(d, NULL, 0); } static inline int pxa168_add_nand(struct pxa3xx_nand_platform_data *info) { - return pxa_register_device(&pxa168_device_nand, info, sizeof(*info)); + return mmp_register_device(&pxa168_device_nand, info, sizeof(*info)); } static inline int pxa168_add_fb(struct pxa168fb_mach_info *mi) { - return pxa_register_device(&pxa168_device_fb, mi, sizeof(*mi)); + return mmp_register_device(&pxa168_device_fb, mi, sizeof(*mi)); } static inline int pxa168_add_keypad(struct pxa27x_keypad_platform_data *data) @@ -129,11 +129,11 @@ static inline int pxa168_add_keypad(struct pxa27x_keypad_platform_data *data) if (cpu_is_pxa168()) data->clear_wakeup_event = pxa168_clear_keypad_wakeup; - return pxa_register_device(&pxa168_device_keypad, data, sizeof(*data)); + return mmp_register_device(&pxa168_device_keypad, data, sizeof(*data)); } static inline int pxa168_add_eth(struct pxa168_eth_platform_data *data) { - return pxa_register_device(&pxa168_device_eth, data, sizeof(*data)); + return mmp_register_device(&pxa168_device_eth, data, sizeof(*data)); } #endif /* __ASM_MACH_PXA168_H */ diff --git a/arch/arm/mach-mmp/pxa910.h b/arch/arm/mach-mmp/pxa910.h index 2dfe38e4acc1..6ace5a8aa15b 100644 --- a/arch/arm/mach-mmp/pxa910.h +++ b/arch/arm/mach-mmp/pxa910.h @@ -13,28 +13,28 @@ extern void __init pxa910_init_irq(void); #include "devices.h" -extern struct pxa_device_desc pxa910_device_uart1; -extern struct pxa_device_desc pxa910_device_uart2; -extern struct pxa_device_desc pxa910_device_twsi0; -extern struct pxa_device_desc pxa910_device_twsi1; -extern struct pxa_device_desc pxa910_device_pwm1; -extern struct pxa_device_desc pxa910_device_pwm2; -extern struct pxa_device_desc pxa910_device_pwm3; -extern struct pxa_device_desc pxa910_device_pwm4; -extern struct pxa_device_desc pxa910_device_nand; +extern struct mmp_device_desc pxa910_device_uart1; +extern struct mmp_device_desc pxa910_device_uart2; +extern struct mmp_device_desc pxa910_device_twsi0; +extern struct mmp_device_desc pxa910_device_twsi1; +extern struct mmp_device_desc pxa910_device_pwm1; +extern struct mmp_device_desc pxa910_device_pwm2; +extern struct mmp_device_desc pxa910_device_pwm3; +extern struct mmp_device_desc pxa910_device_pwm4; +extern struct mmp_device_desc pxa910_device_nand; extern struct platform_device pxa168_device_usb_phy; extern struct platform_device pxa168_device_u2o; extern struct platform_device pxa168_device_u2ootg; extern struct platform_device pxa168_device_u2oehci; -extern struct pxa_device_desc pxa910_device_disp; -extern struct pxa_device_desc pxa910_device_fb; -extern struct pxa_device_desc pxa910_device_panel; +extern struct mmp_device_desc pxa910_device_disp; +extern struct mmp_device_desc pxa910_device_fb; +extern struct mmp_device_desc pxa910_device_panel; extern struct platform_device pxa910_device_gpio; extern struct platform_device pxa910_device_rtc; static inline int pxa910_add_uart(int id) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; switch (id) { case 1: d = &pxa910_device_uart1; break; @@ -44,13 +44,13 @@ static inline int pxa910_add_uart(int id) if (d == NULL) return -EINVAL; - return pxa_register_device(d, NULL, 0); + return mmp_register_device(d, NULL, 0); } static inline int pxa910_add_twsi(int id, struct i2c_pxa_platform_data *data, struct i2c_board_info *info, unsigned size) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; int ret; switch (id) { @@ -64,12 +64,12 @@ static inline int pxa910_add_twsi(int id, struct i2c_pxa_platform_data *data, if (ret) return ret; - return pxa_register_device(d, data, sizeof(*data)); + return mmp_register_device(d, data, sizeof(*data)); } static inline int pxa910_add_pwm(int id) { - struct pxa_device_desc *d = NULL; + struct mmp_device_desc *d = NULL; switch (id) { case 1: d = &pxa910_device_pwm1; break; @@ -80,11 +80,11 @@ static inline int pxa910_add_pwm(int id) return -EINVAL; } - return pxa_register_device(d, NULL, 0); + return mmp_register_device(d, NULL, 0); } static inline int pxa910_add_nand(struct pxa3xx_nand_platform_data *info) { - return pxa_register_device(&pxa910_device_nand, info, sizeof(*info)); + return mmp_register_device(&pxa910_device_nand, info, sizeof(*info)); } #endif /* __ASM_MACH_PXA910_H */ diff --git a/arch/arm/mach-mmp/tavorevb.c b/arch/arm/mach-mmp/tavorevb.c deleted file mode 100644 index 3261d2322198..000000000000 --- a/arch/arm/mach-mmp/tavorevb.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-mmp/tavorevb.c - * - * Support for the Marvell PXA910-based TavorEVB Development Platform. - */ -#include <linux/gpio.h> -#include <linux/gpio-pxa.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/smc91x.h> - -#include <asm/mach-types.h> -#include <asm/mach/arch.h> -#include "addr-map.h" -#include "mfp-pxa910.h" -#include "pxa910.h" -#include "irqs.h" - -#include "common.h" - -static unsigned long tavorevb_pin_config[] __initdata = { - /* UART2 */ - GPIO47_UART2_RXD, - GPIO48_UART2_TXD, - - /* SMC */ - SM_nCS0_nCS0, - SM_ADV_SM_ADV, - SM_SCLK_SM_SCLK, - SM_SCLK_SM_SCLK, - SM_BE0_SM_BE0, - SM_BE1_SM_BE1, - - /* DFI */ - DF_IO0_ND_IO0, - DF_IO1_ND_IO1, - DF_IO2_ND_IO2, - DF_IO3_ND_IO3, - DF_IO4_ND_IO4, - DF_IO5_ND_IO5, - DF_IO6_ND_IO6, - DF_IO7_ND_IO7, - DF_IO8_ND_IO8, - DF_IO9_ND_IO9, - DF_IO10_ND_IO10, - DF_IO11_ND_IO11, - DF_IO12_ND_IO12, - DF_IO13_ND_IO13, - DF_IO14_ND_IO14, - DF_IO15_ND_IO15, - DF_nCS0_SM_nCS2_nCS0, - DF_ALE_SM_WEn_ND_ALE, - DF_CLE_SM_OEn_ND_CLE, - DF_WEn_DF_WEn, - DF_REn_DF_REn, - DF_RDY0_DF_RDY0, -}; - -static struct pxa_gpio_platform_data pxa910_gpio_pdata = { - .irq_base = MMP_GPIO_TO_IRQ(0), -}; - -static struct smc91x_platdata tavorevb_smc91x_info = { - .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, -}; - -static struct resource smc91x_resources[] = { - [0] = { - .start = SMC_CS1_PHYS_BASE + 0x300, - .end = SMC_CS1_PHYS_BASE + 0xfffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = MMP_GPIO_TO_IRQ(80), - .end = MMP_GPIO_TO_IRQ(80), - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, - } -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .dev = { - .platform_data = &tavorevb_smc91x_info, - }, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - -static void __init tavorevb_init(void) -{ - mfp_config(ARRAY_AND_SIZE(tavorevb_pin_config)); - - /* on-chip devices */ - pxa910_add_uart(1); - platform_device_add_data(&pxa910_device_gpio, &pxa910_gpio_pdata, - sizeof(struct pxa_gpio_platform_data)); - platform_device_register(&pxa910_device_gpio); - - /* off-chip devices */ - platform_device_register(&smc91x_device); -} - -MACHINE_START(TAVOREVB, "PXA910 Evaluation Board (aka TavorEVB)") - .map_io = mmp_map_io, - .nr_irqs = MMP_NR_IRQS, - .init_irq = pxa910_init_irq, - .init_time = pxa910_timer_init, - .init_machine = tavorevb_init, - .restart = mmp_restart, -MACHINE_END diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c index 4f240760d4aa..345b2e6d5c7e 100644 --- a/arch/arm/mach-mmp/ttc_dkb.c +++ b/arch/arm/mach-mmp/ttc_dkb.c @@ -253,12 +253,12 @@ static struct spi_board_info spi_board_info[] __initdata = { static void __init add_disp(void) { - pxa_register_device(&pxa910_device_disp, + mmp_register_device(&pxa910_device_disp, &dkb_disp_info, sizeof(dkb_disp_info)); spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); - pxa_register_device(&pxa910_device_fb, + mmp_register_device(&pxa910_device_fb, &dkb_fb_info, sizeof(dkb_fb_info)); - pxa_register_device(&pxa910_device_panel, + mmp_register_device(&pxa910_device_panel, &dkb_tpo_panel_info, sizeof(dkb_tpo_panel_info)); } #endif diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index d4b0cd91a4f9..0ac0567f721d 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -1,4 +1,16 @@ # SPDX-License-Identifier: GPL-2.0-only +menuconfig ARCH_OMAP1 + bool "TI OMAP1" + depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 + depends on CPU_LITTLE_ENDIAN + select ARCH_HAS_HOLES_MEMORYMODEL + select ARCH_OMAP + select CLKSRC_MMIO + select FORCE_PCI if PCCARD + select GPIOLIB + help + Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx) + if ARCH_OMAP1 menu "TI OMAP1 specific features" @@ -6,23 +18,27 @@ menu "TI OMAP1 specific features" comment "OMAP Core Type" config ARCH_OMAP730 + depends on ARCH_MULTI_V5 bool "OMAP730 Based System" select ARCH_OMAP_OTG select CPU_ARM926T select OMAP_MPU_TIMER config ARCH_OMAP850 + depends on ARCH_MULTI_V5 bool "OMAP850 Based System" select ARCH_OMAP_OTG select CPU_ARM926T config ARCH_OMAP15XX + depends on ARCH_MULTI_V4T default y bool "OMAP15xx Based System" select CPU_ARM925T select OMAP_MPU_TIMER config ARCH_OMAP16XX + depends on ARCH_MULTI_V5 bool "OMAP16xx Based System" select ARCH_OMAP_OTG select CPU_ARM926T diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index e5bd4d3b742d..83381e23fab9 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -16,7 +16,9 @@ #include <linux/io.h> #include <linux/clk.h> #include <linux/clkdev.h> +#include <linux/clk-provider.h> #include <linux/soc/ti/omap1-io.h> +#include <linux/spinlock.h> #include <asm/mach-types.h> @@ -28,33 +30,37 @@ #include "sram.h" __u32 arm_idlect1_mask; -struct clk *api_ck_p, *ck_dpll1_p, *ck_ref_p; +/* provide direct internal access (not via clk API) to some clocks */ +struct omap1_clk *api_ck_p, *ck_dpll1_p, *ck_ref_p; -static LIST_HEAD(clocks); -static DEFINE_MUTEX(clocks_mutex); -static DEFINE_SPINLOCK(clockfw_lock); +/* protect registeres shared among clk_enable/disable() and clk_set_rate() operations */ +static DEFINE_SPINLOCK(arm_ckctl_lock); +static DEFINE_SPINLOCK(arm_idlect2_lock); +static DEFINE_SPINLOCK(mod_conf_ctrl_0_lock); +static DEFINE_SPINLOCK(mod_conf_ctrl_1_lock); +static DEFINE_SPINLOCK(swd_clk_div_ctrl_sel_lock); /* * Omap1 specific clock functions */ -unsigned long omap1_uart_recalc(struct clk *clk) +unsigned long omap1_uart_recalc(struct omap1_clk *clk, unsigned long p_rate) { unsigned int val = __raw_readl(clk->enable_reg); return val & 1 << clk->enable_bit ? 48000000 : 12000000; } -unsigned long omap1_sossi_recalc(struct clk *clk) +unsigned long omap1_sossi_recalc(struct omap1_clk *clk, unsigned long p_rate) { u32 div = omap_readl(MOD_CONF_CTRL_1); div = (div >> 17) & 0x7; div++; - return clk->parent->rate / div; + return p_rate / div; } -static void omap1_clk_allow_idle(struct clk *clk) +static void omap1_clk_allow_idle(struct omap1_clk *clk) { struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; @@ -65,7 +71,7 @@ static void omap1_clk_allow_idle(struct clk *clk) arm_idlect1_mask |= 1 << iclk->idlect_shift; } -static void omap1_clk_deny_idle(struct clk *clk) +static void omap1_clk_deny_idle(struct omap1_clk *clk) { struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; @@ -129,7 +135,7 @@ static __u16 verify_ckctl_value(__u16 newval) return newval; } -static int calc_dsor_exp(struct clk *clk, unsigned long rate) +static int calc_dsor_exp(unsigned long rate, unsigned long realrate) { /* Note: If target frequency is too low, this function will return 4, * which is invalid value. Caller must check for this value and act @@ -142,15 +148,11 @@ static int calc_dsor_exp(struct clk *clk, unsigned long rate) * DSP_CK >= TC_CK * DSPMMU_CK >= TC_CK */ - unsigned long realrate; - struct clk * parent; unsigned dsor_exp; - parent = clk->parent; - if (unlikely(parent == NULL)) + if (unlikely(realrate == 0)) return -EIO; - realrate = parent->rate; for (dsor_exp=0; dsor_exp<4; dsor_exp++) { if (realrate <= rate) break; @@ -161,16 +163,50 @@ static int calc_dsor_exp(struct clk *clk, unsigned long rate) return dsor_exp; } -unsigned long omap1_ckctl_recalc(struct clk *clk) +unsigned long omap1_ckctl_recalc(struct omap1_clk *clk, unsigned long p_rate) { /* Calculate divisor encoded as 2-bit exponent */ int dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); - return clk->parent->rate / dsor; + /* update locally maintained rate, required by arm_ck for omap1_show_rates() */ + clk->rate = p_rate / dsor; + return clk->rate; } -unsigned long omap1_ckctl_recalc_dsp_domain(struct clk *clk) +static int omap1_clk_is_enabled(struct clk_hw *hw) { + struct omap1_clk *clk = to_omap1_clk(hw); + bool api_ck_was_enabled = true; + __u32 regval32; + int ret; + + if (!clk->ops) /* no gate -- always enabled */ + return 1; + + if (clk->ops == &clkops_dspck) { + api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw); + if (!api_ck_was_enabled) + if (api_ck_p->ops->enable(api_ck_p) < 0) + return 0; + } + + if (clk->flags & ENABLE_REG_32BIT) + regval32 = __raw_readl(clk->enable_reg); + else + regval32 = __raw_readw(clk->enable_reg); + + ret = regval32 & (1 << clk->enable_bit); + + if (!api_ck_was_enabled) + api_ck_p->ops->disable(api_ck_p); + + return ret; +} + + +unsigned long omap1_ckctl_recalc_dsp_domain(struct omap1_clk *clk, unsigned long p_rate) +{ + bool api_ck_was_enabled; int dsor; /* Calculate divisor encoded as 2-bit exponent @@ -180,15 +216,18 @@ unsigned long omap1_ckctl_recalc_dsp_domain(struct clk *clk) * Note that DSP_CKCTL virt addr = phys addr, so * we must use __raw_readw() instead of omap_readw(). */ - omap1_clk_enable(api_ck_p); + api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw); + if (!api_ck_was_enabled) + api_ck_p->ops->enable(api_ck_p); dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); - omap1_clk_disable(api_ck_p); + if (!api_ck_was_enabled) + api_ck_p->ops->disable(api_ck_p); - return clk->parent->rate / dsor; + return p_rate / dsor; } /* MPU virtual clock functions */ -int omap1_select_table_rate(struct clk *clk, unsigned long rate) +int omap1_select_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) { /* Find the highest supported frequency <= rate and switch to it */ struct mpu_rate * ptr; @@ -223,12 +262,12 @@ int omap1_select_table_rate(struct clk *clk, unsigned long rate) return 0; } -int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate) +int omap1_clk_set_rate_dsp_domain(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) { int dsor_exp; u16 regval; - dsor_exp = calc_dsor_exp(clk, rate); + dsor_exp = calc_dsor_exp(rate, p_rate); if (dsor_exp > 3) dsor_exp = -EINVAL; if (dsor_exp < 0) @@ -238,42 +277,51 @@ int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate) regval &= ~(3 << clk->rate_offset); regval |= dsor_exp << clk->rate_offset; __raw_writew(regval, DSP_CKCTL); - clk->rate = clk->parent->rate / (1 << dsor_exp); + clk->rate = p_rate / (1 << dsor_exp); return 0; } -long omap1_clk_round_rate_ckctl_arm(struct clk *clk, unsigned long rate) +long omap1_clk_round_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate, + unsigned long *p_rate) { - int dsor_exp = calc_dsor_exp(clk, rate); + int dsor_exp = calc_dsor_exp(rate, *p_rate); + if (dsor_exp < 0) return dsor_exp; if (dsor_exp > 3) dsor_exp = 3; - return clk->parent->rate / (1 << dsor_exp); + return *p_rate / (1 << dsor_exp); } -int omap1_clk_set_rate_ckctl_arm(struct clk *clk, unsigned long rate) +int omap1_clk_set_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) { + unsigned long flags; int dsor_exp; u16 regval; - dsor_exp = calc_dsor_exp(clk, rate); + dsor_exp = calc_dsor_exp(rate, p_rate); if (dsor_exp > 3) dsor_exp = -EINVAL; if (dsor_exp < 0) return dsor_exp; + /* protect ARM_CKCTL register from concurrent access via clk_enable/disable() */ + spin_lock_irqsave(&arm_ckctl_lock, flags); + regval = omap_readw(ARM_CKCTL); regval &= ~(3 << clk->rate_offset); regval |= dsor_exp << clk->rate_offset; regval = verify_ckctl_value(regval); omap_writew(regval, ARM_CKCTL); - clk->rate = clk->parent->rate / (1 << dsor_exp); + clk->rate = p_rate / (1 << dsor_exp); + + spin_unlock_irqrestore(&arm_ckctl_lock, flags); + return 0; } -long omap1_round_to_table_rate(struct clk *clk, unsigned long rate) +long omap1_round_to_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate) { /* Find the highest supported frequency <= rate */ struct mpu_rate * ptr; @@ -324,26 +372,40 @@ static unsigned calc_ext_dsor(unsigned long rate) } /* XXX Only needed on 1510 */ -int omap1_set_uart_rate(struct clk *clk, unsigned long rate) +long omap1_round_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate) { + return rate > 24000000 ? 48000000 : 12000000; +} + +int omap1_set_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) +{ + unsigned long flags; unsigned int val; - val = __raw_readl(clk->enable_reg); if (rate == 12000000) - val &= ~(1 << clk->enable_bit); + val = 0; else if (rate == 48000000) - val |= (1 << clk->enable_bit); + val = 1 << clk->enable_bit; else return -EINVAL; + + /* protect MOD_CONF_CTRL_0 register from concurrent access via clk_enable/disable() */ + spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags); + + val |= __raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit); __raw_writel(val, clk->enable_reg); + + spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags); + clk->rate = rate; return 0; } /* External clock (MCLK & BCLK) functions */ -int omap1_set_ext_clk_rate(struct clk *clk, unsigned long rate) +int omap1_set_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) { + unsigned long flags; unsigned dsor; __u16 ratio_bits; @@ -354,25 +416,53 @@ int omap1_set_ext_clk_rate(struct clk *clk, unsigned long rate) else ratio_bits = (dsor - 2) << 2; + /* protect SWD_CLK_DIV_CTRL_SEL register from concurrent access via clk_enable/disable() */ + spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags); + ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd; __raw_writew(ratio_bits, clk->enable_reg); + spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags); + return 0; } -int omap1_set_sossi_rate(struct clk *clk, unsigned long rate) +static int calc_div_sossi(unsigned long rate, unsigned long p_rate) { - u32 l; int div; - unsigned long p_rate; - p_rate = clk->parent->rate; /* Round towards slower frequency */ div = (p_rate + rate - 1) / rate; - div--; + + return --div; +} + +long omap1_round_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate) +{ + int div; + + div = calc_div_sossi(rate, *p_rate); + if (div < 0) + div = 0; + else if (div > 7) + div = 7; + + return *p_rate / (div + 1); +} + +int omap1_set_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) +{ + unsigned long flags; + u32 l; + int div; + + div = calc_div_sossi(rate, p_rate); if (div < 0 || div > 7) return -EINVAL; + /* protect MOD_CONF_CTRL_1 register from concurrent access via clk_enable/disable() */ + spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags); + l = omap_readl(MOD_CONF_CTRL_1); l &= ~(7 << 17); l |= div << 17; @@ -380,15 +470,17 @@ int omap1_set_sossi_rate(struct clk *clk, unsigned long rate) clk->rate = p_rate / (div + 1); + spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags); + return 0; } -long omap1_round_ext_clk_rate(struct clk *clk, unsigned long rate) +long omap1_round_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate) { return 96000000 / calc_ext_dsor(rate); } -void omap1_init_ext_clk(struct clk *clk) +int omap1_init_ext_clk(struct omap1_clk *clk) { unsigned dsor; __u16 ratio_bits; @@ -404,59 +496,59 @@ void omap1_init_ext_clk(struct clk *clk) dsor = ratio_bits + 2; clk-> rate = 96000000 / dsor; + + return 0; } -int omap1_clk_enable(struct clk *clk) +static int omap1_clk_enable(struct clk_hw *hw) { + struct omap1_clk *clk = to_omap1_clk(hw), *parent = to_omap1_clk(clk_hw_get_parent(hw)); int ret = 0; - if (clk->usecount++ == 0) { - if (clk->parent) { - ret = omap1_clk_enable(clk->parent); - if (ret) - goto err; - - if (clk->flags & CLOCK_NO_IDLE_PARENT) - omap1_clk_deny_idle(clk->parent); - } + if (parent && clk->flags & CLOCK_NO_IDLE_PARENT) + omap1_clk_deny_idle(parent); + if (clk->ops && !(WARN_ON(!clk->ops->enable))) ret = clk->ops->enable(clk); - if (ret) { - if (clk->parent) - omap1_clk_disable(clk->parent); - goto err; - } - } - return ret; -err: - clk->usecount--; return ret; } -void omap1_clk_disable(struct clk *clk) +static void omap1_clk_disable(struct clk_hw *hw) { - if (clk->usecount > 0 && !(--clk->usecount)) { + struct omap1_clk *clk = to_omap1_clk(hw), *parent = to_omap1_clk(clk_hw_get_parent(hw)); + + if (clk->ops && !(WARN_ON(!clk->ops->disable))) clk->ops->disable(clk); - if (likely(clk->parent)) { - omap1_clk_disable(clk->parent); - if (clk->flags & CLOCK_NO_IDLE_PARENT) - omap1_clk_allow_idle(clk->parent); - } - } + + if (likely(parent) && clk->flags & CLOCK_NO_IDLE_PARENT) + omap1_clk_allow_idle(parent); } -static int omap1_clk_enable_generic(struct clk *clk) +static int omap1_clk_enable_generic(struct omap1_clk *clk) { + unsigned long flags; __u16 regval16; __u32 regval32; if (unlikely(clk->enable_reg == NULL)) { printk(KERN_ERR "clock.c: Enable for %s without enable code\n", - clk->name); + clk_hw_get_name(&clk->hw)); return -EINVAL; } + /* protect clk->enable_reg from concurrent access via clk_set_rate() */ + if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL)) + spin_lock_irqsave(&arm_ckctl_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2)) + spin_lock_irqsave(&arm_idlect2_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0)) + spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1)) + spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL)) + spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags); + if (clk->flags & ENABLE_REG_32BIT) { regval32 = __raw_readl(clk->enable_reg); regval32 |= (1 << clk->enable_bit); @@ -467,17 +559,41 @@ static int omap1_clk_enable_generic(struct clk *clk) __raw_writew(regval16, clk->enable_reg); } + if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL)) + spin_unlock_irqrestore(&arm_ckctl_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2)) + spin_unlock_irqrestore(&arm_idlect2_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0)) + spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1)) + spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL)) + spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags); + return 0; } -static void omap1_clk_disable_generic(struct clk *clk) +static void omap1_clk_disable_generic(struct omap1_clk *clk) { + unsigned long flags; __u16 regval16; __u32 regval32; if (clk->enable_reg == NULL) return; + /* protect clk->enable_reg from concurrent access via clk_set_rate() */ + if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL)) + spin_lock_irqsave(&arm_ckctl_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2)) + spin_lock_irqsave(&arm_idlect2_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0)) + spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1)) + spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL)) + spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags); + if (clk->flags & ENABLE_REG_32BIT) { regval32 = __raw_readl(clk->enable_reg); regval32 &= ~(1 << clk->enable_bit); @@ -487,6 +603,17 @@ static void omap1_clk_disable_generic(struct clk *clk) regval16 &= ~(1 << clk->enable_bit); __raw_writew(regval16, clk->enable_reg); } + + if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL)) + spin_unlock_irqrestore(&arm_ckctl_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2)) + spin_unlock_irqrestore(&arm_idlect2_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0)) + spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1)) + spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags); + else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL)) + spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags); } const struct clkops clkops_generic = { @@ -494,25 +621,38 @@ const struct clkops clkops_generic = { .disable = omap1_clk_disable_generic, }; -static int omap1_clk_enable_dsp_domain(struct clk *clk) +static int omap1_clk_enable_dsp_domain(struct omap1_clk *clk) { - int retval; + bool api_ck_was_enabled; + int retval = 0; + + api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw); + if (!api_ck_was_enabled) + retval = api_ck_p->ops->enable(api_ck_p); - retval = omap1_clk_enable(api_ck_p); if (!retval) { retval = omap1_clk_enable_generic(clk); - omap1_clk_disable(api_ck_p); + + if (!api_ck_was_enabled) + api_ck_p->ops->disable(api_ck_p); } return retval; } -static void omap1_clk_disable_dsp_domain(struct clk *clk) +static void omap1_clk_disable_dsp_domain(struct omap1_clk *clk) { - if (omap1_clk_enable(api_ck_p) == 0) { - omap1_clk_disable_generic(clk); - omap1_clk_disable(api_ck_p); - } + bool api_ck_was_enabled; + + api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw); + if (!api_ck_was_enabled) + if (api_ck_p->ops->enable(api_ck_p) < 0) + return; + + omap1_clk_disable_generic(clk); + + if (!api_ck_was_enabled) + api_ck_p->ops->disable(api_ck_p); } const struct clkops clkops_dspck = { @@ -521,7 +661,7 @@ const struct clkops clkops_dspck = { }; /* XXX SYSC register handling does not belong in the clock framework */ -static int omap1_clk_enable_uart_functional_16xx(struct clk *clk) +static int omap1_clk_enable_uart_functional_16xx(struct omap1_clk *clk) { int ret; struct uart_clk *uclk; @@ -538,7 +678,7 @@ static int omap1_clk_enable_uart_functional_16xx(struct clk *clk) } /* XXX SYSC register handling does not belong in the clock framework */ -static void omap1_clk_disable_uart_functional_16xx(struct clk *clk) +static void omap1_clk_disable_uart_functional_16xx(struct omap1_clk *clk) { struct uart_clk *uclk; @@ -555,20 +695,33 @@ const struct clkops clkops_uart_16xx = { .disable = omap1_clk_disable_uart_functional_16xx, }; -long omap1_clk_round_rate(struct clk *clk, unsigned long rate) +static unsigned long omap1_clk_recalc_rate(struct clk_hw *hw, unsigned long p_rate) { - if (clk->round_rate != NULL) - return clk->round_rate(clk, rate); + struct omap1_clk *clk = to_omap1_clk(hw); + + if (clk->recalc) + return clk->recalc(clk, p_rate); return clk->rate; } -int omap1_clk_set_rate(struct clk *clk, unsigned long rate) +static long omap1_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *p_rate) +{ + struct omap1_clk *clk = to_omap1_clk(hw); + + if (clk->round_rate != NULL) + return clk->round_rate(clk, rate, p_rate); + + return omap1_clk_recalc_rate(hw, *p_rate); +} + +static int omap1_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate) { + struct omap1_clk *clk = to_omap1_clk(hw); int ret = -EINVAL; if (clk->set_rate) - ret = clk->set_rate(clk, rate); + ret = clk->set_rate(clk, rate, p_rate); return ret; } @@ -576,243 +729,105 @@ int omap1_clk_set_rate(struct clk *clk, unsigned long rate) * Omap1 clock reset and init functions */ +static int omap1_clk_init_op(struct clk_hw *hw) +{ + struct omap1_clk *clk = to_omap1_clk(hw); + + if (clk->init) + return clk->init(clk); + + return 0; +} + #ifdef CONFIG_OMAP_RESET_CLOCKS -void omap1_clk_disable_unused(struct clk *clk) +static void omap1_clk_disable_unused(struct clk_hw *hw) { - __u32 regval32; + struct omap1_clk *clk = to_omap1_clk(hw); + const char *name = clk_hw_get_name(hw); /* Clocks in the DSP domain need api_ck. Just assume bootloader * has not enabled any DSP clocks */ if (clk->enable_reg == DSP_IDLECT2) { - pr_info("Skipping reset check for DSP domain clock \"%s\"\n", - clk->name); + pr_info("Skipping reset check for DSP domain clock \"%s\"\n", name); return; } - /* Is the clock already disabled? */ - if (clk->flags & ENABLE_REG_32BIT) - regval32 = __raw_readl(clk->enable_reg); - else - regval32 = __raw_readw(clk->enable_reg); - - if ((regval32 & (1 << clk->enable_bit)) == 0) - return; - - printk(KERN_INFO "Disabling unused clock \"%s\"... ", clk->name); - clk->ops->disable(clk); + pr_info("Disabling unused clock \"%s\"... ", name); + omap1_clk_disable(hw); printk(" done\n"); } #endif +const struct clk_ops omap1_clk_gate_ops = { + .enable = omap1_clk_enable, + .disable = omap1_clk_disable, + .is_enabled = omap1_clk_is_enabled, +#ifdef CONFIG_OMAP_RESET_CLOCKS + .disable_unused = omap1_clk_disable_unused, +#endif +}; -int clk_enable(struct clk *clk) -{ - unsigned long flags; - int ret; - - if (IS_ERR_OR_NULL(clk)) - return -EINVAL; - - spin_lock_irqsave(&clockfw_lock, flags); - ret = omap1_clk_enable(clk); - spin_unlock_irqrestore(&clockfw_lock, flags); - - return ret; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ - unsigned long flags; - - if (IS_ERR_OR_NULL(clk)) - return; - - spin_lock_irqsave(&clockfw_lock, flags); - if (clk->usecount == 0) { - pr_err("Trying disable clock %s with 0 usecount\n", - clk->name); - WARN_ON(1); - goto out; - } - - omap1_clk_disable(clk); - -out: - spin_unlock_irqrestore(&clockfw_lock, flags); -} -EXPORT_SYMBOL(clk_disable); - -unsigned long clk_get_rate(struct clk *clk) -{ - unsigned long flags; - unsigned long ret; - - if (IS_ERR_OR_NULL(clk)) - return 0; - - spin_lock_irqsave(&clockfw_lock, flags); - ret = clk->rate; - spin_unlock_irqrestore(&clockfw_lock, flags); - - return ret; -} -EXPORT_SYMBOL(clk_get_rate); - -/* - * Optional clock functions defined in include/linux/clk.h - */ - -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - unsigned long flags; - long ret; - - if (IS_ERR_OR_NULL(clk)) - return 0; - - spin_lock_irqsave(&clockfw_lock, flags); - ret = omap1_clk_round_rate(clk, rate); - spin_unlock_irqrestore(&clockfw_lock, flags); - - return ret; -} -EXPORT_SYMBOL(clk_round_rate); - -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned long flags; - int ret = -EINVAL; - - if (IS_ERR_OR_NULL(clk)) - return ret; - - spin_lock_irqsave(&clockfw_lock, flags); - ret = omap1_clk_set_rate(clk, rate); - if (ret == 0) - propagate_rate(clk); - spin_unlock_irqrestore(&clockfw_lock, flags); - - return ret; -} -EXPORT_SYMBOL(clk_set_rate); - -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - WARN_ONCE(1, "clk_set_parent() not implemented for OMAP1\n"); - - return -EINVAL; -} -EXPORT_SYMBOL(clk_set_parent); +const struct clk_ops omap1_clk_rate_ops = { + .recalc_rate = omap1_clk_recalc_rate, + .round_rate = omap1_clk_round_rate, + .set_rate = omap1_clk_set_rate, + .init = omap1_clk_init_op, +}; -struct clk *clk_get_parent(struct clk *clk) -{ - return clk->parent; -} -EXPORT_SYMBOL(clk_get_parent); +const struct clk_ops omap1_clk_full_ops = { + .enable = omap1_clk_enable, + .disable = omap1_clk_disable, + .is_enabled = omap1_clk_is_enabled, +#ifdef CONFIG_OMAP_RESET_CLOCKS + .disable_unused = omap1_clk_disable_unused, +#endif + .recalc_rate = omap1_clk_recalc_rate, + .round_rate = omap1_clk_round_rate, + .set_rate = omap1_clk_set_rate, + .init = omap1_clk_init_op, +}; /* * OMAP specific clock functions shared between omap1 and omap2 */ /* Used for clocks that always have same value as the parent clock */ -unsigned long followparent_recalc(struct clk *clk) +unsigned long followparent_recalc(struct omap1_clk *clk, unsigned long p_rate) { - return clk->parent->rate; + return p_rate; } /* * Used for clocks that have the same value as the parent clock, * divided by some factor */ -unsigned long omap_fixed_divisor_recalc(struct clk *clk) +unsigned long omap_fixed_divisor_recalc(struct omap1_clk *clk, unsigned long p_rate) { WARN_ON(!clk->fixed_div); - return clk->parent->rate / clk->fixed_div; + return p_rate / clk->fixed_div; } /* Propagate rate to children */ -void propagate_rate(struct clk *tclk) +void propagate_rate(struct omap1_clk *tclk) { struct clk *clkp; - list_for_each_entry(clkp, &tclk->children, sibling) { - if (clkp->recalc) - clkp->rate = clkp->recalc(clkp); - propagate_rate(clkp); - } -} - -static LIST_HEAD(root_clks); - -/** - * clk_preinit - initialize any fields in the struct clk before clk init - * @clk: struct clk * to initialize - * - * Initialize any struct clk fields needed before normal clk initialization - * can run. No return value. - */ -void clk_preinit(struct clk *clk) -{ - INIT_LIST_HEAD(&clk->children); -} - -int clk_register(struct clk *clk) -{ - if (IS_ERR_OR_NULL(clk)) - return -EINVAL; - - /* - * trap out already registered clocks - */ - if (clk->node.next || clk->node.prev) - return 0; - - mutex_lock(&clocks_mutex); - if (clk->parent) - list_add(&clk->sibling, &clk->parent->children); - else - list_add(&clk->sibling, &root_clks); - - list_add(&clk->node, &clocks); - if (clk->init) - clk->init(clk); - mutex_unlock(&clocks_mutex); - - return 0; -} -EXPORT_SYMBOL(clk_register); - -void clk_unregister(struct clk *clk) -{ - if (IS_ERR_OR_NULL(clk)) + /* depend on CCF ability to recalculate new rates across whole clock subtree */ + if (WARN_ON(!(clk_hw_get_flags(&tclk->hw) & CLK_GET_RATE_NOCACHE))) return; - mutex_lock(&clocks_mutex); - list_del(&clk->sibling); - list_del(&clk->node); - mutex_unlock(&clocks_mutex); -} -EXPORT_SYMBOL(clk_unregister); - -/* - * Low level helpers - */ -static int clkll_enable_null(struct clk *clk) -{ - return 0; -} + clkp = clk_get_sys(NULL, clk_hw_get_name(&tclk->hw)); + if (WARN_ON(!clkp)) + return; -static void clkll_disable_null(struct clk *clk) -{ + clk_get_rate(clkp); + clk_put(clkp); } -const struct clkops clkops_null = { - .enable = clkll_enable_null, - .disable = clkll_disable_null, +const struct clk_ops omap1_clk_null_ops = { }; /* @@ -820,114 +835,6 @@ const struct clkops clkops_null = { * * Used for clock aliases that are needed on some OMAPs, but not others */ -struct clk dummy_ck = { - .name = "dummy", - .ops = &clkops_null, +struct omap1_clk dummy_ck __refdata = { + .hw.init = CLK_HW_INIT_NO_PARENT("dummy", &omap1_clk_null_ops, 0), }; - -/* - * - */ - -#ifdef CONFIG_OMAP_RESET_CLOCKS -/* - * Disable any unused clocks left on by the bootloader - */ -static int __init clk_disable_unused(void) -{ - struct clk *ck; - unsigned long flags; - - pr_info("clock: disabling unused clocks to save power\n"); - - spin_lock_irqsave(&clockfw_lock, flags); - list_for_each_entry(ck, &clocks, node) { - if (ck->ops == &clkops_null) - continue; - - if (ck->usecount > 0 || !ck->enable_reg) - continue; - - omap1_clk_disable_unused(ck); - } - spin_unlock_irqrestore(&clockfw_lock, flags); - - return 0; -} -late_initcall(clk_disable_unused); -#endif - -#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) -/* - * debugfs support to trace clock tree hierarchy and attributes - */ - -#include <linux/debugfs.h> -#include <linux/seq_file.h> - -static struct dentry *clk_debugfs_root; - -static int debug_clock_show(struct seq_file *s, void *unused) -{ - struct clk *c; - struct clk *pa; - - mutex_lock(&clocks_mutex); - seq_printf(s, "%-30s %-30s %-10s %s\n", - "clock-name", "parent-name", "rate", "use-count"); - - list_for_each_entry(c, &clocks, node) { - pa = c->parent; - seq_printf(s, "%-30s %-30s %-10lu %d\n", - c->name, pa ? pa->name : "none", c->rate, - c->usecount); - } - mutex_unlock(&clocks_mutex); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(debug_clock); - -static void clk_debugfs_register_one(struct clk *c) -{ - struct dentry *d; - struct clk *pa = c->parent; - - d = debugfs_create_dir(c->name, pa ? pa->dent : clk_debugfs_root); - c->dent = d; - - debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount); - debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate); - debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags); -} - -static void clk_debugfs_register(struct clk *c) -{ - struct clk *pa = c->parent; - - if (pa && !pa->dent) - clk_debugfs_register(pa); - - if (!c->dent) - clk_debugfs_register_one(c); -} - -static int __init clk_debugfs_init(void) -{ - struct clk *c; - struct dentry *d; - - d = debugfs_create_dir("clock", NULL); - clk_debugfs_root = d; - - list_for_each_entry(c, &clocks, node) - clk_debugfs_register(c); - - debugfs_create_file("summary", S_IRUGO, d, NULL, &debug_clock_fops); - - return 0; -} -late_initcall(clk_debugfs_init); - -#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */ diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h index 8025e4a22469..16cfb2e86ee4 100644 --- a/arch/arm/mach-omap1/clock.h +++ b/arch/arm/mach-omap1/clock.h @@ -11,12 +11,11 @@ #define __ARCH_ARM_MACH_OMAP1_CLOCK_H #include <linux/clk.h> -#include <linux/list.h> - #include <linux/clkdev.h> +#include <linux/clk-provider.h> struct module; -struct clk; +struct omap1_clk; struct omap_clk { u16 cpu; @@ -29,7 +28,7 @@ struct omap_clk { .lk = { \ .dev_id = dev, \ .con_id = con, \ - .clk = ck, \ + .clk_hw = ck, \ }, \ } @@ -40,10 +39,6 @@ struct omap_clk { #define CK_16XX (1 << 3) /* 16xx, 17xx, 5912 */ #define CK_1710 (1 << 4) /* 1710 extra for rate selection */ - -/* Temporary, needed during the common clock framework conversion */ -#define __clk_get_name(clk) (clk->name) - /** * struct clkops - some clock function pointers * @enable: fn ptr that enables the current clock in hardware @@ -51,8 +46,8 @@ struct omap_clk { * @allow_idle: fn ptr that enables autoidle for the current clock in hardware */ struct clkops { - int (*enable)(struct clk *); - void (*disable)(struct clk *); + int (*enable)(struct omap1_clk *clk); + void (*disable)(struct omap1_clk *clk); }; /* @@ -65,13 +60,9 @@ struct clkops { #define CLOCK_NO_IDLE_PARENT (1 << 2) /** - * struct clk - OMAP struct clk - * @node: list_head connecting this clock into the full clock list + * struct omap1_clk - OMAP1 struct clk + * @hw: struct clk_hw for common clock framework integration * @ops: struct clkops * for this clock - * @name: the name of the clock in the hardware (used in hwmod data and debug) - * @parent: pointer to this clock's parent struct clk - * @children: list_head connecting to the child clks' @sibling list_heads - * @sibling: list_head connecting this clk to its parent clk's @children * @rate: current clock rate * @enable_reg: register to write to enable the clock (see @enable_bit) * @recalc: fn ptr that returns the clock's current rate @@ -79,102 +70,65 @@ struct clkops { * @round_rate: fn ptr that can round the clock's current rate * @init: fn ptr to do clock-specific initialization * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg) - * @usecount: number of users that have requested this clock to be enabled * @fixed_div: when > 0, this clock's rate is its parent's rate / @fixed_div * @flags: see "struct clk.flags possibilities" above * @rate_offset: bitshift for rate selection bitfield (OMAP1 only) - * - * XXX @rate_offset should probably be removed and OMAP1 - * clock code converted to use clksel. - * - * XXX @usecount is poorly named. It should be "enable_count" or - * something similar. "users" in the description refers to kernel - * code (core code or drivers) that have called clk_enable() and not - * yet called clk_disable(); the usecount of parent clocks is also - * incremented by the clock code when clk_enable() is called on child - * clocks and decremented by the clock code when clk_disable() is - * called on child clocks. - * - * XXX @usecount, @children, @sibling should be marked for - * internal use only. - * - * @children and @sibling are used to optimize parent-to-child clock - * tree traversals. (child-to-parent traversals use @parent.) - * - * XXX The notion of the clock's current rate probably needs to be - * separated from the clock's target rate. */ -struct clk { - struct list_head node; +struct omap1_clk { + struct clk_hw hw; const struct clkops *ops; - const char *name; - struct clk *parent; - struct list_head children; - struct list_head sibling; /* node for children */ unsigned long rate; void __iomem *enable_reg; - unsigned long (*recalc)(struct clk *); - int (*set_rate)(struct clk *, unsigned long); - long (*round_rate)(struct clk *, unsigned long); - void (*init)(struct clk *); + unsigned long (*recalc)(struct omap1_clk *clk, unsigned long rate); + int (*set_rate)(struct omap1_clk *clk, unsigned long rate, + unsigned long p_rate); + long (*round_rate)(struct omap1_clk *clk, unsigned long rate, + unsigned long *p_rate); + int (*init)(struct omap1_clk *clk); u8 enable_bit; - s8 usecount; u8 fixed_div; u8 flags; u8 rate_offset; -#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) - struct dentry *dent; /* For visible tree hierarchy */ -#endif }; +#define to_omap1_clk(_hw) container_of(_hw, struct omap1_clk, hw) -extern void clk_preinit(struct clk *clk); -extern int clk_register(struct clk *clk); -extern void clk_unregister(struct clk *clk); -extern void propagate_rate(struct clk *clk); -extern unsigned long followparent_recalc(struct clk *clk); -unsigned long omap_fixed_divisor_recalc(struct clk *clk); +void propagate_rate(struct omap1_clk *clk); +unsigned long followparent_recalc(struct omap1_clk *clk, unsigned long p_rate); +unsigned long omap_fixed_divisor_recalc(struct omap1_clk *clk, unsigned long p_rate); -extern const struct clkops clkops_null; - -extern struct clk dummy_ck; +extern struct omap1_clk dummy_ck; int omap1_clk_init(void); void omap1_clk_late_init(void); -extern int omap1_clk_enable(struct clk *clk); -extern void omap1_clk_disable(struct clk *clk); -extern long omap1_clk_round_rate(struct clk *clk, unsigned long rate); -extern int omap1_clk_set_rate(struct clk *clk, unsigned long rate); -extern unsigned long omap1_ckctl_recalc(struct clk *clk); -extern int omap1_set_sossi_rate(struct clk *clk, unsigned long rate); -extern unsigned long omap1_sossi_recalc(struct clk *clk); -extern unsigned long omap1_ckctl_recalc_dsp_domain(struct clk *clk); -extern int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate); -extern int omap1_set_uart_rate(struct clk *clk, unsigned long rate); -extern unsigned long omap1_uart_recalc(struct clk *clk); -extern int omap1_set_ext_clk_rate(struct clk *clk, unsigned long rate); -extern long omap1_round_ext_clk_rate(struct clk *clk, unsigned long rate); -extern void omap1_init_ext_clk(struct clk *clk); -extern int omap1_select_table_rate(struct clk *clk, unsigned long rate); -extern long omap1_round_to_table_rate(struct clk *clk, unsigned long rate); -extern int omap1_clk_set_rate_ckctl_arm(struct clk *clk, unsigned long rate); -extern long omap1_clk_round_rate_ckctl_arm(struct clk *clk, unsigned long rate); - -#ifdef CONFIG_OMAP_RESET_CLOCKS -extern void omap1_clk_disable_unused(struct clk *clk); -#else -#define omap1_clk_disable_unused NULL -#endif +unsigned long omap1_ckctl_recalc(struct omap1_clk *clk, unsigned long p_rate); +long omap1_round_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate); +int omap1_set_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate); +unsigned long omap1_sossi_recalc(struct omap1_clk *clk, unsigned long p_rate); +unsigned long omap1_ckctl_recalc_dsp_domain(struct omap1_clk *clk, unsigned long p_rate); +int omap1_clk_set_rate_dsp_domain(struct omap1_clk *clk, unsigned long rate, + unsigned long p_rate); +long omap1_round_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate); +int omap1_set_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate); +unsigned long omap1_uart_recalc(struct omap1_clk *clk, unsigned long p_rate); +int omap1_set_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate); +long omap1_round_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate); +int omap1_init_ext_clk(struct omap1_clk *clk); +int omap1_select_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate); +long omap1_round_to_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate); +int omap1_clk_set_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate); +long omap1_clk_round_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate, + unsigned long *p_rate); struct uart_clk { - struct clk clk; - unsigned long sysc_addr; + struct omap1_clk clk; + unsigned long sysc_addr; }; /* Provide a method for preventing idling some ARM IDLECT clocks */ struct arm_idlect1_clk { - struct clk clk; - unsigned long no_idle_count; - __u8 idlect_shift; + struct omap1_clk clk; + unsigned long no_idle_count; + __u8 idlect_shift; }; /* ARM_CKCTL bit shifts */ @@ -224,7 +178,7 @@ struct arm_idlect1_clk { #define SOFT_REQ_REG2 0xfffe0880 extern __u32 arm_idlect1_mask; -extern struct clk *api_ck_p, *ck_dpll1_p, *ck_ref_p; +extern struct omap1_clk *api_ck_p, *ck_dpll1_p, *ck_ref_p; extern const struct clkops clkops_dspck; extern const struct clkops clkops_uart_16xx; @@ -233,4 +187,9 @@ extern const struct clkops clkops_generic; /* used for passing SoC type to omap1_{select,round_to}_table_rate() */ extern u32 cpu_mask; +extern const struct clk_ops omap1_clk_null_ops; +extern const struct clk_ops omap1_clk_gate_ops; +extern const struct clk_ops omap1_clk_rate_ops; +extern const struct clk_ops omap1_clk_full_ops; + #endif diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c index 165b6a75a59b..96d846c37c43 100644 --- a/arch/arm/mach-omap1/clock_data.c +++ b/arch/arm/mach-omap1/clock_data.c @@ -14,6 +14,8 @@ #include <linux/kernel.h> #include <linux/io.h> #include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> #include <linux/cpufreq.h> #include <linux/delay.h> #include <linux/soc/ti/omap1-io.h> @@ -71,16 +73,18 @@ * Omap1 clocks */ -static struct clk ck_ref = { - .name = "ck_ref", - .ops = &clkops_null, +static struct omap1_clk ck_ref = { + .hw.init = CLK_HW_INIT_NO_PARENT("ck_ref", &omap1_clk_rate_ops, 0), .rate = 12000000, }; -static struct clk ck_dpll1 = { - .name = "ck_dpll1", - .ops = &clkops_null, - .parent = &ck_ref, +static struct omap1_clk ck_dpll1 = { + .hw.init = CLK_HW_INIT("ck_dpll1", "ck_ref", &omap1_clk_rate_ops, + /* + * force recursive refresh of rates of the clock + * and its children when clk_get_rate() is called + */ + CLK_GET_RATE_NOCACHE), }; /* @@ -89,32 +93,28 @@ static struct clk ck_dpll1 = { */ static struct arm_idlect1_clk ck_dpll1out = { .clk = { - .name = "ck_dpll1out", + .hw.init = CLK_HW_INIT("ck_dpll1out", "ck_dpll1", &omap1_clk_gate_ops, 0), .ops = &clkops_generic, - .parent = &ck_dpll1, .flags = CLOCK_IDLE_CONTROL | ENABLE_REG_32BIT, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_CKOUT_ARM, - .recalc = &followparent_recalc, }, .idlect_shift = IDL_CLKOUT_ARM_SHIFT, }; -static struct clk sossi_ck = { - .name = "ck_sossi", +static struct omap1_clk sossi_ck = { + .hw.init = CLK_HW_INIT("ck_sossi", "ck_dpll1out", &omap1_clk_full_ops, 0), .ops = &clkops_generic, - .parent = &ck_dpll1out.clk, .flags = CLOCK_NO_IDLE_PARENT | ENABLE_REG_32BIT, .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1), .enable_bit = CONF_MOD_SOSSI_CLK_EN_R, .recalc = &omap1_sossi_recalc, + .round_rate = &omap1_round_sossi_rate, .set_rate = &omap1_set_sossi_rate, }; -static struct clk arm_ck = { - .name = "arm_ck", - .ops = &clkops_null, - .parent = &ck_dpll1, +static struct omap1_clk arm_ck = { + .hw.init = CLK_HW_INIT("arm_ck", "ck_dpll1", &omap1_clk_rate_ops, 0), .rate_offset = CKCTL_ARMDIV_OFFSET, .recalc = &omap1_ckctl_recalc, .round_rate = omap1_clk_round_rate_ckctl_arm, @@ -123,9 +123,9 @@ static struct clk arm_ck = { static struct arm_idlect1_clk armper_ck = { .clk = { - .name = "armper_ck", + .hw.init = CLK_HW_INIT("armper_ck", "ck_dpll1", &omap1_clk_full_ops, + CLK_IS_CRITICAL), .ops = &clkops_generic, - .parent = &ck_dpll1, .flags = CLOCK_IDLE_CONTROL, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_PERCK, @@ -141,46 +141,41 @@ static struct arm_idlect1_clk armper_ck = { * FIXME: This clock seems to be necessary but no-one has asked for its * activation. [ GPIO code for 1510 ] */ -static struct clk arm_gpio_ck = { - .name = "ick", +static struct omap1_clk arm_gpio_ck = { + .hw.init = CLK_HW_INIT("ick", "ck_dpll1", &omap1_clk_gate_ops, CLK_IS_CRITICAL), .ops = &clkops_generic, - .parent = &ck_dpll1, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_GPIOCK, - .recalc = &followparent_recalc, }; static struct arm_idlect1_clk armxor_ck = { .clk = { - .name = "armxor_ck", + .hw.init = CLK_HW_INIT("armxor_ck", "ck_ref", &omap1_clk_gate_ops, + CLK_IS_CRITICAL), .ops = &clkops_generic, - .parent = &ck_ref, .flags = CLOCK_IDLE_CONTROL, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_XORPCK, - .recalc = &followparent_recalc, }, .idlect_shift = IDLXORP_ARM_SHIFT, }; static struct arm_idlect1_clk armtim_ck = { .clk = { - .name = "armtim_ck", + .hw.init = CLK_HW_INIT("armtim_ck", "ck_ref", &omap1_clk_gate_ops, + CLK_IS_CRITICAL), .ops = &clkops_generic, - .parent = &ck_ref, .flags = CLOCK_IDLE_CONTROL, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_TIMCK, - .recalc = &followparent_recalc, }, .idlect_shift = IDLTIM_ARM_SHIFT, }; static struct arm_idlect1_clk armwdt_ck = { .clk = { - .name = "armwdt_ck", + .hw.init = CLK_HW_INIT("armwdt_ck", "ck_ref", &omap1_clk_full_ops, 0), .ops = &clkops_generic, - .parent = &ck_ref, .flags = CLOCK_IDLE_CONTROL, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_WDTCK, @@ -190,11 +185,8 @@ static struct arm_idlect1_clk armwdt_ck = { .idlect_shift = IDLWDT_ARM_SHIFT, }; -static struct clk arminth_ck16xx = { - .name = "arminth_ck", - .ops = &clkops_null, - .parent = &arm_ck, - .recalc = &followparent_recalc, +static struct omap1_clk arminth_ck16xx = { + .hw.init = CLK_HW_INIT("arminth_ck", "arm_ck", &omap1_clk_null_ops, 0), /* Note: On 16xx the frequency can be divided by 2 by programming * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 * @@ -202,10 +194,9 @@ static struct clk arminth_ck16xx = { */ }; -static struct clk dsp_ck = { - .name = "dsp_ck", +static struct omap1_clk dsp_ck = { + .hw.init = CLK_HW_INIT("dsp_ck", "ck_dpll1", &omap1_clk_full_ops, 0), .ops = &clkops_generic, - .parent = &ck_dpll1, .enable_reg = OMAP1_IO_ADDRESS(ARM_CKCTL), .enable_bit = EN_DSPCK, .rate_offset = CKCTL_DSPDIV_OFFSET, @@ -214,20 +205,17 @@ static struct clk dsp_ck = { .set_rate = omap1_clk_set_rate_ckctl_arm, }; -static struct clk dspmmu_ck = { - .name = "dspmmu_ck", - .ops = &clkops_null, - .parent = &ck_dpll1, +static struct omap1_clk dspmmu_ck = { + .hw.init = CLK_HW_INIT("dspmmu_ck", "ck_dpll1", &omap1_clk_rate_ops, 0), .rate_offset = CKCTL_DSPMMUDIV_OFFSET, .recalc = &omap1_ckctl_recalc, .round_rate = omap1_clk_round_rate_ckctl_arm, .set_rate = omap1_clk_set_rate_ckctl_arm, }; -static struct clk dspper_ck = { - .name = "dspper_ck", +static struct omap1_clk dspper_ck = { + .hw.init = CLK_HW_INIT("dspper_ck", "ck_dpll1", &omap1_clk_full_ops, 0), .ops = &clkops_dspck, - .parent = &ck_dpll1, .enable_reg = DSP_IDLECT2, .enable_bit = EN_PERCK, .rate_offset = CKCTL_PERDIV_OFFSET, @@ -236,29 +224,23 @@ static struct clk dspper_ck = { .set_rate = &omap1_clk_set_rate_dsp_domain, }; -static struct clk dspxor_ck = { - .name = "dspxor_ck", +static struct omap1_clk dspxor_ck = { + .hw.init = CLK_HW_INIT("dspxor_ck", "ck_ref", &omap1_clk_gate_ops, 0), .ops = &clkops_dspck, - .parent = &ck_ref, .enable_reg = DSP_IDLECT2, .enable_bit = EN_XORPCK, - .recalc = &followparent_recalc, }; -static struct clk dsptim_ck = { - .name = "dsptim_ck", +static struct omap1_clk dsptim_ck = { + .hw.init = CLK_HW_INIT("dsptim_ck", "ck_ref", &omap1_clk_gate_ops, 0), .ops = &clkops_dspck, - .parent = &ck_ref, .enable_reg = DSP_IDLECT2, .enable_bit = EN_DSPTIMCK, - .recalc = &followparent_recalc, }; static struct arm_idlect1_clk tc_ck = { .clk = { - .name = "tc_ck", - .ops = &clkops_null, - .parent = &ck_dpll1, + .hw.init = CLK_HW_INIT("tc_ck", "ck_dpll1", &omap1_clk_rate_ops, 0), .flags = CLOCK_IDLE_CONTROL, .rate_offset = CKCTL_TCDIV_OFFSET, .recalc = &omap1_ckctl_recalc, @@ -268,116 +250,88 @@ static struct arm_idlect1_clk tc_ck = { .idlect_shift = IDLIF_ARM_SHIFT, }; -static struct clk arminth_ck1510 = { - .name = "arminth_ck", - .ops = &clkops_null, - .parent = &tc_ck.clk, - .recalc = &followparent_recalc, +static struct omap1_clk arminth_ck1510 = { + .hw.init = CLK_HW_INIT("arminth_ck", "tc_ck", &omap1_clk_null_ops, 0), /* Note: On 1510 the frequency follows TC_CK * * 16xx version is in MPU clocks. */ }; -static struct clk tipb_ck = { +static struct omap1_clk tipb_ck = { /* No-idle controlled by "tc_ck" */ - .name = "tipb_ck", - .ops = &clkops_null, - .parent = &tc_ck.clk, - .recalc = &followparent_recalc, + .hw.init = CLK_HW_INIT("tipb_ck", "tc_ck", &omap1_clk_null_ops, 0), }; -static struct clk l3_ocpi_ck = { +static struct omap1_clk l3_ocpi_ck = { /* No-idle controlled by "tc_ck" */ - .name = "l3_ocpi_ck", + .hw.init = CLK_HW_INIT("l3_ocpi_ck", "tc_ck", &omap1_clk_gate_ops, 0), .ops = &clkops_generic, - .parent = &tc_ck.clk, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3), .enable_bit = EN_OCPI_CK, - .recalc = &followparent_recalc, }; -static struct clk tc1_ck = { - .name = "tc1_ck", +static struct omap1_clk tc1_ck = { + .hw.init = CLK_HW_INIT("tc1_ck", "tc_ck", &omap1_clk_gate_ops, 0), .ops = &clkops_generic, - .parent = &tc_ck.clk, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3), .enable_bit = EN_TC1_CK, - .recalc = &followparent_recalc, }; /* * FIXME: This clock seems to be necessary but no-one has asked for its * activation. [ pm.c (SRAM), CCP, Camera ] */ -static struct clk tc2_ck = { - .name = "tc2_ck", + +static struct omap1_clk tc2_ck = { + .hw.init = CLK_HW_INIT("tc2_ck", "tc_ck", &omap1_clk_gate_ops, CLK_IS_CRITICAL), .ops = &clkops_generic, - .parent = &tc_ck.clk, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3), .enable_bit = EN_TC2_CK, - .recalc = &followparent_recalc, }; -static struct clk dma_ck = { +static struct omap1_clk dma_ck = { /* No-idle controlled by "tc_ck" */ - .name = "dma_ck", - .ops = &clkops_null, - .parent = &tc_ck.clk, - .recalc = &followparent_recalc, + .hw.init = CLK_HW_INIT("dma_ck", "tc_ck", &omap1_clk_null_ops, 0), }; -static struct clk dma_lcdfree_ck = { - .name = "dma_lcdfree_ck", - .ops = &clkops_null, - .parent = &tc_ck.clk, - .recalc = &followparent_recalc, +static struct omap1_clk dma_lcdfree_ck = { + .hw.init = CLK_HW_INIT("dma_lcdfree_ck", "tc_ck", &omap1_clk_null_ops, 0), }; static struct arm_idlect1_clk api_ck = { .clk = { - .name = "api_ck", + .hw.init = CLK_HW_INIT("api_ck", "tc_ck", &omap1_clk_gate_ops, 0), .ops = &clkops_generic, - .parent = &tc_ck.clk, .flags = CLOCK_IDLE_CONTROL, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_APICK, - .recalc = &followparent_recalc, }, .idlect_shift = IDLAPI_ARM_SHIFT, }; static struct arm_idlect1_clk lb_ck = { .clk = { - .name = "lb_ck", + .hw.init = CLK_HW_INIT("lb_ck", "tc_ck", &omap1_clk_gate_ops, 0), .ops = &clkops_generic, - .parent = &tc_ck.clk, .flags = CLOCK_IDLE_CONTROL, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_LBCK, - .recalc = &followparent_recalc, }, .idlect_shift = IDLLB_ARM_SHIFT, }; -static struct clk rhea1_ck = { - .name = "rhea1_ck", - .ops = &clkops_null, - .parent = &tc_ck.clk, - .recalc = &followparent_recalc, +static struct omap1_clk rhea1_ck = { + .hw.init = CLK_HW_INIT("rhea1_ck", "tc_ck", &omap1_clk_null_ops, 0), }; -static struct clk rhea2_ck = { - .name = "rhea2_ck", - .ops = &clkops_null, - .parent = &tc_ck.clk, - .recalc = &followparent_recalc, +static struct omap1_clk rhea2_ck = { + .hw.init = CLK_HW_INIT("rhea2_ck", "tc_ck", &omap1_clk_null_ops, 0), }; -static struct clk lcd_ck_16xx = { - .name = "lcd_ck", +static struct omap1_clk lcd_ck_16xx = { + .hw.init = CLK_HW_INIT("lcd_ck", "ck_dpll1", &omap1_clk_full_ops, 0), .ops = &clkops_generic, - .parent = &ck_dpll1, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_LCDCK, .rate_offset = CKCTL_LCDDIV_OFFSET, @@ -388,9 +342,8 @@ static struct clk lcd_ck_16xx = { static struct arm_idlect1_clk lcd_ck_1510 = { .clk = { - .name = "lcd_ck", + .hw.init = CLK_HW_INIT("lcd_ck", "ck_dpll1", &omap1_clk_full_ops, 0), .ops = &clkops_generic, - .parent = &ck_dpll1, .flags = CLOCK_IDLE_CONTROL, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_LCDCK, @@ -402,37 +355,35 @@ static struct arm_idlect1_clk lcd_ck_1510 = { .idlect_shift = OMAP1510_IDLLCD_ARM_SHIFT, }; + /* * XXX The enable_bit here is misused - it simply switches between 12MHz - * and 48MHz. Reimplement with clksel. + * and 48MHz. Reimplement with clk_mux. * * XXX does this need SYSC register handling? */ -static struct clk uart1_1510 = { - .name = "uart1_ck", - .ops = &clkops_null, +static struct omap1_clk uart1_1510 = { /* Direct from ULPD, no real parent */ - .parent = &armper_ck.clk, - .rate = 12000000, + .hw.init = CLK_HW_INIT("uart1_ck", "armper_ck", &omap1_clk_full_ops, 0), .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0), .enable_bit = CONF_MOD_UART1_CLK_MODE_R, + .round_rate = &omap1_round_uart_rate, .set_rate = &omap1_set_uart_rate, .recalc = &omap1_uart_recalc, }; /* * XXX The enable_bit here is misused - it simply switches between 12MHz - * and 48MHz. Reimplement with clksel. + * and 48MHz. Reimplement with clk_mux. * * XXX SYSC register handling does not belong in the clock framework */ static struct uart_clk uart1_16xx = { .clk = { - .name = "uart1_ck", .ops = &clkops_uart_16xx, /* Direct from ULPD, no real parent */ - .parent = &armper_ck.clk, + .hw.init = CLK_HW_INIT("uart1_ck", "armper_ck", &omap1_clk_full_ops, 0), .rate = 48000000, .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0), @@ -443,54 +394,49 @@ static struct uart_clk uart1_16xx = { /* * XXX The enable_bit here is misused - it simply switches between 12MHz - * and 48MHz. Reimplement with clksel. + * and 48MHz. Reimplement with clk_mux. * * XXX does this need SYSC register handling? */ -static struct clk uart2_ck = { - .name = "uart2_ck", - .ops = &clkops_null, +static struct omap1_clk uart2_ck = { /* Direct from ULPD, no real parent */ - .parent = &armper_ck.clk, - .rate = 12000000, + .hw.init = CLK_HW_INIT("uart2_ck", "armper_ck", &omap1_clk_full_ops, 0), .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0), .enable_bit = CONF_MOD_UART2_CLK_MODE_R, + .round_rate = &omap1_round_uart_rate, .set_rate = &omap1_set_uart_rate, .recalc = &omap1_uart_recalc, }; /* * XXX The enable_bit here is misused - it simply switches between 12MHz - * and 48MHz. Reimplement with clksel. + * and 48MHz. Reimplement with clk_mux. * * XXX does this need SYSC register handling? */ -static struct clk uart3_1510 = { - .name = "uart3_ck", - .ops = &clkops_null, +static struct omap1_clk uart3_1510 = { /* Direct from ULPD, no real parent */ - .parent = &armper_ck.clk, - .rate = 12000000, + .hw.init = CLK_HW_INIT("uart3_ck", "armper_ck", &omap1_clk_full_ops, 0), .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0), .enable_bit = CONF_MOD_UART3_CLK_MODE_R, + .round_rate = &omap1_round_uart_rate, .set_rate = &omap1_set_uart_rate, .recalc = &omap1_uart_recalc, }; /* * XXX The enable_bit here is misused - it simply switches between 12MHz - * and 48MHz. Reimplement with clksel. + * and 48MHz. Reimplement with clk_mux. * * XXX SYSC register handling does not belong in the clock framework */ static struct uart_clk uart3_16xx = { .clk = { - .name = "uart3_ck", .ops = &clkops_uart_16xx, /* Direct from ULPD, no real parent */ - .parent = &armper_ck.clk, + .hw.init = CLK_HW_INIT("uart3_ck", "armper_ck", &omap1_clk_full_ops, 0), .rate = 48000000, .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0), @@ -499,30 +445,30 @@ static struct uart_clk uart3_16xx = { .sysc_addr = 0xfffb9854, }; -static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */ - .name = "usb_clko", +static struct omap1_clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */ .ops = &clkops_generic, /* Direct from ULPD, no parent */ + .hw.init = CLK_HW_INIT_NO_PARENT("usb_clko", &omap1_clk_full_ops, 0), .rate = 6000000, .flags = ENABLE_REG_32BIT, .enable_reg = OMAP1_IO_ADDRESS(ULPD_CLOCK_CTRL), .enable_bit = USB_MCLK_EN_BIT, }; -static struct clk usb_hhc_ck1510 = { - .name = "usb_hhc_ck", +static struct omap1_clk usb_hhc_ck1510 = { .ops = &clkops_generic, /* Direct from ULPD, no parent */ + .hw.init = CLK_HW_INIT_NO_PARENT("usb_hhc_ck", &omap1_clk_full_ops, 0), .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ .flags = ENABLE_REG_32BIT, .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0), .enable_bit = USB_HOST_HHC_UHOST_EN, }; -static struct clk usb_hhc_ck16xx = { - .name = "usb_hhc_ck", +static struct omap1_clk usb_hhc_ck16xx = { .ops = &clkops_generic, /* Direct from ULPD, no parent */ + .hw.init = CLK_HW_INIT_NO_PARENT("usb_hhc_ck", &omap1_clk_full_ops, 0), .rate = 48000000, /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ .flags = ENABLE_REG_32BIT, @@ -530,46 +476,46 @@ static struct clk usb_hhc_ck16xx = { .enable_bit = OTG_SYSCON_2_UHOST_EN_SHIFT }; -static struct clk usb_dc_ck = { - .name = "usb_dc_ck", +static struct omap1_clk usb_dc_ck = { .ops = &clkops_generic, /* Direct from ULPD, no parent */ + .hw.init = CLK_HW_INIT_NO_PARENT("usb_dc_ck", &omap1_clk_full_ops, 0), .rate = 48000000, .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG), .enable_bit = SOFT_USB_OTG_DPLL_REQ_SHIFT, }; -static struct clk uart1_7xx = { - .name = "uart1_ck", +static struct omap1_clk uart1_7xx = { .ops = &clkops_generic, /* Direct from ULPD, no parent */ + .hw.init = CLK_HW_INIT_NO_PARENT("uart1_ck", &omap1_clk_full_ops, 0), .rate = 12000000, .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG), .enable_bit = 9, }; -static struct clk uart2_7xx = { - .name = "uart2_ck", +static struct omap1_clk uart2_7xx = { .ops = &clkops_generic, /* Direct from ULPD, no parent */ + .hw.init = CLK_HW_INIT_NO_PARENT("uart2_ck", &omap1_clk_full_ops, 0), .rate = 12000000, .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG), .enable_bit = 11, }; -static struct clk mclk_1510 = { - .name = "mclk", +static struct omap1_clk mclk_1510 = { .ops = &clkops_generic, /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .hw.init = CLK_HW_INIT_NO_PARENT("mclk", &omap1_clk_full_ops, 0), .rate = 12000000, .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG), .enable_bit = SOFT_COM_MCKO_REQ_SHIFT, }; -static struct clk mclk_16xx = { - .name = "mclk", +static struct omap1_clk mclk_16xx = { .ops = &clkops_generic, /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .hw.init = CLK_HW_INIT_NO_PARENT("mclk", &omap1_clk_full_ops, 0), .enable_reg = OMAP1_IO_ADDRESS(COM_CLK_DIV_CTRL_SEL), .enable_bit = COM_ULPD_PLL_CLK_REQ, .set_rate = &omap1_set_ext_clk_rate, @@ -577,17 +523,16 @@ static struct clk mclk_16xx = { .init = &omap1_init_ext_clk, }; -static struct clk bclk_1510 = { - .name = "bclk", - .ops = &clkops_generic, +static struct omap1_clk bclk_1510 = { /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .hw.init = CLK_HW_INIT_NO_PARENT("bclk", &omap1_clk_rate_ops, 0), .rate = 12000000, }; -static struct clk bclk_16xx = { - .name = "bclk", +static struct omap1_clk bclk_16xx = { .ops = &clkops_generic, /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .hw.init = CLK_HW_INIT_NO_PARENT("bclk", &omap1_clk_full_ops, 0), .enable_reg = OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL), .enable_bit = SWD_ULPD_PLL_CLK_REQ, .set_rate = &omap1_set_ext_clk_rate, @@ -595,11 +540,10 @@ static struct clk bclk_16xx = { .init = &omap1_init_ext_clk, }; -static struct clk mmc1_ck = { - .name = "mmc1_ck", +static struct omap1_clk mmc1_ck = { .ops = &clkops_generic, /* Functional clock is direct from ULPD, interface clock is ARMPER */ - .parent = &armper_ck.clk, + .hw.init = CLK_HW_INIT("mmc1_ck", "armper_ck", &omap1_clk_full_ops, 0), .rate = 48000000, .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0), @@ -610,32 +554,29 @@ static struct clk mmc1_ck = { * XXX MOD_CONF_CTRL_0 bit 20 is defined in the 1510 TRM as * CONF_MOD_MCBSP3_AUXON ?? */ -static struct clk mmc2_ck = { - .name = "mmc2_ck", +static struct omap1_clk mmc2_ck = { .ops = &clkops_generic, /* Functional clock is direct from ULPD, interface clock is ARMPER */ - .parent = &armper_ck.clk, + .hw.init = CLK_HW_INIT("mmc2_ck", "armper_ck", &omap1_clk_full_ops, 0), .rate = 48000000, .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0), .enable_bit = 20, }; -static struct clk mmc3_ck = { - .name = "mmc3_ck", +static struct omap1_clk mmc3_ck = { .ops = &clkops_generic, /* Functional clock is direct from ULPD, interface clock is ARMPER */ - .parent = &armper_ck.clk, + .hw.init = CLK_HW_INIT("mmc3_ck", "armper_ck", &omap1_clk_full_ops, 0), .rate = 48000000, .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG), .enable_bit = SOFT_MMC_DPLL_REQ_SHIFT, }; -static struct clk virtual_ck_mpu = { - .name = "mpu", - .ops = &clkops_null, - .parent = &arm_ck, /* Is smarter alias for */ +static struct omap1_clk virtual_ck_mpu = { + /* Is smarter alias for arm_ck */ + .hw.init = CLK_HW_INIT("mpu", "arm_ck", &omap1_clk_rate_ops, 0), .recalc = &followparent_recalc, .set_rate = &omap1_select_table_rate, .round_rate = &omap1_round_to_table_rate, @@ -643,20 +584,14 @@ static struct clk virtual_ck_mpu = { /* virtual functional clock domain for I2C. Just for making sure that ARMXOR_CK remains active during MPU idle whenever this is enabled */ -static struct clk i2c_fck = { - .name = "i2c_fck", - .ops = &clkops_null, +static struct omap1_clk i2c_fck = { + .hw.init = CLK_HW_INIT("i2c_fck", "armxor_ck", &omap1_clk_gate_ops, 0), .flags = CLOCK_NO_IDLE_PARENT, - .parent = &armxor_ck.clk, - .recalc = &followparent_recalc, }; -static struct clk i2c_ick = { - .name = "i2c_ick", - .ops = &clkops_null, +static struct omap1_clk i2c_ick = { + .hw.init = CLK_HW_INIT("i2c_ick", "armper_ck", &omap1_clk_gate_ops, 0), .flags = CLOCK_NO_IDLE_PARENT, - .parent = &armper_ck.clk, - .recalc = &followparent_recalc, }; /* @@ -665,81 +600,81 @@ static struct clk i2c_ick = { static struct omap_clk omap_clks[] = { /* non-ULPD clocks */ - CLK(NULL, "ck_ref", &ck_ref, CK_16XX | CK_1510 | CK_310 | CK_7XX), - CLK(NULL, "ck_dpll1", &ck_dpll1, CK_16XX | CK_1510 | CK_310 | CK_7XX), + CLK(NULL, "ck_ref", &ck_ref.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX), + CLK(NULL, "ck_dpll1", &ck_dpll1.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX), /* CK_GEN1 clocks */ - CLK(NULL, "ck_dpll1out", &ck_dpll1out.clk, CK_16XX), - CLK(NULL, "ck_sossi", &sossi_ck, CK_16XX), - CLK(NULL, "arm_ck", &arm_ck, CK_16XX | CK_1510 | CK_310), - CLK(NULL, "armper_ck", &armper_ck.clk, CK_16XX | CK_1510 | CK_310), - CLK("omap_gpio.0", "ick", &arm_gpio_ck, CK_1510 | CK_310), - CLK(NULL, "armxor_ck", &armxor_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_7XX), - CLK(NULL, "armtim_ck", &armtim_ck.clk, CK_16XX | CK_1510 | CK_310), - CLK("omap_wdt", "fck", &armwdt_ck.clk, CK_16XX | CK_1510 | CK_310), - CLK("omap_wdt", "ick", &armper_ck.clk, CK_16XX), - CLK("omap_wdt", "ick", &dummy_ck, CK_1510 | CK_310), - CLK(NULL, "arminth_ck", &arminth_ck1510, CK_1510 | CK_310), - CLK(NULL, "arminth_ck", &arminth_ck16xx, CK_16XX), + CLK(NULL, "ck_dpll1out", &ck_dpll1out.clk.hw, CK_16XX), + CLK(NULL, "ck_sossi", &sossi_ck.hw, CK_16XX), + CLK(NULL, "arm_ck", &arm_ck.hw, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "armper_ck", &armper_ck.clk.hw, CK_16XX | CK_1510 | CK_310), + CLK("omap_gpio.0", "ick", &arm_gpio_ck.hw, CK_1510 | CK_310), + CLK(NULL, "armxor_ck", &armxor_ck.clk.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX), + CLK(NULL, "armtim_ck", &armtim_ck.clk.hw, CK_16XX | CK_1510 | CK_310), + CLK("omap_wdt", "fck", &armwdt_ck.clk.hw, CK_16XX | CK_1510 | CK_310), + CLK("omap_wdt", "ick", &armper_ck.clk.hw, CK_16XX), + CLK("omap_wdt", "ick", &dummy_ck.hw, CK_1510 | CK_310), + CLK(NULL, "arminth_ck", &arminth_ck1510.hw, CK_1510 | CK_310), + CLK(NULL, "arminth_ck", &arminth_ck16xx.hw, CK_16XX), /* CK_GEN2 clocks */ - CLK(NULL, "dsp_ck", &dsp_ck, CK_16XX | CK_1510 | CK_310), - CLK(NULL, "dspmmu_ck", &dspmmu_ck, CK_16XX | CK_1510 | CK_310), - CLK(NULL, "dspper_ck", &dspper_ck, CK_16XX | CK_1510 | CK_310), - CLK(NULL, "dspxor_ck", &dspxor_ck, CK_16XX | CK_1510 | CK_310), - CLK(NULL, "dsptim_ck", &dsptim_ck, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "dsp_ck", &dsp_ck.hw, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "dspmmu_ck", &dspmmu_ck.hw, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "dspper_ck", &dspper_ck.hw, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "dspxor_ck", &dspxor_ck.hw, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "dsptim_ck", &dsptim_ck.hw, CK_16XX | CK_1510 | CK_310), /* CK_GEN3 clocks */ - CLK(NULL, "tc_ck", &tc_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_7XX), - CLK(NULL, "tipb_ck", &tipb_ck, CK_1510 | CK_310), - CLK(NULL, "l3_ocpi_ck", &l3_ocpi_ck, CK_16XX | CK_7XX), - CLK(NULL, "tc1_ck", &tc1_ck, CK_16XX), - CLK(NULL, "tc2_ck", &tc2_ck, CK_16XX), - CLK(NULL, "dma_ck", &dma_ck, CK_16XX | CK_1510 | CK_310), - CLK(NULL, "dma_lcdfree_ck", &dma_lcdfree_ck, CK_16XX), - CLK(NULL, "api_ck", &api_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_7XX), - CLK(NULL, "lb_ck", &lb_ck.clk, CK_1510 | CK_310), - CLK(NULL, "rhea1_ck", &rhea1_ck, CK_16XX), - CLK(NULL, "rhea2_ck", &rhea2_ck, CK_16XX), - CLK(NULL, "lcd_ck", &lcd_ck_16xx, CK_16XX | CK_7XX), - CLK(NULL, "lcd_ck", &lcd_ck_1510.clk, CK_1510 | CK_310), + CLK(NULL, "tc_ck", &tc_ck.clk.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX), + CLK(NULL, "tipb_ck", &tipb_ck.hw, CK_1510 | CK_310), + CLK(NULL, "l3_ocpi_ck", &l3_ocpi_ck.hw, CK_16XX | CK_7XX), + CLK(NULL, "tc1_ck", &tc1_ck.hw, CK_16XX), + CLK(NULL, "tc2_ck", &tc2_ck.hw, CK_16XX), + CLK(NULL, "dma_ck", &dma_ck.hw, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "dma_lcdfree_ck", &dma_lcdfree_ck.hw, CK_16XX), + CLK(NULL, "api_ck", &api_ck.clk.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX), + CLK(NULL, "lb_ck", &lb_ck.clk.hw, CK_1510 | CK_310), + CLK(NULL, "rhea1_ck", &rhea1_ck.hw, CK_16XX), + CLK(NULL, "rhea2_ck", &rhea2_ck.hw, CK_16XX), + CLK(NULL, "lcd_ck", &lcd_ck_16xx.hw, CK_16XX | CK_7XX), + CLK(NULL, "lcd_ck", &lcd_ck_1510.clk.hw, CK_1510 | CK_310), /* ULPD clocks */ - CLK(NULL, "uart1_ck", &uart1_1510, CK_1510 | CK_310), - CLK(NULL, "uart1_ck", &uart1_16xx.clk, CK_16XX), - CLK(NULL, "uart1_ck", &uart1_7xx, CK_7XX), - CLK(NULL, "uart2_ck", &uart2_ck, CK_16XX | CK_1510 | CK_310), - CLK(NULL, "uart2_ck", &uart2_7xx, CK_7XX), - CLK(NULL, "uart3_ck", &uart3_1510, CK_1510 | CK_310), - CLK(NULL, "uart3_ck", &uart3_16xx.clk, CK_16XX), - CLK(NULL, "usb_clko", &usb_clko, CK_16XX | CK_1510 | CK_310), - CLK(NULL, "usb_hhc_ck", &usb_hhc_ck1510, CK_1510 | CK_310), - CLK(NULL, "usb_hhc_ck", &usb_hhc_ck16xx, CK_16XX), - CLK(NULL, "usb_dc_ck", &usb_dc_ck, CK_16XX | CK_7XX), - CLK(NULL, "mclk", &mclk_1510, CK_1510 | CK_310), - CLK(NULL, "mclk", &mclk_16xx, CK_16XX), - CLK(NULL, "bclk", &bclk_1510, CK_1510 | CK_310), - CLK(NULL, "bclk", &bclk_16xx, CK_16XX), - CLK("mmci-omap.0", "fck", &mmc1_ck, CK_16XX | CK_1510 | CK_310), - CLK("mmci-omap.0", "fck", &mmc3_ck, CK_7XX), - CLK("mmci-omap.0", "ick", &armper_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_7XX), - CLK("mmci-omap.1", "fck", &mmc2_ck, CK_16XX), - CLK("mmci-omap.1", "ick", &armper_ck.clk, CK_16XX), + CLK(NULL, "uart1_ck", &uart1_1510.hw, CK_1510 | CK_310), + CLK(NULL, "uart1_ck", &uart1_16xx.clk.hw, CK_16XX), + CLK(NULL, "uart1_ck", &uart1_7xx.hw, CK_7XX), + CLK(NULL, "uart2_ck", &uart2_ck.hw, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "uart2_ck", &uart2_7xx.hw, CK_7XX), + CLK(NULL, "uart3_ck", &uart3_1510.hw, CK_1510 | CK_310), + CLK(NULL, "uart3_ck", &uart3_16xx.clk.hw, CK_16XX), + CLK(NULL, "usb_clko", &usb_clko.hw, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "usb_hhc_ck", &usb_hhc_ck1510.hw, CK_1510 | CK_310), + CLK(NULL, "usb_hhc_ck", &usb_hhc_ck16xx.hw, CK_16XX), + CLK(NULL, "usb_dc_ck", &usb_dc_ck.hw, CK_16XX | CK_7XX), + CLK(NULL, "mclk", &mclk_1510.hw, CK_1510 | CK_310), + CLK(NULL, "mclk", &mclk_16xx.hw, CK_16XX), + CLK(NULL, "bclk", &bclk_1510.hw, CK_1510 | CK_310), + CLK(NULL, "bclk", &bclk_16xx.hw, CK_16XX), + CLK("mmci-omap.0", "fck", &mmc1_ck.hw, CK_16XX | CK_1510 | CK_310), + CLK("mmci-omap.0", "fck", &mmc3_ck.hw, CK_7XX), + CLK("mmci-omap.0", "ick", &armper_ck.clk.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX), + CLK("mmci-omap.1", "fck", &mmc2_ck.hw, CK_16XX), + CLK("mmci-omap.1", "ick", &armper_ck.clk.hw, CK_16XX), /* Virtual clocks */ - CLK(NULL, "mpu", &virtual_ck_mpu, CK_16XX | CK_1510 | CK_310), - CLK("omap_i2c.1", "fck", &i2c_fck, CK_16XX | CK_1510 | CK_310 | CK_7XX), - CLK("omap_i2c.1", "ick", &i2c_ick, CK_16XX), - CLK("omap_i2c.1", "ick", &dummy_ck, CK_1510 | CK_310 | CK_7XX), - CLK("omap1_spi100k.1", "fck", &dummy_ck, CK_7XX), - CLK("omap1_spi100k.1", "ick", &dummy_ck, CK_7XX), - CLK("omap1_spi100k.2", "fck", &dummy_ck, CK_7XX), - CLK("omap1_spi100k.2", "ick", &dummy_ck, CK_7XX), - CLK("omap_uwire", "fck", &armxor_ck.clk, CK_16XX | CK_1510 | CK_310), - CLK("omap-mcbsp.1", "ick", &dspper_ck, CK_16XX), - CLK("omap-mcbsp.1", "ick", &dummy_ck, CK_1510 | CK_310), - CLK("omap-mcbsp.2", "ick", &armper_ck.clk, CK_16XX), - CLK("omap-mcbsp.2", "ick", &dummy_ck, CK_1510 | CK_310), - CLK("omap-mcbsp.3", "ick", &dspper_ck, CK_16XX), - CLK("omap-mcbsp.3", "ick", &dummy_ck, CK_1510 | CK_310), - CLK("omap-mcbsp.1", "fck", &dspxor_ck, CK_16XX | CK_1510 | CK_310), - CLK("omap-mcbsp.2", "fck", &armper_ck.clk, CK_16XX | CK_1510 | CK_310), - CLK("omap-mcbsp.3", "fck", &dspxor_ck, CK_16XX | CK_1510 | CK_310), + CLK(NULL, "mpu", &virtual_ck_mpu.hw, CK_16XX | CK_1510 | CK_310), + CLK("omap_i2c.1", "fck", &i2c_fck.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX), + CLK("omap_i2c.1", "ick", &i2c_ick.hw, CK_16XX), + CLK("omap_i2c.1", "ick", &dummy_ck.hw, CK_1510 | CK_310 | CK_7XX), + CLK("omap1_spi100k.1", "fck", &dummy_ck.hw, CK_7XX), + CLK("omap1_spi100k.1", "ick", &dummy_ck.hw, CK_7XX), + CLK("omap1_spi100k.2", "fck", &dummy_ck.hw, CK_7XX), + CLK("omap1_spi100k.2", "ick", &dummy_ck.hw, CK_7XX), + CLK("omap_uwire", "fck", &armxor_ck.clk.hw, CK_16XX | CK_1510 | CK_310), + CLK("omap-mcbsp.1", "ick", &dspper_ck.hw, CK_16XX), + CLK("omap-mcbsp.1", "ick", &dummy_ck.hw, CK_1510 | CK_310), + CLK("omap-mcbsp.2", "ick", &armper_ck.clk.hw, CK_16XX), + CLK("omap-mcbsp.2", "ick", &dummy_ck.hw, CK_1510 | CK_310), + CLK("omap-mcbsp.3", "ick", &dspper_ck.hw, CK_16XX), + CLK("omap-mcbsp.3", "ick", &dummy_ck.hw, CK_1510 | CK_310), + CLK("omap-mcbsp.1", "fck", &dspxor_ck.hw, CK_16XX | CK_1510 | CK_310), + CLK("omap-mcbsp.2", "fck", &armper_ck.clk.hw, CK_16XX | CK_1510 | CK_310), + CLK("omap-mcbsp.3", "fck", &dspxor_ck.hw, CK_16XX | CK_1510 | CK_310), }; /* @@ -778,9 +713,6 @@ int __init omap1_clk_init(void) /* By default all idlect1 clocks are allowed to idle */ arm_idlect1_mask = ~0; - for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++) - clk_preinit(c->lk.clk); - cpu_mask = 0; if (cpu_is_omap1710()) cpu_mask |= CK_1710; @@ -793,16 +725,10 @@ int __init omap1_clk_init(void) if (cpu_is_omap310()) cpu_mask |= CK_310; - for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++) - if (c->cpu & cpu_mask) { - clkdev_add(&c->lk); - clk_register(c->lk.clk); - } - /* Pointers to these clocks are needed by code in clock.c */ - api_ck_p = clk_get(NULL, "api_ck"); - ck_dpll1_p = clk_get(NULL, "ck_dpll1"); - ck_ref_p = clk_get(NULL, "ck_ref"); + api_ck_p = &api_ck.clk; + ck_dpll1_p = &ck_dpll1; + ck_ref_p = &ck_ref; if (cpu_is_omap7xx()) ck_ref.rate = 13000000; @@ -844,10 +770,7 @@ int __init omap1_clk_init(void) } } } - propagate_rate(&ck_dpll1); - /* Cache rates for clocks connected to ck_ref (not dpll1) */ - propagate_rate(&ck_ref); - omap1_show_rates(); + if (machine_is_omap_perseus2() || machine_is_omap_fsample()) { /* Select slicer output as OMAP input clock */ omap_writew(omap_readw(OMAP7XX_PCC_UPLD_CTRL) & ~0x1, @@ -879,16 +802,28 @@ int __init omap1_clk_init(void) */ omap_writew(0x0000, ARM_IDLECT2); /* Turn LCD clock off also */ - /* - * Only enable those clocks we will need, let the drivers - * enable other clocks as necessary - */ - clk_enable(&armper_ck.clk); - clk_enable(&armxor_ck.clk); - clk_enable(&armtim_ck.clk); /* This should be done by timer code */ + for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++) { + if (!(c->cpu & cpu_mask)) + continue; + + if (c->lk.clk_hw->init) { /* NULL if provider already registered */ + const struct clk_init_data *init = c->lk.clk_hw->init; + const char *name = c->lk.clk_hw->init->name; + int err; + + err = clk_hw_register(NULL, c->lk.clk_hw); + if (err < 0) { + pr_err("failed to register clock \"%s\"! (%d)\n", name, err); + /* may be tried again, restore init data */ + c->lk.clk_hw->init = init; + continue; + } + } + + clk_hw_register_clkdev(c->lk.clk_hw, c->lk.con_id, c->lk.dev_id); + } - if (cpu_is_omap15xx()) - clk_enable(&arm_gpio_ck); + omap1_show_rates(); return 0; } @@ -900,7 +835,7 @@ void __init omap1_clk_late_init(void) unsigned long rate = ck_dpll1.rate; /* Find the highest supported frequency and enable it */ - if (omap1_select_table_rate(&virtual_ck_mpu, ~0)) { + if (omap1_select_table_rate(&virtual_ck_mpu, ~0, arm_ck.rate)) { pr_err("System frequencies not set, using default. Check your config.\n"); /* * Reprogramming the DPLL is tricky, it must be done from SRAM. diff --git a/arch/arm/mach-omap1/hardware.h b/arch/arm/mach-omap1/hardware.h index 738becbd2972..c228234a1ed4 100644 --- a/arch/arm/mach-omap1/hardware.h +++ b/arch/arm/mach-omap1/hardware.h @@ -64,7 +64,7 @@ static inline u32 omap_cs3_phys(void) #define OMAP1_IO_OFFSET 0x00f00000 /* Virtual IO = 0xff0b0000 */ #define OMAP1_IO_ADDRESS(pa) IOMEM((pa) - OMAP1_IO_OFFSET) -#include <mach/serial.h> +#include "serial.h" /* * --------------------------------------------------------------------------- diff --git a/arch/arm/mach-omap1/include/mach/uncompress.h b/arch/arm/mach-omap1/include/mach/uncompress.h deleted file mode 100644 index 9cca6a56788f..000000000000 --- a/arch/arm/mach-omap1/include/mach/uncompress.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * arch/arm/plat-omap/include/mach/uncompress.h - * - * Serial port stubs for kernel decompress status messages - * - * Initially based on: - * linux-2.4.15-rmk1-dsplinux1.6/arch/arm/plat-omap/include/mach1510/uncompress.h - * Copyright (C) 2000 RidgeRun, Inc. - * Author: Greg Lonnon <glonnon@ridgerun.com> - * - * Rewritten by: - * Author: <source@mvista.com> - * 2004 (c) MontaVista Software, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include <linux/types.h> -#include <linux/serial_reg.h> - -#include <asm/memory.h> -#include <asm/mach-types.h> - -#include "serial.h" - -#define MDR1_MODE_MASK 0x07 - -volatile u8 *uart_base; -int uart_shift; - -/* - * Store the DEBUG_LL uart number into memory. - * See also debug-macro.S, and serial.c for related code. - */ -static void set_omap_uart_info(unsigned char port) -{ - /* - * Get address of some.bss variable and round it down - * a la CONFIG_AUTO_ZRELADDR. - */ - u32 ram_start = (u32)&uart_shift & 0xf8000000; - u32 *uart_info = (u32 *)(ram_start + OMAP_UART_INFO_OFS); - *uart_info = port; -} - -static inline void putc(int c) -{ - if (!uart_base) - return; - - /* Check for UART 16x mode */ - if ((uart_base[UART_OMAP_MDR1 << uart_shift] & MDR1_MODE_MASK) != 0) - return; - - while (!(uart_base[UART_LSR << uart_shift] & UART_LSR_THRE)) - barrier(); - uart_base[UART_TX << uart_shift] = c; -} - -static inline void flush(void) -{ -} - -/* - * Macros to configure UART1 and debug UART - */ -#define _DEBUG_LL_ENTRY(mach, dbg_uart, dbg_shft, dbg_id) \ - if (machine_is_##mach()) { \ - uart_base = (volatile u8 *)(dbg_uart); \ - uart_shift = (dbg_shft); \ - port = (dbg_id); \ - set_omap_uart_info(port); \ - break; \ - } - -#define DEBUG_LL_OMAP7XX(p, mach) \ - _DEBUG_LL_ENTRY(mach, OMAP1_UART##p##_BASE, OMAP7XX_PORT_SHIFT, \ - OMAP1UART##p) - -#define DEBUG_LL_OMAP1(p, mach) \ - _DEBUG_LL_ENTRY(mach, OMAP1_UART##p##_BASE, OMAP_PORT_SHIFT, \ - OMAP1UART##p) - -static inline void arch_decomp_setup(void) -{ - int port = 0; - - /* - * Initialize the port based on the machine ID from the bootloader. - * Note that we're using macros here instead of switch statement - * as machine_is functions are optimized out for the boards that - * are not selected. - */ - do { - /* omap7xx/8xx based boards using UART1 with shift 0 */ - DEBUG_LL_OMAP7XX(1, herald); - DEBUG_LL_OMAP7XX(1, omap_perseus2); - - /* omap15xx/16xx based boards using UART1 */ - DEBUG_LL_OMAP1(1, ams_delta); - DEBUG_LL_OMAP1(1, nokia770); - DEBUG_LL_OMAP1(1, omap_h2); - DEBUG_LL_OMAP1(1, omap_h3); - DEBUG_LL_OMAP1(1, omap_innovator); - DEBUG_LL_OMAP1(1, omap_osk); - DEBUG_LL_OMAP1(1, omap_palmte); - DEBUG_LL_OMAP1(1, omap_palmz71); - - /* omap15xx/16xx based boards using UART2 */ - DEBUG_LL_OMAP1(2, omap_palmtt); - - /* omap15xx/16xx based boards using UART3 */ - DEBUG_LL_OMAP1(3, sx1); - } while (0); -} diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c index 05ee260918fa..d2db9b8aed3f 100644 --- a/arch/arm/mach-omap1/io.c +++ b/arch/arm/mach-omap1/io.c @@ -15,10 +15,8 @@ #include <asm/mach/map.h> #include "tc.h" -#include "mux.h" #include "iomap.h" #include "common.h" -#include "clock.h" /* * The machine specific code may provide the extra mapping besides the @@ -125,11 +123,6 @@ void __init omap1_init_early(void) */ omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL); omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL); - - /* Must init clocks early to assure that timer interrupt works - */ - omap1_clk_init(); - omap1_mux_init(); } void __init omap1_init_late(void) diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index 299ae1106187..88928fc33b2e 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -19,8 +19,7 @@ #include <asm/mach-types.h> -#include <mach/serial.h> - +#include "serial.h" #include "mux.h" #include "pm.h" #include "soc.h" diff --git a/arch/arm/mach-omap1/include/mach/serial.h b/arch/arm/mach-omap1/serial.h index 4700e384c3d9..4700e384c3d9 100644 --- a/arch/arm/mach-omap1/include/mach/serial.h +++ b/arch/arm/mach-omap1/serial.h diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index c34b9af00566..d5e127851dc7 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -51,8 +51,10 @@ #include <asm/mach/time.h> #include "hardware.h" +#include "mux.h" #include "iomap.h" #include "common.h" +#include "clock.h" #ifdef CONFIG_OMAP_MPU_TIMER @@ -224,6 +226,9 @@ static inline void omap_mpu_timer_init(void) */ void __init omap1_timer_init(void) { + omap1_clk_init(); + omap1_mux_init(); + if (omap_32k_timer_init() != 0) omap_mpu_timer_init(); } diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 57f0be4065c1..a5df1d9f3360 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -1,4 +1,19 @@ # SPDX-License-Identifier: GPL-2.0-only +menuconfig ARCH_PXA + bool "PXA2xx/PXA3xx-based" + depends on ARCH_MULTI_V5 + depends on CPU_LITTLE_ENDIAN + select ARM_CPU_SUSPEND if PM + select CLKSRC_PXA + select CLKSRC_MMIO + select TIMER_OF + select CPU_XSCALE if !CPU_XSC3 + select GPIO_PXA + select GPIOLIB + select PLAT_PXA + help + Support for Intel/Marvell's PXA2xx/PXA3xx processor line. + if ARCH_PXA menu "Intel PXA2xx/PXA3xx Implementations" diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 68730ceb8b7c..0aec36e67dc1 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -37,7 +37,8 @@ obj-$(CONFIG_MACH_SAAR) += saar.o obj-$(CONFIG_ARCH_PXA_IDP) += idp.o obj-$(CONFIG_ARCH_VIPER) += viper.o obj-$(CONFIG_MACH_ARCOM_ZEUS) += zeus.o -obj-$(CONFIG_MACH_BALLOON3) += balloon3.o +obj-$(CONFIG_ARCOM_PCMCIA) += viper-pcmcia.o +obj-$(CONFIG_MACH_BALLOON3) += balloon3.o balloon3-pcmcia.o obj-$(CONFIG_MACH_CSB726) += csb726.o obj-$(CONFIG_CSB726_CSB701) += csb701.o obj-$(CONFIG_MACH_CM_X300) += cm-x300.o @@ -47,18 +48,20 @@ obj-$(CONFIG_GUMSTIX_AM200EPD) += am200epd.o obj-$(CONFIG_GUMSTIX_AM300EPD) += am300epd.o obj-$(CONFIG_MACH_XCEP) += xcep.o obj-$(CONFIG_MACH_TRIZEPS4) += trizeps4.o +obj-$(CONFIG_TRIZEPS_PCMCIA) += trizeps4-pcmcia.o obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o obj-$(CONFIG_MACH_PCM027) += pcm027.o obj-$(CONFIG_MACH_PCM990_BASEBOARD) += pcm990-baseboard.o -obj-$(CONFIG_MACH_COLIBRI) += colibri-pxa270.o +obj-$(CONFIG_MACH_COLIBRI) += colibri-pxa270.o colibri-pcmcia.o obj-$(CONFIG_MACH_COLIBRI_EVALBOARD) += colibri-evalboard.o obj-$(CONFIG_MACH_COLIBRI_PXA270_INCOME) += colibri-pxa270-income.o obj-$(CONFIG_MACH_COLIBRI300) += colibri-pxa3xx.o colibri-pxa300.o -obj-$(CONFIG_MACH_COLIBRI320) += colibri-pxa3xx.o colibri-pxa320.o -obj-$(CONFIG_MACH_VPAC270) += vpac270.o +obj-$(CONFIG_MACH_COLIBRI320) += colibri-pxa3xx.o colibri-pxa320.o colibri-pcmcia.o +obj-$(CONFIG_MACH_VPAC270) += vpac270.o vpac270-pcmcia.o # End-user Products obj-$(CONFIG_MACH_H4700) += hx4700.o +obj-$(CONFIG_MACH_H4700) += hx4700-pcmcia.o obj-$(CONFIG_MACH_H5000) += h5000.o obj-$(CONFIG_MACH_HIMALAYA) += himalaya.o obj-$(CONFIG_MACH_MAGICIAN) += magician.o @@ -66,12 +69,12 @@ obj-$(CONFIG_MACH_MIOA701) += mioa701.o mioa701_bootresume.o obj-$(CONFIG_PXA_EZX) += ezx.o obj-$(CONFIG_MACH_MP900C) += mp900.o obj-$(CONFIG_MACH_PALMTE2) += palmte2.o -obj-$(CONFIG_MACH_PALMTC) += palmtc.o +obj-$(CONFIG_MACH_PALMTC) += palmtc.o palmtc-pcmcia.o obj-$(CONFIG_MACH_PALM27X) += palm27x.o obj-$(CONFIG_MACH_PALMT5) += palmt5.o -obj-$(CONFIG_MACH_PALMTX) += palmtx.o +obj-$(CONFIG_MACH_PALMTX) += palmtx.o palmtx-pcmcia.o obj-$(CONFIG_MACH_PALMZ72) += palmz72.o -obj-$(CONFIG_MACH_PALMLD) += palmld.o +obj-$(CONFIG_MACH_PALMLD) += palmld.o palmld-pcmcia.o obj-$(CONFIG_PALM_TREO) += palmtreo.o obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o sharpsl_pm.o corgi_pm.o obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o sharpsl_pm.o spitz_pm.o @@ -79,6 +82,7 @@ obj-$(CONFIG_MACH_POODLE) += poodle.o obj-$(CONFIG_MACH_TOSA) += tosa.o obj-$(CONFIG_MACH_ICONTROL) += icontrol.o mxm8x10.o obj-$(CONFIG_ARCH_PXA_ESERIES) += eseries.o +obj-$(CONFIG_MACH_E740) += e740-pcmcia.o obj-$(CONFIG_MACH_ZIPIT2) += z2.o obj-$(CONFIG_PXA_SYSTEMS_CPLDS) += pxa_cplds_irqs.o diff --git a/arch/arm/mach-pxa/include/mach/addr-map.h b/arch/arm/mach-pxa/addr-map.h index 93cfe7dbfec6..93cfe7dbfec6 100644 --- a/arch/arm/mach-pxa/include/mach/addr-map.h +++ b/arch/arm/mach-pxa/addr-map.h diff --git a/arch/arm/mach-pxa/am300epd.c b/arch/arm/mach-pxa/am300epd.c index 17d08abeeb17..4b55bc89db8f 100644 --- a/arch/arm/mach-pxa/am300epd.c +++ b/arch/arm/mach-pxa/am300epd.c @@ -30,7 +30,7 @@ #include "gumstix.h" #include "mfp-pxa25x.h" -#include <mach/irqs.h> +#include "irqs.h" #include <linux/platform_data/video-pxafb.h> #include "generic.h" diff --git a/arch/arm/mach-pxa/balloon3-pcmcia.c b/arch/arm/mach-pxa/balloon3-pcmcia.c new file mode 100644 index 000000000000..6a27b76cc603 --- /dev/null +++ b/arch/arm/mach-pxa/balloon3-pcmcia.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/drivers/pcmcia/pxa2xx_balloon3.c + * + * Balloon3 PCMCIA specific routines. + * + * Author: Nick Bane + * Created: June, 2006 + * Copyright: Toby Churchill Ltd + * Derived from pxa2xx_mainstone.c, by Nico Pitre + * + * Various modification by Marek Vasut <marek.vasut@gmail.com> + */ + +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/irq.h> +#include <linux/io.h> + +#include "balloon3.h" + +#include <asm/mach-types.h> + +#include <pcmcia/soc_common.h> + +static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + uint16_t ver; + + ver = __raw_readw(BALLOON3_FPGA_VER); + if (ver < 0x4f08) + pr_warn("The FPGA code, version 0x%04x, is too old. " + "PCMCIA/CF support might be broken in this version!", + ver); + + skt->socket.pci_irq = BALLOON3_BP_CF_NRDY_IRQ; + skt->stat[SOC_STAT_CD].gpio = BALLOON3_GPIO_S0_CD; + skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD"; + skt->stat[SOC_STAT_BVD1].irq = BALLOON3_BP_NSTSCHG_IRQ; + skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG"; + + return 0; +} + +static unsigned long balloon3_pcmcia_status[2] = { + BALLOON3_CF_nSTSCHG_BVD1, + BALLOON3_CF_nSTSCHG_BVD1 +}; + +static void balloon3_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + uint16_t status; + int flip; + + /* This actually reads the STATUS register */ + status = __raw_readw(BALLOON3_CF_STATUS_REG); + flip = (status ^ balloon3_pcmcia_status[skt->nr]) + & BALLOON3_CF_nSTSCHG_BVD1; + /* + * Workaround for STSCHG which can't be deasserted: + * We therefore disable/enable corresponding IRQs + * as needed to avoid IRQ locks. + */ + if (flip) { + balloon3_pcmcia_status[skt->nr] = status; + if (status & BALLOON3_CF_nSTSCHG_BVD1) + enable_irq(BALLOON3_BP_NSTSCHG_IRQ); + else + disable_irq(BALLOON3_BP_NSTSCHG_IRQ); + } + + state->ready = !!(status & BALLOON3_CF_nIRQ); + state->bvd1 = !!(status & BALLOON3_CF_nSTSCHG_BVD1); + state->bvd2 = 0; /* not available */ + state->vs_3v = 1; /* Always true its a CF card */ + state->vs_Xv = 0; /* not available */ +} + +static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + __raw_writew(BALLOON3_CF_RESET, BALLOON3_CF_CONTROL_REG + + ((state->flags & SS_RESET) ? + BALLOON3_FPGA_SETnCLR : 0)); + return 0; +} + +static struct pcmcia_low_level balloon3_pcmcia_ops = { + .owner = THIS_MODULE, + .hw_init = balloon3_pcmcia_hw_init, + .socket_state = balloon3_pcmcia_socket_state, + .configure_socket = balloon3_pcmcia_configure_socket, + .first = 0, + .nr = 1, +}; + +static struct platform_device *balloon3_pcmcia_device; + +static int __init balloon3_pcmcia_init(void) +{ + int ret; + + if (!machine_is_balloon3()) + return -ENODEV; + + balloon3_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!balloon3_pcmcia_device) + return -ENOMEM; + + ret = platform_device_add_data(balloon3_pcmcia_device, + &balloon3_pcmcia_ops, sizeof(balloon3_pcmcia_ops)); + + if (!ret) + ret = platform_device_add(balloon3_pcmcia_device); + + if (ret) + platform_device_put(balloon3_pcmcia_device); + + return ret; +} + +static void __exit balloon3_pcmcia_exit(void) +{ + platform_device_unregister(balloon3_pcmcia_device); +} + +module_init(balloon3_pcmcia_init); +module_exit(balloon3_pcmcia_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nick Bane <nick@cecomputing.co.uk>"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); +MODULE_DESCRIPTION("Balloon3 board CF/PCMCIA driver"); diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c index 26140249c784..896d47d9a8dc 100644 --- a/arch/arm/mach-pxa/balloon3.c +++ b/arch/arm/mach-pxa/balloon3.c @@ -40,8 +40,8 @@ #include <asm/mach/flash.h> #include "pxa27x.h" -#include <mach/balloon3.h> -#include <mach/audio.h> +#include "balloon3.h" +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/mmc-pxamci.h> #include "udc.h" diff --git a/arch/arm/mach-pxa/include/mach/balloon3.h b/arch/arm/mach-pxa/balloon3.h index 04f3639c4082..04f3639c4082 100644 --- a/arch/arm/mach-pxa/include/mach/balloon3.h +++ b/arch/arm/mach-pxa/balloon3.h diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c index 2e35354b61f5..01f364a66446 100644 --- a/arch/arm/mach-pxa/cm-x300.c +++ b/arch/arm/mach-pxa/cm-x300.c @@ -40,6 +40,8 @@ #include <linux/spi/spi_gpio.h> #include <linux/spi/tdo24m.h> +#include <linux/soc/pxa/cpu.h> + #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/setup.h> @@ -51,7 +53,7 @@ #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/usb-ohci-pxa27x.h> #include <linux/platform_data/mtd-nand-pxa3xx.h> -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/usb-pxa3xx-ulpi.h> #include <asm/mach/map.h> @@ -354,13 +356,13 @@ static struct platform_device cm_x300_spi_gpio = { static struct gpiod_lookup_table cm_x300_spi_gpiod_table = { .dev_id = "spi_gpio", .table = { - GPIO_LOOKUP("gpio-pxa", GPIO_LCD_SCL, + GPIO_LOOKUP("pca9555.1", GPIO_LCD_SCL - GPIO_LCD_BASE, "sck", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DIN, + GPIO_LOOKUP("pca9555.1", GPIO_LCD_DIN - GPIO_LCD_BASE, "mosi", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DOUT, + GPIO_LOOKUP("pca9555.1", GPIO_LCD_DOUT - GPIO_LCD_BASE, "miso", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("gpio-pxa", GPIO_LCD_CS, + GPIO_LOOKUP("pca9555.1", GPIO_LCD_CS - GPIO_LCD_BASE, "cs", GPIO_ACTIVE_HIGH), { }, }, diff --git a/arch/arm/mach-pxa/colibri-evalboard.c b/arch/arm/mach-pxa/colibri-evalboard.c index b9c173ede891..b62af07b8f96 100644 --- a/arch/arm/mach-pxa/colibri-evalboard.c +++ b/arch/arm/mach-pxa/colibri-evalboard.c @@ -13,7 +13,6 @@ #include <linux/interrupt.h> #include <linux/gpio/machine.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <asm/mach/arch.h> #include <linux/i2c.h> #include <linux/platform_data/i2c-pxa.h> diff --git a/arch/arm/mach-pxa/colibri-pcmcia.c b/arch/arm/mach-pxa/colibri-pcmcia.c new file mode 100644 index 000000000000..9da7b478e5eb --- /dev/null +++ b/arch/arm/mach-pxa/colibri-pcmcia.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/drivers/pcmcia/pxa2xx_colibri.c + * + * Driver for Toradex Colibri PXA270 CF socket + * + * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/gpio.h> + +#include <asm/mach-types.h> + +#include <pcmcia/soc_common.h> + +#define COLIBRI270_RESET_GPIO 53 +#define COLIBRI270_PPEN_GPIO 107 +#define COLIBRI270_BVD1_GPIO 83 +#define COLIBRI270_BVD2_GPIO 82 +#define COLIBRI270_DETECT_GPIO 84 +#define COLIBRI270_READY_GPIO 1 + +#define COLIBRI320_RESET_GPIO 77 +#define COLIBRI320_PPEN_GPIO 57 +#define COLIBRI320_BVD1_GPIO 53 +#define COLIBRI320_BVD2_GPIO 79 +#define COLIBRI320_DETECT_GPIO 81 +#define COLIBRI320_READY_GPIO 29 + +enum { + DETECT = 0, + READY = 1, + BVD1 = 2, + BVD2 = 3, + PPEN = 4, + RESET = 5, +}; + +/* Contents of this array are configured on-the-fly in init function */ +static struct gpio colibri_pcmcia_gpios[] = { + { 0, GPIOF_IN, "PCMCIA Detect" }, + { 0, GPIOF_IN, "PCMCIA Ready" }, + { 0, GPIOF_IN, "PCMCIA BVD1" }, + { 0, GPIOF_IN, "PCMCIA BVD2" }, + { 0, GPIOF_INIT_LOW, "PCMCIA PPEN" }, + { 0, GPIOF_INIT_HIGH,"PCMCIA Reset" }, +}; + +static int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + int ret; + + ret = gpio_request_array(colibri_pcmcia_gpios, + ARRAY_SIZE(colibri_pcmcia_gpios)); + if (ret) + goto err1; + + skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpios[READY].gpio); + skt->stat[SOC_STAT_CD].irq = gpio_to_irq(colibri_pcmcia_gpios[DETECT].gpio); + skt->stat[SOC_STAT_CD].name = "PCMCIA CD"; + +err1: + return ret; +} + +static void colibri_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + gpio_free_array(colibri_pcmcia_gpios, + ARRAY_SIZE(colibri_pcmcia_gpios)); +} + +static void colibri_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + + state->detect = !!gpio_get_value(colibri_pcmcia_gpios[DETECT].gpio); + state->ready = !!gpio_get_value(colibri_pcmcia_gpios[READY].gpio); + state->bvd1 = !!gpio_get_value(colibri_pcmcia_gpios[BVD1].gpio); + state->bvd2 = !!gpio_get_value(colibri_pcmcia_gpios[BVD2].gpio); + state->vs_3v = 1; + state->vs_Xv = 0; +} + +static int +colibri_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + gpio_set_value(colibri_pcmcia_gpios[PPEN].gpio, + !(state->Vcc == 33 && state->Vpp < 50)); + gpio_set_value(colibri_pcmcia_gpios[RESET].gpio, + state->flags & SS_RESET); + return 0; +} + +static struct pcmcia_low_level colibri_pcmcia_ops = { + .owner = THIS_MODULE, + + .first = 0, + .nr = 1, + + .hw_init = colibri_pcmcia_hw_init, + .hw_shutdown = colibri_pcmcia_hw_shutdown, + + .socket_state = colibri_pcmcia_socket_state, + .configure_socket = colibri_pcmcia_configure_socket, +}; + +static struct platform_device *colibri_pcmcia_device; + +static int __init colibri_pcmcia_init(void) +{ + int ret; + + if (!machine_is_colibri() && !machine_is_colibri320()) + return -ENODEV; + + colibri_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!colibri_pcmcia_device) + return -ENOMEM; + + /* Colibri PXA270 */ + if (machine_is_colibri()) { + colibri_pcmcia_gpios[RESET].gpio = COLIBRI270_RESET_GPIO; + colibri_pcmcia_gpios[PPEN].gpio = COLIBRI270_PPEN_GPIO; + colibri_pcmcia_gpios[BVD1].gpio = COLIBRI270_BVD1_GPIO; + colibri_pcmcia_gpios[BVD2].gpio = COLIBRI270_BVD2_GPIO; + colibri_pcmcia_gpios[DETECT].gpio = COLIBRI270_DETECT_GPIO; + colibri_pcmcia_gpios[READY].gpio = COLIBRI270_READY_GPIO; + /* Colibri PXA320 */ + } else if (machine_is_colibri320()) { + colibri_pcmcia_gpios[RESET].gpio = COLIBRI320_RESET_GPIO; + colibri_pcmcia_gpios[PPEN].gpio = COLIBRI320_PPEN_GPIO; + colibri_pcmcia_gpios[BVD1].gpio = COLIBRI320_BVD1_GPIO; + colibri_pcmcia_gpios[BVD2].gpio = COLIBRI320_BVD2_GPIO; + colibri_pcmcia_gpios[DETECT].gpio = COLIBRI320_DETECT_GPIO; + colibri_pcmcia_gpios[READY].gpio = COLIBRI320_READY_GPIO; + } + + ret = platform_device_add_data(colibri_pcmcia_device, + &colibri_pcmcia_ops, sizeof(colibri_pcmcia_ops)); + + if (!ret) + ret = platform_device_add(colibri_pcmcia_device); + + if (ret) + platform_device_put(colibri_pcmcia_device); + + return ret; +} + +static void __exit colibri_pcmcia_exit(void) +{ + platform_device_unregister(colibri_pcmcia_device); +} + +module_init(colibri_pcmcia_init); +module_exit(colibri_pcmcia_exit); + +MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); +MODULE_DESCRIPTION("PCMCIA support for Toradex Colibri PXA270/PXA320"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c index e5879e8b0682..f6eaf464ca83 100644 --- a/arch/arm/mach-pxa/colibri-pxa270-income.c +++ b/arch/arm/mach-pxa/colibri-pxa270-income.c @@ -25,7 +25,6 @@ #include <asm/irq.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/usb-ohci-pxa27x.h> #include "pxa27x.h" diff --git a/arch/arm/mach-pxa/colibri-pxa270.c b/arch/arm/mach-pxa/colibri-pxa270.c index 2f2cd2ae4187..5dc669752836 100644 --- a/arch/arm/mach-pxa/colibri-pxa270.c +++ b/arch/arm/mach-pxa/colibri-pxa270.c @@ -23,7 +23,7 @@ #include <asm/mach-types.h> #include <linux/sizes.h> -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include "colibri.h" #include "pxa27x.h" diff --git a/arch/arm/mach-pxa/colibri-pxa300.c b/arch/arm/mach-pxa/colibri-pxa300.c index 82052dfd96b6..11ca6c4795e7 100644 --- a/arch/arm/mach-pxa/colibri-pxa300.c +++ b/arch/arm/mach-pxa/colibri-pxa300.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/interrupt.h> +#include <linux/soc/pxa/cpu.h> #include <asm/mach-types.h> #include <linux/sizes.h> @@ -23,7 +24,7 @@ #include "colibri.h" #include <linux/platform_data/usb-ohci-pxa27x.h> #include <linux/platform_data/video-pxafb.h> -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include "generic.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/colibri-pxa320.c b/arch/arm/mach-pxa/colibri-pxa320.c index 35dd3adb7712..1a59056e181e 100644 --- a/arch/arm/mach-pxa/colibri-pxa320.c +++ b/arch/arm/mach-pxa/colibri-pxa320.c @@ -24,7 +24,7 @@ #include "colibri.h" #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/usb-ohci-pxa27x.h> -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include "pxa27x-udc.h" #include "udc.h" diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c index 3cead80a2b37..77d6ef5fa42d 100644 --- a/arch/arm/mach-pxa/colibri-pxa3xx.c +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c @@ -13,12 +13,11 @@ #include <linux/gpio.h> #include <linux/etherdevice.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <linux/sizes.h> #include <asm/system_info.h> #include <asm/mach/arch.h> #include <asm/mach/irq.h> -#include <mach/pxa3xx-regs.h> +#include "pxa3xx-regs.h" #include "mfp-pxa300.h" #include "colibri.h" #include <linux/platform_data/mmc-pxamci.h> diff --git a/arch/arm/mach-pxa/colibri.h b/arch/arm/mach-pxa/colibri.h index 85525d49e321..01a46f36cc1f 100644 --- a/arch/arm/mach-pxa/colibri.h +++ b/arch/arm/mach-pxa/colibri.h @@ -3,7 +3,7 @@ #define _COLIBRI_H_ #include <net/ax88796.h> -#include <mach/mfp.h> +#include "mfp.h" /* * base board glue for PXA270 module diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 44659fbc37ba..c546356d0f02 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -39,7 +39,6 @@ #include <asm/setup.h> #include <asm/memory.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <asm/mach/arch.h> @@ -50,7 +49,7 @@ #include <linux/platform_data/irda-pxaficp.h> #include <linux/platform_data/mmc-pxamci.h> #include "udc.h" -#include <mach/corgi.h> +#include "corgi.h" #include "sharpsl_pm.h" #include <asm/mach/sharpsl_param.h> @@ -473,6 +472,25 @@ static struct platform_device corgiled_device = { }, }; +static struct gpiod_lookup_table corgi_audio_gpio_table = { + .dev_id = "corgi-audio", + .table = { + GPIO_LOOKUP("sharp-scoop", + CORGI_GPIO_MUTE_L - CORGI_SCOOP_GPIO_BASE, + "mute-l", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("sharp-scoop", + CORGI_GPIO_MUTE_R - CORGI_SCOOP_GPIO_BASE, + "mute-r", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("sharp-scoop", + CORGI_GPIO_APM_ON - CORGI_SCOOP_GPIO_BASE, + "apm-on", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("sharp-scoop", + CORGI_GPIO_MIC_BIAS - CORGI_SCOOP_GPIO_BASE, + "mic-bias", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /* * Corgi Audio */ @@ -745,6 +763,7 @@ static void __init corgi_init(void) pxa_set_udc_info(&udc_info); gpiod_add_lookup_table(&corgi_mci_gpio_table); + gpiod_add_lookup_table(&corgi_audio_gpio_table); pxa_set_mci_info(&corgi_mci_platform_data); pxa_set_ficp_info(&corgi_ficp_platform_data); pxa_set_i2c_info(NULL); diff --git a/arch/arm/mach-pxa/include/mach/corgi.h b/arch/arm/mach-pxa/corgi.h index b565ca7b8cda..b565ca7b8cda 100644 --- a/arch/arm/mach-pxa/include/mach/corgi.h +++ b/arch/arm/mach-pxa/corgi.h diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c index 092dcb9fced5..555a5c1afd96 100644 --- a/arch/arm/mach-pxa/corgi_pm.c +++ b/arch/arm/mach-pxa/corgi_pm.c @@ -19,10 +19,9 @@ #include <asm/irq.h> #include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/corgi.h> -#include <mach/pxa2xx-regs.h> +#include "corgi.h" +#include "pxa2xx-regs.h" #include "sharpsl_pm.h" #include "generic.h" diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c index 98fcdc6e2944..410b1af87d55 100644 --- a/arch/arm/mach-pxa/csb726.c +++ b/arch/arm/mach-pxa/csb726.c @@ -17,12 +17,13 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> + #include "csb726.h" #include "pxa27x.h" #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/usb-ohci-pxa27x.h> -#include <mach/audio.h> -#include <mach/smemc.h> +#include <linux/platform_data/asoc-pxa.h> +#include "smemc.h" #include "generic.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/csb726.h b/arch/arm/mach-pxa/csb726.h index 30d7cf926b84..628928743bd5 100644 --- a/arch/arm/mach-pxa/csb726.h +++ b/arch/arm/mach-pxa/csb726.h @@ -7,7 +7,7 @@ #ifndef CSB726_H #define CSB726_H -#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ #define CSB726_GPIO_IRQ_LAN 52 #define CSB726_GPIO_IRQ_SM501 53 diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index 09b8495f3fd9..a7b92dd1ca9e 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -9,21 +9,23 @@ #include <linux/dmaengine.h> #include <linux/spi/pxa2xx_spi.h> #include <linux/platform_data/i2c-pxa.h> +#include <linux/soc/pxa/cpu.h> #include "udc.h" #include <linux/platform_data/usb-pxa3xx-ulpi.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/irda-pxaficp.h> -#include <mach/irqs.h> +#include "irqs.h" #include <linux/platform_data/usb-ohci-pxa27x.h> #include <linux/platform_data/keypad-pxa27x.h> #include <linux/platform_data/media/camera-pxa.h> -#include <mach/audio.h> -#include <mach/hardware.h> +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/mmp_dma.h> #include <linux/platform_data/mtd-nand-pxa3xx.h> +#include "regs-ost.h" +#include "reset.h" #include "devices.h" #include "generic.h" @@ -1118,3 +1120,12 @@ void __init pxa2xx_set_dmac_info(struct mmp_dma_platdata *dma_pdata) { pxa_register_device(&pxa2xx_pxa_dma, dma_pdata); } + +void __init pxa_register_wdt(unsigned int reset_status) +{ + struct resource res = DEFINE_RES_MEM(OST_PHYS, OST_LEN); + + reset_status &= RESET_STATUS_WATCHDOG; + platform_device_register_resndata(NULL, "sa1100_wdt", -1, &res, 1, + &reset_status, sizeof(reset_status)); +} diff --git a/arch/arm/mach-pxa/e740-pcmcia.c b/arch/arm/mach-pxa/e740-pcmcia.c new file mode 100644 index 000000000000..11a2c5d42920 --- /dev/null +++ b/arch/arm/mach-pxa/e740-pcmcia.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Toshiba e740 PCMCIA specific routines. + * + * (c) 2004 Ian Molton <spyro@f2s.com> + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> + +#include "eseries-gpio.h" + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <pcmcia/soc_common.h> + +static int e740_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + if (skt->nr == 0) { + skt->stat[SOC_STAT_CD].gpio = GPIO_E740_PCMCIA_CD0; + skt->stat[SOC_STAT_CD].name = "CF card detect"; + skt->stat[SOC_STAT_RDY].gpio = GPIO_E740_PCMCIA_RDY0; + skt->stat[SOC_STAT_RDY].name = "CF ready"; + } else { + skt->stat[SOC_STAT_CD].gpio = GPIO_E740_PCMCIA_CD1; + skt->stat[SOC_STAT_CD].name = "Wifi switch"; + skt->stat[SOC_STAT_RDY].gpio = GPIO_E740_PCMCIA_RDY1; + skt->stat[SOC_STAT_RDY].name = "Wifi ready"; + } + + return 0; +} + +static void e740_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->vs_3v = 1; + state->vs_Xv = 0; +} + +static int e740_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + if (state->flags & SS_RESET) { + if (skt->nr == 0) + gpio_set_value(GPIO_E740_PCMCIA_RST0, 1); + else + gpio_set_value(GPIO_E740_PCMCIA_RST1, 1); + } else { + if (skt->nr == 0) + gpio_set_value(GPIO_E740_PCMCIA_RST0, 0); + else + gpio_set_value(GPIO_E740_PCMCIA_RST1, 0); + } + + switch (state->Vcc) { + case 0: /* Socket off */ + if (skt->nr == 0) + gpio_set_value(GPIO_E740_PCMCIA_PWR0, 0); + else + gpio_set_value(GPIO_E740_PCMCIA_PWR1, 1); + break; + case 50: + case 33: /* socket on */ + if (skt->nr == 0) + gpio_set_value(GPIO_E740_PCMCIA_PWR0, 1); + else + gpio_set_value(GPIO_E740_PCMCIA_PWR1, 0); + break; + default: + printk(KERN_ERR "e740_cs: Unsupported Vcc: %d\n", state->Vcc); + } + + return 0; +} + +static struct pcmcia_low_level e740_pcmcia_ops = { + .owner = THIS_MODULE, + .hw_init = e740_pcmcia_hw_init, + .socket_state = e740_pcmcia_socket_state, + .configure_socket = e740_pcmcia_configure_socket, + .nr = 2, +}; + +static struct platform_device *e740_pcmcia_device; + +static int __init e740_pcmcia_init(void) +{ + int ret; + + if (!machine_is_e740()) + return -ENODEV; + + e740_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!e740_pcmcia_device) + return -ENOMEM; + + ret = platform_device_add_data(e740_pcmcia_device, &e740_pcmcia_ops, + sizeof(e740_pcmcia_ops)); + + if (!ret) + ret = platform_device_add(e740_pcmcia_device); + + if (ret) + platform_device_put(e740_pcmcia_device); + + return ret; +} + +static void __exit e740_pcmcia_exit(void) +{ + platform_device_unregister(e740_pcmcia_device); +} + +module_init(e740_pcmcia_init); +module_exit(e740_pcmcia_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); +MODULE_DESCRIPTION("e740 PCMCIA platform support"); diff --git a/arch/arm/mach-pxa/include/mach/eseries-gpio.h b/arch/arm/mach-pxa/eseries-gpio.h index 5c645600d401..5c645600d401 100644 --- a/arch/arm/mach-pxa/include/mach/eseries-gpio.h +++ b/arch/arm/mach-pxa/eseries-gpio.h diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c index f37c44b6139d..08f8737aa8fd 100644 --- a/arch/arm/mach-pxa/eseries.c +++ b/arch/arm/mach-pxa/eseries.c @@ -24,6 +24,7 @@ #include <linux/mtd/rawnand.h> #include <linux/mtd/partitions.h> #include <linux/memblock.h> +#include <linux/gpio/machine.h> #include <video/w100fb.h> @@ -32,9 +33,9 @@ #include <asm/mach-types.h> #include "pxa25x.h" -#include <mach/eseries-gpio.h> +#include "eseries-gpio.h" #include "eseries-irq.h" -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/video-pxafb.h> #include "udc.h" #include <linux/platform_data/irda-pxaficp.h> @@ -520,6 +521,16 @@ static struct platform_device e740_audio_device = { .id = -1, }; +static struct gpiod_lookup_table e740_audio_gpio_table = { + .dev_id = "e740-audio", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO_E740_WM9705_nAVDD2, "Audio power", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", GPIO_E740_AMP_ON, "Output amp", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", GPIO_E740_MIC_ON, "Mic amp", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /* ----------------------------------------------------------------------- */ static struct platform_device *e740_devices[] __initdata = { @@ -540,6 +551,7 @@ static void __init e740_init(void) "UDCCLK", &pxa25x_device_udc.dev), eseries_get_tmio_gpios(); gpiod_add_lookup_table(&e7xx_gpio_vbus_gpiod_table); + gpiod_add_lookup_table(&e740_audio_gpio_table); platform_add_devices(ARRAY_AND_SIZE(e740_devices)); pxa_set_ac97_info(NULL); pxa_set_ficp_info(&e7xx_ficp_platform_data); @@ -699,7 +711,6 @@ static struct tc6393xb_platform_data e750_tc6393xb_info = { .irq_base = IRQ_BOARD_START, .scr_pll2cr = 0x0cc1, .scr_gper = 0, - .gpio_base = -1, .suspend = &eseries_tmio_suspend, .resume = &eseries_tmio_resume, .enable = &eseries_tmio_enable, @@ -716,6 +727,15 @@ static struct platform_device e750_tc6393xb_device = { .resource = eseries_tmio_resources, }; +static struct gpiod_lookup_table e750_audio_gpio_table = { + .dev_id = "e750-audio", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO_E750_HP_AMP_OFF, "Output amp", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("gpio-pxa", GPIO_E750_SPK_AMP_OFF, "Mic amp", GPIO_ACTIVE_LOW), + { }, + }, +}; + static struct platform_device e750_audio_device = { .name = "e750-audio", .id = -1, @@ -740,6 +760,7 @@ static void __init e750_init(void) "GPIO11_CLK", NULL), eseries_get_tmio_gpios(); gpiod_add_lookup_table(&e7xx_gpio_vbus_gpiod_table); + gpiod_add_lookup_table(&e750_audio_gpio_table); platform_add_devices(ARRAY_AND_SIZE(e750_devices)); pxa_set_ac97_info(NULL); pxa_set_ficp_info(&e7xx_ficp_platform_data); @@ -918,7 +939,6 @@ static struct tc6393xb_platform_data e800_tc6393xb_info = { .irq_base = IRQ_BOARD_START, .scr_pll2cr = 0x0cc1, .scr_gper = 0, - .gpio_base = -1, .suspend = &eseries_tmio_suspend, .resume = &eseries_tmio_resume, .enable = &eseries_tmio_enable, @@ -935,6 +955,15 @@ static struct platform_device e800_tc6393xb_device = { .resource = eseries_tmio_resources, }; +static struct gpiod_lookup_table e800_audio_gpio_table = { + .dev_id = "e800-audio", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO_E800_HP_AMP_OFF, "Output amp", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("gpio-pxa", GPIO_E800_SPK_AMP_ON, "Mic amp", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct platform_device e800_audio_device = { .name = "e800-audio", .id = -1, @@ -959,6 +988,7 @@ static void __init e800_init(void) "GPIO11_CLK", NULL), eseries_get_tmio_gpios(); gpiod_add_lookup_table(&e800_gpio_vbus_gpiod_table); + gpiod_add_lookup_table(&e800_audio_gpio_table); platform_add_devices(ARRAY_AND_SIZE(e800_devices)); pxa_set_ac97_info(NULL); } diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c index eb85950e7c0e..69c2ec02a16c 100644 --- a/arch/arm/mach-pxa/ezx.c +++ b/arch/arm/mach-pxa/ezx.c @@ -29,7 +29,6 @@ #include "pxa27x.h" #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/usb-ohci-pxa27x.h> -#include <mach/hardware.h> #include <linux/platform_data/keypad-pxa27x.h> #include <linux/platform_data/media/camera-pxa.h> diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index ab7cdffd7ea8..02fdde7e3e34 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -17,15 +17,18 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/soc/pxa/cpu.h> +#include <linux/soc/pxa/smemc.h> +#include <linux/clk/pxa.h> -#include <mach/hardware.h> #include <asm/mach/map.h> #include <asm/mach-types.h> -#include <mach/irqs.h> -#include <mach/reset.h> -#include <mach/smemc.h> -#include <mach/pxa3xx-regs.h> +#include "addr-map.h" +#include "irqs.h" +#include "reset.h" +#include "smemc.h" +#include "pxa3xx-regs.h" #include "generic.h" #include <clocksource/pxa.h> @@ -46,28 +49,47 @@ void clear_reset_status(unsigned int mask) void __init pxa_timer_init(void) { if (cpu_is_pxa25x()) - pxa25x_clocks_init(); + pxa25x_clocks_init(io_p2v(0x41300000)); if (cpu_is_pxa27x()) - pxa27x_clocks_init(); + pxa27x_clocks_init(io_p2v(0x41300000)); if (cpu_is_pxa3xx()) - pxa3xx_clocks_init(); + pxa3xx_clocks_init(io_p2v(0x41340000), io_p2v(0x41350000)); pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x40a00000)); } -/* - * Get the clock frequency as reflected by CCCR and the turbo flag. - * We assume these values have been applied via a fcs. - * If info is not 0 we also display the current settings. - */ -unsigned int get_clk_frequency_khz(int info) +void pxa_smemc_set_pcmcia_timing(int sock, u32 mcmem, u32 mcatt, u32 mcio) { - if (cpu_is_pxa25x()) - return pxa25x_get_clk_frequency_khz(info); - else if (cpu_is_pxa27x()) - return pxa27x_get_clk_frequency_khz(info); - return 0; + __raw_writel(mcmem, MCMEM(sock)); + __raw_writel(mcatt, MCATT(sock)); + __raw_writel(mcio, MCIO(sock)); +} +EXPORT_SYMBOL_GPL(pxa_smemc_set_pcmcia_timing); + +void pxa_smemc_set_pcmcia_socket(int nr) +{ + switch (nr) { + case 0: + __raw_writel(0, MECR); + break; + case 1: + /* + * We have at least one socket, so set MECR:CIT + * (Card Is There) + */ + __raw_writel(MECR_CIT, MECR); + break; + case 2: + /* Set CIT and MECR:NOS (Number Of Sockets) */ + __raw_writel(MECR_CIT | MECR_NOS, MECR); + break; + } +} +EXPORT_SYMBOL_GPL(pxa_smemc_set_pcmcia_socket); + +void __iomem *pxa_smemc_get_mdrefr(void) +{ + return MDREFR; } -EXPORT_SYMBOL(get_clk_frequency_khz); /* * Intel PXA2xx internal register mapping. diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index 3b7873f8e1f8..7bb1499de4c5 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -10,7 +10,6 @@ struct irq_data; -extern unsigned int get_clk_frequency_khz(int info); extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int)); extern void __init pxa_map_io(void); @@ -23,19 +22,16 @@ extern void pxa_timer_init(void); #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) #define pxa25x_handle_irq icip_handle_irq -extern int __init pxa25x_clocks_init(void); extern void __init pxa25x_init_irq(void); extern void __init pxa25x_map_io(void); extern void __init pxa26x_init_irq(void); #define pxa27x_handle_irq ichp_handle_irq -extern int __init pxa27x_clocks_init(void); extern unsigned pxa27x_get_clk_frequency_khz(int); extern void __init pxa27x_init_irq(void); extern void __init pxa27x_map_io(void); #define pxa3xx_handle_irq ichp_handle_irq -extern int __init pxa3xx_clocks_init(void); extern void __init pxa3xx_init_irq(void); extern void __init pxa3xx_map_io(void); @@ -71,8 +67,3 @@ extern unsigned pxa25x_get_clk_frequency_khz(int); #define pxa27x_get_clk_frequency_khz(x) (0) #endif -#ifdef CONFIG_PXA3xx -extern unsigned pxa3xx_get_clk_frequency_khz(int); -#else -#define pxa3xx_get_clk_frequency_khz(x) (0) -#endif diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c index 49dd618b10f7..72b08a9bf0fd 100644 --- a/arch/arm/mach-pxa/gumstix.c +++ b/arch/arm/mach-pxa/gumstix.c @@ -28,7 +28,6 @@ #include <asm/setup.h> #include <asm/memory.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <linux/sizes.h> diff --git a/arch/arm/mach-pxa/gumstix.h b/arch/arm/mach-pxa/gumstix.h index 470250cdee16..9005b3c0aabd 100644 --- a/arch/arm/mach-pxa/gumstix.h +++ b/arch/arm/mach-pxa/gumstix.h @@ -3,7 +3,7 @@ * arch/arm/mach-pxa/include/mach/gumstix.h */ -#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* BTRESET - Reset line to Bluetooth module, active low signal. */ #define GPIO_GUMSTIX_BTRESET 7 diff --git a/arch/arm/mach-pxa/h5000.c b/arch/arm/mach-pxa/h5000.c index ece1e71c90a9..212efe24aedb 100644 --- a/arch/arm/mach-pxa/h5000.c +++ b/arch/arm/mach-pxa/h5000.c @@ -29,7 +29,7 @@ #include "pxa25x.h" #include "h5000.h" #include "udc.h" -#include <mach/smemc.h> +#include "smemc.h" #include "generic.h" diff --git a/arch/arm/mach-pxa/hx4700-pcmcia.c b/arch/arm/mach-pxa/hx4700-pcmcia.c new file mode 100644 index 000000000000..e2331dfe427d --- /dev/null +++ b/arch/arm/mach-pxa/hx4700-pcmcia.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/irq.h> + +#include <asm/mach-types.h> +#include "hx4700.h" + +#include <pcmcia/soc_common.h> + +static struct gpio gpios[] = { + { GPIO114_HX4700_CF_RESET, GPIOF_OUT_INIT_LOW, "CF reset" }, + { EGPIO4_CF_3V3_ON, GPIOF_OUT_INIT_LOW, "CF 3.3V enable" }, +}; + +static int hx4700_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + int ret; + + ret = gpio_request_array(gpios, ARRAY_SIZE(gpios)); + if (ret) + goto out; + + /* + * IRQ type must be set before soc_pcmcia_hw_init() calls request_irq(). + * The asic3 default IRQ type is level trigger low level detect, exactly + * the the signal present on GPIOD4_CF_nCD when a CF card is inserted. + * If the IRQ type is not changed, the asic3 interrupt handler will loop + * repeatedly because it is unable to clear the level trigger interrupt. + */ + irq_set_irq_type(gpio_to_irq(GPIOD4_CF_nCD), IRQ_TYPE_EDGE_BOTH); + + skt->stat[SOC_STAT_CD].gpio = GPIOD4_CF_nCD; + skt->stat[SOC_STAT_CD].name = "PCMCIA CD"; + skt->stat[SOC_STAT_RDY].gpio = GPIO60_HX4700_CF_RNB; + skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready"; + +out: + return ret; +} + +static void hx4700_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + gpio_free_array(gpios, ARRAY_SIZE(gpios)); +} + +static void hx4700_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->vs_3v = 1; + state->vs_Xv = 0; +} + +static int hx4700_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + switch (state->Vcc) { + case 0: + gpio_set_value(EGPIO4_CF_3V3_ON, 0); + break; + case 33: + gpio_set_value(EGPIO4_CF_3V3_ON, 1); + break; + default: + printk(KERN_ERR "pcmcia: Unsupported Vcc: %d\n", state->Vcc); + return -EINVAL; + } + + gpio_set_value(GPIO114_HX4700_CF_RESET, (state->flags & SS_RESET) != 0); + + return 0; +} + +static struct pcmcia_low_level hx4700_pcmcia_ops = { + .owner = THIS_MODULE, + .nr = 1, + .hw_init = hx4700_pcmcia_hw_init, + .hw_shutdown = hx4700_pcmcia_hw_shutdown, + .socket_state = hx4700_pcmcia_socket_state, + .configure_socket = hx4700_pcmcia_configure_socket, +}; + +static struct platform_device *hx4700_pcmcia_device; + +static int __init hx4700_pcmcia_init(void) +{ + struct platform_device *pdev; + + if (!machine_is_h4700()) + return -ENODEV; + + pdev = platform_device_register_data(NULL, "pxa2xx-pcmcia", -1, + &hx4700_pcmcia_ops, sizeof(hx4700_pcmcia_ops)); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + hx4700_pcmcia_device = pdev; + + return 0; +} + +static void __exit hx4700_pcmcia_exit(void) +{ + platform_device_unregister(hx4700_pcmcia_device); +} + +module_init(hx4700_pcmcia_init); +module_exit(hx4700_pcmcia_exit); + +MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>"); +MODULE_DESCRIPTION("HP iPAQ hx4700 PCMCIA driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index e1870fbb19e7..2ae06edf413c 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -36,12 +36,12 @@ #include <linux/spi/pxa2xx_spi.h> #include <linux/platform_data/i2c-pxa.h> -#include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include "pxa27x.h" -#include <mach/hx4700.h> +#include "addr-map.h" +#include "hx4700.h" #include <linux/platform_data/irda-pxaficp.h> #include <sound/ak4641.h> @@ -834,6 +834,19 @@ static struct i2c_board_info i2c_board_info[] __initdata = { }, }; +static struct gpiod_lookup_table hx4700_audio_gpio_table = { + .dev_id = "hx4700-audio", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO75_HX4700_EARPHONE_nDET, + "earphone-det", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("gpio-pxa", GPIO92_HX4700_HP_DRIVER, + "hp-driver", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", GPIO107_HX4700_SPK_nSD, + "spk-sd", GPIO_ACTIVE_LOW), + { }, + }, +}; + static struct platform_device audio = { .name = "hx4700-audio", .id = -1, @@ -895,6 +908,7 @@ static void __init hx4700_init(void) gpiod_add_lookup_table(&bq24022_gpiod_table); gpiod_add_lookup_table(&gpio_vbus_gpiod_table); + gpiod_add_lookup_table(&hx4700_audio_gpio_table); platform_add_devices(devices, ARRAY_SIZE(devices)); pwm_add_table(hx4700_pwm_lookup, ARRAY_SIZE(hx4700_pwm_lookup)); diff --git a/arch/arm/mach-pxa/include/mach/hx4700.h b/arch/arm/mach-pxa/hx4700.h index 0c30e6d9c660..0c30e6d9c660 100644 --- a/arch/arm/mach-pxa/include/mach/hx4700.h +++ b/arch/arm/mach-pxa/hx4700.h diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index fb0850af8496..525d01ddfbbb 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -22,7 +22,6 @@ #include <asm/setup.h> #include <asm/memory.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <asm/mach/arch.h> @@ -31,7 +30,6 @@ #include "pxa25x.h" #include "idp.h" #include <linux/platform_data/video-pxafb.h> -#include <mach/bitfield.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/smc91x.h> diff --git a/arch/arm/mach-pxa/idp.h b/arch/arm/mach-pxa/idp.h index a89e6723b1a1..81b9bd9ba754 100644 --- a/arch/arm/mach-pxa/idp.h +++ b/arch/arm/mach-pxa/idp.h @@ -20,7 +20,7 @@ * IDP hardware. */ -#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ #define IDP_FLASH_PHYS (PXA_CS0_PHYS) #define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) diff --git a/arch/arm/mach-pxa/include/mach/audio.h b/arch/arm/mach-pxa/include/mach/audio.h deleted file mode 100644 index 7beebf7297b5..000000000000 --- a/arch/arm/mach-pxa/include/mach/audio.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_ARCH_AUDIO_H__ -#define __ASM_ARCH_AUDIO_H__ - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/ac97_codec.h> - -/* - * @reset_gpio: AC97 reset gpio (normally gpio113 or gpio95) - * a -1 value means no gpio will be used for reset - * @codec_pdata: AC97 codec platform_data - - * reset_gpio should only be specified for pxa27x CPUs where a silicon - * bug prevents correct operation of the reset line. If not specified, - * the default behaviour on these CPUs is to consider gpio 113 as the - * AC97 reset line, which is the default on most boards. - */ -typedef struct { - int (*startup)(struct snd_pcm_substream *, void *); - void (*shutdown)(struct snd_pcm_substream *, void *); - void (*suspend)(void *); - void (*resume)(void *); - void *priv; - int reset_gpio; - void *codec_pdata[AC97_BUS_MAX_DEVICES]; -} pxa2xx_audio_ops_t; - -extern void pxa_set_ac97_info(pxa2xx_audio_ops_t *ops); - -#endif diff --git a/arch/arm/mach-pxa/include/mach/bitfield.h b/arch/arm/mach-pxa/include/mach/bitfield.h deleted file mode 100644 index fe2ca441bc0a..000000000000 --- a/arch/arm/mach-pxa/include/mach/bitfield.h +++ /dev/null @@ -1,114 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * FILE bitfield.h - * - * Version 1.1 - * Author Copyright (c) Marc A. Viredaz, 1998 - * DEC Western Research Laboratory, Palo Alto, CA - * Date April 1998 (April 1997) - * System Advanced RISC Machine (ARM) - * Language C or ARM Assembly - * Purpose Definition of macros to operate on bit fields. - */ - - - -#ifndef __BITFIELD_H -#define __BITFIELD_H - -#ifndef __ASSEMBLY__ -#define UData(Data) ((unsigned long) (Data)) -#else -#define UData(Data) (Data) -#endif - - -/* - * MACRO: Fld - * - * Purpose - * The macro "Fld" encodes a bit field, given its size and its shift value - * with respect to bit 0. - * - * Note - * A more intuitive way to encode bit fields would have been to use their - * mask. However, extracting size and shift value information from a bit - * field's mask is cumbersome and might break the assembler (255-character - * line-size limit). - * - * Input - * Size Size of the bit field, in number of bits. - * Shft Shift value of the bit field with respect to bit 0. - * - * Output - * Fld Encoded bit field. - */ - -#define Fld(Size, Shft) (((Size) << 16) + (Shft)) - - -/* - * MACROS: FSize, FShft, FMsk, FAlnMsk, F1stBit - * - * Purpose - * The macros "FSize", "FShft", "FMsk", "FAlnMsk", and "F1stBit" return - * the size, shift value, mask, aligned mask, and first bit of a - * bit field. - * - * Input - * Field Encoded bit field (using the macro "Fld"). - * - * Output - * FSize Size of the bit field, in number of bits. - * FShft Shift value of the bit field with respect to bit 0. - * FMsk Mask for the bit field. - * FAlnMsk Mask for the bit field, aligned on bit 0. - * F1stBit First bit of the bit field. - */ - -#define FSize(Field) ((Field) >> 16) -#define FShft(Field) ((Field) & 0x0000FFFF) -#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field)) -#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1) -#define F1stBit(Field) (UData (1) << FShft (Field)) - - -/* - * MACRO: FInsrt - * - * Purpose - * The macro "FInsrt" inserts a value into a bit field by shifting the - * former appropriately. - * - * Input - * Value Bit-field value. - * Field Encoded bit field (using the macro "Fld"). - * - * Output - * FInsrt Bit-field value positioned appropriately. - */ - -#define FInsrt(Value, Field) \ - (UData (Value) << FShft (Field)) - - -/* - * MACRO: FExtr - * - * Purpose - * The macro "FExtr" extracts the value of a bit field by masking and - * shifting it appropriately. - * - * Input - * Data Data containing the bit-field to be extracted. - * Field Encoded bit field (using the macro "Fld"). - * - * Output - * FExtr Bit-field value. - */ - -#define FExtr(Data, Field) \ - ((UData (Data) >> FShft (Field)) & FAlnMsk (Field)) - - -#endif /* __BITFIELD_H */ diff --git a/arch/arm/mach-pxa/include/mach/dma.h b/arch/arm/mach-pxa/include/mach/dma.h deleted file mode 100644 index 79f9842a7e1c..000000000000 --- a/arch/arm/mach-pxa/include/mach/dma.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-pxa/include/mach/dma.h - * - * Author: Nicolas Pitre - * Created: Jun 15, 2001 - * Copyright: MontaVista Software, Inc. - */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#include <mach/hardware.h> - -/* DMA Controller Registers Definitions */ -#define DMAC_REGS_VIRT io_p2v(0x40000000) - -#endif /* _ASM_ARCH_DMA_H */ diff --git a/arch/arm/mach-pxa/include/mach/generic.h b/arch/arm/mach-pxa/include/mach/generic.h deleted file mode 100644 index 665542e0c9e2..000000000000 --- a/arch/arm/mach-pxa/include/mach/generic.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../generic.h" diff --git a/arch/arm/mach-pxa/include/mach/hardware.h b/arch/arm/mach-pxa/include/mach/hardware.h deleted file mode 100644 index ee7eab16135f..000000000000 --- a/arch/arm/mach-pxa/include/mach/hardware.h +++ /dev/null @@ -1,305 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-pxa/include/mach/hardware.h - * - * Author: Nicolas Pitre - * Created: Jun 15, 2001 - * Copyright: MontaVista Software Inc. - */ - -#ifndef __ASM_ARCH_HARDWARE_H -#define __ASM_ARCH_HARDWARE_H - -#include <mach/addr-map.h> - -/* - * Workarounds for at least 2 errata so far require this. - * The mapping is set in mach-pxa/generic.c. - */ -#define UNCACHED_PHYS_0 0xfe000000 -#define UNCACHED_PHYS_0_SIZE 0x00100000 - -/* - * Intel PXA2xx internal register mapping: - * - * 0x40000000 - 0x41ffffff <--> 0xf2000000 - 0xf3ffffff - * 0x44000000 - 0x45ffffff <--> 0xf4000000 - 0xf5ffffff - * 0x48000000 - 0x49ffffff <--> 0xf6000000 - 0xf7ffffff - * 0x4c000000 - 0x4dffffff <--> 0xf8000000 - 0xf9ffffff - * 0x50000000 - 0x51ffffff <--> 0xfa000000 - 0xfbffffff - * 0x54000000 - 0x55ffffff <--> 0xfc000000 - 0xfdffffff - * 0x58000000 - 0x59ffffff <--> 0xfe000000 - 0xffffffff - * - * Note that not all PXA2xx chips implement all those addresses, and the - * kernel only maps the minimum needed range of this mapping. - */ -#define io_v2p(x) (0x3c000000 + ((x) & 0x01ffffff) + (((x) & 0x0e000000) << 1)) -#define io_p2v(x) IOMEM(0xf2000000 + ((x) & 0x01ffffff) + (((x) & 0x1c000000) >> 1)) - -#ifndef __ASSEMBLY__ -# define __REG(x) (*((volatile u32 __iomem *)io_p2v(x))) - -/* With indexed regs we don't want to feed the index through io_p2v() - especially if it is a variable, otherwise horrible code will result. */ -# define __REG2(x,y) \ - (*(volatile u32 __iomem*)((u32)&__REG(x) + (y))) - -# define __PREG(x) (io_v2p((u32)&(x))) - -#else - -# define __REG(x) io_p2v(x) -# define __PREG(x) io_v2p(x) - -#endif - -#ifndef __ASSEMBLY__ - -#include <asm/cputype.h> - -/* - * CPU Stepping CPU_ID JTAG_ID - * - * PXA210 B0 0x69052922 0x2926C013 - * PXA210 B1 0x69052923 0x3926C013 - * PXA210 B2 0x69052924 0x4926C013 - * PXA210 C0 0x69052D25 0x5926C013 - * - * PXA250 A0 0x69052100 0x09264013 - * PXA250 A1 0x69052101 0x19264013 - * PXA250 B0 0x69052902 0x29264013 - * PXA250 B1 0x69052903 0x39264013 - * PXA250 B2 0x69052904 0x49264013 - * PXA250 C0 0x69052D05 0x59264013 - * - * PXA255 A0 0x69052D06 0x69264013 - * - * PXA26x A0 0x69052903 0x39264013 - * PXA26x B0 0x69052D05 0x59264013 - * - * PXA27x A0 0x69054110 0x09265013 - * PXA27x A1 0x69054111 0x19265013 - * PXA27x B0 0x69054112 0x29265013 - * PXA27x B1 0x69054113 0x39265013 - * PXA27x C0 0x69054114 0x49265013 - * PXA27x C5 0x69054117 0x79265013 - * - * PXA30x A0 0x69056880 0x0E648013 - * PXA30x A1 0x69056881 0x1E648013 - * PXA31x A0 0x69056890 0x0E649013 - * PXA31x A1 0x69056891 0x1E649013 - * PXA31x A2 0x69056892 0x2E649013 - * PXA32x B1 0x69056825 0x5E642013 - * PXA32x B2 0x69056826 0x6E642013 - * - * PXA930 B0 0x69056835 0x5E643013 - * PXA930 B1 0x69056837 0x7E643013 - * PXA930 B2 0x69056838 0x8E643013 - * - * PXA935 A0 0x56056931 0x1E653013 - * PXA935 B0 0x56056936 0x6E653013 - * PXA935 B1 0x56056938 0x8E653013 - */ -#ifdef CONFIG_PXA25x -#define __cpu_is_pxa210(id) \ - ({ \ - unsigned int _id = (id) & 0xf3f0; \ - _id == 0x2120; \ - }) - -#define __cpu_is_pxa250(id) \ - ({ \ - unsigned int _id = (id) & 0xf3ff; \ - _id <= 0x2105; \ - }) - -#define __cpu_is_pxa255(id) \ - ({ \ - unsigned int _id = (id) & 0xffff; \ - _id == 0x2d06; \ - }) - -#define __cpu_is_pxa25x(id) \ - ({ \ - unsigned int _id = (id) & 0xf300; \ - _id == 0x2100; \ - }) -#else -#define __cpu_is_pxa210(id) (0) -#define __cpu_is_pxa250(id) (0) -#define __cpu_is_pxa255(id) (0) -#define __cpu_is_pxa25x(id) (0) -#endif - -#ifdef CONFIG_PXA27x -#define __cpu_is_pxa27x(id) \ - ({ \ - unsigned int _id = (id) >> 4 & 0xfff; \ - _id == 0x411; \ - }) -#else -#define __cpu_is_pxa27x(id) (0) -#endif - -#ifdef CONFIG_CPU_PXA300 -#define __cpu_is_pxa300(id) \ - ({ \ - unsigned int _id = (id) >> 4 & 0xfff; \ - _id == 0x688; \ - }) -#else -#define __cpu_is_pxa300(id) (0) -#endif - -#ifdef CONFIG_CPU_PXA310 -#define __cpu_is_pxa310(id) \ - ({ \ - unsigned int _id = (id) >> 4 & 0xfff; \ - _id == 0x689; \ - }) -#else -#define __cpu_is_pxa310(id) (0) -#endif - -#ifdef CONFIG_CPU_PXA320 -#define __cpu_is_pxa320(id) \ - ({ \ - unsigned int _id = (id) >> 4 & 0xfff; \ - _id == 0x603 || _id == 0x682; \ - }) -#else -#define __cpu_is_pxa320(id) (0) -#endif - -#ifdef CONFIG_CPU_PXA930 -#define __cpu_is_pxa930(id) \ - ({ \ - unsigned int _id = (id) >> 4 & 0xfff; \ - _id == 0x683; \ - }) -#else -#define __cpu_is_pxa930(id) (0) -#endif - -#ifdef CONFIG_CPU_PXA935 -#define __cpu_is_pxa935(id) \ - ({ \ - unsigned int _id = (id) >> 4 & 0xfff; \ - _id == 0x693; \ - }) -#else -#define __cpu_is_pxa935(id) (0) -#endif - -#define cpu_is_pxa210() \ - ({ \ - __cpu_is_pxa210(read_cpuid_id()); \ - }) - -#define cpu_is_pxa250() \ - ({ \ - __cpu_is_pxa250(read_cpuid_id()); \ - }) - -#define cpu_is_pxa255() \ - ({ \ - __cpu_is_pxa255(read_cpuid_id()); \ - }) - -#define cpu_is_pxa25x() \ - ({ \ - __cpu_is_pxa25x(read_cpuid_id()); \ - }) - -#define cpu_is_pxa27x() \ - ({ \ - __cpu_is_pxa27x(read_cpuid_id()); \ - }) - -#define cpu_is_pxa300() \ - ({ \ - __cpu_is_pxa300(read_cpuid_id()); \ - }) - -#define cpu_is_pxa310() \ - ({ \ - __cpu_is_pxa310(read_cpuid_id()); \ - }) - -#define cpu_is_pxa320() \ - ({ \ - __cpu_is_pxa320(read_cpuid_id()); \ - }) - -#define cpu_is_pxa930() \ - ({ \ - __cpu_is_pxa930(read_cpuid_id()); \ - }) - -#define cpu_is_pxa935() \ - ({ \ - __cpu_is_pxa935(read_cpuid_id()); \ - }) - - - -/* - * CPUID Core Generation Bit - * <= 0x2 for pxa21x/pxa25x/pxa26x/pxa27x - */ -#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) -#define __cpu_is_pxa2xx(id) \ - ({ \ - unsigned int _id = (id) >> 13 & 0x7; \ - _id <= 0x2; \ - }) -#else -#define __cpu_is_pxa2xx(id) (0) -#endif - -#ifdef CONFIG_PXA3xx -#define __cpu_is_pxa3xx(id) \ - ({ \ - __cpu_is_pxa300(id) \ - || __cpu_is_pxa310(id) \ - || __cpu_is_pxa320(id) \ - || __cpu_is_pxa93x(id); \ - }) -#else -#define __cpu_is_pxa3xx(id) (0) -#endif - -#if defined(CONFIG_CPU_PXA930) || defined(CONFIG_CPU_PXA935) -#define __cpu_is_pxa93x(id) \ - ({ \ - __cpu_is_pxa930(id) \ - || __cpu_is_pxa935(id); \ - }) -#else -#define __cpu_is_pxa93x(id) (0) -#endif - -#define cpu_is_pxa2xx() \ - ({ \ - __cpu_is_pxa2xx(read_cpuid_id()); \ - }) - -#define cpu_is_pxa3xx() \ - ({ \ - __cpu_is_pxa3xx(read_cpuid_id()); \ - }) - -#define cpu_is_pxa93x() \ - ({ \ - __cpu_is_pxa93x(read_cpuid_id()); \ - }) - - -/* - * return current memory and LCD clock frequency in units of 10kHz - */ -extern unsigned int get_memclk_frequency_10khz(void); - -#endif - -#endif /* _ASM_ARCH_HARDWARE_H */ diff --git a/arch/arm/mach-pxa/include/mach/mtd-xip.h b/arch/arm/mach-pxa/include/mach/mtd-xip.h deleted file mode 100644 index 4b31bef9e50a..000000000000 --- a/arch/arm/mach-pxa/include/mach/mtd-xip.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * MTD primitives for XIP support. Architecture specific functions - * - * Do not include this file directly. It's included from linux/mtd/xip.h - * - * Author: Nicolas Pitre - * Created: Nov 2, 2004 - * Copyright: (C) 2004 MontaVista Software, Inc. - */ - -#ifndef __ARCH_PXA_MTD_XIP_H__ -#define __ARCH_PXA_MTD_XIP_H__ - -#include <mach/regs-ost.h> - -/* restored July 2017, this did not build since 2011! */ - -#define ICIP io_p2v(0x40d00000) -#define ICMR io_p2v(0x40d00004) -#define xip_irqpending() (readl(ICIP) & readl(ICMR)) - -/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */ -#define xip_currtime() readl(OSCR) -#define xip_elapsed_since(x) (signed)((readl(OSCR) - (x)) / 4) - -/* - * xip_cpu_idle() is used when waiting for a delay equal or larger than - * the system timer tick period. This should put the CPU into idle mode - * to save power and to be woken up only when some interrupts are pending. - * As above, this should not rely upon standard kernel code. - */ - -#define xip_cpu_idle() asm volatile ("mcr p14, 0, %0, c7, c0, 0" :: "r" (1)) - -#endif /* __ARCH_PXA_MTD_XIP_H__ */ diff --git a/arch/arm/mach-pxa/include/mach/regs-ac97.h b/arch/arm/mach-pxa/include/mach/regs-ac97.h deleted file mode 100644 index 1db96fd4df32..000000000000 --- a/arch/arm/mach-pxa/include/mach/regs-ac97.h +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_ARCH_REGS_AC97_H -#define __ASM_ARCH_REGS_AC97_H - -#include <mach/hardware.h> - -/* - * AC97 Controller registers - */ - -#define POCR __REG(0x40500000) /* PCM Out Control Register */ -#define POCR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */ -#define POCR_FSRIE (1 << 1) /* FIFO Service Request Interrupt Enable */ - -#define PICR __REG(0x40500004) /* PCM In Control Register */ -#define PICR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */ -#define PICR_FSRIE (1 << 1) /* FIFO Service Request Interrupt Enable */ - -#define MCCR __REG(0x40500008) /* Mic In Control Register */ -#define MCCR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */ -#define MCCR_FSRIE (1 << 1) /* FIFO Service Request Interrupt Enable */ - -#define GCR __REG(0x4050000C) /* Global Control Register */ -#ifdef CONFIG_PXA3xx -#define GCR_CLKBPB (1 << 31) /* Internal clock enable */ -#endif -#define GCR_nDMAEN (1 << 24) /* non DMA Enable */ -#define GCR_CDONE_IE (1 << 19) /* Command Done Interrupt Enable */ -#define GCR_SDONE_IE (1 << 18) /* Status Done Interrupt Enable */ -#define GCR_SECRDY_IEN (1 << 9) /* Secondary Ready Interrupt Enable */ -#define GCR_PRIRDY_IEN (1 << 8) /* Primary Ready Interrupt Enable */ -#define GCR_SECRES_IEN (1 << 5) /* Secondary Resume Interrupt Enable */ -#define GCR_PRIRES_IEN (1 << 4) /* Primary Resume Interrupt Enable */ -#define GCR_ACLINK_OFF (1 << 3) /* AC-link Shut Off */ -#define GCR_WARM_RST (1 << 2) /* AC97 Warm Reset */ -#define GCR_COLD_RST (1 << 1) /* AC'97 Cold Reset (0 = active) */ -#define GCR_GIE (1 << 0) /* Codec GPI Interrupt Enable */ - -#define POSR __REG(0x40500010) /* PCM Out Status Register */ -#define POSR_FIFOE (1 << 4) /* FIFO error */ -#define POSR_FSR (1 << 2) /* FIFO Service Request */ - -#define PISR __REG(0x40500014) /* PCM In Status Register */ -#define PISR_FIFOE (1 << 4) /* FIFO error */ -#define PISR_EOC (1 << 3) /* DMA End-of-Chain (exclusive clear) */ -#define PISR_FSR (1 << 2) /* FIFO Service Request */ - -#define MCSR __REG(0x40500018) /* Mic In Status Register */ -#define MCSR_FIFOE (1 << 4) /* FIFO error */ -#define MCSR_EOC (1 << 3) /* DMA End-of-Chain (exclusive clear) */ -#define MCSR_FSR (1 << 2) /* FIFO Service Request */ - -#define GSR __REG(0x4050001C) /* Global Status Register */ -#define GSR_CDONE (1 << 19) /* Command Done */ -#define GSR_SDONE (1 << 18) /* Status Done */ -#define GSR_RDCS (1 << 15) /* Read Completion Status */ -#define GSR_BIT3SLT12 (1 << 14) /* Bit 3 of slot 12 */ -#define GSR_BIT2SLT12 (1 << 13) /* Bit 2 of slot 12 */ -#define GSR_BIT1SLT12 (1 << 12) /* Bit 1 of slot 12 */ -#define GSR_SECRES (1 << 11) /* Secondary Resume Interrupt */ -#define GSR_PRIRES (1 << 10) /* Primary Resume Interrupt */ -#define GSR_SCR (1 << 9) /* Secondary Codec Ready */ -#define GSR_PCR (1 << 8) /* Primary Codec Ready */ -#define GSR_MCINT (1 << 7) /* Mic In Interrupt */ -#define GSR_POINT (1 << 6) /* PCM Out Interrupt */ -#define GSR_PIINT (1 << 5) /* PCM In Interrupt */ -#define GSR_ACOFFD (1 << 3) /* AC-link Shut Off Done */ -#define GSR_MOINT (1 << 2) /* Modem Out Interrupt */ -#define GSR_MIINT (1 << 1) /* Modem In Interrupt */ -#define GSR_GSCI (1 << 0) /* Codec GPI Status Change Interrupt */ - -#define CAR __REG(0x40500020) /* CODEC Access Register */ -#define CAR_CAIP (1 << 0) /* Codec Access In Progress */ - -#define PCDR __REG(0x40500040) /* PCM FIFO Data Register */ -#define MCDR __REG(0x40500060) /* Mic-in FIFO Data Register */ - -#define MOCR __REG(0x40500100) /* Modem Out Control Register */ -#define MOCR_FEIE (1 << 3) /* FIFO Error */ -#define MOCR_FSRIE (1 << 1) /* FIFO Service Request Interrupt Enable */ - -#define MICR __REG(0x40500108) /* Modem In Control Register */ -#define MICR_FEIE (1 << 3) /* FIFO Error */ -#define MICR_FSRIE (1 << 1) /* FIFO Service Request Interrupt Enable */ - -#define MOSR __REG(0x40500110) /* Modem Out Status Register */ -#define MOSR_FIFOE (1 << 4) /* FIFO error */ -#define MOSR_FSR (1 << 2) /* FIFO Service Request */ - -#define MISR __REG(0x40500118) /* Modem In Status Register */ -#define MISR_FIFOE (1 << 4) /* FIFO error */ -#define MISR_EOC (1 << 3) /* DMA End-of-Chain (exclusive clear) */ -#define MISR_FSR (1 << 2) /* FIFO Service Request */ - -#define MODR __REG(0x40500140) /* Modem FIFO Data Register */ - -#define PAC_REG_BASE __REG(0x40500200) /* Primary Audio Codec */ -#define SAC_REG_BASE __REG(0x40500300) /* Secondary Audio Codec */ -#define PMC_REG_BASE __REG(0x40500400) /* Primary Modem Codec */ -#define SMC_REG_BASE __REG(0x40500500) /* Secondary Modem Codec */ - -#endif /* __ASM_ARCH_REGS_AC97_H */ diff --git a/arch/arm/mach-pxa/include/mach/regs-lcd.h b/arch/arm/mach-pxa/include/mach/regs-lcd.h deleted file mode 100644 index e2b6e3d1f625..000000000000 --- a/arch/arm/mach-pxa/include/mach/regs-lcd.h +++ /dev/null @@ -1,198 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_ARCH_REGS_LCD_H -#define __ASM_ARCH_REGS_LCD_H - -#include <mach/bitfield.h> - -/* - * LCD Controller Registers and Bits Definitions - */ -#define LCCR0 (0x000) /* LCD Controller Control Register 0 */ -#define LCCR1 (0x004) /* LCD Controller Control Register 1 */ -#define LCCR2 (0x008) /* LCD Controller Control Register 2 */ -#define LCCR3 (0x00C) /* LCD Controller Control Register 3 */ -#define LCCR4 (0x010) /* LCD Controller Control Register 4 */ -#define LCCR5 (0x014) /* LCD Controller Control Register 5 */ -#define LCSR (0x038) /* LCD Controller Status Register 0 */ -#define LCSR1 (0x034) /* LCD Controller Status Register 1 */ -#define LIIDR (0x03C) /* LCD Controller Interrupt ID Register */ -#define TMEDRGBR (0x040) /* TMED RGB Seed Register */ -#define TMEDCR (0x044) /* TMED Control Register */ - -#define FBR0 (0x020) /* DMA Channel 0 Frame Branch Register */ -#define FBR1 (0x024) /* DMA Channel 1 Frame Branch Register */ -#define FBR2 (0x028) /* DMA Channel 2 Frame Branch Register */ -#define FBR3 (0x02C) /* DMA Channel 2 Frame Branch Register */ -#define FBR4 (0x030) /* DMA Channel 2 Frame Branch Register */ -#define FBR5 (0x110) /* DMA Channel 2 Frame Branch Register */ -#define FBR6 (0x114) /* DMA Channel 2 Frame Branch Register */ - -#define OVL1C1 (0x050) /* Overlay 1 Control Register 1 */ -#define OVL1C2 (0x060) /* Overlay 1 Control Register 2 */ -#define OVL2C1 (0x070) /* Overlay 2 Control Register 1 */ -#define OVL2C2 (0x080) /* Overlay 2 Control Register 2 */ - -#define CMDCR (0x100) /* Command Control Register */ -#define PRSR (0x104) /* Panel Read Status Register */ - -#define LCCR3_BPP(x) ((((x) & 0x7) << 24) | (((x) & 0x8) ? (1 << 29) : 0)) - -#define LCCR3_PDFOR_0 (0 << 30) -#define LCCR3_PDFOR_1 (1 << 30) -#define LCCR3_PDFOR_2 (2 << 30) -#define LCCR3_PDFOR_3 (3 << 30) - -#define LCCR4_PAL_FOR_0 (0 << 15) -#define LCCR4_PAL_FOR_1 (1 << 15) -#define LCCR4_PAL_FOR_2 (2 << 15) -#define LCCR4_PAL_FOR_3 (3 << 15) -#define LCCR4_PAL_FOR_MASK (3 << 15) - -#define FDADR0 (0x200) /* DMA Channel 0 Frame Descriptor Address Register */ -#define FDADR1 (0x210) /* DMA Channel 1 Frame Descriptor Address Register */ -#define FDADR2 (0x220) /* DMA Channel 2 Frame Descriptor Address Register */ -#define FDADR3 (0x230) /* DMA Channel 3 Frame Descriptor Address Register */ -#define FDADR4 (0x240) /* DMA Channel 4 Frame Descriptor Address Register */ -#define FDADR5 (0x250) /* DMA Channel 5 Frame Descriptor Address Register */ -#define FDADR6 (0x260) /* DMA Channel 6 Frame Descriptor Address Register */ - -#define LCCR0_ENB (1 << 0) /* LCD Controller enable */ -#define LCCR0_CMS (1 << 1) /* Color/Monochrome Display Select */ -#define LCCR0_Color (LCCR0_CMS*0) /* Color display */ -#define LCCR0_Mono (LCCR0_CMS*1) /* Monochrome display */ -#define LCCR0_SDS (1 << 2) /* Single/Dual Panel Display Select */ -#define LCCR0_Sngl (LCCR0_SDS*0) /* Single panel display */ -#define LCCR0_Dual (LCCR0_SDS*1) /* Dual panel display */ - -#define LCCR0_LDM (1 << 3) /* LCD Disable Done Mask */ -#define LCCR0_SFM (1 << 4) /* Start of frame mask */ -#define LCCR0_IUM (1 << 5) /* Input FIFO underrun mask */ -#define LCCR0_EFM (1 << 6) /* End of Frame mask */ -#define LCCR0_PAS (1 << 7) /* Passive/Active display Select */ -#define LCCR0_Pas (LCCR0_PAS*0) /* Passive display (STN) */ -#define LCCR0_Act (LCCR0_PAS*1) /* Active display (TFT) */ -#define LCCR0_DPD (1 << 9) /* Double Pixel Data (monochrome) */ -#define LCCR0_4PixMono (LCCR0_DPD*0) /* 4-Pixel/clock Monochrome display */ -#define LCCR0_8PixMono (LCCR0_DPD*1) /* 8-Pixel/clock Monochrome display */ -#define LCCR0_DIS (1 << 10) /* LCD Disable */ -#define LCCR0_QDM (1 << 11) /* LCD Quick Disable mask */ -#define LCCR0_PDD (0xff << 12) /* Palette DMA request delay */ -#define LCCR0_PDD_S 12 -#define LCCR0_BM (1 << 20) /* Branch mask */ -#define LCCR0_OUM (1 << 21) /* Output FIFO underrun mask */ -#define LCCR0_LCDT (1 << 22) /* LCD panel type */ -#define LCCR0_RDSTM (1 << 23) /* Read status interrupt mask */ -#define LCCR0_CMDIM (1 << 24) /* Command interrupt mask */ -#define LCCR0_OUC (1 << 25) /* Overlay Underlay control bit */ -#define LCCR0_LDDALT (1 << 26) /* LDD alternate mapping control */ - -#define LCCR1_PPL Fld (10, 0) /* Pixels Per Line - 1 */ -#define LCCR1_DisWdth(Pixel) (((Pixel) - 1) << FShft (LCCR1_PPL)) - -#define LCCR1_HSW Fld (6, 10) /* Horizontal Synchronization */ -#define LCCR1_HorSnchWdth(Tpix) (((Tpix) - 1) << FShft (LCCR1_HSW)) - -#define LCCR1_ELW Fld (8, 16) /* End-of-Line pixel clock Wait - 1 */ -#define LCCR1_EndLnDel(Tpix) (((Tpix) - 1) << FShft (LCCR1_ELW)) - -#define LCCR1_BLW Fld (8, 24) /* Beginning-of-Line pixel clock */ -#define LCCR1_BegLnDel(Tpix) (((Tpix) - 1) << FShft (LCCR1_BLW)) - -#define LCCR2_LPP Fld (10, 0) /* Line Per Panel - 1 */ -#define LCCR2_DisHght(Line) (((Line) - 1) << FShft (LCCR2_LPP)) - -#define LCCR2_VSW Fld (6, 10) /* Vertical Synchronization pulse - 1 */ -#define LCCR2_VrtSnchWdth(Tln) (((Tln) - 1) << FShft (LCCR2_VSW)) - -#define LCCR2_EFW Fld (8, 16) /* End-of-Frame line clock Wait */ -#define LCCR2_EndFrmDel(Tln) ((Tln) << FShft (LCCR2_EFW)) - -#define LCCR2_BFW Fld (8, 24) /* Beginning-of-Frame line clock */ -#define LCCR2_BegFrmDel(Tln) ((Tln) << FShft (LCCR2_BFW)) - -#define LCCR3_API (0xf << 16) /* AC Bias pin trasitions per interrupt */ -#define LCCR3_API_S 16 -#define LCCR3_VSP (1 << 20) /* vertical sync polarity */ -#define LCCR3_HSP (1 << 21) /* horizontal sync polarity */ -#define LCCR3_PCP (1 << 22) /* Pixel Clock Polarity (L_PCLK) */ -#define LCCR3_PixRsEdg (LCCR3_PCP*0) /* Pixel clock Rising-Edge */ -#define LCCR3_PixFlEdg (LCCR3_PCP*1) /* Pixel clock Falling-Edge */ - -#define LCCR3_OEP (1 << 23) /* Output Enable Polarity */ -#define LCCR3_OutEnH (LCCR3_OEP*0) /* Output Enable active High */ -#define LCCR3_OutEnL (LCCR3_OEP*1) /* Output Enable active Low */ - -#define LCCR3_DPC (1 << 27) /* double pixel clock mode */ -#define LCCR3_PCD Fld (8, 0) /* Pixel Clock Divisor */ -#define LCCR3_PixClkDiv(Div) (((Div) << FShft (LCCR3_PCD))) - -#define LCCR3_ACB Fld (8, 8) /* AC Bias */ -#define LCCR3_Acb(Acb) (((Acb) << FShft (LCCR3_ACB))) - -#define LCCR3_HorSnchH (LCCR3_HSP*0) /* HSP Active High */ -#define LCCR3_HorSnchL (LCCR3_HSP*1) /* HSP Active Low */ - -#define LCCR3_VrtSnchH (LCCR3_VSP*0) /* VSP Active High */ -#define LCCR3_VrtSnchL (LCCR3_VSP*1) /* VSP Active Low */ - -#define LCCR5_IUM(x) (1 << ((x) + 23)) /* input underrun mask */ -#define LCCR5_BSM(x) (1 << ((x) + 15)) /* branch mask */ -#define LCCR5_EOFM(x) (1 << ((x) + 7)) /* end of frame mask */ -#define LCCR5_SOFM(x) (1 << ((x) + 0)) /* start of frame mask */ - -#define LCSR_LDD (1 << 0) /* LCD Disable Done */ -#define LCSR_SOF (1 << 1) /* Start of frame */ -#define LCSR_BER (1 << 2) /* Bus error */ -#define LCSR_ABC (1 << 3) /* AC Bias count */ -#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */ -#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */ -#define LCSR_OU (1 << 6) /* output FIFO underrun */ -#define LCSR_QD (1 << 7) /* quick disable */ -#define LCSR_EOF (1 << 8) /* end of frame */ -#define LCSR_BS (1 << 9) /* branch status */ -#define LCSR_SINT (1 << 10) /* subsequent interrupt */ -#define LCSR_RD_ST (1 << 11) /* read status */ -#define LCSR_CMD_INT (1 << 12) /* command interrupt */ - -#define LCSR1_IU(x) (1 << ((x) + 23)) /* Input FIFO underrun */ -#define LCSR1_BS(x) (1 << ((x) + 15)) /* Branch Status */ -#define LCSR1_EOF(x) (1 << ((x) + 7)) /* End of Frame Status */ -#define LCSR1_SOF(x) (1 << ((x) - 1)) /* Start of Frame Status */ - -#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */ - -/* overlay control registers */ -#define OVLxC1_PPL(x) ((((x) - 1) & 0x3ff) << 0) /* Pixels Per Line */ -#define OVLxC1_LPO(x) ((((x) - 1) & 0x3ff) << 10) /* Number of Lines */ -#define OVLxC1_BPP(x) (((x) & 0xf) << 20) /* Bits Per Pixel */ -#define OVLxC1_OEN (1 << 31) /* Enable bit for Overlay */ -#define OVLxC2_XPOS(x) (((x) & 0x3ff) << 0) /* Horizontal Position */ -#define OVLxC2_YPOS(x) (((x) & 0x3ff) << 10) /* Vertical Position */ -#define OVL2C2_PFOR(x) (((x) & 0x7) << 20) /* Pixel Format */ - -/* smartpanel related */ -#define PRSR_DATA(x) ((x) & 0xff) /* Panel Data */ -#define PRSR_A0 (1 << 8) /* Read Data Source */ -#define PRSR_ST_OK (1 << 9) /* Status OK */ -#define PRSR_CON_NT (1 << 10) /* Continue to Next Command */ - -#define SMART_CMD_A0 (0x1 << 8) -#define SMART_CMD_READ_STATUS_REG (0x0 << 9) -#define SMART_CMD_READ_FRAME_BUFFER ((0x0 << 9) | SMART_CMD_A0) -#define SMART_CMD_WRITE_COMMAND (0x1 << 9) -#define SMART_CMD_WRITE_DATA ((0x1 << 9) | SMART_CMD_A0) -#define SMART_CMD_WRITE_FRAME ((0x2 << 9) | SMART_CMD_A0) -#define SMART_CMD_WAIT_FOR_VSYNC (0x3 << 9) -#define SMART_CMD_NOOP (0x4 << 9) -#define SMART_CMD_INTERRUPT (0x5 << 9) - -#define SMART_CMD(x) (SMART_CMD_WRITE_COMMAND | ((x) & 0xff)) -#define SMART_DAT(x) (SMART_CMD_WRITE_DATA | ((x) & 0xff)) - -/* SMART_DELAY() is introduced for software controlled delay primitive which - * can be inserted between command sequences, unused command 0x6 is used here - * and delay ranges from 0ms ~ 255ms - */ -#define SMART_CMD_DELAY (0x6 << 9) -#define SMART_DELAY(ms) (SMART_CMD_DELAY | ((ms) & 0xff)) -#endif /* __ASM_ARCH_REGS_LCD_H */ diff --git a/arch/arm/mach-pxa/include/mach/uncompress.h b/arch/arm/mach-pxa/include/mach/uncompress.h deleted file mode 100644 index 1ed629e38ce6..000000000000 --- a/arch/arm/mach-pxa/include/mach/uncompress.h +++ /dev/null @@ -1,70 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-pxa/include/mach/uncompress.h - * - * Author: Nicolas Pitre - * Copyright: (C) 2001 MontaVista Software Inc. - */ - -#include <linux/serial_reg.h> -#include <asm/mach-types.h> - -#define FFUART_BASE (0x40100000) -#define BTUART_BASE (0x40200000) -#define STUART_BASE (0x40700000) - -unsigned long uart_base; -unsigned int uart_shift; -unsigned int uart_is_pxa; - -static inline unsigned char uart_read(int offset) -{ - return *(volatile unsigned char *)(uart_base + (offset << uart_shift)); -} - -static inline void uart_write(unsigned char val, int offset) -{ - *(volatile unsigned char *)(uart_base + (offset << uart_shift)) = val; -} - -static inline int uart_is_enabled(void) -{ - /* assume enabled by default for non-PXA uarts */ - return uart_is_pxa ? uart_read(UART_IER) & UART_IER_UUE : 1; -} - -static inline void putc(char c) -{ - if (!uart_is_enabled()) - return; - - while (!(uart_read(UART_LSR) & UART_LSR_THRE)) - barrier(); - - uart_write(c, UART_TX); -} - -/* - * This does not append a newline - */ -static inline void flush(void) -{ -} - -static inline void arch_decomp_setup(void) -{ - /* initialize to default */ - uart_base = FFUART_BASE; - uart_shift = 2; - uart_is_pxa = 1; - - if (machine_is_littleton() || machine_is_csb726() || - machine_is_cm_x300() || machine_is_balloon3()) - uart_base = STUART_BASE; - - if (machine_is_arcom_zeus()) { - uart_base = 0x10000000; /* nCS4 */ - uart_shift = 1; - uart_is_pxa = 0; - } -} diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 74efc3ab595f..96f33ef1d9ea 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -17,13 +17,14 @@ #include <linux/irq.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/soc/pxa/cpu.h> #include <asm/exception.h> -#include <mach/hardware.h> -#include <mach/irqs.h> +#include "irqs.h" #include "generic.h" +#include "pxa-regs.h" #define ICIP (0x000) #define ICMR (0x004) diff --git a/arch/arm/mach-pxa/include/mach/irqs.h b/arch/arm/mach-pxa/irqs.h index 22bf536a462d..22bf536a462d 100644 --- a/arch/arm/mach-pxa/include/mach/irqs.h +++ b/arch/arm/mach-pxa/irqs.h diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c index 73f5953b3bb6..f98dc61e87af 100644 --- a/arch/arm/mach-pxa/littleton.c +++ b/arch/arm/mach-pxa/littleton.c @@ -31,7 +31,6 @@ #include <asm/setup.h> #include <asm/memory.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <asm/mach/arch.h> diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index 6fc40bc06910..0e4123c5fd42 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -28,7 +28,6 @@ #include <asm/setup.h> #include <asm/memory.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <linux/sizes.h> @@ -39,12 +38,13 @@ #include "pxa27x.h" #include "lpd270.h" -#include <mach/audio.h> +#include "addr-map.h" +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/irda-pxaficp.h> #include <linux/platform_data/usb-ohci-pxa27x.h> -#include <mach/smemc.h> +#include "smemc.h" #include "generic.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index e2411971422d..4f0944f3b262 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -34,7 +34,6 @@ #include <asm/setup.h> #include <asm/memory.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <linux/sizes.h> @@ -46,14 +45,14 @@ #include <asm/hardware/sa1111.h> #include "pxa25x.h" -#include <mach/audio.h> -#include <mach/lubbock.h> +#include <linux/platform_data/asoc-pxa.h> +#include "lubbock.h" #include "udc.h" #include <linux/platform_data/irda-pxaficp.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/mmc-pxamci.h> #include "pm.h" -#include <mach/smemc.h> +#include "smemc.h" #include "generic.h" #include "devices.h" @@ -132,6 +131,13 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = { // no D+ pullup; lubbock can't connect/disconnect in software }; +static struct resource lubbock_udc_resources[] = { + DEFINE_RES_MEM(0x40600000, 0x10000), + DEFINE_RES_IRQ(IRQ_USB), + DEFINE_RES_IRQ(LUBBOCK_USB_IRQ), + DEFINE_RES_IRQ(LUBBOCK_USB_DISC_IRQ), +}; + /* GPIOs for SA1111 PCMCIA */ static struct gpiod_lookup_table sa1111_pcmcia_gpio_table = { .dev_id = "1800", @@ -497,6 +503,9 @@ static void __init lubbock_init(void) lubbock_init_pcmcia(); clk_add_alias("SA1111_CLK", NULL, "GPIO11_CLK", NULL); + /* lubbock has two extra IRQs */ + pxa25x_device_udc.resource = lubbock_udc_resources; + pxa25x_device_udc.num_resources = ARRAY_SIZE(lubbock_udc_resources); pxa_set_udc_info(&udc_info); pxa_set_fb_info(NULL, &sharp_lm8v31); pxa_set_mci_info(&lubbock_mci_platform_data); diff --git a/arch/arm/mach-pxa/include/mach/lubbock.h b/arch/arm/mach-pxa/lubbock.h index a3af4a2f9446..55cf91e22ae2 100644 --- a/arch/arm/mach-pxa/include/mach/lubbock.h +++ b/arch/arm/mach-pxa/lubbock.h @@ -1,13 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * arch/arm/mach-pxa/include/mach/lubbock.h - * * Author: Nicolas Pitre * Created: Jun 15, 2001 * Copyright: MontaVista Software Inc. */ -#include <mach/irqs.h> +#include "irqs.h" #define LUBBOCK_ETH_PHYS PXA_CS3_PHYS diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index 200fd35168e0..20456a55c4c5 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -29,13 +29,13 @@ #include <linux/regulator/machine.h> #include <linux/platform_data/i2c-pxa.h> -#include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/system_info.h> #include "pxa27x.h" -#include <mach/magician.h> +#include "addr-map.h" +#include "magician.h" #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/irda-pxaficp.h> @@ -53,6 +53,7 @@ #include <linux/spi/spi.h> #include <linux/spi/pxa2xx_spi.h> #include <linux/spi/ads7846.h> +#include <sound/uda1380.h> static unsigned long magician_pin_config[] __initdata = { @@ -681,7 +682,7 @@ static struct platform_device bq24022 = { static struct gpiod_lookup_table bq24022_gpiod_table = { .dev_id = "gpio-regulator", .table = { - GPIO_LOOKUP("gpio-pxa", EGPIO_MAGICIAN_BQ24022_ISET2, + GPIO_LOOKUP("htc-egpio-0", EGPIO_MAGICIAN_BQ24022_ISET2 - MAGICIAN_EGPIO_BASE, NULL, GPIO_ACTIVE_HIGH), GPIO_LOOKUP("gpio-pxa", GPIO30_MAGICIAN_BQ24022_nCHARGE_EN, "enable", GPIO_ACTIVE_LOW), @@ -899,6 +900,53 @@ static struct platform_device strataflash = { }; /* + * audio support + */ +static struct uda1380_platform_data uda1380_info = { + .gpio_power = EGPIO_MAGICIAN_CODEC_POWER, + .gpio_reset = EGPIO_MAGICIAN_CODEC_RESET, + .dac_clk = UDA1380_DAC_CLK_WSPLL, +}; + +static struct i2c_board_info magician_audio_i2c_board_info[] = { + { + I2C_BOARD_INFO("uda1380", 0x18), + .platform_data = &uda1380_info, + }, +}; + +static struct gpiod_lookup_table magician_audio_gpio_table = { + .dev_id = "magician-audio", + .table = { + GPIO_LOOKUP("htc-egpio-0", + EGPIO_MAGICIAN_SPK_POWER - MAGICIAN_EGPIO_BASE, + "SPK_POWER", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("htc-egpio-0", + EGPIO_MAGICIAN_EP_POWER - MAGICIAN_EGPIO_BASE, + "EP_POWER", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("htc-egpio-0", + EGPIO_MAGICIAN_MIC_POWER - MAGICIAN_EGPIO_BASE, + "MIC_POWER", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("htc-egpio-0", + EGPIO_MAGICIAN_IN_SEL0 - MAGICIAN_EGPIO_BASE, + "IN_SEL0", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("htc-egpio-0", + EGPIO_MAGICIAN_IN_SEL1 - MAGICIAN_EGPIO_BASE, + "IN_SEL1", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static void magician_audio_init(void) +{ + i2c_register_board_info(0, + ARRAY_AND_SIZE(magician_audio_i2c_board_info)); + + gpiod_add_lookup_table(&magician_audio_gpio_table); + platform_device_register_simple("magician-audio", -1, NULL, 0); +} + +/* * PXA I2C main controller */ @@ -1048,6 +1096,8 @@ static void __init magician_init(void) gpiod_add_lookup_table(&bq24022_gpiod_table); gpiod_add_lookup_table(&gpio_vbus_gpiod_table); platform_add_devices(ARRAY_AND_SIZE(devices)); + + magician_audio_init(); } MACHINE_START(MAGICIAN, "HTC Magician") diff --git a/arch/arm/mach-pxa/include/mach/magician.h b/arch/arm/mach-pxa/magician.h index 7d3af561af6f..e1e4f9f6b22b 100644 --- a/arch/arm/mach-pxa/include/mach/magician.h +++ b/arch/arm/mach-pxa/magician.h @@ -9,7 +9,7 @@ #define _MAGICIAN_H_ #include <linux/gpio.h> -#include <mach/irqs.h> +#include "irqs.h" /* * PXA GPIOs diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index d237bd030238..fd386f1c414c 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -35,7 +35,6 @@ #include <asm/setup.h> #include <asm/memory.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <linux/sizes.h> @@ -45,14 +44,15 @@ #include <asm/mach/flash.h> #include "pxa27x.h" -#include <mach/mainstone.h> -#include <mach/audio.h> +#include "mainstone.h" +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/irda-pxaficp.h> #include <linux/platform_data/usb-ohci-pxa27x.h> #include <linux/platform_data/keypad-pxa27x.h> -#include <mach/smemc.h> +#include "addr-map.h" +#include "smemc.h" #include "generic.h" #include "devices.h" @@ -548,6 +548,14 @@ static struct gpiod_lookup_table mainstone_pcmcia_gpio_table = { }, }; +static struct gpiod_lookup_table mainstone_wm97xx_gpio_table = { + .dev_id = "wm97xx-touch", + .table = { + GPIO_LOOKUP("gpio-pxa", 4, "touch", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static void __init mainstone_init(void) { int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */ @@ -562,6 +570,7 @@ static void __init mainstone_init(void) "mst-pcmcia1", MST_PCMCIA_INPUTS, 0, NULL, NULL, mst_pcmcia1_irqs); gpiod_add_lookup_table(&mainstone_pcmcia_gpio_table); + gpiod_add_lookup_table(&mainstone_wm97xx_gpio_table); pxa_set_ffuart_info(NULL); pxa_set_btuart_info(NULL); diff --git a/arch/arm/mach-pxa/include/mach/mainstone.h b/arch/arm/mach-pxa/mainstone.h index 1698f2ffd7c7..f116c56cf5d9 100644 --- a/arch/arm/mach-pxa/include/mach/mainstone.h +++ b/arch/arm/mach-pxa/mainstone.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * arch/arm/mach-pxa/include/mach/mainstone.h - * * Author: Nicolas Pitre * Created: Nov 14, 2002 * Copyright: MontaVista Software Inc. @@ -10,7 +8,7 @@ #ifndef ASM_ARCH_MAINSTONE_H #define ASM_ARCH_MAINSTONE_H -#include <mach/irqs.h> +#include "irqs.h" #define MST_ETH_PHYS PXA_CS4_PHYS diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index 6a5451b186c2..57b0782880de 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c @@ -16,8 +16,9 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/syscore_ops.h> +#include <linux/soc/pxa/cpu.h> -#include <mach/pxa2xx-regs.h> +#include "pxa2xx-regs.h" #include "mfp-pxa2xx.h" #include "generic.h" diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.h b/arch/arm/mach-pxa/mfp-pxa2xx.h index 980145e7ee99..683a3ea5f154 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.h +++ b/arch/arm/mach-pxa/mfp-pxa2xx.h @@ -2,7 +2,7 @@ #ifndef __ASM_ARCH_MFP_PXA2XX_H #define __ASM_ARCH_MFP_PXA2XX_H -#include <plat/mfp.h> +#include <linux/soc/pxa/mfp.h> /* * the following MFP_xxx bit definitions in mfp.h are re-used for pxa2xx: diff --git a/arch/arm/mach-pxa/mfp-pxa3xx.c b/arch/arm/mach-pxa/mfp-pxa3xx.c index 56114df9700d..d16ab7451efe 100644 --- a/arch/arm/mach-pxa/mfp-pxa3xx.c +++ b/arch/arm/mach-pxa/mfp-pxa3xx.c @@ -16,9 +16,8 @@ #include <linux/io.h> #include <linux/syscore_ops.h> -#include <mach/hardware.h> #include "mfp-pxa3xx.h" -#include <mach/pxa3xx-regs.h> +#include "pxa3xx-regs.h" #ifdef CONFIG_PM /* diff --git a/arch/arm/mach-pxa/mfp-pxa3xx.h b/arch/arm/mach-pxa/mfp-pxa3xx.h index cdd830926d1c..81fec4fa5a0f 100644 --- a/arch/arm/mach-pxa/mfp-pxa3xx.h +++ b/arch/arm/mach-pxa/mfp-pxa3xx.h @@ -2,7 +2,7 @@ #ifndef __ASM_ARCH_MFP_PXA3XX_H #define __ASM_ARCH_MFP_PXA3XX_H -#include <plat/mfp.h> +#include <linux/soc/pxa/mfp.h> #define MFPR_BASE (0x40e10000) diff --git a/arch/arm/mach-pxa/include/mach/mfp.h b/arch/arm/mach-pxa/mfp.h index dbb961fb570e..7e0879bd4102 100644 --- a/arch/arm/mach-pxa/include/mach/mfp.h +++ b/arch/arm/mach-pxa/mfp.h @@ -13,6 +13,6 @@ #ifndef __ASM_ARCH_MFP_H #define __ASM_ARCH_MFP_H -#include <plat/mfp.h> +#include <linux/soc/pxa/mfp.h> #endif /* __ASM_ARCH_MFP_H */ diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index a79f296e81e0..d08f962ffb04 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -41,8 +41,8 @@ #include "udc.h" #include "pxa27x-udc.h" #include <linux/platform_data/media/camera-pxa.h> -#include <mach/audio.h> -#include <mach/smemc.h> +#include <linux/platform_data/asoc-pxa.h> +#include "smemc.h" #include "mioa701.h" diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c index fde386f6cffe..35546b59c88e 100644 --- a/arch/arm/mach-pxa/mxm8x10.c +++ b/arch/arm/mach-pxa/mxm8x10.c @@ -26,6 +26,7 @@ #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/usb-ohci-pxa27x.h> +#include <linux/platform_data/asoc-pxa.h> #include "pxa320.h" #include "mxm8x10.h" @@ -356,14 +357,9 @@ void __init mxm_8x10_usb_host_init(void) pxa_set_ohci_info(&mxm_8x10_ohci_platform_data); } -/* AC97 Sound Support */ -static struct platform_device mxm_8x10_ac97_device = { - .name = "pxa2xx-ac97" -}; - void __init mxm_8x10_ac97_init(void) { - platform_device_register(&mxm_8x10_ac97_device); + pxa_set_ac97_info(NULL); } /* NAND flash Support */ diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c index 6230381a7ca0..1a8d25eecac3 100644 --- a/arch/arm/mach-pxa/palm27x.c +++ b/arch/arm/mach-pxa/palm27x.c @@ -25,7 +25,7 @@ #include <asm/mach/map.h> #include "pxa27x.h" -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/irda-pxaficp.h> diff --git a/arch/arm/mach-pxa/palmld-pcmcia.c b/arch/arm/mach-pxa/palmld-pcmcia.c new file mode 100644 index 000000000000..720294a50864 --- /dev/null +++ b/arch/arm/mach-pxa/palmld-pcmcia.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/drivers/pcmcia/pxa2xx_palmld.c + * + * Driver for Palm LifeDrive PCMCIA + * + * Copyright (C) 2006 Alex Osborne <ato@meshy.org> + * Copyright (C) 2007-2011 Marek Vasut <marek.vasut@gmail.com> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> + +#include <asm/mach-types.h> +#include <pcmcia/soc_common.h> + +#include "palmld.h" + +static struct gpio palmld_pcmcia_gpios[] = { + { GPIO_NR_PALMLD_PCMCIA_POWER, GPIOF_INIT_LOW, "PCMCIA Power" }, + { GPIO_NR_PALMLD_PCMCIA_RESET, GPIOF_INIT_HIGH,"PCMCIA Reset" }, +}; + +static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + int ret; + + ret = gpio_request_array(palmld_pcmcia_gpios, + ARRAY_SIZE(palmld_pcmcia_gpios)); + + skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMLD_PCMCIA_READY; + skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready"; + + return ret; +} + +static void palmld_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + gpio_free_array(palmld_pcmcia_gpios, ARRAY_SIZE(palmld_pcmcia_gpios)); +} + +static void palmld_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->detect = 1; /* always inserted */ + state->vs_3v = 1; + state->vs_Xv = 0; +} + +static int palmld_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + gpio_set_value(GPIO_NR_PALMLD_PCMCIA_POWER, 1); + gpio_set_value(GPIO_NR_PALMLD_PCMCIA_RESET, + !!(state->flags & SS_RESET)); + + return 0; +} + +static struct pcmcia_low_level palmld_pcmcia_ops = { + .owner = THIS_MODULE, + + .first = 1, + .nr = 1, + + .hw_init = palmld_pcmcia_hw_init, + .hw_shutdown = palmld_pcmcia_hw_shutdown, + + .socket_state = palmld_pcmcia_socket_state, + .configure_socket = palmld_pcmcia_configure_socket, +}; + +static struct platform_device *palmld_pcmcia_device; + +static int __init palmld_pcmcia_init(void) +{ + int ret; + + if (!machine_is_palmld()) + return -ENODEV; + + palmld_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!palmld_pcmcia_device) + return -ENOMEM; + + ret = platform_device_add_data(palmld_pcmcia_device, &palmld_pcmcia_ops, + sizeof(palmld_pcmcia_ops)); + + if (!ret) + ret = platform_device_add(palmld_pcmcia_device); + + if (ret) + platform_device_put(palmld_pcmcia_device); + + return ret; +} + +static void __exit palmld_pcmcia_exit(void) +{ + platform_device_unregister(palmld_pcmcia_device); +} + +module_init(palmld_pcmcia_init); +module_exit(palmld_pcmcia_exit); + +MODULE_AUTHOR("Alex Osborne <ato@meshy.org>," + " Marek Vasut <marek.vasut@gmail.com>"); +MODULE_DESCRIPTION("PCMCIA support for Palm LifeDrive"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c index 5f73716a77f0..32308c63884e 100644 --- a/arch/arm/mach-pxa/palmld.c +++ b/arch/arm/mach-pxa/palmld.c @@ -29,8 +29,8 @@ #include <asm/mach/map.h> #include "pxa27x.h" -#include <mach/audio.h> -#include <mach/palmld.h> +#include "palmld.h" +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/irda-pxaficp.h> @@ -279,9 +279,15 @@ static inline void palmld_leds_init(void) {} * HDD ******************************************************************************/ #if defined(CONFIG_PATA_PALMLD) || defined(CONFIG_PATA_PALMLD_MODULE) +static struct resource palmld_ide_resources[] = { + DEFINE_RES_MEM(PALMLD_IDE_PHYS, 0x1000), +}; + static struct platform_device palmld_ide_device = { - .name = "pata_palmld", - .id = -1, + .name = "pata_palmld", + .id = -1, + .resource = palmld_ide_resources, + .num_resources = ARRAY_SIZE(palmld_ide_resources), }; static struct gpiod_lookup_table palmld_ide_gpio_table = { @@ -341,6 +347,14 @@ static struct gpiod_lookup_table palmld_mci_gpio_table = { }, }; +static struct gpiod_lookup_table palmld_wm97xx_touch_gpio_table = { + .dev_id = "wm97xx-touch", + .table = { + GPIO_LOOKUP("gpio-pxa", 27, "touch", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static void __init palmld_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(palmld_pin_config)); @@ -349,6 +363,7 @@ static void __init palmld_init(void) pxa_set_stuart_info(NULL); palm27x_mmc_init(&palmld_mci_gpio_table); + gpiod_add_lookup_table(&palmld_wm97xx_touch_gpio_table); palm27x_pm_init(PALMLD_STR_BASE); palm27x_lcd_init(-1, &palm_320x480_lcd_mode); palm27x_irda_init(GPIO_NR_PALMLD_IR_DISABLE); diff --git a/arch/arm/mach-pxa/include/mach/palmld.h b/arch/arm/mach-pxa/palmld.h index 99a6d8b3a1e3..99a6d8b3a1e3 100644 --- a/arch/arm/mach-pxa/include/mach/palmld.h +++ b/arch/arm/mach-pxa/palmld.h diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c index 7c7cbb4e677e..463b62ec1b01 100644 --- a/arch/arm/mach-pxa/palmt5.c +++ b/arch/arm/mach-pxa/palmt5.c @@ -29,7 +29,7 @@ #include <asm/mach/map.h> #include "pxa27x.h" -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include "palmt5.h" #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/video-pxafb.h> @@ -190,6 +190,14 @@ static struct gpiod_lookup_table palmt5_mci_gpio_table = { }, }; +static struct gpiod_lookup_table palmt5_wm97xx_touch_gpio_table = { + .dev_id = "wm97xx-touch", + .table = { + GPIO_LOOKUP("gpio-pxa", 27, "touch", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static void __init palmt5_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(palmt5_pin_config)); @@ -198,6 +206,7 @@ static void __init palmt5_init(void) pxa_set_stuart_info(NULL); palm27x_mmc_init(&palmt5_mci_gpio_table); + gpiod_add_lookup_table(&palmt5_wm97xx_touch_gpio_table); palm27x_pm_init(PALMT5_STR_BASE); palm27x_lcd_init(-1, &palm_320x480_lcd_mode); palm27x_udc_init(GPIO_NR_PALMT5_USB_DETECT_N, diff --git a/arch/arm/mach-pxa/palmt5.h b/arch/arm/mach-pxa/palmt5.h index 1fb1da7c8da3..cf84aedca717 100644 --- a/arch/arm/mach-pxa/palmt5.h +++ b/arch/arm/mach-pxa/palmt5.h @@ -11,7 +11,7 @@ #ifndef _INCLUDE_PALMT5_H_ #define _INCLUDE_PALMT5_H_ -#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /** HERE ARE GPIOs **/ diff --git a/arch/arm/mach-pxa/palmtc-pcmcia.c b/arch/arm/mach-pxa/palmtc-pcmcia.c new file mode 100644 index 000000000000..8e3f382343fe --- /dev/null +++ b/arch/arm/mach-pxa/palmtc-pcmcia.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/drivers/pcmcia/pxa2xx_palmtc.c + * + * Driver for Palm Tungsten|C PCMCIA + * + * Copyright (C) 2008 Alex Osborne <ato@meshy.org> + * Copyright (C) 2009-2011 Marek Vasut <marek.vasut@gmail.com> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/delay.h> + +#include <asm/mach-types.h> +#include "palmtc.h" +#include <pcmcia/soc_common.h> + +static struct gpio palmtc_pcmcia_gpios[] = { + { GPIO_NR_PALMTC_PCMCIA_POWER1, GPIOF_INIT_LOW, "PCMCIA Power 1" }, + { GPIO_NR_PALMTC_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" }, + { GPIO_NR_PALMTC_PCMCIA_POWER3, GPIOF_INIT_LOW, "PCMCIA Power 3" }, + { GPIO_NR_PALMTC_PCMCIA_RESET, GPIOF_INIT_HIGH,"PCMCIA Reset" }, + { GPIO_NR_PALMTC_PCMCIA_PWRREADY, GPIOF_IN, "PCMCIA Power Ready" }, +}; + +static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + int ret; + + ret = gpio_request_array(palmtc_pcmcia_gpios, + ARRAY_SIZE(palmtc_pcmcia_gpios)); + + skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTC_PCMCIA_READY; + skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready"; + + return ret; +} + +static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + gpio_free_array(palmtc_pcmcia_gpios, ARRAY_SIZE(palmtc_pcmcia_gpios)); +} + +static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->detect = 1; /* always inserted */ + state->vs_3v = 1; + state->vs_Xv = 0; +} + +static int palmtc_wifi_powerdown(void) +{ + gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1); + gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 0); + mdelay(40); + gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 0); + return 0; +} + +static int palmtc_wifi_powerup(void) +{ + int timeout = 50; + + gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 1); + mdelay(50); + + /* Power up the card, 1.8V first, after a while 3.3V */ + gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 1); + mdelay(100); + gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 1); + + /* Wait till the card is ready */ + while (!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_PWRREADY) && + timeout) { + mdelay(1); + timeout--; + } + + /* Power down the WiFi in case of error */ + if (!timeout) { + palmtc_wifi_powerdown(); + return 1; + } + + /* Reset the card */ + gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1); + mdelay(20); + gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 0); + mdelay(25); + + gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 0); + + return 0; +} + +static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + int ret = 1; + + if (state->Vcc == 0) + ret = palmtc_wifi_powerdown(); + else if (state->Vcc == 33) + ret = palmtc_wifi_powerup(); + + return ret; +} + +static struct pcmcia_low_level palmtc_pcmcia_ops = { + .owner = THIS_MODULE, + + .first = 0, + .nr = 1, + + .hw_init = palmtc_pcmcia_hw_init, + .hw_shutdown = palmtc_pcmcia_hw_shutdown, + + .socket_state = palmtc_pcmcia_socket_state, + .configure_socket = palmtc_pcmcia_configure_socket, +}; + +static struct platform_device *palmtc_pcmcia_device; + +static int __init palmtc_pcmcia_init(void) +{ + int ret; + + if (!machine_is_palmtc()) + return -ENODEV; + + palmtc_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!palmtc_pcmcia_device) + return -ENOMEM; + + ret = platform_device_add_data(palmtc_pcmcia_device, &palmtc_pcmcia_ops, + sizeof(palmtc_pcmcia_ops)); + + if (!ret) + ret = platform_device_add(palmtc_pcmcia_device); + + if (ret) + platform_device_put(palmtc_pcmcia_device); + + return ret; +} + +static void __exit palmtc_pcmcia_exit(void) +{ + platform_device_unregister(palmtc_pcmcia_device); +} + +module_init(palmtc_pcmcia_init); +module_exit(palmtc_pcmcia_exit); + +MODULE_AUTHOR("Alex Osborne <ato@meshy.org>," + " Marek Vasut <marek.vasut@gmail.com>"); +MODULE_DESCRIPTION("PCMCIA support for Palm Tungsten|C"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c index 455cb8ccaf26..3054ffa397ad 100644 --- a/arch/arm/mach-pxa/palmtc.c +++ b/arch/arm/mach-pxa/palmtc.c @@ -29,8 +29,8 @@ #include <asm/mach/map.h> #include "pxa25x.h" -#include <mach/audio.h> -#include <mach/palmtc.h> +#include <linux/platform_data/asoc-pxa.h> +#include "palmtc.h" #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/irda-pxaficp.h> diff --git a/arch/arm/mach-pxa/include/mach/palmtc.h b/arch/arm/mach-pxa/palmtc.h index 9257a02c46e5..9257a02c46e5 100644 --- a/arch/arm/mach-pxa/include/mach/palmtc.h +++ b/arch/arm/mach-pxa/palmtc.h diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c index a2b10db4aacc..fedac670a8af 100644 --- a/arch/arm/mach-pxa/palmte2.c +++ b/arch/arm/mach-pxa/palmte2.c @@ -29,7 +29,7 @@ #include <asm/mach/map.h> #include "pxa25x.h" -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include "palmte2.h" #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/video-pxafb.h> diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c index 2bf0f7f3ea24..238a31f32cba 100644 --- a/arch/arm/mach-pxa/palmtreo.c +++ b/arch/arm/mach-pxa/palmtreo.c @@ -29,7 +29,7 @@ #include "pxa27x.h" #include "pxa27x-udc.h" -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include "palmtreo.h" #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/video-pxafb.h> @@ -37,7 +37,7 @@ #include <linux/platform_data/keypad-pxa27x.h> #include "udc.h" #include <linux/platform_data/usb-ohci-pxa27x.h> -#include <mach/pxa2xx-regs.h> +#include "pxa2xx-regs.h" #include <linux/platform_data/asoc-palm27x.h> #include <linux/platform_data/media/camera-pxa.h> #include "palm27x.h" diff --git a/arch/arm/mach-pxa/palmtx-pcmcia.c b/arch/arm/mach-pxa/palmtx-pcmcia.c new file mode 100644 index 000000000000..8c2aaad93043 --- /dev/null +++ b/arch/arm/mach-pxa/palmtx-pcmcia.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/drivers/pcmcia/pxa2xx_palmtx.c + * + * Driver for Palm T|X PCMCIA + * + * Copyright (C) 2007-2011 Marek Vasut <marek.vasut@gmail.com> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> + +#include <asm/mach-types.h> +#include "palmtx.h" +#include <pcmcia/soc_common.h> + +static struct gpio palmtx_pcmcia_gpios[] = { + { GPIO_NR_PALMTX_PCMCIA_POWER1, GPIOF_INIT_LOW, "PCMCIA Power 1" }, + { GPIO_NR_PALMTX_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" }, + { GPIO_NR_PALMTX_PCMCIA_RESET, GPIOF_INIT_HIGH,"PCMCIA Reset" }, +}; + +static int palmtx_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + int ret; + + ret = gpio_request_array(palmtx_pcmcia_gpios, + ARRAY_SIZE(palmtx_pcmcia_gpios)); + + skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTX_PCMCIA_READY; + skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready"; + + return ret; +} + +static void palmtx_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + gpio_free_array(palmtx_pcmcia_gpios, ARRAY_SIZE(palmtx_pcmcia_gpios)); +} + +static void palmtx_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->detect = 1; /* always inserted */ + state->vs_3v = 1; + state->vs_Xv = 0; +} + +static int +palmtx_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + gpio_set_value(GPIO_NR_PALMTX_PCMCIA_POWER1, 1); + gpio_set_value(GPIO_NR_PALMTX_PCMCIA_POWER2, 1); + gpio_set_value(GPIO_NR_PALMTX_PCMCIA_RESET, + !!(state->flags & SS_RESET)); + + return 0; +} + +static struct pcmcia_low_level palmtx_pcmcia_ops = { + .owner = THIS_MODULE, + + .first = 0, + .nr = 1, + + .hw_init = palmtx_pcmcia_hw_init, + .hw_shutdown = palmtx_pcmcia_hw_shutdown, + + .socket_state = palmtx_pcmcia_socket_state, + .configure_socket = palmtx_pcmcia_configure_socket, +}; + +static struct platform_device *palmtx_pcmcia_device; + +static int __init palmtx_pcmcia_init(void) +{ + int ret; + + if (!machine_is_palmtx()) + return -ENODEV; + + palmtx_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!palmtx_pcmcia_device) + return -ENOMEM; + + ret = platform_device_add_data(palmtx_pcmcia_device, &palmtx_pcmcia_ops, + sizeof(palmtx_pcmcia_ops)); + + if (!ret) + ret = platform_device_add(palmtx_pcmcia_device); + + if (ret) + platform_device_put(palmtx_pcmcia_device); + + return ret; +} + +static void __exit palmtx_pcmcia_exit(void) +{ + platform_device_unregister(palmtx_pcmcia_device); +} + +module_init(palmtx_pcmcia_init); +module_exit(palmtx_pcmcia_exit); + +MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); +MODULE_DESCRIPTION("PCMCIA support for Palm T|X"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c index 07332c92c9f7..c0d0762540ab 100644 --- a/arch/arm/mach-pxa/palmtx.c +++ b/arch/arm/mach-pxa/palmtx.c @@ -32,8 +32,8 @@ #include <asm/mach/map.h> #include "pxa27x.h" -#include <mach/audio.h> -#include <mach/palmtx.h> +#include <linux/platform_data/asoc-pxa.h> +#include "palmtx.h" #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/irda-pxaficp.h> @@ -345,6 +345,14 @@ static struct gpiod_lookup_table palmtx_mci_gpio_table = { }, }; +static struct gpiod_lookup_table palmtx_wm97xx_touch_gpio_table = { + .dev_id = "wm97xx-touch", + .table = { + GPIO_LOOKUP("gpio-pxa", 27, "touch", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static void __init palmtx_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(palmtx_pin_config)); @@ -353,6 +361,7 @@ static void __init palmtx_init(void) pxa_set_stuart_info(NULL); palm27x_mmc_init(&palmtx_mci_gpio_table); + gpiod_add_lookup_table(&palmtx_wm97xx_touch_gpio_table); palm27x_pm_init(PALMTX_STR_BASE); palm27x_lcd_init(-1, &palm_320x480_lcd_mode); palm27x_udc_init(GPIO_NR_PALMTX_USB_DETECT_N, diff --git a/arch/arm/mach-pxa/include/mach/palmtx.h b/arch/arm/mach-pxa/palmtx.h index ec88abf0fc6c..ec88abf0fc6c 100644 --- a/arch/arm/mach-pxa/include/mach/palmtx.h +++ b/arch/arm/mach-pxa/palmtx.h diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c index b4a5fe02a0af..66e8fe6f1661 100644 --- a/arch/arm/mach-pxa/palmz72.c +++ b/arch/arm/mach-pxa/palmz72.c @@ -34,7 +34,7 @@ #include <asm/mach/map.h> #include "pxa27x.h" -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include "palmz72.h" #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/video-pxafb.h> diff --git a/arch/arm/mach-pxa/pcm027.h b/arch/arm/mach-pxa/pcm027.h index 0c4ab636ce4e..58ade4ad6ba3 100644 --- a/arch/arm/mach-pxa/pcm027.h +++ b/arch/arm/mach-pxa/pcm027.h @@ -10,7 +10,7 @@ * Definitions of CPU card resources only */ -#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* phyCORE-PXA270 (PCM027) Interrupts */ #define PCM027_IRQ(x) (IRQ_BOARD_START + (x)) diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c index 8dfcc366d0fe..33a9d2eeca1c 100644 --- a/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/arch/arm/mach-pxa/pcm990-baseboard.c @@ -26,7 +26,7 @@ #include <asm/mach/map.h> #include "pxa27x.h" -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/usb-ohci-pxa27x.h> #include "pcm990_baseboard.h" diff --git a/arch/arm/mach-pxa/pcm990_baseboard.h b/arch/arm/mach-pxa/pcm990_baseboard.h index 5be11d1b7019..18cf71decb03 100644 --- a/arch/arm/mach-pxa/pcm990_baseboard.h +++ b/arch/arm/mach-pxa/pcm990_baseboard.h @@ -7,7 +7,7 @@ */ #include "pcm027.h" -#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* * definitions relevant only when the PCM-990 diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 58cfa434afde..7772a39430ed 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -30,7 +30,6 @@ #include <linux/mtd/sharpsl.h> #include <linux/memblock.h> -#include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/irq.h> #include <asm/setup.h> @@ -40,11 +39,13 @@ #include <asm/mach/irq.h> #include "pxa25x.h" -#include <linux/platform_data/mmc-pxamci.h> #include "udc.h" +#include "poodle.h" + +#include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/irda-pxaficp.h> -#include <mach/poodle.h> #include <linux/platform_data/video-pxafb.h> +#include <linux/platform_data/asoc-poodle.h> #include <asm/hardware/scoop.h> #include <asm/hardware/locomo.h> @@ -156,12 +157,6 @@ static struct scoop_pcmcia_config poodle_pcmcia_config = { EXPORT_SYMBOL(poodle_scoop_device); - -static struct platform_device poodle_audio_device = { - .name = "poodle-audio", - .id = -1, -}; - /* LoCoMo device */ static struct resource locomo_resources[] = { [0] = { @@ -180,7 +175,7 @@ static struct locomo_platform_data locomo_info = { .irq_base = IRQ_BOARD_START, }; -struct platform_device poodle_locomo_device = { +static struct platform_device poodle_locomo_device = { .name = "locomo", .id = 0, .num_resources = ARRAY_SIZE(locomo_resources), @@ -190,7 +185,21 @@ struct platform_device poodle_locomo_device = { }, }; -EXPORT_SYMBOL(poodle_locomo_device); +static struct poodle_audio_platform_data poodle_audio_pdata = { + .locomo_dev = &poodle_locomo_device.dev, + + .gpio_amp_on = POODLE_LOCOMO_GPIO_AMP_ON, + .gpio_mute_l = POODLE_LOCOMO_GPIO_MUTE_L, + .gpio_mute_r = POODLE_LOCOMO_GPIO_MUTE_R, + .gpio_232vcc_on = POODLE_LOCOMO_GPIO_232VCC_ON, + .gpio_jk_b = POODLE_LOCOMO_GPIO_JK_B, +}; + +static struct platform_device poodle_audio_device = { + .name = "poodle-audio", + .id = -1, + .dev.platform_data = &poodle_audio_pdata, +}; #if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MODULE) static struct pxa2xx_spi_controller poodle_spi_info = { diff --git a/arch/arm/mach-pxa/include/mach/poodle.h b/arch/arm/mach-pxa/poodle.h index b56b19351a03..00798b44f204 100644 --- a/arch/arm/mach-pxa/include/mach/poodle.h +++ b/arch/arm/mach-pxa/poodle.h @@ -89,6 +89,4 @@ #define POODLE_NR_IRQS (IRQ_BOARD_START + 4) /* 4 for LoCoMo */ -extern struct platform_device poodle_locomo_device; - #endif /* __ASM_ARCH_POODLE_H */ diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c index d32d5c8e966f..5e5d543fdf46 100644 --- a/arch/arm/mach-pxa/pxa-dt.c +++ b/arch/arm/mach-pxa/pxa-dt.c @@ -11,7 +11,7 @@ #include <linux/of_platform.h> #include <asm/mach/arch.h> #include <asm/mach/time.h> -#include <mach/irqs.h> +#include "irqs.h" #include "generic.h" diff --git a/arch/arm/mach-pxa/pxa-regs.h b/arch/arm/mach-pxa/pxa-regs.h new file mode 100644 index 000000000000..ba5120c06b8a --- /dev/null +++ b/arch/arm/mach-pxa/pxa-regs.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Nicolas Pitre + * Created: Jun 15, 2001 + * Copyright: MontaVista Software Inc. + */ +#ifndef __ASM_MACH_PXA_REGS_H +#define __ASM_MACH_PXA_REGS_H + +/* + * Workarounds for at least 2 errata so far require this. + * The mapping is set in mach-pxa/generic.c. + */ +#define UNCACHED_PHYS_0 0xfe000000 +#define UNCACHED_PHYS_0_SIZE 0x00100000 + +/* + * Intel PXA2xx internal register mapping: + * + * 0x40000000 - 0x41ffffff <--> 0xf2000000 - 0xf3ffffff + * 0x44000000 - 0x45ffffff <--> 0xf4000000 - 0xf5ffffff + * 0x48000000 - 0x49ffffff <--> 0xf6000000 - 0xf7ffffff + * 0x4c000000 - 0x4dffffff <--> 0xf8000000 - 0xf9ffffff + * 0x50000000 - 0x51ffffff <--> 0xfa000000 - 0xfbffffff + * 0x54000000 - 0x55ffffff <--> 0xfc000000 - 0xfdffffff + * 0x58000000 - 0x59ffffff <--> 0xfe000000 - 0xffffffff + * + * Note that not all PXA2xx chips implement all those addresses, and the + * kernel only maps the minimum needed range of this mapping. + */ +#define io_v2p(x) (0x3c000000 + ((x) & 0x01ffffff) + (((x) & 0x0e000000) << 1)) +#define io_p2v(x) IOMEM(0xf2000000 + ((x) & 0x01ffffff) + (((x) & 0x1c000000) >> 1)) + +#ifndef __ASSEMBLY__ +# define __REG(x) (*((volatile u32 __iomem *)io_p2v(x))) + +/* With indexed regs we don't want to feed the index through io_p2v() + especially if it is a variable, otherwise horrible code will result. */ +# define __REG2(x,y) \ + (*(volatile u32 __iomem*)((u32)&__REG(x) + (y))) + +# define __PREG(x) (io_v2p((u32)&(x))) + +#else + +# define __REG(x) io_p2v(x) +# define __PREG(x) io_v2p(x) + +#endif + + +#endif diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index 678641ab46e5..6b34d7c169ea 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -26,16 +26,16 @@ #include <linux/irq.h> #include <linux/irqchip.h> #include <linux/platform_data/mmp_dma.h> +#include <linux/soc/pxa/cpu.h> #include <asm/mach/map.h> #include <asm/suspend.h> -#include <mach/hardware.h> -#include <mach/irqs.h> +#include "irqs.h" #include "pxa25x.h" -#include <mach/reset.h> +#include "reset.h" #include "pm.h" -#include <mach/dma.h> -#include <mach/smemc.h> +#include "addr-map.h" +#include "smemc.h" #include "generic.h" #include "devices.h" @@ -240,7 +240,7 @@ static int __init pxa25x_init(void) if (cpu_is_pxa25x()) { - reset_status = RCSR; + pxa_register_wdt(RCSR); pxa25x_init_pm(); diff --git a/arch/arm/mach-pxa/pxa25x.h b/arch/arm/mach-pxa/pxa25x.h index b58d0fbdb4db..eaaa87666324 100644 --- a/arch/arm/mach-pxa/pxa25x.h +++ b/arch/arm/mach-pxa/pxa25x.h @@ -2,9 +2,9 @@ #ifndef __MACH_PXA25x_H #define __MACH_PXA25x_H -#include <mach/hardware.h> -#include <mach/pxa2xx-regs.h> +#include "addr-map.h" +#include "pxa2xx-regs.h" #include "mfp-pxa25x.h" -#include <mach/irqs.h> +#include "irqs.h" #endif /* __MACH_PXA25x_H */ diff --git a/arch/arm/mach-pxa/pxa27x-udc.h b/arch/arm/mach-pxa/pxa27x-udc.h index faf73804697f..2d3df3b1cb68 100644 --- a/arch/arm/mach-pxa/pxa27x-udc.h +++ b/arch/arm/mach-pxa/pxa27x-udc.h @@ -2,6 +2,8 @@ #ifndef _ASM_ARCH_PXA27X_UDC_H #define _ASM_ARCH_PXA27X_UDC_H +#include "pxa-regs.h" + #ifdef _ASM_ARCH_PXA25X_UDC_H #error You cannot include both PXA25x and PXA27x UDC support #endif diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index f0ba7ed24cb6..afbf6ace954f 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -23,18 +23,18 @@ #include <linux/irq.h> #include <linux/platform_data/i2c-pxa.h> #include <linux/platform_data/mmp_dma.h> +#include <linux/soc/pxa/cpu.h> #include <asm/mach/map.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <asm/suspend.h> -#include <mach/irqs.h> +#include "irqs.h" #include "pxa27x.h" -#include <mach/reset.h> +#include "reset.h" #include <linux/platform_data/usb-ohci-pxa27x.h> #include "pm.h" -#include <mach/dma.h> -#include <mach/smemc.h> +#include "addr-map.h" +#include "smemc.h" #include "generic.h" #include "devices.h" @@ -337,7 +337,7 @@ static int __init pxa27x_init(void) if (cpu_is_pxa27x()) { - reset_status = RCSR; + pxa_register_wdt(RCSR); pxa27x_init_pm(); diff --git a/arch/arm/mach-pxa/pxa27x.h b/arch/arm/mach-pxa/pxa27x.h index abdc02fb4f03..ede96f3f7214 100644 --- a/arch/arm/mach-pxa/pxa27x.h +++ b/arch/arm/mach-pxa/pxa27x.h @@ -3,10 +3,10 @@ #define __MACH_PXA27x_H #include <linux/suspend.h> -#include <mach/hardware.h> -#include <mach/pxa2xx-regs.h> +#include "addr-map.h" +#include "pxa2xx-regs.h" #include "mfp-pxa27x.h" -#include <mach/irqs.h> +#include "irqs.h" #define ARB_CNTRL __REG(0x48000048) /* Arbiter Control Register */ diff --git a/arch/arm/mach-pxa/include/mach/pxa2xx-regs.h b/arch/arm/mach-pxa/pxa2xx-regs.h index fa121e135915..0b7eaf6b5813 100644 --- a/arch/arm/mach-pxa/include/mach/pxa2xx-regs.h +++ b/arch/arm/mach-pxa/pxa2xx-regs.h @@ -11,7 +11,7 @@ #ifndef __PXA2XX_REGS_H #define __PXA2XX_REGS_H -#include <mach/hardware.h> +#include "pxa-regs.h" /* * Power Manager @@ -136,51 +136,6 @@ #define CKEN io_p2v(0x41300004) /* Clock Enable Register */ #define OSCC io_p2v(0x41300008) /* Oscillator Configuration Register */ -#define CCCR_N_MASK 0x0380 /* Run Mode Frequency to Turbo Mode Frequency Multiplier */ -#define CCCR_M_MASK 0x0060 /* Memory Frequency to Run Mode Frequency Multiplier */ -#define CCCR_L_MASK 0x001f /* Crystal Frequency to Memory Frequency Multiplier */ - -#define CCCR_CPDIS_BIT (31) -#define CCCR_PPDIS_BIT (30) -#define CCCR_LCD_26_BIT (27) -#define CCCR_A_BIT (25) - -#define CCSR_N2_MASK CCCR_N_MASK -#define CCSR_M_MASK CCCR_M_MASK -#define CCSR_L_MASK CCCR_L_MASK -#define CCSR_N2_SHIFT 7 - -#define CKEN_AC97CONF (31) /* AC97 Controller Configuration */ -#define CKEN_CAMERA (24) /* Camera Interface Clock Enable */ -#define CKEN_SSP1 (23) /* SSP1 Unit Clock Enable */ -#define CKEN_MEMC (22) /* Memory Controller Clock Enable */ -#define CKEN_MEMSTK (21) /* Memory Stick Host Controller */ -#define CKEN_IM (20) /* Internal Memory Clock Enable */ -#define CKEN_KEYPAD (19) /* Keypad Interface Clock Enable */ -#define CKEN_USIM (18) /* USIM Unit Clock Enable */ -#define CKEN_MSL (17) /* MSL Unit Clock Enable */ -#define CKEN_LCD (16) /* LCD Unit Clock Enable */ -#define CKEN_PWRI2C (15) /* PWR I2C Unit Clock Enable */ -#define CKEN_I2C (14) /* I2C Unit Clock Enable */ -#define CKEN_FICP (13) /* FICP Unit Clock Enable */ -#define CKEN_MMC (12) /* MMC Unit Clock Enable */ -#define CKEN_USB (11) /* USB Unit Clock Enable */ -#define CKEN_ASSP (10) /* ASSP (SSP3) Clock Enable */ -#define CKEN_USBHOST (10) /* USB Host Unit Clock Enable */ -#define CKEN_OSTIMER (9) /* OS Timer Unit Clock Enable */ -#define CKEN_NSSP (9) /* NSSP (SSP2) Clock Enable */ -#define CKEN_I2S (8) /* I2S Unit Clock Enable */ -#define CKEN_BTUART (7) /* BTUART Unit Clock Enable */ -#define CKEN_FFUART (6) /* FFUART Unit Clock Enable */ -#define CKEN_STUART (5) /* STUART Unit Clock Enable */ -#define CKEN_HWUART (4) /* HWUART Unit Clock Enable */ -#define CKEN_SSP3 (4) /* SSP3 Unit Clock Enable */ -#define CKEN_SSP (3) /* SSP Unit Clock Enable */ -#define CKEN_SSP2 (3) /* SSP2 Unit Clock Enable */ -#define CKEN_AC97 (2) /* AC97 Unit Clock Enable */ -#define CKEN_PWM1 (1) /* PWM1 Clock Enable */ -#define CKEN_PWM0 (0) /* PWM0 Clock Enable */ - #define OSCC_OON (1 << 1) /* 32.768kHz OON (write-once only bit) */ #define OSCC_OOK (1 << 0) /* 32.768kHz OOK (read-only bit) */ diff --git a/arch/arm/mach-pxa/pxa2xx.c b/arch/arm/mach-pxa/pxa2xx.c index 2d26cd2afbf3..4aafd692c1e8 100644 --- a/arch/arm/mach-pxa/pxa2xx.c +++ b/arch/arm/mach-pxa/pxa2xx.c @@ -12,10 +12,12 @@ #include <linux/device.h> #include <linux/io.h> -#include <mach/hardware.h> -#include <mach/pxa2xx-regs.h> +#include "pxa2xx-regs.h" #include "mfp-pxa25x.h" -#include <mach/reset.h> +#include "generic.h" +#include "reset.h" +#include "smemc.h" +#include <linux/soc/pxa/smemc.h> #include <linux/platform_data/irda-pxaficp.h> void pxa2xx_clear_reset_status(unsigned int mask) @@ -51,3 +53,27 @@ void pxa2xx_transceiver_mode(struct device *dev, int mode) BUG(); } EXPORT_SYMBOL_GPL(pxa2xx_transceiver_mode); + +#define MDCNFG_DRAC2(mdcnfg) (((mdcnfg) >> 21) & 0x3) +#define MDCNFG_DRAC0(mdcnfg) (((mdcnfg) >> 5) & 0x3) + +int pxa2xx_smemc_get_sdram_rows(void) +{ + static int sdram_rows; + unsigned int drac2 = 0, drac0 = 0; + u32 mdcnfg; + + if (sdram_rows) + return sdram_rows; + + mdcnfg = readl_relaxed(MDCNFG); + + if (mdcnfg & (MDCNFG_DE2 | MDCNFG_DE3)) + drac2 = MDCNFG_DRAC2(mdcnfg); + + if (mdcnfg & (MDCNFG_DE0 | MDCNFG_DE1)) + drac0 = MDCNFG_DRAC0(mdcnfg); + + sdram_rows = 1 << (11 + max(drac0, drac2)); + return sdram_rows; +} diff --git a/arch/arm/mach-pxa/pxa300.c b/arch/arm/mach-pxa/pxa300.c index 7f2f5a6a2263..f77ec118d5b9 100644 --- a/arch/arm/mach-pxa/pxa300.c +++ b/arch/arm/mach-pxa/pxa300.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/soc/pxa/cpu.h> #include "pxa300.h" diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c index 78abcc741df7..e372e6c118de 100644 --- a/arch/arm/mach-pxa/pxa320.c +++ b/arch/arm/mach-pxa/pxa320.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/soc/pxa/cpu.h> #include "pxa320.h" diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h b/arch/arm/mach-pxa/pxa3xx-regs.h index 070f6c74196e..4b11cf81a9e6 100644 --- a/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h +++ b/arch/arm/mach-pxa/pxa3xx-regs.h @@ -10,7 +10,7 @@ #ifndef __ASM_ARCH_PXA3XX_REGS_H #define __ASM_ARCH_PXA3XX_REGS_H -#include <mach/hardware.h> +#include "pxa-regs.h" /* * Oscillator Configuration Register (OSCC) @@ -131,73 +131,4 @@ #define CKENC __REG(0x41340024) /* C Clock Enable Register */ #define AC97_DIV __REG(0x41340014) /* AC97 clock divisor value register */ -#define ACCR_XPDIS (1 << 31) /* Core PLL Output Disable */ -#define ACCR_SPDIS (1 << 30) /* System PLL Output Disable */ -#define ACCR_D0CS (1 << 26) /* D0 Mode Clock Select */ -#define ACCR_PCCE (1 << 11) /* Power Mode Change Clock Enable */ -#define ACCR_DDR_D0CS (1 << 7) /* DDR SDRAM clock frequency in D0CS (PXA31x only) */ - -#define ACCR_SMCFS_MASK (0x7 << 23) /* Static Memory Controller Frequency Select */ -#define ACCR_SFLFS_MASK (0x3 << 18) /* Frequency Select for Internal Memory Controller */ -#define ACCR_XSPCLK_MASK (0x3 << 16) /* Core Frequency during Frequency Change */ -#define ACCR_HSS_MASK (0x3 << 14) /* System Bus-Clock Frequency Select */ -#define ACCR_DMCFS_MASK (0x3 << 12) /* Dynamic Memory Controller Clock Frequency Select */ -#define ACCR_XN_MASK (0x7 << 8) /* Core PLL Turbo-Mode-to-Run-Mode Ratio */ -#define ACCR_XL_MASK (0x1f) /* Core PLL Run-Mode-to-Oscillator Ratio */ - -#define ACCR_SMCFS(x) (((x) & 0x7) << 23) -#define ACCR_SFLFS(x) (((x) & 0x3) << 18) -#define ACCR_XSPCLK(x) (((x) & 0x3) << 16) -#define ACCR_HSS(x) (((x) & 0x3) << 14) -#define ACCR_DMCFS(x) (((x) & 0x3) << 12) -#define ACCR_XN(x) (((x) & 0x7) << 8) -#define ACCR_XL(x) ((x) & 0x1f) - -/* - * Clock Enable Bit - */ -#define CKEN_LCD 1 /* < LCD Clock Enable */ -#define CKEN_USBH 2 /* < USB host clock enable */ -#define CKEN_CAMERA 3 /* < Camera interface clock enable */ -#define CKEN_NAND 4 /* < NAND Flash Controller Clock Enable */ -#define CKEN_USB2 6 /* < USB 2.0 client clock enable. */ -#define CKEN_DMC 8 /* < Dynamic Memory Controller clock enable */ -#define CKEN_SMC 9 /* < Static Memory Controller clock enable */ -#define CKEN_ISC 10 /* < Internal SRAM Controller clock enable */ -#define CKEN_BOOT 11 /* < Boot rom clock enable */ -#define CKEN_MMC1 12 /* < MMC1 Clock enable */ -#define CKEN_MMC2 13 /* < MMC2 clock enable */ -#define CKEN_KEYPAD 14 /* < Keypand Controller Clock Enable */ -#define CKEN_CIR 15 /* < Consumer IR Clock Enable */ -#define CKEN_USIM0 17 /* < USIM[0] Clock Enable */ -#define CKEN_USIM1 18 /* < USIM[1] Clock Enable */ -#define CKEN_TPM 19 /* < TPM clock enable */ -#define CKEN_UDC 20 /* < UDC clock enable */ -#define CKEN_BTUART 21 /* < BTUART clock enable */ -#define CKEN_FFUART 22 /* < FFUART clock enable */ -#define CKEN_STUART 23 /* < STUART clock enable */ -#define CKEN_AC97 24 /* < AC97 clock enable */ -#define CKEN_TOUCH 25 /* < Touch screen Interface Clock Enable */ -#define CKEN_SSP1 26 /* < SSP1 clock enable */ -#define CKEN_SSP2 27 /* < SSP2 clock enable */ -#define CKEN_SSP3 28 /* < SSP3 clock enable */ -#define CKEN_SSP4 29 /* < SSP4 clock enable */ -#define CKEN_MSL0 30 /* < MSL0 clock enable */ -#define CKEN_PWM0 32 /* < PWM[0] clock enable */ -#define CKEN_PWM1 33 /* < PWM[1] clock enable */ -#define CKEN_I2C 36 /* < I2C clock enable */ -#define CKEN_INTC 38 /* < Interrupt controller clock enable */ -#define CKEN_GPIO 39 /* < GPIO clock enable */ -#define CKEN_1WIRE 40 /* < 1-wire clock enable */ -#define CKEN_HSIO2 41 /* < HSIO2 clock enable */ -#define CKEN_MINI_IM 48 /* < Mini-IM */ -#define CKEN_MINI_LCD 49 /* < Mini LCD */ - -#define CKEN_MMC3 5 /* < MMC3 Clock Enable */ -#define CKEN_MVED 43 /* < MVED clock enable */ - -/* Note: GCU clock enable bit differs on PXA300/PXA310 and PXA320 */ -#define CKEN_PXA300_GCU 42 /* Graphics controller clock enable */ -#define CKEN_PXA320_GCU 7 /* Graphics controller clock enable */ - #endif /* __ASM_ARCH_PXA3XX_REGS_H */ diff --git a/arch/arm/mach-pxa/pxa3xx-ulpi.c b/arch/arm/mach-pxa/pxa3xx-ulpi.c index 4bd7da1f8657..c29a7f0fa1b0 100644 --- a/arch/arm/mach-pxa/pxa3xx-ulpi.c +++ b/arch/arm/mach-pxa/pxa3xx-ulpi.c @@ -21,8 +21,8 @@ #include <linux/clk.h> #include <linux/usb.h> #include <linux/usb/otg.h> +#include <linux/soc/pxa/cpu.h> -#include <mach/hardware.h> #include "regs-u2d.h" #include <linux/platform_data/usb-pxa3xx-ulpi.h> diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 560160682df6..979642aa7ffe 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -24,17 +24,18 @@ #include <linux/syscore_ops.h> #include <linux/platform_data/i2c-pxa.h> #include <linux/platform_data/mmp_dma.h> +#include <linux/soc/pxa/cpu.h> +#include <linux/clk/pxa.h> #include <asm/mach/map.h> #include <asm/suspend.h> -#include <mach/hardware.h> -#include <mach/pxa3xx-regs.h> -#include <mach/reset.h> +#include "pxa3xx-regs.h" +#include "reset.h" #include <linux/platform_data/usb-ohci-pxa27x.h> #include "pm.h" -#include <mach/dma.h> -#include <mach/smemc.h> -#include <mach/irqs.h> +#include "addr-map.h" +#include "smemc.h" +#include "irqs.h" #include "generic.h" #include "devices.h" @@ -51,6 +52,10 @@ extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int)); #define NDCR_ND_ARB_EN (1 << 12) #define NDCR_ND_ARB_CNTL (1 << 19) +#define CKEN_BOOT 11 /* < Boot rom clock enable */ +#define CKEN_TPM 19 /* < TPM clock enable */ +#define CKEN_HSIO2 41 /* < HSIO2 clock enable */ + #ifdef CONFIG_PM #define ISRAM_START 0x5c000000 @@ -463,7 +468,7 @@ static int __init pxa3xx_init(void) if (cpu_is_pxa3xx()) { - reset_status = ARSR; + pxa_register_wdt(ARSR); /* * clear RDH bit every time after reset diff --git a/arch/arm/mach-pxa/pxa3xx.h b/arch/arm/mach-pxa/pxa3xx.h index 6d4502aa9d06..81825f7ad258 100644 --- a/arch/arm/mach-pxa/pxa3xx.h +++ b/arch/arm/mach-pxa/pxa3xx.h @@ -2,8 +2,8 @@ #ifndef __MACH_PXA3XX_H #define __MACH_PXA3XX_H -#include <mach/hardware.h> -#include <mach/pxa3xx-regs.h> -#include <mach/irqs.h> +#include "addr-map.h" +#include "pxa3xx-regs.h" +#include "irqs.h" #endif /* __MACH_PXA3XX_H */ diff --git a/arch/arm/mach-pxa/pxa930.c b/arch/arm/mach-pxa/pxa930.c index bf91de4267e5..b9021a40cbd1 100644 --- a/arch/arm/mach-pxa/pxa930.c +++ b/arch/arm/mach-pxa/pxa930.c @@ -13,6 +13,7 @@ #include <linux/irq.h> #include <linux/gpio-pxa.h> #include <linux/platform_device.h> +#include <linux/soc/pxa/cpu.h> #include "pxa930.h" diff --git a/arch/arm/mach-pxa/include/mach/regs-ost.h b/arch/arm/mach-pxa/regs-ost.h index deb564ed8ee7..c8001cfc8d6b 100644 --- a/arch/arm/mach-pxa/include/mach/regs-ost.h +++ b/arch/arm/mach-pxa/regs-ost.h @@ -2,11 +2,13 @@ #ifndef __ASM_MACH_REGS_OST_H #define __ASM_MACH_REGS_OST_H -#include <mach/hardware.h> +#include "pxa-regs.h" /* * OS Timer & Match Registers */ +#define OST_PHYS 0x40A00000 +#define OST_LEN 0x00000020 #define OSMR0 io_p2v(0x40A00000) /* */ #define OSMR1 io_p2v(0x40A00004) /* */ diff --git a/arch/arm/mach-pxa/regs-rtc.h b/arch/arm/mach-pxa/regs-rtc.h index b1f9ff14e335..96255a0f595e 100644 --- a/arch/arm/mach-pxa/regs-rtc.h +++ b/arch/arm/mach-pxa/regs-rtc.h @@ -2,7 +2,7 @@ #ifndef __ASM_MACH_REGS_RTC_H #define __ASM_MACH_REGS_RTC_H -#include <mach/hardware.h> +#include "pxa-regs.h" /* * Real Time Clock diff --git a/arch/arm/mach-pxa/regs-u2d.h b/arch/arm/mach-pxa/regs-u2d.h index fe4c80ad87ec..ab517ba62c9a 100644 --- a/arch/arm/mach-pxa/regs-u2d.h +++ b/arch/arm/mach-pxa/regs-u2d.h @@ -2,8 +2,6 @@ #ifndef __ASM_ARCH_PXA3xx_U2D_H #define __ASM_ARCH_PXA3xx_U2D_H -#include <mach/bitfield.h> - /* * USB2 device controller registers and bits definitions */ diff --git a/arch/arm/mach-pxa/include/mach/regs-uart.h b/arch/arm/mach-pxa/regs-uart.h index 9a168f83afeb..490e9ca16297 100644 --- a/arch/arm/mach-pxa/include/mach/regs-uart.h +++ b/arch/arm/mach-pxa/regs-uart.h @@ -2,6 +2,8 @@ #ifndef __ASM_ARCH_REGS_UART_H #define __ASM_ARCH_REGS_UART_H +#include "pxa-regs.h" + /* * UARTs */ diff --git a/arch/arm/mach-pxa/reset.c b/arch/arm/mach-pxa/reset.c index af78405aa4e9..f0be90573ad3 100644 --- a/arch/arm/mach-pxa/reset.c +++ b/arch/arm/mach-pxa/reset.c @@ -7,12 +7,9 @@ #include <asm/proc-fns.h> #include <asm/system_misc.h> -#include <mach/regs-ost.h> -#include <mach/reset.h> -#include <mach/smemc.h> - -unsigned int reset_status; -EXPORT_SYMBOL(reset_status); +#include "regs-ost.h" +#include "reset.h" +#include "smemc.h" static void do_hw_reset(void); diff --git a/arch/arm/mach-pxa/include/mach/reset.h b/arch/arm/mach-pxa/reset.h index e1c4d100fd45..963dd190bc13 100644 --- a/arch/arm/mach-pxa/include/mach/reset.h +++ b/arch/arm/mach-pxa/reset.h @@ -8,8 +8,8 @@ #define RESET_STATUS_GPIO (1 << 3) /* GPIO Reset */ #define RESET_STATUS_ALL (0xf) -extern unsigned int reset_status; extern void clear_reset_status(unsigned int mask); +extern void pxa_register_wdt(unsigned int reset_status); /** * init_gpio_reset() - register GPIO as reset generator diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index 83cfbb882a2d..a829baf8d922 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -24,7 +24,7 @@ #include <asm/mach-types.h> #include "pm.h" -#include <mach/pxa2xx-regs.h> +#include "pxa2xx-regs.h" #include "regs-rtc.h" #include "sharpsl_pm.h" diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S index 6c5b3ffd2cd3..d58cf52e3848 100644 --- a/arch/arm/mach-pxa/sleep.S +++ b/arch/arm/mach-pxa/sleep.S @@ -13,13 +13,14 @@ #include <linux/linkage.h> #include <asm/assembler.h> -#include <mach/hardware.h> -#include <mach/smemc.h> -#include <mach/pxa2xx-regs.h> +#include "smemc.h" +#include "pxa2xx-regs.h" #define MDREFR_KDIV 0x200a4000 // all banks #define CCCR_SLEEP 0x00000107 // L=7 2N=2 A=0 PPDIS=0 CPDIS=0 - +#define CCCR_N_MASK 0x00000380 +#define CCCR_M_MASK 0x00000060 +#define CCCR_L_MASK 0x0000001f .text #ifdef CONFIG_PXA3xx diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c index 32e82cc92ea5..2d2a321d82f8 100644 --- a/arch/arm/mach-pxa/smemc.c +++ b/arch/arm/mach-pxa/smemc.c @@ -8,9 +8,10 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/syscore_ops.h> +#include <linux/soc/pxa/cpu.h> -#include <mach/hardware.h> -#include <mach/smemc.h> +#include "smemc.h" +#include <linux/soc/pxa/smemc.h> #ifdef CONFIG_PM static unsigned long msc[2]; @@ -70,3 +71,11 @@ static int __init smemc_init(void) } subsys_initcall(smemc_init); #endif + +static const unsigned int df_clkdiv[4] = { 1, 2, 4, 1 }; +unsigned int pxa3xx_smemc_get_memclkdiv(void) +{ + unsigned long memclkcfg = __raw_readl(MEMCLKCFG); + + return df_clkdiv[(memclkcfg >> 16) & 0x3]; +} diff --git a/arch/arm/mach-pxa/include/mach/smemc.h b/arch/arm/mach-pxa/smemc.h index 9b2453a7ab23..9b2453a7ab23 100644 --- a/arch/arm/mach-pxa/include/mach/smemc.h +++ b/arch/arm/mach-pxa/smemc.h diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index a648e7094e84..dd88953adc9d 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -39,14 +39,14 @@ #include "pxa27x.h" #include "pxa27x-udc.h" -#include <mach/reset.h> +#include "reset.h" #include <linux/platform_data/irda-pxaficp.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/usb-ohci-pxa27x.h> #include <linux/platform_data/video-pxafb.h> -#include <mach/spitz.h> +#include "spitz.h" #include "sharpsl_pm.h" -#include <mach/smemc.h> +#include "smemc.h" #include "generic.h" #include "devices.h" @@ -962,11 +962,42 @@ static void __init spitz_i2c_init(void) static inline void spitz_i2c_init(void) {} #endif +static struct gpiod_lookup_table spitz_audio_gpio_table = { + .dev_id = "spitz-audio", + .table = { + GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_L - SPITZ_SCP_GPIO_BASE, + "mute-l", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_R - SPITZ_SCP_GPIO_BASE, + "mute-r", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("sharp-scoop.1", SPITZ_GPIO_MIC_BIAS - SPITZ_SCP2_GPIO_BASE, + "mic", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct gpiod_lookup_table akita_audio_gpio_table = { + .dev_id = "spitz-audio", + .table = { + GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_L - SPITZ_SCP_GPIO_BASE, + "mute-l", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_R - SPITZ_SCP_GPIO_BASE, + "mute-r", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("i2c-max7310", AKITA_GPIO_MIC_BIAS - AKITA_IOEXP_GPIO_BASE, + "mic", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /****************************************************************************** * Audio devices ******************************************************************************/ static inline void spitz_audio_init(void) { + if (machine_is_akita()) + gpiod_add_lookup_table(&akita_audio_gpio_table); + else + gpiod_add_lookup_table(&spitz_audio_gpio_table); + platform_device_register_simple("spitz-audio", -1, NULL, 0); } diff --git a/arch/arm/mach-pxa/include/mach/spitz.h b/arch/arm/mach-pxa/spitz.h index 04828d8918aa..04828d8918aa 100644 --- a/arch/arm/mach-pxa/include/mach/spitz.h +++ b/arch/arm/mach-pxa/spitz.h diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c index 25a1f8c5a738..6689b67f9ce5 100644 --- a/arch/arm/mach-pxa/spitz_pm.c +++ b/arch/arm/mach-pxa/spitz_pm.c @@ -18,9 +18,8 @@ #include <asm/irq.h> #include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/spitz.h> +#include "spitz.h" #include "pxa27x.h" #include "sharpsl_pm.h" diff --git a/arch/arm/mach-pxa/standby.S b/arch/arm/mach-pxa/standby.S index eab1645bb4ad..938310b708a0 100644 --- a/arch/arm/mach-pxa/standby.S +++ b/arch/arm/mach-pxa/standby.S @@ -11,9 +11,8 @@ #include <linux/linkage.h> #include <asm/assembler.h> -#include <mach/hardware.h> -#include <mach/pxa2xx-regs.h> +#include "pxa2xx-regs.h" .text diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 431709725d02..6af8bc404825 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -40,16 +40,16 @@ #include <asm/mach-types.h> #include "pxa25x.h" -#include <mach/reset.h> +#include "reset.h" #include <linux/platform_data/irda-pxaficp.h> #include <linux/platform_data/mmc-pxamci.h> #include "udc.h" #include "tosa_bt.h" -#include <mach/audio.h> -#include <mach/smemc.h> +#include <linux/platform_data/asoc-pxa.h> +#include "smemc.h" #include <asm/mach/arch.h> -#include <mach/tosa.h> +#include "tosa.h" #include <asm/hardware/scoop.h> #include <asm/mach/sharpsl_param.h> @@ -296,9 +296,9 @@ static struct gpiod_lookup_table tosa_mci_gpio_table = { .table = { GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_nSD_DETECT, "cd", GPIO_ACTIVE_LOW), - GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_SD_WP, + GPIO_LOOKUP("sharp-scoop.0", TOSA_GPIO_SD_WP - TOSA_SCOOP_GPIO_BASE, "wp", GPIO_ACTIVE_LOW), - GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_PWR_ON, + GPIO_LOOKUP("sharp-scoop.0", TOSA_GPIO_PWR_ON - TOSA_SCOOP_GPIO_BASE, "power", GPIO_ACTIVE_HIGH), { }, }, @@ -616,6 +616,22 @@ static struct resource tc6393xb_resources[] = { }, }; +static struct gpiod_lookup_table tosa_battery_gpio_table = { + .dev_id = "wm97xx-battery", + .table = { + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_BAT0_CRG, + "main battery full", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_BAT1_CRG, + "jacket battery full", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_BAT0_LOW, + "main battery low", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_BAT1_LOW, + "jacket battery low", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_JACKET_DETECT, + "jacket detect", GPIO_ACTIVE_HIGH), + { }, + }, +}; static int tosa_tc6393xb_enable(struct platform_device *dev) { @@ -709,31 +725,6 @@ static struct tmio_nand_data tosa_tc6393xb_nand_config = { .part_parsers = probes, }; -static int tosa_tc6393xb_setup(struct platform_device *dev) -{ - int rc; - - rc = gpio_request(TOSA_GPIO_CARD_VCC_ON, "CARD_VCC_ON"); - if (rc) - goto err_req; - - rc = gpio_direction_output(TOSA_GPIO_CARD_VCC_ON, 1); - if (rc) - goto err_dir; - - return rc; - -err_dir: - gpio_free(TOSA_GPIO_CARD_VCC_ON); -err_req: - return rc; -} - -static void tosa_tc6393xb_teardown(struct platform_device *dev) -{ - gpio_free(TOSA_GPIO_CARD_VCC_ON); -} - #ifdef CONFIG_MFD_TC6393XB static struct fb_videomode tosa_tc6393xb_lcd_mode[] = { { @@ -778,9 +769,6 @@ static struct tc6393xb_platform_data tosa_tc6393xb_data = { .scr_gper = 0x3300, .irq_base = IRQ_BOARD_START, - .gpio_base = TOSA_TC6393XB_GPIO_BASE, - .setup = tosa_tc6393xb_setup, - .teardown = tosa_tc6393xb_teardown, .enable = tosa_tc6393xb_enable, .disable = tosa_tc6393xb_disable, @@ -821,26 +809,6 @@ static struct pxa2xx_spi_controller pxa_ssp_master_info = { .num_chipselect = 1, }; -static struct gpiod_lookup_table tosa_lcd_gpio_table = { - .dev_id = "spi2.0", - .table = { - GPIO_LOOKUP("tc6393xb", - TOSA_GPIO_TG_ON - TOSA_TC6393XB_GPIO_BASE, - "tg #pwr", GPIO_ACTIVE_HIGH), - { }, - }, -}; - -static struct gpiod_lookup_table tosa_lcd_bl_gpio_table = { - .dev_id = "i2c-tosa-bl", - .table = { - GPIO_LOOKUP("tc6393xb", - TOSA_GPIO_BL_C20MA - TOSA_TC6393XB_GPIO_BASE, - "backlight", GPIO_ACTIVE_HIGH), - { }, - }, -}; - static struct spi_board_info spi_board_info[] __initdata = { { .modalias = "tosa-lcd", @@ -943,6 +911,8 @@ static void __init tosa_init(void) /* enable batt_fault */ PMCR = 0x01; + gpiod_add_lookup_table(&tosa_battery_gpio_table); + gpiod_add_lookup_table(&tosa_mci_gpio_table); pxa_set_mci_info(&tosa_mci_platform_data); pxa_set_ficp_info(&tosa_ficp_platform_data); @@ -951,8 +921,6 @@ static void __init tosa_init(void) platform_scoop_config = &tosa_pcmcia_config; pxa2xx_set_spi_info(2, &pxa_ssp_master_info); - gpiod_add_lookup_table(&tosa_lcd_gpio_table); - gpiod_add_lookup_table(&tosa_lcd_bl_gpio_table); spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); clk_add_alias("CLK_CK3P6MI", tc6393xb_device.name, "GPIO11_CLK", NULL); diff --git a/arch/arm/mach-pxa/include/mach/tosa.h b/arch/arm/mach-pxa/tosa.h index 8bfaca3a8b64..3b3efa0a0e22 100644 --- a/arch/arm/mach-pxa/include/mach/tosa.h +++ b/arch/arm/mach-pxa/tosa.h @@ -55,24 +55,6 @@ #define TOSA_SCOOP_JC_IO_DIR (TOSA_SCOOP_JC_CARD_LIMIT_SEL) /* - * TC6393XB GPIOs - */ -#define TOSA_TC6393XB_GPIO_BASE (PXA_NR_BUILTIN_GPIO + 2 * 12) - -#define TOSA_GPIO_TG_ON (TOSA_TC6393XB_GPIO_BASE + 0) -#define TOSA_GPIO_L_MUTE (TOSA_TC6393XB_GPIO_BASE + 1) -#define TOSA_GPIO_BL_C20MA (TOSA_TC6393XB_GPIO_BASE + 3) -#define TOSA_GPIO_CARD_VCC_ON (TOSA_TC6393XB_GPIO_BASE + 4) -#define TOSA_GPIO_CHARGE_OFF (TOSA_TC6393XB_GPIO_BASE + 6) -#define TOSA_GPIO_CHARGE_OFF_JC (TOSA_TC6393XB_GPIO_BASE + 7) -#define TOSA_GPIO_BAT0_V_ON (TOSA_TC6393XB_GPIO_BASE + 9) -#define TOSA_GPIO_BAT1_V_ON (TOSA_TC6393XB_GPIO_BASE + 10) -#define TOSA_GPIO_BU_CHRG_ON (TOSA_TC6393XB_GPIO_BASE + 11) -#define TOSA_GPIO_BAT_SW_ON (TOSA_TC6393XB_GPIO_BASE + 12) -#define TOSA_GPIO_BAT0_TH_ON (TOSA_TC6393XB_GPIO_BASE + 14) -#define TOSA_GPIO_BAT1_TH_ON (TOSA_TC6393XB_GPIO_BASE + 15) - -/* * PXA GPIOs */ #define TOSA_GPIO_POWERON (0) diff --git a/arch/arm/mach-pxa/trizeps4-pcmcia.c b/arch/arm/mach-pxa/trizeps4-pcmcia.c new file mode 100644 index 000000000000..25e363770565 --- /dev/null +++ b/arch/arm/mach-pxa/trizeps4-pcmcia.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/drivers/pcmcia/pxa2xx_trizeps4.c + * + * TRIZEPS PCMCIA specific routines. + * + * Author: Jürgen Schindele + * Created: 20 02, 2006 + * Copyright: Jürgen Schindele + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> + +#include <asm/mach-types.h> +#include <asm/irq.h> + +#include "pxa2xx-regs.h" +#include "trizeps4.h" + +#include <pcmcia/soc_common.h> + +extern void board_pcmcia_power(int power); + +static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + /* we dont have voltage/card/ready detection + * so we dont need interrupts for it + */ + switch (skt->nr) { + case 0: + skt->stat[SOC_STAT_CD].gpio = GPIO_PCD; + skt->stat[SOC_STAT_CD].name = "cs0_cd"; + skt->stat[SOC_STAT_RDY].gpio = GPIO_PRDY; + skt->stat[SOC_STAT_RDY].name = "cs0_rdy"; + break; + default: + break; + } + /* release the reset of this card */ + pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq); + + return 0; +} + +static unsigned long trizeps_pcmcia_status[2]; + +static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + unsigned short status = 0, change; + status = CFSR_readw(); + change = (status ^ trizeps_pcmcia_status[skt->nr]) & + ConXS_CFSR_BVD_MASK; + if (change) { + trizeps_pcmcia_status[skt->nr] = status; + if (status & ConXS_CFSR_BVD1) { + /* enable_irq empty */ + } else { + /* disable_irq empty */ + } + } + + switch (skt->nr) { + case 0: + /* just fill in fix states */ + state->bvd1 = (status & ConXS_CFSR_BVD1) ? 1 : 0; + state->bvd2 = (status & ConXS_CFSR_BVD2) ? 1 : 0; + state->vs_3v = (status & ConXS_CFSR_VS1) ? 0 : 1; + state->vs_Xv = (status & ConXS_CFSR_VS2) ? 0 : 1; + break; + +#ifndef CONFIG_MACH_TRIZEPS_CONXS + /* on ConXS we only have one slot. Second is inactive */ + case 1: + state->detect = 0; + state->ready = 0; + state->bvd1 = 0; + state->bvd2 = 0; + state->vs_3v = 0; + state->vs_Xv = 0; + break; + +#endif + } +} + +static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + int ret = 0; + unsigned short power = 0; + + /* we do nothing here just check a bit */ + switch (state->Vcc) { + case 0: power &= 0xfc; break; + case 33: power |= ConXS_BCR_S0_VCC_3V3; break; + case 50: + pr_err("%s(): Vcc 5V not supported in socket\n", __func__); + break; + default: + pr_err("%s(): bad Vcc %u\n", __func__, state->Vcc); + ret = -1; + } + + switch (state->Vpp) { + case 0: power &= 0xf3; break; + case 33: power |= ConXS_BCR_S0_VPP_3V3; break; + case 120: + pr_err("%s(): Vpp 12V not supported in socket\n", __func__); + break; + default: + if (state->Vpp != state->Vcc) { + pr_err("%s(): bad Vpp %u\n", __func__, state->Vpp); + ret = -1; + } + } + + switch (skt->nr) { + case 0: /* we only have 3.3V */ + board_pcmcia_power(power); + break; + +#ifndef CONFIG_MACH_TRIZEPS_CONXS + /* on ConXS we only have one slot. Second is inactive */ + case 1: +#endif + default: + break; + } + + return ret; +} + +static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt) +{ + /* default is on */ + board_pcmcia_power(0x9); +} + +static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) +{ + board_pcmcia_power(0x0); +} + +static struct pcmcia_low_level trizeps_pcmcia_ops = { + .owner = THIS_MODULE, + .hw_init = trizeps_pcmcia_hw_init, + .socket_state = trizeps_pcmcia_socket_state, + .configure_socket = trizeps_pcmcia_configure_socket, + .socket_init = trizeps_pcmcia_socket_init, + .socket_suspend = trizeps_pcmcia_socket_suspend, +#ifdef CONFIG_MACH_TRIZEPS_CONXS + .nr = 1, +#else + .nr = 2, +#endif + .first = 0, +}; + +static struct platform_device *trizeps_pcmcia_device; + +static int __init trizeps_pcmcia_init(void) +{ + int ret; + + if (!machine_is_trizeps4() && !machine_is_trizeps4wl()) + return -ENODEV; + + trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!trizeps_pcmcia_device) + return -ENOMEM; + + ret = platform_device_add_data(trizeps_pcmcia_device, + &trizeps_pcmcia_ops, sizeof(trizeps_pcmcia_ops)); + + if (ret == 0) + ret = platform_device_add(trizeps_pcmcia_device); + + if (ret) + platform_device_put(trizeps_pcmcia_device); + + return ret; +} + +static void __exit trizeps_pcmcia_exit(void) +{ + platform_device_unregister(trizeps_pcmcia_device); +} + +fs_initcall(trizeps_pcmcia_init); +module_exit(trizeps_pcmcia_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Juergen Schindele"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index f76f8be09554..716cce885379 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -40,13 +40,13 @@ #include <asm/mach/flash.h> #include "pxa27x.h" -#include <mach/trizeps4.h> -#include <mach/audio.h> +#include "trizeps4.h" +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/irda-pxaficp.h> #include <linux/platform_data/usb-ohci-pxa27x.h> -#include <mach/smemc.h> +#include "smemc.h" #include "generic.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/include/mach/trizeps4.h b/arch/arm/mach-pxa/trizeps4.h index 3cddb1428c5e..b6c19d155ef9 100644 --- a/arch/arm/mach-pxa/include/mach/trizeps4.h +++ b/arch/arm/mach-pxa/trizeps4.h @@ -11,6 +11,7 @@ #ifndef _TRIPEPS4_H_ #define _TRIPEPS4_H_ +#include "addr-map.h" #include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* physical memory regions */ diff --git a/arch/arm/mach-pxa/viper-pcmcia.c b/arch/arm/mach-pxa/viper-pcmcia.c new file mode 100644 index 000000000000..26599dcc49b3 --- /dev/null +++ b/arch/arm/mach-pxa/viper-pcmcia.c @@ -0,0 +1,180 @@ +/* + * Viper/Zeus PCMCIA support + * Copyright 2004 Arcom Control Systems + * + * Maintained by Marc Zyngier <maz@misterjones.org> + * + * Based on: + * iPAQ h2200 PCMCIA support + * Copyright 2004 Koen Kooi <koen@vestingbar.nl> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> + +#include <pcmcia/ss.h> +#include <pcmcia/soc_common.h> + +#include <asm/irq.h> + +#include "viper-pcmcia.h" + +static struct platform_device *arcom_pcmcia_dev; + +static inline struct arcom_pcmcia_pdata *viper_get_pdata(void) +{ + return arcom_pcmcia_dev->dev.platform_data; +} + +static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + struct arcom_pcmcia_pdata *pdata = viper_get_pdata(); + unsigned long flags; + + skt->stat[SOC_STAT_CD].gpio = pdata->cd_gpio; + skt->stat[SOC_STAT_CD].name = "PCMCIA_CD"; + skt->stat[SOC_STAT_RDY].gpio = pdata->rdy_gpio; + skt->stat[SOC_STAT_RDY].name = "CF ready"; + + if (gpio_request(pdata->pwr_gpio, "CF power")) + goto err_request_pwr; + + local_irq_save(flags); + + if (gpio_direction_output(pdata->pwr_gpio, 0)) { + local_irq_restore(flags); + goto err_dir; + } + + local_irq_restore(flags); + + return 0; + +err_dir: + gpio_free(pdata->pwr_gpio); +err_request_pwr: + dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs\n"); + return -1; +} + +/* + * Release all resources. + */ +static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + struct arcom_pcmcia_pdata *pdata = viper_get_pdata(); + + gpio_free(pdata->pwr_gpio); +} + +static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->vs_3v = 1; /* Can only apply 3.3V */ + state->vs_Xv = 0; +} + +static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + struct arcom_pcmcia_pdata *pdata = viper_get_pdata(); + + /* Silently ignore Vpp, output enable, speaker enable. */ + pdata->reset(state->flags & SS_RESET); + + /* Apply socket voltage */ + switch (state->Vcc) { + case 0: + gpio_set_value(pdata->pwr_gpio, 0); + break; + case 33: + gpio_set_value(pdata->pwr_gpio, 1); + break; + default: + dev_err(&arcom_pcmcia_dev->dev, "Unsupported Vcc:%d\n", state->Vcc); + return -1; + } + + return 0; +} + +static struct pcmcia_low_level viper_pcmcia_ops = { + .owner = THIS_MODULE, + .hw_init = viper_pcmcia_hw_init, + .hw_shutdown = viper_pcmcia_hw_shutdown, + .socket_state = viper_pcmcia_socket_state, + .configure_socket = viper_pcmcia_configure_socket, + .nr = 1, +}; + +static struct platform_device *viper_pcmcia_device; + +static int viper_pcmcia_probe(struct platform_device *pdev) +{ + int ret; + + /* I can't imagine more than one device, but you never know... */ + if (arcom_pcmcia_dev) + return -EEXIST; + + if (!pdev->dev.platform_data) + return -EINVAL; + + viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!viper_pcmcia_device) + return -ENOMEM; + + arcom_pcmcia_dev = pdev; + + viper_pcmcia_device->dev.parent = &pdev->dev; + + ret = platform_device_add_data(viper_pcmcia_device, + &viper_pcmcia_ops, + sizeof(viper_pcmcia_ops)); + + if (!ret) + ret = platform_device_add(viper_pcmcia_device); + + if (ret) { + platform_device_put(viper_pcmcia_device); + arcom_pcmcia_dev = NULL; + } + + return ret; +} + +static int viper_pcmcia_remove(struct platform_device *pdev) +{ + platform_device_unregister(viper_pcmcia_device); + arcom_pcmcia_dev = NULL; + return 0; +} + +static struct platform_device_id viper_pcmcia_id_table[] = { + { .name = "viper-pcmcia", }, + { .name = "zeus-pcmcia", }, + { }, +}; + +static struct platform_driver viper_pcmcia_driver = { + .probe = viper_pcmcia_probe, + .remove = viper_pcmcia_remove, + .driver = { + .name = "arcom-pcmcia", + }, + .id_table = viper_pcmcia_id_table, +}; + +module_platform_driver(viper_pcmcia_driver); + +MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-pxa/viper-pcmcia.h b/arch/arm/mach-pxa/viper-pcmcia.h new file mode 100644 index 000000000000..a23b58aff9e1 --- /dev/null +++ b/arch/arm/mach-pxa/viper-pcmcia.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ARCOM_PCMCIA_H +#define __ARCOM_PCMCIA_H + +struct arcom_pcmcia_pdata { + int cd_gpio; + int rdy_gpio; + int pwr_gpio; + void (*reset)(int state); +}; + +#endif diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c index 3aa34e9a15d3..5b43351ee840 100644 --- a/arch/arm/mach-pxa/viper.c +++ b/arch/arm/mach-pxa/viper.c @@ -46,10 +46,10 @@ #include <linux/syscore_ops.h> #include "pxa25x.h" -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/video-pxafb.h> -#include <mach/regs-uart.h> -#include <linux/platform_data/pcmcia-pxa2xx_viper.h> +#include "regs-uart.h" +#include "viper-pcmcia.h" #include "viper.h" #include <asm/setup.h> @@ -851,7 +851,7 @@ static void __init viper_init_vcore_gpios(void) goto err_dir; /* c/should assume redboot set the correct level ??? */ - viper_set_core_cpu_voltage(get_clk_frequency_khz(0), 1); + viper_set_core_cpu_voltage(pxa25x_get_clk_frequency_khz(0), 1); return; @@ -998,6 +998,18 @@ static struct map_desc viper_io_desc[] __initdata = { .length = 0x00800000, .type = MT_DEVICE, }, + { + /* + * ISA I/O space mapping: + * - ports 0x0000-0x0fff are PC/104 + * - ports 0x10000-0x10fff are PCMCIA slot 1 + * - ports 0x11000-0x11fff are PC/104 + */ + .virtual = PCI_IO_VIRT_BASE, + .pfn = __phys_to_pfn(0x30000000), + .length = 0x1000, + .type = MT_DEVICE, + }, }; static void __init viper_map_io(void) diff --git a/arch/arm/mach-pxa/vpac270-pcmcia.c b/arch/arm/mach-pxa/vpac270-pcmcia.c new file mode 100644 index 000000000000..9fd990c8a5fb --- /dev/null +++ b/arch/arm/mach-pxa/vpac270-pcmcia.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/drivers/pcmcia/pxa2xx_vpac270.c + * + * Driver for Voipac PXA270 PCMCIA and CF sockets + * + * Copyright (C) 2010-2011 Marek Vasut <marek.vasut@gmail.com> + */ + +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <asm/mach-types.h> + +#include "vpac270.h" + +#include <pcmcia/soc_common.h> + +static struct gpio vpac270_pcmcia_gpios[] = { + { GPIO107_VPAC270_PCMCIA_PPEN, GPIOF_INIT_LOW, "PCMCIA PPEN" }, + { GPIO11_VPAC270_PCMCIA_RESET, GPIOF_INIT_LOW, "PCMCIA Reset" }, +}; + +static struct gpio vpac270_cf_gpios[] = { + { GPIO16_VPAC270_CF_RESET, GPIOF_INIT_LOW, "CF Reset" }, +}; + +static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + int ret; + + if (skt->nr == 0) { + ret = gpio_request_array(vpac270_pcmcia_gpios, + ARRAY_SIZE(vpac270_pcmcia_gpios)); + + skt->stat[SOC_STAT_CD].gpio = GPIO84_VPAC270_PCMCIA_CD; + skt->stat[SOC_STAT_CD].name = "PCMCIA CD"; + skt->stat[SOC_STAT_RDY].gpio = GPIO35_VPAC270_PCMCIA_RDY; + skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready"; + } else { + ret = gpio_request_array(vpac270_cf_gpios, + ARRAY_SIZE(vpac270_cf_gpios)); + + skt->stat[SOC_STAT_CD].gpio = GPIO17_VPAC270_CF_CD; + skt->stat[SOC_STAT_CD].name = "CF CD"; + skt->stat[SOC_STAT_RDY].gpio = GPIO12_VPAC270_CF_RDY; + skt->stat[SOC_STAT_RDY].name = "CF Ready"; + } + + return ret; +} + +static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + if (skt->nr == 0) + gpio_free_array(vpac270_pcmcia_gpios, + ARRAY_SIZE(vpac270_pcmcia_gpios)); + else + gpio_free_array(vpac270_cf_gpios, + ARRAY_SIZE(vpac270_cf_gpios)); +} + +static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->vs_3v = 1; + state->vs_Xv = 0; +} + +static int +vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + if (skt->nr == 0) { + gpio_set_value(GPIO11_VPAC270_PCMCIA_RESET, + (state->flags & SS_RESET)); + gpio_set_value(GPIO107_VPAC270_PCMCIA_PPEN, + !(state->Vcc == 33 || state->Vcc == 50)); + } else { + gpio_set_value(GPIO16_VPAC270_CF_RESET, + (state->flags & SS_RESET)); + } + + return 0; +} + +static struct pcmcia_low_level vpac270_pcmcia_ops = { + .owner = THIS_MODULE, + + .first = 0, + .nr = 2, + + .hw_init = vpac270_pcmcia_hw_init, + .hw_shutdown = vpac270_pcmcia_hw_shutdown, + + .socket_state = vpac270_pcmcia_socket_state, + .configure_socket = vpac270_pcmcia_configure_socket, +}; + +static struct platform_device *vpac270_pcmcia_device; + +static int __init vpac270_pcmcia_init(void) +{ + int ret; + + if (!machine_is_vpac270()) + return -ENODEV; + + vpac270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!vpac270_pcmcia_device) + return -ENOMEM; + + ret = platform_device_add_data(vpac270_pcmcia_device, + &vpac270_pcmcia_ops, sizeof(vpac270_pcmcia_ops)); + + if (!ret) + ret = platform_device_add(vpac270_pcmcia_device); + + if (ret) + platform_device_put(vpac270_pcmcia_device); + + return ret; +} + +static void __exit vpac270_pcmcia_exit(void) +{ + platform_device_unregister(vpac270_pcmcia_device); +} + +module_init(vpac270_pcmcia_init); +module_exit(vpac270_pcmcia_exit); + +MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); +MODULE_DESCRIPTION("PCMCIA support for Voipac PXA270"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c index 14505e83479e..8f74bafcf1f9 100644 --- a/arch/arm/mach-pxa/vpac270.c +++ b/arch/arm/mach-pxa/vpac270.c @@ -29,8 +29,8 @@ #include <asm/mach/arch.h> #include "pxa27x.h" -#include <mach/audio.h> -#include <mach/vpac270.h> +#include <linux/platform_data/asoc-pxa.h> +#include "vpac270.h" #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/usb-ohci-pxa27x.h> diff --git a/arch/arm/mach-pxa/include/mach/vpac270.h b/arch/arm/mach-pxa/vpac270.h index 0cd094d8c553..0cd094d8c553 100644 --- a/arch/arm/mach-pxa/include/mach/vpac270.h +++ b/arch/arm/mach-pxa/vpac270.h diff --git a/arch/arm/mach-pxa/xcep.c b/arch/arm/mach-pxa/xcep.c index f485146b899f..6bb02b65fb82 100644 --- a/arch/arm/mach-pxa/xcep.c +++ b/arch/arm/mach-pxa/xcep.c @@ -24,9 +24,9 @@ #include <asm/mach/irq.h> #include <asm/mach/map.h> -#include <mach/hardware.h> #include "pxa25x.h" -#include <mach/smemc.h> +#include "addr-map.h" +#include "smemc.h" #include "generic.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c index 7eaeda269927..d03520555497 100644 --- a/arch/arm/mach-pxa/z2.c +++ b/arch/arm/mach-pxa/z2.c @@ -34,7 +34,7 @@ #include "pxa27x.h" #include "mfp-pxa27x.h" -#include <mach/z2.h> +#include "z2.h" #include <linux/platform_data/video-pxafb.h> #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/keypad-pxa27x.h> @@ -651,6 +651,15 @@ static void __init z2_spi_init(void) static inline void z2_spi_init(void) {} #endif +static struct gpiod_lookup_table z2_audio_gpio_table = { + .dev_id = "soc-audio", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO37_ZIPITZ2_HEADSET_DETECT, + "hsdet-gpio", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /****************************************************************************** * Core power regulator ******************************************************************************/ @@ -755,6 +764,8 @@ static void __init z2_init(void) z2_keys_init(); z2_pmic_init(); + gpiod_add_lookup_table(&z2_audio_gpio_table); + pm_power_off = z2_power_off; } diff --git a/arch/arm/mach-pxa/include/mach/z2.h b/arch/arm/mach-pxa/z2.h index a78b2e28b1db..a78b2e28b1db 100644 --- a/arch/arm/mach-pxa/include/mach/z2.h +++ b/arch/arm/mach-pxa/z2.h diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index 97700429633e..ff0d8bb9f557 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -39,17 +39,17 @@ #include "pxa27x.h" #include "devices.h" -#include <mach/regs-uart.h> +#include "regs-uart.h" #include <linux/platform_data/usb-ohci-pxa27x.h> #include <linux/platform_data/mmc-pxamci.h> #include "pxa27x-udc.h" #include "udc.h" #include <linux/platform_data/video-pxafb.h> #include "pm.h" -#include <mach/audio.h> -#include <linux/platform_data/pcmcia-pxa2xx_viper.h> +#include <linux/platform_data/asoc-pxa.h> +#include "viper-pcmcia.h" #include "zeus.h" -#include <mach/smemc.h> +#include "smemc.h" #include "generic.h" @@ -929,6 +929,18 @@ static struct map_desc zeus_io_desc[] __initdata = { .length = 0x00800000, .type = MT_DEVICE, }, + { + /* + * ISA I/O space mapping: + * - ports 0x0000-0x0fff are PC/104 + * - ports 0x10000-0x10fff are PCMCIA slot 1 + * - ports 0x11000-0x11fff are PC/104 + */ + .virtual = PCI_IO_VIRT_BASE, + .pfn = __phys_to_pfn(ZEUS_PC104IO_PHYS), + .length = 0x1000, + .type = MT_DEVICE, + }, }; static void __init zeus_map_io(void) diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c index 79f0025fa17a..8ed75ac29b1a 100644 --- a/arch/arm/mach-pxa/zylonite.c +++ b/arch/arm/mach-pxa/zylonite.c @@ -20,17 +20,19 @@ #include <linux/pwm.h> #include <linux/pwm_backlight.h> #include <linux/smc91x.h> +#include <linux/soc/pxa/cpu.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include "pxa3xx.h" -#include <mach/audio.h> +#include <linux/platform_data/asoc-pxa.h> #include <linux/platform_data/video-pxafb.h> #include "zylonite.h" #include <linux/platform_data/mmc-pxamci.h> #include <linux/platform_data/usb-ohci-pxa27x.h> #include <linux/platform_data/keypad-pxa27x.h> #include <linux/platform_data/mtd-nand-pxa3xx.h> +#include "mfp.h" #include "devices.h" #include "generic.h" @@ -424,6 +426,35 @@ static void __init zylonite_init_ohci(void) static inline void zylonite_init_ohci(void) {} #endif /* CONFIG_USB_OHCI_HCD || CONFIG_USB_OHCI_HCD_MODULE */ +static struct gpiod_lookup_table zylonite_wm97xx_touch_gpio15_table = { + .dev_id = "wm97xx-touch.0", + .table = { + GPIO_LOOKUP("gpio-pxa", mfp_to_gpio(MFP_PIN_GPIO15), + "touch", GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpiod_lookup_table zylonite_wm97xx_touch_gpio26_table = { + .dev_id = "wm97xx-touch.0", + .table = { + GPIO_LOOKUP("gpio-pxa", mfp_to_gpio(MFP_PIN_GPIO26), + "touch", GPIO_ACTIVE_LOW), + { }, + }, +}; + +static void __init zylonite_init_wm97xx_touch(void) +{ + if (!IS_ENABLED(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)) + return; + + if (cpu_is_pxa320()) + gpiod_add_lookup_table(&zylonite_wm97xx_touch_gpio15_table); + else + gpiod_add_lookup_table(&zylonite_wm97xx_touch_gpio26_table); +} + static void __init zylonite_init(void) { pxa_set_ffuart_info(NULL); @@ -449,6 +480,7 @@ static void __init zylonite_init(void) zylonite_init_nand(); zylonite_init_leds(); zylonite_init_ohci(); + zylonite_init_wm97xx_touch(); } MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)") diff --git a/arch/arm/mach-pxa/zylonite.h b/arch/arm/mach-pxa/zylonite.h index 7300ec2aac0d..afe3efcb8e04 100644 --- a/arch/arm/mach-pxa/zylonite.h +++ b/arch/arm/mach-pxa/zylonite.h @@ -2,6 +2,8 @@ #ifndef __ASM_ARCH_ZYLONITE_H #define __ASM_ARCH_ZYLONITE_H +#include <linux/soc/pxa/cpu.h> + #define ZYLONITE_ETH_PHYS 0x14000000 #define EXT_GPIO(x) (128 + (x)) diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c index 956fec1c4940..50a8a3547dbc 100644 --- a/arch/arm/mach-pxa/zylonite_pxa300.c +++ b/arch/arm/mach-pxa/zylonite_pxa300.c @@ -17,6 +17,7 @@ #include <linux/platform_data/i2c-pxa.h> #include <linux/platform_data/pca953x.h> #include <linux/gpio.h> +#include <linux/soc/pxa/cpu.h> #include "pxa300.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/zylonite_pxa320.c b/arch/arm/mach-pxa/zylonite_pxa320.c index 94cb834f36cd..67cab4f1194b 100644 --- a/arch/arm/mach-pxa/zylonite_pxa320.c +++ b/arch/arm/mach-pxa/zylonite_pxa320.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/gpio.h> +#include <linux/soc/pxa/cpu.h> #include "pxa320.h" #include "zylonite.h" diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 4dfb7554649d..6c21f214cd60 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -39,9 +39,6 @@ #include "generic.h" #include <clocksource/pxa.h> -unsigned int reset_status; -EXPORT_SYMBOL(reset_status); - #define NR_FREQS 16 /* @@ -319,10 +316,13 @@ static struct platform_device *sa11x0_devices[] __initdata = { static int __init sa1100_init(void) { + struct resource wdt_res = DEFINE_RES_MEM(0x90000000, 0x20); pm_power_off = sa1100_power_off; regulator_has_full_constraints(); + platform_device_register_simple("sa1100_wdt", -1, &wdt_res, 1); + return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices)); } diff --git a/arch/arm/mach-sa1100/include/mach/reset.h b/arch/arm/mach-sa1100/include/mach/reset.h index 27695650a567..a6723d45ae2a 100644 --- a/arch/arm/mach-sa1100/include/mach/reset.h +++ b/arch/arm/mach-sa1100/include/mach/reset.h @@ -10,7 +10,6 @@ #define RESET_STATUS_GPIO (1 << 3) /* GPIO Reset */ #define RESET_STATUS_ALL (0xf) -extern unsigned int reset_status; static inline void clear_reset_status(unsigned int mask) { RCSR = mask; diff --git a/arch/arm/mm/copypage-xsc3.c b/arch/arm/mm/copypage-xsc3.c index 6f0909dda2f9..c86e79677ff9 100644 --- a/arch/arm/mm/copypage-xsc3.c +++ b/arch/arm/mm/copypage-xsc3.c @@ -29,6 +29,7 @@ static void xsc3_mc_copy_user_page(void *kto, const void *kfrom) int tmp; asm volatile ("\ +.arch xscale \n\ pld [%1, #0] \n\ pld [%1, #32] \n\ 1: pld [%1, #64] \n\ @@ -80,6 +81,7 @@ void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr) { void *ptr, *kaddr = kmap_atomic(page); asm volatile ("\ +.arch xscale \n\ mov r1, %2 \n\ mov r2, #0 \n\ mov r3, #0 \n\ diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 290702328a33..576c0e6c92fc 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -455,7 +455,7 @@ void iounmap(volatile void __iomem *cookie) } EXPORT_SYMBOL(iounmap); -#ifdef CONFIG_PCI +#if defined(CONFIG_PCI) || IS_ENABLED(CONFIG_PCMCIA) static int pci_ioremap_mem_type = MT_DEVICE; void pci_ioremap_set_mem_type(int mem_type) diff --git a/arch/arm/plat-pxa/Kconfig b/arch/arm/plat-pxa/Kconfig deleted file mode 100644 index 6f7a0a39c2b9..000000000000 --- a/arch/arm/plat-pxa/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -if PLAT_PXA - -config PXA_SSP - tristate - help - Enable support for PXA2xx SSP ports - -endif diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile deleted file mode 100644 index 349ea0af8450..000000000000 --- a/arch/arm/plat-pxa/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for code common across different PXA processor families -# -ccflags-$(CONFIG_ARCH_MMP) := -I$(srctree)/$(src)/include - -obj-$(CONFIG_PXA3xx) += mfp.o -obj-$(CONFIG_ARCH_MMP) += mfp.o - -obj-$(CONFIG_PXA_SSP) += ssp.o diff --git a/arch/arm/plat-pxa/include/plat/mfp.h b/arch/arm/plat-pxa/include/plat/mfp.h deleted file mode 100644 index 3accaa9ee781..000000000000 --- a/arch/arm/plat-pxa/include/plat/mfp.h +++ /dev/null @@ -1,472 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/plat-pxa/include/plat/mfp.h - * - * Common Multi-Function Pin Definitions - * - * Copyright (C) 2007 Marvell International Ltd. - * - * 2007-8-21: eric miao <eric.miao@marvell.com> - * initial version - */ - -#ifndef __ASM_PLAT_MFP_H -#define __ASM_PLAT_MFP_H - -#define mfp_to_gpio(m) ((m) % 256) - -/* list of all the configurable MFP pins */ -enum { - MFP_PIN_INVALID = -1, - - MFP_PIN_GPIO0 = 0, - MFP_PIN_GPIO1, - MFP_PIN_GPIO2, - MFP_PIN_GPIO3, - MFP_PIN_GPIO4, - MFP_PIN_GPIO5, - MFP_PIN_GPIO6, - MFP_PIN_GPIO7, - MFP_PIN_GPIO8, - MFP_PIN_GPIO9, - MFP_PIN_GPIO10, - MFP_PIN_GPIO11, - MFP_PIN_GPIO12, - MFP_PIN_GPIO13, - MFP_PIN_GPIO14, - MFP_PIN_GPIO15, - MFP_PIN_GPIO16, - MFP_PIN_GPIO17, - MFP_PIN_GPIO18, - MFP_PIN_GPIO19, - MFP_PIN_GPIO20, - MFP_PIN_GPIO21, - MFP_PIN_GPIO22, - MFP_PIN_GPIO23, - MFP_PIN_GPIO24, - MFP_PIN_GPIO25, - MFP_PIN_GPIO26, - MFP_PIN_GPIO27, - MFP_PIN_GPIO28, - MFP_PIN_GPIO29, - MFP_PIN_GPIO30, - MFP_PIN_GPIO31, - MFP_PIN_GPIO32, - MFP_PIN_GPIO33, - MFP_PIN_GPIO34, - MFP_PIN_GPIO35, - MFP_PIN_GPIO36, - MFP_PIN_GPIO37, - MFP_PIN_GPIO38, - MFP_PIN_GPIO39, - MFP_PIN_GPIO40, - MFP_PIN_GPIO41, - MFP_PIN_GPIO42, - MFP_PIN_GPIO43, - MFP_PIN_GPIO44, - MFP_PIN_GPIO45, - MFP_PIN_GPIO46, - MFP_PIN_GPIO47, - MFP_PIN_GPIO48, - MFP_PIN_GPIO49, - MFP_PIN_GPIO50, - MFP_PIN_GPIO51, - MFP_PIN_GPIO52, - MFP_PIN_GPIO53, - MFP_PIN_GPIO54, - MFP_PIN_GPIO55, - MFP_PIN_GPIO56, - MFP_PIN_GPIO57, - MFP_PIN_GPIO58, - MFP_PIN_GPIO59, - MFP_PIN_GPIO60, - MFP_PIN_GPIO61, - MFP_PIN_GPIO62, - MFP_PIN_GPIO63, - MFP_PIN_GPIO64, - MFP_PIN_GPIO65, - MFP_PIN_GPIO66, - MFP_PIN_GPIO67, - MFP_PIN_GPIO68, - MFP_PIN_GPIO69, - MFP_PIN_GPIO70, - MFP_PIN_GPIO71, - MFP_PIN_GPIO72, - MFP_PIN_GPIO73, - MFP_PIN_GPIO74, - MFP_PIN_GPIO75, - MFP_PIN_GPIO76, - MFP_PIN_GPIO77, - MFP_PIN_GPIO78, - MFP_PIN_GPIO79, - MFP_PIN_GPIO80, - MFP_PIN_GPIO81, - MFP_PIN_GPIO82, - MFP_PIN_GPIO83, - MFP_PIN_GPIO84, - MFP_PIN_GPIO85, - MFP_PIN_GPIO86, - MFP_PIN_GPIO87, - MFP_PIN_GPIO88, - MFP_PIN_GPIO89, - MFP_PIN_GPIO90, - MFP_PIN_GPIO91, - MFP_PIN_GPIO92, - MFP_PIN_GPIO93, - MFP_PIN_GPIO94, - MFP_PIN_GPIO95, - MFP_PIN_GPIO96, - MFP_PIN_GPIO97, - MFP_PIN_GPIO98, - MFP_PIN_GPIO99, - MFP_PIN_GPIO100, - MFP_PIN_GPIO101, - MFP_PIN_GPIO102, - MFP_PIN_GPIO103, - MFP_PIN_GPIO104, - MFP_PIN_GPIO105, - MFP_PIN_GPIO106, - MFP_PIN_GPIO107, - MFP_PIN_GPIO108, - MFP_PIN_GPIO109, - MFP_PIN_GPIO110, - MFP_PIN_GPIO111, - MFP_PIN_GPIO112, - MFP_PIN_GPIO113, - MFP_PIN_GPIO114, - MFP_PIN_GPIO115, - MFP_PIN_GPIO116, - MFP_PIN_GPIO117, - MFP_PIN_GPIO118, - MFP_PIN_GPIO119, - MFP_PIN_GPIO120, - MFP_PIN_GPIO121, - MFP_PIN_GPIO122, - MFP_PIN_GPIO123, - MFP_PIN_GPIO124, - MFP_PIN_GPIO125, - MFP_PIN_GPIO126, - MFP_PIN_GPIO127, - - MFP_PIN_GPIO128, - MFP_PIN_GPIO129, - MFP_PIN_GPIO130, - MFP_PIN_GPIO131, - MFP_PIN_GPIO132, - MFP_PIN_GPIO133, - MFP_PIN_GPIO134, - MFP_PIN_GPIO135, - MFP_PIN_GPIO136, - MFP_PIN_GPIO137, - MFP_PIN_GPIO138, - MFP_PIN_GPIO139, - MFP_PIN_GPIO140, - MFP_PIN_GPIO141, - MFP_PIN_GPIO142, - MFP_PIN_GPIO143, - MFP_PIN_GPIO144, - MFP_PIN_GPIO145, - MFP_PIN_GPIO146, - MFP_PIN_GPIO147, - MFP_PIN_GPIO148, - MFP_PIN_GPIO149, - MFP_PIN_GPIO150, - MFP_PIN_GPIO151, - MFP_PIN_GPIO152, - MFP_PIN_GPIO153, - MFP_PIN_GPIO154, - MFP_PIN_GPIO155, - MFP_PIN_GPIO156, - MFP_PIN_GPIO157, - MFP_PIN_GPIO158, - MFP_PIN_GPIO159, - MFP_PIN_GPIO160, - MFP_PIN_GPIO161, - MFP_PIN_GPIO162, - MFP_PIN_GPIO163, - MFP_PIN_GPIO164, - MFP_PIN_GPIO165, - MFP_PIN_GPIO166, - MFP_PIN_GPIO167, - MFP_PIN_GPIO168, - MFP_PIN_GPIO169, - MFP_PIN_GPIO170, - MFP_PIN_GPIO171, - MFP_PIN_GPIO172, - MFP_PIN_GPIO173, - MFP_PIN_GPIO174, - MFP_PIN_GPIO175, - MFP_PIN_GPIO176, - MFP_PIN_GPIO177, - MFP_PIN_GPIO178, - MFP_PIN_GPIO179, - MFP_PIN_GPIO180, - MFP_PIN_GPIO181, - MFP_PIN_GPIO182, - MFP_PIN_GPIO183, - MFP_PIN_GPIO184, - MFP_PIN_GPIO185, - MFP_PIN_GPIO186, - MFP_PIN_GPIO187, - MFP_PIN_GPIO188, - MFP_PIN_GPIO189, - MFP_PIN_GPIO190, - MFP_PIN_GPIO191, - - MFP_PIN_GPIO255 = 255, - - MFP_PIN_GPIO0_2, - MFP_PIN_GPIO1_2, - MFP_PIN_GPIO2_2, - MFP_PIN_GPIO3_2, - MFP_PIN_GPIO4_2, - MFP_PIN_GPIO5_2, - MFP_PIN_GPIO6_2, - MFP_PIN_GPIO7_2, - MFP_PIN_GPIO8_2, - MFP_PIN_GPIO9_2, - MFP_PIN_GPIO10_2, - MFP_PIN_GPIO11_2, - MFP_PIN_GPIO12_2, - MFP_PIN_GPIO13_2, - MFP_PIN_GPIO14_2, - MFP_PIN_GPIO15_2, - MFP_PIN_GPIO16_2, - MFP_PIN_GPIO17_2, - - MFP_PIN_ULPI_STP, - MFP_PIN_ULPI_NXT, - MFP_PIN_ULPI_DIR, - - MFP_PIN_nXCVREN, - MFP_PIN_DF_CLE_nOE, - MFP_PIN_DF_nADV1_ALE, - MFP_PIN_DF_SCLK_E, - MFP_PIN_DF_SCLK_S, - MFP_PIN_nBE0, - MFP_PIN_nBE1, - MFP_PIN_DF_nADV2_ALE, - MFP_PIN_DF_INT_RnB, - MFP_PIN_DF_nCS0, - MFP_PIN_DF_nCS1, - MFP_PIN_nLUA, - MFP_PIN_nLLA, - MFP_PIN_DF_nWE, - MFP_PIN_DF_ALE_nWE, - MFP_PIN_DF_nRE_nOE, - MFP_PIN_DF_ADDR0, - MFP_PIN_DF_ADDR1, - MFP_PIN_DF_ADDR2, - MFP_PIN_DF_ADDR3, - MFP_PIN_DF_IO0, - MFP_PIN_DF_IO1, - MFP_PIN_DF_IO2, - MFP_PIN_DF_IO3, - MFP_PIN_DF_IO4, - MFP_PIN_DF_IO5, - MFP_PIN_DF_IO6, - MFP_PIN_DF_IO7, - MFP_PIN_DF_IO8, - MFP_PIN_DF_IO9, - MFP_PIN_DF_IO10, - MFP_PIN_DF_IO11, - MFP_PIN_DF_IO12, - MFP_PIN_DF_IO13, - MFP_PIN_DF_IO14, - MFP_PIN_DF_IO15, - MFP_PIN_DF_nCS0_SM_nCS2, - MFP_PIN_DF_nCS1_SM_nCS3, - MFP_PIN_SM_nCS0, - MFP_PIN_SM_nCS1, - MFP_PIN_DF_WEn, - MFP_PIN_DF_REn, - MFP_PIN_DF_CLE_SM_OEn, - MFP_PIN_DF_ALE_SM_WEn, - MFP_PIN_DF_RDY0, - MFP_PIN_DF_RDY1, - - MFP_PIN_SM_SCLK, - MFP_PIN_SM_BE0, - MFP_PIN_SM_BE1, - MFP_PIN_SM_ADV, - MFP_PIN_SM_ADVMUX, - MFP_PIN_SM_RDY, - - MFP_PIN_MMC1_DAT7, - MFP_PIN_MMC1_DAT6, - MFP_PIN_MMC1_DAT5, - MFP_PIN_MMC1_DAT4, - MFP_PIN_MMC1_DAT3, - MFP_PIN_MMC1_DAT2, - MFP_PIN_MMC1_DAT1, - MFP_PIN_MMC1_DAT0, - MFP_PIN_MMC1_CMD, - MFP_PIN_MMC1_CLK, - MFP_PIN_MMC1_CD, - MFP_PIN_MMC1_WP, - - /* additional pins on PXA930 */ - MFP_PIN_GSIM_UIO, - MFP_PIN_GSIM_UCLK, - MFP_PIN_GSIM_UDET, - MFP_PIN_GSIM_nURST, - MFP_PIN_PMIC_INT, - MFP_PIN_RDY, - - /* additional pins on MMP2 */ - MFP_PIN_TWSI1_SCL, - MFP_PIN_TWSI1_SDA, - MFP_PIN_TWSI4_SCL, - MFP_PIN_TWSI4_SDA, - MFP_PIN_CLK_REQ, - - MFP_PIN_MAX, -}; - -/* - * a possible MFP configuration is represented by a 32-bit integer - * - * bit 0.. 9 - MFP Pin Number (1024 Pins Maximum) - * bit 10..12 - Alternate Function Selection - * bit 13..15 - Drive Strength - * bit 16..18 - Low Power Mode State - * bit 19..20 - Low Power Mode Edge Detection - * bit 21..22 - Run Mode Pull State - * - * to facilitate the definition, the following macros are provided - * - * MFP_CFG_DEFAULT - default MFP configuration value, with - * alternate function = 0, - * drive strength = fast 3mA (MFP_DS03X) - * low power mode = default - * edge detection = none - * - * MFP_CFG - default MFPR value with alternate function - * MFP_CFG_DRV - default MFPR value with alternate function and - * pin drive strength - * MFP_CFG_LPM - default MFPR value with alternate function and - * low power mode - * MFP_CFG_X - default MFPR value with alternate function, - * pin drive strength and low power mode - */ - -typedef unsigned long mfp_cfg_t; - -#define MFP_PIN(x) ((x) & 0x3ff) - -#define MFP_AF0 (0x0 << 10) -#define MFP_AF1 (0x1 << 10) -#define MFP_AF2 (0x2 << 10) -#define MFP_AF3 (0x3 << 10) -#define MFP_AF4 (0x4 << 10) -#define MFP_AF5 (0x5 << 10) -#define MFP_AF6 (0x6 << 10) -#define MFP_AF7 (0x7 << 10) -#define MFP_AF_MASK (0x7 << 10) -#define MFP_AF(x) (((x) >> 10) & 0x7) - -#define MFP_DS01X (0x0 << 13) -#define MFP_DS02X (0x1 << 13) -#define MFP_DS03X (0x2 << 13) -#define MFP_DS04X (0x3 << 13) -#define MFP_DS06X (0x4 << 13) -#define MFP_DS08X (0x5 << 13) -#define MFP_DS10X (0x6 << 13) -#define MFP_DS13X (0x7 << 13) -#define MFP_DS_MASK (0x7 << 13) -#define MFP_DS(x) (((x) >> 13) & 0x7) - -#define MFP_LPM_DEFAULT (0x0 << 16) -#define MFP_LPM_DRIVE_LOW (0x1 << 16) -#define MFP_LPM_DRIVE_HIGH (0x2 << 16) -#define MFP_LPM_PULL_LOW (0x3 << 16) -#define MFP_LPM_PULL_HIGH (0x4 << 16) -#define MFP_LPM_FLOAT (0x5 << 16) -#define MFP_LPM_INPUT (0x6 << 16) -#define MFP_LPM_STATE_MASK (0x7 << 16) -#define MFP_LPM_STATE(x) (((x) >> 16) & 0x7) - -#define MFP_LPM_EDGE_NONE (0x0 << 19) -#define MFP_LPM_EDGE_RISE (0x1 << 19) -#define MFP_LPM_EDGE_FALL (0x2 << 19) -#define MFP_LPM_EDGE_BOTH (0x3 << 19) -#define MFP_LPM_EDGE_MASK (0x3 << 19) -#define MFP_LPM_EDGE(x) (((x) >> 19) & 0x3) - -#define MFP_PULL_NONE (0x0 << 21) -#define MFP_PULL_LOW (0x1 << 21) -#define MFP_PULL_HIGH (0x2 << 21) -#define MFP_PULL_BOTH (0x3 << 21) -#define MFP_PULL_FLOAT (0x4 << 21) -#define MFP_PULL_MASK (0x7 << 21) -#define MFP_PULL(x) (((x) >> 21) & 0x7) - -#define MFP_CFG_DEFAULT (MFP_AF0 | MFP_DS03X | MFP_LPM_DEFAULT |\ - MFP_LPM_EDGE_NONE | MFP_PULL_NONE) - -#define MFP_CFG(pin, af) \ - ((MFP_CFG_DEFAULT & ~MFP_AF_MASK) |\ - (MFP_PIN(MFP_PIN_##pin) | MFP_##af)) - -#define MFP_CFG_DRV(pin, af, drv) \ - ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DS_MASK)) |\ - (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_##drv)) - -#define MFP_CFG_LPM(pin, af, lpm) \ - ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_LPM_STATE_MASK)) |\ - (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_LPM_##lpm)) - -#define MFP_CFG_X(pin, af, drv, lpm) \ - ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DS_MASK | MFP_LPM_STATE_MASK)) |\ - (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_##drv | MFP_LPM_##lpm)) - -#if defined(CONFIG_PXA3xx) || defined(CONFIG_ARCH_MMP) -/* - * each MFP pin will have a MFPR register, since the offset of the - * register varies between processors, the processor specific code - * should initialize the pin offsets by mfp_init() - * - * mfp_init_base() - accepts a virtual base for all MFPR registers and - * initialize the MFP table to a default state - * - * mfp_init_addr() - accepts a table of "mfp_addr_map" structure, which - * represents a range of MFP pins from "start" to "end", with the offset - * beginning at "offset", to define a single pin, let "end" = -1. - * - * use - * - * MFP_ADDR_X() to define a range of pins - * MFP_ADDR() to define a single pin - * MFP_ADDR_END to signal the end of pin offset definitions - */ -struct mfp_addr_map { - unsigned int start; - unsigned int end; - unsigned long offset; -}; - -#define MFP_ADDR_X(start, end, offset) \ - { MFP_PIN_##start, MFP_PIN_##end, offset } - -#define MFP_ADDR(pin, offset) \ - { MFP_PIN_##pin, -1, offset } - -#define MFP_ADDR_END { MFP_PIN_INVALID, 0 } - -void __init mfp_init_base(void __iomem *mfpr_base); -void __init mfp_init_addr(struct mfp_addr_map *map); - -/* - * mfp_{read, write}() - for direct read/write access to the MFPR register - * mfp_config() - for configuring a group of MFPR registers - * mfp_config_lpm() - configuring all low power MFPR registers for suspend - * mfp_config_run() - configuring all run time MFPR registers after resume - */ -unsigned long mfp_read(int mfp); -void mfp_write(int mfp, unsigned long mfpr_val); -void mfp_config(unsigned long *mfp_cfgs, int num); -void mfp_config_run(void); -void mfp_config_lpm(void); -#endif /* CONFIG_PXA3xx || CONFIG_ARCH_MMP */ - -#endif /* __ASM_PLAT_MFP_H */ diff --git a/arch/arm/plat-pxa/mfp.c b/arch/arm/plat-pxa/mfp.c deleted file mode 100644 index 17fc4f33f35b..000000000000 --- a/arch/arm/plat-pxa/mfp.c +++ /dev/null @@ -1,282 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/plat-pxa/mfp.c - * - * Multi-Function Pin Support - * - * Copyright (C) 2007 Marvell Internation Ltd. - * - * 2007-08-21: eric miao <eric.miao@marvell.com> - * initial version - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/io.h> - -#include <plat/mfp.h> - -#define MFPR_SIZE (PAGE_SIZE) - -/* MFPR register bit definitions */ -#define MFPR_PULL_SEL (0x1 << 15) -#define MFPR_PULLUP_EN (0x1 << 14) -#define MFPR_PULLDOWN_EN (0x1 << 13) -#define MFPR_SLEEP_SEL (0x1 << 9) -#define MFPR_SLEEP_OE_N (0x1 << 7) -#define MFPR_EDGE_CLEAR (0x1 << 6) -#define MFPR_EDGE_FALL_EN (0x1 << 5) -#define MFPR_EDGE_RISE_EN (0x1 << 4) - -#define MFPR_SLEEP_DATA(x) ((x) << 8) -#define MFPR_DRIVE(x) (((x) & 0x7) << 10) -#define MFPR_AF_SEL(x) (((x) & 0x7) << 0) - -#define MFPR_EDGE_NONE (0) -#define MFPR_EDGE_RISE (MFPR_EDGE_RISE_EN) -#define MFPR_EDGE_FALL (MFPR_EDGE_FALL_EN) -#define MFPR_EDGE_BOTH (MFPR_EDGE_RISE | MFPR_EDGE_FALL) - -/* - * Table that determines the low power modes outputs, with actual settings - * used in parentheses for don't-care values. Except for the float output, - * the configured driven and pulled levels match, so if there is a need for - * non-LPM pulled output, the same configuration could probably be used. - * - * Output value sleep_oe_n sleep_data pullup_en pulldown_en pull_sel - * (bit 7) (bit 8) (bit 14) (bit 13) (bit 15) - * - * Input 0 X(0) X(0) X(0) 0 - * Drive 0 0 0 0 X(1) 0 - * Drive 1 0 1 X(1) 0 0 - * Pull hi (1) 1 X(1) 1 0 0 - * Pull lo (0) 1 X(0) 0 1 0 - * Z (float) 1 X(0) 0 0 0 - */ -#define MFPR_LPM_INPUT (0) -#define MFPR_LPM_DRIVE_LOW (MFPR_SLEEP_DATA(0) | MFPR_PULLDOWN_EN) -#define MFPR_LPM_DRIVE_HIGH (MFPR_SLEEP_DATA(1) | MFPR_PULLUP_EN) -#define MFPR_LPM_PULL_LOW (MFPR_LPM_DRIVE_LOW | MFPR_SLEEP_OE_N) -#define MFPR_LPM_PULL_HIGH (MFPR_LPM_DRIVE_HIGH | MFPR_SLEEP_OE_N) -#define MFPR_LPM_FLOAT (MFPR_SLEEP_OE_N) -#define MFPR_LPM_MASK (0xe080) - -/* - * The pullup and pulldown state of the MFP pin at run mode is by default - * determined by the selected alternate function. In case that some buggy - * devices need to override this default behavior, the definitions below - * indicates the setting of corresponding MFPR bits - * - * Definition pull_sel pullup_en pulldown_en - * MFPR_PULL_NONE 0 0 0 - * MFPR_PULL_LOW 1 0 1 - * MFPR_PULL_HIGH 1 1 0 - * MFPR_PULL_BOTH 1 1 1 - * MFPR_PULL_FLOAT 1 0 0 - */ -#define MFPR_PULL_NONE (0) -#define MFPR_PULL_LOW (MFPR_PULL_SEL | MFPR_PULLDOWN_EN) -#define MFPR_PULL_BOTH (MFPR_PULL_LOW | MFPR_PULLUP_EN) -#define MFPR_PULL_HIGH (MFPR_PULL_SEL | MFPR_PULLUP_EN) -#define MFPR_PULL_FLOAT (MFPR_PULL_SEL) - -/* mfp_spin_lock is used to ensure that MFP register configuration - * (most likely a read-modify-write operation) is atomic, and that - * mfp_table[] is consistent - */ -static DEFINE_SPINLOCK(mfp_spin_lock); - -static void __iomem *mfpr_mmio_base; - -struct mfp_pin { - unsigned long config; /* -1 for not configured */ - unsigned long mfpr_off; /* MFPRxx Register offset */ - unsigned long mfpr_run; /* Run-Mode Register Value */ - unsigned long mfpr_lpm; /* Low Power Mode Register Value */ -}; - -static struct mfp_pin mfp_table[MFP_PIN_MAX]; - -/* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */ -static const unsigned long mfpr_lpm[] = { - MFPR_LPM_INPUT, - MFPR_LPM_DRIVE_LOW, - MFPR_LPM_DRIVE_HIGH, - MFPR_LPM_PULL_LOW, - MFPR_LPM_PULL_HIGH, - MFPR_LPM_FLOAT, - MFPR_LPM_INPUT, -}; - -/* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */ -static const unsigned long mfpr_pull[] = { - MFPR_PULL_NONE, - MFPR_PULL_LOW, - MFPR_PULL_HIGH, - MFPR_PULL_BOTH, - MFPR_PULL_FLOAT, -}; - -/* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */ -static const unsigned long mfpr_edge[] = { - MFPR_EDGE_NONE, - MFPR_EDGE_RISE, - MFPR_EDGE_FALL, - MFPR_EDGE_BOTH, -}; - -#define mfpr_readl(off) \ - __raw_readl(mfpr_mmio_base + (off)) - -#define mfpr_writel(off, val) \ - __raw_writel(val, mfpr_mmio_base + (off)) - -#define mfp_configured(p) ((p)->config != -1) - -/* - * perform a read-back of any valid MFPR register to make sure the - * previous writings are finished - */ -static unsigned long mfpr_off_readback; -#define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + mfpr_off_readback) - -static inline void __mfp_config_run(struct mfp_pin *p) -{ - if (mfp_configured(p)) - mfpr_writel(p->mfpr_off, p->mfpr_run); -} - -static inline void __mfp_config_lpm(struct mfp_pin *p) -{ - if (mfp_configured(p)) { - unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR; - if (mfpr_clr != p->mfpr_run) - mfpr_writel(p->mfpr_off, mfpr_clr); - if (p->mfpr_lpm != mfpr_clr) - mfpr_writel(p->mfpr_off, p->mfpr_lpm); - } -} - -void mfp_config(unsigned long *mfp_cfgs, int num) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&mfp_spin_lock, flags); - - for (i = 0; i < num; i++, mfp_cfgs++) { - unsigned long tmp, c = *mfp_cfgs; - struct mfp_pin *p; - int pin, af, drv, lpm, edge, pull; - - pin = MFP_PIN(c); - BUG_ON(pin >= MFP_PIN_MAX); - p = &mfp_table[pin]; - - af = MFP_AF(c); - drv = MFP_DS(c); - lpm = MFP_LPM_STATE(c); - edge = MFP_LPM_EDGE(c); - pull = MFP_PULL(c); - - /* run-mode pull settings will conflict with MFPR bits of - * low power mode state, calculate mfpr_run and mfpr_lpm - * individually if pull != MFP_PULL_NONE - */ - tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv); - - if (likely(pull == MFP_PULL_NONE)) { - p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; - p->mfpr_lpm = p->mfpr_run; - } else { - p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; - p->mfpr_run = tmp | mfpr_pull[pull]; - } - - p->config = c; __mfp_config_run(p); - } - - mfpr_sync(); - spin_unlock_irqrestore(&mfp_spin_lock, flags); -} - -unsigned long mfp_read(int mfp) -{ - unsigned long val, flags; - - BUG_ON(mfp < 0 || mfp >= MFP_PIN_MAX); - - spin_lock_irqsave(&mfp_spin_lock, flags); - val = mfpr_readl(mfp_table[mfp].mfpr_off); - spin_unlock_irqrestore(&mfp_spin_lock, flags); - - return val; -} - -void mfp_write(int mfp, unsigned long val) -{ - unsigned long flags; - - BUG_ON(mfp < 0 || mfp >= MFP_PIN_MAX); - - spin_lock_irqsave(&mfp_spin_lock, flags); - mfpr_writel(mfp_table[mfp].mfpr_off, val); - mfpr_sync(); - spin_unlock_irqrestore(&mfp_spin_lock, flags); -} - -void __init mfp_init_base(void __iomem *mfpr_base) -{ - int i; - - /* initialize the table with default - unconfigured */ - for (i = 0; i < ARRAY_SIZE(mfp_table); i++) - mfp_table[i].config = -1; - - mfpr_mmio_base = mfpr_base; -} - -void __init mfp_init_addr(struct mfp_addr_map *map) -{ - struct mfp_addr_map *p; - unsigned long offset, flags; - int i; - - spin_lock_irqsave(&mfp_spin_lock, flags); - - /* mfp offset for readback */ - mfpr_off_readback = map[0].offset; - - for (p = map; p->start != MFP_PIN_INVALID; p++) { - offset = p->offset; - i = p->start; - - do { - mfp_table[i].mfpr_off = offset; - mfp_table[i].mfpr_run = 0; - mfp_table[i].mfpr_lpm = 0; - offset += 4; i++; - } while ((i <= p->end) && (p->end != -1)); - } - - spin_unlock_irqrestore(&mfp_spin_lock, flags); -} - -void mfp_config_lpm(void) -{ - struct mfp_pin *p = &mfp_table[0]; - int pin; - - for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++) - __mfp_config_lpm(p); -} - -void mfp_config_run(void) -{ - struct mfp_pin *p = &mfp_table[0]; - int pin; - - for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++) - __mfp_config_run(p); -} diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c deleted file mode 100644 index 563440315acd..000000000000 --- a/arch/arm/plat-pxa/ssp.c +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-pxa/ssp.c - * - * based on linux/arch/arm/mach-sa1100/ssp.c by Russell King - * - * Copyright (C) 2003 Russell King. - * Copyright (C) 2003 Wolfson Microelectronics PLC - * - * PXA2xx SSP driver. This provides the generic core for simple - * IO-based SSP applications and allows easy port setup for DMA access. - * - * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/mutex.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/platform_device.h> -#include <linux/spi/pxa2xx_spi.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_device.h> - -#include <asm/irq.h> - -static DEFINE_MUTEX(ssp_lock); -static LIST_HEAD(ssp_list); - -struct ssp_device *pxa_ssp_request(int port, const char *label) -{ - struct ssp_device *ssp = NULL; - - mutex_lock(&ssp_lock); - - list_for_each_entry(ssp, &ssp_list, node) { - if (ssp->port_id == port && ssp->use_count == 0) { - ssp->use_count++; - ssp->label = label; - break; - } - } - - mutex_unlock(&ssp_lock); - - if (&ssp->node == &ssp_list) - return NULL; - - return ssp; -} -EXPORT_SYMBOL(pxa_ssp_request); - -struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node, - const char *label) -{ - struct ssp_device *ssp = NULL; - - mutex_lock(&ssp_lock); - - list_for_each_entry(ssp, &ssp_list, node) { - if (ssp->of_node == of_node && ssp->use_count == 0) { - ssp->use_count++; - ssp->label = label; - break; - } - } - - mutex_unlock(&ssp_lock); - - if (&ssp->node == &ssp_list) - return NULL; - - return ssp; -} -EXPORT_SYMBOL(pxa_ssp_request_of); - -void pxa_ssp_free(struct ssp_device *ssp) -{ - mutex_lock(&ssp_lock); - if (ssp->use_count) { - ssp->use_count--; - ssp->label = NULL; - } else - dev_err(ssp->dev, "device already free\n"); - mutex_unlock(&ssp_lock); -} -EXPORT_SYMBOL(pxa_ssp_free); - -#ifdef CONFIG_OF -static const struct of_device_id pxa_ssp_of_ids[] = { - { .compatible = "mrvl,pxa25x-ssp", .data = (void *) PXA25x_SSP }, - { .compatible = "mvrl,pxa25x-nssp", .data = (void *) PXA25x_NSSP }, - { .compatible = "mrvl,pxa27x-ssp", .data = (void *) PXA27x_SSP }, - { .compatible = "mrvl,pxa3xx-ssp", .data = (void *) PXA3xx_SSP }, - { .compatible = "mvrl,pxa168-ssp", .data = (void *) PXA168_SSP }, - { .compatible = "mrvl,pxa910-ssp", .data = (void *) PXA910_SSP }, - { .compatible = "mrvl,ce4100-ssp", .data = (void *) CE4100_SSP }, - { }, -}; -MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids); -#endif - -static int pxa_ssp_probe(struct platform_device *pdev) -{ - struct resource *res; - struct ssp_device *ssp; - struct device *dev = &pdev->dev; - - ssp = devm_kzalloc(dev, sizeof(struct ssp_device), GFP_KERNEL); - if (ssp == NULL) - return -ENOMEM; - - ssp->dev = dev; - - ssp->clk = devm_clk_get(dev, NULL); - if (IS_ERR(ssp->clk)) - return PTR_ERR(ssp->clk); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(dev, "no memory resource defined\n"); - return -ENODEV; - } - - res = devm_request_mem_region(dev, res->start, resource_size(res), - pdev->name); - if (res == NULL) { - dev_err(dev, "failed to request memory resource\n"); - return -EBUSY; - } - - ssp->phys_base = res->start; - - ssp->mmio_base = devm_ioremap(dev, res->start, resource_size(res)); - if (ssp->mmio_base == NULL) { - dev_err(dev, "failed to ioremap() registers\n"); - return -ENODEV; - } - - ssp->irq = platform_get_irq(pdev, 0); - if (ssp->irq < 0) { - dev_err(dev, "no IRQ resource defined\n"); - return -ENODEV; - } - - if (dev->of_node) { - const struct of_device_id *id = - of_match_device(of_match_ptr(pxa_ssp_of_ids), dev); - ssp->type = (int) id->data; - } else { - const struct platform_device_id *id = - platform_get_device_id(pdev); - ssp->type = (int) id->driver_data; - - /* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id - * starts from 0, do a translation here - */ - ssp->port_id = pdev->id + 1; - } - - ssp->use_count = 0; - ssp->of_node = dev->of_node; - - mutex_lock(&ssp_lock); - list_add(&ssp->node, &ssp_list); - mutex_unlock(&ssp_lock); - - platform_set_drvdata(pdev, ssp); - - return 0; -} - -static int pxa_ssp_remove(struct platform_device *pdev) -{ - struct ssp_device *ssp; - - ssp = platform_get_drvdata(pdev); - if (ssp == NULL) - return -ENODEV; - - mutex_lock(&ssp_lock); - list_del(&ssp->node); - mutex_unlock(&ssp_lock); - - return 0; -} - -static const struct platform_device_id ssp_id_table[] = { - { "pxa25x-ssp", PXA25x_SSP }, - { "pxa25x-nssp", PXA25x_NSSP }, - { "pxa27x-ssp", PXA27x_SSP }, - { "pxa3xx-ssp", PXA3xx_SSP }, - { "pxa168-ssp", PXA168_SSP }, - { "pxa910-ssp", PXA910_SSP }, - { }, -}; - -static struct platform_driver pxa_ssp_driver = { - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, - .driver = { - .name = "pxa2xx-ssp", - .of_match_table = of_match_ptr(pxa_ssp_of_ids), - }, - .id_table = ssp_id_table, -}; - -static int __init pxa_ssp_init(void) -{ - return platform_driver_register(&pxa_ssp_driver); -} - -static void __exit pxa_ssp_exit(void) -{ - platform_driver_unregister(&pxa_ssp_driver); -} - -arch_initcall(pxa_ssp_init); -module_exit(pxa_ssp_exit); - -MODULE_DESCRIPTION("PXA SSP driver"); -MODULE_AUTHOR("Liam Girdwood"); -MODULE_LICENSE("GPL"); diff --git a/arch/arm64/boot/dts/intel/Makefile b/arch/arm64/boot/dts/intel/Makefile index 0b5477442263..c2a723838344 100644 --- a/arch/arm64/boot/dts/intel/Makefile +++ b/arch/arm64/boot/dts/intel/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_agilex_socdk.dtb \ +dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_agilex_n6000.dtb \ + socfpga_agilex_socdk.dtb \ socfpga_agilex_socdk_nand.dtb \ socfpga_n5x_socdk.dtb dtb-$(CONFIG_ARCH_KEEMBAY) += keembay-evm.dtb diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex_n6000.dts b/arch/arm64/boot/dts/intel/socfpga_agilex_n6000.dts new file mode 100644 index 000000000000..6231a69204b1 --- /dev/null +++ b/arch/arm64/boot/dts/intel/socfpga_agilex_n6000.dts @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021-2022, Intel Corporation + */ +#include "socfpga_agilex.dtsi" + +/ { + model = "SoCFPGA Agilex n6000"; + compatible = "intel,socfpga-agilex-n6000", "intel,socfpga-agilex"; + + aliases { + serial0 = &uart1; + serial1 = &uart0; + ethernet0 = &gmac0; + ethernet1 = &gmac1; + ethernet2 = &gmac2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + /* We expect the bootloader to fill in the reg */ + reg = <0 0 0 0>; + }; + + soc { + bus@80000000 { + compatible = "simple-bus"; + reg = <0x80000000 0x60000000>, + <0xf9000000 0x00100000>; + reg-names = "axi_h2f", "axi_h2f_lw"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0x00000000 0x00000000 0xf9000000 0x00001000>; + + dma-controller@0 { + compatible = "intel,hps-copy-engine"; + reg = <0x00000000 0x00000000 0x00001000>; + #dma-cells = <1>; + }; + }; + }; +}; + +&osc1 { + clock-frequency = <25000000>; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&watchdog0 { + status = "okay"; +}; + +&fpga_mgr { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dts b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts index 56e54ce4d10e..49afbb1a066a 100644 --- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dts +++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts @@ -1052,22 +1052,22 @@ &usb2 { status = "okay"; extcon = <&usb2_id>; +}; - dwc3@7600000 { - extcon = <&usb2_id>; - dr_mode = "otg"; - maximum-speed = "high-speed"; - }; +&usb2_dwc3 { + extcon = <&usb2_id>; + dr_mode = "otg"; + maximum-speed = "high-speed"; }; &usb3 { status = "okay"; extcon = <&usb3_id>; +}; - dwc3@6a00000 { - extcon = <&usb3_id>; - dr_mode = "otg"; - }; +&usb3_dwc3 { + extcon = <&usb3_id>; + dr_mode = "otg"; }; &usb3phy { diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi index a4d363c187fc..c89499e366d3 100644 --- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi @@ -653,7 +653,7 @@ status = "disabled"; }; - usb2: usb2@7000000 { + usb2: usb@70f8800 { compatible = "qcom,ipq6018-dwc3", "qcom,dwc3"; reg = <0x0 0x070F8800 0x0 0x400>; #address-cells = <2>; @@ -662,7 +662,7 @@ clocks = <&gcc GCC_USB1_MASTER_CLK>, <&gcc GCC_USB1_SLEEP_CLK>, <&gcc GCC_USB1_MOCK_UTMI_CLK>; - clock-names = "master", + clock-names = "core", "sleep", "mock_utmi"; @@ -730,7 +730,7 @@ status = "disabled"; }; - usb3: usb3@8A00000 { + usb3: usb@8af8800 { compatible = "qcom,ipq6018-dwc3", "qcom,dwc3"; reg = <0x0 0x8AF8800 0x0 0x400>; #address-cells = <2>; @@ -741,8 +741,8 @@ <&gcc GCC_USB0_MASTER_CLK>, <&gcc GCC_USB0_SLEEP_CLK>, <&gcc GCC_USB0_MOCK_UTMI_CLK>; - clock-names = "sys_noc_axi", - "master", + clock-names = "cfg_noc", + "core", "sleep", "mock_utmi"; @@ -756,7 +756,7 @@ resets = <&gcc GCC_USB0_BCR>; status = "disabled"; - dwc_0: usb@8A00000 { + dwc_0: usb@8a00000 { compatible = "snps,dwc3"; reg = <0x0 0x8A00000 0x0 0xcd00>; interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi index 943243d5515b..4c38b15c6fd4 100644 --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi @@ -553,7 +553,7 @@ }; usb_0: usb@8af8800 { - compatible = "qcom,dwc3"; + compatible = "qcom,ipq8074-dwc3", "qcom,dwc3"; reg = <0x08af8800 0x400>; #address-cells = <1>; #size-cells = <1>; @@ -563,8 +563,8 @@ <&gcc GCC_USB0_MASTER_CLK>, <&gcc GCC_USB0_SLEEP_CLK>, <&gcc GCC_USB0_MOCK_UTMI_CLK>; - clock-names = "sys_noc_axi", - "master", + clock-names = "cfg_noc", + "core", "sleep", "mock_utmi"; @@ -578,7 +578,7 @@ resets = <&gcc GCC_USB0_BCR>; status = "disabled"; - dwc_0: dwc3@8a00000 { + dwc_0: usb@8a00000 { compatible = "snps,dwc3"; reg = <0x8a00000 0xcd00>; interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; @@ -593,7 +593,7 @@ }; usb_1: usb@8cf8800 { - compatible = "qcom,dwc3"; + compatible = "qcom,ipq8074-dwc3", "qcom,dwc3"; reg = <0x08cf8800 0x400>; #address-cells = <1>; #size-cells = <1>; @@ -603,8 +603,8 @@ <&gcc GCC_USB1_MASTER_CLK>, <&gcc GCC_USB1_SLEEP_CLK>, <&gcc GCC_USB1_MOCK_UTMI_CLK>; - clock-names = "sys_noc_axi", - "master", + clock-names = "cfg_noc", + "core", "sleep", "mock_utmi"; @@ -618,7 +618,7 @@ resets = <&gcc GCC_USB1_BCR>; status = "disabled"; - dwc_1: dwc3@8c00000 { + dwc_1: usb@8c00000 { compatible = "snps,dwc3"; reg = <0x8c00000 0xcd00>; interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 49903a6e9dfd..ffc3ec2cd3bc 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -759,10 +759,13 @@ clocks = <&gcc GCC_USB_PHY_CFG_AHB_CLK>, <&gcc GCC_USB30_MASTER_CLK>, <&gcc GCC_PCNOC_USB3_AXI_CLK>, - <&gcc GCC_USB30_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", - "mock_utmi", "sleep"; + <&gcc GCC_USB30_SLEEP_CLK>, + <&gcc GCC_USB30_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, <&gcc GCC_USB30_MASTER_CLK>; diff --git a/arch/arm64/boot/dts/qcom/msm8994.dtsi b/arch/arm64/boot/dts/qcom/msm8994.dtsi index 367ed913902c..0318d42c5736 100644 --- a/arch/arm64/boot/dts/qcom/msm8994.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8994.dtsi @@ -428,7 +428,7 @@ }; usb3: usb@f92f8800 { - compatible = "qcom,msm8996-dwc3", "qcom,dwc3"; + compatible = "qcom,msm8994-dwc3", "qcom,dwc3"; reg = <0xf92f8800 0x400>; #address-cells = <1>; #size-cells = <1>; @@ -438,7 +438,10 @@ <&gcc GCC_SYS_NOC_USB3_AXI_CLK>, <&gcc GCC_USB30_SLEEP_CLK>, <&gcc GCC_USB30_MOCK_UTMI_CLK>; - clock-names = "core", "iface", "sleep", "mock_utmi", "ref", "xo"; + clock-names = "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, <&gcc GCC_USB30_MASTER_CLK>; diff --git a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi index be4f643b1fd1..a7090befc16f 100644 --- a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi @@ -308,19 +308,19 @@ extcon = <&typec>; qcom,select-utmi-as-pipe-clk; +}; - dwc3@6a00000 { - extcon = <&typec>; +&usb3_dwc3 { + extcon = <&typec>; - /* usb3-phy is not used on this device */ - phys = <&hsusb_phy1>; - phy-names = "usb2-phy"; + /* usb3-phy is not used on this device */ + phys = <&hsusb_phy1>; + phy-names = "usb2-phy"; - maximum-speed = "high-speed"; - snps,is-utmi-l1-suspend; - snps,usb2-gadget-lpm-disable; - snps,hird-threshold = /bits/ 8 <0>; - }; + maximum-speed = "high-speed"; + snps,is-utmi-l1-suspend; + snps,usb2-gadget-lpm-disable; + snps,hird-threshold = /bits/ 8 <0>; }; &hsusb_phy1 { diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 205af7b479a8..9932186f7ceb 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -2718,11 +2718,15 @@ interrupt-names = "hs_phy_irq", "ss_phy_irq"; clocks = <&gcc GCC_SYS_NOC_USB3_AXI_CLK>, - <&gcc GCC_USB30_MASTER_CLK>, - <&gcc GCC_AGGRE2_USB3_AXI_CLK>, - <&gcc GCC_USB30_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_SLEEP_CLK>, - <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + <&gcc GCC_USB30_MASTER_CLK>, + <&gcc GCC_AGGRE2_USB3_AXI_CLK>, + <&gcc GCC_USB30_SLEEP_CLK>, + <&gcc GCC_USB30_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, <&gcc GCC_USB30_MASTER_CLK>; @@ -2731,7 +2735,7 @@ power-domains = <&gcc USB30_GDSC>; status = "disabled"; - usb3_dwc3: dwc3@6a00000 { + usb3_dwc3: usb@6a00000 { compatible = "snps,dwc3"; reg = <0x06a00000 0xcc00>; interrupts = <0 131 IRQ_TYPE_LEVEL_HIGH>; @@ -3050,6 +3054,11 @@ <&gcc GCC_USB20_MOCK_UTMI_CLK>, <&gcc GCC_USB20_SLEEP_CLK>, <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB20_MOCK_UTMI_CLK>, <&gcc GCC_USB20_MASTER_CLK>; @@ -3059,7 +3068,7 @@ qcom,select-utmi-as-pipe-clk; status = "disabled"; - dwc3@7600000 { + usb2_dwc3: usb@7600000 { compatible = "snps,dwc3"; reg = <0x07600000 0xcc00>; interrupts = <0 138 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi index 4a84de6cee1e..758c45bbbe78 100644 --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi @@ -2023,10 +2023,13 @@ clocks = <&gcc GCC_CFG_NOC_USB3_AXI_CLK>, <&gcc GCC_USB30_MASTER_CLK>, <&gcc GCC_AGGRE1_USB3_AXI_CLK>, - <&gcc GCC_USB30_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep"; + <&gcc GCC_USB30_SLEEP_CLK>, + <&gcc GCC_USB30_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, <&gcc GCC_USB30_MASTER_CLK>; @@ -2040,7 +2043,7 @@ resets = <&gcc GCC_USB_30_BCR>; - usb3_dwc3: dwc3@a800000 { + usb3_dwc3: usb@a800000 { compatible = "snps,dwc3"; reg = <0x0a800000 0xcd00>; interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi index a80c578484ba..2f3104a84417 100644 --- a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi @@ -337,9 +337,10 @@ &usb3 { status = "okay"; - dwc3@7580000 { - dr_mode = "host"; - }; +}; + +&usb3_dwc3 { + dr_mode = "host"; }; &usb2_phy_prim { diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi index bc446c6002d0..d912166b7552 100644 --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi @@ -529,7 +529,7 @@ }; usb3: usb@7678800 { - compatible = "qcom,dwc3"; + compatible = "qcom,qcs404-dwc3", "qcom,dwc3"; reg = <0x07678800 0x400>; #address-cells = <1>; #size-cells = <1>; @@ -544,7 +544,7 @@ assigned-clock-rates = <19200000>, <200000000>; status = "disabled"; - dwc3@7580000 { + usb3_dwc3: usb@7580000 { compatible = "snps,dwc3"; reg = <0x07580000 0xcd00>; interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; @@ -558,7 +558,7 @@ }; usb2: usb@79b8800 { - compatible = "qcom,dwc3"; + compatible = "qcom,qcs404-dwc3", "qcom,dwc3"; reg = <0x079b8800 0x400>; #address-cells = <1>; #size-cells = <1>; @@ -573,7 +573,7 @@ assigned-clock-rates = <19200000>, <133333333>; status = "disabled"; - dwc3@78c0000 { + usb@78c0000 { compatible = "snps,dwc3"; reg = <0x078c0000 0xcc00>; interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index 82fa009e540f..5dcaac23a138 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -2755,10 +2755,13 @@ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_PRIM_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep"; + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>; @@ -2779,7 +2782,7 @@ <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3 0>; interconnect-names = "usb-ddr", "apps-usb"; - usb_1_dwc3: dwc3@a600000 { + usb_1_dwc3: usb@a600000 { compatible = "snps,dwc3"; reg = <0 0x0a600000 0 0xe000>; interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index f72451f7f539..e66fc67de206 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -3069,10 +3069,13 @@ clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, - <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_SEC_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface","mock_utmi", - "sleep"; + <&gcc GCC_USB30_SEC_SLEEP_CLK>, + <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>; @@ -3102,6 +3105,12 @@ phys = <&usb_2_hsphy>; phy-names = "usb2-phy"; maximum-speed = "high-speed"; + usb-role-switch; + port { + usb2_role_switch: endpoint { + remote-endpoint = <&eud_ep>; + }; + }; }; }; @@ -3194,6 +3203,36 @@ interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>; }; + eud: eud@88e0000 { + compatible = "qcom,sc7280-eud","qcom,eud"; + reg = <0 0x88e0000 0 0x2000>, + <0 0x88e2000 0 0x1000>; + interrupts-extended = <&pdc 11 IRQ_TYPE_LEVEL_HIGH>; + ports { + port@0 { + eud_ep: endpoint { + remote-endpoint = <&usb2_role_switch>; + }; + }; + port@1 { + eud_con: endpoint { + remote-endpoint = <&con_eud>; + }; + }; + }; + }; + + eud_typec: connector { + compatible = "usb-c-connector"; + ports { + port@0 { + con_eud: endpoint { + remote-endpoint = <&eud_con>; + }; + }; + }; + }; + nsp_noc: interconnect@a0c0000 { reg = <0 0x0a0c0000 0 0x10000>; compatible = "qcom,sc7280-nsp-noc"; @@ -3213,21 +3252,26 @@ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_PRIM_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep"; + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 14 IRQ_TYPE_EDGE_BOTH>, + <&pdc 17 IRQ_TYPE_EDGE_BOTH>, <&pdc 15 IRQ_TYPE_EDGE_BOTH>, - <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "hs_phy_irq", "dp_hs_phy_irq", - "dm_hs_phy_irq", "ss_phy_irq"; + <&pdc 14 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq", + "dm_hs_phy_irq", + "dp_hs_phy_irq"; power-domains = <&gcc GCC_USB30_PRIM_GDSC>; diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index 7f875bf9390a..b72e8e6c52f3 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -1215,11 +1215,15 @@ clocks = <&gcc GCC_CFG_NOC_USB3_AXI_CLK>, <&gcc GCC_USB30_MASTER_CLK>, <&gcc GCC_AGGRE2_USB3_AXI_CLK>, - <&rpmcc RPM_SMD_AGGR2_NOC_CLK>, + <&gcc GCC_USB30_SLEEP_CLK>, <&gcc GCC_USB30_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", "bus", - "mock_utmi", "sleep"; + <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "bus"; assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, <&gcc GCC_USB30_MASTER_CLK>, diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 692cf4be4eef..0692ae0e60a4 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3844,10 +3844,13 @@ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_PRIM_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep"; + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>; @@ -3868,7 +3871,7 @@ <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_0 0>; interconnect-names = "usb-ddr", "apps-usb"; - usb_1_dwc3: dwc3@a600000 { + usb_1_dwc3: usb@a600000 { compatible = "snps,dwc3"; reg = <0 0x0a600000 0 0xcd00>; interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>; @@ -3892,10 +3895,13 @@ clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, - <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_SEC_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep"; + <&gcc GCC_USB30_SEC_SLEEP_CLK>, + <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>; @@ -3916,7 +3922,7 @@ <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_1 0>; interconnect-names = "usb-ddr", "apps-usb"; - usb_2_dwc3: dwc3@a800000 { + usb_2_dwc3: usb@a800000 { compatible = "snps,dwc3"; reg = <0 0x0a800000 0 0xcd00>; interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/qcom/sm6125.dtsi b/arch/arm64/boot/dts/qcom/sm6125.dtsi index e81b2a7794fb..135e6e0da27a 100644 --- a/arch/arm64/boot/dts/qcom/sm6125.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6125.dtsi @@ -481,18 +481,24 @@ }; usb3: usb@4ef8800 { - compatible = "qcom,msm8996-dwc3", "qcom,dwc3"; + compatible = "qcom,sm6125-dwc3", "qcom,dwc3"; reg = <0x04ef8800 0x400>; #address-cells = <1>; #size-cells = <1>; ranges; - clocks = <&gcc GCC_USB30_PRIM_MASTER_CLK>, + clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>, <&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>, - <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB3_PRIM_CLKREF_CLK>, <&gcc GCC_USB30_PRIM_SLEEP_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>; diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi index fb1a0f662575..d4f8f33f3f0c 100644 --- a/arch/arm64/boot/dts/qcom/sm6350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi @@ -1034,10 +1034,13 @@ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_PRIM_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep"; + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index f70ae4c56762..8ea44c4b56b4 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3614,11 +3614,15 @@ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB3_SEC_CLKREF_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep", "xo"; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>; @@ -3635,7 +3639,7 @@ resets = <&gcc GCC_USB30_PRIM_BCR>; - usb_1_dwc3: dwc3@a600000 { + usb_1_dwc3: usb@a600000 { compatible = "snps,dwc3"; reg = <0 0x0a600000 0 0xcd00>; interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>; @@ -3659,11 +3663,15 @@ clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, - <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB30_SEC_SLEEP_CLK>, + <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB3_SEC_CLKREF_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep", "xo"; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>; diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index dc2562070336..cf0c97bd5ad3 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -2995,11 +2995,15 @@ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB3_SEC_CLKREF_EN>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep", "xo"; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>; @@ -3046,11 +3050,15 @@ clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, - <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB30_SEC_SLEEP_CLK>, + <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB3_SEC_CLKREF_EN>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep", "xo"; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>; diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index c0137bdcf94b..743cba9b683c 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -2449,10 +2449,13 @@ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_PRIM_SLEEP_CLK>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep"; + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>; @@ -2492,11 +2495,15 @@ clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, - <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB30_SEC_SLEEP_CLK>, + <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB3_SEC_CLKREF_EN>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep", "xo"; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>; diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index 7f52c3cfdfb7..7d08fad76371 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -3107,22 +3107,28 @@ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB3_0_CLKREF_EN>; - clock-names = "cfg_noc", "core", "iface", "mock_utmi", - "sleep", "xo"; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 14 IRQ_TYPE_EDGE_BOTH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, <&pdc 15 IRQ_TYPE_EDGE_BOTH>, - <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "hs_phy_irq", "dp_hs_phy_irq", - "dm_hs_phy_irq", "ss_phy_irq"; + <&pdc 14 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq", + "dm_hs_phy_irq", + "dp_hs_phy_irq"; power-domains = <&gcc USB30_PRIM_GDSC>; diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi index 1cbe2126186e..2dfa67f1cd67 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi @@ -745,10 +745,11 @@ cru: clock-controller@ff500000 { compatible = "rockchip,rk3308-cru"; reg = <0x0 0xff500000 0x0 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; + rockchip,grf = <&grf>; #clock-cells = <1>; #reset-cells = <1>; - rockchip,grf = <&grf>; - assigned-clocks = <&cru SCLK_RTC32K>; assigned-clock-rates = <32768>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi index c99da90328e9..4f0b5feaa5e6 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi @@ -747,6 +747,8 @@ cru: clock-controller@ff760000 { compatible = "rockchip,rk3368-cru"; reg = <0x0 0xff760000 0x0 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; rockchip,grf = <&grf>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts index 141a433429b5..1534e11a9ad1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts @@ -652,8 +652,8 @@ compatible = "brcm,bcm43438-bt"; clocks = <&rk817 1>; clock-names = "lpo"; - device-wake-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>; - host-wake-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>; + device-wakeup-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>; + host-wakeup-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>; shutdown-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>; diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi index 1042e68602de..914f13c0d399 100644 --- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi @@ -397,6 +397,8 @@ cru: clock-controller@fdd20000 { compatible = "rockchip,rk3568-cru"; reg = <0x0 0xfdd20000 0x0 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; #clock-cells = <1>; #reset-cells = <1>; assigned-clocks = <&cru PLL_GPLL>, <&pmucru PLL_PPLL>; diff --git a/arch/arm64/boot/dts/sprd/whale2.dtsi b/arch/arm64/boot/dts/sprd/whale2.dtsi index 79b9591c37aa..89d91abbd5d1 100644 --- a/arch/arm64/boot/dts/sprd/whale2.dtsi +++ b/arch/arm64/boot/dts/sprd/whale2.dtsi @@ -126,7 +126,9 @@ reg = <0 0x20100000 0 0x4000>; interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; #dma-cells = <1>; + /* For backwards compatibility: */ #dma-channels = <32>; + dma-channels = <32>; clock-names = "enable"; clocks = <&apahb_gate CLK_DMA_EB>; }; @@ -272,7 +274,9 @@ compatible = "sprd,sc9860-dma"; reg = <0 0x41580000 0 0x4000>; #dma-cells = <1>; + /* For backwards compatibility: */ #dma-channels = <32>; + dma-channels = <32>; clock-names = "enable", "ashb_eb"; clocks = <&agcp_gate CLK_AGCP_DMAAP_EB>, <&agcp_gate CLK_AGCP_AP_ASHB_EB>; diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index 6328308be272..2e248342476e 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -427,7 +427,7 @@ int swsusp_arch_resume(void) return rc; /* - * We need a zero page that is zero before & after resume in order to + * We need a zero page that is zero before & after resume in order * to break before make on the ttbr1 page tables. */ zero_page = (void *)get_safe_page(GFP_ATOMIC); diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 2f42123e059f..92bcc1768f0b 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -343,9 +343,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) asmlinkage void ret_from_fork(void) asm("ret_from_fork"); -int copy_thread(unsigned long clone_flags, unsigned long stack_start, - unsigned long stk_sz, struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long stack_start = args->stack; + unsigned long tls = args->tls; struct pt_regs *childregs = task_pt_regs(p); memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); @@ -361,7 +363,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, ptrauth_thread_init_kernel(p); - if (likely(!(p->flags & (PF_KTHREAD | PF_IO_WORKER)))) { + if (likely(!args->fn)) { *childregs = *current_pt_regs(); childregs->regs[0] = 0; @@ -399,8 +401,8 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, memset(childregs, 0, sizeof(struct pt_regs)); childregs->pstate = PSR_MODE_EL1h | PSR_IL_BIT; - p->thread.cpu_context.x19 = stack_start; - p->thread.cpu_context.x20 = stk_sz; + p->thread.cpu_context.x19 = (unsigned long)args->fn; + p->thread.cpu_context.x20 = (unsigned long)args->fn_arg; } p->thread.cpu_context.pc = (unsigned long)ret_from_fork; p->thread.cpu_context.sp = (unsigned long)childregs; diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index fea3223704b6..cf3a759f10d4 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -303,13 +303,14 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p) early_fixmap_init(); early_ioremap_init(); - setup_machine_fdt(__fdt_pointer); - /* * Initialise the static keys early as they may be enabled by the - * cpufeature code and early parameters. + * cpufeature code, early parameters, and DT setup. */ jump_label_init(); + + setup_machine_fdt(__fdt_pointer); + parse_early_param(); /* diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index edb2d9206a78..b0980fbb6bc7 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -385,7 +385,7 @@ static int preserve_za_context(struct za_context __user *ctx) return err ? -EFAULT : 0; } -static int restore_za_context(struct user_ctxs __user *user) +static int restore_za_context(struct user_ctxs *user) { int err; unsigned int vq; diff --git a/arch/csky/kernel/process.c b/arch/csky/kernel/process.c index 5de04707aa07..eedddb155669 100644 --- a/arch/csky/kernel/process.c +++ b/arch/csky/kernel/process.c @@ -29,12 +29,11 @@ asmlinkage void ret_from_kernel_thread(void); */ void flush_thread(void){} -int copy_thread(unsigned long clone_flags, - unsigned long usp, - unsigned long kthread_arg, - struct task_struct *p, - unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct switch_stack *childstack; struct pt_regs *childregs = task_pt_regs(p); @@ -48,11 +47,11 @@ int copy_thread(unsigned long clone_flags, /* setup thread.sp for switch_to !!! */ p->thread.sp = (unsigned long)childstack; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { memset(childregs, 0, sizeof(struct pt_regs)); childstack->r15 = (unsigned long) ret_from_kernel_thread; - childstack->r10 = kthread_arg; - childstack->r9 = usp; + childstack->r10 = (unsigned long) args->fn_arg; + childstack->r9 = (unsigned long) args->fn; childregs->sr = mfcr("psr"); } else { *childregs = *(current_pt_regs()); diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c index eab03c691f53..f0552f98a7ba 100644 --- a/arch/hexagon/kernel/process.c +++ b/arch/hexagon/kernel/process.c @@ -50,9 +50,11 @@ void arch_cpu_idle(void) /* * Copy architecture-specific thread state */ -int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, - struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct thread_info *ti = task_thread_info(p); struct hexagon_switch_stack *ss; struct pt_regs *childregs; @@ -73,11 +75,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, sizeof(*ss)); ss->lr = (unsigned long)ret_from_fork; p->thread.switch_sp = ss; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { memset(childregs, 0, sizeof(struct pt_regs)); /* r24 <- fn, r25 <- arg */ - ss->r24 = usp; - ss->r25 = arg; + ss->r24 = (unsigned long)args->fn; + ss->r25 = (unsigned long)args->fn_arg; pt_set_kmode(childregs); return 0; } diff --git a/arch/ia64/include/asm/ptrace.h b/arch/ia64/include/asm/ptrace.h index a10a498eede1..402874489890 100644 --- a/arch/ia64/include/asm/ptrace.h +++ b/arch/ia64/include/asm/ptrace.h @@ -139,10 +139,6 @@ static inline long regs_return_value(struct pt_regs *regs) #define arch_ptrace_stop_needed() \ (!test_thread_flag(TIF_RESTORE_RSE)) - extern void ptrace_attach_sync_user_rbs (struct task_struct *); - #define arch_ptrace_attach(child) \ - ptrace_attach_sync_user_rbs(child) - #define arch_has_single_step() (1) #define arch_has_block_step() (1) diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 89025e3b3f61..416305e550e2 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -296,9 +296,12 @@ ia64_load_extra (struct task_struct *task) * so there is nothing to worry about. */ int -copy_thread(unsigned long clone_flags, unsigned long user_stack_base, - unsigned long user_stack_size, struct task_struct *p, unsigned long tls) +copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long user_stack_base = args->stack; + unsigned long user_stack_size = args->stack_size; + unsigned long tls = args->tls; extern char ia64_ret_from_clone; struct switch_stack *child_stack, *stack; unsigned long rbs, child_rbs, rbs_size; @@ -339,14 +342,14 @@ copy_thread(unsigned long clone_flags, unsigned long user_stack_base, ia64_drop_fpu(p); /* don't pick up stale state from a CPU's fph */ - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { - if (unlikely(!user_stack_base)) { + if (unlikely(args->fn)) { + if (unlikely(args->idle)) { /* fork_idle() called us */ return 0; } memset(child_stack, 0, sizeof(*child_ptregs) + sizeof(*child_stack)); - child_stack->r4 = user_stack_base; /* payload */ - child_stack->r5 = user_stack_size; /* argument */ + child_stack->r4 = (unsigned long) args->fn; + child_stack->r5 = (unsigned long) args->fn_arg; /* * Preserve PSR bits, except for bits 32-34 and 37-45, * which we can't read. diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 4fc6e38a8459..ab8aeb34d1d9 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -618,63 +618,6 @@ void ia64_sync_krbs(void) } /* - * After PTRACE_ATTACH, a thread's register backing store area in user - * space is assumed to contain correct data whenever the thread is - * stopped. arch_ptrace_stop takes care of this on tracing stops. - * But if the child was already stopped for job control when we attach - * to it, then it might not ever get into ptrace_stop by the time we - * want to examine the user memory containing the RBS. - */ -void -ptrace_attach_sync_user_rbs (struct task_struct *child) -{ - int stopped = 0; - struct unw_frame_info info; - - /* - * If the child is in TASK_STOPPED, we need to change that to - * TASK_TRACED momentarily while we operate on it. This ensures - * that the child won't be woken up and return to user mode while - * we are doing the sync. (It can only be woken up for SIGKILL.) - */ - - read_lock(&tasklist_lock); - if (child->sighand) { - spin_lock_irq(&child->sighand->siglock); - if (READ_ONCE(child->__state) == TASK_STOPPED && - !test_and_set_tsk_thread_flag(child, TIF_RESTORE_RSE)) { - set_notify_resume(child); - - WRITE_ONCE(child->__state, TASK_TRACED); - stopped = 1; - } - spin_unlock_irq(&child->sighand->siglock); - } - read_unlock(&tasklist_lock); - - if (!stopped) - return; - - unw_init_from_blocked_task(&info, child); - do_sync_rbs(&info, ia64_sync_user_rbs); - - /* - * Now move the child back into TASK_STOPPED if it should be in a - * job control stop, so that SIGCONT can be used to wake it up. - */ - read_lock(&tasklist_lock); - if (child->sighand) { - spin_lock_irq(&child->sighand->siglock); - if (READ_ONCE(child->__state) == TASK_TRACED && - (child->signal->flags & SIGNAL_STOP_STOPPED)) { - WRITE_ONCE(child->__state, TASK_STOPPED); - } - spin_unlock_irq(&child->sighand->siglock); - } - read_unlock(&tasklist_lock); -} - -/* * Write f32-f127 back to task->thread.fph if it has been modified. */ inline void diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 5010348fa21b..fd6301eafa9d 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -572,7 +572,7 @@ setup_arch (char **cmdline_p) #ifdef CONFIG_ACPI_HOTPLUG_CPU prefill_possible_map(); #endif - per_cpu_scan_finalize((cpumask_weight(&early_cpu_possible_map) == 0 ? + per_cpu_scan_finalize((cpumask_empty(&early_cpu_possible_map) ? 32 : cpumask_weight(&early_cpu_possible_map)), additional_cpus > 0 ? additional_cpus : 0); #endif /* CONFIG_ACPI_NUMA */ diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index d10f780c13b9..d0e935cf2093 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -576,8 +576,6 @@ clear_cpu_sibling_map(int cpu) static void remove_siblinginfo(int cpu) { - int last = 0; - if (cpu_data(cpu)->threads_per_core == 1 && cpu_data(cpu)->cores_per_socket == 1) { cpumask_clear_cpu(cpu, &cpu_core_map[cpu]); @@ -585,8 +583,6 @@ remove_siblinginfo(int cpu) return; } - last = (cpumask_weight(&cpu_core_map[cpu]) == 1 ? 1 : 0); - /* remove it from all sibling map's */ clear_cpu_sibling_map(cpu); } diff --git a/arch/loongarch/Kbuild b/arch/loongarch/Kbuild new file mode 100644 index 000000000000..ab5373d0a24f --- /dev/null +++ b/arch/loongarch/Kbuild @@ -0,0 +1,6 @@ +obj-y += kernel/ +obj-y += mm/ +obj-y += vdso/ + +# for cleaning +subdir- += boot diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig new file mode 100644 index 000000000000..80657bf83b05 --- /dev/null +++ b/arch/loongarch/Kconfig @@ -0,0 +1,438 @@ +# SPDX-License-Identifier: GPL-2.0 +config LOONGARCH + bool + default y + select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI + select ARCH_BINFMT_ELF_STATE + select ARCH_ENABLE_MEMORY_HOTPLUG + select ARCH_ENABLE_MEMORY_HOTREMOVE + select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI + select ARCH_HAS_PHYS_TO_DMA + select ARCH_HAS_PTE_SPECIAL + select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST + select ARCH_INLINE_READ_LOCK if !PREEMPTION + select ARCH_INLINE_READ_LOCK_BH if !PREEMPTION + select ARCH_INLINE_READ_LOCK_IRQ if !PREEMPTION + select ARCH_INLINE_READ_LOCK_IRQSAVE if !PREEMPTION + select ARCH_INLINE_READ_UNLOCK if !PREEMPTION + select ARCH_INLINE_READ_UNLOCK_BH if !PREEMPTION + select ARCH_INLINE_READ_UNLOCK_IRQ if !PREEMPTION + select ARCH_INLINE_READ_UNLOCK_IRQRESTORE if !PREEMPTION + select ARCH_INLINE_WRITE_LOCK if !PREEMPTION + select ARCH_INLINE_WRITE_LOCK_BH if !PREEMPTION + select ARCH_INLINE_WRITE_LOCK_IRQ if !PREEMPTION + select ARCH_INLINE_WRITE_LOCK_IRQSAVE if !PREEMPTION + select ARCH_INLINE_WRITE_UNLOCK if !PREEMPTION + select ARCH_INLINE_WRITE_UNLOCK_BH if !PREEMPTION + select ARCH_INLINE_WRITE_UNLOCK_IRQ if !PREEMPTION + select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE if !PREEMPTION + select ARCH_INLINE_SPIN_TRYLOCK if !PREEMPTION + select ARCH_INLINE_SPIN_TRYLOCK_BH if !PREEMPTION + select ARCH_INLINE_SPIN_LOCK if !PREEMPTION + select ARCH_INLINE_SPIN_LOCK_BH if !PREEMPTION + select ARCH_INLINE_SPIN_LOCK_IRQ if !PREEMPTION + select ARCH_INLINE_SPIN_LOCK_IRQSAVE if !PREEMPTION + select ARCH_INLINE_SPIN_UNLOCK if !PREEMPTION + select ARCH_INLINE_SPIN_UNLOCK_BH if !PREEMPTION + select ARCH_INLINE_SPIN_UNLOCK_IRQ if !PREEMPTION + select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE if !PREEMPTION + select ARCH_MIGHT_HAVE_PC_PARPORT + select ARCH_MIGHT_HAVE_PC_SERIO + select ARCH_SPARSEMEM_ENABLE + select ARCH_SUPPORTS_ACPI + select ARCH_SUPPORTS_ATOMIC_RMW + select ARCH_SUPPORTS_HUGETLBFS + select ARCH_SUPPORTS_NUMA_BALANCING + select ARCH_USE_BUILTIN_BSWAP + select ARCH_USE_CMPXCHG_LOCKREF + select ARCH_USE_QUEUED_RWLOCKS + select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT + select ARCH_WANTS_NO_INSTR + select BUILDTIME_TABLE_SORT + select COMMON_CLK + select GENERIC_CLOCKEVENTS + select GENERIC_CMOS_UPDATE + select GENERIC_CPU_AUTOPROBE + select GENERIC_ENTRY + select GENERIC_FIND_FIRST_BIT + select GENERIC_GETTIMEOFDAY + select GENERIC_IRQ_MULTI_HANDLER + select GENERIC_IRQ_PROBE + select GENERIC_IRQ_SHOW + select GENERIC_LIB_ASHLDI3 + select GENERIC_LIB_ASHRDI3 + select GENERIC_LIB_CMPDI2 + select GENERIC_LIB_LSHRDI3 + select GENERIC_LIB_UCMPDI2 + select GENERIC_PCI_IOMAP + select GENERIC_SCHED_CLOCK + select GENERIC_SMP_IDLE_THREAD + select GENERIC_TIME_VSYSCALL + select GPIOLIB + select HAVE_ARCH_AUDITSYSCALL + select HAVE_ARCH_COMPILER_H + select HAVE_ARCH_MMAP_RND_BITS if MMU + select HAVE_ARCH_SECCOMP_FILTER + select HAVE_ARCH_TRACEHOOK + select HAVE_ARCH_TRANSPARENT_HUGEPAGE + select HAVE_ASM_MODVERSIONS + select HAVE_CONTEXT_TRACKING + select HAVE_COPY_THREAD_TLS + select HAVE_DEBUG_STACKOVERFLOW + select HAVE_DMA_CONTIGUOUS + select HAVE_EXIT_THREAD + select HAVE_FAST_GUP + select HAVE_GENERIC_VDSO + select HAVE_IOREMAP_PROT + select HAVE_IRQ_EXIT_ON_IRQ_STACK + select HAVE_IRQ_TIME_ACCOUNTING + select HAVE_MEMBLOCK + select HAVE_MEMBLOCK_NODE_MAP + select HAVE_MOD_ARCH_SPECIFIC + select HAVE_NMI + select HAVE_PERF_EVENTS + select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RSEQ + select HAVE_SETUP_PER_CPU_AREA if NUMA + select HAVE_SYSCALL_TRACEPOINTS + select HAVE_TIF_NOHZ + select HAVE_VIRT_CPU_ACCOUNTING_GEN if !SMP + select IRQ_FORCED_THREADING + select IRQ_LOONGARCH_CPU + select MODULES_USE_ELF_RELA if MODULES + select NEED_PER_CPU_EMBED_FIRST_CHUNK + select NEED_PER_CPU_PAGE_FIRST_CHUNK + select OF + select OF_EARLY_FLATTREE + select PERF_USE_VMALLOC + select RTC_LIB + select SPARSE_IRQ + select SYSCTL_EXCEPTION_TRACE + select SWIOTLB + select TRACE_IRQFLAGS_SUPPORT + select USE_PERCPU_NUMA_NODE_ID + select ZONE_DMA32 + +config 32BIT + bool + +config 64BIT + def_bool y + +config CPU_HAS_FPU + bool + default y + +config CPU_HAS_PREFETCH + bool + default y + +config GENERIC_CALIBRATE_DELAY + def_bool y + +config GENERIC_CSUM + def_bool y + +config GENERIC_HWEIGHT + def_bool y + +config L1_CACHE_SHIFT + int + default "6" + +config LOCKDEP_SUPPORT + bool + default y + +# MACH_LOONGSON32 and MACH_LOONGSON64 are delibrately carried over from the +# MIPS Loongson code, to preserve Loongson-specific code paths in drivers that +# are shared between architectures, and specifically expecting the symbols. +config MACH_LOONGSON32 + def_bool 32BIT + +config MACH_LOONGSON64 + def_bool 64BIT + +config PAGE_SIZE_4KB + bool + +config PAGE_SIZE_16KB + bool + +config PAGE_SIZE_64KB + bool + +config PGTABLE_2LEVEL + bool + +config PGTABLE_3LEVEL + bool + +config PGTABLE_4LEVEL + bool + +config PGTABLE_LEVELS + int + default 2 if PGTABLE_2LEVEL + default 3 if PGTABLE_3LEVEL + default 4 if PGTABLE_4LEVEL + +config SCHED_OMIT_FRAME_POINTER + bool + default y + +menu "Kernel type and options" + +source "kernel/Kconfig.hz" + +choice + prompt "Page Table Layout" + default 16KB_2LEVEL if 32BIT + default 16KB_3LEVEL if 64BIT + help + Allows choosing the page table layout, which is a combination + of page size and page table levels. The size of virtual memory + address space are determined by the page table layout. + +config 4KB_3LEVEL + bool "4KB with 3 levels" + select PAGE_SIZE_4KB + select PGTABLE_3LEVEL + help + This option selects 4KB page size with 3 level page tables, which + support a maximum of 39 bits of application virtual memory. + +config 4KB_4LEVEL + bool "4KB with 4 levels" + select PAGE_SIZE_4KB + select PGTABLE_4LEVEL + help + This option selects 4KB page size with 4 level page tables, which + support a maximum of 48 bits of application virtual memory. + +config 16KB_2LEVEL + bool "16KB with 2 levels" + select PAGE_SIZE_16KB + select PGTABLE_2LEVEL + help + This option selects 16KB page size with 2 level page tables, which + support a maximum of 36 bits of application virtual memory. + +config 16KB_3LEVEL + bool "16KB with 3 levels" + select PAGE_SIZE_16KB + select PGTABLE_3LEVEL + help + This option selects 16KB page size with 3 level page tables, which + support a maximum of 47 bits of application virtual memory. + +config 64KB_2LEVEL + bool "64KB with 2 levels" + select PAGE_SIZE_64KB + select PGTABLE_2LEVEL + help + This option selects 64KB page size with 2 level page tables, which + support a maximum of 42 bits of application virtual memory. + +config 64KB_3LEVEL + bool "64KB with 3 levels" + select PAGE_SIZE_64KB + select PGTABLE_3LEVEL + help + This option selects 64KB page size with 3 level page tables, which + support a maximum of 55 bits of application virtual memory. + +endchoice + +config CMDLINE + string "Built-in kernel command line" + help + For most platforms, the arguments for the kernel's command line + are provided at run-time, during boot. However, there are cases + where either no arguments are being provided or the provided + arguments are insufficient or even invalid. + + When that occurs, it is possible to define a built-in command + line here and choose how the kernel should use it later on. + +choice + prompt "Kernel command line type" + default CMDLINE_BOOTLOADER + help + Choose how the kernel will handle the provided built-in command + line. + +config CMDLINE_BOOTLOADER + bool "Use bootloader kernel arguments if available" + help + Prefer the command-line passed by the boot loader if available. + Use the built-in command line as fallback in case we get nothing + during boot. This is the default behaviour. + +config CMDLINE_EXTEND + bool "Use built-in to extend bootloader kernel arguments" + help + The command-line arguments provided during boot will be + appended to the built-in command line. This is useful in + cases where the provided arguments are insufficient and + you don't want to or cannot modify them. + +config CMDLINE_FORCE + bool "Always use the built-in kernel command string" + help + Always use the built-in command line, even if we get one during + boot. This is useful in case you need to override the provided + command line on systems where you don't have or want control + over it. + +endchoice + +config DMI + bool "Enable DMI scanning" + select DMI_SCAN_MACHINE_NON_EFI_FALLBACK + default y + help + This enables SMBIOS/DMI feature for systems, and scanning of + DMI to identify machine quirks. + +config EFI + bool "EFI runtime service support" + select UCS2_STRING + select EFI_PARAMS_FROM_FDT + select EFI_RUNTIME_WRAPPERS + help + This enables the kernel to use EFI runtime services that are + available (such as the EFI variable services). + +config SMP + bool "Multi-Processing support" + help + This enables support for systems with more than one CPU. If you have + a system with only one CPU, say N. If you have a system with more + than one CPU, say Y. + + If you say N here, the kernel will run on uni- and multiprocessor + machines, but will use only one CPU of a multiprocessor machine. If + you say Y here, the kernel will run on many, but not all, + uniprocessor machines. On a uniprocessor machine, the kernel + will run faster if you say N here. + + See also the SMP-HOWTO available at <http://www.tldp.org/docs.html#howto>. + + If you don't know what to do here, say N. + +config HOTPLUG_CPU + bool "Support for hot-pluggable CPUs" + depends on SMP + select GENERIC_IRQ_MIGRATION + help + Say Y here to allow turning CPUs off and on. CPUs can be + controlled through /sys/devices/system/cpu. + (Note: power management support will enable this option + automatically on SMP systems. ) + Say N if you want to disable CPU hotplug. + +config NR_CPUS + int "Maximum number of CPUs (2-256)" + range 2 256 + depends on SMP + default "64" + help + This allows you to specify the maximum number of CPUs which this + kernel will support. + +config NUMA + bool "NUMA Support" + select ACPI_NUMA if ACPI + help + Say Y to compile the kernel with NUMA (Non-Uniform Memory Access) + support. This option improves performance on systems with more + than one NUMA node; on single node systems it is generally better + to leave it disabled. + +config NODES_SHIFT + int + default "6" + depends on NUMA + +config FORCE_MAX_ZONEORDER + int "Maximum zone order" + range 14 64 if PAGE_SIZE_64KB + default "14" if PAGE_SIZE_64KB + range 12 64 if PAGE_SIZE_16KB + default "12" if PAGE_SIZE_16KB + range 11 64 + default "11" + help + The kernel memory allocator divides physically contiguous memory + blocks into "zones", where each zone is a power of two number of + pages. This option selects the largest power of two that the kernel + keeps in the memory allocator. If you need to allocate very large + blocks of physically contiguous memory, then you may need to + increase this value. + + This config option is actually maximum order plus one. For example, + a value of 11 means that the largest free memory block is 2^10 pages. + + The page size is not necessarily 4KB. Keep this in mind + when choosing a value for this option. + +config SECCOMP + bool "Enable seccomp to safely compute untrusted bytecode" + depends on PROC_FS + default y + help + This kernel feature is useful for number crunching applications + that may need to compute untrusted bytecode during their + execution. By using pipes or other transports made available to + the process as file descriptors supporting the read/write + syscalls, it's possible to isolate those applications in + their own address space using seccomp. Once seccomp is + enabled via /proc/<pid>/seccomp, it cannot be disabled + and the task is only allowed to execute a few safe syscalls + defined by each seccomp mode. + + If unsure, say Y. Only embedded should say N here. + +endmenu + +config ARCH_SELECT_MEMORY_MODEL + def_bool y + +config ARCH_FLATMEM_ENABLE + def_bool y + depends on !NUMA + +config ARCH_SPARSEMEM_ENABLE + def_bool y + help + Say Y to support efficient handling of sparse physical memory, + for architectures which are either NUMA (Non-Uniform Memory Access) + or have huge holes in the physical address space for other reasons. + See <file:Documentation/vm/numa.rst> for more. + +config ARCH_ENABLE_THP_MIGRATION + def_bool y + depends on TRANSPARENT_HUGEPAGE + +config ARCH_MEMORY_PROBE + def_bool y + depends on MEMORY_HOTPLUG + +config MMU + bool + default y + +config ARCH_MMAP_RND_BITS_MIN + default 12 + +config ARCH_MMAP_RND_BITS_MAX + default 18 + +menu "Power management options" + +source "drivers/acpi/Kconfig" + +endmenu + +source "drivers/firmware/Kconfig" diff --git a/arch/loongarch/Kconfig.debug b/arch/loongarch/Kconfig.debug new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/arch/loongarch/Kconfig.debug diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile new file mode 100644 index 000000000000..fbe4277e6404 --- /dev/null +++ b/arch/loongarch/Makefile @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Huacai Chen <chenhuacai@loongson.cn> +# Copyright (C) 2020-2022 Loongson Technology Corporation Limited + +boot := arch/loongarch/boot + +KBUILD_DEFCONFIG := loongson3_defconfig + +KBUILD_IMAGE = $(boot)/vmlinux + +# +# Select the object file format to substitute into the linker script. +# +64bit-tool-archpref = loongarch64 +32bit-bfd = elf32-loongarch +64bit-bfd = elf64-loongarch +32bit-emul = elf32loongarch +64bit-emul = elf64loongarch + +ifdef CONFIG_64BIT +tool-archpref = $(64bit-tool-archpref) +UTS_MACHINE := loongarch64 +endif + +ifneq ($(SUBARCH),$(ARCH)) + ifeq ($(CROSS_COMPILE),) + CROSS_COMPILE := $(call cc-cross-prefix, $(tool-archpref)-linux- $(tool-archpref)-linux-gnu- $(tool-archpref)-unknown-linux-gnu-) + endif +endif + +ifdef CONFIG_64BIT +ld-emul = $(64bit-emul) +cflags-y += -mabi=lp64s +endif + +cflags-y += -G0 -pipe -msoft-float +LDFLAGS_vmlinux += -G0 -static -n -nostdlib +KBUILD_AFLAGS_KERNEL += -Wa,-mla-global-with-pcrel +KBUILD_CFLAGS_KERNEL += -Wa,-mla-global-with-pcrel +KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs +KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs + +cflags-y += -ffreestanding +cflags-y += $(call cc-option, -mno-check-zero-division) + +load-y = 0x9000000000200000 +bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) + +KBUILD_AFLAGS += $(cflags-y) +KBUILD_CFLAGS += $(cflags-y) +KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y) + +# This is required to get dwarf unwinding tables into .debug_frame +# instead of .eh_frame so we don't discard them. +KBUILD_CFLAGS += -fno-asynchronous-unwind-tables + +# Don't emit unaligned accesses. +# Not all LoongArch cores support unaligned access, and as kernel we can't +# rely on others to provide emulation for these accesses. +KBUILD_CFLAGS += $(call cc-option,-mstrict-align) + +KBUILD_CFLAGS += -isystem $(shell $(CC) -print-file-name=include) + +KBUILD_LDFLAGS += -m $(ld-emul) + +ifdef CONFIG_LOONGARCH +CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \ + egrep -vw '__GNUC_(MINOR_|PATCHLEVEL_)?_' | \ + sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/" -e 's/\$$/&&/g') +endif + +head-y := arch/loongarch/kernel/head.o + +libs-y += arch/loongarch/lib/ + +ifeq ($(KBUILD_EXTMOD),) +prepare: vdso_prepare +vdso_prepare: prepare0 + $(Q)$(MAKE) $(build)=arch/loongarch/vdso include/generated/vdso-offsets.h +endif + +PHONY += vdso_install +vdso_install: + $(Q)$(MAKE) $(build)=arch/loongarch/vdso $@ + +all: $(KBUILD_IMAGE) + +$(KBUILD_IMAGE): vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $@ + +install: + $(Q)install -D -m 755 $(KBUILD_IMAGE) $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE) + $(Q)install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE) + $(Q)install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE) + +define archhelp + echo ' install - install kernel into $(INSTALL_PATH)' + echo +endef diff --git a/arch/arm/mach-pxa/Makefile.boot b/arch/loongarch/boot/.gitignore index bb6e353ecf06..49423ee96ef3 100644 --- a/arch/arm/mach-pxa/Makefile.boot +++ b/arch/loongarch/boot/.gitignore @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only - zreladdr-y += 0xa0008000 - +vmlinux* diff --git a/arch/loongarch/boot/Makefile b/arch/loongarch/boot/Makefile new file mode 100644 index 000000000000..0125b17edc98 --- /dev/null +++ b/arch/loongarch/boot/Makefile @@ -0,0 +1,16 @@ +# +# arch/loongarch/boot/Makefile +# +# Copyright (C) 2020-2022 Loongson Technology Corporation Limited +# + +drop-sections := .comment .note .options .note.gnu.build-id +strip-flags := $(addprefix --remove-section=,$(drop-sections)) -S +OBJCOPYFLAGS_vmlinux.efi := -O binary $(strip-flags) + +targets := vmlinux +quiet_cmd_strip = STRIP $@ + cmd_strip = $(STRIP) -s -o $@ $< + +$(obj)/vmlinux: vmlinux FORCE + $(call if_changed,strip) diff --git a/arch/loongarch/boot/dts/Makefile b/arch/loongarch/boot/dts/Makefile new file mode 100644 index 000000000000..5f1f55e911ad --- /dev/null +++ b/arch/loongarch/boot/dts/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +dtstree := $(srctree)/$(src) + +dtb-y := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts)) diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig new file mode 100644 index 000000000000..eb9149786b6b --- /dev/null +++ b/arch/loongarch/configs/loongson3_defconfig @@ -0,0 +1,771 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_PREEMPT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_NUMA_BALANCING=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SYSFS_DEPRECATED=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_USERFAULTFD=y +CONFIG_PERF_EVENTS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_LOONGARCH=y +CONFIG_64BIT=y +CONFIG_MACH_LOONGSON64=y +CONFIG_DMI=y +CONFIG_EFI=y +CONFIG_SMP=y +CONFIG_HOTPLUG_CPU=y +CONFIG_NR_CPUS=64 +CONFIG_NUMA=y +CONFIG_PAGE_SIZE_16KB=y +CONFIG_HZ_250=y +CONFIG_ACPI=y +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_TAD=y +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_IPMI=m +CONFIG_ACPI_PCI_SLOT=y +CONFIG_ACPI_HOTPLUG_MEMORY=y +CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y +CONFIG_EFI_CAPSULE_LOADER=m +CONFIG_EFI_TEST=m +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_IOSCHED_BFQ=y +CONFIG_BFQ_GROUP_IOSCHED=y +CONFIG_BINFMT_MISC=m +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y +CONFIG_MEMORY_HOTREMOVE=y +CONFIG_KSM=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_ZSWAP=y +CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y +CONFIG_ZPOOL=y +CONFIG_ZBUD=y +CONFIG_Z3FOLD=y +CONFIG_ZSMALLOC=m +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +CONFIG_IP_MROUTE=y +CONFIG_INET_ESP=m +CONFIG_INET_UDP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BBR=m +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_MROUTE=y +CONFIG_NETWORK_PHY_TIMESTAMPING=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_NETDEV=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_TABLES=m +CONFIG_NFT_COUNTER=m +CONFIG_NFT_CONNLIMIT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_NAT=m +CONFIG_NFT_TUNNEL=m +CONFIG_NFT_OBJREF=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m +CONFIG_NETFILTER_XT_SET=m +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CGROUP=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPCOMP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_SET=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_NFCT=y +CONFIG_NF_TABLES_IPV4=y +CONFIG_NFT_DUP_IPV4=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_LOG_ARP=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_NF_TABLES_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_SRH=m +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_SYNPROXY=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_NPT=m +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BPFILTER=y +CONFIG_IP_SCTP=m +CONFIG_RDS=y +CONFIG_L2TP=m +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_CGROUP=m +CONFIG_NET_CLS_BPF=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_BPF=m +CONFIG_OPENVSWITCH=m +CONFIG_NETLINK_DIAG=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_BT=m +CONFIG_BT_HCIBTUSB=m +# CONFIG_BT_HCIBTUSB_BCM is not set +CONFIG_CFG80211=m +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=m +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=y +CONFIG_NET_9P=y +CONFIG_CEPH_LIB=m +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEASPM is not set +CONFIG_PCI_IOV=y +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_SHPC=y +CONFIG_PCCARD=m +CONFIG_YENTA=m +CONFIG_RAPIDIO=y +CONFIG_RAPIDIO_TSI721=y +CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS=y +CONFIG_RAPIDIO_ENUM_BASIC=m +CONFIG_RAPIDIO_CHMAN=m +CONFIG_RAPIDIO_MPORT_CDEV=m +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_MTD=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +CONFIG_PARPORT_SERIAL=y +CONFIG_PARPORT_PC_FIFO=y +CONFIG_ZRAM=m +CONFIG_ZRAM_DEF_COMP_ZSTD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_RBD=m +CONFIG_BLK_DEV_NVME=y +CONFIG_EEPROM_AT24=m +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_ISCSI_TCP=m +CONFIG_SCSI_MVSAS=y +# CONFIG_SCSI_MVSAS_DEBUG is not set +CONFIG_SCSI_MVSAS_TASKLET=y +CONFIG_SCSI_MVUMI=y +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=y +CONFIG_MEGARAID_MAILBOX=y +CONFIG_MEGARAID_LEGACY=y +CONFIG_MEGARAID_SAS=y +CONFIG_SCSI_MPT2SAS=y +CONFIG_LIBFC=m +CONFIG_LIBFCOE=m +CONFIG_FCOE=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_TCM_QLA2XXX=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_PATA_ATIIXP=y +CONFIG_PATA_PCMCIA=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_MULTIPATH=m +CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m +CONFIG_DM_WRITECACHE=m +CONFIG_DM_MIRROR=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +CONFIG_TARGET_CORE=m +CONFIG_TCM_IBLOCK=m +CONFIG_TCM_FILEIO=m +CONFIG_TCM_PSCSI=m +CONFIG_TCM_USER2=m +CONFIG_LOOPBACK_TARGET=m +CONFIG_ISCSI_TARGET=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=y +CONFIG_WIREGUARD=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m +CONFIG_VXLAN=y +CONFIG_RIONET=m +CONFIG_TUN=m +CONFIG_VETH=m +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +CONFIG_BNX2=y +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T3=m +CONFIG_CHELSIO_T4=m +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_E1000=y +CONFIG_E1000E=y +CONFIG_IGB=y +CONFIG_IXGB=y +CONFIG_IXGBE=y +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_R8169=y +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +CONFIG_STMMAC_ETH=y +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_AX88179_178A is not set +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_HUAWEI_CDC_NCM=m +CONFIG_USB_NET_CDC_MBIM=m +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_ARMLINUX is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_ATH9K=m +CONFIG_ATH9K_HTC=m +CONFIG_IWLWIFI=m +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_IWLWIFI_BCAST_FILTERING=y +CONFIG_HOSTAP=m +CONFIG_MT7601U=m +CONFIG_RT2X00=m +CONFIG_RT2800USB=m +CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m +CONFIG_RTL8192DE=m +CONFIG_RTL8723AE=m +CONFIG_RTL8723BE=m +CONFIG_RTL8188EE=m +CONFIG_RTL8192EE=m +CONFIG_RTL8821AE=m +CONFIG_RTL8192CU=m +# CONFIG_RTLWIFI_DEBUG is not set +CONFIG_RTL8XXXU=m +CONFIG_ZD1211RW=m +CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_XTKBD=m +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_MOUSE_PS2_SENTELIC=y +CONFIG_MOUSE_SERIAL=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=m +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_RAW=m +CONFIG_LEGACY_PTY_COUNT=16 +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=16 +CONFIG_SERIAL_8250_RUNTIME_UARTS=16 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_PRINTER=m +CONFIG_IPMI_HANDLER=m +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_HW_RANDOM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_PIIX4=y +CONFIG_I2C_GPIO=y +CONFIG_SPI=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_LOONGSON=y +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_W83795=m +CONFIG_SENSORS_W83627HF=m +CONFIG_RC_CORE=m +CONFIG_LIRC=y +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +CONFIG_IR_IMON_DECODER=m +CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m +CONFIG_MEDIA_PCI_SUPPORT=y +CONFIG_VIDEO_BT848=m +CONFIG_DVB_BT8XX=m +CONFIG_DRM=y +CONFIG_DRM_RADEON=m +CONFIG_DRM_RADEON_USERPTR=y +CONFIG_DRM_AMDGPU=m +CONFIG_DRM_AMDGPU_SI=y +CONFIG_DRM_AMDGPU_CIK=y +CONFIG_DRM_AMDGPU_USERPTR=y +CONFIG_DRM_AST=y +CONFIG_FB=y +CONFIG_FB_EFI=y +CONFIG_FB_RADEON=y +CONFIG_LCD_PLATFORM=m +# CONFIG_VGA_CONSOLE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +# CONFIG_SND_ISA is not set +CONFIG_SND_BT87X=m +CONFIG_SND_BT87X_OVERCLOCK=y +CONFIG_SND_HDA_INTEL=y +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_INPUT_BEEP=y +CONFIG_SND_HDA_PATCH_LOADER=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_HDMI=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_USB_AUDIO=m +CONFIG_HIDRAW=y +CONFIG_UHID=m +CONFIG_HID_A4TECH=m +CONFIG_HID_CHERRY=m +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_DJ=m +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MULTITOUCH=m +CONFIG_HID_SUNPLUS=m +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_OTG=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_REALTEK=m +CONFIG_USB_UAS=m +CONFIG_USB_DWC2=y +CONFIG_USB_DWC2_HOST=y +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_GADGET=y +CONFIG_INFINIBAND=m +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_EFI=y +CONFIG_DMADEVICES=y +CONFIG_UIO=m +CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_UIO_DMEM_GENIRQ=m +CONFIG_UIO_PCI_GENERIC=m +# CONFIG_VIRTIO_MENU is not set +CONFIG_COMEDI=m +CONFIG_COMEDI_PCI_DRIVERS=m +CONFIG_COMEDI_8255_PCI=m +CONFIG_COMEDI_ADL_PCI6208=m +CONFIG_COMEDI_ADL_PCI7X3X=m +CONFIG_COMEDI_ADL_PCI8164=m +CONFIG_COMEDI_ADL_PCI9111=m +CONFIG_COMEDI_ADL_PCI9118=m +CONFIG_COMEDI_ADV_PCI1710=m +CONFIG_COMEDI_ADV_PCI1720=m +CONFIG_COMEDI_ADV_PCI1723=m +CONFIG_COMEDI_ADV_PCI1724=m +CONFIG_COMEDI_ADV_PCI1760=m +CONFIG_COMEDI_ADV_PCI_DIO=m +CONFIG_COMEDI_NI_LABPC_PCI=m +CONFIG_COMEDI_NI_PCIDIO=m +CONFIG_COMEDI_NI_PCIMIO=m +CONFIG_STAGING=y +CONFIG_R8188EU=m +# CONFIG_88EU_AP_MODE is not set +CONFIG_PM_DEVFREQ=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_PWM=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_BTRFS_FS=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=m +CONFIG_OVERLAY_FS=y +CONFIG_OVERLAY_FS_INDEX=y +CONFIG_OVERLAY_FS_XINO_AUTO=y +CONFIG_OVERLAY_FS_METACOPY=y +CONFIG_FSCACHE=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=y +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=936 +CONFIG_FAT_DEFAULT_IOCHARSET="gb2312" +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_CONFIGFS_FS=y +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_CRAMFS=m +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y +CONFIG_NFSD=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_BLOCKLAYOUT=y +CONFIG_CIFS=m +# CONFIG_CIFS_DEBUG is not set +CONFIG_9P_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_936=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_UTF8=y +CONFIG_KEY_DH_OPERATIONS=y +CONFIG_SECURITY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_YAMA=y +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_CRYPTO_USER=m +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +CONFIG_CRYPTO_PCRYPT=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_CHACHA20POLY1305=m +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_LZO=m +CONFIG_CRYPTO_842=m +CONFIG_CRYPTO_LZ4=m +CONFIG_CRYPTO_LZ4HC=m +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_USER_API_RNG=m +CONFIG_CRYPTO_USER_API_AEAD=m +CONFIG_PRINTK_TIME=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set diff --git a/arch/loongarch/include/asm/Kbuild b/arch/loongarch/include/asm/Kbuild new file mode 100644 index 000000000000..83bc0681e72b --- /dev/null +++ b/arch/loongarch/include/asm/Kbuild @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0 +generic-y += dma-contiguous.h +generic-y += export.h +generic-y += parport.h +generic-y += early_ioremap.h +generic-y += qrwlock.h +generic-y += qrwlock_types.h +generic-y += spinlock.h +generic-y += spinlock_types.h +generic-y += rwsem.h +generic-y += segment.h +generic-y += user.h +generic-y += stat.h +generic-y += fcntl.h +generic-y += ioctl.h +generic-y += ioctls.h +generic-y += mman.h +generic-y += msgbuf.h +generic-y += sembuf.h +generic-y += shmbuf.h +generic-y += statfs.h +generic-y += socket.h +generic-y += sockios.h +generic-y += termios.h +generic-y += termbits.h +generic-y += poll.h +generic-y += param.h +generic-y += posix_types.h +generic-y += resource.h +generic-y += kvm_para.h diff --git a/arch/loongarch/include/asm/acenv.h b/arch/loongarch/include/asm/acenv.h new file mode 100644 index 000000000000..52f298f7293b --- /dev/null +++ b/arch/loongarch/include/asm/acenv.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * LoongArch specific ACPICA environments and implementation + * + * Author: Jianmin Lv <lvjianmin@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef _ASM_LOONGARCH_ACENV_H +#define _ASM_LOONGARCH_ACENV_H + +/* + * This header is required by ACPI core, but we have nothing to fill in + * right now. Will be updated later when needed. + */ + +#endif /* _ASM_LOONGARCH_ACENV_H */ diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h new file mode 100644 index 000000000000..62044cd5b7bc --- /dev/null +++ b/arch/loongarch/include/asm/acpi.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Jianmin Lv <lvjianmin@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef _ASM_LOONGARCH_ACPI_H +#define _ASM_LOONGARCH_ACPI_H + +#ifdef CONFIG_ACPI +extern int acpi_strict; +extern int acpi_disabled; +extern int acpi_pci_disabled; +extern int acpi_noirq; + +#define acpi_os_ioremap acpi_os_ioremap +void __init __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size); + +static inline void disable_acpi(void) +{ + acpi_disabled = 1; + acpi_pci_disabled = 1; + acpi_noirq = 1; +} + +static inline bool acpi_has_cpu_in_madt(void) +{ + return true; +} + +extern struct list_head acpi_wakeup_device_list; + +#endif /* !CONFIG_ACPI */ + +#define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT + +#endif /* _ASM_LOONGARCH_ACPI_H */ diff --git a/arch/loongarch/include/asm/addrspace.h b/arch/loongarch/include/asm/addrspace.h new file mode 100644 index 000000000000..b91e0733b2e5 --- /dev/null +++ b/arch/loongarch/include/asm/addrspace.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1996, 99 Ralf Baechle + * Copyright (C) 2000, 2002 Maciej W. Rozycki + * Copyright (C) 1990, 1999 by Silicon Graphics, Inc. + */ +#ifndef _ASM_ADDRSPACE_H +#define _ASM_ADDRSPACE_H + +#include <linux/const.h> + +#include <asm/loongarch.h> + +/* + * This gives the physical RAM offset. + */ +#ifndef __ASSEMBLY__ +#ifndef PHYS_OFFSET +#define PHYS_OFFSET _AC(0, UL) +#endif +extern unsigned long vm_map_base; +#endif /* __ASSEMBLY__ */ + +#ifndef IO_BASE +#define IO_BASE CSR_DMW0_BASE +#endif + +#ifndef CACHE_BASE +#define CACHE_BASE CSR_DMW1_BASE +#endif + +#ifndef UNCACHE_BASE +#define UNCACHE_BASE CSR_DMW0_BASE +#endif + +#define DMW_PABITS 48 +#define TO_PHYS_MASK ((1ULL << DMW_PABITS) - 1) + +/* + * Memory above this physical address will be considered highmem. + */ +#ifndef HIGHMEM_START +#define HIGHMEM_START (_AC(1, UL) << _AC(DMW_PABITS, UL)) +#endif + +#define TO_PHYS(x) ( ((x) & TO_PHYS_MASK)) +#define TO_CACHE(x) (CACHE_BASE | ((x) & TO_PHYS_MASK)) +#define TO_UNCACHE(x) (UNCACHE_BASE | ((x) & TO_PHYS_MASK)) + +/* + * This handles the memory map. + */ +#ifndef PAGE_OFFSET +#define PAGE_OFFSET (CACHE_BASE + PHYS_OFFSET) +#endif + +#ifndef FIXADDR_TOP +#define FIXADDR_TOP ((unsigned long)(long)(int)0xfffe0000) +#endif + +#ifdef __ASSEMBLY__ +#define _ATYPE_ +#define _ATYPE32_ +#define _ATYPE64_ +#define _CONST64_(x) x +#else +#define _ATYPE_ __PTRDIFF_TYPE__ +#define _ATYPE32_ int +#define _ATYPE64_ __s64 +#ifdef CONFIG_64BIT +#define _CONST64_(x) x ## L +#else +#define _CONST64_(x) x ## LL +#endif +#endif + +/* + * 32/64-bit LoongArch address spaces + */ +#ifdef __ASSEMBLY__ +#define _ACAST32_ +#define _ACAST64_ +#else +#define _ACAST32_ (_ATYPE_)(_ATYPE32_) /* widen if necessary */ +#define _ACAST64_ (_ATYPE64_) /* do _not_ narrow */ +#endif + +#ifdef CONFIG_32BIT + +#define UVRANGE 0x00000000 +#define KPRANGE0 0x80000000 +#define KPRANGE1 0xa0000000 +#define KVRANGE 0xc0000000 + +#else + +#define XUVRANGE _CONST64_(0x0000000000000000) +#define XSPRANGE _CONST64_(0x4000000000000000) +#define XKPRANGE _CONST64_(0x8000000000000000) +#define XKVRANGE _CONST64_(0xc000000000000000) + +#endif + +/* + * Returns the physical address of a KPRANGEx / XKPRANGE address + */ +#define PHYSADDR(a) ((_ACAST64_(a)) & TO_PHYS_MASK) + +#endif /* _ASM_ADDRSPACE_H */ diff --git a/arch/loongarch/include/asm/asm-offsets.h b/arch/loongarch/include/asm/asm-offsets.h new file mode 100644 index 000000000000..d9ad88d293e7 --- /dev/null +++ b/arch/loongarch/include/asm/asm-offsets.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <generated/asm-offsets.h> diff --git a/arch/loongarch/include/asm/asm-prototypes.h b/arch/loongarch/include/asm/asm-prototypes.h new file mode 100644 index 000000000000..ed06d3997420 --- /dev/null +++ b/arch/loongarch/include/asm/asm-prototypes.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include <linux/uaccess.h> +#include <asm/fpu.h> +#include <asm/mmu_context.h> +#include <asm/page.h> +#include <asm/ftrace.h> +#include <asm-generic/asm-prototypes.h> diff --git a/arch/loongarch/include/asm/asm.h b/arch/loongarch/include/asm/asm.h new file mode 100644 index 000000000000..40eea6aa469e --- /dev/null +++ b/arch/loongarch/include/asm/asm.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Some useful macros for LoongArch assembler code + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1995, 1996, 1997, 1999, 2001 by Ralf Baechle + * Copyright (C) 1999 by Silicon Graphics, Inc. + * Copyright (C) 2001 MIPS Technologies, Inc. + * Copyright (C) 2002 Maciej W. Rozycki + */ +#ifndef __ASM_ASM_H +#define __ASM_ASM_H + +/* LoongArch pref instruction. */ +#ifdef CONFIG_CPU_HAS_PREFETCH + +#define PREF(hint, addr, offs) \ + preld hint, addr, offs; \ + +#define PREFX(hint, addr, index) \ + preldx hint, addr, index; \ + +#else /* !CONFIG_CPU_HAS_PREFETCH */ + +#define PREF(hint, addr, offs) +#define PREFX(hint, addr, index) + +#endif /* !CONFIG_CPU_HAS_PREFETCH */ + +/* + * Stack alignment + */ +#define STACK_ALIGN ~(0xf) + +/* + * Macros to handle different pointer/register sizes for 32/64-bit code + */ + +/* + * Size of a register + */ +#ifndef __loongarch64 +#define SZREG 4 +#else +#define SZREG 8 +#endif + +/* + * Use the following macros in assemblercode to load/store registers, + * pointers etc. + */ +#if (SZREG == 4) +#define REG_L ld.w +#define REG_S st.w +#define REG_ADD add.w +#define REG_SUB sub.w +#else /* SZREG == 8 */ +#define REG_L ld.d +#define REG_S st.d +#define REG_ADD add.d +#define REG_SUB sub.d +#endif + +/* + * How to add/sub/load/store/shift C int variables. + */ +#if (__SIZEOF_INT__ == 4) +#define INT_ADD add.w +#define INT_ADDI addi.w +#define INT_SUB sub.w +#define INT_L ld.w +#define INT_S st.w +#define INT_SLL slli.w +#define INT_SLLV sll.w +#define INT_SRL srli.w +#define INT_SRLV srl.w +#define INT_SRA srai.w +#define INT_SRAV sra.w +#endif + +#if (__SIZEOF_INT__ == 8) +#define INT_ADD add.d +#define INT_ADDI addi.d +#define INT_SUB sub.d +#define INT_L ld.d +#define INT_S st.d +#define INT_SLL slli.d +#define INT_SLLV sll.d +#define INT_SRL srli.d +#define INT_SRLV srl.d +#define INT_SRA srai.d +#define INT_SRAV sra.d +#endif + +/* + * How to add/sub/load/store/shift C long variables. + */ +#if (__SIZEOF_LONG__ == 4) +#define LONG_ADD add.w +#define LONG_ADDI addi.w +#define LONG_SUB sub.w +#define LONG_L ld.w +#define LONG_S st.w +#define LONG_SLL slli.w +#define LONG_SLLV sll.w +#define LONG_SRL srli.w +#define LONG_SRLV srl.w +#define LONG_SRA srai.w +#define LONG_SRAV sra.w + +#ifdef __ASSEMBLY__ +#define LONG .word +#endif +#define LONGSIZE 4 +#define LONGMASK 3 +#define LONGLOG 2 +#endif + +#if (__SIZEOF_LONG__ == 8) +#define LONG_ADD add.d +#define LONG_ADDI addi.d +#define LONG_SUB sub.d +#define LONG_L ld.d +#define LONG_S st.d +#define LONG_SLL slli.d +#define LONG_SLLV sll.d +#define LONG_SRL srli.d +#define LONG_SRLV srl.d +#define LONG_SRA srai.d +#define LONG_SRAV sra.d + +#ifdef __ASSEMBLY__ +#define LONG .dword +#endif +#define LONGSIZE 8 +#define LONGMASK 7 +#define LONGLOG 3 +#endif + +/* + * How to add/sub/load/store/shift pointers. + */ +#if (__SIZEOF_POINTER__ == 4) +#define PTR_ADD add.w +#define PTR_ADDI addi.w +#define PTR_SUB sub.w +#define PTR_L ld.w +#define PTR_S st.w +#define PTR_LI li.w +#define PTR_SLL slli.w +#define PTR_SLLV sll.w +#define PTR_SRL srli.w +#define PTR_SRLV srl.w +#define PTR_SRA srai.w +#define PTR_SRAV sra.w + +#define PTR_SCALESHIFT 2 + +#ifdef __ASSEMBLY__ +#define PTR .word +#endif +#define PTRSIZE 4 +#define PTRLOG 2 +#endif + +#if (__SIZEOF_POINTER__ == 8) +#define PTR_ADD add.d +#define PTR_ADDI addi.d +#define PTR_SUB sub.d +#define PTR_L ld.d +#define PTR_S st.d +#define PTR_LI li.d +#define PTR_SLL slli.d +#define PTR_SLLV sll.d +#define PTR_SRL srli.d +#define PTR_SRLV srl.d +#define PTR_SRA srai.d +#define PTR_SRAV sra.d + +#define PTR_SCALESHIFT 3 + +#ifdef __ASSEMBLY__ +#define PTR .dword +#endif +#define PTRSIZE 8 +#define PTRLOG 3 +#endif + +#endif /* __ASM_ASM_H */ diff --git a/arch/loongarch/include/asm/asmmacro.h b/arch/loongarch/include/asm/asmmacro.h new file mode 100644 index 000000000000..a1a04083bd67 --- /dev/null +++ b/arch/loongarch/include/asm/asmmacro.h @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_ASMMACRO_H +#define _ASM_ASMMACRO_H + +#include <asm/asm-offsets.h> +#include <asm/regdef.h> +#include <asm/fpregdef.h> +#include <asm/loongarch.h> + + .macro parse_v var val + \var = \val + .endm + + .macro parse_r var r + \var = -1 + .ifc \r, $r0 + \var = 0 + .endif + .ifc \r, $r1 + \var = 1 + .endif + .ifc \r, $r2 + \var = 2 + .endif + .ifc \r, $r3 + \var = 3 + .endif + .ifc \r, $r4 + \var = 4 + .endif + .ifc \r, $r5 + \var = 5 + .endif + .ifc \r, $r6 + \var = 6 + .endif + .ifc \r, $r7 + \var = 7 + .endif + .ifc \r, $r8 + \var = 8 + .endif + .ifc \r, $r9 + \var = 9 + .endif + .ifc \r, $r10 + \var = 10 + .endif + .ifc \r, $r11 + \var = 11 + .endif + .ifc \r, $r12 + \var = 12 + .endif + .ifc \r, $r13 + \var = 13 + .endif + .ifc \r, $r14 + \var = 14 + .endif + .ifc \r, $r15 + \var = 15 + .endif + .ifc \r, $r16 + \var = 16 + .endif + .ifc \r, $r17 + \var = 17 + .endif + .ifc \r, $r18 + \var = 18 + .endif + .ifc \r, $r19 + \var = 19 + .endif + .ifc \r, $r20 + \var = 20 + .endif + .ifc \r, $r21 + \var = 21 + .endif + .ifc \r, $r22 + \var = 22 + .endif + .ifc \r, $r23 + \var = 23 + .endif + .ifc \r, $r24 + \var = 24 + .endif + .ifc \r, $r25 + \var = 25 + .endif + .ifc \r, $r26 + \var = 26 + .endif + .ifc \r, $r27 + \var = 27 + .endif + .ifc \r, $r28 + \var = 28 + .endif + .ifc \r, $r29 + \var = 29 + .endif + .ifc \r, $r30 + \var = 30 + .endif + .ifc \r, $r31 + \var = 31 + .endif + .iflt \var + .error "Unable to parse register name \r" + .endif + .endm + + .macro cpu_save_nonscratch thread + stptr.d s0, \thread, THREAD_REG23 + stptr.d s1, \thread, THREAD_REG24 + stptr.d s2, \thread, THREAD_REG25 + stptr.d s3, \thread, THREAD_REG26 + stptr.d s4, \thread, THREAD_REG27 + stptr.d s5, \thread, THREAD_REG28 + stptr.d s6, \thread, THREAD_REG29 + stptr.d s7, \thread, THREAD_REG30 + stptr.d s8, \thread, THREAD_REG31 + stptr.d sp, \thread, THREAD_REG03 + stptr.d fp, \thread, THREAD_REG22 + .endm + + .macro cpu_restore_nonscratch thread + ldptr.d s0, \thread, THREAD_REG23 + ldptr.d s1, \thread, THREAD_REG24 + ldptr.d s2, \thread, THREAD_REG25 + ldptr.d s3, \thread, THREAD_REG26 + ldptr.d s4, \thread, THREAD_REG27 + ldptr.d s5, \thread, THREAD_REG28 + ldptr.d s6, \thread, THREAD_REG29 + ldptr.d s7, \thread, THREAD_REG30 + ldptr.d s8, \thread, THREAD_REG31 + ldptr.d ra, \thread, THREAD_REG01 + ldptr.d sp, \thread, THREAD_REG03 + ldptr.d fp, \thread, THREAD_REG22 + .endm + + .macro fpu_save_csr thread tmp + movfcsr2gr \tmp, fcsr0 + stptr.w \tmp, \thread, THREAD_FCSR + .endm + + .macro fpu_restore_csr thread tmp + ldptr.w \tmp, \thread, THREAD_FCSR + movgr2fcsr fcsr0, \tmp + .endm + + .macro fpu_save_cc thread tmp0 tmp1 + movcf2gr \tmp0, $fcc0 + move \tmp1, \tmp0 + movcf2gr \tmp0, $fcc1 + bstrins.d \tmp1, \tmp0, 15, 8 + movcf2gr \tmp0, $fcc2 + bstrins.d \tmp1, \tmp0, 23, 16 + movcf2gr \tmp0, $fcc3 + bstrins.d \tmp1, \tmp0, 31, 24 + movcf2gr \tmp0, $fcc4 + bstrins.d \tmp1, \tmp0, 39, 32 + movcf2gr \tmp0, $fcc5 + bstrins.d \tmp1, \tmp0, 47, 40 + movcf2gr \tmp0, $fcc6 + bstrins.d \tmp1, \tmp0, 55, 48 + movcf2gr \tmp0, $fcc7 + bstrins.d \tmp1, \tmp0, 63, 56 + stptr.d \tmp1, \thread, THREAD_FCC + .endm + + .macro fpu_restore_cc thread tmp0 tmp1 + ldptr.d \tmp0, \thread, THREAD_FCC + bstrpick.d \tmp1, \tmp0, 7, 0 + movgr2cf $fcc0, \tmp1 + bstrpick.d \tmp1, \tmp0, 15, 8 + movgr2cf $fcc1, \tmp1 + bstrpick.d \tmp1, \tmp0, 23, 16 + movgr2cf $fcc2, \tmp1 + bstrpick.d \tmp1, \tmp0, 31, 24 + movgr2cf $fcc3, \tmp1 + bstrpick.d \tmp1, \tmp0, 39, 32 + movgr2cf $fcc4, \tmp1 + bstrpick.d \tmp1, \tmp0, 47, 40 + movgr2cf $fcc5, \tmp1 + bstrpick.d \tmp1, \tmp0, 55, 48 + movgr2cf $fcc6, \tmp1 + bstrpick.d \tmp1, \tmp0, 63, 56 + movgr2cf $fcc7, \tmp1 + .endm + + .macro fpu_save_double thread tmp + li.w \tmp, THREAD_FPR0 + PTR_ADD \tmp, \tmp, \thread + fst.d $f0, \tmp, THREAD_FPR0 - THREAD_FPR0 + fst.d $f1, \tmp, THREAD_FPR1 - THREAD_FPR0 + fst.d $f2, \tmp, THREAD_FPR2 - THREAD_FPR0 + fst.d $f3, \tmp, THREAD_FPR3 - THREAD_FPR0 + fst.d $f4, \tmp, THREAD_FPR4 - THREAD_FPR0 + fst.d $f5, \tmp, THREAD_FPR5 - THREAD_FPR0 + fst.d $f6, \tmp, THREAD_FPR6 - THREAD_FPR0 + fst.d $f7, \tmp, THREAD_FPR7 - THREAD_FPR0 + fst.d $f8, \tmp, THREAD_FPR8 - THREAD_FPR0 + fst.d $f9, \tmp, THREAD_FPR9 - THREAD_FPR0 + fst.d $f10, \tmp, THREAD_FPR10 - THREAD_FPR0 + fst.d $f11, \tmp, THREAD_FPR11 - THREAD_FPR0 + fst.d $f12, \tmp, THREAD_FPR12 - THREAD_FPR0 + fst.d $f13, \tmp, THREAD_FPR13 - THREAD_FPR0 + fst.d $f14, \tmp, THREAD_FPR14 - THREAD_FPR0 + fst.d $f15, \tmp, THREAD_FPR15 - THREAD_FPR0 + fst.d $f16, \tmp, THREAD_FPR16 - THREAD_FPR0 + fst.d $f17, \tmp, THREAD_FPR17 - THREAD_FPR0 + fst.d $f18, \tmp, THREAD_FPR18 - THREAD_FPR0 + fst.d $f19, \tmp, THREAD_FPR19 - THREAD_FPR0 + fst.d $f20, \tmp, THREAD_FPR20 - THREAD_FPR0 + fst.d $f21, \tmp, THREAD_FPR21 - THREAD_FPR0 + fst.d $f22, \tmp, THREAD_FPR22 - THREAD_FPR0 + fst.d $f23, \tmp, THREAD_FPR23 - THREAD_FPR0 + fst.d $f24, \tmp, THREAD_FPR24 - THREAD_FPR0 + fst.d $f25, \tmp, THREAD_FPR25 - THREAD_FPR0 + fst.d $f26, \tmp, THREAD_FPR26 - THREAD_FPR0 + fst.d $f27, \tmp, THREAD_FPR27 - THREAD_FPR0 + fst.d $f28, \tmp, THREAD_FPR28 - THREAD_FPR0 + fst.d $f29, \tmp, THREAD_FPR29 - THREAD_FPR0 + fst.d $f30, \tmp, THREAD_FPR30 - THREAD_FPR0 + fst.d $f31, \tmp, THREAD_FPR31 - THREAD_FPR0 + .endm + + .macro fpu_restore_double thread tmp + li.w \tmp, THREAD_FPR0 + PTR_ADD \tmp, \tmp, \thread + fld.d $f0, \tmp, THREAD_FPR0 - THREAD_FPR0 + fld.d $f1, \tmp, THREAD_FPR1 - THREAD_FPR0 + fld.d $f2, \tmp, THREAD_FPR2 - THREAD_FPR0 + fld.d $f3, \tmp, THREAD_FPR3 - THREAD_FPR0 + fld.d $f4, \tmp, THREAD_FPR4 - THREAD_FPR0 + fld.d $f5, \tmp, THREAD_FPR5 - THREAD_FPR0 + fld.d $f6, \tmp, THREAD_FPR6 - THREAD_FPR0 + fld.d $f7, \tmp, THREAD_FPR7 - THREAD_FPR0 + fld.d $f8, \tmp, THREAD_FPR8 - THREAD_FPR0 + fld.d $f9, \tmp, THREAD_FPR9 - THREAD_FPR0 + fld.d $f10, \tmp, THREAD_FPR10 - THREAD_FPR0 + fld.d $f11, \tmp, THREAD_FPR11 - THREAD_FPR0 + fld.d $f12, \tmp, THREAD_FPR12 - THREAD_FPR0 + fld.d $f13, \tmp, THREAD_FPR13 - THREAD_FPR0 + fld.d $f14, \tmp, THREAD_FPR14 - THREAD_FPR0 + fld.d $f15, \tmp, THREAD_FPR15 - THREAD_FPR0 + fld.d $f16, \tmp, THREAD_FPR16 - THREAD_FPR0 + fld.d $f17, \tmp, THREAD_FPR17 - THREAD_FPR0 + fld.d $f18, \tmp, THREAD_FPR18 - THREAD_FPR0 + fld.d $f19, \tmp, THREAD_FPR19 - THREAD_FPR0 + fld.d $f20, \tmp, THREAD_FPR20 - THREAD_FPR0 + fld.d $f21, \tmp, THREAD_FPR21 - THREAD_FPR0 + fld.d $f22, \tmp, THREAD_FPR22 - THREAD_FPR0 + fld.d $f23, \tmp, THREAD_FPR23 - THREAD_FPR0 + fld.d $f24, \tmp, THREAD_FPR24 - THREAD_FPR0 + fld.d $f25, \tmp, THREAD_FPR25 - THREAD_FPR0 + fld.d $f26, \tmp, THREAD_FPR26 - THREAD_FPR0 + fld.d $f27, \tmp, THREAD_FPR27 - THREAD_FPR0 + fld.d $f28, \tmp, THREAD_FPR28 - THREAD_FPR0 + fld.d $f29, \tmp, THREAD_FPR29 - THREAD_FPR0 + fld.d $f30, \tmp, THREAD_FPR30 - THREAD_FPR0 + fld.d $f31, \tmp, THREAD_FPR31 - THREAD_FPR0 + .endm + +.macro not dst src + nor \dst, \src, zero +.endm + +.macro bgt r0 r1 label + blt \r1, \r0, \label +.endm + +.macro bltz r0 label + blt \r0, zero, \label +.endm + +.macro bgez r0 label + bge \r0, zero, \label +.endm + +#endif /* _ASM_ASMMACRO_H */ diff --git a/arch/loongarch/include/asm/atomic.h b/arch/loongarch/include/asm/atomic.h new file mode 100644 index 000000000000..979367ad4e2c --- /dev/null +++ b/arch/loongarch/include/asm/atomic.h @@ -0,0 +1,362 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Atomic operations. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_ATOMIC_H +#define _ASM_ATOMIC_H + +#include <linux/types.h> +#include <asm/barrier.h> +#include <asm/cmpxchg.h> +#include <asm/compiler.h> + +#if __SIZEOF_LONG__ == 4 +#define __LL "ll.w " +#define __SC "sc.w " +#define __AMADD "amadd.w " +#define __AMAND_DB "amand_db.w " +#define __AMOR_DB "amor_db.w " +#define __AMXOR_DB "amxor_db.w " +#elif __SIZEOF_LONG__ == 8 +#define __LL "ll.d " +#define __SC "sc.d " +#define __AMADD "amadd.d " +#define __AMAND_DB "amand_db.d " +#define __AMOR_DB "amor_db.d " +#define __AMXOR_DB "amxor_db.d " +#endif + +#define ATOMIC_INIT(i) { (i) } + +/* + * arch_atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. + */ +#define arch_atomic_read(v) READ_ONCE((v)->counter) + +/* + * arch_atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +#define arch_atomic_set(v, i) WRITE_ONCE((v)->counter, (i)) + +#define ATOMIC_OP(op, I, asm_op) \ +static inline void arch_atomic_##op(int i, atomic_t *v) \ +{ \ + __asm__ __volatile__( \ + "am"#asm_op"_db.w" " $zero, %1, %0 \n" \ + : "+ZB" (v->counter) \ + : "r" (I) \ + : "memory"); \ +} + +#define ATOMIC_OP_RETURN(op, I, asm_op, c_op) \ +static inline int arch_atomic_##op##_return_relaxed(int i, atomic_t *v) \ +{ \ + int result; \ + \ + __asm__ __volatile__( \ + "am"#asm_op"_db.w" " %1, %2, %0 \n" \ + : "+ZB" (v->counter), "=&r" (result) \ + : "r" (I) \ + : "memory"); \ + \ + return result c_op I; \ +} + +#define ATOMIC_FETCH_OP(op, I, asm_op) \ +static inline int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v) \ +{ \ + int result; \ + \ + __asm__ __volatile__( \ + "am"#asm_op"_db.w" " %1, %2, %0 \n" \ + : "+ZB" (v->counter), "=&r" (result) \ + : "r" (I) \ + : "memory"); \ + \ + return result; \ +} + +#define ATOMIC_OPS(op, I, asm_op, c_op) \ + ATOMIC_OP(op, I, asm_op) \ + ATOMIC_OP_RETURN(op, I, asm_op, c_op) \ + ATOMIC_FETCH_OP(op, I, asm_op) + +ATOMIC_OPS(add, i, add, +) +ATOMIC_OPS(sub, -i, add, +) + +#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed +#define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed +#define arch_atomic_fetch_add_relaxed arch_atomic_fetch_add_relaxed +#define arch_atomic_fetch_sub_relaxed arch_atomic_fetch_sub_relaxed + +#undef ATOMIC_OPS + +#define ATOMIC_OPS(op, I, asm_op) \ + ATOMIC_OP(op, I, asm_op) \ + ATOMIC_FETCH_OP(op, I, asm_op) + +ATOMIC_OPS(and, i, and) +ATOMIC_OPS(or, i, or) +ATOMIC_OPS(xor, i, xor) + +#define arch_atomic_fetch_and_relaxed arch_atomic_fetch_and_relaxed +#define arch_atomic_fetch_or_relaxed arch_atomic_fetch_or_relaxed +#define arch_atomic_fetch_xor_relaxed arch_atomic_fetch_xor_relaxed + +#undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + +static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u) +{ + int prev, rc; + + __asm__ __volatile__ ( + "0: ll.w %[p], %[c]\n" + " beq %[p], %[u], 1f\n" + " add.w %[rc], %[p], %[a]\n" + " sc.w %[rc], %[c]\n" + " beqz %[rc], 0b\n" + " b 2f\n" + "1:\n" + __WEAK_LLSC_MB + "2:\n" + : [p]"=&r" (prev), [rc]"=&r" (rc), + [c]"=ZB" (v->counter) + : [a]"r" (a), [u]"r" (u) + : "memory"); + + return prev; +} +#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless + +/* + * arch_atomic_sub_if_positive - conditionally subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically test @v and subtract @i if @v is greater or equal than @i. + * The function returns the old value of @v minus @i. + */ +static inline int arch_atomic_sub_if_positive(int i, atomic_t *v) +{ + int result; + int temp; + + if (__builtin_constant_p(i)) { + __asm__ __volatile__( + "1: ll.w %1, %2 # atomic_sub_if_positive\n" + " addi.w %0, %1, %3 \n" + " or %1, %0, $zero \n" + " blt %0, $zero, 2f \n" + " sc.w %1, %2 \n" + " beq $zero, %1, 1b \n" + "2: \n" + __WEAK_LLSC_MB + : "=&r" (result), "=&r" (temp), + "+" GCC_OFF_SMALL_ASM() (v->counter) + : "I" (-i)); + } else { + __asm__ __volatile__( + "1: ll.w %1, %2 # atomic_sub_if_positive\n" + " sub.w %0, %1, %3 \n" + " or %1, %0, $zero \n" + " blt %0, $zero, 2f \n" + " sc.w %1, %2 \n" + " beq $zero, %1, 1b \n" + "2: \n" + __WEAK_LLSC_MB + : "=&r" (result), "=&r" (temp), + "+" GCC_OFF_SMALL_ASM() (v->counter) + : "r" (i)); + } + + return result; +} + +#define arch_atomic_cmpxchg(v, o, n) (arch_cmpxchg(&((v)->counter), (o), (n))) +#define arch_atomic_xchg(v, new) (arch_xchg(&((v)->counter), (new))) + +/* + * arch_atomic_dec_if_positive - decrement by 1 if old value positive + * @v: pointer of type atomic_t + */ +#define arch_atomic_dec_if_positive(v) arch_atomic_sub_if_positive(1, v) + +#ifdef CONFIG_64BIT + +#define ATOMIC64_INIT(i) { (i) } + +/* + * arch_atomic64_read - read atomic variable + * @v: pointer of type atomic64_t + * + */ +#define arch_atomic64_read(v) READ_ONCE((v)->counter) + +/* + * arch_atomic64_set - set atomic variable + * @v: pointer of type atomic64_t + * @i: required value + */ +#define arch_atomic64_set(v, i) WRITE_ONCE((v)->counter, (i)) + +#define ATOMIC64_OP(op, I, asm_op) \ +static inline void arch_atomic64_##op(long i, atomic64_t *v) \ +{ \ + __asm__ __volatile__( \ + "am"#asm_op"_db.d " " $zero, %1, %0 \n" \ + : "+ZB" (v->counter) \ + : "r" (I) \ + : "memory"); \ +} + +#define ATOMIC64_OP_RETURN(op, I, asm_op, c_op) \ +static inline long arch_atomic64_##op##_return_relaxed(long i, atomic64_t *v) \ +{ \ + long result; \ + __asm__ __volatile__( \ + "am"#asm_op"_db.d " " %1, %2, %0 \n" \ + : "+ZB" (v->counter), "=&r" (result) \ + : "r" (I) \ + : "memory"); \ + \ + return result c_op I; \ +} + +#define ATOMIC64_FETCH_OP(op, I, asm_op) \ +static inline long arch_atomic64_fetch_##op##_relaxed(long i, atomic64_t *v) \ +{ \ + long result; \ + \ + __asm__ __volatile__( \ + "am"#asm_op"_db.d " " %1, %2, %0 \n" \ + : "+ZB" (v->counter), "=&r" (result) \ + : "r" (I) \ + : "memory"); \ + \ + return result; \ +} + +#define ATOMIC64_OPS(op, I, asm_op, c_op) \ + ATOMIC64_OP(op, I, asm_op) \ + ATOMIC64_OP_RETURN(op, I, asm_op, c_op) \ + ATOMIC64_FETCH_OP(op, I, asm_op) + +ATOMIC64_OPS(add, i, add, +) +ATOMIC64_OPS(sub, -i, add, +) + +#define arch_atomic64_add_return_relaxed arch_atomic64_add_return_relaxed +#define arch_atomic64_sub_return_relaxed arch_atomic64_sub_return_relaxed +#define arch_atomic64_fetch_add_relaxed arch_atomic64_fetch_add_relaxed +#define arch_atomic64_fetch_sub_relaxed arch_atomic64_fetch_sub_relaxed + +#undef ATOMIC64_OPS + +#define ATOMIC64_OPS(op, I, asm_op) \ + ATOMIC64_OP(op, I, asm_op) \ + ATOMIC64_FETCH_OP(op, I, asm_op) + +ATOMIC64_OPS(and, i, and) +ATOMIC64_OPS(or, i, or) +ATOMIC64_OPS(xor, i, xor) + +#define arch_atomic64_fetch_and_relaxed arch_atomic64_fetch_and_relaxed +#define arch_atomic64_fetch_or_relaxed arch_atomic64_fetch_or_relaxed +#define arch_atomic64_fetch_xor_relaxed arch_atomic64_fetch_xor_relaxed + +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP + +static inline long arch_atomic64_fetch_add_unless(atomic64_t *v, long a, long u) +{ + long prev, rc; + + __asm__ __volatile__ ( + "0: ll.d %[p], %[c]\n" + " beq %[p], %[u], 1f\n" + " add.d %[rc], %[p], %[a]\n" + " sc.d %[rc], %[c]\n" + " beqz %[rc], 0b\n" + " b 2f\n" + "1:\n" + __WEAK_LLSC_MB + "2:\n" + : [p]"=&r" (prev), [rc]"=&r" (rc), + [c] "=ZB" (v->counter) + : [a]"r" (a), [u]"r" (u) + : "memory"); + + return prev; +} +#define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless + +/* + * arch_atomic64_sub_if_positive - conditionally subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic64_t + * + * Atomically test @v and subtract @i if @v is greater or equal than @i. + * The function returns the old value of @v minus @i. + */ +static inline long arch_atomic64_sub_if_positive(long i, atomic64_t *v) +{ + long result; + long temp; + + if (__builtin_constant_p(i)) { + __asm__ __volatile__( + "1: ll.d %1, %2 # atomic64_sub_if_positive \n" + " addi.d %0, %1, %3 \n" + " or %1, %0, $zero \n" + " blt %0, $zero, 2f \n" + " sc.d %1, %2 \n" + " beq %1, $zero, 1b \n" + "2: \n" + __WEAK_LLSC_MB + : "=&r" (result), "=&r" (temp), + "+" GCC_OFF_SMALL_ASM() (v->counter) + : "I" (-i)); + } else { + __asm__ __volatile__( + "1: ll.d %1, %2 # atomic64_sub_if_positive \n" + " sub.d %0, %1, %3 \n" + " or %1, %0, $zero \n" + " blt %0, $zero, 2f \n" + " sc.d %1, %2 \n" + " beq %1, $zero, 1b \n" + "2: \n" + __WEAK_LLSC_MB + : "=&r" (result), "=&r" (temp), + "+" GCC_OFF_SMALL_ASM() (v->counter) + : "r" (i)); + } + + return result; +} + +#define arch_atomic64_cmpxchg(v, o, n) \ + ((__typeof__((v)->counter))arch_cmpxchg(&((v)->counter), (o), (n))) +#define arch_atomic64_xchg(v, new) (arch_xchg(&((v)->counter), (new))) + +/* + * arch_atomic64_dec_if_positive - decrement by 1 if old value positive + * @v: pointer of type atomic64_t + */ +#define arch_atomic64_dec_if_positive(v) arch_atomic64_sub_if_positive(1, v) + +#endif /* CONFIG_64BIT */ + +#endif /* _ASM_ATOMIC_H */ diff --git a/arch/loongarch/include/asm/barrier.h b/arch/loongarch/include/asm/barrier.h new file mode 100644 index 000000000000..b6517eeeb141 --- /dev/null +++ b/arch/loongarch/include/asm/barrier.h @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_BARRIER_H +#define __ASM_BARRIER_H + +#define __sync() __asm__ __volatile__("dbar 0" : : : "memory") + +#define fast_wmb() __sync() +#define fast_rmb() __sync() +#define fast_mb() __sync() +#define fast_iob() __sync() +#define wbflush() __sync() + +#define wmb() fast_wmb() +#define rmb() fast_rmb() +#define mb() fast_mb() +#define iob() fast_iob() + +#define __smp_mb() __asm__ __volatile__("dbar 0" : : : "memory") +#define __smp_rmb() __asm__ __volatile__("dbar 0" : : : "memory") +#define __smp_wmb() __asm__ __volatile__("dbar 0" : : : "memory") + +#ifdef CONFIG_SMP +#define __WEAK_LLSC_MB " dbar 0 \n" +#else +#define __WEAK_LLSC_MB " \n" +#endif + +#define __smp_mb__before_atomic() barrier() +#define __smp_mb__after_atomic() barrier() + +/** + * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise + * @index: array element index + * @size: number of elements in array + * + * Returns: + * 0 - (@index < @size) + */ +#define array_index_mask_nospec array_index_mask_nospec +static inline unsigned long array_index_mask_nospec(unsigned long index, + unsigned long size) +{ + unsigned long mask; + + __asm__ __volatile__( + "sltu %0, %1, %2\n\t" +#if (__SIZEOF_LONG__ == 4) + "sub.w %0, $r0, %0\n\t" +#elif (__SIZEOF_LONG__ == 8) + "sub.d %0, $r0, %0\n\t" +#endif + : "=r" (mask) + : "r" (index), "r" (size) + :); + + return mask; +} + +#define __smp_load_acquire(p) \ +({ \ + union { typeof(*p) __val; char __c[1]; } __u; \ + unsigned long __tmp = 0; \ + compiletime_assert_atomic_type(*p); \ + switch (sizeof(*p)) { \ + case 1: \ + *(__u8 *)__u.__c = *(volatile __u8 *)p; \ + __smp_mb(); \ + break; \ + case 2: \ + *(__u16 *)__u.__c = *(volatile __u16 *)p; \ + __smp_mb(); \ + break; \ + case 4: \ + __asm__ __volatile__( \ + "amor_db.w %[val], %[tmp], %[mem] \n" \ + : [val] "=&r" (*(__u32 *)__u.__c) \ + : [mem] "ZB" (*(u32 *) p), [tmp] "r" (__tmp) \ + : "memory"); \ + break; \ + case 8: \ + __asm__ __volatile__( \ + "amor_db.d %[val], %[tmp], %[mem] \n" \ + : [val] "=&r" (*(__u64 *)__u.__c) \ + : [mem] "ZB" (*(u64 *) p), [tmp] "r" (__tmp) \ + : "memory"); \ + break; \ + } \ + (typeof(*p))__u.__val; \ +}) + +#define __smp_store_release(p, v) \ +do { \ + union { typeof(*p) __val; char __c[1]; } __u = \ + { .__val = (__force typeof(*p)) (v) }; \ + unsigned long __tmp; \ + compiletime_assert_atomic_type(*p); \ + switch (sizeof(*p)) { \ + case 1: \ + __smp_mb(); \ + *(volatile __u8 *)p = *(__u8 *)__u.__c; \ + break; \ + case 2: \ + __smp_mb(); \ + *(volatile __u16 *)p = *(__u16 *)__u.__c; \ + break; \ + case 4: \ + __asm__ __volatile__( \ + "amswap_db.w %[tmp], %[val], %[mem] \n" \ + : [mem] "+ZB" (*(u32 *)p), [tmp] "=&r" (__tmp) \ + : [val] "r" (*(__u32 *)__u.__c) \ + : ); \ + break; \ + case 8: \ + __asm__ __volatile__( \ + "amswap_db.d %[tmp], %[val], %[mem] \n" \ + : [mem] "+ZB" (*(u64 *)p), [tmp] "=&r" (__tmp) \ + : [val] "r" (*(__u64 *)__u.__c) \ + : ); \ + break; \ + } \ +} while (0) + +#define __smp_store_mb(p, v) \ +do { \ + union { typeof(p) __val; char __c[1]; } __u = \ + { .__val = (__force typeof(p)) (v) }; \ + unsigned long __tmp; \ + switch (sizeof(p)) { \ + case 1: \ + *(volatile __u8 *)&p = *(__u8 *)__u.__c; \ + __smp_mb(); \ + break; \ + case 2: \ + *(volatile __u16 *)&p = *(__u16 *)__u.__c; \ + __smp_mb(); \ + break; \ + case 4: \ + __asm__ __volatile__( \ + "amswap_db.w %[tmp], %[val], %[mem] \n" \ + : [mem] "+ZB" (*(u32 *)&p), [tmp] "=&r" (__tmp) \ + : [val] "r" (*(__u32 *)__u.__c) \ + : ); \ + break; \ + case 8: \ + __asm__ __volatile__( \ + "amswap_db.d %[tmp], %[val], %[mem] \n" \ + : [mem] "+ZB" (*(u64 *)&p), [tmp] "=&r" (__tmp) \ + : [val] "r" (*(__u64 *)__u.__c) \ + : ); \ + break; \ + } \ +} while (0) + +#include <asm-generic/barrier.h> + +#endif /* __ASM_BARRIER_H */ diff --git a/arch/loongarch/include/asm/bitops.h b/arch/loongarch/include/asm/bitops.h new file mode 100644 index 000000000000..69e00f8d8034 --- /dev/null +++ b/arch/loongarch/include/asm/bitops.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_BITOPS_H +#define _ASM_BITOPS_H + +#include <linux/compiler.h> + +#ifndef _LINUX_BITOPS_H +#error only <linux/bitops.h> can be included directly +#endif + +#include <asm/barrier.h> + +#include <asm-generic/bitops/builtin-ffs.h> +#include <asm-generic/bitops/builtin-fls.h> +#include <asm-generic/bitops/builtin-__ffs.h> +#include <asm-generic/bitops/builtin-__fls.h> + +#include <asm-generic/bitops/ffz.h> +#include <asm-generic/bitops/fls64.h> + +#include <asm-generic/bitops/sched.h> +#include <asm-generic/bitops/hweight.h> + +#include <asm-generic/bitops/atomic.h> +#include <asm-generic/bitops/non-atomic.h> +#include <asm-generic/bitops/lock.h> +#include <asm-generic/bitops/le.h> +#include <asm-generic/bitops/ext2-atomic.h> + +#endif /* _ASM_BITOPS_H */ diff --git a/arch/loongarch/include/asm/bitrev.h b/arch/loongarch/include/asm/bitrev.h new file mode 100644 index 000000000000..46f275b9cdf7 --- /dev/null +++ b/arch/loongarch/include/asm/bitrev.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __LOONGARCH_ASM_BITREV_H__ +#define __LOONGARCH_ASM_BITREV_H__ + +#include <linux/swab.h> + +static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x) +{ + u32 ret; + + asm("bitrev.4b %0, %1" : "=r"(ret) : "r"(__swab32(x))); + return ret; +} + +static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x) +{ + u16 ret; + + asm("bitrev.4b %0, %1" : "=r"(ret) : "r"(__swab16(x))); + return ret; +} + +static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x) +{ + u8 ret; + + asm("bitrev.4b %0, %1" : "=r"(ret) : "r"(x)); + return ret; +} + +#endif /* __LOONGARCH_ASM_BITREV_H__ */ diff --git a/arch/loongarch/include/asm/bootinfo.h b/arch/loongarch/include/asm/bootinfo.h new file mode 100644 index 000000000000..9b8d49d9e61b --- /dev/null +++ b/arch/loongarch/include/asm/bootinfo.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_BOOTINFO_H +#define _ASM_BOOTINFO_H + +#include <linux/types.h> +#include <asm/setup.h> + +const char *get_system_type(void); + +extern void init_environ(void); +extern void memblock_init(void); +extern void platform_init(void); +extern void plat_swiotlb_setup(void); +extern int __init init_numa_memory(void); + +struct loongson_board_info { + int bios_size; + const char *bios_vendor; + const char *bios_version; + const char *bios_release_date; + const char *board_name; + const char *board_vendor; +}; + +struct loongson_system_configuration { + int nr_cpus; + int nr_nodes; + int nr_io_pics; + int boot_cpu_id; + int cores_per_node; + int cores_per_package; + const char *cpuname; +}; + +extern u64 efi_system_table; +extern unsigned long fw_arg0, fw_arg1; +extern struct loongson_board_info b_info; +extern struct loongson_system_configuration loongson_sysconf; + +#endif /* _ASM_BOOTINFO_H */ diff --git a/arch/loongarch/include/asm/branch.h b/arch/loongarch/include/asm/branch.h new file mode 100644 index 000000000000..3f33c89f35b4 --- /dev/null +++ b/arch/loongarch/include/asm/branch.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_BRANCH_H +#define _ASM_BRANCH_H + +#include <asm/ptrace.h> + +static inline unsigned long exception_era(struct pt_regs *regs) +{ + return regs->csr_era; +} + +static inline int compute_return_era(struct pt_regs *regs) +{ + regs->csr_era += 4; + return 0; +} + +#endif /* _ASM_BRANCH_H */ diff --git a/arch/loongarch/include/asm/bug.h b/arch/loongarch/include/asm/bug.h new file mode 100644 index 000000000000..bda49108a76d --- /dev/null +++ b/arch/loongarch/include/asm/bug.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_BUG_H +#define __ASM_BUG_H + +#include <linux/compiler.h> + +#ifdef CONFIG_BUG + +#include <asm/break.h> + +static inline void __noreturn BUG(void) +{ + __asm__ __volatile__("break %0" : : "i" (BRK_BUG)); + unreachable(); +} + +#define HAVE_ARCH_BUG + +#endif + +#include <asm-generic/bug.h> + +#endif /* __ASM_BUG_H */ diff --git a/arch/loongarch/include/asm/cache.h b/arch/loongarch/include/asm/cache.h new file mode 100644 index 000000000000..1b6d09617199 --- /dev/null +++ b/arch/loongarch/include/asm/cache.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_CACHE_H +#define _ASM_CACHE_H + +#define L1_CACHE_SHIFT CONFIG_L1_CACHE_SHIFT +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#define __read_mostly __section(".data..read_mostly") + +#endif /* _ASM_CACHE_H */ diff --git a/arch/loongarch/include/asm/cacheflush.h b/arch/loongarch/include/asm/cacheflush.h new file mode 100644 index 000000000000..670900141b7c --- /dev/null +++ b/arch/loongarch/include/asm/cacheflush.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_CACHEFLUSH_H +#define _ASM_CACHEFLUSH_H + +#include <linux/mm.h> +#include <asm/cpu-features.h> +#include <asm/cacheops.h> + +extern void local_flush_icache_range(unsigned long start, unsigned long end); + +#define flush_icache_range local_flush_icache_range +#define flush_icache_user_range local_flush_icache_range + +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 + +#define flush_cache_all() do { } while (0) +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_dup_mm(mm) do { } while (0) +#define flush_cache_range(vma, start, end) do { } while (0) +#define flush_cache_page(vma, vmaddr, pfn) do { } while (0) +#define flush_cache_vmap(start, end) do { } while (0) +#define flush_cache_vunmap(start, end) do { } while (0) +#define flush_icache_page(vma, page) do { } while (0) +#define flush_icache_user_page(vma, page, addr, len) do { } while (0) +#define flush_dcache_page(page) do { } while (0) +#define flush_dcache_mmap_lock(mapping) do { } while (0) +#define flush_dcache_mmap_unlock(mapping) do { } while (0) + +#define cache_op(op, addr) \ + __asm__ __volatile__( \ + " cacop %0, %1 \n" \ + : \ + : "i" (op), "ZC" (*(unsigned char *)(addr))) + +static inline void flush_icache_line_indexed(unsigned long addr) +{ + cache_op(Index_Invalidate_I, addr); +} + +static inline void flush_dcache_line_indexed(unsigned long addr) +{ + cache_op(Index_Writeback_Inv_D, addr); +} + +static inline void flush_vcache_line_indexed(unsigned long addr) +{ + cache_op(Index_Writeback_Inv_V, addr); +} + +static inline void flush_scache_line_indexed(unsigned long addr) +{ + cache_op(Index_Writeback_Inv_S, addr); +} + +static inline void flush_icache_line(unsigned long addr) +{ + cache_op(Hit_Invalidate_I, addr); +} + +static inline void flush_dcache_line(unsigned long addr) +{ + cache_op(Hit_Writeback_Inv_D, addr); +} + +static inline void flush_vcache_line(unsigned long addr) +{ + cache_op(Hit_Writeback_Inv_V, addr); +} + +static inline void flush_scache_line(unsigned long addr) +{ + cache_op(Hit_Writeback_Inv_S, addr); +} + +#include <asm-generic/cacheflush.h> + +#endif /* _ASM_CACHEFLUSH_H */ diff --git a/arch/loongarch/include/asm/cacheops.h b/arch/loongarch/include/asm/cacheops.h new file mode 100644 index 000000000000..dc280efecebd --- /dev/null +++ b/arch/loongarch/include/asm/cacheops.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cache operations for the cache instruction. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_CACHEOPS_H +#define __ASM_CACHEOPS_H + +/* + * Most cache ops are split into a 2 bit field identifying the cache, and a 3 + * bit field identifying the cache operation. + */ +#define CacheOp_Cache 0x03 +#define CacheOp_Op 0x1c + +#define Cache_I 0x00 +#define Cache_D 0x01 +#define Cache_V 0x02 +#define Cache_S 0x03 + +#define Index_Invalidate 0x08 +#define Index_Writeback_Inv 0x08 +#define Hit_Invalidate 0x10 +#define Hit_Writeback_Inv 0x10 +#define CacheOp_User_Defined 0x18 + +#define Index_Invalidate_I (Cache_I | Index_Invalidate) +#define Index_Writeback_Inv_D (Cache_D | Index_Writeback_Inv) +#define Index_Writeback_Inv_V (Cache_V | Index_Writeback_Inv) +#define Index_Writeback_Inv_S (Cache_S | Index_Writeback_Inv) +#define Hit_Invalidate_I (Cache_I | Hit_Invalidate) +#define Hit_Writeback_Inv_D (Cache_D | Hit_Writeback_Inv) +#define Hit_Writeback_Inv_V (Cache_V | Hit_Writeback_Inv) +#define Hit_Writeback_Inv_S (Cache_S | Hit_Writeback_Inv) + +#endif /* __ASM_CACHEOPS_H */ diff --git a/arch/loongarch/include/asm/clocksource.h b/arch/loongarch/include/asm/clocksource.h new file mode 100644 index 000000000000..58e64aa05d26 --- /dev/null +++ b/arch/loongarch/include/asm/clocksource.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_CLOCKSOURCE_H +#define __ASM_CLOCKSOURCE_H + +#include <asm/vdso/clocksource.h> + +#endif /* __ASM_CLOCKSOURCE_H */ diff --git a/arch/loongarch/include/asm/cmpxchg.h b/arch/loongarch/include/asm/cmpxchg.h new file mode 100644 index 000000000000..75b3a4478652 --- /dev/null +++ b/arch/loongarch/include/asm/cmpxchg.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_CMPXCHG_H +#define __ASM_CMPXCHG_H + +#include <asm/barrier.h> +#include <linux/build_bug.h> + +#define __xchg_asm(amswap_db, m, val) \ +({ \ + __typeof(val) __ret; \ + \ + __asm__ __volatile__ ( \ + " "amswap_db" %1, %z2, %0 \n" \ + : "+ZB" (*m), "=&r" (__ret) \ + : "Jr" (val) \ + : "memory"); \ + \ + __ret; \ +}) + +static inline unsigned long __xchg(volatile void *ptr, unsigned long x, + int size) +{ + switch (size) { + case 4: + return __xchg_asm("amswap_db.w", (volatile u32 *)ptr, (u32)x); + + case 8: + return __xchg_asm("amswap_db.d", (volatile u64 *)ptr, (u64)x); + + default: + BUILD_BUG(); + } + + return 0; +} + +#define arch_xchg(ptr, x) \ +({ \ + __typeof__(*(ptr)) __res; \ + \ + __res = (__typeof__(*(ptr))) \ + __xchg((ptr), (unsigned long)(x), sizeof(*(ptr))); \ + \ + __res; \ +}) + +#define __cmpxchg_asm(ld, st, m, old, new) \ +({ \ + __typeof(old) __ret; \ + \ + __asm__ __volatile__( \ + "1: " ld " %0, %2 # __cmpxchg_asm \n" \ + " bne %0, %z3, 2f \n" \ + " or $t0, %z4, $zero \n" \ + " " st " $t0, %1 \n" \ + " beq $zero, $t0, 1b \n" \ + "2: \n" \ + __WEAK_LLSC_MB \ + : "=&r" (__ret), "=ZB"(*m) \ + : "ZB"(*m), "Jr" (old), "Jr" (new) \ + : "t0", "memory"); \ + \ + __ret; \ +}) + +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, + unsigned long new, unsigned int size) +{ + switch (size) { + case 4: + return __cmpxchg_asm("ll.w", "sc.w", (volatile u32 *)ptr, + (u32)old, new); + + case 8: + return __cmpxchg_asm("ll.d", "sc.d", (volatile u64 *)ptr, + (u64)old, new); + + default: + BUILD_BUG(); + } + + return 0; +} + +#define arch_cmpxchg_local(ptr, old, new) \ + ((__typeof__(*(ptr))) \ + __cmpxchg((ptr), \ + (unsigned long)(__typeof__(*(ptr)))(old), \ + (unsigned long)(__typeof__(*(ptr)))(new), \ + sizeof(*(ptr)))) + +#define arch_cmpxchg(ptr, old, new) \ +({ \ + __typeof__(*(ptr)) __res; \ + \ + __res = arch_cmpxchg_local((ptr), (old), (new)); \ + \ + __res; \ +}) + +#ifdef CONFIG_64BIT +#define arch_cmpxchg64_local(ptr, o, n) \ + ({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + arch_cmpxchg_local((ptr), (o), (n)); \ + }) + +#define arch_cmpxchg64(ptr, o, n) \ + ({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + arch_cmpxchg((ptr), (o), (n)); \ + }) +#else +#include <asm-generic/cmpxchg-local.h> +#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n)) +#define arch_cmpxchg64(ptr, o, n) arch_cmpxchg64_local((ptr), (o), (n)) +#endif + +#endif /* __ASM_CMPXCHG_H */ diff --git a/arch/loongarch/include/asm/compiler.h b/arch/loongarch/include/asm/compiler.h new file mode 100644 index 000000000000..657cebe70ace --- /dev/null +++ b/arch/loongarch/include/asm/compiler.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_COMPILER_H +#define _ASM_COMPILER_H + +#define GCC_OFF_SMALL_ASM() "ZC" + +#define LOONGARCH_ISA_LEVEL "loongarch" +#define LOONGARCH_ISA_ARCH_LEVEL "arch=loongarch" +#define LOONGARCH_ISA_LEVEL_RAW loongarch +#define LOONGARCH_ISA_ARCH_LEVEL_RAW LOONGARCH_ISA_LEVEL_RAW + +#endif /* _ASM_COMPILER_H */ diff --git a/arch/loongarch/include/asm/cpu-features.h b/arch/loongarch/include/asm/cpu-features.h new file mode 100644 index 000000000000..a8d87c40a0eb --- /dev/null +++ b/arch/loongarch/include/asm/cpu-features.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 2003, 2004 Ralf Baechle + * Copyright (C) 2004 Maciej W. Rozycki + */ +#ifndef __ASM_CPU_FEATURES_H +#define __ASM_CPU_FEATURES_H + +#include <asm/cpu.h> +#include <asm/cpu-info.h> + +#define cpu_opt(opt) (cpu_data[0].options & (opt)) +#define cpu_has(feat) (cpu_data[0].options & BIT_ULL(feat)) + +#define cpu_has_loongarch (cpu_has_loongarch32 | cpu_has_loongarch64) +#define cpu_has_loongarch32 (cpu_data[0].isa_level & LOONGARCH_CPU_ISA_32BIT) +#define cpu_has_loongarch64 (cpu_data[0].isa_level & LOONGARCH_CPU_ISA_64BIT) + +#define cpu_icache_line_size() cpu_data[0].icache.linesz +#define cpu_dcache_line_size() cpu_data[0].dcache.linesz +#define cpu_vcache_line_size() cpu_data[0].vcache.linesz +#define cpu_scache_line_size() cpu_data[0].scache.linesz + +#ifdef CONFIG_32BIT +# define cpu_has_64bits (cpu_data[0].isa_level & LOONGARCH_CPU_ISA_64BIT) +# define cpu_vabits 31 +# define cpu_pabits 31 +#endif + +#ifdef CONFIG_64BIT +# define cpu_has_64bits 1 +# define cpu_vabits cpu_data[0].vabits +# define cpu_pabits cpu_data[0].pabits +# define __NEED_ADDRBITS_PROBE +#endif + +/* + * SMP assumption: Options of CPU 0 are a superset of all processors. + * This is true for all known LoongArch systems. + */ +#define cpu_has_cpucfg cpu_opt(LOONGARCH_CPU_CPUCFG) +#define cpu_has_lam cpu_opt(LOONGARCH_CPU_LAM) +#define cpu_has_ual cpu_opt(LOONGARCH_CPU_UAL) +#define cpu_has_fpu cpu_opt(LOONGARCH_CPU_FPU) +#define cpu_has_lsx cpu_opt(LOONGARCH_CPU_LSX) +#define cpu_has_lasx cpu_opt(LOONGARCH_CPU_LASX) +#define cpu_has_complex cpu_opt(LOONGARCH_CPU_COMPLEX) +#define cpu_has_crypto cpu_opt(LOONGARCH_CPU_CRYPTO) +#define cpu_has_lvz cpu_opt(LOONGARCH_CPU_LVZ) +#define cpu_has_lbt_x86 cpu_opt(LOONGARCH_CPU_LBT_X86) +#define cpu_has_lbt_arm cpu_opt(LOONGARCH_CPU_LBT_ARM) +#define cpu_has_lbt_mips cpu_opt(LOONGARCH_CPU_LBT_MIPS) +#define cpu_has_lbt (cpu_has_lbt_x86|cpu_has_lbt_arm|cpu_has_lbt_mips) +#define cpu_has_csr cpu_opt(LOONGARCH_CPU_CSR) +#define cpu_has_tlb cpu_opt(LOONGARCH_CPU_TLB) +#define cpu_has_watch cpu_opt(LOONGARCH_CPU_WATCH) +#define cpu_has_vint cpu_opt(LOONGARCH_CPU_VINT) +#define cpu_has_csripi cpu_opt(LOONGARCH_CPU_CSRIPI) +#define cpu_has_extioi cpu_opt(LOONGARCH_CPU_EXTIOI) +#define cpu_has_prefetch cpu_opt(LOONGARCH_CPU_PREFETCH) +#define cpu_has_pmp cpu_opt(LOONGARCH_CPU_PMP) +#define cpu_has_perf cpu_opt(LOONGARCH_CPU_PMP) +#define cpu_has_scalefreq cpu_opt(LOONGARCH_CPU_SCALEFREQ) +#define cpu_has_flatmode cpu_opt(LOONGARCH_CPU_FLATMODE) +#define cpu_has_eiodecode cpu_opt(LOONGARCH_CPU_EIODECODE) +#define cpu_has_guestid cpu_opt(LOONGARCH_CPU_GUESTID) +#define cpu_has_hypervisor cpu_opt(LOONGARCH_CPU_HYPERVISOR) + + +#endif /* __ASM_CPU_FEATURES_H */ diff --git a/arch/loongarch/include/asm/cpu-info.h b/arch/loongarch/include/asm/cpu-info.h new file mode 100644 index 000000000000..b6c4f96079df --- /dev/null +++ b/arch/loongarch/include/asm/cpu-info.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_CPU_INFO_H +#define __ASM_CPU_INFO_H + +#include <linux/cache.h> +#include <linux/types.h> + +#include <asm/loongarch.h> + +/* + * Descriptor for a cache + */ +struct cache_desc { + unsigned int waysize; /* Bytes per way */ + unsigned short sets; /* Number of lines per set */ + unsigned char ways; /* Number of ways */ + unsigned char linesz; /* Size of line in bytes */ + unsigned char waybit; /* Bits to select in a cache set */ + unsigned char flags; /* Flags describing cache properties */ +}; + +struct cpuinfo_loongarch { + u64 asid_cache; + unsigned long asid_mask; + + /* + * Capability and feature descriptor structure for LoongArch CPU + */ + unsigned long long options; + unsigned int processor_id; + unsigned int fpu_vers; + unsigned int fpu_csr0; + unsigned int fpu_mask; + unsigned int cputype; + int isa_level; + int tlbsize; + int tlbsizemtlb; + int tlbsizestlbsets; + int tlbsizestlbways; + struct cache_desc icache; /* Primary I-cache */ + struct cache_desc dcache; /* Primary D or combined I/D cache */ + struct cache_desc vcache; /* Victim cache, between pcache and scache */ + struct cache_desc scache; /* Secondary cache */ + struct cache_desc tcache; /* Tertiary/split secondary cache */ + int core; /* physical core number in package */ + int package;/* physical package number */ + int vabits; /* Virtual Address size in bits */ + int pabits; /* Physical Address size in bits */ + unsigned int ksave_mask; /* Usable KSave mask. */ + unsigned int watch_dreg_count; /* Number data breakpoints */ + unsigned int watch_ireg_count; /* Number instruction breakpoints */ + unsigned int watch_reg_use_cnt; /* min(NUM_WATCH_REGS, watch_dreg_count + watch_ireg_count), Usable by ptrace */ +} __aligned(SMP_CACHE_BYTES); + +extern struct cpuinfo_loongarch cpu_data[]; +#define boot_cpu_data cpu_data[0] +#define current_cpu_data cpu_data[smp_processor_id()] +#define raw_current_cpu_data cpu_data[raw_smp_processor_id()] + +extern void cpu_probe(void); + +extern const char *__cpu_family[]; +extern const char *__cpu_full_name[]; +#define cpu_family_string() __cpu_family[raw_smp_processor_id()] +#define cpu_full_name_string() __cpu_full_name[raw_smp_processor_id()] + +struct seq_file; +struct notifier_block; + +extern int register_proc_cpuinfo_notifier(struct notifier_block *nb); +extern int proc_cpuinfo_notifier_call_chain(unsigned long val, void *v); + +#define proc_cpuinfo_notifier(fn, pri) \ +({ \ + static struct notifier_block fn##_nb = { \ + .notifier_call = fn, \ + .priority = pri \ + }; \ + \ + register_proc_cpuinfo_notifier(&fn##_nb); \ +}) + +struct proc_cpuinfo_notifier_args { + struct seq_file *m; + unsigned long n; +}; + +static inline bool cpus_are_siblings(int cpua, int cpub) +{ + struct cpuinfo_loongarch *infoa = &cpu_data[cpua]; + struct cpuinfo_loongarch *infob = &cpu_data[cpub]; + + if (infoa->package != infob->package) + return false; + + if (infoa->core != infob->core) + return false; + + return true; +} + +static inline unsigned long cpu_asid_mask(struct cpuinfo_loongarch *cpuinfo) +{ + return cpuinfo->asid_mask; +} + +static inline void set_cpu_asid_mask(struct cpuinfo_loongarch *cpuinfo, + unsigned long asid_mask) +{ + cpuinfo->asid_mask = asid_mask; +} + +#endif /* __ASM_CPU_INFO_H */ diff --git a/arch/loongarch/include/asm/cpu.h b/arch/loongarch/include/asm/cpu.h new file mode 100644 index 000000000000..754f28506791 --- /dev/null +++ b/arch/loongarch/include/asm/cpu.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cpu.h: Values of the PRID register used to match up + * various LoongArch CPU types. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_CPU_H +#define _ASM_CPU_H + +/* + * As described in LoongArch specs from Loongson Technology, the PRID register + * (CPUCFG.00) has the following layout: + * + * +---------------+----------------+------------+--------------------+ + * | Reserved | Company ID | Series ID | Product ID | + * +---------------+----------------+------------+--------------------+ + * 31 24 23 16 15 12 11 0 + */ + +/* + * Assigned Company values for bits 23:16 of the PRID register. + */ + +#define PRID_COMP_MASK 0xff0000 + +#define PRID_COMP_LOONGSON 0x140000 + +/* + * Assigned Series ID values for bits 15:12 of the PRID register. In order + * to detect a certain CPU type exactly eventually additional registers may + * need to be examined. + */ + +#define PRID_SERIES_MASK 0xf000 + +#define PRID_SERIES_LA132 0x8000 /* Loongson 32bit */ +#define PRID_SERIES_LA264 0xa000 /* Loongson 64bit, 2-issue */ +#define PRID_SERIES_LA364 0xb000 /* Loongson 64bit,3-issue */ +#define PRID_SERIES_LA464 0xc000 /* Loongson 64bit, 4-issue */ +#define PRID_SERIES_LA664 0xd000 /* Loongson 64bit, 6-issue */ + +/* + * Particular Product ID values for bits 11:0 of the PRID register. + */ + +#define PRID_PRODUCT_MASK 0x0fff + +#if !defined(__ASSEMBLY__) + +enum cpu_type_enum { + CPU_UNKNOWN, + CPU_LOONGSON32, + CPU_LOONGSON64, + CPU_LAST +}; + +#endif /* !__ASSEMBLY */ + +/* + * ISA Level encodings + * + */ + +#define LOONGARCH_CPU_ISA_LA32R 0x00000001 +#define LOONGARCH_CPU_ISA_LA32S 0x00000002 +#define LOONGARCH_CPU_ISA_LA64 0x00000004 + +#define LOONGARCH_CPU_ISA_32BIT (LOONGARCH_CPU_ISA_LA32R | LOONGARCH_CPU_ISA_LA32S) +#define LOONGARCH_CPU_ISA_64BIT LOONGARCH_CPU_ISA_LA64 + +/* + * CPU Option encodings + */ +#define CPU_FEATURE_CPUCFG 0 /* CPU has CPUCFG */ +#define CPU_FEATURE_LAM 1 /* CPU has Atomic instructions */ +#define CPU_FEATURE_UAL 2 /* CPU supports unaligned access */ +#define CPU_FEATURE_FPU 3 /* CPU has FPU */ +#define CPU_FEATURE_LSX 4 /* CPU has LSX (128-bit SIMD) */ +#define CPU_FEATURE_LASX 5 /* CPU has LASX (256-bit SIMD) */ +#define CPU_FEATURE_COMPLEX 6 /* CPU has Complex instructions */ +#define CPU_FEATURE_CRYPTO 7 /* CPU has Crypto instructions */ +#define CPU_FEATURE_LVZ 8 /* CPU has Virtualization extension */ +#define CPU_FEATURE_LBT_X86 9 /* CPU has X86 Binary Translation */ +#define CPU_FEATURE_LBT_ARM 10 /* CPU has ARM Binary Translation */ +#define CPU_FEATURE_LBT_MIPS 11 /* CPU has MIPS Binary Translation */ +#define CPU_FEATURE_TLB 12 /* CPU has TLB */ +#define CPU_FEATURE_CSR 13 /* CPU has CSR */ +#define CPU_FEATURE_WATCH 14 /* CPU has watchpoint registers */ +#define CPU_FEATURE_VINT 15 /* CPU has vectored interrupts */ +#define CPU_FEATURE_CSRIPI 16 /* CPU has CSR-IPI */ +#define CPU_FEATURE_EXTIOI 17 /* CPU has EXT-IOI */ +#define CPU_FEATURE_PREFETCH 18 /* CPU has prefetch instructions */ +#define CPU_FEATURE_PMP 19 /* CPU has perfermance counter */ +#define CPU_FEATURE_SCALEFREQ 20 /* CPU supports cpufreq scaling */ +#define CPU_FEATURE_FLATMODE 21 /* CPU has flat mode */ +#define CPU_FEATURE_EIODECODE 22 /* CPU has EXTIOI interrupt pin decode mode */ +#define CPU_FEATURE_GUESTID 23 /* CPU has GuestID feature */ +#define CPU_FEATURE_HYPERVISOR 24 /* CPU has hypervisor (running in VM) */ + +#define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG) +#define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM) +#define LOONGARCH_CPU_UAL BIT_ULL(CPU_FEATURE_UAL) +#define LOONGARCH_CPU_FPU BIT_ULL(CPU_FEATURE_FPU) +#define LOONGARCH_CPU_LSX BIT_ULL(CPU_FEATURE_LSX) +#define LOONGARCH_CPU_LASX BIT_ULL(CPU_FEATURE_LASX) +#define LOONGARCH_CPU_COMPLEX BIT_ULL(CPU_FEATURE_COMPLEX) +#define LOONGARCH_CPU_CRYPTO BIT_ULL(CPU_FEATURE_CRYPTO) +#define LOONGARCH_CPU_LVZ BIT_ULL(CPU_FEATURE_LVZ) +#define LOONGARCH_CPU_LBT_X86 BIT_ULL(CPU_FEATURE_LBT_X86) +#define LOONGARCH_CPU_LBT_ARM BIT_ULL(CPU_FEATURE_LBT_ARM) +#define LOONGARCH_CPU_LBT_MIPS BIT_ULL(CPU_FEATURE_LBT_MIPS) +#define LOONGARCH_CPU_TLB BIT_ULL(CPU_FEATURE_TLB) +#define LOONGARCH_CPU_CSR BIT_ULL(CPU_FEATURE_CSR) +#define LOONGARCH_CPU_WATCH BIT_ULL(CPU_FEATURE_WATCH) +#define LOONGARCH_CPU_VINT BIT_ULL(CPU_FEATURE_VINT) +#define LOONGARCH_CPU_CSRIPI BIT_ULL(CPU_FEATURE_CSRIPI) +#define LOONGARCH_CPU_EXTIOI BIT_ULL(CPU_FEATURE_EXTIOI) +#define LOONGARCH_CPU_PREFETCH BIT_ULL(CPU_FEATURE_PREFETCH) +#define LOONGARCH_CPU_PMP BIT_ULL(CPU_FEATURE_PMP) +#define LOONGARCH_CPU_SCALEFREQ BIT_ULL(CPU_FEATURE_SCALEFREQ) +#define LOONGARCH_CPU_FLATMODE BIT_ULL(CPU_FEATURE_FLATMODE) +#define LOONGARCH_CPU_EIODECODE BIT_ULL(CPU_FEATURE_EIODECODE) +#define LOONGARCH_CPU_GUESTID BIT_ULL(CPU_FEATURE_GUESTID) +#define LOONGARCH_CPU_HYPERVISOR BIT_ULL(CPU_FEATURE_HYPERVISOR) + +#endif /* _ASM_CPU_H */ diff --git a/arch/loongarch/include/asm/cpufeature.h b/arch/loongarch/include/asm/cpufeature.h new file mode 100644 index 000000000000..4da22a8e63de --- /dev/null +++ b/arch/loongarch/include/asm/cpufeature.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CPU feature definitions for module loading, used by + * module_cpu_feature_match(), see uapi/asm/hwcap.h for LoongArch CPU features. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_CPUFEATURE_H +#define __ASM_CPUFEATURE_H + +#include <uapi/asm/hwcap.h> +#include <asm/elf.h> + +#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap)) + +#define cpu_feature(x) ilog2(HWCAP_ ## x) + +static inline bool cpu_have_feature(unsigned int num) +{ + return elf_hwcap & (1UL << num); +} + +#endif /* __ASM_CPUFEATURE_H */ diff --git a/arch/loongarch/include/asm/delay.h b/arch/loongarch/include/asm/delay.h new file mode 100644 index 000000000000..36d775191310 --- /dev/null +++ b/arch/loongarch/include/asm/delay.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_DELAY_H +#define _ASM_DELAY_H + +#include <linux/param.h> + +extern void __delay(unsigned long cycles); +extern void __ndelay(unsigned long ns); +extern void __udelay(unsigned long us); + +#define ndelay(ns) __ndelay(ns) +#define udelay(us) __udelay(us) + +/* make sure "usecs *= ..." in udelay do not overflow. */ +#if HZ >= 1000 +#define MAX_UDELAY_MS 1 +#elif HZ <= 200 +#define MAX_UDELAY_MS 5 +#else +#define MAX_UDELAY_MS (1000 / HZ) +#endif + +#endif /* _ASM_DELAY_H */ diff --git a/arch/loongarch/include/asm/dma-direct.h b/arch/loongarch/include/asm/dma-direct.h new file mode 100644 index 000000000000..75ccd808a2af --- /dev/null +++ b/arch/loongarch/include/asm/dma-direct.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _LOONGARCH_DMA_DIRECT_H +#define _LOONGARCH_DMA_DIRECT_H + +dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); +phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr); + +#endif /* _LOONGARCH_DMA_DIRECT_H */ diff --git a/arch/loongarch/include/asm/dmi.h b/arch/loongarch/include/asm/dmi.h new file mode 100644 index 000000000000..605493417753 --- /dev/null +++ b/arch/loongarch/include/asm/dmi.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_DMI_H +#define _ASM_DMI_H + +#include <linux/io.h> +#include <linux/memblock.h> + +#define dmi_early_remap(x, l) dmi_remap(x, l) +#define dmi_early_unmap(x, l) dmi_unmap(x) +#define dmi_alloc(l) memblock_alloc(l, PAGE_SIZE) + +static inline void *dmi_remap(u64 phys_addr, unsigned long size) +{ + return ((void *)TO_CACHE(phys_addr)); +} + +static inline void dmi_unmap(void *addr) +{ +} + +#endif /* _ASM_DMI_H */ diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h new file mode 100644 index 000000000000..0127d84d5e1d --- /dev/null +++ b/arch/loongarch/include/asm/efi.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_LOONGARCH_EFI_H +#define _ASM_LOONGARCH_EFI_H + +#include <linux/efi.h> + +void __init efi_init(void); +void __init efi_runtime_init(void); +void efifb_setup_from_dmi(struct screen_info *si, const char *opt); + +#define ARCH_EFI_IRQ_FLAGS_MASK 0x00000004 /* Bit 2: CSR.CRMD.IE */ + +#define arch_efi_call_virt_setup() \ +({ \ +}) + +#define arch_efi_call_virt(p, f, args...) \ +({ \ + efi_##f##_t * __f; \ + __f = p->f; \ + __f(args); \ +}) + +#define arch_efi_call_virt_teardown() \ +({ \ +}) + +#define EFI_ALLOC_ALIGN SZ_64K + +struct screen_info *alloc_screen_info(void); +void free_screen_info(struct screen_info *si); + +static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr) +{ + return ULONG_MAX; +} + +#endif /* _ASM_LOONGARCH_EFI_H */ diff --git a/arch/loongarch/include/asm/elf.h b/arch/loongarch/include/asm/elf.h new file mode 100644 index 000000000000..f3960b18a90e --- /dev/null +++ b/arch/loongarch/include/asm/elf.h @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_ELF_H +#define _ASM_ELF_H + +#include <linux/auxvec.h> +#include <linux/fs.h> +#include <uapi/linux/elf.h> + +#include <asm/current.h> +#include <asm/vdso.h> + +/* The ABI of a file. */ +#define EF_LOONGARCH_ABI_LP64_SOFT_FLOAT 0x1 +#define EF_LOONGARCH_ABI_LP64_SINGLE_FLOAT 0x2 +#define EF_LOONGARCH_ABI_LP64_DOUBLE_FLOAT 0x3 + +#define EF_LOONGARCH_ABI_ILP32_SOFT_FLOAT 0x5 +#define EF_LOONGARCH_ABI_ILP32_SINGLE_FLOAT 0x6 +#define EF_LOONGARCH_ABI_ILP32_DOUBLE_FLOAT 0x7 + +/* LoongArch relocation types used by the dynamic linker */ +#define R_LARCH_NONE 0 +#define R_LARCH_32 1 +#define R_LARCH_64 2 +#define R_LARCH_RELATIVE 3 +#define R_LARCH_COPY 4 +#define R_LARCH_JUMP_SLOT 5 +#define R_LARCH_TLS_DTPMOD32 6 +#define R_LARCH_TLS_DTPMOD64 7 +#define R_LARCH_TLS_DTPREL32 8 +#define R_LARCH_TLS_DTPREL64 9 +#define R_LARCH_TLS_TPREL32 10 +#define R_LARCH_TLS_TPREL64 11 +#define R_LARCH_IRELATIVE 12 +#define R_LARCH_MARK_LA 20 +#define R_LARCH_MARK_PCREL 21 +#define R_LARCH_SOP_PUSH_PCREL 22 +#define R_LARCH_SOP_PUSH_ABSOLUTE 23 +#define R_LARCH_SOP_PUSH_DUP 24 +#define R_LARCH_SOP_PUSH_GPREL 25 +#define R_LARCH_SOP_PUSH_TLS_TPREL 26 +#define R_LARCH_SOP_PUSH_TLS_GOT 27 +#define R_LARCH_SOP_PUSH_TLS_GD 28 +#define R_LARCH_SOP_PUSH_PLT_PCREL 29 +#define R_LARCH_SOP_ASSERT 30 +#define R_LARCH_SOP_NOT 31 +#define R_LARCH_SOP_SUB 32 +#define R_LARCH_SOP_SL 33 +#define R_LARCH_SOP_SR 34 +#define R_LARCH_SOP_ADD 35 +#define R_LARCH_SOP_AND 36 +#define R_LARCH_SOP_IF_ELSE 37 +#define R_LARCH_SOP_POP_32_S_10_5 38 +#define R_LARCH_SOP_POP_32_U_10_12 39 +#define R_LARCH_SOP_POP_32_S_10_12 40 +#define R_LARCH_SOP_POP_32_S_10_16 41 +#define R_LARCH_SOP_POP_32_S_10_16_S2 42 +#define R_LARCH_SOP_POP_32_S_5_20 43 +#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44 +#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45 +#define R_LARCH_SOP_POP_32_U 46 +#define R_LARCH_ADD8 47 +#define R_LARCH_ADD16 48 +#define R_LARCH_ADD24 49 +#define R_LARCH_ADD32 50 +#define R_LARCH_ADD64 51 +#define R_LARCH_SUB8 52 +#define R_LARCH_SUB16 53 +#define R_LARCH_SUB24 54 +#define R_LARCH_SUB32 55 +#define R_LARCH_SUB64 56 +#define R_LARCH_GNU_VTINHERIT 57 +#define R_LARCH_GNU_VTENTRY 58 + +#ifndef ELF_ARCH + +/* ELF register definitions */ + +/* + * General purpose have the following registers: + * Register Number + * GPRs 32 + * ORIG_A0 1 + * ERA 1 + * BADVADDR 1 + * CRMD 1 + * PRMD 1 + * EUEN 1 + * ECFG 1 + * ESTAT 1 + * Reserved 5 + */ +#define ELF_NGREG 45 + +/* + * Floating point have the following registers: + * Register Number + * FPR 32 + * FCC 1 + * FCSR 1 + */ +#define ELF_NFPREG 34 + +typedef unsigned long elf_greg_t; +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef double elf_fpreg_t; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +void loongarch_dump_regs64(u64 *uregs, const struct pt_regs *regs); + +#ifdef CONFIG_32BIT +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch elf32_check_arch + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 + +#define ELF_CORE_COPY_REGS(dest, regs) \ + loongarch_dump_regs32((u32 *)&(dest), (regs)); + +#endif /* CONFIG_32BIT */ + +#ifdef CONFIG_64BIT +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch elf64_check_arch + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS64 + +#define ELF_CORE_COPY_REGS(dest, regs) \ + loongarch_dump_regs64((u64 *)&(dest), (regs)); + +#endif /* CONFIG_64BIT */ + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_LOONGARCH + +#endif /* !defined(ELF_ARCH) */ + +#define loongarch_elf_check_machine(x) ((x)->e_machine == EM_LOONGARCH) + +#define vmcore_elf32_check_arch loongarch_elf_check_machine +#define vmcore_elf64_check_arch loongarch_elf_check_machine + +/* + * Return non-zero if HDR identifies an 32bit ELF binary. + */ +#define elf32_check_arch(hdr) \ +({ \ + int __res = 1; \ + struct elfhdr *__h = (hdr); \ + \ + if (!loongarch_elf_check_machine(__h)) \ + __res = 0; \ + if (__h->e_ident[EI_CLASS] != ELFCLASS32) \ + __res = 0; \ + \ + __res; \ +}) + +/* + * Return non-zero if HDR identifies an 64bit ELF binary. + */ +#define elf64_check_arch(hdr) \ +({ \ + int __res = 1; \ + struct elfhdr *__h = (hdr); \ + \ + if (!loongarch_elf_check_machine(__h)) \ + __res = 0; \ + if (__h->e_ident[EI_CLASS] != ELFCLASS64) \ + __res = 0; \ + \ + __res; \ +}) + +#ifdef CONFIG_32BIT + +#define SET_PERSONALITY2(ex, state) \ +do { \ + current->thread.vdso = &vdso_info; \ + \ + loongarch_set_personality_fcsr(state); \ + \ + if (personality(current->personality) != PER_LINUX) \ + set_personality(PER_LINUX); \ +} while (0) + +#endif /* CONFIG_32BIT */ + +#ifdef CONFIG_64BIT + +#define SET_PERSONALITY2(ex, state) \ +do { \ + unsigned int p; \ + \ + clear_thread_flag(TIF_32BIT_REGS); \ + clear_thread_flag(TIF_32BIT_ADDR); \ + \ + current->thread.vdso = &vdso_info; \ + loongarch_set_personality_fcsr(state); \ + \ + p = personality(current->personality); \ + if (p != PER_LINUX32 && p != PER_LINUX) \ + set_personality(PER_LINUX); \ +} while (0) + +#endif /* CONFIG_64BIT */ + +#define CORE_DUMP_USE_REGSET +#define ELF_EXEC_PAGESIZE PAGE_SIZE + +/* + * This yields a mask that user programs can use to figure out what + * instruction set this cpu supports. This could be done in userspace, + * but it's not easy, and we've already done it here. + */ + +#define ELF_HWCAP (elf_hwcap) +extern unsigned int elf_hwcap; +#include <asm/hwcap.h> + +/* + * This yields a string that ld.so will use to load implementation + * specific libraries for optimization. This is more specific in + * intent than poking at uname or /proc/cpuinfo. + */ + +#define ELF_PLATFORM __elf_platform +extern const char *__elf_platform; + +#define ELF_PLAT_INIT(_r, load_addr) do { \ + _r->regs[1] = _r->regs[2] = _r->regs[3] = _r->regs[4] = 0; \ + _r->regs[5] = _r->regs[6] = _r->regs[7] = _r->regs[8] = 0; \ + _r->regs[9] = _r->regs[10] = _r->regs[11] = _r->regs[12] = 0; \ + _r->regs[13] = _r->regs[14] = _r->regs[15] = _r->regs[16] = 0; \ + _r->regs[17] = _r->regs[18] = _r->regs[19] = _r->regs[20] = 0; \ + _r->regs[21] = _r->regs[22] = _r->regs[23] = _r->regs[24] = 0; \ + _r->regs[25] = _r->regs[26] = _r->regs[27] = _r->regs[28] = 0; \ + _r->regs[29] = _r->regs[30] = _r->regs[31] = 0; \ +} while (0) + +/* + * This is the location that an ET_DYN program is loaded if exec'ed. Typical + * use of this is to invoke "./ld.so someprog" to test out a new version of + * the loader. We need to make sure that it is out of the way of the program + * that it will "exec", and that there is sufficient room for the brk. + */ + +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) + +/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */ +#define ARCH_DLINFO \ +do { \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, \ + (unsigned long)current->mm->context.vdso); \ +} while (0) + +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 +struct linux_binprm; +extern int arch_setup_additional_pages(struct linux_binprm *bprm, + int uses_interp); + +struct arch_elf_state { + int fp_abi; + int interp_fp_abi; +}; + +#define LOONGARCH_ABI_FP_ANY (0) + +#define INIT_ARCH_ELF_STATE { \ + .fp_abi = LOONGARCH_ABI_FP_ANY, \ + .interp_fp_abi = LOONGARCH_ABI_FP_ANY, \ +} + +#define elf_read_implies_exec(ex, exec_stk) (exec_stk == EXSTACK_DEFAULT) + +extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf, + bool is_interp, struct arch_elf_state *state); + +extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr, + struct arch_elf_state *state); + +extern void loongarch_set_personality_fcsr(struct arch_elf_state *state); + +#endif /* _ASM_ELF_H */ diff --git a/arch/loongarch/include/asm/entry-common.h b/arch/loongarch/include/asm/entry-common.h new file mode 100644 index 000000000000..0fe2a098ded9 --- /dev/null +++ b/arch/loongarch/include/asm/entry-common.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef ARCH_LOONGARCH_ENTRY_COMMON_H +#define ARCH_LOONGARCH_ENTRY_COMMON_H + +#include <linux/sched.h> +#include <linux/processor.h> + +static inline bool on_thread_stack(void) +{ + return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); +} + +#endif diff --git a/arch/loongarch/include/asm/exec.h b/arch/loongarch/include/asm/exec.h new file mode 100644 index 000000000000..ba0220812ebb --- /dev/null +++ b/arch/loongarch/include/asm/exec.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_EXEC_H +#define _ASM_EXEC_H + +extern unsigned long arch_align_stack(unsigned long sp); + +#endif /* _ASM_EXEC_H */ diff --git a/arch/loongarch/include/asm/fb.h b/arch/loongarch/include/asm/fb.h new file mode 100644 index 000000000000..3116bde8772d --- /dev/null +++ b/arch/loongarch/include/asm/fb.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_FB_H_ +#define _ASM_FB_H_ + +#include <linux/fb.h> +#include <linux/fs.h> +#include <asm/page.h> + +static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, + unsigned long off) +{ + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +} + +static inline int fb_is_primary_device(struct fb_info *info) +{ + return 0; +} + +#endif /* _ASM_FB_H_ */ diff --git a/arch/loongarch/include/asm/fixmap.h b/arch/loongarch/include/asm/fixmap.h new file mode 100644 index 000000000000..b3541dfa2013 --- /dev/null +++ b/arch/loongarch/include/asm/fixmap.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * fixmap.h: compile-time virtual memory allocation + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef _ASM_FIXMAP_H +#define _ASM_FIXMAP_H + +#define NR_FIX_BTMAPS 64 + +#endif diff --git a/arch/loongarch/include/asm/fpregdef.h b/arch/loongarch/include/asm/fpregdef.h new file mode 100644 index 000000000000..adb16e4b43b0 --- /dev/null +++ b/arch/loongarch/include/asm/fpregdef.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Definitions for the FPU register names + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_FPREGDEF_H +#define _ASM_FPREGDEF_H + +#define fa0 $f0 /* argument registers, fa0/fa1 reused as fv0/fv1 for return value */ +#define fa1 $f1 +#define fa2 $f2 +#define fa3 $f3 +#define fa4 $f4 +#define fa5 $f5 +#define fa6 $f6 +#define fa7 $f7 +#define ft0 $f8 /* caller saved */ +#define ft1 $f9 +#define ft2 $f10 +#define ft3 $f11 +#define ft4 $f12 +#define ft5 $f13 +#define ft6 $f14 +#define ft7 $f15 +#define ft8 $f16 +#define ft9 $f17 +#define ft10 $f18 +#define ft11 $f19 +#define ft12 $f20 +#define ft13 $f21 +#define ft14 $f22 +#define ft15 $f23 +#define fs0 $f24 /* callee saved */ +#define fs1 $f25 +#define fs2 $f26 +#define fs3 $f27 +#define fs4 $f28 +#define fs5 $f29 +#define fs6 $f30 +#define fs7 $f31 + +/* + * Current binutils expects *GPRs* at FCSR position for the FCSR + * operation instructions, so define aliases for those used. + */ +#define fcsr0 $r0 +#define fcsr1 $r1 +#define fcsr2 $r2 +#define fcsr3 $r3 +#define vcsr16 $r16 + +#endif /* _ASM_FPREGDEF_H */ diff --git a/arch/loongarch/include/asm/fpu.h b/arch/loongarch/include/asm/fpu.h new file mode 100644 index 000000000000..358b254d9c1d --- /dev/null +++ b/arch/loongarch/include/asm/fpu.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_FPU_H +#define _ASM_FPU_H + +#include <linux/sched.h> +#include <linux/sched/task_stack.h> +#include <linux/ptrace.h> +#include <linux/thread_info.h> +#include <linux/bitops.h> + +#include <asm/cpu.h> +#include <asm/cpu-features.h> +#include <asm/current.h> +#include <asm/loongarch.h> +#include <asm/processor.h> +#include <asm/ptrace.h> + +struct sigcontext; + +extern void _init_fpu(unsigned int); +extern void _save_fp(struct loongarch_fpu *); +extern void _restore_fp(struct loongarch_fpu *); + +/* + * Mask the FCSR Cause bits according to the Enable bits, observing + * that Unimplemented is always enabled. + */ +static inline unsigned long mask_fcsr_x(unsigned long fcsr) +{ + return fcsr & ((fcsr & FPU_CSR_ALL_E) << + (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E))); +} + +static inline int is_fp_enabled(void) +{ + return (csr_read32(LOONGARCH_CSR_EUEN) & CSR_EUEN_FPEN) ? + 1 : 0; +} + +#define enable_fpu() set_csr_euen(CSR_EUEN_FPEN) + +#define disable_fpu() clear_csr_euen(CSR_EUEN_FPEN) + +#define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU) + +static inline int is_fpu_owner(void) +{ + return test_thread_flag(TIF_USEDFPU); +} + +static inline void __own_fpu(void) +{ + enable_fpu(); + set_thread_flag(TIF_USEDFPU); + KSTK_EUEN(current) |= CSR_EUEN_FPEN; +} + +static inline void own_fpu_inatomic(int restore) +{ + if (cpu_has_fpu && !is_fpu_owner()) { + __own_fpu(); + if (restore) + _restore_fp(¤t->thread.fpu); + } +} + +static inline void own_fpu(int restore) +{ + preempt_disable(); + own_fpu_inatomic(restore); + preempt_enable(); +} + +static inline void lose_fpu_inatomic(int save, struct task_struct *tsk) +{ + if (is_fpu_owner()) { + if (save) + _save_fp(&tsk->thread.fpu); + disable_fpu(); + clear_tsk_thread_flag(tsk, TIF_USEDFPU); + } + KSTK_EUEN(tsk) &= ~(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN); +} + +static inline void lose_fpu(int save) +{ + preempt_disable(); + lose_fpu_inatomic(save, current); + preempt_enable(); +} + +static inline void init_fpu(void) +{ + unsigned int fcsr = current->thread.fpu.fcsr; + + __own_fpu(); + _init_fpu(fcsr); + set_used_math(); +} + +static inline void save_fp(struct task_struct *tsk) +{ + if (cpu_has_fpu) + _save_fp(&tsk->thread.fpu); +} + +static inline void restore_fp(struct task_struct *tsk) +{ + if (cpu_has_fpu) + _restore_fp(&tsk->thread.fpu); +} + +static inline union fpureg *get_fpu_regs(struct task_struct *tsk) +{ + if (tsk == current) { + preempt_disable(); + if (is_fpu_owner()) + _save_fp(¤t->thread.fpu); + preempt_enable(); + } + + return tsk->thread.fpu.fpr; +} + +#endif /* _ASM_FPU_H */ diff --git a/arch/loongarch/include/asm/futex.h b/arch/loongarch/include/asm/futex.h new file mode 100644 index 000000000000..9de8231694ec --- /dev/null +++ b/arch/loongarch/include/asm/futex.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_FUTEX_H +#define _ASM_FUTEX_H + +#include <linux/futex.h> +#include <linux/uaccess.h> +#include <asm/barrier.h> +#include <asm/compiler.h> +#include <asm/errno.h> + +#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ +{ \ + __asm__ __volatile__( \ + "1: ll.w %1, %4 # __futex_atomic_op\n" \ + " " insn " \n" \ + "2: sc.w $t0, %2 \n" \ + " beq $t0, $zero, 1b \n" \ + "3: \n" \ + " .section .fixup,\"ax\" \n" \ + "4: li.w %0, %6 \n" \ + " b 3b \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " "__UA_ADDR "\t1b, 4b \n" \ + " "__UA_ADDR "\t2b, 4b \n" \ + " .previous \n" \ + : "=r" (ret), "=&r" (oldval), \ + "=ZC" (*uaddr) \ + : "0" (0), "ZC" (*uaddr), "Jr" (oparg), \ + "i" (-EFAULT) \ + : "memory", "t0"); \ +} + +static inline int +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) +{ + int oldval = 0, ret = 0; + + pagefault_disable(); + + switch (op) { + case FUTEX_OP_SET: + __futex_atomic_op("move $t0, %z5", ret, oldval, uaddr, oparg); + break; + case FUTEX_OP_ADD: + __futex_atomic_op("add.w $t0, %1, %z5", ret, oldval, uaddr, oparg); + break; + case FUTEX_OP_OR: + __futex_atomic_op("or $t0, %1, %z5", ret, oldval, uaddr, oparg); + break; + case FUTEX_OP_ANDN: + __futex_atomic_op("and $t0, %1, %z5", ret, oldval, uaddr, ~oparg); + break; + case FUTEX_OP_XOR: + __futex_atomic_op("xor $t0, %1, %z5", ret, oldval, uaddr, oparg); + break; + default: + ret = -ENOSYS; + } + + pagefault_enable(); + + if (!ret) + *oval = oldval; + + return ret; +} + +static inline int +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) +{ + int ret = 0; + u32 val = 0; + + if (!access_ok(uaddr, sizeof(u32))) + return -EFAULT; + + __asm__ __volatile__( + "# futex_atomic_cmpxchg_inatomic \n" + "1: ll.w %1, %3 \n" + " bne %1, %z4, 3f \n" + " or $t0, %z5, $zero \n" + "2: sc.w $t0, %2 \n" + " beq $zero, $t0, 1b \n" + "3: \n" + __WEAK_LLSC_MB + " .section .fixup,\"ax\" \n" + "4: li.d %0, %6 \n" + " b 3b \n" + " .previous \n" + " .section __ex_table,\"a\" \n" + " "__UA_ADDR "\t1b, 4b \n" + " "__UA_ADDR "\t2b, 4b \n" + " .previous \n" + : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) + : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), + "i" (-EFAULT) + : "memory", "t0"); + + *uval = val; + + return ret; +} + +#endif /* _ASM_FUTEX_H */ diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/asm/hardirq.h new file mode 100644 index 000000000000..befe8184aa08 --- /dev/null +++ b/arch/loongarch/include/asm/hardirq.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_HARDIRQ_H +#define _ASM_HARDIRQ_H + +#include <linux/cache.h> +#include <linux/threads.h> +#include <linux/irq.h> + +extern void ack_bad_irq(unsigned int irq); +#define ack_bad_irq ack_bad_irq + +#define NR_IPI 2 + +typedef struct { + unsigned int ipi_irqs[NR_IPI]; + unsigned int __softirq_pending; +} ____cacheline_aligned irq_cpustat_t; + +DECLARE_PER_CPU_ALIGNED(irq_cpustat_t, irq_stat); + +#define __ARCH_IRQ_STAT + +#endif /* _ASM_HARDIRQ_H */ diff --git a/arch/loongarch/include/asm/hugetlb.h b/arch/loongarch/include/asm/hugetlb.h new file mode 100644 index 000000000000..aa44b3fe43dd --- /dev/null +++ b/arch/loongarch/include/asm/hugetlb.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_HUGETLB_H +#define __ASM_HUGETLB_H + +#include <asm/page.h> + +uint64_t pmd_to_entrylo(unsigned long pmd_val); + +#define __HAVE_ARCH_PREPARE_HUGEPAGE_RANGE +static inline int prepare_hugepage_range(struct file *file, + unsigned long addr, + unsigned long len) +{ + unsigned long task_size = STACK_TOP; + struct hstate *h = hstate_file(file); + + if (len & ~huge_page_mask(h)) + return -EINVAL; + if (addr & ~huge_page_mask(h)) + return -EINVAL; + if (len > task_size) + return -ENOMEM; + if (task_size - len < addr) + return -EINVAL; + return 0; +} + +#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR +static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + pte_t clear; + pte_t pte = *ptep; + + pte_val(clear) = (unsigned long)invalid_pte_table; + set_pte_at(mm, addr, ptep, clear); + return pte; +} + +#define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH +static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) +{ + pte_t pte; + + pte = huge_ptep_get_and_clear(vma->vm_mm, addr, ptep); + flush_tlb_page(vma, addr); + return pte; +} + +#define __HAVE_ARCH_HUGE_PTE_NONE +static inline int huge_pte_none(pte_t pte) +{ + unsigned long val = pte_val(pte) & ~_PAGE_GLOBAL; + return !val || (val == (unsigned long)invalid_pte_table); +} + +#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS +static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, + pte_t *ptep, pte_t pte, + int dirty) +{ + int changed = !pte_same(*ptep, pte); + + if (changed) { + set_pte_at(vma->vm_mm, addr, ptep, pte); + /* + * There could be some standard sized pages in there, + * get them all. + */ + flush_tlb_range(vma, addr, addr + HPAGE_SIZE); + } + return changed; +} + +#include <asm-generic/hugetlb.h> + +#endif /* __ASM_HUGETLB_H */ diff --git a/arch/loongarch/include/asm/hw_irq.h b/arch/loongarch/include/asm/hw_irq.h new file mode 100644 index 000000000000..af4f4e8fbd85 --- /dev/null +++ b/arch/loongarch/include/asm/hw_irq.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_HW_IRQ_H +#define __ASM_HW_IRQ_H + +#include <linux/atomic.h> + +extern atomic_t irq_err_count; + +/* + * interrupt-retrigger: NOP for now. This may not be appropriate for all + * machines, we'll see ... + */ + +#endif /* __ASM_HW_IRQ_H */ diff --git a/arch/loongarch/include/asm/idle.h b/arch/loongarch/include/asm/idle.h new file mode 100644 index 000000000000..f7f2b7dbf958 --- /dev/null +++ b/arch/loongarch/include/asm/idle.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_IDLE_H +#define __ASM_IDLE_H + +#include <linux/linkage.h> + +extern asmlinkage void __arch_cpu_idle(void); + +#endif /* __ASM_IDLE_H */ diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h new file mode 100644 index 000000000000..575d1bb66ffb --- /dev/null +++ b/arch/loongarch/include/asm/inst.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_INST_H +#define _ASM_INST_H + +#include <linux/types.h> +#include <asm/asm.h> + +#define ADDR_IMMMASK_LU52ID 0xFFF0000000000000 +#define ADDR_IMMMASK_LU32ID 0x000FFFFF00000000 +#define ADDR_IMMMASK_ADDU16ID 0x00000000FFFF0000 + +#define ADDR_IMMSHIFT_LU52ID 52 +#define ADDR_IMMSHIFT_LU32ID 32 +#define ADDR_IMMSHIFT_ADDU16ID 16 + +#define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN) + +enum reg1i20_op { + lu12iw_op = 0x0a, + lu32id_op = 0x0b, +}; + +enum reg2i12_op { + lu52id_op = 0x0c, +}; + +enum reg2i16_op { + jirl_op = 0x13, +}; + +struct reg0i26_format { + unsigned int immediate_h : 10; + unsigned int immediate_l : 16; + unsigned int opcode : 6; +}; + +struct reg1i20_format { + unsigned int rd : 5; + unsigned int immediate : 20; + unsigned int opcode : 7; +}; + +struct reg1i21_format { + unsigned int immediate_h : 5; + unsigned int rj : 5; + unsigned int immediate_l : 16; + unsigned int opcode : 6; +}; + +struct reg2i12_format { + unsigned int rd : 5; + unsigned int rj : 5; + unsigned int immediate : 12; + unsigned int opcode : 10; +}; + +struct reg2i16_format { + unsigned int rd : 5; + unsigned int rj : 5; + unsigned int immediate : 16; + unsigned int opcode : 6; +}; + +union loongarch_instruction { + unsigned int word; + struct reg0i26_format reg0i26_format; + struct reg1i20_format reg1i20_format; + struct reg1i21_format reg1i21_format; + struct reg2i12_format reg2i12_format; + struct reg2i16_format reg2i16_format; +}; + +#define LOONGARCH_INSN_SIZE sizeof(union loongarch_instruction) + +enum loongarch_gpr { + LOONGARCH_GPR_ZERO = 0, + LOONGARCH_GPR_RA = 1, + LOONGARCH_GPR_TP = 2, + LOONGARCH_GPR_SP = 3, + LOONGARCH_GPR_A0 = 4, /* Reused as V0 for return value */ + LOONGARCH_GPR_A1, /* Reused as V1 for return value */ + LOONGARCH_GPR_A2, + LOONGARCH_GPR_A3, + LOONGARCH_GPR_A4, + LOONGARCH_GPR_A5, + LOONGARCH_GPR_A6, + LOONGARCH_GPR_A7, + LOONGARCH_GPR_T0 = 12, + LOONGARCH_GPR_T1, + LOONGARCH_GPR_T2, + LOONGARCH_GPR_T3, + LOONGARCH_GPR_T4, + LOONGARCH_GPR_T5, + LOONGARCH_GPR_T6, + LOONGARCH_GPR_T7, + LOONGARCH_GPR_T8, + LOONGARCH_GPR_FP = 22, + LOONGARCH_GPR_S0 = 23, + LOONGARCH_GPR_S1, + LOONGARCH_GPR_S2, + LOONGARCH_GPR_S3, + LOONGARCH_GPR_S4, + LOONGARCH_GPR_S5, + LOONGARCH_GPR_S6, + LOONGARCH_GPR_S7, + LOONGARCH_GPR_S8, + LOONGARCH_GPR_MAX +}; + +u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm); +u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm); +u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest); + +#endif /* _ASM_INST_H */ diff --git a/arch/loongarch/include/asm/io.h b/arch/loongarch/include/asm/io.h new file mode 100644 index 000000000000..884599739b36 --- /dev/null +++ b/arch/loongarch/include/asm/io.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +#define ARCH_HAS_IOREMAP_WC + +#include <linux/compiler.h> +#include <linux/kernel.h> +#include <linux/types.h> + +#include <asm/addrspace.h> +#include <asm/bug.h> +#include <asm/byteorder.h> +#include <asm/cpu.h> +#include <asm/page.h> +#include <asm/pgtable-bits.h> +#include <asm/string.h> + +/* + * On LoongArch, I/O ports mappring is following: + * + * | .... | + * |-----------------------| + * | pci io ports(64K~32M) | + * |-----------------------| + * | isa io ports(0 ~16K) | + * PCI_IOBASE ->|-----------------------| + * | .... | + */ +#define PCI_IOBASE ((void __iomem *)(vm_map_base + (2 * PAGE_SIZE))) +#define PCI_IOSIZE SZ_32M +#define ISA_IOSIZE SZ_16K +#define IO_SPACE_LIMIT (PCI_IOSIZE - 1) + +/* + * Change "struct page" to physical address. + */ +#define page_to_phys(page) ((phys_addr_t)page_to_pfn(page) << PAGE_SHIFT) + +extern void __init __iomem *early_ioremap(u64 phys_addr, unsigned long size); +extern void __init early_iounmap(void __iomem *addr, unsigned long size); + +#define early_memremap early_ioremap +#define early_memunmap early_iounmap + +static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size, + unsigned long prot_val) +{ + if (prot_val == _CACHE_CC) + return (void __iomem *)(unsigned long)(CACHE_BASE + offset); + else + return (void __iomem *)(unsigned long)(UNCACHE_BASE + offset); +} + +/* + * ioremap - map bus memory into CPU space + * @offset: bus address of the memory + * @size: size of the resource to map + * + * ioremap performs a platform specific sequence of operations to + * make bus memory CPU accessible via the readb/readw/readl/writeb/ + * writew/writel functions and the other mmio helpers. The returned + * address is not guaranteed to be usable directly as a virtual + * address. + */ +#define ioremap(offset, size) \ + ioremap_prot((offset), (size), _CACHE_SUC) + +/* + * ioremap_wc - map bus memory into CPU space + * @offset: bus address of the memory + * @size: size of the resource to map + * + * ioremap_wc performs a platform specific sequence of operations to + * make bus memory CPU accessible via the readb/readw/readl/writeb/ + * writew/writel functions and the other mmio helpers. The returned + * address is not guaranteed to be usable directly as a virtual + * address. + * + * This version of ioremap ensures that the memory is marked uncachable + * but accelerated by means of write-combining feature. It is specifically + * useful for PCIe prefetchable windows, which may vastly improve a + * communications performance. If it was determined on boot stage, what + * CPU CCA doesn't support WUC, the method shall fall-back to the + * _CACHE_SUC option (see cpu_probe() method). + */ +#define ioremap_wc(offset, size) \ + ioremap_prot((offset), (size), _CACHE_WUC) + +/* + * ioremap_cache - map bus memory into CPU space + * @offset: bus address of the memory + * @size: size of the resource to map + * + * ioremap_cache performs a platform specific sequence of operations to + * make bus memory CPU accessible via the readb/readw/readl/writeb/ + * writew/writel functions and the other mmio helpers. The returned + * address is not guaranteed to be usable directly as a virtual + * address. + * + * This version of ioremap ensures that the memory is marked cachable by + * the CPU. Also enables full write-combining. Useful for some + * memory-like regions on I/O busses. + */ +#define ioremap_cache(offset, size) \ + ioremap_prot((offset), (size), _CACHE_CC) + +static inline void iounmap(const volatile void __iomem *addr) +{ +} + +#define mmiowb() asm volatile ("dbar 0" ::: "memory") + +/* + * String version of I/O memory access operations. + */ +extern void __memset_io(volatile void __iomem *dst, int c, size_t count); +extern void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count); +extern void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count); +#define memset_io(c, v, l) __memset_io((c), (v), (l)) +#define memcpy_fromio(a, c, l) __memcpy_fromio((a), (c), (l)) +#define memcpy_toio(c, a, l) __memcpy_toio((c), (a), (l)) + +#include <asm-generic/io.h> + +#endif /* _ASM_IO_H */ diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h new file mode 100644 index 000000000000..ace3ea6da72e --- /dev/null +++ b/arch/loongarch/include/asm/irq.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_IRQ_H +#define _ASM_IRQ_H + +#include <linux/irqdomain.h> +#include <linux/irqreturn.h> + +#define IRQ_STACK_SIZE THREAD_SIZE +#define IRQ_STACK_START (IRQ_STACK_SIZE - 16) + +DECLARE_PER_CPU(unsigned long, irq_stack); + +/* + * The highest address on the IRQ stack contains a dummy frame which is + * structured as follows: + * + * top ------------ + * | task sp | <- irq_stack[cpu] + IRQ_STACK_START + * ------------ + * | | <- First frame of IRQ context + * ------------ + * + * task sp holds a copy of the task stack pointer where the struct pt_regs + * from exception entry can be found. + */ + +static inline bool on_irq_stack(int cpu, unsigned long sp) +{ + unsigned long low = per_cpu(irq_stack, cpu); + unsigned long high = low + IRQ_STACK_SIZE; + + return (low <= sp && sp <= high); +} + +int get_ipi_irq(void); +int get_pmc_irq(void); +int get_timer_irq(void); +void spurious_interrupt(void); + +#define NR_IRQS_LEGACY 16 + +#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace +void arch_trigger_cpumask_backtrace(const struct cpumask *mask, bool exclude_self); + +#define MAX_IO_PICS 2 +#define NR_IRQS (64 + (256 * MAX_IO_PICS)) + +#define CORES_PER_EIO_NODE 4 + +#define LOONGSON_CPU_UART0_VEC 10 /* CPU UART0 */ +#define LOONGSON_CPU_THSENS_VEC 14 /* CPU Thsens */ +#define LOONGSON_CPU_HT0_VEC 16 /* CPU HT0 irq vector base number */ +#define LOONGSON_CPU_HT1_VEC 24 /* CPU HT1 irq vector base number */ + +/* IRQ number definitions */ +#define LOONGSON_LPC_IRQ_BASE 0 +#define LOONGSON_LPC_LAST_IRQ (LOONGSON_LPC_IRQ_BASE + 15) + +#define LOONGSON_CPU_IRQ_BASE 16 +#define LOONGSON_CPU_LAST_IRQ (LOONGSON_CPU_IRQ_BASE + 14) + +#define LOONGSON_PCH_IRQ_BASE 64 +#define LOONGSON_PCH_ACPI_IRQ (LOONGSON_PCH_IRQ_BASE + 47) +#define LOONGSON_PCH_LAST_IRQ (LOONGSON_PCH_IRQ_BASE + 64 - 1) + +#define LOONGSON_MSI_IRQ_BASE (LOONGSON_PCH_IRQ_BASE + 64) +#define LOONGSON_MSI_LAST_IRQ (LOONGSON_PCH_IRQ_BASE + 256 - 1) + +#define GSI_MIN_LPC_IRQ LOONGSON_LPC_IRQ_BASE +#define GSI_MAX_LPC_IRQ (LOONGSON_LPC_IRQ_BASE + 16 - 1) +#define GSI_MIN_CPU_IRQ LOONGSON_CPU_IRQ_BASE +#define GSI_MAX_CPU_IRQ (LOONGSON_CPU_IRQ_BASE + 48 - 1) +#define GSI_MIN_PCH_IRQ LOONGSON_PCH_IRQ_BASE +#define GSI_MAX_PCH_IRQ (LOONGSON_PCH_IRQ_BASE + 256 - 1) + +extern int find_pch_pic(u32 gsi); +extern int eiointc_get_node(int id); + +static inline void eiointc_enable(void) +{ + uint64_t misc; + + misc = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC); + misc |= IOCSR_MISC_FUNC_EXT_IOI_EN; + iocsr_write64(misc, LOONGARCH_IOCSR_MISC_FUNC); +} + +struct acpi_madt_lio_pic; +struct acpi_madt_eio_pic; +struct acpi_madt_ht_pic; +struct acpi_madt_bio_pic; +struct acpi_madt_msi_pic; +struct acpi_madt_lpc_pic; + +struct irq_domain *loongarch_cpu_irq_init(void); + +struct irq_domain *liointc_acpi_init(struct irq_domain *parent, + struct acpi_madt_lio_pic *acpi_liointc); +struct irq_domain *eiointc_acpi_init(struct irq_domain *parent, + struct acpi_madt_eio_pic *acpi_eiointc); + +struct irq_domain *htvec_acpi_init(struct irq_domain *parent, + struct acpi_madt_ht_pic *acpi_htvec); +struct irq_domain *pch_lpc_acpi_init(struct irq_domain *parent, + struct acpi_madt_lpc_pic *acpi_pchlpc); +struct irq_domain *pch_msi_acpi_init(struct irq_domain *parent, + struct acpi_madt_msi_pic *acpi_pchmsi); +struct irq_domain *pch_pic_acpi_init(struct irq_domain *parent, + struct acpi_madt_bio_pic *acpi_pchpic); + +extern struct acpi_madt_lio_pic *acpi_liointc; +extern struct acpi_madt_eio_pic *acpi_eiointc[MAX_IO_PICS]; + +extern struct acpi_madt_ht_pic *acpi_htintc; +extern struct acpi_madt_lpc_pic *acpi_pchlpc; +extern struct acpi_madt_msi_pic *acpi_pchmsi[MAX_IO_PICS]; +extern struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS]; + +extern struct irq_domain *cpu_domain; +extern struct irq_domain *liointc_domain; +extern struct irq_domain *pch_lpc_domain; +extern struct irq_domain *pch_msi_domain[MAX_IO_PICS]; +extern struct irq_domain *pch_pic_domain[MAX_IO_PICS]; + +extern irqreturn_t loongson3_ipi_interrupt(int irq, void *dev); + +#include <asm-generic/irq.h> + +#endif /* _ASM_IRQ_H */ diff --git a/arch/loongarch/include/asm/irq_regs.h b/arch/loongarch/include/asm/irq_regs.h new file mode 100644 index 000000000000..3d62d815bf6b --- /dev/null +++ b/arch/loongarch/include/asm/irq_regs.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_IRQ_REGS_H +#define __ASM_IRQ_REGS_H + +#define ARCH_HAS_OWN_IRQ_REGS + +#include <linux/thread_info.h> + +static inline struct pt_regs *get_irq_regs(void) +{ + return current_thread_info()->regs; +} + +static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs) +{ + struct pt_regs *old_regs; + + old_regs = get_irq_regs(); + current_thread_info()->regs = new_regs; + + return old_regs; +} + +#endif /* __ASM_IRQ_REGS_H */ diff --git a/arch/loongarch/include/asm/irqflags.h b/arch/loongarch/include/asm/irqflags.h new file mode 100644 index 000000000000..52121cd791fe --- /dev/null +++ b/arch/loongarch/include/asm/irqflags.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_IRQFLAGS_H +#define _ASM_IRQFLAGS_H + +#ifndef __ASSEMBLY__ + +#include <linux/compiler.h> +#include <linux/stringify.h> +#include <asm/compiler.h> +#include <asm/loongarch.h> + +static inline void arch_local_irq_enable(void) +{ + u32 flags = CSR_CRMD_IE; + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) + : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); +} + +static inline void arch_local_irq_disable(void) +{ + u32 flags = 0; + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) + : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); +} + +static inline unsigned long arch_local_irq_save(void) +{ + u32 flags = 0; + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) + : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); + return flags; +} + +static inline void arch_local_irq_restore(unsigned long flags) +{ + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) + : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); +} + +static inline unsigned long arch_local_save_flags(void) +{ + u32 flags; + __asm__ __volatile__( + "csrrd %[val], %[reg]\n\t" + : [val] "=r" (flags) + : [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); + return flags; +} + +static inline int arch_irqs_disabled_flags(unsigned long flags) +{ + return !(flags & CSR_CRMD_IE); +} + +static inline int arch_irqs_disabled(void) +{ + return arch_irqs_disabled_flags(arch_local_save_flags()); +} + +#endif /* #ifndef __ASSEMBLY__ */ + +#endif /* _ASM_IRQFLAGS_H */ diff --git a/arch/loongarch/include/asm/kdebug.h b/arch/loongarch/include/asm/kdebug.h new file mode 100644 index 000000000000..d721b4b82fae --- /dev/null +++ b/arch/loongarch/include/asm/kdebug.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_LOONGARCH_KDEBUG_H +#define _ASM_LOONGARCH_KDEBUG_H + +#include <linux/notifier.h> + +enum die_val { + DIE_OOPS = 1, + DIE_RI, + DIE_FP, + DIE_SIMD, + DIE_TRAP, + DIE_PAGE_FAULT, + DIE_BREAK, + DIE_SSTEPBP, + DIE_UPROBE, + DIE_UPROBE_XOL, +}; + +#endif /* _ASM_LOONGARCH_KDEBUG_H */ diff --git a/arch/loongarch/include/asm/linkage.h b/arch/loongarch/include/asm/linkage.h new file mode 100644 index 000000000000..81b0c4cfbf4f --- /dev/null +++ b/arch/loongarch/include/asm/linkage.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +#define __ALIGN .align 2 +#define __ALIGN_STR __stringify(__ALIGN) + +#define SYM_FUNC_START(name) \ + SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) \ + .cfi_startproc; + +#define SYM_FUNC_START_NOALIGN(name) \ + SYM_START(name, SYM_L_GLOBAL, SYM_A_NONE) \ + .cfi_startproc; + +#define SYM_FUNC_START_LOCAL(name) \ + SYM_START(name, SYM_L_LOCAL, SYM_A_ALIGN) \ + .cfi_startproc; + +#define SYM_FUNC_START_LOCAL_NOALIGN(name) \ + SYM_START(name, SYM_L_LOCAL, SYM_A_NONE) \ + .cfi_startproc; + +#define SYM_FUNC_START_WEAK(name) \ + SYM_START(name, SYM_L_WEAK, SYM_A_ALIGN) \ + .cfi_startproc; + +#define SYM_FUNC_START_WEAK_NOALIGN(name) \ + SYM_START(name, SYM_L_WEAK, SYM_A_NONE) \ + .cfi_startproc; + +#define SYM_FUNC_END(name) \ + .cfi_endproc; \ + SYM_END(name, SYM_T_FUNC) + +#endif diff --git a/arch/loongarch/include/asm/local.h b/arch/loongarch/include/asm/local.h new file mode 100644 index 000000000000..2052a2267337 --- /dev/null +++ b/arch/loongarch/include/asm/local.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ARCH_LOONGARCH_LOCAL_H +#define _ARCH_LOONGARCH_LOCAL_H + +#include <linux/percpu.h> +#include <linux/bitops.h> +#include <linux/atomic.h> +#include <asm/cmpxchg.h> +#include <asm/compiler.h> + +typedef struct { + atomic_long_t a; +} local_t; + +#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } + +#define local_read(l) atomic_long_read(&(l)->a) +#define local_set(l, i) atomic_long_set(&(l)->a, (i)) + +#define local_add(i, l) atomic_long_add((i), (&(l)->a)) +#define local_sub(i, l) atomic_long_sub((i), (&(l)->a)) +#define local_inc(l) atomic_long_inc(&(l)->a) +#define local_dec(l) atomic_long_dec(&(l)->a) + +/* + * Same as above, but return the result value + */ +static inline long local_add_return(long i, local_t *l) +{ + unsigned long result; + + __asm__ __volatile__( + " " __AMADD " %1, %2, %0 \n" + : "+ZB" (l->a.counter), "=&r" (result) + : "r" (i) + : "memory"); + result = result + i; + + return result; +} + +static inline long local_sub_return(long i, local_t *l) +{ + unsigned long result; + + __asm__ __volatile__( + " " __AMADD "%1, %2, %0 \n" + : "+ZB" (l->a.counter), "=&r" (result) + : "r" (-i) + : "memory"); + + result = result - i; + + return result; +} + +#define local_cmpxchg(l, o, n) \ + ((long)cmpxchg_local(&((l)->a.counter), (o), (n))) +#define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n))) + +/** + * local_add_unless - add unless the number is a given value + * @l: pointer of type local_t + * @a: the amount to add to l... + * @u: ...unless l is equal to u. + * + * Atomically adds @a to @l, so long as it was not @u. + * Returns non-zero if @l was not @u, and zero otherwise. + */ +#define local_add_unless(l, a, u) \ +({ \ + long c, old; \ + c = local_read(l); \ + while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \ + c = old; \ + c != (u); \ +}) +#define local_inc_not_zero(l) local_add_unless((l), 1, 0) + +#define local_dec_return(l) local_sub_return(1, (l)) +#define local_inc_return(l) local_add_return(1, (l)) + +/* + * local_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @l: pointer of type local_t + * + * Atomically subtracts @i from @l and returns + * true if the result is zero, or false for all + * other cases. + */ +#define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0) + +/* + * local_inc_and_test - increment and test + * @l: pointer of type local_t + * + * Atomically increments @l by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +#define local_inc_and_test(l) (local_inc_return(l) == 0) + +/* + * local_dec_and_test - decrement by 1 and test + * @l: pointer of type local_t + * + * Atomically decrements @l by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +#define local_dec_and_test(l) (local_sub_return(1, (l)) == 0) + +/* + * local_add_negative - add and test if negative + * @l: pointer of type local_t + * @i: integer value to add + * + * Atomically adds @i to @l and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +#define local_add_negative(i, l) (local_add_return(i, (l)) < 0) + +/* Use these for per-cpu local_t variables: on some archs they are + * much more efficient than these naive implementations. Note they take + * a variable, not an address. + */ + +#define __local_inc(l) ((l)->a.counter++) +#define __local_dec(l) ((l)->a.counter++) +#define __local_add(i, l) ((l)->a.counter += (i)) +#define __local_sub(i, l) ((l)->a.counter -= (i)) + +#endif /* _ARCH_LOONGARCH_LOCAL_H */ diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h new file mode 100644 index 000000000000..3ba4f7e87cd2 --- /dev/null +++ b/arch/loongarch/include/asm/loongarch.h @@ -0,0 +1,1516 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_LOONGARCH_H +#define _ASM_LOONGARCH_H + +#include <linux/bits.h> +#include <linux/linkage.h> +#include <linux/types.h> + +#ifndef __ASSEMBLY__ +#include <larchintrin.h> + +/* + * parse_r var, r - Helper assembler macro for parsing register names. + * + * This converts the register name in $n form provided in \r to the + * corresponding register number, which is assigned to the variable \var. It is + * needed to allow explicit encoding of instructions in inline assembly where + * registers are chosen by the compiler in $n form, allowing us to avoid using + * fixed register numbers. + * + * It also allows newer instructions (not implemented by the assembler) to be + * transparently implemented using assembler macros, instead of needing separate + * cases depending on toolchain support. + * + * Simple usage example: + * __asm__ __volatile__("parse_r addr, %0\n\t" + * "#invtlb op, 0, %0\n\t" + * ".word ((0x6498000) | (addr << 10) | (0 << 5) | op)" + * : "=r" (status); + */ + +/* Match an individual register number and assign to \var */ +#define _IFC_REG(n) \ + ".ifc \\r, $r" #n "\n\t" \ + "\\var = " #n "\n\t" \ + ".endif\n\t" + +__asm__(".macro parse_r var r\n\t" + "\\var = -1\n\t" + _IFC_REG(0) _IFC_REG(1) _IFC_REG(2) _IFC_REG(3) + _IFC_REG(4) _IFC_REG(5) _IFC_REG(6) _IFC_REG(7) + _IFC_REG(8) _IFC_REG(9) _IFC_REG(10) _IFC_REG(11) + _IFC_REG(12) _IFC_REG(13) _IFC_REG(14) _IFC_REG(15) + _IFC_REG(16) _IFC_REG(17) _IFC_REG(18) _IFC_REG(19) + _IFC_REG(20) _IFC_REG(21) _IFC_REG(22) _IFC_REG(23) + _IFC_REG(24) _IFC_REG(25) _IFC_REG(26) _IFC_REG(27) + _IFC_REG(28) _IFC_REG(29) _IFC_REG(30) _IFC_REG(31) + ".iflt \\var\n\t" + ".error \"Unable to parse register name \\r\"\n\t" + ".endif\n\t" + ".endm"); + +#undef _IFC_REG + +/* CPUCFG */ +static inline u32 read_cpucfg(u32 reg) +{ + return __cpucfg(reg); +} + +#endif /* !__ASSEMBLY__ */ + +#ifdef __ASSEMBLY__ + +/* LoongArch Registers */ +#define REG_ZERO 0x0 +#define REG_RA 0x1 +#define REG_TP 0x2 +#define REG_SP 0x3 +#define REG_A0 0x4 /* Reused as V0 for return value */ +#define REG_A1 0x5 /* Reused as V1 for return value */ +#define REG_A2 0x6 +#define REG_A3 0x7 +#define REG_A4 0x8 +#define REG_A5 0x9 +#define REG_A6 0xa +#define REG_A7 0xb +#define REG_T0 0xc +#define REG_T1 0xd +#define REG_T2 0xe +#define REG_T3 0xf +#define REG_T4 0x10 +#define REG_T5 0x11 +#define REG_T6 0x12 +#define REG_T7 0x13 +#define REG_T8 0x14 +#define REG_U0 0x15 /* Kernel uses it as percpu base */ +#define REG_FP 0x16 +#define REG_S0 0x17 +#define REG_S1 0x18 +#define REG_S2 0x19 +#define REG_S3 0x1a +#define REG_S4 0x1b +#define REG_S5 0x1c +#define REG_S6 0x1d +#define REG_S7 0x1e +#define REG_S8 0x1f + +#endif /* __ASSEMBLY__ */ + +/* Bit fields for CPUCFG registers */ +#define LOONGARCH_CPUCFG0 0x0 +#define CPUCFG0_PRID GENMASK(31, 0) + +#define LOONGARCH_CPUCFG1 0x1 +#define CPUCFG1_ISGR32 BIT(0) +#define CPUCFG1_ISGR64 BIT(1) +#define CPUCFG1_PAGING BIT(2) +#define CPUCFG1_IOCSR BIT(3) +#define CPUCFG1_PABITS GENMASK(11, 4) +#define CPUCFG1_VABITS GENMASK(19, 12) +#define CPUCFG1_UAL BIT(20) +#define CPUCFG1_RI BIT(21) +#define CPUCFG1_EP BIT(22) +#define CPUCFG1_RPLV BIT(23) +#define CPUCFG1_HUGEPG BIT(24) +#define CPUCFG1_IOCSRBRD BIT(25) +#define CPUCFG1_MSGINT BIT(26) + +#define LOONGARCH_CPUCFG2 0x2 +#define CPUCFG2_FP BIT(0) +#define CPUCFG2_FPSP BIT(1) +#define CPUCFG2_FPDP BIT(2) +#define CPUCFG2_FPVERS GENMASK(5, 3) +#define CPUCFG2_LSX BIT(6) +#define CPUCFG2_LASX BIT(7) +#define CPUCFG2_COMPLEX BIT(8) +#define CPUCFG2_CRYPTO BIT(9) +#define CPUCFG2_LVZP BIT(10) +#define CPUCFG2_LVZVER GENMASK(13, 11) +#define CPUCFG2_LLFTP BIT(14) +#define CPUCFG2_LLFTPREV GENMASK(17, 15) +#define CPUCFG2_X86BT BIT(18) +#define CPUCFG2_ARMBT BIT(19) +#define CPUCFG2_MIPSBT BIT(20) +#define CPUCFG2_LSPW BIT(21) +#define CPUCFG2_LAM BIT(22) + +#define LOONGARCH_CPUCFG3 0x3 +#define CPUCFG3_CCDMA BIT(0) +#define CPUCFG3_SFB BIT(1) +#define CPUCFG3_UCACC BIT(2) +#define CPUCFG3_LLEXC BIT(3) +#define CPUCFG3_SCDLY BIT(4) +#define CPUCFG3_LLDBAR BIT(5) +#define CPUCFG3_ITLBT BIT(6) +#define CPUCFG3_ICACHET BIT(7) +#define CPUCFG3_SPW_LVL GENMASK(10, 8) +#define CPUCFG3_SPW_HG_HF BIT(11) +#define CPUCFG3_RVA BIT(12) +#define CPUCFG3_RVAMAX GENMASK(16, 13) + +#define LOONGARCH_CPUCFG4 0x4 +#define CPUCFG4_CCFREQ GENMASK(31, 0) + +#define LOONGARCH_CPUCFG5 0x5 +#define CPUCFG5_CCMUL GENMASK(15, 0) +#define CPUCFG5_CCDIV GENMASK(31, 16) + +#define LOONGARCH_CPUCFG6 0x6 +#define CPUCFG6_PMP BIT(0) +#define CPUCFG6_PAMVER GENMASK(3, 1) +#define CPUCFG6_PMNUM GENMASK(7, 4) +#define CPUCFG6_PMBITS GENMASK(13, 8) +#define CPUCFG6_UPM BIT(14) + +#define LOONGARCH_CPUCFG16 0x10 +#define CPUCFG16_L1_IUPRE BIT(0) +#define CPUCFG16_L1_IUUNIFY BIT(1) +#define CPUCFG16_L1_DPRE BIT(2) +#define CPUCFG16_L2_IUPRE BIT(3) +#define CPUCFG16_L2_IUUNIFY BIT(4) +#define CPUCFG16_L2_IUPRIV BIT(5) +#define CPUCFG16_L2_IUINCL BIT(6) +#define CPUCFG16_L2_DPRE BIT(7) +#define CPUCFG16_L2_DPRIV BIT(8) +#define CPUCFG16_L2_DINCL BIT(9) +#define CPUCFG16_L3_IUPRE BIT(10) +#define CPUCFG16_L3_IUUNIFY BIT(11) +#define CPUCFG16_L3_IUPRIV BIT(12) +#define CPUCFG16_L3_IUINCL BIT(13) +#define CPUCFG16_L3_DPRE BIT(14) +#define CPUCFG16_L3_DPRIV BIT(15) +#define CPUCFG16_L3_DINCL BIT(16) + +#define LOONGARCH_CPUCFG17 0x11 +#define CPUCFG17_L1I_WAYS_M GENMASK(15, 0) +#define CPUCFG17_L1I_SETS_M GENMASK(23, 16) +#define CPUCFG17_L1I_SIZE_M GENMASK(30, 24) +#define CPUCFG17_L1I_WAYS 0 +#define CPUCFG17_L1I_SETS 16 +#define CPUCFG17_L1I_SIZE 24 + +#define LOONGARCH_CPUCFG18 0x12 +#define CPUCFG18_L1D_WAYS_M GENMASK(15, 0) +#define CPUCFG18_L1D_SETS_M GENMASK(23, 16) +#define CPUCFG18_L1D_SIZE_M GENMASK(30, 24) +#define CPUCFG18_L1D_WAYS 0 +#define CPUCFG18_L1D_SETS 16 +#define CPUCFG18_L1D_SIZE 24 + +#define LOONGARCH_CPUCFG19 0x13 +#define CPUCFG19_L2_WAYS_M GENMASK(15, 0) +#define CPUCFG19_L2_SETS_M GENMASK(23, 16) +#define CPUCFG19_L2_SIZE_M GENMASK(30, 24) +#define CPUCFG19_L2_WAYS 0 +#define CPUCFG19_L2_SETS 16 +#define CPUCFG19_L2_SIZE 24 + +#define LOONGARCH_CPUCFG20 0x14 +#define CPUCFG20_L3_WAYS_M GENMASK(15, 0) +#define CPUCFG20_L3_SETS_M GENMASK(23, 16) +#define CPUCFG20_L3_SIZE_M GENMASK(30, 24) +#define CPUCFG20_L3_WAYS 0 +#define CPUCFG20_L3_SETS 16 +#define CPUCFG20_L3_SIZE 24 + +#define LOONGARCH_CPUCFG48 0x30 +#define CPUCFG48_MCSR_LCK BIT(0) +#define CPUCFG48_NAP_EN BIT(1) +#define CPUCFG48_VFPU_CG BIT(2) +#define CPUCFG48_RAM_CG BIT(3) + +#ifndef __ASSEMBLY__ + +/* CSR */ +static __always_inline u32 csr_read32(u32 reg) +{ + return __csrrd_w(reg); +} + +static __always_inline u64 csr_read64(u32 reg) +{ + return __csrrd_d(reg); +} + +static __always_inline void csr_write32(u32 val, u32 reg) +{ + __csrwr_w(val, reg); +} + +static __always_inline void csr_write64(u64 val, u32 reg) +{ + __csrwr_d(val, reg); +} + +static __always_inline u32 csr_xchg32(u32 val, u32 mask, u32 reg) +{ + return __csrxchg_w(val, mask, reg); +} + +static __always_inline u64 csr_xchg64(u64 val, u64 mask, u32 reg) +{ + return __csrxchg_d(val, mask, reg); +} + +/* IOCSR */ +static __always_inline u32 iocsr_read32(u32 reg) +{ + return __iocsrrd_w(reg); +} + +static __always_inline u64 iocsr_read64(u32 reg) +{ + return __iocsrrd_d(reg); +} + +static __always_inline void iocsr_write32(u32 val, u32 reg) +{ + __iocsrwr_w(val, reg); +} + +static __always_inline void iocsr_write64(u64 val, u32 reg) +{ + __iocsrwr_d(val, reg); +} + +#endif /* !__ASSEMBLY__ */ + +/* CSR register number */ + +/* Basic CSR registers */ +#define LOONGARCH_CSR_CRMD 0x0 /* Current mode info */ +#define CSR_CRMD_WE_SHIFT 9 +#define CSR_CRMD_WE (_ULCAST_(0x1) << CSR_CRMD_WE_SHIFT) +#define CSR_CRMD_DACM_SHIFT 7 +#define CSR_CRMD_DACM_WIDTH 2 +#define CSR_CRMD_DACM (_ULCAST_(0x3) << CSR_CRMD_DACM_SHIFT) +#define CSR_CRMD_DACF_SHIFT 5 +#define CSR_CRMD_DACF_WIDTH 2 +#define CSR_CRMD_DACF (_ULCAST_(0x3) << CSR_CRMD_DACF_SHIFT) +#define CSR_CRMD_PG_SHIFT 4 +#define CSR_CRMD_PG (_ULCAST_(0x1) << CSR_CRMD_PG_SHIFT) +#define CSR_CRMD_DA_SHIFT 3 +#define CSR_CRMD_DA (_ULCAST_(0x1) << CSR_CRMD_DA_SHIFT) +#define CSR_CRMD_IE_SHIFT 2 +#define CSR_CRMD_IE (_ULCAST_(0x1) << CSR_CRMD_IE_SHIFT) +#define CSR_CRMD_PLV_SHIFT 0 +#define CSR_CRMD_PLV_WIDTH 2 +#define CSR_CRMD_PLV (_ULCAST_(0x3) << CSR_CRMD_PLV_SHIFT) + +#define PLV_KERN 0 +#define PLV_USER 3 +#define PLV_MASK 0x3 + +#define LOONGARCH_CSR_PRMD 0x1 /* Prev-exception mode info */ +#define CSR_PRMD_PWE_SHIFT 3 +#define CSR_PRMD_PWE (_ULCAST_(0x1) << CSR_PRMD_PWE_SHIFT) +#define CSR_PRMD_PIE_SHIFT 2 +#define CSR_PRMD_PIE (_ULCAST_(0x1) << CSR_PRMD_PIE_SHIFT) +#define CSR_PRMD_PPLV_SHIFT 0 +#define CSR_PRMD_PPLV_WIDTH 2 +#define CSR_PRMD_PPLV (_ULCAST_(0x3) << CSR_PRMD_PPLV_SHIFT) + +#define LOONGARCH_CSR_EUEN 0x2 /* Extended unit enable */ +#define CSR_EUEN_LBTEN_SHIFT 3 +#define CSR_EUEN_LBTEN (_ULCAST_(0x1) << CSR_EUEN_LBTEN_SHIFT) +#define CSR_EUEN_LASXEN_SHIFT 2 +#define CSR_EUEN_LASXEN (_ULCAST_(0x1) << CSR_EUEN_LASXEN_SHIFT) +#define CSR_EUEN_LSXEN_SHIFT 1 +#define CSR_EUEN_LSXEN (_ULCAST_(0x1) << CSR_EUEN_LSXEN_SHIFT) +#define CSR_EUEN_FPEN_SHIFT 0 +#define CSR_EUEN_FPEN (_ULCAST_(0x1) << CSR_EUEN_FPEN_SHIFT) + +#define LOONGARCH_CSR_MISC 0x3 /* Misc config */ + +#define LOONGARCH_CSR_ECFG 0x4 /* Exception config */ +#define CSR_ECFG_VS_SHIFT 16 +#define CSR_ECFG_VS_WIDTH 3 +#define CSR_ECFG_VS (_ULCAST_(0x7) << CSR_ECFG_VS_SHIFT) +#define CSR_ECFG_IM_SHIFT 0 +#define CSR_ECFG_IM_WIDTH 13 +#define CSR_ECFG_IM (_ULCAST_(0x1fff) << CSR_ECFG_IM_SHIFT) + +#define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ +#define CSR_ESTAT_ESUBCODE_SHIFT 22 +#define CSR_ESTAT_ESUBCODE_WIDTH 9 +#define CSR_ESTAT_ESUBCODE (_ULCAST_(0x1ff) << CSR_ESTAT_ESUBCODE_SHIFT) +#define CSR_ESTAT_EXC_SHIFT 16 +#define CSR_ESTAT_EXC_WIDTH 6 +#define CSR_ESTAT_EXC (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT) +#define CSR_ESTAT_IS_SHIFT 0 +#define CSR_ESTAT_IS_WIDTH 15 +#define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT) + +#define LOONGARCH_CSR_ERA 0x6 /* ERA */ + +#define LOONGARCH_CSR_BADV 0x7 /* Bad virtual address */ + +#define LOONGARCH_CSR_BADI 0x8 /* Bad instruction */ + +#define LOONGARCH_CSR_EENTRY 0xc /* Exception entry */ + +/* TLB related CSR registers */ +#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP */ +#define CSR_TLBIDX_EHINV_SHIFT 31 +#define CSR_TLBIDX_EHINV (_ULCAST_(1) << CSR_TLBIDX_EHINV_SHIFT) +#define CSR_TLBIDX_PS_SHIFT 24 +#define CSR_TLBIDX_PS_WIDTH 6 +#define CSR_TLBIDX_PS (_ULCAST_(0x3f) << CSR_TLBIDX_PS_SHIFT) +#define CSR_TLBIDX_IDX_SHIFT 0 +#define CSR_TLBIDX_IDX_WIDTH 12 +#define CSR_TLBIDX_IDX (_ULCAST_(0xfff) << CSR_TLBIDX_IDX_SHIFT) +#define CSR_TLBIDX_SIZEM 0x3f000000 +#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT +#define CSR_TLBIDX_IDXM 0xfff +#define CSR_INVALID_ENTRY(e) (CSR_TLBIDX_EHINV | e) + +#define LOONGARCH_CSR_TLBEHI 0x11 /* TLB EntryHi */ + +#define LOONGARCH_CSR_TLBELO0 0x12 /* TLB EntryLo0 */ +#define CSR_TLBLO0_RPLV_SHIFT 63 +#define CSR_TLBLO0_RPLV (_ULCAST_(0x1) << CSR_TLBLO0_RPLV_SHIFT) +#define CSR_TLBLO0_NX_SHIFT 62 +#define CSR_TLBLO0_NX (_ULCAST_(0x1) << CSR_TLBLO0_NX_SHIFT) +#define CSR_TLBLO0_NR_SHIFT 61 +#define CSR_TLBLO0_NR (_ULCAST_(0x1) << CSR_TLBLO0_NR_SHIFT) +#define CSR_TLBLO0_PFN_SHIFT 12 +#define CSR_TLBLO0_PFN_WIDTH 36 +#define CSR_TLBLO0_PFN (_ULCAST_(0xfffffffff) << CSR_TLBLO0_PFN_SHIFT) +#define CSR_TLBLO0_GLOBAL_SHIFT 6 +#define CSR_TLBLO0_GLOBAL (_ULCAST_(0x1) << CSR_TLBLO0_GLOBAL_SHIFT) +#define CSR_TLBLO0_CCA_SHIFT 4 +#define CSR_TLBLO0_CCA_WIDTH 2 +#define CSR_TLBLO0_CCA (_ULCAST_(0x3) << CSR_TLBLO0_CCA_SHIFT) +#define CSR_TLBLO0_PLV_SHIFT 2 +#define CSR_TLBLO0_PLV_WIDTH 2 +#define CSR_TLBLO0_PLV (_ULCAST_(0x3) << CSR_TLBLO0_PLV_SHIFT) +#define CSR_TLBLO0_WE_SHIFT 1 +#define CSR_TLBLO0_WE (_ULCAST_(0x1) << CSR_TLBLO0_WE_SHIFT) +#define CSR_TLBLO0_V_SHIFT 0 +#define CSR_TLBLO0_V (_ULCAST_(0x1) << CSR_TLBLO0_V_SHIFT) + +#define LOONGARCH_CSR_TLBELO1 0x13 /* TLB EntryLo1 */ +#define CSR_TLBLO1_RPLV_SHIFT 63 +#define CSR_TLBLO1_RPLV (_ULCAST_(0x1) << CSR_TLBLO1_RPLV_SHIFT) +#define CSR_TLBLO1_NX_SHIFT 62 +#define CSR_TLBLO1_NX (_ULCAST_(0x1) << CSR_TLBLO1_NX_SHIFT) +#define CSR_TLBLO1_NR_SHIFT 61 +#define CSR_TLBLO1_NR (_ULCAST_(0x1) << CSR_TLBLO1_NR_SHIFT) +#define CSR_TLBLO1_PFN_SHIFT 12 +#define CSR_TLBLO1_PFN_WIDTH 36 +#define CSR_TLBLO1_PFN (_ULCAST_(0xfffffffff) << CSR_TLBLO1_PFN_SHIFT) +#define CSR_TLBLO1_GLOBAL_SHIFT 6 +#define CSR_TLBLO1_GLOBAL (_ULCAST_(0x1) << CSR_TLBLO1_GLOBAL_SHIFT) +#define CSR_TLBLO1_CCA_SHIFT 4 +#define CSR_TLBLO1_CCA_WIDTH 2 +#define CSR_TLBLO1_CCA (_ULCAST_(0x3) << CSR_TLBLO1_CCA_SHIFT) +#define CSR_TLBLO1_PLV_SHIFT 2 +#define CSR_TLBLO1_PLV_WIDTH 2 +#define CSR_TLBLO1_PLV (_ULCAST_(0x3) << CSR_TLBLO1_PLV_SHIFT) +#define CSR_TLBLO1_WE_SHIFT 1 +#define CSR_TLBLO1_WE (_ULCAST_(0x1) << CSR_TLBLO1_WE_SHIFT) +#define CSR_TLBLO1_V_SHIFT 0 +#define CSR_TLBLO1_V (_ULCAST_(0x1) << CSR_TLBLO1_V_SHIFT) + +#define LOONGARCH_CSR_GTLBC 0x15 /* Guest TLB control */ +#define CSR_GTLBC_RID_SHIFT 16 +#define CSR_GTLBC_RID_WIDTH 8 +#define CSR_GTLBC_RID (_ULCAST_(0xff) << CSR_GTLBC_RID_SHIFT) +#define CSR_GTLBC_TOTI_SHIFT 13 +#define CSR_GTLBC_TOTI (_ULCAST_(0x1) << CSR_GTLBC_TOTI_SHIFT) +#define CSR_GTLBC_USERID_SHIFT 12 +#define CSR_GTLBC_USERID (_ULCAST_(0x1) << CSR_GTLBC_USERID_SHIFT) +#define CSR_GTLBC_GMTLBSZ_SHIFT 0 +#define CSR_GTLBC_GMTLBSZ_WIDTH 6 +#define CSR_GTLBC_GMTLBSZ (_ULCAST_(0x3f) << CSR_GTLBC_GMTLBSZ_SHIFT) + +#define LOONGARCH_CSR_TRGP 0x16 /* TLBR read guest info */ +#define CSR_TRGP_RID_SHIFT 16 +#define CSR_TRGP_RID_WIDTH 8 +#define CSR_TRGP_RID (_ULCAST_(0xff) << CSR_TRGP_RID_SHIFT) +#define CSR_TRGP_GTLB_SHIFT 0 +#define CSR_TRGP_GTLB (1 << CSR_TRGP_GTLB_SHIFT) + +#define LOONGARCH_CSR_ASID 0x18 /* ASID */ +#define CSR_ASID_BIT_SHIFT 16 /* ASIDBits */ +#define CSR_ASID_BIT_WIDTH 8 +#define CSR_ASID_BIT (_ULCAST_(0xff) << CSR_ASID_BIT_SHIFT) +#define CSR_ASID_ASID_SHIFT 0 +#define CSR_ASID_ASID_WIDTH 10 +#define CSR_ASID_ASID (_ULCAST_(0x3ff) << CSR_ASID_ASID_SHIFT) + +#define LOONGARCH_CSR_PGDL 0x19 /* Page table base address when VA[47] = 0 */ + +#define LOONGARCH_CSR_PGDH 0x1a /* Page table base address when VA[47] = 1 */ + +#define LOONGARCH_CSR_PGD 0x1b /* Page table base */ + +#define LOONGARCH_CSR_PWCTL0 0x1c /* PWCtl0 */ +#define CSR_PWCTL0_PTEW_SHIFT 30 +#define CSR_PWCTL0_PTEW_WIDTH 2 +#define CSR_PWCTL0_PTEW (_ULCAST_(0x3) << CSR_PWCTL0_PTEW_SHIFT) +#define CSR_PWCTL0_DIR1WIDTH_SHIFT 25 +#define CSR_PWCTL0_DIR1WIDTH_WIDTH 5 +#define CSR_PWCTL0_DIR1WIDTH (_ULCAST_(0x1f) << CSR_PWCTL0_DIR1WIDTH_SHIFT) +#define CSR_PWCTL0_DIR1BASE_SHIFT 20 +#define CSR_PWCTL0_DIR1BASE_WIDTH 5 +#define CSR_PWCTL0_DIR1BASE (_ULCAST_(0x1f) << CSR_PWCTL0_DIR1BASE_SHIFT) +#define CSR_PWCTL0_DIR0WIDTH_SHIFT 15 +#define CSR_PWCTL0_DIR0WIDTH_WIDTH 5 +#define CSR_PWCTL0_DIR0WIDTH (_ULCAST_(0x1f) << CSR_PWCTL0_DIR0WIDTH_SHIFT) +#define CSR_PWCTL0_DIR0BASE_SHIFT 10 +#define CSR_PWCTL0_DIR0BASE_WIDTH 5 +#define CSR_PWCTL0_DIR0BASE (_ULCAST_(0x1f) << CSR_PWCTL0_DIR0BASE_SHIFT) +#define CSR_PWCTL0_PTWIDTH_SHIFT 5 +#define CSR_PWCTL0_PTWIDTH_WIDTH 5 +#define CSR_PWCTL0_PTWIDTH (_ULCAST_(0x1f) << CSR_PWCTL0_PTWIDTH_SHIFT) +#define CSR_PWCTL0_PTBASE_SHIFT 0 +#define CSR_PWCTL0_PTBASE_WIDTH 5 +#define CSR_PWCTL0_PTBASE (_ULCAST_(0x1f) << CSR_PWCTL0_PTBASE_SHIFT) + +#define LOONGARCH_CSR_PWCTL1 0x1d /* PWCtl1 */ +#define CSR_PWCTL1_DIR3WIDTH_SHIFT 18 +#define CSR_PWCTL1_DIR3WIDTH_WIDTH 5 +#define CSR_PWCTL1_DIR3WIDTH (_ULCAST_(0x1f) << CSR_PWCTL1_DIR3WIDTH_SHIFT) +#define CSR_PWCTL1_DIR3BASE_SHIFT 12 +#define CSR_PWCTL1_DIR3BASE_WIDTH 5 +#define CSR_PWCTL1_DIR3BASE (_ULCAST_(0x1f) << CSR_PWCTL0_DIR3BASE_SHIFT) +#define CSR_PWCTL1_DIR2WIDTH_SHIFT 6 +#define CSR_PWCTL1_DIR2WIDTH_WIDTH 5 +#define CSR_PWCTL1_DIR2WIDTH (_ULCAST_(0x1f) << CSR_PWCTL1_DIR2WIDTH_SHIFT) +#define CSR_PWCTL1_DIR2BASE_SHIFT 0 +#define CSR_PWCTL1_DIR2BASE_WIDTH 5 +#define CSR_PWCTL1_DIR2BASE (_ULCAST_(0x1f) << CSR_PWCTL0_DIR2BASE_SHIFT) + +#define LOONGARCH_CSR_STLBPGSIZE 0x1e +#define CSR_STLBPGSIZE_PS_WIDTH 6 +#define CSR_STLBPGSIZE_PS (_ULCAST_(0x3f)) + +#define LOONGARCH_CSR_RVACFG 0x1f +#define CSR_RVACFG_RDVA_WIDTH 4 +#define CSR_RVACFG_RDVA (_ULCAST_(0xf)) + +/* Config CSR registers */ +#define LOONGARCH_CSR_CPUID 0x20 /* CPU core id */ +#define CSR_CPUID_COREID_WIDTH 9 +#define CSR_CPUID_COREID _ULCAST_(0x1ff) + +#define LOONGARCH_CSR_PRCFG1 0x21 /* Config1 */ +#define CSR_CONF1_VSMAX_SHIFT 12 +#define CSR_CONF1_VSMAX_WIDTH 3 +#define CSR_CONF1_VSMAX (_ULCAST_(7) << CSR_CONF1_VSMAX_SHIFT) +#define CSR_CONF1_TMRBITS_SHIFT 4 +#define CSR_CONF1_TMRBITS_WIDTH 8 +#define CSR_CONF1_TMRBITS (_ULCAST_(0xff) << CSR_CONF1_TMRBITS_SHIFT) +#define CSR_CONF1_KSNUM_WIDTH 4 +#define CSR_CONF1_KSNUM _ULCAST_(0xf) + +#define LOONGARCH_CSR_PRCFG2 0x22 /* Config2 */ +#define CSR_CONF2_PGMASK_SUPP 0x3ffff000 + +#define LOONGARCH_CSR_PRCFG3 0x23 /* Config3 */ +#define CSR_CONF3_STLBIDX_SHIFT 20 +#define CSR_CONF3_STLBIDX_WIDTH 6 +#define CSR_CONF3_STLBIDX (_ULCAST_(0x3f) << CSR_CONF3_STLBIDX_SHIFT) +#define CSR_CONF3_STLBWAYS_SHIFT 12 +#define CSR_CONF3_STLBWAYS_WIDTH 8 +#define CSR_CONF3_STLBWAYS (_ULCAST_(0xff) << CSR_CONF3_STLBWAYS_SHIFT) +#define CSR_CONF3_MTLBSIZE_SHIFT 4 +#define CSR_CONF3_MTLBSIZE_WIDTH 8 +#define CSR_CONF3_MTLBSIZE (_ULCAST_(0xff) << CSR_CONF3_MTLBSIZE_SHIFT) +#define CSR_CONF3_TLBTYPE_SHIFT 0 +#define CSR_CONF3_TLBTYPE_WIDTH 4 +#define CSR_CONF3_TLBTYPE (_ULCAST_(0xf) << CSR_CONF3_TLBTYPE_SHIFT) + +/* KSave registers */ +#define LOONGARCH_CSR_KS0 0x30 +#define LOONGARCH_CSR_KS1 0x31 +#define LOONGARCH_CSR_KS2 0x32 +#define LOONGARCH_CSR_KS3 0x33 +#define LOONGARCH_CSR_KS4 0x34 +#define LOONGARCH_CSR_KS5 0x35 +#define LOONGARCH_CSR_KS6 0x36 +#define LOONGARCH_CSR_KS7 0x37 +#define LOONGARCH_CSR_KS8 0x38 + +/* Exception allocated KS0, KS1 and KS2 statically */ +#define EXCEPTION_KS0 LOONGARCH_CSR_KS0 +#define EXCEPTION_KS1 LOONGARCH_CSR_KS1 +#define EXCEPTION_KS2 LOONGARCH_CSR_KS2 +#define EXC_KSAVE_MASK (1 << 0 | 1 << 1 | 1 << 2) + +/* Percpu-data base allocated KS3 statically */ +#define PERCPU_BASE_KS LOONGARCH_CSR_KS3 +#define PERCPU_KSAVE_MASK (1 << 3) + +/* KVM allocated KS4 and KS5 statically */ +#define KVM_VCPU_KS LOONGARCH_CSR_KS4 +#define KVM_TEMP_KS LOONGARCH_CSR_KS5 +#define KVM_KSAVE_MASK (1 << 4 | 1 << 5) + +/* Timer registers */ +#define LOONGARCH_CSR_TMID 0x40 /* Timer ID */ + +#define LOONGARCH_CSR_TCFG 0x41 /* Timer config */ +#define CSR_TCFG_VAL_SHIFT 2 +#define CSR_TCFG_VAL_WIDTH 48 +#define CSR_TCFG_VAL (_ULCAST_(0x3fffffffffff) << CSR_TCFG_VAL_SHIFT) +#define CSR_TCFG_PERIOD_SHIFT 1 +#define CSR_TCFG_PERIOD (_ULCAST_(0x1) << CSR_TCFG_PERIOD_SHIFT) +#define CSR_TCFG_EN (_ULCAST_(0x1)) + +#define LOONGARCH_CSR_TVAL 0x42 /* Timer value */ + +#define LOONGARCH_CSR_CNTC 0x43 /* Timer offset */ + +#define LOONGARCH_CSR_TINTCLR 0x44 /* Timer interrupt clear */ +#define CSR_TINTCLR_TI_SHIFT 0 +#define CSR_TINTCLR_TI (1 << CSR_TINTCLR_TI_SHIFT) + +/* Guest registers */ +#define LOONGARCH_CSR_GSTAT 0x50 /* Guest status */ +#define CSR_GSTAT_GID_SHIFT 16 +#define CSR_GSTAT_GID_WIDTH 8 +#define CSR_GSTAT_GID (_ULCAST_(0xff) << CSR_GSTAT_GID_SHIFT) +#define CSR_GSTAT_GIDBIT_SHIFT 4 +#define CSR_GSTAT_GIDBIT_WIDTH 6 +#define CSR_GSTAT_GIDBIT (_ULCAST_(0x3f) << CSR_GSTAT_GIDBIT_SHIFT) +#define CSR_GSTAT_PVM_SHIFT 1 +#define CSR_GSTAT_PVM (_ULCAST_(0x1) << CSR_GSTAT_PVM_SHIFT) +#define CSR_GSTAT_VM_SHIFT 0 +#define CSR_GSTAT_VM (_ULCAST_(0x1) << CSR_GSTAT_VM_SHIFT) + +#define LOONGARCH_CSR_GCFG 0x51 /* Guest config */ +#define CSR_GCFG_GPERF_SHIFT 24 +#define CSR_GCFG_GPERF_WIDTH 3 +#define CSR_GCFG_GPERF (_ULCAST_(0x7) << CSR_GCFG_GPERF_SHIFT) +#define CSR_GCFG_GCI_SHIFT 20 +#define CSR_GCFG_GCI_WIDTH 2 +#define CSR_GCFG_GCI (_ULCAST_(0x3) << CSR_GCFG_GCI_SHIFT) +#define CSR_GCFG_GCI_ALL (_ULCAST_(0x0) << CSR_GCFG_GCI_SHIFT) +#define CSR_GCFG_GCI_HIT (_ULCAST_(0x1) << CSR_GCFG_GCI_SHIFT) +#define CSR_GCFG_GCI_SECURE (_ULCAST_(0x2) << CSR_GCFG_GCI_SHIFT) +#define CSR_GCFG_GCIP_SHIFT 16 +#define CSR_GCFG_GCIP (_ULCAST_(0xf) << CSR_GCFG_GCIP_SHIFT) +#define CSR_GCFG_GCIP_ALL (_ULCAST_(0x1) << CSR_GCFG_GCIP_SHIFT) +#define CSR_GCFG_GCIP_HIT (_ULCAST_(0x1) << (CSR_GCFG_GCIP_SHIFT + 1)) +#define CSR_GCFG_GCIP_SECURE (_ULCAST_(0x1) << (CSR_GCFG_GCIP_SHIFT + 2)) +#define CSR_GCFG_TORU_SHIFT 15 +#define CSR_GCFG_TORU (_ULCAST_(0x1) << CSR_GCFG_TORU_SHIFT) +#define CSR_GCFG_TORUP_SHIFT 14 +#define CSR_GCFG_TORUP (_ULCAST_(0x1) << CSR_GCFG_TORUP_SHIFT) +#define CSR_GCFG_TOP_SHIFT 13 +#define CSR_GCFG_TOP (_ULCAST_(0x1) << CSR_GCFG_TOP_SHIFT) +#define CSR_GCFG_TOPP_SHIFT 12 +#define CSR_GCFG_TOPP (_ULCAST_(0x1) << CSR_GCFG_TOPP_SHIFT) +#define CSR_GCFG_TOE_SHIFT 11 +#define CSR_GCFG_TOE (_ULCAST_(0x1) << CSR_GCFG_TOE_SHIFT) +#define CSR_GCFG_TOEP_SHIFT 10 +#define CSR_GCFG_TOEP (_ULCAST_(0x1) << CSR_GCFG_TOEP_SHIFT) +#define CSR_GCFG_TIT_SHIFT 9 +#define CSR_GCFG_TIT (_ULCAST_(0x1) << CSR_GCFG_TIT_SHIFT) +#define CSR_GCFG_TITP_SHIFT 8 +#define CSR_GCFG_TITP (_ULCAST_(0x1) << CSR_GCFG_TITP_SHIFT) +#define CSR_GCFG_SIT_SHIFT 7 +#define CSR_GCFG_SIT (_ULCAST_(0x1) << CSR_GCFG_SIT_SHIFT) +#define CSR_GCFG_SITP_SHIFT 6 +#define CSR_GCFG_SITP (_ULCAST_(0x1) << CSR_GCFG_SITP_SHIFT) +#define CSR_GCFG_MATC_SHITF 4 +#define CSR_GCFG_MATC_WIDTH 2 +#define CSR_GCFG_MATC_MASK (_ULCAST_(0x3) << CSR_GCFG_MATC_SHITF) +#define CSR_GCFG_MATC_GUEST (_ULCAST_(0x0) << CSR_GCFG_MATC_SHITF) +#define CSR_GCFG_MATC_ROOT (_ULCAST_(0x1) << CSR_GCFG_MATC_SHITF) +#define CSR_GCFG_MATC_NEST (_ULCAST_(0x2) << CSR_GCFG_MATC_SHITF) + +#define LOONGARCH_CSR_GINTC 0x52 /* Guest interrupt control */ +#define CSR_GINTC_HC_SHIFT 16 +#define CSR_GINTC_HC_WIDTH 8 +#define CSR_GINTC_HC (_ULCAST_(0xff) << CSR_GINTC_HC_SHIFT) +#define CSR_GINTC_PIP_SHIFT 8 +#define CSR_GINTC_PIP_WIDTH 8 +#define CSR_GINTC_PIP (_ULCAST_(0xff) << CSR_GINTC_PIP_SHIFT) +#define CSR_GINTC_VIP_SHIFT 0 +#define CSR_GINTC_VIP_WIDTH 8 +#define CSR_GINTC_VIP (_ULCAST_(0xff)) + +#define LOONGARCH_CSR_GCNTC 0x53 /* Guest timer offset */ + +/* LLBCTL register */ +#define LOONGARCH_CSR_LLBCTL 0x60 /* LLBit control */ +#define CSR_LLBCTL_ROLLB_SHIFT 0 +#define CSR_LLBCTL_ROLLB (_ULCAST_(1) << CSR_LLBCTL_ROLLB_SHIFT) +#define CSR_LLBCTL_WCLLB_SHIFT 1 +#define CSR_LLBCTL_WCLLB (_ULCAST_(1) << CSR_LLBCTL_WCLLB_SHIFT) +#define CSR_LLBCTL_KLO_SHIFT 2 +#define CSR_LLBCTL_KLO (_ULCAST_(1) << CSR_LLBCTL_KLO_SHIFT) + +/* Implement dependent */ +#define LOONGARCH_CSR_IMPCTL1 0x80 /* Loongson config1 */ +#define CSR_MISPEC_SHIFT 20 +#define CSR_MISPEC_WIDTH 8 +#define CSR_MISPEC (_ULCAST_(0xff) << CSR_MISPEC_SHIFT) +#define CSR_SSEN_SHIFT 18 +#define CSR_SSEN (_ULCAST_(1) << CSR_SSEN_SHIFT) +#define CSR_SCRAND_SHIFT 17 +#define CSR_SCRAND (_ULCAST_(1) << CSR_SCRAND_SHIFT) +#define CSR_LLEXCL_SHIFT 16 +#define CSR_LLEXCL (_ULCAST_(1) << CSR_LLEXCL_SHIFT) +#define CSR_DISVC_SHIFT 15 +#define CSR_DISVC (_ULCAST_(1) << CSR_DISVC_SHIFT) +#define CSR_VCLRU_SHIFT 14 +#define CSR_VCLRU (_ULCAST_(1) << CSR_VCLRU_SHIFT) +#define CSR_DCLRU_SHIFT 13 +#define CSR_DCLRU (_ULCAST_(1) << CSR_DCLRU_SHIFT) +#define CSR_FASTLDQ_SHIFT 12 +#define CSR_FASTLDQ (_ULCAST_(1) << CSR_FASTLDQ_SHIFT) +#define CSR_USERCAC_SHIFT 11 +#define CSR_USERCAC (_ULCAST_(1) << CSR_USERCAC_SHIFT) +#define CSR_ANTI_MISPEC_SHIFT 10 +#define CSR_ANTI_MISPEC (_ULCAST_(1) << CSR_ANTI_MISPEC_SHIFT) +#define CSR_AUTO_FLUSHSFB_SHIFT 9 +#define CSR_AUTO_FLUSHSFB (_ULCAST_(1) << CSR_AUTO_FLUSHSFB_SHIFT) +#define CSR_STFILL_SHIFT 8 +#define CSR_STFILL (_ULCAST_(1) << CSR_STFILL_SHIFT) +#define CSR_LIFEP_SHIFT 7 +#define CSR_LIFEP (_ULCAST_(1) << CSR_LIFEP_SHIFT) +#define CSR_LLSYNC_SHIFT 6 +#define CSR_LLSYNC (_ULCAST_(1) << CSR_LLSYNC_SHIFT) +#define CSR_BRBTDIS_SHIFT 5 +#define CSR_BRBTDIS (_ULCAST_(1) << CSR_BRBTDIS_SHIFT) +#define CSR_RASDIS_SHIFT 4 +#define CSR_RASDIS (_ULCAST_(1) << CSR_RASDIS_SHIFT) +#define CSR_STPRE_SHIFT 2 +#define CSR_STPRE_WIDTH 2 +#define CSR_STPRE (_ULCAST_(3) << CSR_STPRE_SHIFT) +#define CSR_INSTPRE_SHIFT 1 +#define CSR_INSTPRE (_ULCAST_(1) << CSR_INSTPRE_SHIFT) +#define CSR_DATAPRE_SHIFT 0 +#define CSR_DATAPRE (_ULCAST_(1) << CSR_DATAPRE_SHIFT) + +#define LOONGARCH_CSR_IMPCTL2 0x81 /* Loongson config2 */ +#define CSR_FLUSH_MTLB_SHIFT 0 +#define CSR_FLUSH_MTLB (_ULCAST_(1) << CSR_FLUSH_MTLB_SHIFT) +#define CSR_FLUSH_STLB_SHIFT 1 +#define CSR_FLUSH_STLB (_ULCAST_(1) << CSR_FLUSH_STLB_SHIFT) +#define CSR_FLUSH_DTLB_SHIFT 2 +#define CSR_FLUSH_DTLB (_ULCAST_(1) << CSR_FLUSH_DTLB_SHIFT) +#define CSR_FLUSH_ITLB_SHIFT 3 +#define CSR_FLUSH_ITLB (_ULCAST_(1) << CSR_FLUSH_ITLB_SHIFT) +#define CSR_FLUSH_BTAC_SHIFT 4 +#define CSR_FLUSH_BTAC (_ULCAST_(1) << CSR_FLUSH_BTAC_SHIFT) + +#define LOONGARCH_CSR_GNMI 0x82 + +/* TLB Refill registers */ +#define LOONGARCH_CSR_TLBRENTRY 0x88 /* TLB refill exception entry */ +#define LOONGARCH_CSR_TLBRBADV 0x89 /* TLB refill badvaddr */ +#define LOONGARCH_CSR_TLBRERA 0x8a /* TLB refill ERA */ +#define LOONGARCH_CSR_TLBRSAVE 0x8b /* KSave for TLB refill exception */ +#define LOONGARCH_CSR_TLBRELO0 0x8c /* TLB refill entrylo0 */ +#define LOONGARCH_CSR_TLBRELO1 0x8d /* TLB refill entrylo1 */ +#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */ +#define CSR_TLBREHI_PS_SHIFT 0 +#define CSR_TLBREHI_PS (_ULCAST_(0x3f) << CSR_TLBREHI_PS_SHIFT) +#define LOONGARCH_CSR_TLBRPRMD 0x8f /* TLB refill mode info */ + +/* Machine Error registers */ +#define LOONGARCH_CSR_MERRCTL 0x90 /* MERRCTL */ +#define LOONGARCH_CSR_MERRINFO1 0x91 /* MError info1 */ +#define LOONGARCH_CSR_MERRINFO2 0x92 /* MError info2 */ +#define LOONGARCH_CSR_MERRENTRY 0x93 /* MError exception entry */ +#define LOONGARCH_CSR_MERRERA 0x94 /* MError exception ERA */ +#define LOONGARCH_CSR_MERRSAVE 0x95 /* KSave for machine error exception */ + +#define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */ + +#define LOONGARCH_CSR_PRID 0xc0 + +/* Shadow MCSR : 0xc0 ~ 0xff */ +#define LOONGARCH_CSR_MCSR0 0xc0 /* CPUCFG0 and CPUCFG1 */ +#define MCSR0_INT_IMPL_SHIFT 58 +#define MCSR0_INT_IMPL 0 +#define MCSR0_IOCSR_BRD_SHIFT 57 +#define MCSR0_IOCSR_BRD (_ULCAST_(1) << MCSR0_IOCSR_BRD_SHIFT) +#define MCSR0_HUGEPG_SHIFT 56 +#define MCSR0_HUGEPG (_ULCAST_(1) << MCSR0_HUGEPG_SHIFT) +#define MCSR0_RPLMTLB_SHIFT 55 +#define MCSR0_RPLMTLB (_ULCAST_(1) << MCSR0_RPLMTLB_SHIFT) +#define MCSR0_EP_SHIFT 54 +#define MCSR0_EP (_ULCAST_(1) << MCSR0_EP_SHIFT) +#define MCSR0_RI_SHIFT 53 +#define MCSR0_RI (_ULCAST_(1) << MCSR0_RI_SHIFT) +#define MCSR0_UAL_SHIFT 52 +#define MCSR0_UAL (_ULCAST_(1) << MCSR0_UAL_SHIFT) +#define MCSR0_VABIT_SHIFT 44 +#define MCSR0_VABIT_WIDTH 8 +#define MCSR0_VABIT (_ULCAST_(0xff) << MCSR0_VABIT_SHIFT) +#define VABIT_DEFAULT 0x2f +#define MCSR0_PABIT_SHIFT 36 +#define MCSR0_PABIT_WIDTH 8 +#define MCSR0_PABIT (_ULCAST_(0xff) << MCSR0_PABIT_SHIFT) +#define PABIT_DEFAULT 0x2f +#define MCSR0_IOCSR_SHIFT 35 +#define MCSR0_IOCSR (_ULCAST_(1) << MCSR0_IOCSR_SHIFT) +#define MCSR0_PAGING_SHIFT 34 +#define MCSR0_PAGING (_ULCAST_(1) << MCSR0_PAGING_SHIFT) +#define MCSR0_GR64_SHIFT 33 +#define MCSR0_GR64 (_ULCAST_(1) << MCSR0_GR64_SHIFT) +#define GR64_DEFAULT 1 +#define MCSR0_GR32_SHIFT 32 +#define MCSR0_GR32 (_ULCAST_(1) << MCSR0_GR32_SHIFT) +#define GR32_DEFAULT 0 +#define MCSR0_PRID_WIDTH 32 +#define MCSR0_PRID 0x14C010 + +#define LOONGARCH_CSR_MCSR1 0xc1 /* CPUCFG2 and CPUCFG3 */ +#define MCSR1_HPFOLD_SHIFT 43 +#define MCSR1_HPFOLD (_ULCAST_(1) << MCSR1_HPFOLD_SHIFT) +#define MCSR1_SPW_LVL_SHIFT 40 +#define MCSR1_SPW_LVL_WIDTH 3 +#define MCSR1_SPW_LVL (_ULCAST_(7) << MCSR1_SPW_LVL_SHIFT) +#define MCSR1_ICACHET_SHIFT 39 +#define MCSR1_ICACHET (_ULCAST_(1) << MCSR1_ICACHET_SHIFT) +#define MCSR1_ITLBT_SHIFT 38 +#define MCSR1_ITLBT (_ULCAST_(1) << MCSR1_ITLBT_SHIFT) +#define MCSR1_LLDBAR_SHIFT 37 +#define MCSR1_LLDBAR (_ULCAST_(1) << MCSR1_LLDBAR_SHIFT) +#define MCSR1_SCDLY_SHIFT 36 +#define MCSR1_SCDLY (_ULCAST_(1) << MCSR1_SCDLY_SHIFT) +#define MCSR1_LLEXC_SHIFT 35 +#define MCSR1_LLEXC (_ULCAST_(1) << MCSR1_LLEXC_SHIFT) +#define MCSR1_UCACC_SHIFT 34 +#define MCSR1_UCACC (_ULCAST_(1) << MCSR1_UCACC_SHIFT) +#define MCSR1_SFB_SHIFT 33 +#define MCSR1_SFB (_ULCAST_(1) << MCSR1_SFB_SHIFT) +#define MCSR1_CCDMA_SHIFT 32 +#define MCSR1_CCDMA (_ULCAST_(1) << MCSR1_CCDMA_SHIFT) +#define MCSR1_LAMO_SHIFT 22 +#define MCSR1_LAMO (_ULCAST_(1) << MCSR1_LAMO_SHIFT) +#define MCSR1_LSPW_SHIFT 21 +#define MCSR1_LSPW (_ULCAST_(1) << MCSR1_LSPW_SHIFT) +#define MCSR1_MIPSBT_SHIFT 20 +#define MCSR1_MIPSBT (_ULCAST_(1) << MCSR1_MIPSBT_SHIFT) +#define MCSR1_ARMBT_SHIFT 19 +#define MCSR1_ARMBT (_ULCAST_(1) << MCSR1_ARMBT_SHIFT) +#define MCSR1_X86BT_SHIFT 18 +#define MCSR1_X86BT (_ULCAST_(1) << MCSR1_X86BT_SHIFT) +#define MCSR1_LLFTPVERS_SHIFT 15 +#define MCSR1_LLFTPVERS_WIDTH 3 +#define MCSR1_LLFTPVERS (_ULCAST_(7) << MCSR1_LLFTPVERS_SHIFT) +#define MCSR1_LLFTP_SHIFT 14 +#define MCSR1_LLFTP (_ULCAST_(1) << MCSR1_LLFTP_SHIFT) +#define MCSR1_VZVERS_SHIFT 11 +#define MCSR1_VZVERS_WIDTH 3 +#define MCSR1_VZVERS (_ULCAST_(7) << MCSR1_VZVERS_SHIFT) +#define MCSR1_VZ_SHIFT 10 +#define MCSR1_VZ (_ULCAST_(1) << MCSR1_VZ_SHIFT) +#define MCSR1_CRYPTO_SHIFT 9 +#define MCSR1_CRYPTO (_ULCAST_(1) << MCSR1_CRYPTO_SHIFT) +#define MCSR1_COMPLEX_SHIFT 8 +#define MCSR1_COMPLEX (_ULCAST_(1) << MCSR1_COMPLEX_SHIFT) +#define MCSR1_LASX_SHIFT 7 +#define MCSR1_LASX (_ULCAST_(1) << MCSR1_LASX_SHIFT) +#define MCSR1_LSX_SHIFT 6 +#define MCSR1_LSX (_ULCAST_(1) << MCSR1_LSX_SHIFT) +#define MCSR1_FPVERS_SHIFT 3 +#define MCSR1_FPVERS_WIDTH 3 +#define MCSR1_FPVERS (_ULCAST_(7) << MCSR1_FPVERS_SHIFT) +#define MCSR1_FPDP_SHIFT 2 +#define MCSR1_FPDP (_ULCAST_(1) << MCSR1_FPDP_SHIFT) +#define MCSR1_FPSP_SHIFT 1 +#define MCSR1_FPSP (_ULCAST_(1) << MCSR1_FPSP_SHIFT) +#define MCSR1_FP_SHIFT 0 +#define MCSR1_FP (_ULCAST_(1) << MCSR1_FP_SHIFT) + +#define LOONGARCH_CSR_MCSR2 0xc2 /* CPUCFG4 and CPUCFG5 */ +#define MCSR2_CCDIV_SHIFT 48 +#define MCSR2_CCDIV_WIDTH 16 +#define MCSR2_CCDIV (_ULCAST_(0xffff) << MCSR2_CCDIV_SHIFT) +#define MCSR2_CCMUL_SHIFT 32 +#define MCSR2_CCMUL_WIDTH 16 +#define MCSR2_CCMUL (_ULCAST_(0xffff) << MCSR2_CCMUL_SHIFT) +#define MCSR2_CCFREQ_WIDTH 32 +#define MCSR2_CCFREQ (_ULCAST_(0xffffffff)) +#define CCFREQ_DEFAULT 0x5f5e100 /* 100MHz */ + +#define LOONGARCH_CSR_MCSR3 0xc3 /* CPUCFG6 */ +#define MCSR3_UPM_SHIFT 14 +#define MCSR3_UPM (_ULCAST_(1) << MCSR3_UPM_SHIFT) +#define MCSR3_PMBITS_SHIFT 8 +#define MCSR3_PMBITS_WIDTH 6 +#define MCSR3_PMBITS (_ULCAST_(0x3f) << MCSR3_PMBITS_SHIFT) +#define PMBITS_DEFAULT 0x40 +#define MCSR3_PMNUM_SHIFT 4 +#define MCSR3_PMNUM_WIDTH 4 +#define MCSR3_PMNUM (_ULCAST_(0xf) << MCSR3_PMNUM_SHIFT) +#define MCSR3_PAMVER_SHIFT 1 +#define MCSR3_PAMVER_WIDTH 3 +#define MCSR3_PAMVER (_ULCAST_(0x7) << MCSR3_PAMVER_SHIFT) +#define MCSR3_PMP_SHIFT 0 +#define MCSR3_PMP (_ULCAST_(1) << MCSR3_PMP_SHIFT) + +#define LOONGARCH_CSR_MCSR8 0xc8 /* CPUCFG16 and CPUCFG17 */ +#define MCSR8_L1I_SIZE_SHIFT 56 +#define MCSR8_L1I_SIZE_WIDTH 7 +#define MCSR8_L1I_SIZE (_ULCAST_(0x7f) << MCSR8_L1I_SIZE_SHIFT) +#define MCSR8_L1I_IDX_SHIFT 48 +#define MCSR8_L1I_IDX_WIDTH 8 +#define MCSR8_L1I_IDX (_ULCAST_(0xff) << MCSR8_L1I_IDX_SHIFT) +#define MCSR8_L1I_WAY_SHIFT 32 +#define MCSR8_L1I_WAY_WIDTH 16 +#define MCSR8_L1I_WAY (_ULCAST_(0xffff) << MCSR8_L1I_WAY_SHIFT) +#define MCSR8_L3DINCL_SHIFT 16 +#define MCSR8_L3DINCL (_ULCAST_(1) << MCSR8_L3DINCL_SHIFT) +#define MCSR8_L3DPRIV_SHIFT 15 +#define MCSR8_L3DPRIV (_ULCAST_(1) << MCSR8_L3DPRIV_SHIFT) +#define MCSR8_L3DPRE_SHIFT 14 +#define MCSR8_L3DPRE (_ULCAST_(1) << MCSR8_L3DPRE_SHIFT) +#define MCSR8_L3IUINCL_SHIFT 13 +#define MCSR8_L3IUINCL (_ULCAST_(1) << MCSR8_L3IUINCL_SHIFT) +#define MCSR8_L3IUPRIV_SHIFT 12 +#define MCSR8_L3IUPRIV (_ULCAST_(1) << MCSR8_L3IUPRIV_SHIFT) +#define MCSR8_L3IUUNIFY_SHIFT 11 +#define MCSR8_L3IUUNIFY (_ULCAST_(1) << MCSR8_L3IUUNIFY_SHIFT) +#define MCSR8_L3IUPRE_SHIFT 10 +#define MCSR8_L3IUPRE (_ULCAST_(1) << MCSR8_L3IUPRE_SHIFT) +#define MCSR8_L2DINCL_SHIFT 9 +#define MCSR8_L2DINCL (_ULCAST_(1) << MCSR8_L2DINCL_SHIFT) +#define MCSR8_L2DPRIV_SHIFT 8 +#define MCSR8_L2DPRIV (_ULCAST_(1) << MCSR8_L2DPRIV_SHIFT) +#define MCSR8_L2DPRE_SHIFT 7 +#define MCSR8_L2DPRE (_ULCAST_(1) << MCSR8_L2DPRE_SHIFT) +#define MCSR8_L2IUINCL_SHIFT 6 +#define MCSR8_L2IUINCL (_ULCAST_(1) << MCSR8_L2IUINCL_SHIFT) +#define MCSR8_L2IUPRIV_SHIFT 5 +#define MCSR8_L2IUPRIV (_ULCAST_(1) << MCSR8_L2IUPRIV_SHIFT) +#define MCSR8_L2IUUNIFY_SHIFT 4 +#define MCSR8_L2IUUNIFY (_ULCAST_(1) << MCSR8_L2IUUNIFY_SHIFT) +#define MCSR8_L2IUPRE_SHIFT 3 +#define MCSR8_L2IUPRE (_ULCAST_(1) << MCSR8_L2IUPRE_SHIFT) +#define MCSR8_L1DPRE_SHIFT 2 +#define MCSR8_L1DPRE (_ULCAST_(1) << MCSR8_L1DPRE_SHIFT) +#define MCSR8_L1IUUNIFY_SHIFT 1 +#define MCSR8_L1IUUNIFY (_ULCAST_(1) << MCSR8_L1IUUNIFY_SHIFT) +#define MCSR8_L1IUPRE_SHIFT 0 +#define MCSR8_L1IUPRE (_ULCAST_(1) << MCSR8_L1IUPRE_SHIFT) + +#define LOONGARCH_CSR_MCSR9 0xc9 /* CPUCFG18 and CPUCFG19 */ +#define MCSR9_L2U_SIZE_SHIFT 56 +#define MCSR9_L2U_SIZE_WIDTH 7 +#define MCSR9_L2U_SIZE (_ULCAST_(0x7f) << MCSR9_L2U_SIZE_SHIFT) +#define MCSR9_L2U_IDX_SHIFT 48 +#define MCSR9_L2U_IDX_WIDTH 8 +#define MCSR9_L2U_IDX (_ULCAST_(0xff) << MCSR9_IDX_LOG_SHIFT) +#define MCSR9_L2U_WAY_SHIFT 32 +#define MCSR9_L2U_WAY_WIDTH 16 +#define MCSR9_L2U_WAY (_ULCAST_(0xffff) << MCSR9_L2U_WAY_SHIFT) +#define MCSR9_L1D_SIZE_SHIFT 24 +#define MCSR9_L1D_SIZE_WIDTH 7 +#define MCSR9_L1D_SIZE (_ULCAST_(0x7f) << MCSR9_L1D_SIZE_SHIFT) +#define MCSR9_L1D_IDX_SHIFT 16 +#define MCSR9_L1D_IDX_WIDTH 8 +#define MCSR9_L1D_IDX (_ULCAST_(0xff) << MCSR9_L1D_IDX_SHIFT) +#define MCSR9_L1D_WAY_SHIFT 0 +#define MCSR9_L1D_WAY_WIDTH 16 +#define MCSR9_L1D_WAY (_ULCAST_(0xffff) << MCSR9_L1D_WAY_SHIFT) + +#define LOONGARCH_CSR_MCSR10 0xca /* CPUCFG20 */ +#define MCSR10_L3U_SIZE_SHIFT 24 +#define MCSR10_L3U_SIZE_WIDTH 7 +#define MCSR10_L3U_SIZE (_ULCAST_(0x7f) << MCSR10_L3U_SIZE_SHIFT) +#define MCSR10_L3U_IDX_SHIFT 16 +#define MCSR10_L3U_IDX_WIDTH 8 +#define MCSR10_L3U_IDX (_ULCAST_(0xff) << MCSR10_L3U_IDX_SHIFT) +#define MCSR10_L3U_WAY_SHIFT 0 +#define MCSR10_L3U_WAY_WIDTH 16 +#define MCSR10_L3U_WAY (_ULCAST_(0xffff) << MCSR10_L3U_WAY_SHIFT) + +#define LOONGARCH_CSR_MCSR24 0xf0 /* cpucfg48 */ +#define MCSR24_RAMCG_SHIFT 3 +#define MCSR24_RAMCG (_ULCAST_(1) << MCSR24_RAMCG_SHIFT) +#define MCSR24_VFPUCG_SHIFT 2 +#define MCSR24_VFPUCG (_ULCAST_(1) << MCSR24_VFPUCG_SHIFT) +#define MCSR24_NAPEN_SHIFT 1 +#define MCSR24_NAPEN (_ULCAST_(1) << MCSR24_NAPEN_SHIFT) +#define MCSR24_MCSRLOCK_SHIFT 0 +#define MCSR24_MCSRLOCK (_ULCAST_(1) << MCSR24_MCSRLOCK_SHIFT) + +/* Uncached accelerate windows registers */ +#define LOONGARCH_CSR_UCAWIN 0x100 +#define LOONGARCH_CSR_UCAWIN0_LO 0x102 +#define LOONGARCH_CSR_UCAWIN0_HI 0x103 +#define LOONGARCH_CSR_UCAWIN1_LO 0x104 +#define LOONGARCH_CSR_UCAWIN1_HI 0x105 +#define LOONGARCH_CSR_UCAWIN2_LO 0x106 +#define LOONGARCH_CSR_UCAWIN2_HI 0x107 +#define LOONGARCH_CSR_UCAWIN3_LO 0x108 +#define LOONGARCH_CSR_UCAWIN3_HI 0x109 + +/* Direct Map windows registers */ +#define LOONGARCH_CSR_DMWIN0 0x180 /* 64 direct map win0: MEM & IF */ +#define LOONGARCH_CSR_DMWIN1 0x181 /* 64 direct map win1: MEM & IF */ +#define LOONGARCH_CSR_DMWIN2 0x182 /* 64 direct map win2: MEM */ +#define LOONGARCH_CSR_DMWIN3 0x183 /* 64 direct map win3: MEM */ + +/* Direct Map window 0/1 */ +#define CSR_DMW0_PLV0 _CONST64_(1 << 0) +#define CSR_DMW0_VSEG _CONST64_(0x8000) +#define CSR_DMW0_BASE (CSR_DMW0_VSEG << DMW_PABITS) +#define CSR_DMW0_INIT (CSR_DMW0_BASE | CSR_DMW0_PLV0) + +#define CSR_DMW1_PLV0 _CONST64_(1 << 0) +#define CSR_DMW1_MAT _CONST64_(1 << 4) +#define CSR_DMW1_VSEG _CONST64_(0x9000) +#define CSR_DMW1_BASE (CSR_DMW1_VSEG << DMW_PABITS) +#define CSR_DMW1_INIT (CSR_DMW1_BASE | CSR_DMW1_MAT | CSR_DMW1_PLV0) + +/* Performance Counter registers */ +#define LOONGARCH_CSR_PERFCTRL0 0x200 /* 32 perf event 0 config */ +#define LOONGARCH_CSR_PERFCNTR0 0x201 /* 64 perf event 0 count value */ +#define LOONGARCH_CSR_PERFCTRL1 0x202 /* 32 perf event 1 config */ +#define LOONGARCH_CSR_PERFCNTR1 0x203 /* 64 perf event 1 count value */ +#define LOONGARCH_CSR_PERFCTRL2 0x204 /* 32 perf event 2 config */ +#define LOONGARCH_CSR_PERFCNTR2 0x205 /* 64 perf event 2 count value */ +#define LOONGARCH_CSR_PERFCTRL3 0x206 /* 32 perf event 3 config */ +#define LOONGARCH_CSR_PERFCNTR3 0x207 /* 64 perf event 3 count value */ +#define CSR_PERFCTRL_PLV0 (_ULCAST_(1) << 16) +#define CSR_PERFCTRL_PLV1 (_ULCAST_(1) << 17) +#define CSR_PERFCTRL_PLV2 (_ULCAST_(1) << 18) +#define CSR_PERFCTRL_PLV3 (_ULCAST_(1) << 19) +#define CSR_PERFCTRL_IE (_ULCAST_(1) << 20) +#define CSR_PERFCTRL_EVENT 0x3ff + +/* Debug registers */ +#define LOONGARCH_CSR_MWPC 0x300 /* data breakpoint config */ +#define LOONGARCH_CSR_MWPS 0x301 /* data breakpoint status */ + +#define LOONGARCH_CSR_DB0ADDR 0x310 /* data breakpoint 0 address */ +#define LOONGARCH_CSR_DB0MASK 0x311 /* data breakpoint 0 mask */ +#define LOONGARCH_CSR_DB0CTL 0x312 /* data breakpoint 0 control */ +#define LOONGARCH_CSR_DB0ASID 0x313 /* data breakpoint 0 asid */ + +#define LOONGARCH_CSR_DB1ADDR 0x318 /* data breakpoint 1 address */ +#define LOONGARCH_CSR_DB1MASK 0x319 /* data breakpoint 1 mask */ +#define LOONGARCH_CSR_DB1CTL 0x31a /* data breakpoint 1 control */ +#define LOONGARCH_CSR_DB1ASID 0x31b /* data breakpoint 1 asid */ + +#define LOONGARCH_CSR_DB2ADDR 0x320 /* data breakpoint 2 address */ +#define LOONGARCH_CSR_DB2MASK 0x321 /* data breakpoint 2 mask */ +#define LOONGARCH_CSR_DB2CTL 0x322 /* data breakpoint 2 control */ +#define LOONGARCH_CSR_DB2ASID 0x323 /* data breakpoint 2 asid */ + +#define LOONGARCH_CSR_DB3ADDR 0x328 /* data breakpoint 3 address */ +#define LOONGARCH_CSR_DB3MASK 0x329 /* data breakpoint 3 mask */ +#define LOONGARCH_CSR_DB3CTL 0x32a /* data breakpoint 3 control */ +#define LOONGARCH_CSR_DB3ASID 0x32b /* data breakpoint 3 asid */ + +#define LOONGARCH_CSR_DB4ADDR 0x330 /* data breakpoint 4 address */ +#define LOONGARCH_CSR_DB4MASK 0x331 /* data breakpoint 4 maks */ +#define LOONGARCH_CSR_DB4CTL 0x332 /* data breakpoint 4 control */ +#define LOONGARCH_CSR_DB4ASID 0x333 /* data breakpoint 4 asid */ + +#define LOONGARCH_CSR_DB5ADDR 0x338 /* data breakpoint 5 address */ +#define LOONGARCH_CSR_DB5MASK 0x339 /* data breakpoint 5 mask */ +#define LOONGARCH_CSR_DB5CTL 0x33a /* data breakpoint 5 control */ +#define LOONGARCH_CSR_DB5ASID 0x33b /* data breakpoint 5 asid */ + +#define LOONGARCH_CSR_DB6ADDR 0x340 /* data breakpoint 6 address */ +#define LOONGARCH_CSR_DB6MASK 0x341 /* data breakpoint 6 mask */ +#define LOONGARCH_CSR_DB6CTL 0x342 /* data breakpoint 6 control */ +#define LOONGARCH_CSR_DB6ASID 0x343 /* data breakpoint 6 asid */ + +#define LOONGARCH_CSR_DB7ADDR 0x348 /* data breakpoint 7 address */ +#define LOONGARCH_CSR_DB7MASK 0x349 /* data breakpoint 7 mask */ +#define LOONGARCH_CSR_DB7CTL 0x34a /* data breakpoint 7 control */ +#define LOONGARCH_CSR_DB7ASID 0x34b /* data breakpoint 7 asid */ + +#define LOONGARCH_CSR_FWPC 0x380 /* instruction breakpoint config */ +#define LOONGARCH_CSR_FWPS 0x381 /* instruction breakpoint status */ + +#define LOONGARCH_CSR_IB0ADDR 0x390 /* inst breakpoint 0 address */ +#define LOONGARCH_CSR_IB0MASK 0x391 /* inst breakpoint 0 mask */ +#define LOONGARCH_CSR_IB0CTL 0x392 /* inst breakpoint 0 control */ +#define LOONGARCH_CSR_IB0ASID 0x393 /* inst breakpoint 0 asid */ + +#define LOONGARCH_CSR_IB1ADDR 0x398 /* inst breakpoint 1 address */ +#define LOONGARCH_CSR_IB1MASK 0x399 /* inst breakpoint 1 mask */ +#define LOONGARCH_CSR_IB1CTL 0x39a /* inst breakpoint 1 control */ +#define LOONGARCH_CSR_IB1ASID 0x39b /* inst breakpoint 1 asid */ + +#define LOONGARCH_CSR_IB2ADDR 0x3a0 /* inst breakpoint 2 address */ +#define LOONGARCH_CSR_IB2MASK 0x3a1 /* inst breakpoint 2 mask */ +#define LOONGARCH_CSR_IB2CTL 0x3a2 /* inst breakpoint 2 control */ +#define LOONGARCH_CSR_IB2ASID 0x3a3 /* inst breakpoint 2 asid */ + +#define LOONGARCH_CSR_IB3ADDR 0x3a8 /* inst breakpoint 3 address */ +#define LOONGARCH_CSR_IB3MASK 0x3a9 /* breakpoint 3 mask */ +#define LOONGARCH_CSR_IB3CTL 0x3aa /* inst breakpoint 3 control */ +#define LOONGARCH_CSR_IB3ASID 0x3ab /* inst breakpoint 3 asid */ + +#define LOONGARCH_CSR_IB4ADDR 0x3b0 /* inst breakpoint 4 address */ +#define LOONGARCH_CSR_IB4MASK 0x3b1 /* inst breakpoint 4 mask */ +#define LOONGARCH_CSR_IB4CTL 0x3b2 /* inst breakpoint 4 control */ +#define LOONGARCH_CSR_IB4ASID 0x3b3 /* inst breakpoint 4 asid */ + +#define LOONGARCH_CSR_IB5ADDR 0x3b8 /* inst breakpoint 5 address */ +#define LOONGARCH_CSR_IB5MASK 0x3b9 /* inst breakpoint 5 mask */ +#define LOONGARCH_CSR_IB5CTL 0x3ba /* inst breakpoint 5 control */ +#define LOONGARCH_CSR_IB5ASID 0x3bb /* inst breakpoint 5 asid */ + +#define LOONGARCH_CSR_IB6ADDR 0x3c0 /* inst breakpoint 6 address */ +#define LOONGARCH_CSR_IB6MASK 0x3c1 /* inst breakpoint 6 mask */ +#define LOONGARCH_CSR_IB6CTL 0x3c2 /* inst breakpoint 6 control */ +#define LOONGARCH_CSR_IB6ASID 0x3c3 /* inst breakpoint 6 asid */ + +#define LOONGARCH_CSR_IB7ADDR 0x3c8 /* inst breakpoint 7 address */ +#define LOONGARCH_CSR_IB7MASK 0x3c9 /* inst breakpoint 7 mask */ +#define LOONGARCH_CSR_IB7CTL 0x3ca /* inst breakpoint 7 control */ +#define LOONGARCH_CSR_IB7ASID 0x3cb /* inst breakpoint 7 asid */ + +#define LOONGARCH_CSR_DEBUG 0x500 /* debug config */ +#define LOONGARCH_CSR_DERA 0x501 /* debug era */ +#define LOONGARCH_CSR_DESAVE 0x502 /* debug save */ + +/* + * CSR_ECFG IM + */ +#define ECFG0_IM 0x00001fff +#define ECFGB_SIP0 0 +#define ECFGF_SIP0 (_ULCAST_(1) << ECFGB_SIP0) +#define ECFGB_SIP1 1 +#define ECFGF_SIP1 (_ULCAST_(1) << ECFGB_SIP1) +#define ECFGB_IP0 2 +#define ECFGF_IP0 (_ULCAST_(1) << ECFGB_IP0) +#define ECFGB_IP1 3 +#define ECFGF_IP1 (_ULCAST_(1) << ECFGB_IP1) +#define ECFGB_IP2 4 +#define ECFGF_IP2 (_ULCAST_(1) << ECFGB_IP2) +#define ECFGB_IP3 5 +#define ECFGF_IP3 (_ULCAST_(1) << ECFGB_IP3) +#define ECFGB_IP4 6 +#define ECFGF_IP4 (_ULCAST_(1) << ECFGB_IP4) +#define ECFGB_IP5 7 +#define ECFGF_IP5 (_ULCAST_(1) << ECFGB_IP5) +#define ECFGB_IP6 8 +#define ECFGF_IP6 (_ULCAST_(1) << ECFGB_IP6) +#define ECFGB_IP7 9 +#define ECFGF_IP7 (_ULCAST_(1) << ECFGB_IP7) +#define ECFGB_PMC 10 +#define ECFGF_PMC (_ULCAST_(1) << ECFGB_PMC) +#define ECFGB_TIMER 11 +#define ECFGF_TIMER (_ULCAST_(1) << ECFGB_TIMER) +#define ECFGB_IPI 12 +#define ECFGF_IPI (_ULCAST_(1) << ECFGB_IPI) +#define ECFGF(hwirq) (_ULCAST_(1) << hwirq) + +#define ESTATF_IP 0x00001fff + +#define LOONGARCH_IOCSR_FEATURES 0x8 +#define IOCSRF_TEMP BIT_ULL(0) +#define IOCSRF_NODECNT BIT_ULL(1) +#define IOCSRF_MSI BIT_ULL(2) +#define IOCSRF_EXTIOI BIT_ULL(3) +#define IOCSRF_CSRIPI BIT_ULL(4) +#define IOCSRF_FREQCSR BIT_ULL(5) +#define IOCSRF_FREQSCALE BIT_ULL(6) +#define IOCSRF_DVFSV1 BIT_ULL(7) +#define IOCSRF_EIODECODE BIT_ULL(9) +#define IOCSRF_FLATMODE BIT_ULL(10) +#define IOCSRF_VM BIT_ULL(11) + +#define LOONGARCH_IOCSR_VENDOR 0x10 + +#define LOONGARCH_IOCSR_CPUNAME 0x20 + +#define LOONGARCH_IOCSR_NODECNT 0x408 + +#define LOONGARCH_IOCSR_MISC_FUNC 0x420 +#define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21) +#define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48) + +#define LOONGARCH_IOCSR_CPUTEMP 0x428 + +/* PerCore CSR, only accessible by local cores */ +#define LOONGARCH_IOCSR_IPI_STATUS 0x1000 +#define LOONGARCH_IOCSR_IPI_EN 0x1004 +#define LOONGARCH_IOCSR_IPI_SET 0x1008 +#define LOONGARCH_IOCSR_IPI_CLEAR 0x100c +#define LOONGARCH_IOCSR_MBUF0 0x1020 +#define LOONGARCH_IOCSR_MBUF1 0x1028 +#define LOONGARCH_IOCSR_MBUF2 0x1030 +#define LOONGARCH_IOCSR_MBUF3 0x1038 + +#define LOONGARCH_IOCSR_IPI_SEND 0x1040 +#define IOCSR_IPI_SEND_IP_SHIFT 0 +#define IOCSR_IPI_SEND_CPU_SHIFT 16 +#define IOCSR_IPI_SEND_BLOCKING BIT(31) + +#define LOONGARCH_IOCSR_MBUF_SEND 0x1048 +#define IOCSR_MBUF_SEND_BLOCKING BIT_ULL(31) +#define IOCSR_MBUF_SEND_BOX_SHIFT 2 +#define IOCSR_MBUF_SEND_BOX_LO(box) (box << 1) +#define IOCSR_MBUF_SEND_BOX_HI(box) ((box << 1) + 1) +#define IOCSR_MBUF_SEND_CPU_SHIFT 16 +#define IOCSR_MBUF_SEND_BUF_SHIFT 32 +#define IOCSR_MBUF_SEND_H32_MASK 0xFFFFFFFF00000000ULL + +#define LOONGARCH_IOCSR_ANY_SEND 0x1158 +#define IOCSR_ANY_SEND_BLOCKING BIT_ULL(31) +#define IOCSR_ANY_SEND_CPU_SHIFT 16 +#define IOCSR_ANY_SEND_MASK_SHIFT 27 +#define IOCSR_ANY_SEND_BUF_SHIFT 32 +#define IOCSR_ANY_SEND_H32_MASK 0xFFFFFFFF00000000ULL + +/* Register offset and bit definition for CSR access */ +#define LOONGARCH_IOCSR_TIMER_CFG 0x1060 +#define LOONGARCH_IOCSR_TIMER_TICK 0x1070 +#define IOCSR_TIMER_CFG_RESERVED (_ULCAST_(1) << 63) +#define IOCSR_TIMER_CFG_PERIODIC (_ULCAST_(1) << 62) +#define IOCSR_TIMER_CFG_EN (_ULCAST_(1) << 61) +#define IOCSR_TIMER_MASK 0x0ffffffffffffULL +#define IOCSR_TIMER_INITVAL_RST (_ULCAST_(0xffff) << 48) + +#define LOONGARCH_IOCSR_EXTIOI_NODEMAP_BASE 0x14a0 +#define LOONGARCH_IOCSR_EXTIOI_IPMAP_BASE 0x14c0 +#define LOONGARCH_IOCSR_EXTIOI_EN_BASE 0x1600 +#define LOONGARCH_IOCSR_EXTIOI_BOUNCE_BASE 0x1680 +#define LOONGARCH_IOCSR_EXTIOI_ISR_BASE 0x1800 +#define LOONGARCH_IOCSR_EXTIOI_ROUTE_BASE 0x1c00 +#define IOCSR_EXTIOI_VECTOR_NUM 256 + +#ifndef __ASSEMBLY__ + +static inline u64 drdtime(void) +{ + int rID = 0; + u64 val = 0; + + __asm__ __volatile__( + "rdtime.d %0, %1 \n\t" + : "=r"(val), "=r"(rID) + : + ); + return val; +} + +static inline unsigned int get_csr_cpuid(void) +{ + return csr_read32(LOONGARCH_CSR_CPUID); +} + +static inline void csr_any_send(unsigned int addr, unsigned int data, + unsigned int data_mask, unsigned int cpu) +{ + uint64_t val = 0; + + val = IOCSR_ANY_SEND_BLOCKING | addr; + val |= (cpu << IOCSR_ANY_SEND_CPU_SHIFT); + val |= (data_mask << IOCSR_ANY_SEND_MASK_SHIFT); + val |= ((uint64_t)data << IOCSR_ANY_SEND_BUF_SHIFT); + iocsr_write64(val, LOONGARCH_IOCSR_ANY_SEND); +} + +static inline unsigned int read_csr_excode(void) +{ + return (csr_read32(LOONGARCH_CSR_ESTAT) & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT; +} + +static inline void write_csr_index(unsigned int idx) +{ + csr_xchg32(idx, CSR_TLBIDX_IDXM, LOONGARCH_CSR_TLBIDX); +} + +static inline unsigned int read_csr_pagesize(void) +{ + return (csr_read32(LOONGARCH_CSR_TLBIDX) & CSR_TLBIDX_SIZEM) >> CSR_TLBIDX_SIZE; +} + +static inline void write_csr_pagesize(unsigned int size) +{ + csr_xchg32(size << CSR_TLBIDX_SIZE, CSR_TLBIDX_SIZEM, LOONGARCH_CSR_TLBIDX); +} + +static inline unsigned int read_csr_tlbrefill_pagesize(void) +{ + return (csr_read64(LOONGARCH_CSR_TLBREHI) & CSR_TLBREHI_PS) >> CSR_TLBREHI_PS_SHIFT; +} + +static inline void write_csr_tlbrefill_pagesize(unsigned int size) +{ + csr_xchg64(size << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI); +} + +#define read_csr_asid() csr_read32(LOONGARCH_CSR_ASID) +#define write_csr_asid(val) csr_write32(val, LOONGARCH_CSR_ASID) +#define read_csr_entryhi() csr_read64(LOONGARCH_CSR_TLBEHI) +#define write_csr_entryhi(val) csr_write64(val, LOONGARCH_CSR_TLBEHI) +#define read_csr_entrylo0() csr_read64(LOONGARCH_CSR_TLBELO0) +#define write_csr_entrylo0(val) csr_write64(val, LOONGARCH_CSR_TLBELO0) +#define read_csr_entrylo1() csr_read64(LOONGARCH_CSR_TLBELO1) +#define write_csr_entrylo1(val) csr_write64(val, LOONGARCH_CSR_TLBELO1) +#define read_csr_ecfg() csr_read32(LOONGARCH_CSR_ECFG) +#define write_csr_ecfg(val) csr_write32(val, LOONGARCH_CSR_ECFG) +#define read_csr_estat() csr_read32(LOONGARCH_CSR_ESTAT) +#define write_csr_estat(val) csr_write32(val, LOONGARCH_CSR_ESTAT) +#define read_csr_tlbidx() csr_read32(LOONGARCH_CSR_TLBIDX) +#define write_csr_tlbidx(val) csr_write32(val, LOONGARCH_CSR_TLBIDX) +#define read_csr_euen() csr_read32(LOONGARCH_CSR_EUEN) +#define write_csr_euen(val) csr_write32(val, LOONGARCH_CSR_EUEN) +#define read_csr_cpuid() csr_read32(LOONGARCH_CSR_CPUID) +#define read_csr_prcfg1() csr_read64(LOONGARCH_CSR_PRCFG1) +#define write_csr_prcfg1(val) csr_write64(val, LOONGARCH_CSR_PRCFG1) +#define read_csr_prcfg2() csr_read64(LOONGARCH_CSR_PRCFG2) +#define write_csr_prcfg2(val) csr_write64(val, LOONGARCH_CSR_PRCFG2) +#define read_csr_prcfg3() csr_read64(LOONGARCH_CSR_PRCFG3) +#define write_csr_prcfg3(val) csr_write64(val, LOONGARCH_CSR_PRCFG3) +#define read_csr_stlbpgsize() csr_read32(LOONGARCH_CSR_STLBPGSIZE) +#define write_csr_stlbpgsize(val) csr_write32(val, LOONGARCH_CSR_STLBPGSIZE) +#define read_csr_rvacfg() csr_read32(LOONGARCH_CSR_RVACFG) +#define write_csr_rvacfg(val) csr_write32(val, LOONGARCH_CSR_RVACFG) +#define write_csr_tintclear(val) csr_write32(val, LOONGARCH_CSR_TINTCLR) +#define read_csr_impctl1() csr_read64(LOONGARCH_CSR_IMPCTL1) +#define write_csr_impctl1(val) csr_write64(val, LOONGARCH_CSR_IMPCTL1) +#define write_csr_impctl2(val) csr_write64(val, LOONGARCH_CSR_IMPCTL2) + +#define read_csr_perfctrl0() csr_read64(LOONGARCH_CSR_PERFCTRL0) +#define read_csr_perfcntr0() csr_read64(LOONGARCH_CSR_PERFCNTR0) +#define read_csr_perfctrl1() csr_read64(LOONGARCH_CSR_PERFCTRL1) +#define read_csr_perfcntr1() csr_read64(LOONGARCH_CSR_PERFCNTR1) +#define read_csr_perfctrl2() csr_read64(LOONGARCH_CSR_PERFCTRL2) +#define read_csr_perfcntr2() csr_read64(LOONGARCH_CSR_PERFCNTR2) +#define read_csr_perfctrl3() csr_read64(LOONGARCH_CSR_PERFCTRL3) +#define read_csr_perfcntr3() csr_read64(LOONGARCH_CSR_PERFCNTR3) +#define write_csr_perfctrl0(val) csr_write64(val, LOONGARCH_CSR_PERFCTRL0) +#define write_csr_perfcntr0(val) csr_write64(val, LOONGARCH_CSR_PERFCNTR0) +#define write_csr_perfctrl1(val) csr_write64(val, LOONGARCH_CSR_PERFCTRL1) +#define write_csr_perfcntr1(val) csr_write64(val, LOONGARCH_CSR_PERFCNTR1) +#define write_csr_perfctrl2(val) csr_write64(val, LOONGARCH_CSR_PERFCTRL2) +#define write_csr_perfcntr2(val) csr_write64(val, LOONGARCH_CSR_PERFCNTR2) +#define write_csr_perfctrl3(val) csr_write64(val, LOONGARCH_CSR_PERFCTRL3) +#define write_csr_perfcntr3(val) csr_write64(val, LOONGARCH_CSR_PERFCNTR3) + +/* + * Manipulate bits in a register. + */ +#define __BUILD_CSR_COMMON(name) \ +static inline unsigned long \ +set_##name(unsigned long set) \ +{ \ + unsigned long res, new; \ + \ + res = read_##name(); \ + new = res | set; \ + write_##name(new); \ + \ + return res; \ +} \ + \ +static inline unsigned long \ +clear_##name(unsigned long clear) \ +{ \ + unsigned long res, new; \ + \ + res = read_##name(); \ + new = res & ~clear; \ + write_##name(new); \ + \ + return res; \ +} \ + \ +static inline unsigned long \ +change_##name(unsigned long change, unsigned long val) \ +{ \ + unsigned long res, new; \ + \ + res = read_##name(); \ + new = res & ~change; \ + new |= (val & change); \ + write_##name(new); \ + \ + return res; \ +} + +#define __BUILD_CSR_OP(name) __BUILD_CSR_COMMON(csr_##name) + +__BUILD_CSR_OP(euen) +__BUILD_CSR_OP(ecfg) +__BUILD_CSR_OP(tlbidx) + +#define set_csr_estat(val) \ + csr_xchg32(val, val, LOONGARCH_CSR_ESTAT) +#define clear_csr_estat(val) \ + csr_xchg32(~(val), val, LOONGARCH_CSR_ESTAT) + +#endif /* __ASSEMBLY__ */ + +/* Generic EntryLo bit definitions */ +#define ENTRYLO_V (_ULCAST_(1) << 0) +#define ENTRYLO_D (_ULCAST_(1) << 1) +#define ENTRYLO_PLV_SHIFT 2 +#define ENTRYLO_PLV (_ULCAST_(3) << ENTRYLO_PLV_SHIFT) +#define ENTRYLO_C_SHIFT 4 +#define ENTRYLO_C (_ULCAST_(3) << ENTRYLO_C_SHIFT) +#define ENTRYLO_G (_ULCAST_(1) << 6) +#define ENTRYLO_NR (_ULCAST_(1) << 61) +#define ENTRYLO_NX (_ULCAST_(1) << 62) + +/* Values for PageSize register */ +#define PS_4K 0x0000000c +#define PS_8K 0x0000000d +#define PS_16K 0x0000000e +#define PS_32K 0x0000000f +#define PS_64K 0x00000010 +#define PS_128K 0x00000011 +#define PS_256K 0x00000012 +#define PS_512K 0x00000013 +#define PS_1M 0x00000014 +#define PS_2M 0x00000015 +#define PS_4M 0x00000016 +#define PS_8M 0x00000017 +#define PS_16M 0x00000018 +#define PS_32M 0x00000019 +#define PS_64M 0x0000001a +#define PS_128M 0x0000001b +#define PS_256M 0x0000001c +#define PS_512M 0x0000001d +#define PS_1G 0x0000001e + +/* Default page size for a given kernel configuration */ +#ifdef CONFIG_PAGE_SIZE_4KB +#define PS_DEFAULT_SIZE PS_4K +#elif defined(CONFIG_PAGE_SIZE_16KB) +#define PS_DEFAULT_SIZE PS_16K +#elif defined(CONFIG_PAGE_SIZE_64KB) +#define PS_DEFAULT_SIZE PS_64K +#else +#error Bad page size configuration! +#endif + +/* Default huge tlb size for a given kernel configuration */ +#ifdef CONFIG_PAGE_SIZE_4KB +#define PS_HUGE_SIZE PS_1M +#elif defined(CONFIG_PAGE_SIZE_16KB) +#define PS_HUGE_SIZE PS_16M +#elif defined(CONFIG_PAGE_SIZE_64KB) +#define PS_HUGE_SIZE PS_256M +#else +#error Bad page size configuration for hugetlbfs! +#endif + +/* ExStatus.ExcCode */ +#define EXCCODE_RSV 0 /* Reserved */ +#define EXCCODE_TLBL 1 /* TLB miss on a load */ +#define EXCCODE_TLBS 2 /* TLB miss on a store */ +#define EXCCODE_TLBI 3 /* TLB miss on a ifetch */ +#define EXCCODE_TLBM 4 /* TLB modified fault */ +#define EXCCODE_TLBNR 5 /* TLB Read-Inhibit exception */ +#define EXCCODE_TLBNX 6 /* TLB Execution-Inhibit exception */ +#define EXCCODE_TLBPE 7 /* TLB Privilege Error */ +#define EXCCODE_ADE 8 /* Address Error */ + #define EXSUBCODE_ADEF 0 /* Fetch Instruction */ + #define EXSUBCODE_ADEM 1 /* Access Memory*/ +#define EXCCODE_ALE 9 /* Unalign Access */ +#define EXCCODE_OOB 10 /* Out of bounds */ +#define EXCCODE_SYS 11 /* System call */ +#define EXCCODE_BP 12 /* Breakpoint */ +#define EXCCODE_INE 13 /* Inst. Not Exist */ +#define EXCCODE_IPE 14 /* Inst. Privileged Error */ +#define EXCCODE_FPDIS 15 /* FPU Disabled */ +#define EXCCODE_LSXDIS 16 /* LSX Disabled */ +#define EXCCODE_LASXDIS 17 /* LASX Disabled */ +#define EXCCODE_FPE 18 /* Floating Point Exception */ + #define EXCSUBCODE_FPE 0 /* Floating Point Exception */ + #define EXCSUBCODE_VFPE 1 /* Vector Exception */ +#define EXCCODE_WATCH 19 /* Watch address reference */ +#define EXCCODE_BTDIS 20 /* Binary Trans. Disabled */ +#define EXCCODE_BTE 21 /* Binary Trans. Exception */ +#define EXCCODE_PSI 22 /* Guest Privileged Error */ +#define EXCCODE_HYP 23 /* Hypercall */ +#define EXCCODE_GCM 24 /* Guest CSR modified */ + #define EXCSUBCODE_GCSC 0 /* Software caused */ + #define EXCSUBCODE_GCHC 1 /* Hardware caused */ +#define EXCCODE_SE 25 /* Security */ + +#define EXCCODE_INT_START 64 +#define EXCCODE_SIP0 64 +#define EXCCODE_SIP1 65 +#define EXCCODE_IP0 66 +#define EXCCODE_IP1 67 +#define EXCCODE_IP2 68 +#define EXCCODE_IP3 69 +#define EXCCODE_IP4 70 +#define EXCCODE_IP5 71 +#define EXCCODE_IP6 72 +#define EXCCODE_IP7 73 +#define EXCCODE_PMC 74 /* Performance Counter */ +#define EXCCODE_TIMER 75 +#define EXCCODE_IPI 76 +#define EXCCODE_NMI 77 +#define EXCCODE_INT_END 78 +#define EXCCODE_INT_NUM (EXCCODE_INT_END - EXCCODE_INT_START) + +/* FPU register names */ +#define LOONGARCH_FCSR0 $r0 +#define LOONGARCH_FCSR1 $r1 +#define LOONGARCH_FCSR2 $r2 +#define LOONGARCH_FCSR3 $r3 + +/* FPU Status Register Values */ +#define FPU_CSR_RSVD 0xe0e0fce0 + +/* + * X the exception cause indicator + * E the exception enable + * S the sticky/flag bit + */ +#define FPU_CSR_ALL_X 0x1f000000 +#define FPU_CSR_INV_X 0x10000000 +#define FPU_CSR_DIV_X 0x08000000 +#define FPU_CSR_OVF_X 0x04000000 +#define FPU_CSR_UDF_X 0x02000000 +#define FPU_CSR_INE_X 0x01000000 + +#define FPU_CSR_ALL_S 0x001f0000 +#define FPU_CSR_INV_S 0x00100000 +#define FPU_CSR_DIV_S 0x00080000 +#define FPU_CSR_OVF_S 0x00040000 +#define FPU_CSR_UDF_S 0x00020000 +#define FPU_CSR_INE_S 0x00010000 + +#define FPU_CSR_ALL_E 0x0000001f +#define FPU_CSR_INV_E 0x00000010 +#define FPU_CSR_DIV_E 0x00000008 +#define FPU_CSR_OVF_E 0x00000004 +#define FPU_CSR_UDF_E 0x00000002 +#define FPU_CSR_INE_E 0x00000001 + +/* Bits 8 and 9 of FPU Status Register specify the rounding mode */ +#define FPU_CSR_RM 0x300 +#define FPU_CSR_RN 0x000 /* nearest */ +#define FPU_CSR_RZ 0x100 /* towards zero */ +#define FPU_CSR_RU 0x200 /* towards +Infinity */ +#define FPU_CSR_RD 0x300 /* towards -Infinity */ + +#define read_fcsr(source) \ +({ \ + unsigned int __res; \ +\ + __asm__ __volatile__( \ + " movfcsr2gr %0, "__stringify(source)" \n" \ + : "=r" (__res)); \ + __res; \ +}) + +#define write_fcsr(dest, val) \ +do { \ + __asm__ __volatile__( \ + " movgr2fcsr %0, "__stringify(dest)" \n" \ + : : "r" (val)); \ +} while (0) + +#endif /* _ASM_LOONGARCH_H */ diff --git a/arch/loongarch/include/asm/loongson.h b/arch/loongarch/include/asm/loongson.h new file mode 100644 index 000000000000..6a8038725ba7 --- /dev/null +++ b/arch/loongarch/include/asm/loongson.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_LOONGSON_H +#define __ASM_LOONGSON_H + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/pci.h> +#include <asm/addrspace.h> +#include <asm/bootinfo.h> + +extern const struct plat_smp_ops loongson3_smp_ops; + +#define LOONGSON_REG(x) \ + (*(volatile u32 *)((char *)TO_UNCACHE(LOONGSON_REG_BASE) + (x))) + +#define LOONGSON_LIO_BASE 0x18000000 +#define LOONGSON_LIO_SIZE 0x00100000 /* 1M */ +#define LOONGSON_LIO_TOP (LOONGSON_LIO_BASE+LOONGSON_LIO_SIZE-1) + +#define LOONGSON_BOOT_BASE 0x1c000000 +#define LOONGSON_BOOT_SIZE 0x02000000 /* 32M */ +#define LOONGSON_BOOT_TOP (LOONGSON_BOOT_BASE+LOONGSON_BOOT_SIZE-1) + +#define LOONGSON_REG_BASE 0x1fe00000 +#define LOONGSON_REG_SIZE 0x00100000 /* 1M */ +#define LOONGSON_REG_TOP (LOONGSON_REG_BASE+LOONGSON_REG_SIZE-1) + +/* GPIO Regs - r/w */ + +#define LOONGSON_GPIODATA LOONGSON_REG(0x11c) +#define LOONGSON_GPIOIE LOONGSON_REG(0x120) +#define LOONGSON_REG_GPIO_BASE (LOONGSON_REG_BASE + 0x11c) + +#define MAX_PACKAGES 16 + +/* Chip Config register of each physical cpu package */ +extern u64 loongson_chipcfg[MAX_PACKAGES]; +#define LOONGSON_CHIPCFG(id) (*(volatile u32 *)(loongson_chipcfg[id])) + +/* Chip Temperature register of each physical cpu package */ +extern u64 loongson_chiptemp[MAX_PACKAGES]; +#define LOONGSON_CHIPTEMP(id) (*(volatile u32 *)(loongson_chiptemp[id])) + +/* Freq Control register of each physical cpu package */ +extern u64 loongson_freqctrl[MAX_PACKAGES]; +#define LOONGSON_FREQCTRL(id) (*(volatile u32 *)(loongson_freqctrl[id])) + +#define xconf_readl(addr) readl(addr) +#define xconf_readq(addr) readq(addr) + +static inline void xconf_writel(u32 val, volatile void __iomem *addr) +{ + asm volatile ( + " st.w %[v], %[hw], 0 \n" + " ld.b $r0, %[hw], 0 \n" + : + : [hw] "r" (addr), [v] "r" (val) + ); +} + +static inline void xconf_writeq(u64 val64, volatile void __iomem *addr) +{ + asm volatile ( + " st.d %[v], %[hw], 0 \n" + " ld.b $r0, %[hw], 0 \n" + : + : [hw] "r" (addr), [v] "r" (val64) + ); +} + +/* ============== LS7A registers =============== */ +#define LS7A_PCH_REG_BASE 0x10000000UL +/* LPC regs */ +#define LS7A_LPC_REG_BASE (LS7A_PCH_REG_BASE + 0x00002000) +/* CHIPCFG regs */ +#define LS7A_CHIPCFG_REG_BASE (LS7A_PCH_REG_BASE + 0x00010000) +/* MISC reg base */ +#define LS7A_MISC_REG_BASE (LS7A_PCH_REG_BASE + 0x00080000) +/* ACPI regs */ +#define LS7A_ACPI_REG_BASE (LS7A_MISC_REG_BASE + 0x00050000) +/* RTC regs */ +#define LS7A_RTC_REG_BASE (LS7A_MISC_REG_BASE + 0x00050100) + +#define LS7A_DMA_CFG (volatile void *)TO_UNCACHE(LS7A_CHIPCFG_REG_BASE + 0x041c) +#define LS7A_DMA_NODE_SHF 8 +#define LS7A_DMA_NODE_MASK 0x1F00 + +#define LS7A_INT_MASK_REG (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x020) +#define LS7A_INT_EDGE_REG (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x060) +#define LS7A_INT_CLEAR_REG (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x080) +#define LS7A_INT_HTMSI_EN_REG (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x040) +#define LS7A_INT_ROUTE_ENTRY_REG (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x100) +#define LS7A_INT_HTMSI_VEC_REG (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x200) +#define LS7A_INT_STATUS_REG (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x3a0) +#define LS7A_INT_POL_REG (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x3e0) +#define LS7A_LPC_INT_CTL (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x2000) +#define LS7A_LPC_INT_ENA (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x2004) +#define LS7A_LPC_INT_STS (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x2008) +#define LS7A_LPC_INT_CLR (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x200c) +#define LS7A_LPC_INT_POL (volatile void *)TO_UNCACHE(LS7A_PCH_REG_BASE + 0x2010) + +#define LS7A_PMCON_SOC_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x000) +#define LS7A_PMCON_RESUME_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x004) +#define LS7A_PMCON_RTC_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x008) +#define LS7A_PM1_EVT_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x00c) +#define LS7A_PM1_ENA_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x010) +#define LS7A_PM1_CNT_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x014) +#define LS7A_PM1_TMR_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x018) +#define LS7A_P_CNT_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x01c) +#define LS7A_GPE0_STS_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x028) +#define LS7A_GPE0_ENA_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x02c) +#define LS7A_RST_CNT_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x030) +#define LS7A_WD_SET_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x034) +#define LS7A_WD_TIMER_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x038) +#define LS7A_THSENS_CNT_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x04c) +#define LS7A_GEN_RTC_1_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x050) +#define LS7A_GEN_RTC_2_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x054) +#define LS7A_DPM_CFG_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x400) +#define LS7A_DPM_STS_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x404) +#define LS7A_DPM_CNT_REG (volatile void *)TO_UNCACHE(LS7A_ACPI_REG_BASE + 0x408) + +typedef enum { + ACPI_PCI_HOTPLUG_STATUS = 1 << 1, + ACPI_CPU_HOTPLUG_STATUS = 1 << 2, + ACPI_MEM_HOTPLUG_STATUS = 1 << 3, + ACPI_POWERBUTTON_STATUS = 1 << 8, + ACPI_RTC_WAKE_STATUS = 1 << 10, + ACPI_PCI_WAKE_STATUS = 1 << 14, + ACPI_ANY_WAKE_STATUS = 1 << 15, +} AcpiEventStatusBits; + +#define HT1LO_OFFSET 0xe0000000000UL + +/* PCI Configuration Space Base */ +#define MCFG_EXT_PCICFG_BASE 0xefe00000000UL + +/* REG ACCESS*/ +#define ls7a_readb(addr) (*(volatile unsigned char *)TO_UNCACHE(addr)) +#define ls7a_readw(addr) (*(volatile unsigned short *)TO_UNCACHE(addr)) +#define ls7a_readl(addr) (*(volatile unsigned int *)TO_UNCACHE(addr)) +#define ls7a_readq(addr) (*(volatile unsigned long *)TO_UNCACHE(addr)) +#define ls7a_writeb(val, addr) *(volatile unsigned char *)TO_UNCACHE(addr) = (val) +#define ls7a_writew(val, addr) *(volatile unsigned short *)TO_UNCACHE(addr) = (val) +#define ls7a_writel(val, addr) *(volatile unsigned int *)TO_UNCACHE(addr) = (val) +#define ls7a_writeq(val, addr) *(volatile unsigned long *)TO_UNCACHE(addr) = (val) + +#endif /* __ASM_LOONGSON_H */ diff --git a/arch/loongarch/include/asm/mmu.h b/arch/loongarch/include/asm/mmu.h new file mode 100644 index 000000000000..0cc2d0803537 --- /dev/null +++ b/arch/loongarch/include/asm/mmu.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_MMU_H +#define __ASM_MMU_H + +#include <linux/atomic.h> +#include <linux/spinlock.h> + +typedef struct { + u64 asid[NR_CPUS]; + void *vdso; +} mm_context_t; + +#endif /* __ASM_MMU_H */ diff --git a/arch/loongarch/include/asm/mmu_context.h b/arch/loongarch/include/asm/mmu_context.h new file mode 100644 index 000000000000..9f97c3453b9c --- /dev/null +++ b/arch/loongarch/include/asm/mmu_context.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Switch a MMU context. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_MMU_CONTEXT_H +#define _ASM_MMU_CONTEXT_H + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/mm_types.h> +#include <linux/smp.h> +#include <linux/slab.h> + +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> +#include <asm-generic/mm_hooks.h> + +/* + * All unused by hardware upper bits will be considered + * as a software asid extension. + */ +static inline u64 asid_version_mask(unsigned int cpu) +{ + return ~(u64)(cpu_asid_mask(&cpu_data[cpu])); +} + +static inline u64 asid_first_version(unsigned int cpu) +{ + return cpu_asid_mask(&cpu_data[cpu]) + 1; +} + +#define cpu_context(cpu, mm) ((mm)->context.asid[cpu]) +#define asid_cache(cpu) (cpu_data[cpu].asid_cache) +#define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & cpu_asid_mask(&cpu_data[cpu])) + +static inline int asid_valid(struct mm_struct *mm, unsigned int cpu) +{ + if ((cpu_context(cpu, mm) ^ asid_cache(cpu)) & asid_version_mask(cpu)) + return 0; + + return 1; +} + +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ +} + +/* Normal, classic get_new_mmu_context */ +static inline void +get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) +{ + u64 asid = asid_cache(cpu); + + if (!((++asid) & cpu_asid_mask(&cpu_data[cpu]))) + local_flush_tlb_user(); /* start new asid cycle */ + + cpu_context(cpu, mm) = asid_cache(cpu) = asid; +} + +/* + * Initialize the context related info for a new mm_struct + * instance. + */ +static inline int +init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + int i; + + for_each_possible_cpu(i) + cpu_context(i, mm) = 0; + + return 0; +} + +static inline void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + unsigned int cpu = smp_processor_id(); + + /* Check if our ASID is of an older version and thus invalid */ + if (!asid_valid(next, cpu)) + get_new_mmu_context(next, cpu); + + write_csr_asid(cpu_asid(cpu, next)); + + if (next != &init_mm) + csr_write64((unsigned long)next->pgd, LOONGARCH_CSR_PGDL); + else + csr_write64((unsigned long)invalid_pg_dir, LOONGARCH_CSR_PGDL); + + /* + * Mark current->active_mm as not "active" anymore. + * We don't want to mislead possible IPI tlb flush routines. + */ + cpumask_set_cpu(cpu, mm_cpumask(next)); +} + +#define switch_mm_irqs_off switch_mm_irqs_off + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + unsigned long flags; + + local_irq_save(flags); + switch_mm_irqs_off(prev, next, tsk); + local_irq_restore(flags); +} + +/* + * Destroy context related info for an mm_struct that is about + * to be put to rest. + */ +static inline void destroy_context(struct mm_struct *mm) +{ +} + +#define activate_mm(prev, next) switch_mm(prev, next, current) +#define deactivate_mm(task, mm) do { } while (0) + +/* + * If mm is currently active, we can't really drop it. + * Instead, we will get a new one for it. + */ +static inline void +drop_mmu_context(struct mm_struct *mm, unsigned int cpu) +{ + int asid; + unsigned long flags; + + local_irq_save(flags); + + asid = read_csr_asid() & cpu_asid_mask(¤t_cpu_data); + + if (asid == cpu_asid(cpu, mm)) { + if (!current->mm || (current->mm == mm)) { + get_new_mmu_context(mm, cpu); + write_csr_asid(cpu_asid(cpu, mm)); + goto out; + } + } + + /* Will get a new context next time */ + cpu_context(cpu, mm) = 0; + cpumask_clear_cpu(cpu, mm_cpumask(mm)); +out: + local_irq_restore(flags); +} + +#endif /* _ASM_MMU_CONTEXT_H */ diff --git a/arch/loongarch/include/asm/mmzone.h b/arch/loongarch/include/asm/mmzone.h new file mode 100644 index 000000000000..fe67d0b4b33d --- /dev/null +++ b/arch/loongarch/include/asm/mmzone.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen (chenhuacai@loongson.cn) + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_MMZONE_H_ +#define _ASM_MMZONE_H_ + +#include <asm/page.h> +#include <asm/numa.h> + +extern struct pglist_data *node_data[]; + +#define NODE_DATA(nid) (node_data[(nid)]) + +extern void setup_zero_pages(void); + +#endif /* _ASM_MMZONE_H_ */ diff --git a/arch/loongarch/include/asm/module.h b/arch/loongarch/include/asm/module.h new file mode 100644 index 000000000000..9f6718df1854 --- /dev/null +++ b/arch/loongarch/include/asm/module.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_MODULE_H +#define _ASM_MODULE_H + +#include <asm/inst.h> +#include <asm-generic/module.h> + +#define RELA_STACK_DEPTH 16 + +struct mod_section { + Elf_Shdr *shdr; + int num_entries; + int max_entries; +}; + +struct mod_arch_specific { + struct mod_section plt; + struct mod_section plt_idx; +}; + +struct plt_entry { + u32 inst_lu12iw; + u32 inst_lu32id; + u32 inst_lu52id; + u32 inst_jirl; +}; + +struct plt_idx_entry { + unsigned long symbol_addr; +}; + +Elf_Addr module_emit_plt_entry(struct module *mod, unsigned long val); + +static inline struct plt_entry emit_plt_entry(unsigned long val) +{ + u32 lu12iw, lu32id, lu52id, jirl; + + lu12iw = (lu12iw_op << 25 | (((val >> 12) & 0xfffff) << 5) | LOONGARCH_GPR_T1); + lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID)); + lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID)); + jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xfff)); + + return (struct plt_entry) { lu12iw, lu32id, lu52id, jirl }; +} + +static inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val) +{ + return (struct plt_idx_entry) { val }; +} + +static inline int get_plt_idx(unsigned long val, const struct mod_section *sec) +{ + int i; + struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sec->shdr->sh_addr; + + for (i = 0; i < sec->num_entries; i++) { + if (plt_idx[i].symbol_addr == val) + return i; + } + + return -1; +} + +static inline struct plt_entry *get_plt_entry(unsigned long val, + const struct mod_section *sec_plt, + const struct mod_section *sec_plt_idx) +{ + int plt_idx = get_plt_idx(val, sec_plt_idx); + struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr; + + if (plt_idx < 0) + return NULL; + + return plt + plt_idx; +} + +#endif /* _ASM_MODULE_H */ diff --git a/arch/loongarch/include/asm/module.lds.h b/arch/loongarch/include/asm/module.lds.h new file mode 100644 index 000000000000..31c1c0db11a3 --- /dev/null +++ b/arch/loongarch/include/asm/module.lds.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2020-2022 Loongson Technology Corporation Limited */ +SECTIONS { + . = ALIGN(4); + .plt : { BYTE(0) } + .plt.idx : { BYTE(0) } +} diff --git a/arch/loongarch/include/asm/numa.h b/arch/loongarch/include/asm/numa.h new file mode 100644 index 000000000000..27f319b49862 --- /dev/null +++ b/arch/loongarch/include/asm/numa.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Jianmin Lv <lvjianmin@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef _ASM_LOONGARCH_NUMA_H +#define _ASM_LOONGARCH_NUMA_H + +#include <linux/nodemask.h> + +#define NODE_ADDRSPACE_SHIFT 44 + +#define pa_to_nid(addr) (((addr) & 0xf00000000000) >> NODE_ADDRSPACE_SHIFT) +#define nid_to_addrbase(nid) (_ULCAST_(nid) << NODE_ADDRSPACE_SHIFT) + +#ifdef CONFIG_NUMA + +extern int numa_off; +extern s16 __cpuid_to_node[CONFIG_NR_CPUS]; +extern nodemask_t numa_nodes_parsed __initdata; + +struct numa_memblk { + u64 start; + u64 end; + int nid; +}; + +#define NR_NODE_MEMBLKS (MAX_NUMNODES*2) +struct numa_meminfo { + int nr_blks; + struct numa_memblk blk[NR_NODE_MEMBLKS]; +}; + +extern int __init numa_add_memblk(int nodeid, u64 start, u64 end); + +extern void __init early_numa_add_cpu(int cpuid, s16 node); +extern void numa_add_cpu(unsigned int cpu); +extern void numa_remove_cpu(unsigned int cpu); + +static inline void numa_clear_node(int cpu) +{ +} + +static inline void set_cpuid_to_node(int cpuid, s16 node) +{ + __cpuid_to_node[cpuid] = node; +} + +extern int early_cpu_to_node(int cpu); + +#else + +static inline void early_numa_add_cpu(int cpuid, s16 node) { } +static inline void numa_add_cpu(unsigned int cpu) { } +static inline void numa_remove_cpu(unsigned int cpu) { } + +static inline int early_cpu_to_node(int cpu) +{ + return 0; +} + +#endif /* CONFIG_NUMA */ + +#endif /* _ASM_LOONGARCH_NUMA_H */ diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h new file mode 100644 index 000000000000..3dba4986f6c9 --- /dev/null +++ b/arch/loongarch/include/asm/page.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_PAGE_H +#define _ASM_PAGE_H + +#include <linux/const.h> + +/* + * PAGE_SHIFT determines the page size + */ +#ifdef CONFIG_PAGE_SIZE_4KB +#define PAGE_SHIFT 12 +#endif +#ifdef CONFIG_PAGE_SIZE_16KB +#define PAGE_SHIFT 14 +#endif +#ifdef CONFIG_PAGE_SIZE_64KB +#define PAGE_SHIFT 16 +#endif +#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) + +#define HPAGE_SHIFT (PAGE_SHIFT + PAGE_SHIFT - 3) +#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) +#define HPAGE_MASK (~(HPAGE_SIZE - 1)) +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) + +#ifndef __ASSEMBLY__ + +#include <linux/kernel.h> +#include <linux/pfn.h> + +#define MAX_DMA32_PFN (1UL << (32 - PAGE_SHIFT)) + +/* + * It's normally defined only for FLATMEM config but it's + * used in our early mem init code for all memory models. + * So always define it. + */ +#define ARCH_PFN_OFFSET PFN_UP(PHYS_OFFSET) + +extern void clear_page(void *page); +extern void copy_page(void *to, void *from); + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +extern unsigned long shm_align_mask; + +struct page; +struct vm_area_struct; +void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma); + +#define __HAVE_ARCH_COPY_USER_HIGHPAGE + +typedef struct { unsigned long pte; } pte_t; +#define pte_val(x) ((x).pte) +#define __pte(x) ((pte_t) { (x) }) +typedef struct page *pgtable_t; + +typedef struct { unsigned long pgd; } pgd_t; +#define pgd_val(x) ((x).pgd) +#define __pgd(x) ((pgd_t) { (x) }) + +/* + * Manipulate page protection bits + */ +typedef struct { unsigned long pgprot; } pgprot_t; +#define pgprot_val(x) ((x).pgprot) +#define __pgprot(x) ((pgprot_t) { (x) }) +#define pte_pgprot(x) __pgprot(pte_val(x) & ~_PFN_MASK) + +#define ptep_buddy(x) ((pte_t *)((unsigned long)(x) ^ sizeof(pte_t))) + +/* + * __pa()/__va() should be used only during mem init. + */ +#define __pa(x) PHYSADDR(x) +#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET)) + +#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) + +#ifdef CONFIG_FLATMEM + +static inline int pfn_valid(unsigned long pfn) +{ + /* avoid <linux/mm.h> include hell */ + extern unsigned long max_mapnr; + unsigned long pfn_offset = ARCH_PFN_OFFSET; + + return pfn >= pfn_offset && pfn < max_mapnr; +} + +#endif + +#define virt_to_pfn(kaddr) PFN_DOWN(virt_to_phys((void *)(kaddr))) +#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr)) + +extern int __virt_addr_valid(volatile void *kaddr); +#define virt_addr_valid(kaddr) __virt_addr_valid((volatile void *)(kaddr)) + +#define VM_DATA_DEFAULT_FLAGS \ + (VM_READ | VM_WRITE | \ + ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#include <asm-generic/memory_model.h> +#include <asm-generic/getorder.h> + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_PAGE_H */ diff --git a/arch/loongarch/include/asm/percpu.h b/arch/loongarch/include/asm/percpu.h new file mode 100644 index 000000000000..34f15a6fb1e7 --- /dev/null +++ b/arch/loongarch/include/asm/percpu.h @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_PERCPU_H +#define __ASM_PERCPU_H + +#include <asm/cmpxchg.h> + +/* Use r21 for fast access */ +register unsigned long __my_cpu_offset __asm__("$r21"); + +static inline void set_my_cpu_offset(unsigned long off) +{ + __my_cpu_offset = off; + csr_write64(off, PERCPU_BASE_KS); +} +#define __my_cpu_offset __my_cpu_offset + +#define PERCPU_OP(op, asm_op, c_op) \ +static inline unsigned long __percpu_##op(void *ptr, \ + unsigned long val, int size) \ +{ \ + unsigned long ret; \ + \ + switch (size) { \ + case 4: \ + __asm__ __volatile__( \ + "am"#asm_op".w" " %[ret], %[val], %[ptr] \n" \ + : [ret] "=&r" (ret), [ptr] "+ZB"(*(u32 *)ptr) \ + : [val] "r" (val)); \ + break; \ + case 8: \ + __asm__ __volatile__( \ + "am"#asm_op".d" " %[ret], %[val], %[ptr] \n" \ + : [ret] "=&r" (ret), [ptr] "+ZB"(*(u64 *)ptr) \ + : [val] "r" (val)); \ + break; \ + default: \ + ret = 0; \ + BUILD_BUG(); \ + } \ + \ + return ret c_op val; \ +} + +PERCPU_OP(add, add, +) +PERCPU_OP(and, and, &) +PERCPU_OP(or, or, |) +#undef PERCPU_OP + +static inline unsigned long __percpu_read(void *ptr, int size) +{ + unsigned long ret; + + switch (size) { + case 1: + __asm__ __volatile__ ("ldx.b %[ret], $r21, %[ptr] \n" + : [ret] "=&r"(ret) + : [ptr] "r"(ptr) + : "memory"); + break; + case 2: + __asm__ __volatile__ ("ldx.h %[ret], $r21, %[ptr] \n" + : [ret] "=&r"(ret) + : [ptr] "r"(ptr) + : "memory"); + break; + case 4: + __asm__ __volatile__ ("ldx.w %[ret], $r21, %[ptr] \n" + : [ret] "=&r"(ret) + : [ptr] "r"(ptr) + : "memory"); + break; + case 8: + __asm__ __volatile__ ("ldx.d %[ret], $r21, %[ptr] \n" + : [ret] "=&r"(ret) + : [ptr] "r"(ptr) + : "memory"); + break; + default: + ret = 0; + BUILD_BUG(); + } + + return ret; +} + +static inline void __percpu_write(void *ptr, unsigned long val, int size) +{ + switch (size) { + case 1: + __asm__ __volatile__("stx.b %[val], $r21, %[ptr] \n" + : + : [val] "r" (val), [ptr] "r" (ptr) + : "memory"); + break; + case 2: + __asm__ __volatile__("stx.h %[val], $r21, %[ptr] \n" + : + : [val] "r" (val), [ptr] "r" (ptr) + : "memory"); + break; + case 4: + __asm__ __volatile__("stx.w %[val], $r21, %[ptr] \n" + : + : [val] "r" (val), [ptr] "r" (ptr) + : "memory"); + break; + case 8: + __asm__ __volatile__("stx.d %[val], $r21, %[ptr] \n" + : + : [val] "r" (val), [ptr] "r" (ptr) + : "memory"); + break; + default: + BUILD_BUG(); + } +} + +static inline unsigned long __percpu_xchg(void *ptr, unsigned long val, + int size) +{ + switch (size) { + case 4: + return __xchg_asm("amswap.w", (volatile u32 *)ptr, (u32)val); + + case 8: + return __xchg_asm("amswap.d", (volatile u64 *)ptr, (u64)val); + + default: + BUILD_BUG(); + } + + return 0; +} + +/* this_cpu_cmpxchg */ +#define _protect_cmpxchg_local(pcp, o, n) \ +({ \ + typeof(*raw_cpu_ptr(&(pcp))) __ret; \ + preempt_disable_notrace(); \ + __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n); \ + preempt_enable_notrace(); \ + __ret; \ +}) + +#define _percpu_read(pcp) \ +({ \ + typeof(pcp) __retval; \ + __retval = (typeof(pcp))__percpu_read(&(pcp), sizeof(pcp)); \ + __retval; \ +}) + +#define _percpu_write(pcp, val) \ +do { \ + __percpu_write(&(pcp), (unsigned long)(val), sizeof(pcp)); \ +} while (0) \ + +#define _pcp_protect(operation, pcp, val) \ +({ \ + typeof(pcp) __retval; \ + preempt_disable_notrace(); \ + __retval = (typeof(pcp))operation(raw_cpu_ptr(&(pcp)), \ + (val), sizeof(pcp)); \ + preempt_enable_notrace(); \ + __retval; \ +}) + +#define _percpu_add(pcp, val) \ + _pcp_protect(__percpu_add, pcp, val) + +#define _percpu_add_return(pcp, val) _percpu_add(pcp, val) + +#define _percpu_and(pcp, val) \ + _pcp_protect(__percpu_and, pcp, val) + +#define _percpu_or(pcp, val) \ + _pcp_protect(__percpu_or, pcp, val) + +#define _percpu_xchg(pcp, val) ((typeof(pcp)) \ + _pcp_protect(__percpu_xchg, pcp, (unsigned long)(val))) + +#define this_cpu_add_4(pcp, val) _percpu_add(pcp, val) +#define this_cpu_add_8(pcp, val) _percpu_add(pcp, val) + +#define this_cpu_add_return_4(pcp, val) _percpu_add_return(pcp, val) +#define this_cpu_add_return_8(pcp, val) _percpu_add_return(pcp, val) + +#define this_cpu_and_4(pcp, val) _percpu_and(pcp, val) +#define this_cpu_and_8(pcp, val) _percpu_and(pcp, val) + +#define this_cpu_or_4(pcp, val) _percpu_or(pcp, val) +#define this_cpu_or_8(pcp, val) _percpu_or(pcp, val) + +#define this_cpu_read_1(pcp) _percpu_read(pcp) +#define this_cpu_read_2(pcp) _percpu_read(pcp) +#define this_cpu_read_4(pcp) _percpu_read(pcp) +#define this_cpu_read_8(pcp) _percpu_read(pcp) + +#define this_cpu_write_1(pcp, val) _percpu_write(pcp, val) +#define this_cpu_write_2(pcp, val) _percpu_write(pcp, val) +#define this_cpu_write_4(pcp, val) _percpu_write(pcp, val) +#define this_cpu_write_8(pcp, val) _percpu_write(pcp, val) + +#define this_cpu_xchg_4(pcp, val) _percpu_xchg(pcp, val) +#define this_cpu_xchg_8(pcp, val) _percpu_xchg(pcp, val) + +#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) +#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) + +#include <asm-generic/percpu.h> + +#endif /* __ASM_PERCPU_H */ diff --git a/arch/loongarch/include/asm/perf_event.h b/arch/loongarch/include/asm/perf_event.h new file mode 100644 index 000000000000..dcb3b17053a8 --- /dev/null +++ b/arch/loongarch/include/asm/perf_event.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __LOONGARCH_PERF_EVENT_H__ +#define __LOONGARCH_PERF_EVENT_H__ +/* Nothing to show here; the file is required by linux/perf_event.h. */ +#endif /* __LOONGARCH_PERF_EVENT_H__ */ diff --git a/arch/loongarch/include/asm/pgalloc.h b/arch/loongarch/include/asm/pgalloc.h new file mode 100644 index 000000000000..b0a57b25c131 --- /dev/null +++ b/arch/loongarch/include/asm/pgalloc.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_PGALLOC_H +#define _ASM_PGALLOC_H + +#include <linux/mm.h> +#include <linux/sched.h> + +#define __HAVE_ARCH_PMD_ALLOC_ONE +#define __HAVE_ARCH_PUD_ALLOC_ONE +#include <asm-generic/pgalloc.h> + +static inline void pmd_populate_kernel(struct mm_struct *mm, + pmd_t *pmd, pte_t *pte) +{ + set_pmd(pmd, __pmd((unsigned long)pte)); +} + +static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t pte) +{ + set_pmd(pmd, __pmd((unsigned long)page_address(pte))); +} + +#ifndef __PAGETABLE_PMD_FOLDED + +static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + set_pud(pud, __pud((unsigned long)pmd)); +} +#endif + +#ifndef __PAGETABLE_PUD_FOLDED + +static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud) +{ + set_p4d(p4d, __p4d((unsigned long)pud)); +} + +#endif /* __PAGETABLE_PUD_FOLDED */ + +extern void pagetable_init(void); + +/* + * Initialize a new pmd table with invalid pointers. + */ +extern void pmd_init(unsigned long page, unsigned long pagetable); + +/* + * Initialize a new pgd / pmd table with invalid pointers. + */ +extern void pgd_init(unsigned long page); +extern pgd_t *pgd_alloc(struct mm_struct *mm); + +#define __pte_free_tlb(tlb, pte, address) \ +do { \ + pgtable_pte_page_dtor(pte); \ + tlb_remove_page((tlb), pte); \ +} while (0) + +#ifndef __PAGETABLE_PMD_FOLDED + +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pmd_t *pmd; + struct page *pg; + + pg = alloc_pages(GFP_KERNEL_ACCOUNT, PMD_ORDER); + if (!pg) + return NULL; + + if (!pgtable_pmd_page_ctor(pg)) { + __free_pages(pg, PMD_ORDER); + return NULL; + } + + pmd = (pmd_t *)page_address(pg); + pmd_init((unsigned long)pmd, (unsigned long)invalid_pte_table); + return pmd; +} + +#define __pmd_free_tlb(tlb, x, addr) pmd_free((tlb)->mm, x) + +#endif + +#ifndef __PAGETABLE_PUD_FOLDED + +static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pud_t *pud; + + pud = (pud_t *) __get_free_pages(GFP_KERNEL, PUD_ORDER); + if (pud) + pud_init((unsigned long)pud, (unsigned long)invalid_pmd_table); + return pud; +} + +#define __pud_free_tlb(tlb, x, addr) pud_free((tlb)->mm, x) + +#endif /* __PAGETABLE_PUD_FOLDED */ + +#endif /* _ASM_PGALLOC_H */ diff --git a/arch/loongarch/include/asm/pgtable-bits.h b/arch/loongarch/include/asm/pgtable-bits.h new file mode 100644 index 000000000000..3badd112d9ab --- /dev/null +++ b/arch/loongarch/include/asm/pgtable-bits.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_PGTABLE_BITS_H +#define _ASM_PGTABLE_BITS_H + +/* Page table bits */ +#define _PAGE_VALID_SHIFT 0 +#define _PAGE_ACCESSED_SHIFT 0 /* Reuse Valid for Accessed */ +#define _PAGE_DIRTY_SHIFT 1 +#define _PAGE_PLV_SHIFT 2 /* 2~3, two bits */ +#define _CACHE_SHIFT 4 /* 4~5, two bits */ +#define _PAGE_GLOBAL_SHIFT 6 +#define _PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */ +#define _PAGE_PRESENT_SHIFT 7 +#define _PAGE_WRITE_SHIFT 8 +#define _PAGE_MODIFIED_SHIFT 9 +#define _PAGE_PROTNONE_SHIFT 10 +#define _PAGE_SPECIAL_SHIFT 11 +#define _PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */ +#define _PAGE_PFN_SHIFT 12 +#define _PAGE_PFN_END_SHIFT 48 +#define _PAGE_NO_READ_SHIFT 61 +#define _PAGE_NO_EXEC_SHIFT 62 +#define _PAGE_RPLV_SHIFT 63 + +/* Used by software */ +#define _PAGE_PRESENT (_ULCAST_(1) << _PAGE_PRESENT_SHIFT) +#define _PAGE_WRITE (_ULCAST_(1) << _PAGE_WRITE_SHIFT) +#define _PAGE_ACCESSED (_ULCAST_(1) << _PAGE_ACCESSED_SHIFT) +#define _PAGE_MODIFIED (_ULCAST_(1) << _PAGE_MODIFIED_SHIFT) +#define _PAGE_PROTNONE (_ULCAST_(1) << _PAGE_PROTNONE_SHIFT) +#define _PAGE_SPECIAL (_ULCAST_(1) << _PAGE_SPECIAL_SHIFT) + +/* Used by TLB hardware (placed in EntryLo*) */ +#define _PAGE_VALID (_ULCAST_(1) << _PAGE_VALID_SHIFT) +#define _PAGE_DIRTY (_ULCAST_(1) << _PAGE_DIRTY_SHIFT) +#define _PAGE_PLV (_ULCAST_(3) << _PAGE_PLV_SHIFT) +#define _PAGE_GLOBAL (_ULCAST_(1) << _PAGE_GLOBAL_SHIFT) +#define _PAGE_HUGE (_ULCAST_(1) << _PAGE_HUGE_SHIFT) +#define _PAGE_HGLOBAL (_ULCAST_(1) << _PAGE_HGLOBAL_SHIFT) +#define _PAGE_NO_READ (_ULCAST_(1) << _PAGE_NO_READ_SHIFT) +#define _PAGE_NO_EXEC (_ULCAST_(1) << _PAGE_NO_EXEC_SHIFT) +#define _PAGE_RPLV (_ULCAST_(1) << _PAGE_RPLV_SHIFT) +#define _CACHE_MASK (_ULCAST_(3) << _CACHE_SHIFT) +#define _PFN_SHIFT (PAGE_SHIFT - 12 + _PAGE_PFN_SHIFT) + +#define _PAGE_USER (PLV_USER << _PAGE_PLV_SHIFT) +#define _PAGE_KERN (PLV_KERN << _PAGE_PLV_SHIFT) + +#define _PFN_MASK (~((_ULCAST_(1) << (_PFN_SHIFT)) - 1) & \ + ((_ULCAST_(1) << (_PAGE_PFN_END_SHIFT)) - 1)) + +/* + * Cache attributes + */ +#ifndef _CACHE_SUC +#define _CACHE_SUC (0<<_CACHE_SHIFT) /* Strong-ordered UnCached */ +#endif +#ifndef _CACHE_CC +#define _CACHE_CC (1<<_CACHE_SHIFT) /* Coherent Cached */ +#endif +#ifndef _CACHE_WUC +#define _CACHE_WUC (2<<_CACHE_SHIFT) /* Weak-ordered UnCached */ +#endif + +#define __READABLE (_PAGE_VALID) +#define __WRITEABLE (_PAGE_DIRTY | _PAGE_WRITE) + +#define _PAGE_CHG_MASK (_PAGE_MODIFIED | _PAGE_SPECIAL | _PFN_MASK | _CACHE_MASK | _PAGE_PLV) +#define _HPAGE_CHG_MASK (_PAGE_MODIFIED | _PAGE_SPECIAL | _PFN_MASK | _CACHE_MASK | _PAGE_PLV | _PAGE_HUGE) + +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_NO_READ | \ + _PAGE_USER | _CACHE_CC) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_WRITE | \ + _PAGE_USER | _CACHE_CC) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _CACHE_CC) + +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ + _PAGE_GLOBAL | _PAGE_KERN | _CACHE_CC) +#define PAGE_KERNEL_SUC __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ + _PAGE_GLOBAL | _PAGE_KERN | _CACHE_SUC) +#define PAGE_KERNEL_WUC __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ + _PAGE_GLOBAL | _PAGE_KERN | _CACHE_WUC) + +#define __P000 __pgprot(_CACHE_CC | _PAGE_USER | _PAGE_PROTNONE | _PAGE_NO_EXEC | _PAGE_NO_READ) +#define __P001 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_NO_EXEC) +#define __P010 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_NO_EXEC) +#define __P011 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_NO_EXEC) +#define __P100 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT) +#define __P101 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT) +#define __P110 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT) +#define __P111 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT) + +#define __S000 __pgprot(_CACHE_CC | _PAGE_USER | _PAGE_PROTNONE | _PAGE_NO_EXEC | _PAGE_NO_READ) +#define __S001 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_NO_EXEC) +#define __S010 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE) +#define __S011 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE) +#define __S100 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT) +#define __S101 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT) +#define __S110 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_WRITE) +#define __S111 __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_WRITE) + +#ifndef __ASSEMBLY__ + +#define pgprot_noncached pgprot_noncached + +static inline pgprot_t pgprot_noncached(pgprot_t _prot) +{ + unsigned long prot = pgprot_val(_prot); + + prot = (prot & ~_CACHE_MASK) | _CACHE_SUC; + + return __pgprot(prot); +} + +#define pgprot_writecombine pgprot_writecombine + +static inline pgprot_t pgprot_writecombine(pgprot_t _prot) +{ + unsigned long prot = pgprot_val(_prot); + + prot = (prot & ~_CACHE_MASK) | _CACHE_WUC; + + return __pgprot(prot); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_PGTABLE_BITS_H */ diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h new file mode 100644 index 000000000000..5dc84d8f18d6 --- /dev/null +++ b/arch/loongarch/include/asm/pgtable.h @@ -0,0 +1,565 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 2003 Ralf Baechle + * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. + */ +#ifndef _ASM_PGTABLE_H +#define _ASM_PGTABLE_H + +#include <linux/compiler.h> +#include <asm/addrspace.h> +#include <asm/pgtable-bits.h> + +#if CONFIG_PGTABLE_LEVELS == 2 +#include <asm-generic/pgtable-nopmd.h> +#elif CONFIG_PGTABLE_LEVELS == 3 +#include <asm-generic/pgtable-nopud.h> +#else +#include <asm-generic/pgtable-nop4d.h> +#endif + +#define PGD_ORDER 0 +#define PUD_ORDER 0 +#define PMD_ORDER 0 +#define PTE_ORDER 0 + +#if CONFIG_PGTABLE_LEVELS == 2 +#define PGDIR_SHIFT (PAGE_SHIFT + (PAGE_SHIFT + PTE_ORDER - 3)) +#elif CONFIG_PGTABLE_LEVELS == 3 +#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT + PTE_ORDER - 3)) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) +#define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT + PMD_ORDER - 3)) +#elif CONFIG_PGTABLE_LEVELS == 4 +#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT + PTE_ORDER - 3)) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) +#define PUD_SHIFT (PMD_SHIFT + (PAGE_SHIFT + PMD_ORDER - 3)) +#define PUD_SIZE (1UL << PUD_SHIFT) +#define PUD_MASK (~(PUD_SIZE-1)) +#define PGDIR_SHIFT (PUD_SHIFT + (PAGE_SHIFT + PUD_ORDER - 3)) +#endif + +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +#define VA_BITS (PGDIR_SHIFT + (PAGE_SHIFT + PGD_ORDER - 3)) + +#define PTRS_PER_PGD ((PAGE_SIZE << PGD_ORDER) >> 3) +#if CONFIG_PGTABLE_LEVELS > 3 +#define PTRS_PER_PUD ((PAGE_SIZE << PUD_ORDER) >> 3) +#endif +#if CONFIG_PGTABLE_LEVELS > 2 +#define PTRS_PER_PMD ((PAGE_SIZE << PMD_ORDER) >> 3) +#endif +#define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) >> 3) + +#define USER_PTRS_PER_PGD ((TASK_SIZE64 / PGDIR_SIZE)?(TASK_SIZE64 / PGDIR_SIZE):1) + +#ifndef __ASSEMBLY__ + +#include <linux/mm_types.h> +#include <linux/mmzone.h> +#include <asm/fixmap.h> +#include <asm/io.h> + +struct mm_struct; +struct vm_area_struct; + +/* + * ZERO_PAGE is a global shared page that is always zero; used + * for zero-mapped memory areas etc.. + */ + +extern unsigned long empty_zero_page; +extern unsigned long zero_page_mask; + +#define ZERO_PAGE(vaddr) \ + (virt_to_page((void *)(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask)))) +#define __HAVE_COLOR_ZERO_PAGE + +/* + * TLB refill handlers may also map the vmalloc area into xkvrange. + * Avoid the first couple of pages so NULL pointer dereferences will + * still reliably trap. + */ +#define MODULES_VADDR (vm_map_base + PCI_IOSIZE + (2 * PAGE_SIZE)) +#define MODULES_END (MODULES_VADDR + SZ_256M) + +#define VMALLOC_START MODULES_END +#define VMALLOC_END \ + (vm_map_base + \ + min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE) + +#define pte_ERROR(e) \ + pr_err("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e)) +#ifndef __PAGETABLE_PMD_FOLDED +#define pmd_ERROR(e) \ + pr_err("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e)) +#endif +#ifndef __PAGETABLE_PUD_FOLDED +#define pud_ERROR(e) \ + pr_err("%s:%d: bad pud %016lx.\n", __FILE__, __LINE__, pud_val(e)) +#endif +#define pgd_ERROR(e) \ + pr_err("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e)) + +extern pte_t invalid_pte_table[PTRS_PER_PTE]; + +#ifndef __PAGETABLE_PUD_FOLDED + +typedef struct { unsigned long pud; } pud_t; +#define pud_val(x) ((x).pud) +#define __pud(x) ((pud_t) { (x) }) + +extern pud_t invalid_pud_table[PTRS_PER_PUD]; + +/* + * Empty pgd/p4d entries point to the invalid_pud_table. + */ +static inline int p4d_none(p4d_t p4d) +{ + return p4d_val(p4d) == (unsigned long)invalid_pud_table; +} + +static inline int p4d_bad(p4d_t p4d) +{ + return p4d_val(p4d) & ~PAGE_MASK; +} + +static inline int p4d_present(p4d_t p4d) +{ + return p4d_val(p4d) != (unsigned long)invalid_pud_table; +} + +static inline void p4d_clear(p4d_t *p4dp) +{ + p4d_val(*p4dp) = (unsigned long)invalid_pud_table; +} + +static inline pud_t *p4d_pgtable(p4d_t p4d) +{ + return (pud_t *)p4d_val(p4d); +} + +static inline void set_p4d(p4d_t *p4d, p4d_t p4dval) +{ + *p4d = p4dval; +} + +#define p4d_phys(p4d) virt_to_phys((void *)p4d_val(p4d)) +#define p4d_page(p4d) (pfn_to_page(p4d_phys(p4d) >> PAGE_SHIFT)) + +#endif + +#ifndef __PAGETABLE_PMD_FOLDED + +typedef struct { unsigned long pmd; } pmd_t; +#define pmd_val(x) ((x).pmd) +#define __pmd(x) ((pmd_t) { (x) }) + +extern pmd_t invalid_pmd_table[PTRS_PER_PMD]; + +/* + * Empty pud entries point to the invalid_pmd_table. + */ +static inline int pud_none(pud_t pud) +{ + return pud_val(pud) == (unsigned long)invalid_pmd_table; +} + +static inline int pud_bad(pud_t pud) +{ + return pud_val(pud) & ~PAGE_MASK; +} + +static inline int pud_present(pud_t pud) +{ + return pud_val(pud) != (unsigned long)invalid_pmd_table; +} + +static inline void pud_clear(pud_t *pudp) +{ + pud_val(*pudp) = ((unsigned long)invalid_pmd_table); +} + +static inline pmd_t *pud_pgtable(pud_t pud) +{ + return (pmd_t *)pud_val(pud); +} + +#define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while (0) + +#define pud_phys(pud) virt_to_phys((void *)pud_val(pud)) +#define pud_page(pud) (pfn_to_page(pud_phys(pud) >> PAGE_SHIFT)) + +#endif + +/* + * Empty pmd entries point to the invalid_pte_table. + */ +static inline int pmd_none(pmd_t pmd) +{ + return pmd_val(pmd) == (unsigned long)invalid_pte_table; +} + +static inline int pmd_bad(pmd_t pmd) +{ + return (pmd_val(pmd) & ~PAGE_MASK); +} + +static inline int pmd_present(pmd_t pmd) +{ + if (unlikely(pmd_val(pmd) & _PAGE_HUGE)) + return !!(pmd_val(pmd) & (_PAGE_PRESENT | _PAGE_PROTNONE)); + + return pmd_val(pmd) != (unsigned long)invalid_pte_table; +} + +static inline void pmd_clear(pmd_t *pmdp) +{ + pmd_val(*pmdp) = ((unsigned long)invalid_pte_table); +} + +#define set_pmd(pmdptr, pmdval) do { *(pmdptr) = (pmdval); } while (0) + +#define pmd_phys(pmd) virt_to_phys((void *)pmd_val(pmd)) + +#ifndef CONFIG_TRANSPARENT_HUGEPAGE +#define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT)) +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +#define pmd_page_vaddr(pmd) pmd_val(pmd) + +extern pmd_t mk_pmd(struct page *page, pgprot_t prot); +extern void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd); + +#define pte_page(x) pfn_to_page(pte_pfn(x)) +#define pte_pfn(x) ((unsigned long)(((x).pte & _PFN_MASK) >> _PFN_SHIFT)) +#define pfn_pte(pfn, prot) __pte(((pfn) << _PFN_SHIFT) | pgprot_val(prot)) +#define pfn_pmd(pfn, prot) __pmd(((pfn) << _PFN_SHIFT) | pgprot_val(prot)) + +/* + * Initialize a new pgd / pmd table with invalid pointers. + */ +extern void pgd_init(unsigned long page); +extern void pud_init(unsigned long page, unsigned long pagetable); +extern void pmd_init(unsigned long page, unsigned long pagetable); + +/* + * Non-present pages: high 40 bits are offset, next 8 bits type, + * low 16 bits zero. + */ +static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) +{ pte_t pte; pte_val(pte) = (type << 16) | (offset << 24); return pte; } + +#define __swp_type(x) (((x).val >> 16) & 0xff) +#define __swp_offset(x) ((x).val >> 24) +#define __swp_entry(type, offset) ((swp_entry_t) { pte_val(mk_swap_pte((type), (offset))) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) +#define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val(pmd) }) +#define __swp_entry_to_pmd(x) ((pmd_t) { (x).val | _PAGE_HUGE }) + +extern void paging_init(void); + +#define pte_none(pte) (!(pte_val(pte) & ~_PAGE_GLOBAL)) +#define pte_present(pte) (pte_val(pte) & (_PAGE_PRESENT | _PAGE_PROTNONE)) +#define pte_no_exec(pte) (pte_val(pte) & _PAGE_NO_EXEC) + +static inline void set_pte(pte_t *ptep, pte_t pteval) +{ + *ptep = pteval; + if (pte_val(pteval) & _PAGE_GLOBAL) { + pte_t *buddy = ptep_buddy(ptep); + /* + * Make sure the buddy is global too (if it's !none, + * it better already be global) + */ +#ifdef CONFIG_SMP + /* + * For SMP, multiple CPUs can race, so we need to do + * this atomically. + */ + unsigned long page_global = _PAGE_GLOBAL; + unsigned long tmp; + + __asm__ __volatile__ ( + "1:" __LL "%[tmp], %[buddy] \n" + " bnez %[tmp], 2f \n" + " or %[tmp], %[tmp], %[global] \n" + __SC "%[tmp], %[buddy] \n" + " beqz %[tmp], 1b \n" + " nop \n" + "2: \n" + __WEAK_LLSC_MB + : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp) + : [global] "r" (page_global)); +#else /* !CONFIG_SMP */ + if (pte_none(*buddy)) + pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL; +#endif /* CONFIG_SMP */ + } +} + +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval) +{ + set_pte(ptep, pteval); +} + +static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +{ + /* Preserve global status for the pair */ + if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL) + set_pte_at(mm, addr, ptep, __pte(_PAGE_GLOBAL)); + else + set_pte_at(mm, addr, ptep, __pte(0)); +} + +#define PGD_T_LOG2 (__builtin_ffs(sizeof(pgd_t)) - 1) +#define PMD_T_LOG2 (__builtin_ffs(sizeof(pmd_t)) - 1) +#define PTE_T_LOG2 (__builtin_ffs(sizeof(pte_t)) - 1) + +extern pgd_t swapper_pg_dir[]; +extern pgd_t invalid_pg_dir[]; + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } +static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } + +static inline pte_t pte_mkold(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_ACCESSED; + return pte; +} + +static inline pte_t pte_mkyoung(pte_t pte) +{ + pte_val(pte) |= _PAGE_ACCESSED; + return pte; +} + +static inline pte_t pte_mkclean(pte_t pte) +{ + pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_MODIFIED); + return pte; +} + +static inline pte_t pte_mkdirty(pte_t pte) +{ + pte_val(pte) |= (_PAGE_DIRTY | _PAGE_MODIFIED); + return pte; +} + +static inline pte_t pte_mkwrite(pte_t pte) +{ + pte_val(pte) |= (_PAGE_WRITE | _PAGE_DIRTY); + return pte; +} + +static inline pte_t pte_wrprotect(pte_t pte) +{ + pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_DIRTY); + return pte; +} + +static inline int pte_huge(pte_t pte) { return pte_val(pte) & _PAGE_HUGE; } + +static inline pte_t pte_mkhuge(pte_t pte) +{ + pte_val(pte) |= _PAGE_HUGE; + return pte; +} + +#if defined(CONFIG_ARCH_HAS_PTE_SPECIAL) +static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; } +static inline pte_t pte_mkspecial(pte_t pte) { pte_val(pte) |= _PAGE_SPECIAL; return pte; } +#endif /* CONFIG_ARCH_HAS_PTE_SPECIAL */ + +#define pte_accessible pte_accessible +static inline unsigned long pte_accessible(struct mm_struct *mm, pte_t a) +{ + if (pte_val(a) & _PAGE_PRESENT) + return true; + + if ((pte_val(a) & _PAGE_PROTNONE) && + atomic_read(&mm->tlb_flush_pending)) + return true; + + return false; +} + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ +#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + return __pte((pte_val(pte) & _PAGE_CHG_MASK) | + (pgprot_val(newprot) & ~_PAGE_CHG_MASK)); +} + +extern void __update_tlb(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep); + +static inline void update_mmu_cache(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep) +{ + __update_tlb(vma, address, ptep); +} + +static inline void update_mmu_cache_pmd(struct vm_area_struct *vma, + unsigned long address, pmd_t *pmdp) +{ + __update_tlb(vma, address, (pte_t *)pmdp); +} + +#define kern_addr_valid(addr) (1) + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + +/* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/ +#define pmdp_establish generic_pmdp_establish + +static inline int pmd_trans_huge(pmd_t pmd) +{ + return !!(pmd_val(pmd) & _PAGE_HUGE) && pmd_present(pmd); +} + +static inline pmd_t pmd_mkhuge(pmd_t pmd) +{ + pmd_val(pmd) = (pmd_val(pmd) & ~(_PAGE_GLOBAL)) | + ((pmd_val(pmd) & _PAGE_GLOBAL) << (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)); + pmd_val(pmd) |= _PAGE_HUGE; + + return pmd; +} + +#define pmd_write pmd_write +static inline int pmd_write(pmd_t pmd) +{ + return !!(pmd_val(pmd) & _PAGE_WRITE); +} + +static inline pmd_t pmd_mkwrite(pmd_t pmd) +{ + pmd_val(pmd) |= (_PAGE_WRITE | _PAGE_DIRTY); + return pmd; +} + +static inline pmd_t pmd_wrprotect(pmd_t pmd) +{ + pmd_val(pmd) &= ~(_PAGE_WRITE | _PAGE_DIRTY); + return pmd; +} + +static inline int pmd_dirty(pmd_t pmd) +{ + return !!(pmd_val(pmd) & _PAGE_MODIFIED); +} + +static inline pmd_t pmd_mkclean(pmd_t pmd) +{ + pmd_val(pmd) &= ~(_PAGE_DIRTY | _PAGE_MODIFIED); + return pmd; +} + +static inline pmd_t pmd_mkdirty(pmd_t pmd) +{ + pmd_val(pmd) |= (_PAGE_DIRTY | _PAGE_MODIFIED); + return pmd; +} + +static inline int pmd_young(pmd_t pmd) +{ + return !!(pmd_val(pmd) & _PAGE_ACCESSED); +} + +static inline pmd_t pmd_mkold(pmd_t pmd) +{ + pmd_val(pmd) &= ~_PAGE_ACCESSED; + return pmd; +} + +static inline pmd_t pmd_mkyoung(pmd_t pmd) +{ + pmd_val(pmd) |= _PAGE_ACCESSED; + return pmd; +} + +static inline unsigned long pmd_pfn(pmd_t pmd) +{ + return (pmd_val(pmd) & _PFN_MASK) >> _PFN_SHIFT; +} + +static inline struct page *pmd_page(pmd_t pmd) +{ + if (pmd_trans_huge(pmd)) + return pfn_to_page(pmd_pfn(pmd)); + + return pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT); +} + +static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) +{ + pmd_val(pmd) = (pmd_val(pmd) & _HPAGE_CHG_MASK) | + (pgprot_val(newprot) & ~_HPAGE_CHG_MASK); + return pmd; +} + +static inline pmd_t pmd_mkinvalid(pmd_t pmd) +{ + pmd_val(pmd) &= ~(_PAGE_PRESENT | _PAGE_VALID | _PAGE_DIRTY | _PAGE_PROTNONE); + + return pmd; +} + +/* + * The generic version pmdp_huge_get_and_clear uses a version of pmd_clear() with a + * different prototype. + */ +#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR +static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, + unsigned long address, pmd_t *pmdp) +{ + pmd_t old = *pmdp; + + pmd_clear(pmdp); + + return old; +} + +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +#ifdef CONFIG_NUMA_BALANCING +static inline long pte_protnone(pte_t pte) +{ + return (pte_val(pte) & _PAGE_PROTNONE); +} + +static inline long pmd_protnone(pmd_t pmd) +{ + return (pmd_val(pmd) & _PAGE_PROTNONE); +} +#endif /* CONFIG_NUMA_BALANCING */ + +/* + * We provide our own get_unmapped area to cope with the virtual aliasing + * constraints placed on us by the cache architecture. + */ +#define HAVE_ARCH_UNMAPPED_AREA +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_PGTABLE_H */ diff --git a/arch/loongarch/include/asm/prefetch.h b/arch/loongarch/include/asm/prefetch.h new file mode 100644 index 000000000000..1672262a5e2e --- /dev/null +++ b/arch/loongarch/include/asm/prefetch.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_PREFETCH_H +#define __ASM_PREFETCH_H + +#define Pref_Load 0 +#define Pref_Store 8 + +#ifdef __ASSEMBLY__ + + .macro __pref hint addr +#ifdef CONFIG_CPU_HAS_PREFETCH + preld \hint, \addr, 0 +#endif + .endm + + .macro pref_load addr + __pref Pref_Load, \addr + .endm + + .macro pref_store addr + __pref Pref_Store, \addr + .endm + +#endif + +#endif /* __ASM_PREFETCH_H */ diff --git a/arch/loongarch/include/asm/processor.h b/arch/loongarch/include/asm/processor.h new file mode 100644 index 000000000000..1d63c934b289 --- /dev/null +++ b/arch/loongarch/include/asm/processor.h @@ -0,0 +1,209 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_PROCESSOR_H +#define _ASM_PROCESSOR_H + +#include <linux/atomic.h> +#include <linux/cpumask.h> +#include <linux/sizes.h> + +#include <asm/cpu.h> +#include <asm/cpu-info.h> +#include <asm/loongarch.h> +#include <asm/vdso/processor.h> +#include <uapi/asm/ptrace.h> +#include <uapi/asm/sigcontext.h> + +#ifdef CONFIG_32BIT + +#define TASK_SIZE 0x80000000UL +#define TASK_SIZE_MIN TASK_SIZE +#define STACK_TOP_MAX TASK_SIZE + +#define TASK_IS_32BIT_ADDR 1 + +#endif + +#ifdef CONFIG_64BIT + +#define TASK_SIZE32 0x100000000UL +#define TASK_SIZE64 (0x1UL << ((cpu_vabits > VA_BITS) ? VA_BITS : cpu_vabits)) + +#define TASK_SIZE (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE64) +#define TASK_SIZE_MIN TASK_SIZE32 +#define STACK_TOP_MAX TASK_SIZE64 + +#define TASK_SIZE_OF(tsk) \ + (test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE64) + +#define TASK_IS_32BIT_ADDR test_thread_flag(TIF_32BIT_ADDR) + +#endif + +#define VDSO_RANDOMIZE_SIZE (TASK_IS_32BIT_ADDR ? SZ_1M : SZ_64M) + +unsigned long stack_top(void); +#define STACK_TOP stack_top() + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3) + +#define FPU_REG_WIDTH 256 +#define FPU_ALIGN __attribute__((aligned(32))) + +union fpureg { + __u32 val32[FPU_REG_WIDTH / 32]; + __u64 val64[FPU_REG_WIDTH / 64]; +}; + +#define FPR_IDX(width, idx) (idx) + +#define BUILD_FPR_ACCESS(width) \ +static inline u##width get_fpr##width(union fpureg *fpr, unsigned idx) \ +{ \ + return fpr->val##width[FPR_IDX(width, idx)]; \ +} \ + \ +static inline void set_fpr##width(union fpureg *fpr, unsigned int idx, \ + u##width val) \ +{ \ + fpr->val##width[FPR_IDX(width, idx)] = val; \ +} + +BUILD_FPR_ACCESS(32) +BUILD_FPR_ACCESS(64) + +struct loongarch_fpu { + unsigned int fcsr; + unsigned int vcsr; + uint64_t fcc; /* 8x8 */ + union fpureg fpr[NUM_FPU_REGS]; +}; + +#define INIT_CPUMASK { \ + {0,} \ +} + +#define ARCH_MIN_TASKALIGN 32 + +struct loongarch_vdso_info; + +/* + * If you change thread_struct remember to change the #defines below too! + */ +struct thread_struct { + /* Main processor registers. */ + unsigned long reg01, reg03, reg22; /* ra sp fp */ + unsigned long reg23, reg24, reg25, reg26; /* s0-s3 */ + unsigned long reg27, reg28, reg29, reg30, reg31; /* s4-s8 */ + + /* CSR registers */ + unsigned long csr_prmd; + unsigned long csr_crmd; + unsigned long csr_euen; + unsigned long csr_ecfg; + unsigned long csr_badvaddr; /* Last user fault */ + + /* Scratch registers */ + unsigned long scr0; + unsigned long scr1; + unsigned long scr2; + unsigned long scr3; + + /* Eflags register */ + unsigned long eflags; + + /* Other stuff associated with the thread. */ + unsigned long trap_nr; + unsigned long error_code; + struct loongarch_vdso_info *vdso; + + /* + * FPU & vector registers, must be at last because + * they are conditionally copied at fork(). + */ + struct loongarch_fpu fpu FPU_ALIGN; +}; + +#define INIT_THREAD { \ + /* \ + * Main processor registers \ + */ \ + .reg01 = 0, \ + .reg03 = 0, \ + .reg22 = 0, \ + .reg23 = 0, \ + .reg24 = 0, \ + .reg25 = 0, \ + .reg26 = 0, \ + .reg27 = 0, \ + .reg28 = 0, \ + .reg29 = 0, \ + .reg30 = 0, \ + .reg31 = 0, \ + .csr_crmd = 0, \ + .csr_prmd = 0, \ + .csr_euen = 0, \ + .csr_ecfg = 0, \ + .csr_badvaddr = 0, \ + /* \ + * Other stuff associated with the process \ + */ \ + .trap_nr = 0, \ + .error_code = 0, \ + /* \ + * FPU & vector registers \ + */ \ + .fpu = { \ + .fcsr = 0, \ + .vcsr = 0, \ + .fcc = 0, \ + .fpr = {{{0,},},}, \ + }, \ +} + +struct task_struct; + +/* Free all resources held by a thread. */ +#define release_thread(thread) do { } while (0) + +enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_HALT, IDLE_NOMWAIT, IDLE_POLL}; + +extern unsigned long boot_option_idle_override; +/* + * Do necessary setup to start up a newly executed thread. + */ +extern void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp); + +static inline void flush_thread(void) +{ +} + +unsigned long __get_wchan(struct task_struct *p); + +#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \ + THREAD_SIZE - 32 - sizeof(struct pt_regs)) +#define task_pt_regs(tsk) ((struct pt_regs *)__KSTK_TOS(tsk)) +#define KSTK_EIP(tsk) (task_pt_regs(tsk)->csr_era) +#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[3]) +#define KSTK_EUEN(tsk) (task_pt_regs(tsk)->csr_euen) +#define KSTK_ECFG(tsk) (task_pt_regs(tsk)->csr_ecfg) + +#define return_address() ({__asm__ __volatile__("":::"$1"); __builtin_return_address(0);}) + +#ifdef CONFIG_CPU_HAS_PREFETCH + +#define ARCH_HAS_PREFETCH +#define prefetch(x) __builtin_prefetch((x), 0, 1) + +#define ARCH_HAS_PREFETCHW +#define prefetchw(x) __builtin_prefetch((x), 1, 1) + +#endif + +#endif /* _ASM_PROCESSOR_H */ diff --git a/arch/loongarch/include/asm/ptrace.h b/arch/loongarch/include/asm/ptrace.h new file mode 100644 index 000000000000..17838c6b7ccd --- /dev/null +++ b/arch/loongarch/include/asm/ptrace.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_PTRACE_H +#define _ASM_PTRACE_H + +#include <asm/page.h> +#include <asm/thread_info.h> +#include <uapi/asm/ptrace.h> + +/* + * This struct defines the way the registers are stored on the stack during + * a system call/exception. If you add a register here, please also add it to + * regoffset_table[] in arch/loongarch/kernel/ptrace.c. + */ +struct pt_regs { + /* Main processor registers. */ + unsigned long regs[32]; + + /* Original syscall arg0. */ + unsigned long orig_a0; + + /* Special CSR registers. */ + unsigned long csr_era; + unsigned long csr_badvaddr; + unsigned long csr_crmd; + unsigned long csr_prmd; + unsigned long csr_euen; + unsigned long csr_ecfg; + unsigned long csr_estat; + unsigned long __last[0]; +} __aligned(8); + +static inline int regs_irqs_disabled(struct pt_regs *regs) +{ + return arch_irqs_disabled_flags(regs->csr_prmd); +} + +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ + return regs->regs[3]; +} + +/* + * Don't use asm-generic/ptrace.h it defines FP accessors that don't make + * sense on LoongArch. We rather want an error if they get invoked. + */ + +static inline void instruction_pointer_set(struct pt_regs *regs, unsigned long val) +{ + regs->csr_era = val; +} + +/* Query offset/name of register from its name/offset */ +extern int regs_query_register_offset(const char *name); +#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last)) + +/** + * regs_get_register() - get register value from its offset + * @regs: pt_regs from which register value is gotten. + * @offset: offset number of the register. + * + * regs_get_register returns the value of a register. The @offset is the + * offset of the register in struct pt_regs address which specified by @regs. + * If @offset is bigger than MAX_REG_OFFSET, this returns 0. + */ +static inline unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset) +{ + if (unlikely(offset > MAX_REG_OFFSET)) + return 0; + + return *(unsigned long *)((unsigned long)regs + offset); +} + +/** + * regs_within_kernel_stack() - check the address in the stack + * @regs: pt_regs which contains kernel stack pointer. + * @addr: address which is checked. + * + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). + * If @addr is within the kernel stack, it returns true. If not, returns false. + */ +static inline int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) +{ + return ((addr & ~(THREAD_SIZE - 1)) == + (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); +} + +/** + * regs_get_kernel_stack_nth() - get Nth entry of the stack + * @regs: pt_regs which contains kernel stack pointer. + * @n: stack entry number. + * + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which + * is specified by @regs. If the @n th entry is NOT in the kernel stack, + * this returns 0. + */ +static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) +{ + unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); + + addr += n; + if (regs_within_kernel_stack(regs, (unsigned long)addr)) + return *addr; + else + return 0; +} + +struct task_struct; + +/* + * Does the process account for user or for system time? + */ +#define user_mode(regs) (((regs)->csr_prmd & PLV_MASK) == PLV_USER) + +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->regs[4]; +} + +#define instruction_pointer(regs) ((regs)->csr_era) +#define profile_pc(regs) instruction_pointer(regs) + +extern void die(const char *, struct pt_regs *) __noreturn; + +static inline void die_if_kernel(const char *str, struct pt_regs *regs) +{ + if (unlikely(!user_mode(regs))) + die(str, regs); +} + +#define current_pt_regs() \ +({ \ + unsigned long sp = (unsigned long)__builtin_frame_address(0); \ + (struct pt_regs *)((sp | (THREAD_SIZE - 1)) + 1 - 32) - 1; \ +}) + +/* Helpers for working with the user stack pointer */ + +static inline unsigned long user_stack_pointer(struct pt_regs *regs) +{ + return regs->regs[3]; +} + +static inline void user_stack_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + regs->regs[3] = val; +} + +#endif /* _ASM_PTRACE_H */ diff --git a/arch/loongarch/include/asm/reboot.h b/arch/loongarch/include/asm/reboot.h new file mode 100644 index 000000000000..51151749d8f0 --- /dev/null +++ b/arch/loongarch/include/asm/reboot.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_REBOOT_H +#define _ASM_REBOOT_H + +extern void (*pm_restart)(void); + +#endif /* _ASM_REBOOT_H */ diff --git a/arch/loongarch/include/asm/regdef.h b/arch/loongarch/include/asm/regdef.h new file mode 100644 index 000000000000..49a374c2612c --- /dev/null +++ b/arch/loongarch/include/asm/regdef.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_REGDEF_H +#define _ASM_REGDEF_H + +#define zero $r0 /* wired zero */ +#define ra $r1 /* return address */ +#define tp $r2 +#define sp $r3 /* stack pointer */ +#define a0 $r4 /* argument registers, a0/a1 reused as v0/v1 for return value */ +#define a1 $r5 +#define a2 $r6 +#define a3 $r7 +#define a4 $r8 +#define a5 $r9 +#define a6 $r10 +#define a7 $r11 +#define t0 $r12 /* caller saved */ +#define t1 $r13 +#define t2 $r14 +#define t3 $r15 +#define t4 $r16 +#define t5 $r17 +#define t6 $r18 +#define t7 $r19 +#define t8 $r20 +#define u0 $r21 +#define fp $r22 /* frame pointer */ +#define s0 $r23 /* callee saved */ +#define s1 $r24 +#define s2 $r25 +#define s3 $r26 +#define s4 $r27 +#define s5 $r28 +#define s6 $r29 +#define s7 $r30 +#define s8 $r31 + +#endif /* _ASM_REGDEF_H */ diff --git a/arch/loongarch/include/asm/seccomp.h b/arch/loongarch/include/asm/seccomp.h new file mode 100644 index 000000000000..31d6ab42e43e --- /dev/null +++ b/arch/loongarch/include/asm/seccomp.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_SECCOMP_H +#define _ASM_SECCOMP_H + +#include <asm/unistd.h> + +#include <asm-generic/seccomp.h> + +#ifdef CONFIG_32BIT +# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_LOONGARCH32 +# define SECCOMP_ARCH_NATIVE_NR NR_syscalls +# define SECCOMP_ARCH_NATIVE_NAME "loongarch32" +#else +# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_LOONGARCH64 +# define SECCOMP_ARCH_NATIVE_NR NR_syscalls +# define SECCOMP_ARCH_NATIVE_NAME "loongarch64" +#endif + +#endif /* _ASM_SECCOMP_H */ diff --git a/arch/loongarch/include/asm/serial.h b/arch/loongarch/include/asm/serial.h new file mode 100644 index 000000000000..3fb550eb9115 --- /dev/null +++ b/arch/loongarch/include/asm/serial.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM__SERIAL_H +#define __ASM__SERIAL_H + +#define BASE_BAUD 0 +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#endif /* __ASM__SERIAL_H */ diff --git a/arch/loongarch/include/asm/setup.h b/arch/loongarch/include/asm/setup.h new file mode 100644 index 000000000000..6d7d2a3e23dd --- /dev/null +++ b/arch/loongarch/include/asm/setup.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef _LOONGARCH_SETUP_H +#define _LOONGARCH_SETUP_H + +#include <linux/types.h> +#include <uapi/asm/setup.h> + +#define VECSIZE 0x200 + +extern unsigned long eentry; +extern unsigned long tlbrentry; +extern void cpu_cache_init(void); +extern void per_cpu_trap_init(int cpu); +extern void set_handler(unsigned long offset, void *addr, unsigned long len); +extern void set_merr_handler(unsigned long offset, void *addr, unsigned long len); + +#endif /* __SETUP_H */ diff --git a/arch/loongarch/include/asm/shmparam.h b/arch/loongarch/include/asm/shmparam.h new file mode 100644 index 000000000000..c9554f48d2df --- /dev/null +++ b/arch/loongarch/include/asm/shmparam.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_SHMPARAM_H +#define _ASM_SHMPARAM_H + +#define __ARCH_FORCE_SHMLBA 1 + +#define SHMLBA SZ_64K /* attach addr a multiple of this */ + +#endif /* _ASM_SHMPARAM_H */ diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h new file mode 100644 index 000000000000..551e1f37c705 --- /dev/null +++ b/arch/loongarch/include/asm/smp.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_SMP_H +#define __ASM_SMP_H + +#include <linux/atomic.h> +#include <linux/bitops.h> +#include <linux/linkage.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/cpumask.h> + +void loongson3_smp_setup(void); +void loongson3_prepare_cpus(unsigned int max_cpus); +void loongson3_boot_secondary(int cpu, struct task_struct *idle); +void loongson3_init_secondary(void); +void loongson3_smp_finish(void); +void loongson3_send_ipi_single(int cpu, unsigned int action); +void loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action); +#ifdef CONFIG_HOTPLUG_CPU +int loongson3_cpu_disable(void); +void loongson3_cpu_die(unsigned int cpu); +#endif + +#ifdef CONFIG_SMP + +static inline void plat_smp_setup(void) +{ + loongson3_smp_setup(); +} + +#else /* !CONFIG_SMP */ + +static inline void plat_smp_setup(void) { } + +#endif /* !CONFIG_SMP */ + +extern int smp_num_siblings; +extern int num_processors; +extern int disabled_cpus; +extern cpumask_t cpu_sibling_map[]; +extern cpumask_t cpu_core_map[]; +extern cpumask_t cpu_foreign_map[]; + +static inline int raw_smp_processor_id(void) +{ +#if defined(__VDSO__) + extern int vdso_smp_processor_id(void) + __compiletime_error("VDSO should not call smp_processor_id()"); + return vdso_smp_processor_id(); +#else + return current_thread_info()->cpu; +#endif +} +#define raw_smp_processor_id raw_smp_processor_id + +/* Map from cpu id to sequential logical cpu number. This will only + * not be idempotent when cpus failed to come on-line. */ +extern int __cpu_number_map[NR_CPUS]; +#define cpu_number_map(cpu) __cpu_number_map[cpu] + +/* The reverse map from sequential logical cpu number to cpu id. */ +extern int __cpu_logical_map[NR_CPUS]; +#define cpu_logical_map(cpu) __cpu_logical_map[cpu] + +#define cpu_physical_id(cpu) cpu_logical_map(cpu) + +#define SMP_BOOT_CPU 0x1 +#define SMP_RESCHEDULE 0x2 +#define SMP_CALL_FUNCTION 0x4 + +struct secondary_data { + unsigned long stack; + unsigned long thread_info; +}; +extern struct secondary_data cpuboot_data; + +extern asmlinkage void smpboot_entry(void); + +extern void calculate_cpu_foreign_map(void); + +/* + * Generate IPI list text + */ +extern void show_ipi_list(struct seq_file *p, int prec); + +/* + * This function sends a 'reschedule' IPI to another CPU. + * it goes straight through and wastes no time serializing + * anything. Worst case is that we lose a reschedule ... + */ +static inline void smp_send_reschedule(int cpu) +{ + loongson3_send_ipi_single(cpu, SMP_RESCHEDULE); +} + +static inline void arch_send_call_function_single_ipi(int cpu) +{ + loongson3_send_ipi_single(cpu, SMP_CALL_FUNCTION); +} + +static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask) +{ + loongson3_send_ipi_mask(mask, SMP_CALL_FUNCTION); +} + +#ifdef CONFIG_HOTPLUG_CPU +static inline int __cpu_disable(void) +{ + return loongson3_cpu_disable(); +} + +static inline void __cpu_die(unsigned int cpu) +{ + loongson3_cpu_die(cpu); +} + +extern void play_dead(void); +#endif + +#endif /* __ASM_SMP_H */ diff --git a/arch/loongarch/include/asm/sparsemem.h b/arch/loongarch/include/asm/sparsemem.h new file mode 100644 index 000000000000..3d18cdf1b069 --- /dev/null +++ b/arch/loongarch/include/asm/sparsemem.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LOONGARCH_SPARSEMEM_H +#define _LOONGARCH_SPARSEMEM_H + +#ifdef CONFIG_SPARSEMEM + +/* + * SECTION_SIZE_BITS 2^N: how big each section will be + * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space + */ +#define SECTION_SIZE_BITS 29 /* 2^29 = Largest Huge Page Size */ +#define MAX_PHYSMEM_BITS 48 + +#endif /* CONFIG_SPARSEMEM */ + +#ifdef CONFIG_MEMORY_HOTPLUG +int memory_add_physaddr_to_nid(u64 addr); +#define memory_add_physaddr_to_nid memory_add_physaddr_to_nid +#endif + +#define INIT_MEMBLOCK_RESERVED_REGIONS (INIT_MEMBLOCK_REGIONS + NR_CPUS) + +#endif /* _LOONGARCH_SPARSEMEM_H */ diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h new file mode 100644 index 000000000000..4ca953062b5b --- /dev/null +++ b/arch/loongarch/include/asm/stackframe.h @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_STACKFRAME_H +#define _ASM_STACKFRAME_H + +#include <linux/threads.h> + +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/asm-offsets.h> +#include <asm/loongarch.h> +#include <asm/thread_info.h> + +/* Make the addition of cfi info a little easier. */ + .macro cfi_rel_offset reg offset=0 docfi=0 + .if \docfi + .cfi_rel_offset \reg, \offset + .endif + .endm + + .macro cfi_st reg offset=0 docfi=0 + cfi_rel_offset \reg, \offset, \docfi + LONG_S \reg, sp, \offset + .endm + + .macro cfi_restore reg offset=0 docfi=0 + .if \docfi + .cfi_restore \reg + .endif + .endm + + .macro cfi_ld reg offset=0 docfi=0 + LONG_L \reg, sp, \offset + cfi_restore \reg \offset \docfi + .endm + + .macro BACKUP_T0T1 + csrwr t0, EXCEPTION_KS0 + csrwr t1, EXCEPTION_KS1 + .endm + + .macro RELOAD_T0T1 + csrrd t0, EXCEPTION_KS0 + csrrd t1, EXCEPTION_KS1 + .endm + + .macro SAVE_TEMP docfi=0 + RELOAD_T0T1 + cfi_st t0, PT_R12, \docfi + cfi_st t1, PT_R13, \docfi + cfi_st t2, PT_R14, \docfi + cfi_st t3, PT_R15, \docfi + cfi_st t4, PT_R16, \docfi + cfi_st t5, PT_R17, \docfi + cfi_st t6, PT_R18, \docfi + cfi_st t7, PT_R19, \docfi + cfi_st t8, PT_R20, \docfi + .endm + + .macro SAVE_STATIC docfi=0 + cfi_st s0, PT_R23, \docfi + cfi_st s1, PT_R24, \docfi + cfi_st s2, PT_R25, \docfi + cfi_st s3, PT_R26, \docfi + cfi_st s4, PT_R27, \docfi + cfi_st s5, PT_R28, \docfi + cfi_st s6, PT_R29, \docfi + cfi_st s7, PT_R30, \docfi + cfi_st s8, PT_R31, \docfi + .endm + +/* + * get_saved_sp returns the SP for the current CPU by looking in the + * kernelsp array for it. It stores the current sp in t0 and loads the + * new value in sp. + */ + .macro get_saved_sp docfi=0 + la.abs t1, kernelsp +#ifdef CONFIG_SMP + csrrd t0, PERCPU_BASE_KS + LONG_ADD t1, t1, t0 +#endif + move t0, sp + .if \docfi + .cfi_register sp, t0 + .endif + LONG_L sp, t1, 0 + .endm + + .macro set_saved_sp stackp temp temp2 + la.abs \temp, kernelsp +#ifdef CONFIG_SMP + LONG_ADD \temp, \temp, u0 +#endif + LONG_S \stackp, \temp, 0 + .endm + + .macro SAVE_SOME docfi=0 + csrrd t1, LOONGARCH_CSR_PRMD + andi t1, t1, 0x3 /* extract pplv bit */ + move t0, sp + beqz t1, 8f + /* Called from user mode, new stack. */ + get_saved_sp docfi=\docfi +8: + PTR_ADDI sp, sp, -PT_SIZE + .if \docfi + .cfi_def_cfa sp, 0 + .endif + cfi_st t0, PT_R3, \docfi + cfi_rel_offset sp, PT_R3, \docfi + LONG_S zero, sp, PT_R0 + csrrd t0, LOONGARCH_CSR_PRMD + LONG_S t0, sp, PT_PRMD + csrrd t0, LOONGARCH_CSR_CRMD + LONG_S t0, sp, PT_CRMD + csrrd t0, LOONGARCH_CSR_EUEN + LONG_S t0, sp, PT_EUEN + csrrd t0, LOONGARCH_CSR_ECFG + LONG_S t0, sp, PT_ECFG + csrrd t0, LOONGARCH_CSR_ESTAT + PTR_S t0, sp, PT_ESTAT + cfi_st ra, PT_R1, \docfi + cfi_st a0, PT_R4, \docfi + cfi_st a1, PT_R5, \docfi + cfi_st a2, PT_R6, \docfi + cfi_st a3, PT_R7, \docfi + cfi_st a4, PT_R8, \docfi + cfi_st a5, PT_R9, \docfi + cfi_st a6, PT_R10, \docfi + cfi_st a7, PT_R11, \docfi + csrrd ra, LOONGARCH_CSR_ERA + LONG_S ra, sp, PT_ERA + .if \docfi + .cfi_rel_offset ra, PT_ERA + .endif + cfi_st tp, PT_R2, \docfi + cfi_st fp, PT_R22, \docfi + + /* Set thread_info if we're coming from user mode */ + csrrd t0, LOONGARCH_CSR_PRMD + andi t0, t0, 0x3 /* extract pplv bit */ + beqz t0, 9f + + li.d tp, ~_THREAD_MASK + and tp, tp, sp + cfi_st u0, PT_R21, \docfi + csrrd u0, PERCPU_BASE_KS +9: + .endm + + .macro SAVE_ALL docfi=0 + SAVE_SOME \docfi + SAVE_TEMP \docfi + SAVE_STATIC \docfi + .endm + + .macro RESTORE_TEMP docfi=0 + cfi_ld t0, PT_R12, \docfi + cfi_ld t1, PT_R13, \docfi + cfi_ld t2, PT_R14, \docfi + cfi_ld t3, PT_R15, \docfi + cfi_ld t4, PT_R16, \docfi + cfi_ld t5, PT_R17, \docfi + cfi_ld t6, PT_R18, \docfi + cfi_ld t7, PT_R19, \docfi + cfi_ld t8, PT_R20, \docfi + .endm + + .macro RESTORE_STATIC docfi=0 + cfi_ld s0, PT_R23, \docfi + cfi_ld s1, PT_R24, \docfi + cfi_ld s2, PT_R25, \docfi + cfi_ld s3, PT_R26, \docfi + cfi_ld s4, PT_R27, \docfi + cfi_ld s5, PT_R28, \docfi + cfi_ld s6, PT_R29, \docfi + cfi_ld s7, PT_R30, \docfi + cfi_ld s8, PT_R31, \docfi + .endm + + .macro RESTORE_SOME docfi=0 + LONG_L a0, sp, PT_PRMD + andi a0, a0, 0x3 /* extract pplv bit */ + beqz a0, 8f + cfi_ld u0, PT_R21, \docfi +8: + LONG_L a0, sp, PT_ERA + csrwr a0, LOONGARCH_CSR_ERA + LONG_L a0, sp, PT_PRMD + csrwr a0, LOONGARCH_CSR_PRMD + cfi_ld ra, PT_R1, \docfi + cfi_ld a0, PT_R4, \docfi + cfi_ld a1, PT_R5, \docfi + cfi_ld a2, PT_R6, \docfi + cfi_ld a3, PT_R7, \docfi + cfi_ld a4, PT_R8, \docfi + cfi_ld a5, PT_R9, \docfi + cfi_ld a6, PT_R10, \docfi + cfi_ld a7, PT_R11, \docfi + cfi_ld tp, PT_R2, \docfi + cfi_ld fp, PT_R22, \docfi + .endm + + .macro RESTORE_SP_AND_RET docfi=0 + cfi_ld sp, PT_R3, \docfi + ertn + .endm + + .macro RESTORE_ALL_AND_RET docfi=0 + RESTORE_STATIC \docfi + RESTORE_TEMP \docfi + RESTORE_SOME \docfi + RESTORE_SP_AND_RET \docfi + .endm + +#endif /* _ASM_STACKFRAME_H */ diff --git a/arch/loongarch/include/asm/stacktrace.h b/arch/loongarch/include/asm/stacktrace.h new file mode 100644 index 000000000000..26483e396ad1 --- /dev/null +++ b/arch/loongarch/include/asm/stacktrace.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_STACKTRACE_H +#define _ASM_STACKTRACE_H + +#include <asm/asm.h> +#include <asm/ptrace.h> +#include <asm/loongarch.h> +#include <linux/stringify.h> + +#define STR_LONG_L __stringify(LONG_L) +#define STR_LONG_S __stringify(LONG_S) +#define STR_LONGSIZE __stringify(LONGSIZE) + +#define STORE_ONE_REG(r) \ + STR_LONG_S " $r" __stringify(r)", %1, "STR_LONGSIZE"*"__stringify(r)"\n\t" + +#define CSRRD_ONE_REG(reg) \ + __stringify(csrrd) " %0, "__stringify(reg)"\n\t" + +static __always_inline void prepare_frametrace(struct pt_regs *regs) +{ + __asm__ __volatile__( + /* Save $r1 */ + STORE_ONE_REG(1) + /* Use $r1 to save PC */ + "pcaddi $r1, 0\n\t" + STR_LONG_S " $r1, %0\n\t" + /* Restore $r1 */ + STR_LONG_L " $r1, %1, "STR_LONGSIZE"\n\t" + STORE_ONE_REG(2) + STORE_ONE_REG(3) + STORE_ONE_REG(4) + STORE_ONE_REG(5) + STORE_ONE_REG(6) + STORE_ONE_REG(7) + STORE_ONE_REG(8) + STORE_ONE_REG(9) + STORE_ONE_REG(10) + STORE_ONE_REG(11) + STORE_ONE_REG(12) + STORE_ONE_REG(13) + STORE_ONE_REG(14) + STORE_ONE_REG(15) + STORE_ONE_REG(16) + STORE_ONE_REG(17) + STORE_ONE_REG(18) + STORE_ONE_REG(19) + STORE_ONE_REG(20) + STORE_ONE_REG(21) + STORE_ONE_REG(22) + STORE_ONE_REG(23) + STORE_ONE_REG(24) + STORE_ONE_REG(25) + STORE_ONE_REG(26) + STORE_ONE_REG(27) + STORE_ONE_REG(28) + STORE_ONE_REG(29) + STORE_ONE_REG(30) + STORE_ONE_REG(31) + : "=m" (regs->csr_era) + : "r" (regs->regs) + : "memory"); + __asm__ __volatile__(CSRRD_ONE_REG(LOONGARCH_CSR_BADV) : "=r" (regs->csr_badvaddr)); + __asm__ __volatile__(CSRRD_ONE_REG(LOONGARCH_CSR_CRMD) : "=r" (regs->csr_crmd)); + __asm__ __volatile__(CSRRD_ONE_REG(LOONGARCH_CSR_PRMD) : "=r" (regs->csr_prmd)); + __asm__ __volatile__(CSRRD_ONE_REG(LOONGARCH_CSR_EUEN) : "=r" (regs->csr_euen)); + __asm__ __volatile__(CSRRD_ONE_REG(LOONGARCH_CSR_ECFG) : "=r" (regs->csr_ecfg)); + __asm__ __volatile__(CSRRD_ONE_REG(LOONGARCH_CSR_ESTAT) : "=r" (regs->csr_estat)); +} + +#endif /* _ASM_STACKTRACE_H */ diff --git a/arch/loongarch/include/asm/string.h b/arch/loongarch/include/asm/string.h new file mode 100644 index 000000000000..b07e60ded957 --- /dev/null +++ b/arch/loongarch/include/asm/string.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_STRING_H +#define _ASM_STRING_H + +extern void *memset(void *__s, int __c, size_t __count); +extern void *memcpy(void *__to, __const__ void *__from, size_t __n); +extern void *memmove(void *__dest, __const__ void *__src, size_t __n); + +#endif /* _ASM_STRING_H */ diff --git a/arch/loongarch/include/asm/switch_to.h b/arch/loongarch/include/asm/switch_to.h new file mode 100644 index 000000000000..2a8d04375574 --- /dev/null +++ b/arch/loongarch/include/asm/switch_to.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_SWITCH_TO_H +#define _ASM_SWITCH_TO_H + +#include <asm/cpu-features.h> +#include <asm/fpu.h> + +struct task_struct; + +/** + * __switch_to - switch execution of a task + * @prev: The task previously executed. + * @next: The task to begin executing. + * @next_ti: task_thread_info(next). + * + * This function is used whilst scheduling to save the context of prev & load + * the context of next. Returns prev. + */ +extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev, + struct task_struct *next, struct thread_info *next_ti); + +/* + * For newly created kernel threads switch_to() will return to + * ret_from_kernel_thread, newly created user threads to ret_from_fork. + * That is, everything following __switch_to() will be skipped for new threads. + * So everything that matters to new threads should be placed before __switch_to(). + */ +#define switch_to(prev, next, last) \ +do { \ + lose_fpu_inatomic(1, prev); \ + (last) = __switch_to(prev, next, task_thread_info(next)); \ +} while (0) + +#endif /* _ASM_SWITCH_TO_H */ diff --git a/arch/loongarch/include/asm/syscall.h b/arch/loongarch/include/asm/syscall.h new file mode 100644 index 000000000000..e286dc58476e --- /dev/null +++ b/arch/loongarch/include/asm/syscall.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_LOONGARCH_SYSCALL_H +#define __ASM_LOONGARCH_SYSCALL_H + +#include <linux/compiler.h> +#include <uapi/linux/audit.h> +#include <linux/elf-em.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/uaccess.h> +#include <asm/ptrace.h> +#include <asm/unistd.h> + +extern void *sys_call_table[]; + +static inline long syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->regs[11]; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + regs->regs[4] = regs->orig_a0; +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + unsigned long error = regs->regs[4]; + + return IS_ERR_VALUE(error) ? error : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->regs[4]; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + regs->regs[4] = (long) error ? error : val; +} + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned long *args) +{ + args[0] = regs->orig_a0; + memcpy(&args[1], ®s->regs[5], 5 * sizeof(long)); +} + +static inline int syscall_get_arch(struct task_struct *task) +{ + return AUDIT_ARCH_LOONGARCH64; +} + +static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs) +{ + return false; +} + +#endif /* __ASM_LOONGARCH_SYSCALL_H */ diff --git a/arch/loongarch/include/asm/thread_info.h b/arch/loongarch/include/asm/thread_info.h new file mode 100644 index 000000000000..99beb11c2fa8 --- /dev/null +++ b/arch/loongarch/include/asm/thread_info.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * thread_info.h: LoongArch low-level thread information + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef _ASM_THREAD_INFO_H +#define _ASM_THREAD_INFO_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +#include <asm/processor.h> + +/* + * low level task data that entry.S needs immediate access to + * - this struct should fit entirely inside of one cache line + * - this struct shares the supervisor stack pages + * - if the contents of this structure are changed, the assembly constants + * must also be changed + */ +struct thread_info { + struct task_struct *task; /* main task structure */ + unsigned long flags; /* low level flags */ + unsigned long tp_value; /* thread pointer */ + __u32 cpu; /* current CPU */ + int preempt_count; /* 0 => preemptible, <0 => BUG */ + struct pt_regs *regs; + unsigned long syscall; /* syscall number */ + unsigned long syscall_work; /* SYSCALL_WORK_ flags */ +}; + +/* + * macros/functions for gaining access to the thread information structure + */ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = INIT_PREEMPT_COUNT, \ +} + +/* How to get the thread information struct from C. */ +register struct thread_info *__current_thread_info __asm__("$r2"); + +static inline struct thread_info *current_thread_info(void) +{ + return __current_thread_info; +} + +register unsigned long current_stack_pointer __asm__("$r3"); + +#endif /* !__ASSEMBLY__ */ + +/* thread information allocation */ +#define THREAD_SIZE SZ_16K +#define THREAD_MASK (THREAD_SIZE - 1UL) +#define THREAD_SIZE_ORDER ilog2(THREAD_SIZE / PAGE_SIZE) +/* + * thread information flags + * - these are process state flags that various assembly files may need to + * access + * - pending work-to-be-done flags are in LSW + * - other flags in MSW + */ +#define TIF_SIGPENDING 1 /* signal pending */ +#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ +#define TIF_NOTIFY_RESUME 3 /* callback before returning to user */ +#define TIF_NOTIFY_SIGNAL 4 /* signal notifications exist */ +#define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */ +#define TIF_NOHZ 6 /* in adaptive nohz mode */ +#define TIF_UPROBE 7 /* breakpointed or singlestepping */ +#define TIF_USEDFPU 8 /* FPU was used by this task this quantum (SMP) */ +#define TIF_USEDSIMD 9 /* SIMD has been used this quantum */ +#define TIF_MEMDIE 10 /* is terminating due to OOM killer */ +#define TIF_FIXADE 11 /* Fix address errors in software */ +#define TIF_LOGADE 12 /* Log address errors to syslog */ +#define TIF_32BIT_REGS 13 /* 32-bit general purpose registers */ +#define TIF_32BIT_ADDR 14 /* 32-bit address space */ +#define TIF_LOAD_WATCH 15 /* If set, load watch registers */ +#define TIF_SINGLESTEP 16 /* Single Step */ +#define TIF_LSX_CTX_LIVE 17 /* LSX context must be preserved */ +#define TIF_LASX_CTX_LIVE 18 /* LASX context must be preserved */ + +#define _TIF_SIGPENDING (1<<TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) +#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) +#define _TIF_NOTIFY_SIGNAL (1<<TIF_NOTIFY_SIGNAL) +#define _TIF_NOHZ (1<<TIF_NOHZ) +#define _TIF_UPROBE (1<<TIF_UPROBE) +#define _TIF_USEDFPU (1<<TIF_USEDFPU) +#define _TIF_USEDSIMD (1<<TIF_USEDSIMD) +#define _TIF_FIXADE (1<<TIF_FIXADE) +#define _TIF_LOGADE (1<<TIF_LOGADE) +#define _TIF_32BIT_REGS (1<<TIF_32BIT_REGS) +#define _TIF_32BIT_ADDR (1<<TIF_32BIT_ADDR) +#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH) +#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) +#define _TIF_LSX_CTX_LIVE (1<<TIF_LSX_CTX_LIVE) +#define _TIF_LASX_CTX_LIVE (1<<TIF_LASX_CTX_LIVE) + +#endif /* __KERNEL__ */ +#endif /* _ASM_THREAD_INFO_H */ diff --git a/arch/loongarch/include/asm/time.h b/arch/loongarch/include/asm/time.h new file mode 100644 index 000000000000..2eae219301d0 --- /dev/null +++ b/arch/loongarch/include/asm/time.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_TIME_H +#define _ASM_TIME_H + +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <asm/loongarch.h> + +extern u64 cpu_clock_freq; +extern u64 const_clock_freq; + +extern void sync_counter(void); + +static inline unsigned int calc_const_freq(void) +{ + unsigned int res; + unsigned int base_freq; + unsigned int cfm, cfd; + + res = read_cpucfg(LOONGARCH_CPUCFG2); + if (!(res & CPUCFG2_LLFTP)) + return 0; + + base_freq = read_cpucfg(LOONGARCH_CPUCFG4); + res = read_cpucfg(LOONGARCH_CPUCFG5); + cfm = res & 0xffff; + cfd = (res >> 16) & 0xffff; + + if (!base_freq || !cfm || !cfd) + return 0; + + return (base_freq * cfm / cfd); +} + +/* + * Initialize the calling CPU's timer interrupt as clockevent device + */ +extern int constant_clockevent_init(void); +extern int constant_clocksource_init(void); + +static inline void clockevent_set_clock(struct clock_event_device *cd, + unsigned int clock) +{ + clockevents_calc_mult_shift(cd, clock, 4); +} + +#endif /* _ASM_TIME_H */ diff --git a/arch/loongarch/include/asm/timex.h b/arch/loongarch/include/asm/timex.h new file mode 100644 index 000000000000..d3ed99a4fdbd --- /dev/null +++ b/arch/loongarch/include/asm/timex.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_TIMEX_H +#define _ASM_TIMEX_H + +#ifdef __KERNEL__ + +#include <linux/compiler.h> + +#include <asm/cpu.h> +#include <asm/cpu-features.h> + +/* + * Standard way to access the cycle counter. + * Currently only used on SMP for scheduling. + * + * We know that all SMP capable CPUs have cycle counters. + */ + +typedef unsigned long cycles_t; + +#define get_cycles get_cycles + +static inline cycles_t get_cycles(void) +{ + return drdtime(); +} + +#endif /* __KERNEL__ */ + +#endif /* _ASM_TIMEX_H */ diff --git a/arch/loongarch/include/asm/tlb.h b/arch/loongarch/include/asm/tlb.h new file mode 100644 index 000000000000..4f629ae9d5a9 --- /dev/null +++ b/arch/loongarch/include/asm/tlb.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_TLB_H +#define __ASM_TLB_H + +#include <linux/mm_types.h> +#include <asm/cpu-features.h> +#include <asm/loongarch.h> + +/* + * TLB Invalidate Flush + */ +static inline void tlbclr(void) +{ + __asm__ __volatile__("tlbclr"); +} + +static inline void tlbflush(void) +{ + __asm__ __volatile__("tlbflush"); +} + +/* + * TLB R/W operations. + */ +static inline void tlb_probe(void) +{ + __asm__ __volatile__("tlbsrch"); +} + +static inline void tlb_read(void) +{ + __asm__ __volatile__("tlbrd"); +} + +static inline void tlb_write_indexed(void) +{ + __asm__ __volatile__("tlbwr"); +} + +static inline void tlb_write_random(void) +{ + __asm__ __volatile__("tlbfill"); +} + +enum invtlb_ops { + /* Invalid all tlb */ + INVTLB_ALL = 0x0, + /* Invalid current tlb */ + INVTLB_CURRENT_ALL = 0x1, + /* Invalid all global=1 lines in current tlb */ + INVTLB_CURRENT_GTRUE = 0x2, + /* Invalid all global=0 lines in current tlb */ + INVTLB_CURRENT_GFALSE = 0x3, + /* Invalid global=0 and matched asid lines in current tlb */ + INVTLB_GFALSE_AND_ASID = 0x4, + /* Invalid addr with global=0 and matched asid in current tlb */ + INVTLB_ADDR_GFALSE_AND_ASID = 0x5, + /* Invalid addr with global=1 or matched asid in current tlb */ + INVTLB_ADDR_GTRUE_OR_ASID = 0x6, + /* Invalid matched gid in guest tlb */ + INVGTLB_GID = 0x9, + /* Invalid global=1, matched gid in guest tlb */ + INVGTLB_GID_GTRUE = 0xa, + /* Invalid global=0, matched gid in guest tlb */ + INVGTLB_GID_GFALSE = 0xb, + /* Invalid global=0, matched gid and asid in guest tlb */ + INVGTLB_GID_GFALSE_ASID = 0xc, + /* Invalid global=0 , matched gid, asid and addr in guest tlb */ + INVGTLB_GID_GFALSE_ASID_ADDR = 0xd, + /* Invalid global=1 , matched gid, asid and addr in guest tlb */ + INVGTLB_GID_GTRUE_ASID_ADDR = 0xe, + /* Invalid all gid gva-->gpa guest tlb */ + INVGTLB_ALLGID_GVA_TO_GPA = 0x10, + /* Invalid all gid gpa-->hpa tlb */ + INVTLB_ALLGID_GPA_TO_HPA = 0x11, + /* Invalid all gid tlb, including gva-->gpa and gpa-->hpa */ + INVTLB_ALLGID = 0x12, + /* Invalid matched gid gva-->gpa guest tlb */ + INVGTLB_GID_GVA_TO_GPA = 0x13, + /* Invalid matched gid gpa-->hpa tlb */ + INVTLB_GID_GPA_TO_HPA = 0x14, + /* Invalid matched gid tlb,including gva-->gpa and gpa-->hpa */ + INVTLB_GID_ALL = 0x15, + /* Invalid matched gid and addr gpa-->hpa tlb */ + INVTLB_GID_ADDR = 0x16, +}; + +/* + * invtlb op info addr + * (0x1 << 26) | (0x24 << 20) | (0x13 << 15) | + * (addr << 10) | (info << 5) | op + */ +static inline void invtlb(u32 op, u32 info, u64 addr) +{ + __asm__ __volatile__( + "parse_r addr,%0\n\t" + "parse_r info,%1\n\t" + ".word ((0x6498000) | (addr << 10) | (info << 5) | %2)\n\t" + : + : "r"(addr), "r"(info), "i"(op) + : + ); +} + +static inline void invtlb_addr(u32 op, u32 info, u64 addr) +{ + __asm__ __volatile__( + "parse_r addr,%0\n\t" + ".word ((0x6498000) | (addr << 10) | (0 << 5) | %1)\n\t" + : + : "r"(addr), "i"(op) + : + ); +} + +static inline void invtlb_info(u32 op, u32 info, u64 addr) +{ + __asm__ __volatile__( + "parse_r info,%0\n\t" + ".word ((0x6498000) | (0 << 10) | (info << 5) | %1)\n\t" + : + : "r"(info), "i"(op) + : + ); +} + +static inline void invtlb_all(u32 op, u32 info, u64 addr) +{ + __asm__ __volatile__( + ".word ((0x6498000) | (0 << 10) | (0 << 5) | %0)\n\t" + : + : "i"(op) + : + ); +} + +/* + * LoongArch doesn't need any special per-pte or per-vma handling, except + * we need to flush cache for area to be unmapped. + */ +#define tlb_start_vma(tlb, vma) \ + do { \ + if (!(tlb)->fullmm) \ + flush_cache_range(vma, vma->vm_start, vma->vm_end); \ + } while (0) +#define tlb_end_vma(tlb, vma) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) + +static void tlb_flush(struct mmu_gather *tlb); + +#define tlb_flush tlb_flush +#include <asm-generic/tlb.h> + +static inline void tlb_flush(struct mmu_gather *tlb) +{ + struct vm_area_struct vma; + + vma.vm_mm = tlb->mm; + vma.vm_flags = 0; + if (tlb->fullmm) { + flush_tlb_mm(tlb->mm); + return; + } + + flush_tlb_range(&vma, tlb->start, tlb->end); +} + +extern void handle_tlb_load(void); +extern void handle_tlb_store(void); +extern void handle_tlb_modify(void); +extern void handle_tlb_refill(void); +extern void handle_tlb_protect(void); + +extern void dump_tlb_all(void); +extern void dump_tlb_regs(void); + +#endif /* __ASM_TLB_H */ diff --git a/arch/loongarch/include/asm/tlbflush.h b/arch/loongarch/include/asm/tlbflush.h new file mode 100644 index 000000000000..a0785e590681 --- /dev/null +++ b/arch/loongarch/include/asm/tlbflush.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_TLBFLUSH_H +#define __ASM_TLBFLUSH_H + +#include <linux/mm.h> + +/* + * TLB flushing: + * + * - flush_tlb_all() flushes all processes TLB entries + * - flush_tlb_mm(mm) flushes the specified mm context TLB entries + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(vma, start, end) flushes a range of pages + * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages + */ +extern void local_flush_tlb_all(void); +extern void local_flush_tlb_user(void); +extern void local_flush_tlb_kernel(void); +extern void local_flush_tlb_mm(struct mm_struct *mm); +extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); +extern void local_flush_tlb_kernel_range(unsigned long start, unsigned long end); +extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); +extern void local_flush_tlb_one(unsigned long vaddr); + +#ifdef CONFIG_SMP + +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *); +extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long, unsigned long); +extern void flush_tlb_kernel_range(unsigned long, unsigned long); +extern void flush_tlb_page(struct vm_area_struct *, unsigned long); +extern void flush_tlb_one(unsigned long vaddr); + +#else /* CONFIG_SMP */ + +#define flush_tlb_all() local_flush_tlb_all() +#define flush_tlb_mm(mm) local_flush_tlb_mm(mm) +#define flush_tlb_range(vma, vmaddr, end) local_flush_tlb_range(vma, vmaddr, end) +#define flush_tlb_kernel_range(vmaddr, end) local_flush_tlb_kernel_range(vmaddr, end) +#define flush_tlb_page(vma, page) local_flush_tlb_page(vma, page) +#define flush_tlb_one(vaddr) local_flush_tlb_one(vaddr) + +#endif /* CONFIG_SMP */ + +#endif /* __ASM_TLBFLUSH_H */ diff --git a/arch/loongarch/include/asm/topology.h b/arch/loongarch/include/asm/topology.h new file mode 100644 index 000000000000..66128dec0bf6 --- /dev/null +++ b/arch/loongarch/include/asm/topology.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_TOPOLOGY_H +#define __ASM_TOPOLOGY_H + +#include <linux/smp.h> + +#ifdef CONFIG_NUMA + +extern cpumask_t cpus_on_node[]; + +#define cpumask_of_node(node) (&cpus_on_node[node]) + +struct pci_bus; +extern int pcibus_to_node(struct pci_bus *); + +#define cpumask_of_pcibus(bus) (cpu_online_mask) + +extern unsigned char node_distances[MAX_NUMNODES][MAX_NUMNODES]; + +void numa_set_distance(int from, int to, int distance); + +#define node_distance(from, to) (node_distances[(from)][(to)]) + +#else +#define pcibus_to_node(bus) 0 +#endif + +#ifdef CONFIG_SMP +#define topology_physical_package_id(cpu) (cpu_data[cpu].package) +#define topology_core_id(cpu) (cpu_data[cpu].core) +#define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) +#define topology_sibling_cpumask(cpu) (&cpu_sibling_map[cpu]) +#endif + +#include <asm-generic/topology.h> + +static inline void arch_fix_phys_package_id(int num, u32 slot) { } +#endif /* __ASM_TOPOLOGY_H */ diff --git a/arch/loongarch/include/asm/types.h b/arch/loongarch/include/asm/types.h new file mode 100644 index 000000000000..baf15a0dcf8b --- /dev/null +++ b/arch/loongarch/include/asm/types.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_TYPES_H +#define _ASM_TYPES_H + +#include <asm-generic/int-ll64.h> +#include <uapi/asm/types.h> + +#ifdef __ASSEMBLY__ +#define _ULCAST_ +#define _U64CAST_ +#else +#define _ULCAST_ (unsigned long) +#define _U64CAST_ (u64) +#endif + +#endif /* _ASM_TYPES_H */ diff --git a/arch/loongarch/include/asm/uaccess.h b/arch/loongarch/include/asm/uaccess.h new file mode 100644 index 000000000000..217c6a3727b1 --- /dev/null +++ b/arch/loongarch/include/asm/uaccess.h @@ -0,0 +1,269 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1996, 1997, 1998, 1999, 2000, 03, 04 by Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2007 Maciej W. Rozycki + * Copyright (C) 2014, Imagination Technologies Ltd. + */ +#ifndef _ASM_UACCESS_H +#define _ASM_UACCESS_H + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/extable.h> +#include <asm/pgtable.h> +#include <asm-generic/extable.h> +#include <asm-generic/access_ok.h> + +extern u64 __ua_limit; + +#define __UA_ADDR ".dword" +#define __UA_LA "la.abs" +#define __UA_LIMIT __ua_limit + +/* + * get_user: - Get a simple variable from user space. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep if pagefaults are + * enabled. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ +#define get_user(x, ptr) \ +({ \ + const __typeof__(*(ptr)) __user *__p = (ptr); \ + \ + might_fault(); \ + access_ok(__p, sizeof(*__p)) ? __get_user((x), __p) : \ + ((x) = 0, -EFAULT); \ +}) + +/* + * put_user: - Write a simple value into user space. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep if pagefaults are + * enabled. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Returns zero on success, or -EFAULT on error. + */ +#define put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) __user *__p = (ptr); \ + \ + might_fault(); \ + access_ok(__p, sizeof(*__p)) ? __put_user((x), __p) : -EFAULT; \ +}) + +/* + * __get_user: - Get a simple variable from user space, with less checking. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep if pagefaults are + * enabled. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Caller must check the pointer with access_ok() before calling this + * function. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ +#define __get_user(x, ptr) \ +({ \ + int __gu_err = 0; \ + \ + __chk_user_ptr(ptr); \ + __get_user_common((x), sizeof(*(ptr)), ptr); \ + __gu_err; \ +}) + +/* + * __put_user: - Write a simple value into user space, with less checking. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep if pagefaults are + * enabled. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Caller must check the pointer with access_ok() before calling this + * function. + * + * Returns zero on success, or -EFAULT on error. + */ +#define __put_user(x, ptr) \ +({ \ + int __pu_err = 0; \ + __typeof__(*(ptr)) __pu_val; \ + \ + __pu_val = (x); \ + __chk_user_ptr(ptr); \ + __put_user_common(ptr, sizeof(*(ptr))); \ + __pu_err; \ +}) + +struct __large_struct { unsigned long buf[100]; }; +#define __m(x) (*(struct __large_struct __user *)(x)) + +#define __get_user_common(val, size, ptr) \ +do { \ + switch (size) { \ + case 1: __get_data_asm(val, "ld.b", ptr); break; \ + case 2: __get_data_asm(val, "ld.h", ptr); break; \ + case 4: __get_data_asm(val, "ld.w", ptr); break; \ + case 8: __get_data_asm(val, "ld.d", ptr); break; \ + default: BUILD_BUG(); break; \ + } \ +} while (0) + +#define __get_kernel_common(val, size, ptr) __get_user_common(val, size, ptr) + +#define __get_data_asm(val, insn, ptr) \ +{ \ + long __gu_tmp; \ + \ + __asm__ __volatile__( \ + "1: " insn " %1, %2 \n" \ + "2: \n" \ + " .section .fixup,\"ax\" \n" \ + "3: li.w %0, %3 \n" \ + " or %1, $r0, $r0 \n" \ + " b 2b \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " "__UA_ADDR "\t1b, 3b \n" \ + " .previous \n" \ + : "+r" (__gu_err), "=r" (__gu_tmp) \ + : "m" (__m(ptr)), "i" (-EFAULT)); \ + \ + (val) = (__typeof__(*(ptr))) __gu_tmp; \ +} + +#define __put_user_common(ptr, size) \ +do { \ + switch (size) { \ + case 1: __put_data_asm("st.b", ptr); break; \ + case 2: __put_data_asm("st.h", ptr); break; \ + case 4: __put_data_asm("st.w", ptr); break; \ + case 8: __put_data_asm("st.d", ptr); break; \ + default: BUILD_BUG(); break; \ + } \ +} while (0) + +#define __put_kernel_common(ptr, size) __put_user_common(ptr, size) + +#define __put_data_asm(insn, ptr) \ +{ \ + __asm__ __volatile__( \ + "1: " insn " %z2, %1 # __put_user_asm\n" \ + "2: \n" \ + " .section .fixup,\"ax\" \n" \ + "3: li.w %0, %3 \n" \ + " b 2b \n" \ + " .previous \n" \ + " .section __ex_table,\"a\" \n" \ + " " __UA_ADDR " 1b, 3b \n" \ + " .previous \n" \ + : "+r" (__pu_err), "=m" (__m(ptr)) \ + : "Jr" (__pu_val), "i" (-EFAULT)); \ +} + +#define __get_kernel_nofault(dst, src, type, err_label) \ +do { \ + int __gu_err = 0; \ + \ + __get_kernel_common(*((type *)(dst)), sizeof(type), \ + (__force type *)(src)); \ + if (unlikely(__gu_err)) \ + goto err_label; \ +} while (0) + +#define __put_kernel_nofault(dst, src, type, err_label) \ +do { \ + type __pu_val; \ + int __pu_err = 0; \ + \ + __pu_val = *(__force type *)(src); \ + __put_kernel_common(((type *)(dst)), sizeof(type)); \ + if (unlikely(__pu_err)) \ + goto err_label; \ +} while (0) + +extern unsigned long __copy_user(void *to, const void *from, __kernel_size_t n); + +static inline unsigned long __must_check +raw_copy_from_user(void *to, const void __user *from, unsigned long n) +{ + return __copy_user(to, from, n); +} + +static inline unsigned long __must_check +raw_copy_to_user(void __user *to, const void *from, unsigned long n) +{ + return __copy_user(to, from, n); +} + +#define INLINE_COPY_FROM_USER +#define INLINE_COPY_TO_USER + +/* + * __clear_user: - Zero a block of memory in user space, with less checking. + * @addr: Destination address, in user space. + * @size: Number of bytes to zero. + * + * Zero a block of memory in user space. Caller must check + * the specified block with access_ok() before calling this function. + * + * Returns number of bytes that could not be cleared. + * On success, this will be zero. + */ +extern unsigned long __clear_user(void __user *addr, __kernel_size_t size); + +#define clear_user(addr, n) \ +({ \ + void __user *__cl_addr = (addr); \ + unsigned long __cl_size = (n); \ + if (__cl_size && access_ok(__cl_addr, __cl_size)) \ + __cl_size = __clear_user(__cl_addr, __cl_size); \ + __cl_size; \ +}) + +extern long strncpy_from_user(char *to, const char __user *from, long n); +extern long strnlen_user(const char __user *str, long n); + +#endif /* _ASM_UACCESS_H */ diff --git a/arch/loongarch/include/asm/unistd.h b/arch/loongarch/include/asm/unistd.h new file mode 100644 index 000000000000..cfddb0116a8c --- /dev/null +++ b/arch/loongarch/include/asm/unistd.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <uapi/asm/unistd.h> + +#define NR_syscalls (__NR_syscalls) diff --git a/arch/loongarch/include/asm/vdso.h b/arch/loongarch/include/asm/vdso.h new file mode 100644 index 000000000000..8f8a0f9a4953 --- /dev/null +++ b/arch/loongarch/include/asm/vdso.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_VDSO_H +#define __ASM_VDSO_H + +#include <linux/mm_types.h> +#include <vdso/datapage.h> + +#include <asm/barrier.h> + +/* + * struct loongarch_vdso_info - Details of a VDSO image. + * @vdso: Pointer to VDSO image (page-aligned). + * @size: Size of the VDSO image (page-aligned). + * @off_rt_sigreturn: Offset of the rt_sigreturn() trampoline. + * @code_mapping: Special mapping structure for vdso code. + * @code_mapping: Special mapping structure for vdso data. + * + * This structure contains details of a VDSO image, including the image data + * and offsets of certain symbols required by the kernel. It is generated as + * part of the VDSO build process, aside from the mapping page array, which is + * populated at runtime. + */ +struct loongarch_vdso_info { + void *vdso; + unsigned long size; + unsigned long offset_sigreturn; + struct vm_special_mapping code_mapping; + struct vm_special_mapping data_mapping; +}; + +extern struct loongarch_vdso_info vdso_info; + +#endif /* __ASM_VDSO_H */ diff --git a/arch/loongarch/include/asm/vdso/clocksource.h b/arch/loongarch/include/asm/vdso/clocksource.h new file mode 100644 index 000000000000..13cd580d406d --- /dev/null +++ b/arch/loongarch/include/asm/vdso/clocksource.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __ASM_VDSOCLOCKSOURCE_H +#define __ASM_VDSOCLOCKSOURCE_H + +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_CPU + +#endif /* __ASM_VDSOCLOCKSOURCE_H */ diff --git a/arch/loongarch/include/asm/vdso/gettimeofday.h b/arch/loongarch/include/asm/vdso/gettimeofday.h new file mode 100644 index 000000000000..7b2cd37641e2 --- /dev/null +++ b/arch/loongarch/include/asm/vdso/gettimeofday.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_VDSO_GETTIMEOFDAY_H +#define __ASM_VDSO_GETTIMEOFDAY_H + +#ifndef __ASSEMBLY__ + +#include <asm/unistd.h> +#include <asm/vdso/vdso.h> + +#define VDSO_HAS_CLOCK_GETRES 1 + +static __always_inline long gettimeofday_fallback( + struct __kernel_old_timeval *_tv, + struct timezone *_tz) +{ + register struct __kernel_old_timeval *tv asm("a0") = _tv; + register struct timezone *tz asm("a1") = _tz; + register long nr asm("a7") = __NR_gettimeofday; + register long ret asm("a0"); + + asm volatile( + " syscall 0\n" + : "+r" (ret) + : "r" (nr), "r" (tv), "r" (tz) + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$t8", "memory"); + + return ret; +} + +static __always_inline long clock_gettime_fallback( + clockid_t _clkid, + struct __kernel_timespec *_ts) +{ + register clockid_t clkid asm("a0") = _clkid; + register struct __kernel_timespec *ts asm("a1") = _ts; + register long nr asm("a7") = __NR_clock_gettime; + register long ret asm("a0"); + + asm volatile( + " syscall 0\n" + : "+r" (ret) + : "r" (nr), "r" (clkid), "r" (ts) + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$t8", "memory"); + + return ret; +} + +static __always_inline int clock_getres_fallback( + clockid_t _clkid, + struct __kernel_timespec *_ts) +{ + register clockid_t clkid asm("a0") = _clkid; + register struct __kernel_timespec *ts asm("a1") = _ts; + register long nr asm("a7") = __NR_clock_getres; + register long ret asm("a0"); + + asm volatile( + " syscall 0\n" + : "+r" (ret) + : "r" (nr), "r" (clkid), "r" (ts) + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$t8", "memory"); + + return ret; +} + +static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, + const struct vdso_data *vd) +{ + uint64_t count; + + __asm__ __volatile__( + " rdtime.d %0, $zero\n" + : "=r" (count)); + + return count; +} + +static inline bool loongarch_vdso_hres_capable(void) +{ + return true; +} +#define __arch_vdso_hres_capable loongarch_vdso_hres_capable + +static __always_inline const struct vdso_data *__arch_get_vdso_data(void) +{ + return get_vdso_data(); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/loongarch/include/asm/vdso/processor.h b/arch/loongarch/include/asm/vdso/processor.h new file mode 100644 index 000000000000..ef5770b343a0 --- /dev/null +++ b/arch/loongarch/include/asm/vdso/processor.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __ASM_VDSO_PROCESSOR_H +#define __ASM_VDSO_PROCESSOR_H + +#ifndef __ASSEMBLY__ + +#define cpu_relax() barrier() + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_VDSO_PROCESSOR_H */ diff --git a/arch/loongarch/include/asm/vdso/vdso.h b/arch/loongarch/include/asm/vdso/vdso.h new file mode 100644 index 000000000000..5a01643a65b3 --- /dev/null +++ b/arch/loongarch/include/asm/vdso/vdso.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __ASSEMBLY__ + +#include <asm/asm.h> +#include <asm/page.h> + +static inline unsigned long get_vdso_base(void) +{ + unsigned long addr; + + __asm__( + " la.pcrel %0, _start\n" + : "=r" (addr) + : + :); + + return addr; +} + +static inline const struct vdso_data *get_vdso_data(void) +{ + return (const struct vdso_data *)(get_vdso_base() - PAGE_SIZE); +} + +#endif /* __ASSEMBLY__ */ diff --git a/arch/loongarch/include/asm/vdso/vsyscall.h b/arch/loongarch/include/asm/vdso/vsyscall.h new file mode 100644 index 000000000000..5de615383a22 --- /dev/null +++ b/arch/loongarch/include/asm/vdso/vsyscall.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSO_VSYSCALL_H +#define __ASM_VDSO_VSYSCALL_H + +#ifndef __ASSEMBLY__ + +#include <linux/timekeeper_internal.h> +#include <vdso/datapage.h> + +extern struct vdso_data *vdso_data; + +/* + * Update the vDSO data page to keep in sync with kernel timekeeping. + */ +static __always_inline +struct vdso_data *__loongarch_get_k_vdso_data(void) +{ + return vdso_data; +} +#define __arch_get_k_vdso_data __loongarch_get_k_vdso_data + +/* The asm-generic header needs to be included after the definitions above */ +#include <asm-generic/vdso/vsyscall.h> + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_VDSO_VSYSCALL_H */ diff --git a/arch/loongarch/include/asm/vermagic.h b/arch/loongarch/include/asm/vermagic.h new file mode 100644 index 000000000000..8b47ccfe3aad --- /dev/null +++ b/arch/loongarch/include/asm/vermagic.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_VERMAGIC_H +#define _ASM_VERMAGIC_H + +#define MODULE_PROC_FAMILY "LOONGARCH " + +#ifdef CONFIG_32BIT +#define MODULE_KERNEL_TYPE "32BIT " +#elif defined CONFIG_64BIT +#define MODULE_KERNEL_TYPE "64BIT " +#endif + +#define MODULE_ARCH_VERMAGIC \ + MODULE_PROC_FAMILY MODULE_KERNEL_TYPE + +#endif /* _ASM_VERMAGIC_H */ diff --git a/arch/loongarch/include/asm/vmalloc.h b/arch/loongarch/include/asm/vmalloc.h new file mode 100644 index 000000000000..965a0d41ac2d --- /dev/null +++ b/arch/loongarch/include/asm/vmalloc.h @@ -0,0 +1,4 @@ +#ifndef _ASM_LOONGARCH_VMALLOC_H +#define _ASM_LOONGARCH_VMALLOC_H + +#endif /* _ASM_LOONGARCH_VMALLOC_H */ diff --git a/arch/loongarch/include/uapi/asm/Kbuild b/arch/loongarch/include/uapi/asm/Kbuild new file mode 100644 index 000000000000..4aa680ca2e5f --- /dev/null +++ b/arch/loongarch/include/uapi/asm/Kbuild @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +generic-y += kvm_para.h diff --git a/arch/loongarch/include/uapi/asm/auxvec.h b/arch/loongarch/include/uapi/asm/auxvec.h new file mode 100644 index 000000000000..922d9e6b5058 --- /dev/null +++ b/arch/loongarch/include/uapi/asm/auxvec.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_AUXVEC_H +#define __ASM_AUXVEC_H + +/* Location of VDSO image. */ +#define AT_SYSINFO_EHDR 33 + +#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */ + +#endif /* __ASM_AUXVEC_H */ diff --git a/arch/loongarch/include/uapi/asm/bitsperlong.h b/arch/loongarch/include/uapi/asm/bitsperlong.h new file mode 100644 index 000000000000..00b4ba1e5cdf --- /dev/null +++ b/arch/loongarch/include/uapi/asm/bitsperlong.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __ASM_LOONGARCH_BITSPERLONG_H +#define __ASM_LOONGARCH_BITSPERLONG_H + +#define __BITS_PER_LONG (__SIZEOF_LONG__ * 8) + +#include <asm-generic/bitsperlong.h> + +#endif /* __ASM_LOONGARCH_BITSPERLONG_H */ diff --git a/arch/loongarch/include/uapi/asm/break.h b/arch/loongarch/include/uapi/asm/break.h new file mode 100644 index 000000000000..bb9b82ba59f2 --- /dev/null +++ b/arch/loongarch/include/uapi/asm/break.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef __UAPI_ASM_BREAK_H +#define __UAPI_ASM_BREAK_H + +#define BRK_DEFAULT 0 /* Used as default */ +#define BRK_BUG 1 /* Used by BUG() */ +#define BRK_KDB 2 /* Used in KDB_ENTER() */ +#define BRK_MATHEMU 3 /* Used by FPU emulator */ +#define BRK_USERBP 4 /* User bp (used by debuggers) */ +#define BRK_SSTEPBP 5 /* User bp (used by debuggers) */ +#define BRK_OVERFLOW 6 /* Overflow check */ +#define BRK_DIVZERO 7 /* Divide by zero check */ +#define BRK_RANGE 8 /* Range error check */ +#define BRK_MULOVFL 9 /* Multiply overflow */ +#define BRK_KPROBE_BP 10 /* Kprobe break */ +#define BRK_KPROBE_SSTEPBP 11 /* Kprobe single step break */ +#define BRK_UPROBE_BP 12 /* See <asm/uprobes.h> */ +#define BRK_UPROBE_XOLBP 13 /* See <asm/uprobes.h> */ + +#endif /* __UAPI_ASM_BREAK_H */ diff --git a/arch/loongarch/include/uapi/asm/byteorder.h b/arch/loongarch/include/uapi/asm/byteorder.h new file mode 100644 index 000000000000..b1722d890deb --- /dev/null +++ b/arch/loongarch/include/uapi/asm/byteorder.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_BYTEORDER_H +#define _ASM_BYTEORDER_H + +#include <linux/byteorder/little_endian.h> + +#endif /* _ASM_BYTEORDER_H */ diff --git a/arch/loongarch/include/uapi/asm/hwcap.h b/arch/loongarch/include/uapi/asm/hwcap.h new file mode 100644 index 000000000000..8840b72fa8e8 --- /dev/null +++ b/arch/loongarch/include/uapi/asm/hwcap.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_ASM_HWCAP_H +#define _UAPI_ASM_HWCAP_H + +/* HWCAP flags */ +#define HWCAP_LOONGARCH_CPUCFG (1 << 0) +#define HWCAP_LOONGARCH_LAM (1 << 1) +#define HWCAP_LOONGARCH_UAL (1 << 2) +#define HWCAP_LOONGARCH_FPU (1 << 3) +#define HWCAP_LOONGARCH_LSX (1 << 4) +#define HWCAP_LOONGARCH_LASX (1 << 5) +#define HWCAP_LOONGARCH_CRC32 (1 << 6) +#define HWCAP_LOONGARCH_COMPLEX (1 << 7) +#define HWCAP_LOONGARCH_CRYPTO (1 << 8) +#define HWCAP_LOONGARCH_LVZ (1 << 9) +#define HWCAP_LOONGARCH_LBT_X86 (1 << 10) +#define HWCAP_LOONGARCH_LBT_ARM (1 << 11) +#define HWCAP_LOONGARCH_LBT_MIPS (1 << 12) + +#endif /* _UAPI_ASM_HWCAP_H */ diff --git a/arch/loongarch/include/uapi/asm/ptrace.h b/arch/loongarch/include/uapi/asm/ptrace.h new file mode 100644 index 000000000000..083193f4a5d5 --- /dev/null +++ b/arch/loongarch/include/uapi/asm/ptrace.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _UAPI_ASM_PTRACE_H +#define _UAPI_ASM_PTRACE_H + +#include <linux/types.h> + +#ifndef __KERNEL__ +#include <stdint.h> +#endif + +/* + * For PTRACE_{POKE,PEEK}USR. 0 - 31 are GPRs, + * 32 is syscall's original ARG0, 33 is PC, 34 is BADVADDR. + */ +#define GPR_BASE 0 +#define GPR_NUM 32 +#define GPR_END (GPR_BASE + GPR_NUM - 1) +#define ARG0 (GPR_END + 1) +#define PC (GPR_END + 2) +#define BADVADDR (GPR_END + 3) + +#define NUM_FPU_REGS 32 + +struct user_pt_regs { + /* Main processor registers. */ + unsigned long regs[32]; + + /* Original syscall arg0. */ + unsigned long orig_a0; + + /* Special CSR registers. */ + unsigned long csr_era; + unsigned long csr_badv; + unsigned long reserved[10]; +} __attribute__((aligned(8))); + +struct user_fp_state { + uint64_t fpr[32]; + uint64_t fcc; + uint32_t fcsr; +}; + +#define PTRACE_SYSEMU 0x1f +#define PTRACE_SYSEMU_SINGLESTEP 0x20 + +#endif /* _UAPI_ASM_PTRACE_H */ diff --git a/arch/loongarch/include/uapi/asm/reg.h b/arch/loongarch/include/uapi/asm/reg.h new file mode 100644 index 000000000000..90ad910c60eb --- /dev/null +++ b/arch/loongarch/include/uapi/asm/reg.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Various register offset definitions for debuggers, core file + * examiners and whatnot. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#ifndef __UAPI_ASM_LOONGARCH_REG_H +#define __UAPI_ASM_LOONGARCH_REG_H + +#define LOONGARCH_EF_R0 0 +#define LOONGARCH_EF_R1 1 +#define LOONGARCH_EF_R2 2 +#define LOONGARCH_EF_R3 3 +#define LOONGARCH_EF_R4 4 +#define LOONGARCH_EF_R5 5 +#define LOONGARCH_EF_R6 6 +#define LOONGARCH_EF_R7 7 +#define LOONGARCH_EF_R8 8 +#define LOONGARCH_EF_R9 9 +#define LOONGARCH_EF_R10 10 +#define LOONGARCH_EF_R11 11 +#define LOONGARCH_EF_R12 12 +#define LOONGARCH_EF_R13 13 +#define LOONGARCH_EF_R14 14 +#define LOONGARCH_EF_R15 15 +#define LOONGARCH_EF_R16 16 +#define LOONGARCH_EF_R17 17 +#define LOONGARCH_EF_R18 18 +#define LOONGARCH_EF_R19 19 +#define LOONGARCH_EF_R20 20 +#define LOONGARCH_EF_R21 21 +#define LOONGARCH_EF_R22 22 +#define LOONGARCH_EF_R23 23 +#define LOONGARCH_EF_R24 24 +#define LOONGARCH_EF_R25 25 +#define LOONGARCH_EF_R26 26 +#define LOONGARCH_EF_R27 27 +#define LOONGARCH_EF_R28 28 +#define LOONGARCH_EF_R29 29 +#define LOONGARCH_EF_R30 30 +#define LOONGARCH_EF_R31 31 + +/* + * Saved special registers + */ +#define LOONGARCH_EF_ORIG_A0 32 +#define LOONGARCH_EF_CSR_ERA 33 +#define LOONGARCH_EF_CSR_BADV 34 +#define LOONGARCH_EF_CSR_CRMD 35 +#define LOONGARCH_EF_CSR_PRMD 36 +#define LOONGARCH_EF_CSR_EUEN 37 +#define LOONGARCH_EF_CSR_ECFG 38 +#define LOONGARCH_EF_CSR_ESTAT 39 + +#define LOONGARCH_EF_SIZE 320 /* size in bytes */ + +#endif /* __UAPI_ASM_LOONGARCH_REG_H */ diff --git a/arch/loongarch/include/uapi/asm/sigcontext.h b/arch/loongarch/include/uapi/asm/sigcontext.h new file mode 100644 index 000000000000..52e49b8bf4be --- /dev/null +++ b/arch/loongarch/include/uapi/asm/sigcontext.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _UAPI_ASM_SIGCONTEXT_H +#define _UAPI_ASM_SIGCONTEXT_H + +#include <linux/types.h> +#include <linux/posix_types.h> + +/* FP context was used */ +#define SC_USED_FP (1 << 0) +/* Address error was due to memory load */ +#define SC_ADDRERR_RD (1 << 30) +/* Address error was due to memory store */ +#define SC_ADDRERR_WR (1 << 31) + +struct sigcontext { + __u64 sc_pc; + __u64 sc_regs[32]; + __u32 sc_flags; + __u64 sc_extcontext[0] __attribute__((__aligned__(16))); +}; + +#define CONTEXT_INFO_ALIGN 16 +struct sctx_info { + __u32 magic; + __u32 size; + __u64 padding; /* padding to 16 bytes */ +}; + +/* FPU context */ +#define FPU_CTX_MAGIC 0x46505501 +#define FPU_CTX_ALIGN 8 +struct fpu_context { + __u64 regs[32]; + __u64 fcc; + __u32 fcsr; +}; + +#endif /* _UAPI_ASM_SIGCONTEXT_H */ diff --git a/arch/loongarch/include/uapi/asm/signal.h b/arch/loongarch/include/uapi/asm/signal.h new file mode 100644 index 000000000000..992d965aa13f --- /dev/null +++ b/arch/loongarch/include/uapi/asm/signal.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#ifndef _UAPI_ASM_SIGNAL_H +#define _UAPI_ASM_SIGNAL_H + +#define MINSIGSTKSZ 4096 +#define SIGSTKSZ 16384 + +#include <asm-generic/signal.h> + +#endif diff --git a/arch/loongarch/include/uapi/asm/ucontext.h b/arch/loongarch/include/uapi/asm/ucontext.h new file mode 100644 index 000000000000..12577e22b1c7 --- /dev/null +++ b/arch/loongarch/include/uapi/asm/ucontext.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LOONGARCH_UAPI_ASM_UCONTEXT_H +#define __LOONGARCH_UAPI_ASM_UCONTEXT_H + +/** + * struct ucontext - user context structure + * @uc_flags: + * @uc_link: + * @uc_stack: + * @uc_mcontext: holds basic processor state + * @uc_sigmask: + * @uc_extcontext: holds extended processor state + */ +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + /* There's some padding here to allow sigset_t to be expanded in the + * future. Though this is unlikely, other architectures put uc_sigmask + * at the end of this structure and explicitly state it can be + * expanded, so we didn't want to box ourselves in here. */ + __u8 __unused[1024 / 8 - sizeof(sigset_t)]; + /* We can't put uc_sigmask at the end of this structure because we need + * to be able to expand sigcontext in the future. For example, the + * vector ISA extension will almost certainly add ISA state. We want + * to ensure all user-visible ISA state can be saved and restored via a + * ucontext, so we're putting this at the end in order to allow for + * infinite extensibility. Since we know this will be extended and we + * assume sigset_t won't be extended an extreme amount, we're + * prioritizing this. */ + struct sigcontext uc_mcontext; +}; + +#endif /* __LOONGARCH_UAPI_ASM_UCONTEXT_H */ diff --git a/arch/loongarch/include/uapi/asm/unistd.h b/arch/loongarch/include/uapi/asm/unistd.h new file mode 100644 index 000000000000..fcb668984f03 --- /dev/null +++ b/arch/loongarch/include/uapi/asm/unistd.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#define __ARCH_WANT_SYS_CLONE +#define __ARCH_WANT_SYS_CLONE3 + +#include <asm-generic/unistd.h> diff --git a/arch/loongarch/kernel/.gitignore b/arch/loongarch/kernel/.gitignore new file mode 100644 index 000000000000..bbb90f92d051 --- /dev/null +++ b/arch/loongarch/kernel/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +vmlinux.lds diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile new file mode 100644 index 000000000000..940de9173542 --- /dev/null +++ b/arch/loongarch/kernel/Makefile @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the Linux/LoongArch kernel. +# + +extra-y := head.o vmlinux.lds + +obj-y += cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \ + traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \ + elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o + +obj-$(CONFIG_ACPI) += acpi.o +obj-$(CONFIG_EFI) += efi.o + +obj-$(CONFIG_CPU_HAS_FPU) += fpu.o + +obj-$(CONFIG_MODULES) += module.o module-sections.o + +obj-$(CONFIG_PROC_FS) += proc.o + +obj-$(CONFIG_SMP) += smp.o + +obj-$(CONFIG_NUMA) += numa.o + +CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) diff --git a/arch/loongarch/kernel/access-helper.h b/arch/loongarch/kernel/access-helper.h new file mode 100644 index 000000000000..4a35ca81bd08 --- /dev/null +++ b/arch/loongarch/kernel/access-helper.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <linux/uaccess.h> + +static inline int __get_inst(u32 *i, u32 *p, bool user) +{ + return user ? get_user(*i, (u32 __user *)p) : get_kernel_nofault(*i, p); +} + +static inline int __get_addr(unsigned long *a, unsigned long *p, bool user) +{ + return user ? get_user(*a, (unsigned long __user *)p) : get_kernel_nofault(*a, p); +} diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c new file mode 100644 index 000000000000..b16c3dea5eeb --- /dev/null +++ b/arch/loongarch/kernel/acpi.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * acpi.c - Architecture-Specific Low-Level ACPI Boot Support + * + * Author: Jianmin Lv <lvjianmin@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/memblock.h> +#include <linux/serial_core.h> +#include <asm/io.h> +#include <asm/numa.h> +#include <asm/loongson.h> + +int acpi_disabled; +EXPORT_SYMBOL(acpi_disabled); +int acpi_noirq; +int acpi_pci_disabled; +EXPORT_SYMBOL(acpi_pci_disabled); +int acpi_strict = 1; /* We have no workarounds on LoongArch */ +int num_processors; +int disabled_cpus; +enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM; + +u64 acpi_saved_sp; + +#define MAX_CORE_PIC 256 + +#define PREFIX "ACPI: " + +int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) +{ + if (irqp != NULL) + *irqp = acpi_register_gsi(NULL, gsi, -1, -1); + return (*irqp >= 0) ? 0 : -EINVAL; +} +EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); + +int acpi_isa_irq_to_gsi(unsigned int isa_irq, u32 *gsi) +{ + if (gsi) + *gsi = isa_irq; + return 0; +} + +/* + * success: return IRQ number (>=0) + * failure: return < 0 + */ +int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) +{ + struct irq_fwspec fwspec; + + switch (gsi) { + case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ: + fwspec.fwnode = liointc_domain->fwnode; + fwspec.param[0] = gsi - GSI_MIN_CPU_IRQ; + fwspec.param_count = 1; + + return irq_create_fwspec_mapping(&fwspec); + + case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ: + if (!pch_lpc_domain) + return -EINVAL; + + fwspec.fwnode = pch_lpc_domain->fwnode; + fwspec.param[0] = gsi - GSI_MIN_LPC_IRQ; + fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity); + fwspec.param_count = 2; + + return irq_create_fwspec_mapping(&fwspec); + + case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ: + if (!pch_pic_domain[0]) + return -EINVAL; + + fwspec.fwnode = pch_pic_domain[0]->fwnode; + fwspec.param[0] = gsi - GSI_MIN_PCH_IRQ; + fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH; + fwspec.param_count = 2; + + return irq_create_fwspec_mapping(&fwspec); + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(acpi_register_gsi); + +void acpi_unregister_gsi(u32 gsi) +{ + +} +EXPORT_SYMBOL_GPL(acpi_unregister_gsi); + +void __init __iomem * __acpi_map_table(unsigned long phys, unsigned long size) +{ + + if (!phys || !size) + return NULL; + + return early_memremap(phys, size); +} +void __init __acpi_unmap_table(void __iomem *map, unsigned long size) +{ + if (!map || !size) + return; + + early_memunmap(map, size); +} + +void __init __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) +{ + if (!memblock_is_memory(phys)) + return ioremap(phys, size); + else + return ioremap_cache(phys, size); +} + +void __init acpi_boot_table_init(void) +{ + /* + * If acpi_disabled, bail out + */ + if (acpi_disabled) + return; + + /* + * Initialize the ACPI boot-time table parser. + */ + if (acpi_table_init()) { + disable_acpi(); + return; + } +} + +static int set_processor_mask(u32 id, u32 flags) +{ + + int cpu, cpuid = id; + + if (num_processors >= nr_cpu_ids) { + pr_warn(PREFIX "nr_cpus/possible_cpus limit of %i reached." + " processor 0x%x ignored.\n", nr_cpu_ids, cpuid); + + return -ENODEV; + + } + if (cpuid == loongson_sysconf.boot_cpu_id) + cpu = 0; + else + cpu = cpumask_next_zero(-1, cpu_present_mask); + + if (flags & ACPI_MADT_ENABLED) { + num_processors++; + set_cpu_possible(cpu, true); + set_cpu_present(cpu, true); + __cpu_number_map[cpuid] = cpu; + __cpu_logical_map[cpu] = cpuid; + } else + disabled_cpus++; + + return cpu; +} + +static void __init acpi_process_madt(void) +{ + int i; + + for (i = 0; i < NR_CPUS; i++) { + __cpu_number_map[i] = -1; + __cpu_logical_map[i] = -1; + } + + loongson_sysconf.nr_cpus = num_processors; +} + +int __init acpi_boot_init(void) +{ + /* + * If acpi_disabled, bail out + */ + if (acpi_disabled) + return -1; + + loongson_sysconf.boot_cpu_id = read_csr_cpuid(); + + /* + * Process the Multiple APIC Description Table (MADT), if present + */ + acpi_process_madt(); + + /* Do not enable ACPI SPCR console by default */ + acpi_parse_spcr(earlycon_acpi_spcr_enable, false); + + return 0; +} + +#ifdef CONFIG_ACPI_NUMA + +static __init int setup_node(int pxm) +{ + return acpi_map_pxm_to_node(pxm); +} + +/* + * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for + * I/O localities since SRAT does not list them. I/O localities are + * not supported at this point. + */ +unsigned int numa_distance_cnt; + +static inline unsigned int get_numa_distances_cnt(struct acpi_table_slit *slit) +{ + return slit->locality_count; +} + +void __init numa_set_distance(int from, int to, int distance) +{ + if ((u8)distance != distance || (from == to && distance != LOCAL_DISTANCE)) { + pr_warn_once("Warning: invalid distance parameter, from=%d to=%d distance=%d\n", + from, to, distance); + return; + } + + node_distances[from][to] = distance; +} + +/* Callback for Proximity Domain -> CPUID mapping */ +void __init +acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) +{ + int pxm, node; + + if (srat_disabled()) + return; + if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { + bad_srat(); + return; + } + if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) + return; + pxm = pa->proximity_domain_lo; + if (acpi_srat_revision >= 2) { + pxm |= (pa->proximity_domain_hi[0] << 8); + pxm |= (pa->proximity_domain_hi[1] << 16); + pxm |= (pa->proximity_domain_hi[2] << 24); + } + node = setup_node(pxm); + if (node < 0) { + pr_err("SRAT: Too many proximity domains %x\n", pxm); + bad_srat(); + return; + } + + if (pa->apic_id >= CONFIG_NR_CPUS) { + pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n", + pxm, pa->apic_id, node); + return; + } + + early_numa_add_cpu(pa->apic_id, node); + + set_cpuid_to_node(pa->apic_id, node); + node_set(node, numa_nodes_parsed); + pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", pxm, pa->apic_id, node); +} + +void __init acpi_numa_arch_fixup(void) {} +#endif + +void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size) +{ + memblock_reserve(addr, size); +} + +#ifdef CONFIG_ACPI_HOTPLUG_CPU + +#include <acpi/processor.h> + +static int __ref acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) +{ +#ifdef CONFIG_ACPI_NUMA + int nid; + + nid = acpi_get_node(handle); + if (nid != NUMA_NO_NODE) { + set_cpuid_to_node(physid, nid); + node_set(nid, numa_nodes_parsed); + set_cpu_numa_node(cpu, nid); + cpumask_set_cpu(cpu, cpumask_of_node(nid)); + } +#endif + return 0; +} + +int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu) +{ + int cpu; + + cpu = set_processor_mask(physid, ACPI_MADT_ENABLED); + if (cpu < 0) { + pr_info(PREFIX "Unable to map lapic to logical cpu number\n"); + return cpu; + } + + acpi_map_cpu2node(handle, cpu, physid); + + *pcpu = cpu; + + return 0; +} +EXPORT_SYMBOL(acpi_map_cpu); + +int acpi_unmap_cpu(int cpu) +{ +#ifdef CONFIG_ACPI_NUMA + set_cpuid_to_node(cpu_logical_map(cpu), NUMA_NO_NODE); +#endif + set_cpu_present(cpu, false); + num_processors--; + + pr_info("cpu%d hot remove!\n", cpu); + + return 0; +} +EXPORT_SYMBOL(acpi_unmap_cpu); + +#endif /* CONFIG_ACPI_HOTPLUG_CPU */ diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c new file mode 100644 index 000000000000..bfb65eb2844f --- /dev/null +++ b/arch/loongarch/kernel/asm-offsets.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * asm-offsets.c: Calculate pt_regs and task_struct offsets. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/kbuild.h> +#include <linux/suspend.h> +#include <asm/cpu-info.h> +#include <asm/ptrace.h> +#include <asm/processor.h> + +void output_ptreg_defines(void) +{ + COMMENT("LoongArch pt_regs offsets."); + OFFSET(PT_R0, pt_regs, regs[0]); + OFFSET(PT_R1, pt_regs, regs[1]); + OFFSET(PT_R2, pt_regs, regs[2]); + OFFSET(PT_R3, pt_regs, regs[3]); + OFFSET(PT_R4, pt_regs, regs[4]); + OFFSET(PT_R5, pt_regs, regs[5]); + OFFSET(PT_R6, pt_regs, regs[6]); + OFFSET(PT_R7, pt_regs, regs[7]); + OFFSET(PT_R8, pt_regs, regs[8]); + OFFSET(PT_R9, pt_regs, regs[9]); + OFFSET(PT_R10, pt_regs, regs[10]); + OFFSET(PT_R11, pt_regs, regs[11]); + OFFSET(PT_R12, pt_regs, regs[12]); + OFFSET(PT_R13, pt_regs, regs[13]); + OFFSET(PT_R14, pt_regs, regs[14]); + OFFSET(PT_R15, pt_regs, regs[15]); + OFFSET(PT_R16, pt_regs, regs[16]); + OFFSET(PT_R17, pt_regs, regs[17]); + OFFSET(PT_R18, pt_regs, regs[18]); + OFFSET(PT_R19, pt_regs, regs[19]); + OFFSET(PT_R20, pt_regs, regs[20]); + OFFSET(PT_R21, pt_regs, regs[21]); + OFFSET(PT_R22, pt_regs, regs[22]); + OFFSET(PT_R23, pt_regs, regs[23]); + OFFSET(PT_R24, pt_regs, regs[24]); + OFFSET(PT_R25, pt_regs, regs[25]); + OFFSET(PT_R26, pt_regs, regs[26]); + OFFSET(PT_R27, pt_regs, regs[27]); + OFFSET(PT_R28, pt_regs, regs[28]); + OFFSET(PT_R29, pt_regs, regs[29]); + OFFSET(PT_R30, pt_regs, regs[30]); + OFFSET(PT_R31, pt_regs, regs[31]); + OFFSET(PT_CRMD, pt_regs, csr_crmd); + OFFSET(PT_PRMD, pt_regs, csr_prmd); + OFFSET(PT_EUEN, pt_regs, csr_euen); + OFFSET(PT_ECFG, pt_regs, csr_ecfg); + OFFSET(PT_ESTAT, pt_regs, csr_estat); + OFFSET(PT_ERA, pt_regs, csr_era); + OFFSET(PT_BVADDR, pt_regs, csr_badvaddr); + OFFSET(PT_ORIG_A0, pt_regs, orig_a0); + DEFINE(PT_SIZE, sizeof(struct pt_regs)); + BLANK(); +} + +void output_task_defines(void) +{ + COMMENT("LoongArch task_struct offsets."); + OFFSET(TASK_STATE, task_struct, __state); + OFFSET(TASK_THREAD_INFO, task_struct, stack); + OFFSET(TASK_FLAGS, task_struct, flags); + OFFSET(TASK_MM, task_struct, mm); + OFFSET(TASK_PID, task_struct, pid); + DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct)); + BLANK(); +} + +void output_thread_info_defines(void) +{ + COMMENT("LoongArch thread_info offsets."); + OFFSET(TI_TASK, thread_info, task); + OFFSET(TI_FLAGS, thread_info, flags); + OFFSET(TI_TP_VALUE, thread_info, tp_value); + OFFSET(TI_CPU, thread_info, cpu); + OFFSET(TI_PRE_COUNT, thread_info, preempt_count); + OFFSET(TI_REGS, thread_info, regs); + DEFINE(_THREAD_SIZE, THREAD_SIZE); + DEFINE(_THREAD_MASK, THREAD_MASK); + DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE); + DEFINE(_IRQ_STACK_START, IRQ_STACK_START); + BLANK(); +} + +void output_thread_defines(void) +{ + COMMENT("LoongArch specific thread_struct offsets."); + OFFSET(THREAD_REG01, task_struct, thread.reg01); + OFFSET(THREAD_REG03, task_struct, thread.reg03); + OFFSET(THREAD_REG22, task_struct, thread.reg22); + OFFSET(THREAD_REG23, task_struct, thread.reg23); + OFFSET(THREAD_REG24, task_struct, thread.reg24); + OFFSET(THREAD_REG25, task_struct, thread.reg25); + OFFSET(THREAD_REG26, task_struct, thread.reg26); + OFFSET(THREAD_REG27, task_struct, thread.reg27); + OFFSET(THREAD_REG28, task_struct, thread.reg28); + OFFSET(THREAD_REG29, task_struct, thread.reg29); + OFFSET(THREAD_REG30, task_struct, thread.reg30); + OFFSET(THREAD_REG31, task_struct, thread.reg31); + OFFSET(THREAD_CSRCRMD, task_struct, + thread.csr_crmd); + OFFSET(THREAD_CSRPRMD, task_struct, + thread.csr_prmd); + OFFSET(THREAD_CSREUEN, task_struct, + thread.csr_euen); + OFFSET(THREAD_CSRECFG, task_struct, + thread.csr_ecfg); + + OFFSET(THREAD_SCR0, task_struct, thread.scr0); + OFFSET(THREAD_SCR1, task_struct, thread.scr1); + OFFSET(THREAD_SCR2, task_struct, thread.scr2); + OFFSET(THREAD_SCR3, task_struct, thread.scr3); + + OFFSET(THREAD_EFLAGS, task_struct, thread.eflags); + + OFFSET(THREAD_FPU, task_struct, thread.fpu); + + OFFSET(THREAD_BVADDR, task_struct, \ + thread.csr_badvaddr); + OFFSET(THREAD_ECODE, task_struct, \ + thread.error_code); + OFFSET(THREAD_TRAPNO, task_struct, thread.trap_nr); + BLANK(); +} + +void output_thread_fpu_defines(void) +{ + OFFSET(THREAD_FPR0, loongarch_fpu, fpr[0]); + OFFSET(THREAD_FPR1, loongarch_fpu, fpr[1]); + OFFSET(THREAD_FPR2, loongarch_fpu, fpr[2]); + OFFSET(THREAD_FPR3, loongarch_fpu, fpr[3]); + OFFSET(THREAD_FPR4, loongarch_fpu, fpr[4]); + OFFSET(THREAD_FPR5, loongarch_fpu, fpr[5]); + OFFSET(THREAD_FPR6, loongarch_fpu, fpr[6]); + OFFSET(THREAD_FPR7, loongarch_fpu, fpr[7]); + OFFSET(THREAD_FPR8, loongarch_fpu, fpr[8]); + OFFSET(THREAD_FPR9, loongarch_fpu, fpr[9]); + OFFSET(THREAD_FPR10, loongarch_fpu, fpr[10]); + OFFSET(THREAD_FPR11, loongarch_fpu, fpr[11]); + OFFSET(THREAD_FPR12, loongarch_fpu, fpr[12]); + OFFSET(THREAD_FPR13, loongarch_fpu, fpr[13]); + OFFSET(THREAD_FPR14, loongarch_fpu, fpr[14]); + OFFSET(THREAD_FPR15, loongarch_fpu, fpr[15]); + OFFSET(THREAD_FPR16, loongarch_fpu, fpr[16]); + OFFSET(THREAD_FPR17, loongarch_fpu, fpr[17]); + OFFSET(THREAD_FPR18, loongarch_fpu, fpr[18]); + OFFSET(THREAD_FPR19, loongarch_fpu, fpr[19]); + OFFSET(THREAD_FPR20, loongarch_fpu, fpr[20]); + OFFSET(THREAD_FPR21, loongarch_fpu, fpr[21]); + OFFSET(THREAD_FPR22, loongarch_fpu, fpr[22]); + OFFSET(THREAD_FPR23, loongarch_fpu, fpr[23]); + OFFSET(THREAD_FPR24, loongarch_fpu, fpr[24]); + OFFSET(THREAD_FPR25, loongarch_fpu, fpr[25]); + OFFSET(THREAD_FPR26, loongarch_fpu, fpr[26]); + OFFSET(THREAD_FPR27, loongarch_fpu, fpr[27]); + OFFSET(THREAD_FPR28, loongarch_fpu, fpr[28]); + OFFSET(THREAD_FPR29, loongarch_fpu, fpr[29]); + OFFSET(THREAD_FPR30, loongarch_fpu, fpr[30]); + OFFSET(THREAD_FPR31, loongarch_fpu, fpr[31]); + + OFFSET(THREAD_FCSR, loongarch_fpu, fcsr); + OFFSET(THREAD_FCC, loongarch_fpu, fcc); + OFFSET(THREAD_VCSR, loongarch_fpu, vcsr); + BLANK(); +} + +void output_mm_defines(void) +{ + COMMENT("Size of struct page"); + DEFINE(STRUCT_PAGE_SIZE, sizeof(struct page)); + BLANK(); + COMMENT("Linux mm_struct offsets."); + OFFSET(MM_USERS, mm_struct, mm_users); + OFFSET(MM_PGD, mm_struct, pgd); + OFFSET(MM_CONTEXT, mm_struct, context); + BLANK(); + DEFINE(_PGD_T_SIZE, sizeof(pgd_t)); + DEFINE(_PMD_T_SIZE, sizeof(pmd_t)); + DEFINE(_PTE_T_SIZE, sizeof(pte_t)); + BLANK(); + DEFINE(_PGD_T_LOG2, PGD_T_LOG2); +#ifndef __PAGETABLE_PMD_FOLDED + DEFINE(_PMD_T_LOG2, PMD_T_LOG2); +#endif + DEFINE(_PTE_T_LOG2, PTE_T_LOG2); + BLANK(); + DEFINE(_PGD_ORDER, PGD_ORDER); +#ifndef __PAGETABLE_PMD_FOLDED + DEFINE(_PMD_ORDER, PMD_ORDER); +#endif + DEFINE(_PTE_ORDER, PTE_ORDER); + BLANK(); + DEFINE(_PMD_SHIFT, PMD_SHIFT); + DEFINE(_PGDIR_SHIFT, PGDIR_SHIFT); + BLANK(); + DEFINE(_PTRS_PER_PGD, PTRS_PER_PGD); + DEFINE(_PTRS_PER_PMD, PTRS_PER_PMD); + DEFINE(_PTRS_PER_PTE, PTRS_PER_PTE); + BLANK(); + DEFINE(_PAGE_SHIFT, PAGE_SHIFT); + DEFINE(_PAGE_SIZE, PAGE_SIZE); + BLANK(); +} + +void output_sc_defines(void) +{ + COMMENT("Linux sigcontext offsets."); + OFFSET(SC_REGS, sigcontext, sc_regs); + OFFSET(SC_PC, sigcontext, sc_pc); + BLANK(); +} + +void output_signal_defines(void) +{ + COMMENT("Linux signal numbers."); + DEFINE(_SIGHUP, SIGHUP); + DEFINE(_SIGINT, SIGINT); + DEFINE(_SIGQUIT, SIGQUIT); + DEFINE(_SIGILL, SIGILL); + DEFINE(_SIGTRAP, SIGTRAP); + DEFINE(_SIGIOT, SIGIOT); + DEFINE(_SIGABRT, SIGABRT); + DEFINE(_SIGFPE, SIGFPE); + DEFINE(_SIGKILL, SIGKILL); + DEFINE(_SIGBUS, SIGBUS); + DEFINE(_SIGSEGV, SIGSEGV); + DEFINE(_SIGSYS, SIGSYS); + DEFINE(_SIGPIPE, SIGPIPE); + DEFINE(_SIGALRM, SIGALRM); + DEFINE(_SIGTERM, SIGTERM); + DEFINE(_SIGUSR1, SIGUSR1); + DEFINE(_SIGUSR2, SIGUSR2); + DEFINE(_SIGCHLD, SIGCHLD); + DEFINE(_SIGPWR, SIGPWR); + DEFINE(_SIGWINCH, SIGWINCH); + DEFINE(_SIGURG, SIGURG); + DEFINE(_SIGIO, SIGIO); + DEFINE(_SIGSTOP, SIGSTOP); + DEFINE(_SIGTSTP, SIGTSTP); + DEFINE(_SIGCONT, SIGCONT); + DEFINE(_SIGTTIN, SIGTTIN); + DEFINE(_SIGTTOU, SIGTTOU); + DEFINE(_SIGVTALRM, SIGVTALRM); + DEFINE(_SIGPROF, SIGPROF); + DEFINE(_SIGXCPU, SIGXCPU); + DEFINE(_SIGXFSZ, SIGXFSZ); + BLANK(); +} + +#ifdef CONFIG_SMP +void output_smpboot_defines(void) +{ + COMMENT("Linux smp cpu boot offsets."); + OFFSET(CPU_BOOT_STACK, secondary_data, stack); + OFFSET(CPU_BOOT_TINFO, secondary_data, thread_info); + BLANK(); +} +#endif diff --git a/arch/loongarch/kernel/cacheinfo.c b/arch/loongarch/kernel/cacheinfo.c new file mode 100644 index 000000000000..8c9fe29e98f0 --- /dev/null +++ b/arch/loongarch/kernel/cacheinfo.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * LoongArch cacheinfo support + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/cacheinfo.h> + +/* Populates leaf and increments to next leaf */ +#define populate_cache(cache, leaf, c_level, c_type) \ +do { \ + leaf->type = c_type; \ + leaf->level = c_level; \ + leaf->coherency_line_size = c->cache.linesz; \ + leaf->number_of_sets = c->cache.sets; \ + leaf->ways_of_associativity = c->cache.ways; \ + leaf->size = c->cache.linesz * c->cache.sets * \ + c->cache.ways; \ + leaf++; \ +} while (0) + +int init_cache_level(unsigned int cpu) +{ + struct cpuinfo_loongarch *c = ¤t_cpu_data; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + int levels = 0, leaves = 0; + + /* + * If Dcache is not set, we assume the cache structures + * are not properly initialized. + */ + if (c->dcache.waysize) + levels += 1; + else + return -ENOENT; + + + leaves += (c->icache.waysize) ? 2 : 1; + + if (c->vcache.waysize) { + levels++; + leaves++; + } + + if (c->scache.waysize) { + levels++; + leaves++; + } + + if (c->tcache.waysize) { + levels++; + leaves++; + } + + this_cpu_ci->num_levels = levels; + this_cpu_ci->num_leaves = leaves; + return 0; +} + +static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, + struct cacheinfo *sib_leaf) +{ + return !((this_leaf->level == 1) || (this_leaf->level == 2)); +} + +static void cache_cpumap_setup(unsigned int cpu) +{ + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf, *sib_leaf; + unsigned int index; + + for (index = 0; index < this_cpu_ci->num_leaves; index++) { + unsigned int i; + + this_leaf = this_cpu_ci->info_list + index; + /* skip if shared_cpu_map is already populated */ + if (!cpumask_empty(&this_leaf->shared_cpu_map)) + continue; + + cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); + for_each_online_cpu(i) { + struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i); + + if (i == cpu || !sib_cpu_ci->info_list) + continue;/* skip if itself or no cacheinfo */ + sib_leaf = sib_cpu_ci->info_list + index; + if (cache_leaves_are_shared(this_leaf, sib_leaf)) { + cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map); + cpumask_set_cpu(i, &this_leaf->shared_cpu_map); + } + } + } +} + +int populate_cache_leaves(unsigned int cpu) +{ + int level = 1; + struct cpuinfo_loongarch *c = ¤t_cpu_data; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf = this_cpu_ci->info_list; + + if (c->icache.waysize) { + populate_cache(dcache, this_leaf, level, CACHE_TYPE_DATA); + populate_cache(icache, this_leaf, level++, CACHE_TYPE_INST); + } else { + populate_cache(dcache, this_leaf, level++, CACHE_TYPE_UNIFIED); + } + + if (c->vcache.waysize) + populate_cache(vcache, this_leaf, level++, CACHE_TYPE_UNIFIED); + + if (c->scache.waysize) + populate_cache(scache, this_leaf, level++, CACHE_TYPE_UNIFIED); + + if (c->tcache.waysize) + populate_cache(tcache, this_leaf, level++, CACHE_TYPE_UNIFIED); + + cache_cpumap_setup(cpu); + this_cpu_ci->cpu_map_populated = true; + + return 0; +} diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c new file mode 100644 index 000000000000..6c87ea36b257 --- /dev/null +++ b/arch/loongarch/kernel/cpu-probe.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Processor capabilities determination functions. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/ptrace.h> +#include <linux/smp.h> +#include <linux/stddef.h> +#include <linux/export.h> +#include <linux/printk.h> +#include <linux/uaccess.h> + +#include <asm/cpu-features.h> +#include <asm/elf.h> +#include <asm/fpu.h> +#include <asm/loongarch.h> +#include <asm/pgtable-bits.h> +#include <asm/setup.h> + +/* Hardware capabilities */ +unsigned int elf_hwcap __read_mostly; +EXPORT_SYMBOL_GPL(elf_hwcap); + +/* + * Determine the FCSR mask for FPU hardware. + */ +static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_loongarch *c) +{ + unsigned long sr, mask, fcsr, fcsr0, fcsr1; + + fcsr = c->fpu_csr0; + mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM; + + sr = read_csr_euen(); + enable_fpu(); + + fcsr0 = fcsr & mask; + write_fcsr(LOONGARCH_FCSR0, fcsr0); + fcsr0 = read_fcsr(LOONGARCH_FCSR0); + + fcsr1 = fcsr | ~mask; + write_fcsr(LOONGARCH_FCSR0, fcsr1); + fcsr1 = read_fcsr(LOONGARCH_FCSR0); + + write_fcsr(LOONGARCH_FCSR0, fcsr); + + write_csr_euen(sr); + + c->fpu_mask = ~(fcsr0 ^ fcsr1) & ~mask; +} + +static inline void set_elf_platform(int cpu, const char *plat) +{ + if (cpu == 0) + __elf_platform = plat; +} + +/* MAP BASE */ +unsigned long vm_map_base; +EXPORT_SYMBOL_GPL(vm_map_base); + +static void cpu_probe_addrbits(struct cpuinfo_loongarch *c) +{ +#ifdef __NEED_ADDRBITS_PROBE + c->pabits = (read_cpucfg(LOONGARCH_CPUCFG1) & CPUCFG1_PABITS) >> 4; + c->vabits = (read_cpucfg(LOONGARCH_CPUCFG1) & CPUCFG1_VABITS) >> 12; + vm_map_base = 0UL - (1UL << c->vabits); +#endif +} + +static void set_isa(struct cpuinfo_loongarch *c, unsigned int isa) +{ + switch (isa) { + case LOONGARCH_CPU_ISA_LA64: + c->isa_level |= LOONGARCH_CPU_ISA_LA64; + fallthrough; + case LOONGARCH_CPU_ISA_LA32S: + c->isa_level |= LOONGARCH_CPU_ISA_LA32S; + fallthrough; + case LOONGARCH_CPU_ISA_LA32R: + c->isa_level |= LOONGARCH_CPU_ISA_LA32R; + break; + } +} + +static void cpu_probe_common(struct cpuinfo_loongarch *c) +{ + unsigned int config; + unsigned long asid_mask; + + c->options = LOONGARCH_CPU_CPUCFG | LOONGARCH_CPU_CSR | + LOONGARCH_CPU_TLB | LOONGARCH_CPU_VINT | LOONGARCH_CPU_WATCH; + + elf_hwcap |= HWCAP_LOONGARCH_CRC32; + + config = read_cpucfg(LOONGARCH_CPUCFG1); + if (config & CPUCFG1_UAL) { + c->options |= LOONGARCH_CPU_UAL; + elf_hwcap |= HWCAP_LOONGARCH_UAL; + } + + config = read_cpucfg(LOONGARCH_CPUCFG2); + if (config & CPUCFG2_LAM) { + c->options |= LOONGARCH_CPU_LAM; + elf_hwcap |= HWCAP_LOONGARCH_LAM; + } + if (config & CPUCFG2_FP) { + c->options |= LOONGARCH_CPU_FPU; + elf_hwcap |= HWCAP_LOONGARCH_FPU; + } + if (config & CPUCFG2_COMPLEX) { + c->options |= LOONGARCH_CPU_COMPLEX; + elf_hwcap |= HWCAP_LOONGARCH_COMPLEX; + } + if (config & CPUCFG2_CRYPTO) { + c->options |= LOONGARCH_CPU_CRYPTO; + elf_hwcap |= HWCAP_LOONGARCH_CRYPTO; + } + if (config & CPUCFG2_LVZP) { + c->options |= LOONGARCH_CPU_LVZ; + elf_hwcap |= HWCAP_LOONGARCH_LVZ; + } + + config = read_cpucfg(LOONGARCH_CPUCFG6); + if (config & CPUCFG6_PMP) + c->options |= LOONGARCH_CPU_PMP; + + config = iocsr_read32(LOONGARCH_IOCSR_FEATURES); + if (config & IOCSRF_CSRIPI) + c->options |= LOONGARCH_CPU_CSRIPI; + if (config & IOCSRF_EXTIOI) + c->options |= LOONGARCH_CPU_EXTIOI; + if (config & IOCSRF_FREQSCALE) + c->options |= LOONGARCH_CPU_SCALEFREQ; + if (config & IOCSRF_FLATMODE) + c->options |= LOONGARCH_CPU_FLATMODE; + if (config & IOCSRF_EIODECODE) + c->options |= LOONGARCH_CPU_EIODECODE; + if (config & IOCSRF_VM) + c->options |= LOONGARCH_CPU_HYPERVISOR; + + config = csr_read32(LOONGARCH_CSR_ASID); + config = (config & CSR_ASID_BIT) >> CSR_ASID_BIT_SHIFT; + asid_mask = GENMASK(config - 1, 0); + set_cpu_asid_mask(c, asid_mask); + + config = read_csr_prcfg1(); + c->ksave_mask = GENMASK((config & CSR_CONF1_KSNUM) - 1, 0); + c->ksave_mask &= ~(EXC_KSAVE_MASK | PERCPU_KSAVE_MASK | KVM_KSAVE_MASK); + + config = read_csr_prcfg3(); + switch (config & CSR_CONF3_TLBTYPE) { + case 0: + c->tlbsizemtlb = 0; + c->tlbsizestlbsets = 0; + c->tlbsizestlbways = 0; + c->tlbsize = 0; + break; + case 1: + c->tlbsizemtlb = ((config & CSR_CONF3_MTLBSIZE) >> CSR_CONF3_MTLBSIZE_SHIFT) + 1; + c->tlbsizestlbsets = 0; + c->tlbsizestlbways = 0; + c->tlbsize = c->tlbsizemtlb + c->tlbsizestlbsets * c->tlbsizestlbways; + break; + case 2: + c->tlbsizemtlb = ((config & CSR_CONF3_MTLBSIZE) >> CSR_CONF3_MTLBSIZE_SHIFT) + 1; + c->tlbsizestlbsets = 1 << ((config & CSR_CONF3_STLBIDX) >> CSR_CONF3_STLBIDX_SHIFT); + c->tlbsizestlbways = ((config & CSR_CONF3_STLBWAYS) >> CSR_CONF3_STLBWAYS_SHIFT) + 1; + c->tlbsize = c->tlbsizemtlb + c->tlbsizestlbsets * c->tlbsizestlbways; + break; + default: + pr_warn("Warning: unknown TLB type\n"); + } +} + +#define MAX_NAME_LEN 32 +#define VENDOR_OFFSET 0 +#define CPUNAME_OFFSET 9 + +static char cpu_full_name[MAX_NAME_LEN] = " - "; + +static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int cpu) +{ + uint64_t *vendor = (void *)(&cpu_full_name[VENDOR_OFFSET]); + uint64_t *cpuname = (void *)(&cpu_full_name[CPUNAME_OFFSET]); + + __cpu_full_name[cpu] = cpu_full_name; + *vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR); + *cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME); + + switch (c->processor_id & PRID_SERIES_MASK) { + case PRID_SERIES_LA132: + c->cputype = CPU_LOONGSON32; + set_isa(c, LOONGARCH_CPU_ISA_LA32S); + __cpu_family[cpu] = "Loongson-32bit"; + pr_info("32-bit Loongson Processor probed (LA132 Core)\n"); + break; + case PRID_SERIES_LA264: + c->cputype = CPU_LOONGSON64; + set_isa(c, LOONGARCH_CPU_ISA_LA64); + __cpu_family[cpu] = "Loongson-64bit"; + pr_info("64-bit Loongson Processor probed (LA264 Core)\n"); + break; + case PRID_SERIES_LA364: + c->cputype = CPU_LOONGSON64; + set_isa(c, LOONGARCH_CPU_ISA_LA64); + __cpu_family[cpu] = "Loongson-64bit"; + pr_info("64-bit Loongson Processor probed (LA364 Core)\n"); + break; + case PRID_SERIES_LA464: + c->cputype = CPU_LOONGSON64; + set_isa(c, LOONGARCH_CPU_ISA_LA64); + __cpu_family[cpu] = "Loongson-64bit"; + pr_info("64-bit Loongson Processor probed (LA464 Core)\n"); + break; + case PRID_SERIES_LA664: + c->cputype = CPU_LOONGSON64; + set_isa(c, LOONGARCH_CPU_ISA_LA64); + __cpu_family[cpu] = "Loongson-64bit"; + pr_info("64-bit Loongson Processor probed (LA664 Core)\n"); + break; + default: /* Default to 64 bit */ + c->cputype = CPU_LOONGSON64; + set_isa(c, LOONGARCH_CPU_ISA_LA64); + __cpu_family[cpu] = "Loongson-64bit"; + pr_info("64-bit Loongson Processor probed (Unknown Core)\n"); + } +} + +#ifdef CONFIG_64BIT +/* For use by uaccess.h */ +u64 __ua_limit; +EXPORT_SYMBOL(__ua_limit); +#endif + +const char *__cpu_family[NR_CPUS]; +const char *__cpu_full_name[NR_CPUS]; +const char *__elf_platform; + +static void cpu_report(void) +{ + struct cpuinfo_loongarch *c = ¤t_cpu_data; + + pr_info("CPU%d revision is: %08x (%s)\n", + smp_processor_id(), c->processor_id, cpu_family_string()); + if (c->options & LOONGARCH_CPU_FPU) + pr_info("FPU%d revision is: %08x\n", smp_processor_id(), c->fpu_vers); +} + +void cpu_probe(void) +{ + unsigned int cpu = smp_processor_id(); + struct cpuinfo_loongarch *c = ¤t_cpu_data; + + /* + * Set a default ELF platform, cpu probe may later + * overwrite it with a more precise value + */ + set_elf_platform(cpu, "loongarch"); + + c->cputype = CPU_UNKNOWN; + c->processor_id = read_cpucfg(LOONGARCH_CPUCFG0); + c->fpu_vers = (read_cpucfg(LOONGARCH_CPUCFG2) >> 3) & 0x3; + + c->fpu_csr0 = FPU_CSR_RN; + c->fpu_mask = FPU_CSR_RSVD; + + cpu_probe_common(c); + + per_cpu_trap_init(cpu); + + switch (c->processor_id & PRID_COMP_MASK) { + case PRID_COMP_LOONGSON: + cpu_probe_loongson(c, cpu); + break; + } + + BUG_ON(!__cpu_family[cpu]); + BUG_ON(c->cputype == CPU_UNKNOWN); + + cpu_probe_addrbits(c); + +#ifdef CONFIG_64BIT + if (cpu == 0) + __ua_limit = ~((1ull << cpu_vabits) - 1); +#endif + + cpu_report(); +} diff --git a/arch/loongarch/kernel/dma.c b/arch/loongarch/kernel/dma.c new file mode 100644 index 000000000000..8c9b5314a13e --- /dev/null +++ b/arch/loongarch/kernel/dma.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/init.h> +#include <linux/dma-direct.h> +#include <linux/dma-mapping.h> +#include <linux/dma-map-ops.h> +#include <linux/swiotlb.h> + +#include <asm/bootinfo.h> +#include <asm/dma.h> +#include <asm/loongson.h> + +/* + * We extract 4bit node id (bit 44~47) from Loongson-3's + * 48bit physical address space and embed it into 40bit. + */ + +static int node_id_offset; + +dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) +{ + long nid = (paddr >> 44) & 0xf; + + return ((nid << 44) ^ paddr) | (nid << node_id_offset); +} + +phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) +{ + long nid = (daddr >> node_id_offset) & 0xf; + + return ((nid << node_id_offset) ^ daddr) | (nid << 44); +} + +void __init plat_swiotlb_setup(void) +{ + swiotlb_init(true, SWIOTLB_VERBOSE); + node_id_offset = ((readl(LS7A_DMA_CFG) & LS7A_DMA_NODE_MASK) >> LS7A_DMA_NODE_SHF) + 36; +} diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c new file mode 100644 index 000000000000..a50b60c587fa --- /dev/null +++ b/arch/loongarch/kernel/efi.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * EFI initialization + * + * Author: Jianmin Lv <lvjianmin@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <linux/acpi.h> +#include <linux/efi.h> +#include <linux/efi-bgrt.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/io.h> +#include <linux/kobject.h> +#include <linux/memblock.h> +#include <linux/reboot.h> +#include <linux/uaccess.h> + +#include <asm/early_ioremap.h> +#include <asm/efi.h> +#include <asm/loongson.h> + +static unsigned long efi_nr_tables; +static unsigned long efi_config_table; + +static efi_system_table_t *efi_systab; +static efi_config_table_type_t arch_tables[] __initdata = {{},}; + +void __init efi_runtime_init(void) +{ + if (!efi_enabled(EFI_BOOT)) + return; + + if (efi_runtime_disabled()) { + pr_info("EFI runtime services will be disabled.\n"); + return; + } + + efi.runtime = (efi_runtime_services_t *)efi_systab->runtime; + efi.runtime_version = (unsigned int)efi.runtime->hdr.revision; + + efi_native_runtime_setup(); + set_bit(EFI_RUNTIME_SERVICES, &efi.flags); +} + +void __init efi_init(void) +{ + int size; + void *config_tables; + + if (!efi_system_table) + return; + + efi_systab = (efi_system_table_t *)early_memremap_ro(efi_system_table, sizeof(*efi_systab)); + if (!efi_systab) { + pr_err("Can't find EFI system table.\n"); + return; + } + + set_bit(EFI_64BIT, &efi.flags); + efi_nr_tables = efi_systab->nr_tables; + efi_config_table = (unsigned long)efi_systab->tables; + + size = sizeof(efi_config_table_t); + config_tables = early_memremap(efi_config_table, efi_nr_tables * size); + efi_config_parse_tables(config_tables, efi_systab->nr_tables, arch_tables); + early_memunmap(config_tables, efi_nr_tables * size); +} diff --git a/arch/loongarch/kernel/elf.c b/arch/loongarch/kernel/elf.c new file mode 100644 index 000000000000..183e94fc9c69 --- /dev/null +++ b/arch/loongarch/kernel/elf.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <linux/binfmts.h> +#include <linux/elf.h> +#include <linux/export.h> +#include <linux/sched.h> + +#include <asm/cpu-features.h> +#include <asm/cpu-info.h> + +int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, + bool is_interp, struct arch_elf_state *state) +{ + return 0; +} + +int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr, + struct arch_elf_state *state) +{ + return 0; +} + +void loongarch_set_personality_fcsr(struct arch_elf_state *state) +{ + current->thread.fpu.fcsr = boot_cpu_data.fpu_csr0; +} diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S new file mode 100644 index 000000000000..d5b3dbcf5425 --- /dev/null +++ b/arch/loongarch/kernel/entry.S @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2001 MIPS Technologies, Inc. + */ + +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/loongarch.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> +#include <asm/thread_info.h> + + .text + .cfi_sections .debug_frame + .align 5 +SYM_FUNC_START(handle_syscall) + csrrd t0, PERCPU_BASE_KS + la.abs t1, kernelsp + add.d t1, t1, t0 + move t2, sp + ld.d sp, t1, 0 + + addi.d sp, sp, -PT_SIZE + cfi_st t2, PT_R3 + cfi_rel_offset sp, PT_R3 + st.d zero, sp, PT_R0 + csrrd t2, LOONGARCH_CSR_PRMD + st.d t2, sp, PT_PRMD + csrrd t2, LOONGARCH_CSR_CRMD + st.d t2, sp, PT_CRMD + csrrd t2, LOONGARCH_CSR_EUEN + st.d t2, sp, PT_EUEN + csrrd t2, LOONGARCH_CSR_ECFG + st.d t2, sp, PT_ECFG + csrrd t2, LOONGARCH_CSR_ESTAT + st.d t2, sp, PT_ESTAT + cfi_st ra, PT_R1 + cfi_st a0, PT_R4 + cfi_st a1, PT_R5 + cfi_st a2, PT_R6 + cfi_st a3, PT_R7 + cfi_st a4, PT_R8 + cfi_st a5, PT_R9 + cfi_st a6, PT_R10 + cfi_st a7, PT_R11 + csrrd ra, LOONGARCH_CSR_ERA + st.d ra, sp, PT_ERA + cfi_rel_offset ra, PT_ERA + + cfi_st tp, PT_R2 + cfi_st u0, PT_R21 + cfi_st fp, PT_R22 + + SAVE_STATIC + + move u0, t0 + li.d tp, ~_THREAD_MASK + and tp, tp, sp + + move a0, sp + bl do_syscall + + RESTORE_ALL_AND_RET +SYM_FUNC_END(handle_syscall) + +SYM_CODE_START(ret_from_fork) + bl schedule_tail # a0 = struct task_struct *prev + move a0, sp + bl syscall_exit_to_user_mode + RESTORE_STATIC + RESTORE_SOME + RESTORE_SP_AND_RET +SYM_CODE_END(ret_from_fork) + +SYM_CODE_START(ret_from_kernel_thread) + bl schedule_tail # a0 = struct task_struct *prev + move a0, s1 + jirl ra, s0, 0 + move a0, sp + bl syscall_exit_to_user_mode + RESTORE_STATIC + RESTORE_SOME + RESTORE_SP_AND_RET +SYM_CODE_END(ret_from_kernel_thread) diff --git a/arch/loongarch/kernel/env.c b/arch/loongarch/kernel/env.c new file mode 100644 index 000000000000..467946ecf451 --- /dev/null +++ b/arch/loongarch/kernel/env.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/acpi.h> +#include <linux/efi.h> +#include <linux/export.h> +#include <linux/memblock.h> +#include <linux/of_fdt.h> +#include <asm/early_ioremap.h> +#include <asm/bootinfo.h> +#include <asm/loongson.h> + +u64 efi_system_table; +struct loongson_system_configuration loongson_sysconf; +EXPORT_SYMBOL(loongson_sysconf); + +u64 loongson_chipcfg[MAX_PACKAGES]; +u64 loongson_chiptemp[MAX_PACKAGES]; +u64 loongson_freqctrl[MAX_PACKAGES]; +unsigned long long smp_group[MAX_PACKAGES]; + +static void __init register_addrs_set(u64 *registers, const u64 addr, int num) +{ + u64 i; + + for (i = 0; i < num; i++) { + *registers = (i << 44) | addr; + registers++; + } +} + +void __init init_environ(void) +{ + int efi_boot = fw_arg0; + struct efi_memory_map_data data; + void *fdt_ptr = early_memremap_ro(fw_arg1, SZ_64K); + + if (efi_boot) + set_bit(EFI_BOOT, &efi.flags); + else + clear_bit(EFI_BOOT, &efi.flags); + + early_init_dt_scan(fdt_ptr); + early_init_fdt_reserve_self(); + efi_system_table = efi_get_fdt_params(&data); + + efi_memmap_init_early(&data); + memblock_reserve(data.phys_map & PAGE_MASK, + PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK))); + + register_addrs_set(smp_group, TO_UNCACHE(0x1fe01000), 16); + register_addrs_set(loongson_chipcfg, TO_UNCACHE(0x1fe00180), 16); + register_addrs_set(loongson_chiptemp, TO_UNCACHE(0x1fe0019c), 16); + register_addrs_set(loongson_freqctrl, TO_UNCACHE(0x1fe001d0), 16); +} + +static int __init init_cpu_fullname(void) +{ + int cpu; + + if (loongson_sysconf.cpuname && !strncmp(loongson_sysconf.cpuname, "Loongson", 8)) { + for (cpu = 0; cpu < NR_CPUS; cpu++) + __cpu_full_name[cpu] = loongson_sysconf.cpuname; + } + return 0; +} +arch_initcall(init_cpu_fullname); + +static ssize_t boardinfo_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, + "BIOS Information\n" + "Vendor\t\t\t: %s\n" + "Version\t\t\t: %s\n" + "ROM Size\t\t: %d KB\n" + "Release Date\t\t: %s\n\n" + "Board Information\n" + "Manufacturer\t\t: %s\n" + "Board Name\t\t: %s\n" + "Family\t\t\t: LOONGSON64\n\n", + b_info.bios_vendor, b_info.bios_version, + b_info.bios_size, b_info.bios_release_date, + b_info.board_vendor, b_info.board_name); +} + +static struct kobj_attribute boardinfo_attr = __ATTR(boardinfo, 0444, + boardinfo_show, NULL); + +static int __init boardinfo_init(void) +{ + struct kobject *loongson_kobj; + + loongson_kobj = kobject_create_and_add("loongson", firmware_kobj); + + return sysfs_create_file(loongson_kobj, &boardinfo_attr.attr); +} +late_initcall(boardinfo_init); diff --git a/arch/loongarch/kernel/fpu.S b/arch/loongarch/kernel/fpu.S new file mode 100644 index 000000000000..75c6ce0682a2 --- /dev/null +++ b/arch/loongarch/kernel/fpu.S @@ -0,0 +1,261 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Lu Zeng <zenglu@loongson.cn> + * Pei Huang <huangpei@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/asm-offsets.h> +#include <asm/errno.h> +#include <asm/export.h> +#include <asm/fpregdef.h> +#include <asm/loongarch.h> +#include <asm/regdef.h> + +#define FPU_REG_WIDTH 8 +#define LSX_REG_WIDTH 16 +#define LASX_REG_WIDTH 32 + + .macro EX insn, reg, src, offs +.ex\@: \insn \reg, \src, \offs + .section __ex_table,"a" + PTR .ex\@, fault + .previous + .endm + + .macro sc_save_fp base + EX fst.d $f0, \base, (0 * FPU_REG_WIDTH) + EX fst.d $f1, \base, (1 * FPU_REG_WIDTH) + EX fst.d $f2, \base, (2 * FPU_REG_WIDTH) + EX fst.d $f3, \base, (3 * FPU_REG_WIDTH) + EX fst.d $f4, \base, (4 * FPU_REG_WIDTH) + EX fst.d $f5, \base, (5 * FPU_REG_WIDTH) + EX fst.d $f6, \base, (6 * FPU_REG_WIDTH) + EX fst.d $f7, \base, (7 * FPU_REG_WIDTH) + EX fst.d $f8, \base, (8 * FPU_REG_WIDTH) + EX fst.d $f9, \base, (9 * FPU_REG_WIDTH) + EX fst.d $f10, \base, (10 * FPU_REG_WIDTH) + EX fst.d $f11, \base, (11 * FPU_REG_WIDTH) + EX fst.d $f12, \base, (12 * FPU_REG_WIDTH) + EX fst.d $f13, \base, (13 * FPU_REG_WIDTH) + EX fst.d $f14, \base, (14 * FPU_REG_WIDTH) + EX fst.d $f15, \base, (15 * FPU_REG_WIDTH) + EX fst.d $f16, \base, (16 * FPU_REG_WIDTH) + EX fst.d $f17, \base, (17 * FPU_REG_WIDTH) + EX fst.d $f18, \base, (18 * FPU_REG_WIDTH) + EX fst.d $f19, \base, (19 * FPU_REG_WIDTH) + EX fst.d $f20, \base, (20 * FPU_REG_WIDTH) + EX fst.d $f21, \base, (21 * FPU_REG_WIDTH) + EX fst.d $f22, \base, (22 * FPU_REG_WIDTH) + EX fst.d $f23, \base, (23 * FPU_REG_WIDTH) + EX fst.d $f24, \base, (24 * FPU_REG_WIDTH) + EX fst.d $f25, \base, (25 * FPU_REG_WIDTH) + EX fst.d $f26, \base, (26 * FPU_REG_WIDTH) + EX fst.d $f27, \base, (27 * FPU_REG_WIDTH) + EX fst.d $f28, \base, (28 * FPU_REG_WIDTH) + EX fst.d $f29, \base, (29 * FPU_REG_WIDTH) + EX fst.d $f30, \base, (30 * FPU_REG_WIDTH) + EX fst.d $f31, \base, (31 * FPU_REG_WIDTH) + .endm + + .macro sc_restore_fp base + EX fld.d $f0, \base, (0 * FPU_REG_WIDTH) + EX fld.d $f1, \base, (1 * FPU_REG_WIDTH) + EX fld.d $f2, \base, (2 * FPU_REG_WIDTH) + EX fld.d $f3, \base, (3 * FPU_REG_WIDTH) + EX fld.d $f4, \base, (4 * FPU_REG_WIDTH) + EX fld.d $f5, \base, (5 * FPU_REG_WIDTH) + EX fld.d $f6, \base, (6 * FPU_REG_WIDTH) + EX fld.d $f7, \base, (7 * FPU_REG_WIDTH) + EX fld.d $f8, \base, (8 * FPU_REG_WIDTH) + EX fld.d $f9, \base, (9 * FPU_REG_WIDTH) + EX fld.d $f10, \base, (10 * FPU_REG_WIDTH) + EX fld.d $f11, \base, (11 * FPU_REG_WIDTH) + EX fld.d $f12, \base, (12 * FPU_REG_WIDTH) + EX fld.d $f13, \base, (13 * FPU_REG_WIDTH) + EX fld.d $f14, \base, (14 * FPU_REG_WIDTH) + EX fld.d $f15, \base, (15 * FPU_REG_WIDTH) + EX fld.d $f16, \base, (16 * FPU_REG_WIDTH) + EX fld.d $f17, \base, (17 * FPU_REG_WIDTH) + EX fld.d $f18, \base, (18 * FPU_REG_WIDTH) + EX fld.d $f19, \base, (19 * FPU_REG_WIDTH) + EX fld.d $f20, \base, (20 * FPU_REG_WIDTH) + EX fld.d $f21, \base, (21 * FPU_REG_WIDTH) + EX fld.d $f22, \base, (22 * FPU_REG_WIDTH) + EX fld.d $f23, \base, (23 * FPU_REG_WIDTH) + EX fld.d $f24, \base, (24 * FPU_REG_WIDTH) + EX fld.d $f25, \base, (25 * FPU_REG_WIDTH) + EX fld.d $f26, \base, (26 * FPU_REG_WIDTH) + EX fld.d $f27, \base, (27 * FPU_REG_WIDTH) + EX fld.d $f28, \base, (28 * FPU_REG_WIDTH) + EX fld.d $f29, \base, (29 * FPU_REG_WIDTH) + EX fld.d $f30, \base, (30 * FPU_REG_WIDTH) + EX fld.d $f31, \base, (31 * FPU_REG_WIDTH) + .endm + + .macro sc_save_fcc base, tmp0, tmp1 + movcf2gr \tmp0, $fcc0 + move \tmp1, \tmp0 + movcf2gr \tmp0, $fcc1 + bstrins.d \tmp1, \tmp0, 15, 8 + movcf2gr \tmp0, $fcc2 + bstrins.d \tmp1, \tmp0, 23, 16 + movcf2gr \tmp0, $fcc3 + bstrins.d \tmp1, \tmp0, 31, 24 + movcf2gr \tmp0, $fcc4 + bstrins.d \tmp1, \tmp0, 39, 32 + movcf2gr \tmp0, $fcc5 + bstrins.d \tmp1, \tmp0, 47, 40 + movcf2gr \tmp0, $fcc6 + bstrins.d \tmp1, \tmp0, 55, 48 + movcf2gr \tmp0, $fcc7 + bstrins.d \tmp1, \tmp0, 63, 56 + EX st.d \tmp1, \base, 0 + .endm + + .macro sc_restore_fcc base, tmp0, tmp1 + EX ld.d \tmp0, \base, 0 + bstrpick.d \tmp1, \tmp0, 7, 0 + movgr2cf $fcc0, \tmp1 + bstrpick.d \tmp1, \tmp0, 15, 8 + movgr2cf $fcc1, \tmp1 + bstrpick.d \tmp1, \tmp0, 23, 16 + movgr2cf $fcc2, \tmp1 + bstrpick.d \tmp1, \tmp0, 31, 24 + movgr2cf $fcc3, \tmp1 + bstrpick.d \tmp1, \tmp0, 39, 32 + movgr2cf $fcc4, \tmp1 + bstrpick.d \tmp1, \tmp0, 47, 40 + movgr2cf $fcc5, \tmp1 + bstrpick.d \tmp1, \tmp0, 55, 48 + movgr2cf $fcc6, \tmp1 + bstrpick.d \tmp1, \tmp0, 63, 56 + movgr2cf $fcc7, \tmp1 + .endm + + .macro sc_save_fcsr base, tmp0 + movfcsr2gr \tmp0, fcsr0 + EX st.w \tmp0, \base, 0 + .endm + + .macro sc_restore_fcsr base, tmp0 + EX ld.w \tmp0, \base, 0 + movgr2fcsr fcsr0, \tmp0 + .endm + + .macro sc_save_vcsr base, tmp0 + movfcsr2gr \tmp0, vcsr16 + EX st.w \tmp0, \base, 0 + .endm + + .macro sc_restore_vcsr base, tmp0 + EX ld.w \tmp0, \base, 0 + movgr2fcsr vcsr16, \tmp0 + .endm + +/* + * Save a thread's fp context. + */ +SYM_FUNC_START(_save_fp) + fpu_save_csr a0 t1 + fpu_save_double a0 t1 # clobbers t1 + fpu_save_cc a0 t1 t2 # clobbers t1, t2 + jirl zero, ra, 0 +SYM_FUNC_END(_save_fp) +EXPORT_SYMBOL(_save_fp) + +/* + * Restore a thread's fp context. + */ +SYM_FUNC_START(_restore_fp) + fpu_restore_double a0 t1 # clobbers t1 + fpu_restore_csr a0 t1 + fpu_restore_cc a0 t1 t2 # clobbers t1, t2 + jirl zero, ra, 0 +SYM_FUNC_END(_restore_fp) + +/* + * Load the FPU with signalling NANS. This bit pattern we're using has + * the property that no matter whether considered as single or as double + * precision represents signaling NANS. + * + * The value to initialize fcsr0 to comes in $a0. + */ + +SYM_FUNC_START(_init_fpu) + li.w t1, CSR_EUEN_FPEN + csrxchg t1, t1, LOONGARCH_CSR_EUEN + + movgr2fcsr fcsr0, a0 + + li.w t1, -1 # SNaN + + movgr2fr.d $f0, t1 + movgr2fr.d $f1, t1 + movgr2fr.d $f2, t1 + movgr2fr.d $f3, t1 + movgr2fr.d $f4, t1 + movgr2fr.d $f5, t1 + movgr2fr.d $f6, t1 + movgr2fr.d $f7, t1 + movgr2fr.d $f8, t1 + movgr2fr.d $f9, t1 + movgr2fr.d $f10, t1 + movgr2fr.d $f11, t1 + movgr2fr.d $f12, t1 + movgr2fr.d $f13, t1 + movgr2fr.d $f14, t1 + movgr2fr.d $f15, t1 + movgr2fr.d $f16, t1 + movgr2fr.d $f17, t1 + movgr2fr.d $f18, t1 + movgr2fr.d $f19, t1 + movgr2fr.d $f20, t1 + movgr2fr.d $f21, t1 + movgr2fr.d $f22, t1 + movgr2fr.d $f23, t1 + movgr2fr.d $f24, t1 + movgr2fr.d $f25, t1 + movgr2fr.d $f26, t1 + movgr2fr.d $f27, t1 + movgr2fr.d $f28, t1 + movgr2fr.d $f29, t1 + movgr2fr.d $f30, t1 + movgr2fr.d $f31, t1 + + jirl zero, ra, 0 +SYM_FUNC_END(_init_fpu) + +/* + * a0: fpregs + * a1: fcc + * a2: fcsr + */ +SYM_FUNC_START(_save_fp_context) + sc_save_fcc a1 t1 t2 + sc_save_fcsr a2 t1 + sc_save_fp a0 + li.w a0, 0 # success + jirl zero, ra, 0 +SYM_FUNC_END(_save_fp_context) + +/* + * a0: fpregs + * a1: fcc + * a2: fcsr + */ +SYM_FUNC_START(_restore_fp_context) + sc_restore_fp a0 + sc_restore_fcc a1 t1 t2 + sc_restore_fcsr a2 t1 + li.w a0, 0 # success + jirl zero, ra, 0 +SYM_FUNC_END(_restore_fp_context) + +SYM_FUNC_START(fault) + li.w a0, -EFAULT # failure + jirl zero, ra, 0 +SYM_FUNC_END(fault) diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S new file mode 100644 index 000000000000..93496852b3cc --- /dev/null +++ b/arch/loongarch/kernel/genex.S @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2002, 2007 Maciej W. Rozycki + * Copyright (C) 2001, 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/loongarch.h> +#include <asm/regdef.h> +#include <asm/fpregdef.h> +#include <asm/stackframe.h> +#include <asm/thread_info.h> + + .align 5 +SYM_FUNC_START(__arch_cpu_idle) + /* start of rollback region */ + LONG_L t0, tp, TI_FLAGS + nop + andi t0, t0, _TIF_NEED_RESCHED + bnez t0, 1f + nop + nop + nop + idle 0 + /* end of rollback region */ +1: jirl zero, ra, 0 +SYM_FUNC_END(__arch_cpu_idle) + +SYM_FUNC_START(handle_vint) + BACKUP_T0T1 + SAVE_ALL + la.abs t1, __arch_cpu_idle + LONG_L t0, sp, PT_ERA + /* 32 byte rollback region */ + ori t0, t0, 0x1f + xori t0, t0, 0x1f + bne t0, t1, 1f + LONG_S t0, sp, PT_ERA +1: move a0, sp + move a1, sp + la.abs t0, do_vint + jirl ra, t0, 0 + RESTORE_ALL_AND_RET +SYM_FUNC_END(handle_vint) + +SYM_FUNC_START(except_vec_cex) + b cache_parity_error +SYM_FUNC_END(except_vec_cex) + + .macro build_prep_badv + csrrd t0, LOONGARCH_CSR_BADV + PTR_S t0, sp, PT_BVADDR + .endm + + .macro build_prep_fcsr + movfcsr2gr a1, fcsr0 + .endm + + .macro build_prep_none + .endm + + .macro BUILD_HANDLER exception handler prep + .align 5 + SYM_FUNC_START(handle_\exception) + BACKUP_T0T1 + SAVE_ALL + build_prep_\prep + move a0, sp + la.abs t0, do_\handler + jirl ra, t0, 0 + RESTORE_ALL_AND_RET + SYM_FUNC_END(handle_\exception) + .endm + + BUILD_HANDLER ade ade badv + BUILD_HANDLER ale ale badv + BUILD_HANDLER bp bp none + BUILD_HANDLER fpe fpe fcsr + BUILD_HANDLER fpu fpu none + BUILD_HANDLER lsx lsx none + BUILD_HANDLER lasx lasx none + BUILD_HANDLER lbt lbt none + BUILD_HANDLER ri ri none + BUILD_HANDLER watch watch none + BUILD_HANDLER reserved reserved none /* others */ + +SYM_FUNC_START(handle_sys) + la.abs t0, handle_syscall + jirl zero, t0, 0 +SYM_FUNC_END(handle_sys) diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S new file mode 100644 index 000000000000..e596dfcd924b --- /dev/null +++ b/arch/loongarch/kernel/head.S @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/init.h> +#include <linux/threads.h> + +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/regdef.h> +#include <asm/loongarch.h> +#include <asm/stackframe.h> + + __REF + +SYM_ENTRY(_stext, SYM_L_GLOBAL, SYM_A_NONE) + +SYM_CODE_START(kernel_entry) # kernel entry point + + /* Config direct window and set PG */ + li.d t0, CSR_DMW0_INIT # UC, PLV0, 0x8000 xxxx xxxx xxxx + csrwr t0, LOONGARCH_CSR_DMWIN0 + li.d t0, CSR_DMW1_INIT # CA, PLV0, 0x9000 xxxx xxxx xxxx + csrwr t0, LOONGARCH_CSR_DMWIN1 + /* Enable PG */ + li.w t0, 0xb0 # PLV=0, IE=0, PG=1 + csrwr t0, LOONGARCH_CSR_CRMD + li.w t0, 0x04 # PLV=0, PIE=1, PWE=0 + csrwr t0, LOONGARCH_CSR_PRMD + li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0 + csrwr t0, LOONGARCH_CSR_EUEN + + /* We might not get launched at the address the kernel is linked to, + so we jump there. */ + la.abs t0, 0f + jirl zero, t0, 0 +0: + la t0, __bss_start # clear .bss + st.d zero, t0, 0 + la t1, __bss_stop - LONGSIZE +1: + addi.d t0, t0, LONGSIZE + st.d zero, t0, 0 + bne t0, t1, 1b + + la t0, fw_arg0 + st.d a0, t0, 0 # firmware arguments + la t0, fw_arg1 + st.d a1, t0, 0 + + /* KSave3 used for percpu base, initialized as 0 */ + csrwr zero, PERCPU_BASE_KS + /* GPR21 used for percpu base (runtime), initialized as 0 */ + or u0, zero, zero + + la tp, init_thread_union + /* Set the SP after an empty pt_regs. */ + PTR_LI sp, (_THREAD_SIZE - 32 - PT_SIZE) + PTR_ADD sp, sp, tp + set_saved_sp sp, t0, t1 + PTR_ADDI sp, sp, -4 * SZREG # init stack pointer + + bl start_kernel + +SYM_CODE_END(kernel_entry) + +#ifdef CONFIG_SMP + +/* + * SMP slave cpus entry point. Board specific code for bootstrap calls this + * function after setting up the stack and tp registers. + */ +SYM_CODE_START(smpboot_entry) + li.d t0, CSR_DMW0_INIT # UC, PLV0 + csrwr t0, LOONGARCH_CSR_DMWIN0 + li.d t0, CSR_DMW1_INIT # CA, PLV0 + csrwr t0, LOONGARCH_CSR_DMWIN1 + li.w t0, 0xb0 # PLV=0, IE=0, PG=1 + csrwr t0, LOONGARCH_CSR_CRMD + li.w t0, 0x04 # PLV=0, PIE=1, PWE=0 + csrwr t0, LOONGARCH_CSR_PRMD + li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0 + csrwr t0, LOONGARCH_CSR_EUEN + + la.abs t0, cpuboot_data + ld.d sp, t0, CPU_BOOT_STACK + ld.d tp, t0, CPU_BOOT_TINFO + + la.abs t0, 0f + jirl zero, t0, 0 +0: + bl start_secondary +SYM_CODE_END(smpboot_entry) + +#endif /* CONFIG_SMP */ + +SYM_ENTRY(kernel_entry_end, SYM_L_GLOBAL, SYM_A_NONE) diff --git a/arch/loongarch/kernel/idle.c b/arch/loongarch/kernel/idle.c new file mode 100644 index 000000000000..1a65d0527d25 --- /dev/null +++ b/arch/loongarch/kernel/idle.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LoongArch idle loop support. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/cpu.h> +#include <linux/irqflags.h> +#include <asm/cpu.h> +#include <asm/idle.h> + +void __cpuidle arch_cpu_idle(void) +{ + raw_local_irq_enable(); + __arch_cpu_idle(); /* idle instruction needs irq enabled */ +} diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c new file mode 100644 index 000000000000..b1df0ec34bd1 --- /dev/null +++ b/arch/loongarch/kernel/inst.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <asm/inst.h> + +u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm) +{ + union loongarch_instruction insn; + + insn.reg1i20_format.opcode = lu32id_op; + insn.reg1i20_format.rd = rd; + insn.reg1i20_format.immediate = imm; + + return insn.word; +} + +u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm) +{ + union loongarch_instruction insn; + + insn.reg2i12_format.opcode = lu52id_op; + insn.reg2i12_format.rd = rd; + insn.reg2i12_format.rj = rj; + insn.reg2i12_format.immediate = imm; + + return insn.word; +} + +u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest) +{ + union loongarch_instruction insn; + + insn.reg2i16_format.opcode = jirl_op; + insn.reg2i16_format.rd = rd; + insn.reg2i16_format.rj = rj; + insn.reg2i16_format.immediate = (dest - pc) >> 2; + + return insn.word; +} diff --git a/arch/loongarch/kernel/io.c b/arch/loongarch/kernel/io.c new file mode 100644 index 000000000000..cb85bda5a6ad --- /dev/null +++ b/arch/loongarch/kernel/io.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/export.h> +#include <linux/types.h> +#include <linux/io.h> + +/* + * Copy data from IO memory space to "real" memory space. + */ +void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) +{ + while (count && !IS_ALIGNED((unsigned long)from, 8)) { + *(u8 *)to = __raw_readb(from); + from++; + to++; + count--; + } + + while (count >= 8) { + *(u64 *)to = __raw_readq(from); + from += 8; + to += 8; + count -= 8; + } + + while (count) { + *(u8 *)to = __raw_readb(from); + from++; + to++; + count--; + } +} +EXPORT_SYMBOL(__memcpy_fromio); + +/* + * Copy data from "real" memory space to IO memory space. + */ +void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) +{ + while (count && !IS_ALIGNED((unsigned long)to, 8)) { + __raw_writeb(*(u8 *)from, to); + from++; + to++; + count--; + } + + while (count >= 8) { + __raw_writeq(*(u64 *)from, to); + from += 8; + to += 8; + count -= 8; + } + + while (count) { + __raw_writeb(*(u8 *)from, to); + from++; + to++; + count--; + } +} +EXPORT_SYMBOL(__memcpy_toio); + +/* + * "memset" on IO memory space. + */ +void __memset_io(volatile void __iomem *dst, int c, size_t count) +{ + u64 qc = (u8)c; + + qc |= qc << 8; + qc |= qc << 16; + qc |= qc << 32; + + while (count && !IS_ALIGNED((unsigned long)dst, 8)) { + __raw_writeb(c, dst); + dst++; + count--; + } + + while (count >= 8) { + __raw_writeq(qc, dst); + dst += 8; + count -= 8; + } + + while (count) { + __raw_writeb(c, dst); + dst++; + count--; + } +} +EXPORT_SYMBOL(__memset_io); diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c new file mode 100644 index 000000000000..4b671d305ede --- /dev/null +++ b/arch/loongarch/kernel/irq.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/kernel.h> +#include <linux/acpi.h> +#include <linux/atomic.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irqchip.h> +#include <linux/kernel_stat.h> +#include <linux/proc_fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/kallsyms.h> +#include <linux/uaccess.h> + +#include <asm/irq.h> +#include <asm/loongson.h> +#include <asm/setup.h> + +DEFINE_PER_CPU(unsigned long, irq_stack); + +struct irq_domain *cpu_domain; +struct irq_domain *liointc_domain; +struct irq_domain *pch_lpc_domain; +struct irq_domain *pch_msi_domain[MAX_IO_PICS]; +struct irq_domain *pch_pic_domain[MAX_IO_PICS]; + +/* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves. + */ +void ack_bad_irq(unsigned int irq) +{ + pr_warn("Unexpected IRQ # %d\n", irq); +} + +atomic_t irq_err_count; + +asmlinkage void spurious_interrupt(void) +{ + atomic_inc(&irq_err_count); +} + +int arch_show_interrupts(struct seq_file *p, int prec) +{ +#ifdef CONFIG_SMP + show_ipi_list(p, prec); +#endif + seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); + return 0; +} + +void __init init_IRQ(void) +{ + int i, r, ipi_irq; + static int ipi_dummy_dev; + unsigned int order = get_order(IRQ_STACK_SIZE); + struct page *page; + + clear_csr_ecfg(ECFG0_IM); + clear_csr_estat(ESTATF_IP); + + irqchip_init(); +#ifdef CONFIG_SMP + ipi_irq = EXCCODE_IPI - EXCCODE_INT_START; + irq_set_percpu_devid(ipi_irq); + r = request_percpu_irq(ipi_irq, loongson3_ipi_interrupt, "IPI", &ipi_dummy_dev); + if (r < 0) + panic("IPI IRQ request failed\n"); +#endif + + for (i = 0; i < NR_IRQS; i++) + irq_set_noprobe(i); + + for_each_possible_cpu(i) { + page = alloc_pages_node(cpu_to_node(i), GFP_KERNEL, order); + + per_cpu(irq_stack, i) = (unsigned long)page_address(page); + pr_debug("CPU%d IRQ stack at 0x%lx - 0x%lx\n", i, + per_cpu(irq_stack, i), per_cpu(irq_stack, i) + IRQ_STACK_SIZE); + } + + set_csr_ecfg(ECFGF_IP0 | ECFGF_IP1 | ECFGF_IP2 | ECFGF_IPI | ECFGF_PMC); +} diff --git a/arch/loongarch/kernel/mem.c b/arch/loongarch/kernel/mem.c new file mode 100644 index 000000000000..7423361b0ebc --- /dev/null +++ b/arch/loongarch/kernel/mem.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/efi.h> +#include <linux/initrd.h> +#include <linux/memblock.h> + +#include <asm/bootinfo.h> +#include <asm/loongson.h> +#include <asm/sections.h> + +void __init memblock_init(void) +{ + u32 mem_type; + u64 mem_start, mem_end, mem_size; + efi_memory_desc_t *md; + + /* Parse memory information */ + for_each_efi_memory_desc(md) { + mem_type = md->type; + mem_start = md->phys_addr; + mem_size = md->num_pages << EFI_PAGE_SHIFT; + mem_end = mem_start + mem_size; + + switch (mem_type) { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_PERSISTENT_MEMORY: + case EFI_CONVENTIONAL_MEMORY: + memblock_add(mem_start, mem_size); + if (max_low_pfn < (mem_end >> PAGE_SHIFT)) + max_low_pfn = mem_end >> PAGE_SHIFT; + break; + case EFI_PAL_CODE: + case EFI_UNUSABLE_MEMORY: + case EFI_ACPI_RECLAIM_MEMORY: + memblock_add(mem_start, mem_size); + fallthrough; + case EFI_RESERVED_TYPE: + case EFI_RUNTIME_SERVICES_CODE: + case EFI_RUNTIME_SERVICES_DATA: + case EFI_MEMORY_MAPPED_IO: + case EFI_MEMORY_MAPPED_IO_PORT_SPACE: + memblock_reserve(mem_start, mem_size); + break; + } + } + + memblock_set_current_limit(PFN_PHYS(max_low_pfn)); + memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0); + + /* Reserve the first 2MB */ + memblock_reserve(PHYS_OFFSET, 0x200000); + + /* Reserve the kernel text/data/bss */ + memblock_reserve(__pa_symbol(&_text), + __pa_symbol(&_end) - __pa_symbol(&_text)); + + /* Reserve the initrd */ + reserve_initrd_mem(); +} diff --git a/arch/loongarch/kernel/module-sections.c b/arch/loongarch/kernel/module-sections.c new file mode 100644 index 000000000000..6d498288977d --- /dev/null +++ b/arch/loongarch/kernel/module-sections.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <linux/elf.h> +#include <linux/kernel.h> +#include <linux/module.h> + +Elf_Addr module_emit_plt_entry(struct module *mod, unsigned long val) +{ + int nr; + struct mod_section *plt_sec = &mod->arch.plt; + struct mod_section *plt_idx_sec = &mod->arch.plt_idx; + struct plt_entry *plt = get_plt_entry(val, plt_sec, plt_idx_sec); + struct plt_idx_entry *plt_idx; + + if (plt) + return (Elf_Addr)plt; + + nr = plt_sec->num_entries; + + /* There is no duplicate entry, create a new one */ + plt = (struct plt_entry *)plt_sec->shdr->sh_addr; + plt[nr] = emit_plt_entry(val); + plt_idx = (struct plt_idx_entry *)plt_idx_sec->shdr->sh_addr; + plt_idx[nr] = emit_plt_idx_entry(val); + + plt_sec->num_entries++; + plt_idx_sec->num_entries++; + BUG_ON(plt_sec->num_entries > plt_sec->max_entries); + + return (Elf_Addr)&plt[nr]; +} + +static int is_rela_equal(const Elf_Rela *x, const Elf_Rela *y) +{ + return x->r_info == y->r_info && x->r_addend == y->r_addend; +} + +static bool duplicate_rela(const Elf_Rela *rela, int idx) +{ + int i; + + for (i = 0; i < idx; i++) { + if (is_rela_equal(&rela[i], &rela[idx])) + return true; + } + + return false; +} + +static void count_max_entries(Elf_Rela *relas, int num, unsigned int *plts) +{ + unsigned int i, type; + + for (i = 0; i < num; i++) { + type = ELF_R_TYPE(relas[i].r_info); + if (type == R_LARCH_SOP_PUSH_PLT_PCREL) { + if (!duplicate_rela(relas, i)) + (*plts)++; + } + } +} + +int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) +{ + unsigned int i, num_plts = 0; + + /* + * Find the empty .plt sections. + */ + for (i = 0; i < ehdr->e_shnum; i++) { + if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt")) + mod->arch.plt.shdr = sechdrs + i; + else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt.idx")) + mod->arch.plt_idx.shdr = sechdrs + i; + } + + if (!mod->arch.plt.shdr) { + pr_err("%s: module PLT section(s) missing\n", mod->name); + return -ENOEXEC; + } + if (!mod->arch.plt_idx.shdr) { + pr_err("%s: module PLT.IDX section(s) missing\n", mod->name); + return -ENOEXEC; + } + + /* Calculate the maxinum number of entries */ + for (i = 0; i < ehdr->e_shnum; i++) { + int num_rela = sechdrs[i].sh_size / sizeof(Elf_Rela); + Elf_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset; + Elf_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info; + + if (sechdrs[i].sh_type != SHT_RELA) + continue; + + /* ignore relocations that operate on non-exec sections */ + if (!(dst_sec->sh_flags & SHF_EXECINSTR)) + continue; + + count_max_entries(relas, num_rela, &num_plts); + } + + mod->arch.plt.shdr->sh_type = SHT_NOBITS; + mod->arch.plt.shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC; + mod->arch.plt.shdr->sh_addralign = L1_CACHE_BYTES; + mod->arch.plt.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_entry); + mod->arch.plt.num_entries = 0; + mod->arch.plt.max_entries = num_plts; + + mod->arch.plt_idx.shdr->sh_type = SHT_NOBITS; + mod->arch.plt_idx.shdr->sh_flags = SHF_ALLOC; + mod->arch.plt_idx.shdr->sh_addralign = L1_CACHE_BYTES; + mod->arch.plt_idx.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_idx_entry); + mod->arch.plt_idx.num_entries = 0; + mod->arch.plt_idx.max_entries = num_plts; + + return 0; +} diff --git a/arch/loongarch/kernel/module.c b/arch/loongarch/kernel/module.c new file mode 100644 index 000000000000..638427ff0d51 --- /dev/null +++ b/arch/loongarch/kernel/module.c @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#define pr_fmt(fmt) "kmod: " fmt + +#include <linux/moduleloader.h> +#include <linux/elf.h> +#include <linux/mm.h> +#include <linux/numa.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> + +static inline bool signed_imm_check(long val, unsigned int bit) +{ + return -(1L << (bit - 1)) <= val && val < (1L << (bit - 1)); +} + +static inline bool unsigned_imm_check(unsigned long val, unsigned int bit) +{ + return val < (1UL << bit); +} + +static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top) +{ + if (*rela_stack_top >= RELA_STACK_DEPTH) + return -ENOEXEC; + + rela_stack[(*rela_stack_top)++] = stack_value; + pr_debug("%s stack_value = 0x%llx\n", __func__, stack_value); + + return 0; +} + +static int rela_stack_pop(s64 *stack_value, s64 *rela_stack, size_t *rela_stack_top) +{ + if (*rela_stack_top == 0) + return -ENOEXEC; + + *stack_value = rela_stack[--(*rela_stack_top)]; + pr_debug("%s stack_value = 0x%llx\n", __func__, *stack_value); + + return 0; +} + +static int apply_r_larch_none(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + return 0; +} + +static int apply_r_larch_error(struct module *me, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + pr_err("%s: Unsupport relocation type %u, please add its support.\n", me->name, type); + return -EINVAL; +} + +static int apply_r_larch_32(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + *location = v; + return 0; +} + +static int apply_r_larch_64(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + *(Elf_Addr *)location = v; + return 0; +} + +static int apply_r_larch_sop_push_pcrel(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + return rela_stack_push(v - (u64)location, rela_stack, rela_stack_top); +} + +static int apply_r_larch_sop_push_absolute(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + return rela_stack_push(v, rela_stack, rela_stack_top); +} + +static int apply_r_larch_sop_push_dup(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + int err = 0; + s64 opr1; + + err = rela_stack_pop(&opr1, rela_stack, rela_stack_top); + if (err) + return err; + err = rela_stack_push(opr1, rela_stack, rela_stack_top); + if (err) + return err; + err = rela_stack_push(opr1, rela_stack, rela_stack_top); + if (err) + return err; + + return 0; +} + +static int apply_r_larch_sop_push_plt_pcrel(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + ptrdiff_t offset = (void *)v - (void *)location; + + if (offset >= SZ_128M) + v = module_emit_plt_entry(mod, v); + + if (offset < -SZ_128M) + v = module_emit_plt_entry(mod, v); + + return apply_r_larch_sop_push_pcrel(mod, location, v, rela_stack, rela_stack_top, type); +} + +static int apply_r_larch_sop(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + int err = 0; + s64 opr1, opr2, opr3; + + if (type == R_LARCH_SOP_IF_ELSE) { + err = rela_stack_pop(&opr3, rela_stack, rela_stack_top); + if (err) + return err; + } + + err = rela_stack_pop(&opr2, rela_stack, rela_stack_top); + if (err) + return err; + err = rela_stack_pop(&opr1, rela_stack, rela_stack_top); + if (err) + return err; + + switch (type) { + case R_LARCH_SOP_AND: + err = rela_stack_push(opr1 & opr2, rela_stack, rela_stack_top); + break; + case R_LARCH_SOP_ADD: + err = rela_stack_push(opr1 + opr2, rela_stack, rela_stack_top); + break; + case R_LARCH_SOP_SUB: + err = rela_stack_push(opr1 - opr2, rela_stack, rela_stack_top); + break; + case R_LARCH_SOP_SL: + err = rela_stack_push(opr1 << opr2, rela_stack, rela_stack_top); + break; + case R_LARCH_SOP_SR: + err = rela_stack_push(opr1 >> opr2, rela_stack, rela_stack_top); + break; + case R_LARCH_SOP_IF_ELSE: + err = rela_stack_push(opr1 ? opr2 : opr3, rela_stack, rela_stack_top); + break; + default: + pr_err("%s: Unsupport relocation type %u\n", mod->name, type); + return -EINVAL; + } + + return err; +} + +static int apply_r_larch_sop_imm_field(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + int err = 0; + s64 opr1; + union loongarch_instruction *insn = (union loongarch_instruction *)location; + + err = rela_stack_pop(&opr1, rela_stack, rela_stack_top); + if (err) + return err; + + switch (type) { + case R_LARCH_SOP_POP_32_U_10_12: + if (!unsigned_imm_check(opr1, 12)) + goto overflow; + + /* (*(uint32_t *) PC) [21 ... 10] = opr [11 ... 0] */ + insn->reg2i12_format.immediate = opr1 & 0xfff; + return 0; + case R_LARCH_SOP_POP_32_S_10_12: + if (!signed_imm_check(opr1, 12)) + goto overflow; + + insn->reg2i12_format.immediate = opr1 & 0xfff; + return 0; + case R_LARCH_SOP_POP_32_S_10_16: + if (!signed_imm_check(opr1, 16)) + goto overflow; + + insn->reg2i16_format.immediate = opr1 & 0xffff; + return 0; + case R_LARCH_SOP_POP_32_S_10_16_S2: + if (opr1 % 4) + goto unaligned; + + if (!signed_imm_check(opr1, 18)) + goto overflow; + + insn->reg2i16_format.immediate = (opr1 >> 2) & 0xffff; + return 0; + case R_LARCH_SOP_POP_32_S_5_20: + if (!signed_imm_check(opr1, 20)) + goto overflow; + + insn->reg1i20_format.immediate = (opr1) & 0xfffff; + return 0; + case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: + if (opr1 % 4) + goto unaligned; + + if (!signed_imm_check(opr1, 23)) + goto overflow; + + opr1 >>= 2; + insn->reg1i21_format.immediate_l = opr1 & 0xffff; + insn->reg1i21_format.immediate_h = (opr1 >> 16) & 0x1f; + return 0; + case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: + if (opr1 % 4) + goto unaligned; + + if (!signed_imm_check(opr1, 28)) + goto overflow; + + opr1 >>= 2; + insn->reg0i26_format.immediate_l = opr1 & 0xffff; + insn->reg0i26_format.immediate_h = (opr1 >> 16) & 0x3ff; + return 0; + case R_LARCH_SOP_POP_32_U: + if (!unsigned_imm_check(opr1, 32)) + goto overflow; + + /* (*(uint32_t *) PC) = opr */ + *location = (u32)opr1; + return 0; + default: + pr_err("%s: Unsupport relocation type %u\n", mod->name, type); + return -EINVAL; + } + +overflow: + pr_err("module %s: opr1 = 0x%llx overflow! dangerous %s (%u) relocation\n", + mod->name, opr1, __func__, type); + return -ENOEXEC; + +unaligned: + pr_err("module %s: opr1 = 0x%llx unaligned! dangerous %s (%u) relocation\n", + mod->name, opr1, __func__, type); + return -ENOEXEC; +} + +static int apply_r_larch_add_sub(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type) +{ + switch (type) { + case R_LARCH_ADD32: + *(s32 *)location += v; + return 0; + case R_LARCH_ADD64: + *(s64 *)location += v; + return 0; + case R_LARCH_SUB32: + *(s32 *)location -= v; + return 0; + case R_LARCH_SUB64: + *(s64 *)location -= v; + return 0; + default: + pr_err("%s: Unsupport relocation type %u\n", mod->name, type); + return -EINVAL; + } +} + +/* + * reloc_handlers_rela() - Apply a particular relocation to a module + * @mod: the module to apply the reloc to + * @location: the address at which the reloc is to be applied + * @v: the value of the reloc, with addend for RELA-style + * @rela_stack: the stack used for store relocation info, LOCAL to THIS module + * @rela_stac_top: where the stack operation(pop/push) applies to + * + * Return: 0 upon success, else -ERRNO + */ +typedef int (*reloc_rela_handler)(struct module *mod, u32 *location, Elf_Addr v, + s64 *rela_stack, size_t *rela_stack_top, unsigned int type); + +/* The handlers for known reloc types */ +static reloc_rela_handler reloc_rela_handlers[] = { + [R_LARCH_NONE ... R_LARCH_SUB64] = apply_r_larch_error, + + [R_LARCH_NONE] = apply_r_larch_none, + [R_LARCH_32] = apply_r_larch_32, + [R_LARCH_64] = apply_r_larch_64, + [R_LARCH_MARK_LA] = apply_r_larch_none, + [R_LARCH_MARK_PCREL] = apply_r_larch_none, + [R_LARCH_SOP_PUSH_PCREL] = apply_r_larch_sop_push_pcrel, + [R_LARCH_SOP_PUSH_ABSOLUTE] = apply_r_larch_sop_push_absolute, + [R_LARCH_SOP_PUSH_DUP] = apply_r_larch_sop_push_dup, + [R_LARCH_SOP_PUSH_PLT_PCREL] = apply_r_larch_sop_push_plt_pcrel, + [R_LARCH_SOP_SUB ... R_LARCH_SOP_IF_ELSE] = apply_r_larch_sop, + [R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field, + [R_LARCH_ADD32 ... R_LARCH_SUB64] = apply_r_larch_add_sub, +}; + +int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, + struct module *mod) +{ + int i, err; + unsigned int type; + s64 rela_stack[RELA_STACK_DEPTH]; + size_t rela_stack_top = 0; + reloc_rela_handler handler; + void *location; + Elf_Addr v; + Elf_Sym *sym; + Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr; + + pr_debug("%s: Applying relocate section %u to %u\n", __func__, relsec, + sechdrs[relsec].sh_info); + + rela_stack_top = 0; + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; + /* This is the symbol it is referring to */ + sym = (Elf_Sym *)sechdrs[symindex].sh_addr + ELF_R_SYM(rel[i].r_info); + if (IS_ERR_VALUE(sym->st_value)) { + /* Ignore unresolved weak symbol */ + if (ELF_ST_BIND(sym->st_info) == STB_WEAK) + continue; + pr_warn("%s: Unknown symbol %s\n", mod->name, strtab + sym->st_name); + return -ENOENT; + } + + type = ELF_R_TYPE(rel[i].r_info); + + if (type < ARRAY_SIZE(reloc_rela_handlers)) + handler = reloc_rela_handlers[type]; + else + handler = NULL; + + if (!handler) { + pr_err("%s: Unknown relocation type %u\n", mod->name, type); + return -EINVAL; + } + + pr_debug("type %d st_value %llx r_addend %llx loc %llx\n", + (int)ELF_R_TYPE(rel[i].r_info), + sym->st_value, rel[i].r_addend, (u64)location); + + v = sym->st_value + rel[i].r_addend; + err = handler(mod, location, v, rela_stack, &rela_stack_top, type); + if (err) + return err; + } + + return 0; +} + +void *module_alloc(unsigned long size) +{ + return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, + GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0)); +} diff --git a/arch/loongarch/kernel/numa.c b/arch/loongarch/kernel/numa.c new file mode 100644 index 000000000000..a76f547a5aa3 --- /dev/null +++ b/arch/loongarch/kernel/numa.c @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Xiang Gao <gaoxiang@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/mmzone.h> +#include <linux/export.h> +#include <linux/nodemask.h> +#include <linux/swap.h> +#include <linux/memblock.h> +#include <linux/pfn.h> +#include <linux/acpi.h> +#include <linux/efi.h> +#include <linux/irq.h> +#include <linux/pci.h> +#include <asm/bootinfo.h> +#include <asm/loongson.h> +#include <asm/numa.h> +#include <asm/page.h> +#include <asm/pgalloc.h> +#include <asm/sections.h> +#include <asm/time.h> + +int numa_off; +struct pglist_data *node_data[MAX_NUMNODES]; +unsigned char node_distances[MAX_NUMNODES][MAX_NUMNODES]; + +EXPORT_SYMBOL(node_data); +EXPORT_SYMBOL(node_distances); + +static struct numa_meminfo numa_meminfo; +cpumask_t cpus_on_node[MAX_NUMNODES]; +cpumask_t phys_cpus_on_node[MAX_NUMNODES]; +EXPORT_SYMBOL(cpus_on_node); + +/* + * apicid, cpu, node mappings + */ +s16 __cpuid_to_node[CONFIG_NR_CPUS] = { + [0 ... CONFIG_NR_CPUS - 1] = NUMA_NO_NODE +}; +EXPORT_SYMBOL(__cpuid_to_node); + +nodemask_t numa_nodes_parsed __initdata; + +#ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA +unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; +EXPORT_SYMBOL(__per_cpu_offset); + +static int __init pcpu_cpu_to_node(int cpu) +{ + return early_cpu_to_node(cpu); +} + +static int __init pcpu_cpu_distance(unsigned int from, unsigned int to) +{ + if (early_cpu_to_node(from) == early_cpu_to_node(to)) + return LOCAL_DISTANCE; + else + return REMOTE_DISTANCE; +} + +void __init pcpu_populate_pte(unsigned long addr) +{ + pgd_t *pgd = pgd_offset_k(addr); + p4d_t *p4d = p4d_offset(pgd, addr); + pud_t *pud; + pmd_t *pmd; + + if (p4d_none(*p4d)) { + pud_t *new; + + new = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + pgd_populate(&init_mm, pgd, new); +#ifndef __PAGETABLE_PUD_FOLDED + pud_init((unsigned long)new, (unsigned long)invalid_pmd_table); +#endif + } + + pud = pud_offset(p4d, addr); + if (pud_none(*pud)) { + pmd_t *new; + + new = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + pud_populate(&init_mm, pud, new); +#ifndef __PAGETABLE_PMD_FOLDED + pmd_init((unsigned long)new, (unsigned long)invalid_pte_table); +#endif + } + + pmd = pmd_offset(pud, addr); + if (!pmd_present(*pmd)) { + pte_t *new; + + new = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + pmd_populate_kernel(&init_mm, pmd, new); + } +} + +void __init setup_per_cpu_areas(void) +{ + unsigned long delta; + unsigned int cpu; + int rc = -EINVAL; + + if (pcpu_chosen_fc == PCPU_FC_AUTO) { + if (nr_node_ids >= 8) + pcpu_chosen_fc = PCPU_FC_PAGE; + else + pcpu_chosen_fc = PCPU_FC_EMBED; + } + + /* + * Always reserve area for module percpu variables. That's + * what the legacy allocator did. + */ + if (pcpu_chosen_fc != PCPU_FC_PAGE) { + rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE, + PERCPU_DYNAMIC_RESERVE, PMD_SIZE, + pcpu_cpu_distance, pcpu_cpu_to_node); + if (rc < 0) + pr_warn("%s allocator failed (%d), falling back to page size\n", + pcpu_fc_names[pcpu_chosen_fc], rc); + } + if (rc < 0) + rc = pcpu_page_first_chunk(PERCPU_MODULE_RESERVE, pcpu_cpu_to_node); + if (rc < 0) + panic("cannot initialize percpu area (err=%d)", rc); + + delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; + for_each_possible_cpu(cpu) + __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu]; +} +#endif + +/* + * Get nodeid by logical cpu number. + * __cpuid_to_node maps phyical cpu id to node, so we + * should use cpu_logical_map(cpu) to index it. + * + * This routine is only used in early phase during + * booting, after setup_per_cpu_areas calling and numa_node + * initialization, cpu_to_node will be used instead. + */ +int early_cpu_to_node(int cpu) +{ + int physid = cpu_logical_map(cpu); + + if (physid < 0) + return NUMA_NO_NODE; + + return __cpuid_to_node[physid]; +} + +void __init early_numa_add_cpu(int cpuid, s16 node) +{ + int cpu = __cpu_number_map[cpuid]; + + if (cpu < 0) + return; + + cpumask_set_cpu(cpu, &cpus_on_node[node]); + cpumask_set_cpu(cpuid, &phys_cpus_on_node[node]); +} + +void numa_add_cpu(unsigned int cpu) +{ + int nid = cpu_to_node(cpu); + cpumask_set_cpu(cpu, &cpus_on_node[nid]); +} + +void numa_remove_cpu(unsigned int cpu) +{ + int nid = cpu_to_node(cpu); + cpumask_clear_cpu(cpu, &cpus_on_node[nid]); +} + +static int __init numa_add_memblk_to(int nid, u64 start, u64 end, + struct numa_meminfo *mi) +{ + /* ignore zero length blks */ + if (start == end) + return 0; + + /* whine about and ignore invalid blks */ + if (start > end || nid < 0 || nid >= MAX_NUMNODES) { + pr_warn("NUMA: Warning: invalid memblk node %d [mem %#010Lx-%#010Lx]\n", + nid, start, end - 1); + return 0; + } + + if (mi->nr_blks >= NR_NODE_MEMBLKS) { + pr_err("NUMA: too many memblk ranges\n"); + return -EINVAL; + } + + mi->blk[mi->nr_blks].start = PFN_ALIGN(start); + mi->blk[mi->nr_blks].end = PFN_ALIGN(end - PAGE_SIZE + 1); + mi->blk[mi->nr_blks].nid = nid; + mi->nr_blks++; + return 0; +} + +/** + * numa_add_memblk - Add one numa_memblk to numa_meminfo + * @nid: NUMA node ID of the new memblk + * @start: Start address of the new memblk + * @end: End address of the new memblk + * + * Add a new memblk to the default numa_meminfo. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int __init numa_add_memblk(int nid, u64 start, u64 end) +{ + return numa_add_memblk_to(nid, start, end, &numa_meminfo); +} + +static void __init alloc_node_data(int nid) +{ + void *nd; + unsigned long nd_pa; + size_t nd_sz = roundup(sizeof(pg_data_t), PAGE_SIZE); + + nd_pa = memblock_phys_alloc_try_nid(nd_sz, SMP_CACHE_BYTES, nid); + if (!nd_pa) { + pr_err("Cannot find %zu Byte for node_data (initial node: %d)\n", nd_sz, nid); + return; + } + + nd = __va(nd_pa); + + node_data[nid] = nd; + memset(nd, 0, sizeof(pg_data_t)); +} + +static void __init node_mem_init(unsigned int node) +{ + unsigned long start_pfn, end_pfn; + unsigned long node_addrspace_offset; + + node_addrspace_offset = nid_to_addrbase(node); + pr_info("Node%d's addrspace_offset is 0x%lx\n", + node, node_addrspace_offset); + + get_pfn_range_for_nid(node, &start_pfn, &end_pfn); + pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx\n", + node, start_pfn, end_pfn); + + alloc_node_data(node); +} + +#ifdef CONFIG_ACPI_NUMA + +/* + * Sanity check to catch more bad NUMA configurations (they are amazingly + * common). Make sure the nodes cover all memory. + */ +static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) +{ + int i; + u64 numaram, biosram; + + numaram = 0; + for (i = 0; i < mi->nr_blks; i++) { + u64 s = mi->blk[i].start >> PAGE_SHIFT; + u64 e = mi->blk[i].end >> PAGE_SHIFT; + + numaram += e - s; + numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e); + if ((s64)numaram < 0) + numaram = 0; + } + max_pfn = max_low_pfn; + biosram = max_pfn - absent_pages_in_range(0, max_pfn); + + BUG_ON((s64)(biosram - numaram) >= (1 << (20 - PAGE_SHIFT))); + return true; +} + +static void __init add_node_intersection(u32 node, u64 start, u64 size, u32 type) +{ + static unsigned long num_physpages; + + num_physpages += (size >> PAGE_SHIFT); + pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx Bytes\n", + node, type, start, size); + pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n", + start >> PAGE_SHIFT, (start + size) >> PAGE_SHIFT, num_physpages); + memblock_set_node(start, size, &memblock.memory, node); +} + +/* + * add_numamem_region + * + * Add a uasable memory region described by BIOS. The + * routine gets each intersection between BIOS's region + * and node's region, and adds them into node's memblock + * pool. + * + */ +static void __init add_numamem_region(u64 start, u64 end, u32 type) +{ + u32 i; + u64 ofs = start; + + if (start >= end) { + pr_debug("Invalid region: %016llx-%016llx\n", start, end); + return; + } + + for (i = 0; i < numa_meminfo.nr_blks; i++) { + struct numa_memblk *mb = &numa_meminfo.blk[i]; + + if (ofs > mb->end) + continue; + + if (end > mb->end) { + add_node_intersection(mb->nid, ofs, mb->end - ofs, type); + ofs = mb->end; + } else { + add_node_intersection(mb->nid, ofs, end - ofs, type); + break; + } + } +} + +static void __init init_node_memblock(void) +{ + u32 mem_type; + u64 mem_end, mem_start, mem_size; + efi_memory_desc_t *md; + + /* Parse memory information and activate */ + for_each_efi_memory_desc(md) { + mem_type = md->type; + mem_start = md->phys_addr; + mem_size = md->num_pages << EFI_PAGE_SHIFT; + mem_end = mem_start + mem_size; + + switch (mem_type) { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_PERSISTENT_MEMORY: + case EFI_CONVENTIONAL_MEMORY: + add_numamem_region(mem_start, mem_end, mem_type); + break; + case EFI_PAL_CODE: + case EFI_UNUSABLE_MEMORY: + case EFI_ACPI_RECLAIM_MEMORY: + add_numamem_region(mem_start, mem_end, mem_type); + fallthrough; + case EFI_RESERVED_TYPE: + case EFI_RUNTIME_SERVICES_CODE: + case EFI_RUNTIME_SERVICES_DATA: + case EFI_MEMORY_MAPPED_IO: + case EFI_MEMORY_MAPPED_IO_PORT_SPACE: + pr_info("Resvd: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx Bytes\n", + mem_type, mem_start, mem_size); + break; + } + } +} + +static void __init numa_default_distance(void) +{ + int row, col; + + for (row = 0; row < MAX_NUMNODES; row++) + for (col = 0; col < MAX_NUMNODES; col++) { + if (col == row) + node_distances[row][col] = LOCAL_DISTANCE; + else + /* We assume that one node per package here! + * + * A SLIT should be used for multiple nodes + * per package to override default setting. + */ + node_distances[row][col] = REMOTE_DISTANCE; + } +} + +int __init init_numa_memory(void) +{ + int i; + int ret; + int node; + + for (i = 0; i < NR_CPUS; i++) + set_cpuid_to_node(i, NUMA_NO_NODE); + + numa_default_distance(); + nodes_clear(numa_nodes_parsed); + nodes_clear(node_possible_map); + nodes_clear(node_online_map); + memset(&numa_meminfo, 0, sizeof(numa_meminfo)); + + /* Parse SRAT and SLIT if provided by firmware. */ + ret = acpi_numa_init(); + if (ret < 0) + return ret; + + node_possible_map = numa_nodes_parsed; + if (WARN_ON(nodes_empty(node_possible_map))) + return -EINVAL; + + init_node_memblock(); + if (numa_meminfo_cover_memory(&numa_meminfo) == false) + return -EINVAL; + + for_each_node_mask(node, node_possible_map) { + node_mem_init(node); + node_set_online(node); + } + max_low_pfn = PHYS_PFN(memblock_end_of_DRAM()); + + setup_nr_node_ids(); + loongson_sysconf.nr_nodes = nr_node_ids; + loongson_sysconf.cores_per_node = cpumask_weight(&phys_cpus_on_node[0]); + + return 0; +} + +EXPORT_SYMBOL(init_numa_memory); +#endif + +void __init paging_init(void) +{ + unsigned int node; + unsigned long zones_size[MAX_NR_ZONES] = {0, }; + + for_each_online_node(node) { + unsigned long start_pfn, end_pfn; + + get_pfn_range_for_nid(node, &start_pfn, &end_pfn); + + if (end_pfn > max_low_pfn) + max_low_pfn = end_pfn; + } +#ifdef CONFIG_ZONE_DMA32 + zones_size[ZONE_DMA32] = MAX_DMA32_PFN; +#endif + zones_size[ZONE_NORMAL] = max_low_pfn; + free_area_init(zones_size); +} + +void __init mem_init(void) +{ + high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT); + memblock_free_all(); + setup_zero_pages(); /* This comes from node 0 */ +} + +int pcibus_to_node(struct pci_bus *bus) +{ + return dev_to_node(&bus->dev); +} +EXPORT_SYMBOL(pcibus_to_node); diff --git a/arch/loongarch/kernel/proc.c b/arch/loongarch/kernel/proc.c new file mode 100644 index 000000000000..1effc73850fe --- /dev/null +++ b/arch/loongarch/kernel/proc.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <asm/bootinfo.h> +#include <asm/cpu.h> +#include <asm/cpu-features.h> +#include <asm/idle.h> +#include <asm/processor.h> +#include <asm/time.h> + +/* + * No lock; only written during early bootup by CPU 0. + */ +static RAW_NOTIFIER_HEAD(proc_cpuinfo_chain); + +int __ref register_proc_cpuinfo_notifier(struct notifier_block *nb) +{ + return raw_notifier_chain_register(&proc_cpuinfo_chain, nb); +} + +int proc_cpuinfo_notifier_call_chain(unsigned long val, void *v) +{ + return raw_notifier_call_chain(&proc_cpuinfo_chain, val, v); +} + +static int show_cpuinfo(struct seq_file *m, void *v) +{ + unsigned long n = (unsigned long) v - 1; + unsigned int version = cpu_data[n].processor_id & 0xff; + unsigned int fp_version = cpu_data[n].fpu_vers; + struct proc_cpuinfo_notifier_args proc_cpuinfo_notifier_args; + +#ifdef CONFIG_SMP + if (!cpu_online(n)) + return 0; +#endif + + /* + * For the first processor also print the system type + */ + if (n == 0) + seq_printf(m, "system type\t\t: %s\n\n", get_system_type()); + + seq_printf(m, "processor\t\t: %ld\n", n); + seq_printf(m, "package\t\t\t: %d\n", cpu_data[n].package); + seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); + seq_printf(m, "CPU Family\t\t: %s\n", __cpu_family[n]); + seq_printf(m, "Model Name\t\t: %s\n", __cpu_full_name[n]); + seq_printf(m, "CPU Revision\t\t: 0x%02x\n", version); + seq_printf(m, "FPU Revision\t\t: 0x%02x\n", fp_version); + seq_printf(m, "CPU MHz\t\t\t: %llu.%02llu\n", + cpu_clock_freq / 1000000, (cpu_clock_freq / 10000) % 100); + seq_printf(m, "BogoMIPS\t\t: %llu.%02llu\n", + (lpj_fine * cpu_clock_freq / const_clock_freq) / (500000/HZ), + ((lpj_fine * cpu_clock_freq / const_clock_freq) / (5000/HZ)) % 100); + seq_printf(m, "TLB Entries\t\t: %d\n", cpu_data[n].tlbsize); + seq_printf(m, "Address Sizes\t\t: %d bits physical, %d bits virtual\n", + cpu_pabits + 1, cpu_vabits + 1); + + seq_printf(m, "ISA\t\t\t:"); + if (cpu_has_loongarch32) + seq_printf(m, " loongarch32"); + if (cpu_has_loongarch64) + seq_printf(m, " loongarch64"); + seq_printf(m, "\n"); + + seq_printf(m, "Features\t\t:"); + if (cpu_has_cpucfg) seq_printf(m, " cpucfg"); + if (cpu_has_lam) seq_printf(m, " lam"); + if (cpu_has_ual) seq_printf(m, " ual"); + if (cpu_has_fpu) seq_printf(m, " fpu"); + if (cpu_has_lsx) seq_printf(m, " lsx"); + if (cpu_has_lasx) seq_printf(m, " lasx"); + if (cpu_has_complex) seq_printf(m, " complex"); + if (cpu_has_crypto) seq_printf(m, " crypto"); + if (cpu_has_lvz) seq_printf(m, " lvz"); + if (cpu_has_lbt_x86) seq_printf(m, " lbt_x86"); + if (cpu_has_lbt_arm) seq_printf(m, " lbt_arm"); + if (cpu_has_lbt_mips) seq_printf(m, " lbt_mips"); + seq_printf(m, "\n"); + + seq_printf(m, "Hardware Watchpoint\t: %s", + cpu_has_watch ? "yes, " : "no\n"); + if (cpu_has_watch) { + seq_printf(m, "iwatch count: %d, dwatch count: %d\n", + cpu_data[n].watch_ireg_count, cpu_data[n].watch_dreg_count); + } + + proc_cpuinfo_notifier_args.m = m; + proc_cpuinfo_notifier_args.n = n; + + raw_notifier_call_chain(&proc_cpuinfo_chain, 0, + &proc_cpuinfo_notifier_args); + + seq_printf(m, "\n"); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + unsigned long i = *pos; + + return i < NR_CPUS ? (void *)(i + 1) : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +const struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c new file mode 100644 index 000000000000..6d944d65f600 --- /dev/null +++ b/arch/loongarch/kernel/process.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1994 - 1999, 2000 by Ralf Baechle and others. + * Copyright (C) 2005, 2006 by Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2004 Thiemo Seufer + * Copyright (C) 2013 Imagination Technologies Ltd. + */ +#include <linux/cpu.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/sched/debug.h> +#include <linux/sched/task.h> +#include <linux/sched/task_stack.h> +#include <linux/mm.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/export.h> +#include <linux/ptrace.h> +#include <linux/mman.h> +#include <linux/personality.h> +#include <linux/sys.h> +#include <linux/completion.h> +#include <linux/kallsyms.h> +#include <linux/random.h> +#include <linux/prctl.h> +#include <linux/nmi.h> + +#include <asm/asm.h> +#include <asm/bootinfo.h> +#include <asm/cpu.h> +#include <asm/elf.h> +#include <asm/fpu.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/irq_regs.h> +#include <asm/loongarch.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/reg.h> +#include <asm/vdso.h> + +/* + * Idle related variables and functions + */ + +unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE; +EXPORT_SYMBOL(boot_option_idle_override); + +#ifdef CONFIG_HOTPLUG_CPU +void arch_cpu_idle_dead(void) +{ + play_dead(); +} +#endif + +asmlinkage void ret_from_fork(void); +asmlinkage void ret_from_kernel_thread(void); + +void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) +{ + unsigned long crmd; + unsigned long prmd; + unsigned long euen; + + /* New thread loses kernel privileges. */ + crmd = regs->csr_crmd & ~(PLV_MASK); + crmd |= PLV_USER; + regs->csr_crmd = crmd; + + prmd = regs->csr_prmd & ~(PLV_MASK); + prmd |= PLV_USER; + regs->csr_prmd = prmd; + + euen = regs->csr_euen & ~(CSR_EUEN_FPEN); + regs->csr_euen = euen; + lose_fpu(0); + + clear_thread_flag(TIF_LSX_CTX_LIVE); + clear_thread_flag(TIF_LASX_CTX_LIVE); + clear_used_math(); + regs->csr_era = pc; + regs->regs[3] = sp; +} + +void exit_thread(struct task_struct *tsk) +{ +} + +int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) +{ + /* + * Save any process state which is live in hardware registers to the + * parent context prior to duplication. This prevents the new child + * state becoming stale if the parent is preempted before copy_thread() + * gets a chance to save the parent's live hardware registers to the + * child context. + */ + preempt_disable(); + + if (is_fpu_owner()) + save_fp(current); + + preempt_enable(); + + if (used_math()) + memcpy(dst, src, sizeof(struct task_struct)); + else + memcpy(dst, src, offsetof(struct task_struct, thread.fpu.fpr)); + + return 0; +} + +/* + * Copy architecture-specific thread state + */ +int copy_thread(unsigned long clone_flags, unsigned long usp, + unsigned long kthread_arg, struct task_struct *p, unsigned long tls) +{ + unsigned long childksp; + struct pt_regs *childregs, *regs = current_pt_regs(); + + childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE - 32; + + /* set up new TSS. */ + childregs = (struct pt_regs *) childksp - 1; + /* Put the stack after the struct pt_regs. */ + childksp = (unsigned long) childregs; + p->thread.csr_euen = 0; + p->thread.csr_crmd = csr_read32(LOONGARCH_CSR_CRMD); + p->thread.csr_prmd = csr_read32(LOONGARCH_CSR_PRMD); + p->thread.csr_ecfg = csr_read32(LOONGARCH_CSR_ECFG); + if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + /* kernel thread */ + p->thread.reg23 = usp; /* fn */ + p->thread.reg24 = kthread_arg; + p->thread.reg03 = childksp; + p->thread.reg01 = (unsigned long) ret_from_kernel_thread; + memset(childregs, 0, sizeof(struct pt_regs)); + childregs->csr_euen = p->thread.csr_euen; + childregs->csr_crmd = p->thread.csr_crmd; + childregs->csr_prmd = p->thread.csr_prmd; + childregs->csr_ecfg = p->thread.csr_ecfg; + return 0; + } + + /* user thread */ + *childregs = *regs; + childregs->regs[4] = 0; /* Child gets zero as return value */ + if (usp) + childregs->regs[3] = usp; + + p->thread.reg03 = (unsigned long) childregs; + p->thread.reg01 = (unsigned long) ret_from_fork; + + /* + * New tasks lose permission to use the fpu. This accelerates context + * switching for most programs since they don't use the fpu. + */ + childregs->csr_euen = 0; + + clear_tsk_thread_flag(p, TIF_USEDFPU); + clear_tsk_thread_flag(p, TIF_USEDSIMD); + clear_tsk_thread_flag(p, TIF_LSX_CTX_LIVE); + clear_tsk_thread_flag(p, TIF_LASX_CTX_LIVE); + + if (clone_flags & CLONE_SETTLS) + childregs->regs[2] = tls; + + return 0; +} + +unsigned long __get_wchan(struct task_struct *task) +{ + return 0; +} + +unsigned long stack_top(void) +{ + unsigned long top = TASK_SIZE & PAGE_MASK; + + /* Space for the VDSO & data page */ + top -= PAGE_ALIGN(current->thread.vdso->size); + top -= PAGE_SIZE; + + /* Space to randomize the VDSO base */ + if (current->flags & PF_RANDOMIZE) + top -= VDSO_RANDOMIZE_SIZE; + + return top; +} + +/* + * Don't forget that the stack pointer must be aligned on a 8 bytes + * boundary for 32-bits ABI and 16 bytes for 64-bits ABI. + */ +unsigned long arch_align_stack(unsigned long sp) +{ + if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) + sp -= get_random_int() & ~PAGE_MASK; + + return sp & STACK_ALIGN; +} + +static DEFINE_PER_CPU(call_single_data_t, backtrace_csd); +static struct cpumask backtrace_csd_busy; + +static void handle_backtrace(void *info) +{ + nmi_cpu_backtrace(get_irq_regs()); + cpumask_clear_cpu(smp_processor_id(), &backtrace_csd_busy); +} + +static void raise_backtrace(cpumask_t *mask) +{ + call_single_data_t *csd; + int cpu; + + for_each_cpu(cpu, mask) { + /* + * If we previously sent an IPI to the target CPU & it hasn't + * cleared its bit in the busy cpumask then it didn't handle + * our previous IPI & it's not safe for us to reuse the + * call_single_data_t. + */ + if (cpumask_test_and_set_cpu(cpu, &backtrace_csd_busy)) { + pr_warn("Unable to send backtrace IPI to CPU%u - perhaps it hung?\n", + cpu); + continue; + } + + csd = &per_cpu(backtrace_csd, cpu); + csd->func = handle_backtrace; + smp_call_function_single_async(cpu, csd); + } +} + +void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) +{ + nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace); +} + +#ifdef CONFIG_64BIT +void loongarch_dump_regs64(u64 *uregs, const struct pt_regs *regs) +{ + unsigned int i; + + for (i = LOONGARCH_EF_R1; i <= LOONGARCH_EF_R31; i++) { + uregs[i] = regs->regs[i - LOONGARCH_EF_R0]; + } + + uregs[LOONGARCH_EF_ORIG_A0] = regs->orig_a0; + uregs[LOONGARCH_EF_CSR_ERA] = regs->csr_era; + uregs[LOONGARCH_EF_CSR_BADV] = regs->csr_badvaddr; + uregs[LOONGARCH_EF_CSR_CRMD] = regs->csr_crmd; + uregs[LOONGARCH_EF_CSR_PRMD] = regs->csr_prmd; + uregs[LOONGARCH_EF_CSR_EUEN] = regs->csr_euen; + uregs[LOONGARCH_EF_CSR_ECFG] = regs->csr_ecfg; + uregs[LOONGARCH_EF_CSR_ESTAT] = regs->csr_estat; +} +#endif /* CONFIG_64BIT */ diff --git a/arch/loongarch/kernel/ptrace.c b/arch/loongarch/kernel/ptrace.c new file mode 100644 index 000000000000..e6ab87948e1d --- /dev/null +++ b/arch/loongarch/kernel/ptrace.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1992 Ross Biro + * Copyright (C) Linus Torvalds + * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle + * Copyright (C) 1996 David S. Miller + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999 MIPS Technologies, Inc. + * Copyright (C) 2000 Ulf Carlsson + */ +#include <linux/kernel.h> +#include <linux/audit.h> +#include <linux/compiler.h> +#include <linux/context_tracking.h> +#include <linux/elf.h> +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/ptrace.h> +#include <linux/regset.h> +#include <linux/sched.h> +#include <linux/sched/task_stack.h> +#include <linux/security.h> +#include <linux/smp.h> +#include <linux/stddef.h> +#include <linux/seccomp.h> +#include <linux/uaccess.h> + +#include <asm/byteorder.h> +#include <asm/cpu.h> +#include <asm/cpu-info.h> +#include <asm/fpu.h> +#include <asm/loongarch.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/reg.h> +#include <asm/syscall.h> + +static void init_fp_ctx(struct task_struct *target) +{ + /* The target already has context */ + if (tsk_used_math(target)) + return; + + /* Begin with data registers set to all 1s... */ + memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr)); + set_stopped_child_used_math(target); +} + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure single step bits etc are not set. + */ +void ptrace_disable(struct task_struct *child) +{ + /* Don't load the watchpoint registers for the ex-child. */ + clear_tsk_thread_flag(child, TIF_LOAD_WATCH); + clear_tsk_thread_flag(child, TIF_SINGLESTEP); +} + +/* regset get/set implementations */ + +static int gpr_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + int r; + struct pt_regs *regs = task_pt_regs(target); + + r = membuf_write(&to, ®s->regs, sizeof(u64) * GPR_NUM); + r = membuf_write(&to, ®s->orig_a0, sizeof(u64)); + r = membuf_write(&to, ®s->csr_era, sizeof(u64)); + r = membuf_write(&to, ®s->csr_badvaddr, sizeof(u64)); + + return r; +} + +static int gpr_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int err; + int a0_start = sizeof(u64) * GPR_NUM; + int era_start = a0_start + sizeof(u64); + int badvaddr_start = era_start + sizeof(u64); + struct pt_regs *regs = task_pt_regs(target); + + err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s->regs, + 0, a0_start); + err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s->orig_a0, + a0_start, a0_start + sizeof(u64)); + err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s->csr_era, + era_start, era_start + sizeof(u64)); + err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s->csr_badvaddr, + badvaddr_start, badvaddr_start + sizeof(u64)); + + return err; +} + + +/* + * Get the general floating-point registers. + */ +static int gfpr_get(struct task_struct *target, struct membuf *to) +{ + return membuf_write(to, &target->thread.fpu.fpr, + sizeof(elf_fpreg_t) * NUM_FPU_REGS); +} + +static int gfpr_get_simd(struct task_struct *target, struct membuf *to) +{ + int i, r; + u64 fpr_val; + + BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); + for (i = 0; i < NUM_FPU_REGS; i++) { + fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); + r = membuf_write(to, &fpr_val, sizeof(elf_fpreg_t)); + } + + return r; +} + +/* + * Choose the appropriate helper for general registers, and then copy + * the FCC and FCSR registers separately. + */ +static int fpr_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + int r; + + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) + r = gfpr_get(target, &to); + else + r = gfpr_get_simd(target, &to); + + r = membuf_write(&to, &target->thread.fpu.fcc, sizeof(target->thread.fpu.fcc)); + r = membuf_write(&to, &target->thread.fpu.fcsr, sizeof(target->thread.fpu.fcsr)); + + return r; +} + +static int gfpr_set(struct task_struct *target, + unsigned int *pos, unsigned int *count, + const void **kbuf, const void __user **ubuf) +{ + return user_regset_copyin(pos, count, kbuf, ubuf, + &target->thread.fpu.fpr, + 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +} + +static int gfpr_set_simd(struct task_struct *target, + unsigned int *pos, unsigned int *count, + const void **kbuf, const void __user **ubuf) +{ + int i, err; + u64 fpr_val; + + BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); + for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) { + err = user_regset_copyin(pos, count, kbuf, ubuf, + &fpr_val, i * sizeof(elf_fpreg_t), + (i + 1) * sizeof(elf_fpreg_t)); + if (err) + return err; + set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); + } + + return 0; +} + +/* + * Choose the appropriate helper for general registers, and then copy + * the FCC register separately. + */ +static int fpr_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + const int fcc_start = NUM_FPU_REGS * sizeof(elf_fpreg_t); + const int fcc_end = fcc_start + sizeof(u64); + int err; + + BUG_ON(count % sizeof(elf_fpreg_t)); + if (pos + count > sizeof(elf_fpregset_t)) + return -EIO; + + init_fp_ctx(target); + + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) + err = gfpr_set(target, &pos, &count, &kbuf, &ubuf); + else + err = gfpr_set_simd(target, &pos, &count, &kbuf, &ubuf); + if (err) + return err; + + if (count > 0) + err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.fpu.fcc, + fcc_start, fcc_end); + + return err; +} + +static int cfg_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + int i, r; + u32 cfg_val; + + i = 0; + while (to.left > 0) { + cfg_val = read_cpucfg(i++); + r = membuf_write(&to, &cfg_val, sizeof(u32)); + } + + return r; +} + +/* + * CFG registers are read-only. + */ +static int cfg_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + return 0; +} + +struct pt_regs_offset { + const char *name; + int offset; +}; + +#define REG_OFFSET_NAME(n, r) {.name = #n, .offset = offsetof(struct pt_regs, r)} +#define REG_OFFSET_END {.name = NULL, .offset = 0} + +static const struct pt_regs_offset regoffset_table[] = { + REG_OFFSET_NAME(r0, regs[0]), + REG_OFFSET_NAME(r1, regs[1]), + REG_OFFSET_NAME(r2, regs[2]), + REG_OFFSET_NAME(r3, regs[3]), + REG_OFFSET_NAME(r4, regs[4]), + REG_OFFSET_NAME(r5, regs[5]), + REG_OFFSET_NAME(r6, regs[6]), + REG_OFFSET_NAME(r7, regs[7]), + REG_OFFSET_NAME(r8, regs[8]), + REG_OFFSET_NAME(r9, regs[9]), + REG_OFFSET_NAME(r10, regs[10]), + REG_OFFSET_NAME(r11, regs[11]), + REG_OFFSET_NAME(r12, regs[12]), + REG_OFFSET_NAME(r13, regs[13]), + REG_OFFSET_NAME(r14, regs[14]), + REG_OFFSET_NAME(r15, regs[15]), + REG_OFFSET_NAME(r16, regs[16]), + REG_OFFSET_NAME(r17, regs[17]), + REG_OFFSET_NAME(r18, regs[18]), + REG_OFFSET_NAME(r19, regs[19]), + REG_OFFSET_NAME(r20, regs[20]), + REG_OFFSET_NAME(r21, regs[21]), + REG_OFFSET_NAME(r22, regs[22]), + REG_OFFSET_NAME(r23, regs[23]), + REG_OFFSET_NAME(r24, regs[24]), + REG_OFFSET_NAME(r25, regs[25]), + REG_OFFSET_NAME(r26, regs[26]), + REG_OFFSET_NAME(r27, regs[27]), + REG_OFFSET_NAME(r28, regs[28]), + REG_OFFSET_NAME(r29, regs[29]), + REG_OFFSET_NAME(r30, regs[30]), + REG_OFFSET_NAME(r31, regs[31]), + REG_OFFSET_NAME(orig_a0, orig_a0), + REG_OFFSET_NAME(csr_era, csr_era), + REG_OFFSET_NAME(csr_badvaddr, csr_badvaddr), + REG_OFFSET_NAME(csr_crmd, csr_crmd), + REG_OFFSET_NAME(csr_prmd, csr_prmd), + REG_OFFSET_NAME(csr_euen, csr_euen), + REG_OFFSET_NAME(csr_ecfg, csr_ecfg), + REG_OFFSET_NAME(csr_estat, csr_estat), + REG_OFFSET_END, +}; + +/** + * regs_query_register_offset() - query register offset from its name + * @name: the name of a register + * + * regs_query_register_offset() returns the offset of a register in struct + * pt_regs from its name. If the name is invalid, this returns -EINVAL; + */ +int regs_query_register_offset(const char *name) +{ + const struct pt_regs_offset *roff; + + for (roff = regoffset_table; roff->name != NULL; roff++) + if (!strcmp(roff->name, name)) + return roff->offset; + return -EINVAL; +} + +enum loongarch_regset { + REGSET_GPR, + REGSET_FPR, + REGSET_CPUCFG, +}; + +static const struct user_regset loongarch64_regsets[] = { + [REGSET_GPR] = { + .core_note_type = NT_PRSTATUS, + .n = ELF_NGREG, + .size = sizeof(elf_greg_t), + .align = sizeof(elf_greg_t), + .regset_get = gpr_get, + .set = gpr_set, + }, + [REGSET_FPR] = { + .core_note_type = NT_PRFPREG, + .n = ELF_NFPREG, + .size = sizeof(elf_fpreg_t), + .align = sizeof(elf_fpreg_t), + .regset_get = fpr_get, + .set = fpr_set, + }, + [REGSET_CPUCFG] = { + .core_note_type = NT_LOONGARCH_CPUCFG, + .n = 64, + .size = sizeof(u32), + .align = sizeof(u32), + .regset_get = cfg_get, + .set = cfg_set, + }, +}; + +static const struct user_regset_view user_loongarch64_view = { + .name = "loongarch64", + .e_machine = ELF_ARCH, + .regsets = loongarch64_regsets, + .n = ARRAY_SIZE(loongarch64_regsets), +}; + + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_loongarch64_view; +} + +static inline int read_user(struct task_struct *target, unsigned long addr, + unsigned long __user *data) +{ + unsigned long tmp = 0; + + switch (addr) { + case 0 ... 31: + tmp = task_pt_regs(target)->regs[addr]; + break; + case ARG0: + tmp = task_pt_regs(target)->orig_a0; + break; + case PC: + tmp = task_pt_regs(target)->csr_era; + break; + case BADVADDR: + tmp = task_pt_regs(target)->csr_badvaddr; + break; + default: + return -EIO; + } + + return put_user(tmp, data); +} + +static inline int write_user(struct task_struct *target, unsigned long addr, + unsigned long data) +{ + switch (addr) { + case 0 ... 31: + task_pt_regs(target)->regs[addr] = data; + break; + case ARG0: + task_pt_regs(target)->orig_a0 = data; + break; + case PC: + task_pt_regs(target)->csr_era = data; + break; + case BADVADDR: + task_pt_regs(target)->csr_badvaddr = data; + break; + default: + return -EIO; + } + + return 0; +} + +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) +{ + int ret; + unsigned long __user *datap = (void __user *) data; + + switch (request) { + case PTRACE_PEEKUSR: + ret = read_user(child, addr, datap); + break; + + case PTRACE_POKEUSR: + ret = write_user(child, addr, data); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +} diff --git a/arch/loongarch/kernel/reset.c b/arch/loongarch/kernel/reset.c new file mode 100644 index 000000000000..2b86469e4718 --- /dev/null +++ b/arch/loongarch/kernel/reset.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/kernel.h> +#include <linux/acpi.h> +#include <linux/efi.h> +#include <linux/export.h> +#include <linux/pm.h> +#include <linux/types.h> +#include <linux/reboot.h> +#include <linux/delay.h> +#include <linux/console.h> + +#include <acpi/reboot.h> +#include <asm/compiler.h> +#include <asm/idle.h> +#include <asm/loongarch.h> +#include <asm/reboot.h> + +static void default_halt(void) +{ + local_irq_disable(); + clear_csr_ecfg(ECFG0_IM); + + pr_notice("\n\n** You can safely turn off the power now **\n\n"); + console_flush_on_panic(CONSOLE_FLUSH_PENDING); + + while (true) { + __arch_cpu_idle(); + } +} + +static void default_poweroff(void) +{ +#ifdef CONFIG_EFI + efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); +#endif + while (true) { + __arch_cpu_idle(); + } +} + +static void default_restart(void) +{ +#ifdef CONFIG_EFI + if (efi_capsule_pending(NULL)) + efi_reboot(REBOOT_WARM, NULL); + else + efi_reboot(REBOOT_COLD, NULL); +#endif + if (!acpi_disabled) + acpi_reboot(); + + while (true) { + __arch_cpu_idle(); + } +} + +void (*pm_restart)(void); +EXPORT_SYMBOL(pm_restart); + +void (*pm_power_off)(void); +EXPORT_SYMBOL(pm_power_off); + +void machine_halt(void) +{ +#ifdef CONFIG_SMP + preempt_disable(); + smp_send_stop(); +#endif + default_halt(); +} + +void machine_power_off(void) +{ +#ifdef CONFIG_SMP + preempt_disable(); + smp_send_stop(); +#endif + pm_power_off(); +} + +void machine_restart(char *command) +{ +#ifdef CONFIG_SMP + preempt_disable(); + smp_send_stop(); +#endif + do_kernel_restart(command); + pm_restart(); +} + +static int __init loongarch_reboot_setup(void) +{ + pm_restart = default_restart; + pm_power_off = default_poweroff; + + return 0; +} + +arch_initcall(loongarch_reboot_setup); diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c new file mode 100644 index 000000000000..185e4035811a --- /dev/null +++ b/arch/loongarch/kernel/setup.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 1995 Waldorf Electronics + * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03 Ralf Baechle + * Copyright (C) 1996 Stoned Elipot + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 2000, 2001, 2002, 2007 Maciej W. Rozycki + */ +#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/dmi.h> +#include <linux/efi.h> +#include <linux/export.h> +#include <linux/screen_info.h> +#include <linux/memblock.h> +#include <linux/initrd.h> +#include <linux/ioport.h> +#include <linux/root_dev.h> +#include <linux/console.h> +#include <linux/pfn.h> +#include <linux/platform_device.h> +#include <linux/sizes.h> +#include <linux/device.h> +#include <linux/dma-map-ops.h> +#include <linux/swiotlb.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <asm/cache.h> +#include <asm/cpu.h> +#include <asm/dma.h> +#include <asm/efi.h> +#include <asm/loongson.h> +#include <asm/numa.h> +#include <asm/pgalloc.h> +#include <asm/sections.h> +#include <asm/setup.h> +#include <asm/smp.h> +#include <asm/time.h> + +#define SMBIOS_BIOSSIZE_OFFSET 0x09 +#define SMBIOS_BIOSEXTERN_OFFSET 0x13 +#define SMBIOS_FREQLOW_OFFSET 0x16 +#define SMBIOS_FREQHIGH_OFFSET 0x17 +#define SMBIOS_FREQLOW_MASK 0xFF +#define SMBIOS_CORE_PACKAGE_OFFSET 0x23 +#define LOONGSON_EFI_ENABLE (1 << 3) + +#ifdef CONFIG_VT +struct screen_info screen_info; +#endif + +unsigned long fw_arg0, fw_arg1; +DEFINE_PER_CPU(unsigned long, kernelsp); +struct cpuinfo_loongarch cpu_data[NR_CPUS] __read_mostly; + +EXPORT_SYMBOL(cpu_data); + +struct loongson_board_info b_info; +static const char dmi_empty_string[] = " "; + +/* + * Setup information + * + * These are initialized so they are in the .data section + */ + +static int num_standard_resources; +static struct resource *standard_resources; + +static struct resource code_resource = { .name = "Kernel code", }; +static struct resource data_resource = { .name = "Kernel data", }; +static struct resource bss_resource = { .name = "Kernel bss", }; + +const char *get_system_type(void) +{ + return "generic-loongson-machine"; +} + +static const char *dmi_string_parse(const struct dmi_header *dm, u8 s) +{ + const u8 *bp = ((u8 *) dm) + dm->length; + + if (s) { + s--; + while (s > 0 && *bp) { + bp += strlen(bp) + 1; + s--; + } + + if (*bp != 0) { + size_t len = strlen(bp)+1; + size_t cmp_len = len > 8 ? 8 : len; + + if (!memcmp(bp, dmi_empty_string, cmp_len)) + return dmi_empty_string; + + return bp; + } + } + + return ""; +} + +static void __init parse_cpu_table(const struct dmi_header *dm) +{ + long freq_temp = 0; + char *dmi_data = (char *)dm; + + freq_temp = ((*(dmi_data + SMBIOS_FREQHIGH_OFFSET) << 8) + + ((*(dmi_data + SMBIOS_FREQLOW_OFFSET)) & SMBIOS_FREQLOW_MASK)); + cpu_clock_freq = freq_temp * 1000000; + + loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]); + loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_CORE_PACKAGE_OFFSET); + + pr_info("CpuClock = %llu\n", cpu_clock_freq); +} + +static void __init parse_bios_table(const struct dmi_header *dm) +{ + int bios_extern; + char *dmi_data = (char *)dm; + + bios_extern = *(dmi_data + SMBIOS_BIOSEXTERN_OFFSET); + b_info.bios_size = *(dmi_data + SMBIOS_BIOSSIZE_OFFSET); + + if (bios_extern & LOONGSON_EFI_ENABLE) + set_bit(EFI_BOOT, &efi.flags); + else + clear_bit(EFI_BOOT, &efi.flags); +} + +static void __init find_tokens(const struct dmi_header *dm, void *dummy) +{ + switch (dm->type) { + case 0x0: /* Extern BIOS */ + parse_bios_table(dm); + break; + case 0x4: /* Calling interface */ + parse_cpu_table(dm); + break; + } +} +static void __init smbios_parse(void) +{ + b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR); + b_info.bios_version = (void *)dmi_get_system_info(DMI_BIOS_VERSION); + b_info.bios_release_date = (void *)dmi_get_system_info(DMI_BIOS_DATE); + b_info.board_vendor = (void *)dmi_get_system_info(DMI_BOARD_VENDOR); + b_info.board_name = (void *)dmi_get_system_info(DMI_BOARD_NAME); + dmi_walk(find_tokens, NULL); +} + +static int usermem __initdata; + +static int __init early_parse_mem(char *p) +{ + phys_addr_t start, size; + + if (!p) { + pr_err("mem parameter is empty, do nothing\n"); + return -EINVAL; + } + + /* + * If a user specifies memory size, we + * blow away any automatically generated + * size. + */ + if (usermem == 0) { + usermem = 1; + memblock_remove(memblock_start_of_DRAM(), + memblock_end_of_DRAM() - memblock_start_of_DRAM()); + } + start = 0; + size = memparse(p, &p); + if (*p == '@') + start = memparse(p + 1, &p); + else { + pr_err("Invalid format!\n"); + return -EINVAL; + } + + if (!IS_ENABLED(CONFIG_NUMA)) + memblock_add(start, size); + else + memblock_add_node(start, size, pa_to_nid(start), MEMBLOCK_NONE); + + return 0; +} +early_param("mem", early_parse_mem); + +void __init platform_init(void) +{ + efi_init(); +#ifdef CONFIG_ACPI_TABLE_UPGRADE + acpi_table_upgrade(); +#endif +#ifdef CONFIG_ACPI + acpi_gbl_use_default_register_widths = false; + acpi_boot_table_init(); + acpi_boot_init(); +#endif + +#ifdef CONFIG_NUMA + init_numa_memory(); +#endif + dmi_setup(); + smbios_parse(); + pr_info("The BIOS Version: %s\n", b_info.bios_version); + + efi_runtime_init(); +} + +static void __init check_kernel_sections_mem(void) +{ + phys_addr_t start = __pa_symbol(&_text); + phys_addr_t size = __pa_symbol(&_end) - start; + + if (!memblock_is_region_memory(start, size)) { + pr_info("Kernel sections are not in the memory maps\n"); + memblock_add(start, size); + } +} + +/* + * arch_mem_init - initialize memory management subsystem + */ +static void __init arch_mem_init(char **cmdline_p) +{ + if (usermem) + pr_info("User-defined physical RAM map overwrite\n"); + + check_kernel_sections_mem(); + + /* + * In order to reduce the possibility of kernel panic when failed to + * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate + * low memory as small as possible before plat_swiotlb_setup(), so + * make sparse_init() using top-down allocation. + */ + memblock_set_bottom_up(false); + sparse_init(); + memblock_set_bottom_up(true); + + plat_swiotlb_setup(); + + dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); + + memblock_dump_all(); + + early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn)); +} + +static void __init resource_init(void) +{ + long i = 0; + size_t res_size; + struct resource *res; + struct memblock_region *region; + + code_resource.start = __pa_symbol(&_text); + code_resource.end = __pa_symbol(&_etext) - 1; + data_resource.start = __pa_symbol(&_etext); + data_resource.end = __pa_symbol(&_edata) - 1; + bss_resource.start = __pa_symbol(&__bss_start); + bss_resource.end = __pa_symbol(&__bss_stop) - 1; + + num_standard_resources = memblock.memory.cnt; + res_size = num_standard_resources * sizeof(*standard_resources); + standard_resources = memblock_alloc(res_size, SMP_CACHE_BYTES); + + for_each_mem_region(region) { + res = &standard_resources[i++]; + if (!memblock_is_nomap(region)) { + res->name = "System RAM"; + res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; + res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); + res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; + } else { + res->name = "Reserved"; + res->flags = IORESOURCE_MEM; + res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region)); + res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1; + } + + request_resource(&iomem_resource, res); + + /* + * We don't know which RAM region contains kernel data, + * so we try it repeatedly and let the resource manager + * test it. + */ + request_resource(res, &code_resource); + request_resource(res, &data_resource); + request_resource(res, &bss_resource); + } +} + +static int __init reserve_memblock_reserved_regions(void) +{ + u64 i, j; + + for (i = 0; i < num_standard_resources; ++i) { + struct resource *mem = &standard_resources[i]; + phys_addr_t r_start, r_end, mem_size = resource_size(mem); + + if (!memblock_is_region_reserved(mem->start, mem_size)) + continue; + + for_each_reserved_mem_range(j, &r_start, &r_end) { + resource_size_t start, end; + + start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start); + end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end); + + if (start > mem->end || end < mem->start) + continue; + + reserve_region_with_split(mem, start, end, "Reserved"); + } + } + + return 0; +} +arch_initcall(reserve_memblock_reserved_regions); + +#ifdef CONFIG_SMP +static void __init prefill_possible_map(void) +{ + int i, possible; + + possible = num_processors + disabled_cpus; + if (possible > nr_cpu_ids) + possible = nr_cpu_ids; + + pr_info("SMP: Allowing %d CPUs, %d hotplug CPUs\n", + possible, max((possible - num_processors), 0)); + + for (i = 0; i < possible; i++) + set_cpu_possible(i, true); + for (; i < NR_CPUS; i++) + set_cpu_possible(i, false); + + nr_cpu_ids = possible; +} +#else +static inline void prefill_possible_map(void) {} +#endif + +void __init setup_arch(char **cmdline_p) +{ + cpu_probe(); + *cmdline_p = boot_command_line; + + init_environ(); + memblock_init(); + parse_early_param(); + + platform_init(); + pagetable_init(); + arch_mem_init(cmdline_p); + + resource_init(); + plat_smp_setup(); + prefill_possible_map(); + + paging_init(); +} diff --git a/arch/loongarch/kernel/signal.c b/arch/loongarch/kernel/signal.c new file mode 100644 index 000000000000..7f4889df4a17 --- /dev/null +++ b/arch/loongarch/kernel/signal.c @@ -0,0 +1,566 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1994 - 2000 Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2014, Imagination Technologies Ltd. + */ +#include <linux/audit.h> +#include <linux/cache.h> +#include <linux/context_tracking.h> +#include <linux/irqflags.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/personality.h> +#include <linux/smp.h> +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/wait.h> +#include <linux/ptrace.h> +#include <linux/unistd.h> +#include <linux/compiler.h> +#include <linux/syscalls.h> +#include <linux/uaccess.h> + +#include <asm/asm.h> +#include <asm/cacheflush.h> +#include <asm/cpu-features.h> +#include <asm/fpu.h> +#include <asm/ucontext.h> +#include <asm/vdso.h> + +#ifdef DEBUG_SIG +# define DEBUGP(fmt, args...) printk("%s: " fmt, __func__, ##args) +#else +# define DEBUGP(fmt, args...) +#endif + +/* Make sure we will not lose FPU ownership */ +#define lock_fpu_owner() ({ preempt_disable(); pagefault_disable(); }) +#define unlock_fpu_owner() ({ pagefault_enable(); preempt_enable(); }) + +/* Assembly functions to move context to/from the FPU */ +extern asmlinkage int +_save_fp_context(void __user *fpregs, void __user *fcc, void __user *csr); +extern asmlinkage int +_restore_fp_context(void __user *fpregs, void __user *fcc, void __user *csr); + +struct rt_sigframe { + struct siginfo rs_info; + struct ucontext rs_uctx; +}; + +struct _ctx_layout { + struct sctx_info *addr; + unsigned int size; +}; + +struct extctx_layout { + unsigned long size; + unsigned int flags; + struct _ctx_layout fpu; + struct _ctx_layout end; +}; + +static void __user *get_ctx_through_ctxinfo(struct sctx_info *info) +{ + return (void __user *)((char *)info + sizeof(struct sctx_info)); +} + +/* + * Thread saved context copy to/from a signal context presumed to be on the + * user stack, and therefore accessed with appropriate macros from uaccess.h. + */ +static int copy_fpu_to_sigcontext(struct fpu_context __user *ctx) +{ + int i; + int err = 0; + uint64_t __user *regs = (uint64_t *)&ctx->regs; + uint64_t __user *fcc = &ctx->fcc; + uint32_t __user *fcsr = &ctx->fcsr; + + for (i = 0; i < NUM_FPU_REGS; i++) { + err |= + __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), + ®s[i]); + } + err |= __put_user(current->thread.fpu.fcc, fcc); + err |= __put_user(current->thread.fpu.fcsr, fcsr); + + return err; +} + +static int copy_fpu_from_sigcontext(struct fpu_context __user *ctx) +{ + int i; + int err = 0; + u64 fpr_val; + uint64_t __user *regs = (uint64_t *)&ctx->regs; + uint64_t __user *fcc = &ctx->fcc; + uint32_t __user *fcsr = &ctx->fcsr; + + for (i = 0; i < NUM_FPU_REGS; i++) { + err |= __get_user(fpr_val, ®s[i]); + set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); + } + err |= __get_user(current->thread.fpu.fcc, fcc); + err |= __get_user(current->thread.fpu.fcsr, fcsr); + + return err; +} + +/* + * Wrappers for the assembly _{save,restore}_fp_context functions. + */ +static int save_hw_fpu_context(struct fpu_context __user *ctx) +{ + uint64_t __user *regs = (uint64_t *)&ctx->regs; + uint64_t __user *fcc = &ctx->fcc; + uint32_t __user *fcsr = &ctx->fcsr; + + return _save_fp_context(regs, fcc, fcsr); +} + +static int restore_hw_fpu_context(struct fpu_context __user *ctx) +{ + uint64_t __user *regs = (uint64_t *)&ctx->regs; + uint64_t __user *fcc = &ctx->fcc; + uint32_t __user *fcsr = &ctx->fcsr; + + return _restore_fp_context(regs, fcc, fcsr); +} + +static int fcsr_pending(unsigned int __user *fcsr) +{ + int err, sig = 0; + unsigned int csr, enabled; + + err = __get_user(csr, fcsr); + enabled = ((csr & FPU_CSR_ALL_E) << 24); + /* + * If the signal handler set some FPU exceptions, clear it and + * send SIGFPE. + */ + if (csr & enabled) { + csr &= ~enabled; + err |= __put_user(csr, fcsr); + sig = SIGFPE; + } + return err ?: sig; +} + +/* + * Helper routines + */ +static int protected_save_fpu_context(struct extctx_layout *extctx) +{ + int err = 0; + struct sctx_info __user *info = extctx->fpu.addr; + struct fpu_context __user *fpu_ctx = (struct fpu_context *)get_ctx_through_ctxinfo(info); + uint64_t __user *regs = (uint64_t *)&fpu_ctx->regs; + uint64_t __user *fcc = &fpu_ctx->fcc; + uint32_t __user *fcsr = &fpu_ctx->fcsr; + + while (1) { + lock_fpu_owner(); + if (is_fpu_owner()) + err = save_hw_fpu_context(fpu_ctx); + else + err = copy_fpu_to_sigcontext(fpu_ctx); + unlock_fpu_owner(); + + err |= __put_user(FPU_CTX_MAGIC, &info->magic); + err |= __put_user(extctx->fpu.size, &info->size); + + if (likely(!err)) + break; + /* Touch the FPU context and try again */ + err = __put_user(0, ®s[0]) | + __put_user(0, ®s[31]) | + __put_user(0, fcc) | + __put_user(0, fcsr); + if (err) + return err; /* really bad sigcontext */ + } + + return err; +} + +static int protected_restore_fpu_context(struct extctx_layout *extctx) +{ + int err = 0, sig = 0, tmp __maybe_unused; + struct sctx_info __user *info = extctx->fpu.addr; + struct fpu_context __user *fpu_ctx = (struct fpu_context *)get_ctx_through_ctxinfo(info); + uint64_t __user *regs = (uint64_t *)&fpu_ctx->regs; + uint64_t __user *fcc = &fpu_ctx->fcc; + uint32_t __user *fcsr = &fpu_ctx->fcsr; + + err = sig = fcsr_pending(fcsr); + if (err < 0) + return err; + + while (1) { + lock_fpu_owner(); + if (is_fpu_owner()) + err = restore_hw_fpu_context(fpu_ctx); + else + err = copy_fpu_from_sigcontext(fpu_ctx); + unlock_fpu_owner(); + + if (likely(!err)) + break; + /* Touch the FPU context and try again */ + err = __get_user(tmp, ®s[0]) | + __get_user(tmp, ®s[31]) | + __get_user(tmp, fcc) | + __get_user(tmp, fcsr); + if (err) + break; /* really bad sigcontext */ + } + + return err ?: sig; +} + +static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, + struct extctx_layout *extctx) +{ + int i, err = 0; + struct sctx_info __user *info; + + err |= __put_user(regs->csr_era, &sc->sc_pc); + err |= __put_user(extctx->flags, &sc->sc_flags); + + err |= __put_user(0, &sc->sc_regs[0]); + for (i = 1; i < 32; i++) + err |= __put_user(regs->regs[i], &sc->sc_regs[i]); + + if (extctx->fpu.addr) + err |= protected_save_fpu_context(extctx); + + /* Set the "end" magic */ + info = (struct sctx_info *)extctx->end.addr; + err |= __put_user(0, &info->magic); + err |= __put_user(0, &info->size); + + return err; +} + +static int parse_extcontext(struct sigcontext __user *sc, struct extctx_layout *extctx) +{ + int err = 0; + unsigned int magic, size; + struct sctx_info __user *info = (struct sctx_info __user *)&sc->sc_extcontext; + + while(1) { + err |= __get_user(magic, &info->magic); + err |= __get_user(size, &info->size); + if (err) + return err; + + switch (magic) { + case 0: /* END */ + goto done; + + case FPU_CTX_MAGIC: + if (size < (sizeof(struct sctx_info) + + sizeof(struct fpu_context))) + goto invalid; + extctx->fpu.addr = info; + break; + + default: + goto invalid; + } + + info = (struct sctx_info *)((char *)info + size); + } + +done: + return 0; + +invalid: + return -EINVAL; +} + +static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) +{ + int i, err = 0; + struct extctx_layout extctx; + + memset(&extctx, 0, sizeof(struct extctx_layout)); + + err = __get_user(extctx.flags, &sc->sc_flags); + if (err) + goto bad; + + err = parse_extcontext(sc, &extctx); + if (err) + goto bad; + + conditional_used_math(extctx.flags & SC_USED_FP); + + /* + * The signal handler may have used FPU; give it up if the program + * doesn't want it following sigreturn. + */ + if (!(extctx.flags & SC_USED_FP)) + lose_fpu(0); + + /* Always make any pending restarted system calls return -EINTR */ + current->restart_block.fn = do_no_restart_syscall; + + err |= __get_user(regs->csr_era, &sc->sc_pc); + for (i = 1; i < 32; i++) + err |= __get_user(regs->regs[i], &sc->sc_regs[i]); + + if (extctx.fpu.addr) + err |= protected_restore_fpu_context(&extctx); + +bad: + return err; +} + +static unsigned int handle_flags(void) +{ + unsigned int flags = 0; + + flags = used_math() ? SC_USED_FP : 0; + + switch (current->thread.error_code) { + case 1: + flags |= SC_ADDRERR_RD; + break; + case 2: + flags |= SC_ADDRERR_WR; + break; + } + + return flags; +} + +static unsigned long extframe_alloc(struct extctx_layout *extctx, + struct _ctx_layout *layout, + size_t size, unsigned int align, unsigned long base) +{ + unsigned long new_base = base - size; + + new_base = round_down(new_base, (align < 16 ? 16 : align)); + new_base -= sizeof(struct sctx_info); + + layout->addr = (void *)new_base; + layout->size = (unsigned int)(base - new_base); + extctx->size += layout->size; + + return new_base; +} + +static unsigned long setup_extcontext(struct extctx_layout *extctx, unsigned long sp) +{ + unsigned long new_sp = sp; + + memset(extctx, 0, sizeof(struct extctx_layout)); + + extctx->flags = handle_flags(); + + /* Grow down, alloc "end" context info first. */ + new_sp -= sizeof(struct sctx_info); + extctx->end.addr = (void *)new_sp; + extctx->end.size = (unsigned int)sizeof(struct sctx_info); + extctx->size += extctx->end.size; + + if (extctx->flags & SC_USED_FP) { + if (cpu_has_fpu) + new_sp = extframe_alloc(extctx, &extctx->fpu, + sizeof(struct fpu_context), FPU_CTX_ALIGN, new_sp); + } + + return new_sp; +} + +void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, + struct extctx_layout *extctx) +{ + unsigned long sp; + + /* Default to using normal stack */ + sp = regs->regs[3]; + + /* + * If we are on the alternate signal stack and would overflow it, don't. + * Return an always-bogus address instead so we will die with SIGSEGV. + */ + if (on_sig_stack(sp) && + !likely(on_sig_stack(sp - sizeof(struct rt_sigframe)))) + return (void __user __force *)(-1UL); + + sp = sigsp(sp, ksig); + sp = round_down(sp, 16); + sp = setup_extcontext(extctx, sp); + sp -= sizeof(struct rt_sigframe); + + if (!IS_ALIGNED(sp, 16)) + BUG(); + + return (void __user *)sp; +} + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ + +asmlinkage long sys_rt_sigreturn(void) +{ + int sig; + sigset_t set; + struct pt_regs *regs; + struct rt_sigframe __user *frame; + + regs = current_pt_regs(); + frame = (struct rt_sigframe __user *)regs->regs[3]; + if (!access_ok(frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->rs_uctx.uc_sigmask, sizeof(set))) + goto badframe; + + set_current_blocked(&set); + + sig = restore_sigcontext(regs, &frame->rs_uctx.uc_mcontext); + if (sig < 0) + goto badframe; + else if (sig) + force_sig(sig); + + regs->regs[0] = 0; /* No syscall restarting */ + if (restore_altstack(&frame->rs_uctx.uc_stack)) + goto badframe; + + return regs->regs[4]; + +badframe: + force_sig(SIGSEGV); + return 0; +} + +static int setup_rt_frame(void *sig_return, struct ksignal *ksig, + struct pt_regs *regs, sigset_t *set) +{ + int err = 0; + struct extctx_layout extctx; + struct rt_sigframe __user *frame; + + frame = get_sigframe(ksig, regs, &extctx); + if (!access_ok(frame, sizeof(*frame) + extctx.size)) + return -EFAULT; + + /* Create siginfo. */ + err |= copy_siginfo_to_user(&frame->rs_info, &ksig->info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->rs_uctx.uc_flags); + err |= __put_user(NULL, &frame->rs_uctx.uc_link); + err |= __save_altstack(&frame->rs_uctx.uc_stack, regs->regs[3]); + err |= setup_sigcontext(regs, &frame->rs_uctx.uc_mcontext, &extctx); + err |= __copy_to_user(&frame->rs_uctx.uc_sigmask, set, sizeof(*set)); + + if (err) + return -EFAULT; + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = pointer to siginfo + * a2 = pointer to ucontext + * + * c0_era point to the signal handler, $r3 (sp) points to + * the struct rt_sigframe. + */ + regs->regs[4] = ksig->sig; + regs->regs[5] = (unsigned long) &frame->rs_info; + regs->regs[6] = (unsigned long) &frame->rs_uctx; + regs->regs[3] = (unsigned long) frame; + regs->regs[1] = (unsigned long) sig_return; + regs->csr_era = (unsigned long) ksig->ka.sa.sa_handler; + + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", + current->comm, current->pid, + frame, regs->csr_era, regs->regs[1]); + + return 0; +} + +static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) +{ + int ret; + sigset_t *oldset = sigmask_to_save(); + void *vdso = current->mm->context.vdso; + + /* Are we from a system call? */ + if (regs->regs[0]) { + switch (regs->regs[4]) { + case -ERESTART_RESTARTBLOCK: + case -ERESTARTNOHAND: + regs->regs[4] = -EINTR; + break; + case -ERESTARTSYS: + if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { + regs->regs[4] = -EINTR; + break; + } + fallthrough; + case -ERESTARTNOINTR: + regs->regs[4] = regs->orig_a0; + regs->csr_era -= 4; + } + + regs->regs[0] = 0; /* Don't deal with this again. */ + } + + rseq_signal_deliver(ksig, regs); + + ret = setup_rt_frame(vdso + current->thread.vdso->offset_sigreturn, ksig, regs, oldset); + + signal_setup_done(ret, ksig, 0); +} + +void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal) +{ + struct ksignal ksig; + + if (has_signal && get_signal(&ksig)) { + /* Whee! Actually deliver the signal. */ + handle_signal(&ksig, regs); + return; + } + + /* Are we from a system call? */ + if (regs->regs[0]) { + switch (regs->regs[4]) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs->regs[4] = regs->orig_a0; + regs->csr_era -= 4; + break; + + case -ERESTART_RESTARTBLOCK: + regs->regs[4] = regs->orig_a0; + regs->regs[11] = __NR_restart_syscall; + regs->csr_era -= 4; + break; + } + regs->regs[0] = 0; /* Don't deal with this again. */ + } + + /* + * If there's no signal to deliver, we just put the saved sigmask + * back + */ + restore_saved_sigmask(); +} diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c new file mode 100644 index 000000000000..b8c53b755a25 --- /dev/null +++ b/arch/loongarch/kernel/smp.c @@ -0,0 +1,751 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 2000, 2001 Kanoj Sarcar + * Copyright (C) 2000, 2001 Ralf Baechle + * Copyright (C) 2000, 2001 Silicon Graphics, Inc. + * Copyright (C) 2000, 2001, 2003 Broadcom Corporation + */ +#include <linux/cpu.h> +#include <linux/cpumask.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/seq_file.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/export.h> +#include <linux/time.h> +#include <linux/tracepoint.h> +#include <linux/sched/hotplug.h> +#include <linux/sched/task_stack.h> + +#include <asm/cpu.h> +#include <asm/idle.h> +#include <asm/loongson.h> +#include <asm/mmu_context.h> +#include <asm/numa.h> +#include <asm/processor.h> +#include <asm/setup.h> +#include <asm/time.h> + +int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ +EXPORT_SYMBOL(__cpu_number_map); + +int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */ +EXPORT_SYMBOL(__cpu_logical_map); + +/* Number of threads (siblings) per CPU core */ +int smp_num_siblings = 1; +EXPORT_SYMBOL(smp_num_siblings); + +/* Representing the threads (siblings) of each logical CPU */ +cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; +EXPORT_SYMBOL(cpu_sibling_map); + +/* Representing the core map of multi-core chips of each logical CPU */ +cpumask_t cpu_core_map[NR_CPUS] __read_mostly; +EXPORT_SYMBOL(cpu_core_map); + +static DECLARE_COMPLETION(cpu_starting); +static DECLARE_COMPLETION(cpu_running); + +/* + * A logcal cpu mask containing only one VPE per core to + * reduce the number of IPIs on large MT systems. + */ +cpumask_t cpu_foreign_map[NR_CPUS] __read_mostly; +EXPORT_SYMBOL(cpu_foreign_map); + +/* representing cpus for which sibling maps can be computed */ +static cpumask_t cpu_sibling_setup_map; + +/* representing cpus for which core maps can be computed */ +static cpumask_t cpu_core_setup_map; + +struct secondary_data cpuboot_data; +static DEFINE_PER_CPU(int, cpu_state); +DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); +EXPORT_PER_CPU_SYMBOL(irq_stat); + +enum ipi_msg_type { + IPI_RESCHEDULE, + IPI_CALL_FUNCTION, +}; + +static const char *ipi_types[NR_IPI] __tracepoint_string = { + [IPI_RESCHEDULE] = "Rescheduling interrupts", + [IPI_CALL_FUNCTION] = "Function call interrupts", +}; + +void show_ipi_list(struct seq_file *p, int prec) +{ + unsigned int cpu, i; + + for (i = 0; i < NR_IPI; i++) { + seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i, prec >= 4 ? " " : ""); + for_each_online_cpu(cpu) + seq_printf(p, "%10u ", per_cpu(irq_stat, cpu).ipi_irqs[i]); + seq_printf(p, " LoongArch %d %s\n", i + 1, ipi_types[i]); + } +} + +/* Send mailbox buffer via Mail_Send */ +static void csr_mail_send(uint64_t data, int cpu, int mailbox) +{ + uint64_t val; + + /* Send high 32 bits */ + val = IOCSR_MBUF_SEND_BLOCKING; + val |= (IOCSR_MBUF_SEND_BOX_HI(mailbox) << IOCSR_MBUF_SEND_BOX_SHIFT); + val |= (cpu << IOCSR_MBUF_SEND_CPU_SHIFT); + val |= (data & IOCSR_MBUF_SEND_H32_MASK); + iocsr_write64(val, LOONGARCH_IOCSR_MBUF_SEND); + + /* Send low 32 bits */ + val = IOCSR_MBUF_SEND_BLOCKING; + val |= (IOCSR_MBUF_SEND_BOX_LO(mailbox) << IOCSR_MBUF_SEND_BOX_SHIFT); + val |= (cpu << IOCSR_MBUF_SEND_CPU_SHIFT); + val |= (data << IOCSR_MBUF_SEND_BUF_SHIFT); + iocsr_write64(val, LOONGARCH_IOCSR_MBUF_SEND); +}; + +static u32 ipi_read_clear(int cpu) +{ + u32 action; + + /* Load the ipi register to figure out what we're supposed to do */ + action = iocsr_read32(LOONGARCH_IOCSR_IPI_STATUS); + /* Clear the ipi register to clear the interrupt */ + iocsr_write32(action, LOONGARCH_IOCSR_IPI_CLEAR); + smp_mb(); + + return action; +} + +static void ipi_write_action(int cpu, u32 action) +{ + unsigned int irq = 0; + + while ((irq = ffs(action))) { + uint32_t val = IOCSR_IPI_SEND_BLOCKING; + + val |= (irq - 1); + val |= (cpu << IOCSR_IPI_SEND_CPU_SHIFT); + iocsr_write32(val, LOONGARCH_IOCSR_IPI_SEND); + action &= ~BIT(irq - 1); + } +} + +void loongson3_send_ipi_single(int cpu, unsigned int action) +{ + ipi_write_action(cpu_logical_map(cpu), (u32)action); +} + +void loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action) +{ + unsigned int i; + + for_each_cpu(i, mask) + ipi_write_action(cpu_logical_map(i), (u32)action); +} + +irqreturn_t loongson3_ipi_interrupt(int irq, void *dev) +{ + unsigned int action; + unsigned int cpu = smp_processor_id(); + + action = ipi_read_clear(cpu_logical_map(cpu)); + + if (action & SMP_RESCHEDULE) { + scheduler_ipi(); + per_cpu(irq_stat, cpu).ipi_irqs[IPI_RESCHEDULE]++; + } + + if (action & SMP_CALL_FUNCTION) { + generic_smp_call_function_interrupt(); + per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++; + } + + return IRQ_HANDLED; +} + +void __init loongson3_smp_setup(void) +{ + cpu_data[0].core = cpu_logical_map(0) % loongson_sysconf.cores_per_package; + cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package; + + iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_EN); + pr_info("Detected %i available CPU(s)\n", loongson_sysconf.nr_cpus); +} + +void __init loongson3_prepare_cpus(unsigned int max_cpus) +{ + int i = 0; + + for (i = 0; i < loongson_sysconf.nr_cpus; i++) { + set_cpu_present(i, true); + csr_mail_send(0, __cpu_logical_map[i], 0); + } + + per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; +} + +/* + * Setup the PC, SP, and TP of a secondary processor and start it running! + */ +void loongson3_boot_secondary(int cpu, struct task_struct *idle) +{ + unsigned long entry; + + pr_info("Booting CPU#%d...\n", cpu); + + entry = __pa_symbol((unsigned long)&smpboot_entry); + cpuboot_data.stack = (unsigned long)__KSTK_TOS(idle); + cpuboot_data.thread_info = (unsigned long)task_thread_info(idle); + + csr_mail_send(entry, cpu_logical_map(cpu), 0); + + loongson3_send_ipi_single(cpu, SMP_BOOT_CPU); +} + +/* + * SMP init and finish on secondary CPUs + */ +void loongson3_init_secondary(void) +{ + unsigned int cpu = smp_processor_id(); + unsigned int imask = ECFGF_IP0 | ECFGF_IP1 | ECFGF_IP2 | + ECFGF_IPI | ECFGF_PMC | ECFGF_TIMER; + + change_csr_ecfg(ECFG0_IM, imask); + + iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_EN); + +#ifdef CONFIG_NUMA + numa_add_cpu(cpu); +#endif + per_cpu(cpu_state, cpu) = CPU_ONLINE; + cpu_data[cpu].core = + cpu_logical_map(cpu) % loongson_sysconf.cores_per_package; + cpu_data[cpu].package = + cpu_logical_map(cpu) / loongson_sysconf.cores_per_package; +} + +void loongson3_smp_finish(void) +{ + local_irq_enable(); + iocsr_write64(0, LOONGARCH_IOCSR_MBUF0); + pr_info("CPU#%d finished\n", smp_processor_id()); +} + +#ifdef CONFIG_HOTPLUG_CPU + +static bool io_master(int cpu) +{ + if (cpu == 0) + return true; + + return false; +} + +int loongson3_cpu_disable(void) +{ + unsigned long flags; + unsigned int cpu = smp_processor_id(); + + if (io_master(cpu)) + return -EBUSY; + +#ifdef CONFIG_NUMA + numa_remove_cpu(cpu); +#endif + set_cpu_online(cpu, false); + calculate_cpu_foreign_map(); + local_irq_save(flags); + irq_migrate_all_off_this_cpu(); + clear_csr_ecfg(ECFG0_IM); + local_irq_restore(flags); + local_flush_tlb_all(); + + return 0; +} + +void loongson3_cpu_die(unsigned int cpu) +{ + while (per_cpu(cpu_state, cpu) != CPU_DEAD) + cpu_relax(); + + mb(); +} + +/* + * The target CPU should go to XKPRANGE (uncached area) and flush + * ICache/DCache/VCache before the control CPU can safely disable its clock. + */ +static void loongson3_play_dead(int *state_addr) +{ + register int val; + register void *addr; + register void (*init_fn)(void); + + __asm__ __volatile__( + " li.d %[addr], 0x8000000000000000\n" + "1: cacop 0x8, %[addr], 0 \n" /* flush ICache */ + " cacop 0x8, %[addr], 1 \n" + " cacop 0x8, %[addr], 2 \n" + " cacop 0x8, %[addr], 3 \n" + " cacop 0x9, %[addr], 0 \n" /* flush DCache */ + " cacop 0x9, %[addr], 1 \n" + " cacop 0x9, %[addr], 2 \n" + " cacop 0x9, %[addr], 3 \n" + " addi.w %[sets], %[sets], -1 \n" + " addi.d %[addr], %[addr], 0x40 \n" + " bnez %[sets], 1b \n" + " li.d %[addr], 0x8000000000000000\n" + "2: cacop 0xa, %[addr], 0 \n" /* flush VCache */ + " cacop 0xa, %[addr], 1 \n" + " cacop 0xa, %[addr], 2 \n" + " cacop 0xa, %[addr], 3 \n" + " cacop 0xa, %[addr], 4 \n" + " cacop 0xa, %[addr], 5 \n" + " cacop 0xa, %[addr], 6 \n" + " cacop 0xa, %[addr], 7 \n" + " cacop 0xa, %[addr], 8 \n" + " cacop 0xa, %[addr], 9 \n" + " cacop 0xa, %[addr], 10 \n" + " cacop 0xa, %[addr], 11 \n" + " cacop 0xa, %[addr], 12 \n" + " cacop 0xa, %[addr], 13 \n" + " cacop 0xa, %[addr], 14 \n" + " cacop 0xa, %[addr], 15 \n" + " addi.w %[vsets], %[vsets], -1 \n" + " addi.d %[addr], %[addr], 0x40 \n" + " bnez %[vsets], 2b \n" + " li.w %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */ + " st.w %[val], %[state_addr], 0 \n" + " dbar 0 \n" + " cacop 0x11, %[state_addr], 0 \n" /* flush entry of *state_addr */ + : [addr] "=&r" (addr), [val] "=&r" (val) + : [state_addr] "r" (state_addr), + [sets] "r" (cpu_data[smp_processor_id()].dcache.sets), + [vsets] "r" (cpu_data[smp_processor_id()].vcache.sets)); + + local_irq_enable(); + change_csr_ecfg(ECFG0_IM, ECFGF_IPI); + + __asm__ __volatile__( + " idle 0 \n" + " li.w $t0, 0x1020 \n" + " iocsrrd.d %[init_fn], $t0 \n" /* Get init PC */ + : [init_fn] "=&r" (addr) + : /* No Input */ + : "a0"); + init_fn = __va(addr); + + init_fn(); + unreachable(); +} + +void play_dead(void) +{ + int *state_addr; + unsigned int cpu = smp_processor_id(); + void (*play_dead_uncached)(int *s); + + idle_task_exit(); + play_dead_uncached = (void *)TO_UNCACHE(__pa((unsigned long)loongson3_play_dead)); + state_addr = &per_cpu(cpu_state, cpu); + mb(); + play_dead_uncached(state_addr); +} + +static int loongson3_enable_clock(unsigned int cpu) +{ + uint64_t core_id = cpu_data[cpu].core; + uint64_t package_id = cpu_data[cpu].package; + + LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3); + + return 0; +} + +static int loongson3_disable_clock(unsigned int cpu) +{ + uint64_t core_id = cpu_data[cpu].core; + uint64_t package_id = cpu_data[cpu].package; + + LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3)); + + return 0; +} + +static int register_loongson3_notifier(void) +{ + return cpuhp_setup_state_nocalls(CPUHP_LOONGARCH_SOC_PREPARE, + "loongarch/loongson:prepare", + loongson3_enable_clock, + loongson3_disable_clock); +} +early_initcall(register_loongson3_notifier); + +#endif + +/* + * Power management + */ +#ifdef CONFIG_PM + +static int loongson3_ipi_suspend(void) +{ + return 0; +} + +static void loongson3_ipi_resume(void) +{ + iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_EN); +} + +static struct syscore_ops loongson3_ipi_syscore_ops = { + .resume = loongson3_ipi_resume, + .suspend = loongson3_ipi_suspend, +}; + +/* + * Enable boot cpu ipi before enabling nonboot cpus + * during syscore_resume. + */ +static int __init ipi_pm_init(void) +{ + register_syscore_ops(&loongson3_ipi_syscore_ops); + return 0; +} + +core_initcall(ipi_pm_init); +#endif + +static inline void set_cpu_sibling_map(int cpu) +{ + int i; + + cpumask_set_cpu(cpu, &cpu_sibling_setup_map); + + if (smp_num_siblings <= 1) + cpumask_set_cpu(cpu, &cpu_sibling_map[cpu]); + else { + for_each_cpu(i, &cpu_sibling_setup_map) { + if (cpus_are_siblings(cpu, i)) { + cpumask_set_cpu(i, &cpu_sibling_map[cpu]); + cpumask_set_cpu(cpu, &cpu_sibling_map[i]); + } + } + } +} + +static inline void set_cpu_core_map(int cpu) +{ + int i; + + cpumask_set_cpu(cpu, &cpu_core_setup_map); + + for_each_cpu(i, &cpu_core_setup_map) { + if (cpu_data[cpu].package == cpu_data[i].package) { + cpumask_set_cpu(i, &cpu_core_map[cpu]); + cpumask_set_cpu(cpu, &cpu_core_map[i]); + } + } +} + +/* + * Calculate a new cpu_foreign_map mask whenever a + * new cpu appears or disappears. + */ +void calculate_cpu_foreign_map(void) +{ + int i, k, core_present; + cpumask_t temp_foreign_map; + + /* Re-calculate the mask */ + cpumask_clear(&temp_foreign_map); + for_each_online_cpu(i) { + core_present = 0; + for_each_cpu(k, &temp_foreign_map) + if (cpus_are_siblings(i, k)) + core_present = 1; + if (!core_present) + cpumask_set_cpu(i, &temp_foreign_map); + } + + for_each_online_cpu(i) + cpumask_andnot(&cpu_foreign_map[i], + &temp_foreign_map, &cpu_sibling_map[i]); +} + +/* Preload SMP state for boot cpu */ +void smp_prepare_boot_cpu(void) +{ + unsigned int cpu, node, rr_node; + + set_cpu_possible(0, true); + set_cpu_online(0, true); + set_my_cpu_offset(per_cpu_offset(0)); + + rr_node = first_node(node_online_map); + for_each_possible_cpu(cpu) { + node = early_cpu_to_node(cpu); + + /* + * The mapping between present cpus and nodes has been + * built during MADT and SRAT parsing. + * + * If possible cpus = present cpus here, early_cpu_to_node + * will return valid node. + * + * If possible cpus > present cpus here (e.g. some possible + * cpus will be added by cpu-hotplug later), for possible but + * not present cpus, early_cpu_to_node will return NUMA_NO_NODE, + * and we just map them to online nodes in round-robin way. + * Once hotplugged, new correct mapping will be built for them. + */ + if (node != NUMA_NO_NODE) + set_cpu_numa_node(cpu, node); + else { + set_cpu_numa_node(cpu, rr_node); + rr_node = next_node_in(rr_node, node_online_map); + } + } +} + +/* called from main before smp_init() */ +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + init_new_context(current, &init_mm); + current_thread_info()->cpu = 0; + loongson3_prepare_cpus(max_cpus); + set_cpu_sibling_map(0); + set_cpu_core_map(0); + calculate_cpu_foreign_map(); +#ifndef CONFIG_HOTPLUG_CPU + init_cpu_present(cpu_possible_mask); +#endif +} + +int __cpu_up(unsigned int cpu, struct task_struct *tidle) +{ + loongson3_boot_secondary(cpu, tidle); + + /* Wait for CPU to start and be ready to sync counters */ + if (!wait_for_completion_timeout(&cpu_starting, + msecs_to_jiffies(5000))) { + pr_crit("CPU%u: failed to start\n", cpu); + return -EIO; + } + + /* Wait for CPU to finish startup & mark itself online before return */ + wait_for_completion(&cpu_running); + + return 0; +} + +/* + * First C code run on the secondary CPUs after being started up by + * the master. + */ +asmlinkage void start_secondary(void) +{ + unsigned int cpu; + + sync_counter(); + cpu = smp_processor_id(); + set_my_cpu_offset(per_cpu_offset(cpu)); + + cpu_probe(); + constant_clockevent_init(); + loongson3_init_secondary(); + + set_cpu_sibling_map(cpu); + set_cpu_core_map(cpu); + + notify_cpu_starting(cpu); + + /* Notify boot CPU that we're starting */ + complete(&cpu_starting); + + /* The CPU is running, now mark it online */ + set_cpu_online(cpu, true); + + calculate_cpu_foreign_map(); + + /* + * Notify boot CPU that we're up & online and it can safely return + * from __cpu_up() + */ + complete(&cpu_running); + + /* + * irq will be enabled in loongson3_smp_finish(), enabling it too + * early is dangerous. + */ + WARN_ON_ONCE(!irqs_disabled()); + loongson3_smp_finish(); + + cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); +} + +void __init smp_cpus_done(unsigned int max_cpus) +{ +} + +static void stop_this_cpu(void *dummy) +{ + set_cpu_online(smp_processor_id(), false); + calculate_cpu_foreign_map(); + local_irq_disable(); + while (true); +} + +void smp_send_stop(void) +{ + smp_call_function(stop_this_cpu, NULL, 0); +} + +int setup_profiling_timer(unsigned int multiplier) +{ + return 0; +} + +static void flush_tlb_all_ipi(void *info) +{ + local_flush_tlb_all(); +} + +void flush_tlb_all(void) +{ + on_each_cpu(flush_tlb_all_ipi, NULL, 1); +} + +static void flush_tlb_mm_ipi(void *mm) +{ + local_flush_tlb_mm((struct mm_struct *)mm); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + if (atomic_read(&mm->mm_users) == 0) + return; /* happens as a result of exit_mmap() */ + + preempt_disable(); + + if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + on_each_cpu_mask(mm_cpumask(mm), flush_tlb_mm_ipi, mm, 1); + } else { + unsigned int cpu; + + for_each_online_cpu(cpu) { + if (cpu != smp_processor_id() && cpu_context(cpu, mm)) + cpu_context(cpu, mm) = 0; + } + local_flush_tlb_mm(mm); + } + + preempt_enable(); +} + +struct flush_tlb_data { + struct vm_area_struct *vma; + unsigned long addr1; + unsigned long addr2; +}; + +static void flush_tlb_range_ipi(void *info) +{ + struct flush_tlb_data *fd = info; + + local_flush_tlb_range(fd->vma, fd->addr1, fd->addr2); +} + +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + + preempt_disable(); + if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + struct flush_tlb_data fd = { + .vma = vma, + .addr1 = start, + .addr2 = end, + }; + + on_each_cpu_mask(mm_cpumask(mm), flush_tlb_range_ipi, &fd, 1); + } else { + unsigned int cpu; + + for_each_online_cpu(cpu) { + if (cpu != smp_processor_id() && cpu_context(cpu, mm)) + cpu_context(cpu, mm) = 0; + } + local_flush_tlb_range(vma, start, end); + } + preempt_enable(); +} + +static void flush_tlb_kernel_range_ipi(void *info) +{ + struct flush_tlb_data *fd = info; + + local_flush_tlb_kernel_range(fd->addr1, fd->addr2); +} + +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + struct flush_tlb_data fd = { + .addr1 = start, + .addr2 = end, + }; + + on_each_cpu(flush_tlb_kernel_range_ipi, &fd, 1); +} + +static void flush_tlb_page_ipi(void *info) +{ + struct flush_tlb_data *fd = info; + + local_flush_tlb_page(fd->vma, fd->addr1); +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + preempt_disable(); + if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) { + struct flush_tlb_data fd = { + .vma = vma, + .addr1 = page, + }; + + on_each_cpu_mask(mm_cpumask(vma->vm_mm), flush_tlb_page_ipi, &fd, 1); + } else { + unsigned int cpu; + + for_each_online_cpu(cpu) { + if (cpu != smp_processor_id() && cpu_context(cpu, vma->vm_mm)) + cpu_context(cpu, vma->vm_mm) = 0; + } + local_flush_tlb_page(vma, page); + } + preempt_enable(); +} +EXPORT_SYMBOL(flush_tlb_page); + +static void flush_tlb_one_ipi(void *info) +{ + unsigned long vaddr = (unsigned long) info; + + local_flush_tlb_one(vaddr); +} + +void flush_tlb_one(unsigned long vaddr) +{ + on_each_cpu(flush_tlb_one_ipi, (void *)vaddr, 1); +} +EXPORT_SYMBOL(flush_tlb_one); diff --git a/arch/loongarch/kernel/switch.S b/arch/loongarch/kernel/switch.S new file mode 100644 index 000000000000..53e2fa8e580e --- /dev/null +++ b/arch/loongarch/kernel/switch.S @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/asm-offsets.h> +#include <asm/loongarch.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> +#include <asm/thread_info.h> + +/* + * task_struct *__switch_to(task_struct *prev, task_struct *next, + * struct thread_info *next_ti) + */ + .align 5 +SYM_FUNC_START(__switch_to) + csrrd t1, LOONGARCH_CSR_PRMD + stptr.d t1, a0, THREAD_CSRPRMD + + cpu_save_nonscratch a0 + stptr.d ra, a0, THREAD_REG01 + move tp, a2 + cpu_restore_nonscratch a1 + + li.w t0, _THREAD_SIZE - 32 + PTR_ADD t0, t0, tp + set_saved_sp t0, t1, t2 + + ldptr.d t1, a1, THREAD_CSRPRMD + csrwr t1, LOONGARCH_CSR_PRMD + + jr ra +SYM_FUNC_END(__switch_to) diff --git a/arch/loongarch/kernel/syscall.c b/arch/loongarch/kernel/syscall.c new file mode 100644 index 000000000000..3fc4211db989 --- /dev/null +++ b/arch/loongarch/kernel/syscall.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Author: Hanlu Li <lihanlu@loongson.cn> + * Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/capability.h> +#include <linux/entry-common.h> +#include <linux/errno.h> +#include <linux/linkage.h> +#include <linux/syscalls.h> +#include <linux/unistd.h> + +#include <asm/asm.h> +#include <asm/signal.h> +#include <asm/switch_to.h> +#include <asm-generic/syscalls.h> + +#undef __SYSCALL +#define __SYSCALL(nr, call) [nr] = (call), + +SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, unsigned long, + prot, unsigned long, flags, unsigned long, fd, off_t, offset) +{ + if (offset & ~PAGE_MASK) + return -EINVAL; + + return ksys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); +} + +void *sys_call_table[__NR_syscalls] = { + [0 ... __NR_syscalls - 1] = sys_ni_syscall, +#include <asm/unistd.h> +}; + +typedef long (*sys_call_fn)(unsigned long, unsigned long, + unsigned long, unsigned long, unsigned long, unsigned long); + +void noinstr do_syscall(struct pt_regs *regs) +{ + unsigned long nr; + sys_call_fn syscall_fn; + + nr = regs->regs[11]; + /* Set for syscall restarting */ + if (nr < NR_syscalls) + regs->regs[0] = nr + 1; + + regs->csr_era += 4; + regs->orig_a0 = regs->regs[4]; + regs->regs[4] = -ENOSYS; + + nr = syscall_enter_from_user_mode(regs, nr); + + if (nr < NR_syscalls) { + syscall_fn = sys_call_table[nr]; + regs->regs[4] = syscall_fn(regs->orig_a0, regs->regs[5], regs->regs[6], + regs->regs[7], regs->regs[8], regs->regs[9]); + } + + syscall_exit_to_user_mode(regs); +} diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c new file mode 100644 index 000000000000..fe6823875895 --- /dev/null +++ b/arch/loongarch/kernel/time.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Common time service routines for LoongArch machines. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/clockchips.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/sched_clock.h> +#include <linux/spinlock.h> + +#include <asm/cpu-features.h> +#include <asm/loongarch.h> +#include <asm/time.h> + +u64 cpu_clock_freq; +EXPORT_SYMBOL(cpu_clock_freq); +u64 const_clock_freq; +EXPORT_SYMBOL(const_clock_freq); + +static DEFINE_RAW_SPINLOCK(state_lock); +static DEFINE_PER_CPU(struct clock_event_device, constant_clockevent_device); + +static void constant_event_handler(struct clock_event_device *dev) +{ +} + +irqreturn_t constant_timer_interrupt(int irq, void *data) +{ + int cpu = smp_processor_id(); + struct clock_event_device *cd; + + /* Clear Timer Interrupt */ + write_csr_tintclear(CSR_TINTCLR_TI); + cd = &per_cpu(constant_clockevent_device, cpu); + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +static int constant_set_state_oneshot(struct clock_event_device *evt) +{ + unsigned long timer_config; + + raw_spin_lock(&state_lock); + + timer_config = csr_read64(LOONGARCH_CSR_TCFG); + timer_config |= CSR_TCFG_EN; + timer_config &= ~CSR_TCFG_PERIOD; + csr_write64(timer_config, LOONGARCH_CSR_TCFG); + + raw_spin_unlock(&state_lock); + + return 0; +} + +static int constant_set_state_oneshot_stopped(struct clock_event_device *evt) +{ + unsigned long timer_config; + + raw_spin_lock(&state_lock); + + timer_config = csr_read64(LOONGARCH_CSR_TCFG); + timer_config &= ~CSR_TCFG_EN; + csr_write64(timer_config, LOONGARCH_CSR_TCFG); + + raw_spin_unlock(&state_lock); + + return 0; +} + +static int constant_set_state_periodic(struct clock_event_device *evt) +{ + unsigned long period; + unsigned long timer_config; + + raw_spin_lock(&state_lock); + + period = const_clock_freq / HZ; + timer_config = period & CSR_TCFG_VAL; + timer_config |= (CSR_TCFG_PERIOD | CSR_TCFG_EN); + csr_write64(timer_config, LOONGARCH_CSR_TCFG); + + raw_spin_unlock(&state_lock); + + return 0; +} + +static int constant_set_state_shutdown(struct clock_event_device *evt) +{ + return 0; +} + +static int constant_timer_next_event(unsigned long delta, struct clock_event_device *evt) +{ + unsigned long timer_config; + + delta &= CSR_TCFG_VAL; + timer_config = delta | CSR_TCFG_EN; + csr_write64(timer_config, LOONGARCH_CSR_TCFG); + + return 0; +} + +static unsigned long __init get_loops_per_jiffy(void) +{ + unsigned long lpj = (unsigned long)const_clock_freq; + + do_div(lpj, HZ); + + return lpj; +} + +static long init_timeval; + +void sync_counter(void) +{ + /* Ensure counter begin at 0 */ + csr_write64(-init_timeval, LOONGARCH_CSR_CNTC); +} + +int constant_clockevent_init(void) +{ + unsigned int irq; + unsigned int cpu = smp_processor_id(); + unsigned long min_delta = 0x600; + unsigned long max_delta = (1UL << 48) - 1; + struct clock_event_device *cd; + static int timer_irq_installed = 0; + + irq = EXCCODE_TIMER - EXCCODE_INT_START; + + cd = &per_cpu(constant_clockevent_device, cpu); + + cd->name = "Constant"; + cd->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_PERCPU; + + cd->irq = irq; + cd->rating = 320; + cd->cpumask = cpumask_of(cpu); + cd->set_state_oneshot = constant_set_state_oneshot; + cd->set_state_oneshot_stopped = constant_set_state_oneshot_stopped; + cd->set_state_periodic = constant_set_state_periodic; + cd->set_state_shutdown = constant_set_state_shutdown; + cd->set_next_event = constant_timer_next_event; + cd->event_handler = constant_event_handler; + + clockevents_config_and_register(cd, const_clock_freq, min_delta, max_delta); + + if (timer_irq_installed) + return 0; + + timer_irq_installed = 1; + + sync_counter(); + + if (request_irq(irq, constant_timer_interrupt, IRQF_PERCPU | IRQF_TIMER, "timer", NULL)) + pr_err("Failed to request irq %d (timer)\n", irq); + + lpj_fine = get_loops_per_jiffy(); + pr_info("Constant clock event device register\n"); + + return 0; +} + +static u64 read_const_counter(struct clocksource *clk) +{ + return drdtime(); +} + +static u64 native_sched_clock(void) +{ + return read_const_counter(NULL); +} + +static struct clocksource clocksource_const = { + .name = "Constant", + .rating = 400, + .read = read_const_counter, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .vdso_clock_mode = VDSO_CLOCKMODE_CPU, +}; + +int __init constant_clocksource_init(void) +{ + int res; + unsigned long freq = const_clock_freq; + + res = clocksource_register_hz(&clocksource_const, freq); + + sched_clock_register(native_sched_clock, 64, freq); + + pr_info("Constant clock source device register\n"); + + return res; +} + +void __init time_init(void) +{ + if (!cpu_has_cpucfg) + const_clock_freq = cpu_clock_freq; + else + const_clock_freq = calc_const_freq(); + + init_timeval = drdtime() - csr_read64(LOONGARCH_CSR_CNTC); + + constant_clockevent_init(); + constant_clocksource_init(); +} diff --git a/arch/loongarch/kernel/topology.c b/arch/loongarch/kernel/topology.c new file mode 100644 index 000000000000..ab1a75c0b5a6 --- /dev/null +++ b/arch/loongarch/kernel/topology.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/cpu.h> +#include <linux/cpumask.h> +#include <linux/init.h> +#include <linux/node.h> +#include <linux/nodemask.h> +#include <linux/percpu.h> + +static DEFINE_PER_CPU(struct cpu, cpu_devices); + +#ifdef CONFIG_HOTPLUG_CPU +int arch_register_cpu(int cpu) +{ + int ret; + struct cpu *c = &per_cpu(cpu_devices, cpu); + + c->hotpluggable = 1; + ret = register_cpu(c, cpu); + if (ret < 0) + pr_warn("register_cpu %d failed (%d)\n", cpu, ret); + + return ret; +} +EXPORT_SYMBOL(arch_register_cpu); + +void arch_unregister_cpu(int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + + c->hotpluggable = 0; + unregister_cpu(c); +} +EXPORT_SYMBOL(arch_unregister_cpu); +#endif + +static int __init topology_init(void) +{ + int i, ret; + + for_each_present_cpu(i) { + struct cpu *c = &per_cpu(cpu_devices, i); + + c->hotpluggable = !!i; + ret = register_cpu(c, i); + if (ret < 0) + pr_warn("topology_init: register_cpu %d failed (%d)\n", i, ret); + } + + return 0; +} + +subsys_initcall(topology_init); diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c new file mode 100644 index 000000000000..e4060f84a221 --- /dev/null +++ b/arch/loongarch/kernel/traps.c @@ -0,0 +1,725 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/bitops.h> +#include <linux/bug.h> +#include <linux/compiler.h> +#include <linux/context_tracking.h> +#include <linux/entry-common.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/extable.h> +#include <linux/mm.h> +#include <linux/sched/mm.h> +#include <linux/sched/debug.h> +#include <linux/smp.h> +#include <linux/spinlock.h> +#include <linux/kallsyms.h> +#include <linux/memblock.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/kgdb.h> +#include <linux/kdebug.h> +#include <linux/kprobes.h> +#include <linux/notifier.h> +#include <linux/irq.h> +#include <linux/perf_event.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <asm/branch.h> +#include <asm/break.h> +#include <asm/cpu.h> +#include <asm/fpu.h> +#include <asm/loongarch.h> +#include <asm/mmu_context.h> +#include <asm/pgtable.h> +#include <asm/ptrace.h> +#include <asm/sections.h> +#include <asm/siginfo.h> +#include <asm/stacktrace.h> +#include <asm/tlb.h> +#include <asm/types.h> + +#include "access-helper.h" + +extern asmlinkage void handle_ade(void); +extern asmlinkage void handle_ale(void); +extern asmlinkage void handle_sys(void); +extern asmlinkage void handle_bp(void); +extern asmlinkage void handle_ri(void); +extern asmlinkage void handle_fpu(void); +extern asmlinkage void handle_fpe(void); +extern asmlinkage void handle_lbt(void); +extern asmlinkage void handle_lsx(void); +extern asmlinkage void handle_lasx(void); +extern asmlinkage void handle_reserved(void); +extern asmlinkage void handle_watch(void); +extern asmlinkage void handle_vint(void); + +static void show_backtrace(struct task_struct *task, const struct pt_regs *regs, + const char *loglvl, bool user) +{ + unsigned long addr; + unsigned long *sp = (unsigned long *)(regs->regs[3] & ~3); + + printk("%sCall Trace:", loglvl); +#ifdef CONFIG_KALLSYMS + printk("%s\n", loglvl); +#endif + while (!kstack_end(sp)) { + if (__get_addr(&addr, sp++, user)) { + printk("%s (Bad stack address)", loglvl); + break; + } + if (__kernel_text_address(addr)) + print_ip_sym(loglvl, addr); + } + printk("%s\n", loglvl); +} + +static void show_stacktrace(struct task_struct *task, + const struct pt_regs *regs, const char *loglvl, bool user) +{ + int i; + const int field = 2 * sizeof(unsigned long); + unsigned long stackdata; + unsigned long *sp = (unsigned long *)regs->regs[3]; + + printk("%sStack :", loglvl); + i = 0; + while ((unsigned long) sp & (PAGE_SIZE - 1)) { + if (i && ((i % (64 / field)) == 0)) { + pr_cont("\n"); + printk("%s ", loglvl); + } + if (i > 39) { + pr_cont(" ..."); + break; + } + + if (__get_addr(&stackdata, sp++, user)) { + pr_cont(" (Bad stack address)"); + break; + } + + pr_cont(" %0*lx", field, stackdata); + i++; + } + pr_cont("\n"); + show_backtrace(task, regs, loglvl, user); +} + +void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl) +{ + struct pt_regs regs; + + regs.csr_crmd = 0; + if (sp) { + regs.csr_era = 0; + regs.regs[1] = 0; + regs.regs[3] = (unsigned long)sp; + } else { + if (!task || task == current) + prepare_frametrace(®s); + else { + regs.csr_era = task->thread.reg01; + regs.regs[1] = 0; + regs.regs[3] = task->thread.reg03; + regs.regs[22] = task->thread.reg22; + } + } + + show_stacktrace(task, ®s, loglvl, false); +} + +static void show_code(unsigned int *pc, bool user) +{ + long i; + unsigned int insn; + + printk("Code:"); + + for(i = -3 ; i < 6 ; i++) { + if (__get_inst(&insn, pc + i, user)) { + pr_cont(" (Bad address in era)\n"); + break; + } + pr_cont("%c%08x%c", (i?' ':'<'), insn, (i?' ':'>')); + } + pr_cont("\n"); +} + +static void __show_regs(const struct pt_regs *regs) +{ + const int field = 2 * sizeof(unsigned long); + unsigned int excsubcode; + unsigned int exccode; + int i; + + show_regs_print_info(KERN_DEFAULT); + + /* + * Saved main processor registers + */ + for (i = 0; i < 32; ) { + if ((i % 4) == 0) + printk("$%2d :", i); + pr_cont(" %0*lx", field, regs->regs[i]); + + i++; + if ((i % 4) == 0) + pr_cont("\n"); + } + + /* + * Saved csr registers + */ + printk("era : %0*lx %pS\n", field, regs->csr_era, + (void *) regs->csr_era); + printk("ra : %0*lx %pS\n", field, regs->regs[1], + (void *) regs->regs[1]); + + printk("CSR crmd: %08lx ", regs->csr_crmd); + printk("CSR prmd: %08lx ", regs->csr_prmd); + printk("CSR euen: %08lx ", regs->csr_euen); + printk("CSR ecfg: %08lx ", regs->csr_ecfg); + printk("CSR estat: %08lx ", regs->csr_estat); + + pr_cont("\n"); + + exccode = ((regs->csr_estat) & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT; + excsubcode = ((regs->csr_estat) & CSR_ESTAT_ESUBCODE) >> CSR_ESTAT_ESUBCODE_SHIFT; + printk("ExcCode : %x (SubCode %x)\n", exccode, excsubcode); + + if (exccode >= EXCCODE_TLBL && exccode <= EXCCODE_ALE) + printk("BadVA : %0*lx\n", field, regs->csr_badvaddr); + + printk("PrId : %08x (%s)\n", read_cpucfg(LOONGARCH_CPUCFG0), + cpu_family_string()); +} + +void show_regs(struct pt_regs *regs) +{ + __show_regs((struct pt_regs *)regs); + dump_stack(); +} + +void show_registers(struct pt_regs *regs) +{ + __show_regs(regs); + print_modules(); + printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", + current->comm, current->pid, current_thread_info(), current); + + show_stacktrace(current, regs, KERN_DEFAULT, user_mode(regs)); + show_code((void *)regs->csr_era, user_mode(regs)); + printk("\n"); +} + +static DEFINE_RAW_SPINLOCK(die_lock); + +void __noreturn die(const char *str, struct pt_regs *regs) +{ + static int die_counter; + int sig = SIGSEGV; + + oops_enter(); + + if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_nr, + SIGSEGV) == NOTIFY_STOP) + sig = 0; + + console_verbose(); + raw_spin_lock_irq(&die_lock); + bust_spinlocks(1); + + printk("%s[#%d]:\n", str, ++die_counter); + show_registers(regs); + add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); + raw_spin_unlock_irq(&die_lock); + + oops_exit(); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) + panic("Fatal exception"); + + make_task_dead(sig); +} + +static inline void setup_vint_size(unsigned int size) +{ + unsigned int vs; + + vs = ilog2(size/4); + + if (vs == 0 || vs > 7) + panic("vint_size %d Not support yet", vs); + + csr_xchg32(vs<<CSR_ECFG_VS_SHIFT, CSR_ECFG_VS, LOONGARCH_CSR_ECFG); +} + +/* + * Send SIGFPE according to FCSR Cause bits, which must have already + * been masked against Enable bits. This is impotant as Inexact can + * happen together with Overflow or Underflow, and `ptrace' can set + * any bits. + */ +void force_fcsr_sig(unsigned long fcsr, void __user *fault_addr, + struct task_struct *tsk) +{ + int si_code = FPE_FLTUNK; + + if (fcsr & FPU_CSR_INV_X) + si_code = FPE_FLTINV; + else if (fcsr & FPU_CSR_DIV_X) + si_code = FPE_FLTDIV; + else if (fcsr & FPU_CSR_OVF_X) + si_code = FPE_FLTOVF; + else if (fcsr & FPU_CSR_UDF_X) + si_code = FPE_FLTUND; + else if (fcsr & FPU_CSR_INE_X) + si_code = FPE_FLTRES; + + force_sig_fault(SIGFPE, si_code, fault_addr); +} + +int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcsr) +{ + int si_code; + + switch (sig) { + case 0: + return 0; + + case SIGFPE: + force_fcsr_sig(fcsr, fault_addr, current); + return 1; + + case SIGBUS: + force_sig_fault(SIGBUS, BUS_ADRERR, fault_addr); + return 1; + + case SIGSEGV: + mmap_read_lock(current->mm); + if (vma_lookup(current->mm, (unsigned long)fault_addr)) + si_code = SEGV_ACCERR; + else + si_code = SEGV_MAPERR; + mmap_read_unlock(current->mm); + force_sig_fault(SIGSEGV, si_code, fault_addr); + return 1; + + default: + force_sig(sig); + return 1; + } +} + +/* + * Delayed fp exceptions when doing a lazy ctx switch + */ +asmlinkage void noinstr do_fpe(struct pt_regs *regs, unsigned long fcsr) +{ + int sig; + void __user *fault_addr; + irqentry_state_t state = irqentry_enter(regs); + + if (notify_die(DIE_FP, "FP exception", regs, 0, current->thread.trap_nr, + SIGFPE) == NOTIFY_STOP) + goto out; + + /* Clear FCSR.Cause before enabling interrupts */ + write_fcsr(LOONGARCH_FCSR0, fcsr & ~mask_fcsr_x(fcsr)); + local_irq_enable(); + + die_if_kernel("FP exception in kernel code", regs); + + sig = SIGFPE; + fault_addr = (void __user *) regs->csr_era; + + /* Send a signal if required. */ + process_fpemu_return(sig, fault_addr, fcsr); + +out: + local_irq_disable(); + irqentry_exit(regs, state); +} + +asmlinkage void noinstr do_ade(struct pt_regs *regs) +{ + irqentry_state_t state = irqentry_enter(regs); + + die_if_kernel("Kernel ade access", regs); + force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)regs->csr_badvaddr); + + irqentry_exit(regs, state); +} + +asmlinkage void noinstr do_ale(struct pt_regs *regs) +{ + irqentry_state_t state = irqentry_enter(regs); + + die_if_kernel("Kernel ale access", regs); + force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr); + + irqentry_exit(regs, state); +} + +asmlinkage void noinstr do_bp(struct pt_regs *regs) +{ + bool user = user_mode(regs); + unsigned int opcode, bcode; + unsigned long era = exception_era(regs); + irqentry_state_t state = irqentry_enter(regs); + + local_irq_enable(); + current->thread.trap_nr = read_csr_excode(); + if (__get_inst(&opcode, (u32 *)era, user)) + goto out_sigsegv; + + bcode = (opcode & 0x7fff); + + /* + * notify the kprobe handlers, if instruction is likely to + * pertain to them. + */ + switch (bcode) { + case BRK_KPROBE_BP: + if (notify_die(DIE_BREAK, "Kprobe", regs, bcode, + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) + goto out; + else + break; + case BRK_KPROBE_SSTEPBP: + if (notify_die(DIE_SSTEPBP, "Kprobe_SingleStep", regs, bcode, + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) + goto out; + else + break; + case BRK_UPROBE_BP: + if (notify_die(DIE_UPROBE, "Uprobe", regs, bcode, + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) + goto out; + else + break; + case BRK_UPROBE_XOLBP: + if (notify_die(DIE_UPROBE_XOL, "Uprobe_XOL", regs, bcode, + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) + goto out; + else + break; + default: + if (notify_die(DIE_TRAP, "Break", regs, bcode, + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) + goto out; + else + break; + } + + switch (bcode) { + case BRK_BUG: + die_if_kernel("Kernel bug detected", regs); + force_sig(SIGTRAP); + break; + case BRK_DIVZERO: + die_if_kernel("Break instruction in kernel code", regs); + force_sig_fault(SIGFPE, FPE_INTDIV, (void __user *)regs->csr_era); + break; + case BRK_OVERFLOW: + die_if_kernel("Break instruction in kernel code", regs); + force_sig_fault(SIGFPE, FPE_INTOVF, (void __user *)regs->csr_era); + break; + default: + die_if_kernel("Break instruction in kernel code", regs); + force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->csr_era); + break; + } + +out: + local_irq_disable(); + irqentry_exit(regs, state); + return; + +out_sigsegv: + force_sig(SIGSEGV); + goto out; +} + +asmlinkage void noinstr do_watch(struct pt_regs *regs) +{ + pr_warn("Hardware watch point handler not implemented!\n"); +} + +asmlinkage void noinstr do_ri(struct pt_regs *regs) +{ + int status = -1; + unsigned int opcode = 0; + unsigned int __user *era = (unsigned int __user *)exception_era(regs); + unsigned long old_era = regs->csr_era; + unsigned long old_ra = regs->regs[1]; + irqentry_state_t state = irqentry_enter(regs); + + local_irq_enable(); + current->thread.trap_nr = read_csr_excode(); + + if (notify_die(DIE_RI, "RI Fault", regs, 0, current->thread.trap_nr, + SIGILL) == NOTIFY_STOP) + goto out; + + die_if_kernel("Reserved instruction in kernel code", regs); + + if (unlikely(compute_return_era(regs) < 0)) + goto out; + + if (unlikely(get_user(opcode, era) < 0)) { + status = SIGSEGV; + current->thread.error_code = 1; + } + + if (status < 0) + status = SIGILL; + + if (unlikely(status > 0)) { + regs->csr_era = old_era; /* Undo skip-over. */ + regs->regs[1] = old_ra; + force_sig(status); + } + +out: + local_irq_disable(); + irqentry_exit(regs, state); +} + +static void init_restore_fp(void) +{ + if (!used_math()) { + /* First time FP context user. */ + init_fpu(); + } else { + /* This task has formerly used the FP context */ + if (!is_fpu_owner()) + own_fpu_inatomic(1); + } + + BUG_ON(!is_fp_enabled()); +} + +asmlinkage void noinstr do_fpu(struct pt_regs *regs) +{ + irqentry_state_t state = irqentry_enter(regs); + + local_irq_enable(); + die_if_kernel("do_fpu invoked from kernel context!", regs); + + preempt_disable(); + init_restore_fp(); + preempt_enable(); + + local_irq_disable(); + irqentry_exit(regs, state); +} + +asmlinkage void noinstr do_lsx(struct pt_regs *regs) +{ + irqentry_state_t state = irqentry_enter(regs); + + local_irq_enable(); + force_sig(SIGILL); + local_irq_disable(); + + irqentry_exit(regs, state); +} + +asmlinkage void noinstr do_lasx(struct pt_regs *regs) +{ + irqentry_state_t state = irqentry_enter(regs); + + local_irq_enable(); + force_sig(SIGILL); + local_irq_disable(); + + irqentry_exit(regs, state); +} + +asmlinkage void noinstr do_lbt(struct pt_regs *regs) +{ + irqentry_state_t state = irqentry_enter(regs); + + local_irq_enable(); + force_sig(SIGILL); + local_irq_disable(); + + irqentry_exit(regs, state); +} + +asmlinkage void noinstr do_reserved(struct pt_regs *regs) +{ + irqentry_state_t state = irqentry_enter(regs); + + local_irq_enable(); + /* + * Game over - no way to handle this if it ever occurs. Most probably + * caused by a fatal error after another hardware/software error. + */ + pr_err("Caught reserved exception %u on pid:%d [%s] - should not happen\n", + read_csr_excode(), current->pid, current->comm); + die_if_kernel("do_reserved exception", regs); + force_sig(SIGUNUSED); + + local_irq_disable(); + + irqentry_exit(regs, state); +} + +asmlinkage void cache_parity_error(void) +{ + /* For the moment, report the problem and hang. */ + pr_err("Cache error exception:\n"); + pr_err("csr_merrctl == %08x\n", csr_read32(LOONGARCH_CSR_MERRCTL)); + pr_err("csr_merrera == %016llx\n", csr_read64(LOONGARCH_CSR_MERRERA)); + panic("Can't handle the cache error!"); +} + +asmlinkage void noinstr handle_loongarch_irq(struct pt_regs *regs) +{ + struct pt_regs *old_regs; + + irq_enter_rcu(); + old_regs = set_irq_regs(regs); + handle_arch_irq(regs); + set_irq_regs(old_regs); + irq_exit_rcu(); +} + +asmlinkage void noinstr do_vint(struct pt_regs *regs, unsigned long sp) +{ + register int cpu; + register unsigned long stack; + irqentry_state_t state = irqentry_enter(regs); + + cpu = smp_processor_id(); + + if (on_irq_stack(cpu, sp)) + handle_loongarch_irq(regs); + else { + stack = per_cpu(irq_stack, cpu) + IRQ_STACK_START; + + /* Save task's sp on IRQ stack for unwinding */ + *(unsigned long *)stack = sp; + + __asm__ __volatile__( + "move $s0, $sp \n" /* Preserve sp */ + "move $sp, %[stk] \n" /* Switch stack */ + "move $a0, %[regs] \n" + "bl handle_loongarch_irq \n" + "move $sp, $s0 \n" /* Restore sp */ + : /* No outputs */ + : [stk] "r" (stack), [regs] "r" (regs) + : "$a0", "$a1", "$a2", "$a3", "$a4", "$a5", "$a6", "$a7", "$s0", + "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", + "memory"); + } + + irqentry_exit(regs, state); +} + +extern void tlb_init(int cpu); +extern void cache_error_setup(void); + +unsigned long eentry; +unsigned long tlbrentry; + +long exception_handlers[VECSIZE * 128 / sizeof(long)] __aligned(SZ_64K); + +static void configure_exception_vector(void) +{ + eentry = (unsigned long)exception_handlers; + tlbrentry = (unsigned long)exception_handlers + 80*VECSIZE; + + csr_write64(eentry, LOONGARCH_CSR_EENTRY); + csr_write64(eentry, LOONGARCH_CSR_MERRENTRY); + csr_write64(tlbrentry, LOONGARCH_CSR_TLBRENTRY); +} + +void per_cpu_trap_init(int cpu) +{ + unsigned int i; + + setup_vint_size(VECSIZE); + + configure_exception_vector(); + + if (!cpu_data[cpu].asid_cache) + cpu_data[cpu].asid_cache = asid_first_version(cpu); + + mmgrab(&init_mm); + current->active_mm = &init_mm; + BUG_ON(current->mm); + enter_lazy_tlb(&init_mm, current); + + /* Initialise exception handlers */ + if (cpu == 0) + for (i = 0; i < 64; i++) + set_handler(i * VECSIZE, handle_reserved, VECSIZE); + + tlb_init(cpu); + cpu_cache_init(); +} + +/* Install CPU exception handler */ +void set_handler(unsigned long offset, void *addr, unsigned long size) +{ + memcpy((void *)(eentry + offset), addr, size); + local_flush_icache_range(eentry + offset, eentry + offset + size); +} + +static const char panic_null_cerr[] = + "Trying to set NULL cache error exception handler\n"; + +/* + * Install uncached CPU exception handler. + * This is suitable only for the cache error exception which is the only + * exception handler that is being run uncached. + */ +void set_merr_handler(unsigned long offset, void *addr, unsigned long size) +{ + unsigned long uncached_eentry = TO_UNCACHE(__pa(eentry)); + + if (!addr) + panic(panic_null_cerr); + + memcpy((void *)(uncached_eentry + offset), addr, size); +} + +void __init trap_init(void) +{ + long i; + + /* Set interrupt vector handler */ + for (i = EXCCODE_INT_START; i < EXCCODE_INT_END; i++) + set_handler(i * VECSIZE, handle_vint, VECSIZE); + + set_handler(EXCCODE_ADE * VECSIZE, handle_ade, VECSIZE); + set_handler(EXCCODE_ALE * VECSIZE, handle_ale, VECSIZE); + set_handler(EXCCODE_SYS * VECSIZE, handle_sys, VECSIZE); + set_handler(EXCCODE_BP * VECSIZE, handle_bp, VECSIZE); + set_handler(EXCCODE_INE * VECSIZE, handle_ri, VECSIZE); + set_handler(EXCCODE_IPE * VECSIZE, handle_ri, VECSIZE); + set_handler(EXCCODE_FPDIS * VECSIZE, handle_fpu, VECSIZE); + set_handler(EXCCODE_LSXDIS * VECSIZE, handle_lsx, VECSIZE); + set_handler(EXCCODE_LASXDIS * VECSIZE, handle_lasx, VECSIZE); + set_handler(EXCCODE_FPE * VECSIZE, handle_fpe, VECSIZE); + set_handler(EXCCODE_BTDIS * VECSIZE, handle_lbt, VECSIZE); + set_handler(EXCCODE_WATCH * VECSIZE, handle_watch, VECSIZE); + + cache_error_setup(); + + local_flush_icache_range(eentry, eentry + 0x400); +} diff --git a/arch/loongarch/kernel/vdso.c b/arch/loongarch/kernel/vdso.c new file mode 100644 index 000000000000..e20c8ca87473 --- /dev/null +++ b/arch/loongarch/kernel/vdso.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <linux/binfmts.h> +#include <linux/elf.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/random.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/timekeeper_internal.h> + +#include <asm/page.h> +#include <asm/vdso.h> +#include <vdso/helpers.h> +#include <vdso/vsyscall.h> +#include <generated/vdso-offsets.h> + +extern char vdso_start[], vdso_end[]; + +/* Kernel-provided data used by the VDSO. */ +static union loongarch_vdso_data { + u8 page[PAGE_SIZE]; + struct vdso_data data[CS_BASES]; +} loongarch_vdso_data __page_aligned_data; +struct vdso_data *vdso_data = loongarch_vdso_data.data; +static struct page *vdso_pages[] = { NULL }; + +static int vdso_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *new_vma) +{ + current->mm->context.vdso = (void *)(new_vma->vm_start); + + return 0; +} + +struct loongarch_vdso_info vdso_info = { + .vdso = vdso_start, + .size = PAGE_SIZE, + .code_mapping = { + .name = "[vdso]", + .pages = vdso_pages, + .mremap = vdso_mremap, + }, + .data_mapping = { + .name = "[vvar]", + }, + .offset_sigreturn = vdso_offset_sigreturn, +}; + +static int __init init_vdso(void) +{ + unsigned long i, pfn; + + BUG_ON(!PAGE_ALIGNED(vdso_info.vdso)); + BUG_ON(!PAGE_ALIGNED(vdso_info.size)); + + pfn = __phys_to_pfn(__pa_symbol(vdso_info.vdso)); + for (i = 0; i < vdso_info.size / PAGE_SIZE; i++) + vdso_info.code_mapping.pages[i] = pfn_to_page(pfn + i); + + return 0; +} +subsys_initcall(init_vdso); + +static unsigned long vdso_base(void) +{ + unsigned long base = STACK_TOP; + + if (current->flags & PF_RANDOMIZE) { + base += get_random_int() & (VDSO_RANDOMIZE_SIZE - 1); + base = PAGE_ALIGN(base); + } + + return base; +} + +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) +{ + int ret; + unsigned long vvar_size, size, data_addr, vdso_addr; + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + struct loongarch_vdso_info *info = current->thread.vdso; + + if (mmap_write_lock_killable(mm)) + return -EINTR; + + /* + * Determine total area size. This includes the VDSO data itself + * and the data page. + */ + vvar_size = PAGE_SIZE; + size = vvar_size + info->size; + + data_addr = get_unmapped_area(NULL, vdso_base(), size, 0, 0); + if (IS_ERR_VALUE(data_addr)) { + ret = data_addr; + goto out; + } + vdso_addr = data_addr + PAGE_SIZE; + + vma = _install_special_mapping(mm, data_addr, vvar_size, + VM_READ | VM_MAYREAD, + &info->data_mapping); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto out; + } + + /* Map VDSO data page. */ + ret = remap_pfn_range(vma, data_addr, + virt_to_phys(vdso_data) >> PAGE_SHIFT, + PAGE_SIZE, PAGE_READONLY); + if (ret) + goto out; + + /* Map VDSO code page. */ + vma = _install_special_mapping(mm, vdso_addr, info->size, + VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, + &info->code_mapping); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto out; + } + + mm->context.vdso = (void *)vdso_addr; + ret = 0; + +out: + mmap_write_unlock(mm); + return ret; +} diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..9d508158fe1a --- /dev/null +++ b/arch/loongarch/kernel/vmlinux.lds.S @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include <linux/sizes.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> + +#define PAGE_SIZE _PAGE_SIZE + +/* + * Put .bss..swapper_pg_dir as the first thing in .bss. This will + * ensure that it has .bss alignment (64K). + */ +#define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir) + +#include <asm-generic/vmlinux.lds.h> + +/* + * Max avaliable Page Size is 64K, so we set SectionAlignment + * field of EFI application to 64K. + */ +PECOFF_FILE_ALIGN = 0x200; +PECOFF_SEGMENT_ALIGN = 0x10000; + +OUTPUT_ARCH(loongarch) +ENTRY(kernel_entry) +PHDRS { + text PT_LOAD FLAGS(7); /* RWX */ + note PT_NOTE FLAGS(4); /* R__ */ +} + +jiffies = jiffies_64; + +SECTIONS +{ + . = VMLINUX_LOAD_ADDRESS; + + _text = .; + HEAD_TEXT_SECTION + + . = ALIGN(PECOFF_SEGMENT_ALIGN); + .text : { + TEXT_TEXT + SCHED_TEXT + CPUIDLE_TEXT + LOCK_TEXT + KPROBES_TEXT + IRQENTRY_TEXT + SOFTIRQENTRY_TEXT + *(.fixup) + *(.gnu.warning) + } :text = 0 + . = ALIGN(PECOFF_SEGMENT_ALIGN); + _etext = .; + + EXCEPTION_TABLE(16) + + . = ALIGN(PECOFF_SEGMENT_ALIGN); + __init_begin = .; + __inittext_begin = .; + + INIT_TEXT_SECTION(PAGE_SIZE) + .exit.text : { + EXIT_TEXT + } + + . = ALIGN(PECOFF_SEGMENT_ALIGN); + __inittext_end = .; + + __initdata_begin = .; + + INIT_DATA_SECTION(16) + .exit.data : { + EXIT_DATA + } + +#ifdef CONFIG_SMP + PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT) +#endif + + .init.bss : { + *(.init.bss) + } + . = ALIGN(PECOFF_SEGMENT_ALIGN); + __initdata_end = .; + + __init_end = .; + + _sdata = .; + RO_DATA(4096) + RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE) + + .sdata : { + *(.sdata) + } + .edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGN); } + _edata = .; + + BSS_SECTION(0, SZ_64K, 8) + . = ALIGN(PECOFF_SEGMENT_ALIGN); + + _end = .; + + STABS_DEBUG + DWARF_DEBUG + + .gptab.sdata : { + *(.gptab.data) + *(.gptab.sdata) + } + .gptab.sbss : { + *(.gptab.bss) + *(.gptab.sbss) + } + + DISCARDS + /DISCARD/ : { + *(.gnu.attributes) + *(.options) + *(.eh_frame) + } +} diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile new file mode 100644 index 000000000000..e36635fccb69 --- /dev/null +++ b/arch/loongarch/lib/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for LoongArch-specific library files. +# + +lib-y += delay.o clear_user.o copy_user.o dump_tlb.o diff --git a/arch/loongarch/lib/clear_user.S b/arch/loongarch/lib/clear_user.S new file mode 100644 index 000000000000..25d9be5fbb19 --- /dev/null +++ b/arch/loongarch/lib/clear_user.S @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/export.h> +#include <asm/regdef.h> + +.macro fixup_ex from, to, offset, fix +.if \fix + .section .fixup, "ax" +\to: addi.d a0, a1, \offset + jr ra + .previous +.endif + .section __ex_table, "a" + PTR \from\()b, \to\()b + .previous +.endm + +/* + * unsigned long __clear_user(void *addr, size_t size) + * + * a0: addr + * a1: size + */ +SYM_FUNC_START(__clear_user) + beqz a1, 2f + +1: st.b zero, a0, 0 + addi.d a0, a0, 1 + addi.d a1, a1, -1 + bgt a1, zero, 1b + +2: move a0, a1 + jr ra + + fixup_ex 1, 3, 0, 1 +SYM_FUNC_END(__clear_user) + +EXPORT_SYMBOL(__clear_user) diff --git a/arch/loongarch/lib/copy_user.S b/arch/loongarch/lib/copy_user.S new file mode 100644 index 000000000000..9ae507f851b5 --- /dev/null +++ b/arch/loongarch/lib/copy_user.S @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/export.h> +#include <asm/regdef.h> + +.macro fixup_ex from, to, offset, fix +.if \fix + .section .fixup, "ax" +\to: addi.d a0, a2, \offset + jr ra + .previous +.endif + .section __ex_table, "a" + PTR \from\()b, \to\()b + .previous +.endm + +/* + * unsigned long __copy_user(void *to, const void *from, size_t n) + * + * a0: to + * a1: from + * a2: n + */ +SYM_FUNC_START(__copy_user) + beqz a2, 3f + +1: ld.b t0, a1, 0 +2: st.b t0, a0, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + addi.d a2, a2, -1 + bgt a2, zero, 1b + +3: move a0, a2 + jr ra + + fixup_ex 1, 4, 0, 1 + fixup_ex 2, 4, 0, 0 +SYM_FUNC_END(__copy_user) + +EXPORT_SYMBOL(__copy_user) diff --git a/arch/loongarch/lib/delay.c b/arch/loongarch/lib/delay.c new file mode 100644 index 000000000000..5d856694fcfe --- /dev/null +++ b/arch/loongarch/lib/delay.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/smp.h> +#include <linux/timex.h> + +#include <asm/compiler.h> +#include <asm/processor.h> + +void __delay(unsigned long cycles) +{ + u64 t0 = get_cycles(); + + while ((unsigned long)(get_cycles() - t0) < cycles) + cpu_relax(); +} +EXPORT_SYMBOL(__delay); + +/* + * Division by multiplication: you don't have to worry about + * loss of precision. + * + * Use only for very small delays ( < 1 msec). Should probably use a + * lookup table, really, as the multiplications take much too long with + * short delays. This is a "reasonable" implementation, though (and the + * first constant multiplications gets optimized away if the delay is + * a constant) + */ + +void __udelay(unsigned long us) +{ + __delay((us * 0x000010c7ull * HZ * lpj_fine) >> 32); +} +EXPORT_SYMBOL(__udelay); + +void __ndelay(unsigned long ns) +{ + __delay((ns * 0x00000005ull * HZ * lpj_fine) >> 32); +} +EXPORT_SYMBOL(__ndelay); diff --git a/arch/loongarch/lib/dump_tlb.c b/arch/loongarch/lib/dump_tlb.c new file mode 100644 index 000000000000..cda2c6bc7f09 --- /dev/null +++ b/arch/loongarch/lib/dump_tlb.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle. + * Copyright (C) 1999 by Silicon Graphics, Inc. + */ +#include <linux/kernel.h> +#include <linux/mm.h> + +#include <asm/loongarch.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/tlb.h> + +void dump_tlb_regs(void) +{ + const int field = 2 * sizeof(unsigned long); + + pr_info("Index : %0x\n", read_csr_tlbidx()); + pr_info("PageSize : %0x\n", read_csr_pagesize()); + pr_info("EntryHi : %0*llx\n", field, read_csr_entryhi()); + pr_info("EntryLo0 : %0*llx\n", field, read_csr_entrylo0()); + pr_info("EntryLo1 : %0*llx\n", field, read_csr_entrylo1()); +} + +static void dump_tlb(int first, int last) +{ + unsigned long s_entryhi, entryhi, asid; + unsigned long long entrylo0, entrylo1, pa; + unsigned int index; + unsigned int s_index, s_asid; + unsigned int pagesize, c0, c1, i; + unsigned long asidmask = cpu_asid_mask(¤t_cpu_data); + int pwidth = 11; + int vwidth = 11; + int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4); + + s_entryhi = read_csr_entryhi(); + s_index = read_csr_tlbidx(); + s_asid = read_csr_asid(); + + for (i = first; i <= last; i++) { + write_csr_index(i); + tlb_read(); + pagesize = read_csr_pagesize(); + entryhi = read_csr_entryhi(); + entrylo0 = read_csr_entrylo0(); + entrylo1 = read_csr_entrylo1(); + index = read_csr_tlbidx(); + asid = read_csr_asid(); + + /* EHINV bit marks entire entry as invalid */ + if (index & CSR_TLBIDX_EHINV) + continue; + /* + * ASID takes effect in absence of G (global) bit. + */ + if (!((entrylo0 | entrylo1) & ENTRYLO_G) && + asid != s_asid) + continue; + + /* + * Only print entries in use + */ + pr_info("Index: %2d pgsize=%x ", i, (1 << pagesize)); + + c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; + c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; + + pr_cont("va=%0*lx asid=%0*lx", + vwidth, (entryhi & ~0x1fffUL), asidwidth, asid & asidmask); + + /* NR/NX are in awkward places, so mask them off separately */ + pa = entrylo0 & ~(ENTRYLO_NR | ENTRYLO_NX); + pa = pa & PAGE_MASK; + pr_cont("\n\t["); + pr_cont("ri=%d xi=%d ", + (entrylo0 & ENTRYLO_NR) ? 1 : 0, + (entrylo0 & ENTRYLO_NX) ? 1 : 0); + pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d plv=%lld] [", + pwidth, pa, c0, + (entrylo0 & ENTRYLO_D) ? 1 : 0, + (entrylo0 & ENTRYLO_V) ? 1 : 0, + (entrylo0 & ENTRYLO_G) ? 1 : 0, + (entrylo0 & ENTRYLO_PLV) >> ENTRYLO_PLV_SHIFT); + /* NR/NX are in awkward places, so mask them off separately */ + pa = entrylo1 & ~(ENTRYLO_NR | ENTRYLO_NX); + pa = pa & PAGE_MASK; + pr_cont("ri=%d xi=%d ", + (entrylo1 & ENTRYLO_NR) ? 1 : 0, + (entrylo1 & ENTRYLO_NX) ? 1 : 0); + pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d plv=%lld]\n", + pwidth, pa, c1, + (entrylo1 & ENTRYLO_D) ? 1 : 0, + (entrylo1 & ENTRYLO_V) ? 1 : 0, + (entrylo1 & ENTRYLO_G) ? 1 : 0, + (entrylo1 & ENTRYLO_PLV) >> ENTRYLO_PLV_SHIFT); + } + pr_info("\n"); + + write_csr_entryhi(s_entryhi); + write_csr_tlbidx(s_index); + write_csr_asid(s_asid); +} + +void dump_tlb_all(void) +{ + dump_tlb(0, current_cpu_data.tlbsize - 1); +} diff --git a/arch/loongarch/mm/Makefile b/arch/loongarch/mm/Makefile new file mode 100644 index 000000000000..8ffc6383f836 --- /dev/null +++ b/arch/loongarch/mm/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the Linux/LoongArch-specific parts of the memory manager. +# + +obj-y += init.o cache.o tlb.o tlbex.o extable.o \ + fault.o ioremap.o maccess.o mmap.o pgtable.o page.o + +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/loongarch/mm/cache.c b/arch/loongarch/mm/cache.c new file mode 100644 index 000000000000..9e5ce5aa73f7 --- /dev/null +++ b/arch/loongarch/mm/cache.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1994 - 2003, 06, 07 by Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2007 MIPS Technologies, Inc. + */ +#include <linux/export.h> +#include <linux/fcntl.h> +#include <linux/fs.h> +#include <linux/highmem.h> +#include <linux/kernel.h> +#include <linux/linkage.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/syscalls.h> + +#include <asm/cacheflush.h> +#include <asm/cpu.h> +#include <asm/cpu-features.h> +#include <asm/dma.h> +#include <asm/loongarch.h> +#include <asm/processor.h> +#include <asm/setup.h> + +/* + * LoongArch maintains ICache/DCache coherency by hardware, + * we just need "ibar" to avoid instruction hazard here. + */ +void local_flush_icache_range(unsigned long start, unsigned long end) +{ + asm volatile ("\tibar 0\n"::); +} +EXPORT_SYMBOL(local_flush_icache_range); + +void cache_error_setup(void) +{ + extern char __weak except_vec_cex; + set_merr_handler(0x0, &except_vec_cex, 0x80); +} + +static unsigned long icache_size __read_mostly; +static unsigned long dcache_size __read_mostly; +static unsigned long vcache_size __read_mostly; +static unsigned long scache_size __read_mostly; + +static char *way_string[] = { NULL, "direct mapped", "2-way", + "3-way", "4-way", "5-way", "6-way", "7-way", "8-way", + "9-way", "10-way", "11-way", "12-way", + "13-way", "14-way", "15-way", "16-way", +}; + +static void probe_pcache(void) +{ + struct cpuinfo_loongarch *c = ¤t_cpu_data; + unsigned int lsize, sets, ways; + unsigned int config; + + config = read_cpucfg(LOONGARCH_CPUCFG17); + lsize = 1 << ((config & CPUCFG17_L1I_SIZE_M) >> CPUCFG17_L1I_SIZE); + sets = 1 << ((config & CPUCFG17_L1I_SETS_M) >> CPUCFG17_L1I_SETS); + ways = ((config & CPUCFG17_L1I_WAYS_M) >> CPUCFG17_L1I_WAYS) + 1; + + c->icache.linesz = lsize; + c->icache.sets = sets; + c->icache.ways = ways; + icache_size = sets * ways * lsize; + c->icache.waysize = icache_size / c->icache.ways; + + config = read_cpucfg(LOONGARCH_CPUCFG18); + lsize = 1 << ((config & CPUCFG18_L1D_SIZE_M) >> CPUCFG18_L1D_SIZE); + sets = 1 << ((config & CPUCFG18_L1D_SETS_M) >> CPUCFG18_L1D_SETS); + ways = ((config & CPUCFG18_L1D_WAYS_M) >> CPUCFG18_L1D_WAYS) + 1; + + c->dcache.linesz = lsize; + c->dcache.sets = sets; + c->dcache.ways = ways; + dcache_size = sets * ways * lsize; + c->dcache.waysize = dcache_size / c->dcache.ways; + + c->options |= LOONGARCH_CPU_PREFETCH; + + pr_info("Primary instruction cache %ldkB, %s, %s, linesize %d bytes.\n", + icache_size >> 10, way_string[c->icache.ways], "VIPT", c->icache.linesz); + + pr_info("Primary data cache %ldkB, %s, %s, %s, linesize %d bytes\n", + dcache_size >> 10, way_string[c->dcache.ways], "VIPT", "no aliases", c->dcache.linesz); +} + +static void probe_vcache(void) +{ + struct cpuinfo_loongarch *c = ¤t_cpu_data; + unsigned int lsize, sets, ways; + unsigned int config; + + config = read_cpucfg(LOONGARCH_CPUCFG19); + lsize = 1 << ((config & CPUCFG19_L2_SIZE_M) >> CPUCFG19_L2_SIZE); + sets = 1 << ((config & CPUCFG19_L2_SETS_M) >> CPUCFG19_L2_SETS); + ways = ((config & CPUCFG19_L2_WAYS_M) >> CPUCFG19_L2_WAYS) + 1; + + c->vcache.linesz = lsize; + c->vcache.sets = sets; + c->vcache.ways = ways; + vcache_size = lsize * sets * ways; + c->vcache.waysize = vcache_size / c->vcache.ways; + + pr_info("Unified victim cache %ldkB %s, linesize %d bytes.\n", + vcache_size >> 10, way_string[c->vcache.ways], c->vcache.linesz); +} + +static void probe_scache(void) +{ + struct cpuinfo_loongarch *c = ¤t_cpu_data; + unsigned int lsize, sets, ways; + unsigned int config; + + config = read_cpucfg(LOONGARCH_CPUCFG20); + lsize = 1 << ((config & CPUCFG20_L3_SIZE_M) >> CPUCFG20_L3_SIZE); + sets = 1 << ((config & CPUCFG20_L3_SETS_M) >> CPUCFG20_L3_SETS); + ways = ((config & CPUCFG20_L3_WAYS_M) >> CPUCFG20_L3_WAYS) + 1; + + c->scache.linesz = lsize; + c->scache.sets = sets; + c->scache.ways = ways; + /* 4 cores. scaches are shared */ + scache_size = lsize * sets * ways; + c->scache.waysize = scache_size / c->scache.ways; + + pr_info("Unified secondary cache %ldkB %s, linesize %d bytes.\n", + scache_size >> 10, way_string[c->scache.ways], c->scache.linesz); +} + +void cpu_cache_init(void) +{ + probe_pcache(); + probe_vcache(); + probe_scache(); + + shm_align_mask = PAGE_SIZE - 1; +} diff --git a/arch/loongarch/mm/extable.c b/arch/loongarch/mm/extable.c new file mode 100644 index 000000000000..bc20988f2b87 --- /dev/null +++ b/arch/loongarch/mm/extable.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/extable.h> +#include <linux/spinlock.h> +#include <asm/branch.h> +#include <linux/uaccess.h> + +int fixup_exception(struct pt_regs *regs) +{ + const struct exception_table_entry *fixup; + + fixup = search_exception_tables(exception_era(regs)); + if (fixup) { + regs->csr_era = fixup->fixup; + + return 1; + } + + return 0; +} diff --git a/arch/loongarch/mm/fault.c b/arch/loongarch/mm/fault.c new file mode 100644 index 000000000000..605579b19a00 --- /dev/null +++ b/arch/loongarch/mm/fault.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from MIPS: + * Copyright (C) 1995 - 2000 by Ralf Baechle + */ +#include <linux/context_tracking.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/entry-common.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/ratelimit.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/kdebug.h> +#include <linux/kprobes.h> +#include <linux/perf_event.h> +#include <linux/uaccess.h> + +#include <asm/branch.h> +#include <asm/mmu_context.h> +#include <asm/ptrace.h> + +int show_unhandled_signals = 1; + +static void __kprobes no_context(struct pt_regs *regs, unsigned long address) +{ + const int field = sizeof(unsigned long) * 2; + + /* Are we prepared to handle this kernel fault? */ + if (fixup_exception(regs)) + return; + + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + bust_spinlocks(1); + + pr_alert("CPU %d Unable to handle kernel paging request at " + "virtual address %0*lx, era == %0*lx, ra == %0*lx\n", + raw_smp_processor_id(), field, address, field, regs->csr_era, + field, regs->regs[1]); + die("Oops", regs); +} + +static void __kprobes do_out_of_memory(struct pt_regs *regs, unsigned long address) +{ + /* + * We ran out of memory, call the OOM killer, and return the userspace + * (which will retry the fault, or kill us if we got oom-killed). + */ + if (!user_mode(regs)) { + no_context(regs, address); + return; + } + pagefault_out_of_memory(); +} + +static void __kprobes do_sigbus(struct pt_regs *regs, + unsigned long write, unsigned long address, int si_code) +{ + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) { + no_context(regs, address); + return; + } + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + current->thread.csr_badvaddr = address; + current->thread.trap_nr = read_csr_excode(); + force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address); +} + +static void __kprobes do_sigsegv(struct pt_regs *regs, + unsigned long write, unsigned long address, int si_code) +{ + const int field = sizeof(unsigned long) * 2; + static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) { + no_context(regs, address); + return; + } + + /* User mode accesses just cause a SIGSEGV */ + current->thread.csr_badvaddr = address; + if (!write) + current->thread.error_code = 1; + else + current->thread.error_code = 2; + current->thread.trap_nr = read_csr_excode(); + + if (show_unhandled_signals && + unhandled_signal(current, SIGSEGV) && __ratelimit(&ratelimit_state)) { + pr_info("do_page_fault(): sending SIGSEGV to %s for invalid %s %0*lx\n", + current->comm, + write ? "write access to" : "read access from", + field, address); + pr_info("era = %0*lx in", field, + (unsigned long) regs->csr_era); + print_vma_addr(KERN_CONT " ", regs->csr_era); + pr_cont("\n"); + pr_info("ra = %0*lx in", field, + (unsigned long) regs->regs[1]); + print_vma_addr(KERN_CONT " ", regs->regs[1]); + pr_cont("\n"); + } + force_sig_fault(SIGSEGV, si_code, (void __user *)address); +} + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + */ +static void __kprobes __do_page_fault(struct pt_regs *regs, + unsigned long write, unsigned long address) +{ + int si_code = SEGV_MAPERR; + unsigned int flags = FAULT_FLAG_DEFAULT; + struct task_struct *tsk = current; + struct mm_struct *mm = tsk->mm; + struct vm_area_struct *vma = NULL; + vm_fault_t fault; + + /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + */ + if (address & __UA_LIMIT) { + if (!user_mode(regs)) + no_context(regs, address); + else + do_sigsegv(regs, write, address, si_code); + return; + } + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (faulthandler_disabled() || !mm) { + do_sigsegv(regs, write, address, si_code); + return; + } + + if (user_mode(regs)) + flags |= FAULT_FLAG_USER; + + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); +retry: + mmap_read_lock(mm); + vma = find_vma(mm, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (!expand_stack(vma, address)) + goto good_area; +/* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + mmap_read_unlock(mm); + do_sigsegv(regs, write, address, si_code); + return; + +/* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + si_code = SEGV_ACCERR; + + if (write) { + flags |= FAULT_FLAG_WRITE; + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { + if (!(vma->vm_flags & VM_READ) && address != exception_era(regs)) + goto bad_area; + if (!(vma->vm_flags & VM_EXEC) && address == exception_era(regs)) + goto bad_area; + } + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + fault = handle_mm_fault(vma, address, flags, regs); + + if (fault_signal_pending(fault, regs)) { + if (!user_mode(regs)) + no_context(regs, address); + return; + } + + if (unlikely(fault & VM_FAULT_RETRY)) { + flags |= FAULT_FLAG_TRIED; + + /* + * No need to mmap_read_unlock(mm) as we would + * have already released it in __lock_page_or_retry + * in mm/filemap.c. + */ + goto retry; + } + if (unlikely(fault & VM_FAULT_ERROR)) { + mmap_read_unlock(mm); + if (fault & VM_FAULT_OOM) { + do_out_of_memory(regs, address); + return; + } else if (fault & VM_FAULT_SIGSEGV) { + do_sigsegv(regs, write, address, si_code); + return; + } else if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) { + do_sigbus(regs, write, address, si_code); + return; + } + BUG(); + } + + mmap_read_unlock(mm); +} + +asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, + unsigned long write, unsigned long address) +{ + irqentry_state_t state = irqentry_enter(regs); + + /* Enable interrupt if enabled in parent context */ + if (likely(regs->csr_prmd & CSR_PRMD_PIE)) + local_irq_enable(); + + __do_page_fault(regs, write, address); + + local_irq_disable(); + + irqentry_exit(regs, state); +} diff --git a/arch/loongarch/mm/hugetlbpage.c b/arch/loongarch/mm/hugetlbpage.c new file mode 100644 index 000000000000..ba138117b124 --- /dev/null +++ b/arch/loongarch/mm/hugetlbpage.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/hugetlb.h> +#include <linux/pagemap.h> +#include <linux/err.h> +#include <linux/sysctl.h> +#include <asm/mman.h> +#include <asm/tlb.h> +#include <asm/tlbflush.h> + +pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long addr, unsigned long sz) +{ + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + pte_t *pte = NULL; + + pgd = pgd_offset(mm, addr); + p4d = p4d_alloc(mm, pgd, addr); + pud = pud_alloc(mm, p4d, addr); + if (pud) + pte = (pte_t *)pmd_alloc(mm, pud, addr); + + return pte; +} + +pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr, + unsigned long sz) +{ + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd = NULL; + + pgd = pgd_offset(mm, addr); + if (pgd_present(*pgd)) { + p4d = p4d_offset(pgd, addr); + if (p4d_present(*p4d)) { + pud = pud_offset(p4d, addr); + if (pud_present(*pud)) + pmd = pmd_offset(pud, addr); + } + } + return (pte_t *) pmd; +} + +/* + * This function checks for proper alignment of input addr and len parameters. + */ +int is_aligned_hugepage_range(unsigned long addr, unsigned long len) +{ + if (len & ~HPAGE_MASK) + return -EINVAL; + if (addr & ~HPAGE_MASK) + return -EINVAL; + return 0; +} + +int pmd_huge(pmd_t pmd) +{ + return (pmd_val(pmd) & _PAGE_HUGE) != 0; +} + +int pud_huge(pud_t pud) +{ + return (pud_val(pud) & _PAGE_HUGE) != 0; +} + +uint64_t pmd_to_entrylo(unsigned long pmd_val) +{ + uint64_t val; + /* PMD as PTE. Must be huge page */ + if (!pmd_huge(__pmd(pmd_val))) + panic("%s", __func__); + + val = pmd_val ^ _PAGE_HUGE; + val |= ((val & _PAGE_HGLOBAL) >> + (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)); + + return val; +} diff --git a/arch/loongarch/mm/init.c b/arch/loongarch/mm/init.c new file mode 100644 index 000000000000..7094a68c9b83 --- /dev/null +++ b/arch/loongarch/mm/init.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/init.h> +#include <linux/export.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/pagemap.h> +#include <linux/memblock.h> +#include <linux/memremap.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/highmem.h> +#include <linux/swap.h> +#include <linux/proc_fs.h> +#include <linux/pfn.h> +#include <linux/hardirq.h> +#include <linux/gfp.h> +#include <linux/initrd.h> +#include <linux/mmzone.h> + +#include <asm/asm-offsets.h> +#include <asm/bootinfo.h> +#include <asm/cpu.h> +#include <asm/dma.h> +#include <asm/mmu_context.h> +#include <asm/sections.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/tlb.h> + +/* + * We have up to 8 empty zeroed pages so we can map one of the right colour + * when needed. Since page is never written to after the initialization we + * don't have to care about aliases on other CPUs. + */ +unsigned long empty_zero_page, zero_page_mask; +EXPORT_SYMBOL_GPL(empty_zero_page); +EXPORT_SYMBOL(zero_page_mask); + +void setup_zero_pages(void) +{ + unsigned int order, i; + struct page *page; + + order = 0; + + empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order); + if (!empty_zero_page) + panic("Oh boy, that early out of memory?"); + + page = virt_to_page((void *)empty_zero_page); + split_page(page, order); + for (i = 0; i < (1 << order); i++, page++) + mark_page_reserved(page); + + zero_page_mask = ((PAGE_SIZE << order) - 1) & PAGE_MASK; +} + +void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma) +{ + void *vfrom, *vto; + + vto = kmap_atomic(to); + vfrom = kmap_atomic(from); + copy_page(vto, vfrom); + kunmap_atomic(vfrom); + kunmap_atomic(vto); + /* Make sure this page is cleared on other CPU's too before using it */ + smp_wmb(); +} + +int __ref page_is_ram(unsigned long pfn) +{ + unsigned long addr = PFN_PHYS(pfn); + + return memblock_is_memory(addr) && !memblock_is_reserved(addr); +} + +#ifndef CONFIG_NUMA +void __init paging_init(void) +{ + unsigned long max_zone_pfns[MAX_NR_ZONES]; + +#ifdef CONFIG_ZONE_DMA + max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; +#endif +#ifdef CONFIG_ZONE_DMA32 + max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; +#endif + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; + + free_area_init(max_zone_pfns); +} + +void __init mem_init(void) +{ + max_mapnr = max_low_pfn; + high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT); + + memblock_free_all(); + setup_zero_pages(); /* Setup zeroed pages. */ +} +#endif /* !CONFIG_NUMA */ + +void __ref free_initmem(void) +{ + free_initmem_default(POISON_FREE_INITMEM); +} + +#ifdef CONFIG_MEMORY_HOTPLUG +int arch_add_memory(int nid, u64 start, u64 size, struct mhp_params *params) +{ + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long nr_pages = size >> PAGE_SHIFT; + int ret; + + ret = __add_pages(nid, start_pfn, nr_pages, params); + + if (ret) + pr_warn("%s: Problem encountered in __add_pages() as ret=%d\n", + __func__, ret); + + return ret; +} + +#ifdef CONFIG_NUMA +int memory_add_physaddr_to_nid(u64 start) +{ + int nid; + + nid = pa_to_nid(start); + return nid; +} +EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); +#endif + +#ifdef CONFIG_MEMORY_HOTREMOVE +void arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap) +{ + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long nr_pages = size >> PAGE_SHIFT; + struct page *page = pfn_to_page(start_pfn); + + /* With altmap the first mapped page is offset from @start */ + if (altmap) + page += vmem_altmap_offset(altmap); + __remove_pages(start_pfn, nr_pages, altmap); +} +#endif +#endif + +/* + * Align swapper_pg_dir in to 64K, allows its address to be loaded + * with a single LUI instruction in the TLB handlers. If we used + * __aligned(64K), its size would get rounded up to the alignment + * size, and waste space. So we place it in its own section and align + * it in the linker script. + */ +pgd_t swapper_pg_dir[_PTRS_PER_PGD] __section(".bss..swapper_pg_dir"); + +pgd_t invalid_pg_dir[_PTRS_PER_PGD] __page_aligned_bss; +#ifndef __PAGETABLE_PUD_FOLDED +pud_t invalid_pud_table[PTRS_PER_PUD] __page_aligned_bss; +#endif +#ifndef __PAGETABLE_PMD_FOLDED +pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned_bss; +EXPORT_SYMBOL_GPL(invalid_pmd_table); +#endif +pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned_bss; +EXPORT_SYMBOL(invalid_pte_table); diff --git a/arch/loongarch/mm/ioremap.c b/arch/loongarch/mm/ioremap.c new file mode 100644 index 000000000000..73b0980ab6f5 --- /dev/null +++ b/arch/loongarch/mm/ioremap.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <asm/io.h> + +void __init __iomem *early_ioremap(u64 phys_addr, unsigned long size) +{ + return ((void __iomem *)TO_CACHE(phys_addr)); +} + +void __init early_iounmap(void __iomem *addr, unsigned long size) +{ + +} + +void *early_memremap_ro(resource_size_t phys_addr, unsigned long size) +{ + return early_memremap(phys_addr, size); +} + +void *early_memremap_prot(resource_size_t phys_addr, unsigned long size, + unsigned long prot_val) +{ + return early_memremap(phys_addr, size); +} diff --git a/arch/loongarch/mm/maccess.c b/arch/loongarch/mm/maccess.c new file mode 100644 index 000000000000..58173842c6be --- /dev/null +++ b/arch/loongarch/mm/maccess.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/uaccess.h> +#include <linux/kernel.h> + +bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size) +{ + /* highest bit set means kernel space */ + return (unsigned long)unsafe_src >> (BITS_PER_LONG - 1); +} diff --git a/arch/loongarch/mm/mmap.c b/arch/loongarch/mm/mmap.c new file mode 100644 index 000000000000..52e40f0ba732 --- /dev/null +++ b/arch/loongarch/mm/mmap.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/compiler.h> +#include <linux/elf-randomize.h> +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/export.h> +#include <linux/personality.h> +#include <linux/random.h> +#include <linux/sched/signal.h> +#include <linux/sched/mm.h> + +unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ +EXPORT_SYMBOL(shm_align_mask); + +#define COLOUR_ALIGN(addr, pgoff) \ + ((((addr) + shm_align_mask) & ~shm_align_mask) + \ + (((pgoff) << PAGE_SHIFT) & shm_align_mask)) + +enum mmap_allocation_direction {UP, DOWN}; + +static unsigned long arch_get_unmapped_area_common(struct file *filp, + unsigned long addr0, unsigned long len, unsigned long pgoff, + unsigned long flags, enum mmap_allocation_direction dir) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long addr = addr0; + int do_color_align; + struct vm_unmapped_area_info info; + + if (unlikely(len > TASK_SIZE)) + return -ENOMEM; + + if (flags & MAP_FIXED) { + /* Even MAP_FIXED mappings must reside within TASK_SIZE */ + if (TASK_SIZE - len < addr) + return -EINVAL; + + /* + * We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && + ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) + return -EINVAL; + return addr; + } + + do_color_align = 0; + if (filp || (flags & MAP_SHARED)) + do_color_align = 1; + + /* requesting a specific address */ + if (addr) { + if (do_color_align) + addr = COLOUR_ALIGN(addr, pgoff); + else + addr = PAGE_ALIGN(addr); + + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vm_start_gap(vma))) + return addr; + } + + info.length = len; + info.align_mask = do_color_align ? (PAGE_MASK & shm_align_mask) : 0; + info.align_offset = pgoff << PAGE_SHIFT; + + if (dir == DOWN) { + info.flags = VM_UNMAPPED_AREA_TOPDOWN; + info.low_limit = PAGE_SIZE; + info.high_limit = mm->mmap_base; + addr = vm_unmapped_area(&info); + + if (!(addr & ~PAGE_MASK)) + return addr; + + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + } + + info.flags = 0; + info.low_limit = mm->mmap_base; + info.high_limit = TASK_SIZE; + return vm_unmapped_area(&info); +} + +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr0, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + return arch_get_unmapped_area_common(filp, + addr0, len, pgoff, flags, UP); +} + +/* + * There is no need to export this but sched.h declares the function as + * extern so making it static here results in an error. + */ +unsigned long arch_get_unmapped_area_topdown(struct file *filp, + unsigned long addr0, unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + return arch_get_unmapped_area_common(filp, + addr0, len, pgoff, flags, DOWN); +} + +int __virt_addr_valid(volatile void *kaddr) +{ + unsigned long vaddr = (unsigned long)kaddr; + + if ((vaddr < PAGE_OFFSET) || (vaddr >= vm_map_base)) + return 0; + + return pfn_valid(PFN_DOWN(virt_to_phys(kaddr))); +} +EXPORT_SYMBOL_GPL(__virt_addr_valid); diff --git a/arch/loongarch/mm/page.S b/arch/loongarch/mm/page.S new file mode 100644 index 000000000000..ddc78ab33c7b --- /dev/null +++ b/arch/loongarch/mm/page.S @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/linkage.h> +#include <asm/asm.h> +#include <asm/export.h> +#include <asm/page.h> +#include <asm/regdef.h> + + .align 5 +SYM_FUNC_START(clear_page) + lu12i.w t0, 1 << (PAGE_SHIFT - 12) + add.d t0, t0, a0 +1: + st.d zero, a0, 0 + st.d zero, a0, 8 + st.d zero, a0, 16 + st.d zero, a0, 24 + st.d zero, a0, 32 + st.d zero, a0, 40 + st.d zero, a0, 48 + st.d zero, a0, 56 + addi.d a0, a0, 128 + st.d zero, a0, -64 + st.d zero, a0, -56 + st.d zero, a0, -48 + st.d zero, a0, -40 + st.d zero, a0, -32 + st.d zero, a0, -24 + st.d zero, a0, -16 + st.d zero, a0, -8 + bne t0, a0, 1b + + jirl $r0, ra, 0 +SYM_FUNC_END(clear_page) +EXPORT_SYMBOL(clear_page) + +.align 5 +SYM_FUNC_START(copy_page) + lu12i.w t8, 1 << (PAGE_SHIFT - 12) + add.d t8, t8, a0 +1: + ld.d t0, a1, 0 + ld.d t1, a1, 8 + ld.d t2, a1, 16 + ld.d t3, a1, 24 + ld.d t4, a1, 32 + ld.d t5, a1, 40 + ld.d t6, a1, 48 + ld.d t7, a1, 56 + + st.d t0, a0, 0 + st.d t1, a0, 8 + ld.d t0, a1, 64 + ld.d t1, a1, 72 + st.d t2, a0, 16 + st.d t3, a0, 24 + ld.d t2, a1, 80 + ld.d t3, a1, 88 + st.d t4, a0, 32 + st.d t5, a0, 40 + ld.d t4, a1, 96 + ld.d t5, a1, 104 + st.d t6, a0, 48 + st.d t7, a0, 56 + ld.d t6, a1, 112 + ld.d t7, a1, 120 + addi.d a0, a0, 128 + addi.d a1, a1, 128 + + st.d t0, a0, -64 + st.d t1, a0, -56 + st.d t2, a0, -48 + st.d t3, a0, -40 + st.d t4, a0, -32 + st.d t5, a0, -24 + st.d t6, a0, -16 + st.d t7, a0, -8 + + bne t8, a0, 1b + jirl $r0, ra, 0 +SYM_FUNC_END(copy_page) +EXPORT_SYMBOL(copy_page) diff --git a/arch/loongarch/mm/pgtable.c b/arch/loongarch/mm/pgtable.c new file mode 100644 index 000000000000..0569647152e9 --- /dev/null +++ b/arch/loongarch/mm/pgtable.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/init.h> +#include <linux/export.h> +#include <linux/mm.h> +#include <asm/pgalloc.h> +#include <asm/pgtable.h> +#include <asm/tlbflush.h> + +pgd_t *pgd_alloc(struct mm_struct *mm) +{ + pgd_t *ret, *init; + + ret = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ORDER); + if (ret) { + init = pgd_offset(&init_mm, 0UL); + pgd_init((unsigned long)ret); + memcpy(ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + } + + return ret; +} +EXPORT_SYMBOL_GPL(pgd_alloc); + +void pgd_init(unsigned long page) +{ + unsigned long *p, *end; + unsigned long entry; + +#if !defined(__PAGETABLE_PUD_FOLDED) + entry = (unsigned long)invalid_pud_table; +#elif !defined(__PAGETABLE_PMD_FOLDED) + entry = (unsigned long)invalid_pmd_table; +#else + entry = (unsigned long)invalid_pte_table; +#endif + + p = (unsigned long *) page; + end = p + PTRS_PER_PGD; + + do { + p[0] = entry; + p[1] = entry; + p[2] = entry; + p[3] = entry; + p[4] = entry; + p += 8; + p[-3] = entry; + p[-2] = entry; + p[-1] = entry; + } while (p != end); +} +EXPORT_SYMBOL_GPL(pgd_init); + +#ifndef __PAGETABLE_PMD_FOLDED +void pmd_init(unsigned long addr, unsigned long pagetable) +{ + unsigned long *p, *end; + + p = (unsigned long *) addr; + end = p + PTRS_PER_PMD; + + do { + p[0] = pagetable; + p[1] = pagetable; + p[2] = pagetable; + p[3] = pagetable; + p[4] = pagetable; + p += 8; + p[-3] = pagetable; + p[-2] = pagetable; + p[-1] = pagetable; + } while (p != end); +} +EXPORT_SYMBOL_GPL(pmd_init); +#endif + +#ifndef __PAGETABLE_PUD_FOLDED +void pud_init(unsigned long addr, unsigned long pagetable) +{ + unsigned long *p, *end; + + p = (unsigned long *)addr; + end = p + PTRS_PER_PUD; + + do { + p[0] = pagetable; + p[1] = pagetable; + p[2] = pagetable; + p[3] = pagetable; + p[4] = pagetable; + p += 8; + p[-3] = pagetable; + p[-2] = pagetable; + p[-1] = pagetable; + } while (p != end); +} +#endif + +pmd_t mk_pmd(struct page *page, pgprot_t prot) +{ + pmd_t pmd; + + pmd_val(pmd) = (page_to_pfn(page) << _PFN_SHIFT) | pgprot_val(prot); + + return pmd; +} + +void set_pmd_at(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp, pmd_t pmd) +{ + *pmdp = pmd; + flush_tlb_all(); +} + +void __init pagetable_init(void) +{ + /* Initialize the entire pgd. */ + pgd_init((unsigned long)swapper_pg_dir); + pgd_init((unsigned long)invalid_pg_dir); +#ifndef __PAGETABLE_PUD_FOLDED + pud_init((unsigned long)invalid_pud_table, (unsigned long)invalid_pmd_table); +#endif +#ifndef __PAGETABLE_PMD_FOLDED + pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table); +#endif +} diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c new file mode 100644 index 000000000000..e272f8ac57d1 --- /dev/null +++ b/arch/loongarch/mm/tlb.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/mm.h> +#include <linux/hugetlb.h> +#include <linux/export.h> + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/mmu_context.h> +#include <asm/pgtable.h> +#include <asm/tlb.h> + +void local_flush_tlb_all(void) +{ + invtlb_all(INVTLB_CURRENT_ALL, 0, 0); +} +EXPORT_SYMBOL(local_flush_tlb_all); + +void local_flush_tlb_user(void) +{ + invtlb_all(INVTLB_CURRENT_GFALSE, 0, 0); +} +EXPORT_SYMBOL(local_flush_tlb_user); + +void local_flush_tlb_kernel(void) +{ + invtlb_all(INVTLB_CURRENT_GTRUE, 0, 0); +} +EXPORT_SYMBOL(local_flush_tlb_kernel); + +/* + * All entries common to a mm share an asid. To effectively flush + * these entries, we just bump the asid. + */ +void local_flush_tlb_mm(struct mm_struct *mm) +{ + int cpu; + + preempt_disable(); + + cpu = smp_processor_id(); + + if (asid_valid(mm, cpu)) + drop_mmu_context(mm, cpu); + else + cpumask_clear_cpu(cpu, mm_cpumask(mm)); + + preempt_enable(); +} + +void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + int cpu = smp_processor_id(); + + if (asid_valid(mm, cpu)) { + unsigned long size, flags; + + local_irq_save(flags); + start = round_down(start, PAGE_SIZE << 1); + end = round_up(end, PAGE_SIZE << 1); + size = (end - start) >> (PAGE_SHIFT + 1); + if (size <= (current_cpu_data.tlbsizestlbsets ? + current_cpu_data.tlbsize / 8 : + current_cpu_data.tlbsize / 2)) { + int asid = cpu_asid(cpu, mm); + + while (start < end) { + invtlb(INVTLB_ADDR_GFALSE_AND_ASID, asid, start); + start += (PAGE_SIZE << 1); + } + } else { + drop_mmu_context(mm, cpu); + } + local_irq_restore(flags); + } else { + cpumask_clear_cpu(cpu, mm_cpumask(mm)); + } +} + +void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + unsigned long size, flags; + + local_irq_save(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + size = (size + 1) >> 1; + if (size <= (current_cpu_data.tlbsizestlbsets ? + current_cpu_data.tlbsize / 8 : + current_cpu_data.tlbsize / 2)) { + + start &= (PAGE_MASK << 1); + end += ((PAGE_SIZE << 1) - 1); + end &= (PAGE_MASK << 1); + + while (start < end) { + invtlb_addr(INVTLB_ADDR_GTRUE_OR_ASID, 0, start); + start += (PAGE_SIZE << 1); + } + } else { + local_flush_tlb_kernel(); + } + local_irq_restore(flags); +} + +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + int cpu = smp_processor_id(); + + if (asid_valid(vma->vm_mm, cpu)) { + int newpid; + + newpid = cpu_asid(cpu, vma->vm_mm); + page &= (PAGE_MASK << 1); + invtlb(INVTLB_ADDR_GFALSE_AND_ASID, newpid, page); + } else { + cpumask_clear_cpu(cpu, mm_cpumask(vma->vm_mm)); + } +} + +/* + * This one is only used for pages with the global bit set so we don't care + * much about the ASID. + */ +void local_flush_tlb_one(unsigned long page) +{ + page &= (PAGE_MASK << 1); + invtlb_addr(INVTLB_ADDR_GTRUE_OR_ASID, 0, page); +} + +static void __update_hugetlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) +{ +#ifdef CONFIG_HUGETLB_PAGE + int idx; + unsigned long lo; + unsigned long flags; + + local_irq_save(flags); + + address &= (PAGE_MASK << 1); + write_csr_entryhi(address); + tlb_probe(); + idx = read_csr_tlbidx(); + write_csr_pagesize(PS_HUGE_SIZE); + lo = pmd_to_entrylo(pte_val(*ptep)); + write_csr_entrylo0(lo); + write_csr_entrylo1(lo + (HPAGE_SIZE >> 1)); + + if (idx < 0) + tlb_write_random(); + else + tlb_write_indexed(); + write_csr_pagesize(PS_DEFAULT_SIZE); + + local_irq_restore(flags); +#endif +} + +void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) +{ + int idx; + unsigned long flags; + + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) + return; + + if (pte_val(*ptep) & _PAGE_HUGE) { + __update_hugetlb(vma, address, ptep); + return; + } + + local_irq_save(flags); + + if ((unsigned long)ptep & sizeof(pte_t)) + ptep--; + + address &= (PAGE_MASK << 1); + write_csr_entryhi(address); + tlb_probe(); + idx = read_csr_tlbidx(); + write_csr_pagesize(PS_DEFAULT_SIZE); + write_csr_entrylo0(pte_val(*ptep++)); + write_csr_entrylo1(pte_val(*ptep)); + if (idx < 0) + tlb_write_random(); + else + tlb_write_indexed(); + + local_irq_restore(flags); +} + +static void setup_ptwalker(void) +{ + unsigned long pwctl0, pwctl1; + unsigned long pgd_i = 0, pgd_w = 0; + unsigned long pud_i = 0, pud_w = 0; + unsigned long pmd_i = 0, pmd_w = 0; + unsigned long pte_i = 0, pte_w = 0; + + pgd_i = PGDIR_SHIFT; + pgd_w = PAGE_SHIFT - 3; +#if CONFIG_PGTABLE_LEVELS > 3 + pud_i = PUD_SHIFT; + pud_w = PAGE_SHIFT - 3; +#endif +#if CONFIG_PGTABLE_LEVELS > 2 + pmd_i = PMD_SHIFT; + pmd_w = PAGE_SHIFT - 3; +#endif + pte_i = PAGE_SHIFT; + pte_w = PAGE_SHIFT - 3; + + pwctl0 = pte_i | pte_w << 5 | pmd_i << 10 | pmd_w << 15 | pud_i << 20 | pud_w << 25; + pwctl1 = pgd_i | pgd_w << 6; + + csr_write64(pwctl0, LOONGARCH_CSR_PWCTL0); + csr_write64(pwctl1, LOONGARCH_CSR_PWCTL1); + csr_write64((long)swapper_pg_dir, LOONGARCH_CSR_PGDH); + csr_write64((long)invalid_pg_dir, LOONGARCH_CSR_PGDL); + csr_write64((long)smp_processor_id(), LOONGARCH_CSR_TMID); +} + +static void output_pgtable_bits_defines(void) +{ +#define pr_define(fmt, ...) \ + pr_debug("#define " fmt, ##__VA_ARGS__) + + pr_debug("#include <asm/asm.h>\n"); + pr_debug("#include <asm/regdef.h>\n"); + pr_debug("\n"); + + pr_define("_PAGE_VALID_SHIFT %d\n", _PAGE_VALID_SHIFT); + pr_define("_PAGE_DIRTY_SHIFT %d\n", _PAGE_DIRTY_SHIFT); + pr_define("_PAGE_HUGE_SHIFT %d\n", _PAGE_HUGE_SHIFT); + pr_define("_PAGE_GLOBAL_SHIFT %d\n", _PAGE_GLOBAL_SHIFT); + pr_define("_PAGE_PRESENT_SHIFT %d\n", _PAGE_PRESENT_SHIFT); + pr_define("_PAGE_WRITE_SHIFT %d\n", _PAGE_WRITE_SHIFT); + pr_define("_PAGE_NO_READ_SHIFT %d\n", _PAGE_NO_READ_SHIFT); + pr_define("_PAGE_NO_EXEC_SHIFT %d\n", _PAGE_NO_EXEC_SHIFT); + pr_define("_PFN_SHIFT %d\n", _PFN_SHIFT); + pr_debug("\n"); +} + +#ifdef CONFIG_NUMA +static unsigned long pcpu_handlers[NR_CPUS]; +#endif +extern long exception_handlers[VECSIZE * 128 / sizeof(long)]; + +void setup_tlb_handler(int cpu) +{ + setup_ptwalker(); + output_pgtable_bits_defines(); + + /* The tlb handlers are generated only once */ + if (cpu == 0) { + memcpy((void *)tlbrentry, handle_tlb_refill, 0x80); + local_flush_icache_range(tlbrentry, tlbrentry + 0x80); + set_handler(EXCCODE_TLBI * VECSIZE, handle_tlb_load, VECSIZE); + set_handler(EXCCODE_TLBL * VECSIZE, handle_tlb_load, VECSIZE); + set_handler(EXCCODE_TLBS * VECSIZE, handle_tlb_store, VECSIZE); + set_handler(EXCCODE_TLBM * VECSIZE, handle_tlb_modify, VECSIZE); + set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE); + set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE); + set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE); + } +#ifdef CONFIG_NUMA + else { + void *addr; + struct page *page; + const int vec_sz = sizeof(exception_handlers); + + if (pcpu_handlers[cpu]) + return; + + page = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL, get_order(vec_sz)); + if (!page) + return; + + addr = page_address(page); + pcpu_handlers[cpu] = virt_to_phys(addr); + memcpy((void *)addr, (void *)eentry, vec_sz); + local_flush_icache_range((unsigned long)addr, (unsigned long)addr + vec_sz); + csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_TLBRENTRY); + csr_write64(pcpu_handlers[cpu] + 80*VECSIZE, LOONGARCH_CSR_TLBRENTRY); + } +#endif +} + +void tlb_init(int cpu) +{ + write_csr_pagesize(PS_DEFAULT_SIZE); + write_csr_stlbpgsize(PS_DEFAULT_SIZE); + write_csr_tlbrefill_pagesize(PS_DEFAULT_SIZE); + setup_tlb_handler(cpu); + local_flush_tlb_all(); +} diff --git a/arch/loongarch/mm/tlbex.S b/arch/loongarch/mm/tlbex.S new file mode 100644 index 000000000000..7eee40271577 --- /dev/null +++ b/arch/loongarch/mm/tlbex.S @@ -0,0 +1,546 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <asm/asm.h> +#include <asm/export.h> +#include <asm/loongarch.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + + .macro tlb_do_page_fault, write + SYM_FUNC_START(tlb_do_page_fault_\write) + SAVE_ALL + csrrd a2, LOONGARCH_CSR_BADV + move a0, sp + REG_S a2, sp, PT_BVADDR + li.w a1, \write + la.abs t0, do_page_fault + jirl ra, t0, 0 + RESTORE_ALL_AND_RET + SYM_FUNC_END(tlb_do_page_fault_\write) + .endm + + tlb_do_page_fault 0 + tlb_do_page_fault 1 + +SYM_FUNC_START(handle_tlb_protect) + BACKUP_T0T1 + SAVE_ALL + move a0, sp + move a1, zero + csrrd a2, LOONGARCH_CSR_BADV + REG_S a2, sp, PT_BVADDR + la.abs t0, do_page_fault + jirl ra, t0, 0 + RESTORE_ALL_AND_RET +SYM_FUNC_END(handle_tlb_protect) + +SYM_FUNC_START(handle_tlb_load) + csrwr t0, EXCEPTION_KS0 + csrwr t1, EXCEPTION_KS1 + csrwr ra, EXCEPTION_KS2 + + /* + * The vmalloc handling is not in the hotpath. + */ + csrrd t0, LOONGARCH_CSR_BADV + blt t0, $r0, vmalloc_load + csrrd t1, LOONGARCH_CSR_PGDL + +vmalloc_done_load: + /* Get PGD offset in bytes */ + srli.d t0, t0, PGDIR_SHIFT + andi t0, t0, (PTRS_PER_PGD - 1) + slli.d t0, t0, 3 + add.d t1, t1, t0 +#if CONFIG_PGTABLE_LEVELS > 3 + csrrd t0, LOONGARCH_CSR_BADV + ld.d t1, t1, 0 + srli.d t0, t0, PUD_SHIFT + andi t0, t0, (PTRS_PER_PUD - 1) + slli.d t0, t0, 3 + add.d t1, t1, t0 +#endif +#if CONFIG_PGTABLE_LEVELS > 2 + csrrd t0, LOONGARCH_CSR_BADV + ld.d t1, t1, 0 + srli.d t0, t0, PMD_SHIFT + andi t0, t0, (PTRS_PER_PMD - 1) + slli.d t0, t0, 3 + add.d t1, t1, t0 +#endif + ld.d ra, t1, 0 + + /* + * For huge tlb entries, pmde doesn't contain an address but + * instead contains the tlb pte. Check the PAGE_HUGE bit and + * see if we need to jump to huge tlb processing. + */ + andi t0, ra, _PAGE_HUGE + bne t0, $r0, tlb_huge_update_load + + csrrd t0, LOONGARCH_CSR_BADV + srli.d t0, t0, (PAGE_SHIFT + PTE_ORDER) + andi t0, t0, (PTRS_PER_PTE - 1) + slli.d t0, t0, _PTE_T_LOG2 + add.d t1, ra, t0 + +#ifdef CONFIG_SMP +smp_pgtable_change_load: +#endif +#ifdef CONFIG_SMP + ll.d t0, t1, 0 +#else + ld.d t0, t1, 0 +#endif + tlbsrch + + srli.d ra, t0, _PAGE_PRESENT_SHIFT + andi ra, ra, 1 + beq ra, $r0, nopage_tlb_load + + ori t0, t0, _PAGE_VALID +#ifdef CONFIG_SMP + sc.d t0, t1, 0 + beq t0, $r0, smp_pgtable_change_load +#else + st.d t0, t1, 0 +#endif + ori t1, t1, 8 + xori t1, t1, 8 + ld.d t0, t1, 0 + ld.d t1, t1, 8 + csrwr t0, LOONGARCH_CSR_TLBELO0 + csrwr t1, LOONGARCH_CSR_TLBELO1 + tlbwr +leave_load: + csrrd t0, EXCEPTION_KS0 + csrrd t1, EXCEPTION_KS1 + csrrd ra, EXCEPTION_KS2 + ertn +#ifdef CONFIG_64BIT +vmalloc_load: + la.abs t1, swapper_pg_dir + b vmalloc_done_load +#endif + + /* + * This is the entry point when build_tlbchange_handler_head + * spots a huge page. + */ +tlb_huge_update_load: +#ifdef CONFIG_SMP + ll.d t0, t1, 0 +#else + ld.d t0, t1, 0 +#endif + srli.d ra, t0, _PAGE_PRESENT_SHIFT + andi ra, ra, 1 + beq ra, $r0, nopage_tlb_load + tlbsrch + + ori t0, t0, _PAGE_VALID +#ifdef CONFIG_SMP + sc.d t0, t1, 0 + beq t0, $r0, tlb_huge_update_load + ld.d t0, t1, 0 +#else + st.d t0, t1, 0 +#endif + addu16i.d t1, $r0, -(CSR_TLBIDX_EHINV >> 16) + addi.d ra, t1, 0 + csrxchg ra, t1, LOONGARCH_CSR_TLBIDX + tlbwr + + csrxchg $r0, t1, LOONGARCH_CSR_TLBIDX + + /* + * A huge PTE describes an area the size of the + * configured huge page size. This is twice the + * of the large TLB entry size we intend to use. + * A TLB entry half the size of the configured + * huge page size is configured into entrylo0 + * and entrylo1 to cover the contiguous huge PTE + * address space. + */ + /* Huge page: Move Global bit */ + xori t0, t0, _PAGE_HUGE + lu12i.w t1, _PAGE_HGLOBAL >> 12 + and t1, t0, t1 + srli.d t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT) + or t0, t0, t1 + + addi.d ra, t0, 0 + csrwr t0, LOONGARCH_CSR_TLBELO0 + addi.d t0, ra, 0 + + /* Convert to entrylo1 */ + addi.d t1, $r0, 1 + slli.d t1, t1, (HPAGE_SHIFT - 1) + add.d t0, t0, t1 + csrwr t0, LOONGARCH_CSR_TLBELO1 + + /* Set huge page tlb entry size */ + addu16i.d t0, $r0, (CSR_TLBIDX_PS >> 16) + addu16i.d t1, $r0, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16)) + csrxchg t1, t0, LOONGARCH_CSR_TLBIDX + + tlbfill + + addu16i.d t0, $r0, (CSR_TLBIDX_PS >> 16) + addu16i.d t1, $r0, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16)) + csrxchg t1, t0, LOONGARCH_CSR_TLBIDX + +nopage_tlb_load: + dbar 0 + csrrd ra, EXCEPTION_KS2 + la.abs t0, tlb_do_page_fault_0 + jirl $r0, t0, 0 +SYM_FUNC_END(handle_tlb_load) + +SYM_FUNC_START(handle_tlb_store) + csrwr t0, EXCEPTION_KS0 + csrwr t1, EXCEPTION_KS1 + csrwr ra, EXCEPTION_KS2 + + /* + * The vmalloc handling is not in the hotpath. + */ + csrrd t0, LOONGARCH_CSR_BADV + blt t0, $r0, vmalloc_store + csrrd t1, LOONGARCH_CSR_PGDL + +vmalloc_done_store: + /* Get PGD offset in bytes */ + srli.d t0, t0, PGDIR_SHIFT + andi t0, t0, (PTRS_PER_PGD - 1) + slli.d t0, t0, 3 + add.d t1, t1, t0 + +#if CONFIG_PGTABLE_LEVELS > 3 + csrrd t0, LOONGARCH_CSR_BADV + ld.d t1, t1, 0 + srli.d t0, t0, PUD_SHIFT + andi t0, t0, (PTRS_PER_PUD - 1) + slli.d t0, t0, 3 + add.d t1, t1, t0 +#endif +#if CONFIG_PGTABLE_LEVELS > 2 + csrrd t0, LOONGARCH_CSR_BADV + ld.d t1, t1, 0 + srli.d t0, t0, PMD_SHIFT + andi t0, t0, (PTRS_PER_PMD - 1) + slli.d t0, t0, 3 + add.d t1, t1, t0 +#endif + ld.d ra, t1, 0 + + /* + * For huge tlb entries, pmde doesn't contain an address but + * instead contains the tlb pte. Check the PAGE_HUGE bit and + * see if we need to jump to huge tlb processing. + */ + andi t0, ra, _PAGE_HUGE + bne t0, $r0, tlb_huge_update_store + + csrrd t0, LOONGARCH_CSR_BADV + srli.d t0, t0, (PAGE_SHIFT + PTE_ORDER) + andi t0, t0, (PTRS_PER_PTE - 1) + slli.d t0, t0, _PTE_T_LOG2 + add.d t1, ra, t0 + +#ifdef CONFIG_SMP +smp_pgtable_change_store: +#endif +#ifdef CONFIG_SMP + ll.d t0, t1, 0 +#else + ld.d t0, t1, 0 +#endif + tlbsrch + + srli.d ra, t0, _PAGE_PRESENT_SHIFT + andi ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT) + xori ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT) + bne ra, $r0, nopage_tlb_store + + ori t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED) +#ifdef CONFIG_SMP + sc.d t0, t1, 0 + beq t0, $r0, smp_pgtable_change_store +#else + st.d t0, t1, 0 +#endif + + ori t1, t1, 8 + xori t1, t1, 8 + ld.d t0, t1, 0 + ld.d t1, t1, 8 + csrwr t0, LOONGARCH_CSR_TLBELO0 + csrwr t1, LOONGARCH_CSR_TLBELO1 + tlbwr +leave_store: + csrrd t0, EXCEPTION_KS0 + csrrd t1, EXCEPTION_KS1 + csrrd ra, EXCEPTION_KS2 + ertn +#ifdef CONFIG_64BIT +vmalloc_store: + la.abs t1, swapper_pg_dir + b vmalloc_done_store +#endif + + /* + * This is the entry point when build_tlbchange_handler_head + * spots a huge page. + */ +tlb_huge_update_store: +#ifdef CONFIG_SMP + ll.d t0, t1, 0 +#else + ld.d t0, t1, 0 +#endif + srli.d ra, t0, _PAGE_PRESENT_SHIFT + andi ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT) + xori ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT) + bne ra, $r0, nopage_tlb_store + + tlbsrch + ori t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED) + +#ifdef CONFIG_SMP + sc.d t0, t1, 0 + beq t0, $r0, tlb_huge_update_store + ld.d t0, t1, 0 +#else + st.d t0, t1, 0 +#endif + addu16i.d t1, $r0, -(CSR_TLBIDX_EHINV >> 16) + addi.d ra, t1, 0 + csrxchg ra, t1, LOONGARCH_CSR_TLBIDX + tlbwr + + csrxchg $r0, t1, LOONGARCH_CSR_TLBIDX + /* + * A huge PTE describes an area the size of the + * configured huge page size. This is twice the + * of the large TLB entry size we intend to use. + * A TLB entry half the size of the configured + * huge page size is configured into entrylo0 + * and entrylo1 to cover the contiguous huge PTE + * address space. + */ + /* Huge page: Move Global bit */ + xori t0, t0, _PAGE_HUGE + lu12i.w t1, _PAGE_HGLOBAL >> 12 + and t1, t0, t1 + srli.d t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT) + or t0, t0, t1 + + addi.d ra, t0, 0 + csrwr t0, LOONGARCH_CSR_TLBELO0 + addi.d t0, ra, 0 + + /* Convert to entrylo1 */ + addi.d t1, $r0, 1 + slli.d t1, t1, (HPAGE_SHIFT - 1) + add.d t0, t0, t1 + csrwr t0, LOONGARCH_CSR_TLBELO1 + + /* Set huge page tlb entry size */ + addu16i.d t0, $r0, (CSR_TLBIDX_PS >> 16) + addu16i.d t1, $r0, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16)) + csrxchg t1, t0, LOONGARCH_CSR_TLBIDX + + tlbfill + + /* Reset default page size */ + addu16i.d t0, $r0, (CSR_TLBIDX_PS >> 16) + addu16i.d t1, $r0, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16)) + csrxchg t1, t0, LOONGARCH_CSR_TLBIDX + +nopage_tlb_store: + dbar 0 + csrrd ra, EXCEPTION_KS2 + la.abs t0, tlb_do_page_fault_1 + jirl $r0, t0, 0 +SYM_FUNC_END(handle_tlb_store) + +SYM_FUNC_START(handle_tlb_modify) + csrwr t0, EXCEPTION_KS0 + csrwr t1, EXCEPTION_KS1 + csrwr ra, EXCEPTION_KS2 + + /* + * The vmalloc handling is not in the hotpath. + */ + csrrd t0, LOONGARCH_CSR_BADV + blt t0, $r0, vmalloc_modify + csrrd t1, LOONGARCH_CSR_PGDL + +vmalloc_done_modify: + /* Get PGD offset in bytes */ + srli.d t0, t0, PGDIR_SHIFT + andi t0, t0, (PTRS_PER_PGD - 1) + slli.d t0, t0, 3 + add.d t1, t1, t0 +#if CONFIG_PGTABLE_LEVELS > 3 + csrrd t0, LOONGARCH_CSR_BADV + ld.d t1, t1, 0 + srli.d t0, t0, PUD_SHIFT + andi t0, t0, (PTRS_PER_PUD - 1) + slli.d t0, t0, 3 + add.d t1, t1, t0 +#endif +#if CONFIG_PGTABLE_LEVELS > 2 + csrrd t0, LOONGARCH_CSR_BADV + ld.d t1, t1, 0 + srli.d t0, t0, PMD_SHIFT + andi t0, t0, (PTRS_PER_PMD - 1) + slli.d t0, t0, 3 + add.d t1, t1, t0 +#endif + ld.d ra, t1, 0 + + /* + * For huge tlb entries, pmde doesn't contain an address but + * instead contains the tlb pte. Check the PAGE_HUGE bit and + * see if we need to jump to huge tlb processing. + */ + andi t0, ra, _PAGE_HUGE + bne t0, $r0, tlb_huge_update_modify + + csrrd t0, LOONGARCH_CSR_BADV + srli.d t0, t0, (PAGE_SHIFT + PTE_ORDER) + andi t0, t0, (PTRS_PER_PTE - 1) + slli.d t0, t0, _PTE_T_LOG2 + add.d t1, ra, t0 + +#ifdef CONFIG_SMP +smp_pgtable_change_modify: +#endif +#ifdef CONFIG_SMP + ll.d t0, t1, 0 +#else + ld.d t0, t1, 0 +#endif + tlbsrch + + srli.d ra, t0, _PAGE_WRITE_SHIFT + andi ra, ra, 1 + beq ra, $r0, nopage_tlb_modify + + ori t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED) +#ifdef CONFIG_SMP + sc.d t0, t1, 0 + beq t0, $r0, smp_pgtable_change_modify +#else + st.d t0, t1, 0 +#endif + ori t1, t1, 8 + xori t1, t1, 8 + ld.d t0, t1, 0 + ld.d t1, t1, 8 + csrwr t0, LOONGARCH_CSR_TLBELO0 + csrwr t1, LOONGARCH_CSR_TLBELO1 + tlbwr +leave_modify: + csrrd t0, EXCEPTION_KS0 + csrrd t1, EXCEPTION_KS1 + csrrd ra, EXCEPTION_KS2 + ertn +#ifdef CONFIG_64BIT +vmalloc_modify: + la.abs t1, swapper_pg_dir + b vmalloc_done_modify +#endif + + /* + * This is the entry point when + * build_tlbchange_handler_head spots a huge page. + */ +tlb_huge_update_modify: +#ifdef CONFIG_SMP + ll.d t0, t1, 0 +#else + ld.d t0, t1, 0 +#endif + + srli.d ra, t0, _PAGE_WRITE_SHIFT + andi ra, ra, 1 + beq ra, $r0, nopage_tlb_modify + + tlbsrch + ori t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED) + +#ifdef CONFIG_SMP + sc.d t0, t1, 0 + beq t0, $r0, tlb_huge_update_modify + ld.d t0, t1, 0 +#else + st.d t0, t1, 0 +#endif + /* + * A huge PTE describes an area the size of the + * configured huge page size. This is twice the + * of the large TLB entry size we intend to use. + * A TLB entry half the size of the configured + * huge page size is configured into entrylo0 + * and entrylo1 to cover the contiguous huge PTE + * address space. + */ + /* Huge page: Move Global bit */ + xori t0, t0, _PAGE_HUGE + lu12i.w t1, _PAGE_HGLOBAL >> 12 + and t1, t0, t1 + srli.d t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT) + or t0, t0, t1 + + addi.d ra, t0, 0 + csrwr t0, LOONGARCH_CSR_TLBELO0 + addi.d t0, ra, 0 + + /* Convert to entrylo1 */ + addi.d t1, $r0, 1 + slli.d t1, t1, (HPAGE_SHIFT - 1) + add.d t0, t0, t1 + csrwr t0, LOONGARCH_CSR_TLBELO1 + + /* Set huge page tlb entry size */ + addu16i.d t0, $r0, (CSR_TLBIDX_PS >> 16) + addu16i.d t1, $r0, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16)) + csrxchg t1, t0, LOONGARCH_CSR_TLBIDX + + tlbwr + + /* Reset default page size */ + addu16i.d t0, $r0, (CSR_TLBIDX_PS >> 16) + addu16i.d t1, $r0, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16)) + csrxchg t1, t0, LOONGARCH_CSR_TLBIDX + +nopage_tlb_modify: + dbar 0 + csrrd ra, EXCEPTION_KS2 + la.abs t0, tlb_do_page_fault_1 + jirl $r0, t0, 0 +SYM_FUNC_END(handle_tlb_modify) + +SYM_FUNC_START(handle_tlb_refill) + csrwr t0, LOONGARCH_CSR_TLBRSAVE + csrrd t0, LOONGARCH_CSR_PGD + lddir t0, t0, 3 +#if CONFIG_PGTABLE_LEVELS > 3 + lddir t0, t0, 2 +#endif +#if CONFIG_PGTABLE_LEVELS > 2 + lddir t0, t0, 1 +#endif + ldpte t0, 0 + ldpte t0, 1 + tlbfill + csrrd t0, LOONGARCH_CSR_TLBRSAVE + ertn +SYM_FUNC_END(handle_tlb_refill) diff --git a/arch/loongarch/pci/Makefile b/arch/loongarch/pci/Makefile new file mode 100644 index 000000000000..8101ef3df71c --- /dev/null +++ b/arch/loongarch/pci/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the PCI specific kernel interface routines under Linux. +# + +obj-y += pci.o +obj-$(CONFIG_ACPI) += acpi.o diff --git a/arch/loongarch/vdso/.gitignore b/arch/loongarch/vdso/.gitignore new file mode 100644 index 000000000000..652e31d82582 --- /dev/null +++ b/arch/loongarch/vdso/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +vdso.lds diff --git a/arch/loongarch/vdso/Makefile b/arch/loongarch/vdso/Makefile new file mode 100644 index 000000000000..6b6e16732c60 --- /dev/null +++ b/arch/loongarch/vdso/Makefile @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: GPL-2.0 +# Objects to go into the VDSO. + +# Absolute relocation type $(ARCH_REL_TYPE_ABS) needs to be defined before +# the inclusion of generic Makefile. +ARCH_REL_TYPE_ABS := R_LARCH_32|R_LARCH_64|R_LARCH_MARK_LA|R_LARCH_JUMP_SLOT +include $(srctree)/lib/vdso/Makefile + +obj-vdso-y := elf.o vgettimeofday.o sigreturn.o + +# Common compiler flags between ABIs. +ccflags-vdso := \ + $(filter -I%,$(KBUILD_CFLAGS)) \ + $(filter -E%,$(KBUILD_CFLAGS)) \ + $(filter -march=%,$(KBUILD_CFLAGS)) \ + $(filter -m%-float,$(KBUILD_CFLAGS)) \ + -D__VDSO__ + +ifeq ($(cc-name),clang) +ccflags-vdso += $(filter --target=%,$(KBUILD_CFLAGS)) +endif + +cflags-vdso := $(ccflags-vdso) \ + $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ + -O2 -g -fno-strict-aliasing -fno-common -fno-builtin -G0 \ + -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \ + $(call cc-option, -fno-asynchronous-unwind-tables) \ + $(call cc-option, -fno-stack-protector) +aflags-vdso := $(ccflags-vdso) \ + -D__ASSEMBLY__ -Wa,-gdwarf-2 + +ifneq ($(c-gettimeofday-y),) + CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y) +endif + +# VDSO linker flags. +ldflags-y := -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \ + $(filter -E%,$(KBUILD_CFLAGS)) -nostdlib -shared \ + --hash-style=sysv --build-id -T + +GCOV_PROFILE := n + +# +# Shared build commands. +# + +quiet_cmd_vdsold_and_vdso_check = LD $@ + cmd_vdsold_and_vdso_check = $(cmd_ld); $(cmd_vdso_check) + +quiet_cmd_vdsoas_o_S = AS $@ + cmd_vdsoas_o_S = $(CC) $(a_flags) -c -o $@ $< + +# Generate VDSO offsets using helper script +gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh +quiet_cmd_vdsosym = VDSOSYM $@ + cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ + +include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE + $(call if_changed,vdsosym) + +# +# Build native VDSO. +# + +native-abi := $(filter -mabi=%,$(KBUILD_CFLAGS)) + +targets += $(obj-vdso-y) +targets += vdso.lds vdso.so.dbg vdso.so + +obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o) + +$(obj-vdso): KBUILD_CFLAGS := $(cflags-vdso) $(native-abi) +$(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi) + +$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) $(native-abi) + +$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE + $(call if_changed,vdsold_and_vdso_check) + +$(obj)/vdso.so: OBJCOPYFLAGS := -S +$(obj)/vdso.so: $(obj)/vdso.so.dbg FORCE + $(call if_changed,objcopy) + +obj-y += vdso.o + +$(obj)/vdso.o : $(obj)/vdso.so + +# install commands for the unstripped file +quiet_cmd_vdso_install = INSTALL $@ + cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ + +vdso.so: $(obj)/vdso.so.dbg + @mkdir -p $(MODLIB)/vdso + $(call cmd,vdso_install) + +vdso_install: vdso.so diff --git a/arch/loongarch/vdso/elf.S b/arch/loongarch/vdso/elf.S new file mode 100644 index 000000000000..9bb21b9f9583 --- /dev/null +++ b/arch/loongarch/vdso/elf.S @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <asm/vdso/vdso.h> + +#include <linux/elfnote.h> +#include <linux/version.h> + +ELFNOTE_START(Linux, 0, "a") + .long LINUX_VERSION_CODE +ELFNOTE_END diff --git a/arch/loongarch/vdso/gen_vdso_offsets.sh b/arch/loongarch/vdso/gen_vdso_offsets.sh new file mode 100755 index 000000000000..1bb4e12642ff --- /dev/null +++ b/arch/loongarch/vdso/gen_vdso_offsets.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +# +# Derived from RISC-V and ARM64: +# Author: Will Deacon <will.deacon@arm.com> +# +# Match symbols in the DSO that look like VDSO_*; produce a header file +# of constant offsets into the shared object. +# + +LC_ALL=C sed -n -e 's/^00*/0/' -e \ +'s/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso_offset_\2\t0x\1/p' diff --git a/arch/loongarch/vdso/sigreturn.S b/arch/loongarch/vdso/sigreturn.S new file mode 100644 index 000000000000..9cb3c58fad03 --- /dev/null +++ b/arch/loongarch/vdso/sigreturn.S @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <asm/vdso/vdso.h> + +#include <linux/linkage.h> +#include <uapi/asm/unistd.h> + +#include <asm/regdef.h> +#include <asm/asm.h> + + .section .text + .cfi_sections .debug_frame + +SYM_FUNC_START(__vdso_rt_sigreturn) + + li.w a7, __NR_rt_sigreturn + syscall 0 + +SYM_FUNC_END(__vdso_rt_sigreturn) diff --git a/arch/loongarch/vdso/vdso.S b/arch/loongarch/vdso/vdso.S new file mode 100644 index 000000000000..46789bade6ff --- /dev/null +++ b/arch/loongarch/vdso/vdso.S @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + * + * Derived from RISC-V: + * Copyright (C) 2014 Regents of the University of California + */ + +#include <linux/init.h> +#include <linux/linkage.h> +#include <asm/page.h> + + __PAGE_ALIGNED_DATA + + .globl vdso_start, vdso_end + .balign PAGE_SIZE +vdso_start: + .incbin "arch/loongarch/vdso/vdso.so" + .balign PAGE_SIZE +vdso_end: + + .previous diff --git a/arch/loongarch/vdso/vdso.lds.S b/arch/loongarch/vdso/vdso.lds.S new file mode 100644 index 000000000000..955f02de4a2d --- /dev/null +++ b/arch/loongarch/vdso/vdso.lds.S @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Author: Huacai Chen <chenhuacai@loongson.cn> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +OUTPUT_FORMAT("elf64-loongarch", "elf64-loongarch", "elf64-loongarch") + +OUTPUT_ARCH(loongarch) + +SECTIONS +{ + PROVIDE(_start = .); + . = SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + .note : { *(.note.*) } :text :note + + .text : { *(.text*) } :text + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + + .dynamic : { *(.dynamic) } :text :dynamic + + .rodata : { *(.rodata*) } :text + + _end = .; + PROVIDE(end = .); + + /DISCARD/ : { + *(.gnu.attributes) + *(.note.GNU-stack) + *(.data .data.* .gnu.linkonce.d.* .sdata*) + *(.bss .sbss .dynbss .dynsbss) + } +} + +PHDRS +{ + text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + note PT_NOTE FLAGS(4); /* PF_R */ + eh_frame_hdr PT_GNU_EH_FRAME; +} + +VERSION +{ + LINUX_5.10 { + global: + __vdso_clock_getres; + __vdso_clock_gettime; + __vdso_gettimeofday; + __vdso_rt_sigreturn; + local: *; + }; +} + +/* + * Make the sigreturn code visible to the kernel. + */ +VDSO_sigreturn = __vdso_rt_sigreturn; diff --git a/arch/loongarch/vdso/vgettimeofday.c b/arch/loongarch/vdso/vgettimeofday.c new file mode 100644 index 000000000000..b1f4548dae92 --- /dev/null +++ b/arch/loongarch/vdso/vgettimeofday.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * LoongArch userspace implementations of gettimeofday() and similar. + * + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ +#include <linux/types.h> + +int __vdso_clock_gettime(clockid_t clock, + struct __kernel_timespec *ts) +{ + return __cvdso_clock_gettime(clock, ts); +} + +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, + struct timezone *tz) +{ + return __cvdso_gettimeofday(tv, tz); +} + +int __vdso_clock_getres(clockid_t clock_id, + struct __kernel_timespec *res) +{ + return __cvdso_clock_getres(clock_id, res); +} diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index e160a7c57bd3..2cb4a61bcfac 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -137,9 +137,11 @@ asmlinkage int m68k_clone3(struct pt_regs *regs) return sys_clone3((struct clone_args __user *)regs->d1, regs->d2); } -int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, - struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct fork_frame { struct switch_stack sw; struct pt_regs regs; @@ -156,12 +158,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, */ p->thread.fc = USER_DATA; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { /* kernel thread */ memset(frame, 0, sizeof(struct fork_frame)); frame->regs.sr = PS_S; - frame->sw.a3 = usp; /* function */ - frame->sw.d7 = arg; + frame->sw.a3 = (unsigned long)args->fn; + frame->sw.d7 = (unsigned long)args->fn_arg; frame->sw.retpc = (unsigned long)ret_from_kernel_thread; p->thread.usp = 0; return 0; diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 1b944d319d73..3c6241bcaea8 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -52,20 +52,22 @@ void flush_thread(void) { } -int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, - struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct pt_regs *childregs = task_pt_regs(p); struct thread_info *ti = task_thread_info(p); - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { /* if we're creating a new kernel thread then just zeroing all * the registers. That's OK for a brand new thread.*/ memset(childregs, 0, sizeof(struct pt_regs)); memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); ti->cpu_context.r1 = (unsigned long)childregs; - ti->cpu_context.r20 = (unsigned long)usp; /* fn */ - ti->cpu_context.r19 = (unsigned long)arg; + ti->cpu_context.r20 = (unsigned long)args->fn; + ti->cpu_context.r19 = (unsigned long)args->fn_arg; childregs->pt_mode = 1; local_save_flags(childregs->msr); ti->cpu_context.msr = childregs->msr & ~MSR_IE; diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c index cd72eaa1168f..e70e529ddd91 100644 --- a/arch/mips/alchemy/devboards/db1300.c +++ b/arch/mips/alchemy/devboards/db1300.c @@ -732,16 +732,7 @@ static struct platform_device db1300_lcd_dev = { /**********************************************************************/ #if IS_ENABLED(CONFIG_TOUCHSCREEN_WM97XX) -static void db1300_wm97xx_irqen(struct wm97xx *wm, int enable) -{ - if (enable) - enable_irq(DB1300_AC97_PEN_INT); - else - disable_irq_nosync(DB1300_AC97_PEN_INT); -} - static struct wm97xx_mach_ops db1300_wm97xx_ops = { - .irq_enable = db1300_wm97xx_irqen, .irq_gpio = WM97XX_GPIO_3, }; diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi index b998301f179c..c182a656d63b 100644 --- a/arch/mips/boot/dts/ingenic/jz4780.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi @@ -577,7 +577,7 @@ }; otg: usb@13500000 { - compatible = "ingenic,jz4780-otg", "snps,dwc2"; + compatible = "ingenic,jz4780-otg"; reg = <0x13500000 0x40000>; interrupt-parent = <&intc>; diff --git a/arch/mips/boot/dts/ingenic/x1000.dtsi b/arch/mips/boot/dts/ingenic/x1000.dtsi index ecbfed49dc77..b0a034b468bb 100644 --- a/arch/mips/boot/dts/ingenic/x1000.dtsi +++ b/arch/mips/boot/dts/ingenic/x1000.dtsi @@ -398,7 +398,7 @@ }; otg: usb@13500000 { - compatible = "ingenic,x1000-otg", "snps,dwc2"; + compatible = "ingenic,x1000-otg"; reg = <0x13500000 0x40000>; interrupt-parent = <&intc>; diff --git a/arch/mips/boot/dts/ingenic/x1830.dtsi b/arch/mips/boot/dts/ingenic/x1830.dtsi index efd556902cfd..dbf21afaccb1 100644 --- a/arch/mips/boot/dts/ingenic/x1830.dtsi +++ b/arch/mips/boot/dts/ingenic/x1830.dtsi @@ -408,7 +408,7 @@ }; otg: usb@13500000 { - compatible = "ingenic,x1830-otg", "snps,dwc2"; + compatible = "ingenic,x1830-otg"; reg = <0x13500000 0x40000>; interrupt-parent = <&intc>; diff --git a/arch/mips/include/uapi/asm/stat.h b/arch/mips/include/uapi/asm/stat.h index 8a8bb78883a4..aaccdc61be74 100644 --- a/arch/mips/include/uapi/asm/stat.h +++ b/arch/mips/include/uapi/asm/stat.h @@ -22,8 +22,8 @@ struct stat { __kernel_ino_t st_ino; __kernel_mode_t st_mode; __u32 st_nlink; - __kernel_uid_t st_uid; - __kernel_gid_t st_gid; + __kernel_uid32_t st_uid; + __kernel_gid32_t st_gid; unsigned st_rdev; long st_pad2[2]; long st_size; @@ -58,8 +58,8 @@ struct stat64 { __kernel_mode_t st_mode; __u32 st_nlink; - __kernel_uid_t st_uid; - __kernel_gid_t st_gid; + __kernel_uid32_t st_uid; + __kernel_gid32_t st_gid; unsigned long st_rdev; unsigned long st_pad1[3]; /* Reserved for st_rdev expansion */ @@ -99,8 +99,8 @@ struct stat { __kernel_mode_t st_mode; __u32 st_nlink; - __kernel_uid_t st_uid; - __kernel_gid_t st_gid; + __kernel_uid32_t st_uid; + __kernel_gid32_t st_gid; unsigned int st_rdev; unsigned int st_pad1[3]; /* Reserved for st_rdev expansion */ diff --git a/arch/mips/include/uapi/asm/termbits.h b/arch/mips/include/uapi/asm/termbits.h index dfeffba729b7..1eb60903d6f0 100644 --- a/arch/mips/include/uapi/asm/termbits.h +++ b/arch/mips/include/uapi/asm/termbits.h @@ -11,11 +11,9 @@ #ifndef _ASM_TERMBITS_H #define _ASM_TERMBITS_H -#include <linux/posix_types.h> +#include <asm-generic/termbits-common.h> -typedef unsigned char cc_t; -typedef unsigned int speed_t; -typedef unsigned int tcflag_t; +typedef unsigned int tcflag_t; /* * The ABI says nothing about NCC but seems to use NCCS as @@ -54,175 +52,126 @@ struct ktermios { }; /* c_cc characters */ -#define VINTR 0 /* Interrupt character [ISIG]. */ -#define VQUIT 1 /* Quit character [ISIG]. */ -#define VERASE 2 /* Erase character [ICANON]. */ -#define VKILL 3 /* Kill-line character [ICANON]. */ -#define VMIN 4 /* Minimum number of bytes read at once [!ICANON]. */ -#define VTIME 5 /* Time-out value (tenths of a second) [!ICANON]. */ -#define VEOL2 6 /* Second EOL character [ICANON]. */ +#define VINTR 0 /* Interrupt character [ISIG] */ +#define VQUIT 1 /* Quit character [ISIG] */ +#define VERASE 2 /* Erase character [ICANON] */ +#define VKILL 3 /* Kill-line character [ICANON] */ +#define VMIN 4 /* Minimum number of bytes read at once [!ICANON] */ +#define VTIME 5 /* Time-out value (tenths of a second) [!ICANON] */ +#define VEOL2 6 /* Second EOL character [ICANON] */ #define VSWTC 7 /* ??? */ #define VSWTCH VSWTC -#define VSTART 8 /* Start (X-ON) character [IXON, IXOFF]. */ -#define VSTOP 9 /* Stop (X-OFF) character [IXON, IXOFF]. */ -#define VSUSP 10 /* Suspend character [ISIG]. */ +#define VSTART 8 /* Start (X-ON) character [IXON, IXOFF] */ +#define VSTOP 9 /* Stop (X-OFF) character [IXON, IXOFF] */ +#define VSUSP 10 /* Suspend character [ISIG] */ #if 0 /* * VDSUSP is not supported */ -#define VDSUSP 11 /* Delayed suspend character [ISIG]. */ +#define VDSUSP 11 /* Delayed suspend character [ISIG] */ #endif -#define VREPRINT 12 /* Reprint-line character [ICANON]. */ -#define VDISCARD 13 /* Discard character [IEXTEN]. */ -#define VWERASE 14 /* Word-erase character [ICANON]. */ -#define VLNEXT 15 /* Literal-next character [IEXTEN]. */ -#define VEOF 16 /* End-of-file character [ICANON]. */ -#define VEOL 17 /* End-of-line character [ICANON]. */ +#define VREPRINT 12 /* Reprint-line character [ICANON] */ +#define VDISCARD 13 /* Discard character [IEXTEN] */ +#define VWERASE 14 /* Word-erase character [ICANON] */ +#define VLNEXT 15 /* Literal-next character [IEXTEN] */ +#define VEOF 16 /* End-of-file character [ICANON] */ +#define VEOL 17 /* End-of-line character [ICANON] */ /* c_iflag bits */ -#define IGNBRK 0000001 /* Ignore break condition. */ -#define BRKINT 0000002 /* Signal interrupt on break. */ -#define IGNPAR 0000004 /* Ignore characters with parity errors. */ -#define PARMRK 0000010 /* Mark parity and framing errors. */ -#define INPCK 0000020 /* Enable input parity check. */ -#define ISTRIP 0000040 /* Strip 8th bit off characters. */ -#define INLCR 0000100 /* Map NL to CR on input. */ -#define IGNCR 0000200 /* Ignore CR. */ -#define ICRNL 0000400 /* Map CR to NL on input. */ -#define IUCLC 0001000 /* Map upper case to lower case on input. */ -#define IXON 0002000 /* Enable start/stop output control. */ -#define IXANY 0004000 /* Any character will restart after stop. */ -#define IXOFF 0010000 /* Enable start/stop input control. */ -#define IMAXBEL 0020000 /* Ring bell when input queue is full. */ -#define IUTF8 0040000 /* Input is UTF-8 */ +#define IUCLC 0x0200 /* Map upper case to lower case on input */ +#define IXON 0x0400 /* Enable start/stop output control */ +#define IXOFF 0x1000 /* Enable start/stop input control */ +#define IMAXBEL 0x2000 /* Ring bell when input queue is full */ +#define IUTF8 0x4000 /* Input is UTF-8 */ /* c_oflag bits */ -#define OPOST 0000001 /* Perform output processing. */ -#define OLCUC 0000002 /* Map lower case to upper case on output. */ -#define ONLCR 0000004 /* Map NL to CR-NL on output. */ -#define OCRNL 0000010 -#define ONOCR 0000020 -#define ONLRET 0000040 -#define OFILL 0000100 -#define OFDEL 0000200 -#define NLDLY 0000400 -#define NL0 0000000 -#define NL1 0000400 -#define CRDLY 0003000 -#define CR0 0000000 -#define CR1 0001000 -#define CR2 0002000 -#define CR3 0003000 -#define TABDLY 0014000 -#define TAB0 0000000 -#define TAB1 0004000 -#define TAB2 0010000 -#define TAB3 0014000 -#define XTABS 0014000 -#define BSDLY 0020000 -#define BS0 0000000 -#define BS1 0020000 -#define VTDLY 0040000 -#define VT0 0000000 -#define VT1 0040000 -#define FFDLY 0100000 -#define FF0 0000000 -#define FF1 0100000 +#define OLCUC 0x00002 /* Map lower case to upper case on output */ +#define ONLCR 0x00004 /* Map NL to CR-NL on output */ +#define NLDLY 0x00100 +#define NL0 0x00000 +#define NL1 0x00100 +#define CRDLY 0x00600 +#define CR0 0x00000 +#define CR1 0x00200 +#define CR2 0x00400 +#define CR3 0x00600 +#define TABDLY 0x01800 +#define TAB0 0x00000 +#define TAB1 0x00800 +#define TAB2 0x01000 +#define TAB3 0x01800 +#define XTABS 0x01800 +#define BSDLY 0x02000 +#define BS0 0x00000 +#define BS1 0x02000 +#define VTDLY 0x04000 +#define VT0 0x00000 +#define VT1 0x04000 +#define FFDLY 0x08000 +#define FF0 0x00000 +#define FF1 0x08000 /* #define PAGEOUT ??? #define WRAP ??? */ /* c_cflag bit meaning */ -#define CBAUD 0010017 -#define B0 0000000 /* hang up */ -#define B50 0000001 -#define B75 0000002 -#define B110 0000003 -#define B134 0000004 -#define B150 0000005 -#define B200 0000006 -#define B300 0000007 -#define B600 0000010 -#define B1200 0000011 -#define B1800 0000012 -#define B2400 0000013 -#define B4800 0000014 -#define B9600 0000015 -#define B19200 0000016 -#define B38400 0000017 -#define EXTA B19200 -#define EXTB B38400 -#define CSIZE 0000060 /* Number of bits per byte (mask). */ -#define CS5 0000000 /* 5 bits per byte. */ -#define CS6 0000020 /* 6 bits per byte. */ -#define CS7 0000040 /* 7 bits per byte. */ -#define CS8 0000060 /* 8 bits per byte. */ -#define CSTOPB 0000100 /* Two stop bits instead of one. */ -#define CREAD 0000200 /* Enable receiver. */ -#define PARENB 0000400 /* Parity enable. */ -#define PARODD 0001000 /* Odd parity instead of even. */ -#define HUPCL 0002000 /* Hang up on last close. */ -#define CLOCAL 0004000 /* Ignore modem status lines. */ -#define CBAUDEX 0010000 -#define BOTHER 0010000 -#define B57600 0010001 -#define B115200 0010002 -#define B230400 0010003 -#define B460800 0010004 -#define B500000 0010005 -#define B576000 0010006 -#define B921600 0010007 -#define B1000000 0010010 -#define B1152000 0010011 -#define B1500000 0010012 -#define B2000000 0010013 -#define B2500000 0010014 -#define B3000000 0010015 -#define B3500000 0010016 -#define B4000000 0010017 -#define CIBAUD 002003600000 /* input baud rate */ -#define CMSPAR 010000000000 /* mark or space (stick) parity */ -#define CRTSCTS 020000000000 /* flow control */ - -#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ +#define CBAUD 0x0000100f +#define CSIZE 0x00000030 /* Number of bits per byte (mask) */ +#define CS5 0x00000000 /* 5 bits per byte */ +#define CS6 0x00000010 /* 6 bits per byte */ +#define CS7 0x00000020 /* 7 bits per byte */ +#define CS8 0x00000030 /* 8 bits per byte */ +#define CSTOPB 0x00000040 /* Two stop bits instead of one */ +#define CREAD 0x00000080 /* Enable receiver */ +#define PARENB 0x00000100 /* Parity enable */ +#define PARODD 0x00000200 /* Odd parity instead of even */ +#define HUPCL 0x00000400 /* Hang up on last close */ +#define CLOCAL 0x00000800 /* Ignore modem status lines */ +#define CBAUDEX 0x00001000 +#define BOTHER 0x00001000 +#define B57600 0x00001001 +#define B115200 0x00001002 +#define B230400 0x00001003 +#define B460800 0x00001004 +#define B500000 0x00001005 +#define B576000 0x00001006 +#define B921600 0x00001007 +#define B1000000 0x00001008 +#define B1152000 0x00001009 +#define B1500000 0x0000100a +#define B2000000 0x0000100b +#define B2500000 0x0000100c +#define B3000000 0x0000100d +#define B3500000 0x0000100e +#define B4000000 0x0000100f +#define CIBAUD 0x100f0000 /* input baud rate */ /* c_lflag bits */ -#define ISIG 0000001 /* Enable signals. */ -#define ICANON 0000002 /* Do erase and kill processing. */ -#define XCASE 0000004 -#define ECHO 0000010 /* Enable echo. */ -#define ECHOE 0000020 /* Visual erase for ERASE. */ -#define ECHOK 0000040 /* Echo NL after KILL. */ -#define ECHONL 0000100 /* Echo NL even if ECHO is off. */ -#define NOFLSH 0000200 /* Disable flush after interrupt. */ -#define IEXTEN 0000400 /* Enable DISCARD and LNEXT. */ -#define ECHOCTL 0001000 /* Echo control characters as ^X. */ -#define ECHOPRT 0002000 /* Hardcopy visual erase. */ -#define ECHOKE 0004000 /* Visual erase for KILL. */ -#define FLUSHO 0020000 -#define PENDIN 0040000 /* Retype pending input (state). */ -#define TOSTOP 0100000 /* Send SIGTTOU for background output. */ -#define ITOSTOP TOSTOP -#define EXTPROC 0200000 /* External processing on pty */ +#define ISIG 0x00001 /* Enable signals */ +#define ICANON 0x00002 /* Do erase and kill processing */ +#define XCASE 0x00004 +#define ECHO 0x00008 /* Enable echo */ +#define ECHOE 0x00010 /* Visual erase for ERASE */ +#define ECHOK 0x00020 /* Echo NL after KILL */ +#define ECHONL 0x00040 /* Echo NL even if ECHO is off */ +#define NOFLSH 0x00080 /* Disable flush after interrupt */ +#define IEXTEN 0x00100 /* Enable DISCARD and LNEXT */ +#define ECHOCTL 0x00200 /* Echo control characters as ^X */ +#define ECHOPRT 0x00400 /* Hardcopy visual erase */ +#define ECHOKE 0x00800 /* Visual erase for KILL */ +#define FLUSHO 0x02000 +#define PENDIN 0x04000 /* Retype pending input (state) */ +#define TOSTOP 0x08000 /* Send SIGTTOU for background output */ +#define ITOSTOP TOSTOP +#define EXTPROC 0x10000 /* External processing on pty */ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -/* tcflow() and TCXONC use these */ -#define TCOOFF 0 /* Suspend output. */ -#define TCOON 1 /* Restart suspended output. */ -#define TCIOFF 2 /* Send a STOP character. */ -#define TCION 3 /* Send a START character. */ - -/* tcflush() and TCFLSH use these */ -#define TCIFLUSH 0 /* Discard data received but not yet read. */ -#define TCOFLUSH 1 /* Discard data written but not yet sent. */ -#define TCIOFLUSH 2 /* Discard all pending data. */ - /* tcsetattr uses these */ -#define TCSANOW TCSETS /* Change immediately. */ -#define TCSADRAIN TCSETSW /* Change when pending output is written. */ -#define TCSAFLUSH TCSETSF /* Flush pending input before changing. */ +#define TCSANOW TCSETS /* Change immediately */ +#define TCSADRAIN TCSETSW /* Change when pending output is written */ +#define TCSAFLUSH TCSETSF /* Flush pending input before changing */ #endif /* _ASM_TERMBITS_H */ diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index c2d5f4bfe1f3..35b912bce429 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -105,10 +105,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) /* * Copy architecture-specific thread state */ -int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long kthread_arg, struct task_struct *p, - unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct thread_info *ti = task_thread_info(p); struct pt_regs *childregs, *regs = current_pt_regs(); unsigned long childksp; @@ -120,12 +121,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, /* Put the stack after the struct pt_regs. */ childksp = (unsigned long) childregs; p->thread.cp0_status = (read_c0_status() & ~(ST0_CU2|ST0_CU1)) | ST0_KERNEL_CUMASK; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { /* kernel thread */ unsigned long status = p->thread.cp0_status; memset(childregs, 0, sizeof(struct pt_regs)); - p->thread.reg16 = usp; /* fn */ - p->thread.reg17 = kthread_arg; + p->thread.reg16 = (unsigned long)args->fn; + p->thread.reg17 = (unsigned long)args->fn_arg; p->thread.reg29 = childksp; p->thread.reg31 = (unsigned long) ret_from_kernel_thread; #if defined(CONFIG_CPU_R3000) diff --git a/arch/nios2/kernel/process.c b/arch/nios2/kernel/process.c index f8ea522a1588..29593b98567d 100644 --- a/arch/nios2/kernel/process.c +++ b/arch/nios2/kernel/process.c @@ -100,21 +100,23 @@ void flush_thread(void) { } -int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, - struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct pt_regs *childregs = task_pt_regs(p); struct pt_regs *regs; struct switch_stack *stack; struct switch_stack *childstack = ((struct switch_stack *)childregs) - 1; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { memset(childstack, 0, sizeof(struct switch_stack) + sizeof(struct pt_regs)); - childstack->r16 = usp; /* fn */ - childstack->r17 = arg; + childstack->r16 = (unsigned long) args->fn; + childstack->r17 = (unsigned long) args->fn_arg; childstack->ra = (unsigned long) ret_from_kernel_thread; childregs->estatus = STATUS_PIE; childregs->sp = (unsigned long) childstack; diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c index 1d4c0921aafa..52dc983ddeba 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c @@ -167,9 +167,11 @@ extern asmlinkage void ret_from_fork(void); */ int -copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, - struct task_struct *p, unsigned long tls) +copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct pt_regs *userregs; struct pt_regs *kregs; unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; @@ -187,10 +189,10 @@ copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, sp -= sizeof(struct pt_regs); kregs = (struct pt_regs *)sp; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { memset(kregs, 0, sizeof(struct pt_regs)); - kregs->gpr[20] = usp; /* fn, kernel thread */ - kregs->gpr[22] = arg; + kregs->gpr[20] = (unsigned long)args->fn; + kregs->gpr[22] = (unsigned long)args->fn_arg; } else { *userregs = *current_pt_regs(); diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index aca1710fd658..e38d993d87f2 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -18,7 +18,6 @@ boot := arch/parisc/boot KBUILD_IMAGE := $(boot)/bzImage -NM = sh $(srctree)/arch/parisc/nm CHECKFLAGS += -D__hppa__=1 ifdef CONFIG_64BIT diff --git a/arch/parisc/include/asm/fb.h b/arch/parisc/include/asm/fb.h index c4cd6360f996..d63a2acb91f2 100644 --- a/arch/parisc/include/asm/fb.h +++ b/arch/parisc/include/asm/fb.h @@ -12,9 +12,13 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; } +#if defined(CONFIG_STI_CONSOLE) || defined(CONFIG_FB_STI) +int fb_is_primary_device(struct fb_info *info); +#else static inline int fb_is_primary_device(struct fb_info *info) { return 0; } +#endif #endif /* _ASM_FB_H_ */ diff --git a/arch/parisc/include/uapi/asm/termbits.h b/arch/parisc/include/uapi/asm/termbits.h index 40e920f8d683..3a8938d26fb4 100644 --- a/arch/parisc/include/uapi/asm/termbits.h +++ b/arch/parisc/include/uapi/asm/termbits.h @@ -2,10 +2,8 @@ #ifndef __ARCH_PARISC_TERMBITS_H__ #define __ARCH_PARISC_TERMBITS_H__ -#include <linux/posix_types.h> +#include <asm-generic/termbits-common.h> -typedef unsigned char cc_t; -typedef unsigned int speed_t; typedef unsigned int tcflag_t; #define NCCS 19 @@ -41,158 +39,107 @@ struct ktermios { }; /* c_cc characters */ -#define VINTR 0 -#define VQUIT 1 -#define VERASE 2 -#define VKILL 3 -#define VEOF 4 -#define VTIME 5 -#define VMIN 6 -#define VSWTC 7 -#define VSTART 8 -#define VSTOP 9 -#define VSUSP 10 -#define VEOL 11 -#define VREPRINT 12 -#define VDISCARD 13 -#define VWERASE 14 -#define VLNEXT 15 -#define VEOL2 16 - +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 /* c_iflag bits */ -#define IGNBRK 0000001 -#define BRKINT 0000002 -#define IGNPAR 0000004 -#define PARMRK 0000010 -#define INPCK 0000020 -#define ISTRIP 0000040 -#define INLCR 0000100 -#define IGNCR 0000200 -#define ICRNL 0000400 -#define IUCLC 0001000 -#define IXON 0002000 -#define IXANY 0004000 -#define IXOFF 0010000 -#define IMAXBEL 0040000 -#define IUTF8 0100000 +#define IUCLC 0x0200 +#define IXON 0x0400 +#define IXOFF 0x1000 +#define IMAXBEL 0x4000 +#define IUTF8 0x8000 /* c_oflag bits */ -#define OPOST 0000001 -#define OLCUC 0000002 -#define ONLCR 0000004 -#define OCRNL 0000010 -#define ONOCR 0000020 -#define ONLRET 0000040 -#define OFILL 0000100 -#define OFDEL 0000200 -#define NLDLY 0000400 -#define NL0 0000000 -#define NL1 0000400 -#define CRDLY 0003000 -#define CR0 0000000 -#define CR1 0001000 -#define CR2 0002000 -#define CR3 0003000 -#define TABDLY 0014000 -#define TAB0 0000000 -#define TAB1 0004000 -#define TAB2 0010000 -#define TAB3 0014000 -#define XTABS 0014000 -#define BSDLY 0020000 -#define BS0 0000000 -#define BS1 0020000 -#define VTDLY 0040000 -#define VT0 0000000 -#define VT1 0040000 -#define FFDLY 0100000 -#define FF0 0000000 -#define FF1 0100000 +#define OLCUC 0x00002 +#define ONLCR 0x00004 +#define NLDLY 0x00100 +#define NL0 0x00000 +#define NL1 0x00100 +#define CRDLY 0x00600 +#define CR0 0x00000 +#define CR1 0x00200 +#define CR2 0x00400 +#define CR3 0x00600 +#define TABDLY 0x01800 +#define TAB0 0x00000 +#define TAB1 0x00800 +#define TAB2 0x01000 +#define TAB3 0x01800 +#define XTABS 0x01800 +#define BSDLY 0x02000 +#define BS0 0x00000 +#define BS1 0x02000 +#define VTDLY 0x04000 +#define VT0 0x00000 +#define VT1 0x04000 +#define FFDLY 0x08000 +#define FF0 0x00000 +#define FF1 0x08000 /* c_cflag bit meaning */ -#define CBAUD 0010017 -#define B0 0000000 /* hang up */ -#define B50 0000001 -#define B75 0000002 -#define B110 0000003 -#define B134 0000004 -#define B150 0000005 -#define B200 0000006 -#define B300 0000007 -#define B600 0000010 -#define B1200 0000011 -#define B1800 0000012 -#define B2400 0000013 -#define B4800 0000014 -#define B9600 0000015 -#define B19200 0000016 -#define B38400 0000017 -#define EXTA B19200 -#define EXTB B38400 -#define CSIZE 0000060 -#define CS5 0000000 -#define CS6 0000020 -#define CS7 0000040 -#define CS8 0000060 -#define CSTOPB 0000100 -#define CREAD 0000200 -#define PARENB 0000400 -#define PARODD 0001000 -#define HUPCL 0002000 -#define CLOCAL 0004000 -#define CBAUDEX 0010000 -#define BOTHER 0010000 -#define B57600 0010001 -#define B115200 0010002 -#define B230400 0010003 -#define B460800 0010004 -#define B500000 0010005 -#define B576000 0010006 -#define B921600 0010007 -#define B1000000 0010010 -#define B1152000 0010011 -#define B1500000 0010012 -#define B2000000 0010013 -#define B2500000 0010014 -#define B3000000 0010015 -#define B3500000 0010016 -#define B4000000 0010017 -#define CIBAUD 002003600000 /* input baud rate */ -#define CMSPAR 010000000000 /* mark or space (stick) parity */ -#define CRTSCTS 020000000000 /* flow control */ - -#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ - +#define CBAUD 0x0000100f +#define CSIZE 0x00000030 +#define CS5 0x00000000 +#define CS6 0x00000010 +#define CS7 0x00000020 +#define CS8 0x00000030 +#define CSTOPB 0x00000040 +#define CREAD 0x00000080 +#define PARENB 0x00000100 +#define PARODD 0x00000200 +#define HUPCL 0x00000400 +#define CLOCAL 0x00000800 +#define CBAUDEX 0x00001000 +#define BOTHER 0x00001000 +#define B57600 0x00001001 +#define B115200 0x00001002 +#define B230400 0x00001003 +#define B460800 0x00001004 +#define B500000 0x00001005 +#define B576000 0x00001006 +#define B921600 0x00001007 +#define B1000000 0x00001008 +#define B1152000 0x00001009 +#define B1500000 0x0000100a +#define B2000000 0x0000100b +#define B2500000 0x0000100c +#define B3000000 0x0000100d +#define B3500000 0x0000100e +#define B4000000 0x0000100f +#define CIBAUD 0x100f0000 /* input baud rate */ /* c_lflag bits */ -#define ISIG 0000001 -#define ICANON 0000002 -#define XCASE 0000004 -#define ECHO 0000010 -#define ECHOE 0000020 -#define ECHOK 0000040 -#define ECHONL 0000100 -#define NOFLSH 0000200 -#define TOSTOP 0000400 -#define ECHOCTL 0001000 -#define ECHOPRT 0002000 -#define ECHOKE 0004000 -#define FLUSHO 0010000 -#define PENDIN 0040000 -#define IEXTEN 0100000 -#define EXTPROC 0200000 - -/* tcflow() and TCXONC use these */ -#define TCOOFF 0 -#define TCOON 1 -#define TCIOFF 2 -#define TCION 3 - -/* tcflush() and TCFLSH use these */ -#define TCIFLUSH 0 -#define TCOFLUSH 1 -#define TCIOFLUSH 2 +#define ISIG 0x00001 +#define ICANON 0x00002 +#define XCASE 0x00004 +#define ECHO 0x00008 +#define ECHOE 0x00010 +#define ECHOK 0x00020 +#define ECHONL 0x00040 +#define NOFLSH 0x00080 +#define TOSTOP 0x00100 +#define ECHOCTL 0x00200 +#define ECHOPRT 0x00400 +#define ECHOKE 0x00800 +#define FLUSHO 0x01000 +#define PENDIN 0x04000 +#define IEXTEN 0x08000 +#define EXTPROC 0x10000 /* tcsetattr uses these */ #define TCSANOW 0 diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index d145184696ea..7c37e09c92da 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -206,9 +206,11 @@ arch_initcall(parisc_idle_init); * Copy architecture-specific thread state */ int -copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long kthread_arg, struct task_struct *p, unsigned long tls) +copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct pt_regs *cregs = &(p->thread.regs); void *stack = task_stack_page(p); @@ -218,10 +220,10 @@ copy_thread(unsigned long clone_flags, unsigned long usp, extern void * const ret_from_kernel_thread; extern void * const child_return; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { /* kernel thread */ memset(cregs, 0, sizeof(struct pt_regs)); - if (!usp) /* idle thread */ + if (args->idle) /* idle thread */ return 0; /* Must exit via ret_from_kernel_thread in order * to call schedule_tail() @@ -233,12 +235,12 @@ copy_thread(unsigned long clone_flags, unsigned long usp, * ret_from_kernel_thread. */ #ifdef CONFIG_64BIT - cregs->gr[27] = ((unsigned long *)usp)[3]; - cregs->gr[26] = ((unsigned long *)usp)[2]; + cregs->gr[27] = ((unsigned long *)args->fn)[3]; + cregs->gr[26] = ((unsigned long *)args->fn)[2]; #else - cregs->gr[26] = usp; + cregs->gr[26] = (unsigned long) args->fn; #endif - cregs->gr[25] = kthread_arg; + cregs->gr[25] = (unsigned long) args->fn_arg; } else { /* user thread */ /* usp must be word aligned. This also prevents users from diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index 26eb568f8b96..dddaaa6e7a82 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c @@ -327,8 +327,6 @@ int init_per_cpu(int cpunum) set_firmware_width(); ret = pdc_coproc_cfg(&coproc_cfg); - store_cpu_topology(cpunum); - if(ret >= 0 && coproc_cfg.ccr_functional) { mtctl(coproc_cfg.ccr_functional, 10); /* 10 == Coprocessor Control Reg */ diff --git a/arch/parisc/kernel/topology.c b/arch/parisc/kernel/topology.c index 9696e3cb6a2a..b9d845e314f8 100644 --- a/arch/parisc/kernel/topology.c +++ b/arch/parisc/kernel/topology.c @@ -20,8 +20,6 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); -static int dualcores_found; - /* * store_cpu_topology is called at boot when only one cpu is running * and with the mutex cpu_hotplug.lock locked, when several cpus have booted, @@ -60,7 +58,6 @@ void store_cpu_topology(unsigned int cpuid) if (p->cpu_loc) { cpuid_topo->core_id++; cpuid_topo->package_id = cpu_topology[cpu].package_id; - dualcores_found = 1; continue; } } @@ -80,22 +77,11 @@ void store_cpu_topology(unsigned int cpuid) cpu_topology[cpuid].package_id); } -static struct sched_domain_topology_level parisc_mc_topology[] = { -#ifdef CONFIG_SCHED_MC - { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, -#endif - - { cpu_cpu_mask, SD_INIT_NAME(DIE) }, - { NULL, }, -}; - /* * init_cpu_topology is called at boot when only one cpu is running * which prevent simultaneous write access to cpu_topology array */ void __init init_cpu_topology(void) { - /* Set scheduler topology descriptor */ - if (dualcores_found) - set_sched_topology(parisc_mc_topology); + reset_cpu_topology(); } diff --git a/arch/parisc/nm b/arch/parisc/nm deleted file mode 100644 index c788308de33f..000000000000 --- a/arch/parisc/nm +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -## -# Hack to have an nm which removes the local symbols. We also rely -# on this nm being hidden out of the ordinarily executable path -## -${CROSS_COMPILE}nm $* | grep -v '.LC*[0-9]*$' diff --git a/arch/powerpc/include/uapi/asm/stat.h b/arch/powerpc/include/uapi/asm/stat.h index a28c9a1201fa..d50901664239 100644 --- a/arch/powerpc/include/uapi/asm/stat.h +++ b/arch/powerpc/include/uapi/asm/stat.h @@ -37,8 +37,8 @@ struct stat { __kernel_mode_t st_mode; unsigned short st_nlink; #endif - __kernel_uid_t st_uid; - __kernel_gid_t st_gid; + __kernel_uid32_t st_uid; + __kernel_gid32_t st_gid; unsigned long st_rdev; long st_size; unsigned long st_blksize; diff --git a/arch/powerpc/include/uapi/asm/termbits.h b/arch/powerpc/include/uapi/asm/termbits.h index ed18bc61f63d..21dc86dcb2f1 100644 --- a/arch/powerpc/include/uapi/asm/termbits.h +++ b/arch/powerpc/include/uapi/asm/termbits.h @@ -9,8 +9,8 @@ * 2 of the License, or (at your option) any later version. */ -typedef unsigned char cc_t; -typedef unsigned int speed_t; +#include <asm-generic/termbits-common.h> + typedef unsigned int tcflag_t; /* @@ -64,115 +64,72 @@ struct ktermios { #define VDISCARD 16 /* c_iflag bits */ -#define IGNBRK 0000001 -#define BRKINT 0000002 -#define IGNPAR 0000004 -#define PARMRK 0000010 -#define INPCK 0000020 -#define ISTRIP 0000040 -#define INLCR 0000100 -#define IGNCR 0000200 -#define ICRNL 0000400 -#define IXON 0001000 -#define IXOFF 0002000 -#define IXANY 0004000 -#define IUCLC 0010000 -#define IMAXBEL 0020000 -#define IUTF8 0040000 +#define IXON 0x0200 +#define IXOFF 0x0400 +#define IUCLC 0x1000 +#define IMAXBEL 0x2000 +#define IUTF8 0x4000 /* c_oflag bits */ -#define OPOST 0000001 -#define ONLCR 0000002 -#define OLCUC 0000004 - -#define OCRNL 0000010 -#define ONOCR 0000020 -#define ONLRET 0000040 - -#define OFILL 00000100 -#define OFDEL 00000200 -#define NLDLY 00001400 -#define NL0 00000000 -#define NL1 00000400 -#define NL2 00001000 -#define NL3 00001400 -#define TABDLY 00006000 -#define TAB0 00000000 -#define TAB1 00002000 -#define TAB2 00004000 -#define TAB3 00006000 -#define XTABS 00006000 /* required by POSIX to == TAB3 */ -#define CRDLY 00030000 -#define CR0 00000000 -#define CR1 00010000 -#define CR2 00020000 -#define CR3 00030000 -#define FFDLY 00040000 -#define FF0 00000000 -#define FF1 00040000 -#define BSDLY 00100000 -#define BS0 00000000 -#define BS1 00100000 -#define VTDLY 00200000 -#define VT0 00000000 -#define VT1 00200000 +#define ONLCR 0x00002 +#define OLCUC 0x00004 +#define NLDLY 0x00300 +#define NL0 0x00000 +#define NL1 0x00100 +#define NL2 0x00200 +#define NL3 0x00300 +#define TABDLY 0x00c00 +#define TAB0 0x00000 +#define TAB1 0x00400 +#define TAB2 0x00800 +#define TAB3 0x00c00 +#define XTABS 0x00c00 /* required by POSIX to == TAB3 */ +#define CRDLY 0x03000 +#define CR0 0x00000 +#define CR1 0x01000 +#define CR2 0x02000 +#define CR3 0x03000 +#define FFDLY 0x04000 +#define FF0 0x00000 +#define FF1 0x04000 +#define BSDLY 0x08000 +#define BS0 0x00000 +#define BS1 0x08000 +#define VTDLY 0x10000 +#define VT0 0x00000 +#define VT1 0x10000 /* c_cflag bit meaning */ -#define CBAUD 0000377 -#define B0 0000000 /* hang up */ -#define B50 0000001 -#define B75 0000002 -#define B110 0000003 -#define B134 0000004 -#define B150 0000005 -#define B200 0000006 -#define B300 0000007 -#define B600 0000010 -#define B1200 0000011 -#define B1800 0000012 -#define B2400 0000013 -#define B4800 0000014 -#define B9600 0000015 -#define B19200 0000016 -#define B38400 0000017 -#define EXTA B19200 -#define EXTB B38400 -#define CBAUDEX 0000000 -#define B57600 00020 -#define B115200 00021 -#define B230400 00022 -#define B460800 00023 -#define B500000 00024 -#define B576000 00025 -#define B921600 00026 -#define B1000000 00027 -#define B1152000 00030 -#define B1500000 00031 -#define B2000000 00032 -#define B2500000 00033 -#define B3000000 00034 -#define B3500000 00035 -#define B4000000 00036 -#define BOTHER 00037 - -#define CIBAUD 077600000 -#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ - -#define CSIZE 00001400 -#define CS5 00000000 -#define CS6 00000400 -#define CS7 00001000 -#define CS8 00001400 - -#define CSTOPB 00002000 -#define CREAD 00004000 -#define PARENB 00010000 -#define PARODD 00020000 -#define HUPCL 00040000 - -#define CLOCAL 00100000 -#define CMSPAR 010000000000 /* mark or space (stick) parity */ -#define CRTSCTS 020000000000 /* flow control */ +#define CBAUD 0x000000ff +#define CBAUDEX 0x00000000 +#define BOTHER 0x0000001f +#define B57600 0x00000010 +#define B115200 0x00000011 +#define B230400 0x00000012 +#define B460800 0x00000013 +#define B500000 0x00000014 +#define B576000 0x00000015 +#define B921600 0x00000016 +#define B1000000 0x00000017 +#define B1152000 0x00000018 +#define B1500000 0x00000019 +#define B2000000 0x0000001a +#define B2500000 0x0000001b +#define B3000000 0x0000001c +#define B3500000 0x0000001d +#define B4000000 0x0000001e +#define CSIZE 0x00000300 +#define CS5 0x00000000 +#define CS6 0x00000100 +#define CS7 0x00000200 +#define CS8 0x00000300 +#define CSTOPB 0x00000400 +#define CREAD 0x00000800 +#define PARENB 0x00001000 +#define PARODD 0x00002000 +#define HUPCL 0x00004000 +#define CLOCAL 0x00008000 +#define CIBAUD 0x00ff0000 /* c_lflag bits */ #define ISIG 0x00000080 @@ -192,17 +149,6 @@ struct ktermios { #define IEXTEN 0x00000400 #define EXTPROC 0x10000000 -/* Values for the ACTION argument to `tcflow'. */ -#define TCOOFF 0 -#define TCOON 1 -#define TCIOFF 2 -#define TCION 3 - -/* Values for the QUEUE_SELECTOR argument to `tcflush'. */ -#define TCIFLUSH 0 -#define TCOFLUSH 1 -#define TCIOFLUSH 2 - /* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'. */ #define TCSANOW 0 #define TCSADRAIN 1 diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index d00b20c65966..b62046bf3bb8 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1713,10 +1713,11 @@ static void setup_ksp_vsid(struct task_struct *p, unsigned long sp) /* * Copy architecture-specific thread state */ -int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long kthread_arg, struct task_struct *p, - unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct pt_regs *childregs, *kregs; extern void ret_from_fork(void); extern void ret_from_fork_scv(void); @@ -1733,18 +1734,18 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, /* Copy registers */ sp -= sizeof(struct pt_regs); childregs = (struct pt_regs *) sp; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { /* kernel thread */ memset(childregs, 0, sizeof(struct pt_regs)); childregs->gpr[1] = sp + sizeof(struct pt_regs); /* function */ - if (usp) - childregs->gpr[14] = ppc_function_entry((void *)usp); + if (args->fn) + childregs->gpr[14] = ppc_function_entry((void *)args->fn); #ifdef CONFIG_PPC64 clear_tsk_thread_flag(p, TIF_32BIT); childregs->softe = IRQS_ENABLED; #endif - childregs->gpr[15] = kthread_arg; + childregs->gpr[15] = (unsigned long)args->fn_arg; p->thread.regs = NULL; /* no user register state */ ti->flags |= _TIF_RESTOREALL; f = ret_from_kernel_thread; diff --git a/arch/riscv/Kbuild b/arch/riscv/Kbuild index f562c7343fda..afa83e307a2e 100644 --- a/arch/riscv/Kbuild +++ b/arch/riscv/Kbuild @@ -2,6 +2,8 @@ obj-y += kernel/ mm/ net/ obj-$(CONFIG_BUILTIN_DTB) += boot/dts/ +obj-y += errata/ +obj-$(CONFIG_KVM) += kvm/ obj-$(CONFIG_ARCH_HAS_KEXEC_PURGATORY) += purgatory/ diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 905e550e0fd3..c22f58155948 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -396,7 +396,7 @@ config RISCV_SBI_V01 config RISCV_BOOT_SPINWAIT bool "Spinwait booting method" depends on SMP - default y + default y if RISCV_SBI_V01 || RISCV_M_MODE help This enables support for booting Linux via spinwait method. In the spinwait method, all cores randomly jump to Linux. One of the cores @@ -407,6 +407,12 @@ config RISCV_BOOT_SPINWAIT rely on ordered booting via SBI HSM extension which gets chosen dynamically at runtime if the firmware supports it. + Since spinwait is incompatible with sparse hart IDs, it requires + NR_CPUS be large enough to contain the physical hart ID of the first + hart to enter Linux. + + If unsure what to do here, say N. + config KEXEC bool "Kexec system call" select KEXEC_CORE diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index e3b1d06e4db1..34cf8a598617 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -103,9 +103,6 @@ endif head-y := arch/riscv/kernel/head.o -core-y += arch/riscv/errata/ -core-$(CONFIG_KVM) += arch/riscv/kvm/ - libs-y += arch/riscv/lib/ libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a diff --git a/arch/riscv/boot/dts/microchip/Makefile b/arch/riscv/boot/dts/microchip/Makefile index 855c1502d912..39aae7b04f1c 100644 --- a/arch/riscv/boot/dts/microchip/Makefile +++ b/arch/riscv/boot/dts/microchip/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += microchip-mpfs-icicle-kit.dtb +dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-icicle-kit.dtb +dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-polarberry.dtb obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y)) diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs-fabric.dtsi b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi index ccaac3371cf9..0d28858b83f2 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs-fabric.dtsi +++ b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit-fabric.dtsi @@ -2,6 +2,8 @@ /* Copyright (c) 2020-2021 Microchip Technology Inc */ / { + compatible = "microchip,mpfs-icicle-reference-rtlv2203", "microchip,mpfs"; + core_pwm0: pwm@41000000 { compatible = "microchip,corepwm-rtl-v4"; reg = <0x0 0x41000000 0x0 0xF0>; diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts index 3392153dd0f1..044982a11df5 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts +++ b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts @@ -3,7 +3,8 @@ /dts-v1/; -#include "microchip-mpfs.dtsi" +#include "mpfs.dtsi" +#include "mpfs-icicle-kit-fabric.dtsi" /* Clock frequency (in Hz) of the rtcclk */ #define RTCCLK_FREQ 1000000 @@ -32,41 +33,71 @@ ddrc_cache_lo: memory@80000000 { device_type = "memory"; reg = <0x0 0x80000000 0x0 0x2e000000>; - clocks = <&clkcfg CLK_DDRC>; status = "okay"; }; ddrc_cache_hi: memory@1000000000 { device_type = "memory"; reg = <0x10 0x0 0x0 0x40000000>; - clocks = <&clkcfg CLK_DDRC>; status = "okay"; }; }; -&refclk { - clock-frequency = <125000000>; +&core_pwm0 { + status = "okay"; }; -&mmuart1 { +&gpio2 { + interrupts = <53>, <53>, <53>, <53>, + <53>, <53>, <53>, <53>, + <53>, <53>, <53>, <53>, + <53>, <53>, <53>, <53>, + <53>, <53>, <53>, <53>, + <53>, <53>, <53>, <53>, + <53>, <53>, <53>, <53>, + <53>, <53>, <53>, <53>; status = "okay"; }; -&mmuart2 { +&i2c0 { status = "okay"; }; -&mmuart3 { +&i2c1 { status = "okay"; }; -&mmuart4 { +&i2c2 { status = "okay"; }; -&mmc { +&mac0 { + phy-mode = "sgmii"; + phy-handle = <&phy0>; + status = "okay"; +}; + +&mac1 { + phy-mode = "sgmii"; + phy-handle = <&phy1>; status = "okay"; + phy1: ethernet-phy@9 { + reg = <9>; + ti,fifo-depth = <0x1>; + }; + + phy0: ethernet-phy@8 { + reg = <8>; + ti,fifo-depth = <0x1>; + }; +}; + +&mbox { + status = "okay"; +}; + +&mmc { bus-width = <4>; disable-wp; cap-sd-highspeed; @@ -78,73 +109,46 @@ sd-uhs-sdr25; sd-uhs-sdr50; sd-uhs-sdr104; -}; - -&spi0 { status = "okay"; }; -&spi1 { +&mmuart1 { status = "okay"; }; -&qspi { +&mmuart2 { status = "okay"; }; -&i2c0 { +&mmuart3 { status = "okay"; }; -&i2c1 { +&mmuart4 { status = "okay"; }; -&i2c2 { +&pcie { status = "okay"; }; -&mac0 { - phy-mode = "sgmii"; - phy-handle = <&phy0>; -}; - -&mac1 { +&qspi { status = "okay"; - phy-mode = "sgmii"; - phy-handle = <&phy1>; - phy1: ethernet-phy@9 { - reg = <9>; - ti,fifo-depth = <0x1>; - }; - phy0: ethernet-phy@8 { - reg = <8>; - ti,fifo-depth = <0x1>; - }; }; -&gpio2 { - interrupts = <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>; - status = "okay"; +&refclk { + clock-frequency = <125000000>; }; &rtc { status = "okay"; }; -&usb { +&spi0 { status = "okay"; - dr_mode = "host"; }; -&mbox { +&spi1 { status = "okay"; }; @@ -152,10 +156,7 @@ status = "okay"; }; -&pcie { - status = "okay"; -}; - -&core_pwm0 { +&usb { status = "okay"; + dr_mode = "host"; }; diff --git a/arch/riscv/boot/dts/microchip/mpfs-polarberry-fabric.dtsi b/arch/riscv/boot/dts/microchip/mpfs-polarberry-fabric.dtsi new file mode 100644 index 000000000000..49380c428ec9 --- /dev/null +++ b/arch/riscv/boot/dts/microchip/mpfs-polarberry-fabric.dtsi @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* Copyright (c) 2020-2022 Microchip Technology Inc */ + +/ { + fabric_clk3: fabric-clk3 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <62500000>; + }; + + fabric_clk1: fabric-clk1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + }; +}; diff --git a/arch/riscv/boot/dts/microchip/mpfs-polarberry.dts b/arch/riscv/boot/dts/microchip/mpfs-polarberry.dts new file mode 100644 index 000000000000..82c93c8f5c17 --- /dev/null +++ b/arch/riscv/boot/dts/microchip/mpfs-polarberry.dts @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* Copyright (c) 2020-2022 Microchip Technology Inc */ + +/dts-v1/; + +#include "mpfs.dtsi" +#include "mpfs-polarberry-fabric.dtsi" + +/* Clock frequency (in Hz) of the rtcclk */ +#define MTIMER_FREQ 1000000 + +/ { + model = "Sundance PolarBerry"; + compatible = "sundance,polarberry", "microchip,mpfs"; + + aliases { + ethernet0 = &mac1; + serial0 = &mmuart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + cpus { + timebase-frequency = <MTIMER_FREQ>; + }; + + ddrc_cache_lo: memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x2e000000>; + }; + + ddrc_cache_hi: memory@1000000000 { + device_type = "memory"; + reg = <0x10 0x00000000 0x0 0xC0000000>; + }; +}; + +/* + * phy0 is connected to mac0, but the port itself is on the (optional) carrier + * board. + */ +&mac0 { + phy-mode = "sgmii"; + phy-handle = <&phy0>; + status = "disabled"; +}; + +&mac1 { + phy-mode = "sgmii"; + phy-handle = <&phy1>; + status = "okay"; + + phy1: ethernet-phy@5 { + reg = <5>; + ti,fifo-depth = <0x01>; + }; + + phy0: ethernet-phy@4 { + reg = <4>; + ti,fifo-depth = <0x01>; + }; +}; + +&mbox { + status = "okay"; +}; + +&mmc { + bus-width = <4>; + disable-wp; + cap-sd-highspeed; + cap-mmc-highspeed; + card-detect-delay = <200>; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + status = "okay"; +}; + +&mmuart0 { + status = "okay"; +}; + +&refclk { + clock-frequency = <125000000>; +}; + +&rtc { + status = "okay"; +}; + +&syscontroller { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi b/arch/riscv/boot/dts/microchip/mpfs.dtsi index cf2f55e1dcb6..8c3259134194 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi +++ b/arch/riscv/boot/dts/microchip/mpfs.dtsi @@ -3,7 +3,6 @@ /dts-v1/; #include "dt-bindings/clock/microchip,mpfs-clock.h" -#include "microchip-mpfs-fabric.dtsi" / { #address-cells = <2>; @@ -146,6 +145,11 @@ #clock-cells = <0>; }; + syscontroller: syscontroller { + compatible = "microchip,mpfs-sys-controller"; + mboxes = <&mbox 0>; + }; + soc { #address-cells = <2>; #size-cells = <2>; @@ -446,10 +450,5 @@ #mbox-cells = <1>; status = "disabled"; }; - - syscontroller: syscontroller { - compatible = "microchip,mpfs-sys-controller"; - mboxes = <&mbox 0>; - }; }; }; diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h index e13b1f6bb400..ec2f3f1b836f 100644 --- a/arch/riscv/include/asm/alternative-macros.h +++ b/arch/riscv/include/asm/alternative-macros.h @@ -27,9 +27,9 @@ \new_c .option pop 889 : - .previous .org . - (889b - 888b) + (887b - 886b) .org . - (887b - 886b) + (889b - 888b) + .previous .endif .endm @@ -94,9 +94,9 @@ new_c "\n" \ ".option pop\n" \ "889 :\n" \ - ".previous\n" \ ".org . - (887b - 886b) + (889b - 888b)\n" \ ".org . - (889b - 888b) + (887b - 886b)\n" \ + ".previous\n" \ ".endif\n" #define __ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, enable) \ diff --git a/arch/riscv/include/asm/irq_work.h b/arch/riscv/include/asm/irq_work.h index d6c277992f76..b53891964ae0 100644 --- a/arch/riscv/include/asm/irq_work.h +++ b/arch/riscv/include/asm/irq_work.h @@ -4,7 +4,7 @@ static inline bool arch_irq_work_has_interrupt(void) { - return true; + return IS_ENABLED(CONFIG_SMP); } extern void arch_irq_work_raise(void); #endif /* _ASM_RISCV_IRQ_WORK_H */ diff --git a/arch/riscv/include/asm/unistd.h b/arch/riscv/include/asm/unistd.h index 5ddac412b578..221630bdbd07 100644 --- a/arch/riscv/include/asm/unistd.h +++ b/arch/riscv/include/asm/unistd.h @@ -9,7 +9,6 @@ */ #define __ARCH_WANT_SYS_CLONE -#define __ARCH_WANT_MEMFD_SECRET #ifdef CONFIG_COMPAT #define __ARCH_WANT_COMPAT_TRUNCATE64 diff --git a/arch/riscv/include/uapi/asm/unistd.h b/arch/riscv/include/uapi/asm/unistd.h index c9e50eed14aa..73d7cdd2ec49 100644 --- a/arch/riscv/include/uapi/asm/unistd.h +++ b/arch/riscv/include/uapi/asm/unistd.h @@ -21,6 +21,7 @@ #endif /* __LP64__ */ #define __ARCH_WANT_SYS_CLONE3 +#define __ARCH_WANT_MEMFD_SECRET #include <asm-generic/unistd.h> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index dea3ea19deee..a6f62a6d1edd 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -213,11 +213,10 @@ void __init riscv_fill_hwcap(void) else elf_hwcap = this_hwcap; - if (bitmap_weight(riscv_isa, RISCV_ISA_EXT_MAX)) - bitmap_and(riscv_isa, riscv_isa, this_isa, RISCV_ISA_EXT_MAX); - else + if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX)) bitmap_copy(riscv_isa, this_isa, RISCV_ISA_EXT_MAX); - + else + bitmap_and(riscv_isa, riscv_isa, this_isa, RISCV_ISA_EXT_MAX); } /* We don't support systems with F but without D, so mask those out diff --git a/arch/riscv/kernel/efi.c b/arch/riscv/kernel/efi.c index 024159298231..1aa540350abd 100644 --- a/arch/riscv/kernel/efi.c +++ b/arch/riscv/kernel/efi.c @@ -65,7 +65,7 @@ static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data) if (md->attribute & EFI_MEMORY_RO) { val = pte_val(pte) & ~_PAGE_WRITE; - val = pte_val(pte) | _PAGE_READ; + val |= _PAGE_READ; pte = __pte(val); } if (md->attribute & EFI_MEMORY_XP) { diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 273eb0fa1f50..b865046e4dbb 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S @@ -298,6 +298,7 @@ clear_bss_done: REG_S a0, (a2) /* Initialize page tables and relocate to virtual addresses */ + la tp, init_task la sp, init_thread_union + THREAD_SIZE XIP_FIXUP_OFFSET sp #ifdef CONFIG_BUILTIN_DTB diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 1c7be865ab31..ceb9ebab6558 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -157,13 +157,15 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) return 0; } -int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, - struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct pt_regs *childregs = task_pt_regs(p); /* p->thread holds context to be restored by __switch_to() */ - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { /* Kernel thread */ memset(childregs, 0, sizeof(struct pt_regs)); childregs->gp = gp_in_global; @@ -171,8 +173,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, childregs->status = SR_PP | SR_PIE; p->thread.ra = (unsigned long)ret_from_kernel_thread; - p->thread.s[0] = usp; /* fn */ - p->thread.s[1] = arg; + p->thread.s[0] = (unsigned long)args->fn; + p->thread.s[1] = (unsigned long)args->fn_arg; } else { *childregs = *(current_pt_regs()); if (usp) /* User fork */ diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index e0373a3056e8..f0f36a4a0e9b 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -190,7 +190,7 @@ static void __init init_resources(void) res = &mem_res[res_idx--]; res->name = "Reserved"; - res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + res->flags = IORESOURCE_MEM | IORESOURCE_EXCLUSIVE; res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region)); res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1; @@ -215,7 +215,7 @@ static void __init init_resources(void) if (unlikely(memblock_is_nomap(region))) { res->name = "Reserved"; - res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + res->flags = IORESOURCE_MEM | IORESOURCE_EXCLUSIVE; } else { res->name = "System RAM"; res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index eed613599ba6..d466ec670e1f 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -76,38 +76,74 @@ static void __init zone_sizes_init(void) } #if defined(CONFIG_MMU) && defined(CONFIG_DEBUG_VM) + +#define LOG2_SZ_1K ilog2(SZ_1K) +#define LOG2_SZ_1M ilog2(SZ_1M) +#define LOG2_SZ_1G ilog2(SZ_1G) +#define LOG2_SZ_1T ilog2(SZ_1T) + static inline void print_mlk(char *name, unsigned long b, unsigned long t) { pr_notice("%12s : 0x%08lx - 0x%08lx (%4ld kB)\n", name, b, t, - (((t) - (b)) >> 10)); + (((t) - (b)) >> LOG2_SZ_1K)); } static inline void print_mlm(char *name, unsigned long b, unsigned long t) { pr_notice("%12s : 0x%08lx - 0x%08lx (%4ld MB)\n", name, b, t, - (((t) - (b)) >> 20)); + (((t) - (b)) >> LOG2_SZ_1M)); +} + +static inline void print_mlg(char *name, unsigned long b, unsigned long t) +{ + pr_notice("%12s : 0x%08lx - 0x%08lx (%4ld GB)\n", name, b, t, + (((t) - (b)) >> LOG2_SZ_1G)); +} + +#ifdef CONFIG_64BIT +static inline void print_mlt(char *name, unsigned long b, unsigned long t) +{ + pr_notice("%12s : 0x%08lx - 0x%08lx (%4ld TB)\n", name, b, t, + (((t) - (b)) >> LOG2_SZ_1T)); +} +#else +#define print_mlt(n, b, t) do {} while (0) +#endif + +static inline void print_ml(char *name, unsigned long b, unsigned long t) +{ + unsigned long diff = t - b; + + if (IS_ENABLED(CONFIG_64BIT) && (diff >> LOG2_SZ_1T) >= 10) + print_mlt(name, b, t); + else if ((diff >> LOG2_SZ_1G) >= 10) + print_mlg(name, b, t); + else if ((diff >> LOG2_SZ_1M) >= 10) + print_mlm(name, b, t); + else + print_mlk(name, b, t); } static void __init print_vm_layout(void) { pr_notice("Virtual kernel memory layout:\n"); - print_mlk("fixmap", (unsigned long)FIXADDR_START, - (unsigned long)FIXADDR_TOP); - print_mlm("pci io", (unsigned long)PCI_IO_START, - (unsigned long)PCI_IO_END); - print_mlm("vmemmap", (unsigned long)VMEMMAP_START, - (unsigned long)VMEMMAP_END); - print_mlm("vmalloc", (unsigned long)VMALLOC_START, - (unsigned long)VMALLOC_END); - print_mlm("lowmem", (unsigned long)PAGE_OFFSET, - (unsigned long)high_memory); + print_ml("fixmap", (unsigned long)FIXADDR_START, + (unsigned long)FIXADDR_TOP); + print_ml("pci io", (unsigned long)PCI_IO_START, + (unsigned long)PCI_IO_END); + print_ml("vmemmap", (unsigned long)VMEMMAP_START, + (unsigned long)VMEMMAP_END); + print_ml("vmalloc", (unsigned long)VMALLOC_START, + (unsigned long)VMALLOC_END); + print_ml("lowmem", (unsigned long)PAGE_OFFSET, + (unsigned long)high_memory); if (IS_ENABLED(CONFIG_64BIT)) { #ifdef CONFIG_KASAN - print_mlm("kasan", KASAN_SHADOW_START, KASAN_SHADOW_END); + print_ml("kasan", KASAN_SHADOW_START, KASAN_SHADOW_END); #endif - print_mlm("kernel", (unsigned long)KERNEL_LINK_ADDR, - (unsigned long)ADDRESS_SPACE_END); + print_ml("kernel", (unsigned long)KERNEL_LINK_ADDR, + (unsigned long)ADDRESS_SPACE_END); } } #else @@ -843,7 +879,7 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa) * MMU is not enabled, the page tables are allocated directly using * early_pmd/pud/p4d and the address returned is the physical one. */ -void __init pt_ops_set_early(void) +static void __init pt_ops_set_early(void) { pt_ops.alloc_pte = alloc_pte_early; pt_ops.get_pte_virt = get_pte_virt_early; @@ -865,7 +901,7 @@ void __init pt_ops_set_early(void) * Note that this is called with MMU disabled, hence kernel_mapping_pa_to_va, * but it will be used as described above. */ -void __init pt_ops_set_fixmap(void) +static void __init pt_ops_set_fixmap(void) { pt_ops.alloc_pte = kernel_mapping_pa_to_va((uintptr_t)alloc_pte_fixmap); pt_ops.get_pte_virt = kernel_mapping_pa_to_va((uintptr_t)get_pte_virt_fixmap); @@ -883,7 +919,7 @@ void __init pt_ops_set_fixmap(void) * MMU is enabled and page table setup is complete, so from now, we can use * generic page allocation functions to setup page table. */ -void __init pt_ops_set_late(void) +static void __init pt_ops_set_late(void) { pt_ops.alloc_pte = alloc_pte_late; pt_ops.get_pte_virt = get_pte_virt_late; diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index b17239ae7bd4..b1a88f6cc349 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -732,11 +732,11 @@ config VFIO_AP depends on S390_AP_IOMMU && VFIO_MDEV && KVM depends on ZCRYPT help - This driver grants access to Adjunct Processor (AP) devices - via the VFIO mediated device interface. + This driver grants access to Adjunct Processor (AP) devices + via the VFIO mediated device interface. - To compile this driver as a module, choose M here: the module - will be called vfio_ap. + To compile this driver as a module, choose M here: the module + will be called vfio_ap. endmenu diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug index e94a2a7f6bf4..c4300ea4abf8 100644 --- a/arch/s390/Kconfig.debug +++ b/arch/s390/Kconfig.debug @@ -14,9 +14,9 @@ config DEBUG_ENTRY If unsure, say N. config CIO_INJECT - bool "CIO Inject interfaces" - depends on DEBUG_KERNEL && DEBUG_FS - help - This option provides a debugging facility to inject certain artificial events - and instruction responses to the CIO layer of Linux kernel. The newly created - debugfs user-interfaces will be at /sys/kernel/debug/s390/cio/* + bool "CIO Inject interfaces" + depends on DEBUG_KERNEL && DEBUG_FS + help + This option provides a debugging facility to inject certain artificial events + and instruction responses to the CIO layer of Linux kernel. The newly created + debugfs user-interfaces will be at /sys/kernel/debug/s390/cio/* diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 54c7536f2482..1023e9d43d44 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -701,7 +701,7 @@ static inline void _gcm_sg_unmap_and_advance(struct gcm_sg_walk *gw, unsigned int nbytes) { gw->walk_bytes_remain -= nbytes; - scatterwalk_unmap(&gw->walk); + scatterwalk_unmap(gw->walk_ptr); scatterwalk_advance(&gw->walk, nbytes); scatterwalk_done(&gw->walk, 0, gw->walk_bytes_remain); gw->walk_ptr = NULL; @@ -776,7 +776,7 @@ static int gcm_out_walk_go(struct gcm_sg_walk *gw, unsigned int minbytesneeded) goto out; } - scatterwalk_unmap(&gw->walk); + scatterwalk_unmap(gw->walk_ptr); gw->walk_ptr = NULL; gw->ptr = gw->buf; diff --git a/arch/s390/include/asm/asm-extable.h b/arch/s390/include/asm/asm-extable.h index f24d9591aaed..b74f1070ddb2 100644 --- a/arch/s390/include/asm/asm-extable.h +++ b/arch/s390/include/asm/asm-extable.h @@ -3,12 +3,24 @@ #define __ASM_EXTABLE_H #include <linux/stringify.h> +#include <linux/bits.h> #include <asm/asm-const.h> -#define EX_TYPE_NONE 0 -#define EX_TYPE_FIXUP 1 -#define EX_TYPE_BPF 2 -#define EX_TYPE_UACCESS 3 +#define EX_TYPE_NONE 0 +#define EX_TYPE_FIXUP 1 +#define EX_TYPE_BPF 2 +#define EX_TYPE_UA_STORE 3 +#define EX_TYPE_UA_LOAD_MEM 4 +#define EX_TYPE_UA_LOAD_REG 5 + +#define EX_DATA_REG_ERR_SHIFT 0 +#define EX_DATA_REG_ERR GENMASK(3, 0) + +#define EX_DATA_REG_ADDR_SHIFT 4 +#define EX_DATA_REG_ADDR GENMASK(7, 4) + +#define EX_DATA_LEN_SHIFT 8 +#define EX_DATA_LEN GENMASK(11, 8) #define __EX_TABLE(_section, _fault, _target, _type) \ stringify_in_c(.section _section,"a";) \ @@ -19,35 +31,58 @@ stringify_in_c(.short 0;) \ stringify_in_c(.previous) -#define __EX_TABLE_UA(_section, _fault, _target, _type, _reg) \ - stringify_in_c(.section _section,"a";) \ - stringify_in_c(.align 4;) \ - stringify_in_c(.long (_fault) - .;) \ - stringify_in_c(.long (_target) - .;) \ - stringify_in_c(.short (_type);) \ - stringify_in_c(.macro extable_reg reg;) \ - stringify_in_c(.set .Lfound, 0;) \ - stringify_in_c(.set .Lregnr, 0;) \ - stringify_in_c(.irp rs,r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15;) \ - stringify_in_c(.ifc "\reg", "%%\rs";) \ - stringify_in_c(.set .Lfound, 1;) \ - stringify_in_c(.short .Lregnr;) \ - stringify_in_c(.endif;) \ - stringify_in_c(.set .Lregnr, .Lregnr+1;) \ - stringify_in_c(.endr;) \ - stringify_in_c(.ifne (.Lfound != 1);) \ - stringify_in_c(.error "extable_reg: bad register argument";) \ - stringify_in_c(.endif;) \ - stringify_in_c(.endm;) \ - stringify_in_c(extable_reg _reg;) \ - stringify_in_c(.purgem extable_reg;) \ +#define __EX_TABLE_UA(_section, _fault, _target, _type, _regerr, _regaddr, _len)\ + stringify_in_c(.section _section,"a";) \ + stringify_in_c(.align 4;) \ + stringify_in_c(.long (_fault) - .;) \ + stringify_in_c(.long (_target) - .;) \ + stringify_in_c(.short (_type);) \ + stringify_in_c(.macro extable_reg regerr, regaddr;) \ + stringify_in_c(.set .Lfound, 0;) \ + stringify_in_c(.set .Lcurr, 0;) \ + stringify_in_c(.irp rs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15;) \ + stringify_in_c( .ifc "\regerr", "%%r\rs";) \ + stringify_in_c( .set .Lfound, 1;) \ + stringify_in_c( .set .Lregerr, .Lcurr;) \ + stringify_in_c( .endif;) \ + stringify_in_c( .set .Lcurr, .Lcurr+1;) \ + stringify_in_c(.endr;) \ + stringify_in_c(.ifne (.Lfound != 1);) \ + stringify_in_c( .error "extable_reg: bad register argument1";) \ + stringify_in_c(.endif;) \ + stringify_in_c(.set .Lfound, 0;) \ + stringify_in_c(.set .Lcurr, 0;) \ + stringify_in_c(.irp rs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15;) \ + stringify_in_c( .ifc "\regaddr", "%%r\rs";) \ + stringify_in_c( .set .Lfound, 1;) \ + stringify_in_c( .set .Lregaddr, .Lcurr;) \ + stringify_in_c( .endif;) \ + stringify_in_c( .set .Lcurr, .Lcurr+1;) \ + stringify_in_c(.endr;) \ + stringify_in_c(.ifne (.Lfound != 1);) \ + stringify_in_c( .error "extable_reg: bad register argument2";) \ + stringify_in_c(.endif;) \ + stringify_in_c(.short .Lregerr << EX_DATA_REG_ERR_SHIFT | \ + .Lregaddr << EX_DATA_REG_ADDR_SHIFT | \ + _len << EX_DATA_LEN_SHIFT;) \ + stringify_in_c(.endm;) \ + stringify_in_c(extable_reg _regerr,_regaddr;) \ + stringify_in_c(.purgem extable_reg;) \ stringify_in_c(.previous) #define EX_TABLE(_fault, _target) \ __EX_TABLE(__ex_table, _fault, _target, EX_TYPE_FIXUP) + #define EX_TABLE_AMODE31(_fault, _target) \ __EX_TABLE(.amode31.ex_table, _fault, _target, EX_TYPE_FIXUP) -#define EX_TABLE_UA(_fault, _target, _reg) \ - __EX_TABLE_UA(__ex_table, _fault, _target, EX_TYPE_UACCESS, _reg) + +#define EX_TABLE_UA_STORE(_fault, _target, _regerr) \ + __EX_TABLE_UA(__ex_table, _fault, _target, EX_TYPE_UA_STORE, _regerr, _regerr, 0) + +#define EX_TABLE_UA_LOAD_MEM(_fault, _target, _regerr, _regmem, _len) \ + __EX_TABLE_UA(__ex_table, _fault, _target, EX_TYPE_UA_LOAD_MEM, _regerr, _regmem, _len) + +#define EX_TABLE_UA_LOAD_REG(_fault, _target, _regerr, _regzero) \ + __EX_TABLE_UA(__ex_table, _fault, _target, EX_TYPE_UA_LOAD_REG, _regerr, _regzero, 0) #endif /* __ASM_EXTABLE_H */ diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h index 63098df81c9f..649ecdcc8734 100644 --- a/arch/s390/include/asm/kexec.h +++ b/arch/s390/include/asm/kexec.h @@ -31,7 +31,7 @@ #define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31) /* Allocate control page with GFP_DMA */ -#define KEXEC_CONTROL_MEMORY_GFP GFP_DMA +#define KEXEC_CONTROL_MEMORY_GFP (GFP_DMA | __GFP_NORETRY) /* Maximum address we can use for the crash control pages */ #define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL) diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index add764a2be8c..bd66f8e34949 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -304,12 +304,6 @@ static __always_inline void __noreturn disabled_wait(void) while (1); } -/* - * Basic Program Check Handler. - */ -extern void s390_base_pgm_handler(void); -extern void (*s390_base_pgm_handler_fn)(struct pt_regs *regs); - #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL extern int memcpy_real(void *, unsigned long, size_t); diff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h index f8500191993d..b23c658dce77 100644 --- a/arch/s390/include/asm/stacktrace.h +++ b/arch/s390/include/asm/stacktrace.h @@ -39,8 +39,15 @@ static inline bool on_stack(struct stack_info *info, * Kernel uses the packed stack layout (-mpacked-stack). */ struct stack_frame { - unsigned long empty1[5]; - unsigned int empty2[8]; + union { + unsigned long empty[9]; + struct { + unsigned long sie_control_block; + unsigned long sie_savearea; + unsigned long sie_reason; + unsigned long sie_flags; + }; + }; unsigned long gprs[10]; unsigned long back_chain; }; diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index 1f150a7cfb3d..f4511e21d646 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -3,7 +3,7 @@ * S390 version * Copyright IBM Corp. 1999, 2000 * Author(s): Hartmut Penner (hp@de.ibm.com), - * Martin Schwidefsky (schwidefsky@de.ibm.com) + * Martin Schwidefsky (schwidefsky@de.ibm.com) * * Derived from "include/asm-i386/uaccess.h" */ @@ -55,9 +55,6 @@ copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned lo return n; } -int __put_user_bad(void) __attribute__((noreturn)); -int __get_user_bad(void) __attribute__((noreturn)); - union oac { unsigned int val; struct { @@ -80,8 +77,14 @@ union oac { }; }; -#define __put_get_user_asm(to, from, size, oac_spec) \ +int __noreturn __put_user_bad(void); + +#define __put_user_asm(to, from, size) \ ({ \ + union oac __oac_spec = { \ + .oac1.as = PSW_BITS_AS_SECONDARY, \ + .oac1.a = 1, \ + }; \ int __rc; \ \ asm volatile( \ @@ -89,26 +92,15 @@ union oac { "0: mvcos %[_to],%[_from],%[_size]\n" \ "1: xr %[rc],%[rc]\n" \ "2:\n" \ - EX_TABLE_UA(0b,2b,%[rc]) EX_TABLE_UA(1b,2b,%[rc]) \ + EX_TABLE_UA_STORE(0b, 2b, %[rc]) \ + EX_TABLE_UA_STORE(1b, 2b, %[rc]) \ : [rc] "=&d" (__rc), [_to] "+Q" (*(to)) \ : [_size] "d" (size), [_from] "Q" (*(from)), \ - [spec] "d" (oac_spec.val) \ + [spec] "d" (__oac_spec.val) \ : "cc", "0"); \ __rc; \ }) -#define __put_user_asm(to, from, size) \ - __put_get_user_asm(to, from, size, ((union oac) { \ - .oac1.as = PSW_BITS_AS_SECONDARY, \ - .oac1.a = 1 \ - })) - -#define __get_user_asm(to, from, size) \ - __put_get_user_asm(to, from, size, ((union oac) { \ - .oac2.as = PSW_BITS_AS_SECONDARY, \ - .oac2.a = 1 \ - })) \ - static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned long size) { int rc; @@ -141,6 +133,31 @@ static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned lon return rc; } +int __noreturn __get_user_bad(void); + +#define __get_user_asm(to, from, size) \ +({ \ + union oac __oac_spec = { \ + .oac2.as = PSW_BITS_AS_SECONDARY, \ + .oac2.a = 1, \ + }; \ + int __rc; \ + \ + asm volatile( \ + " lr 0,%[spec]\n" \ + "0: mvcos 0(%[_to]),%[_from],%[_size]\n" \ + "1: xr %[rc],%[rc]\n" \ + "2:\n" \ + EX_TABLE_UA_LOAD_MEM(0b, 2b, %[rc], %[_to], %[_ksize]) \ + EX_TABLE_UA_LOAD_MEM(1b, 2b, %[rc], %[_to], %[_ksize]) \ + : [rc] "=&d" (__rc), "=Q" (*(to)) \ + : [_size] "d" (size), [_from] "Q" (*(from)), \ + [spec] "d" (__oac_spec.val), [_to] "a" (to), \ + [_ksize] "K" (size) \ + : "cc", "0"); \ + __rc; \ +}) + static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size) { int rc; @@ -177,77 +194,77 @@ static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsign * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type. */ -#define __put_user(x, ptr) \ -({ \ - __typeof__(*(ptr)) __x = (x); \ - int __pu_err = -EFAULT; \ - __chk_user_ptr(ptr); \ - switch (sizeof (*(ptr))) { \ - case 1: \ - case 2: \ - case 4: \ - case 8: \ - __pu_err = __put_user_fn(&__x, ptr, \ - sizeof(*(ptr))); \ - break; \ - default: \ - __put_user_bad(); \ - break; \ - } \ - __builtin_expect(__pu_err, 0); \ +#define __put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) __x = (x); \ + int __pu_err = -EFAULT; \ + \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + case 2: \ + case 4: \ + case 8: \ + __pu_err = __put_user_fn(&__x, ptr, sizeof(*(ptr))); \ + break; \ + default: \ + __put_user_bad(); \ + break; \ + } \ + __builtin_expect(__pu_err, 0); \ }) -#define put_user(x, ptr) \ -({ \ - might_fault(); \ - __put_user(x, ptr); \ +#define put_user(x, ptr) \ +({ \ + might_fault(); \ + __put_user(x, ptr); \ }) - -#define __get_user(x, ptr) \ -({ \ - int __gu_err = -EFAULT; \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: { \ - unsigned char __x = 0; \ - __gu_err = __get_user_fn(&__x, ptr, \ - sizeof(*(ptr))); \ - (x) = *(__force __typeof__(*(ptr)) *) &__x; \ - break; \ - }; \ - case 2: { \ - unsigned short __x = 0; \ - __gu_err = __get_user_fn(&__x, ptr, \ - sizeof(*(ptr))); \ - (x) = *(__force __typeof__(*(ptr)) *) &__x; \ - break; \ - }; \ - case 4: { \ - unsigned int __x = 0; \ - __gu_err = __get_user_fn(&__x, ptr, \ - sizeof(*(ptr))); \ - (x) = *(__force __typeof__(*(ptr)) *) &__x; \ - break; \ - }; \ - case 8: { \ - unsigned long long __x = 0; \ - __gu_err = __get_user_fn(&__x, ptr, \ - sizeof(*(ptr))); \ - (x) = *(__force __typeof__(*(ptr)) *) &__x; \ - break; \ - }; \ - default: \ - __get_user_bad(); \ - break; \ - } \ - __builtin_expect(__gu_err, 0); \ +#define __get_user(x, ptr) \ +({ \ + int __gu_err = -EFAULT; \ + \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: { \ + unsigned char __x; \ + \ + __gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr))); \ + (x) = *(__force __typeof__(*(ptr)) *)&__x; \ + break; \ + }; \ + case 2: { \ + unsigned short __x; \ + \ + __gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr))); \ + (x) = *(__force __typeof__(*(ptr)) *)&__x; \ + break; \ + }; \ + case 4: { \ + unsigned int __x; \ + \ + __gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr))); \ + (x) = *(__force __typeof__(*(ptr)) *)&__x; \ + break; \ + }; \ + case 8: { \ + unsigned long __x; \ + \ + __gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr))); \ + (x) = *(__force __typeof__(*(ptr)) *)&__x; \ + break; \ + }; \ + default: \ + __get_user_bad(); \ + break; \ + } \ + __builtin_expect(__gu_err, 0); \ }) -#define get_user(x, ptr) \ -({ \ - might_fault(); \ - __get_user(x, ptr); \ +#define get_user(x, ptr) \ +({ \ + might_fault(); \ + __get_user(x, ptr); \ }) /* @@ -278,19 +295,20 @@ int __noreturn __put_kernel_bad(void); int __rc; \ \ asm volatile( \ - "0: " insn " %2,%1\n" \ - "1: xr %0,%0\n" \ + "0: " insn " %[_val],%[_to]\n" \ + "1: xr %[rc],%[rc]\n" \ "2:\n" \ - EX_TABLE_UA(0b,2b,%0) EX_TABLE_UA(1b,2b,%0) \ - : "=d" (__rc), "+Q" (*(to)) \ - : "d" (val) \ + EX_TABLE_UA_STORE(0b, 2b, %[rc]) \ + EX_TABLE_UA_STORE(1b, 2b, %[rc]) \ + : [rc] "=d" (__rc), [_to] "+Q" (*(to)) \ + : [_val] "d" (val) \ : "cc"); \ __rc; \ }) #define __put_kernel_nofault(dst, src, type, err_label) \ do { \ - u64 __x = (u64)(*((type *)(src))); \ + unsigned long __x = (unsigned long)(*((type *)(src))); \ int __pk_err; \ \ switch (sizeof(type)) { \ @@ -321,12 +339,13 @@ int __noreturn __get_kernel_bad(void); int __rc; \ \ asm volatile( \ - "0: " insn " %1,%2\n" \ - "1: xr %0,%0\n" \ + "0: " insn " %[_val],%[_from]\n" \ + "1: xr %[rc],%[rc]\n" \ "2:\n" \ - EX_TABLE_UA(0b,2b,%0) EX_TABLE_UA(1b,2b,%0) \ - : "=d" (__rc), "+d" (val) \ - : "Q" (*(from)) \ + EX_TABLE_UA_LOAD_REG(0b, 2b, %[rc], %[_val]) \ + EX_TABLE_UA_LOAD_REG(1b, 2b, %[rc], %[_val]) \ + : [rc] "=d" (__rc), [_val] "=d" (val) \ + : [_from] "Q" (*(from)) \ : "cc"); \ __rc; \ }) @@ -337,28 +356,28 @@ do { \ \ switch (sizeof(type)) { \ case 1: { \ - u8 __x = 0; \ + unsigned char __x; \ \ __gk_err = __get_kernel_asm(__x, (type *)(src), "ic"); \ *((type *)(dst)) = (type)__x; \ break; \ }; \ case 2: { \ - u16 __x = 0; \ + unsigned short __x; \ \ __gk_err = __get_kernel_asm(__x, (type *)(src), "lh"); \ *((type *)(dst)) = (type)__x; \ break; \ }; \ case 4: { \ - u32 __x = 0; \ + unsigned int __x; \ \ __gk_err = __get_kernel_asm(__x, (type *)(src), "l"); \ *((type *)(dst)) = (type)__x; \ break; \ }; \ case 8: { \ - u64 __x = 0; \ + unsigned long __x; \ \ __gk_err = __get_kernel_asm(__x, (type *)(src), "lg"); \ *((type *)(dst)) = (type)__x; \ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 5851041bb214..27d6b3c7aa06 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -33,7 +33,7 @@ CFLAGS_stacktrace.o += -fno-optimize-sibling-calls CFLAGS_dumpstack.o += -fno-optimize-sibling-calls CFLAGS_unwind_bc.o += -fno-optimize-sibling-calls -obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o +obj-y := traps.o time.o process.o earlypgm.o early.o setup.o idle.o vtime.o obj-y += processor.o syscall.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o obj-y += sysinfo.o lgr.o os_info.o machine_kexec.o diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 7c74f0e17e5a..d8ce965c0a97 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -32,6 +32,22 @@ int main(void) /* pt_regs offsets */ OFFSET(__PT_PSW, pt_regs, psw); OFFSET(__PT_GPRS, pt_regs, gprs); + OFFSET(__PT_R0, pt_regs, gprs[0]); + OFFSET(__PT_R1, pt_regs, gprs[1]); + OFFSET(__PT_R2, pt_regs, gprs[2]); + OFFSET(__PT_R3, pt_regs, gprs[3]); + OFFSET(__PT_R4, pt_regs, gprs[4]); + OFFSET(__PT_R5, pt_regs, gprs[5]); + OFFSET(__PT_R6, pt_regs, gprs[6]); + OFFSET(__PT_R7, pt_regs, gprs[7]); + OFFSET(__PT_R8, pt_regs, gprs[8]); + OFFSET(__PT_R9, pt_regs, gprs[9]); + OFFSET(__PT_R10, pt_regs, gprs[10]); + OFFSET(__PT_R11, pt_regs, gprs[11]); + OFFSET(__PT_R12, pt_regs, gprs[12]); + OFFSET(__PT_R13, pt_regs, gprs[13]); + OFFSET(__PT_R14, pt_regs, gprs[14]); + OFFSET(__PT_R15, pt_regs, gprs[15]); OFFSET(__PT_ORIG_GPR2, pt_regs, orig_gpr2); OFFSET(__PT_FLAGS, pt_regs, flags); OFFSET(__PT_CR1, pt_regs, cr1); @@ -41,11 +57,11 @@ int main(void) /* stack_frame offsets */ OFFSET(__SF_BACKCHAIN, stack_frame, back_chain); OFFSET(__SF_GPRS, stack_frame, gprs); - OFFSET(__SF_EMPTY, stack_frame, empty1[0]); - OFFSET(__SF_SIE_CONTROL, stack_frame, empty1[1]); - OFFSET(__SF_SIE_SAVEAREA, stack_frame, empty1[2]); - OFFSET(__SF_SIE_REASON, stack_frame, empty1[3]); - OFFSET(__SF_SIE_FLAGS, stack_frame, empty1[4]); + OFFSET(__SF_EMPTY, stack_frame, empty[0]); + OFFSET(__SF_SIE_CONTROL, stack_frame, sie_control_block); + OFFSET(__SF_SIE_SAVEAREA, stack_frame, sie_savearea); + OFFSET(__SF_SIE_REASON, stack_frame, sie_reason); + OFFSET(__SF_SIE_FLAGS, stack_frame, sie_flags); DEFINE(STACK_FRAME_OVERHEAD, sizeof(struct stack_frame)); BLANK(); /* idle data offsets */ diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 08cc86a0db90..432c8c987256 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -149,7 +149,7 @@ static __init void setup_topology(void) topology_max_mnest = max_mnest; } -static void early_pgm_check_handler(struct pt_regs *regs) +void __do_early_pgm_check(struct pt_regs *regs) { if (!fixup_exception(regs)) disabled_wait(); @@ -159,12 +159,11 @@ static noinline __init void setup_lowcore_early(void) { psw_t psw; - psw.addr = (unsigned long)s390_base_pgm_handler; + psw.addr = (unsigned long)early_pgm_check_handler; psw.mask = PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA; if (IS_ENABLED(CONFIG_KASAN)) psw.mask |= PSW_MASK_DAT; S390_lowcore.program_new_psw = psw; - s390_base_pgm_handler_fn = early_pgm_check_handler; S390_lowcore.preempt_count = INIT_PREEMPT_COUNT; } diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/earlypgm.S index 172c23c8ca00..f521c6da37b8 100644 --- a/arch/s390/kernel/base.S +++ b/arch/s390/kernel/earlypgm.S @@ -1,23 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * arch/s390/kernel/base.S - * * Copyright IBM Corp. 2006, 2007 * Author(s): Michael Holzheu <holzheu@de.ibm.com> */ #include <linux/linkage.h> #include <asm/asm-offsets.h> -#include <asm/nospec-insn.h> -#include <asm/ptrace.h> - GEN_BR_THUNK %r9 - GEN_BR_THUNK %r14 - -__PT_R0 = __PT_GPRS -__PT_R8 = __PT_GPRS + 64 - -ENTRY(s390_base_pgm_handler) +ENTRY(early_pgm_check_handler) stmg %r8,%r15,__LC_SAVE_AREA_SYNC aghi %r15,-(STACK_FRAME_OVERHEAD+__PT_SIZE) la %r11,STACK_FRAME_OVERHEAD(%r15) @@ -26,25 +16,8 @@ ENTRY(s390_base_pgm_handler) mvc __PT_PSW(16,%r11),__LC_PGM_OLD_PSW mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC lgr %r2,%r11 - larl %r1,s390_base_pgm_handler_fn - lg %r9,0(%r1) - ltgr %r9,%r9 - jz 1f - BASR_EX %r14,%r9 + brasl %r14,__do_early_pgm_check mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) lpswe __LC_RETURN_PSW -1: larl %r13,disabled_wait_psw - lpswe 0(%r13) -ENDPROC(s390_base_pgm_handler) - - .align 8 -disabled_wait_psw: - .quad 0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler - - .section .bss - .align 8 - .globl s390_base_pgm_handler_fn -s390_base_pgm_handler_fn: - .quad 0 - .previous +ENDPROC(early_pgm_check_handler) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index df41132ccd06..d2a1f2f4f5b8 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -29,23 +29,6 @@ #include <asm/export.h> #include <asm/nospec-insn.h> -__PT_R0 = __PT_GPRS -__PT_R1 = __PT_GPRS + 8 -__PT_R2 = __PT_GPRS + 16 -__PT_R3 = __PT_GPRS + 24 -__PT_R4 = __PT_GPRS + 32 -__PT_R5 = __PT_GPRS + 40 -__PT_R6 = __PT_GPRS + 48 -__PT_R7 = __PT_GPRS + 56 -__PT_R8 = __PT_GPRS + 64 -__PT_R9 = __PT_GPRS + 72 -__PT_R10 = __PT_GPRS + 80 -__PT_R11 = __PT_GPRS + 88 -__PT_R12 = __PT_GPRS + 96 -__PT_R13 = __PT_GPRS + 104 -__PT_R14 = __PT_GPRS + 112 -__PT_R15 = __PT_GPRS + 120 - STACK_SHIFT = PAGE_SHIFT + THREAD_SIZE_ORDER STACK_SIZE = 1 << STACK_SHIFT STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE @@ -268,6 +251,10 @@ ENTRY(sie64a) BPEXIT __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) .Lsie_entry: sie 0(%r14) +# Let the next instruction be NOP to avoid triggering a machine check +# and handling it in a guest as result of the instruction execution. + nopr 7 +.Lsie_leave: BPOFF BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) .Lsie_skip: @@ -564,7 +551,7 @@ ENTRY(mcck_int_handler) jno .Lmcck_panic #if IS_ENABLED(CONFIG_KVM) OUTSIDE %r9,.Lsie_gmap,.Lsie_done,6f - OUTSIDE %r9,.Lsie_entry,.Lsie_skip,4f + OUTSIDE %r9,.Lsie_entry,.Lsie_leave,4f oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST j 5f 4: CHKSTG .Lmcck_panic diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 56e5e3712fbb..995ec7449feb 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -17,10 +17,12 @@ void ext_int_handler(void); void io_int_handler(void); void mcck_int_handler(void); void restart_int_handler(void); +void early_pgm_check_handler(void); void __ret_from_fork(struct task_struct *prev, struct pt_regs *regs); void __do_pgm_check(struct pt_regs *regs); void __do_syscall(struct pt_regs *regs, int per_trap); +void __do_early_pgm_check(struct pt_regs *regs); void do_protection_exception(struct pt_regs *regs); void do_dat_exception(struct pt_regs *regs); diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c index ea7729bebaa0..c27321cb0969 100644 --- a/arch/s390/kernel/perf_event.c +++ b/arch/s390/kernel/perf_event.c @@ -30,7 +30,7 @@ static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs) if (!stack) return NULL; - return (struct kvm_s390_sie_block *) stack->empty1[0]; + return (struct kvm_s390_sie_block *)stack->sie_control_block; } static bool is_in_guest(struct pt_regs *regs) diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 71d86f73b02c..89949b9f3cf8 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -94,9 +94,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) return 0; } -int copy_thread(unsigned long clone_flags, unsigned long new_stackp, - unsigned long arg, struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long new_stackp = args->stack; + unsigned long tls = args->tls; struct fake_frame { struct stack_frame sf; @@ -130,15 +132,15 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, frame->sf.gprs[9] = (unsigned long)frame; /* Store access registers to kernel stack of new process. */ - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { /* kernel thread */ memset(&frame->childregs, 0, sizeof(struct pt_regs)); frame->childregs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK; frame->childregs.psw.addr = (unsigned long)__ret_from_fork; - frame->childregs.gprs[9] = new_stackp; /* function */ - frame->childregs.gprs[10] = arg; + frame->childregs.gprs[9] = (unsigned long)args->fn; + frame->childregs.gprs[10] = (unsigned long)args->fn_arg; frame->childregs.orig_gpr2 = -1; frame->childregs.last_break = 1; return 0; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 76ad6408cb2c..8fcb56141689 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1332,8 +1332,7 @@ static int kvm_s390_set_processor_feat(struct kvm *kvm, mutex_unlock(&kvm->lock); return -EBUSY; } - bitmap_copy(kvm->arch.cpu_feat, (unsigned long *) data.feat, - KVM_S390_VM_CPU_FEAT_NR_BITS); + bitmap_from_arr64(kvm->arch.cpu_feat, data.feat, KVM_S390_VM_CPU_FEAT_NR_BITS); mutex_unlock(&kvm->lock); VM_EVENT(kvm, 3, "SET: guest feat: 0x%16.16llx.0x%16.16llx.0x%16.16llx", data.feat[0], @@ -1504,8 +1503,7 @@ static int kvm_s390_get_processor_feat(struct kvm *kvm, { struct kvm_s390_vm_cpu_feat data; - bitmap_copy((unsigned long *) data.feat, kvm->arch.cpu_feat, - KVM_S390_VM_CPU_FEAT_NR_BITS); + bitmap_to_arr64(data.feat, kvm->arch.cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS); if (copy_to_user((void __user *)attr->addr, &data, sizeof(data))) return -EFAULT; VM_EVENT(kvm, 3, "GET: guest feat: 0x%16.16llx.0x%16.16llx.0x%16.16llx", @@ -1520,9 +1518,7 @@ static int kvm_s390_get_machine_feat(struct kvm *kvm, { struct kvm_s390_vm_cpu_feat data; - bitmap_copy((unsigned long *) data.feat, - kvm_s390_available_cpu_feat, - KVM_S390_VM_CPU_FEAT_NR_BITS); + bitmap_to_arr64(data.feat, kvm_s390_available_cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS); if (copy_to_user((void __user *)attr->addr, &data, sizeof(data))) return -EFAULT; VM_EVENT(kvm, 3, "GET: host feat: 0x%16.16llx.0x%16.16llx.0x%16.16llx", diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c index 8ac8ad2474a0..1e4d2187541a 100644 --- a/arch/s390/mm/extable.c +++ b/arch/s390/mm/extable.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 +#include <linux/bitfield.h> #include <linux/extable.h> +#include <linux/string.h> #include <linux/errno.h> #include <linux/panic.h> #include <asm/asm-extable.h> @@ -24,9 +26,34 @@ static bool ex_handler_fixup(const struct exception_table_entry *ex, struct pt_r return true; } -static bool ex_handler_uaccess(const struct exception_table_entry *ex, struct pt_regs *regs) +static bool ex_handler_ua_store(const struct exception_table_entry *ex, struct pt_regs *regs) { - regs->gprs[ex->data] = -EFAULT; + unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data); + + regs->gprs[reg_err] = -EFAULT; + regs->psw.addr = extable_fixup(ex); + return true; +} + +static bool ex_handler_ua_load_mem(const struct exception_table_entry *ex, struct pt_regs *regs) +{ + unsigned int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data); + unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data); + size_t len = FIELD_GET(EX_DATA_LEN, ex->data); + + regs->gprs[reg_err] = -EFAULT; + memset((void *)regs->gprs[reg_addr], 0, len); + regs->psw.addr = extable_fixup(ex); + return true; +} + +static bool ex_handler_ua_load_reg(const struct exception_table_entry *ex, struct pt_regs *regs) +{ + unsigned int reg_zero = FIELD_GET(EX_DATA_REG_ADDR, ex->data); + unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data); + + regs->gprs[reg_err] = -EFAULT; + regs->gprs[reg_zero] = 0; regs->psw.addr = extable_fixup(ex); return true; } @@ -43,8 +70,12 @@ bool fixup_exception(struct pt_regs *regs) return ex_handler_fixup(ex, regs); case EX_TYPE_BPF: return ex_handler_bpf(ex, regs); - case EX_TYPE_UACCESS: - return ex_handler_uaccess(ex, regs); + case EX_TYPE_UA_STORE: + return ex_handler_ua_store(ex, regs); + case EX_TYPE_UA_LOAD_MEM: + return ex_handler_ua_load_mem(ex, regs); + case EX_TYPE_UA_LOAD_REG: + return ex_handler_ua_load_reg(ex, regs); } panic("invalid exception table entry"); } diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index 1ac73917a8d3..b8ae4a4aa2ba 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -2608,6 +2608,18 @@ static int __s390_enable_skey_pte(pte_t *pte, unsigned long addr, return 0; } +/* + * Give a chance to schedule after setting a key to 256 pages. + * We only hold the mm lock, which is a rwsem and the kvm srcu. + * Both can sleep. + */ +static int __s390_enable_skey_pmd(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + cond_resched(); + return 0; +} + static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr, unsigned long hmask, unsigned long next, struct mm_walk *walk) @@ -2630,12 +2642,14 @@ static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr, end = start + HPAGE_SIZE - 1; __storage_key_init_range(start, end); set_bit(PG_arch_1, &page->flags); + cond_resched(); return 0; } static const struct mm_walk_ops enable_skey_walk_ops = { .hugetlb_entry = __s390_enable_skey_hugetlb, .pte_entry = __s390_enable_skey_pte, + .pmd_entry = __s390_enable_skey_pmd, }; int s390_enable_skey(void) diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 697df02362af..4909dcd762e8 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -748,7 +748,7 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep) pgste_val(pgste) |= PGSTE_GR_BIT | PGSTE_GC_BIT; ptev = pte_val(*ptep); if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE)) - page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 1); + page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 0); pgste_set_unlock(ptep, pgste); preempt_enable(); } diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index ca01286a0610..a808843375e7 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -92,9 +92,11 @@ void release_thread(struct task_struct *dead_task) asmlinkage void ret_from_fork(void); asmlinkage void ret_from_kernel_thread(void); -int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, - struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct thread_info *ti = task_thread_info(p); struct pt_regs *childregs; @@ -114,11 +116,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, childregs = task_pt_regs(p); p->thread.sp = (unsigned long) childregs; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { memset(childregs, 0, sizeof(struct pt_regs)); p->thread.pc = (unsigned long) ret_from_kernel_thread; - childregs->regs[4] = arg; - childregs->regs[5] = usp; + childregs->regs[4] = (unsigned long) args->fn_arg; + childregs->regs[5] = (unsigned long) args->fn; childregs->sr = SR_MD; #if defined(CONFIG_SH_FPU) childregs->sr |= SR_FD; diff --git a/arch/sparc/include/uapi/asm/stat.h b/arch/sparc/include/uapi/asm/stat.h index e03d6f8ec301..47f54133a141 100644 --- a/arch/sparc/include/uapi/asm/stat.h +++ b/arch/sparc/include/uapi/asm/stat.h @@ -11,8 +11,8 @@ struct stat { __kernel_ino_t st_ino; __kernel_mode_t st_mode; short st_nlink; - __kernel_uid_t st_uid; - __kernel_gid_t st_gid; + __kernel_uid32_t st_uid; + __kernel_gid32_t st_gid; unsigned int st_rdev; long st_size; long st_atime; diff --git a/arch/sparc/include/uapi/asm/termbits.h b/arch/sparc/include/uapi/asm/termbits.h index ce5ad5d0f105..4321322701fc 100644 --- a/arch/sparc/include/uapi/asm/termbits.h +++ b/arch/sparc/include/uapi/asm/termbits.h @@ -2,15 +2,12 @@ #ifndef _UAPI_SPARC_TERMBITS_H #define _UAPI_SPARC_TERMBITS_H -#include <linux/posix_types.h> - -typedef unsigned char cc_t; -typedef unsigned int speed_t; +#include <asm-generic/termbits-common.h> #if defined(__sparc__) && defined(__arch64__) -typedef unsigned int tcflag_t; +typedef unsigned int tcflag_t; #else -typedef unsigned long tcflag_t; +typedef unsigned long tcflag_t; #endif #define NCC 8 @@ -61,21 +58,19 @@ struct ktermios { }; /* c_cc characters */ -#define VINTR 0 -#define VQUIT 1 -#define VERASE 2 -#define VKILL 3 -#define VEOF 4 -#define VEOL 5 -#define VEOL2 6 -#define VSWTC 7 -#define VSTART 8 -#define VSTOP 9 - - +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VEOL 5 +#define VEOL2 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 #define VSUSP 10 -#define VDSUSP 11 /* SunOS POSIX nicety I do believe... */ +#define VDSUSP 11 /* SunOS POSIX nicety I do believe... */ #define VREPRINT 12 #define VDISCARD 13 #define VWERASE 14 @@ -90,121 +85,83 @@ struct ktermios { #endif /* c_iflag bits */ -#define IGNBRK 0x00000001 -#define BRKINT 0x00000002 -#define IGNPAR 0x00000004 -#define PARMRK 0x00000008 -#define INPCK 0x00000010 -#define ISTRIP 0x00000020 -#define INLCR 0x00000040 -#define IGNCR 0x00000080 -#define ICRNL 0x00000100 -#define IUCLC 0x00000200 -#define IXON 0x00000400 -#define IXANY 0x00000800 -#define IXOFF 0x00001000 -#define IMAXBEL 0x00002000 -#define IUTF8 0x00004000 +#define IUCLC 0x0200 +#define IXON 0x0400 +#define IXOFF 0x1000 +#define IMAXBEL 0x2000 +#define IUTF8 0x4000 /* c_oflag bits */ -#define OPOST 0x00000001 -#define OLCUC 0x00000002 -#define ONLCR 0x00000004 -#define OCRNL 0x00000008 -#define ONOCR 0x00000010 -#define ONLRET 0x00000020 -#define OFILL 0x00000040 -#define OFDEL 0x00000080 -#define NLDLY 0x00000100 -#define NL0 0x00000000 -#define NL1 0x00000100 -#define CRDLY 0x00000600 -#define CR0 0x00000000 -#define CR1 0x00000200 -#define CR2 0x00000400 -#define CR3 0x00000600 -#define TABDLY 0x00001800 -#define TAB0 0x00000000 -#define TAB1 0x00000800 -#define TAB2 0x00001000 -#define TAB3 0x00001800 -#define XTABS 0x00001800 -#define BSDLY 0x00002000 -#define BS0 0x00000000 -#define BS1 0x00002000 -#define VTDLY 0x00004000 -#define VT0 0x00000000 -#define VT1 0x00004000 -#define FFDLY 0x00008000 -#define FF0 0x00000000 -#define FF1 0x00008000 -#define PAGEOUT 0x00010000 /* SUNOS specific */ -#define WRAP 0x00020000 /* SUNOS specific */ +#define OLCUC 0x00002 +#define ONLCR 0x00004 +#define NLDLY 0x00100 +#define NL0 0x00000 +#define NL1 0x00100 +#define CRDLY 0x00600 +#define CR0 0x00000 +#define CR1 0x00200 +#define CR2 0x00400 +#define CR3 0x00600 +#define TABDLY 0x01800 +#define TAB0 0x00000 +#define TAB1 0x00800 +#define TAB2 0x01000 +#define TAB3 0x01800 +#define XTABS 0x01800 +#define BSDLY 0x02000 +#define BS0 0x00000 +#define BS1 0x02000 +#define VTDLY 0x04000 +#define VT0 0x00000 +#define VT1 0x04000 +#define FFDLY 0x08000 +#define FF0 0x00000 +#define FF1 0x08000 +#define PAGEOUT 0x10000 /* SUNOS specific */ +#define WRAP 0x20000 /* SUNOS specific */ /* c_cflag bit meaning */ -#define CBAUD 0x0000100f -#define B0 0x00000000 /* hang up */ -#define B50 0x00000001 -#define B75 0x00000002 -#define B110 0x00000003 -#define B134 0x00000004 -#define B150 0x00000005 -#define B200 0x00000006 -#define B300 0x00000007 -#define B600 0x00000008 -#define B1200 0x00000009 -#define B1800 0x0000000a -#define B2400 0x0000000b -#define B4800 0x0000000c -#define B9600 0x0000000d -#define B19200 0x0000000e -#define B38400 0x0000000f -#define EXTA B19200 -#define EXTB B38400 -#define CSIZE 0x00000030 -#define CS5 0x00000000 -#define CS6 0x00000010 -#define CS7 0x00000020 -#define CS8 0x00000030 -#define CSTOPB 0x00000040 -#define CREAD 0x00000080 -#define PARENB 0x00000100 -#define PARODD 0x00000200 -#define HUPCL 0x00000400 -#define CLOCAL 0x00000800 -#define CBAUDEX 0x00001000 +#define CBAUD 0x0000100f +#define CSIZE 0x00000030 +#define CS5 0x00000000 +#define CS6 0x00000010 +#define CS7 0x00000020 +#define CS8 0x00000030 +#define CSTOPB 0x00000040 +#define CREAD 0x00000080 +#define PARENB 0x00000100 +#define PARODD 0x00000200 +#define HUPCL 0x00000400 +#define CLOCAL 0x00000800 +#define CBAUDEX 0x00001000 /* We'll never see these speeds with the Zilogs, but for completeness... */ -#define BOTHER 0x00001000 -#define B57600 0x00001001 -#define B115200 0x00001002 -#define B230400 0x00001003 -#define B460800 0x00001004 +#define BOTHER 0x00001000 +#define B57600 0x00001001 +#define B115200 0x00001002 +#define B230400 0x00001003 +#define B460800 0x00001004 /* This is what we can do with the Zilogs. */ -#define B76800 0x00001005 +#define B76800 0x00001005 /* This is what we can do with the SAB82532. */ -#define B153600 0x00001006 -#define B307200 0x00001007 -#define B614400 0x00001008 -#define B921600 0x00001009 +#define B153600 0x00001006 +#define B307200 0x00001007 +#define B614400 0x00001008 +#define B921600 0x00001009 /* And these are the rest... */ -#define B500000 0x0000100a -#define B576000 0x0000100b -#define B1000000 0x0000100c -#define B1152000 0x0000100d -#define B1500000 0x0000100e -#define B2000000 0x0000100f +#define B500000 0x0000100a +#define B576000 0x0000100b +#define B1000000 0x0000100c +#define B1152000 0x0000100d +#define B1500000 0x0000100e +#define B2000000 0x0000100f /* These have totally bogus values and nobody uses them so far. Later on we'd have to use say 0x10000x and adjust CBAUD constant and drivers accordingly. -#define B2500000 0x00001010 -#define B3000000 0x00001011 -#define B3500000 0x00001012 -#define B4000000 0x00001013 */ -#define CIBAUD 0x100f0000 /* input baud rate (not used) */ -#define CMSPAR 0x40000000 /* mark or space (stick) parity */ -#define CRTSCTS 0x80000000 /* flow control */ - -#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ +#define B2500000 0x00001010 +#define B3000000 0x00001011 +#define B3500000 0x00001012 +#define B4000000 0x00001013 */ +#define CIBAUD 0x100f0000 /* input baud rate (not used) */ /* c_lflag bits */ #define ISIG 0x00000001 @@ -219,7 +176,7 @@ struct ktermios { #define ECHOCTL 0x00000200 #define ECHOPRT 0x00000400 #define ECHOKE 0x00000800 -#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */ +#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */ #define FLUSHO 0x00002000 #define PENDIN 0x00004000 #define IEXTEN 0x00008000 @@ -244,21 +201,9 @@ struct ktermios { /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ #define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ - -/* tcflow() and TCXONC use these */ -#define TCOOFF 0 -#define TCOON 1 -#define TCIOFF 2 -#define TCION 3 - -/* tcflush() and TCFLSH use these */ -#define TCIFLUSH 0 -#define TCOFLUSH 1 -#define TCIOFLUSH 2 - /* tcsetattr uses these */ -#define TCSANOW 0 -#define TCSADRAIN 1 -#define TCSAFLUSH 2 +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 #endif /* _UAPI_SPARC_TERMBITS_H */ diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 88c0c14aaff0..33b0215a4182 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -259,9 +259,11 @@ clone_stackframe(struct sparc_stackf __user *dst, extern void ret_from_fork(void); extern void ret_from_kernel_thread(void); -int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, - struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long sp = args->stack; + unsigned long tls = args->tls; struct thread_info *ti = task_thread_info(p); struct pt_regs *childregs, *regs = current_pt_regs(); char *new_stack; @@ -296,13 +298,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, ti->ksp = (unsigned long) new_stack; p->thread.kregs = childregs; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { extern int nwindows; unsigned long psr; memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ); ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8); - childregs->u_regs[UREG_G1] = sp; /* function */ - childregs->u_regs[UREG_G2] = arg; + childregs->u_regs[UREG_G1] = (unsigned long) args->fn; + childregs->u_regs[UREG_G2] = (unsigned long) args->fn_arg; psr = childregs->psr = get_psr(); ti->kpsr = psr | PSR_PIL; ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows); diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 9a2ceb080ac9..6335b698a4b4 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -564,9 +564,11 @@ barf: * Parent --> %o0 == childs pid, %o1 == 0 * Child --> %o0 == parents pid, %o1 == 1 */ -int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, - struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long sp = args->stack; + unsigned long tls = args->tls; struct thread_info *t = task_thread_info(p); struct pt_regs *regs = current_pt_regs(); struct sparc_stackf *parent_sf; @@ -584,12 +586,12 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, sizeof(struct sparc_stackf)); t->fpsaved[0] = 0; - if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (unlikely(args->fn)) { memset(child_trap_frame, 0, child_stack_sz); __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = (current_pt_regs()->tstate + 1) & TSTATE_CWP; - t->kregs->u_regs[UREG_G1] = sp; /* function */ - t->kregs->u_regs[UREG_G2] = arg; + t->kregs->u_regs[UREG_G1] = (unsigned long) args->fn; + t->kregs->u_regs[UREG_G2] = (unsigned long) args->fn_arg; return 0; } diff --git a/arch/um/Kconfig b/arch/um/Kconfig index e8983d098e73..4ec22e156a2e 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -6,6 +6,7 @@ config UML bool default y select ARCH_EPHEMERAL_INODES + select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_KCOV select ARCH_HAS_STRNCPY_FROM_USER select ARCH_HAS_STRNLEN_USER diff --git a/arch/um/drivers/Kconfig b/arch/um/drivers/Kconfig index f145842c40b9..914da774bd39 100644 --- a/arch/um/drivers/Kconfig +++ b/arch/um/drivers/Kconfig @@ -64,6 +64,13 @@ config XTERM_CHAN its own xterm. It is safe to say 'Y' here. +config XTERM_CHAN_DEFAULT_EMULATOR + string "xterm channel default terminal emulator" + depends on XTERM_CHAN + default "xterm" + help + This option allows changing the default terminal emulator. + config NOCONFIG_CHAN bool default !(XTERM_CHAN && TTY_CHAN && PTY_CHAN && PORT_CHAN && NULL_CHAN) @@ -231,6 +238,14 @@ config UML_NET_DAEMON If unsure, say N. +config UML_NET_DAEMON_DEFAULT_SOCK + string "Default socket for daemon transport" + default "/tmp/uml.ctl" + depends on UML_NET_DAEMON + help + This option allows setting the default socket for the daemon + transport, normally it defaults to /tmp/uml.ctl. + config UML_NET_VECTOR bool "Vector I/O high performance network devices" depends on UML_NET diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index 803666e85414..e1dc4292bd22 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile @@ -70,4 +70,6 @@ obj-$(CONFIG_UML_PCI_OVER_VIRTIO) += virt-pci.o USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o CFLAGS_null.o = -DDEV_NULL=$(DEV_NULL_PATH) +CFLAGS_xterm.o += '-DCONFIG_XTERM_CHAN_DEFAULT_EMULATOR="$(CONFIG_XTERM_CHAN_DEFAULT_EMULATOR)"' + include arch/um/scripts/Makefile.rules diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 62997055c454..26a702a06515 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -133,7 +133,7 @@ static void line_timer_cb(struct work_struct *work) struct line *line = container_of(work, struct line, task.work); if (!line->throttled) - chan_interrupt(line, line->driver->read_irq); + chan_interrupt(line, line->read_irq); } int enable_chan(struct line *line) @@ -195,9 +195,9 @@ void free_irqs(void) chan = list_entry(ele, struct chan, free_list); if (chan->input && chan->enabled) - um_free_irq(chan->line->driver->read_irq, chan); + um_free_irq(chan->line->read_irq, chan); if (chan->output && chan->enabled) - um_free_irq(chan->line->driver->write_irq, chan); + um_free_irq(chan->line->write_irq, chan); chan->enabled = 0; } } @@ -215,9 +215,9 @@ static void close_one_chan(struct chan *chan, int delay_free_irq) spin_unlock_irqrestore(&irqs_to_free_lock, flags); } else { if (chan->input && chan->enabled) - um_free_irq(chan->line->driver->read_irq, chan); + um_free_irq(chan->line->read_irq, chan); if (chan->output && chan->enabled) - um_free_irq(chan->line->driver->write_irq, chan); + um_free_irq(chan->line->write_irq, chan); chan->enabled = 0; } if (chan->ops->close != NULL) diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 6040817c036f..25727ed648b7 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -220,7 +220,7 @@ static int winch_tramp(int fd, struct tty_port *port, int *fd_out, unsigned long *stack_out) { struct winch_data data; - int fds[2], n, err; + int fds[2], n, err, pid; char c; err = os_pipe(fds, 1, 1); @@ -238,8 +238,9 @@ static int winch_tramp(int fd, struct tty_port *port, int *fd_out, * problem with /dev/net/tun, which if held open by this * thread, prevents the TUN/TAP device from being reused. */ - err = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out); - if (err < 0) { + pid = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out); + if (pid < 0) { + err = pid; printk(UM_KERN_ERR "fork of winch_thread failed - errno = %d\n", -err); goto out_close; @@ -263,7 +264,7 @@ static int winch_tramp(int fd, struct tty_port *port, int *fd_out, goto out_close; } - return err; + return pid; out_close: close(fds[1]); diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index fd2402669c49..afde1e82c056 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c @@ -65,7 +65,7 @@ static int daemon_setup(char *str, char **mac_out, void *data) *init = ((struct daemon_init) { .sock_type = "unix", - .ctl_sock = "/tmp/uml.ctl" }); + .ctl_sock = CONFIG_UML_NET_DAEMON_DEFAULT_SOCK }); remain = split_if_spec(str, mac_out, &init->sock_type, &init->ctl_sock, NULL); diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 8febf95da96e..02b0befd6763 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -139,7 +139,7 @@ static int flush_buffer(struct line *line) count = line->buffer + LINE_BUFSIZE - line->head; n = write_chan(line->chan_out, line->head, count, - line->driver->write_irq); + line->write_irq); if (n < 0) return n; if (n == count) { @@ -156,7 +156,7 @@ static int flush_buffer(struct line *line) count = line->tail - line->head; n = write_chan(line->chan_out, line->head, count, - line->driver->write_irq); + line->write_irq); if (n < 0) return n; @@ -195,7 +195,7 @@ int line_write(struct tty_struct *tty, const unsigned char *buf, int len) ret = buffer_data(line, buf, len); else { n = write_chan(line->chan_out, buf, len, - line->driver->write_irq); + line->write_irq); if (n < 0) { ret = n; goto out_up; @@ -215,7 +215,7 @@ void line_throttle(struct tty_struct *tty) { struct line *line = tty->driver_data; - deactivate_chan(line->chan_in, line->driver->read_irq); + deactivate_chan(line->chan_in, line->read_irq); line->throttled = 1; } @@ -224,7 +224,7 @@ void line_unthrottle(struct tty_struct *tty) struct line *line = tty->driver_data; line->throttled = 0; - chan_interrupt(line, line->driver->read_irq); + chan_interrupt(line, line->read_irq); } static irqreturn_t line_write_interrupt(int irq, void *data) @@ -260,19 +260,23 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data) int err; if (input) { - err = um_request_irq(driver->read_irq, fd, IRQ_READ, - line_interrupt, IRQF_SHARED, + err = um_request_irq(UM_IRQ_ALLOC, fd, IRQ_READ, + line_interrupt, 0, driver->read_irq_name, data); if (err < 0) return err; + + line->read_irq = err; } if (output) { - err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, - line_write_interrupt, IRQF_SHARED, + err = um_request_irq(UM_IRQ_ALLOC, fd, IRQ_WRITE, + line_write_interrupt, 0, driver->write_irq_name, data); if (err < 0) return err; + + line->write_irq = err; } return 0; diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index bdb16b96e76f..f15be75a3bf3 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -23,9 +23,7 @@ struct line_driver { const short minor_start; const short type; const short subtype; - const int read_irq; const char *read_irq_name; - const int write_irq; const char *write_irq_name; struct mc_device mc; struct tty_driver *driver; @@ -35,6 +33,8 @@ struct line { struct tty_port port; int valid; + int read_irq, write_irq; + char *init_str; struct list_head chan_list; struct chan *chan_in, *chan_out; diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 41eae2e8fb65..8514966778d5 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -47,9 +47,7 @@ static struct line_driver driver = { .minor_start = 64, .type = TTY_DRIVER_TYPE_SERIAL, .subtype = 0, - .read_irq = SSL_IRQ, .read_irq_name = "ssl", - .write_irq = SSL_WRITE_IRQ, .write_irq_name = "ssl-write", .mc = { .list = LIST_HEAD_INIT(driver.mc.list), diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index e8b762f4d8c2..489d5a746ed3 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -53,9 +53,7 @@ static struct line_driver driver = { .minor_start = 0, .type = TTY_DRIVER_TYPE_CONSOLE, .subtype = SYSTEM_TYPE_CONSOLE, - .read_irq = CONSOLE_IRQ, .read_irq_name = "console", - .write_irq = CONSOLE_WRITE_IRQ, .write_irq_name = "console-write", .mc = { .list = LIST_HEAD_INIT(driver.mc.list), diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index ba562d68dc04..82ff3785bf69 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -63,6 +63,7 @@ struct virtio_uml_device { u8 config_changed_irq:1; uint64_t vq_irq_vq_map; + int recv_rc; }; struct virtio_uml_vq_info { @@ -148,14 +149,6 @@ static int vhost_user_recv(struct virtio_uml_device *vu_dev, rc = vhost_user_recv_header(fd, msg); - if (rc == -ECONNRESET && vu_dev->registered) { - struct virtio_uml_platform_data *pdata; - - pdata = vu_dev->pdata; - - virtio_break_device(&vu_dev->vdev); - schedule_work(&pdata->conn_broken_wk); - } if (rc) return rc; size = msg->header.size; @@ -164,6 +157,21 @@ static int vhost_user_recv(struct virtio_uml_device *vu_dev, return full_read(fd, &msg->payload, size, false); } +static void vhost_user_check_reset(struct virtio_uml_device *vu_dev, + int rc) +{ + struct virtio_uml_platform_data *pdata = vu_dev->pdata; + + if (rc != -ECONNRESET) + return; + + if (!vu_dev->registered) + return; + + virtio_break_device(&vu_dev->vdev); + schedule_work(&pdata->conn_broken_wk); +} + static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev, struct vhost_user_msg *msg, size_t max_payload_size) @@ -171,8 +179,10 @@ static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev, int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg, max_payload_size, true); - if (rc) + if (rc) { + vhost_user_check_reset(vu_dev, rc); return rc; + } if (msg->header.flags != (VHOST_USER_FLAG_REPLY | VHOST_USER_VERSION)) return -EPROTO; @@ -369,6 +379,7 @@ static irqreturn_t vu_req_read_message(struct virtio_uml_device *vu_dev, sizeof(msg.msg.payload) + sizeof(msg.extra_payload)); + vu_dev->recv_rc = rc; if (rc) return IRQ_NONE; @@ -412,7 +423,9 @@ static irqreturn_t vu_req_interrupt(int irq, void *data) if (!um_irq_timetravel_handler_used()) ret = vu_req_read_message(vu_dev, NULL); - if (vu_dev->vq_irq_vq_map) { + if (vu_dev->recv_rc) { + vhost_user_check_reset(vu_dev, vu_dev->recv_rc); + } else if (vu_dev->vq_irq_vq_map) { struct virtqueue *vq; virtio_device_for_each_vq((&vu_dev->vdev), vq) { diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index 87ca4a47cd66..6918de5e2956 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -42,7 +42,7 @@ static void *xterm_init(char *str, int device, const struct chan_opts *opts) } /* Only changed by xterm_setup, which is a setup */ -static char *terminal_emulator = "xterm"; +static char *terminal_emulator = CONFIG_XTERM_CHAN_DEFAULT_EMULATOR; static char *title_switch = "-T"; static char *exec_switch = "-e"; @@ -79,8 +79,9 @@ __uml_setup("xterm=", xterm_setup, " respectively. The title switch must have the form '<switch> title',\n" " not '<switch>=title'. Similarly, the exec switch must have the form\n" " '<switch> command arg1 arg2 ...'.\n" -" The default values are 'xterm=xterm,-T,-e'. Values for gnome-terminal\n" -" are 'xterm=gnome-terminal,-t,-x'.\n\n" +" The default values are 'xterm=" CONFIG_XTERM_CHAN_DEFAULT_EMULATOR + ",-T,-e'.\n" +" Values for gnome-terminal are 'xterm=gnome-terminal,-t,-x'.\n\n" ); static int xterm_open(int input, int output, int primary, void *d, diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index f1f3f52f1e9c..b2d834a29f3a 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild @@ -4,6 +4,7 @@ generic-y += bug.h generic-y += compat.h generic-y += current.h generic-y += device.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.h diff --git a/arch/um/include/asm/irq.h b/arch/um/include/asm/irq.h index e187c789369d..749dfe8512e8 100644 --- a/arch/um/include/asm/irq.h +++ b/arch/um/include/asm/irq.h @@ -4,19 +4,15 @@ #define TIMER_IRQ 0 #define UMN_IRQ 1 -#define CONSOLE_IRQ 2 -#define CONSOLE_WRITE_IRQ 3 -#define UBD_IRQ 4 -#define UM_ETH_IRQ 5 -#define SSL_IRQ 6 -#define SSL_WRITE_IRQ 7 -#define ACCEPT_IRQ 8 -#define MCONSOLE_IRQ 9 -#define WINCH_IRQ 10 -#define SIGIO_WRITE_IRQ 11 -#define TELNETD_IRQ 12 -#define XTERM_IRQ 13 -#define RANDOM_IRQ 14 +#define UBD_IRQ 2 +#define UM_ETH_IRQ 3 +#define ACCEPT_IRQ 4 +#define MCONSOLE_IRQ 5 +#define WINCH_IRQ 6 +#define SIGIO_WRITE_IRQ 7 +#define TELNETD_IRQ 8 +#define XTERM_IRQ 9 +#define RANDOM_IRQ 10 #ifdef CONFIG_UML_NET_VECTOR diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h index 1395cbd7e340..c7b4b49826a2 100644 --- a/arch/um/include/asm/thread_info.h +++ b/arch/um/include/asm/thread_info.h @@ -60,6 +60,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_RESTORE_SIGMASK 7 #define TIF_NOTIFY_RESUME 8 #define TIF_SECCOMP 9 /* secure computing */ +#define TIF_SINGLESTEP 10 /* single stepping userspace */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) @@ -68,5 +69,6 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_MEMDIE (1 << TIF_MEMDIE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) #endif diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index c85e40c72779..58938d75871a 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -43,7 +43,7 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) { PT_REGS_IP(regs) = eip; PT_REGS_SP(regs) = esp; - current->ptrace &= ~PT_DTRACE; + clear_thread_flag(TIF_SINGLESTEP); #ifdef SUBARCH_EXECVE1 SUBARCH_EXECVE1(regs->regs); #endif diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 80504680be08..80b90b1276a1 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -154,16 +154,17 @@ void fork_handler(void) userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs); } -int copy_thread(unsigned long clone_flags, unsigned long sp, - unsigned long arg, struct task_struct * p, unsigned long tls) +int copy_thread(struct task_struct * p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long sp = args->stack; + unsigned long tls = args->tls; void (*handler)(void); - int kthread = current->flags & (PF_KTHREAD | PF_IO_WORKER); int ret = 0; p->thread = (struct thread_struct) INIT_THREAD; - if (!kthread) { + if (!args->fn) { memcpy(&p->thread.regs.regs, current_pt_regs(), sizeof(p->thread.regs.regs)); PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0); @@ -175,14 +176,14 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, arch_copy_thread(¤t->thread.arch, &p->thread.arch); } else { get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp); - p->thread.request.u.thread.proc = (int (*)(void *))sp; - p->thread.request.u.thread.arg = (void *)arg; + p->thread.request.u.thread.proc = args->fn; + p->thread.request.u.thread.arg = args->fn_arg; handler = new_thread_handler; } new_thread(task_stack_page(p), &p->thread.switch_buf, handler); - if (!kthread) { + if (!args->fn) { clear_flushed_tls(p); /* @@ -335,7 +336,7 @@ int singlestepping(void * t) { struct task_struct *task = t ? t : current; - if (!(task->ptrace & PT_DTRACE)) + if (!test_thread_flag(TIF_SINGLESTEP)) return 0; if (task->thread.singlestep_syscall) diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index bfaf6ab1ac03..5154b27de580 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -11,7 +11,7 @@ void user_enable_single_step(struct task_struct *child) { - child->ptrace |= PT_DTRACE; + set_tsk_thread_flag(child, TIF_SINGLESTEP); child->thread.singlestep_syscall = 0; #ifdef SUBARCH_SET_SINGLESTEPPING @@ -21,7 +21,7 @@ void user_enable_single_step(struct task_struct *child) void user_disable_single_step(struct task_struct *child) { - child->ptrace &= ~PT_DTRACE; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->thread.singlestep_syscall = 0; #ifdef SUBARCH_SET_SINGLESTEPPING @@ -120,7 +120,7 @@ static void send_sigtrap(struct uml_pt_regs *regs, int error_code) } /* - * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and + * XXX Check TIF_SINGLESTEP for singlestepping check and * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check */ int syscall_trace_enter(struct pt_regs *regs) @@ -144,7 +144,7 @@ void syscall_trace_leave(struct pt_regs *regs) audit_syscall_exit(regs); /* Fake a debug trap */ - if (ptraced & PT_DTRACE) + if (test_thread_flag(TIF_SINGLESTEP)) send_sigtrap(®s->regs, 0); if (!test_thread_flag(TIF_SYSCALL_TRACE)) diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c index 88cd9b5c1b74..ae4658f576ab 100644 --- a/arch/um/kernel/signal.c +++ b/arch/um/kernel/signal.c @@ -53,7 +53,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) unsigned long sp; int err; - if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) + if (test_thread_flag(TIF_SINGLESTEP) && (current->ptrace & PT_PTRACED)) singlestep = 1; /* Did we come from a system call? */ @@ -128,7 +128,7 @@ void do_signal(struct pt_regs *regs) * on the host. The tracing thread will check this flag and * PTRACE_SYSCALL if necessary. */ - if (current->ptrace & PT_DTRACE) + if (test_thread_flag(TIF_SINGLESTEP)) current->thread.singlestep_syscall = is_syscall(PT_REGS_IP(¤t->thread.regs)); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a293a30e4cdd..9783ebc4e021 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -41,11 +41,11 @@ config FORCE_DYNAMIC_FTRACE depends on FUNCTION_TRACER select DYNAMIC_FTRACE help - We keep the static function tracing (!DYNAMIC_FTRACE) around - in order to test the non static function tracing in the - generic code, as other architectures still use it. But we - only need to keep it around for x86_64. No need to keep it - for x86_32. For x86_32, force DYNAMIC_FTRACE. + We keep the static function tracing (!DYNAMIC_FTRACE) around + in order to test the non static function tracing in the + generic code, as other architectures still use it. But we + only need to keep it around for x86_64. No need to keep it + for x86_32. For x86_32, force DYNAMIC_FTRACE. # # Arch settings # @@ -258,6 +258,7 @@ config X86 select HAVE_PREEMPT_DYNAMIC_CALL select HAVE_RSEQ select HAVE_SYSCALL_TRACEPOINTS + select HAVE_UACCESS_VALIDATION if HAVE_OBJTOOL select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_USER_RETURN_NOTIFIER select HAVE_GENERIC_VDSO @@ -393,9 +394,9 @@ config CC_HAS_SANE_STACKPROTECTOR default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC)) if 64BIT default $(success,$(srctree)/scripts/gcc-x86_32-has-stack-protector.sh $(CC)) help - We have to make sure stack protector is unconditionally disabled if - the compiler produces broken code or if it does not let us control - the segment on 32-bit kernels. + We have to make sure stack protector is unconditionally disabled if + the compiler produces broken code or if it does not let us control + the segment on 32-bit kernels. menu "Processor type and features" @@ -531,7 +532,7 @@ config X86_EXTENDED_PLATFORM If you have one of these systems, or if you want to build a generic distribution kernel, say Y here - otherwise say N. -endif +endif # X86_32 if X86_64 config X86_EXTENDED_PLATFORM @@ -550,7 +551,7 @@ config X86_EXTENDED_PLATFORM If you have one of these systems, or if you want to build a generic distribution kernel, say Y here - otherwise say N. -endif +endif # X86_64 # This is an alphabetically sorted list of 64 bit extended platforms # Please maintain the alphabetic order if and when there are additions config X86_NUMACHIP @@ -598,9 +599,9 @@ config X86_GOLDFISH bool "Goldfish (Virtual Platform)" depends on X86_EXTENDED_PLATFORM help - Enable support for the Goldfish virtual platform used primarily - for Android development. Unless you are building for the Android - Goldfish emulator say N here. + Enable support for the Goldfish virtual platform used primarily + for Android development. Unless you are building for the Android + Goldfish emulator say N here. config X86_INTEL_CE bool "CE4100 TV platform" @@ -899,7 +900,7 @@ config INTEL_TDX_GUEST memory contents and CPU state. TDX guests are protected from some attacks from the VMM. -endif #HYPERVISOR_GUEST +endif # HYPERVISOR_GUEST source "arch/x86/Kconfig.cpu" @@ -1166,16 +1167,16 @@ config X86_MCE_INTEL prompt "Intel MCE features" depends on X86_MCE && X86_LOCAL_APIC help - Additional support for intel specific MCE features such as - the thermal monitor. + Additional support for intel specific MCE features such as + the thermal monitor. config X86_MCE_AMD def_bool y prompt "AMD MCE features" depends on X86_MCE && X86_LOCAL_APIC && AMD_NB help - Additional support for AMD specific MCE features such as - the DRAM Error Threshold. + Additional support for AMD specific MCE features such as + the DRAM Error Threshold. config X86_ANCIENT_MCE bool "Support for old Pentium 5 / WinChip machine checks" @@ -1253,18 +1254,18 @@ config X86_VSYSCALL_EMULATION default y depends on X86_64 help - This enables emulation of the legacy vsyscall page. Disabling - it is roughly equivalent to booting with vsyscall=none, except - that it will also disable the helpful warning if a program - tries to use a vsyscall. With this option set to N, offending - programs will just segfault, citing addresses of the form - 0xffffffffff600?00. + This enables emulation of the legacy vsyscall page. Disabling + it is roughly equivalent to booting with vsyscall=none, except + that it will also disable the helpful warning if a program + tries to use a vsyscall. With this option set to N, offending + programs will just segfault, citing addresses of the form + 0xffffffffff600?00. - This option is required by many programs built before 2013, and - care should be used even with newer programs if set to N. + This option is required by many programs built before 2013, and + care should be used even with newer programs if set to N. - Disabling this option saves about 7K of kernel size and - possibly 4K of additional runtime pagetable memory. + Disabling this option saves about 7K of kernel size and + possibly 4K of additional runtime pagetable memory. config X86_IOPL_IOPERM bool "IOPERM and IOPL Emulation" @@ -1357,17 +1358,16 @@ config MICROCODE_AMD If you select this option, microcode patch loading support for AMD processors will be enabled. -config MICROCODE_OLD_INTERFACE - bool "Ancient loading interface (DEPRECATED)" +config MICROCODE_LATE_LOADING + bool "Late microcode loading (DANGEROUS)" default n depends on MICROCODE help - DO NOT USE THIS! This is the ancient /dev/cpu/microcode interface - which was used by userspace tools like iucode_tool and microcode.ctl. - It is inadequate because it runs too late to be able to properly - load microcode on a machine and it needs special tools. Instead, you - should've switched to the early loading method with the initrd or - builtin microcode by now: Documentation/x86/microcode.rst + Loading microcode late, when the system is up and executing instructions + is a tricky business and should be avoided if possible. Just the sequence + of synchronizing all cores and SMT threads is one fragile dance which does + not guarantee that cores might not softlock after the loading. Therefore, + use this at your own risk. Late loading taints the kernel too. config X86_MSR tristate "/dev/cpu/*/msr - Model-specific register support" @@ -2001,15 +2001,15 @@ config EFI_MIXED bool "EFI mixed-mode support" depends on EFI_STUB && X86_64 help - Enabling this feature allows a 64-bit kernel to be booted - on a 32-bit firmware, provided that your CPU supports 64-bit - mode. + Enabling this feature allows a 64-bit kernel to be booted + on a 32-bit firmware, provided that your CPU supports 64-bit + mode. - Note that it is not possible to boot a mixed-mode enabled - kernel via the EFI boot stub - a bootloader that supports - the EFI handover protocol must be used. + Note that it is not possible to boot a mixed-mode enabled + kernel via the EFI boot stub - a bootloader that supports + the EFI handover protocol must be used. - If unsure, say N. + If unsure, say N. source "kernel/Kconfig.hz" @@ -2234,16 +2234,16 @@ config RANDOMIZE_MEMORY select DYNAMIC_MEMORY_LAYOUT default RANDOMIZE_BASE help - Randomizes the base virtual address of kernel memory sections - (physical memory mapping, vmalloc & vmemmap). This security feature - makes exploits relying on predictable memory locations less reliable. + Randomizes the base virtual address of kernel memory sections + (physical memory mapping, vmalloc & vmemmap). This security feature + makes exploits relying on predictable memory locations less reliable. - The order of allocations remains unchanged. Entropy is generated in - the same way as RANDOMIZE_BASE. Current implementation in the optimal - configuration have in average 30,000 different possible virtual - addresses for each memory section. + The order of allocations remains unchanged. Entropy is generated in + the same way as RANDOMIZE_BASE. Current implementation in the optimal + configuration have in average 30,000 different possible virtual + addresses for each memory section. - If unsure, say Y. + If unsure, say Y. config RANDOMIZE_MEMORY_PHYSICAL_PADDING hex "Physical memory mapping padding" if EXPERT @@ -2253,12 +2253,12 @@ config RANDOMIZE_MEMORY_PHYSICAL_PADDING range 0x1 0x40 if MEMORY_HOTPLUG range 0x0 0x40 help - Define the padding in terabytes added to the existing physical - memory size during kernel memory randomization. It is useful - for memory hotplug support but reduces the entropy available for - address randomization. + Define the padding in terabytes added to the existing physical + memory size during kernel memory randomization. It is useful + for memory hotplug support but reduces the entropy available for + address randomization. - If unsure, leave at the default value. + If unsure, leave at the default value. config HOTPLUG_CPU def_bool y @@ -2605,7 +2605,6 @@ source "drivers/idle/Kconfig" endmenu - menu "Bus options (PCI etc.)" choice @@ -2829,7 +2828,6 @@ config AMD_NB endmenu - menu "Binary Emulations" config IA32_EMULATION @@ -2867,14 +2865,12 @@ config COMPAT def_bool y depends on IA32_EMULATION || X86_X32_ABI -if COMPAT config COMPAT_FOR_U64_ALIGNMENT def_bool y -endif + depends on COMPAT endmenu - config HAVE_ATOMIC_IOMAP def_bool y depends on X86_32 diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index d872a7522e55..340399f69954 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -73,20 +73,19 @@ config DEBUG_TLBFLUSH bool "Set upper limit of TLB entries to flush one-by-one" depends on DEBUG_KERNEL help + X86-only for now. - X86-only for now. + This option allows the user to tune the amount of TLB entries the + kernel flushes one-by-one instead of doing a full TLB flush. In + certain situations, the former is cheaper. This is controlled by the + tlb_flushall_shift knob under /sys/kernel/debug/x86. If you set it + to -1, the code flushes the whole TLB unconditionally. Otherwise, + for positive values of it, the kernel will use single TLB entry + invalidating instructions according to the following formula: - This option allows the user to tune the amount of TLB entries the - kernel flushes one-by-one instead of doing a full TLB flush. In - certain situations, the former is cheaper. This is controlled by the - tlb_flushall_shift knob under /sys/kernel/debug/x86. If you set it - to -1, the code flushes the whole TLB unconditionally. Otherwise, - for positive values of it, the kernel will use single TLB entry - invalidating instructions according to the following formula: + flush_entries <= active_tlb_entries / 2^tlb_flushall_shift - flush_entries <= active_tlb_entries / 2^tlb_flushall_shift - - If in doubt, say "N". + If in doubt, say "N". config IOMMU_DEBUG bool "Enable IOMMU debugging" @@ -119,10 +118,10 @@ config X86_DECODER_SELFTEST depends on DEBUG_KERNEL && INSTRUCTION_DECODER depends on !COMPILE_TEST help - Perform x86 instruction decoder selftests at build time. - This option is useful for checking the sanity of x86 instruction - decoder code. - If unsure, say "N". + Perform x86 instruction decoder selftests at build time. + This option is useful for checking the sanity of x86 instruction + decoder code. + If unsure, say "N". choice prompt "IO delay type" diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 0352e4589efa..f912d7770130 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -163,7 +163,7 @@ extra_header_fields: .long 0x200 # SizeOfHeaders .long 0 # CheckSum .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) -#ifdef CONFIG_DXE_MEM_ATTRIBUTES +#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics #else .word 0 # DllCharacteristics diff --git a/arch/x86/events/Kconfig b/arch/x86/events/Kconfig index 09c56965750a..dabdf3d7bf84 100644 --- a/arch/x86/events/Kconfig +++ b/arch/x86/events/Kconfig @@ -6,24 +6,24 @@ config PERF_EVENTS_INTEL_UNCORE depends on PERF_EVENTS && CPU_SUP_INTEL && PCI default y help - Include support for Intel uncore performance events. These are - available on NehalemEX and more modern processors. + Include support for Intel uncore performance events. These are + available on NehalemEX and more modern processors. config PERF_EVENTS_INTEL_RAPL tristate "Intel/AMD rapl performance events" depends on PERF_EVENTS && (CPU_SUP_INTEL || CPU_SUP_AMD) && PCI default y help - Include support for Intel and AMD rapl performance events for power - monitoring on modern processors. + Include support for Intel and AMD rapl performance events for power + monitoring on modern processors. config PERF_EVENTS_INTEL_CSTATE tristate "Intel cstate performance events" depends on PERF_EVENTS && CPU_SUP_INTEL && PCI default y help - Include support for Intel cstate performance events for power - monitoring on modern processors. + Include support for Intel cstate performance events for power + monitoring on modern processors. config PERF_EVENTS_AMD_POWER depends on PERF_EVENTS && CPU_SUP_AMD diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 955ae91c56dc..45024abd929f 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -276,7 +276,7 @@ static struct event_constraint intel_icl_event_constraints[] = { INTEL_EVENT_CONSTRAINT_RANGE(0x03, 0x0a, 0xf), INTEL_EVENT_CONSTRAINT_RANGE(0x1f, 0x28, 0xf), INTEL_EVENT_CONSTRAINT(0x32, 0xf), /* SW_PREFETCH_ACCESS.* */ - INTEL_EVENT_CONSTRAINT_RANGE(0x48, 0x54, 0xf), + INTEL_EVENT_CONSTRAINT_RANGE(0x48, 0x56, 0xf), INTEL_EVENT_CONSTRAINT_RANGE(0x60, 0x8b, 0xf), INTEL_UEVENT_CONSTRAINT(0x04a3, 0xff), /* CYCLE_ACTIVITY.STALLS_TOTAL */ INTEL_UEVENT_CONSTRAINT(0x10a3, 0xff), /* CYCLE_ACTIVITY.CYCLES_MEM_ANY */ diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 66d3e3b1d24d..ea34cc31b047 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -54,7 +54,7 @@ extern const char * const x86_power_flags[32]; extern const char * const x86_bug_flags[NBUGINTS*32]; #define test_cpu_cap(c, bit) \ - test_bit(bit, (unsigned long *)((c)->x86_capability)) + arch_test_bit(bit, (unsigned long *)((c)->x86_capability)) /* * There are 32 bits/features in each mask word. The high bits diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index bed74a0f2932..71943dce691e 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -270,6 +270,8 @@ static inline u32 efi64_convert_status(efi_status_t status) return (u32)(status | (u64)status >> 32); } +#define __efi64_split(val) (val) & U32_MAX, (u64)(val) >> 32 + #define __efi64_argmap_free_pages(addr, size) \ ((addr), 0, (size)) @@ -317,6 +319,13 @@ static inline u32 efi64_convert_status(efi_status_t status) #define __efi64_argmap_hash_log_extend_event(prot, fl, addr, size, ev) \ ((prot), (fl), 0ULL, (u64)(addr), 0ULL, (u64)(size), 0ULL, ev) +/* DXE services */ +#define __efi64_argmap_get_memory_space_descriptor(phys, desc) \ + (__efi64_split(phys), (desc)) + +#define __efi64_argmap_set_memory_space_descriptor(phys, size, flags) \ + (__efi64_split(phys), __efi64_split(size), __efi64_split(flags)) + /* * The macros below handle the plumbing for the argument mapping. To add a * mapping for a specific EFI method, simply define a macro diff --git a/arch/x86/include/asm/extable.h b/arch/x86/include/asm/extable.h index 155c991ba95e..eeed395c3177 100644 --- a/arch/x86/include/asm/extable.h +++ b/arch/x86/include/asm/extable.h @@ -42,9 +42,13 @@ extern int ex_get_fixup_type(unsigned long ip); extern void early_fixup_exception(struct pt_regs *regs, int trapnr); #ifdef CONFIG_X86_MCE -extern void ex_handler_msr_mce(struct pt_regs *regs, bool wrmsr); +extern void __noreturn ex_handler_msr_mce(struct pt_regs *regs, bool wrmsr); #else -static inline void ex_handler_msr_mce(struct pt_regs *regs, bool wrmsr) { } +static inline void __noreturn ex_handler_msr_mce(struct pt_regs *regs, bool wrmsr) +{ + for (;;) + cpu_relax(); +} #endif #if defined(CONFIG_BPF_JIT) && defined(CONFIG_X86_64) diff --git a/arch/x86/include/asm/fpu/sched.h b/arch/x86/include/asm/fpu/sched.h index 99a8820e8cc4..b2486b2cbc6e 100644 --- a/arch/x86/include/asm/fpu/sched.h +++ b/arch/x86/include/asm/fpu/sched.h @@ -11,7 +11,7 @@ extern void save_fpregs_to_fpstate(struct fpu *fpu); extern void fpu__drop(struct fpu *fpu); -extern int fpu_clone(struct task_struct *dst, unsigned long clone_flags); +extern int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal); extern void fpu_flush_thread(void); /* diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 91d0f93a00c7..356308c73951 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -559,7 +559,7 @@ static __always_inline void native_swapgs(void) #endif } -static inline unsigned long current_top_of_stack(void) +static __always_inline unsigned long current_top_of_stack(void) { /* * We can't read directly from tss.sp0: sp0 on x86_32 is special in @@ -569,7 +569,7 @@ static inline unsigned long current_top_of_stack(void) return this_cpu_read_stable(cpu_current_top_of_stack); } -static inline bool on_thread_stack(void) +static __always_inline bool on_thread_stack(void) { return (unsigned long)(current_top_of_stack() - current_stack_pointer) < THREAD_SIZE; diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h index b5f0d2ff47e4..c08eb0fdd11f 100644 --- a/arch/x86/include/asm/switch_to.h +++ b/arch/x86/include/asm/switch_to.h @@ -78,13 +78,13 @@ static inline void update_task_stack(struct task_struct *task) } static inline void kthread_frame_init(struct inactive_task_frame *frame, - unsigned long fun, unsigned long arg) + int (*fun)(void *), void *arg) { - frame->bx = fun; + frame->bx = (unsigned long)fun; #ifdef CONFIG_X86_32 - frame->di = arg; + frame->di = (unsigned long)arg; #else - frame->r12 = arg; + frame->r12 = (unsigned long)arg; #endif } diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 1fc67df50014..fa9ec20783fa 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -347,9 +347,6 @@ unsigned long arbitrary_virt_to_mfn(void *vaddr); void make_lowmem_page_readonly(void *vaddr); void make_lowmem_page_readwrite(void *vaddr); -#define xen_remap(cookie, size) ioremap((cookie), (size)) -#define xen_unmap(cookie) iounmap((cookie)) - static inline bool xen_arch_need_swiotlb(struct device *dev, phys_addr_t phys, dma_addr_t dev_addr) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 2e9142797c99..c296cb1c0113 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -2222,6 +2222,7 @@ void cpu_init_secondary(void) } #endif +#ifdef CONFIG_MICROCODE_LATE_LOADING /* * The microcode loader calls this upon late microcode load to recheck features, * only when microcode has been updated. Caller holds microcode_mutex and CPU @@ -2251,6 +2252,7 @@ void microcode_check(void) pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n"); pr_warn("x86/CPU: Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); } +#endif /* * Invoked from core CPU hotplug code after hotplug operations diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 239ff5fcec6a..ad57e0e4d674 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -373,101 +373,10 @@ static int apply_microcode_on_target(int cpu) return ret; } -#ifdef CONFIG_MICROCODE_OLD_INTERFACE -static int do_microcode_update(const void __user *buf, size_t size) -{ - int error = 0; - int cpu; - - for_each_online_cpu(cpu) { - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; - enum ucode_state ustate; - - if (!uci->valid) - continue; - - ustate = microcode_ops->request_microcode_user(cpu, buf, size); - if (ustate == UCODE_ERROR) { - error = -1; - break; - } else if (ustate == UCODE_NEW) { - apply_microcode_on_target(cpu); - } - } - - return error; -} - -static int microcode_open(struct inode *inode, struct file *file) -{ - return capable(CAP_SYS_RAWIO) ? stream_open(inode, file) : -EPERM; -} - -static ssize_t microcode_write(struct file *file, const char __user *buf, - size_t len, loff_t *ppos) -{ - ssize_t ret = -EINVAL; - unsigned long nr_pages = totalram_pages(); - - if ((len >> PAGE_SHIFT) > nr_pages) { - pr_err("too much data (max %ld pages)\n", nr_pages); - return ret; - } - - cpus_read_lock(); - mutex_lock(µcode_mutex); - - if (do_microcode_update(buf, len) == 0) - ret = (ssize_t)len; - - if (ret > 0) - perf_check_microcode(); - - mutex_unlock(µcode_mutex); - cpus_read_unlock(); - - return ret; -} - -static const struct file_operations microcode_fops = { - .owner = THIS_MODULE, - .write = microcode_write, - .open = microcode_open, - .llseek = no_llseek, -}; - -static struct miscdevice microcode_dev = { - .minor = MICROCODE_MINOR, - .name = "microcode", - .nodename = "cpu/microcode", - .fops = µcode_fops, -}; - -static int __init microcode_dev_init(void) -{ - int error; - - error = misc_register(µcode_dev); - if (error) { - pr_err("can't misc_register on minor=%d\n", MICROCODE_MINOR); - return error; - } - - return 0; -} - -static void __exit microcode_dev_exit(void) -{ - misc_deregister(µcode_dev); -} -#else -#define microcode_dev_init() 0 -#define microcode_dev_exit() do { } while (0) -#endif - /* fake device for request_firmware */ static struct platform_device *microcode_pdev; +#ifdef CONFIG_MICROCODE_LATE_LOADING /* * Late loading dance. Why the heavy-handed stomp_machine effort? * @@ -584,6 +493,9 @@ static int microcode_reload_late(void) { int ret; + pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n"); + pr_err("You should switch to early loading, if possible.\n"); + atomic_set(&late_cpus_in, 0); atomic_set(&late_cpus_out, 0); @@ -632,9 +544,14 @@ put: if (ret == 0) ret = size; + add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); + return ret; } +static DEVICE_ATTR_WO(reload); +#endif + static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -651,7 +568,6 @@ static ssize_t pf_show(struct device *dev, return sprintf(buf, "0x%x\n", uci->cpu_sig.pf); } -static DEVICE_ATTR_WO(reload); static DEVICE_ATTR(version, 0444, version_show, NULL); static DEVICE_ATTR(processor_flags, 0444, pf_show, NULL); @@ -804,7 +720,9 @@ static int mc_cpu_down_prep(unsigned int cpu) } static struct attribute *cpu_root_microcode_attrs[] = { +#ifdef CONFIG_MICROCODE_LATE_LOADING &dev_attr_reload.attr, +#endif NULL }; @@ -838,10 +756,7 @@ static int __init microcode_init(void) cpus_read_lock(); mutex_lock(µcode_mutex); - error = subsys_interface_register(&mc_cpu_interface); - if (!error) - perf_check_microcode(); mutex_unlock(µcode_mutex); cpus_read_unlock(); @@ -856,10 +771,6 @@ static int __init microcode_init(void) goto out_driver; } - error = microcode_dev_init(); - if (error) - goto out_ucode_group; - register_syscore_ops(&mc_syscore_ops); cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:starting", mc_cpu_starting, NULL); @@ -870,10 +781,6 @@ static int __init microcode_init(void) return 0; - out_ucode_group: - sysfs_remove_group(&cpu_subsys.dev_root->kobj, - &cpu_root_microcode_group); - out_driver: cpus_read_lock(); mutex_lock(µcode_mutex); diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 0fdc807ae13f..0531d6a06df5 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -556,7 +556,7 @@ static inline void fpu_inherit_perms(struct fpu *dst_fpu) } /* Clone current's FPU state on fork */ -int fpu_clone(struct task_struct *dst, unsigned long clone_flags) +int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal) { struct fpu *src_fpu = ¤t->thread.fpu; struct fpu *dst_fpu = &dst->thread.fpu; @@ -579,7 +579,7 @@ int fpu_clone(struct task_struct *dst, unsigned long clone_flags) * No FPU state inheritance for kernel threads and IO * worker threads. */ - if (dst->flags & (PF_KTHREAD | PF_IO_WORKER)) { + if (minimal) { /* Clear out the minimal state */ memcpy(&dst_fpu->fpstate->regs, &init_fpstate.regs, init_fpstate_copy_size()); diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 58fb48d3004f..9b2772b7e1f3 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -131,9 +131,11 @@ static int set_new_tls(struct task_struct *p, unsigned long tls) return do_set_thread_area_64(p, ARCH_SET_FS, tls); } -int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, - struct task_struct *p, unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long sp = args->stack; + unsigned long tls = args->tls; struct inactive_task_frame *frame; struct fork_frame *fork_frame; struct pt_regs *childregs; @@ -171,13 +173,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, frame->flags = X86_EFLAGS_FIXED; #endif - fpu_clone(p, clone_flags); + fpu_clone(p, clone_flags, args->fn); /* Kernel thread ? */ if (unlikely(p->flags & PF_KTHREAD)) { p->thread.pkru = pkru_get_init_value(); memset(childregs, 0, sizeof(struct pt_regs)); - kthread_frame_init(frame, sp, arg); + kthread_frame_init(frame, args->fn, args->fn_arg); return 0; } @@ -193,10 +195,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, if (sp) childregs->sp = sp; - if (unlikely(p->flags & PF_IO_WORKER)) { + if (unlikely(args->fn)) { /* - * An IO thread is a user space thread, but it doesn't - * return to ret_after_fork(). + * A user space thread, but it doesn't return to + * ret_after_fork(). * * In order to indicate that to tools like gdb, * we reset the stack and instruction pointers. @@ -206,7 +208,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, */ childregs->sp = 0; childregs->ip = 0; - kthread_frame_init(frame, sp, arg); + kthread_frame_init(frame, args->fn, args->fn_arg); return 0; } diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 249981bf3d8a..3ebb85327edb 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -903,18 +903,18 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_CMDLINE_BOOL #ifdef CONFIG_CMDLINE_OVERRIDE - strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); + strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); #else if (builtin_cmdline[0]) { /* append boot loader cmdline to builtin */ strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE); strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE); - strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); + strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); } #endif #endif - strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); + strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; /* diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index 0f3c307b37b3..8e2b2552b5ee 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c @@ -180,8 +180,7 @@ void set_task_blockstep(struct task_struct *task, bool on) * * NOTE: this means that set/clear TIF_BLOCKSTEP is only safe if * task is current or it can't be running, otherwise we can race - * with __switch_to_xtra(). We rely on ptrace_freeze_traced() but - * PTRACE_KILL is not safe. + * with __switch_to_xtra(). We rely on ptrace_freeze_traced(). */ local_irq_disable(); debugctl = get_debugctlmsr(); diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index a0702b6be3e8..e2e95a6fccfd 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -90,7 +90,7 @@ static void synic_update_vector(struct kvm_vcpu_hv_synic *synic, { struct kvm_vcpu *vcpu = hv_synic_to_vcpu(synic); struct kvm_hv *hv = to_kvm_hv(vcpu->kvm); - int auto_eoi_old, auto_eoi_new; + bool auto_eoi_old, auto_eoi_new; if (vector < HV_SYNIC_FIRST_VALID_VECTOR) return; @@ -100,16 +100,16 @@ static void synic_update_vector(struct kvm_vcpu_hv_synic *synic, else __clear_bit(vector, synic->vec_bitmap); - auto_eoi_old = bitmap_weight(synic->auto_eoi_bitmap, 256); + auto_eoi_old = !bitmap_empty(synic->auto_eoi_bitmap, 256); if (synic_has_vector_auto_eoi(synic, vector)) __set_bit(vector, synic->auto_eoi_bitmap); else __clear_bit(vector, synic->auto_eoi_bitmap); - auto_eoi_new = bitmap_weight(synic->auto_eoi_bitmap, 256); + auto_eoi_new = !bitmap_empty(synic->auto_eoi_bitmap, 256); - if (!!auto_eoi_old == !!auto_eoi_new) + if (auto_eoi_old == auto_eoi_new) return; if (!enable_apicv) @@ -1855,7 +1855,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc) all_cpus = flush_ex.hv_vp_set.format != HV_GENERIC_SET_SPARSE_4K; - if (hc->var_cnt != bitmap_weight((unsigned long *)&valid_bank_mask, 64)) + if (hc->var_cnt != hweight64(valid_bank_mask)) return HV_STATUS_INVALID_HYPERCALL_INPUT; if (all_cpus) @@ -1956,7 +1956,7 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc) valid_bank_mask = send_ipi_ex.vp_set.valid_bank_mask; all_cpus = send_ipi_ex.vp_set.format == HV_GENERIC_SET_ALL; - if (hc->var_cnt != bitmap_weight((unsigned long *)&valid_bank_mask, 64)) + if (hc->var_cnt != hweight64(valid_bank_mask)) return HV_STATUS_INVALID_HYPERCALL_INPUT; if (all_cpus) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index f5aeade623d6..a07e8cd753ec 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6219,7 +6219,7 @@ static noinstr void vmx_l1d_flush(struct kvm_vcpu *vcpu) int size = PAGE_SIZE << L1D_CACHE_ORDER; /* - * This code is only executed when the the flush mode is 'cond' or + * This code is only executed when the flush mode is 'cond' or * 'always' */ if (static_branch_likely(&vmx_l1d_flush_cond)) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b81ef4f497f4..e9473c7c7390 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -11937,7 +11937,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) if (current->mm == kvm->mm) { /* * Free memory regions allocated on behalf of userspace, - * unless the the memory map has changed due to process exit + * unless the memory map has changed due to process exit * or fd copying. */ mutex_lock(&kvm->slots_lock); diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index cb290a2f0747..39c5246964a9 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1240,8 +1240,8 @@ remove_pagetable(unsigned long start, unsigned long end, bool direct, void __ref vmemmap_free(unsigned long start, unsigned long end, struct vmem_altmap *altmap) { - VM_BUG_ON(!IS_ALIGNED(start, PAGE_SIZE)); - VM_BUG_ON(!IS_ALIGNED(end, PAGE_SIZE)); + VM_BUG_ON(!PAGE_ALIGNED(start)); + VM_BUG_ON(!PAGE_ALIGNED(end)); remove_pagetable(start, end, false, altmap); } @@ -1605,8 +1605,8 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node, { int err; - VM_BUG_ON(!IS_ALIGNED(start, PAGE_SIZE)); - VM_BUG_ON(!IS_ALIGNED(end, PAGE_SIZE)); + VM_BUG_ON(!PAGE_ALIGNED(start)); + VM_BUG_ON(!PAGE_ALIGNED(end)); if (end - start < PAGES_PER_SECTION * sizeof(struct page)) err = vmemmap_populate_basepages(start, end, node, NULL); diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S index 854dd81804b7..9ffe2bad27d5 100644 --- a/arch/x86/platform/efi/efi_thunk_64.S +++ b/arch/x86/platform/efi/efi_thunk_64.S @@ -8,7 +8,7 @@ * The below thunking functions are only used after ExitBootServices() * has been called. This simplifies things considerably as compared with * the early EFI thunking because we can leave all the kernel state - * intact (GDT, IDT, etc) and simply invoke the the 32-bit EFI runtime + * intact (GDT, IDT, etc) and simply invoke the 32-bit EFI runtime * services from __KERNEL32_CS. This means we can continue to service * interrupts across an EFI mixed mode call. * diff --git a/arch/x86/um/ldt.c b/arch/x86/um/ldt.c index 3ee234b6234d..255a44dd415a 100644 --- a/arch/x86/um/ldt.c +++ b/arch/x86/um/ldt.c @@ -23,9 +23,11 @@ static long write_ldt_entry(struct mm_id *mm_idp, int func, { long res; void *stub_addr; + + BUILD_BUG_ON(sizeof(*desc) % sizeof(long)); + res = syscall_stub_data(mm_idp, (unsigned long *)desc, - (sizeof(*desc) + sizeof(long) - 1) & - ~(sizeof(long) - 1), + sizeof(*desc) / sizeof(long), addr, &stub_addr); if (!res) { unsigned long args[] = { func, diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 7e38292dd07a..68e0e2f06d66 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -263,10 +263,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) * involved. Much simpler to just not copy those live frames across. */ -int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn, - unsigned long thread_fn_arg, struct task_struct *p, - unsigned long tls) +int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + unsigned long clone_flags = args->flags; + unsigned long usp_thread_fn = args->stack; + unsigned long tls = args->tls; struct pt_regs *childregs = task_pt_regs(p); #if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) @@ -286,7 +287,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn, #error Unsupported Xtensa ABI #endif - if (!(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { + if (!args->fn) { struct pt_regs *regs = current_pt_regs(); unsigned long usp = usp_thread_fn ? usp_thread_fn : regs->areg[1]; @@ -338,15 +339,15 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn, * Window underflow will load registers from the * spill slots on the stack on return from _switch_to. */ - SPILL_SLOT(childregs, 2) = usp_thread_fn; - SPILL_SLOT(childregs, 3) = thread_fn_arg; + SPILL_SLOT(childregs, 2) = (unsigned long)args->fn; + SPILL_SLOT(childregs, 3) = (unsigned long)args->fn_arg; #elif defined(__XTENSA_CALL0_ABI__) /* * a12 = thread_fn, a13 = thread_fn arg. * _switch_to epilogue will load registers from the stack. */ - ((unsigned long *)p->thread.sp)[0] = usp_thread_fn; - ((unsigned long *)p->thread.sp)[1] = thread_fn_arg; + ((unsigned long *)p->thread.sp)[0] = (unsigned long)args->fn; + ((unsigned long *)p->thread.sp)[1] = (unsigned long)args->fn_arg; #else #error Unsupported Xtensa ABI #endif diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index 22cdaa6729d3..f29477162ede 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -224,12 +224,12 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) void user_enable_single_step(struct task_struct *child) { - child->ptrace |= PT_SINGLESTEP; + set_tsk_thread_flag(child, TIF_SINGLESTEP); } void user_disable_single_step(struct task_struct *child) { - child->ptrace &= ~PT_SINGLESTEP; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); } /* diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index c9ffd42db873..876d5df157ed 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -472,7 +472,7 @@ static void do_signal(struct pt_regs *regs) /* Set up the stack frame */ ret = setup_frame(&ksig, sigmask_to_save(), regs); signal_setup_done(ret, &ksig, 0); - if (current->ptrace & PT_SINGLESTEP) + if (test_thread_flag(TIF_SINGLESTEP)) task_pt_regs(current)->icountlevel = 1; return; @@ -498,7 +498,7 @@ static void do_signal(struct pt_regs *regs) /* If there's no signal to deliver, we just restore the saved mask. */ restore_saved_sigmask(); - if (current->ptrace & PT_SINGLESTEP) + if (test_thread_flag(TIF_SINGLESTEP)) task_pt_regs(current)->icountlevel = 1; return; } |