diff options
Diffstat (limited to 'arch')
432 files changed, 14344 insertions, 4754 deletions
diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c index 99e8d47..92c0d46 100644 --- a/arch/alpha/kernel/pci-sysfs.c +++ b/arch/alpha/kernel/pci-sysfs.c @@ -77,10 +77,10 @@ static int pci_mmap_resource(struct kobject *kobj, if (i >= PCI_ROM_RESOURCE) return -ENODEV; - if (!__pci_mmap_fits(pdev, i, vma, sparse)) + if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start)) return -EINVAL; - if (iomem_is_exclusive(res->start)) + if (!__pci_mmap_fits(pdev, i, vma, sparse)) return -EINVAL; pcibios_resource_to_bus(pdev->bus, &bar, res); diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index a876743..8894f7e 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -10,8 +10,9 @@ config ARC def_bool y select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC select BUILDTIME_EXTABLE_SORT - select COMMON_CLK + select CLKSRC_OF select CLONE_BACKWARDS + select COMMON_CLK select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS select GENERIC_FIND_FIRST_BIT @@ -30,6 +31,7 @@ config ARC select HAVE_MOD_ARCH_SPECIFIC if ARC_DW2_UNWIND select HAVE_OPROFILE select HAVE_PERF_EVENTS + select HANDLE_DOMAIN_IRQ select IRQ_DOMAIN select MODULES_USE_ELF_RELA select NO_BOOTMEM @@ -95,6 +97,7 @@ source "arch/arc/plat-sim/Kconfig" source "arch/arc/plat-tb10x/Kconfig" source "arch/arc/plat-axs10x/Kconfig" #New platform adds here +source "arch/arc/plat-eznps/Kconfig" endmenu @@ -490,6 +493,17 @@ config ARCH_DMA_ADDR_T_64BIT config ARC_PLAT_NEEDS_PHYS_TO_DMA bool +config ARC_KVADDR_SIZE + int "Kernel Virtaul Address Space size (MB)" + range 0 512 + default "256" + help + The kernel address space is carved out of 256MB of translated address + space for catering to vmalloc, modules, pkmap, fixmap. This however may + not suffice vmalloc requirements of a 4K CPU EZChip system. So allow + this to be stretched to 512 MB (by extending into the reserved + kernel-user gutter) + config ARC_CURR_IN_REG bool "Dedicate Register r25 for current_task pointer" default y diff --git a/arch/arc/Makefile b/arch/arc/Makefile index def69e3..02fabef 100644 --- a/arch/arc/Makefile +++ b/arch/arc/Makefile @@ -115,6 +115,11 @@ core-y += arch/arc/boot/dts/ core-$(CONFIG_ARC_PLAT_SIM) += arch/arc/plat-sim/ core-$(CONFIG_ARC_PLAT_TB10X) += arch/arc/plat-tb10x/ core-$(CONFIG_ARC_PLAT_AXS10X) += arch/arc/plat-axs10x/ +core-$(CONFIG_ARC_PLAT_EZNPS) += arch/arc/plat-eznps/ + +ifdef CONFIG_ARC_PLAT_EZNPS +KBUILD_CPPFLAGS += -I$(srctree)/arch/arc/plat-eznps/include +endif drivers-$(CONFIG_OPROFILE) += arch/arc/oprofile/ diff --git a/arch/arc/boot/dts/abilis_tb10x.dtsi b/arch/arc/boot/dts/abilis_tb10x.dtsi index cfb5052..de53f5c 100644 --- a/arch/arc/boot/dts/abilis_tb10x.dtsi +++ b/arch/arc/boot/dts/abilis_tb10x.dtsi @@ -35,6 +35,20 @@ }; }; + /* TIMER0 with interrupt for clockevent */ + timer0 { + compatible = "snps,arc-timer"; + interrupts = <3>; + interrupt-parent = <&intc>; + clocks = <&cpu_clk>; + }; + + /* TIMER1 for free running clocksource */ + timer1 { + compatible = "snps,arc-timer"; + clocks = <&cpu_clk>; + }; + soc100 { #address-cells = <1>; #size-cells = <1>; @@ -112,7 +126,7 @@ chan_allocation_order = <0>; chan_priority = <1>; block_size = <0x7ff>; - data_width = <2>; + data-width = <4>; clocks = <&ahb_clk>; clock-names = "hclk"; }; diff --git a/arch/arc/boot/dts/axc001.dtsi b/arch/arc/boot/dts/axc001.dtsi index 420dcfd..40bcecf 100644 --- a/arch/arc/boot/dts/axc001.dtsi +++ b/arch/arc/boot/dts/axc001.dtsi @@ -11,6 +11,8 @@ * Note that this file only supports the 770D CPU */ +/include/ "skeleton.dtsi" + / { compatible = "snps,arc"; clock-frequency = <750000000>; /* 750 MHZ */ @@ -24,7 +26,13 @@ ranges = <0x00000000 0xf0000000 0x10000000>; - cpu_intc: arc700-intc@cpu { + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <750000000>; + }; + + core_intc: arc700-intc@cpu { compatible = "snps,arc700-intc"; interrupt-controller; #interrupt-cells = <1>; @@ -48,7 +56,7 @@ reg = <0>; interrupt-controller; #interrupt-cells = <2>; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; interrupts = <15>; }; }; @@ -86,7 +94,7 @@ compatible = "snps,dw-apb-ictl"; reg = < 0xe0012000 0x200 >; interrupt-controller; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; interrupts = < 7 >; }; diff --git a/arch/arc/boot/dts/axc003.dtsi b/arch/arc/boot/dts/axc003.dtsi index f90fadf..cabe0de 100644 --- a/arch/arc/boot/dts/axc003.dtsi +++ b/arch/arc/boot/dts/axc003.dtsi @@ -10,6 +10,8 @@ * Device tree for AXC003 CPU card: HS38x UP configuration */ +/include/ "skeleton_hs.dtsi" + / { compatible = "snps,arc"; clock-frequency = <90000000>; @@ -23,7 +25,13 @@ ranges = <0x00000000 0xf0000000 0x10000000>; - cpu_intc: archs-intc@cpu { + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <90000000>; + }; + + core_intc: archs-intc@cpu { compatible = "snps,archs-intc"; interrupt-controller; #interrupt-cells = <1>; @@ -47,7 +55,7 @@ reg = <0>; interrupt-controller; #interrupt-cells = <2>; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; interrupts = <25>; }; }; @@ -66,7 +74,7 @@ arcpct0: pct { compatible = "snps,archs-pct"; #interrupt-cells = <1>; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; interrupts = <20>; }; }; @@ -89,7 +97,7 @@ compatible = "snps,dw-apb-ictl"; reg = < 0xe0012000 0x200 >; interrupt-controller; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; interrupts = < 24 >; }; diff --git a/arch/arc/boot/dts/axc003_idu.dtsi b/arch/arc/boot/dts/axc003_idu.dtsi index 06a9f29..ed1674b 100644 --- a/arch/arc/boot/dts/axc003_idu.dtsi +++ b/arch/arc/boot/dts/axc003_idu.dtsi @@ -10,6 +10,8 @@ * Device tree for AXC003 CPU card: HS38x2 (Dual Core) with IDU intc */ +/include/ "skeleton_hs_idu.dtsi" + / { compatible = "snps,arc"; clock-frequency = <90000000>; @@ -23,7 +25,13 @@ ranges = <0x00000000 0xf0000000 0x10000000>; - cpu_intc: archs-intc@cpu { + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <100000000>; + }; + + core_intc: archs-intc@cpu { compatible = "snps,archs-intc"; interrupt-controller; #interrupt-cells = <1>; @@ -32,7 +40,7 @@ idu_intc: idu-interrupt-controller { compatible = "snps,archs-idu-intc"; interrupt-controller; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; /* * <hwirq distribution> @@ -89,7 +97,7 @@ arcpct0: pct { compatible = "snps,archs-pct"; #interrupt-cells = <1>; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; interrupts = <20>; }; }; diff --git a/arch/arc/boot/dts/axs10x_mb.dtsi b/arch/arc/boot/dts/axs10x_mb.dtsi index 44a578c..68c84a2 100644 --- a/arch/arc/boot/dts/axs10x_mb.dtsi +++ b/arch/arc/boot/dts/axs10x_mb.dtsi @@ -16,7 +16,20 @@ ranges = <0x00000000 0xe0000000 0x10000000>; interrupt-parent = <&mb_intc>; + i2sclk: i2sclk@100a0 { + compatible = "snps,axs10x-i2s-pll-clock"; + reg = <0x100a0 0x10>; + clocks = <&i2spll_clk>; + #clock-cells = <0>; + }; + clocks { + i2spll_clk: i2spll_clk { + compatible = "fixed-clock"; + clock-frequency = <27000000>; + #clock-cells = <0>; + }; + i2cclk: i2cclk { compatible = "fixed-clock"; clock-frequency = <50000000>; diff --git a/arch/arc/boot/dts/eznps.dts b/arch/arc/boot/dts/eznps.dts new file mode 100644 index 0000000..b89f6c3 --- /dev/null +++ b/arch/arc/boot/dts/eznps.dts @@ -0,0 +1,96 @@ +/* + * Copyright(c) 2015 EZchip Technologies. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +/dts-v1/; + +/ { + compatible = "ezchip,arc-nps"; + clock-frequency = <83333333>; /* 83.333333 MHZ */ + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + present-cpus = "0-1,16-17"; + possible-cpus = "0-4095"; + + aliases { + ethernet0 = &gmac0; + }; + + chosen { + bootargs = "earlycon=uart8250,mmio32be,0xf7209000,115200n8 console=ttyS0,115200n8"; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x20000000>; /* 512M */ + }; + + clocks { + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <83333333>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + /* child and parent address space 1:1 mapped */ + ranges; + + intc: interrupt-controller { + compatible = "ezchip,nps400-ic"; + interrupt-controller; + #interrupt-cells = <1>; + }; + + timer0: timer_clkevt { + compatible = "snps,arc-timer"; + interrupts = <3>; + clocks = <&sysclk>; + }; + + timer1: timer_clksrc { + compatible = "ezchip,nps400-timer"; + clocks = <&sysclk>; + clock-names="sysclk"; + }; + + uart@f7209000 { + compatible = "snps,dw-apb-uart"; + device_type = "serial"; + reg = <0xf7209000 0x100>; + interrupts = <6>; + clocks = <&sysclk>; + clock-names="baudclk"; + baud = <115200>; + reg-shift = <2>; + reg-io-width = <4>; + native-endian; + }; + + gmac0: ethernet@f7470000 { + compatible = "ezchip,nps-mgt-enet"; + reg = <0xf7470000 0x1940>; + interrupts = <7>; + /* Filled in by U-Boot */ + mac-address = [ 00 C0 00 F0 04 03 ]; + }; + }; +}; diff --git a/arch/arc/boot/dts/nsim_700.dts b/arch/arc/boot/dts/nsim_700.dts index 105a001..5d5e373 100644 --- a/arch/arc/boot/dts/nsim_700.dts +++ b/arch/arc/boot/dts/nsim_700.dts @@ -14,7 +14,7 @@ clock-frequency = <80000000>; /* 80 MHZ */ #address-cells = <1>; #size-cells = <1>; - interrupt-parent = <&intc>; + interrupt-parent = <&core_intc>; chosen { bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8"; @@ -32,7 +32,13 @@ /* child and parent address space 1:1 mapped */ ranges; - intc: interrupt-controller { + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <80000000>; + }; + + core_intc: interrupt-controller { compatible = "snps,arc700-intc"; interrupt-controller; #interrupt-cells = <1>; diff --git a/arch/arc/boot/dts/nsim_hs.dts b/arch/arc/boot/dts/nsim_hs.dts index f46633e..bf05fe5 100644 --- a/arch/arc/boot/dts/nsim_hs.dts +++ b/arch/arc/boot/dts/nsim_hs.dts @@ -7,7 +7,7 @@ */ /dts-v1/; -/include/ "skeleton.dtsi" +/include/ "skeleton_hs.dtsi" / { compatible = "snps,nsim_hs"; @@ -39,6 +39,12 @@ bus addr, parent bus addr, size */ ranges = <0x80000000 0x0 0x80000000 0x80000000>; + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <80000000>; + }; + core_intc: core-interrupt-controller { compatible = "snps,archs-intc"; interrupt-controller; diff --git a/arch/arc/boot/dts/nsim_hs_idu.dts b/arch/arc/boot/dts/nsim_hs_idu.dts index 46ab319..99eabe1 100644 --- a/arch/arc/boot/dts/nsim_hs_idu.dts +++ b/arch/arc/boot/dts/nsim_hs_idu.dts @@ -7,7 +7,7 @@ */ /dts-v1/; -/include/ "skeleton.dtsi" +/include/ "skeleton_hs_idu.dtsi" / { compatible = "snps,nsim_hs"; @@ -29,6 +29,12 @@ /* child and parent address space 1:1 mapped */ ranges; + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <80000000>; + }; + core_intc: core-interrupt-controller { compatible = "snps,archs-intc"; interrupt-controller; diff --git a/arch/arc/boot/dts/nsimosci.dts b/arch/arc/boot/dts/nsimosci.dts index d94b4ce..b5b060a 100644 --- a/arch/arc/boot/dts/nsimosci.dts +++ b/arch/arc/boot/dts/nsimosci.dts @@ -14,7 +14,7 @@ clock-frequency = <20000000>; /* 20 MHZ */ #address-cells = <1>; #size-cells = <1>; - interrupt-parent = <&intc>; + interrupt-parent = <&core_intc>; chosen { /* this is for console on PGU */ @@ -35,7 +35,13 @@ /* child and parent address space 1:1 mapped */ ranges; - intc: interrupt-controller { + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <20000000>; + }; + + core_intc: interrupt-controller { compatible = "snps,arc700-intc"; interrupt-controller; #interrupt-cells = <1>; diff --git a/arch/arc/boot/dts/nsimosci_hs.dts b/arch/arc/boot/dts/nsimosci_hs.dts index 034a313..325e730 100644 --- a/arch/arc/boot/dts/nsimosci_hs.dts +++ b/arch/arc/boot/dts/nsimosci_hs.dts @@ -7,7 +7,7 @@ */ /dts-v1/; -/include/ "skeleton.dtsi" +/include/ "skeleton_hs.dtsi" / { compatible = "snps,nsimosci_hs"; @@ -35,6 +35,12 @@ /* child and parent address space 1:1 mapped */ ranges; + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <20000000>; + }; + core_intc: core-interrupt-controller { compatible = "snps,archs-intc"; interrupt-controller; diff --git a/arch/arc/boot/dts/nsimosci_hs_idu.dts b/arch/arc/boot/dts/nsimosci_hs_idu.dts index 8a1297e..ee03d71 100644 --- a/arch/arc/boot/dts/nsimosci_hs_idu.dts +++ b/arch/arc/boot/dts/nsimosci_hs_idu.dts @@ -7,7 +7,7 @@ */ /dts-v1/; -/include/ "skeleton.dtsi" +/include/ "skeleton_hs_idu.dtsi" / { compatible = "snps,nsimosci_hs"; @@ -33,6 +33,12 @@ /* child and parent address space 1:1 mapped */ ranges; + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <5000000>; + }; + core_intc: core-interrupt-controller { compatible = "snps,archs-intc"; interrupt-controller; diff --git a/arch/arc/boot/dts/skeleton.dtsi b/arch/arc/boot/dts/skeleton.dtsi index 296d371..3a10cc6 100644 --- a/arch/arc/boot/dts/skeleton.dtsi +++ b/arch/arc/boot/dts/skeleton.dtsi @@ -30,6 +30,20 @@ }; }; + /* TIMER0 with interrupt for clockevent */ + timer0 { + compatible = "snps,arc-timer"; + interrupts = <3>; + interrupt-parent = <&core_intc>; + clocks = <&core_clk>; + }; + + /* TIMER1 for free running clocksource */ + timer1 { + compatible = "snps,arc-timer"; + clocks = <&core_clk>; + }; + memory { device_type = "memory"; reg = <0x80000000 0x10000000>; /* 256M */ diff --git a/arch/arc/boot/dts/skeleton_hs.dtsi b/arch/arc/boot/dts/skeleton_hs.dtsi new file mode 100644 index 0000000..71fd308 --- /dev/null +++ b/arch/arc/boot/dts/skeleton_hs.dtsi @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/ { + compatible = "snps,arc"; + clock-frequency = <80000000>; /* 80 MHZ */ + #address-cells = <1>; + #size-cells = <1>; + chosen { }; + aliases { }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "snps,archs38"; + reg = <0>; + }; + }; + + /* TIMER0 with interrupt for clockevent */ + timer0 { + compatible = "snps,arc-timer"; + interrupts = <16>; + interrupt-parent = <&core_intc>; + clocks = <&core_clk>; + }; + + /* 64-bit Local RTC: preferred clocksource for UP */ + rtc { + compatible = "snps,archs-timer-rtc"; + clocks = <&core_clk>; + }; + + /* TIMER1 for free running clocksource: Fallback if rtc not found */ + timer1 { + compatible = "snps,arc-timer"; + clocks = <&core_clk>; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x10000000>; /* 256M */ + }; +}; diff --git a/arch/arc/boot/dts/skeleton_hs_idu.dtsi b/arch/arc/boot/dts/skeleton_hs_idu.dtsi new file mode 100644 index 0000000..d1cb25a --- /dev/null +++ b/arch/arc/boot/dts/skeleton_hs_idu.dtsi @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/ { + compatible = "snps,arc"; + clock-frequency = <80000000>; /* 80 MHZ */ + #address-cells = <1>; + #size-cells = <1>; + chosen { }; + aliases { }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "snps,archs38xN"; + reg = <0>; + }; + }; + + /* TIMER0 with interrupt for clockevent */ + timer0 { + compatible = "snps,arc-timer"; + interrupts = <16>; + interrupt-parent = <&core_intc>; + clocks = <&core_clk>; + }; + + /* 64-bit Global Free Running Counter */ + gfrc { + compatible = "snps,archs-timer-gfrc"; + clocks = <&core_clk>; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x10000000>; /* 256M */ + }; +}; diff --git a/arch/arc/boot/dts/vdk_axc003.dtsi b/arch/arc/boot/dts/vdk_axc003.dtsi index 84226bd..ad4ee43 100644 --- a/arch/arc/boot/dts/vdk_axc003.dtsi +++ b/arch/arc/boot/dts/vdk_axc003.dtsi @@ -10,6 +10,8 @@ * Device tree for AXC003 CPU card: HS38x UP configuration (VDK version) */ +/include/ "skeleton_hs.dtsi" + / { compatible = "snps,arc"; clock-frequency = <50000000>; @@ -23,7 +25,13 @@ ranges = <0x00000000 0xf0000000 0x10000000>; - cpu_intc: archs-intc@cpu { + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <50000000>; + }; + + core_intc: archs-intc@cpu { compatible = "snps,archs-intc"; interrupt-controller; #interrupt-cells = <1>; @@ -33,7 +41,7 @@ compatible = "snps,dw-apb-uart"; reg = <0x5000 0x100>; clock-frequency = <2403200>; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; interrupts = <19>; baud = <115200>; reg-shift = <2>; @@ -47,7 +55,7 @@ compatible = "snps,dw-apb-ictl"; reg = < 0xe0012000 0x200 >; interrupt-controller; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; interrupts = < 18 >; }; diff --git a/arch/arc/boot/dts/vdk_axc003_idu.dtsi b/arch/arc/boot/dts/vdk_axc003_idu.dtsi index 31f0fb5..a3cb626 100644 --- a/arch/arc/boot/dts/vdk_axc003_idu.dtsi +++ b/arch/arc/boot/dts/vdk_axc003_idu.dtsi @@ -11,6 +11,8 @@ * HS38x2 (Dual Core) with IDU intc (VDK version) */ +/include/ "skeleton_hs_idu.dtsi" + / { compatible = "snps,arc"; clock-frequency = <50000000>; @@ -24,7 +26,13 @@ ranges = <0x00000000 0xf0000000 0x10000000>; - cpu_intc: archs-intc@cpu { + core_clk: core_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <50000000>; + }; + + core_intc: archs-intc@cpu { compatible = "snps,archs-intc"; interrupt-controller; #interrupt-cells = <1>; @@ -33,7 +41,7 @@ idu_intc: idu-interrupt-controller { compatible = "snps,archs-idu-intc"; interrupt-controller; - interrupt-parent = <&cpu_intc>; + interrupt-parent = <&core_intc>; /* * <hwirq distribution> diff --git a/arch/arc/configs/nps_defconfig b/arch/arc/configs/nps_defconfig new file mode 100644 index 0000000..ede625c --- /dev/null +++ b/arch/arc/configs/nps_defconfig @@ -0,0 +1,84 @@ +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_EPOLL is not set +# CONFIG_SIGNALFD is not set +# CONFIG_TIMERFD is not set +# CONFIG_EVENTFD is not set +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_KPROBES=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARC_PLAT_EZNPS=y +CONFIG_SMP=y +CONFIG_NR_CPUS=4096 +CONFIG_ARC_CACHE_LINE_SHIFT=5 +# CONFIG_ARC_CACHE_PAGES is not set +# CONFIG_ARC_HAS_LLSC is not set +CONFIG_ARC_KVADDR_SIZE=402 +CONFIG_ARC_EMUL_UNALIGNED=y +CONFIG_ARC_UBOOT_SUPPORT=y +CONFIG_PREEMPT=y +CONFIG_NET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +# CONFIG_IPV6 is not set +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=1 +CONFIG_BLK_DEV_RAM_SIZE=2048 +CONFIG_NETDEVICES=y +CONFIG_NETCONSOLE=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=1 +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_DNOTIFY is not set +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_ENABLE_DEFAULT_TRACERS=y diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 7730d30..5f3dcbb 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -17,6 +17,8 @@ #include <asm/barrier.h> #include <asm/smp.h> +#ifndef CONFIG_ARC_PLAT_EZNPS + #define atomic_read(v) READ_ONCE((v)->counter) #ifdef CONFIG_ARC_HAS_LLSC @@ -180,13 +182,88 @@ ATOMIC_OP(andnot, &= ~, bic) ATOMIC_OP(or, |=, or) ATOMIC_OP(xor, ^=, xor) -#undef ATOMIC_OPS -#undef ATOMIC_OP_RETURN -#undef ATOMIC_OP #undef SCOND_FAIL_RETRY_VAR_DEF #undef SCOND_FAIL_RETRY_ASM #undef SCOND_FAIL_RETRY_VARS +#else /* CONFIG_ARC_PLAT_EZNPS */ + +static inline int atomic_read(const atomic_t *v) +{ + int temp; + + __asm__ __volatile__( + " ld.di %0, [%1]" + : "=r"(temp) + : "r"(&v->counter) + : "memory"); + return temp; +} + +static inline void atomic_set(atomic_t *v, int i) +{ + __asm__ __volatile__( + " st.di %0,[%1]" + : + : "r"(i), "r"(&v->counter) + : "memory"); +} + +#define ATOMIC_OP(op, c_op, asm_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + __asm__ __volatile__( \ + " mov r2, %0\n" \ + " mov r3, %1\n" \ + " .word %2\n" \ + : \ + : "r"(i), "r"(&v->counter), "i"(asm_op) \ + : "r2", "r3", "memory"); \ +} \ + +#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned int temp = i; \ + \ + /* Explicit full memory barrier needed before/after */ \ + smp_mb(); \ + \ + __asm__ __volatile__( \ + " mov r2, %0\n" \ + " mov r3, %1\n" \ + " .word %2\n" \ + " mov %0, r2" \ + : "+r"(temp) \ + : "r"(&v->counter), "i"(asm_op) \ + : "r2", "r3", "memory"); \ + \ + smp_mb(); \ + \ + temp c_op i; \ + \ + return temp; \ +} + +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_OP_RETURN(op, c_op, asm_op) + +ATOMIC_OPS(add, +=, CTOP_INST_AADD_DI_R2_R2_R3) +#define atomic_sub(i, v) atomic_add(-(i), (v)) +#define atomic_sub_return(i, v) atomic_add_return(-(i), (v)) + +ATOMIC_OP(and, &=, CTOP_INST_AAND_DI_R2_R2_R3) +#define atomic_andnot(mask, v) atomic_and(~(mask), (v)) +ATOMIC_OP(or, |=, CTOP_INST_AOR_DI_R2_R2_R3) +ATOMIC_OP(xor, ^=, CTOP_INST_AXOR_DI_R2_R2_R3) + +#endif /* CONFIG_ARC_PLAT_EZNPS */ + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + /** * __atomic_add_unless - add unless the number is a given value * @v: pointer of type atomic_t diff --git a/arch/arc/include/asm/barrier.h b/arch/arc/include/asm/barrier.h index a720998..b1e3274 100644 --- a/arch/arc/include/asm/barrier.h +++ b/arch/arc/include/asm/barrier.h @@ -30,9 +30,7 @@ #define rmb() asm volatile("dmb 1\n" : : : "memory") #define wmb() asm volatile("dmb 2\n" : : : "memory") -#endif - -#ifdef CONFIG_ISA_ARCOMPACT +#elif !defined(CONFIG_ARC_PLAT_EZNPS) /* CONFIG_ISA_ARCOMPACT */ /* * ARCompact based cores (ARC700) only have SYNC instruction which is super @@ -41,6 +39,14 @@ */ #define mb() asm volatile("sync\n" : : : "memory") + +#else /* CONFIG_ARC_PLAT_EZNPS */ + +#include <plat/ctop.h> + +#define mb() asm volatile (".word %0" : : "i"(CTOP_INST_SCHD_RW) : "memory") +#define rmb() asm volatile (".word %0" : : "i"(CTOP_INST_SCHD_RD) : "memory") + #endif #include <asm-generic/barrier.h> diff --git a/arch/arc/include/asm/bitops.h b/arch/arc/include/asm/bitops.h index 0352fb8..8da87fe 100644 --- a/arch/arc/include/asm/bitops.h +++ b/arch/arc/include/asm/bitops.h @@ -22,7 +22,7 @@ #include <asm/smp.h> #endif -#if defined(CONFIG_ARC_HAS_LLSC) +#ifdef CONFIG_ARC_HAS_LLSC /* * Hardware assisted Atomic-R-M-W @@ -88,7 +88,7 @@ static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long * return (old & (1 << nr)) != 0; \ } -#else /* !CONFIG_ARC_HAS_LLSC */ +#elif !defined(CONFIG_ARC_PLAT_EZNPS) /* * Non hardware assisted Atomic-R-M-W @@ -139,7 +139,55 @@ static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long * return (old & (1UL << (nr & 0x1f))) != 0; \ } -#endif /* CONFIG_ARC_HAS_LLSC */ +#else /* CONFIG_ARC_PLAT_EZNPS */ + +#define BIT_OP(op, c_op, asm_op) \ +static inline void op##_bit(unsigned long nr, volatile unsigned long *m)\ +{ \ + m += nr >> 5; \ + \ + nr = (1UL << (nr & 0x1f)); \ + if (asm_op == CTOP_INST_AAND_DI_R2_R2_R3) \ + nr = ~nr; \ + \ + __asm__ __volatile__( \ + " mov r2, %0\n" \ + " mov r3, %1\n" \ + " .word %2\n" \ + : \ + : "r"(nr), "r"(m), "i"(asm_op) \ + : "r2", "r3", "memory"); \ +} + +#define TEST_N_BIT_OP(op, c_op, asm_op) \ +static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *m)\ +{ \ + unsigned long old; \ + \ + m += nr >> 5; \ + \ + nr = old = (1UL << (nr & 0x1f)); \ + if (asm_op == CTOP_INST_AAND_DI_R2_R2_R3) \ + old = ~old; \ + \ + /* Explicit full memory barrier needed before/after */ \ + smp_mb(); \ + \ + __asm__ __volatile__( \ + " mov r2, %0\n" \ + " mov r3, %1\n" \ + " .word %2\n" \ + " mov %0, r2" \ + : "+r"(old) \ + : "r"(m), "i"(asm_op) \ + : "r2", "r3", "memory"); \ + \ + smp_mb(); \ + \ + return (old & nr) != 0; \ +} + +#endif /* CONFIG_ARC_PLAT_EZNPS */ /*************************************** * Non atomic variants @@ -181,9 +229,15 @@ static inline int __test_and_##op##_bit(unsigned long nr, volatile unsigned long /* __test_and_set_bit(), __test_and_clear_bit(), __test_and_change_bit() */\ __TEST_N_BIT_OP(op, c_op, asm_op) +#ifndef CONFIG_ARC_PLAT_EZNPS BIT_OPS(set, |, bset) BIT_OPS(clear, & ~, bclr) BIT_OPS(change, ^, bxor) +#else +BIT_OPS(set, |, CTOP_INST_AOR_DI_R2_R2_R3) +BIT_OPS(clear, & ~, CTOP_INST_AAND_DI_R2_R2_R3) +BIT_OPS(change, ^, CTOP_INST_AXOR_DI_R2_R2_R3) +#endif /* * This routine doesn't need to be atomic. diff --git a/arch/arc/include/asm/clk.h b/arch/arc/include/asm/clk.h deleted file mode 100644 index bf9d29f..0000000 --- a/arch/arc/include/asm/clk.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _ASM_ARC_CLK_H -#define _ASM_ARC_CLK_H - -/* Although we can't really hide core_freq, the accessor is still better way */ -extern unsigned long core_freq; - -static inline unsigned long arc_get_core_freq(void) -{ - return core_freq; -} - -extern int arc_set_core_freq(unsigned long); - -#endif diff --git a/arch/arc/include/asm/cmpxchg.h b/arch/arc/include/asm/cmpxchg.h index a444be6..d819de1 100644 --- a/arch/arc/include/asm/cmpxchg.h +++ b/arch/arc/include/asm/cmpxchg.h @@ -44,7 +44,7 @@ __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new) return prev; } -#else +#elif !defined(CONFIG_ARC_PLAT_EZNPS) static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new) @@ -64,23 +64,48 @@ __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new) return prev; } +#else /* CONFIG_ARC_PLAT_EZNPS */ + +static inline unsigned long +__cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new) +{ + /* + * Explicit full memory barrier needed before/after + */ + smp_mb(); + + write_aux_reg(CTOP_AUX_GPA1, expected); + + __asm__ __volatile__( + " mov r2, %0\n" + " mov r3, %1\n" + " .word %2\n" + " mov %0, r2" + : "+r"(new) + : "r"(ptr), "i"(CTOP_INST_EXC_DI_R2_R2_R3) + : "r2", "r3", "memory"); + + smp_mb(); + + return new; +} + #endif /* CONFIG_ARC_HAS_LLSC */ #define cmpxchg(ptr, o, n) ((typeof(*(ptr)))__cmpxchg((ptr), \ (unsigned long)(o), (unsigned long)(n))) /* - * Since not supported natively, ARC cmpxchg() uses atomic_ops_lock (UP/SMP) - * just to gaurantee semantics. - * atomic_cmpxchg() needs to use the same locks as it's other atomic siblings - * which also happens to be atomic_ops_lock. - * - * Thus despite semantically being different, implementation of atomic_cmpxchg() - * is same as cmpxchg(). + * atomic_cmpxchg is same as cmpxchg + * LLSC: only different in data-type, semantics are exactly same + * !LLSC: cmpxchg() has to use an external lock atomic_ops_lock to guarantee + * semantics, and this lock also happens to be used by atomic_*() */ #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) +#ifndef CONFIG_ARC_PLAT_EZNPS + /* * xchg (reg with memory) based on "Native atomic" EX insn */ @@ -143,6 +168,41 @@ static inline unsigned long __xchg(unsigned long val, volatile void *ptr, #endif +#else /* CONFIG_ARC_PLAT_EZNPS */ + +static inline unsigned long __xchg(unsigned long val, volatile void *ptr, + int size) +{ + extern unsigned long __xchg_bad_pointer(void); + + switch (size) { + case 4: + /* + * Explicit full memory barrier needed before/after + */ + smp_mb(); + + __asm__ __volatile__( + " mov r2, %0\n" + " mov r3, %1\n" + " .word %2\n" + " mov %0, r2\n" + : "+r"(val) + : "r"(ptr), "i"(CTOP_INST_XEX_DI_R2_R2_R3) + : "r2", "r3", "memory"); + + smp_mb(); + + return val; + } + return __xchg_bad_pointer(); +} + +#define xchg(ptr, with) ((typeof(*(ptr)))__xchg((unsigned long)(with), (ptr), \ + sizeof(*(ptr)))) + +#endif /* CONFIG_ARC_PLAT_EZNPS */ + /* * "atomic" variant of xchg() * REQ: It needs to follow the same serialization rules as other atomic_xxx() diff --git a/arch/arc/include/asm/entry-compact.h b/arch/arc/include/asm/entry-compact.h index 1d8f57c..e0e1faf0 100644 --- a/arch/arc/include/asm/entry-compact.h +++ b/arch/arc/include/asm/entry-compact.h @@ -36,6 +36,10 @@ #include <asm/irqflags-compact.h> #include <asm/thread_info.h> /* For THREAD_SIZE */ +#ifdef CONFIG_ARC_PLAT_EZNPS +#include <plat/ctop.h> +#endif + /*-------------------------------------------------------------- * Switch to Kernel Mode stack if SP points to User Mode stack * @@ -296,11 +300,13 @@ bic \reg, sp, (THREAD_SIZE - 1) .endm +#ifndef CONFIG_ARC_PLAT_EZNPS /* Get CPU-ID of this core */ .macro GET_CPU_ID reg lr \reg, [identity] lsr \reg, \reg, 8 bmsk \reg, \reg, 7 .endm +#endif #endif /* __ASM_ARC_ENTRY_COMPACT_H */ diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index 49014f0..c0fa0d2 100644 --- a/arch/arc/include/asm/irq.h +++ b/arch/arc/include/asm/irq.h @@ -13,21 +13,14 @@ #define NR_IRQS 128 /* allow some CPU external IRQ handling */ /* Platform Independent IRQs */ -#ifdef CONFIG_ISA_ARCOMPACT -#define TIMER0_IRQ 3 -#define TIMER1_IRQ 4 -#else -#define TIMER0_IRQ 16 -#define TIMER1_IRQ 17 +#ifdef CONFIG_ISA_ARCV2 +#define IPI_IRQ 19 +#define SOFTIRQ_IRQ 21 #endif #include <linux/interrupt.h> #include <asm-generic/irq.h> extern void arc_init_IRQ(void); -void arc_local_timer_setup(void); -void arc_request_percpu_irq(int irq, int cpu, - irqreturn_t (*isr)(int irq, void *dev), - const char *irq_nm, void *percpu_dev); #endif diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 0d53854..296c342 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -31,7 +31,11 @@ void clear_user_page(void *to, unsigned long u_vaddr, struct page *page); * These are used to make use of C type-checking.. */ typedef struct { +#ifdef CONFIG_ARC_HAS_PAE40 + unsigned long long pte; +#else unsigned long pte; +#endif } pte_t; typedef struct { unsigned long pgd; diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 10d4b8b..034bbdc 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -217,7 +217,7 @@ #define BITS_FOR_PTE (PGDIR_SHIFT - PAGE_SHIFT) #define BITS_FOR_PGD (32 - PGDIR_SHIFT) -#define PGDIR_SIZE (1UL << PGDIR_SHIFT) /* vaddr span, not PDG sz */ +#define PGDIR_SIZE _BITUL(PGDIR_SHIFT) /* vaddr span, not PDG sz */ #define PGDIR_MASK (~(PGDIR_SIZE-1)) #define PTRS_PER_PTE _BITUL(BITS_FOR_PTE) diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h index 1d694c1..f9048994 100644 --- a/arch/arc/include/asm/processor.h +++ b/arch/arc/include/asm/processor.h @@ -57,9 +57,19 @@ struct task_struct; * A lot of busy-wait loops in SMP are based off of non-volatile data otherwise * get optimised away by gcc */ -#define cpu_relax() __asm__ __volatile__ ("" : : : "memory") +#ifndef CONFIG_EZNPS_MTM_EXT -#define cpu_relax_lowlatency() cpu_relax() +#define cpu_relax() barrier() +#define cpu_relax_lowlatency() cpu_relax() + +#else + +#define cpu_relax() \ + __asm__ __volatile__ (".word %0" : : "i"(CTOP_INST_SCHD_RW) : "memory") + +#define cpu_relax_lowlatency() barrier() + +#endif #define copy_segments(tsk, mm) do { } while (0) #define release_segments(mm) do { } while (0) @@ -97,7 +107,7 @@ extern unsigned int get_wchan(struct task_struct *p); #endif /* !__ASSEMBLY__ */ /* - * System Memory Map on ARC + * Default System Memory Map on ARC * * ---------------------------- (lower 2G, Translated) ------------------------- * 0x0000_0000 0x5FFF_FFFF (user vaddr: TASK_SIZE) @@ -109,20 +119,37 @@ extern unsigned int get_wchan(struct task_struct *p); * 0xC000_0000 0xFFFF_FFFF (peripheral uncached space) * ----------------------------------------------------------------------------- */ -#define VMALLOC_START 0x70000000 -/* - * 1 PGDIR_SIZE each for fixmap/pkmap, 2 PGDIR_SIZE gutter - * See asm/highmem.h for details - */ -#define VMALLOC_SIZE (PAGE_OFFSET - VMALLOC_START - PGDIR_SIZE * 4) -#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE) +#define TASK_SIZE 0x60000000 -#define USER_KERNEL_GUTTER 0x10000000 +#define VMALLOC_START (PAGE_OFFSET - (CONFIG_ARC_KVADDR_SIZE << 20)) -#define TASK_SIZE (VMALLOC_START - USER_KERNEL_GUTTER) +/* 1 PGDIR_SIZE each for fixmap/pkmap, 2 PGDIR_SIZE gutter (see asm/highmem.h) */ +#define VMALLOC_SIZE ((CONFIG_ARC_KVADDR_SIZE << 20) - PGDIR_SIZE * 4) +#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE) + +#define USER_KERNEL_GUTTER (VMALLOC_START - TASK_SIZE) + +#ifdef CONFIG_ARC_PLAT_EZNPS +/* NPS architecture defines special window of 129M in user address space for + * special memory areas, when accessing this window the MMU do not use TLB. + * Instead MMU direct the access to: + * 0x57f00000:0x57ffffff -- 1M of closely coupled memory (aka CMEM) + * 0x58000000:0x5fffffff -- 16 huge pages, 8M each, with fixed map (aka FMTs) + * + * CMEM - is the fastest memory we got and its size is 16K. + * FMT - is used to map either to internal/external memory. + * Internal memory is the second fast memory and its size is 16M + * External memory is the biggest memory (16G) and also the slowest. + * + * STACK_TOP need to be PMD align (21bit) that is why we supply 0x57e00000. + */ +#define STACK_TOP 0x57e00000 +#else #define STACK_TOP TASK_SIZE +#endif + #define STACK_TOP_MAX STACK_TOP /* This decides where the kernel will search for a free chunk of vm diff --git a/arch/arc/include/asm/setup.h b/arch/arc/include/asm/setup.h index 3078466..48b37c6 100644 --- a/arch/arc/include/asm/setup.h +++ b/arch/arc/include/asm/setup.h @@ -12,7 +12,11 @@ #include <linux/types.h> #include <uapi/asm/setup.h> +#ifdef CONFIG_ARC_PLAT_EZNPS +#define COMMAND_LINE_SIZE 2048 +#else #define COMMAND_LINE_SIZE 256 +#endif /* * Data structure to map a ID to string diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h index db8c59d..800e7c4 100644 --- a/arch/arc/include/asm/spinlock.h +++ b/arch/arc/include/asm/spinlock.h @@ -610,7 +610,9 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) static inline int arch_read_trylock(arch_rwlock_t *rw) { int ret = 0; + unsigned long flags; + local_irq_save(flags); arch_spin_lock(&(rw->lock_mutex)); /* @@ -623,6 +625,7 @@ static inline int arch_read_trylock(arch_rwlock_t *rw) } arch_spin_unlock(&(rw->lock_mutex)); + local_irq_restore(flags); smp_mb(); return ret; @@ -632,7 +635,9 @@ static inline int arch_read_trylock(arch_rwlock_t *rw) static inline int arch_write_trylock(arch_rwlock_t *rw) { int ret = 0; + unsigned long flags; + local_irq_save(flags); arch_spin_lock(&(rw->lock_mutex)); /* @@ -646,6 +651,7 @@ static inline int arch_write_trylock(arch_rwlock_t *rw) ret = 1; } arch_spin_unlock(&(rw->lock_mutex)); + local_irq_restore(flags); return ret; } @@ -664,16 +670,24 @@ static inline void arch_write_lock(arch_rwlock_t *rw) static inline void arch_read_unlock(arch_rwlock_t *rw) { + unsigned long flags; + + local_irq_save(flags); arch_spin_lock(&(rw->lock_mutex)); rw->counter++; arch_spin_unlock(&(rw->lock_mutex)); + local_irq_restore(flags); } static inline void arch_write_unlock(arch_rwlock_t *rw) { + unsigned long flags; + + local_irq_save(flags); arch_spin_lock(&(rw->lock_mutex)); rw->counter = __ARCH_RW_LOCK_UNLOCKED__; arch_spin_unlock(&(rw->lock_mutex)); + local_irq_restore(flags); } #endif diff --git a/arch/arc/include/uapi/asm/byteorder.h b/arch/arc/include/uapi/asm/byteorder.h index 9da71d4..ea5ca444 100644 --- a/arch/arc/include/uapi/asm/byteorder.h +++ b/arch/arc/include/uapi/asm/byteorder.h @@ -9,7 +9,7 @@ #ifndef __ASM_ARC_BYTEORDER_H #define __ASM_ARC_BYTEORDER_H -#ifdef CONFIG_CPU_BIG_ENDIAN +#ifdef __BIG_ENDIAN__ #include <linux/byteorder/big_endian.h> #else #include <linux/byteorder/little_endian.h> diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index 1bc2036..cfcdedf 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile @@ -9,7 +9,7 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o -obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o clk.o +obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o obj-$(CONFIG_PCI) += pcibios.o diff --git a/arch/arc/kernel/clk.c b/arch/arc/kernel/clk.c deleted file mode 100644 index 10c7b0b..0000000 --- a/arch/arc/kernel/clk.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <asm/clk.h> - -unsigned long core_freq = 80000000; - -/* - * As of now we default to device-tree provided clock - * In future we can determine this in early boot - */ -int arc_set_core_freq(unsigned long freq) -{ - core_freq = freq; - return 0; -} diff --git a/arch/arc/kernel/ctx_sw.c b/arch/arc/kernel/ctx_sw.c index 5d446df..6f4cb0d 100644 --- a/arch/arc/kernel/ctx_sw.c +++ b/arch/arc/kernel/ctx_sw.c @@ -16,6 +16,9 @@ #include <asm/asm-offsets.h> #include <linux/sched.h> +#ifdef CONFIG_ARC_PLAT_EZNPS +#include <plat/ctop.h> +#endif #define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4) @@ -67,9 +70,16 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task) #ifndef CONFIG_SMP "st %2, [@_current_task] \n\t" #else +#ifdef CONFIG_ARC_PLAT_EZNPS + "lr r24, [%4] \n\t" +#ifndef CONFIG_EZNPS_MTM_EXT + "lsr r24, r24, 4 \n\t" +#endif +#else "lr r24, [identity] \n\t" "lsr r24, r24, 8 \n\t" "bmsk r24, r24, 7 \n\t" +#endif "add2 r24, @_current_task, r24 \n\t" "st %2, [r24] \n\t" #endif @@ -107,6 +117,9 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task) : "=r"(tmp) : "n"(KSP_WORD_OFF), "r"(next), "r"(prev) +#ifdef CONFIG_ARC_PLAT_EZNPS + , "i"(CTOP_AUX_LOGIC_GLOBAL_ID) +#endif : "blink" ); diff --git a/arch/arc/kernel/devtree.c b/arch/arc/kernel/devtree.c index 7e844fd..f1e07c2 100644 --- a/arch/arc/kernel/devtree.c +++ b/arch/arc/kernel/devtree.c @@ -14,7 +14,6 @@ #include <linux/memblock.h> #include <linux/of.h> #include <linux/of_fdt.h> -#include <asm/clk.h> #include <asm/mach_desc.h> #ifdef CONFIG_SERIAL_EARLYCON @@ -28,14 +27,12 @@ unsigned int __init arc_early_base_baud(void) static void __init arc_set_early_base_baud(unsigned long dt_root) { - unsigned int core_clk = arc_get_core_freq(); - if (of_flat_dt_is_compatible(dt_root, "abilis,arc-tb10x")) - arc_base_baud = core_clk/3; + arc_base_baud = 166666666; /* Fixed 166.6MHz clk (TB10x) */ else if (of_flat_dt_is_compatible(dt_root, "snps,arc-sdp")) arc_base_baud = 33333333; /* Fixed 33MHz clk (AXS10x) */ else - arc_base_baud = core_clk; + arc_base_baud = 50000000; /* Fixed default 50MHz */ } #else #define arc_set_early_base_baud(dt_root) @@ -65,8 +62,6 @@ const struct machine_desc * __init setup_machine_fdt(void *dt) { const struct machine_desc *mdesc; unsigned long dt_root; - const void *clk; - int len; if (!early_init_dt_scan(dt)) return NULL; @@ -76,10 +71,6 @@ const struct machine_desc * __init setup_machine_fdt(void *dt) machine_halt(); dt_root = of_get_flat_dt_root(); - clk = of_get_flat_dt_prop(dt_root, "clock-frequency", &len); - if (clk) - arc_set_core_freq(of_read_ulong(clk, len/4)); - arc_set_early_base_baud(dt_root); return mdesc; diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 9425263..6c24faf 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -137,23 +137,30 @@ static const struct irq_domain_ops arcv2_irq_ops = { .map = arcv2_irq_map, }; -static struct irq_domain *root_domain; static int __init init_onchip_IRQ(struct device_node *intc, struct device_node *parent) { + struct irq_domain *root_domain; + if (parent) panic("DeviceTree incore intc not a root irq controller\n"); - root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0, - &arcv2_irq_ops, NULL); - + root_domain = irq_domain_add_linear(intc, NR_CPU_IRQS, &arcv2_irq_ops, NULL); if (!root_domain) panic("root irq domain not avail\n"); - /* with this we don't need to export root_domain */ + /* + * Needed for primary domain lookup to succeed + * This is a primary irqchip, and can never have a parent + */ irq_set_default_host(root_domain); +#ifdef CONFIG_SMP + irq_create_mapping(root_domain, IPI_IRQ); +#endif + irq_create_mapping(root_domain, SOFTIRQ_IRQ); + return 0; } diff --git a/arch/arc/kernel/intc-compact.c b/arch/arc/kernel/intc-compact.c index 224d1c3..c5cceca 100644 --- a/arch/arc/kernel/intc-compact.c +++ b/arch/arc/kernel/intc-compact.c @@ -14,6 +14,8 @@ #include <linux/irqchip.h> #include <asm/irq.h> +#define TIMER0_IRQ 3 /* Fixed by ISA */ + /* * Early Hardware specific Interrupt setup * -Platform independent, needed for each CPU (not foldable into init_IRQ) @@ -79,8 +81,9 @@ static struct irq_chip onchip_intc = { static int arc_intc_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { - switch (irq) { + switch (hw) { case TIMER0_IRQ: + irq_set_percpu_devid(irq); irq_set_chip_and_handler(irq, &onchip_intc, handle_percpu_irq); break; default: @@ -94,21 +97,23 @@ static const struct irq_domain_ops arc_intc_domain_ops = { .map = arc_intc_domain_map, }; -static struct irq_domain *root_domain; - static int __init init_onchip_IRQ(struct device_node *intc, struct device_node *parent) { + struct irq_domain *root_domain; + if (parent) panic("DeviceTree incore intc not a root irq controller\n"); - root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0, + root_domain = irq_domain_add_linear(intc, NR_CPU_IRQS, &arc_intc_domain_ops, NULL); - if (!root_domain) panic("root irq domain not avail\n"); - /* with this we don't need to export root_domain */ + /* + * Needed for primary domain lookup to succeed + * This is a primary irqchip, and can never have a parent + */ irq_set_default_host(root_domain); return 0; diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index ba17f85..538b36a 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -41,53 +41,7 @@ void __init init_IRQ(void) * "C" Entry point for any ARC ISR, called from low level vector handler * @irq is the vector number read from ICAUSE reg of on-chip intc */ -void arch_do_IRQ(unsigned int irq, struct pt_regs *regs) +void arch_do_IRQ(unsigned int hwirq, struct pt_regs *regs) { - struct pt_regs *old_regs = set_irq_regs(regs); - - irq_enter(); - generic_handle_irq(irq); - irq_exit(); - set_irq_regs(old_regs); -} - -/* - * API called for requesting percpu interrupts - called by each CPU - * - For boot CPU, actually request the IRQ with genirq core + enables - * - For subsequent callers only enable called locally - * - * Relies on being called by boot cpu first (i.e. request called ahead) of - * any enable as expected by genirq. Hence Suitable only for TIMER, IPI - * which are guaranteed to be setup on boot core first. - * Late probed peripherals such as perf can't use this as there no guarantee - * of being called on boot CPU first. - */ - -void arc_request_percpu_irq(int irq, int cpu, - irqreturn_t (*isr)(int irq, void *dev), - const char *irq_nm, - void *percpu_dev) -{ - /* Boot cpu calls request, all call enable */ - if (!cpu) { - int rc; - -#ifdef CONFIG_ISA_ARCOMPACT - /* - * A subsequent request_percpu_irq() fails if percpu_devid is - * not set. That in turns sets NOAUTOEN, meaning each core needs - * to call enable_percpu_irq() - * - * For ARCv2, this is done in irq map function since we know - * which irqs are strictly per cpu - */ - irq_set_percpu_devid(irq); -#endif - - rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev); - if (rc) - panic("Percpu IRQ request failed for %d\n", irq); - } - - enable_percpu_irq(irq, 0); + handle_domain_irq(NULL, hwirq, regs); } diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index c41c364..72f9179 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -15,9 +15,6 @@ #include <asm/mcip.h> #include <asm/setup.h> -#define IPI_IRQ 19 -#define SOFTIRQ_IRQ 21 - static char smp_cpuinfo_buf[128]; static int idu_detected; @@ -116,15 +113,13 @@ static void mcip_probe_n_setup(void) IS_AVAIL1(mp.dbg, "DEBUG "), IS_AVAIL1(mp.gfrc, "GFRC")); + cpuinfo_arc700[0].extn.gfrc = mp.gfrc; idu_detected = mp.idu; if (mp.dbg) { __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf); __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf); } - - if (IS_ENABLED(CONFIG_ARC_HAS_GFRC) && !mp.gfrc) - panic("kernel trying to use non-existent GFRC\n"); } struct plat_smp_ops plat_smp_ops = { diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 151acf0..f63b8bf 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -13,7 +13,6 @@ #include <linux/console.h> #include <linux/module.h> #include <linux/cpu.h> -#include <linux/clk-provider.h> #include <linux/of_fdt.h> #include <linux/of_platform.h> #include <linux/cache.h> @@ -24,7 +23,6 @@ #include <asm/page.h> #include <asm/irq.h> #include <asm/unwind.h> -#include <asm/clk.h> #include <asm/mach_desc.h> #include <asm/smp.h> @@ -220,10 +218,6 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) if (tbl->info.id == 0) n += scnprintf(buf + n, len - n, "UNKNOWN ARC Processor\n"); - n += scnprintf(buf + n, len - n, "CPU speed\t: %u.%02u Mhz\n", - (unsigned int)(arc_get_core_freq() / 1000000), - (unsigned int)(arc_get_core_freq() / 10000) % 100); - n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ", IS_AVAIL1(cpu->extn.timer0, "Timer0 "), IS_AVAIL1(cpu->extn.timer1, "Timer1 "), @@ -314,9 +308,6 @@ static void arc_chk_core_config(void) if (!cpu->extn.timer1) panic("Timer1 is not present!\n"); - if (IS_ENABLED(CONFIG_ARC_HAS_RTC) && !cpu->extn.rtc) - panic("RTC is not present\n"); - #ifdef CONFIG_ARC_HAS_DCCM /* * DCCM can be arbit placed in hardware. @@ -444,7 +435,6 @@ void __init setup_arch(char **cmdline_p) static int __init customize_machine(void) { - of_clk_init(NULL); /* * Traverses flattened DeviceTree - registering platform devices * (if any) complete with their resources @@ -477,6 +467,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) { char *str; int cpu_id = ptr_to_cpu(v); + struct device_node *core_clk = of_find_node_by_name(NULL, "core_clk"); + u32 freq = 0; if (!cpu_online(cpu_id)) { seq_printf(m, "processor [%d]\t: Offline\n", cpu_id); @@ -489,6 +481,11 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, arc_cpu_mumbojumbo(cpu_id, str, PAGE_SIZE)); + of_property_read_u32(core_clk, "clock-frequency", &freq); + if (freq) + seq_printf(m, "CPU speed\t: %u.%02u Mhz\n", + freq / 1000000, (freq / 10000) % 100); + seq_printf(m, "Bogo MIPS\t: %lu.%02lu\n", loops_per_jiffy / (500000 / HZ), (loops_per_jiffy / (5000 / HZ)) % 100); diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 4cb3add..f183cc6 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -126,11 +126,6 @@ void start_kernel_secondary(void) current->active_mm = mm; cpumask_set_cpu(cpu, mm_cpumask(mm)); - notify_cpu_starting(cpu); - set_cpu_online(cpu, true); - - pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); - /* Some SMP H/w setup - for each cpu */ if (plat_smp_ops.init_per_cpu) plat_smp_ops.init_per_cpu(cpu); @@ -138,7 +133,10 @@ void start_kernel_secondary(void) if (machine_desc->init_per_cpu) machine_desc->init_per_cpu(cpu); - arc_local_timer_setup(); + notify_cpu_starting(cpu); + set_cpu_online(cpu, true); + + pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); local_irq_enable(); preempt_disable(); @@ -346,6 +344,10 @@ irqreturn_t do_IPI(int irq, void *dev_id) /* * API called by platform code to hookup arch-common ISR to their IPI IRQ + * + * Note: If IPI is provided by platform (vs. say ARC MCIP), their intc setup/map + * function needs to call call irq_set_percpu_devid() for IPI IRQ, otherwise + * request_percpu_irq() below will fail */ static DEFINE_PER_CPU(int, ipi_dev); @@ -353,7 +355,16 @@ int smp_ipi_irq_setup(int cpu, int irq) { int *dev = per_cpu_ptr(&ipi_dev, cpu); - arc_request_percpu_irq(irq, cpu, do_IPI, "IPI Interrupt", dev); + /* Boot cpu calls request, all call enable */ + if (!cpu) { + int rc; + + rc = request_percpu_irq(irq, do_IPI, "IPI Interrupt", dev); + if (rc) + panic("Percpu IRQ request failed for %d\n", irq); + } + + enable_percpu_irq(irq, 0); return 0; } diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 7d9a736..4549ab2 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -29,21 +29,16 @@ * which however is currently broken */ -#include <linux/spinlock.h> #include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/time.h> -#include <linux/init.h> -#include <linux/timex.h> -#include <linux/profile.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/clocksource.h> #include <linux/clockchips.h> +#include <linux/cpu.h> +#include <linux/of.h> +#include <linux/of_irq.h> #include <asm/irq.h> #include <asm/arcregs.h> -#include <asm/clk.h> -#include <asm/mach_desc.h> #include <asm/mcip.h> @@ -60,16 +55,35 @@ #define ARC_TIMER_MAX 0xFFFFFFFF -/********** Clock Source Device *********/ - -#ifdef CONFIG_ARC_HAS_GFRC +static unsigned long arc_timer_freq; -static int arc_counter_setup(void) +static int noinline arc_get_timer_clk(struct device_node *node) { - return 1; + struct clk *clk; + int ret; + + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_err("timer missing clk"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("Couldn't enable parent clk\n"); + return ret; + } + + arc_timer_freq = clk_get_rate(clk); + + return 0; } -static cycle_t arc_counter_read(struct clocksource *cs) +/********** Clock Source Device *********/ + +#ifdef CONFIG_ARC_HAS_GFRC + +static cycle_t arc_read_gfrc(struct clocksource *cs) { unsigned long flags; union { @@ -94,15 +108,31 @@ static cycle_t arc_counter_read(struct clocksource *cs) return stamp.full; } -static struct clocksource arc_counter = { +static struct clocksource arc_counter_gfrc = { .name = "ARConnect GFRC", .rating = 400, - .read = arc_counter_read, + .read = arc_read_gfrc, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#else +static void __init arc_cs_setup_gfrc(struct device_node *node) +{ + int exists = cpuinfo_arc700[0].extn.gfrc; + int ret; + + if (WARN(!exists, "Global-64-bit-Ctr clocksource not detected")) + return; + + ret = arc_get_timer_clk(node); + if (ret) + return; + + clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); +} +CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); + +#endif #ifdef CONFIG_ARC_HAS_RTC @@ -110,15 +140,7 @@ static struct clocksource arc_counter = { #define AUX_RTC_LOW 0x104 #define AUX_RTC_HIGH 0x105 -int arc_counter_setup(void) -{ - write_aux_reg(AUX_RTC_CTRL, 1); - - /* Not usable in SMP */ - return !IS_ENABLED(CONFIG_SMP); -} - -static cycle_t arc_counter_read(struct clocksource *cs) +static cycle_t arc_read_rtc(struct clocksource *cs) { unsigned long status; union { @@ -142,47 +164,78 @@ static cycle_t arc_counter_read(struct clocksource *cs) return stamp.full; } -static struct clocksource arc_counter = { +static struct clocksource arc_counter_rtc = { .name = "ARCv2 RTC", .rating = 350, - .read = arc_counter_read, + .read = arc_read_rtc, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#else /* !CONFIG_ARC_HAS_RTC */ - -/* - * set 32bit TIMER1 to keep counting monotonically and wraparound - */ -int arc_counter_setup(void) +static void __init arc_cs_setup_rtc(struct device_node *node) { - write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX); - write_aux_reg(ARC_REG_TIMER1_CNT, 0); - write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); + int exists = cpuinfo_arc700[smp_processor_id()].extn.rtc; + int ret; + + if (WARN(!exists, "Local-64-bit-Ctr clocksource not detected")) + return; + + /* Local to CPU hence not usable in SMP */ + if (WARN(IS_ENABLED(CONFIG_SMP), "Local-64-bit-Ctr not usable in SMP")) + return; + + ret = arc_get_timer_clk(node); + if (ret) + return; + + write_aux_reg(AUX_RTC_CTRL, 1); - /* Not usable in SMP */ - return !IS_ENABLED(CONFIG_SMP); + clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); } +CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); -static cycle_t arc_counter_read(struct clocksource *cs) +#endif + +/* + * 32bit TIMER1 to keep counting monotonically and wraparound + */ + +static cycle_t arc_read_timer1(struct clocksource *cs) { return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT); } -static struct clocksource arc_counter = { +static struct clocksource arc_counter_timer1 = { .name = "ARC Timer1", .rating = 300, - .read = arc_counter_read, + .read = arc_read_timer1, .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#endif -#endif +static void __init arc_cs_setup_timer1(struct device_node *node) +{ + int ret; + + /* Local to CPU hence not usable in SMP */ + if (IS_ENABLED(CONFIG_SMP)) + return; + + ret = arc_get_timer_clk(node); + if (ret) + return; + + write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX); + write_aux_reg(ARC_REG_TIMER1_CNT, 0); + write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); + + clocksource_register_hz(&arc_counter_timer1, arc_timer_freq); +} /********** Clock Event Device *********/ +static int arc_timer_irq; + /* * Arm the timer to interrupt after @cycles * The distinction for oneshot/periodic is done in arc_event_timer_ack() below @@ -209,7 +262,7 @@ static int arc_clkevent_set_periodic(struct clock_event_device *dev) * At X Hz, 1 sec = 1000ms -> X cycles; * 10ms -> X / 100 cycles */ - arc_timer_event_setup(arc_get_core_freq() / HZ); + arc_timer_event_setup(arc_timer_freq / HZ); return 0; } @@ -218,7 +271,6 @@ static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = { .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .rating = 300, - .irq = TIMER0_IRQ, /* hardwired, no need for resources */ .set_next_event = arc_clkevent_set_next_event, .set_state_periodic = arc_clkevent_set_periodic, }; @@ -244,45 +296,81 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int arc_timer_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); + + evt->cpumask = cpumask_of(smp_processor_id()); + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + clockevents_config_and_register(evt, arc_timer_freq, + 0, ULONG_MAX); + enable_percpu_irq(arc_timer_irq, 0); + break; + case CPU_DYING: + disable_percpu_irq(arc_timer_irq); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block arc_timer_cpu_nb = { + .notifier_call = arc_timer_cpu_notify, +}; + /* - * Setup the local event timer for @cpu + * clockevent setup for boot CPU */ -void arc_local_timer_setup() +static void __init arc_clockevent_setup(struct device_node *node) { struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); - int cpu = smp_processor_id(); + int ret; + + register_cpu_notifier(&arc_timer_cpu_nb); - evt->cpumask = cpumask_of(cpu); - clockevents_config_and_register(evt, arc_get_core_freq(), + arc_timer_irq = irq_of_parse_and_map(node, 0); + if (arc_timer_irq <= 0) + panic("clockevent: missing irq"); + + ret = arc_get_timer_clk(node); + if (ret) + panic("clockevent: missing clk"); + + evt->irq = arc_timer_irq; + evt->cpumask = cpumask_of(smp_processor_id()); + clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMER_MAX); - /* setup the per-cpu timer IRQ handler - for all cpus */ - arc_request_percpu_irq(TIMER0_IRQ, cpu, timer_irq_handler, - "Timer0 (per-cpu-tick)", evt); + /* Needs apriori irq_set_percpu_devid() done in intc map function */ + ret = request_percpu_irq(arc_timer_irq, timer_irq_handler, + "Timer0 (per-cpu-tick)", evt); + if (ret) + panic("clockevent: unable to request irq\n"); + + enable_percpu_irq(arc_timer_irq, 0); } +static void __init arc_of_timer_init(struct device_node *np) +{ + static int init_count = 0; + + if (!init_count) { + init_count = 1; + arc_clockevent_setup(np); + } else { + arc_cs_setup_timer1(np); + } +} +CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); + /* * Called from start_kernel() - boot CPU only - * - * -Sets up h/w timers as applicable on boot cpu - * -Also sets up any global state needed for timer subsystem: - * - for "counting" timer, registers a clocksource, usable across CPUs - * (provided that underlying counter h/w is synchronized across cores) - * - for "event" timer, sets up TIMER0 IRQ (as that is platform agnostic) */ void __init time_init(void) { - /* - * sets up the timekeeping free-flowing counter which also returns - * whether the counter is usable as clocksource - */ - if (arc_counter_setup()) - /* - * CLK upto 4.29 GHz can be safely represented in 32 bits - * because Max 32 bit number is 4,294,967,295 - */ - clocksource_register_hz(&arc_counter, arc_get_core_freq()); - - /* sets up the periodic event timer */ - arc_local_timer_setup(); + of_clk_init(NULL); + clocksource_probe(); } diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index 7046c12..ec868a9 100644 --- a/arch/arc/mm/tlb.c +++ b/arch/arc/mm/tlb.c @@ -814,6 +814,17 @@ void arc_mmu_init(void) printk(arc_mmu_mumbojumbo(0, str, sizeof(str))); + /* + * Can't be done in processor.h due to header include depenedencies + */ + BUILD_BUG_ON(!IS_ALIGNED((CONFIG_ARC_KVADDR_SIZE << 20), PMD_SIZE)); + + /* + * stack top size sanity check, + * Can't be done in processor.h due to header include depenedencies + */ + BUILD_BUG_ON(!IS_ALIGNED(STACK_TOP, PMD_SIZE)); + /* For efficiency sake, kernel is compile time built for a MMU ver * This must match the hardware it is running on. * Linux built for MMU V2, if run on MMU V1 will break down because V1 diff --git a/arch/arc/plat-axs10x/axs10x.c b/arch/arc/plat-axs10x/axs10x.c index 1b0f0f4..8654870 100644 --- a/arch/arc/plat-axs10x/axs10x.c +++ b/arch/arc/plat-axs10x/axs10x.c @@ -14,10 +14,11 @@ * */ +#include <linux/of_fdt.h> #include <linux/of_platform.h> +#include <linux/libfdt.h> #include <asm/asm-offsets.h> -#include <asm/clk.h> #include <asm/io.h> #include <asm/mach_desc.h> #include <asm/mcip.h> @@ -389,6 +390,13 @@ axs103_set_freq(unsigned int id, unsigned int fd, unsigned int od) static void __init axs103_early_init(void) { + int offset = fdt_path_offset(initial_boot_params, "/cpu_card/core_clk"); + const struct fdt_property *prop = fdt_get_property(initial_boot_params, + offset, + "clock-frequency", + NULL); + u32 freq = be32_to_cpu(*(u32*)(prop->data)) / 1000000, orig = freq; + /* * AXS103 configurations for SMP/QUAD configurations share device tree * which defaults to 90 MHz. However recent failures of Quad config @@ -401,12 +409,10 @@ static void __init axs103_early_init(void) #ifdef CONFIG_ARC_MCIP unsigned int num_cores = (read_aux_reg(ARC_REG_MCIP_BCR) >> 16) & 0x3F; if (num_cores > 2) - arc_set_core_freq(50 * 1000000); - else if (num_cores == 2) - arc_set_core_freq(75 * 1000000); + freq = 50; #endif - switch (arc_get_core_freq()/1000000) { + switch (freq) { case 33: axs103_set_freq(1, 1, 1); break; @@ -431,11 +437,18 @@ static void __init axs103_early_init(void) * DT "clock-frequency" might not match with board value. * Hence update it to match the board value. */ - arc_set_core_freq(axs103_get_freq() * 1000000); + freq = axs103_get_freq(); break; } - pr_info("Freq is %dMHz\n", axs103_get_freq()); + pr_info("Freq is %dMHz\n", freq); + + /* Patching .dtb in-place with new core clock value */ + if (freq != orig ) { + freq = cpu_to_be32(freq * 1000000); + fdt_setprop_inplace(initial_boot_params, offset, + "clock-frequency", &freq, sizeof(freq)); + } /* Memory maps already config in pre-bootloader */ diff --git a/arch/arc/plat-eznps/Kconfig b/arch/arc/plat-eznps/Kconfig new file mode 100644 index 0000000..1d175cc --- /dev/null +++ b/arch/arc/plat-eznps/Kconfig @@ -0,0 +1,35 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +menuconfig ARC_PLAT_EZNPS + bool "\"EZchip\" ARC dev platform" + select ARC_HAS_COH_CACHES if SMP + select CPU_BIG_ENDIAN + select CLKSRC_NPS + select EZNPS_GIC + select EZCHIP_NPS_MANAGEMENT_ENET if ETHERNET + help + Support for EZchip development platforms, + based on ARC700 cores. + We handle few flavours: + - Hardware Emulator AKA HE which is FPGA based chasis + - Simulator based on MetaWare nSIM + - NPS400 chip based on ASIC + +config EZNPS_MTM_EXT + bool "ARC-EZchip MTM Extensions" + select CPUMASK_OFFSTACK + depends on ARC_PLAT_EZNPS && SMP + default y + help + Here we add new hierarchy for CPUs topology. + We got: + Core + Thread + At the new thread level each CPU represent one HW thread. + At highest hierarchy each core contain 16 threads, + any of them seem like CPU from Linux point of view. + All threads within same core share the execution unit of the + core and HW scheduler round robin between them. diff --git a/arch/arc/plat-eznps/Makefile b/arch/arc/plat-eznps/Makefile new file mode 100644 index 0000000..21091b1 --- /dev/null +++ b/arch/arc/plat-eznps/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the linux kernel. +# + +obj-y := entry.o platform.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_EZNPS_MTM_EXT) += mtm.o diff --git a/arch/arc/plat-eznps/entry.S b/arch/arc/plat-eznps/entry.S new file mode 100644 index 0000000..328261c --- /dev/null +++ b/arch/arc/plat-eznps/entry.S @@ -0,0 +1,70 @@ +/******************************************************************************* + + EZNPS CPU startup Code + Copyright(c) 2012 EZchip Technologies. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + +*******************************************************************************/ +#include <linux/linkage.h> +#include <asm/entry.h> +#include <asm/cache.h> +#include <plat/ctop.h> + + .cpu A7 + + .section .init.text, "ax",@progbits + .align 1024 ; HW requierment for restart first PC + +ENTRY(res_service) +#ifdef CONFIG_EZNPS_MTM_EXT + ; There is no work for HW thread id != 0 + lr r3, [CTOP_AUX_THREAD_ID] + cmp r3, 0 + jne stext +#endif + +#ifdef CONFIG_ARC_HAS_DCACHE + ; With no cache coherency mechanism D$ need to be used very carefully. + ; Address space: + ; 0G-2G: We disable CONFIG_ARC_CACHE_PAGES. + ; 2G-3G: We disable D$ by setting this bit. + ; 3G-4G: D$ is disabled by architecture. + ; FMT are huge pages for user application reside at 0-2G. + ; Only FMT left as one who can use D$ where each such page got + ; disable/enable bit for cachability. + ; Programmer will use FMT pages for private data so cache coherency + ; would not be a problem. + ; First thing we invalidate D$ + sr 1, [ARC_REG_DC_IVDC] + sr HW_COMPLY_KRN_NOT_D_CACHED, [CTOP_AUX_HW_COMPLY] +#endif + +#ifdef CONFIG_SMP + ; We set logical cpuid to be used by GET_CPUID + ; We do not use physical cpuid since we want ids to be continious when + ; it comes to cpus on the same quad cluster. + ; This is useful for applications that used shared resources of a quad + ; cluster such SRAMS. + lr r3, [CTOP_AUX_CORE_ID] + sr r3, [CTOP_AUX_LOGIC_CORE_ID] + lr r3, [CTOP_AUX_CLUSTER_ID] + ; Set logical is acheived by swap of 2 middle bits of cluster id (4 bit) + ; r3 is used since we use short instruction and we need q-class reg + .short CTOP_INST_MOV2B_FLIP_R3_B1_B2_INST + .word CTOP_INST_MOV2B_FLIP_R3_B1_B2_LIMM + sr r3, [CTOP_AUX_LOGIC_CLUSTER_ID] +#endif + + j stext +END(res_service) diff --git a/arch/arc/plat-eznps/include/plat/ctop.h b/arch/arc/plat-eznps/include/plat/ctop.h new file mode 100644 index 0000000..9d6718c --- /dev/null +++ b/arch/arc/plat-eznps/include/plat/ctop.h @@ -0,0 +1,209 @@ +/* + * Copyright(c) 2015 EZchip Technologies. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +#ifndef _PLAT_EZNPS_CTOP_H +#define _PLAT_EZNPS_CTOP_H + +#ifndef CONFIG_ARC_PLAT_EZNPS +#error "Incorrect ctop.h include" +#endif + +#include <soc/nps/common.h> + +/* core auxiliary registers */ +#ifdef __ASSEMBLY__ +#define CTOP_AUX_BASE (-0x800) +#else +#define CTOP_AUX_BASE 0xFFFFF800 +#endif + +#define CTOP_AUX_GLOBAL_ID (CTOP_AUX_BASE + 0x000) +#define CTOP_AUX_CLUSTER_ID (CTOP_AUX_BASE + 0x004) +#define CTOP_AUX_CORE_ID (CTOP_AUX_BASE + 0x008) +#define CTOP_AUX_THREAD_ID (CTOP_AUX_BASE + 0x00C) +#define CTOP_AUX_LOGIC_GLOBAL_ID (CTOP_AUX_BASE + 0x010) +#define CTOP_AUX_LOGIC_CLUSTER_ID (CTOP_AUX_BASE + 0x014) +#define CTOP_AUX_LOGIC_CORE_ID (CTOP_AUX_BASE + 0x018) +#define CTOP_AUX_MT_CTRL (CTOP_AUX_BASE + 0x020) +#define CTOP_AUX_HW_COMPLY (CTOP_AUX_BASE + 0x024) +#define CTOP_AUX_LPC (CTOP_AUX_BASE + 0x030) +#define CTOP_AUX_EFLAGS (CTOP_AUX_BASE + 0x080) +#define CTOP_AUX_IACK (CTOP_AUX_BASE + 0x088) +#define CTOP_AUX_GPA1 (CTOP_AUX_BASE + 0x08C) +#define CTOP_AUX_UDMC (CTOP_AUX_BASE + 0x300) + +/* EZchip core instructions */ +#define CTOP_INST_HWSCHD_OFF_R3 0x3B6F00BF +#define CTOP_INST_HWSCHD_OFF_R4 0x3C6F00BF +#define CTOP_INST_HWSCHD_RESTORE_R3 0x3E6F70C3 +#define CTOP_INST_HWSCHD_RESTORE_R4 0x3E6F7103 +#define CTOP_INST_SCHD_RW 0x3E6F7004 +#define CTOP_INST_SCHD_RD 0x3E6F7084 +#define CTOP_INST_ASRI_0_R3 0x3B56003E +#define CTOP_INST_XEX_DI_R2_R2_R3 0x4A664C00 +#define CTOP_INST_EXC_DI_R2_R2_R3 0x4A664C01 +#define CTOP_INST_AADD_DI_R2_R2_R3 0x4A664C02 +#define CTOP_INST_AAND_DI_R2_R2_R3 0x4A664C04 +#define CTOP_INST_AOR_DI_R2_R2_R3 0x4A664C05 +#define CTOP_INST_AXOR_DI_R2_R2_R3 0x4A664C06 + +/* Do not use D$ for address in 2G-3G */ +#define HW_COMPLY_KRN_NOT_D_CACHED _BITUL(28) + +#define NPS_MSU_EN_CFG 0x80 +#define NPS_CRG_BLKID 0x480 +#define NPS_CRG_SYNC_BIT _BITUL(0) +#define NPS_GIM_BLKID 0x5C0 + +/* GIM registers and fields*/ +#define NPS_GIM_UART_LINE _BITUL(7) +#define NPS_GIM_DBG_LAN_EAST_TX_DONE_LINE _BITUL(10) +#define NPS_GIM_DBG_LAN_EAST_RX_RDY_LINE _BITUL(11) +#define NPS_GIM_DBG_LAN_WEST_TX_DONE_LINE _BITUL(25) +#define NPS_GIM_DBG_LAN_WEST_RX_RDY_LINE _BITUL(26) + +#ifndef __ASSEMBLY__ +/* Functional registers definition */ +struct nps_host_reg_mtm_cfg { + union { + struct { + u32 gen:1, gdis:1, clk_gate_dis:1, asb:1, + __reserved:9, nat:3, ten:16; + }; + u32 value; + }; +}; + +struct nps_host_reg_mtm_cpu_cfg { + union { + struct { + u32 csa:22, dmsid:6, __reserved:3, cs:1; + }; + u32 value; + }; +}; + +struct nps_host_reg_thr_init { + union { + struct { + u32 str:1, __reserved:27, thr_id:4; + }; + u32 value; + }; +}; + +struct nps_host_reg_thr_init_sts { + union { + struct { + u32 bsy:1, err:1, __reserved:26, thr_id:4; + }; + u32 value; + }; +}; + +struct nps_host_reg_msu_en_cfg { + union { + struct { + u32 __reserved1:11, + rtc_en:1, ipc_en:1, gim_1_en:1, + gim_0_en:1, ipi_en:1, buff_e_rls_bmuw:1, + buff_e_alc_bmuw:1, buff_i_rls_bmuw:1, buff_i_alc_bmuw:1, + buff_e_rls_bmue:1, buff_e_alc_bmue:1, buff_i_rls_bmue:1, + buff_i_alc_bmue:1, __reserved2:1, buff_e_pre_en:1, + buff_i_pre_en:1, pmuw_ja_en:1, pmue_ja_en:1, + pmuw_nj_en:1, pmue_nj_en:1, msu_en:1; + }; + u32 value; + }; +}; + +struct nps_host_reg_gim_p_int_dst { + union { + struct { + u32 int_out_en:1, __reserved1:4, + is:1, intm:2, __reserved2:4, + nid:4, __reserved3:4, cid:4, + __reserved4:4, tid:4; + }; + u32 value; + }; +}; + +/* AUX registers definition */ +struct nps_host_reg_aux_udmc { + union { + struct { + u32 dcp:1, cme:1, __reserved:19, nat:3, + __reserved2:5, dcas:3; + }; + u32 value; + }; +}; + +struct nps_host_reg_aux_mt_ctrl { + union { + struct { + u32 mten:1, hsen:1, scd:1, sten:1, + st_cnt:8, __reserved:8, + hs_cnt:8, __reserved1:4; + }; + u32 value; + }; +}; + +struct nps_host_reg_aux_hw_comply { + union { + struct { + u32 me:1, le:1, te:1, knc:1, __reserved:28; + }; + u32 value; + }; +}; + +struct nps_host_reg_aux_lpc { + union { + struct { + u32 mep:1, __reserved:31; + }; + u32 value; + }; +}; + +/* CRG registers */ +#define REG_GEN_PURP_0 nps_host_reg_non_cl(NPS_CRG_BLKID, 0x1BF) + +/* GIM registers */ +#define REG_GIM_P_INT_EN_0 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x100) +#define REG_GIM_P_INT_POL_0 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x110) +#define REG_GIM_P_INT_SENS_0 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x114) +#define REG_GIM_P_INT_BLK_0 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x118) +#define REG_GIM_P_INT_DST_10 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x13A) +#define REG_GIM_P_INT_DST_11 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x13B) +#define REG_GIM_P_INT_DST_25 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x149) +#define REG_GIM_P_INT_DST_26 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x14A) + +#else + +.macro GET_CPU_ID reg + lr \reg, [CTOP_AUX_LOGIC_GLOBAL_ID] +#ifndef CONFIG_EZNPS_MTM_EXT + lsr \reg, \reg, 4 +#endif +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* _PLAT_EZNPS_CTOP_H */ diff --git a/arch/arc/plat-eznps/include/plat/mtm.h b/arch/arc/plat-eznps/include/plat/mtm.h new file mode 100644 index 0000000..29b91b5 --- /dev/null +++ b/arch/arc/plat-eznps/include/plat/mtm.h @@ -0,0 +1,60 @@ +/* + * Copyright(c) 2015 EZchip Technologies. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +#ifndef _PLAT_EZNPS_MTM_H +#define _PLAT_EZNPS_MTM_H + +#include <plat/ctop.h> + +static inline void *nps_mtm_reg_addr(u32 cpu, u32 reg) +{ + struct global_id gid; + u32 core, blkid; + + gid.value = cpu; + core = gid.core; + blkid = (((core & 0x0C) << 2) | (core & 0x03)); + + return nps_host_reg(cpu, blkid, reg); +} + +#ifdef CONFIG_EZNPS_MTM_EXT +#define NPS_CPU_TO_THREAD_NUM(cpu) \ + ({ struct global_id gid; gid.value = cpu; gid.thread; }) + +/* MTM registers */ +#define MTM_CFG(cpu) nps_mtm_reg_addr(cpu, 0x81) +#define MTM_THR_INIT(cpu) nps_mtm_reg_addr(cpu, 0x92) +#define MTM_THR_INIT_STS(cpu) nps_mtm_reg_addr(cpu, 0x93) + +#define get_thread(map) map.thread +#define eznps_max_cpus 4096 +#define eznps_cpus_per_cluster 256 + +void mtm_enable_core(unsigned int cpu); +int mtm_enable_thread(int cpu); +#else /* !CONFIG_EZNPS_MTM_EXT */ + +#define get_thread(map) 0 +#define eznps_max_cpus 256 +#define eznps_cpus_per_cluster 16 +#define mtm_enable_core(cpu) +#define mtm_enable_thread(cpu) 1 +#define NPS_CPU_TO_THREAD_NUM(cpu) 0 + +#endif /* CONFIG_EZNPS_MTM_EXT */ + +#endif /* _PLAT_EZNPS_MTM_H */ diff --git a/arch/arc/plat-eznps/include/plat/smp.h b/arch/arc/plat-eznps/include/plat/smp.h new file mode 100644 index 0000000..06b59bd --- /dev/null +++ b/arch/arc/plat-eznps/include/plat/smp.h @@ -0,0 +1,26 @@ +/* + * Copyright(c) 2015 EZchip Technologies. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +#ifndef __PLAT_EZNPS_SMP_H +#define __PLAT_EZNPS_SMP_H + +#ifdef CONFIG_SMP + +extern void res_service(void); + +#endif /* CONFIG_SMP */ + +#endif diff --git a/arch/arc/plat-eznps/mtm.c b/arch/arc/plat-eznps/mtm.c new file mode 100644 index 0000000..aaaaffd --- /dev/null +++ b/arch/arc/plat-eznps/mtm.c @@ -0,0 +1,133 @@ +/* + * Copyright(c) 2015 EZchip Technologies. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +#include <linux/smp.h> +#include <linux/io.h> +#include <linux/log2.h> +#include <asm/arcregs.h> +#include <plat/mtm.h> +#include <plat/smp.h> + +#define MT_CTRL_HS_CNT 0xFF +#define MT_CTRL_ST_CNT 0xF +#define NPS_NUM_HW_THREADS 0x10 + +static void mtm_init_nat(int cpu) +{ + struct nps_host_reg_mtm_cfg mtm_cfg; + struct nps_host_reg_aux_udmc udmc; + int log_nat, nat = 0, i, t; + + /* Iterate core threads and update nat */ + for (i = 0, t = cpu; i < NPS_NUM_HW_THREADS; i++, t++) + nat += test_bit(t, cpumask_bits(cpu_possible_mask)); + + log_nat = ilog2(nat); + + udmc.value = read_aux_reg(CTOP_AUX_UDMC); + udmc.nat = log_nat; + write_aux_reg(CTOP_AUX_UDMC, udmc.value); + + mtm_cfg.value = ioread32be(MTM_CFG(cpu)); + mtm_cfg.nat = log_nat; + iowrite32be(mtm_cfg.value, MTM_CFG(cpu)); +} + +static void mtm_init_thread(int cpu) +{ + int i, tries = 5; + struct nps_host_reg_thr_init thr_init; + struct nps_host_reg_thr_init_sts thr_init_sts; + + /* Set thread init register */ + thr_init.value = 0; + iowrite32be(thr_init.value, MTM_THR_INIT(cpu)); + thr_init.thr_id = NPS_CPU_TO_THREAD_NUM(cpu); + thr_init.str = 1; + iowrite32be(thr_init.value, MTM_THR_INIT(cpu)); + + /* Poll till thread init is done */ + for (i = 0; i < tries; i++) { + thr_init_sts.value = ioread32be(MTM_THR_INIT_STS(cpu)); + if (thr_init_sts.thr_id == thr_init.thr_id) { + if (thr_init_sts.bsy) + continue; + else if (thr_init_sts.err) + pr_warn("Failed to thread init cpu %u\n", cpu); + break; + } + + pr_warn("Wrong thread id in thread init for cpu %u\n", cpu); + break; + } + + if (i == tries) + pr_warn("Got thread init timeout for cpu %u\n", cpu); +} + +int mtm_enable_thread(int cpu) +{ + struct nps_host_reg_mtm_cfg mtm_cfg; + + if (NPS_CPU_TO_THREAD_NUM(cpu) == 0) + return 1; + + /* Enable thread in mtm */ + mtm_cfg.value = ioread32be(MTM_CFG(cpu)); + mtm_cfg.ten |= (1 << (NPS_CPU_TO_THREAD_NUM(cpu))); + iowrite32be(mtm_cfg.value, MTM_CFG(cpu)); + + return 0; +} + +void mtm_enable_core(unsigned int cpu) +{ + int i; + struct nps_host_reg_aux_mt_ctrl mt_ctrl; + struct nps_host_reg_mtm_cfg mtm_cfg; + + if (NPS_CPU_TO_THREAD_NUM(cpu) != 0) + return; + + /* Initialize Number of Active Threads */ + mtm_init_nat(cpu); + + /* Initialize mtm_cfg */ + mtm_cfg.value = ioread32be(MTM_CFG(cpu)); + mtm_cfg.ten = 1; + iowrite32be(mtm_cfg.value, MTM_CFG(cpu)); + + /* Initialize all other threads in core */ + for (i = 1; i < NPS_NUM_HW_THREADS; i++) + mtm_init_thread(cpu + i); + + + /* Enable HW schedule, stall counter, mtm */ + mt_ctrl.value = 0; + mt_ctrl.hsen = 1; + mt_ctrl.hs_cnt = MT_CTRL_HS_CNT; + mt_ctrl.sten = 1; + mt_ctrl.st_cnt = MT_CTRL_ST_CNT; + mt_ctrl.mten = 1; + write_aux_reg(CTOP_AUX_MT_CTRL, mt_ctrl.value); + + /* + * HW scheduling mechanism will start working + * Only after call to instruction "schd.rw". + * cpu_relax() calls "schd.rw" instruction. + */ + cpu_relax(); +} diff --git a/arch/arc/plat-eznps/platform.c b/arch/arc/plat-eznps/platform.c new file mode 100644 index 0000000..7ad6d2b --- /dev/null +++ b/arch/arc/plat-eznps/platform.c @@ -0,0 +1,102 @@ +/* + * Copyright(c) 2015 EZchip Technologies. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <asm/mach_desc.h> +#include <plat/mtm.h> + +static void __init eznps_configure_msu(void) +{ + int cpu; + struct nps_host_reg_msu_en_cfg msu_en_cfg = {.value = 0}; + + msu_en_cfg.msu_en = 1; + msu_en_cfg.ipi_en = 1; + msu_en_cfg.gim_0_en = 1; + msu_en_cfg.gim_1_en = 1; + + /* enable IPI and GIM messages on all clusters */ + for (cpu = 0 ; cpu < eznps_max_cpus; cpu += eznps_cpus_per_cluster) + iowrite32be(msu_en_cfg.value, + nps_host_reg(cpu, NPS_MSU_BLKID, NPS_MSU_EN_CFG)); +} + +static void __init eznps_configure_gim(void) +{ + u32 reg_value; + u32 gim_int_lines; + struct nps_host_reg_gim_p_int_dst gim_p_int_dst = {.value = 0}; + + gim_int_lines = NPS_GIM_UART_LINE; + gim_int_lines |= NPS_GIM_DBG_LAN_EAST_TX_DONE_LINE; + gim_int_lines |= NPS_GIM_DBG_LAN_EAST_RX_RDY_LINE; + gim_int_lines |= NPS_GIM_DBG_LAN_WEST_TX_DONE_LINE; + gim_int_lines |= NPS_GIM_DBG_LAN_WEST_RX_RDY_LINE; + + /* + * IRQ polarity + * low or high level + * negative or positive edge + */ + reg_value = ioread32be(REG_GIM_P_INT_POL_0); + reg_value &= ~gim_int_lines; + iowrite32be(reg_value, REG_GIM_P_INT_POL_0); + + /* IRQ type level or edge */ + reg_value = ioread32be(REG_GIM_P_INT_SENS_0); + reg_value |= NPS_GIM_DBG_LAN_EAST_TX_DONE_LINE; + reg_value |= NPS_GIM_DBG_LAN_WEST_TX_DONE_LINE; + iowrite32be(reg_value, REG_GIM_P_INT_SENS_0); + + /* + * GIM interrupt select type for + * dbg_lan TX and RX interrupts + * should be type 1 + * type 0 = IRQ line 6 + * type 1 = IRQ line 7 + */ + gim_p_int_dst.is = 1; + iowrite32be(gim_p_int_dst.value, REG_GIM_P_INT_DST_10); + iowrite32be(gim_p_int_dst.value, REG_GIM_P_INT_DST_11); + iowrite32be(gim_p_int_dst.value, REG_GIM_P_INT_DST_25); + iowrite32be(gim_p_int_dst.value, REG_GIM_P_INT_DST_26); + + /* + * CTOP IRQ lines should be defined + * as blocking in GIM + */ + iowrite32be(gim_int_lines, REG_GIM_P_INT_BLK_0); + + /* enable CTOP IRQ lines in GIM */ + iowrite32be(gim_int_lines, REG_GIM_P_INT_EN_0); +} + +static void __init eznps_early_init(void) +{ + eznps_configure_msu(); + eznps_configure_gim(); +} + +static const char *eznps_compat[] __initconst = { + "ezchip,arc-nps", + NULL, +}; + +MACHINE_START(NPS, "nps") + .dt_compat = eznps_compat, + .init_early = eznps_early_init, +MACHINE_END diff --git a/arch/arc/plat-eznps/smp.c b/arch/arc/plat-eznps/smp.c new file mode 100644 index 0000000..5e901f8 --- /dev/null +++ b/arch/arc/plat-eznps/smp.c @@ -0,0 +1,155 @@ +/* + * Copyright(c) 2015 EZchip Technologies. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +#include <linux/smp.h> +#include <linux/of_fdt.h> +#include <linux/io.h> +#include <linux/irqdomain.h> +#include <asm/irq.h> +#include <plat/ctop.h> +#include <plat/smp.h> +#include <plat/mtm.h> + +#define NPS_DEFAULT_MSID 0x34 +#define NPS_MTM_CPU_CFG 0x90 + +static char smp_cpuinfo_buf[128] = {"Extn [EZNPS-SMP]\t: On\n"}; + +/* Get cpu map from device tree */ +static int __init eznps_get_map(const char *name, struct cpumask *cpumask) +{ + unsigned long dt_root = of_get_flat_dt_root(); + const char *buf; + + buf = of_get_flat_dt_prop(dt_root, name, NULL); + if (!buf) + return 1; + + cpulist_parse(buf, cpumask); + + return 0; +} + +/* Update board cpu maps */ +static void __init eznps_init_cpumasks(void) +{ + struct cpumask cpumask; + + if (eznps_get_map("present-cpus", &cpumask)) { + pr_err("Failed to get present-cpus from dtb"); + return; + } + init_cpu_present(&cpumask); + + if (eznps_get_map("possible-cpus", &cpumask)) { + pr_err("Failed to get possible-cpus from dtb"); + return; + } + init_cpu_possible(&cpumask); +} + +static void eznps_init_core(unsigned int cpu) +{ + u32 sync_value; + struct nps_host_reg_aux_hw_comply hw_comply; + struct nps_host_reg_aux_lpc lpc; + + if (NPS_CPU_TO_THREAD_NUM(cpu) != 0) + return; + + hw_comply.value = read_aux_reg(CTOP_AUX_HW_COMPLY); + hw_comply.me = 1; + hw_comply.le = 1; + hw_comply.te = 1; + write_aux_reg(CTOP_AUX_HW_COMPLY, hw_comply.value); + + /* Enable MMU clock */ + lpc.mep = 1; + write_aux_reg(CTOP_AUX_LPC, lpc.value); + + /* Boot CPU only */ + if (!cpu) { + /* Write to general purpose register in CRG */ + sync_value = ioread32be(REG_GEN_PURP_0); + sync_value |= NPS_CRG_SYNC_BIT; + iowrite32be(sync_value, REG_GEN_PURP_0); + } +} + +/* + * Master kick starting another CPU + */ +static void __init eznps_smp_wakeup_cpu(int cpu, unsigned long pc) +{ + struct nps_host_reg_mtm_cpu_cfg cpu_cfg; + + if (mtm_enable_thread(cpu) == 0) + return; + + /* set PC, dmsid, and start CPU */ + cpu_cfg.value = (u32)res_service; + cpu_cfg.dmsid = NPS_DEFAULT_MSID; + cpu_cfg.cs = 1; + iowrite32be(cpu_cfg.value, nps_mtm_reg_addr(cpu, NPS_MTM_CPU_CFG)); +} + +static void eznps_ipi_send(int cpu) +{ + struct global_id gid; + struct { + union { + struct { + u32 num:8, cluster:8, core:8, thread:8; + }; + u32 value; + }; + } ipi; + + gid.value = cpu; + ipi.thread = get_thread(gid); + ipi.core = gid.core; + ipi.cluster = nps_cluster_logic_to_phys(gid.cluster); + ipi.num = NPS_IPI_IRQ; + + __asm__ __volatile__( + " mov r3, %0\n" + " .word %1\n" + : + : "r"(ipi.value), "i"(CTOP_INST_ASRI_0_R3) + : "r3"); +} + +static void eznps_init_per_cpu(int cpu) +{ + smp_ipi_irq_setup(cpu, NPS_IPI_IRQ); + + eznps_init_core(cpu); + mtm_enable_core(cpu); +} + +static void eznps_ipi_clear(int irq) +{ + write_aux_reg(CTOP_AUX_IACK, 1 << irq); +} + +struct plat_smp_ops plat_smp_ops = { + .info = smp_cpuinfo_buf, + .init_early_smp = eznps_init_cpumasks, + .cpu_kick = eznps_smp_wakeup_cpu, + .ipi_send = eznps_ipi_send, + .init_per_cpu = eznps_init_per_cpu, + .ipi_clear = eznps_ipi_clear, +}; diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index 31cc2f2..10b27b9 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -48,9 +48,29 @@ <1 24>, <1 25>, <1 26>, + /* dma channel 11-14 share one irq */ <1 27>, + <1 27>, + <1 27>, + <1 27>, + /* unused shared irq for all channels */ <1 28>; - + interrupt-names = "dma0", + "dma1", + "dma2", + "dma3", + "dma4", + "dma5", + "dma6", + "dma7", + "dma8", + "dma9", + "dma10", + "dma11", + "dma12", + "dma13", + "dma14", + "dma-shared-all"; #dma-cells = <1>; brcm,dma-channel-mask = <0x7f35>; }; diff --git a/arch/arm/boot/dts/imx6q-apalis-ixora.dts b/arch/arm/boot/dts/imx6q-apalis-ixora.dts index 8e3e146..8e67ca2 100644 --- a/arch/arm/boot/dts/imx6q-apalis-ixora.dts +++ b/arch/arm/boot/dts/imx6q-apalis-ixora.dts @@ -219,8 +219,9 @@ }; &pcie { - /* active-low meaning opposite of regular PERST# active-low polarity */ - reset-gpio = <&gpio1 28 GPIO_ACTIVE_LOW>; + /* active-high meaning opposite of regular PERST# active-low polarity */ + reset-gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>; + reset-gpio-active-high; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qp.dtsi b/arch/arm/boot/dts/imx6qp.dtsi index 1ada714..886dbf2 100644 --- a/arch/arm/boot/dts/imx6qp.dtsi +++ b/arch/arm/boot/dts/imx6qp.dtsi @@ -82,5 +82,8 @@ "ldb_di0", "ldb_di1", "prg"; }; + pcie: pcie@0x01000000 { + compatible = "fsl,imx6qp-pcie", "snps,dw-pcie"; + }; }; }; diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index 14594ce..449acf0 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -117,7 +117,7 @@ chan_priority = <1>; block_size = <0xfff>; dma-masters = <2>; - data_width = <3 3>; + data-width = <8 8>; }; dma@eb000000 { @@ -133,7 +133,7 @@ chan_allocation_order = <1>; chan_priority = <1>; block_size = <0xfff>; - data_width = <3 3>; + data-width = <8 8>; }; fsmc: flash@b0000000 { diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 6ad1ced..02283eb 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -118,7 +118,7 @@ static inline unsigned long dma_max_pfn(struct device *dev) #define arch_setup_dma_ops arch_setup_dma_ops extern void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - struct iommu_ops *iommu, bool coherent); + const struct iommu_ops *iommu, bool coherent); #define arch_teardown_dma_ops arch_teardown_dma_ops extern void arch_teardown_dma_ops(struct device *dev); diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 738d5ee..0df6b1f 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -187,6 +187,7 @@ struct kvm_vm_stat { struct kvm_vcpu_stat { u32 halt_successful_poll; u32 halt_attempted_poll; + u32 halt_poll_invalid; u32 halt_wakeup; u32 hvc_exit_stat; u64 wfe_exit_stat; @@ -290,6 +291,7 @@ static inline void kvm_arch_hardware_unsetup(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} +static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_init_debug(void) {} static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index f17a8d4..f9a6506 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -47,6 +47,7 @@ #include <linux/highmem.h> #include <asm/cacheflush.h> #include <asm/pgalloc.h> +#include <asm/stage2_pgtable.h> int create_hyp_mappings(void *from, void *to); int create_hyp_io_mappings(void *from, void *to, phys_addr_t); @@ -106,14 +107,16 @@ static inline void kvm_clean_pte(pte_t *pte) clean_pte_table(pte); } -static inline void kvm_set_s2pte_writable(pte_t *pte) +static inline pte_t kvm_s2pte_mkwrite(pte_t pte) { - pte_val(*pte) |= L_PTE_S2_RDWR; + pte_val(pte) |= L_PTE_S2_RDWR; + return pte; } -static inline void kvm_set_s2pmd_writable(pmd_t *pmd) +static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd) { - pmd_val(*pmd) |= L_PMD_S2_RDWR; + pmd_val(pmd) |= L_PMD_S2_RDWR; + return pmd; } static inline void kvm_set_s2pte_readonly(pte_t *pte) @@ -136,22 +139,6 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd) return (pmd_val(*pmd) & L_PMD_S2_RDWR) == L_PMD_S2_RDONLY; } - -/* Open coded p*d_addr_end that can deal with 64bit addresses */ -#define kvm_pgd_addr_end(addr, end) \ -({ u64 __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK; \ - (__boundary - 1 < (end) - 1)? __boundary: (end); \ -}) - -#define kvm_pud_addr_end(addr,end) (end) - -#define kvm_pmd_addr_end(addr, end) \ -({ u64 __boundary = ((addr) + PMD_SIZE) & PMD_MASK; \ - (__boundary - 1 < (end) - 1)? __boundary: (end); \ -}) - -#define kvm_pgd_index(addr) pgd_index(addr) - static inline bool kvm_page_empty(void *ptr) { struct page *ptr_page = virt_to_page(ptr); @@ -160,19 +147,11 @@ static inline bool kvm_page_empty(void *ptr) #define kvm_pte_table_empty(kvm, ptep) kvm_page_empty(ptep) #define kvm_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp) -#define kvm_pud_table_empty(kvm, pudp) (0) - -#define KVM_PREALLOC_LEVEL 0 +#define kvm_pud_table_empty(kvm, pudp) false -static inline void *kvm_get_hwpgd(struct kvm *kvm) -{ - return kvm->arch.pgd; -} - -static inline unsigned int kvm_get_hwpgd_size(void) -{ - return PTRS_PER_S2_PGD * sizeof(pgd_t); -} +#define hyp_pte_table_empty(ptep) kvm_page_empty(ptep) +#define hyp_pmd_table_empty(pmdp) kvm_page_empty(pmdp) +#define hyp_pud_table_empty(pudp) false struct kvm; diff --git a/arch/arm/include/asm/stage2_pgtable.h b/arch/arm/include/asm/stage2_pgtable.h new file mode 100644 index 0000000..460d616 --- /dev/null +++ b/arch/arm/include/asm/stage2_pgtable.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 - ARM Ltd + * + * stage2 page table helpers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __ARM_S2_PGTABLE_H_ +#define __ARM_S2_PGTABLE_H_ + +#define stage2_pgd_none(pgd) pgd_none(pgd) +#define stage2_pgd_clear(pgd) pgd_clear(pgd) +#define stage2_pgd_present(pgd) pgd_present(pgd) +#define stage2_pgd_populate(pgd, pud) pgd_populate(NULL, pgd, pud) +#define stage2_pud_offset(pgd, address) pud_offset(pgd, address) +#define stage2_pud_free(pud) pud_free(NULL, pud) + +#define stage2_pud_none(pud) pud_none(pud) +#define stage2_pud_clear(pud) pud_clear(pud) +#define stage2_pud_present(pud) pud_present(pud) +#define stage2_pud_populate(pud, pmd) pud_populate(NULL, pud, pmd) +#define stage2_pmd_offset(pud, address) pmd_offset(pud, address) +#define stage2_pmd_free(pmd) pmd_free(NULL, pmd) + +#define stage2_pud_huge(pud) pud_huge(pud) + +/* Open coded p*d_addr_end that can deal with 64bit addresses */ +static inline phys_addr_t stage2_pgd_addr_end(phys_addr_t addr, phys_addr_t end) +{ + phys_addr_t boundary = (addr + PGDIR_SIZE) & PGDIR_MASK; + + return (boundary - 1 < end - 1) ? boundary : end; +} + +#define stage2_pud_addr_end(addr, end) (end) + +static inline phys_addr_t stage2_pmd_addr_end(phys_addr_t addr, phys_addr_t end) +{ + phys_addr_t boundary = (addr + PMD_SIZE) & PMD_MASK; + + return (boundary - 1 < end - 1) ? boundary : end; +} + +#define stage2_pgd_index(addr) pgd_index(addr) + +#define stage2_pte_table_empty(ptep) kvm_page_empty(ptep) +#define stage2_pmd_table_empty(pmdp) kvm_page_empty(pmdp) +#define stage2_pud_table_empty(pudp) false + +#endif /* __ARM_S2_PGTABLE_H_ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 9ef013d..237d5d8 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -444,7 +444,7 @@ static void update_vttbr(struct kvm *kvm) kvm_next_vmid &= (1 << kvm_vmid_bits) - 1; /* update vttbr to be used with the new vmid */ - pgd_phys = virt_to_phys(kvm_get_hwpgd(kvm)); + pgd_phys = virt_to_phys(kvm->arch.pgd); BUG_ON(pgd_phys & ~VTTBR_BADDR_MASK); vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits); kvm->arch.vttbr = pgd_phys | vmid; diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index be30212..45c43ae 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -43,11 +43,9 @@ static unsigned long hyp_idmap_start; static unsigned long hyp_idmap_end; static phys_addr_t hyp_idmap_vector; +#define S2_PGD_SIZE (PTRS_PER_S2_PGD * sizeof(pgd_t)) #define hyp_pgd_order get_order(PTRS_PER_PGD * sizeof(pgd_t)) -#define kvm_pmd_huge(_x) (pmd_huge(_x) || pmd_trans_huge(_x)) -#define kvm_pud_huge(_x) pud_huge(_x) - #define KVM_S2PTE_FLAG_IS_IOMAP (1UL << 0) #define KVM_S2_FLAG_LOGGING_ACTIVE (1UL << 1) @@ -69,14 +67,7 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) { - /* - * This function also gets called when dealing with HYP page - * tables. As HYP doesn't have an associated struct kvm (and - * the HYP page tables are fairly static), we don't do - * anything there. - */ - if (kvm) - kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, kvm, ipa); + kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, kvm, ipa); } /* @@ -115,7 +106,7 @@ static bool kvm_is_device_pfn(unsigned long pfn) */ static void stage2_dissolve_pmd(struct kvm *kvm, phys_addr_t addr, pmd_t *pmd) { - if (!kvm_pmd_huge(*pmd)) + if (!pmd_thp_or_huge(*pmd)) return; pmd_clear(pmd); @@ -155,29 +146,29 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc) return p; } -static void clear_pgd_entry(struct kvm *kvm, pgd_t *pgd, phys_addr_t addr) +static void clear_stage2_pgd_entry(struct kvm *kvm, pgd_t *pgd, phys_addr_t addr) { - pud_t *pud_table __maybe_unused = pud_offset(pgd, 0); - pgd_clear(pgd); + pud_t *pud_table __maybe_unused = stage2_pud_offset(pgd, 0UL); + stage2_pgd_clear(pgd); kvm_tlb_flush_vmid_ipa(kvm, addr); - pud_free(NULL, pud_table); + stage2_pud_free(pud_table); put_page(virt_to_page(pgd)); } -static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr) +static void clear_stage2_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr) { - pmd_t *pmd_table = pmd_offset(pud, 0); - VM_BUG_ON(pud_huge(*pud)); - pud_clear(pud); + pmd_t *pmd_table __maybe_unused = stage2_pmd_offset(pud, 0); + VM_BUG_ON(stage2_pud_huge(*pud)); + stage2_pud_clear(pud); kvm_tlb_flush_vmid_ipa(kvm, addr); - pmd_free(NULL, pmd_table); + stage2_pmd_free(pmd_table); put_page(virt_to_page(pud)); } -static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr) +static void clear_stage2_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr) { pte_t *pte_table = pte_offset_kernel(pmd, 0); - VM_BUG_ON(kvm_pmd_huge(*pmd)); + VM_BUG_ON(pmd_thp_or_huge(*pmd)); pmd_clear(pmd); kvm_tlb_flush_vmid_ipa(kvm, addr); pte_free_kernel(NULL, pte_table); @@ -204,7 +195,7 @@ static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr) * the corresponding TLBs, we call kvm_flush_dcache_p*() to make sure * the IO subsystem will never hit in the cache. */ -static void unmap_ptes(struct kvm *kvm, pmd_t *pmd, +static void unmap_stage2_ptes(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr, phys_addr_t end) { phys_addr_t start_addr = addr; @@ -226,21 +217,21 @@ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd, } } while (pte++, addr += PAGE_SIZE, addr != end); - if (kvm_pte_table_empty(kvm, start_pte)) - clear_pmd_entry(kvm, pmd, start_addr); + if (stage2_pte_table_empty(start_pte)) + clear_stage2_pmd_entry(kvm, pmd, start_addr); } -static void unmap_pmds(struct kvm *kvm, pud_t *pud, +static void unmap_stage2_pmds(struct kvm *kvm, pud_t *pud, phys_addr_t addr, phys_addr_t end) { phys_addr_t next, start_addr = addr; pmd_t *pmd, *start_pmd; - start_pmd = pmd = pmd_offset(pud, addr); + start_pmd = pmd = stage2_pmd_offset(pud, addr); do { - next = kvm_pmd_addr_end(addr, end); + next = stage2_pmd_addr_end(addr, end); if (!pmd_none(*pmd)) { - if (kvm_pmd_huge(*pmd)) { + if (pmd_thp_or_huge(*pmd)) { pmd_t old_pmd = *pmd; pmd_clear(pmd); @@ -250,57 +241,64 @@ static void unmap_pmds(struct kvm *kvm, pud_t *pud, put_page(virt_to_page(pmd)); } else { - unmap_ptes(kvm, pmd, addr, next); + unmap_stage2_ptes(kvm, pmd, addr, next); } } } while (pmd++, addr = next, addr != end); - if (kvm_pmd_table_empty(kvm, start_pmd)) - clear_pud_entry(kvm, pud, start_addr); + if (stage2_pmd_table_empty(start_pmd)) + clear_stage2_pud_entry(kvm, pud, start_addr); } -static void unmap_puds(struct kvm *kvm, pgd_t *pgd, +static void unmap_stage2_puds(struct kvm *kvm, pgd_t *pgd, phys_addr_t addr, phys_addr_t end) { phys_addr_t next, start_addr = addr; pud_t *pud, *start_pud; - start_pud = pud = pud_offset(pgd, addr); + start_pud = pud = stage2_pud_offset(pgd, addr); do { - next = kvm_pud_addr_end(addr, end); - if (!pud_none(*pud)) { - if (pud_huge(*pud)) { + next = stage2_pud_addr_end(addr, end); + if (!stage2_pud_none(*pud)) { + if (stage2_pud_huge(*pud)) { pud_t old_pud = *pud; - pud_clear(pud); + stage2_pud_clear(pud); kvm_tlb_flush_vmid_ipa(kvm, addr); - kvm_flush_dcache_pud(old_pud); - put_page(virt_to_page(pud)); } else { - unmap_pmds(kvm, pud, addr, next); + unmap_stage2_pmds(kvm, pud, addr, next); } } } while (pud++, addr = next, addr != end); - if (kvm_pud_table_empty(kvm, start_pud)) - clear_pgd_entry(kvm, pgd, start_addr); + if (stage2_pud_table_empty(start_pud)) + clear_stage2_pgd_entry(kvm, pgd, start_addr); } - -static void unmap_range(struct kvm *kvm, pgd_t *pgdp, - phys_addr_t start, u64 size) +/** + * unmap_stage2_range -- Clear stage2 page table entries to unmap a range + * @kvm: The VM pointer + * @start: The intermediate physical base address of the range to unmap + * @size: The size of the area to unmap + * + * Clear a range of stage-2 mappings, lowering the various ref-counts. Must + * be called while holding mmu_lock (unless for freeing the stage2 pgd before + * destroying the VM), otherwise another faulting VCPU may come in and mess + * with things behind our backs. + */ +static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size) { pgd_t *pgd; phys_addr_t addr = start, end = start + size; phys_addr_t next; - pgd = pgdp + kvm_pgd_index(addr); + pgd = kvm->arch.pgd + stage2_pgd_index(addr); do { - next = kvm_pgd_addr_end(addr, end); - if (!pgd_none(*pgd)) - unmap_puds(kvm, pgd, addr, next); + next = stage2_pgd_addr_end(addr, end); + if (!stage2_pgd_none(*pgd)) + unmap_stage2_puds(kvm, pgd, addr, next); } while (pgd++, addr = next, addr != end); } @@ -322,11 +320,11 @@ static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud, pmd_t *pmd; phys_addr_t next; - pmd = pmd_offset(pud, addr); + pmd = stage2_pmd_offset(pud, addr); do { - next = kvm_pmd_addr_end(addr, end); + next = stage2_pmd_addr_end(addr, end); if (!pmd_none(*pmd)) { - if (kvm_pmd_huge(*pmd)) + if (pmd_thp_or_huge(*pmd)) kvm_flush_dcache_pmd(*pmd); else stage2_flush_ptes(kvm, pmd, addr, next); @@ -340,11 +338,11 @@ static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd, pud_t *pud; phys_addr_t next; - pud = pud_offset(pgd, addr); + pud = stage2_pud_offset(pgd, addr); do { - next = kvm_pud_addr_end(addr, end); - if (!pud_none(*pud)) { - if (pud_huge(*pud)) + next = stage2_pud_addr_end(addr, end); + if (!stage2_pud_none(*pud)) { + if (stage2_pud_huge(*pud)) kvm_flush_dcache_pud(*pud); else stage2_flush_pmds(kvm, pud, addr, next); @@ -360,9 +358,9 @@ static void stage2_flush_memslot(struct kvm *kvm, phys_addr_t next; pgd_t *pgd; - pgd = kvm->arch.pgd + kvm_pgd_index(addr); + pgd = kvm->arch.pgd + stage2_pgd_index(addr); do { - next = kvm_pgd_addr_end(addr, end); + next = stage2_pgd_addr_end(addr, end); stage2_flush_puds(kvm, pgd, addr, next); } while (pgd++, addr = next, addr != end); } @@ -391,6 +389,100 @@ static void stage2_flush_vm(struct kvm *kvm) srcu_read_unlock(&kvm->srcu, idx); } +static void clear_hyp_pgd_entry(pgd_t *pgd) +{ + pud_t *pud_table __maybe_unused = pud_offset(pgd, 0UL); + pgd_clear(pgd); + pud_free(NULL, pud_table); + put_page(virt_to_page(pgd)); +} + +static void clear_hyp_pud_entry(pud_t *pud) +{ + pmd_t *pmd_table __maybe_unused = pmd_offset(pud, 0); + VM_BUG_ON(pud_huge(*pud)); + pud_clear(pud); + pmd_free(NULL, pmd_table); + put_page(virt_to_page(pud)); +} + +static void clear_hyp_pmd_entry(pmd_t *pmd) +{ + pte_t *pte_table = pte_offset_kernel(pmd, 0); + VM_BUG_ON(pmd_thp_or_huge(*pmd)); + pmd_clear(pmd); + pte_free_kernel(NULL, pte_table); + put_page(virt_to_page(pmd)); +} + +static void unmap_hyp_ptes(pmd_t *pmd, phys_addr_t addr, phys_addr_t end) +{ + pte_t *pte, *start_pte; + + start_pte = pte = pte_offset_kernel(pmd, addr); + do { + if (!pte_none(*pte)) { + kvm_set_pte(pte, __pte(0)); + put_page(virt_to_page(pte)); + } + } while (pte++, addr += PAGE_SIZE, addr != end); + + if (hyp_pte_table_empty(start_pte)) + clear_hyp_pmd_entry(pmd); +} + +static void unmap_hyp_pmds(pud_t *pud, phys_addr_t addr, phys_addr_t end) +{ + phys_addr_t next; + pmd_t *pmd, *start_pmd; + + start_pmd = pmd = pmd_offset(pud, addr); + do { + next = pmd_addr_end(addr, end); + /* Hyp doesn't use huge pmds */ + if (!pmd_none(*pmd)) + unmap_hyp_ptes(pmd, addr, next); + } while (pmd++, addr = next, addr != end); + + if (hyp_pmd_table_empty(start_pmd)) + clear_hyp_pud_entry(pud); +} + +static void unmap_hyp_puds(pgd_t *pgd, phys_addr_t addr, phys_addr_t end) +{ + phys_addr_t next; + pud_t *pud, *start_pud; + + start_pud = pud = pud_offset(pgd, addr); + do { + next = pud_addr_end(addr, end); + /* Hyp doesn't use huge puds */ + if (!pud_none(*pud)) + unmap_hyp_pmds(pud, addr, next); + } while (pud++, addr = next, addr != end); + + if (hyp_pud_table_empty(start_pud)) + clear_hyp_pgd_entry(pgd); +} + +static void unmap_hyp_range(pgd_t *pgdp, phys_addr_t start, u64 size) +{ + pgd_t *pgd; + phys_addr_t addr = start, end = start + size; + phys_addr_t next; + + /* + * We don't unmap anything from HYP, except at the hyp tear down. + * Hence, we don't have to invalidate the TLBs here. + */ + pgd = pgdp + pgd_index(addr); + do { + next = pgd_addr_end(addr, end); + if (!pgd_none(*pgd)) + unmap_hyp_puds(pgd, addr, next); + } while (pgd++, addr = next, addr != end); +} + /** * free_boot_hyp_pgd - free HYP boot page tables * @@ -401,14 +493,14 @@ void free_boot_hyp_pgd(void) mutex_lock(&kvm_hyp_pgd_mutex); if (boot_hyp_pgd) { - unmap_range(NULL, boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE); - unmap_range(NULL, boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE); + unmap_hyp_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE); + unmap_hyp_range(boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE); free_pages((unsigned long)boot_hyp_pgd, hyp_pgd_order); boot_hyp_pgd = NULL; } if (hyp_pgd) - unmap_range(NULL, hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE); + unmap_hyp_range(hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE); mutex_unlock(&kvm_hyp_pgd_mutex); } @@ -433,9 +525,9 @@ void free_hyp_pgds(void) if (hyp_pgd) { for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) - unmap_range(NULL, hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); + unmap_hyp_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE) - unmap_range(NULL, hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); + unmap_hyp_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); free_pages((unsigned long)hyp_pgd, hyp_pgd_order); hyp_pgd = NULL; @@ -645,20 +737,6 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr) __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE); } -/* Free the HW pgd, one page at a time */ -static void kvm_free_hwpgd(void *hwpgd) -{ - free_pages_exact(hwpgd, kvm_get_hwpgd_size()); -} - -/* Allocate the HW PGD, making sure that each page gets its own refcount */ -static void *kvm_alloc_hwpgd(void) -{ - unsigned int size = kvm_get_hwpgd_size(); - - return alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO); -} - /** * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation. * @kvm: The KVM struct pointer for the VM. @@ -673,81 +751,22 @@ static void *kvm_alloc_hwpgd(void) int kvm_alloc_stage2_pgd(struct kvm *kvm) { pgd_t *pgd; - void *hwpgd; if (kvm->arch.pgd != NULL) { kvm_err("kvm_arch already initialized?\n"); return -EINVAL; } - hwpgd = kvm_alloc_hwpgd(); - if (!hwpgd) + /* Allocate the HW PGD, making sure that each page gets its own refcount */ + pgd = alloc_pages_exact(S2_PGD_SIZE, GFP_KERNEL | __GFP_ZERO); + if (!pgd) return -ENOMEM; - /* When the kernel uses more levels of page tables than the - * guest, we allocate a fake PGD and pre-populate it to point - * to the next-level page table, which will be the real - * initial page table pointed to by the VTTBR. - * - * When KVM_PREALLOC_LEVEL==2, we allocate a single page for - * the PMD and the kernel will use folded pud. - * When KVM_PREALLOC_LEVEL==1, we allocate 2 consecutive PUD - * pages. - */ - if (KVM_PREALLOC_LEVEL > 0) { - int i; - - /* - * Allocate fake pgd for the page table manipulation macros to - * work. This is not used by the hardware and we have no - * alignment requirement for this allocation. - */ - pgd = kmalloc(PTRS_PER_S2_PGD * sizeof(pgd_t), - GFP_KERNEL | __GFP_ZERO); - - if (!pgd) { - kvm_free_hwpgd(hwpgd); - return -ENOMEM; - } - - /* Plug the HW PGD into the fake one. */ - for (i = 0; i < PTRS_PER_S2_PGD; i++) { - if (KVM_PREALLOC_LEVEL == 1) - pgd_populate(NULL, pgd + i, - (pud_t *)hwpgd + i * PTRS_PER_PUD); - else if (KVM_PREALLOC_LEVEL == 2) - pud_populate(NULL, pud_offset(pgd, 0) + i, - (pmd_t *)hwpgd + i * PTRS_PER_PMD); - } - } else { - /* - * Allocate actual first-level Stage-2 page table used by the - * hardware for Stage-2 page table walks. - */ - pgd = (pgd_t *)hwpgd; - } - kvm_clean_pgd(pgd); kvm->arch.pgd = pgd; return 0; } -/** - * unmap_stage2_range -- Clear stage2 page table entries to unmap a range - * @kvm: The VM pointer - * @start: The intermediate physical base address of the range to unmap - * @size: The size of the area to unmap - * - * Clear a range of stage-2 mappings, lowering the various ref-counts. Must - * be called while holding mmu_lock (unless for freeing the stage2 pgd before - * destroying the VM), otherwise another faulting VCPU may come in and mess - * with things behind our backs. - */ -static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size) -{ - unmap_range(kvm, kvm->arch.pgd, start, size); -} - static void stage2_unmap_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot) { @@ -830,10 +849,8 @@ void kvm_free_stage2_pgd(struct kvm *kvm) return; unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE); - kvm_free_hwpgd(kvm_get_hwpgd(kvm)); - if (KVM_PREALLOC_LEVEL > 0) - kfree(kvm->arch.pgd); - + /* Free the HW pgd, one page at a time */ + free_pages_exact(kvm->arch.pgd, S2_PGD_SIZE); kvm->arch.pgd = NULL; } @@ -843,16 +860,16 @@ static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache pgd_t *pgd; pud_t *pud; - pgd = kvm->arch.pgd + kvm_pgd_index(addr); - if (WARN_ON(pgd_none(*pgd))) { + pgd = kvm->arch.pgd + stage2_pgd_index(addr); + if (WARN_ON(stage2_pgd_none(*pgd))) { if (!cache) return NULL; pud = mmu_memory_cache_alloc(cache); - pgd_populate(NULL, pgd, pud); + stage2_pgd_populate(pgd, pud); get_page(virt_to_page(pgd)); } - return pud_offset(pgd, addr); + return stage2_pud_offset(pgd, addr); } static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, @@ -862,15 +879,15 @@ static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache pmd_t *pmd; pud = stage2_get_pud(kvm, cache, addr); - if (pud_none(*pud)) { + if (stage2_pud_none(*pud)) { if (!cache) return NULL; pmd = mmu_memory_cache_alloc(cache); - pud_populate(NULL, pud, pmd); + stage2_pud_populate(pud, pmd); get_page(virt_to_page(pud)); } - return pmd_offset(pud, addr); + return stage2_pmd_offset(pud, addr); } static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache @@ -893,11 +910,14 @@ static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd)); old_pmd = *pmd; - kvm_set_pmd(pmd, *new_pmd); - if (pmd_present(old_pmd)) + if (pmd_present(old_pmd)) { + pmd_clear(pmd); kvm_tlb_flush_vmid_ipa(kvm, addr); - else + } else { get_page(virt_to_page(pmd)); + } + + kvm_set_pmd(pmd, *new_pmd); return 0; } @@ -946,15 +966,38 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, /* Create 2nd stage page table mapping - Level 3 */ old_pte = *pte; - kvm_set_pte(pte, *new_pte); - if (pte_present(old_pte)) + if (pte_present(old_pte)) { + kvm_set_pte(pte, __pte(0)); kvm_tlb_flush_vmid_ipa(kvm, addr); - else + } else { get_page(virt_to_page(pte)); + } + kvm_set_pte(pte, *new_pte); return 0; } +#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +static int stage2_ptep_test_and_clear_young(pte_t *pte) +{ + if (pte_young(*pte)) { + *pte = pte_mkold(*pte); + return 1; + } + return 0; +} +#else +static int stage2_ptep_test_and_clear_young(pte_t *pte) +{ + return __ptep_test_and_clear_young(pte); +} +#endif + +static int stage2_pmdp_test_and_clear_young(pmd_t *pmd) +{ + return stage2_ptep_test_and_clear_young((pte_t *)pmd); +} + /** * kvm_phys_addr_ioremap - map a device range to guest IPA * @@ -978,7 +1021,7 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa, pte_t pte = pfn_pte(pfn, PAGE_S2_DEVICE); if (writable) - kvm_set_s2pte_writable(&pte); + pte = kvm_s2pte_mkwrite(pte); ret = mmu_topup_memory_cache(&cache, KVM_MMU_CACHE_MIN_PAGES, KVM_NR_MEM_OBJS); @@ -1078,12 +1121,12 @@ static void stage2_wp_pmds(pud_t *pud, phys_addr_t addr, phys_addr_t end) pmd_t *pmd; phys_addr_t next; - pmd = pmd_offset(pud, addr); + pmd = stage2_pmd_offset(pud, addr); do { - next = kvm_pmd_addr_end(addr, end); + next = stage2_pmd_addr_end(addr, end); if (!pmd_none(*pmd)) { - if (kvm_pmd_huge(*pmd)) { + if (pmd_thp_or_huge(*pmd)) { if (!kvm_s2pmd_readonly(pmd)) kvm_set_s2pmd_readonly(pmd); } else { @@ -1106,12 +1149,12 @@ static void stage2_wp_puds(pgd_t *pgd, phys_addr_t addr, phys_addr_t end) pud_t *pud; phys_addr_t next; - pud = pud_offset(pgd, addr); + pud = stage2_pud_offset(pgd, addr); do { - next = kvm_pud_addr_end(addr, end); - if (!pud_none(*pud)) { + next = stage2_pud_addr_end(addr, end); + if (!stage2_pud_none(*pud)) { /* TODO:PUD not supported, revisit later if supported */ - BUG_ON(kvm_pud_huge(*pud)); + BUG_ON(stage2_pud_huge(*pud)); stage2_wp_pmds(pud, addr, next); } } while (pud++, addr = next, addr != end); @@ -1128,7 +1171,7 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) pgd_t *pgd; phys_addr_t next; - pgd = kvm->arch.pgd + kvm_pgd_index(addr); + pgd = kvm->arch.pgd + stage2_pgd_index(addr); do { /* * Release kvm_mmu_lock periodically if the memory region is @@ -1140,8 +1183,8 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) if (need_resched() || spin_needbreak(&kvm->mmu_lock)) cond_resched_lock(&kvm->mmu_lock); - next = kvm_pgd_addr_end(addr, end); - if (pgd_present(*pgd)) + next = stage2_pgd_addr_end(addr, end); + if (stage2_pgd_present(*pgd)) stage2_wp_puds(pgd, addr, next); } while (pgd++, addr = next, addr != end); } @@ -1320,7 +1363,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, pmd_t new_pmd = pfn_pmd(pfn, mem_type); new_pmd = pmd_mkhuge(new_pmd); if (writable) { - kvm_set_s2pmd_writable(&new_pmd); + new_pmd = kvm_s2pmd_mkwrite(new_pmd); kvm_set_pfn_dirty(pfn); } coherent_cache_guest_page(vcpu, pfn, PMD_SIZE, fault_ipa_uncached); @@ -1329,7 +1372,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, pte_t new_pte = pfn_pte(pfn, mem_type); if (writable) { - kvm_set_s2pte_writable(&new_pte); + new_pte = kvm_s2pte_mkwrite(new_pte); kvm_set_pfn_dirty(pfn); mark_page_dirty(kvm, gfn); } @@ -1348,6 +1391,8 @@ out_unlock: * Resolve the access fault by making the page young again. * Note that because the faulting entry is guaranteed not to be * cached in the TLB, we don't need to invalidate anything. + * Only the HW Access Flag updates are supported for Stage 2 (no DBM), + * so there is no need for atomic (pte|pmd)_mkyoung operations. */ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa) { @@ -1364,7 +1409,7 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa) if (!pmd || pmd_none(*pmd)) /* Nothing there */ goto out; - if (kvm_pmd_huge(*pmd)) { /* THP, HugeTLB */ + if (pmd_thp_or_huge(*pmd)) { /* THP, HugeTLB */ *pmd = pmd_mkyoung(*pmd); pfn = pmd_pfn(*pmd); pfn_valid = true; @@ -1588,25 +1633,14 @@ static int kvm_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data) if (!pmd || pmd_none(*pmd)) /* Nothing there */ return 0; - if (kvm_pmd_huge(*pmd)) { /* THP, HugeTLB */ - if (pmd_young(*pmd)) { - *pmd = pmd_mkold(*pmd); - return 1; - } - - return 0; - } + if (pmd_thp_or_huge(*pmd)) /* THP, HugeTLB */ + return stage2_pmdp_test_and_clear_young(pmd); pte = pte_offset_kernel(pmd, gpa); if (pte_none(*pte)) return 0; - if (pte_young(*pte)) { - *pte = pte_mkold(*pte); /* Just a page... */ - return 1; - } - - return 0; + return stage2_ptep_test_and_clear_young(pte); } static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data) @@ -1618,7 +1652,7 @@ static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data) if (!pmd || pmd_none(*pmd)) /* Nothing there */ return 0; - if (kvm_pmd_huge(*pmd)) /* THP, HugeTLB */ + if (pmd_thp_or_huge(*pmd)) /* THP, HugeTLB */ return pmd_young(*pmd); pte = pte_offset_kernel(pmd, gpa); diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index c941e93..5c2ca06 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2215,7 +2215,7 @@ static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent) } static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, - struct iommu_ops *iommu) + const struct iommu_ops *iommu) { struct dma_iommu_mapping *mapping; @@ -2253,7 +2253,7 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) #else static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, - struct iommu_ops *iommu) + const struct iommu_ops *iommu) { return false; } @@ -2270,7 +2270,7 @@ static struct dma_map_ops *arm_get_dma_map_ops(bool coherent) } void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - struct iommu_ops *iommu, bool coherent) + const struct iommu_ops *iommu, bool coherent) { struct dma_map_ops *dma_ops; diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index ba437f0..7dbea6c 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -48,7 +48,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) } void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - struct iommu_ops *iommu, bool coherent); + const struct iommu_ops *iommu, bool coherent); #define arch_setup_dma_ops arch_setup_dma_ops #ifdef CONFIG_IOMMU_DMA diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 1b3dc9df..2cdb6b5 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -85,32 +85,37 @@ #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H) /* TCR_EL2 Registers bits */ -#define TCR_EL2_RES1 ((1 << 31) | (1 << 23)) -#define TCR_EL2_TBI (1 << 20) -#define TCR_EL2_PS (7 << 16) -#define TCR_EL2_PS_40B (2 << 16) -#define TCR_EL2_TG0 (1 << 14) -#define TCR_EL2_SH0 (3 << 12) -#define TCR_EL2_ORGN0 (3 << 10) -#define TCR_EL2_IRGN0 (3 << 8) -#define TCR_EL2_T0SZ 0x3f -#define TCR_EL2_MASK (TCR_EL2_TG0 | TCR_EL2_SH0 | \ - TCR_EL2_ORGN0 | TCR_EL2_IRGN0 | TCR_EL2_T0SZ) +#define TCR_EL2_RES1 ((1 << 31) | (1 << 23)) +#define TCR_EL2_TBI (1 << 20) +#define TCR_EL2_PS_SHIFT 16 +#define TCR_EL2_PS_MASK (7 << TCR_EL2_PS_SHIFT) +#define TCR_EL2_PS_40B (2 << TCR_EL2_PS_SHIFT) +#define TCR_EL2_TG0_MASK TCR_TG0_MASK +#define TCR_EL2_SH0_MASK TCR_SH0_MASK +#define TCR_EL2_ORGN0_MASK TCR_ORGN0_MASK +#define TCR_EL2_IRGN0_MASK TCR_IRGN0_MASK +#define TCR_EL2_T0SZ_MASK 0x3f +#define TCR_EL2_MASK (TCR_EL2_TG0_MASK | TCR_EL2_SH0_MASK | \ + TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK | TCR_EL2_T0SZ_MASK) /* VTCR_EL2 Registers bits */ #define VTCR_EL2_RES1 (1 << 31) -#define VTCR_EL2_PS_MASK (7 << 16) -#define VTCR_EL2_TG0_MASK (1 << 14) -#define VTCR_EL2_TG0_4K (0 << 14) -#define VTCR_EL2_TG0_64K (1 << 14) -#define VTCR_EL2_SH0_MASK (3 << 12) -#define VTCR_EL2_SH0_INNER (3 << 12) -#define VTCR_EL2_ORGN0_MASK (3 << 10) -#define VTCR_EL2_ORGN0_WBWA (1 << 10) -#define VTCR_EL2_IRGN0_MASK (3 << 8) -#define VTCR_EL2_IRGN0_WBWA (1 << 8) -#define VTCR_EL2_SL0_MASK (3 << 6) -#define VTCR_EL2_SL0_LVL1 (1 << 6) +#define VTCR_EL2_HD (1 << 22) +#define VTCR_EL2_HA (1 << 21) +#define VTCR_EL2_PS_MASK TCR_EL2_PS_MASK +#define VTCR_EL2_TG0_MASK TCR_TG0_MASK +#define VTCR_EL2_TG0_4K TCR_TG0_4K +#define VTCR_EL2_TG0_16K TCR_TG0_16K +#define VTCR_EL2_TG0_64K TCR_TG0_64K +#define VTCR_EL2_SH0_MASK TCR_SH0_MASK +#define VTCR_EL2_SH0_INNER TCR_SH0_INNER +#define VTCR_EL2_ORGN0_MASK TCR_ORGN0_MASK +#define VTCR_EL2_ORGN0_WBWA TCR_ORGN0_WBWA +#define VTCR_EL2_IRGN0_MASK TCR_IRGN0_MASK +#define VTCR_EL2_IRGN0_WBWA TCR_IRGN0_WBWA +#define VTCR_EL2_SL0_SHIFT 6 +#define VTCR_EL2_SL0_MASK (3 << VTCR_EL2_SL0_SHIFT) +#define VTCR_EL2_SL0_LVL1 (1 << VTCR_EL2_SL0_SHIFT) #define VTCR_EL2_T0SZ_MASK 0x3f #define VTCR_EL2_T0SZ_40B 24 #define VTCR_EL2_VS_SHIFT 19 @@ -126,35 +131,45 @@ * (see hyp-init.S). * * Note that when using 4K pages, we concatenate two first level page tables - * together. + * together. With 16K pages, we concatenate 16 first level page tables. * * The magic numbers used for VTTBR_X in this patch can be found in Tables * D4-23 and D4-25 in ARM DDI 0487A.b. */ + +#define VTCR_EL2_T0SZ_IPA VTCR_EL2_T0SZ_40B +#define VTCR_EL2_COMMON_BITS (VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \ + VTCR_EL2_IRGN0_WBWA | VTCR_EL2_RES1) + #ifdef CONFIG_ARM64_64K_PAGES /* * Stage2 translation configuration: - * 40bits input (T0SZ = 24) * 64kB pages (TG0 = 1) * 2 level page tables (SL = 1) */ -#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SH0_INNER | \ - VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \ - VTCR_EL2_SL0_LVL1 | VTCR_EL2_RES1) -#define VTTBR_X (38 - VTCR_EL2_T0SZ_40B) -#else +#define VTCR_EL2_TGRAN_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SL0_LVL1) +#define VTTBR_X_TGRAN_MAGIC 38 +#elif defined(CONFIG_ARM64_16K_PAGES) +/* + * Stage2 translation configuration: + * 16kB pages (TG0 = 2) + * 2 level page tables (SL = 1) + */ +#define VTCR_EL2_TGRAN_FLAGS (VTCR_EL2_TG0_16K | VTCR_EL2_SL0_LVL1) +#define VTTBR_X_TGRAN_MAGIC 42 +#else /* 4K */ /* * Stage2 translation configuration: - * 40bits input (T0SZ = 24) * 4kB pages (TG0 = 0) * 3 level page tables (SL = 1) */ -#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SH0_INNER | \ - VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \ - VTCR_EL2_SL0_LVL1 | VTCR_EL2_RES1) -#define VTTBR_X (37 - VTCR_EL2_T0SZ_40B) +#define VTCR_EL2_TGRAN_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SL0_LVL1) +#define VTTBR_X_TGRAN_MAGIC 37 #endif +#define VTCR_EL2_FLAGS (VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN_FLAGS) +#define VTTBR_X (VTTBR_X_TGRAN_MAGIC - VTCR_EL2_T0SZ_IPA) + #define VTTBR_BADDR_SHIFT (VTTBR_X - 1) #define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) #define VTTBR_VMID_SHIFT (UL(48)) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 90a8d23..e63d23b 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -295,6 +295,7 @@ struct kvm_vm_stat { struct kvm_vcpu_stat { u32 halt_successful_poll; u32 halt_attempted_poll; + u32 halt_poll_invalid; u32 halt_wakeup; u32 hvc_exit_stat; u64 wfe_exit_stat; @@ -369,6 +370,7 @@ static inline void kvm_arch_hardware_unsetup(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} +static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {} void kvm_arm_init_debug(void); void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index e8d39d4..f05ac27 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -45,18 +45,6 @@ */ #define TRAMPOLINE_VA (HYP_PAGE_OFFSET_MASK & PAGE_MASK) -/* - * KVM_MMU_CACHE_MIN_PAGES is the number of stage2 page table translation - * levels in addition to the PGD and potentially the PUD which are - * pre-allocated (we pre-allocate the fake PGD and the PUD when the Stage-2 - * tables use one level of tables less than the kernel. - */ -#ifdef CONFIG_ARM64_64K_PAGES -#define KVM_MMU_CACHE_MIN_PAGES 1 -#else -#define KVM_MMU_CACHE_MIN_PAGES 2 -#endif - #ifdef __ASSEMBLY__ #include <asm/alternative.h> @@ -91,6 +79,8 @@ alternative_endif #define KVM_PHYS_SIZE (1UL << KVM_PHYS_SHIFT) #define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1UL) +#include <asm/stage2_pgtable.h> + int create_hyp_mappings(void *from, void *to); int create_hyp_io_mappings(void *from, void *to, phys_addr_t); void free_boot_hyp_pgd(void); @@ -122,19 +112,32 @@ static inline void kvm_clean_pmd_entry(pmd_t *pmd) {} static inline void kvm_clean_pte(pte_t *pte) {} static inline void kvm_clean_pte_entry(pte_t *pte) {} -static inline void kvm_set_s2pte_writable(pte_t *pte) +static inline pte_t kvm_s2pte_mkwrite(pte_t pte) { - pte_val(*pte) |= PTE_S2_RDWR; + pte_val(pte) |= PTE_S2_RDWR; + return pte; } -static inline void kvm_set_s2pmd_writable(pmd_t *pmd) +static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd) { - pmd_val(*pmd) |= PMD_S2_RDWR; + pmd_val(pmd) |= PMD_S2_RDWR; + return pmd; } static inline void kvm_set_s2pte_readonly(pte_t *pte) { - pte_val(*pte) = (pte_val(*pte) & ~PTE_S2_RDWR) | PTE_S2_RDONLY; + pteval_t pteval; + unsigned long tmp; + + asm volatile("// kvm_set_s2pte_readonly\n" + " prfm pstl1strm, %2\n" + "1: ldxr %0, %2\n" + " and %0, %0, %3 // clear PTE_S2_RDWR\n" + " orr %0, %0, %4 // set PTE_S2_RDONLY\n" + " stxr %w1, %0, %2\n" + " cbnz %w1, 1b\n" + : "=&r" (pteval), "=&r" (tmp), "+Q" (pte_val(*pte)) + : "L" (~PTE_S2_RDWR), "L" (PTE_S2_RDONLY)); } static inline bool kvm_s2pte_readonly(pte_t *pte) @@ -144,69 +147,12 @@ static inline bool kvm_s2pte_readonly(pte_t *pte) static inline void kvm_set_s2pmd_readonly(pmd_t *pmd) { - pmd_val(*pmd) = (pmd_val(*pmd) & ~PMD_S2_RDWR) | PMD_S2_RDONLY; + kvm_set_s2pte_readonly((pte_t *)pmd); } static inline bool kvm_s2pmd_readonly(pmd_t *pmd) { - return (pmd_val(*pmd) & PMD_S2_RDWR) == PMD_S2_RDONLY; -} - - -#define kvm_pgd_addr_end(addr, end) pgd_addr_end(addr, end) -#define kvm_pud_addr_end(addr, end) pud_addr_end(addr, end) -#define kvm_pmd_addr_end(addr, end) pmd_addr_end(addr, end) - -/* - * In the case where PGDIR_SHIFT is larger than KVM_PHYS_SHIFT, we can address - * the entire IPA input range with a single pgd entry, and we would only need - * one pgd entry. Note that in this case, the pgd is actually not used by - * the MMU for Stage-2 translations, but is merely a fake pgd used as a data - * structure for the kernel pgtable macros to work. - */ -#if PGDIR_SHIFT > KVM_PHYS_SHIFT -#define PTRS_PER_S2_PGD_SHIFT 0 -#else -#define PTRS_PER_S2_PGD_SHIFT (KVM_PHYS_SHIFT - PGDIR_SHIFT) -#endif -#define PTRS_PER_S2_PGD (1 << PTRS_PER_S2_PGD_SHIFT) - -#define kvm_pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1)) - -/* - * If we are concatenating first level stage-2 page tables, we would have less - * than or equal to 16 pointers in the fake PGD, because that's what the - * architecture allows. In this case, (4 - CONFIG_PGTABLE_LEVELS) - * represents the first level for the host, and we add 1 to go to the next - * level (which uses contatenation) for the stage-2 tables. - */ -#if PTRS_PER_S2_PGD <= 16 -#define KVM_PREALLOC_LEVEL (4 - CONFIG_PGTABLE_LEVELS + 1) -#else -#define KVM_PREALLOC_LEVEL (0) -#endif - -static inline void *kvm_get_hwpgd(struct kvm *kvm) -{ - pgd_t *pgd = kvm->arch.pgd; - pud_t *pud; - - if (KVM_PREALLOC_LEVEL == 0) - return pgd; - - pud = pud_offset(pgd, 0); - if (KVM_PREALLOC_LEVEL == 1) - return pud; - - BUG_ON(KVM_PREALLOC_LEVEL != 2); - return pmd_offset(pud, 0); -} - -static inline unsigned int kvm_get_hwpgd_size(void) -{ - if (KVM_PREALLOC_LEVEL > 0) - return PTRS_PER_S2_PGD * PAGE_SIZE; - return PTRS_PER_S2_PGD * sizeof(pgd_t); + return kvm_s2pte_readonly((pte_t *)pmd); } static inline bool kvm_page_empty(void *ptr) @@ -215,23 +161,20 @@ static inline bool kvm_page_empty(void *ptr) return page_count(ptr_page) == 1; } -#define kvm_pte_table_empty(kvm, ptep) kvm_page_empty(ptep) +#define hyp_pte_table_empty(ptep) kvm_page_empty(ptep) #ifdef __PAGETABLE_PMD_FOLDED -#define kvm_pmd_table_empty(kvm, pmdp) (0) +#define hyp_pmd_table_empty(pmdp) (0) #else -#define kvm_pmd_table_empty(kvm, pmdp) \ - (kvm_page_empty(pmdp) && (!(kvm) || KVM_PREALLOC_LEVEL < 2)) +#define hyp_pmd_table_empty(pmdp) kvm_page_empty(pmdp) #endif #ifdef __PAGETABLE_PUD_FOLDED -#define kvm_pud_table_empty(kvm, pudp) (0) +#define hyp_pud_table_empty(pudp) (0) #else -#define kvm_pud_table_empty(kvm, pudp) \ - (kvm_page_empty(pudp) && (!(kvm) || KVM_PREALLOC_LEVEL < 1)) +#define hyp_pud_table_empty(pudp) kvm_page_empty(pudp) #endif - struct kvm; #define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l)) diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h index 9786f77..2813748 100644 --- a/arch/arm64/include/asm/pgtable-hwdef.h +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -207,23 +207,69 @@ #define TCR_T1SZ(x) ((UL(64) - (x)) << TCR_T1SZ_OFFSET) #define TCR_TxSZ(x) (TCR_T0SZ(x) | TCR_T1SZ(x)) #define TCR_TxSZ_WIDTH 6 -#define TCR_IRGN_NC ((UL(0) << 8) | (UL(0) << 24)) -#define TCR_IRGN_WBWA ((UL(1) << 8) | (UL(1) << 24)) -#define TCR_IRGN_WT ((UL(2) << 8) | (UL(2) << 24)) -#define TCR_IRGN_WBnWA ((UL(3) << 8) | (UL(3) << 24)) -#define TCR_IRGN_MASK ((UL(3) << 8) | (UL(3) << 24)) -#define TCR_ORGN_NC ((UL(0) << 10) | (UL(0) << 26)) -#define TCR_ORGN_WBWA ((UL(1) << 10) | (UL(1) << 26)) -#define TCR_ORGN_WT ((UL(2) << 10) | (UL(2) << 26)) -#define TCR_ORGN_WBnWA ((UL(3) << 10) | (UL(3) << 26)) -#define TCR_ORGN_MASK ((UL(3) << 10) | (UL(3) << 26)) -#define TCR_SHARED ((UL(3) << 12) | (UL(3) << 28)) -#define TCR_TG0_4K (UL(0) << 14) -#define TCR_TG0_64K (UL(1) << 14) -#define TCR_TG0_16K (UL(2) << 14) -#define TCR_TG1_16K (UL(1) << 30) -#define TCR_TG1_4K (UL(2) << 30) -#define TCR_TG1_64K (UL(3) << 30) + +#define TCR_IRGN0_SHIFT 8 +#define TCR_IRGN0_MASK (UL(3) << TCR_IRGN0_SHIFT) +#define TCR_IRGN0_NC (UL(0) << TCR_IRGN0_SHIFT) +#define TCR_IRGN0_WBWA (UL(1) << TCR_IRGN0_SHIFT) +#define TCR_IRGN0_WT (UL(2) << TCR_IRGN0_SHIFT) +#define TCR_IRGN0_WBnWA (UL(3) << TCR_IRGN0_SHIFT) + +#define TCR_IRGN1_SHIFT 24 +#define TCR_IRGN1_MASK (UL(3) << TCR_IRGN1_SHIFT) +#define TCR_IRGN1_NC (UL(0) << TCR_IRGN1_SHIFT) +#define TCR_IRGN1_WBWA (UL(1) << TCR_IRGN1_SHIFT) +#define TCR_IRGN1_WT (UL(2) << TCR_IRGN1_SHIFT) +#define TCR_IRGN1_WBnWA (UL(3) << TCR_IRGN1_SHIFT) + +#define TCR_IRGN_NC (TCR_IRGN0_NC | TCR_IRGN1_NC) +#define TCR_IRGN_WBWA (TCR_IRGN0_WBWA | TCR_IRGN1_WBWA) +#define TCR_IRGN_WT (TCR_IRGN0_WT | TCR_IRGN1_WT) +#define TCR_IRGN_WBnWA (TCR_IRGN0_WBnWA | TCR_IRGN1_WBnWA) +#define TCR_IRGN_MASK (TCR_IRGN0_MASK | TCR_IRGN1_MASK) + + +#define TCR_ORGN0_SHIFT 10 +#define TCR_ORGN0_MASK (UL(3) << TCR_ORGN0_SHIFT) +#define TCR_ORGN0_NC (UL(0) << TCR_ORGN0_SHIFT) +#define TCR_ORGN0_WBWA (UL(1) << TCR_ORGN0_SHIFT) +#define TCR_ORGN0_WT (UL(2) << TCR_ORGN0_SHIFT) +#define TCR_ORGN0_WBnWA (UL(3) << TCR_ORGN0_SHIFT) + +#define TCR_ORGN1_SHIFT 26 +#define TCR_ORGN1_MASK (UL(3) << TCR_ORGN1_SHIFT) +#define TCR_ORGN1_NC (UL(0) << TCR_ORGN1_SHIFT) +#define TCR_ORGN1_WBWA (UL(1) << TCR_ORGN1_SHIFT) +#define TCR_ORGN1_WT (UL(2) << TCR_ORGN1_SHIFT) +#define TCR_ORGN1_WBnWA (UL(3) << TCR_ORGN1_SHIFT) + +#define TCR_ORGN_NC (TCR_ORGN0_NC | TCR_ORGN1_NC) +#define TCR_ORGN_WBWA (TCR_ORGN0_WBWA | TCR_ORGN1_WBWA) +#define TCR_ORGN_WT (TCR_ORGN0_WT | TCR_ORGN1_WT) +#define TCR_ORGN_WBnWA (TCR_ORGN0_WBnWA | TCR_ORGN1_WBnWA) +#define TCR_ORGN_MASK (TCR_ORGN0_MASK | TCR_ORGN1_MASK) + +#define TCR_SH0_SHIFT 12 +#define TCR_SH0_MASK (UL(3) << TCR_SH0_SHIFT) +#define TCR_SH0_INNER (UL(3) << TCR_SH0_SHIFT) + +#define TCR_SH1_SHIFT 28 +#define TCR_SH1_MASK (UL(3) << TCR_SH1_SHIFT) +#define TCR_SH1_INNER (UL(3) << TCR_SH1_SHIFT) +#define TCR_SHARED (TCR_SH0_INNER | TCR_SH1_INNER) + +#define TCR_TG0_SHIFT 14 +#define TCR_TG0_MASK (UL(3) << TCR_TG0_SHIFT) +#define TCR_TG0_4K (UL(0) << TCR_TG0_SHIFT) +#define TCR_TG0_64K (UL(1) << TCR_TG0_SHIFT) +#define TCR_TG0_16K (UL(2) << TCR_TG0_SHIFT) + +#define TCR_TG1_SHIFT 30 +#define TCR_TG1_MASK (UL(3) << TCR_TG1_SHIFT) +#define TCR_TG1_16K (UL(1) << TCR_TG1_SHIFT) +#define TCR_TG1_4K (UL(2) << TCR_TG1_SHIFT) +#define TCR_TG1_64K (UL(3) << TCR_TG1_SHIFT) + #define TCR_ASID16 (UL(1) << 36) #define TCR_TBI0 (UL(1) << 37) #define TCR_HA (UL(1) << 39) diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index a7ac45a..46472a9 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -300,6 +300,8 @@ static inline int pmd_protnone(pmd_t pmd) #define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) #define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) & ~PMD_SECT_VALID)) +#define pmd_thp_or_huge(pmd) (pmd_huge(pmd) || pmd_trans_huge(pmd)) + #define __HAVE_ARCH_PMD_WRITE #define pmd_write(pmd) pte_write(pmd_pte(pmd)) @@ -549,14 +551,12 @@ static inline int pmdp_set_access_flags(struct vm_area_struct *vma, * Atomic pte/pmd modifications. */ #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG -static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, - unsigned long address, - pte_t *ptep) +static inline int __ptep_test_and_clear_young(pte_t *ptep) { pteval_t pteval; unsigned int tmp, res; - asm volatile("// ptep_test_and_clear_young\n" + asm volatile("// __ptep_test_and_clear_young\n" " prfm pstl1strm, %2\n" "1: ldxr %0, %2\n" " ubfx %w3, %w0, %5, #1 // extract PTE_AF (young)\n" @@ -569,6 +569,13 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, return res; } +static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, + pte_t *ptep) +{ + return __ptep_test_and_clear_young(ptep); +} + #ifdef CONFIG_TRANSPARENT_HUGEPAGE #define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, diff --git a/arch/arm64/include/asm/stage2_pgtable-nopmd.h b/arch/arm64/include/asm/stage2_pgtable-nopmd.h new file mode 100644 index 0000000..2656a0f --- /dev/null +++ b/arch/arm64/include/asm/stage2_pgtable-nopmd.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 - ARM Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __ARM64_S2_PGTABLE_NOPMD_H_ +#define __ARM64_S2_PGTABLE_NOPMD_H_ + +#include <asm/stage2_pgtable-nopud.h> + +#define __S2_PGTABLE_PMD_FOLDED + +#define S2_PMD_SHIFT S2_PUD_SHIFT +#define S2_PTRS_PER_PMD 1 +#define S2_PMD_SIZE (1UL << S2_PMD_SHIFT) +#define S2_PMD_MASK (~(S2_PMD_SIZE-1)) + +#define stage2_pud_none(pud) (0) +#define stage2_pud_present(pud) (1) +#define stage2_pud_clear(pud) do { } while (0) +#define stage2_pud_populate(pud, pmd) do { } while (0) +#define stage2_pmd_offset(pud, address) ((pmd_t *)(pud)) + +#define stage2_pmd_free(pmd) do { } while (0) + +#define stage2_pmd_addr_end(addr, end) (end) + +#define stage2_pud_huge(pud) (0) +#define stage2_pmd_table_empty(pmdp) (0) + +#endif diff --git a/arch/arm64/include/asm/stage2_pgtable-nopud.h b/arch/arm64/include/asm/stage2_pgtable-nopud.h new file mode 100644 index 0000000..5ee87b5 --- /dev/null +++ b/arch/arm64/include/asm/stage2_pgtable-nopud.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 - ARM Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __ARM64_S2_PGTABLE_NOPUD_H_ +#define __ARM64_S2_PGTABLE_NOPUD_H_ + +#define __S2_PGTABLE_PUD_FOLDED + +#define S2_PUD_SHIFT S2_PGDIR_SHIFT +#define S2_PTRS_PER_PUD 1 +#define S2_PUD_SIZE (_AC(1, UL) << S2_PUD_SHIFT) +#define S2_PUD_MASK (~(S2_PUD_SIZE-1)) + +#define stage2_pgd_none(pgd) (0) +#define stage2_pgd_present(pgd) (1) +#define stage2_pgd_clear(pgd) do { } while (0) +#define stage2_pgd_populate(pgd, pud) do { } while (0) + +#define stage2_pud_offset(pgd, address) ((pud_t *)(pgd)) + +#define stage2_pud_free(x) do { } while (0) + +#define stage2_pud_addr_end(addr, end) (end) +#define stage2_pud_table_empty(pmdp) (0) + +#endif diff --git a/arch/arm64/include/asm/stage2_pgtable.h b/arch/arm64/include/asm/stage2_pgtable.h new file mode 100644 index 0000000..8b68099 --- /dev/null +++ b/arch/arm64/include/asm/stage2_pgtable.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2016 - ARM Ltd + * + * stage2 page table helpers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __ARM64_S2_PGTABLE_H_ +#define __ARM64_S2_PGTABLE_H_ + +#include <asm/pgtable.h> + +/* + * The hardware supports concatenation of up to 16 tables at stage2 entry level + * and we use the feature whenever possible. + * + * Now, the minimum number of bits resolved at any level is (PAGE_SHIFT - 3). + * On arm64, the smallest PAGE_SIZE supported is 4k, which means + * (PAGE_SHIFT - 3) > 4 holds for all page sizes. + * This implies, the total number of page table levels at stage2 expected + * by the hardware is actually the number of levels required for (KVM_PHYS_SHIFT - 4) + * in normal translations(e.g, stage1), since we cannot have another level in + * the range (KVM_PHYS_SHIFT, KVM_PHYS_SHIFT - 4). + */ +#define STAGE2_PGTABLE_LEVELS ARM64_HW_PGTABLE_LEVELS(KVM_PHYS_SHIFT - 4) + +/* + * With all the supported VA_BITs and 40bit guest IPA, the following condition + * is always true: + * + * STAGE2_PGTABLE_LEVELS <= CONFIG_PGTABLE_LEVELS + * + * We base our stage-2 page table walker helpers on this assumption and + * fall back to using the host version of the helper wherever possible. + * i.e, if a particular level is not folded (e.g, PUD) at stage2, we fall back + * to using the host version, since it is guaranteed it is not folded at host. + * + * If the condition breaks in the future, we can rearrange the host level + * definitions and reuse them for stage2. Till then... + */ +#if STAGE2_PGTABLE_LEVELS > CONFIG_PGTABLE_LEVELS +#error "Unsupported combination of guest IPA and host VA_BITS." +#endif + +/* S2_PGDIR_SHIFT is the size mapped by top-level stage2 entry */ +#define S2_PGDIR_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - STAGE2_PGTABLE_LEVELS) +#define S2_PGDIR_SIZE (_AC(1, UL) << S2_PGDIR_SHIFT) +#define S2_PGDIR_MASK (~(S2_PGDIR_SIZE - 1)) + +/* + * The number of PTRS across all concatenated stage2 tables given by the + * number of bits resolved at the initial level. + */ +#define PTRS_PER_S2_PGD (1 << (KVM_PHYS_SHIFT - S2_PGDIR_SHIFT)) + +/* + * KVM_MMU_CACHE_MIN_PAGES is the number of stage2 page table translation + * levels in addition to the PGD. + */ +#define KVM_MMU_CACHE_MIN_PAGES (STAGE2_PGTABLE_LEVELS - 1) + + +#if STAGE2_PGTABLE_LEVELS > 3 + +#define S2_PUD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(1) +#define S2_PUD_SIZE (_AC(1, UL) << S2_PUD_SHIFT) +#define S2_PUD_MASK (~(S2_PUD_SIZE - 1)) + +#define stage2_pgd_none(pgd) pgd_none(pgd) +#define stage2_pgd_clear(pgd) pgd_clear(pgd) +#define stage2_pgd_present(pgd) pgd_present(pgd) +#define stage2_pgd_populate(pgd, pud) pgd_populate(NULL, pgd, pud) +#define stage2_pud_offset(pgd, address) pud_offset(pgd, address) +#define stage2_pud_free(pud) pud_free(NULL, pud) + +#define stage2_pud_table_empty(pudp) kvm_page_empty(pudp) + +static inline phys_addr_t stage2_pud_addr_end(phys_addr_t addr, phys_addr_t end) +{ + phys_addr_t boundary = (addr + S2_PUD_SIZE) & S2_PUD_MASK; + + return (boundary - 1 < end - 1) ? boundary : end; +} + +#endif /* STAGE2_PGTABLE_LEVELS > 3 */ + + +#if STAGE2_PGTABLE_LEVELS > 2 + +#define S2_PMD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(2) +#define S2_PMD_SIZE (_AC(1, UL) << S2_PMD_SHIFT) +#define S2_PMD_MASK (~(S2_PMD_SIZE - 1)) + +#define stage2_pud_none(pud) pud_none(pud) +#define stage2_pud_clear(pud) pud_clear(pud) +#define stage2_pud_present(pud) pud_present(pud) +#define stage2_pud_populate(pud, pmd) pud_populate(NULL, pud, pmd) +#define stage2_pmd_offset(pud, address) pmd_offset(pud, address) +#define stage2_pmd_free(pmd) pmd_free(NULL, pmd) + +#define stage2_pud_huge(pud) pud_huge(pud) +#define stage2_pmd_table_empty(pmdp) kvm_page_empty(pmdp) + +static inline phys_addr_t stage2_pmd_addr_end(phys_addr_t addr, phys_addr_t end) +{ + phys_addr_t boundary = (addr + S2_PMD_SIZE) & S2_PMD_MASK; + + return (boundary - 1 < end - 1) ? boundary : end; +} + +#endif /* STAGE2_PGTABLE_LEVELS > 2 */ + +#define stage2_pte_table_empty(ptep) kvm_page_empty(ptep) + +#if STAGE2_PGTABLE_LEVELS == 2 +#include <asm/stage2_pgtable-nopmd.h> +#elif STAGE2_PGTABLE_LEVELS == 3 +#include <asm/stage2_pgtable-nopud.h> +#endif + + +#define stage2_pgd_index(addr) (((addr) >> S2_PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1)) + +static inline phys_addr_t stage2_pgd_addr_end(phys_addr_t addr, phys_addr_t end) +{ + phys_addr_t boundary = (addr + S2_PGDIR_SIZE) & S2_PGDIR_MASK; + + return (boundary - 1 < end - 1) ? boundary : end; +} + +#endif /* __ARM64_S2_PGTABLE_H_ */ diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index de7450d..aa2e34e 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -22,7 +22,6 @@ config KVM_ARM_VGIC_V3 config KVM bool "Kernel-based Virtual Machine (KVM) support" depends on OF - depends on !ARM64_16K_PAGES select MMU_NOTIFIER select PREEMPT_NOTIFIERS select ANON_INODES diff --git a/arch/arm64/kvm/hyp/s2-setup.c b/arch/arm64/kvm/hyp/s2-setup.c index bcbe761..b81f409 100644 --- a/arch/arm64/kvm/hyp/s2-setup.c +++ b/arch/arm64/kvm/hyp/s2-setup.c @@ -66,6 +66,14 @@ u32 __hyp_text __init_stage2_translation(void) val |= 64 - (parange > 40 ? 40 : parange); /* + * Check the availability of Hardware Access Flag / Dirty Bit + * Management in ID_AA64MMFR1_EL1 and enable the feature in VTCR_EL2. + */ + tmp = (read_sysreg(id_aa64mmfr1_el1) >> ID_AA64MMFR1_HADBS_SHIFT) & 0xf; + if (IS_ENABLED(CONFIG_ARM64_HW_AFDBM) && tmp) + val |= VTCR_EL2_HA; + + /* * Read the VMIDBits bits from ID_AA64MMFR1_EL1 and set the VS * bit in VTCR_EL2. */ diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index fd8b942..c566ec8 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -562,8 +562,8 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size, struct page **pages; pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent); - pages = iommu_dma_alloc(dev, iosize, gfp, ioprot, handle, - flush_page); + pages = iommu_dma_alloc(dev, iosize, gfp, attrs, ioprot, + handle, flush_page); if (!pages) return NULL; @@ -947,13 +947,13 @@ void arch_teardown_dma_ops(struct device *dev) #else static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - struct iommu_ops *iommu) + const struct iommu_ops *iommu) { } #endif /* CONFIG_IOMMU_DMA */ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - struct iommu_ops *iommu, bool coherent) + const struct iommu_ops *iommu, bool coherent) { if (!dev->archdata.dma_ops) dev->archdata.dma_ops = &swiotlb_dma_ops; diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index bf445aa..00d6dcc 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -1365,8 +1365,8 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data) slave->dma_dev = &dw_dmac0_device.dev; slave->src_id = 0; slave->dst_id = 1; - slave->src_master = 1; - slave->dst_master = 0; + slave->m_master = 1; + slave->p_master = 0; data->dma_slave = slave; data->dma_filter = at32_mci_dma_filter; @@ -2061,16 +2061,16 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data, if (flags & AC97C_CAPTURE) { rx_dws->dma_dev = &dw_dmac0_device.dev; rx_dws->src_id = 3; - rx_dws->src_master = 0; - rx_dws->dst_master = 1; + rx_dws->m_master = 0; + rx_dws->p_master = 1; } /* Check if DMA slave interface for playback should be configured. */ if (flags & AC97C_PLAYBACK) { tx_dws->dma_dev = &dw_dmac0_device.dev; tx_dws->dst_id = 4; - tx_dws->src_master = 0; - tx_dws->dst_master = 1; + tx_dws->m_master = 0; + tx_dws->p_master = 1; } if (platform_device_add_data(pdev, data, @@ -2141,8 +2141,8 @@ at32_add_device_abdac(unsigned int id, struct atmel_abdac_pdata *data) dws->dma_dev = &dw_dmac0_device.dev; dws->dst_id = 2; - dws->src_master = 0; - dws->dst_master = 1; + dws->m_master = 0; + dws->p_master = 1; if (platform_device_add_data(pdev, data, sizeof(struct atmel_abdac_pdata))) diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 2889412..07a4e32 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -1904,13 +1904,10 @@ static int mca_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { - int hotcpu = (unsigned long) hcpu; - switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: - smp_call_function_single(hotcpu, ia64_mca_cmc_vector_adjust, - NULL, 0); + ia64_mca_cmc_vector_adjust(NULL); break; } return NOTIFY_OK; diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index 6f7d4a4..77edd68 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -548,6 +548,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, return; } switch (vector) { + default: case 29: siginfo.si_code = TRAP_HWBKPT; #ifdef CONFIG_ITANIUM diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index e7ae608..7f0d316 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -1378,6 +1378,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) * extract the instruction from the bundle given the slot number */ switch (ipsr->ri) { + default: case 0: u.l = (bundle[0] >> 5); break; case 1: u.l = (bundle[0] >> 46) | (bundle[1] << 18); break; case 2: u.l = (bundle[1] >> 23); break; diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c index 231234c..c31fe63 100644 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ b/arch/ia64/sn/kernel/io_acpi_init.c @@ -426,7 +426,6 @@ sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info, void sn_acpi_slot_fixup(struct pci_dev *dev) { - void __iomem *addr; struct pcidev_info *pcidev_info = NULL; struct sn_irq_info *sn_irq_info = NULL; struct resource *res; diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index c15a41e..d63809a 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -151,7 +151,7 @@ sn_io_slot_fixup(struct pci_dev *dev) { int idx; struct resource *res; - unsigned long addr, size; + unsigned long size; struct pcidev_info *pcidev_info; struct sn_irq_info *sn_irq_info; int status; @@ -186,7 +186,7 @@ sn_io_slot_fixup(struct pci_dev *dev) continue; res->start = pcidev_info->pdi_pio_mapped_addr[idx]; - res->end = addr + size; + res->end = res->start + size; /* * if it's already in the device structure, remove it before diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index f9c8d9f..c98dc96 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c @@ -54,7 +54,7 @@ sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long); void -sn2_ptc_deadlock_recovery(short *, short, short, int, +sn2_ptc_deadlock_recovery(nodemask_t, short, short, int, volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long); @@ -169,7 +169,7 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, int use_cpu_ptcga; volatile unsigned long *ptc0, *ptc1; unsigned long itc, itc2, flags, data0 = 0, data1 = 0, rr_value, old_rr = 0; - short nasids[MAX_NUMNODES], nix; + short nix; nodemask_t nodes_flushed; int active, max_active, deadlock, flush_opt = sn2_flush_opt; @@ -218,9 +218,7 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, } itc = ia64_get_itc(); - nix = 0; - for_each_node_mask(cnode, nodes_flushed) - nasids[nix++] = cnodeid_to_nasid(cnode); + nix = nodes_weight(nodes_flushed); rr_value = (mm->context << 3) | REGION_NUMBER(start); @@ -270,8 +268,10 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK); deadlock = 0; active = 0; - for (ibegin = 0, i = 0; i < nix; i++) { - nasid = nasids[i]; + ibegin = 0; + i = 0; + for_each_node_mask(cnode, nodes_flushed) { + nasid = cnodeid_to_nasid(cnode); if (use_cpu_ptcga && unlikely(nasid == mynasid)) { ia64_ptcga(start, nbits << 2); ia64_srlz_i(); @@ -286,13 +286,14 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, if ((deadlock = wait_piowc())) { if (flush_opt == 1) goto done; - sn2_ptc_deadlock_recovery(nasids, ibegin, i, mynasid, ptc0, data0, ptc1, data1); + sn2_ptc_deadlock_recovery(nodes_flushed, ibegin, i, mynasid, ptc0, data0, ptc1, data1); if (reset_max_active_on_deadlock()) max_active = 1; } active = 0; ibegin = i + 1; } + i++; } start += (1UL << nbits); } while (start < end); @@ -327,11 +328,12 @@ done: */ void -sn2_ptc_deadlock_recovery(short *nasids, short ib, short ie, int mynasid, +sn2_ptc_deadlock_recovery(nodemask_t nodes, short ib, short ie, int mynasid, volatile unsigned long *ptc0, unsigned long data0, volatile unsigned long *ptc1, unsigned long data1) { short nasid, i; + int cnode; unsigned long *piows, zeroval, n; __this_cpu_inc(ptcstats.deadlocks); @@ -339,17 +341,26 @@ sn2_ptc_deadlock_recovery(short *nasids, short ib, short ie, int mynasid, piows = (unsigned long *) pda->pio_write_status_addr; zeroval = pda->pio_write_status_val; + i = 0; + for_each_node_mask(cnode, nodes) { + if (i < ib) + goto next; + + if (i > ie) + break; - for (i=ib; i <= ie; i++) { - nasid = nasids[i]; + nasid = cnodeid_to_nasid(cnode); if (local_node_uses_ptc_ga(is_shub1()) && nasid == mynasid) - continue; + goto next; + ptc0 = CHANGE_NASID(nasid, ptc0); if (ptc1) ptc1 = CHANGE_NASID(nasid, ptc1); n = sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval); __this_cpu_add(ptcstats.deadlocks2, n); +next: + i++; } } diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index d2ac117..5663f41 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -62,6 +62,7 @@ config MIPS select HAVE_IRQ_TIME_ACCOUNTING select GENERIC_TIME_VSYSCALL select ARCH_CLOCKSOURCE_DATA + select HANDLE_DOMAIN_IRQ menu "Machine selection" @@ -137,7 +138,7 @@ config ATH79 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_MIPS16 - select SYS_SUPPORTS_ZBOOT + select SYS_SUPPORTS_ZBOOT_UART_PROM select USE_OF help Support for the Atheros AR71XX/AR724X/AR913X SoCs. @@ -194,6 +195,7 @@ config BCM47XX select GPIOLIB select LEDS_GPIO_REGISTER select BCM47XX_NVRAM + select BCM47XX_SPROM help Support for BCM47XX based boards @@ -471,6 +473,7 @@ config MIPS_MALTA select SYS_SUPPORTS_MULTITHREADING select SYS_SUPPORTS_SMARTMIPS select SYS_SUPPORTS_ZBOOT + select SYS_SUPPORTS_RELOCATABLE select USE_OF select ZONE_DMA32 if 64BIT select BUILTIN_DTB @@ -505,6 +508,7 @@ config MIPS_SEAD3 select MIPS_MSC select SYS_HAS_CPU_MIPS32_R1 select SYS_HAS_CPU_MIPS32_R2 + select SYS_HAS_CPU_MIPS32_R6 select SYS_HAS_CPU_MIPS64_R1 select SYS_HAS_EARLY_PRINTK select SYS_SUPPORTS_32BIT_KERNEL @@ -514,6 +518,7 @@ config MIPS_SEAD3 select SYS_SUPPORTS_SMARTMIPS select SYS_SUPPORTS_MICROMIPS select SYS_SUPPORTS_MIPS16 + select SYS_SUPPORTS_RELOCATABLE select USB_EHCI_BIG_ENDIAN_DESC select USB_EHCI_BIG_ENDIAN_MMIO select USE_OF @@ -1153,6 +1158,13 @@ config ISA_DMA_API config HOLES_IN_ZONE bool +config SYS_SUPPORTS_RELOCATABLE + bool + help + Selected if the platform supports relocating the kernel. + The platform must provide plat_get_fdt() if it selects CONFIG_USE_OF + to allow access to command line and entropy sources. + # # Endianness selection. Sufficiently obscure so many users don't know what to # answer,so we try hard to limit the available choices. Also the use of a @@ -1340,11 +1352,30 @@ config CPU_LOONGSON3 select CPU_SUPPORTS_HUGEPAGES select WEAK_ORDERING select WEAK_REORDERING_BEYOND_LLSC + select MIPS_PGD_C0_CONTEXT select GPIOLIB help The Loongson 3 processor implements the MIPS64R2 instruction set with many extensions. +config LOONGSON3_ENHANCEMENT + bool "New Loongson 3 CPU Enhancements" + default n + select CPU_MIPSR2 + select CPU_HAS_PREFETCH + depends on CPU_LOONGSON3 + help + New Loongson 3 CPU (since Loongson-3A R2, as opposed to Loongson-3A + R1, Loongson-3B R1 and Loongson-3B R2) has many enhancements, such as + FTLB, L1-VCache, EI/DI/Wait/Prefetch instruction, DSP/DSPv2 ASE, User + Local register, Read-Inhibit/Execute-Inhibit, SFB (Store Fill Buffer), + Fast TLB refill support, etc. + + This option enable those enhancements which are not probed at run + time. If you want a generic kernel to run on all Loongson 3 machines, + please say 'N' here. If you want a high-performance kernel to run on + new Loongson 3 machines only, please say 'Y' here. + config CPU_LOONGSON2E bool "Loongson 2E" depends on SYS_HAS_CPU_LOONGSON2E @@ -1373,6 +1404,8 @@ config CPU_LOONGSON1B bool "Loongson 1B" depends on SYS_HAS_CPU_LOONGSON1B select CPU_LOONGSON1 + select ARCH_WANT_OPTIONAL_GPIOLIB + select LEDS_GPIO_REGISTER help The Loongson 1B is a 32-bit SoC, which implements the MIPS32 release 2 instruction set. @@ -1671,6 +1704,7 @@ config CPU_XLP select CPU_HAS_PREFETCH select CPU_MIPSR2 select CPU_SUPPORTS_HUGEPAGES + select MIPS_ASID_BITS_VARIABLE help Netlogic Microsystems XLP processors. endchoice @@ -1796,6 +1830,7 @@ config CPU_BMIPS4380 select MIPS_L1_CACHE_SHIFT_6 select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU + select CPU_HAS_RIXI config CPU_BMIPS5000 bool @@ -1803,10 +1838,12 @@ config CPU_BMIPS5000 select MIPS_L1_CACHE_SHIFT_7 select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU + select CPU_HAS_RIXI config SYS_HAS_CPU_LOONGSON3 bool select CPU_SUPPORTS_CPUFREQ + select CPU_HAS_RIXI config SYS_HAS_CPU_LOONGSON2E bool @@ -1959,11 +1996,15 @@ config CPU_MIPSR1 config CPU_MIPSR2 bool default y if CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_CAVIUM_OCTEON + select CPU_HAS_RIXI select MIPS_SPRAM config CPU_MIPSR6 bool default y if CPU_MIPS32_R6 || CPU_MIPS64_R6 + select CPU_HAS_RIXI + select HAVE_ARCH_BITREVERSE + select MIPS_ASID_BITS_VARIABLE select MIPS_SPRAM config EVA @@ -1997,7 +2038,7 @@ config MIPS_PGD_C0_CONTEXT # config HARDWARE_WATCHPOINTS bool - default y if CPU_MIPSR1 || CPU_MIPSR2 + default y if CPU_MIPSR1 || CPU_MIPSR2 || CPU_MIPSR6 menu "Kernel type" @@ -2040,6 +2081,16 @@ config KVM_GUEST_TIMER_FREQ emulation when determining guest CPU Frequency. Instead, the guest's timer frequency is specified directly. +config MIPS_VA_BITS_48 + bool "48 bits virtual memory" + depends on 64BIT + help + Support a maximum at least 48 bits of application virtual memory. + Default is 40 bits or less, depending on the CPU. + This option result in a small memory overhead for page tables. + This option is only supported with 16k and 64k page sizes. + If unsure, say N. + choice prompt "Kernel page size" default PAGE_SIZE_4KB @@ -2047,6 +2098,7 @@ choice config PAGE_SIZE_4KB bool "4kB" depends on !CPU_LOONGSON2 && !CPU_LOONGSON3 + depends on !MIPS_VA_BITS_48 help This option select the standard 4kB Linux page size. On some R3000-family processors this is the only available page size. Using @@ -2056,6 +2108,7 @@ config PAGE_SIZE_4KB config PAGE_SIZE_8KB bool "8kB" depends on CPU_R8000 || CPU_CAVIUM_OCTEON + depends on !MIPS_VA_BITS_48 help Using 8kB page size will result in higher performance kernel at the price of higher memory consumption. This option is available @@ -2074,6 +2127,7 @@ config PAGE_SIZE_16KB config PAGE_SIZE_32KB bool "32kB" depends on CPU_CAVIUM_OCTEON + depends on !MIPS_VA_BITS_48 help Using 32kB page size will result in higher performance kernel at the price of higher memory consumption. This option is available @@ -2278,7 +2332,7 @@ config MIPS_CMP config MIPS_CPS bool "MIPS Coherent Processing System support" - depends on SYS_SUPPORTS_MIPS_CPS && !CPU_MIPSR6 + depends on SYS_SUPPORTS_MIPS_CPS select MIPS_CM select MIPS_CPC select MIPS_CPS_PM if HOTPLUG_CPU @@ -2369,6 +2423,9 @@ config CPU_HAS_WB config XKS01 bool +config CPU_HAS_RIXI + bool + # # Vectored interrupt mode is an R2 feature # @@ -2399,6 +2456,21 @@ config CPU_R4000_WORKAROUNDS config CPU_R4400_WORKAROUNDS bool +config MIPS_ASID_SHIFT + int + default 6 if CPU_R3000 || CPU_TX39XX + default 4 if CPU_R8000 + default 0 + +config MIPS_ASID_BITS + int + default 0 if MIPS_ASID_BITS_VARIABLE + default 6 if CPU_R3000 || CPU_TX39XX + default 8 + +config MIPS_ASID_BITS_VARIABLE + bool + # # - Highmem only makes sense for the 32-bit kernel. # - The current highmem code will only work properly on physically indexed @@ -2468,6 +2540,61 @@ config NUMA config SYS_SUPPORTS_NUMA bool +config RELOCATABLE + bool "Relocatable kernel" + depends on SYS_SUPPORTS_RELOCATABLE && (CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_MIPS32_R6 || CPU_MIPS64_R6) + help + This builds a kernel image that retains relocation information + so it can be loaded someplace besides the default 1MB. + The relocations make the kernel binary about 15% larger, + but are discarded at runtime + +config RELOCATION_TABLE_SIZE + hex "Relocation table size" + depends on RELOCATABLE + range 0x0 0x01000000 + default "0x00100000" + ---help--- + A table of relocation data will be appended to the kernel binary + and parsed at boot to fix up the relocated kernel. + + This option allows the amount of space reserved for the table to be + adjusted, although the default of 1Mb should be ok in most cases. + + The build will fail and a valid size suggested if this is too small. + + If unsure, leave at the default value. + +config RANDOMIZE_BASE + bool "Randomize the address of the kernel image" + depends on RELOCATABLE + ---help--- + Randomizes the physical and virtual address at which the + kernel image is loaded, as a security feature that + deters exploit attempts relying on knowledge of the location + of kernel internals. + + Entropy is generated using any coprocessor 0 registers available. + + The kernel will be offset by up to RANDOMIZE_BASE_MAX_OFFSET. + + If unsure, say N. + +config RANDOMIZE_BASE_MAX_OFFSET + hex "Maximum kASLR offset" if EXPERT + depends on RANDOMIZE_BASE + range 0x0 0x40000000 if EVA || 64BIT + range 0x0 0x08000000 + default "0x01000000" + ---help--- + When kASLR is active, this provides the maximum offset that will + be applied to the kernel image. It should be set according to the + amount of physical RAM available in the target system minus + PHYSICAL_START and must be a power of 2. + + This is limited by the size of KSEG0, 256Mb on 32-bit or 1Gb with + EVA or 64-bit. The default is 16Mb. + config NODES_SHIFT int default "6" @@ -2475,7 +2602,7 @@ config NODES_SHIFT config HW_PERF_EVENTS bool "Enable hardware performance counter support for perf events" - depends on PERF_EVENTS && OPROFILE=n && (CPU_MIPS32 || CPU_MIPS64 || CPU_R10000 || CPU_SB1 || CPU_CAVIUM_OCTEON || CPU_XLP || CPU_LOONGSON3) + depends on PERF_EVENTS && !OPROFILE && (CPU_MIPS32 || CPU_MIPS64 || CPU_R10000 || CPU_SB1 || CPU_CAVIUM_OCTEON || CPU_XLP || CPU_LOONGSON3) default y help Enable hardware performance counter support for perf events. If @@ -2808,6 +2935,10 @@ choice config MIPS_CMDLINE_FROM_BOOTLOADER bool "Bootloader kernel arguments if available" + + config MIPS_CMDLINE_BUILTIN_EXTEND + depends on CMDLINE_BOOL + bool "Extend builtin kernel arguments with bootloader arguments" endchoice endmenu diff --git a/arch/mips/Makefile b/arch/mips/Makefile index e78d60d..efd7a9d 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -12,6 +12,9 @@ # for "archclean" cleaning up for this architecture. # +archscripts: scripts_basic + $(Q)$(MAKE) $(build)=arch/mips/boot/tools relocs + KBUILD_DEFCONFIG := ip22_defconfig # @@ -93,6 +96,10 @@ LDFLAGS_vmlinux += -G 0 -static -n -nostdlib KBUILD_AFLAGS_MODULE += -mlong-calls KBUILD_CFLAGS_MODULE += -mlong-calls +ifeq ($(CONFIG_RELOCATABLE),y) +LDFLAGS_vmlinux += --emit-relocs +endif + # # pass -msoft-float to GAS if it supports it. However on newer binutils # (specifically newer than 2.24.51.20140728) we then also need to explicitly @@ -193,6 +200,8 @@ ifeq ($(CONFIG_CPU_HAS_MSA),y) toolchain-msa := $(call cc-option-yn,$(mips-cflags) -mhard-float -mfp64 -Wa$(comma)-mmsa) cflags-$(toolchain-msa) += -DTOOLCHAIN_SUPPORTS_MSA endif +toolchain-virt := $(call cc-option-yn,$(mips-cflags) -mvirt) +cflags-$(toolchain-virt) += -DTOOLCHAIN_SUPPORTS_VIRT cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_NEVER) += -mcompact-branches=never cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_OPTIMAL) += -mcompact-branches=optimal @@ -310,6 +319,10 @@ rom.bin rom.sw: vmlinux $(bootvars-y) $@ endif +CMD_RELOCS = arch/mips/boot/tools/relocs +quiet_cmd_relocs = RELOCS $< + cmd_relocs = $(CMD_RELOCS) $< + # # Some machines like the Indy need 32-bit ELF binaries for booting purposes. # Other need ECOFF, so we build a 32-bit ELF binary for them which we then @@ -318,6 +331,11 @@ endif quiet_cmd_32 = OBJCOPY $@ cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ vmlinux.32: vmlinux +ifeq ($(CONFIG_RELOCATABLE)$(CONFIG_64BIT),yy) +# Currently, objcopy fails to handle the relocations in the elf64 +# So the relocs tool must be run here to remove them first + $(call cmd,relocs) +endif $(call cmd,32) # @@ -333,6 +351,9 @@ all: $(all-y) # boot $(boot-y): $(vmlinux-32) FORCE +ifeq ($(CONFIG_RELOCATABLE)$(CONFIG_32BIT),yy) + $(call cmd,relocs) +endif $(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) \ $(bootvars-y) arch/mips/boot/$@ @@ -385,6 +406,7 @@ endif archclean: $(Q)$(MAKE) $(clean)=arch/mips/boot $(Q)$(MAKE) $(clean)=arch/mips/boot/compressed + $(Q)$(MAKE) $(clean)=arch/mips/boot/tools $(Q)$(MAKE) $(clean)=arch/mips/lasat define archhelp diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index bd34f40..7ba7ea0 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -1043,8 +1043,7 @@ static int __init alchemy_clk_init(void) /* Root of the Alchemy clock tree: external 12MHz crystal osc */ c = clk_register_fixed_rate(NULL, ALCHEMY_ROOT_CLK, NULL, - CLK_IS_ROOT, - ALCHEMY_ROOTCLK_RATE); + 0, ALCHEMY_ROOTCLK_RATE); ERRCK(c) /* CPU core clock */ diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index 13c04cf..dfc6020 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -71,18 +71,6 @@ config ATH79_MACH_UBNT_XM Say 'Y' here if you want your kernel to support the Ubiquiti Networks XM (rev 1.0) board. -choice - prompt "Build a DTB in the kernel" - optional - help - Select a devicetree that should be built into the kernel. - - config DTB_TL_WR1043ND_V1 - bool "TL-WR1043ND Version 1" - select BUILTIN_DTB - select SOC_AR913X -endchoice - endmenu config SOC_AR71XX diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c index 618dfd7..2e73784 100644 --- a/arch/mips/ath79/clock.c +++ b/arch/mips/ath79/clock.c @@ -18,17 +18,21 @@ #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <dt-bindings/clock/ath79-clk.h> #include <asm/div64.h> #include <asm/mach-ath79/ath79.h> #include <asm/mach-ath79/ar71xx_regs.h> #include "common.h" +#include "machtypes.h" #define AR71XX_BASE_FREQ 40000000 #define AR724X_BASE_FREQ 40000000 -static struct clk *clks[3]; +static struct clk *clks[ATH79_CLK_END]; static struct clk_onecell_data clk_data = { .clks = clks, .clk_num = ARRAY_SIZE(clks), @@ -40,7 +44,7 @@ static struct clk *__init ath79_add_sys_clkdev( struct clk *clk; int err; - clk = clk_register_fixed_rate(NULL, id, NULL, CLK_IS_ROOT, rate); + clk = clk_register_fixed_rate(NULL, id, NULL, 0, rate); if (!clk) panic("failed to allocate %s clock structure", id); @@ -78,107 +82,139 @@ static void __init ar71xx_clocks_init(void) ahb_rate = cpu_rate / div; ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + clks[ATH79_CLK_CPU] = ath79_add_sys_clkdev("cpu", cpu_rate); + clks[ATH79_CLK_DDR] = ath79_add_sys_clkdev("ddr", ddr_rate); + clks[ATH79_CLK_AHB] = ath79_add_sys_clkdev("ahb", ahb_rate); clk_add_alias("wdt", NULL, "ahb", NULL); clk_add_alias("uart", NULL, "ahb", NULL); } -static void __init ar724x_clocks_init(void) +static struct clk * __init ath79_reg_ffclk(const char *name, + const char *parent_name, unsigned int mult, unsigned int div) { - unsigned long ref_rate; - unsigned long cpu_rate; - unsigned long ddr_rate; - unsigned long ahb_rate; - u32 pll; - u32 freq; - u32 div; + struct clk *clk; - ref_rate = AR724X_BASE_FREQ; - pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG); + clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div); + if (!clk) + panic("failed to allocate %s clock structure", name); - div = ((pll >> AR724X_PLL_FB_SHIFT) & AR724X_PLL_FB_MASK); - freq = div * ref_rate; + return clk; +} +static void __init ar724x_clk_init(struct clk *ref_clk, void __iomem *pll_base) +{ + u32 pll; + u32 mult, div, ddr_div, ahb_div; + + pll = __raw_readl(pll_base + AR724X_PLL_REG_CPU_CONFIG); + + mult = ((pll >> AR724X_PLL_FB_SHIFT) & AR724X_PLL_FB_MASK); div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK) * 2; - freq /= div; - cpu_rate = freq; + ddr_div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; + ahb_div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; - div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; - ddr_rate = freq / div; + clks[ATH79_CLK_CPU] = ath79_reg_ffclk("cpu", "ref", mult, div); + clks[ATH79_CLK_DDR] = ath79_reg_ffclk("ddr", "ref", mult, div * ddr_div); + clks[ATH79_CLK_AHB] = ath79_reg_ffclk("ahb", "ref", mult, div * ahb_div); +} - div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; - ahb_rate = cpu_rate / div; +static void __init ar724x_clocks_init(void) +{ + struct clk *ref_clk; - ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + ref_clk = ath79_add_sys_clkdev("ref", AR724X_BASE_FREQ); + + ar724x_clk_init(ref_clk, ath79_pll_base); + + /* just make happy plat_time_init() from arch/mips/ath79/setup.c */ + clk_register_clkdev(clks[ATH79_CLK_CPU], "cpu", NULL); + clk_register_clkdev(clks[ATH79_CLK_DDR], "ddr", NULL); + clk_register_clkdev(clks[ATH79_CLK_AHB], "ahb", NULL); clk_add_alias("wdt", NULL, "ahb", NULL); clk_add_alias("uart", NULL, "ahb", NULL); } -static void __init ar933x_clocks_init(void) +static void __init ar9330_clk_init(struct clk *ref_clk, void __iomem *pll_base) { - unsigned long ref_rate; - unsigned long cpu_rate; - unsigned long ddr_rate; - unsigned long ahb_rate; u32 clock_ctrl; - u32 cpu_config; - u32 freq; - u32 t; + u32 ref_div; + u32 ninit_mul; + u32 out_div; - t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); - if (t & AR933X_BOOTSTRAP_REF_CLK_40) - ref_rate = (40 * 1000 * 1000); - else - ref_rate = (25 * 1000 * 1000); + u32 cpu_div; + u32 ddr_div; + u32 ahb_div; - clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG); + clock_ctrl = __raw_readl(pll_base + AR933X_PLL_CLOCK_CTRL_REG); if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { - cpu_rate = ref_rate; - ahb_rate = ref_rate; - ddr_rate = ref_rate; + ref_div = 1; + ninit_mul = 1; + out_div = 1; + + cpu_div = 1; + ddr_div = 1; + ahb_div = 1; } else { - cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG); + u32 cpu_config; + u32 t; + + cpu_config = __raw_readl(pll_base + AR933X_PLL_CPU_CONFIG_REG); t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & AR933X_PLL_CPU_CONFIG_REFDIV_MASK; - freq = ref_rate / t; + ref_div = t; - t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & + ninit_mul = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & AR933X_PLL_CPU_CONFIG_NINT_MASK; - freq *= t; t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; if (t == 0) t = 1; - freq >>= t; + out_div = (1 << t); - t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & + cpu_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1; - cpu_rate = freq / t; - t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & + ddr_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1; - ddr_rate = freq / t; - t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & + ahb_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1; - ahb_rate = freq / t; } - ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + clks[ATH79_CLK_CPU] = ath79_reg_ffclk("cpu", "ref", + ninit_mul, ref_div * out_div * cpu_div); + clks[ATH79_CLK_DDR] = ath79_reg_ffclk("ddr", "ref", + ninit_mul, ref_div * out_div * ddr_div); + clks[ATH79_CLK_AHB] = ath79_reg_ffclk("ahb", "ref", + ninit_mul, ref_div * out_div * ahb_div); +} + +static void __init ar933x_clocks_init(void) +{ + struct clk *ref_clk; + unsigned long ref_rate; + u32 t; + + t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); + if (t & AR933X_BOOTSTRAP_REF_CLK_40) + ref_rate = (40 * 1000 * 1000); + else + ref_rate = (25 * 1000 * 1000); + + ref_clk = ath79_add_sys_clkdev("ref", ref_rate); + + ar9330_clk_init(ref_clk, ath79_pll_base); + + /* just make happy plat_time_init() from arch/mips/ath79/setup.c */ + clk_register_clkdev(clks[ATH79_CLK_CPU], "cpu", NULL); + clk_register_clkdev(clks[ATH79_CLK_DDR], "ddr", NULL); + clk_register_clkdev(clks[ATH79_CLK_AHB], "ahb", NULL); clk_add_alias("wdt", NULL, "ahb", NULL); clk_add_alias("uart", NULL, "ref", NULL); @@ -310,9 +346,9 @@ static void __init ar934x_clocks_init(void) ahb_rate = cpu_pll / (postdiv + 1); ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + clks[ATH79_CLK_CPU] = ath79_add_sys_clkdev("cpu", cpu_rate); + clks[ATH79_CLK_DDR] = ath79_add_sys_clkdev("ddr", ddr_rate); + clks[ATH79_CLK_AHB] = ath79_add_sys_clkdev("ahb", ahb_rate); clk_add_alias("wdt", NULL, "ref", NULL); clk_add_alias("uart", NULL, "ref", NULL); @@ -397,9 +433,9 @@ static void __init qca955x_clocks_init(void) ahb_rate = cpu_pll / (postdiv + 1); ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + clks[ATH79_CLK_CPU] = ath79_add_sys_clkdev("cpu", cpu_rate); + clks[ATH79_CLK_DDR] = ath79_add_sys_clkdev("ddr", ddr_rate); + clks[ATH79_CLK_AHB] = ath79_add_sys_clkdev("ahb", ahb_rate); clk_add_alias("wdt", NULL, "ref", NULL); clk_add_alias("uart", NULL, "ref", NULL); @@ -419,8 +455,6 @@ void __init ath79_clocks_init(void) qca955x_clocks_init(); else BUG(); - - of_clk_init(NULL); } unsigned long __init @@ -447,8 +481,49 @@ static void __init ath79_clocks_init_dt(struct device_node *np) CLK_OF_DECLARE(ar7100, "qca,ar7100-pll", ath79_clocks_init_dt); CLK_OF_DECLARE(ar7240, "qca,ar7240-pll", ath79_clocks_init_dt); -CLK_OF_DECLARE(ar9130, "qca,ar9130-pll", ath79_clocks_init_dt); -CLK_OF_DECLARE(ar9330, "qca,ar9330-pll", ath79_clocks_init_dt); CLK_OF_DECLARE(ar9340, "qca,ar9340-pll", ath79_clocks_init_dt); CLK_OF_DECLARE(ar9550, "qca,qca9550-pll", ath79_clocks_init_dt); + +static void __init ath79_clocks_init_dt_ng(struct device_node *np) +{ + struct clk *ref_clk; + void __iomem *pll_base; + const char *dnfn = of_node_full_name(np); + + ref_clk = of_clk_get(np, 0); + if (IS_ERR(ref_clk)) { + pr_err("%s: of_clk_get failed\n", dnfn); + goto err; + } + + pll_base = of_iomap(np, 0); + if (!pll_base) { + pr_err("%s: can't map pll registers\n", dnfn); + goto err_clk; + } + + if (of_device_is_compatible(np, "qca,ar9130-pll")) + ar724x_clk_init(ref_clk, pll_base); + else if (of_device_is_compatible(np, "qca,ar9330-pll")) + ar9330_clk_init(ref_clk, pll_base); + else { + pr_err("%s: could not find any appropriate clk_init()\n", dnfn); + goto err_clk; + } + + if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) { + pr_err("%s: could not register clk provider\n", dnfn); + goto err_clk; + } + + return; + +err_clk: + clk_put(ref_clk); + +err: + return; +} +CLK_OF_DECLARE(ar9130_clk, "qca,ar9130-pll", ath79_clocks_init_dt_ng); +CLK_OF_DECLARE(ar9330_clk, "qca,ar9330-pll", ath79_clocks_init_dt_ng); #endif diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c index 3cedd1f..d071a3a 100644 --- a/arch/mips/ath79/common.c +++ b/arch/mips/ath79/common.c @@ -46,12 +46,12 @@ void ath79_ddr_ctrl_init(void) { ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE); - if (soc_is_ar71xx() || soc_is_ar934x()) { - ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c; - ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c; - } else { + if (soc_is_ar913x() || soc_is_ar724x() || soc_is_ar933x()) { ath79_ddr_wb_flush_base = ath79_ddr_base + 0x7c; ath79_ddr_pci_win_base = 0; + } else { + ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c; + ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c; } } EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init); @@ -76,14 +76,14 @@ void ath79_ddr_set_pci_windows(void) { BUG_ON(!ath79_ddr_pci_win_base); - __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0); - __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 1); - __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 2); - __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 3); - __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 4); - __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 5); - __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 6); - __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 7); + __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0x0); + __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 0x4); + __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 0x8); + __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 0xc); + __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 0x10); + __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 0x14); + __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 0x18); + __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 0x1c); } EXPORT_SYMBOL_GPL(ath79_ddr_set_pci_windows); diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c index be451ee4a..7adab18 100644 --- a/arch/mips/ath79/setup.c +++ b/arch/mips/ath79/setup.c @@ -17,6 +17,7 @@ #include <linux/bootmem.h> #include <linux/err.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/of_platform.h> #include <linux/of_fdt.h> @@ -203,26 +204,57 @@ void __init plat_mem_setup(void) fdt_start = fw_getenvl("fdt_start"); if (fdt_start) __dt_setup_arch((void *)KSEG0ADDR(fdt_start)); -#ifdef CONFIG_BUILTIN_DTB - else - __dt_setup_arch(__dtb_start); -#endif + else if (fw_arg0 == -2) + __dt_setup_arch((void *)KSEG0ADDR(fw_arg1)); - ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE, - AR71XX_RESET_SIZE); - ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE, - AR71XX_PLL_SIZE); - ath79_detect_sys_type(); - ath79_ddr_ctrl_init(); + if (mips_machtype != ATH79_MACH_GENERIC_OF) { + ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE, + AR71XX_RESET_SIZE); + ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE, + AR71XX_PLL_SIZE); + ath79_detect_sys_type(); + ath79_ddr_ctrl_init(); - if (mips_machtype != ATH79_MACH_GENERIC_OF) detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX); - _machine_restart = ath79_restart; + /* OF machines should use the reset driver */ + _machine_restart = ath79_restart; + } + _machine_halt = ath79_halt; pm_power_off = ath79_halt; } +static void __init ath79_of_plat_time_init(void) +{ + struct device_node *np; + struct clk *clk; + unsigned long cpu_clk_rate; + + of_clk_init(NULL); + + np = of_get_cpu_node(0, NULL); + if (!np) { + pr_err("Failed to get CPU node\n"); + return; + } + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk)); + return; + } + + cpu_clk_rate = clk_get_rate(clk); + + pr_info("CPU clock: %lu.%03lu MHz\n", + cpu_clk_rate / 1000000, (cpu_clk_rate / 1000) % 1000); + + mips_hpt_frequency = cpu_clk_rate / 2; + + clk_put(clk); +} + void __init plat_time_init(void) { unsigned long cpu_clk_rate; @@ -230,6 +262,11 @@ void __init plat_time_init(void) unsigned long ddr_clk_rate; unsigned long ref_clk_rate; + if (IS_ENABLED(CONFIG_OF) && mips_machtype == ATH79_MACH_GENERIC_OF) { + ath79_of_plat_time_init(); + return; + } + ath79_clocks_init(); cpu_clk_rate = ath79_get_sys_clk_rate("cpu"); diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile index 66bea4e..6d86150 100644 --- a/arch/mips/bcm47xx/Makefile +++ b/arch/mips/bcm47xx/Makefile @@ -3,5 +3,5 @@ # under Linux. # -obj-y += irq.o prom.o serial.o setup.o time.o sprom.o +obj-y += irq.o prom.o serial.o setup.o time.o obj-y += board.o buttons.o leds.o workarounds.o diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h index 41796be..0367ac7 100644 --- a/arch/mips/bcm47xx/bcm47xx_private.h +++ b/arch/mips/bcm47xx/bcm47xx_private.h @@ -10,9 +10,6 @@ /* prom.c */ void __init bcm47xx_prom_highmem_init(void); -/* sprom.c */ -void bcm47xx_sprom_register_fallbacks(void); - /* buttons.c */ int __init bcm47xx_buttons_register(void); diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index c807e32..6054d49 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -28,6 +28,7 @@ #include "bcm47xx_private.h" +#include <linux/bcm47xx_sprom.h> #include <linux/export.h> #include <linux/types.h> #include <linux/ethtool.h> @@ -151,7 +152,6 @@ void __init plat_mem_setup(void) pr_info("Using bcma bus\n"); #ifdef CONFIG_BCM47XX_BCMA bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA; - bcm47xx_sprom_register_fallbacks(); bcm47xx_register_bcma(); bcm47xx_set_system_type(bcm47xx_bus.bcma.bus.chipinfo.id); #ifdef CONFIG_HIGHMEM diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c deleted file mode 100644 index ca7ad13..0000000 --- a/arch/mips/bcm47xx/sprom.c +++ /dev/null @@ -1,724 +0,0 @@ -/* - * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> - * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> - * Copyright (C) 2006 Michael Buesch <m@bues.ch> - * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org> - * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <bcm47xx.h> -#include <linux/if_ether.h> -#include <linux/etherdevice.h> - -static void create_key(const char *prefix, const char *postfix, - const char *name, char *buf, int len) -{ - if (prefix && postfix) - snprintf(buf, len, "%s%s%s", prefix, name, postfix); - else if (prefix) - snprintf(buf, len, "%s%s", prefix, name); - else if (postfix) - snprintf(buf, len, "%s%s", name, postfix); - else - snprintf(buf, len, "%s", name); -} - -static int get_nvram_var(const char *prefix, const char *postfix, - const char *name, char *buf, int len, bool fallback) -{ - char key[40]; - int err; - - create_key(prefix, postfix, name, key, sizeof(key)); - - err = bcm47xx_nvram_getenv(key, buf, len); - if (fallback && err == -ENOENT && prefix) { - create_key(NULL, postfix, name, key, sizeof(key)); - err = bcm47xx_nvram_getenv(key, buf, len); - } - return err; -} - -#define NVRAM_READ_VAL(type) \ -static void nvram_read_ ## type(const char *prefix, \ - const char *postfix, const char *name, \ - type *val, type allset, bool fallback) \ -{ \ - char buf[100]; \ - int err; \ - type var; \ - \ - err = get_nvram_var(prefix, postfix, name, buf, sizeof(buf), \ - fallback); \ - if (err < 0) \ - return; \ - err = kstrto ## type(strim(buf), 0, &var); \ - if (err) { \ - pr_warn("can not parse nvram name %s%s%s with value %s got %i\n", \ - prefix, name, postfix, buf, err); \ - return; \ - } \ - if (allset && var == allset) \ - return; \ - *val = var; \ -} - -NVRAM_READ_VAL(u8) -NVRAM_READ_VAL(s8) -NVRAM_READ_VAL(u16) -NVRAM_READ_VAL(u32) - -#undef NVRAM_READ_VAL - -static void nvram_read_u32_2(const char *prefix, const char *name, - u16 *val_lo, u16 *val_hi, bool fallback) -{ - char buf[100]; - int err; - u32 val; - - err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); - if (err < 0) - return; - err = kstrtou32(strim(buf), 0, &val); - if (err) { - pr_warn("can not parse nvram name %s%s with value %s got %i\n", - prefix, name, buf, err); - return; - } - *val_lo = (val & 0x0000FFFFU); - *val_hi = (val & 0xFFFF0000U) >> 16; -} - -static void nvram_read_leddc(const char *prefix, const char *name, - u8 *leddc_on_time, u8 *leddc_off_time, - bool fallback) -{ - char buf[100]; - int err; - u32 val; - - err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); - if (err < 0) - return; - err = kstrtou32(strim(buf), 0, &val); - if (err) { - pr_warn("can not parse nvram name %s%s with value %s got %i\n", - prefix, name, buf, err); - return; - } - - if (val == 0xffff || val == 0xffffffff) - return; - - *leddc_on_time = val & 0xff; - *leddc_off_time = (val >> 16) & 0xff; -} - -static void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6]) -{ - if (strchr(buf, ':')) - sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], - &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], - &macaddr[5]); - else if (strchr(buf, '-')) - sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0], - &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], - &macaddr[5]); - else - pr_warn("Can not parse mac address: %s\n", buf); -} - -static void nvram_read_macaddr(const char *prefix, const char *name, - u8 val[6], bool fallback) -{ - char buf[100]; - int err; - - err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); - if (err < 0) - return; - - bcm47xx_nvram_parse_macaddr(buf, val); -} - -static void nvram_read_alpha2(const char *prefix, const char *name, - char val[2], bool fallback) -{ - char buf[10]; - int err; - - err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); - if (err < 0) - return; - if (buf[0] == '0') - return; - if (strlen(buf) > 2) { - pr_warn("alpha2 is too long %s\n", buf); - return; - } - memcpy(val, buf, 2); -} - -/* This is one-function-only macro, it uses local "sprom" variable! */ -#define ENTRY(_revmask, _type, _prefix, _name, _val, _allset, _fallback) \ - if (_revmask & BIT(sprom->revision)) \ - nvram_read_ ## _type(_prefix, NULL, _name, &sprom->_val, \ - _allset, _fallback) -/* - * Special version of filling function that can be safely called for any SPROM - * revision. For every NVRAM to SPROM mapping it contains bitmask of revisions - * for which the mapping is valid. - * It obviously requires some hexadecimal/bitmasks knowledge, but allows - * writing cleaner code (easy revisions handling). - * Note that while SPROM revision 0 was never used, we still keep BIT(0) - * reserved for it, just to keep numbering sane. - */ -static void bcm47xx_sprom_fill_auto(struct ssb_sprom *sprom, - const char *prefix, bool fallback) -{ - const char *pre = prefix; - bool fb = fallback; - - /* Broadcom extracts it for rev 8+ but it was found on 2 and 4 too */ - ENTRY(0xfffffffe, u16, pre, "devid", dev_id, 0, fallback); - - ENTRY(0xfffffffe, u16, pre, "boardrev", board_rev, 0, true); - ENTRY(0xfffffffe, u32, pre, "boardflags", boardflags, 0, fb); - ENTRY(0xfffffff0, u32, pre, "boardflags2", boardflags2, 0, fb); - ENTRY(0xfffff800, u32, pre, "boardflags3", boardflags3, 0, fb); - ENTRY(0x00000002, u16, pre, "boardflags", boardflags_lo, 0, fb); - ENTRY(0xfffffffc, u16, pre, "boardtype", board_type, 0, true); - ENTRY(0xfffffffe, u16, pre, "boardnum", board_num, 0, fb); - ENTRY(0x00000002, u8, pre, "cc", country_code, 0, fb); - ENTRY(0xfffffff8, u8, pre, "regrev", regrev, 0, fb); - - ENTRY(0xfffffffe, u8, pre, "ledbh0", gpio0, 0xff, fb); - ENTRY(0xfffffffe, u8, pre, "ledbh1", gpio1, 0xff, fb); - ENTRY(0xfffffffe, u8, pre, "ledbh2", gpio2, 0xff, fb); - ENTRY(0xfffffffe, u8, pre, "ledbh3", gpio3, 0xff, fb); - - ENTRY(0x0000070e, u16, pre, "pa0b0", pa0b0, 0, fb); - ENTRY(0x0000070e, u16, pre, "pa0b1", pa0b1, 0, fb); - ENTRY(0x0000070e, u16, pre, "pa0b2", pa0b2, 0, fb); - ENTRY(0x0000070e, u8, pre, "pa0itssit", itssi_bg, 0, fb); - ENTRY(0x0000070e, u8, pre, "pa0maxpwr", maxpwr_bg, 0, fb); - - ENTRY(0x0000070c, u8, pre, "opo", opo, 0, fb); - ENTRY(0xfffffffe, u8, pre, "aa2g", ant_available_bg, 0, fb); - ENTRY(0xfffffffe, u8, pre, "aa5g", ant_available_a, 0, fb); - ENTRY(0x000007fe, s8, pre, "ag0", antenna_gain.a0, 0, fb); - ENTRY(0x000007fe, s8, pre, "ag1", antenna_gain.a1, 0, fb); - ENTRY(0x000007f0, s8, pre, "ag2", antenna_gain.a2, 0, fb); - ENTRY(0x000007f0, s8, pre, "ag3", antenna_gain.a3, 0, fb); - - ENTRY(0x0000070e, u16, pre, "pa1b0", pa1b0, 0, fb); - ENTRY(0x0000070e, u16, pre, "pa1b1", pa1b1, 0, fb); - ENTRY(0x0000070e, u16, pre, "pa1b2", pa1b2, 0, fb); - ENTRY(0x0000070c, u16, pre, "pa1lob0", pa1lob0, 0, fb); - ENTRY(0x0000070c, u16, pre, "pa1lob1", pa1lob1, 0, fb); - ENTRY(0x0000070c, u16, pre, "pa1lob2", pa1lob2, 0, fb); - ENTRY(0x0000070c, u16, pre, "pa1hib0", pa1hib0, 0, fb); - ENTRY(0x0000070c, u16, pre, "pa1hib1", pa1hib1, 0, fb); - ENTRY(0x0000070c, u16, pre, "pa1hib2", pa1hib2, 0, fb); - ENTRY(0x0000070e, u8, pre, "pa1itssit", itssi_a, 0, fb); - ENTRY(0x0000070e, u8, pre, "pa1maxpwr", maxpwr_a, 0, fb); - ENTRY(0x0000070c, u8, pre, "pa1lomaxpwr", maxpwr_al, 0, fb); - ENTRY(0x0000070c, u8, pre, "pa1himaxpwr", maxpwr_ah, 0, fb); - - ENTRY(0x00000708, u8, pre, "bxa2g", bxa2g, 0, fb); - ENTRY(0x00000708, u8, pre, "rssisav2g", rssisav2g, 0, fb); - ENTRY(0x00000708, u8, pre, "rssismc2g", rssismc2g, 0, fb); - ENTRY(0x00000708, u8, pre, "rssismf2g", rssismf2g, 0, fb); - ENTRY(0x00000708, u8, pre, "bxa5g", bxa5g, 0, fb); - ENTRY(0x00000708, u8, pre, "rssisav5g", rssisav5g, 0, fb); - ENTRY(0x00000708, u8, pre, "rssismc5g", rssismc5g, 0, fb); - ENTRY(0x00000708, u8, pre, "rssismf5g", rssismf5g, 0, fb); - ENTRY(0x00000708, u8, pre, "tri2g", tri2g, 0, fb); - ENTRY(0x00000708, u8, pre, "tri5g", tri5g, 0, fb); - ENTRY(0x00000708, u8, pre, "tri5gl", tri5gl, 0, fb); - ENTRY(0x00000708, u8, pre, "tri5gh", tri5gh, 0, fb); - ENTRY(0x00000708, s8, pre, "rxpo2g", rxpo2g, 0, fb); - ENTRY(0x00000708, s8, pre, "rxpo5g", rxpo5g, 0, fb); - ENTRY(0xfffffff0, u8, pre, "txchain", txchain, 0xf, fb); - ENTRY(0xfffffff0, u8, pre, "rxchain", rxchain, 0xf, fb); - ENTRY(0xfffffff0, u8, pre, "antswitch", antswitch, 0xff, fb); - ENTRY(0x00000700, u8, pre, "tssipos2g", fem.ghz2.tssipos, 0, fb); - ENTRY(0x00000700, u8, pre, "extpagain2g", fem.ghz2.extpa_gain, 0, fb); - ENTRY(0x00000700, u8, pre, "pdetrange2g", fem.ghz2.pdet_range, 0, fb); - ENTRY(0x00000700, u8, pre, "triso2g", fem.ghz2.tr_iso, 0, fb); - ENTRY(0x00000700, u8, pre, "antswctl2g", fem.ghz2.antswlut, 0, fb); - ENTRY(0x00000700, u8, pre, "tssipos5g", fem.ghz5.tssipos, 0, fb); - ENTRY(0x00000700, u8, pre, "extpagain5g", fem.ghz5.extpa_gain, 0, fb); - ENTRY(0x00000700, u8, pre, "pdetrange5g", fem.ghz5.pdet_range, 0, fb); - ENTRY(0x00000700, u8, pre, "triso5g", fem.ghz5.tr_iso, 0, fb); - ENTRY(0x00000700, u8, pre, "antswctl5g", fem.ghz5.antswlut, 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid2ga0", txpid2g[0], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid2ga1", txpid2g[1], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid2ga2", txpid2g[2], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid2ga3", txpid2g[3], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5ga0", txpid5g[0], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5ga1", txpid5g[1], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5ga2", txpid5g[2], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5ga3", txpid5g[3], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5gla0", txpid5gl[0], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5gla1", txpid5gl[1], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5gla2", txpid5gl[2], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5gla3", txpid5gl[3], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5gha0", txpid5gh[0], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5gha1", txpid5gh[1], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5gha2", txpid5gh[2], 0, fb); - ENTRY(0x000000f0, u8, pre, "txpid5gha3", txpid5gh[3], 0, fb); - - ENTRY(0xffffff00, u8, pre, "tempthresh", tempthresh, 0, fb); - ENTRY(0xffffff00, u8, pre, "tempoffset", tempoffset, 0, fb); - ENTRY(0xffffff00, u16, pre, "rawtempsense", rawtempsense, 0, fb); - ENTRY(0xffffff00, u8, pre, "measpower", measpower, 0, fb); - ENTRY(0xffffff00, u8, pre, "tempsense_slope", tempsense_slope, 0, fb); - ENTRY(0xffffff00, u8, pre, "tempcorrx", tempcorrx, 0, fb); - ENTRY(0xffffff00, u8, pre, "tempsense_option", tempsense_option, 0, fb); - ENTRY(0x00000700, u8, pre, "freqoffset_corr", freqoffset_corr, 0, fb); - ENTRY(0x00000700, u8, pre, "iqcal_swp_dis", iqcal_swp_dis, 0, fb); - ENTRY(0x00000700, u8, pre, "hw_iqcal_en", hw_iqcal_en, 0, fb); - ENTRY(0x00000700, u8, pre, "elna2g", elna2g, 0, fb); - ENTRY(0x00000700, u8, pre, "elna5g", elna5g, 0, fb); - ENTRY(0xffffff00, u8, pre, "phycal_tempdelta", phycal_tempdelta, 0, fb); - ENTRY(0xffffff00, u8, pre, "temps_period", temps_period, 0, fb); - ENTRY(0xffffff00, u8, pre, "temps_hysteresis", temps_hysteresis, 0, fb); - ENTRY(0xffffff00, u8, pre, "measpower1", measpower1, 0, fb); - ENTRY(0xffffff00, u8, pre, "measpower2", measpower2, 0, fb); - - ENTRY(0x000001f0, u16, pre, "cck2gpo", cck2gpo, 0, fb); - ENTRY(0x000001f0, u32, pre, "ofdm2gpo", ofdm2gpo, 0, fb); - ENTRY(0x000001f0, u32, pre, "ofdm5gpo", ofdm5gpo, 0, fb); - ENTRY(0x000001f0, u32, pre, "ofdm5glpo", ofdm5glpo, 0, fb); - ENTRY(0x000001f0, u32, pre, "ofdm5ghpo", ofdm5ghpo, 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs2gpo0", mcs2gpo[0], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs2gpo1", mcs2gpo[1], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs2gpo2", mcs2gpo[2], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs2gpo3", mcs2gpo[3], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs2gpo4", mcs2gpo[4], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs2gpo5", mcs2gpo[5], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs2gpo6", mcs2gpo[6], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs2gpo7", mcs2gpo[7], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5gpo0", mcs5gpo[0], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5gpo1", mcs5gpo[1], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5gpo2", mcs5gpo[2], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5gpo3", mcs5gpo[3], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5gpo4", mcs5gpo[4], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5gpo5", mcs5gpo[5], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5gpo6", mcs5gpo[6], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5gpo7", mcs5gpo[7], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5glpo0", mcs5glpo[0], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5glpo1", mcs5glpo[1], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5glpo2", mcs5glpo[2], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5glpo3", mcs5glpo[3], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5glpo4", mcs5glpo[4], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5glpo5", mcs5glpo[5], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5glpo6", mcs5glpo[6], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5glpo7", mcs5glpo[7], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5ghpo0", mcs5ghpo[0], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5ghpo1", mcs5ghpo[1], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5ghpo2", mcs5ghpo[2], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5ghpo3", mcs5ghpo[3], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5ghpo4", mcs5ghpo[4], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5ghpo5", mcs5ghpo[5], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5ghpo6", mcs5ghpo[6], 0, fb); - ENTRY(0x000001f0, u16, pre, "mcs5ghpo7", mcs5ghpo[7], 0, fb); - ENTRY(0x000001f0, u16, pre, "cddpo", cddpo, 0, fb); - ENTRY(0x000001f0, u16, pre, "stbcpo", stbcpo, 0, fb); - ENTRY(0x000001f0, u16, pre, "bw40po", bw40po, 0, fb); - ENTRY(0x000001f0, u16, pre, "bwduppo", bwduppo, 0, fb); - - ENTRY(0xfffffe00, u16, pre, "cckbw202gpo", cckbw202gpo, 0, fb); - ENTRY(0xfffffe00, u16, pre, "cckbw20ul2gpo", cckbw20ul2gpo, 0, fb); - ENTRY(0x00000600, u32, pre, "legofdmbw202gpo", legofdmbw202gpo, 0, fb); - ENTRY(0x00000600, u32, pre, "legofdmbw20ul2gpo", legofdmbw20ul2gpo, 0, fb); - ENTRY(0x00000600, u32, pre, "legofdmbw205glpo", legofdmbw205glpo, 0, fb); - ENTRY(0x00000600, u32, pre, "legofdmbw20ul5glpo", legofdmbw20ul5glpo, 0, fb); - ENTRY(0x00000600, u32, pre, "legofdmbw205gmpo", legofdmbw205gmpo, 0, fb); - ENTRY(0x00000600, u32, pre, "legofdmbw20ul5gmpo", legofdmbw20ul5gmpo, 0, fb); - ENTRY(0x00000600, u32, pre, "legofdmbw205ghpo", legofdmbw205ghpo, 0, fb); - ENTRY(0x00000600, u32, pre, "legofdmbw20ul5ghpo", legofdmbw20ul5ghpo, 0, fb); - ENTRY(0xfffffe00, u32, pre, "mcsbw202gpo", mcsbw202gpo, 0, fb); - ENTRY(0x00000600, u32, pre, "mcsbw20ul2gpo", mcsbw20ul2gpo, 0, fb); - ENTRY(0xfffffe00, u32, pre, "mcsbw402gpo", mcsbw402gpo, 0, fb); - ENTRY(0xfffffe00, u32, pre, "mcsbw205glpo", mcsbw205glpo, 0, fb); - ENTRY(0x00000600, u32, pre, "mcsbw20ul5glpo", mcsbw20ul5glpo, 0, fb); - ENTRY(0xfffffe00, u32, pre, "mcsbw405glpo", mcsbw405glpo, 0, fb); - ENTRY(0xfffffe00, u32, pre, "mcsbw205gmpo", mcsbw205gmpo, 0, fb); - ENTRY(0x00000600, u32, pre, "mcsbw20ul5gmpo", mcsbw20ul5gmpo, 0, fb); - ENTRY(0xfffffe00, u32, pre, "mcsbw405gmpo", mcsbw405gmpo, 0, fb); - ENTRY(0xfffffe00, u32, pre, "mcsbw205ghpo", mcsbw205ghpo, 0, fb); - ENTRY(0x00000600, u32, pre, "mcsbw20ul5ghpo", mcsbw20ul5ghpo, 0, fb); - ENTRY(0xfffffe00, u32, pre, "mcsbw405ghpo", mcsbw405ghpo, 0, fb); - ENTRY(0x00000600, u16, pre, "mcs32po", mcs32po, 0, fb); - ENTRY(0x00000600, u16, pre, "legofdm40duppo", legofdm40duppo, 0, fb); - ENTRY(0x00000700, u8, pre, "pcieingress_war", pcieingress_war, 0, fb); - - /* TODO: rev 11 support */ - ENTRY(0x00000700, u8, pre, "rxgainerr2ga0", rxgainerr2ga[0], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr2ga1", rxgainerr2ga[1], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr2ga2", rxgainerr2ga[2], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gla0", rxgainerr5gla[0], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gla1", rxgainerr5gla[1], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gla2", rxgainerr5gla[2], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gma0", rxgainerr5gma[0], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gma1", rxgainerr5gma[1], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gma2", rxgainerr5gma[2], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gha0", rxgainerr5gha[0], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gha1", rxgainerr5gha[1], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gha2", rxgainerr5gha[2], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gua0", rxgainerr5gua[0], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gua1", rxgainerr5gua[1], 0, fb); - ENTRY(0x00000700, u8, pre, "rxgainerr5gua2", rxgainerr5gua[2], 0, fb); - - ENTRY(0xfffffe00, u8, pre, "sar2g", sar2g, 0, fb); - ENTRY(0xfffffe00, u8, pre, "sar5g", sar5g, 0, fb); - - /* TODO: rev 11 support */ - ENTRY(0x00000700, u8, pre, "noiselvl2ga0", noiselvl2ga[0], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl2ga1", noiselvl2ga[1], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl2ga2", noiselvl2ga[2], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gla0", noiselvl5gla[0], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gla1", noiselvl5gla[1], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gla2", noiselvl5gla[2], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gma0", noiselvl5gma[0], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gma1", noiselvl5gma[1], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gma2", noiselvl5gma[2], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gha0", noiselvl5gha[0], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gha1", noiselvl5gha[1], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gha2", noiselvl5gha[2], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gua0", noiselvl5gua[0], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gua1", noiselvl5gua[1], 0, fb); - ENTRY(0x00000700, u8, pre, "noiselvl5gua2", noiselvl5gua[2], 0, fb); -} -#undef ENTRY /* It's specififc, uses local variable, don't use it (again). */ - -static void bcm47xx_fill_sprom_path_r4589(struct ssb_sprom *sprom, - const char *prefix, bool fallback) -{ - char postfix[2]; - int i; - - for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) { - struct ssb_sprom_core_pwr_info *pwr_info; - - pwr_info = &sprom->core_pwr_info[i]; - - snprintf(postfix, sizeof(postfix), "%i", i); - nvram_read_u8(prefix, postfix, "maxp2ga", - &pwr_info->maxpwr_2g, 0, fallback); - nvram_read_u8(prefix, postfix, "itt2ga", - &pwr_info->itssi_2g, 0, fallback); - nvram_read_u8(prefix, postfix, "itt5ga", - &pwr_info->itssi_5g, 0, fallback); - nvram_read_u16(prefix, postfix, "pa2gw0a", - &pwr_info->pa_2g[0], 0, fallback); - nvram_read_u16(prefix, postfix, "pa2gw1a", - &pwr_info->pa_2g[1], 0, fallback); - nvram_read_u16(prefix, postfix, "pa2gw2a", - &pwr_info->pa_2g[2], 0, fallback); - nvram_read_u8(prefix, postfix, "maxp5ga", - &pwr_info->maxpwr_5g, 0, fallback); - nvram_read_u8(prefix, postfix, "maxp5gha", - &pwr_info->maxpwr_5gh, 0, fallback); - nvram_read_u8(prefix, postfix, "maxp5gla", - &pwr_info->maxpwr_5gl, 0, fallback); - nvram_read_u16(prefix, postfix, "pa5gw0a", - &pwr_info->pa_5g[0], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5gw1a", - &pwr_info->pa_5g[1], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5gw2a", - &pwr_info->pa_5g[2], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5glw0a", - &pwr_info->pa_5gl[0], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5glw1a", - &pwr_info->pa_5gl[1], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5glw2a", - &pwr_info->pa_5gl[2], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5ghw0a", - &pwr_info->pa_5gh[0], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5ghw1a", - &pwr_info->pa_5gh[1], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5ghw2a", - &pwr_info->pa_5gh[2], 0, fallback); - } -} - -static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom, - const char *prefix, bool fallback) -{ - char postfix[2]; - int i; - - for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) { - struct ssb_sprom_core_pwr_info *pwr_info; - - pwr_info = &sprom->core_pwr_info[i]; - - snprintf(postfix, sizeof(postfix), "%i", i); - nvram_read_u16(prefix, postfix, "pa2gw3a", - &pwr_info->pa_2g[3], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5gw3a", - &pwr_info->pa_5g[3], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5glw3a", - &pwr_info->pa_5gl[3], 0, fallback); - nvram_read_u16(prefix, postfix, "pa5ghw3a", - &pwr_info->pa_5gh[3], 0, fallback); - } -} - -static bool bcm47xx_is_valid_mac(u8 *mac) -{ - return mac && !(mac[0] == 0x00 && mac[1] == 0x90 && mac[2] == 0x4c); -} - -static int bcm47xx_increase_mac_addr(u8 *mac, u8 num) -{ - u8 *oui = mac + ETH_ALEN/2 - 1; - u8 *p = mac + ETH_ALEN - 1; - - do { - (*p) += num; - if (*p > num) - break; - p--; - num = 1; - } while (p != oui); - - if (p == oui) { - pr_err("unable to fetch mac address\n"); - return -ENOENT; - } - return 0; -} - -static int mac_addr_used = 2; - -static void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, - const char *prefix, bool fallback) -{ - bool fb = fallback; - - nvram_read_macaddr(prefix, "et0macaddr", sprom->et0mac, fallback); - nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0, - fallback); - nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0, - fallback); - - nvram_read_macaddr(prefix, "et1macaddr", sprom->et1mac, fallback); - nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0, - fallback); - nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0, - fallback); - - nvram_read_macaddr(prefix, "et2macaddr", sprom->et2mac, fb); - nvram_read_u8(prefix, NULL, "et2mdcport", &sprom->et2mdcport, 0, fb); - nvram_read_u8(prefix, NULL, "et2phyaddr", &sprom->et2phyaddr, 0, fb); - - nvram_read_macaddr(prefix, "macaddr", sprom->il0mac, fallback); - nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback); - - /* The address prefix 00:90:4C is used by Broadcom in their initial - * configuration. When a mac address with the prefix 00:90:4C is used - * all devices from the same series are sharing the same mac address. - * To prevent mac address collisions we replace them with a mac address - * based on the base address. - */ - if (!bcm47xx_is_valid_mac(sprom->il0mac)) { - u8 mac[6]; - - nvram_read_macaddr(NULL, "et0macaddr", mac, false); - if (bcm47xx_is_valid_mac(mac)) { - int err = bcm47xx_increase_mac_addr(mac, mac_addr_used); - - if (!err) { - ether_addr_copy(sprom->il0mac, mac); - mac_addr_used++; - } - } - } -} - -static void bcm47xx_fill_board_data(struct ssb_sprom *sprom, const char *prefix, - bool fallback) -{ - nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo, - &sprom->boardflags_hi, fallback); - nvram_read_u32_2(prefix, "boardflags2", &sprom->boardflags2_lo, - &sprom->boardflags2_hi, fallback); -} - -void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix, - bool fallback) -{ - bcm47xx_fill_sprom_ethernet(sprom, prefix, fallback); - bcm47xx_fill_board_data(sprom, prefix, fallback); - - nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0, fallback); - - /* Entries requiring custom functions */ - nvram_read_alpha2(prefix, "ccode", sprom->alpha2, fallback); - if (sprom->revision >= 3) - nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time, - &sprom->leddc_off_time, fallback); - - switch (sprom->revision) { - case 4: - case 5: - bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback); - bcm47xx_fill_sprom_path_r45(sprom, prefix, fallback); - break; - case 8: - case 9: - bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback); - break; - } - - bcm47xx_sprom_fill_auto(sprom, prefix, fallback); -} - -#if defined(CONFIG_BCM47XX_SSB) -static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out) -{ - char prefix[10]; - - switch (bus->bustype) { - case SSB_BUSTYPE_SSB: - bcm47xx_fill_sprom(out, NULL, false); - return 0; - case SSB_BUSTYPE_PCI: - memset(out, 0, sizeof(struct ssb_sprom)); - snprintf(prefix, sizeof(prefix), "pci/%u/%u/", - bus->host_pci->bus->number + 1, - PCI_SLOT(bus->host_pci->devfn)); - bcm47xx_fill_sprom(out, prefix, false); - return 0; - default: - pr_warn("Unable to fill SPROM for given bustype.\n"); - return -EINVAL; - } -} -#endif - -#if defined(CONFIG_BCM47XX_BCMA) -/* - * Having many NVRAM entries for PCI devices led to repeating prefixes like - * pci/1/1/ all the time and wasting flash space. So at some point Broadcom - * decided to introduce prefixes like 0: 1: 2: etc. - * If we find e.g. devpath0=pci/2/1 or devpath0=pci/2/1/ we should use 0: - * instead of pci/2/1/. - */ -static void bcm47xx_sprom_apply_prefix_alias(char *prefix, size_t prefix_size) -{ - size_t prefix_len = strlen(prefix); - size_t short_len = prefix_len - 1; - char nvram_var[10]; - char buf[20]; - int i; - - /* Passed prefix has to end with a slash */ - if (prefix_len <= 0 || prefix[prefix_len - 1] != '/') - return; - - for (i = 0; i < 3; i++) { - if (snprintf(nvram_var, sizeof(nvram_var), "devpath%d", i) <= 0) - continue; - if (bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf)) < 0) - continue; - if (!strcmp(buf, prefix) || - (short_len && strlen(buf) == short_len && !strncmp(buf, prefix, short_len))) { - snprintf(prefix, prefix_size, "%d:", i); - return; - } - } -} - -static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out) -{ - struct bcma_boardinfo *binfo = &bus->boardinfo; - struct bcma_device *core; - char buf[10]; - char *prefix; - bool fallback = false; - - switch (bus->hosttype) { - case BCMA_HOSTTYPE_PCI: - memset(out, 0, sizeof(struct ssb_sprom)); - /* On BCM47XX all PCI buses share the same domain */ - if (config_enabled(CONFIG_BCM47XX)) - snprintf(buf, sizeof(buf), "pci/%u/%u/", - bus->host_pci->bus->number + 1, - PCI_SLOT(bus->host_pci->devfn)); - else - snprintf(buf, sizeof(buf), "pci/%u/%u/", - pci_domain_nr(bus->host_pci->bus) + 1, - bus->host_pci->bus->number); - bcm47xx_sprom_apply_prefix_alias(buf, sizeof(buf)); - prefix = buf; - break; - case BCMA_HOSTTYPE_SOC: - memset(out, 0, sizeof(struct ssb_sprom)); - core = bcma_find_core(bus, BCMA_CORE_80211); - if (core) { - snprintf(buf, sizeof(buf), "sb/%u/", - core->core_index); - prefix = buf; - fallback = true; - } else { - prefix = NULL; - } - break; - default: - pr_warn("Unable to fill SPROM for given bustype.\n"); - return -EINVAL; - } - - nvram_read_u16(prefix, NULL, "boardvendor", &binfo->vendor, 0, true); - if (!binfo->vendor) - binfo->vendor = SSB_BOARDVENDOR_BCM; - nvram_read_u16(prefix, NULL, "boardtype", &binfo->type, 0, true); - - bcm47xx_fill_sprom(out, prefix, fallback); - - return 0; -} -#endif - -/* - * On bcm47xx we need to register SPROM fallback handler very early, so we can't - * use anything like platform device / driver for this. - */ -void bcm47xx_sprom_register_fallbacks(void) -{ -#if defined(CONFIG_BCM47XX_SSB) - if (ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb)) - pr_warn("Failed to register ssb SPROM handler\n"); -#endif - -#if defined(CONFIG_BCM47XX_BCMA) - if (bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma)) - pr_warn("Failed to register bcma SPROM handler\n"); -#endif -} diff --git a/arch/mips/bmips/Kconfig b/arch/mips/bmips/Kconfig index e2c4fd6..264328d 100644 --- a/arch/mips/bmips/Kconfig +++ b/arch/mips/bmips/Kconfig @@ -21,6 +21,10 @@ config DT_BCM93384WVG_VIPER bool "BCM93384WVG Viper CPU (EXPERIMENTAL)" select BUILTIN_DTB +config DT_BCM96358NB4SER + bool "BCM96358NB4SER" + select BUILTIN_DTB + config DT_BCM96368MVWG bool "BCM96368MVWG" select BUILTIN_DTB diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index 3553528..f146d12 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -95,6 +95,15 @@ static void bcm6328_quirks(void) bcm63xx_fixup_cpu1(); } +static void bcm6358_quirks(void) +{ + /* + * BCM6358 needs special handling for its shared TLB, so + * disable SMP for now + */ + bmips_smp_enabled = 0; +} + static void bcm6368_quirks(void) { bcm63xx_fixup_cpu1(); @@ -104,13 +113,16 @@ static const struct bmips_quirk bmips_quirk_list[] = { { "brcm,bcm3384-viper", &bcm3384_viper_quirks }, { "brcm,bcm33843-viper", &bcm3384_viper_quirks }, { "brcm,bcm6328", &bcm6328_quirks }, + { "brcm,bcm6358", &bcm6358_quirks }, { "brcm,bcm6368", &bcm6368_quirks }, { "brcm,bcm63168", &bcm6368_quirks }, + { "brcm,bcm63268", &bcm6368_quirks }, { }, }; void __init prom_init(void) { + bmips_cpu_setup(); register_bmips_smp_ops(); } diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 309d2ad..90aca95 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -37,8 +37,13 @@ vmlinuzobjs-$(CONFIG_DEBUG_ZBOOT) += $(obj)/dbg.o vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART_PROM) += $(obj)/uart-prom.o vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o +vmlinuzobjs-$(CONFIG_ATH79) += $(obj)/uart-ath79.o endif +extra-y += uart-ath79.c +$(obj)/uart-ath79.c: $(srctree)/arch/mips/ath79/early_printk.c + $(call cmd,shipped) + vmlinuzobjs-$(CONFIG_KERNEL_XZ) += $(obj)/ashldi3.o $(obj)/bswapsi.o extra-y += ashldi3.c bswapsi.c diff --git a/arch/mips/boot/dts/brcm/Makefile b/arch/mips/boot/dts/brcm/Makefile index eabeb60..fda9d38 100644 --- a/arch/mips/boot/dts/brcm/Makefile +++ b/arch/mips/boot/dts/brcm/Makefile @@ -1,5 +1,6 @@ dtb-$(CONFIG_DT_BCM93384WVG) += bcm93384wvg.dtb dtb-$(CONFIG_DT_BCM93384WVG_VIPER) += bcm93384wvg_viper.dtb +dtb-$(CONFIG_DT_BCM96358NB4SER) += bcm96358nb4ser.dtb dtb-$(CONFIG_DT_BCM96368MVWG) += bcm96368mvwg.dtb dtb-$(CONFIG_DT_BCM9EJTAGPRB) += bcm9ejtagprb.dtb dtb-$(CONFIG_DT_BCM97125CBMB) += bcm97125cbmb.dtb @@ -14,6 +15,7 @@ dtb-$(CONFIG_DT_BCM97435SVMB) += bcm97435svmb.dtb dtb-$(CONFIG_DT_NONE) += \ bcm93384wvg.dtb \ bcm93384wvg_viper.dtb \ + bcm96358nb4ser.dtb \ bcm96368mvwg.dtb \ bcm9ejtagprb.dtb \ bcm97125cbmb.dtb \ diff --git a/arch/mips/boot/dts/brcm/bcm6328.dtsi b/arch/mips/boot/dts/brcm/bcm6328.dtsi index 9d19236..5633b9d 100644 --- a/arch/mips/boot/dts/brcm/bcm6328.dtsi +++ b/arch/mips/boot/dts/brcm/bcm6328.dtsi @@ -23,7 +23,7 @@ }; clocks { - periph_clk: periph_clk { + periph_clk: periph-clk { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <50000000>; @@ -31,11 +31,11 @@ }; aliases { - leds0 = &leds0; - uart0 = &uart0; + serial0 = &uart0; + serial1 = &uart1; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -50,16 +50,16 @@ compatible = "simple-bus"; ranges; - periph_intc: periph_intc@10000020 { - compatible = "brcm,bcm3380-l2-intc"; - reg = <0x10000024 0x4 0x1000002c 0x4>, - <0x10000020 0x4 0x10000028 0x4>; + periph_intc: interrupt-controller@10000020 { + compatible = "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x10>, + <0x10000030 0x10>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&cpu_intc>; - interrupts = <2>; + interrupts = <2>, <3>; }; uart0: serial@10000100 { @@ -71,13 +71,22 @@ status = "disabled"; }; - timer: timer@10000040 { + uart1: serial@10000120 { + compatible = "brcm,bcm6345-uart"; + reg = <0x10000120 0x18>; + interrupt-parent = <&periph_intc>; + interrupts = <39>; + clocks = <&periph_clk>; + status = "disabled"; + }; + + timer: syscon@10000040 { compatible = "syscon"; reg = <0x10000040 0x2c>; native-endian; }; - reboot { + reboot: syscon-reboot@10000068 { compatible = "syscon-reboot"; regmap = <&timer>; offset = <0x28>; @@ -91,5 +100,24 @@ reg = <0x10000800 0x24>; status = "disabled"; }; + + ehci: usb@10002500 { + compatible = "brcm,bcm6328-ehci", "generic-ehci"; + reg = <0x10002500 0x100>; + big-endian; + interrupt-parent = <&periph_intc>; + interrupts = <42>; + status = "disabled"; + }; + + ohci: usb@10002600 { + compatible = "brcm,bcm6328-ohci", "generic-ohci"; + reg = <0x10002600 0x100>; + big-endian; + no-big-frame-no; + interrupt-parent = <&periph_intc>; + interrupts = <41>; + status = "disabled"; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm6358.dtsi b/arch/mips/boot/dts/brcm/bcm6358.dtsi new file mode 100644 index 0000000..f9d8d39 --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm6358.dtsi @@ -0,0 +1,130 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "brcm,bcm6358"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + mips-hpt-frequency = <150000000>; + + cpu@0 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <0>; + }; + + cpu@1 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <1>; + }; + }; + + clocks { + periph_clk: periph-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + }; + }; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + cpu_intc: interrupt-controller { + #address-cells = <0>; + compatible = "mti,cpu-interrupt-controller"; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + ubus { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "simple-bus"; + ranges; + + periph_cntl: syscon@fffe0000 { + compatible = "syscon"; + reg = <0xfffe0000 0xc>; + native-endian; + }; + + reboot: syscon-reboot@fffe0008 { + compatible = "syscon-reboot"; + regmap = <&periph_cntl>; + offset = <0x8>; + mask = <0x1>; + }; + + periph_intc: interrupt-controller@fffe000c { + compatible = "brcm,bcm6345-l1-intc"; + reg = <0xfffe000c 0x8>, + <0xfffe0038 0x8>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; + }; + + leds0: led-controller@fffe00d0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6358-leds"; + reg = <0xfffe00d0 0x8>; + + status = "disabled"; + }; + + uart0: serial@fffe0100 { + compatible = "brcm,bcm6345-uart"; + reg = <0xfffe0100 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <2>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + + uart1: serial@fffe0120 { + compatible = "brcm,bcm6345-uart"; + reg = <0xfffe0120 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <3>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + + ehci: usb@fffe1300 { + compatible = "brcm,bcm6358-ehci", "generic-ehci"; + reg = <0xfffe1300 0x100>; + big-endian; + interrupt-parent = <&periph_intc>; + interrupts = <10>; + status = "disabled"; + }; + + ohci: usb@fffe1400 { + compatible = "brcm,bcm6358-ohci", "generic-ohci"; + reg = <0xfffe1400 0x100>; + big-endian; + no-big-frame-no; + interrupt-parent = <&periph_intc>; + interrupts = <5>; + status = "disabled"; + }; + }; +}; diff --git a/arch/mips/boot/dts/brcm/bcm6368.dtsi b/arch/mips/boot/dts/brcm/bcm6368.dtsi index 1f6b9b5..d0e3a70 100644 --- a/arch/mips/boot/dts/brcm/bcm6368.dtsi +++ b/arch/mips/boot/dts/brcm/bcm6368.dtsi @@ -20,11 +20,10 @@ device_type = "cpu"; reg = <1>; }; - }; clocks { - periph_clk: periph_clk { + periph_clk: periph-clk { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <50000000>; @@ -32,11 +31,11 @@ }; aliases { - leds0 = &leds0; - uart0 = &uart0; + serial0 = &uart0; + serial1 = &uart1; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -64,16 +63,16 @@ mask = <0x1>; }; - periph_intc: periph_intc@10000020 { - compatible = "brcm,bcm3380-l2-intc"; - reg = <0x10000024 0x4 0x1000002c 0x4>, - <0x10000020 0x4 0x10000028 0x4>; + periph_intc: interrupt-controller@10000020 { + compatible = "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x10>, + <0x10000030 0x10>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&cpu_intc>; - interrupts = <2>; + interrupts = <2>, <3>; }; leds0: led-controller@100000d0 { @@ -93,7 +92,16 @@ status = "disabled"; }; - ehci0: usb@10001500 { + uart1: serial@10000120 { + compatible = "brcm,bcm6345-uart"; + reg = <0x10000120 0x18>; + interrupt-parent = <&periph_intc>; + interrupts = <3>; + clocks = <&periph_clk>; + status = "disabled"; + }; + + ehci: usb@10001500 { compatible = "brcm,bcm6368-ehci", "generic-ehci"; reg = <0x10001500 0x100>; big-endian; @@ -102,7 +110,7 @@ status = "disabled"; }; - ohci0: usb@10001600 { + ohci: usb@10001600 { compatible = "brcm,bcm6368-ohci", "generic-ohci"; reg = <0x10001600 0x100>; big-endian; diff --git a/arch/mips/boot/dts/brcm/bcm7125.dtsi b/arch/mips/boot/dts/brcm/bcm7125.dtsi index 3ae1605..550e1d9 100644 --- a/arch/mips/boot/dts/brcm/bcm7125.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7125.dtsi @@ -85,14 +85,15 @@ compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; - brcm,int-map-mask = <0x44>; + brcm,int-map-mask = <0x44>, <0xf000000>; brcm,int-fwd-mask = <0x70000>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&periph_intc>; - interrupts = <18>; + interrupts = <18>, <19>; + interrupt-names = "upg_main", "upg_bsc"; }; sun_top_ctrl: syscon@404000 { @@ -118,6 +119,70 @@ status = "disabled"; }; + uart1: serial@406b40 { + compatible = "ns16550a"; + reg = <0x406b40 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + native-endian; + interrupt-parent = <&periph_intc>; + interrupts = <64>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + uart2: serial@406b80 { + compatible = "ns16550a"; + reg = <0x406b80 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + native-endian; + interrupt-parent = <&periph_intc>; + interrupts = <65>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + bsca: i2c@406200 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406200 0x58>; + interrupts = <24>; + interrupt-names = "upg_bsca"; + status = "disabled"; + }; + + bscb: i2c@406280 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406280 0x58>; + interrupts = <25>; + interrupt-names = "upg_bscb"; + status = "disabled"; + }; + + bscc: i2c@406300 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406300 0x58>; + interrupts = <26>; + interrupt-names = "upg_bscc"; + status = "disabled"; + }; + + bscd: i2c@406380 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406380 0x58>; + interrupts = <27>; + interrupt-names = "upg_bscd"; + status = "disabled"; + }; + ehci0: usb@488300 { compatible = "brcm,bcm7125-ehci", "generic-ehci"; reg = <0x488300 0x100>; diff --git a/arch/mips/boot/dts/brcm/bcm7346.dtsi b/arch/mips/boot/dts/brcm/bcm7346.dtsi index be79919..ec95906 100644 --- a/arch/mips/boot/dts/brcm/bcm7346.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7346.dtsi @@ -24,8 +24,6 @@ aliases { uart0 = &uart0; - uart1 = &uart1; - uart2 = &uart2; }; cpu_intc: cpu_intc { @@ -323,8 +321,6 @@ interrupts = <40>; #address-cells = <1>; #size-cells = <0>; - brcm,broken-ncq; - brcm,broken-phy; status = "disabled"; sata0: sata-port@0 { @@ -338,7 +334,7 @@ }; }; - sata_phy: sata-phy@1800000 { + sata_phy: sata-phy@180100 { compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; reg = <0x180100 0x0eff>; reg-names = "phy"; diff --git a/arch/mips/boot/dts/brcm/bcm7358.dtsi b/arch/mips/boot/dts/brcm/bcm7358.dtsi index 060805b..ca57fb5 100644 --- a/arch/mips/boot/dts/brcm/bcm7358.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7358.dtsi @@ -18,8 +18,6 @@ aliases { uart0 = &uart0; - uart1 = &uart1; - uart2 = &uart2; }; cpu_intc: cpu_intc { diff --git a/arch/mips/boot/dts/brcm/bcm7360.dtsi b/arch/mips/boot/dts/brcm/bcm7360.dtsi index bcdb09b..1c0c3d4 100644 --- a/arch/mips/boot/dts/brcm/bcm7360.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7360.dtsi @@ -18,8 +18,6 @@ aliases { uart0 = &uart0; - uart1 = &uart1; - uart2 = &uart2; }; cpu_intc: cpu_intc { @@ -241,5 +239,45 @@ interrupts = <66>; status = "disabled"; }; + + sata: sata@181000 { + compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci"; + reg-names = "ahci", "top-ctrl"; + reg = <0x181000 0xa9c>, <0x180020 0x1c>; + interrupt-parent = <&periph_intc>; + interrupts = <86>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + sata0: sata-port@0 { + reg = <0>; + phys = <&sata_phy0>; + }; + + sata1: sata-port@1 { + reg = <1>; + phys = <&sata_phy1>; + }; + }; + + sata_phy: sata-phy@180100 { + compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; + reg = <0x180100 0x0eff>; + reg-names = "phy"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + sata_phy0: sata-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + sata_phy1: sata-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm7362.dtsi b/arch/mips/boot/dts/brcm/bcm7362.dtsi index d3b1b76..6b4713a 100644 --- a/arch/mips/boot/dts/brcm/bcm7362.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7362.dtsi @@ -24,8 +24,6 @@ aliases { uart0 = &uart0; - uart1 = &uart1; - uart2 = &uart2; }; cpu_intc: cpu_intc { @@ -246,8 +244,6 @@ interrupts = <86>; #address-cells = <1>; #size-cells = <0>; - brcm,broken-ncq; - brcm,broken-phy; status = "disabled"; sata0: sata-port@0 { @@ -261,7 +257,7 @@ }; }; - sata_phy: sata-phy@1800000 { + sata_phy: sata-phy@180100 { compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; reg = <0x180100 0x0eff>; reg-names = "phy"; diff --git a/arch/mips/boot/dts/brcm/bcm7420.dtsi b/arch/mips/boot/dts/brcm/bcm7420.dtsi index 3302a1b..0586bf6 100644 --- a/arch/mips/boot/dts/brcm/bcm7420.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7420.dtsi @@ -86,14 +86,15 @@ compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; - brcm,int-map-mask = <0x44>; + brcm,int-map-mask = <0x44>, <0x1f000000>; brcm,int-fwd-mask = <0x70000>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&periph_intc>; - interrupts = <18>; + interrupts = <18>, <19>; + interrupt-names = "upg_main", "upg_bsc"; }; sun_top_ctrl: syscon@404000 { @@ -118,6 +119,78 @@ status = "disabled"; }; + uart1: serial@406b40 { + compatible = "ns16550a"; + reg = <0x406b40 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <64>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + uart2: serial@406b80 { + compatible = "ns16550a"; + reg = <0x406b80 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <65>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + bsca: i2c@406200 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406200 0x58>; + interrupts = <24>; + interrupt-names = "upg_bsca"; + status = "disabled"; + }; + + bscb: i2c@406280 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406280 0x58>; + interrupts = <25>; + interrupt-names = "upg_bscb"; + status = "disabled"; + }; + + bscc: i2c@406300 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406300 0x58>; + interrupts = <26>; + interrupt-names = "upg_bscc"; + status = "disabled"; + }; + + bscd: i2c@406380 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406380 0x58>; + interrupts = <27>; + interrupt-names = "upg_bscd"; + status = "disabled"; + }; + + bsce: i2c@406800 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406800 0x58>; + interrupts = <28>; + interrupt-names = "upg_bsce"; + status = "disabled"; + }; + enet0: ethernet@468000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7425.dtsi b/arch/mips/boot/dts/brcm/bcm7425.dtsi index 15b27aa..c1c15ed 100644 --- a/arch/mips/boot/dts/brcm/bcm7425.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7425.dtsi @@ -87,14 +87,32 @@ compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; - brcm,int-map-mask = <0x44>; + brcm,int-map-mask = <0x44>, <0x7000000>; brcm,int-fwd-mask = <0x70000>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&periph_intc>; - interrupts = <55>; + interrupts = <55>, <53>; + interrupt-names = "upg_main", "upg_bsc"; + }; + + upg_aon_irq0_intc: upg_aon_irq0_intc@409480 { + compatible = "brcm,bcm7120-l2-intc"; + reg = <0x409480 0x8>; + + brcm,int-map-mask = <0x40>, <0x18000000>, <0x100000>; + brcm,int-fwd-mask = <0>; + brcm,irq-can-wake; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&periph_intc>; + interrupts = <56>, <54>, <59>; + interrupt-names = "upg_main_aon", "upg_bsc_aon", + "upg_spi"; }; sun_top_ctrl: syscon@404000 { @@ -119,6 +137,78 @@ status = "disabled"; }; + uart1: serial@406b40 { + compatible = "ns16550a"; + reg = <0x406b40 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <62>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + uart2: serial@406b80 { + compatible = "ns16550a"; + reg = <0x406b80 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <63>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + bsca: i2c@409180 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_aon_irq0_intc>; + reg = <0x409180 0x58>; + interrupts = <27>; + interrupt-names = "upg_bsca"; + status = "disabled"; + }; + + bscb: i2c@409400 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_aon_irq0_intc>; + reg = <0x409400 0x58>; + interrupts = <28>; + interrupt-names = "upg_bscb"; + status = "disabled"; + }; + + bscc: i2c@406200 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406200 0x58>; + interrupts = <24>; + interrupt-names = "upg_bscc"; + status = "disabled"; + }; + + bscd: i2c@406280 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406280 0x58>; + interrupts = <25>; + interrupt-names = "upg_bscd"; + status = "disabled"; + }; + + bsce: i2c@406300 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406300 0x58>; + interrupts = <26>; + interrupt-names = "upg_bsce"; + status = "disabled"; + }; + enet0: ethernet@b80000 { phy-mode = "internal"; phy-handle = <&phy1>; @@ -227,11 +317,9 @@ reg-names = "ahci", "top-ctrl"; reg = <0x181000 0xa9c>, <0x180020 0x1c>; interrupt-parent = <&periph_intc>; - interrupts = <40>; + interrupts = <41>; #address-cells = <1>; #size-cells = <0>; - brcm,broken-ncq; - brcm,broken-phy; status = "disabled"; sata0: sata-port@0 { @@ -245,7 +333,7 @@ }; }; - sata_phy: sata-phy@1800000 { + sata_phy: sata-phy@180100 { compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; reg = <0x180100 0x0eff>; reg-names = "phy"; diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi index 56035e5..a874d3a 100644 --- a/arch/mips/boot/dts/brcm/bcm7435.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi @@ -7,7 +7,7 @@ #address-cells = <1>; #size-cells = <0>; - mips-hpt-frequency = <163125000>; + mips-hpt-frequency = <175625000>; cpu@0 { compatible = "brcm,bmips5200"; @@ -63,13 +63,14 @@ periph_intc: periph_intc@41b500 { compatible = "brcm,bcm7038-l1-intc"; - reg = <0x41b500 0x40>, <0x41b600 0x40>; + reg = <0x41b500 0x40>, <0x41b600 0x40>, + <0x41b700 0x40>, <0x41b800 0x40>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&cpu_intc>; - interrupts = <2>, <3>; + interrupts = <2>, <3>, <2>, <3>; }; sun_l2_intc: sun_l2_intc@403000 { @@ -101,14 +102,32 @@ compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; - brcm,int-map-mask = <0x44>; + brcm,int-map-mask = <0x44>, <0x7000000>; brcm,int-fwd-mask = <0x70000>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&periph_intc>; - interrupts = <60>; + interrupts = <60>, <58>; + interrupt-names = "upg_main", "upg_bsc"; + }; + + upg_aon_irq0_intc: upg_aon_irq0_intc@409480 { + compatible = "brcm,bcm7120-l2-intc"; + reg = <0x409480 0x8>; + + brcm,int-map-mask = <0x40>, <0x18000000>, <0x100000>; + brcm,int-fwd-mask = <0>; + brcm,irq-can-wake; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&periph_intc>; + interrupts = <61>, <59>, <64>; + interrupt-names = "upg_main_aon", "upg_bsc_aon", + "upg_spi"; }; sun_top_ctrl: syscon@404000 { @@ -133,6 +152,78 @@ status = "disabled"; }; + uart1: serial@406b40 { + compatible = "ns16550a"; + reg = <0x406b40 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <67>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + uart2: serial@406b80 { + compatible = "ns16550a"; + reg = <0x406b80 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <68>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + bsca: i2c@406300 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406300 0x58>; + interrupts = <26>; + interrupt-names = "upg_bsca"; + status = "disabled"; + }; + + bscb: i2c@409400 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_aon_irq0_intc>; + reg = <0x409400 0x58>; + interrupts = <28>; + interrupt-names = "upg_bscb"; + status = "disabled"; + }; + + bscc: i2c@406200 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406200 0x58>; + interrupts = <24>; + interrupt-names = "upg_bscc"; + status = "disabled"; + }; + + bscd: i2c@406280 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406280 0x58>; + interrupts = <25>; + interrupt-names = "upg_bscd"; + status = "disabled"; + }; + + bsce: i2c@409180 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_aon_irq0_intc>; + reg = <0x409180 0x58>; + interrupts = <27>; + interrupt-names = "upg_bsce"; + status = "disabled"; + }; + enet0: ethernet@b80000 { phy-mode = "internal"; phy-handle = <&phy1>; @@ -235,5 +326,45 @@ interrupts = <78>; status = "disabled"; }; + + sata: sata@181000 { + compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci"; + reg-names = "ahci", "top-ctrl"; + reg = <0x181000 0xa9c>, <0x180020 0x1c>; + interrupt-parent = <&periph_intc>; + interrupts = <45>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + sata0: sata-port@0 { + reg = <0>; + phys = <&sata_phy0>; + }; + + sata1: sata-port@1 { + reg = <1>; + phys = <&sata_phy1>; + }; + }; + + sata_phy: sata-phy@180100 { + compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; + reg = <0x180100 0x0eff>; + reg-names = "phy"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + sata_phy0: sata-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + sata_phy1: sata-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm96358nb4ser.dts b/arch/mips/boot/dts/brcm/bcm96358nb4ser.dts new file mode 100644 index 0000000..f412117 --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm96358nb4ser.dts @@ -0,0 +1,46 @@ +/dts-v1/; + +/include/ "bcm6358.dtsi" + +/ { + compatible = "sfr,nb4-ser", "brcm,bcm6358"; + model = "SFR Neufbox 4 (Sercomm)"; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x02000000>; + }; + + chosen { + stdout-path = &uart0; + }; +}; + +&leds0 { + status = "ok"; + + led@0 { + reg = <0>; + active-low; + label = "nb4-ser:white:alarm"; + }; + led@2 { + reg = <2>; + active-low; + label = "nb4-ser:white:tv"; + }; + led@3 { + reg = <3>; + active-low; + label = "nb4-ser:white:tel"; + }; + led@4 { + reg = <4>; + active-low; + label = "nb4-ser:white:adsl"; + }; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm96368mvwg.dts b/arch/mips/boot/dts/brcm/bcm96368mvwg.dts index 0e890c2..8c71c68 100644 --- a/arch/mips/boot/dts/brcm/bcm96368mvwg.dts +++ b/arch/mips/boot/dts/brcm/bcm96368mvwg.dts @@ -22,10 +22,10 @@ }; /* FIXME: need to set up USB_CTRL registers first */ -&ehci0 { +&ehci { status = "disabled"; }; -&ohci0 { +&ohci { status = "disabled"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97125cbmb.dts b/arch/mips/boot/dts/brcm/bcm97125cbmb.dts index e046b11..f2449d1 100644 --- a/arch/mips/boot/dts/brcm/bcm97125cbmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97125cbmb.dts @@ -21,6 +21,30 @@ status = "okay"; }; +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&bsca { + status = "okay"; +}; + +&bscb { + status = "okay"; +}; + +&bscc { + status = "okay"; +}; + +&bscd { + status = "okay"; +}; + /* FIXME: USB is wonky; disable it for now */ &ehci0 { status = "disabled"; diff --git a/arch/mips/boot/dts/brcm/bcm97360svmb.dts b/arch/mips/boot/dts/brcm/bcm97360svmb.dts index d48462e..73124be 100644 --- a/arch/mips/boot/dts/brcm/bcm97360svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97360svmb.dts @@ -56,3 +56,11 @@ &ohci0 { status = "okay"; }; + +&sata { + status = "okay"; +}; + +&sata_phy { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm97420c.dts b/arch/mips/boot/dts/brcm/bcm97420c.dts index 67fe1f3..600d57a 100644 --- a/arch/mips/boot/dts/brcm/bcm97420c.dts +++ b/arch/mips/boot/dts/brcm/bcm97420c.dts @@ -23,6 +23,34 @@ status = "okay"; }; +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&bsca { + status = "okay"; +}; + +&bscb { + status = "okay"; +}; + +&bscc { + status = "okay"; +}; + +&bscd { + status = "okay"; +}; + +&bsce { + status = "okay"; +}; + /* FIXME: MAC driver comes up but cannot attach to PHY */ &enet0 { status = "disabled"; diff --git a/arch/mips/boot/dts/brcm/bcm97425svmb.dts b/arch/mips/boot/dts/brcm/bcm97425svmb.dts index 689c68a..119c714 100644 --- a/arch/mips/boot/dts/brcm/bcm97425svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97425svmb.dts @@ -23,6 +23,34 @@ status = "okay"; }; +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&bsca { + status = "okay"; +}; + +&bscb { + status = "okay"; +}; + +&bscc { + status = "okay"; +}; + +&bscd { + status = "okay"; +}; + +&bsce { + status = "okay"; +}; + &enet0 { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97435svmb.dts b/arch/mips/boot/dts/brcm/bcm97435svmb.dts index 1df0881..43e3ba2 100644 --- a/arch/mips/boot/dts/brcm/bcm97435svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97435svmb.dts @@ -14,7 +14,7 @@ }; chosen { - bootargs = "console=ttyS0,115200 maxcpus=1"; + bootargs = "console=ttyS0,115200"; stdout-path = &uart0; }; }; @@ -23,6 +23,34 @@ status = "okay"; }; +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&bsca { + status = "okay"; +}; + +&bscb { + status = "okay"; +}; + +&bscc { + status = "okay"; +}; + +&bscd { + status = "okay"; +}; + +&bsce { + status = "okay"; +}; + &enet0 { status = "okay"; }; @@ -58,3 +86,11 @@ &ohci3 { status = "okay"; }; + +&sata { + status = "okay"; +}; + +&sata_phy { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts new file mode 100644 index 0000000..d6bc994 --- /dev/null +++ b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts @@ -0,0 +1,78 @@ +/* + * Device tree source for D-Link DSR-1000N. + * + * Written by: Aaro Koskinen <aaro.koskinen@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/include/ "octeon_3xxx.dtsi" + +/ { + model = "dlink,dsr-1000n"; + + soc@0 { + smi0: mdio@1180000001800 { + phy8: ethernet-phy@8 { + reg = <8>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + }; + + pip: pip@11800a0000000 { + interface@0 { + ethernet@0 { + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + ethernet@1 { + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + ethernet@2 { + phy-handle = <&phy8>; + }; + }; + }; + + twsi0: i2c@1180000001000 { + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + }; + + uart0: serial@1180000000800 { + clock-frequency = <500000000>; + }; + + usbn: usbn@1180068000000 { + refclk-frequency = <12000000>; + refclk-type = "crystal"; + }; + }; + + leds { + compatible = "gpio-leds"; + + usb1 { + label = "usb1"; + gpios = <&gpio 9 1>; /* Active low */ + }; + + usb2 { + label = "usb2"; + gpios = <&gpio 10 1>; /* Active low */ + }; + }; + + aliases { + pip = &pip; + }; +}; diff --git a/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dts b/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dts index 9c48e05..de61f02 100644 --- a/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dts +++ b/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dts @@ -1,4 +1,3 @@ -/dts-v1/; /* * OCTEON 3XXX, 5XXX, 63XX device tree skeleton. * @@ -6,56 +5,12 @@ * use. Because of this, it contains a super-set of the available * devices and properties. */ -/ { - compatible = "cavium,octeon-3860"; - #address-cells = <2>; - #size-cells = <2>; - interrupt-parent = <&ciu>; - - soc@0 { - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges; /* Direct mapping */ - - ciu: interrupt-controller@1070000000000 { - compatible = "cavium,octeon-3860-ciu"; - interrupt-controller; - /* Interrupts are specified by two parts: - * 1) Controller register (0 or 1) - * 2) Bit within the register (0..63) - */ - #interrupt-cells = <2>; - reg = <0x10700 0x00000000 0x0 0x7000>; - }; - gpio: gpio-controller@1070000000800 { - #gpio-cells = <2>; - compatible = "cavium,octeon-3860-gpio"; - reg = <0x10700 0x00000800 0x0 0x100>; - gpio-controller; - /* Interrupts are specified by two parts: - * 1) GPIO pin number (0..15) - * 2) Triggering (1 - edge rising - * 2 - edge falling - * 4 - level active high - * 8 - level active low) - */ - interrupt-controller; - #interrupt-cells = <2>; - /* The GPIO pin connect to 16 consecutive CUI bits */ - interrupts = <0 16>, <0 17>, <0 18>, <0 19>, - <0 20>, <0 21>, <0 22>, <0 23>, - <0 24>, <0 25>, <0 26>, <0 27>, - <0 28>, <0 29>, <0 30>, <0 31>; - }; +/include/ "octeon_3xxx.dtsi" +/ { + soc@0 { smi0: mdio@1180000001800 { - compatible = "cavium,octeon-3860-mdio"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x11800 0x00001800 0x0 0x40>; - phy0: ethernet-phy@0 { compatible = "marvell,88e1118"; marvell,reg-init = @@ -220,35 +175,16 @@ }; pip: pip@11800a0000000 { - compatible = "cavium,octeon-3860-pip"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x11800 0xa0000000 0x0 0x2000>; - interface@0 { - compatible = "cavium,octeon-3860-pip-interface"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; /* interface */ - ethernet@0 { - compatible = "cavium,octeon-3860-pip-port"; - reg = <0x0>; /* Port */ - local-mac-address = [ 00 00 00 00 00 00 ]; phy-handle = <&phy2>; cavium,alt-phy-handle = <&phy100>; }; ethernet@1 { - compatible = "cavium,octeon-3860-pip-port"; - reg = <0x1>; /* Port */ - local-mac-address = [ 00 00 00 00 00 00 ]; phy-handle = <&phy3>; cavium,alt-phy-handle = <&phy101>; }; ethernet@2 { - compatible = "cavium,octeon-3860-pip-port"; - reg = <0x2>; /* Port */ - local-mac-address = [ 00 00 00 00 00 00 ]; phy-handle = <&phy4>; cavium,alt-phy-handle = <&phy102>; }; @@ -322,11 +258,6 @@ }; interface@1 { - compatible = "cavium,octeon-3860-pip-interface"; - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; /* interface */ - ethernet@0 { compatible = "cavium,octeon-3860-pip-port"; reg = <0x0>; /* Port */ @@ -355,13 +286,6 @@ }; twsi0: i2c@1180000001000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "cavium,octeon-3860-twsi"; - reg = <0x11800 0x00001000 0x0 0x200>; - interrupts = <0 45>; - clock-frequency = <100000>; - rtc@68 { compatible = "dallas,ds1337"; reg = <0x68>; @@ -381,15 +305,6 @@ clock-frequency = <100000>; }; - uart0: serial@1180000000800 { - compatible = "cavium,octeon-3860-uart","ns16550"; - reg = <0x11800 0x00000800 0x0 0x400>; - clock-frequency = <0>; - current-speed = <115200>; - reg-shift = <3>; - interrupts = <0 34>; - }; - uart1: serial@1180000000c00 { compatible = "cavium,octeon-3860-uart","ns16550"; reg = <0x11800 0x00000c00 0x0 0x400>; @@ -409,98 +324,6 @@ }; bootbus: bootbus@1180000000000 { - compatible = "cavium,octeon-3860-bootbus"; - reg = <0x11800 0x00000000 0x0 0x200>; - /* The chip select number and offset */ - #address-cells = <2>; - /* The size of the chip select region */ - #size-cells = <1>; - ranges = <0 0 0x0 0x1f400000 0xc00000>, - <1 0 0x10000 0x30000000 0>, - <2 0 0x10000 0x40000000 0>, - <3 0 0x10000 0x50000000 0>, - <4 0 0x0 0x1d020000 0x10000>, - <5 0 0x0 0x1d040000 0x10000>, - <6 0 0x0 0x1d050000 0x10000>, - <7 0 0x10000 0x90000000 0>; - - cavium,cs-config@0 { - compatible = "cavium,octeon-3860-bootbus-config"; - cavium,cs-index = <0>; - cavium,t-adr = <20>; - cavium,t-ce = <60>; - cavium,t-oe = <60>; - cavium,t-we = <45>; - cavium,t-rd-hld = <35>; - cavium,t-wr-hld = <45>; - cavium,t-pause = <0>; - cavium,t-wait = <0>; - cavium,t-page = <35>; - cavium,t-rd-dly = <0>; - - cavium,pages = <0>; - cavium,bus-width = <8>; - }; - cavium,cs-config@4 { - compatible = "cavium,octeon-3860-bootbus-config"; - cavium,cs-index = <4>; - cavium,t-adr = <320>; - cavium,t-ce = <320>; - cavium,t-oe = <320>; - cavium,t-we = <320>; - cavium,t-rd-hld = <320>; - cavium,t-wr-hld = <320>; - cavium,t-pause = <320>; - cavium,t-wait = <320>; - cavium,t-page = <320>; - cavium,t-rd-dly = <0>; - - cavium,pages = <0>; - cavium,bus-width = <8>; - }; - cavium,cs-config@5 { - compatible = "cavium,octeon-3860-bootbus-config"; - cavium,cs-index = <5>; - cavium,t-adr = <5>; - cavium,t-ce = <300>; - cavium,t-oe = <125>; - cavium,t-we = <150>; - cavium,t-rd-hld = <100>; - cavium,t-wr-hld = <30>; - cavium,t-pause = <0>; - cavium,t-wait = <30>; - cavium,t-page = <320>; - cavium,t-rd-dly = <0>; - - cavium,pages = <0>; - cavium,bus-width = <16>; - }; - cavium,cs-config@6 { - compatible = "cavium,octeon-3860-bootbus-config"; - cavium,cs-index = <6>; - cavium,t-adr = <5>; - cavium,t-ce = <300>; - cavium,t-oe = <270>; - cavium,t-we = <150>; - cavium,t-rd-hld = <100>; - cavium,t-wr-hld = <70>; - cavium,t-pause = <0>; - cavium,t-wait = <0>; - cavium,t-page = <320>; - cavium,t-rd-dly = <0>; - - cavium,pages = <0>; - cavium,wait-mode; - cavium,bus-width = <16>; - }; - - flash0: nor@0,0 { - compatible = "cfi-flash"; - reg = <0 0 0x800000>; - #address-cells = <1>; - #size-cells = <1>; - }; - led0: led-display@4,0 { compatible = "avago,hdsp-253x"; reg = <4 0x20 0x20>, <4 0 0x20>; @@ -515,17 +338,6 @@ }; }; - dma0: dma-engine@1180000000100 { - compatible = "cavium,octeon-5750-bootbus-dma"; - reg = <0x11800 0x00000100 0x0 0x8>; - interrupts = <0 63>; - }; - dma1: dma-engine@1180000000108 { - compatible = "cavium,octeon-5750-bootbus-dma"; - reg = <0x11800 0x00000108 0x0 0x8>; - interrupts = <0 63>; - }; - uctl: uctl@118006f000000 { compatible = "cavium,octeon-6335-uctl"; reg = <0x11800 0x6f000000 0x0 0x100>; @@ -552,21 +364,10 @@ }; usbn: usbn@1180068000000 { - compatible = "cavium,octeon-5750-usbn"; - reg = <0x11800 0x68000000 0x0 0x1000>; - ranges; /* Direct mapping */ - #address-cells = <2>; - #size-cells = <2>; /* 12MHz, 24MHz and 48MHz allowed */ refclk-frequency = <12000000>; /* Either "crystal" or "external" */ refclk-type = "crystal"; - - usbc@16f0010000000 { - compatible = "cavium,octeon-5750-usbc"; - reg = <0x16f00 0x10000000 0x0 0x80000>; - interrupts = <0 56>; - }; }; }; diff --git a/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dtsi b/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dtsi new file mode 100644 index 0000000..5302148 --- /dev/null +++ b/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dtsi @@ -0,0 +1,231 @@ +/* OCTEON 3XXX DTS common parts. */ + +/dts-v1/; + +/ { + compatible = "cavium,octeon-3860"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&ciu>; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; /* Direct mapping */ + + ciu: interrupt-controller@1070000000000 { + compatible = "cavium,octeon-3860-ciu"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0 or 1) + * 2) Bit within the register (0..63) + */ + #interrupt-cells = <2>; + reg = <0x10700 0x00000000 0x0 0x7000>; + }; + + gpio: gpio-controller@1070000000800 { + #gpio-cells = <2>; + compatible = "cavium,octeon-3860-gpio"; + reg = <0x10700 0x00000800 0x0 0x100>; + gpio-controller; + /* Interrupts are specified by two parts: + * 1) GPIO pin number (0..15) + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + interrupt-controller; + #interrupt-cells = <2>; + /* The GPIO pin connect to 16 consecutive CUI bits */ + interrupts = <0 16>, <0 17>, <0 18>, <0 19>, + <0 20>, <0 21>, <0 22>, <0 23>, + <0 24>, <0 25>, <0 26>, <0 27>, + <0 28>, <0 29>, <0 30>, <0 31>; + }; + + smi0: mdio@1180000001800 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001800 0x0 0x40>; + }; + + pip: pip@11800a0000000 { + compatible = "cavium,octeon-3860-pip"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0xa0000000 0x0 0x2000>; + + interface@0 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + }; + + interface@1 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; /* interface */ + }; + }; + + twsi0: i2c@1180000001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001000 0x0 0x200>; + interrupts = <0 45>; + clock-frequency = <100000>; + }; + + uart0: serial@1180000000800 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000800 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <0 34>; + }; + + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + ranges = <0 0 0x0 0x1f400000 0xc00000>, + <1 0 0x10000 0x30000000 0>, + <2 0 0x10000 0x40000000 0>, + <3 0 0x10000 0x50000000 0>, + <4 0 0x0 0x1d020000 0x10000>, + <5 0 0x0 0x1d040000 0x10000>, + <6 0 0x0 0x1d050000 0x10000>, + <7 0 0x10000 0x90000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <20>; + cavium,t-ce = <60>; + cavium,t-oe = <60>; + cavium,t-we = <45>; + cavium,t-rd-hld = <35>; + cavium,t-wr-hld = <45>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <35>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@4 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <4>; + cavium,t-adr = <320>; + cavium,t-ce = <320>; + cavium,t-oe = <320>; + cavium,t-we = <320>; + cavium,t-rd-hld = <320>; + cavium,t-wr-hld = <320>; + cavium,t-pause = <320>; + cavium,t-wait = <320>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@5 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <5>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <125>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <30>; + cavium,t-pause = <0>; + cavium,t-wait = <30>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <16>; + }; + cavium,cs-config@6 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <6>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <270>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <70>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,wait-mode; + cavium,bus-width = <16>; + }; + + flash0: nor@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + }; + }; + + dma0: dma-engine@1180000000100 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000100 0x0 0x8>; + interrupts = <0 63>; + }; + + dma1: dma-engine@1180000000108 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000108 0x0 0x8>; + interrupts = <0 63>; + }; + + usbn: usbn@1180068000000 { + compatible = "cavium,octeon-5750-usbn"; + reg = <0x11800 0x68000000 0x0 0x1000>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + + usbc@16f0010000000 { + compatible = "cavium,octeon-5750-usbc"; + reg = <0x16f00 0x10000000 0x0 0x80000>; + interrupts = <0 56>; + }; + }; + }; +}; diff --git a/arch/mips/boot/dts/cavium-octeon/ubnt_e100.dts b/arch/mips/boot/dts/cavium-octeon/ubnt_e100.dts new file mode 100644 index 0000000..243e5dc --- /dev/null +++ b/arch/mips/boot/dts/cavium-octeon/ubnt_e100.dts @@ -0,0 +1,59 @@ +/* + * Device tree source for EdgeRouter Lite. + * + * Written by: Aaro Koskinen <aaro.koskinen@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/include/ "octeon_3xxx.dtsi" + +/ { + model = "ubnt,e100"; + + soc@0 { + smi0: mdio@1180000001800 { + phy5: ethernet-phy@5 { + reg = <5>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + phy6: ethernet-phy@6 { + reg = <6>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + phy7: ethernet-phy@7 { + reg = <7>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + }; + + pip: pip@11800a0000000 { + interface@0 { + ethernet@0 { + phy-handle = <&phy7>; + }; + ethernet@1 { + phy-handle = <&phy6>; + }; + ethernet@2 { + phy-handle = <&phy5>; + }; + }; + }; + + uart0: serial@1180000000800 { + clock-frequency = <500000000>; + }; + + usbn: usbn@1180068000000 { + refclk-frequency = <12000000>; + refclk-type = "crystal"; + }; + }; + + aliases { + pip = &pip; + }; +}; diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi index 8b2437c..4a9c8f2 100644 --- a/arch/mips/boot/dts/ingenic/jz4740.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi @@ -65,4 +65,18 @@ clocks = <&ext>, <&cgu JZ4740_CLK_UART1>; clock-names = "baud", "module"; }; + + uhc: uhc@13030000 { + compatible = "ingenic,jz4740-ohci", "generic-ohci"; + reg = <0x13030000 0x1000>; + + clocks = <&cgu JZ4740_CLK_UHC>; + assigned-clocks = <&cgu JZ4740_CLK_UHC>; + assigned-clock-rates = <48000000>; + + interrupt-parent = <&intc>; + interrupts = <3>; + + status = "disabled"; + }; }; diff --git a/arch/mips/boot/dts/lantiq/easy50712.dts b/arch/mips/boot/dts/lantiq/easy50712.dts index 143b8a3..b599625 100644 --- a/arch/mips/boot/dts/lantiq/easy50712.dts +++ b/arch/mips/boot/dts/lantiq/easy50712.dts @@ -52,7 +52,7 @@ }; gpio: pinmux@E100B10 { - compatible = "lantiq,pinctrl-xway"; + compatible = "lantiq,danube-pinctrl"; pinctrl-names = "default"; pinctrl-0 = <&state_default>; diff --git a/arch/mips/boot/dts/pic32/pic32mzda-clk.dtsi b/arch/mips/boot/dts/pic32/pic32mzda-clk.dtsi deleted file mode 100644 index ef13350..0000000 --- a/arch/mips/boot/dts/pic32/pic32mzda-clk.dtsi +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Device Tree Source for PIC32MZDA clock data - * - * Purna Chandra Mandal <purna.mandal@microchip.com> - * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. - * - * Licensed under GPLv2 or later. - */ - -/* all fixed rate clocks */ - -/ { - POSC:posc_clk { /* On-chip primary oscillator */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - }; - - FRC:frc_clk { /* internal FRC oscillator */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <8000000>; - }; - - BFRC:bfrc_clk { /* internal backup FRC oscillator */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <8000000>; - }; - - LPRC:lprc_clk { /* internal low-power FRC oscillator */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <32000>; - }; - - /* UPLL provides clock to USBCORE */ - UPLL:usb_phy_clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - clock-output-names = "usbphy_clk"; - }; - - TxCKI:txcki_clk { /* external clock input on TxCLKI pin */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <4000000>; - status = "disabled"; - }; - - /* external clock input on REFCLKIx pin */ - REFIx:refix_clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - status = "disabled"; - }; - - /* PIC32 specific clks */ - pic32_clktree { - #address-cells = <1>; - #size-cells = <1>; - reg = <0x1f801200 0x200>; - compatible = "microchip,pic32mzda-clk"; - ranges = <0 0x1f801200 0x200>; - - /* secondary oscillator; external input on SOSCI pin */ - SOSC:sosc_clk@0 { - #clock-cells = <0>; - compatible = "microchip,pic32mzda-sosc"; - clock-frequency = <32768>; - reg = <0x000 0x10>, /* enable reg */ - <0x1d0 0x10>; /* status reg */ - microchip,bit-mask = <0x02>; /* enable mask */ - microchip,status-bit-mask = <0x10>; /* status-mask*/ - }; - - FRCDIV:frcdiv_clk { - #clock-cells = <0>; - compatible = "microchip,pic32mzda-frcdivclk"; - clocks = <&FRC>; - clock-output-names = "frcdiv_clk"; - }; - - /* System PLL clock */ - SYSPLL:spll_clk@020 { - #clock-cells = <0>; - compatible = "microchip,pic32mzda-syspll"; - reg = <0x020 0x10>, /* SPLL register */ - <0x1d0 0x10>; /* CLKSTAT register */ - clocks = <&POSC>, <&FRC>; - clock-output-names = "sys_pll"; - microchip,status-bit-mask = <0x80>; /* SPLLRDY */ - }; - - /* system clock; mux with postdiv & slew */ - SYSCLK:sys_clk@1c0 { - #clock-cells = <0>; - compatible = "microchip,pic32mzda-sysclk-v2"; - reg = <0x1c0 0x04>; /* SLEWCON */ - clocks = <&FRCDIV>, <&SYSPLL>, <&POSC>, <&SOSC>, - <&LPRC>, <&FRCDIV>; - microchip,clock-indices = <0>, <1>, <2>, <4>, - <5>, <7>; - clock-output-names = "sys_clk"; - }; - - /* Peripheral bus1 clock */ - PBCLK1:pb1_clk@140 { - reg = <0x140 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb1_clk"; - /* used by system modules, not gateable */ - microchip,ignore-unused; - }; - - /* Peripheral bus2 clock */ - PBCLK2:pb2_clk@150 { - reg = <0x150 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb2_clk"; - /* avoid gating even if unused */ - microchip,ignore-unused; - }; - - /* Peripheral bus3 clock */ - PBCLK3:pb3_clk@160 { - reg = <0x160 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb3_clk"; - }; - - /* Peripheral bus4 clock(I/O ports, GPIO) */ - PBCLK4:pb4_clk@170 { - reg = <0x170 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb4_clk"; - }; - - /* Peripheral bus clock */ - PBCLK5:pb5_clk@180 { - reg = <0x180 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb5_clk"; - }; - - /* Peripheral Bus6 clock; */ - PBCLK6:pb6_clk@190 { - reg = <0x190 0x10>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - #clock-cells = <0>; - }; - - /* Peripheral bus7 clock */ - PBCLK7:pb7_clk@1a0 { - reg = <0x1a0 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - /* CPU is driven by this clock; so named */ - clock-output-names = "cpu_clk"; - clocks = <&SYSCLK>; - }; - - /* Reference Oscillator clock for SPI/I2S */ - REFCLKO1:refo1_clk@80 { - reg = <0x080 0x20>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>, <&PBCLK1>, <&POSC>, <&FRC>, <&LPRC>, - <&SOSC>, <&SYSPLL>, <&REFIx>, <&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - clock-output-names = "refo1_clk"; - }; - - /* Reference Oscillator clock for SQI */ - REFCLKO2:refo2_clk@a0 { - reg = <0x0a0 0x20>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>, <&PBCLK1>, <&POSC>, <&FRC>, <&LPRC>, - <&SOSC>, <&SYSPLL>, <&REFIx>, <&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - clock-output-names = "refo2_clk"; - }; - - /* Reference Oscillator clock, ADC */ - REFCLKO3:refo3_clk@c0 { - reg = <0x0c0 0x20>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>, <&PBCLK1>, <&POSC>, <&FRC>, <&LPRC>, - <&SOSC>, <&SYSPLL>, <&REFIx>, <&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - #clock-cells = <0>; - clock-output-names = "refo3_clk"; - }; - - /* Reference Oscillator clock */ - REFCLKO4:refo4_clk@e0 { - reg = <0x0e0 0x20>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>, <&PBCLK1>, <&POSC>, <&FRC>, <&LPRC>, - <&SOSC>, <&SYSPLL>, <&REFIx>, <&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - #clock-cells = <0>; - clock-output-names = "refo4_clk"; - }; - - /* Reference Oscillator clock, LCD */ - REFCLKO5:refo5_clk@100 { - reg = <0x100 0x20>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>,<&PBCLK1>,<&POSC>,<&FRC>,<&LPRC>, - <&SOSC>,<&SYSPLL>,<&REFIx>,<&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - #clock-cells = <0>; - clock-output-names = "refo5_clk"; - }; - }; -}; diff --git a/arch/mips/boot/dts/pic32/pic32mzda.dtsi b/arch/mips/boot/dts/pic32/pic32mzda.dtsi index ad9e3318..5353a63 100644 --- a/arch/mips/boot/dts/pic32/pic32mzda.dtsi +++ b/arch/mips/boot/dts/pic32/pic32mzda.dtsi @@ -6,11 +6,9 @@ * published by the Free Software Foundation. * */ - +#include <dt-bindings/clock/microchip,pic32-clock.h> #include <dt-bindings/interrupt-controller/irq.h> -#include "pic32mzda-clk.dtsi" - / { #address-cells = <1>; #size-cells = <1>; @@ -50,6 +48,29 @@ interrupts = <0 IRQ_TYPE_EDGE_RISING>; }; + /* external clock input on TxCLKI pin */ + txcki: txcki_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <4000000>; + status = "disabled"; + }; + + /* external input on REFCLKIx pin */ + refix: refix_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + status = "disabled"; + }; + + rootclk: clock-controller@1f801200 { + compatible = "microchip,pic32mzda-clk"; + reg = <0x1f801200 0x200>; + #clock-cells = <1>; + microchip,pic32mzda-sosc; + }; + evic: interrupt-controller@1f810000 { compatible = "microchip,pic32mzda-evic"; interrupt-controller; @@ -63,7 +84,7 @@ #size-cells = <1>; compatible = "microchip,pic32mzda-pinctrl"; reg = <0x1f801400 0x400>; - clocks = <&PBCLK1>; + clocks = <&rootclk PB1CLK>; }; /* PORTA */ @@ -75,7 +96,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <0>; gpio-ranges = <&pic32_pinctrl 0 0 16>; }; @@ -89,7 +110,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <1>; gpio-ranges = <&pic32_pinctrl 0 16 16>; }; @@ -103,7 +124,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <2>; gpio-ranges = <&pic32_pinctrl 0 32 16>; }; @@ -117,7 +138,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <3>; gpio-ranges = <&pic32_pinctrl 0 48 16>; }; @@ -131,7 +152,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <4>; gpio-ranges = <&pic32_pinctrl 0 64 16>; }; @@ -145,7 +166,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <5>; gpio-ranges = <&pic32_pinctrl 0 80 16>; }; @@ -159,7 +180,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <6>; gpio-ranges = <&pic32_pinctrl 0 96 16>; }; @@ -173,7 +194,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <7>; gpio-ranges = <&pic32_pinctrl 0 112 16>; }; @@ -189,7 +210,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <8>; gpio-ranges = <&pic32_pinctrl 0 128 16>; }; @@ -203,7 +224,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <9>; gpio-ranges = <&pic32_pinctrl 0 144 16>; }; @@ -212,7 +233,7 @@ compatible = "microchip,pic32mzda-sdhci"; reg = <0x1f8ec000 0x100>; interrupts = <191 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&REFCLKO4>, <&PBCLK5>; + clocks = <&rootclk REF4CLK>, <&rootclk PB5CLK>; clock-names = "base_clk", "sys_clk"; bus-width = <4>; cap-sd-highspeed; @@ -225,7 +246,7 @@ interrupts = <112 IRQ_TYPE_LEVEL_HIGH>, <113 IRQ_TYPE_LEVEL_HIGH>, <114 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -235,7 +256,7 @@ interrupts = <145 IRQ_TYPE_LEVEL_HIGH>, <146 IRQ_TYPE_LEVEL_HIGH>, <147 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -245,7 +266,7 @@ interrupts = <157 IRQ_TYPE_LEVEL_HIGH>, <158 IRQ_TYPE_LEVEL_HIGH>, <159 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -255,7 +276,7 @@ interrupts = <170 IRQ_TYPE_LEVEL_HIGH>, <171 IRQ_TYPE_LEVEL_HIGH>, <172 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -265,7 +286,7 @@ interrupts = <179 IRQ_TYPE_LEVEL_HIGH>, <180 IRQ_TYPE_LEVEL_HIGH>, <181 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -275,7 +296,7 @@ interrupts = <188 IRQ_TYPE_LEVEL_HIGH>, <189 IRQ_TYPE_LEVEL_HIGH>, <190 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; }; diff --git a/arch/mips/boot/dts/pic32/pic32mzda_sk.dts b/arch/mips/boot/dts/pic32/pic32mzda_sk.dts index 5d434a5..fc74010 100644 --- a/arch/mips/boot/dts/pic32/pic32mzda_sk.dts +++ b/arch/mips/boot/dts/pic32/pic32mzda_sk.dts @@ -95,8 +95,9 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdhc1>; status = "okay"; - assigned-clocks = <&REFCLKO2>,<&REFCLKO4>,<&REFCLKO5>; - assigned-clock-rates = <50000000>,<25000000>,<40000000>; + assigned-clocks = <&rootclk REF2CLK>, <&rootclk REF4CLK>, + <&rootclk REF5CLK>; + assigned-clock-rates = <50000000>, <25000000>, <40000000>; }; &pic32_pinctrl { diff --git a/arch/mips/boot/dts/qca/Makefile b/arch/mips/boot/dts/qca/Makefile index 2d61455d..63a9ddf 100644 --- a/arch/mips/boot/dts/qca/Makefile +++ b/arch/mips/boot/dts/qca/Makefile @@ -1,8 +1,9 @@ # All DTBs dtb-$(CONFIG_ATH79) += ar9132_tl_wr1043nd_v1.dtb - -# Select a DTB to build in the kernel -obj-$(CONFIG_DTB_TL_WR1043ND_V1) += ar9132_tl_wr1043nd_v1.dtb.o +dtb-$(CONFIG_ATH79) += ar9331_dpt_module.dtb +dtb-$(CONFIG_ATH79) += ar9331_dragino_ms14.dtb +dtb-$(CONFIG_ATH79) += ar9331_omega.dtb +dtb-$(CONFIG_ATH79) += ar9331_tl_mr3020.dtb # Force kbuild to make empty built-in.o if necessary obj- += dummy.o diff --git a/arch/mips/boot/dts/qca/ar9132.dtsi b/arch/mips/boot/dts/qca/ar9132.dtsi index 3c2ed9e..302f0a8 100644 --- a/arch/mips/boot/dts/qca/ar9132.dtsi +++ b/arch/mips/boot/dts/qca/ar9132.dtsi @@ -1,3 +1,5 @@ +#include <dt-bindings/clock/ath79-clk.h> + / { compatible = "qca,ar9132"; @@ -11,6 +13,7 @@ cpu@0 { device_type = "cpu"; compatible = "mips,mips24Kc"; + clocks = <&pll ATH79_CLK_CPU>; reg = <0>; }; }; @@ -52,12 +55,12 @@ #qca,ddr-wb-channel-cells = <1>; }; - uart@18020000 { + uart: uart@18020000 { compatible = "ns8250"; reg = <0x18020000 0x20>; interrupts = <3>; - clocks = <&pll 2>; + clocks = <&pll ATH79_CLK_AHB>; clock-names = "uart"; reg-io-width = <4>; @@ -94,13 +97,13 @@ clock-output-names = "cpu", "ddr", "ahb"; }; - wdt@18060008 { + wdt: wdt@18060008 { compatible = "qca,ar7130-wdt"; reg = <0x18060008 0x8>; interrupts = <4>; - clocks = <&pll 2>; + clocks = <&pll ATH79_CLK_AHB>; clock-names = "wdt"; }; @@ -125,7 +128,7 @@ }; }; - usb@1b000100 { + usb: usb@1b000100 { compatible = "qca,ar7100-ehci", "generic-ehci"; reg = <0x1b000100 0x100>; @@ -140,11 +143,11 @@ status = "disabled"; }; - spi@1f000000 { + spi: spi@1f000000 { compatible = "qca,ar9132-spi", "qca,ar7100-spi"; reg = <0x1f000000 0x10>; - clocks = <&pll 2>; + clocks = <&pll ATH79_CLK_AHB>; clock-names = "ahb"; status = "disabled"; diff --git a/arch/mips/boot/dts/qca/ar9132_tl_wr1043nd_v1.dts b/arch/mips/boot/dts/qca/ar9132_tl_wr1043nd_v1.dts index 4f1540e5f..3c3b7ce 100644 --- a/arch/mips/boot/dts/qca/ar9132_tl_wr1043nd_v1.dts +++ b/arch/mips/boot/dts/qca/ar9132_tl_wr1043nd_v1.dts @@ -9,10 +9,6 @@ compatible = "tplink,tl-wr1043nd-v1", "qca,ar9132"; model = "TP-Link TL-WR1043ND Version 1"; - alias { - serial0 = "/ahb/apb/uart@18020000"; - }; - memory@0 { device_type = "memory"; reg = <0x0 0x2000000>; @@ -24,55 +20,6 @@ clock-frequency = <40000000>; }; - ahb { - apb { - uart@18020000 { - status = "okay"; - }; - - pll-controller@18050000 { - clocks = <&extosc>; - }; - }; - - usb@1b000100 { - status = "okay"; - }; - - spi@1f000000 { - status = "okay"; - num-cs = <1>; - - flash@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "s25sl064a"; - reg = <0>; - spi-max-frequency = <25000000>; - - partition@0 { - label = "u-boot"; - reg = <0x000000 0x020000>; - }; - - partition@1 { - label = "firmware"; - reg = <0x020000 0x7D0000>; - }; - - partition@2 { - label = "art"; - reg = <0x7F0000 0x010000>; - read-only; - }; - }; - }; - }; - - usb-phy { - status = "okay"; - }; - gpio-keys { compatible = "gpio-keys-polled"; #address-cells = <1>; @@ -118,3 +65,48 @@ }; }; }; + +&uart { + status = "okay"; +}; + +&pll { + clocks = <&extosc>; +}; + +&usb { + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + status = "okay"; + num-cs = <1>; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "s25sl064a"; + reg = <0>; + spi-max-frequency = <25000000>; + + partition@0 { + label = "u-boot"; + reg = <0x000000 0x020000>; + }; + + partition@1 { + label = "firmware"; + reg = <0x020000 0x7D0000>; + }; + + partition@2 { + label = "art"; + reg = <0x7F0000 0x010000>; + read-only; + }; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331.dtsi b/arch/mips/boot/dts/qca/ar9331.dtsi new file mode 100644 index 0000000..cf47ed4 --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331.dtsi @@ -0,0 +1,155 @@ +#include <dt-bindings/clock/ath79-clk.h> + +/ { + compatible = "qca,ar9331"; + + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "mips,mips24Kc"; + clocks = <&pll ATH79_CLK_CPU>; + reg = <0>; + }; + }; + + cpuintc: interrupt-controller { + compatible = "qca,ar7100-cpu-intc"; + + interrupt-controller; + #interrupt-cells = <1>; + + qca,ddr-wb-channel-interrupts = <2>, <3>; + qca,ddr-wb-channels = <&ddr_ctrl 3>, <&ddr_ctrl 2>; + }; + + ref: ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + ahb { + compatible = "simple-bus"; + ranges; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&cpuintc>; + + apb { + compatible = "simple-bus"; + ranges; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&miscintc>; + + ddr_ctrl: memory-controller@18000000 { + compatible = "qca,ar7240-ddr-controller"; + reg = <0x18000000 0x100>; + + #qca,ddr-wb-channel-cells = <1>; + }; + + uart: uart@18020000 { + compatible = "qca,ar9330-uart"; + reg = <0x18020000 0x14>; + + interrupts = <3>; + + clocks = <&ref>; + clock-names = "uart"; + + status = "disabled"; + }; + + gpio: gpio@18040000 { + compatible = "qca,ar7100-gpio"; + reg = <0x18040000 0x34>; + interrupts = <2>; + + ngpios = <30>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + status = "disabled"; + }; + + pll: pll-controller@18050000 { + compatible = "qca,ar9330-pll"; + reg = <0x18050000 0x100>; + + clocks = <&ref>; + clock-names = "ref"; + + #clock-cells = <1>; + }; + + miscintc: interrupt-controller@18060010 { + compatible = "qca,ar7240-misc-intc"; + reg = <0x18060010 0x4>; + + interrupt-parent = <&cpuintc>; + interrupts = <6>; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + rst: reset-controller@1806001c { + compatible = "qca,ar7100-reset"; + reg = <0x1806001c 0x4>; + + #reset-cells = <1>; + }; + }; + + usb: usb@1b000100 { + compatible = "chipidea,usb2"; + reg = <0x1b000000 0x200>; + + interrupts = <3>; + resets = <&rst 5>; + + phy-names = "usb-phy"; + phys = <&usb_phy>; + + status = "disabled"; + }; + + spi: spi@1f000000 { + compatible = "qca,ar7100-spi"; + reg = <0x1f000000 0x10>; + + clocks = <&pll ATH79_CLK_AHB>; + clock-names = "ahb"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + usb_phy: usb-phy { + compatible = "qca,ar7100-usb-phy"; + + reset-names = "usb-phy", "usb-suspend-override"; + resets = <&rst 4>, <&rst 3>; + + #phy-cells = <0>; + + status = "disabled"; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331_dpt_module.dts b/arch/mips/boot/dts/qca/ar9331_dpt_module.dts new file mode 100644 index 0000000..98e7450 --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331_dpt_module.dts @@ -0,0 +1,78 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +#include "ar9331.dtsi" + +/ { + model = "DPTechnics DPT-Module"; + compatible = "dptechnics,dpt-module"; + + aliases { + serial0 = &uart; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x4000000>; + }; + + leds { + compatible = "gpio-leds"; + + system { + label = "dpt-module:green:system"; + gpios = <&gpio 27 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "reset"; + linux,code = <KEY_RESTART>; + gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&ref { + clock-frequency = <25000000>; +}; + +&uart { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&usb { + dr_mode = "host"; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + num-chipselects = <1>; + status = "okay"; + + /* Winbond 25Q128FVSG SPI flash */ + spiflash: w25q128@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "winbond,w25q128", "jedec,spi-nor"; + spi-max-frequency = <104000000>; + reg = <0>; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331_dragino_ms14.dts b/arch/mips/boot/dts/qca/ar9331_dragino_ms14.dts new file mode 100644 index 0000000..56f8320 --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331_dragino_ms14.dts @@ -0,0 +1,102 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +#include "ar9331.dtsi" + +/ { + model = "Dragino MS14 (Dragino 2)"; + compatible = "dragino,ms14"; + + aliases { + serial0 = &uart; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x4000000>; + }; + + leds { + compatible = "gpio-leds"; + + wlan { + label = "dragino2:red:wlan"; + gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + lan { + label = "dragino2:red:lan"; + gpios = <&gpio 13 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + wan { + label = "dragino2:red:wan"; + gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + system { + label = "dragino2:red:system"; + gpios = <&gpio 28 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "jumpstart"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + }; + + button@1 { + label = "reset"; + linux,code = <KEY_RESTART>; + gpios = <&gpio 12 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&ref { + clock-frequency = <25000000>; +}; + +&uart { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&usb { + dr_mode = "host"; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + num-chipselects = <1>; + status = "okay"; + + /* Winbond 25Q128BVFG SPI flash */ + spiflash: w25q128@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "winbond,w25q128", "jedec,spi-nor"; + spi-max-frequency = <104000000>; + reg = <0>; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331_omega.dts b/arch/mips/boot/dts/qca/ar9331_omega.dts new file mode 100644 index 0000000..b2be3b0 --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331_omega.dts @@ -0,0 +1,78 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +#include "ar9331.dtsi" + +/ { + model = "Onion Omega"; + compatible = "onion,omega"; + + aliases { + serial0 = &uart; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x4000000>; + }; + + leds { + compatible = "gpio-leds"; + + system { + label = "onion:amber:system"; + gpios = <&gpio 27 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "reset"; + linux,code = <KEY_RESTART>; + gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&ref { + clock-frequency = <25000000>; +}; + +&uart { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&usb { + dr_mode = "host"; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + num-chipselects = <1>; + status = "okay"; + + /* Winbond 25Q128FVSG SPI flash */ + spiflash: w25q128@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "winbond,w25q128", "jedec,spi-nor"; + spi-max-frequency = <104000000>; + reg = <0>; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331_tl_mr3020.dts b/arch/mips/boot/dts/qca/ar9331_tl_mr3020.dts new file mode 100644 index 0000000..919cf3b --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331_tl_mr3020.dts @@ -0,0 +1,118 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +#include "ar9331.dtsi" + +/ { + model = "TP-Link TL-MR3020"; + compatible = "tplink,tl-mr3020"; + + aliases { + serial0 = &uart; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x2000000>; + }; + + leds { + compatible = "gpio-leds"; + + wlan { + label = "tp-link:green:wlan"; + gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + lan { + label = "tp-link:green:lan"; + gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + wps { + label = "tp-link:green:wps"; + gpios = <&gpio 26 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led3g { + label = "tp-link:green:3g"; + gpios = <&gpio 27 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "wps"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; + }; + + button@1 { + label = "sw1"; + linux,code = <BTN_0>; + gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; + }; + + button@2 { + label = "sw2"; + linux,code = <BTN_1>; + gpios = <&gpio 20 GPIO_ACTIVE_HIGH>; + }; + }; + + reg_usb_vbus: reg_usb_vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&ref { + clock-frequency = <25000000>; +}; + +&uart { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&usb { + dr_mode = "host"; + vbus-supply = <®_usb_vbus>; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + num-chipselects = <1>; + status = "okay"; + + /* Spansion S25FL032PIF SPI flash */ + spiflash: s25sl032p@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25sl032p", "jedec,spi-nor"; + spi-max-frequency = <104000000>; + reg = <0>; + }; +}; diff --git a/arch/mips/boot/tools/.gitignore b/arch/mips/boot/tools/.gitignore new file mode 100644 index 0000000..be0ed06 --- /dev/null +++ b/arch/mips/boot/tools/.gitignore @@ -0,0 +1 @@ +relocs diff --git a/arch/mips/boot/tools/Makefile b/arch/mips/boot/tools/Makefile new file mode 100644 index 0000000..d232a68 --- /dev/null +++ b/arch/mips/boot/tools/Makefile @@ -0,0 +1,8 @@ + +hostprogs-y += relocs +relocs-objs += relocs_32.o +relocs-objs += relocs_64.o +relocs-objs += relocs_main.o +PHONY += relocs +relocs: $(obj)/relocs + @: diff --git a/arch/mips/boot/tools/relocs.c b/arch/mips/boot/tools/relocs.c new file mode 100644 index 0000000..b9cbf78 --- /dev/null +++ b/arch/mips/boot/tools/relocs.c @@ -0,0 +1,680 @@ +/* This is included from relocs_32/64.c */ + +#define ElfW(type) _ElfW(ELF_BITS, type) +#define _ElfW(bits, type) __ElfW(bits, type) +#define __ElfW(bits, type) Elf##bits##_##type + +#define Elf_Addr ElfW(Addr) +#define Elf_Ehdr ElfW(Ehdr) +#define Elf_Phdr ElfW(Phdr) +#define Elf_Shdr ElfW(Shdr) +#define Elf_Sym ElfW(Sym) + +static Elf_Ehdr ehdr; + +struct relocs { + uint32_t *offset; + unsigned long count; + unsigned long size; +}; + +static struct relocs relocs; + +struct section { + Elf_Shdr shdr; + struct section *link; + Elf_Sym *symtab; + Elf_Rel *reltab; + char *strtab; + long shdr_offset; +}; +static struct section *secs; + +static const char * const regex_sym_kernel = { +/* Symbols matching these regex's should never be relocated */ + "^(__crc_)", +}; + +static regex_t sym_regex_c; + +static int regex_skip_reloc(const char *sym_name) +{ + return !regexec(&sym_regex_c, sym_name, 0, NULL, 0); +} + +static void regex_init(void) +{ + char errbuf[128]; + int err; + + err = regcomp(&sym_regex_c, regex_sym_kernel, + REG_EXTENDED|REG_NOSUB); + + if (err) { + regerror(err, &sym_regex_c, errbuf, sizeof(errbuf)); + die("%s", errbuf); + } +} + +static const char *rel_type(unsigned type) +{ + static const char * const type_name[] = { +#define REL_TYPE(X)[X] = #X + REL_TYPE(R_MIPS_NONE), + REL_TYPE(R_MIPS_16), + REL_TYPE(R_MIPS_32), + REL_TYPE(R_MIPS_REL32), + REL_TYPE(R_MIPS_26), + REL_TYPE(R_MIPS_HI16), + REL_TYPE(R_MIPS_LO16), + REL_TYPE(R_MIPS_GPREL16), + REL_TYPE(R_MIPS_LITERAL), + REL_TYPE(R_MIPS_GOT16), + REL_TYPE(R_MIPS_PC16), + REL_TYPE(R_MIPS_CALL16), + REL_TYPE(R_MIPS_GPREL32), + REL_TYPE(R_MIPS_64), + REL_TYPE(R_MIPS_HIGHER), + REL_TYPE(R_MIPS_HIGHEST), + REL_TYPE(R_MIPS_PC21_S2), + REL_TYPE(R_MIPS_PC26_S2), +#undef REL_TYPE + }; + const char *name = "unknown type rel type name"; + + if (type < ARRAY_SIZE(type_name) && type_name[type]) + name = type_name[type]; + return name; +} + +static const char *sec_name(unsigned shndx) +{ + const char *sec_strtab; + const char *name; + + sec_strtab = secs[ehdr.e_shstrndx].strtab; + if (shndx < ehdr.e_shnum) + name = sec_strtab + secs[shndx].shdr.sh_name; + else if (shndx == SHN_ABS) + name = "ABSOLUTE"; + else if (shndx == SHN_COMMON) + name = "COMMON"; + else + name = "<noname>"; + return name; +} + +static struct section *sec_lookup(const char *secname) +{ + int i; + + for (i = 0; i < ehdr.e_shnum; i++) + if (strcmp(secname, sec_name(i)) == 0) + return &secs[i]; + + return NULL; +} + +static const char *sym_name(const char *sym_strtab, Elf_Sym *sym) +{ + const char *name; + + if (sym->st_name) + name = sym_strtab + sym->st_name; + else + name = sec_name(sym->st_shndx); + return name; +} + +#if BYTE_ORDER == LITTLE_ENDIAN +#define le16_to_cpu(val) (val) +#define le32_to_cpu(val) (val) +#define le64_to_cpu(val) (val) +#define be16_to_cpu(val) bswap_16(val) +#define be32_to_cpu(val) bswap_32(val) +#define be64_to_cpu(val) bswap_64(val) + +#define cpu_to_le16(val) (val) +#define cpu_to_le32(val) (val) +#define cpu_to_le64(val) (val) +#define cpu_to_be16(val) bswap_16(val) +#define cpu_to_be32(val) bswap_32(val) +#define cpu_to_be64(val) bswap_64(val) +#endif +#if BYTE_ORDER == BIG_ENDIAN +#define le16_to_cpu(val) bswap_16(val) +#define le32_to_cpu(val) bswap_32(val) +#define le64_to_cpu(val) bswap_64(val) +#define be16_to_cpu(val) (val) +#define be32_to_cpu(val) (val) +#define be64_to_cpu(val) (val) + +#define cpu_to_le16(val) bswap_16(val) +#define cpu_to_le32(val) bswap_32(val) +#define cpu_to_le64(val) bswap_64(val) +#define cpu_to_be16(val) (val) +#define cpu_to_be32(val) (val) +#define cpu_to_be64(val) (val) +#endif + +static uint16_t elf16_to_cpu(uint16_t val) +{ + if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + return le16_to_cpu(val); + else + return be16_to_cpu(val); +} + +static uint32_t elf32_to_cpu(uint32_t val) +{ + if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + return le32_to_cpu(val); + else + return be32_to_cpu(val); +} + +static uint32_t cpu_to_elf32(uint32_t val) +{ + if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + return cpu_to_le32(val); + else + return cpu_to_be32(val); +} + +#define elf_half_to_cpu(x) elf16_to_cpu(x) +#define elf_word_to_cpu(x) elf32_to_cpu(x) + +#if ELF_BITS == 64 +static uint64_t elf64_to_cpu(uint64_t val) +{ + if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + return le64_to_cpu(val); + else + return be64_to_cpu(val); +} +#define elf_addr_to_cpu(x) elf64_to_cpu(x) +#define elf_off_to_cpu(x) elf64_to_cpu(x) +#define elf_xword_to_cpu(x) elf64_to_cpu(x) +#else +#define elf_addr_to_cpu(x) elf32_to_cpu(x) +#define elf_off_to_cpu(x) elf32_to_cpu(x) +#define elf_xword_to_cpu(x) elf32_to_cpu(x) +#endif + +static void read_ehdr(FILE *fp) +{ + if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) + die("Cannot read ELF header: %s\n", strerror(errno)); + + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) + die("No ELF magic\n"); + + if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) + die("Not a %d bit executable\n", ELF_BITS); + + if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) && + (ehdr.e_ident[EI_DATA] != ELFDATA2MSB)) + die("Unknown ELF Endianness\n"); + + if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) + die("Unknown ELF version\n"); + + /* Convert the fields to native endian */ + ehdr.e_type = elf_half_to_cpu(ehdr.e_type); + ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine); + ehdr.e_version = elf_word_to_cpu(ehdr.e_version); + ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry); + ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff); + ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff); + ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags); + ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize); + ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize); + ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum); + ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize); + ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum); + ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx); + + if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) + die("Unsupported ELF header type\n"); + + if (ehdr.e_machine != ELF_MACHINE) + die("Not for %s\n", ELF_MACHINE_NAME); + + if (ehdr.e_version != EV_CURRENT) + die("Unknown ELF version\n"); + + if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) + die("Bad Elf header size\n"); + + if (ehdr.e_phentsize != sizeof(Elf_Phdr)) + die("Bad program header entry\n"); + + if (ehdr.e_shentsize != sizeof(Elf_Shdr)) + die("Bad section header entry\n"); + + if (ehdr.e_shstrndx >= ehdr.e_shnum) + die("String table index out of bounds\n"); +} + +static void read_shdrs(FILE *fp) +{ + int i; + Elf_Shdr shdr; + + secs = calloc(ehdr.e_shnum, sizeof(struct section)); + if (!secs) + die("Unable to allocate %d section headers\n", ehdr.e_shnum); + + if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", ehdr.e_shoff, strerror(errno)); + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + + sec->shdr_offset = ftell(fp); + if (fread(&shdr, sizeof(shdr), 1, fp) != 1) + die("Cannot read ELF section headers %d/%d: %s\n", + i, ehdr.e_shnum, strerror(errno)); + sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name); + sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type); + sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags); + sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr); + sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset); + sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size); + sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link); + sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info); + sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign); + sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize); + if (sec->shdr.sh_link < ehdr.e_shnum) + sec->link = &secs[sec->shdr.sh_link]; + } +} + +static void read_strtabs(FILE *fp) +{ + int i; + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + + if (sec->shdr.sh_type != SHT_STRTAB) + continue; + + sec->strtab = malloc(sec->shdr.sh_size); + if (!sec->strtab) + die("malloc of %d bytes for strtab failed\n", + sec->shdr.sh_size); + + if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr.sh_offset, strerror(errno)); + + if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) != + sec->shdr.sh_size) + die("Cannot read symbol table: %s\n", strerror(errno)); + } +} + +static void read_symtabs(FILE *fp) +{ + int i, j; + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + if (sec->shdr.sh_type != SHT_SYMTAB) + continue; + + sec->symtab = malloc(sec->shdr.sh_size); + if (!sec->symtab) + die("malloc of %d bytes for symtab failed\n", + sec->shdr.sh_size); + + if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr.sh_offset, strerror(errno)); + + if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) != + sec->shdr.sh_size) + die("Cannot read symbol table: %s\n", strerror(errno)); + + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) { + Elf_Sym *sym = &sec->symtab[j]; + + sym->st_name = elf_word_to_cpu(sym->st_name); + sym->st_value = elf_addr_to_cpu(sym->st_value); + sym->st_size = elf_xword_to_cpu(sym->st_size); + sym->st_shndx = elf_half_to_cpu(sym->st_shndx); + } + } +} + +static void read_relocs(FILE *fp) +{ + static unsigned long base = 0; + int i, j; + + if (!base) { + struct section *sec = sec_lookup(".text"); + + if (!sec) + die("Could not find .text section\n"); + + base = sec->shdr.sh_addr; + } + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + + if (sec->shdr.sh_type != SHT_REL_TYPE) + continue; + + sec->reltab = malloc(sec->shdr.sh_size); + if (!sec->reltab) + die("malloc of %d bytes for relocs failed\n", + sec->shdr.sh_size); + + if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr.sh_offset, strerror(errno)); + + if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) != + sec->shdr.sh_size) + die("Cannot read symbol table: %s\n", strerror(errno)); + + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { + Elf_Rel *rel = &sec->reltab[j]; + + rel->r_offset = elf_addr_to_cpu(rel->r_offset); + /* Set offset into kernel image */ + rel->r_offset -= base; +#if (ELF_BITS == 32) + rel->r_info = elf_xword_to_cpu(rel->r_info); +#else + /* Convert MIPS64 RELA format - only the symbol + * index needs converting to native endianness + */ + rel->r_info = rel->r_info; + ELF_R_SYM(rel->r_info) = elf32_to_cpu(ELF_R_SYM(rel->r_info)); +#endif +#if (SHT_REL_TYPE == SHT_RELA) + rel->r_addend = elf_xword_to_cpu(rel->r_addend); +#endif + } + } +} + +static void remove_relocs(FILE *fp) +{ + int i; + Elf_Shdr shdr; + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + + if (sec->shdr.sh_type != SHT_REL_TYPE) + continue; + + if (fseek(fp, sec->shdr_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr_offset, strerror(errno)); + + if (fread(&shdr, sizeof(shdr), 1, fp) != 1) + die("Cannot read ELF section headers %d/%d: %s\n", + i, ehdr.e_shnum, strerror(errno)); + + /* Set relocation section size to 0, effectively removing it. + * This is necessary due to lack of support for relocations + * in objcopy when creating 32bit elf from 64bit elf. + */ + shdr.sh_size = 0; + + if (fseek(fp, sec->shdr_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr_offset, strerror(errno)); + + if (fwrite(&shdr, sizeof(shdr), 1, fp) != 1) + die("Cannot write ELF section headers %d/%d: %s\n", + i, ehdr.e_shnum, strerror(errno)); + } +} + +static void add_reloc(struct relocs *r, uint32_t offset, unsigned type) +{ + /* Relocation representation in binary table: + * |76543210|76543210|76543210|76543210| + * | Type | offset from _text >> 2 | + */ + offset >>= 2; + if (offset > 0x00FFFFFF) + die("Kernel image exceeds maximum size for relocation!\n"); + + offset = (offset & 0x00FFFFFF) | ((type & 0xFF) << 24); + + if (r->count == r->size) { + unsigned long newsize = r->size + 50000; + void *mem = realloc(r->offset, newsize * sizeof(r->offset[0])); + + if (!mem) + die("realloc failed\n"); + + r->offset = mem; + r->size = newsize; + } + r->offset[r->count++] = offset; +} + +static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, + Elf_Sym *sym, const char *symname)) +{ + int i; + + /* Walk through the relocations */ + for (i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf_Sym *sh_symtab; + struct section *sec_applies, *sec_symtab; + int j; + struct section *sec = &secs[i]; + + if (sec->shdr.sh_type != SHT_REL_TYPE) + continue; + + sec_symtab = sec->link; + sec_applies = &secs[sec->shdr.sh_info]; + if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) + continue; + + sh_symtab = sec_symtab->symtab; + sym_strtab = sec_symtab->link->strtab; + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { + Elf_Rel *rel = &sec->reltab[j]; + Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)]; + const char *symname = sym_name(sym_strtab, sym); + + process(sec, rel, sym, symname); + } + } +} + +static int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, + const char *symname) +{ + unsigned r_type = ELF_R_TYPE(rel->r_info); + unsigned bind = ELF_ST_BIND(sym->st_info); + + if ((bind == STB_WEAK) && (sym->st_value == 0)) { + /* Don't relocate weak symbols without a target */ + return 0; + } + + if (regex_skip_reloc(symname)) + return 0; + + switch (r_type) { + case R_MIPS_NONE: + case R_MIPS_REL32: + case R_MIPS_PC16: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: + /* + * NONE can be ignored and PC relative relocations don't + * need to be adjusted. + */ + case R_MIPS_HIGHEST: + case R_MIPS_HIGHER: + /* We support relocating within the same 4Gb segment only, + * thus leaving the top 32bits unchanged + */ + case R_MIPS_LO16: + /* We support relocating by 64k jumps only + * thus leaving the bottom 16bits unchanged + */ + break; + + case R_MIPS_64: + case R_MIPS_32: + case R_MIPS_26: + case R_MIPS_HI16: + add_reloc(&relocs, rel->r_offset, r_type); + break; + + default: + die("Unsupported relocation type: %s (%d)\n", + rel_type(r_type), r_type); + break; + } + + return 0; +} + +static int write_reloc_as_bin(uint32_t v, FILE *f) +{ + unsigned char buf[4]; + + v = cpu_to_elf32(v); + + memcpy(buf, &v, sizeof(uint32_t)); + return fwrite(buf, 1, 4, f); +} + +static int write_reloc_as_text(uint32_t v, FILE *f) +{ + int res; + + res = fprintf(f, "\t.long 0x%08"PRIx32"\n", v); + if (res < 0) + return res; + else + return sizeof(uint32_t); +} + +static void emit_relocs(int as_text, int as_bin, FILE *outf) +{ + int i; + int (*write_reloc)(uint32_t, FILE *) = write_reloc_as_bin; + int size = 0; + int size_reserved; + struct section *sec_reloc; + + sec_reloc = sec_lookup(".data.reloc"); + if (!sec_reloc) + die("Could not find relocation section\n"); + + size_reserved = sec_reloc->shdr.sh_size; + + /* Collect up the relocations */ + walk_relocs(do_reloc); + + /* Print the relocations */ + if (as_text) { + /* Print the relocations in a form suitable that + * gas will like. + */ + printf(".section \".data.reloc\",\"a\"\n"); + printf(".balign 4\n"); + /* Output text to stdout */ + write_reloc = write_reloc_as_text; + outf = stdout; + } else if (as_bin) { + /* Output raw binary to stdout */ + outf = stdout; + } else { + /* Seek to offset of the relocation section. + * Each relocation is then written into the + * vmlinux kernel image. + */ + if (fseek(outf, sec_reloc->shdr.sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + sec_reloc->shdr.sh_offset, strerror(errno)); + } + } + + for (i = 0; i < relocs.count; i++) + size += write_reloc(relocs.offset[i], outf); + + /* Print a stop, but only if we've actually written some relocs */ + if (size) + size += write_reloc(0, outf); + + if (size > size_reserved) + /* Die, but suggest a value for CONFIG_RELOCATION_TABLE_SIZE + * which will fix this problem and allow a bit of headroom + * if more kernel features are enabled + */ + die("Relocations overflow available space!\n" \ + "Please adjust CONFIG_RELOCATION_TABLE_SIZE " \ + "to at least 0x%08x\n", (size + 0x1000) & ~0xFFF); +} + +/* + * As an aid to debugging problems with different linkers + * print summary information about the relocs. + * Since different linkers tend to emit the sections in + * different orders we use the section names in the output. + */ +static int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, + const char *symname) +{ + printf("%16s 0x%08x %16s %40s %16s\n", + sec_name(sec->shdr.sh_info), + (unsigned int)rel->r_offset, + rel_type(ELF_R_TYPE(rel->r_info)), + symname, + sec_name(sym->st_shndx)); + return 0; +} + +static void print_reloc_info(void) +{ + printf("%16s %10s %16s %40s %16s\n", + "reloc section", + "offset", + "reloc type", + "symbol", + "symbol section"); + walk_relocs(do_reloc_info); +} + +#if ELF_BITS == 64 +# define process process_64 +#else +# define process process_32 +#endif + +void process(FILE *fp, int as_text, int as_bin, + int show_reloc_info, int keep_relocs) +{ + regex_init(); + read_ehdr(fp); + read_shdrs(fp); + read_strtabs(fp); + read_symtabs(fp); + read_relocs(fp); + if (show_reloc_info) { + print_reloc_info(); + return; + } + emit_relocs(as_text, as_bin, fp); + if (!keep_relocs) + remove_relocs(fp); +} diff --git a/arch/mips/boot/tools/relocs.h b/arch/mips/boot/tools/relocs.h new file mode 100644 index 0000000..3cf676f --- /dev/null +++ b/arch/mips/boot/tools/relocs.h @@ -0,0 +1,45 @@ +#ifndef RELOCS_H +#define RELOCS_H + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <elf.h> +#include <byteswap.h> +#define USE_BSD +#include <endian.h> +#include <regex.h> + +void die(char *fmt, ...); + +/* + * Introduced for MIPSr6 + */ +#ifndef R_MIPS_PC21_S2 +#define R_MIPS_PC21_S2 60 +#endif + +#ifndef R_MIPS_PC26_S2 +#define R_MIPS_PC26_S2 61 +#endif + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +enum symtype { + S_ABS, + S_REL, + S_SEG, + S_LIN, + S_NSYMTYPES +}; + +void process_32(FILE *fp, int as_text, int as_bin, + int show_reloc_info, int keep_relocs); +void process_64(FILE *fp, int as_text, int as_bin, + int show_reloc_info, int keep_relocs); +#endif /* RELOCS_H */ diff --git a/arch/mips/boot/tools/relocs_32.c b/arch/mips/boot/tools/relocs_32.c new file mode 100644 index 0000000..915bdc0 --- /dev/null +++ b/arch/mips/boot/tools/relocs_32.c @@ -0,0 +1,17 @@ +#include "relocs.h" + +#define ELF_BITS 32 + +#define ELF_MACHINE EM_MIPS +#define ELF_MACHINE_NAME "MIPS" +#define SHT_REL_TYPE SHT_REL +#define Elf_Rel ElfW(Rel) + +#define ELF_CLASS ELFCLASS32 +#define ELF_R_SYM(val) ELF32_R_SYM(val) +#define ELF_R_TYPE(val) ELF32_R_TYPE(val) +#define ELF_ST_TYPE(o) ELF32_ST_TYPE(o) +#define ELF_ST_BIND(o) ELF32_ST_BIND(o) +#define ELF_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o) + +#include "relocs.c" diff --git a/arch/mips/boot/tools/relocs_64.c b/arch/mips/boot/tools/relocs_64.c new file mode 100644 index 0000000..b671b5e --- /dev/null +++ b/arch/mips/boot/tools/relocs_64.c @@ -0,0 +1,27 @@ +#include "relocs.h" + +#define ELF_BITS 64 + +#define ELF_MACHINE EM_MIPS +#define ELF_MACHINE_NAME "MIPS64" +#define SHT_REL_TYPE SHT_RELA +#define Elf_Rel Elf64_Rela + +typedef uint8_t Elf64_Byte; + +typedef struct { + Elf64_Word r_sym; /* Symbol index. */ + Elf64_Byte r_ssym; /* Special symbol. */ + Elf64_Byte r_type3; /* Third relocation. */ + Elf64_Byte r_type2; /* Second relocation. */ + Elf64_Byte r_type; /* First relocation. */ +} Elf64_Mips_Rela; + +#define ELF_CLASS ELFCLASS64 +#define ELF_R_SYM(val) (((Elf64_Mips_Rela *)(&val))->r_sym) +#define ELF_R_TYPE(val) (((Elf64_Mips_Rela *)(&val))->r_type) +#define ELF_ST_TYPE(o) ELF64_ST_TYPE(o) +#define ELF_ST_BIND(o) ELF64_ST_BIND(o) +#define ELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o) + +#include "relocs.c" diff --git a/arch/mips/boot/tools/relocs_main.c b/arch/mips/boot/tools/relocs_main.c new file mode 100644 index 0000000..d8fe234 --- /dev/null +++ b/arch/mips/boot/tools/relocs_main.c @@ -0,0 +1,84 @@ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <endian.h> +#include <elf.h> + +#include "relocs.h" + +void die(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static void usage(void) +{ + die("relocs [--reloc-info|--text|--bin|--keep] vmlinux\n"); +} + +int main(int argc, char **argv) +{ + int show_reloc_info, as_text, as_bin, keep_relocs; + const char *fname; + FILE *fp; + int i; + unsigned char e_ident[EI_NIDENT]; + + show_reloc_info = 0; + as_text = 0; + as_bin = 0; + keep_relocs = 0; + fname = NULL; + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + + if (*arg == '-') { + if (strcmp(arg, "--reloc-info") == 0) { + show_reloc_info = 1; + continue; + } + if (strcmp(arg, "--text") == 0) { + as_text = 1; + continue; + } + if (strcmp(arg, "--bin") == 0) { + as_bin = 1; + continue; + } + if (strcmp(arg, "--keep") == 0) { + keep_relocs = 1; + continue; + } + } else if (!fname) { + fname = arg; + continue; + } + usage(); + } + if (!fname) + usage(); + + fp = fopen(fname, "r+"); + if (!fp) + die("Cannot open %s: %s\n", fname, strerror(errno)); + + if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT) + die("Cannot read %s: %s", fname, strerror(errno)); + + rewind(fp); + if (e_ident[EI_CLASS] == ELFCLASS64) + process_64(fp, as_text, as_bin, show_reloc_info, keep_relocs); + else + process_32(fp, as_text, as_bin, show_reloc_info, keep_relocs); + fclose(fp); + return 0; +} diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c index 1882e64..23c2344 100644 --- a/arch/mips/cavium-octeon/csrc-octeon.c +++ b/arch/mips/cavium-octeon/csrc-octeon.c @@ -19,6 +19,7 @@ #include <asm/octeon/cvmx-ipd-defs.h> #include <asm/octeon/cvmx-mio-defs.h> #include <asm/octeon/cvmx-rst-defs.h> +#include <asm/octeon/cvmx-fpa-defs.h> static u64 f; static u64 rdiv; @@ -65,9 +66,13 @@ void __init octeon_setup_delays(void) */ void octeon_init_cvmcount(void) { + u64 clk_reg; unsigned long flags; unsigned loops = 2; + clk_reg = octeon_has_feature(OCTEON_FEATURE_FPA3) ? + CVMX_FPA_CLK_COUNT : CVMX_IPD_CLK_COUNT; + /* Clobber loops so GCC will not unroll the following while loop. */ asm("" : "+r" (loops)); @@ -77,18 +82,18 @@ void octeon_init_cvmcount(void) * which should give more deterministic timing. */ while (loops--) { - u64 ipd_clk_count = cvmx_read_csr(CVMX_IPD_CLK_COUNT); + u64 clk_count = cvmx_read_csr(clk_reg); if (rdiv != 0) { - ipd_clk_count *= rdiv; + clk_count *= rdiv; if (f != 0) { asm("dmultu\t%[cnt],%[f]\n\t" "mfhi\t%[cnt]" - : [cnt] "+r" (ipd_clk_count) + : [cnt] "+r" (clk_count) : [f] "r" (f) : "hi", "lo"); } } - write_c0_cvmcount(ipd_clk_count); + write_c0_cvmcount(clk_count); } local_irq_restore(flags); } diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index 376701f..ff26d02 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -87,6 +87,8 @@ int cvmx_helper_get_number_of_interfaces(void) return 9; if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) return 4; + if (OCTEON_IS_MODEL(OCTEON_CN7XXX)) + return 5; else return 3; } @@ -260,6 +262,41 @@ static cvmx_helper_interface_mode_t __cvmx_get_mode_octeon2(int interface) } /** + * @INTERNAL + * Return interface mode for CN7XXX. + */ +static cvmx_helper_interface_mode_t __cvmx_get_mode_cn7xxx(int interface) +{ + union cvmx_gmxx_inf_mode mode; + + mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + + switch (interface) { + case 0: + case 1: + switch (mode.cn68xx.mode) { + case 0: + return CVMX_HELPER_INTERFACE_MODE_DISABLED; + case 1: + case 2: + return CVMX_HELPER_INTERFACE_MODE_SGMII; + case 3: + return CVMX_HELPER_INTERFACE_MODE_XAUI; + default: + return CVMX_HELPER_INTERFACE_MODE_SGMII; + } + case 2: + return CVMX_HELPER_INTERFACE_MODE_NPI; + case 3: + return CVMX_HELPER_INTERFACE_MODE_LOOP; + case 4: + return CVMX_HELPER_INTERFACE_MODE_RGMII; + default: + return CVMX_HELPER_INTERFACE_MODE_DISABLED; + } +} + +/** * Get the operating mode of an interface. Depending on the Octeon * chip and configuration, this function returns an enumeration * of the type of packet I/O supported by an interface. @@ -278,6 +315,12 @@ cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface) return CVMX_HELPER_INTERFACE_MODE_DISABLED; /* + * OCTEON III models + */ + if (OCTEON_IS_MODEL(OCTEON_CN7XXX)) + return __cvmx_get_mode_cn7xxx(interface); + + /* * Octeon II models */ if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF71XX)) diff --git a/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c b/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c index 3d17fac..cc1b1d2 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c +++ b/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c @@ -32,86 +32,22 @@ #include <linux/module.h> #include <asm/octeon/cvmx.h> -#include <asm/octeon/cvmx-spinlock.h> #include <asm/octeon/cvmx-sysinfo.h> -/** +/* * This structure defines the private state maintained by sysinfo module. - * */ -static struct { - struct cvmx_sysinfo sysinfo; /* system information */ - cvmx_spinlock_t lock; /* mutex spinlock */ - -} state = { - .lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER -}; - +static struct cvmx_sysinfo sysinfo; /* system information */ /* - * Global variables that define the min/max of the memory region set - * up for 32 bit userspace access. - */ -uint64_t linux_mem32_min; -uint64_t linux_mem32_max; -uint64_t linux_mem32_wired; -uint64_t linux_mem32_offset; - -/** - * This function returns the application information as obtained + * Returns the application information as obtained * by the bootloader. This provides the core mask of the cores * running the same application image, as well as the physical * memory regions available to the core. - * - * Returns Pointer to the boot information structure - * */ struct cvmx_sysinfo *cvmx_sysinfo_get(void) { - return &(state.sysinfo); + return &sysinfo; } EXPORT_SYMBOL(cvmx_sysinfo_get); -/** - * This function is used in non-simple executive environments (such as - * Linux kernel, u-boot, etc.) to configure the minimal fields that - * are required to use simple executive files directly. - * - * Locking (if required) must be handled outside of this - * function - * - * @phy_mem_desc_ptr: - * Pointer to global physical memory descriptor - * (bootmem descriptor) @board_type: Octeon board - * type enumeration - * - * @board_rev_major: - * Board major revision - * @board_rev_minor: - * Board minor revision - * @cpu_clock_hz: - * CPU clock freqency in hertz - * - * Returns 0: Failure - * 1: success - */ -int cvmx_sysinfo_minimal_initialize(void *phy_mem_desc_ptr, - uint16_t board_type, - uint8_t board_rev_major, - uint8_t board_rev_minor, - uint32_t cpu_clock_hz) -{ - - /* The sysinfo structure was already initialized */ - if (state.sysinfo.board_type) - return 0; - - memset(&(state.sysinfo), 0x0, sizeof(state.sysinfo)); - state.sysinfo.phy_mem_desc_ptr = phy_mem_desc_ptr; - state.sysinfo.board_type = board_type; - state.sysinfo.board_rev_major = board_rev_major; - state.sysinfo.board_rev_minor = board_rev_minor; - state.sysinfo.cpu_clock_hz = cpu_clock_hz; - - return 1; -} diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c index b2104bd..d08a2bc 100644 --- a/arch/mips/cavium-octeon/executive/octeon-model.c +++ b/arch/mips/cavium-octeon/executive/octeon-model.c @@ -71,11 +71,11 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, uint32_t fuse_data = 0; fus3.u64 = 0; - if (!OCTEON_IS_MODEL(OCTEON_CN6XXX)) + if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)) fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3); fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); - num_cores = cvmx_pop(cvmx_read_csr(CVMX_CIU_FUSE)); + num_cores = cvmx_octeon_num_cores(); /* Make sure the non existent devices look disabled */ switch ((chip_id >> 8) & 0xff) { @@ -121,6 +121,15 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, * later. */ switch (num_cores) { + case 48: + core_model = "90"; + break; + case 44: + core_model = "88"; + break; + case 40: + core_model = "85"; + break; case 32: core_model = "80"; break; @@ -297,7 +306,7 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, if (fus_dat3.s.nozip) suffix = "SCP"; - if (fus_dat3.s.bar2_en) + if (fus_dat3.cn56xx.bar2_en) suffix = "NSPB2"; } if (fus3.cn56xx.crip_1024k) @@ -369,6 +378,73 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, else suffix = "AAP"; break; + case 0x94: /* CNF71XX */ + family = "F71"; + if (fus_dat3.cnf71xx.nozip) + suffix = "SCP"; + else + suffix = "AAP"; + break; + case 0x95: /* CN78XX */ + if (num_cores == 6) /* Other core counts match generic */ + core_model = "35"; + if (OCTEON_IS_MODEL(OCTEON_CN76XX)) + family = "76"; + else + family = "78"; + if (fus_dat3.cn78xx.l2c_crip == 2) + family = "77"; + if (fus_dat3.cn78xx.nozip + && fus_dat3.cn78xx.nodfa_dte + && fus_dat3.cn78xx.nohna_dte) { + if (fus_dat3.cn78xx.nozip && + !fus_dat2.cn78xx.raid_en && + fus_dat3.cn78xx.nohna_dte) { + suffix = "CP"; + } else { + suffix = "SCP"; + } + } else if (fus_dat2.cn78xx.raid_en == 0) + suffix = "HCP"; + else + suffix = "AAP"; + break; + case 0x96: /* CN70XX */ + family = "70"; + if (cvmx_read_csr(CVMX_MIO_FUS_PDF) & (0x1ULL << 32)) + family = "71"; + if (fus_dat2.cn70xx.nocrypto) + suffix = "CP"; + else if (fus_dat3.cn70xx.nodfa_dte) + suffix = "SCP"; + else + suffix = "AAP"; + break; + case 0x97: /* CN73XX */ + if (num_cores == 6) /* Other core counts match generic */ + core_model = "35"; + family = "73"; + if (fus_dat3.cn73xx.l2c_crip == 2) + family = "72"; + if (fus_dat3.cn73xx.nozip + && fus_dat3.cn73xx.nodfa_dte + && fus_dat3.cn73xx.nohna_dte) { + if (!fus_dat2.cn73xx.raid_en) + suffix = "CP"; + else + suffix = "SCP"; + } else + suffix = "AAP"; + break; + case 0x98: /* CN75XX */ + family = "F75"; + if (fus_dat3.cn78xx.nozip + && fus_dat3.cn78xx.nodfa_dte + && fus_dat3.cn78xx.nohna_dte) + suffix = "SCP"; + else + suffix = "AAP"; + break; default: family = "XX"; core_model = "XX"; diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 4f9eb05..368eb49 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2004-2014 Cavium, Inc. + * Copyright (C) 2004-2016 Cavium, Inc. */ #include <linux/of_address.h> @@ -19,16 +19,53 @@ #include <asm/octeon/octeon.h> #include <asm/octeon/cvmx-ciu2-defs.h> +#include <asm/octeon/cvmx-ciu3-defs.h> static DEFINE_PER_CPU(unsigned long, octeon_irq_ciu0_en_mirror); static DEFINE_PER_CPU(unsigned long, octeon_irq_ciu1_en_mirror); static DEFINE_PER_CPU(raw_spinlock_t, octeon_irq_ciu_spinlock); +static DEFINE_PER_CPU(unsigned int, octeon_irq_ciu3_idt_ip2); + +static DEFINE_PER_CPU(unsigned int, octeon_irq_ciu3_idt_ip3); +static DEFINE_PER_CPU(struct octeon_ciu3_info *, octeon_ciu3_info); +#define CIU3_MBOX_PER_CORE 10 + +/* + * The 8 most significant bits of the intsn identify the interrupt major block. + * Each major block might use its own interrupt domain. Thus 256 domains are + * needed. + */ +#define MAX_CIU3_DOMAINS 256 + +typedef irq_hw_number_t (*octeon_ciu3_intsn2hw_t)(struct irq_domain *, unsigned int); + +/* Information for each ciu3 in the system */ +struct octeon_ciu3_info { + u64 ciu3_addr; + int node; + struct irq_domain *domain[MAX_CIU3_DOMAINS]; + octeon_ciu3_intsn2hw_t intsn2hw[MAX_CIU3_DOMAINS]; +}; + +/* Each ciu3 in the system uses its own data (one ciu3 per node) */ +static struct octeon_ciu3_info *octeon_ciu3_info_per_node[4]; struct octeon_irq_ciu_domain_data { int num_sum; /* number of sum registers (2 or 3). */ }; -static __read_mostly u8 octeon_irq_ciu_to_irq[8][64]; +/* Register offsets from ciu3_addr */ +#define CIU3_CONST 0x220 +#define CIU3_IDT_CTL(_idt) ((_idt) * 8 + 0x110000) +#define CIU3_IDT_PP(_idt, _idx) ((_idt) * 32 + (_idx) * 8 + 0x120000) +#define CIU3_IDT_IO(_idt) ((_idt) * 8 + 0x130000) +#define CIU3_DEST_PP_INT(_pp_ip) ((_pp_ip) * 8 + 0x200000) +#define CIU3_DEST_IO_INT(_io) ((_io) * 8 + 0x210000) +#define CIU3_ISC_CTL(_intsn) ((_intsn) * 8 + 0x80000000) +#define CIU3_ISC_W1C(_intsn) ((_intsn) * 8 + 0x90000000) +#define CIU3_ISC_W1S(_intsn) ((_intsn) * 8 + 0xa0000000) + +static __read_mostly int octeon_irq_ciu_to_irq[8][64]; struct octeon_ciu_chip_data { union { @@ -39,10 +76,11 @@ struct octeon_ciu_chip_data { struct { /* only used for ciu/ciu2 */ u8 line; u8 bit; - u8 gpio_line; }; }; + int gpio_line; int current_cpu; /* Next CPU expected to take this irq */ + int ciu_node; /* NUMA node number of the CIU */ }; struct octeon_core_chip_data { @@ -626,6 +664,18 @@ static void octeon_irq_ciu_enable_all_v2(struct irq_data *data) } } +static int octeon_irq_ciu_set_type(struct irq_data *data, unsigned int t) +{ + irqd_set_trigger_type(data, t); + + if (t & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(data, handle_edge_irq); + else + irq_set_handler_locked(data, handle_level_irq); + + return IRQ_SET_MASK_OK; +} + static void octeon_irq_gpio_setup(struct irq_data *data) { union cvmx_gpio_bit_cfgx cfg; @@ -663,7 +713,7 @@ static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t) irqd_set_trigger_type(data, t); octeon_irq_gpio_setup(data); - if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH) + if (t & IRQ_TYPE_EDGE_BOTH) irq_set_handler_locked(data, handle_edge_irq); else irq_set_handler_locked(data, handle_level_irq); @@ -863,6 +913,16 @@ static int octeon_irq_ciu_set_affinity_sum2(struct irq_data *data, } #endif +static unsigned int edge_startup(struct irq_data *data) +{ + /* ack any pending edge-irq at startup, so there is + * an _edge_ to fire on when the event reappears. + */ + data->chip->irq_ack(data); + data->chip->irq_enable(data); + return 0; +} + /* * Newer octeon chips have support for lockless CIU operation. */ @@ -1158,16 +1218,6 @@ static struct irq_chip *octeon_irq_ciu_chip; static struct irq_chip *octeon_irq_ciu_chip_edge; static struct irq_chip *octeon_irq_gpio_chip; -static bool octeon_irq_virq_in_range(unsigned int virq) -{ - /* We cannot let it overflow the mapping array. */ - if (virq < (1ul << 8 * sizeof(octeon_irq_ciu_to_irq[0][0]))) - return true; - - WARN_ONCE(true, "virq out of range %u.\n", virq); - return false; -} - static int octeon_irq_ciu_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { @@ -1176,13 +1226,6 @@ static int octeon_irq_ciu_map(struct irq_domain *d, unsigned int bit = hw & 63; struct octeon_irq_ciu_domain_data *dd = d->host_data; - if (!octeon_irq_virq_in_range(virq)) - return -EINVAL; - - /* Don't map irq if it is reserved for GPIO. */ - if (line == 0 && bit >= 16 && bit <32) - return 0; - if (line >= dd->num_sum || octeon_irq_ciu_to_irq[line][bit] != 0) return -EINVAL; @@ -1215,9 +1258,6 @@ static int octeon_irq_gpio_map(struct irq_domain *d, unsigned int line, bit; int r; - if (!octeon_irq_virq_in_range(virq)) - return -EINVAL; - line = (hw + gpiod->base_hwirq) >> 6; bit = (hw + gpiod->base_hwirq) & 63; if (line > ARRAY_SIZE(octeon_irq_ciu_to_irq) || @@ -1899,9 +1939,6 @@ static int octeon_irq_ciu2_map(struct irq_domain *d, unsigned int line = hw >> 6; unsigned int bit = hw & 63; - if (!octeon_irq_virq_in_range(virq)) - return -EINVAL; - /* * Don't map irq if it is reserved for GPIO. * (Line 7 are the GPIO lines.) @@ -2294,10 +2331,598 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, return 0; } +int octeon_irq_ciu3_xlat(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + struct octeon_ciu3_info *ciu3_info = d->host_data; + unsigned int hwirq, type, intsn_major; + union cvmx_ciu3_iscx_ctl isc; + + if (intsize < 2) + return -EINVAL; + hwirq = intspec[0]; + type = intspec[1]; + + if (hwirq >= (1 << 20)) + return -EINVAL; + + intsn_major = hwirq >> 12; + switch (intsn_major) { + case 0x04: /* Software handled separately. */ + return -EINVAL; + default: + break; + } + + isc.u64 = cvmx_read_csr(ciu3_info->ciu3_addr + CIU3_ISC_CTL(hwirq)); + if (!isc.s.imp) + return -EINVAL; + + switch (type) { + case 4: /* official value for level triggering. */ + *out_type = IRQ_TYPE_LEVEL_HIGH; + break; + case 0: /* unofficial value, but we might as well let it work. */ + case 1: /* official value for edge triggering. */ + *out_type = IRQ_TYPE_EDGE_RISING; + break; + default: /* Nothing else is acceptable. */ + return -EINVAL; + } + + *out_hwirq = hwirq; + + return 0; +} + +void octeon_irq_ciu3_enable(struct irq_data *data) +{ + int cpu; + union cvmx_ciu3_iscx_ctl isc_ctl; + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_ctl_addr; + + struct octeon_ciu_chip_data *cd; + + cpu = next_cpu_for_irq(data); + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + cvmx_write_csr(cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn), isc_w1c.u64); + + isc_ctl_addr = cd->ciu3_addr + CIU3_ISC_CTL(cd->intsn); + isc_ctl.u64 = 0; + isc_ctl.s.en = 1; + isc_ctl.s.idt = per_cpu(octeon_irq_ciu3_idt_ip2, cpu); + cvmx_write_csr(isc_ctl_addr, isc_ctl.u64); + cvmx_read_csr(isc_ctl_addr); +} + +void octeon_irq_ciu3_disable(struct irq_data *data) +{ + u64 isc_ctl_addr; + union cvmx_ciu3_iscx_w1c isc_w1c; + + struct octeon_ciu_chip_data *cd; + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + + isc_ctl_addr = cd->ciu3_addr + CIU3_ISC_CTL(cd->intsn); + cvmx_write_csr(cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn), isc_w1c.u64); + cvmx_write_csr(isc_ctl_addr, 0); + cvmx_read_csr(isc_ctl_addr); +} + +void octeon_irq_ciu3_ack(struct irq_data *data) +{ + u64 isc_w1c_addr; + union cvmx_ciu3_iscx_w1c isc_w1c; + struct octeon_ciu_chip_data *cd; + u32 trigger_type = irqd_get_trigger_type(data); + + /* + * We use a single irq_chip, so we have to do nothing to ack a + * level interrupt. + */ + if (!(trigger_type & IRQ_TYPE_EDGE_BOTH)) + return; + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.raw = 1; + + isc_w1c_addr = cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn); + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); +} + +void octeon_irq_ciu3_mask(struct irq_data *data) +{ + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_w1c_addr; + struct octeon_ciu_chip_data *cd; + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + + isc_w1c_addr = cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn); + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); +} + +void octeon_irq_ciu3_mask_ack(struct irq_data *data) +{ + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_w1c_addr; + struct octeon_ciu_chip_data *cd; + u32 trigger_type = irqd_get_trigger_type(data); + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + + /* + * We use a single irq_chip, so only ack an edge (!level) + * interrupt. + */ + if (trigger_type & IRQ_TYPE_EDGE_BOTH) + isc_w1c.s.raw = 1; + + isc_w1c_addr = cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn); + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); +} + +#ifdef CONFIG_SMP +int octeon_irq_ciu3_set_affinity(struct irq_data *data, + const struct cpumask *dest, bool force) +{ + union cvmx_ciu3_iscx_ctl isc_ctl; + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_ctl_addr; + int cpu; + bool enable_one = !irqd_irq_disabled(data) && !irqd_irq_masked(data); + struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data); + + if (!cpumask_subset(dest, cpumask_of_node(cd->ciu_node))) + return -EINVAL; + + if (!enable_one) + return IRQ_SET_MASK_OK; + + cd = irq_data_get_irq_chip_data(data); + cpu = cpumask_first(dest); + if (cpu >= nr_cpu_ids) + cpu = smp_processor_id(); + cd->current_cpu = cpu; + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + cvmx_write_csr(cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn), isc_w1c.u64); + + isc_ctl_addr = cd->ciu3_addr + CIU3_ISC_CTL(cd->intsn); + isc_ctl.u64 = 0; + isc_ctl.s.en = 1; + isc_ctl.s.idt = per_cpu(octeon_irq_ciu3_idt_ip2, cpu); + cvmx_write_csr(isc_ctl_addr, isc_ctl.u64); + cvmx_read_csr(isc_ctl_addr); + + return IRQ_SET_MASK_OK; +} +#endif + +static struct irq_chip octeon_irq_chip_ciu3 = { + .name = "CIU3", + .irq_startup = edge_startup, + .irq_enable = octeon_irq_ciu3_enable, + .irq_disable = octeon_irq_ciu3_disable, + .irq_ack = octeon_irq_ciu3_ack, + .irq_mask = octeon_irq_ciu3_mask, + .irq_mask_ack = octeon_irq_ciu3_mask_ack, + .irq_unmask = octeon_irq_ciu3_enable, + .irq_set_type = octeon_irq_ciu_set_type, +#ifdef CONFIG_SMP + .irq_set_affinity = octeon_irq_ciu3_set_affinity, + .irq_cpu_offline = octeon_irq_cpu_offline_ciu, +#endif +}; + +int octeon_irq_ciu3_mapx(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw, struct irq_chip *chip) +{ + struct octeon_ciu3_info *ciu3_info = d->host_data; + struct octeon_ciu_chip_data *cd = kzalloc_node(sizeof(*cd), GFP_KERNEL, + ciu3_info->node); + if (!cd) + return -ENOMEM; + cd->intsn = hw; + cd->current_cpu = -1; + cd->ciu3_addr = ciu3_info->ciu3_addr; + cd->ciu_node = ciu3_info->node; + irq_set_chip_and_handler(virq, chip, handle_edge_irq); + irq_set_chip_data(virq, cd); + + return 0; +} + +static int octeon_irq_ciu3_map(struct irq_domain *d, + unsigned int virq, irq_hw_number_t hw) +{ + return octeon_irq_ciu3_mapx(d, virq, hw, &octeon_irq_chip_ciu3); +} + +static struct irq_domain_ops octeon_dflt_domain_ciu3_ops = { + .map = octeon_irq_ciu3_map, + .unmap = octeon_irq_free_cd, + .xlate = octeon_irq_ciu3_xlat, +}; + +static void octeon_irq_ciu3_ip2(void) +{ + union cvmx_ciu3_destx_pp_int dest_pp_int; + struct octeon_ciu3_info *ciu3_info; + u64 ciu3_addr; + + ciu3_info = __this_cpu_read(octeon_ciu3_info); + ciu3_addr = ciu3_info->ciu3_addr; + + dest_pp_int.u64 = cvmx_read_csr(ciu3_addr + CIU3_DEST_PP_INT(3 * cvmx_get_local_core_num())); + + if (likely(dest_pp_int.s.intr)) { + irq_hw_number_t intsn = dest_pp_int.s.intsn; + irq_hw_number_t hw; + struct irq_domain *domain; + /* Get the domain to use from the major block */ + int block = intsn >> 12; + int ret; + + domain = ciu3_info->domain[block]; + if (ciu3_info->intsn2hw[block]) + hw = ciu3_info->intsn2hw[block](domain, intsn); + else + hw = intsn; + + ret = handle_domain_irq(domain, hw, NULL); + if (ret < 0) { + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_w1c_addr = ciu3_addr + CIU3_ISC_W1C(intsn); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); + spurious_interrupt(); + } + } else { + spurious_interrupt(); + } +} + +/* + * 10 mbox per core starting from zero. + * Base mbox is core * 10 + */ +static unsigned int octeon_irq_ciu3_base_mbox_intsn(int core) +{ + /* SW (mbox) are 0x04 in bits 12..19 */ + return 0x04000 + CIU3_MBOX_PER_CORE * core; +} + +static unsigned int octeon_irq_ciu3_mbox_intsn_for_core(int core, unsigned int mbox) +{ + return octeon_irq_ciu3_base_mbox_intsn(core) + mbox; +} + +static unsigned int octeon_irq_ciu3_mbox_intsn_for_cpu(int cpu, unsigned int mbox) +{ + int local_core = octeon_coreid_for_cpu(cpu) & 0x3f; + + return octeon_irq_ciu3_mbox_intsn_for_core(local_core, mbox); +} + +static void octeon_irq_ciu3_mbox(void) +{ + union cvmx_ciu3_destx_pp_int dest_pp_int; + struct octeon_ciu3_info *ciu3_info; + u64 ciu3_addr; + int core = cvmx_get_local_core_num(); + + ciu3_info = __this_cpu_read(octeon_ciu3_info); + ciu3_addr = ciu3_info->ciu3_addr; + + dest_pp_int.u64 = cvmx_read_csr(ciu3_addr + CIU3_DEST_PP_INT(1 + 3 * core)); + + if (likely(dest_pp_int.s.intr)) { + irq_hw_number_t intsn = dest_pp_int.s.intsn; + int mbox = intsn - octeon_irq_ciu3_base_mbox_intsn(core); + + if (likely(mbox >= 0 && mbox < CIU3_MBOX_PER_CORE)) { + do_IRQ(mbox + OCTEON_IRQ_MBOX0); + } else { + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_w1c_addr = ciu3_addr + CIU3_ISC_W1C(intsn); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); + spurious_interrupt(); + } + } else { + spurious_interrupt(); + } +} + +void octeon_ciu3_mbox_send(int cpu, unsigned int mbox) +{ + struct octeon_ciu3_info *ciu3_info; + unsigned int intsn; + union cvmx_ciu3_iscx_w1s isc_w1s; + u64 isc_w1s_addr; + + if (WARN_ON_ONCE(mbox >= CIU3_MBOX_PER_CORE)) + return; + + intsn = octeon_irq_ciu3_mbox_intsn_for_cpu(cpu, mbox); + ciu3_info = per_cpu(octeon_ciu3_info, cpu); + isc_w1s_addr = ciu3_info->ciu3_addr + CIU3_ISC_W1S(intsn); + + isc_w1s.u64 = 0; + isc_w1s.s.raw = 1; + + cvmx_write_csr(isc_w1s_addr, isc_w1s.u64); + cvmx_read_csr(isc_w1s_addr); +} + +static void octeon_irq_ciu3_mbox_set_enable(struct irq_data *data, int cpu, bool en) +{ + struct octeon_ciu3_info *ciu3_info; + unsigned int intsn; + u64 isc_ctl_addr, isc_w1c_addr; + union cvmx_ciu3_iscx_ctl isc_ctl; + unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0; + + intsn = octeon_irq_ciu3_mbox_intsn_for_cpu(cpu, mbox); + ciu3_info = per_cpu(octeon_ciu3_info, cpu); + isc_w1c_addr = ciu3_info->ciu3_addr + CIU3_ISC_W1C(intsn); + isc_ctl_addr = ciu3_info->ciu3_addr + CIU3_ISC_CTL(intsn); + + isc_ctl.u64 = 0; + isc_ctl.s.en = 1; + + cvmx_write_csr(isc_w1c_addr, isc_ctl.u64); + cvmx_write_csr(isc_ctl_addr, 0); + if (en) { + unsigned int idt = per_cpu(octeon_irq_ciu3_idt_ip3, cpu); + + isc_ctl.u64 = 0; + isc_ctl.s.en = 1; + isc_ctl.s.idt = idt; + cvmx_write_csr(isc_ctl_addr, isc_ctl.u64); + } + cvmx_read_csr(isc_ctl_addr); +} + +static void octeon_irq_ciu3_mbox_enable(struct irq_data *data) +{ + int cpu; + unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0; + + WARN_ON(mbox >= CIU3_MBOX_PER_CORE); + + for_each_online_cpu(cpu) + octeon_irq_ciu3_mbox_set_enable(data, cpu, true); +} + +static void octeon_irq_ciu3_mbox_disable(struct irq_data *data) +{ + int cpu; + unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0; + + WARN_ON(mbox >= CIU3_MBOX_PER_CORE); + + for_each_online_cpu(cpu) + octeon_irq_ciu3_mbox_set_enable(data, cpu, false); +} + +static void octeon_irq_ciu3_mbox_ack(struct irq_data *data) +{ + struct octeon_ciu3_info *ciu3_info; + unsigned int intsn; + u64 isc_w1c_addr; + union cvmx_ciu3_iscx_w1c isc_w1c; + unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0; + + intsn = octeon_irq_ciu3_mbox_intsn_for_core(cvmx_get_local_core_num(), mbox); + + isc_w1c.u64 = 0; + isc_w1c.s.raw = 1; + + ciu3_info = __this_cpu_read(octeon_ciu3_info); + isc_w1c_addr = ciu3_info->ciu3_addr + CIU3_ISC_W1C(intsn); + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); +} + +static void octeon_irq_ciu3_mbox_cpu_online(struct irq_data *data) +{ + octeon_irq_ciu3_mbox_set_enable(data, smp_processor_id(), true); +} + +static void octeon_irq_ciu3_mbox_cpu_offline(struct irq_data *data) +{ + octeon_irq_ciu3_mbox_set_enable(data, smp_processor_id(), false); +} + +static int octeon_irq_ciu3_alloc_resources(struct octeon_ciu3_info *ciu3_info) +{ + u64 b = ciu3_info->ciu3_addr; + int idt_ip2, idt_ip3, idt_ip4; + int unused_idt2; + int core = cvmx_get_local_core_num(); + int i; + + __this_cpu_write(octeon_ciu3_info, ciu3_info); + + /* + * 4 idt per core starting from 1 because zero is reserved. + * Base idt per core is 4 * core + 1 + */ + idt_ip2 = core * 4 + 1; + idt_ip3 = core * 4 + 2; + idt_ip4 = core * 4 + 3; + unused_idt2 = core * 4 + 4; + __this_cpu_write(octeon_irq_ciu3_idt_ip2, idt_ip2); + __this_cpu_write(octeon_irq_ciu3_idt_ip3, idt_ip3); + + /* ip2 interrupts for this CPU */ + cvmx_write_csr(b + CIU3_IDT_CTL(idt_ip2), 0); + cvmx_write_csr(b + CIU3_IDT_PP(idt_ip2, 0), 1ull << core); + cvmx_write_csr(b + CIU3_IDT_IO(idt_ip2), 0); + + /* ip3 interrupts for this CPU */ + cvmx_write_csr(b + CIU3_IDT_CTL(idt_ip3), 1); + cvmx_write_csr(b + CIU3_IDT_PP(idt_ip3, 0), 1ull << core); + cvmx_write_csr(b + CIU3_IDT_IO(idt_ip3), 0); + + /* ip4 interrupts for this CPU */ + cvmx_write_csr(b + CIU3_IDT_CTL(idt_ip4), 2); + cvmx_write_csr(b + CIU3_IDT_PP(idt_ip4, 0), 0); + cvmx_write_csr(b + CIU3_IDT_IO(idt_ip4), 0); + + cvmx_write_csr(b + CIU3_IDT_CTL(unused_idt2), 0); + cvmx_write_csr(b + CIU3_IDT_PP(unused_idt2, 0), 0); + cvmx_write_csr(b + CIU3_IDT_IO(unused_idt2), 0); + + for (i = 0; i < CIU3_MBOX_PER_CORE; i++) { + unsigned int intsn = octeon_irq_ciu3_mbox_intsn_for_core(core, i); + + cvmx_write_csr(b + CIU3_ISC_W1C(intsn), 2); + cvmx_write_csr(b + CIU3_ISC_CTL(intsn), 0); + } + + return 0; +} + +static void octeon_irq_setup_secondary_ciu3(void) +{ + struct octeon_ciu3_info *ciu3_info; + + ciu3_info = octeon_ciu3_info_per_node[cvmx_get_node_num()]; + octeon_irq_ciu3_alloc_resources(ciu3_info); + irq_cpu_online(); + + /* Enable the CIU lines */ + set_c0_status(STATUSF_IP3 | STATUSF_IP2); + if (octeon_irq_use_ip4) + set_c0_status(STATUSF_IP4); + else + clear_c0_status(STATUSF_IP4); +} + +static struct irq_chip octeon_irq_chip_ciu3_mbox = { + .name = "CIU3-M", + .irq_enable = octeon_irq_ciu3_mbox_enable, + .irq_disable = octeon_irq_ciu3_mbox_disable, + .irq_ack = octeon_irq_ciu3_mbox_ack, + + .irq_cpu_online = octeon_irq_ciu3_mbox_cpu_online, + .irq_cpu_offline = octeon_irq_ciu3_mbox_cpu_offline, + .flags = IRQCHIP_ONOFFLINE_ENABLED, +}; + +static int __init octeon_irq_init_ciu3(struct device_node *ciu_node, + struct device_node *parent) +{ + int i; + int node; + struct irq_domain *domain; + struct octeon_ciu3_info *ciu3_info; + const __be32 *zero_addr; + u64 base_addr; + union cvmx_ciu3_const consts; + + node = 0; /* of_node_to_nid(ciu_node); */ + ciu3_info = kzalloc_node(sizeof(*ciu3_info), GFP_KERNEL, node); + + if (!ciu3_info) + return -ENOMEM; + + zero_addr = of_get_address(ciu_node, 0, NULL, NULL); + if (WARN_ON(!zero_addr)) + return -EINVAL; + + base_addr = of_translate_address(ciu_node, zero_addr); + base_addr = (u64)phys_to_virt(base_addr); + + ciu3_info->ciu3_addr = base_addr; + ciu3_info->node = node; + + consts.u64 = cvmx_read_csr(base_addr + CIU3_CONST); + + octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu3; + + octeon_irq_ip2 = octeon_irq_ciu3_ip2; + octeon_irq_ip3 = octeon_irq_ciu3_mbox; + octeon_irq_ip4 = octeon_irq_ip4_mask; + + if (node == cvmx_get_node_num()) { + /* Mips internal */ + octeon_irq_init_core(); + + /* Only do per CPU things if it is the CIU of the boot node. */ + i = irq_alloc_descs_from(OCTEON_IRQ_MBOX0, 8, node); + WARN_ON(i < 0); + + for (i = 0; i < 8; i++) + irq_set_chip_and_handler(i + OCTEON_IRQ_MBOX0, + &octeon_irq_chip_ciu3_mbox, handle_percpu_irq); + } + + /* + * Initialize all domains to use the default domain. Specific major + * blocks will overwrite the default domain as needed. + */ + domain = irq_domain_add_tree(ciu_node, &octeon_dflt_domain_ciu3_ops, + ciu3_info); + for (i = 0; i < MAX_CIU3_DOMAINS; i++) + ciu3_info->domain[i] = domain; + + octeon_ciu3_info_per_node[node] = ciu3_info; + + if (node == cvmx_get_node_num()) { + /* Only do per CPU things if it is the CIU of the boot node. */ + octeon_irq_ciu3_alloc_resources(ciu3_info); + if (node == 0) + irq_set_default_host(domain); + + octeon_irq_use_ip4 = false; + /* Enable the CIU lines */ + set_c0_status(STATUSF_IP2 | STATUSF_IP3); + clear_c0_status(STATUSF_IP4); + } + + return 0; +} + static struct of_device_id ciu_types[] __initdata = { {.compatible = "cavium,octeon-3860-ciu", .data = octeon_irq_init_ciu}, {.compatible = "cavium,octeon-3860-gpio", .data = octeon_irq_init_gpio}, {.compatible = "cavium,octeon-6880-ciu2", .data = octeon_irq_init_ciu2}, + {.compatible = "cavium,octeon-7890-ciu3", .data = octeon_irq_init_ciu3}, {.compatible = "cavium,octeon-7130-cib", .data = octeon_irq_init_cib}, {} }; diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index d113c8d..7aeafed 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -13,6 +13,7 @@ #include <linux/i2c.h> #include <linux/usb.h> #include <linux/dma-mapping.h> +#include <linux/etherdevice.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/slab.h> @@ -525,10 +526,17 @@ static void __init octeon_fdt_set_phy(int eth, int phy_addr) static void __init octeon_fdt_set_mac_addr(int n, u64 *pmac) { + const u8 *old_mac; + int old_len; u8 new_mac[6]; u64 mac = *pmac; int r; + old_mac = fdt_getprop(initial_boot_params, n, "local-mac-address", + &old_len); + if (!old_mac || old_len != 6 || is_valid_ether_addr(old_mac)) + return; + new_mac[0] = (mac >> 40) & 0xff; new_mac[1] = (mac >> 32) & 0xff; new_mac[2] = (mac >> 24) & 0xff; @@ -560,7 +568,7 @@ static void __init octeon_fdt_rm_ethernet(int node) fdt_nop_node(initial_boot_params, node); } -static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pmac) +static void __init octeon_fdt_pip_port(int iface, int i, int p, int max) { char name_buffer[20]; int eth; @@ -583,10 +591,9 @@ static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pm phy_addr = cvmx_helper_board_get_mii_address(ipd_port); octeon_fdt_set_phy(eth, phy_addr); - octeon_fdt_set_mac_addr(eth, pmac); } -static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac) +static void __init octeon_fdt_pip_iface(int pip, int idx) { char name_buffer[20]; int iface; @@ -602,7 +609,73 @@ static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac) count = cvmx_helper_ports_on_interface(idx); for (p = 0; p < 16; p++) - octeon_fdt_pip_port(iface, idx, p, count - 1, pmac); + octeon_fdt_pip_port(iface, idx, p, count - 1); +} + +void __init octeon_fill_mac_addresses(void) +{ + const char *alias_prop; + char name_buffer[20]; + u64 mac_addr_base; + int aliases; + int pip; + int i; + + aliases = fdt_path_offset(initial_boot_params, "/aliases"); + if (aliases < 0) + return; + + mac_addr_base = + ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | + ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | + ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | + ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | + ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | + (octeon_bootinfo->mac_addr_base[5] & 0xffull); + + for (i = 0; i < 2; i++) { + int mgmt; + + snprintf(name_buffer, sizeof(name_buffer), "mix%d", i); + alias_prop = fdt_getprop(initial_boot_params, aliases, + name_buffer, NULL); + if (!alias_prop) + continue; + mgmt = fdt_path_offset(initial_boot_params, alias_prop); + if (mgmt < 0) + continue; + octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); + } + + alias_prop = fdt_getprop(initial_boot_params, aliases, "pip", NULL); + if (!alias_prop) + return; + + pip = fdt_path_offset(initial_boot_params, alias_prop); + if (pip < 0) + return; + + for (i = 0; i <= 4; i++) { + int iface; + int p; + + snprintf(name_buffer, sizeof(name_buffer), "interface@%d", i); + iface = fdt_subnode_offset(initial_boot_params, pip, + name_buffer); + if (iface < 0) + continue; + for (p = 0; p < 16; p++) { + int eth; + + snprintf(name_buffer, sizeof(name_buffer), + "ethernet@%x", p); + eth = fdt_subnode_offset(initial_boot_params, iface, + name_buffer); + if (eth < 0) + continue; + octeon_fdt_set_mac_addr(eth, &mac_addr_base); + } + } } int __init octeon_prune_device_tree(void) @@ -612,7 +685,6 @@ int __init octeon_prune_device_tree(void) const char *alias_prop; char name_buffer[20]; int aliases; - u64 mac_addr_base; if (fdt_check_header(initial_boot_params)) panic("Corrupt Device Tree."); @@ -623,15 +695,6 @@ int __init octeon_prune_device_tree(void) return -EINVAL; } - - mac_addr_base = - ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | - ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | - ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | - ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | - ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | - (octeon_bootinfo->mac_addr_base[5] & 0xffull); - if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) max_port = 2; else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) @@ -660,7 +723,6 @@ int __init octeon_prune_device_tree(void) } else { int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i); octeon_fdt_set_phy(mgmt, phy_addr); - octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); } } } @@ -670,7 +732,7 @@ int __init octeon_prune_device_tree(void) int pip = fdt_path_offset(initial_boot_params, pip_path); if (pip >= 0) for (i = 0; i <= 4; i++) - octeon_fdt_pip_iface(pip, i, &mac_addr_base); + octeon_fdt_pip_iface(pip, i); } /* I2C */ diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index cd7101f..64f852b 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -43,8 +43,6 @@ #include <asm/octeon/cvmx-mio-defs.h> #include <asm/octeon/cvmx-rst-defs.h> -extern struct plat_smp_ops octeon_smp_ops; - #ifdef CONFIG_PCI extern void pci_console_init(const char *arg); #endif @@ -466,15 +464,25 @@ static void octeon_halt(void) static char __read_mostly octeon_system_type[80]; -static int __init init_octeon_system_type(void) +static void __init init_octeon_system_type(void) { - snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)", - cvmx_board_type_to_string(octeon_bootinfo->board_type), - octeon_model_get_string(read_c0_prid())); + char const *board_type; + + board_type = cvmx_board_type_to_string(octeon_bootinfo->board_type); + if (board_type == NULL) { + struct device_node *root; + int ret; + + root = of_find_node_by_path("/"); + ret = of_property_read_string(root, "model", &board_type); + of_node_put(root); + if (ret) + board_type = "Unsupported Board"; + } - return 0; + snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)", + board_type, octeon_model_get_string(read_c0_prid())); } -early_initcall(init_octeon_system_type); /** * Return a string representing the system type @@ -492,8 +500,6 @@ const char *get_system_type(void) void octeon_user_io_init(void) { union octeon_cvmemctl cvmmemctl; - union cvmx_iob_fau_timeout fau_timeout; - union cvmx_pow_nw_tim nm_tim; /* Get the current settings for CP0_CVMMEMCTL_REG */ cvmmemctl.u64 = read_c0_cvmmemctl(); @@ -595,17 +601,27 @@ void octeon_user_io_init(void) CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128); - /* Set a default for the hardware timeouts */ - fau_timeout.u64 = 0; - fau_timeout.s.tout_val = 0xfff; - /* Disable tagwait FAU timeout */ - fau_timeout.s.tout_enb = 0; - cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_timeout.u64); + if (octeon_has_feature(OCTEON_FEATURE_FAU)) { + union cvmx_iob_fau_timeout fau_timeout; + + /* Set a default for the hardware timeouts */ + fau_timeout.u64 = 0; + fau_timeout.s.tout_val = 0xfff; + /* Disable tagwait FAU timeout */ + fau_timeout.s.tout_enb = 0; + cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_timeout.u64); + } - nm_tim.u64 = 0; - /* 4096 cycles */ - nm_tim.s.nw_tim = 3; - cvmx_write_csr(CVMX_POW_NW_TIM, nm_tim.u64); + if ((!OCTEON_IS_MODEL(OCTEON_CN68XX) && + !OCTEON_IS_MODEL(OCTEON_CN7XXX)) || + OCTEON_IS_MODEL(OCTEON_CN70XX)) { + union cvmx_pow_nw_tim nm_tim; + + nm_tim.u64 = 0; + /* 4096 cycles */ + nm_tim.s.nw_tim = 3; + cvmx_write_csr(CVMX_POW_NW_TIM, nm_tim.u64); + } write_octeon_c0_icacheerr(0); write_c0_derraddr1(0); @@ -637,9 +653,22 @@ void __init prom_init(void) sysinfo = cvmx_sysinfo_get(); memset(sysinfo, 0, sizeof(*sysinfo)); sysinfo->system_dram_size = octeon_bootinfo->dram_size << 20; - sysinfo->phy_mem_desc_ptr = - cvmx_phys_to_ptr(octeon_bootinfo->phy_mem_desc_addr); - sysinfo->core_mask = octeon_bootinfo->core_mask; + sysinfo->phy_mem_desc_addr = (u64)phys_to_virt(octeon_bootinfo->phy_mem_desc_addr); + + if ((octeon_bootinfo->major_version > 1) || + (octeon_bootinfo->major_version == 1 && + octeon_bootinfo->minor_version >= 4)) + cvmx_coremask_copy(&sysinfo->core_mask, + &octeon_bootinfo->ext_core_mask); + else + cvmx_coremask_set64(&sysinfo->core_mask, + octeon_bootinfo->core_mask); + + /* Some broken u-boot pass garbage in upper bits, clear them out */ + if (!OCTEON_IS_MODEL(OCTEON_CN78XX)) + for (i = 512; i < 1024; i++) + cvmx_coremask_clear_core(&sysinfo->core_mask, i); + sysinfo->exception_base_addr = octeon_bootinfo->exception_base_addr; sysinfo->cpu_clock_hz = octeon_bootinfo->eclock_hz; sysinfo->dram_data_rate_hz = octeon_bootinfo->dclock_hz * 2; @@ -867,7 +896,7 @@ void __init prom_init(void) #endif octeon_user_io_init(); - register_smp_ops(&octeon_smp_ops); + octeon_setup_smp(); } /* Exclude a single page from the regions obtained in plat_mem_setup. */ @@ -1079,6 +1108,7 @@ void __init prom_free_prom_memory(void) } } +void __init octeon_fill_mac_addresses(void); int octeon_prune_device_tree(void); extern const char __appended_dtb; @@ -1088,11 +1118,13 @@ void __init device_tree_init(void) { const void *fdt; bool do_prune; + bool fill_mac; #ifdef CONFIG_MIPS_ELF_APPENDED_DTB if (!fdt_check_header(&__appended_dtb)) { fdt = &__appended_dtb; do_prune = false; + fill_mac = true; pr_info("Using appended Device Tree.\n"); } else #endif @@ -1101,13 +1133,16 @@ void __init device_tree_init(void) if (fdt_check_header(fdt)) panic("Corrupt Device Tree passed to kernel."); do_prune = false; + fill_mac = false; pr_info("Using passed Device Tree.\n"); } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { fdt = &__dtb_octeon_68xx_begin; do_prune = true; + fill_mac = true; } else { fdt = &__dtb_octeon_3xxx_begin; do_prune = true; + fill_mac = true; } initial_boot_params = (void *)fdt; @@ -1116,7 +1151,10 @@ void __init device_tree_init(void) octeon_prune_device_tree(); pr_info("Using internal Device Tree.\n"); } + if (fill_mac) + octeon_fill_mac_addresses(); unflatten_and_copy_device_tree(); + init_octeon_system_type(); } static int __initdata disable_octeon_edac_p; diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 42412ba..dff88aa 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -30,25 +30,55 @@ uint64_t octeon_bootloader_entry_addr; EXPORT_SYMBOL(octeon_bootloader_entry_addr); #endif +static void octeon_icache_flush(void) +{ + asm volatile ("synci 0($0)\n"); +} + +static void (*octeon_message_functions[8])(void) = { + scheduler_ipi, + generic_smp_call_function_interrupt, + octeon_icache_flush, +}; + static irqreturn_t mailbox_interrupt(int irq, void *dev_id) { - const int coreid = cvmx_get_core_num(); - uint64_t action; + u64 mbox_clrx = CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()); + u64 action; + int i; + + /* + * Make sure the function array initialization remains + * correct. + */ + BUILD_BUG_ON(SMP_RESCHEDULE_YOURSELF != (1 << 0)); + BUILD_BUG_ON(SMP_CALL_FUNCTION != (1 << 1)); + BUILD_BUG_ON(SMP_ICACHE_FLUSH != (1 << 2)); + + /* + * Load the mailbox register to figure out what we're supposed + * to do. + */ + action = cvmx_read_csr(mbox_clrx); - /* Load the mailbox register to figure out what we're supposed to do */ - action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)) & 0xffff; + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + action &= 0xff; + else + action &= 0xffff; /* Clear the mailbox to clear the interrupt */ - cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action); + cvmx_write_csr(mbox_clrx, action); - if (action & SMP_CALL_FUNCTION) - generic_smp_call_function_interrupt(); - if (action & SMP_RESCHEDULE_YOURSELF) - scheduler_ipi(); + for (i = 0; i < ARRAY_SIZE(octeon_message_functions) && action;) { + if (action & 1) { + void (*fn)(void) = octeon_message_functions[i]; - /* Check if we've been told to flush the icache */ - if (action & SMP_ICACHE_FLUSH) - asm volatile ("synci 0($0)\n"); + if (fn) + fn(); + } + action >>= 1; + i++; + } return IRQ_HANDLED; } @@ -97,13 +127,15 @@ static void octeon_smp_hotplug_setup(void) #endif } -static void octeon_smp_setup(void) +static void __init octeon_smp_setup(void) { const int coreid = cvmx_get_core_num(); int cpus; int id; - int core_mask = octeon_get_boot_coremask(); + struct cvmx_sysinfo *sysinfo = cvmx_sysinfo_get(); + #ifdef CONFIG_HOTPLUG_CPU + int core_mask = octeon_get_boot_coremask(); unsigned int num_cores = cvmx_octeon_num_cores(); #endif @@ -119,7 +151,7 @@ static void octeon_smp_setup(void) /* The present CPUs get the lowest CPU numbers. */ cpus = 1; for (id = 0; id < NR_CPUS; id++) { - if ((id != coreid) && (core_mask & (1 << id))) { + if ((id != coreid) && cvmx_coremask_is_core_set(&sysinfo->core_mask, id)) { set_cpu_possible(cpus, true); set_cpu_present(cpus, true); __cpu_number_map[id] = cpus; @@ -196,7 +228,7 @@ static void octeon_init_secondary(void) * Callout to firmware before smp_init * */ -void octeon_prepare_cpus(unsigned int max_cpus) +static void __init octeon_prepare_cpus(unsigned int max_cpus) { /* * Only the low order mailbox bits are used for IPIs, leave @@ -242,7 +274,7 @@ static int octeon_cpu_disable(void) cpumask_clear_cpu(cpu, &cpu_callin_map); octeon_fixup_irqs(); - flush_cache_all(); + __flush_cache_all(); local_flush_tlb_all(); return 0; @@ -388,3 +420,92 @@ struct plat_smp_ops octeon_smp_ops = { .cpu_die = octeon_cpu_die, #endif }; + +static irqreturn_t octeon_78xx_reched_interrupt(int irq, void *dev_id) +{ + scheduler_ipi(); + return IRQ_HANDLED; +} + +static irqreturn_t octeon_78xx_call_function_interrupt(int irq, void *dev_id) +{ + generic_smp_call_function_interrupt(); + return IRQ_HANDLED; +} + +static irqreturn_t octeon_78xx_icache_flush_interrupt(int irq, void *dev_id) +{ + octeon_icache_flush(); + return IRQ_HANDLED; +} + +/* + * Callout to firmware before smp_init + */ +static void octeon_78xx_prepare_cpus(unsigned int max_cpus) +{ + if (request_irq(OCTEON_IRQ_MBOX0 + 0, + octeon_78xx_reched_interrupt, + IRQF_PERCPU | IRQF_NO_THREAD, "Scheduler", + octeon_78xx_reched_interrupt)) { + panic("Cannot request_irq for SchedulerIPI"); + } + if (request_irq(OCTEON_IRQ_MBOX0 + 1, + octeon_78xx_call_function_interrupt, + IRQF_PERCPU | IRQF_NO_THREAD, "SMP-Call", + octeon_78xx_call_function_interrupt)) { + panic("Cannot request_irq for SMP-Call"); + } + if (request_irq(OCTEON_IRQ_MBOX0 + 2, + octeon_78xx_icache_flush_interrupt, + IRQF_PERCPU | IRQF_NO_THREAD, "ICache-Flush", + octeon_78xx_icache_flush_interrupt)) { + panic("Cannot request_irq for ICache-Flush"); + } +} + +static void octeon_78xx_send_ipi_single(int cpu, unsigned int action) +{ + int i; + + for (i = 0; i < 8; i++) { + if (action & 1) + octeon_ciu3_mbox_send(cpu, i); + action >>= 1; + } +} + +static void octeon_78xx_send_ipi_mask(const struct cpumask *mask, + unsigned int action) +{ + unsigned int cpu; + + for_each_cpu(cpu, mask) + octeon_78xx_send_ipi_single(cpu, action); +} + +static struct plat_smp_ops octeon_78xx_smp_ops = { + .send_ipi_single = octeon_78xx_send_ipi_single, + .send_ipi_mask = octeon_78xx_send_ipi_mask, + .init_secondary = octeon_init_secondary, + .smp_finish = octeon_smp_finish, + .boot_secondary = octeon_boot_secondary, + .smp_setup = octeon_smp_setup, + .prepare_cpus = octeon_78xx_prepare_cpus, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_disable = octeon_cpu_disable, + .cpu_die = octeon_cpu_die, +#endif +}; + +void __init octeon_setup_smp(void) +{ + struct plat_smp_ops *ops; + + if (octeon_has_feature(OCTEON_FEATURE_CIU3)) + ops = &octeon_78xx_smp_ops; + else + ops = &octeon_smp_ops; + + register_smp_ops(ops); +} diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig index 0db4eb3..fad8e96 100644 --- a/arch/mips/configs/bcm47xx_defconfig +++ b/arch/mips/configs/bcm47xx_defconfig @@ -23,7 +23,6 @@ CONFIG_IP_MROUTE=y CONFIG_IP_MROUTE_MULTIPLE_TABLES=y CONFIG_SYN_COOKIES=y CONFIG_TCP_CONG_ADVANCED=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_IPV6_MROUTE=y diff --git a/arch/mips/configs/bcm63xx_defconfig b/arch/mips/configs/bcm63xx_defconfig index 3fec264..5599a9f 100644 --- a/arch/mips/configs/bcm63xx_defconfig +++ b/arch/mips/configs/bcm63xx_defconfig @@ -44,6 +44,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set CONFIG_MTD=y +CONFIG_MTD_BCM63XX_PARTS=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index e070dac..d20b09d 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -62,7 +62,6 @@ CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m # CONFIG_INET_LRO is not set CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IPV6_OPTIMISTIC_DAD=y diff --git a/arch/mips/configs/bmips_be_defconfig b/arch/mips/configs/bmips_be_defconfig index 24dcb90..acf7785 100644 --- a/arch/mips/configs/bmips_be_defconfig +++ b/arch/mips/configs/bmips_be_defconfig @@ -36,6 +36,7 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_PRINTK_TIME=y CONFIG_BRCMSTB_GISB_ARB=y CONFIG_MTD=y +CONFIG_MTD_BCM63XX_PARTS=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y diff --git a/arch/mips/configs/cavium_octeon_defconfig b/arch/mips/configs/cavium_octeon_defconfig index e57058d..dcac308 100644 --- a/arch/mips/configs/cavium_octeon_defconfig +++ b/arch/mips/configs/cavium_octeon_defconfig @@ -119,14 +119,16 @@ CONFIG_SPI=y CONFIG_SPI_OCTEON=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y -# CONFIG_USB_SUPPORT is not set -CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y -CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y -CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB=m +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_HCD_PLATFORM=m +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_PLATFORM=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_STAGING=y CONFIG_OCTEON_ETHERNET=y +CONFIG_OCTEON_USB=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y @@ -152,6 +154,9 @@ CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MD5_OCTEON=y +CONFIG_CRYPTO_SHA1_OCTEON=m +CONFIG_CRYPTO_SHA256_OCTEON=m +CONFIG_CRYPTO_SHA512_OCTEON=m CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index ebc011c..2b6cb41 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig @@ -30,7 +30,6 @@ CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_AH=m diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index 6ba9ce9..5d83ff7 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -48,7 +48,6 @@ CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m # CONFIG_INET_LRO is not set CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IPV6_OPTIMISTIC_DAD=y diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 77e9f50..2b74aee 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -43,7 +43,6 @@ CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IPV6_OPTIMISTIC_DAD=y diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig index a5e85e1..3019fce 100644 --- a/arch/mips/configs/jazz_defconfig +++ b/arch/mips/configs/jazz_defconfig @@ -34,7 +34,6 @@ CONFIG_IP_PIMSM_V2=y CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_AH=m diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index d1f198b..5da76e0 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -71,7 +71,6 @@ CONFIG_TCP_CONG_ADVANCED=y CONFIG_TCP_CONG_BIC=y CONFIG_DEFAULT_BIC=y CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_TUNNEL=m CONFIG_IPV6_MULTIPLE_TABLES=y diff --git a/arch/mips/configs/ls1b_defconfig b/arch/mips/configs/loongson1b_defconfig index 1b2cc1f..c442f27 100644 --- a/arch/mips/configs/ls1b_defconfig +++ b/arch/mips/configs/loongson1b_defconfig @@ -1,19 +1,17 @@ CONFIG_MACH_LOONGSON32=y CONFIG_PREEMPT=y # CONFIG_SECCOMP is not set -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_XZ=y CONFIG_SYSVIPC=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_NAMESPACES=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y # CONFIG_COMPAT_BRK is not set @@ -41,6 +39,12 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_LOONGSON1=y +CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_SCSI=m # CONFIG_SCSI_PROC_FS is not set @@ -48,7 +52,6 @@ CONFIG_BLK_DEV_SD=m # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_BROADCOM is not set -# CONFIG_NET_VENDOR_CHELSIO is not set # CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set @@ -56,7 +59,6 @@ CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_SMSC is not set CONFIG_STMMAC_ETH=y -CONFIG_STMMAC_DA=y # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_WLAN is not set CONFIG_INPUT_EVDEV=y @@ -69,18 +71,25 @@ CONFIG_LEGACY_PTY_COUNT=8 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_HW_RANDOM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIO_LOONGSON1=y # CONFIG_HWMON is not set # CONFIG_VGA_CONSOLE is not set -CONFIG_USB_HID=m CONFIG_HID_GENERIC=m +CONFIG_USB_HID=m CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_HCD_PLATFORM=y # CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_HCD_PLATFORM=y CONFIG_USB_STORAGE=m CONFIG_USB_SERIAL=m CONFIG_USB_SERIAL_PL2303=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_LOONGSON1=y # CONFIG_IOMMU_SUPPORT is not set @@ -96,15 +105,21 @@ CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y -# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_ATIME_SUPPORT=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_ISO8859_1=m +CONFIG_DYNAMIC_DEBUG=y # CONFIG_ENABLE_WARN_DEPRECATED is not set # CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_DEBUG_FS=y CONFIG_MAGIC_SYSRQ=y # CONFIG_SCHED_DEBUG is not set # CONFIG_DEBUG_PREEMPT is not set # CONFIG_FTRACE is not set # CONFIG_EARLY_PRINTK is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_HW is not set diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 9b6926d..f3f6005 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -51,7 +51,6 @@ CONFIG_INET_IPCOMP=m CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m -CONFIG_IPV6_PRIVACY=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m diff --git a/arch/mips/configs/nlm_xlp_defconfig b/arch/mips/configs/nlm_xlp_defconfig index b3d1d37..b496c25 100644 --- a/arch/mips/configs/nlm_xlp_defconfig +++ b/arch/mips/configs/nlm_xlp_defconfig @@ -95,7 +95,6 @@ CONFIG_TCP_CONG_YEAH=m CONFIG_TCP_CONG_ILLINOIS=m CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y -CONFIG_IPV6_PRIVACY=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig index 3d8016d..8e99ad8 100644 --- a/arch/mips/configs/nlm_xlr_defconfig +++ b/arch/mips/configs/nlm_xlr_defconfig @@ -75,7 +75,6 @@ CONFIG_TCP_CONG_YEAH=m CONFIG_TCP_CONG_ILLINOIS=m CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y -CONFIG_IPV6_PRIVACY=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index 82db4e3..c2b4e3f 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -37,7 +37,6 @@ CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_AH=m diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index a0b8943..1c3bf9f 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -60,6 +60,7 @@ EXPORT_SYMBOL(dec_kn_slot_size); int dec_tc_bus; DEFINE_SPINLOCK(ioasic_ssr_lock); +EXPORT_SYMBOL(ioasic_ssr_lock); volatile u32 *ioasic_base; diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index c7fe4d0..9740066 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -1,5 +1,6 @@ # MIPS headers generic-(CONFIG_GENERIC_CSUM) += checksum.h +generic-y += clkdev.h generic-y += cputime.h generic-y += current.h generic-y += dma-contiguous.h diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 867f924..6741673 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -235,6 +235,7 @@ .macro ld_b wd, off, base .set push .set mips32r2 + .set fp=64 .set msa ld.b $w\wd, \off(\base) .set pop @@ -243,6 +244,7 @@ .macro ld_h wd, off, base .set push .set mips32r2 + .set fp=64 .set msa ld.h $w\wd, \off(\base) .set pop @@ -251,6 +253,7 @@ .macro ld_w wd, off, base .set push .set mips32r2 + .set fp=64 .set msa ld.w $w\wd, \off(\base) .set pop @@ -268,6 +271,7 @@ .macro st_b wd, off, base .set push .set mips32r2 + .set fp=64 .set msa st.b $w\wd, \off(\base) .set pop @@ -276,6 +280,7 @@ .macro st_h wd, off, base .set push .set mips32r2 + .set fp=64 .set msa st.h $w\wd, \off(\base) .set pop @@ -284,6 +289,7 @@ .macro st_w wd, off, base .set push .set mips32r2 + .set fp=64 .set msa st.w $w\wd, \off(\base) .set pop @@ -298,21 +304,21 @@ .set pop .endm - .macro copy_u_w ws, n + .macro copy_s_w ws, n .set push .set mips32r2 .set fp=64 .set msa - copy_u.w $1, $w\ws[\n] + copy_s.w $1, $w\ws[\n] .set pop .endm - .macro copy_u_d ws, n + .macro copy_s_d ws, n .set push .set mips64r2 .set fp=64 .set msa - copy_u.d $1, $w\ws[\n] + copy_s.d $1, $w\ws[\n] .set pop .endm @@ -346,8 +352,8 @@ #define STH_MSA_INSN 0x5800081f #define STW_MSA_INSN 0x5800082f #define STD_MSA_INSN 0x5800083f -#define COPY_UW_MSA_INSN 0x58f00056 -#define COPY_UD_MSA_INSN 0x58f80056 +#define COPY_SW_MSA_INSN 0x58b00056 +#define COPY_SD_MSA_INSN 0x58b80056 #define INSERT_W_MSA_INSN 0x59300816 #define INSERT_D_MSA_INSN 0x59380816 #else @@ -361,8 +367,8 @@ #define STH_MSA_INSN 0x78000825 #define STW_MSA_INSN 0x78000826 #define STD_MSA_INSN 0x78000827 -#define COPY_UW_MSA_INSN 0x78f00059 -#define COPY_UD_MSA_INSN 0x78f80059 +#define COPY_SW_MSA_INSN 0x78b00059 +#define COPY_SD_MSA_INSN 0x78b80059 #define INSERT_W_MSA_INSN 0x79300819 #define INSERT_D_MSA_INSN 0x79380819 #endif @@ -393,7 +399,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word LDB_MSA_INSN | (\wd << 6) .set pop .endm @@ -402,7 +408,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word LDH_MSA_INSN | (\wd << 6) .set pop .endm @@ -411,7 +417,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word LDW_MSA_INSN | (\wd << 6) .set pop .endm @@ -420,7 +426,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word LDD_MSA_INSN | (\wd << 6) .set pop .endm @@ -429,7 +435,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word STB_MSA_INSN | (\wd << 6) .set pop .endm @@ -438,7 +444,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word STH_MSA_INSN | (\wd << 6) .set pop .endm @@ -447,7 +453,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word STW_MSA_INSN | (\wd << 6) .set pop .endm @@ -456,26 +462,26 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word STD_MSA_INSN | (\wd << 6) .set pop .endm - .macro copy_u_w ws, n + .macro copy_s_w ws, n .set push .set noat SET_HARDFLOAT .insn - .word COPY_UW_MSA_INSN | (\n << 16) | (\ws << 11) + .word COPY_SW_MSA_INSN | (\n << 16) | (\ws << 11) .set pop .endm - .macro copy_u_d ws, n + .macro copy_s_d ws, n .set push .set noat SET_HARDFLOAT .insn - .word COPY_UD_MSA_INSN | (\n << 16) | (\ws << 11) + .word COPY_SD_MSA_INSN | (\n << 16) | (\ws << 11) .set pop .endm @@ -496,41 +502,52 @@ .endm #endif +#ifdef TOOLCHAIN_SUPPORTS_MSA +#define FPR_BASE_OFFS THREAD_FPR0 +#define FPR_BASE $1 +#else +#define FPR_BASE_OFFS 0 +#define FPR_BASE \thread +#endif + .macro msa_save_all thread - st_d 0, THREAD_FPR0, \thread - st_d 1, THREAD_FPR1, \thread - st_d 2, THREAD_FPR2, \thread - st_d 3, THREAD_FPR3, \thread - st_d 4, THREAD_FPR4, \thread - st_d 5, THREAD_FPR5, \thread - st_d 6, THREAD_FPR6, \thread - st_d 7, THREAD_FPR7, \thread - st_d 8, THREAD_FPR8, \thread - st_d 9, THREAD_FPR9, \thread - st_d 10, THREAD_FPR10, \thread - st_d 11, THREAD_FPR11, \thread - st_d 12, THREAD_FPR12, \thread - st_d 13, THREAD_FPR13, \thread - st_d 14, THREAD_FPR14, \thread - st_d 15, THREAD_FPR15, \thread - st_d 16, THREAD_FPR16, \thread - st_d 17, THREAD_FPR17, \thread - st_d 18, THREAD_FPR18, \thread - st_d 19, THREAD_FPR19, \thread - st_d 20, THREAD_FPR20, \thread - st_d 21, THREAD_FPR21, \thread - st_d 22, THREAD_FPR22, \thread - st_d 23, THREAD_FPR23, \thread - st_d 24, THREAD_FPR24, \thread - st_d 25, THREAD_FPR25, \thread - st_d 26, THREAD_FPR26, \thread - st_d 27, THREAD_FPR27, \thread - st_d 28, THREAD_FPR28, \thread - st_d 29, THREAD_FPR29, \thread - st_d 30, THREAD_FPR30, \thread - st_d 31, THREAD_FPR31, \thread .set push .set noat +#ifdef TOOLCHAIN_SUPPORTS_MSA + PTR_ADDU FPR_BASE, \thread, FPR_BASE_OFFS +#endif + st_d 0, THREAD_FPR0 - FPR_BASE_OFFS, FPR_BASE + st_d 1, THREAD_FPR1 - FPR_BASE_OFFS, FPR_BASE + st_d 2, THREAD_FPR2 - FPR_BASE_OFFS, FPR_BASE + st_d 3, THREAD_FPR3 - FPR_BASE_OFFS, FPR_BASE + st_d 4, THREAD_FPR4 - FPR_BASE_OFFS, FPR_BASE + st_d 5, THREAD_FPR5 - FPR_BASE_OFFS, FPR_BASE + st_d 6, THREAD_FPR6 - FPR_BASE_OFFS, FPR_BASE + st_d 7, THREAD_FPR7 - FPR_BASE_OFFS, FPR_BASE + st_d 8, THREAD_FPR8 - FPR_BASE_OFFS, FPR_BASE + st_d 9, THREAD_FPR9 - FPR_BASE_OFFS, FPR_BASE + st_d 10, THREAD_FPR10 - FPR_BASE_OFFS, FPR_BASE + st_d 11, THREAD_FPR11 - FPR_BASE_OFFS, FPR_BASE + st_d 12, THREAD_FPR12 - FPR_BASE_OFFS, FPR_BASE + st_d 13, THREAD_FPR13 - FPR_BASE_OFFS, FPR_BASE + st_d 14, THREAD_FPR14 - FPR_BASE_OFFS, FPR_BASE + st_d 15, THREAD_FPR15 - FPR_BASE_OFFS, FPR_BASE + st_d 16, THREAD_FPR16 - FPR_BASE_OFFS, FPR_BASE + st_d 17, THREAD_FPR17 - FPR_BASE_OFFS, FPR_BASE + st_d 18, THREAD_FPR18 - FPR_BASE_OFFS, FPR_BASE + st_d 19, THREAD_FPR19 - FPR_BASE_OFFS, FPR_BASE + st_d 20, THREAD_FPR20 - FPR_BASE_OFFS, FPR_BASE + st_d 21, THREAD_FPR21 - FPR_BASE_OFFS, FPR_BASE + st_d 22, THREAD_FPR22 - FPR_BASE_OFFS, FPR_BASE + st_d 23, THREAD_FPR23 - FPR_BASE_OFFS, FPR_BASE + st_d 24, THREAD_FPR24 - FPR_BASE_OFFS, FPR_BASE + st_d 25, THREAD_FPR25 - FPR_BASE_OFFS, FPR_BASE + st_d 26, THREAD_FPR26 - FPR_BASE_OFFS, FPR_BASE + st_d 27, THREAD_FPR27 - FPR_BASE_OFFS, FPR_BASE + st_d 28, THREAD_FPR28 - FPR_BASE_OFFS, FPR_BASE + st_d 29, THREAD_FPR29 - FPR_BASE_OFFS, FPR_BASE + st_d 30, THREAD_FPR30 - FPR_BASE_OFFS, FPR_BASE + st_d 31, THREAD_FPR31 - FPR_BASE_OFFS, FPR_BASE SET_HARDFLOAT _cfcmsa $1, MSA_CSR sw $1, THREAD_MSA_CSR(\thread) @@ -543,40 +560,46 @@ SET_HARDFLOAT lw $1, THREAD_MSA_CSR(\thread) _ctcmsa MSA_CSR, $1 - .set pop - ld_d 0, THREAD_FPR0, \thread - ld_d 1, THREAD_FPR1, \thread - ld_d 2, THREAD_FPR2, \thread - ld_d 3, THREAD_FPR3, \thread - ld_d 4, THREAD_FPR4, \thread - ld_d 5, THREAD_FPR5, \thread - ld_d 6, THREAD_FPR6, \thread - ld_d 7, THREAD_FPR7, \thread - ld_d 8, THREAD_FPR8, \thread - ld_d 9, THREAD_FPR9, \thread - ld_d 10, THREAD_FPR10, \thread - ld_d 11, THREAD_FPR11, \thread - ld_d 12, THREAD_FPR12, \thread - ld_d 13, THREAD_FPR13, \thread - ld_d 14, THREAD_FPR14, \thread - ld_d 15, THREAD_FPR15, \thread - ld_d 16, THREAD_FPR16, \thread - ld_d 17, THREAD_FPR17, \thread - ld_d 18, THREAD_FPR18, \thread - ld_d 19, THREAD_FPR19, \thread - ld_d 20, THREAD_FPR20, \thread - ld_d 21, THREAD_FPR21, \thread - ld_d 22, THREAD_FPR22, \thread - ld_d 23, THREAD_FPR23, \thread - ld_d 24, THREAD_FPR24, \thread - ld_d 25, THREAD_FPR25, \thread - ld_d 26, THREAD_FPR26, \thread - ld_d 27, THREAD_FPR27, \thread - ld_d 28, THREAD_FPR28, \thread - ld_d 29, THREAD_FPR29, \thread - ld_d 30, THREAD_FPR30, \thread - ld_d 31, THREAD_FPR31, \thread - .endm +#ifdef TOOLCHAIN_SUPPORTS_MSA + PTR_ADDU FPR_BASE, \thread, FPR_BASE_OFFS +#endif + ld_d 0, THREAD_FPR0 - FPR_BASE_OFFS, FPR_BASE + ld_d 1, THREAD_FPR1 - FPR_BASE_OFFS, FPR_BASE + ld_d 2, THREAD_FPR2 - FPR_BASE_OFFS, FPR_BASE + ld_d 3, THREAD_FPR3 - FPR_BASE_OFFS, FPR_BASE + ld_d 4, THREAD_FPR4 - FPR_BASE_OFFS, FPR_BASE + ld_d 5, THREAD_FPR5 - FPR_BASE_OFFS, FPR_BASE + ld_d 6, THREAD_FPR6 - FPR_BASE_OFFS, FPR_BASE + ld_d 7, THREAD_FPR7 - FPR_BASE_OFFS, FPR_BASE + ld_d 8, THREAD_FPR8 - FPR_BASE_OFFS, FPR_BASE + ld_d 9, THREAD_FPR9 - FPR_BASE_OFFS, FPR_BASE + ld_d 10, THREAD_FPR10 - FPR_BASE_OFFS, FPR_BASE + ld_d 11, THREAD_FPR11 - FPR_BASE_OFFS, FPR_BASE + ld_d 12, THREAD_FPR12 - FPR_BASE_OFFS, FPR_BASE + ld_d 13, THREAD_FPR13 - FPR_BASE_OFFS, FPR_BASE + ld_d 14, THREAD_FPR14 - FPR_BASE_OFFS, FPR_BASE + ld_d 15, THREAD_FPR15 - FPR_BASE_OFFS, FPR_BASE + ld_d 16, THREAD_FPR16 - FPR_BASE_OFFS, FPR_BASE + ld_d 17, THREAD_FPR17 - FPR_BASE_OFFS, FPR_BASE + ld_d 18, THREAD_FPR18 - FPR_BASE_OFFS, FPR_BASE + ld_d 19, THREAD_FPR19 - FPR_BASE_OFFS, FPR_BASE + ld_d 20, THREAD_FPR20 - FPR_BASE_OFFS, FPR_BASE + ld_d 21, THREAD_FPR21 - FPR_BASE_OFFS, FPR_BASE + ld_d 22, THREAD_FPR22 - FPR_BASE_OFFS, FPR_BASE + ld_d 23, THREAD_FPR23 - FPR_BASE_OFFS, FPR_BASE + ld_d 24, THREAD_FPR24 - FPR_BASE_OFFS, FPR_BASE + ld_d 25, THREAD_FPR25 - FPR_BASE_OFFS, FPR_BASE + ld_d 26, THREAD_FPR26 - FPR_BASE_OFFS, FPR_BASE + ld_d 27, THREAD_FPR27 - FPR_BASE_OFFS, FPR_BASE + ld_d 28, THREAD_FPR28 - FPR_BASE_OFFS, FPR_BASE + ld_d 29, THREAD_FPR29 - FPR_BASE_OFFS, FPR_BASE + ld_d 30, THREAD_FPR30 - FPR_BASE_OFFS, FPR_BASE + ld_d 31, THREAD_FPR31 - FPR_BASE_OFFS, FPR_BASE + .set pop + .endm + +#undef FPR_BASE_OFFS +#undef FPR_BASE .macro msa_init_upper wd #ifdef CONFIG_64BIT diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h index ce9666c..fa57cef 100644 --- a/arch/mips/include/asm/bitops.h +++ b/arch/mips/include/asm/bitops.h @@ -19,25 +19,10 @@ #include <asm/byteorder.h> /* sigh ... */ #include <asm/compiler.h> #include <asm/cpu-features.h> +#include <asm/llsc.h> #include <asm/sgidefs.h> #include <asm/war.h> -#if _MIPS_SZLONG == 32 -#define SZLONG_LOG 5 -#define SZLONG_MASK 31UL -#define __LL "ll " -#define __SC "sc " -#define __INS "ins " -#define __EXT "ext " -#elif _MIPS_SZLONG == 64 -#define SZLONG_LOG 6 -#define SZLONG_MASK 63UL -#define __LL "lld " -#define __SC "scd " -#define __INS "dins " -#define __EXT "dext " -#endif - /* * These are the "slower" versions of the functions and are in bitops.c. * These functions call raw_local_irq_{save,restore}(). diff --git a/arch/mips/include/asm/bitrev.h b/arch/mips/include/asm/bitrev.h new file mode 100644 index 0000000..bc739a4 --- /dev/null +++ b/arch/mips/include/asm/bitrev.h @@ -0,0 +1,30 @@ +#ifndef __MIPS_ASM_BITREV_H__ +#define __MIPS_ASM_BITREV_H__ + +#include <linux/swab.h> + +static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x) +{ + u32 ret; + + asm("bitswap %0, %1" : "=r"(ret) : "r"(__swab32(x))); + return ret; +} + +static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x) +{ + u16 ret; + + asm("bitswap %0, %1" : "=r"(ret) : "r"(__swab16(x))); + return ret; +} + +static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x) +{ + u8 ret; + + asm("bitswap %0, %1" : "=r"(ret) : "r"(x)); + return ret; +} + +#endif /* __MIPS_ASM_BITREV_H__ */ diff --git a/arch/mips/include/asm/bmips.h b/arch/mips/include/asm/bmips.h index 6d25ad3..a92aee7 100644 --- a/arch/mips/include/asm/bmips.h +++ b/arch/mips/include/asm/bmips.h @@ -88,6 +88,7 @@ extern unsigned long bmips_tp1_irqs; extern void bmips_ebase_setup(void); extern asmlinkage void plat_wired_tlb_setup(void); +extern void bmips_cpu_setup(void); static inline unsigned long bmips_read_zscm_reg(unsigned int offset) { diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index b603804..9f67033 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -144,4 +144,22 @@ static inline void plat_swiotlb_setup(void) {} #endif /* CONFIG_SWIOTLB */ +#ifdef CONFIG_USE_OF +/** + * plat_get_fdt() - Return a pointer to the platform's device tree blob + * + * This function provides a platform independent API to get a pointer to the + * flattened device tree blob. The interface between bootloader and kernel + * is not consistent across platforms so it is necessary to provide this + * API such that common startup code can locate the FDT. + * + * This is used by the KASLR code to get command line arguments and random + * seed from the device tree. Any platform wishing to use KASLR should + * provide this API and select SYS_SUPPORTS_RELOCATABLE. + * + * Return: Pointer to the flattened device tree blob. + */ +extern void *plat_get_fdt(void); +#endif /* CONFIG_USE_OF */ + #endif /* _ASM_BOOTINFO_H */ diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h index 723229f..34ed22e 100644 --- a/arch/mips/include/asm/cacheflush.h +++ b/arch/mips/include/asm/cacheflush.h @@ -51,7 +51,6 @@ extern void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn); extern void __flush_dcache_page(struct page *page); -extern void __flush_icache_page(struct vm_area_struct *vma, struct page *page); #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 static inline void flush_dcache_page(struct page *page) @@ -77,11 +76,6 @@ static inline void flush_anon_page(struct vm_area_struct *vma, static inline void flush_icache_page(struct vm_area_struct *vma, struct page *page) { - if (!cpu_has_ic_fills_f_dc && (vma->vm_flags & VM_EXEC) && - Page_dcache_dirty(page)) { - __flush_icache_page(vma, page); - ClearPageDcacheDirty(page); - } } extern void (*flush_icache_range)(unsigned long start, unsigned long end); @@ -132,6 +126,7 @@ static inline void kunmap_noncoherent(void) static inline void flush_kernel_dcache_page(struct page *page) { BUG_ON(cpu_has_dc_aliases && PageHighMem(page)); + flush_dcache_page(page); } /* diff --git a/arch/mips/include/asm/cacheops.h b/arch/mips/include/asm/cacheops.h index c3212ff..8031fbc 100644 --- a/arch/mips/include/asm/cacheops.h +++ b/arch/mips/include/asm/cacheops.h @@ -21,6 +21,7 @@ #define Cache_I 0x00 #define Cache_D 0x01 #define Cache_T 0x02 +#define Cache_V 0x02 /* Loongson-3 */ #define Cache_S 0x03 #define Index_Writeback_Inv 0x00 @@ -107,4 +108,9 @@ */ #define Hit_Invalidate_I_Loongson2 (Cache_I | 0x00) +/* + * Loongson3-specific cacheops + */ +#define Index_Writeback_Inv_V (Cache_V | Index_Writeback_Inv) + #endif /* __ASM_CACHEOPS_H */ diff --git a/arch/mips/include/asm/clkdev.h b/arch/mips/include/asm/clkdev.h deleted file mode 100644 index 1b3ad7b..0000000 --- a/arch/mips/include/asm/clkdev.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * based on arch/arm/include/asm/clkdev.h - * - * Copyright (C) 2008 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Helper for the clk API to assist looking up a struct clk. - */ -#ifndef __ASM_CLKDEV_H -#define __ASM_CLKDEV_H - -#include <linux/slab.h> - -#ifndef CONFIG_COMMON_CLK -#define __clk_get(clk) ({ 1; }) -#define __clk_put(clk) do { } while (0) -#endif - -static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) -{ - return kzalloc(size, GFP_KERNEL); -} - -#endif diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index eeec8c8..e6f19fc 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -35,6 +35,9 @@ #ifndef cpu_has_htw #define cpu_has_htw (cpu_data[0].options & MIPS_CPU_HTW) #endif +#ifndef cpu_has_ldpte +#define cpu_has_ldpte (cpu_data[0].options & MIPS_CPU_LDPTE) +#endif #ifndef cpu_has_rixiex #define cpu_has_rixiex (cpu_data[0].options & MIPS_CPU_RIXIEX) #endif @@ -117,6 +120,21 @@ #ifndef kernel_uses_llsc #define kernel_uses_llsc cpu_has_llsc #endif +#ifndef cpu_has_guestctl0ext +#define cpu_has_guestctl0ext (cpu_data[0].options & MIPS_CPU_GUESTCTL0EXT) +#endif +#ifndef cpu_has_guestctl1 +#define cpu_has_guestctl1 (cpu_data[0].options & MIPS_CPU_GUESTCTL1) +#endif +#ifndef cpu_has_guestctl2 +#define cpu_has_guestctl2 (cpu_data[0].options & MIPS_CPU_GUESTCTL2) +#endif +#ifndef cpu_has_guestid +#define cpu_has_guestid (cpu_data[0].options & MIPS_CPU_GUESTID) +#endif +#ifndef cpu_has_drg +#define cpu_has_drg (cpu_data[0].options & MIPS_CPU_DRG) +#endif #ifndef cpu_has_mips16 #define cpu_has_mips16 (cpu_data[0].ases & MIPS_ASE_MIPS16) #endif @@ -142,8 +160,14 @@ # endif #endif +#ifndef cpu_has_lpa +#define cpu_has_lpa (cpu_data[0].options & MIPS_CPU_LPA) +#endif +#ifndef cpu_has_mvh +#define cpu_has_mvh (cpu_data[0].options & MIPS_CPU_MVH) +#endif #ifndef cpu_has_xpa -#define cpu_has_xpa (cpu_data[0].options & MIPS_CPU_XPA) +#define cpu_has_xpa (cpu_has_lpa && cpu_has_mvh) #endif #ifndef cpu_has_vtag_icache #define cpu_has_vtag_icache (cpu_data[0].icache.flags & MIPS_CACHE_VTAG) @@ -307,10 +331,18 @@ #define cpu_has_dsp2 (cpu_data[0].ases & MIPS_ASE_DSP2P) #endif +#ifndef cpu_has_dsp3 +#define cpu_has_dsp3 (cpu_data[0].ases & MIPS_ASE_DSP3) +#endif + #ifndef cpu_has_mipsmt #define cpu_has_mipsmt (cpu_data[0].ases & MIPS_ASE_MIPSMT) #endif +#ifndef cpu_has_vp +#define cpu_has_vp (cpu_data[0].options & MIPS_CPU_VP) +#endif + #ifndef cpu_has_userlocal #define cpu_has_userlocal (cpu_data[0].options & MIPS_CPU_ULRI) #endif @@ -421,4 +453,107 @@ #define cpu_has_nan_2008 (cpu_data[0].options & MIPS_CPU_NAN_2008) #endif +#ifndef cpu_has_ebase_wg +# define cpu_has_ebase_wg (cpu_data[0].options & MIPS_CPU_EBASE_WG) +#endif + +#ifndef cpu_has_badinstr +# define cpu_has_badinstr (cpu_data[0].options & MIPS_CPU_BADINSTR) +#endif + +#ifndef cpu_has_badinstrp +# define cpu_has_badinstrp (cpu_data[0].options & MIPS_CPU_BADINSTRP) +#endif + +#ifndef cpu_has_contextconfig +# define cpu_has_contextconfig (cpu_data[0].options & MIPS_CPU_CTXTC) +#endif + +#ifndef cpu_has_perf +# define cpu_has_perf (cpu_data[0].options & MIPS_CPU_PERF) +#endif + +/* + * Guest capabilities + */ +#ifndef cpu_guest_has_conf1 +#define cpu_guest_has_conf1 (cpu_data[0].guest.conf & (1 << 1)) +#endif +#ifndef cpu_guest_has_conf2 +#define cpu_guest_has_conf2 (cpu_data[0].guest.conf & (1 << 2)) +#endif +#ifndef cpu_guest_has_conf3 +#define cpu_guest_has_conf3 (cpu_data[0].guest.conf & (1 << 3)) +#endif +#ifndef cpu_guest_has_conf4 +#define cpu_guest_has_conf4 (cpu_data[0].guest.conf & (1 << 4)) +#endif +#ifndef cpu_guest_has_conf5 +#define cpu_guest_has_conf5 (cpu_data[0].guest.conf & (1 << 5)) +#endif +#ifndef cpu_guest_has_conf6 +#define cpu_guest_has_conf6 (cpu_data[0].guest.conf & (1 << 6)) +#endif +#ifndef cpu_guest_has_conf7 +#define cpu_guest_has_conf7 (cpu_data[0].guest.conf & (1 << 7)) +#endif +#ifndef cpu_guest_has_fpu +#define cpu_guest_has_fpu (cpu_data[0].guest.options & MIPS_CPU_FPU) +#endif +#ifndef cpu_guest_has_watch +#define cpu_guest_has_watch (cpu_data[0].guest.options & MIPS_CPU_WATCH) +#endif +#ifndef cpu_guest_has_contextconfig +#define cpu_guest_has_contextconfig (cpu_data[0].guest.options & MIPS_CPU_CTXTC) +#endif +#ifndef cpu_guest_has_segments +#define cpu_guest_has_segments (cpu_data[0].guest.options & MIPS_CPU_SEGMENTS) +#endif +#ifndef cpu_guest_has_badinstr +#define cpu_guest_has_badinstr (cpu_data[0].guest.options & MIPS_CPU_BADINSTR) +#endif +#ifndef cpu_guest_has_badinstrp +#define cpu_guest_has_badinstrp (cpu_data[0].guest.options & MIPS_CPU_BADINSTRP) +#endif +#ifndef cpu_guest_has_htw +#define cpu_guest_has_htw (cpu_data[0].guest.options & MIPS_CPU_HTW) +#endif +#ifndef cpu_guest_has_msa +#define cpu_guest_has_msa (cpu_data[0].guest.ases & MIPS_ASE_MSA) +#endif +#ifndef cpu_guest_has_kscr +#define cpu_guest_has_kscr(n) (cpu_data[0].guest.kscratch_mask & (1u << (n))) +#endif +#ifndef cpu_guest_has_rw_llb +#define cpu_guest_has_rw_llb (cpu_has_mips_r6 || (cpu_data[0].guest.options & MIPS_CPU_RW_LLB)) +#endif +#ifndef cpu_guest_has_perf +#define cpu_guest_has_perf (cpu_data[0].guest.options & MIPS_CPU_PERF) +#endif +#ifndef cpu_guest_has_maar +#define cpu_guest_has_maar (cpu_data[0].guest.options & MIPS_CPU_MAAR) +#endif + +/* + * Guest dynamic capabilities + */ +#ifndef cpu_guest_has_dyn_fpu +#define cpu_guest_has_dyn_fpu (cpu_data[0].guest.options_dyn & MIPS_CPU_FPU) +#endif +#ifndef cpu_guest_has_dyn_watch +#define cpu_guest_has_dyn_watch (cpu_data[0].guest.options_dyn & MIPS_CPU_WATCH) +#endif +#ifndef cpu_guest_has_dyn_contextconfig +#define cpu_guest_has_dyn_contextconfig (cpu_data[0].guest.options_dyn & MIPS_CPU_CTXTC) +#endif +#ifndef cpu_guest_has_dyn_perf +#define cpu_guest_has_dyn_perf (cpu_data[0].guest.options_dyn & MIPS_CPU_PERF) +#endif +#ifndef cpu_guest_has_dyn_msa +#define cpu_guest_has_dyn_msa (cpu_data[0].guest.ases_dyn & MIPS_ASE_MSA) +#endif +#ifndef cpu_guest_has_dyn_maar +#define cpu_guest_has_dyn_maar (cpu_data[0].guest.options_dyn & MIPS_CPU_MAAR) +#endif + #endif /* __ASM_CPU_FEATURES_H */ diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index af12c1f..edbe273 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h @@ -28,6 +28,15 @@ struct cache_desc { unsigned char flags; /* Flags describing cache properties */ }; +struct guest_info { + unsigned long ases; + unsigned long ases_dyn; + unsigned long long options; + unsigned long long options_dyn; + u8 conf; + u8 kscratch_mask; +}; + /* * Flag definitions */ @@ -40,6 +49,9 @@ struct cache_desc { struct cpuinfo_mips { unsigned long asid_cache; +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + unsigned long asid_mask; +#endif /* * Capability and feature descriptor structure for MIPS CPU @@ -60,6 +72,7 @@ struct cpuinfo_mips { int tlbsizeftlbways; 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 srsets; /* Shadow register sets */ @@ -68,7 +81,7 @@ struct cpuinfo_mips { #ifdef CONFIG_64BIT int vmbits; /* Virtual memory size in bits */ #endif -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) /* * There is not necessarily a 1:1 mapping of VPE num to CPU number * in particular on multi-core systems. @@ -91,6 +104,11 @@ struct cpuinfo_mips { * htw_start/htw_stop calls */ unsigned int htw_seq; + + /* VZ & Guest features */ + struct guest_info guest; + unsigned int gtoffset_mask; + unsigned int guestid_mask; } __attribute__((aligned(SMP_CACHE_BYTES))); extern struct cpuinfo_mips cpu_data[]; @@ -125,10 +143,31 @@ struct proc_cpuinfo_notifier_args { unsigned long n; }; -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) # define cpu_vpe_id(cpuinfo) ((cpuinfo)->vpe_id) #else # define cpu_vpe_id(cpuinfo) ({ (void)cpuinfo; 0; }) #endif +static inline unsigned long cpu_asid_inc(void) +{ + return 1 << CONFIG_MIPS_ASID_SHIFT; +} + +static inline unsigned long cpu_asid_mask(struct cpuinfo_mips *cpuinfo) +{ +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + return cpuinfo->asid_mask; +#endif + return ((1 << CONFIG_MIPS_ASID_BITS) - 1) << CONFIG_MIPS_ASID_SHIFT; +} + +static inline void set_cpu_asid_mask(struct cpuinfo_mips *cpuinfo, + unsigned long asid_mask) +{ +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + cpuinfo->asid_mask = asid_mask; +#endif +} + #endif /* __ASM_CPU_INFO_H */ diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h index abee2bf..fbe1881 100644 --- a/arch/mips/include/asm/cpu-type.h +++ b/arch/mips/include/asm/cpu-type.h @@ -77,8 +77,13 @@ static inline int __pure __get_cpu_type(const int cpu_type) */ #endif +#ifdef CONFIG_SYS_HAS_CPU_MIPS32_R6 + case CPU_M6250: +#endif + #ifdef CONFIG_SYS_HAS_CPU_MIPS64_R6 case CPU_I6400: + case CPU_P6600: #endif #ifdef CONFIG_SYS_HAS_CPU_R3000 diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index a97ca97..f672df8 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -42,6 +42,7 @@ #define PRID_COMP_LEXRA 0x0b0000 #define PRID_COMP_NETLOGIC 0x0c0000 #define PRID_COMP_CAVIUM 0x0d0000 +#define PRID_COMP_LOONGSON 0x140000 #define PRID_COMP_INGENIC_D0 0xd00000 /* JZ4740, JZ4750 */ #define PRID_COMP_INGENIC_D1 0xd10000 /* JZ4770, JZ4775 */ #define PRID_COMP_INGENIC_E1 0xe10000 /* JZ4780 */ @@ -118,9 +119,11 @@ #define PRID_IMP_INTERAPTIV_MP 0xa100 #define PRID_IMP_PROAPTIV_UP 0xa200 #define PRID_IMP_PROAPTIV_MP 0xa300 +#define PRID_IMP_P6600 0xa400 #define PRID_IMP_M5150 0xa700 #define PRID_IMP_P5600 0xa800 #define PRID_IMP_I6400 0xa900 +#define PRID_IMP_M6250 0xab00 /* * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE @@ -169,6 +172,8 @@ #define PRID_IMP_CAVIUM_CNF71XX 0x9400 #define PRID_IMP_CAVIUM_CN78XX 0x9500 #define PRID_IMP_CAVIUM_CN70XX 0x9600 +#define PRID_IMP_CAVIUM_CN73XX 0x9700 +#define PRID_IMP_CAVIUM_CNF75XX 0x9800 /* * These are the PRID's for when 23:16 == PRID_COMP_INGENIC_* @@ -237,9 +242,10 @@ #define PRID_REV_LOONGSON1B 0x0020 #define PRID_REV_LOONGSON2E 0x0002 #define PRID_REV_LOONGSON2F 0x0003 -#define PRID_REV_LOONGSON3A 0x0005 +#define PRID_REV_LOONGSON3A_R1 0x0005 #define PRID_REV_LOONGSON3B_R1 0x0006 #define PRID_REV_LOONGSON3B_R2 0x0007 +#define PRID_REV_LOONGSON3A_R2 0x0008 /* * Older processors used to encode processor version and revision in two @@ -307,8 +313,8 @@ enum cpu_type_enum { CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K, CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, - CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, CPU_M5150, - CPU_I6400, + CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, + CPU_M5150, CPU_I6400, CPU_P6600, CPU_M6250, /* * MIPS64 class processors @@ -346,48 +352,68 @@ enum cpu_type_enum { MIPS_CPU_ISA_M64R6) /* + * Private version of BIT_ULL() to escape include file recursion hell. + * We soon will have to switch to another mechanism that will work with + * more than 64 bits anyway. + */ +#define MBIT_ULL(bit) (1ULL << (bit)) + +/* * CPU Option encodings */ -#define MIPS_CPU_TLB 0x00000001ull /* CPU has TLB */ -#define MIPS_CPU_4KEX 0x00000002ull /* "R4K" exception model */ -#define MIPS_CPU_3K_CACHE 0x00000004ull /* R3000-style caches */ -#define MIPS_CPU_4K_CACHE 0x00000008ull /* R4000-style caches */ -#define MIPS_CPU_TX39_CACHE 0x00000010ull /* TX3900-style caches */ -#define MIPS_CPU_FPU 0x00000020ull /* CPU has FPU */ -#define MIPS_CPU_32FPR 0x00000040ull /* 32 dbl. prec. FP registers */ -#define MIPS_CPU_COUNTER 0x00000080ull /* Cycle count/compare */ -#define MIPS_CPU_WATCH 0x00000100ull /* watchpoint registers */ -#define MIPS_CPU_DIVEC 0x00000200ull /* dedicated interrupt vector */ -#define MIPS_CPU_VCE 0x00000400ull /* virt. coherence conflict possible */ -#define MIPS_CPU_CACHE_CDEX_P 0x00000800ull /* Create_Dirty_Exclusive CACHE op */ -#define MIPS_CPU_CACHE_CDEX_S 0x00001000ull /* ... same for seconary cache ... */ -#define MIPS_CPU_MCHECK 0x00002000ull /* Machine check exception */ -#define MIPS_CPU_EJTAG 0x00004000ull /* EJTAG exception */ -#define MIPS_CPU_NOFPUEX 0x00008000ull /* no FPU exception */ -#define MIPS_CPU_LLSC 0x00010000ull /* CPU has ll/sc instructions */ -#define MIPS_CPU_INCLUSIVE_CACHES 0x00020000ull /* P-cache subset enforced */ -#define MIPS_CPU_PREFETCH 0x00040000ull /* CPU has usable prefetch */ -#define MIPS_CPU_VINT 0x00080000ull /* CPU supports MIPSR2 vectored interrupts */ -#define MIPS_CPU_VEIC 0x00100000ull /* CPU supports MIPSR2 external interrupt controller mode */ -#define MIPS_CPU_ULRI 0x00200000ull /* CPU has ULRI feature */ -#define MIPS_CPU_PCI 0x00400000ull /* CPU has Perf Ctr Int indicator */ -#define MIPS_CPU_RIXI 0x00800000ull /* CPU has TLB Read/eXec Inhibit */ -#define MIPS_CPU_MICROMIPS 0x01000000ull /* CPU has microMIPS capability */ -#define MIPS_CPU_TLBINV 0x02000000ull /* CPU supports TLBINV/F */ -#define MIPS_CPU_SEGMENTS 0x04000000ull /* CPU supports Segmentation Control registers */ -#define MIPS_CPU_EVA 0x80000000ull /* CPU supports Enhanced Virtual Addressing */ -#define MIPS_CPU_HTW 0x100000000ull /* CPU support Hardware Page Table Walker */ -#define MIPS_CPU_RIXIEX 0x200000000ull /* CPU has unique exception codes for {Read, Execute}-Inhibit exceptions */ -#define MIPS_CPU_MAAR 0x400000000ull /* MAAR(I) registers are present */ -#define MIPS_CPU_FRE 0x800000000ull /* FRE & UFE bits implemented */ -#define MIPS_CPU_RW_LLB 0x1000000000ull /* LLADDR/LLB writes are allowed */ -#define MIPS_CPU_XPA 0x2000000000ull /* CPU supports Extended Physical Addressing */ -#define MIPS_CPU_CDMM 0x4000000000ull /* CPU has Common Device Memory Map */ -#define MIPS_CPU_BP_GHIST 0x8000000000ull /* R12K+ Branch Prediction Global History */ -#define MIPS_CPU_SP 0x10000000000ull /* Small (1KB) page support */ -#define MIPS_CPU_FTLB 0x20000000000ull /* CPU has Fixed-page-size TLB */ -#define MIPS_CPU_NAN_LEGACY 0x40000000000ull /* Legacy NaN implemented */ -#define MIPS_CPU_NAN_2008 0x80000000000ull /* 2008 NaN implemented */ +#define MIPS_CPU_TLB MBIT_ULL( 0) /* CPU has TLB */ +#define MIPS_CPU_4KEX MBIT_ULL( 1) /* "R4K" exception model */ +#define MIPS_CPU_3K_CACHE MBIT_ULL( 2) /* R3000-style caches */ +#define MIPS_CPU_4K_CACHE MBIT_ULL( 3) /* R4000-style caches */ +#define MIPS_CPU_TX39_CACHE MBIT_ULL( 4) /* TX3900-style caches */ +#define MIPS_CPU_FPU MBIT_ULL( 5) /* CPU has FPU */ +#define MIPS_CPU_32FPR MBIT_ULL( 6) /* 32 dbl. prec. FP registers */ +#define MIPS_CPU_COUNTER MBIT_ULL( 7) /* Cycle count/compare */ +#define MIPS_CPU_WATCH MBIT_ULL( 8) /* watchpoint registers */ +#define MIPS_CPU_DIVEC MBIT_ULL( 9) /* dedicated interrupt vector */ +#define MIPS_CPU_VCE MBIT_ULL(10) /* virt. coherence conflict possible */ +#define MIPS_CPU_CACHE_CDEX_P MBIT_ULL(11) /* Create_Dirty_Exclusive CACHE op */ +#define MIPS_CPU_CACHE_CDEX_S MBIT_ULL(12) /* ... same for seconary cache ... */ +#define MIPS_CPU_MCHECK MBIT_ULL(13) /* Machine check exception */ +#define MIPS_CPU_EJTAG MBIT_ULL(14) /* EJTAG exception */ +#define MIPS_CPU_NOFPUEX MBIT_ULL(15) /* no FPU exception */ +#define MIPS_CPU_LLSC MBIT_ULL(16) /* CPU has ll/sc instructions */ +#define MIPS_CPU_INCLUSIVE_CACHES MBIT_ULL(17) /* P-cache subset enforced */ +#define MIPS_CPU_PREFETCH MBIT_ULL(18) /* CPU has usable prefetch */ +#define MIPS_CPU_VINT MBIT_ULL(19) /* CPU supports MIPSR2 vectored interrupts */ +#define MIPS_CPU_VEIC MBIT_ULL(20) /* CPU supports MIPSR2 external interrupt controller mode */ +#define MIPS_CPU_ULRI MBIT_ULL(21) /* CPU has ULRI feature */ +#define MIPS_CPU_PCI MBIT_ULL(22) /* CPU has Perf Ctr Int indicator */ +#define MIPS_CPU_RIXI MBIT_ULL(23) /* CPU has TLB Read/eXec Inhibit */ +#define MIPS_CPU_MICROMIPS MBIT_ULL(24) /* CPU has microMIPS capability */ +#define MIPS_CPU_TLBINV MBIT_ULL(25) /* CPU supports TLBINV/F */ +#define MIPS_CPU_SEGMENTS MBIT_ULL(26) /* CPU supports Segmentation Control registers */ +#define MIPS_CPU_EVA MBIT_ULL(27) /* CPU supports Enhanced Virtual Addressing */ +#define MIPS_CPU_HTW MBIT_ULL(28) /* CPU support Hardware Page Table Walker */ +#define MIPS_CPU_RIXIEX MBIT_ULL(29) /* CPU has unique exception codes for {Read, Execute}-Inhibit exceptions */ +#define MIPS_CPU_MAAR MBIT_ULL(30) /* MAAR(I) registers are present */ +#define MIPS_CPU_FRE MBIT_ULL(31) /* FRE & UFE bits implemented */ +#define MIPS_CPU_RW_LLB MBIT_ULL(32) /* LLADDR/LLB writes are allowed */ +#define MIPS_CPU_LPA MBIT_ULL(33) /* CPU supports Large Physical Addressing */ +#define MIPS_CPU_CDMM MBIT_ULL(34) /* CPU has Common Device Memory Map */ +#define MIPS_CPU_BP_GHIST MBIT_ULL(35) /* R12K+ Branch Prediction Global History */ +#define MIPS_CPU_SP MBIT_ULL(36) /* Small (1KB) page support */ +#define MIPS_CPU_FTLB MBIT_ULL(37) /* CPU has Fixed-page-size TLB */ +#define MIPS_CPU_NAN_LEGACY MBIT_ULL(38) /* Legacy NaN implemented */ +#define MIPS_CPU_NAN_2008 MBIT_ULL(39) /* 2008 NaN implemented */ +#define MIPS_CPU_VP MBIT_ULL(40) /* MIPSr6 Virtual Processors (multi-threading) */ +#define MIPS_CPU_LDPTE MBIT_ULL(41) /* CPU has ldpte/lddir instructions */ +#define MIPS_CPU_MVH MBIT_ULL(42) /* CPU supports MFHC0/MTHC0 */ +#define MIPS_CPU_EBASE_WG MBIT_ULL(43) /* CPU has EBase.WG */ +#define MIPS_CPU_BADINSTR MBIT_ULL(44) /* CPU has BadInstr register */ +#define MIPS_CPU_BADINSTRP MBIT_ULL(45) /* CPU has BadInstrP register */ +#define MIPS_CPU_CTXTC MBIT_ULL(46) /* CPU has [X]ConfigContext registers */ +#define MIPS_CPU_PERF MBIT_ULL(47) /* CPU has MIPS performance counters */ +#define MIPS_CPU_GUESTCTL0EXT MBIT_ULL(48) /* CPU has VZ GuestCtl0Ext register */ +#define MIPS_CPU_GUESTCTL1 MBIT_ULL(49) /* CPU has VZ GuestCtl1 register */ +#define MIPS_CPU_GUESTCTL2 MBIT_ULL(50) /* CPU has VZ GuestCtl2 register */ +#define MIPS_CPU_GUESTID MBIT_ULL(51) /* CPU uses VZ ASE GuestID feature */ +#define MIPS_CPU_DRG MBIT_ULL(52) /* CPU has VZ Direct Root to Guest (DRG) */ /* * CPU ASE encodings @@ -401,5 +427,6 @@ enum cpu_type_enum { #define MIPS_ASE_DSP2P 0x00000040 /* Signal Processing ASE Rev 2 */ #define MIPS_ASE_VZ 0x00000080 /* Virtualization ASE */ #define MIPS_ASE_MSA 0x00000100 /* MIPS SIMD Architecture */ +#define MIPS_ASE_DSP3 0x00000200 /* Signal Processing ASE Rev 3*/ #endif /* _ASM_CPU_H */ diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index e090fc3..f5f4571 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -111,6 +111,11 @@ #define R_MIPS_CALLHI16 30 #define R_MIPS_CALLLO16 31 /* + * Introduced for MIPSr6. + */ +#define R_MIPS_PC21_S2 60 +#define R_MIPS_PC26_S2 61 +/* * This range is reserved for vendor specific relocations. */ #define R_MIPS_LOVENDOR 100 @@ -170,16 +175,14 @@ #define SHF_MIPS_NAMES 0x02000000 #define SHF_MIPS_NODUPES 0x01000000 -#ifndef ELF_ARCH -/* ELF register definitions */ -#define ELF_NGREG 45 -#define ELF_NFPREG 33 - -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]; +#define MIPS_ABI_FP_ANY 0 /* FP ABI doesn't matter */ +#define MIPS_ABI_FP_DOUBLE 1 /* -mdouble-float */ +#define MIPS_ABI_FP_SINGLE 2 /* -msingle-float */ +#define MIPS_ABI_FP_SOFT 3 /* -msoft-float */ +#define MIPS_ABI_FP_OLD_64 4 /* -mips32r2 -mfp64 */ +#define MIPS_ABI_FP_XX 5 /* -mfpxx */ +#define MIPS_ABI_FP_64 6 /* -mips32r2 -mfp64 */ +#define MIPS_ABI_FP_64A 7 /* -mips32r2 -mfp64 -mno-odd-spreg */ struct mips_elf_abiflags_v0 { uint16_t version; /* Version of flags structure */ @@ -196,16 +199,54 @@ struct mips_elf_abiflags_v0 { uint32_t flags2; }; -#define MIPS_ABI_FP_ANY 0 /* FP ABI doesn't matter */ -#define MIPS_ABI_FP_DOUBLE 1 /* -mdouble-float */ -#define MIPS_ABI_FP_SINGLE 2 /* -msingle-float */ -#define MIPS_ABI_FP_SOFT 3 /* -msoft-float */ -#define MIPS_ABI_FP_OLD_64 4 /* -mips32r2 -mfp64 */ -#define MIPS_ABI_FP_XX 5 /* -mfpxx */ -#define MIPS_ABI_FP_64 6 /* -mips32r2 -mfp64 */ -#define MIPS_ABI_FP_64A 7 /* -mips32r2 -mfp64 -mno-odd-spreg */ +#ifndef ELF_ARCH +/* ELF register definitions */ +#define ELF_NGREG 45 +#define ELF_NFPREG 33 + +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]; #ifdef CONFIG_32BIT +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch elfo32_check_arch + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 + +#endif /* CONFIG_32BIT */ + +#ifdef CONFIG_64BIT +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch elfn64_check_arch + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS64 + +#endif /* CONFIG_64BIT */ + +/* + * These are used to set parameters in the core dumps. + */ +#ifdef __MIPSEB__ +#define ELF_DATA ELFDATA2MSB +#elif defined(__MIPSEL__) +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_MIPS + +#endif /* !defined(ELF_ARCH) */ /* * In order to be sure that we don't attempt to execute an O32 binary which @@ -219,10 +260,15 @@ struct mips_elf_abiflags_v0 { # define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64 #endif +#define mips_elf_check_machine(x) ((x)->e_machine == EM_MIPS) + +#define vmcore_elf32_check_arch mips_elf_check_machine +#define vmcore_elf64_check_arch mips_elf_check_machine + /* - * This is used to ensure we don't load something for the wrong architecture. + * Return non-zero if HDR identifies an o32 ELF binary. */ -#define elf_check_arch(hdr) \ +#define elfo32_check_arch(hdr) \ ({ \ int __res = 1; \ struct elfhdr *__h = (hdr); \ @@ -243,17 +289,9 @@ struct mips_elf_abiflags_v0 { }) /* - * These are used to set parameters in the core dumps. - */ -#define ELF_CLASS ELFCLASS32 - -#endif /* CONFIG_32BIT */ - -#ifdef CONFIG_64BIT -/* - * This is used to ensure we don't load something for the wrong architecture. + * Return non-zero if HDR identifies an n64 ELF binary. */ -#define elf_check_arch(hdr) \ +#define elfn64_check_arch(hdr) \ ({ \ int __res = 1; \ struct elfhdr *__h = (hdr); \ @@ -267,28 +305,23 @@ struct mips_elf_abiflags_v0 { }) /* - * These are used to set parameters in the core dumps. + * Return non-zero if HDR identifies an n32 ELF binary. */ -#define ELF_CLASS ELFCLASS64 - -#endif /* CONFIG_64BIT */ - -/* - * These are used to set parameters in the core dumps. - */ -#ifdef __MIPSEB__ -#define ELF_DATA ELFDATA2MSB -#elif defined(__MIPSEL__) -#define ELF_DATA ELFDATA2LSB -#endif -#define ELF_ARCH EM_MIPS - -#endif /* !defined(ELF_ARCH) */ - -#define mips_elf_check_machine(x) ((x)->e_machine == EM_MIPS) - -#define vmcore_elf32_check_arch mips_elf_check_machine -#define vmcore_elf64_check_arch mips_elf_check_machine +#define elfn32_check_arch(hdr) \ +({ \ + int __res = 1; \ + struct elfhdr *__h = (hdr); \ + \ + if (!mips_elf_check_machine(__h)) \ + __res = 0; \ + if (__h->e_ident[EI_CLASS] != ELFCLASS32) \ + __res = 0; \ + if (((__h->e_flags & EF_MIPS_ABI2) == 0) || \ + ((__h->e_flags & EF_MIPS_ABI) != 0)) \ + __res = 0; \ + \ + __res; \ +}) struct mips_abi; @@ -300,17 +333,16 @@ extern struct mips_abi mips_abi_n32; #define SET_PERSONALITY2(ex, state) \ do { \ - if (personality(current->personality) != PER_LINUX) \ - set_personality(PER_LINUX); \ - \ clear_thread_flag(TIF_HYBRID_FPREGS); \ set_thread_flag(TIF_32BIT_FPREGS); \ \ - mips_set_personality_fp(state); \ - \ current->thread.abi = &mips_abi; \ \ + mips_set_personality_fp(state); \ mips_set_personality_nan(state); \ + \ + if (personality(current->personality) != PER_LINUX) \ + set_personality(PER_LINUX); \ } while (0) #endif /* CONFIG_32BIT */ @@ -321,6 +353,7 @@ do { \ #define __SET_PERSONALITY32_N32() \ do { \ set_thread_flag(TIF_32BIT_ADDR); \ + \ current->thread.abi = &mips_abi_n32; \ } while (0) #else @@ -336,9 +369,9 @@ do { \ clear_thread_flag(TIF_HYBRID_FPREGS); \ set_thread_flag(TIF_32BIT_FPREGS); \ \ - mips_set_personality_fp(state); \ - \ current->thread.abi = &mips_abi_32; \ + \ + mips_set_personality_fp(state); \ } while (0) #else #define __SET_PERSONALITY32_O32(ex, state) \ diff --git a/arch/mips/include/asm/hazards.h b/arch/mips/include/asm/hazards.h index 7b99efd..dbb1eb6 100644 --- a/arch/mips/include/asm/hazards.h +++ b/arch/mips/include/asm/hazards.h @@ -22,7 +22,8 @@ /* * TLB hazards */ -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) && !defined(CONFIG_CPU_CAVIUM_OCTEON) +#if (defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)) && \ + !defined(CONFIG_CPU_CAVIUM_OCTEON) && !defined(CONFIG_LOONGSON3_ENHANCEMENT) /* * MIPSR2 defines ehb for hazard avoidance @@ -155,8 +156,8 @@ do { \ } while (0) #elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \ - defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_CPU_R10000) || \ - defined(CONFIG_CPU_R5500) || defined(CONFIG_CPU_XLR) + defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_LOONGSON3_ENHANCEMENT) || \ + defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_R5500) || defined(CONFIG_CPU_XLR) /* * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer. diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 01880b3..64f2500 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -19,8 +19,10 @@ #ifdef __KERNEL__ +#include <linux/bug.h> #include <linux/interrupt.h> #include <linux/uaccess.h> +#include <asm/cpu-features.h> #include <asm/kmap_types.h> /* undef for production */ @@ -50,7 +52,7 @@ extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); -#define flush_cache_kmaps() flush_cache_all() +#define flush_cache_kmaps() BUG_ON(cpu_has_dc_aliases) extern void kmap_init(void); diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 2b4dc7a..ecabc00 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -304,10 +304,10 @@ static inline void iounmap(const volatile void __iomem *addr) #undef __IS_KSEG1 } -#ifdef CONFIG_CPU_CAVIUM_OCTEON -#define war_octeon_io_reorder_wmb() wmb() +#if defined(CONFIG_CPU_CAVIUM_OCTEON) || defined(CONFIG_LOONGSON3_ENHANCEMENT) +#define war_io_reorder_wmb() wmb() #else -#define war_octeon_io_reorder_wmb() do { } while (0) +#define war_io_reorder_wmb() do { } while (0) #endif #define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, irq) \ @@ -318,7 +318,7 @@ static inline void pfx##write##bwlq(type val, \ volatile type *__mem; \ type __val; \ \ - war_octeon_io_reorder_wmb(); \ + war_io_reorder_wmb(); \ \ __mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem)); \ \ @@ -387,7 +387,7 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ volatile type *__addr; \ type __val; \ \ - war_octeon_io_reorder_wmb(); \ + war_io_reorder_wmb(); \ \ __addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \ \ diff --git a/arch/mips/include/asm/irq_regs.h b/arch/mips/include/asm/irq_regs.h index 33bd2a0..8c48d6d 100644 --- a/arch/mips/include/asm/irq_regs.h +++ b/arch/mips/include/asm/irq_regs.h @@ -18,4 +18,14 @@ 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/mips/include/asm/irqflags.h b/arch/mips/include/asm/irqflags.h index 65c351e..9d3610b 100644 --- a/arch/mips/include/asm/irqflags.h +++ b/arch/mips/include/asm/irqflags.h @@ -41,7 +41,12 @@ static inline unsigned long arch_local_irq_save(void) " .set push \n" " .set reorder \n" " .set noat \n" +#if defined(CONFIG_CPU_LOONGSON3) + " mfc0 %[flags], $12 \n" + " di \n" +#else " di %[flags] \n" +#endif " andi %[flags], 1 \n" " " __stringify(__irq_disable_hazard) " \n" " .set pop \n" diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index f6b1279..6733ac5 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -122,6 +122,7 @@ struct kvm_vcpu_stat { u32 flush_dcache_exits; u32 halt_successful_poll; u32 halt_attempted_poll; + u32 halt_poll_invalid; u32 halt_wakeup; }; @@ -311,17 +312,18 @@ enum emulation_result { #define MIPS3_PG_FRAME 0x3fffffc0 #define VPN2_MASK 0xffffe000 +#define KVM_ENTRYHI_ASID MIPS_ENTRYHI_ASID #define TLB_IS_GLOBAL(x) (((x).tlb_lo0 & MIPS3_PG_G) && \ ((x).tlb_lo1 & MIPS3_PG_G)) #define TLB_VPN2(x) ((x).tlb_hi & VPN2_MASK) -#define TLB_ASID(x) ((x).tlb_hi & ASID_MASK) +#define TLB_ASID(x) ((x).tlb_hi & KVM_ENTRYHI_ASID) #define TLB_IS_VALID(x, va) (((va) & (1 << PAGE_SHIFT)) \ ? ((x).tlb_lo1 & MIPS3_PG_V) \ : ((x).tlb_lo0 & MIPS3_PG_V)) #define TLB_HI_VPN2_HIT(x, y) ((TLB_VPN2(x) & ~(x).tlb_mask) == \ ((y) & VPN2_MASK & ~(x).tlb_mask)) #define TLB_HI_ASID_HIT(x, y) (TLB_IS_GLOBAL(x) || \ - TLB_ASID(x) == ((y) & ASID_MASK)) + TLB_ASID(x) == ((y) & KVM_ENTRYHI_ASID)) struct kvm_mips_tlb { long tlb_mask; @@ -747,7 +749,7 @@ extern enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu, uint32_t kvm_mips_read_count(struct kvm_vcpu *vcpu); void kvm_mips_write_count(struct kvm_vcpu *vcpu, uint32_t count); -void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare); +void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare, bool ack); void kvm_mips_init_count(struct kvm_vcpu *vcpu); int kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl); int kvm_mips_set_count_resume(struct kvm_vcpu *vcpu, s64 count_resume); @@ -812,5 +814,6 @@ static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} +static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {} #endif /* __MIPS_KVM_HOST_H__ */ diff --git a/arch/mips/include/asm/llsc.h b/arch/mips/include/asm/llsc.h new file mode 100644 index 0000000..c6d17d1 --- /dev/null +++ b/arch/mips/include/asm/llsc.h @@ -0,0 +1,28 @@ +/* + * 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. + * + * Macros for 32/64-bit neutral inline assembler + */ + +#ifndef __ASM_LLSC_H +#define __ASM_LLSC_H + +#if _MIPS_SZLONG == 32 +#define SZLONG_LOG 5 +#define SZLONG_MASK 31UL +#define __LL "ll " +#define __SC "sc " +#define __INS "ins " +#define __EXT "ext " +#elif _MIPS_SZLONG == 64 +#define SZLONG_LOG 6 +#define SZLONG_MASK 63UL +#define __LL "lld " +#define __SC "scd " +#define __INS "dins " +#define __EXT "dext " +#endif + +#endif /* __ASM_LLSC_H */ diff --git a/arch/mips/include/asm/mach-bmips/cpu-feature-overrides.h b/arch/mips/include/asm/mach-bmips/cpu-feature-overrides.h new file mode 100644 index 0000000..fa0583e --- /dev/null +++ b/arch/mips/include/asm/mach-bmips/cpu-feature-overrides.h @@ -0,0 +1,14 @@ +#ifndef __ASM_MACH_BMIPS_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_BMIPS_CPU_FEATURE_OVERRIDES_H + +/* Invariants across all BMIPS processors */ +#define cpu_has_vtag_icache 0 +#define cpu_icache_snoops_remote_store 1 + +/* Processor ISA compatibility is MIPS32R1 */ +#define cpu_has_mips32r1 1 +#define cpu_has_mips32r2 0 +#define cpu_has_mips64r1 0 +#define cpu_has_mips64r2 0 + +#endif /* __ASM_MACH_BMIPS_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-bmips/ioremap.h b/arch/mips/include/asm/mach-bmips/ioremap.h new file mode 100644 index 0000000..29c7a7b --- /dev/null +++ b/arch/mips/include/asm/mach-bmips/ioremap.h @@ -0,0 +1,33 @@ +#ifndef __ASM_MACH_BMIPS_IOREMAP_H +#define __ASM_MACH_BMIPS_IOREMAP_H + +#include <linux/types.h> + +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) +{ + return phys_addr; +} + +static inline int is_bmips_internal_registers(phys_addr_t offset) +{ + if (offset >= 0xfff80000) + return 1; + + return 0; +} + +static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size, + unsigned long flags) +{ + if (is_bmips_internal_registers(offset)) + return (void __iomem *)offset; + + return NULL; +} + +static inline int plat_iounmap(const volatile void __iomem *addr) +{ + return is_bmips_internal_registers((unsigned long)addr); +} + +#endif /* __ASM_MACH_BMIPS_IOREMAP_H */ diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h index 32cfbe6..073b8bf 100644 --- a/arch/mips/include/asm/mach-jz4740/platform.h +++ b/arch/mips/include/asm/mach-jz4740/platform.h @@ -19,7 +19,6 @@ #include <linux/platform_device.h> -extern struct platform_device jz4740_usb_ohci_device; extern struct platform_device jz4740_udc_device; extern struct platform_device jz4740_udc_xceiv_device; extern struct platform_device jz4740_mmc_device; diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h index 98d6a2f..7023883 100644 --- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_FALCON_H__ diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h index 4e5ae65..8064d7a 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LANTIQ_H__ #define _LANTIQ_H__ diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h index e23bf7c..17d2fdc 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LANTIQ_PLATFORM_H__ diff --git a/arch/mips/include/asm/mach-lantiq/xway/irq.h b/arch/mips/include/asm/mach-lantiq/xway/irq.h index a1471d2..83e5f03 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/irq.h +++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef __LANTIQ_IRQ_H diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h index 5eadfe5..1410763 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LANTIQ_XWAY_IRQ_H__ diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index dd6005b..f873107 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_XWAY_H__ diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h index 5f8693d..4901833 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h +++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h @@ -12,7 +12,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2011 John Crispin <blogic@openwrt.org> + * Copyright (C) 2011 John Crispin <john@phrozen.org> */ #ifndef LTQ_DMA_H__ diff --git a/arch/mips/include/asm/mach-loongson32/cpufreq.h b/arch/mips/include/asm/mach-loongson32/cpufreq.h index 6843fa1..2f1ecb0 100644 --- a/arch/mips/include/asm/mach-loongson32/cpufreq.h +++ b/arch/mips/include/asm/mach-loongson32/cpufreq.h @@ -9,7 +9,6 @@ * option) any later version. */ - #ifndef __ASM_MACH_LOONGSON32_CPUFREQ_H #define __ASM_MACH_LOONGSON32_CPUFREQ_H diff --git a/arch/mips/include/asm/mach-loongson32/dma.h b/arch/mips/include/asm/mach-loongson32/dma.h new file mode 100644 index 0000000..ad1dec7 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson32/dma.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015 Zhang, Keguang <keguang.zhang@gmail.com> + * + * Loongson 1 NAND platform support. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ASM_MACH_LOONGSON32_DMA_H +#define __ASM_MACH_LOONGSON32_DMA_H + +#define LS1X_DMA_CHANNEL0 0 +#define LS1X_DMA_CHANNEL1 1 +#define LS1X_DMA_CHANNEL2 2 + +struct plat_ls1x_dma { + int nr_channels; +}; + +extern struct plat_ls1x_dma ls1b_dma_pdata; + +#endif /* __ASM_MACH_LOONGSON32_DMA_H */ diff --git a/arch/mips/include/asm/mach-loongson32/irq.h b/arch/mips/include/asm/mach-loongson32/irq.h index 0d35b99..c1c7441 100644 --- a/arch/mips/include/asm/mach-loongson32/irq.h +++ b/arch/mips/include/asm/mach-loongson32/irq.h @@ -9,7 +9,6 @@ * option) any later version. */ - #ifndef __ASM_MACH_LOONGSON32_IRQ_H #define __ASM_MACH_LOONGSON32_IRQ_H diff --git a/arch/mips/include/asm/mach-loongson32/loongson1.h b/arch/mips/include/asm/mach-loongson32/loongson1.h index 12aa129..978f6df 100644 --- a/arch/mips/include/asm/mach-loongson32/loongson1.h +++ b/arch/mips/include/asm/mach-loongson32/loongson1.h @@ -9,7 +9,6 @@ * option) any later version. */ - #ifndef __ASM_MACH_LOONGSON32_LOONGSON1_H #define __ASM_MACH_LOONGSON32_LOONGSON1_H @@ -18,6 +17,9 @@ /* Loongson 1 Register Bases */ #define LS1X_MUX_BASE 0x1fd00420 #define LS1X_INTC_BASE 0x1fd01040 +#define LS1X_GPIO0_BASE 0x1fd010c0 +#define LS1X_GPIO1_BASE 0x1fd010c4 +#define LS1X_DMAC_BASE 0x1fd01160 #define LS1X_EHCI_BASE 0x1fe00000 #define LS1X_OHCI_BASE 0x1fe08000 #define LS1X_GMAC0_BASE 0x1fe10000 diff --git a/arch/mips/include/asm/mach-loongson32/nand.h b/arch/mips/include/asm/mach-loongson32/nand.h new file mode 100644 index 0000000..e274912 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson32/nand.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015 Zhang, Keguang <keguang.zhang@gmail.com> + * + * Loongson 1 NAND platform support. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ASM_MACH_LOONGSON32_NAND_H +#define __ASM_MACH_LOONGSON32_NAND_H + +#include <linux/dmaengine.h> +#include <linux/mtd/partitions.h> + +struct plat_ls1x_nand { + struct mtd_partition *parts; + unsigned int nr_parts; + + int hold_cycle; + int wait_cycle; +}; + +extern struct plat_ls1x_nand ls1b_nand_pdata; + +bool ls1x_dma_filter_fn(struct dma_chan *chan, void *param); + +#endif /* __ASM_MACH_LOONGSON32_NAND_H */ diff --git a/arch/mips/include/asm/mach-loongson32/platform.h b/arch/mips/include/asm/mach-loongson32/platform.h index c32f03f..672531a 100644 --- a/arch/mips/include/asm/mach-loongson32/platform.h +++ b/arch/mips/include/asm/mach-loongson32/platform.h @@ -7,20 +7,28 @@ * option) any later version. */ - #ifndef __ASM_MACH_LOONGSON32_PLATFORM_H #define __ASM_MACH_LOONGSON32_PLATFORM_H #include <linux/platform_device.h> +#include <dma.h> +#include <nand.h> + extern struct platform_device ls1x_uart_pdev; extern struct platform_device ls1x_cpufreq_pdev; +extern struct platform_device ls1x_dma_pdev; extern struct platform_device ls1x_eth0_pdev; extern struct platform_device ls1x_eth1_pdev; extern struct platform_device ls1x_ehci_pdev; +extern struct platform_device ls1x_gpio0_pdev; +extern struct platform_device ls1x_gpio1_pdev; +extern struct platform_device ls1x_nand_pdev; extern struct platform_device ls1x_rtc_pdev; -extern void __init ls1x_clk_init(void); -extern void __init ls1x_serial_setup(struct platform_device *pdev); +void __init ls1x_clk_init(void); +void __init ls1x_dma_set_platdata(struct plat_ls1x_dma *pdata); +void __init ls1x_nand_set_platdata(struct plat_ls1x_nand *pdata); +void __init ls1x_serial_set_uartclk(struct platform_device *pdev); #endif /* __ASM_MACH_LOONGSON32_PLATFORM_H */ diff --git a/arch/mips/include/asm/mach-loongson32/regs-clk.h b/arch/mips/include/asm/mach-loongson32/regs-clk.h index 1f5a715..4d56fc3 100644 --- a/arch/mips/include/asm/mach-loongson32/regs-clk.h +++ b/arch/mips/include/asm/mach-loongson32/regs-clk.h @@ -19,18 +19,18 @@ #define LS1X_CLK_PLL_DIV LS1X_CLK_REG(0x4) /* Clock PLL Divisor Register Bits */ -#define DIV_DC_EN (0x1 << 31) -#define DIV_DC_RST (0x1 << 30) -#define DIV_CPU_EN (0x1 << 25) -#define DIV_CPU_RST (0x1 << 24) -#define DIV_DDR_EN (0x1 << 19) -#define DIV_DDR_RST (0x1 << 18) -#define RST_DC_EN (0x1 << 5) -#define RST_DC (0x1 << 4) -#define RST_DDR_EN (0x1 << 3) -#define RST_DDR (0x1 << 2) -#define RST_CPU_EN (0x1 << 1) -#define RST_CPU 0x1 +#define DIV_DC_EN BIT(31) +#define DIV_DC_RST BIT(30) +#define DIV_CPU_EN BIT(25) +#define DIV_CPU_RST BIT(24) +#define DIV_DDR_EN BIT(19) +#define DIV_DDR_RST BIT(18) +#define RST_DC_EN BIT(5) +#define RST_DC BIT(4) +#define RST_DDR_EN BIT(3) +#define RST_DDR BIT(2) +#define RST_CPU_EN BIT(1) +#define RST_CPU BIT(0) #define DIV_DC_SHIFT 26 #define DIV_CPU_SHIFT 20 diff --git a/arch/mips/include/asm/mach-loongson32/regs-mux.h b/arch/mips/include/asm/mach-loongson32/regs-mux.h index 8302d92..7c394f9 100644 --- a/arch/mips/include/asm/mach-loongson32/regs-mux.h +++ b/arch/mips/include/asm/mach-loongson32/regs-mux.h @@ -19,49 +19,49 @@ #define LS1X_MUX_CTRL1 LS1X_MUX_REG(0x4) /* MUX CTRL0 Register Bits */ -#define UART0_USE_PWM23 (0x1 << 28) -#define UART0_USE_PWM01 (0x1 << 27) -#define UART1_USE_LCD0_5_6_11 (0x1 << 26) -#define I2C2_USE_CAN1 (0x1 << 25) -#define I2C1_USE_CAN0 (0x1 << 24) -#define NAND3_USE_UART5 (0x1 << 23) -#define NAND3_USE_UART4 (0x1 << 22) -#define NAND3_USE_UART1_DAT (0x1 << 21) -#define NAND3_USE_UART1_CTS (0x1 << 20) -#define NAND3_USE_PWM23 (0x1 << 19) -#define NAND3_USE_PWM01 (0x1 << 18) -#define NAND2_USE_UART5 (0x1 << 17) -#define NAND2_USE_UART4 (0x1 << 16) -#define NAND2_USE_UART1_DAT (0x1 << 15) -#define NAND2_USE_UART1_CTS (0x1 << 14) -#define NAND2_USE_PWM23 (0x1 << 13) -#define NAND2_USE_PWM01 (0x1 << 12) -#define NAND1_USE_UART5 (0x1 << 11) -#define NAND1_USE_UART4 (0x1 << 10) -#define NAND1_USE_UART1_DAT (0x1 << 9) -#define NAND1_USE_UART1_CTS (0x1 << 8) -#define NAND1_USE_PWM23 (0x1 << 7) -#define NAND1_USE_PWM01 (0x1 << 6) -#define GMAC1_USE_UART1 (0x1 << 4) -#define GMAC1_USE_UART0 (0x1 << 3) -#define LCD_USE_UART0_DAT (0x1 << 2) -#define LCD_USE_UART15 (0x1 << 1) -#define LCD_USE_UART0 0x1 +#define UART0_USE_PWM23 BIT(28) +#define UART0_USE_PWM01 BIT(27) +#define UART1_USE_LCD0_5_6_11 BIT(26) +#define I2C2_USE_CAN1 BIT(25) +#define I2C1_USE_CAN0 BIT(24) +#define NAND3_USE_UART5 BIT(23) +#define NAND3_USE_UART4 BIT(22) +#define NAND3_USE_UART1_DAT BIT(21) +#define NAND3_USE_UART1_CTS BIT(20) +#define NAND3_USE_PWM23 BIT(19) +#define NAND3_USE_PWM01 BIT(18) +#define NAND2_USE_UART5 BIT(17) +#define NAND2_USE_UART4 BIT(16) +#define NAND2_USE_UART1_DAT BIT(15) +#define NAND2_USE_UART1_CTS BIT(14) +#define NAND2_USE_PWM23 BIT(13) +#define NAND2_USE_PWM01 BIT(12) +#define NAND1_USE_UART5 BIT(11) +#define NAND1_USE_UART4 BIT(10) +#define NAND1_USE_UART1_DAT BIT(9) +#define NAND1_USE_UART1_CTS BIT(8) +#define NAND1_USE_PWM23 BIT(7) +#define NAND1_USE_PWM01 BIT(6) +#define GMAC1_USE_UART1 BIT(4) +#define GMAC1_USE_UART0 BIT(3) +#define LCD_USE_UART0_DAT BIT(2) +#define LCD_USE_UART15 BIT(1) +#define LCD_USE_UART0 BIT(0) /* MUX CTRL1 Register Bits */ -#define USB_RESET (0x1 << 31) -#define SPI1_CS_USE_PWM01 (0x1 << 24) -#define SPI1_USE_CAN (0x1 << 23) -#define DISABLE_DDR_CONFSPACE (0x1 << 20) -#define DDR32TO16EN (0x1 << 16) -#define GMAC1_SHUT (0x1 << 13) -#define GMAC0_SHUT (0x1 << 12) -#define USB_SHUT (0x1 << 11) -#define UART1_3_USE_CAN1 (0x1 << 5) -#define UART1_2_USE_CAN0 (0x1 << 4) -#define GMAC1_USE_TXCLK (0x1 << 3) -#define GMAC0_USE_TXCLK (0x1 << 2) -#define GMAC1_USE_PWM23 (0x1 << 1) -#define GMAC0_USE_PWM01 0x1 +#define USB_RESET BIT(31) +#define SPI1_CS_USE_PWM01 BIT(24) +#define SPI1_USE_CAN BIT(23) +#define DISABLE_DDR_CONFSPACE BIT(20) +#define DDR32TO16EN BIT(16) +#define GMAC1_SHUT BIT(13) +#define GMAC0_SHUT BIT(12) +#define USB_SHUT BIT(11) +#define UART1_3_USE_CAN1 BIT(5) +#define UART1_2_USE_CAN0 BIT(4) +#define GMAC1_USE_TXCLK BIT(3) +#define GMAC0_USE_TXCLK BIT(2) +#define GMAC1_USE_PWM23 BIT(1) +#define GMAC0_USE_PWM01 BIT(0) #endif /* __ASM_MACH_LOONGSON32_REGS_MUX_H */ diff --git a/arch/mips/include/asm/mach-loongson32/regs-pwm.h b/arch/mips/include/asm/mach-loongson32/regs-pwm.h index 69f174e..4119600 100644 --- a/arch/mips/include/asm/mach-loongson32/regs-pwm.h +++ b/arch/mips/include/asm/mach-loongson32/regs-pwm.h @@ -19,11 +19,11 @@ #define PWM_CTRL 0xc /* PWM Control Register Bits */ -#define CNT_RST (0x1 << 7) -#define INT_SR (0x1 << 6) -#define INT_EN (0x1 << 5) -#define PWM_SINGLE (0x1 << 4) -#define PWM_OE (0x1 << 3) -#define CNT_EN 0x1 +#define CNT_RST BIT(7) +#define INT_SR BIT(6) +#define INT_EN BIT(5) +#define PWM_SINGLE BIT(4) +#define PWM_OE BIT(3) +#define CNT_EN BIT(0) #endif /* __ASM_MACH_LOONGSON32_REGS_PWM_H */ diff --git a/arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h b/arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h index 98963c2..89328a3d 100644 --- a/arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h @@ -16,11 +16,6 @@ #ifndef __ASM_MACH_LOONGSON64_CPU_FEATURE_OVERRIDES_H #define __ASM_MACH_LOONGSON64_CPU_FEATURE_OVERRIDES_H -#define cpu_dcache_line_size() 32 -#define cpu_icache_line_size() 32 -#define cpu_scache_line_size() 32 - - #define cpu_has_32fpr 1 #define cpu_has_3k_cache 0 #define cpu_has_4k_cache 1 @@ -31,24 +26,17 @@ #define cpu_has_counter 1 #define cpu_has_dc_aliases (PAGE_SIZE < 0x4000) #define cpu_has_divec 0 -#define cpu_has_dsp 0 -#define cpu_has_dsp2 0 #define cpu_has_ejtag 0 -#define cpu_has_ic_fills_f_dc 0 #define cpu_has_inclusive_pcaches 1 #define cpu_has_llsc 1 #define cpu_has_mcheck 0 #define cpu_has_mdmx 0 #define cpu_has_mips16 0 -#define cpu_has_mips32r2 0 #define cpu_has_mips3d 0 -#define cpu_has_mips64r2 0 #define cpu_has_mipsmt 0 -#define cpu_has_prefetch 0 #define cpu_has_smartmips 0 #define cpu_has_tlb 1 #define cpu_has_tx39_cache 0 -#define cpu_has_userlocal 0 #define cpu_has_vce 0 #define cpu_has_veic 0 #define cpu_has_vint 0 @@ -56,6 +44,10 @@ #define cpu_has_watch 1 #define cpu_has_local_ebase 0 -#define cpu_has_wsbh IS_ENABLED(CONFIG_CPU_LOONGSON3) +#ifdef CONFIG_CPU_LOONGSON3 +#define cpu_has_wsbh 1 +#define cpu_has_ic_fills_f_dc 1 +#define cpu_hwrena_impl_bits 0xc0000000 +#endif #endif /* __ASM_MACH_LOONGSON64_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h b/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h index 3f2f84f..8393bc54 100644 --- a/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h @@ -23,8 +23,15 @@ or t0, (0x1 << 7) mtc0 t0, $16, 3 /* Set ELPA on LOONGSON3 pagegrain */ - li t0, (0x1 << 29) + mfc0 t0, $5, 1 + or t0, (0x1 << 29) mtc0 t0, $5, 1 +#ifdef CONFIG_LOONGSON3_ENHANCEMENT + /* Enable STFill Buffer */ + mfc0 t0, $16, 6 + or t0, 0x100 + mtc0 t0, $16, 6 +#endif _ehb .set pop #endif @@ -42,8 +49,15 @@ or t0, (0x1 << 7) mtc0 t0, $16, 3 /* Set ELPA on LOONGSON3 pagegrain */ - li t0, (0x1 << 29) + mfc0 t0, $5, 1 + or t0, (0x1 << 29) mtc0 t0, $5, 1 +#ifdef CONFIG_LOONGSON3_ENHANCEMENT + /* Enable STFill Buffer */ + mfc0 t0, $16, 6 + or t0, 0x100 + mtc0 t0, $16, 6 +#endif _ehb .set pop #endif diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h index 455d406..a73350b 100644 --- a/arch/mips/include/asm/mach-ralink/mt7620.h +++ b/arch/mips/include/asm/mach-ralink/mt7620.h @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #ifndef _MT7620_REGS_H_ @@ -72,6 +72,7 @@ #define SYSCFG0_DRAM_TYPE_SDRAM 0 #define SYSCFG0_DRAM_TYPE_DDR1 1 #define SYSCFG0_DRAM_TYPE_DDR2 2 +#define SYSCFG0_DRAM_TYPE_UNKNOWN 3 #define SYSCFG0_DRAM_TYPE_DDR2_MT7628 0 #define SYSCFG0_DRAM_TYPE_DDR1_MT7628 1 diff --git a/arch/mips/include/asm/mach-ralink/mt7621.h b/arch/mips/include/asm/mach-ralink/mt7621.h index 610b61e..a672e06 100644 --- a/arch/mips/include/asm/mach-ralink/mt7621.h +++ b/arch/mips/include/asm/mach-ralink/mt7621.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2015 John Crispin <john@phrozen.org> */ #ifndef _MT7621_REGS_H_ diff --git a/arch/mips/include/asm/mach-ralink/pinmux.h b/arch/mips/include/asm/mach-ralink/pinmux.h index be106cb..ba8ac33 100644 --- a/arch/mips/include/asm/mach-ralink/pinmux.h +++ b/arch/mips/include/asm/mach-ralink/pinmux.h @@ -3,7 +3,7 @@ * it under the terms of the GNU General Public License version 2 as * publishhed by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #ifndef _RT288X_PINMUX_H__ diff --git a/arch/mips/include/asm/mach-ralink/ralink_regs.h b/arch/mips/include/asm/mach-ralink/ralink_regs.h index 4c9fba6..9df1a53 100644 --- a/arch/mips/include/asm/mach-ralink/ralink_regs.h +++ b/arch/mips/include/asm/mach-ralink/ralink_regs.h @@ -1,7 +1,7 @@ /* * Ralink SoC register definitions * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * diff --git a/arch/mips/include/asm/mach-ralink/rt288x.h b/arch/mips/include/asm/mach-ralink/rt288x.h index 03ad716..25ae104 100644 --- a/arch/mips/include/asm/mach-ralink/rt288x.h +++ b/arch/mips/include/asm/mach-ralink/rt288x.h @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #ifndef _RT288X_REGS_H_ diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h index 2eea793..ac2d65c 100644 --- a/arch/mips/include/asm/mach-ralink/rt305x.h +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #ifndef _RT305X_REGS_H_ diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index d463539..9411a4c 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -208,6 +208,7 @@ BUILD_CM_RW(l2_config, MIPS_CM_GCB_OFS + 0x130) BUILD_CM_RW(sys_config2, MIPS_CM_GCB_OFS + 0x150) BUILD_CM_RW(l2_pft_control, MIPS_CM_GCB_OFS + 0x300) BUILD_CM_RW(l2_pft_control_b, MIPS_CM_GCB_OFS + 0x308) +BUILD_CM_RW(bev_base, MIPS_CM_GCB_OFS + 0x680) /* Core Local & Core Other register accessor functions */ BUILD_CM_Cx_RW(reset_release, 0x00) @@ -290,8 +291,8 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_GCR_GIC_BASE_GICEN_MSK (_ULCAST_(0x1) << 0) /* GCR_CPC_BASE register fields */ -#define CM_GCR_CPC_BASE_CPCBASE_SHF 17 -#define CM_GCR_CPC_BASE_CPCBASE_MSK (_ULCAST_(0x7fff) << 17) +#define CM_GCR_CPC_BASE_CPCBASE_SHF 15 +#define CM_GCR_CPC_BASE_CPCBASE_MSK (_ULCAST_(0x1ffff) << 15) #define CM_GCR_CPC_BASE_CPCEN_SHF 0 #define CM_GCR_CPC_BASE_CPCEN_MSK (_ULCAST_(0x1) << 0) @@ -461,7 +462,10 @@ static inline unsigned int mips_cm_max_vp_width(void) if (mips_cm_revision() >= CM_REV_CM3) return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW_MSK; - return smp_num_siblings; + if (config_enabled(CONFIG_SMP)) + return smp_num_siblings; + + return 1; } /** @@ -505,7 +509,7 @@ extern void mips_cm_unlock_other(void); #else /* !CONFIG_MIPS_CM */ -static inline void mips_cm_lock_other(unsigned int core) { } +static inline void mips_cm_lock_other(unsigned int core, unsigned int vp) { } static inline void mips_cm_unlock_other(void) { } #endif /* !CONFIG_MIPS_CM */ diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h index e090352..8c519f9 100644 --- a/arch/mips/include/asm/mips-cpc.h +++ b/arch/mips/include/asm/mips-cpc.h @@ -106,6 +106,9 @@ BUILD_CPC_R_(revision, MIPS_CPC_GCB_OFS + 0x20) BUILD_CPC_Cx_RW(cmd, 0x00) BUILD_CPC_Cx_RW(stat_conf, 0x08) BUILD_CPC_Cx_RW(other, 0x10) +BUILD_CPC_Cx_RW(vp_stop, 0x20) +BUILD_CPC_Cx_RW(vp_run, 0x28) +BUILD_CPC_Cx_RW(vp_running, 0x30) /* CPC_Cx_CMD register fields */ #define CPC_Cx_CMD_SHF 0 diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 3ad19ad..25d0157 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -55,8 +55,14 @@ #define CP0_BADINSTR $8, 1 #define CP0_COUNT $9 #define CP0_ENTRYHI $10 +#define CP0_GUESTCTL1 $10, 4 +#define CP0_GUESTCTL2 $10, 5 +#define CP0_GUESTCTL3 $10, 6 #define CP0_COMPARE $11 +#define CP0_GUESTCTL0EXT $11, 4 #define CP0_STATUS $12 +#define CP0_GUESTCTL0 $12, 6 +#define CP0_GTOFFSET $12, 7 #define CP0_CAUSE $13 #define CP0_EPC $14 #define CP0_PRID $15 @@ -229,6 +235,8 @@ /* MIPS32/64 EntryHI bit definitions */ #define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) +#define MIPS_ENTRYHI_ASIDX (_ULCAST_(0x3) << 8) +#define MIPS_ENTRYHI_ASID (_ULCAST_(0xff) << 0) /* * R4x00 interrupt enable / cause bits @@ -390,6 +398,8 @@ #define CAUSEF_IP7 (_ULCAST_(1) << 15) #define CAUSEB_FDCI 21 #define CAUSEF_FDCI (_ULCAST_(1) << 21) +#define CAUSEB_WP 22 +#define CAUSEF_WP (_ULCAST_(1) << 22) #define CAUSEB_IV 23 #define CAUSEF_IV (_ULCAST_(1) << 23) #define CAUSEB_PCI 26 @@ -611,7 +621,8 @@ #define MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT (_ULCAST_(1) << 14) #define MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT (_ULCAST_(2) << 14) #define MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT (_ULCAST_(3) << 14) -#define MIPS_CONF4_KSCREXIST (_ULCAST_(255) << 16) +#define MIPS_CONF4_KSCREXIST_SHIFT (16) +#define MIPS_CONF4_KSCREXIST (_ULCAST_(255) << MIPS_CONF4_KSCREXIST_SHIFT) #define MIPS_CONF4_VTLBSIZEEXT_SHIFT (24) #define MIPS_CONF4_VTLBSIZEEXT (_ULCAST_(15) << MIPS_CONF4_VTLBSIZEEXT_SHIFT) #define MIPS_CONF4_AE (_ULCAST_(1) << 28) @@ -623,6 +634,7 @@ #define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5) +#define MIPS_CONF5_VP (_ULCAST_(1) << 7) #define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_MSAEN (_ULCAST_(1) << 27) @@ -633,6 +645,8 @@ #define MIPS_CONF6_SYND (_ULCAST_(1) << 13) /* proAptiv FTLB on/off bit */ #define MIPS_CONF6_FTLBEN (_ULCAST_(1) << 15) +/* Loongson-3 FTLB on/off bit */ +#define MIPS_CONF6_FTLBDIS (_ULCAST_(1) << 22) /* FTLB probability bits */ #define MIPS_CONF6_FTLBP_SHIFT (16) @@ -645,12 +659,38 @@ /* FTLB probability bits for R6 */ #define MIPS_CONF7_FTLBP_SHIFT (18) +/* WatchLo* register definitions */ +#define MIPS_WATCHLO_IRW (_ULCAST_(0x7) << 0) + +/* WatchHi* register definitions */ +#define MIPS_WATCHHI_M (_ULCAST_(1) << 31) +#define MIPS_WATCHHI_G (_ULCAST_(1) << 30) +#define MIPS_WATCHHI_WM (_ULCAST_(0x3) << 28) +#define MIPS_WATCHHI_WM_R_RVA (_ULCAST_(0) << 28) +#define MIPS_WATCHHI_WM_R_GPA (_ULCAST_(1) << 28) +#define MIPS_WATCHHI_WM_G_GVA (_ULCAST_(2) << 28) +#define MIPS_WATCHHI_EAS (_ULCAST_(0x3) << 24) +#define MIPS_WATCHHI_ASID (_ULCAST_(0xff) << 16) +#define MIPS_WATCHHI_MASK (_ULCAST_(0x1ff) << 3) +#define MIPS_WATCHHI_I (_ULCAST_(1) << 2) +#define MIPS_WATCHHI_R (_ULCAST_(1) << 1) +#define MIPS_WATCHHI_W (_ULCAST_(1) << 0) +#define MIPS_WATCHHI_IRW (_ULCAST_(0x7) << 0) + /* MAAR bit definitions */ #define MIPS_MAAR_ADDR ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12) #define MIPS_MAAR_ADDR_SHIFT 12 #define MIPS_MAAR_S (_ULCAST_(1) << 1) #define MIPS_MAAR_V (_ULCAST_(1) << 0) +/* EBase bit definitions */ +#define MIPS_EBASE_CPUNUM_SHIFT 0 +#define MIPS_EBASE_CPUNUM (_ULCAST_(0x3ff) << 0) +#define MIPS_EBASE_WG_SHIFT 11 +#define MIPS_EBASE_WG (_ULCAST_(1) << 11) +#define MIPS_EBASE_BASE_SHIFT 12 +#define MIPS_EBASE_BASE (~_ULCAST_((1 << MIPS_EBASE_BASE_SHIFT) - 1)) + /* CMGCRBase bit definitions */ #define MIPS_CMGCRB_BASE 11 #define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1)) @@ -706,6 +746,94 @@ #define MIPS_PWCTL_PSN_SHIFT 0 #define MIPS_PWCTL_PSN_MASK 0x0000003f +/* GuestCtl0 fields */ +#define MIPS_GCTL0_GM_SHIFT 31 +#define MIPS_GCTL0_GM (_ULCAST_(1) << MIPS_GCTL0_GM_SHIFT) +#define MIPS_GCTL0_RI_SHIFT 30 +#define MIPS_GCTL0_RI (_ULCAST_(1) << MIPS_GCTL0_RI_SHIFT) +#define MIPS_GCTL0_MC_SHIFT 29 +#define MIPS_GCTL0_MC (_ULCAST_(1) << MIPS_GCTL0_MC_SHIFT) +#define MIPS_GCTL0_CP0_SHIFT 28 +#define MIPS_GCTL0_CP0 (_ULCAST_(1) << MIPS_GCTL0_CP0_SHIFT) +#define MIPS_GCTL0_AT_SHIFT 26 +#define MIPS_GCTL0_AT (_ULCAST_(0x3) << MIPS_GCTL0_AT_SHIFT) +#define MIPS_GCTL0_GT_SHIFT 25 +#define MIPS_GCTL0_GT (_ULCAST_(1) << MIPS_GCTL0_GT_SHIFT) +#define MIPS_GCTL0_CG_SHIFT 24 +#define MIPS_GCTL0_CG (_ULCAST_(1) << MIPS_GCTL0_CG_SHIFT) +#define MIPS_GCTL0_CF_SHIFT 23 +#define MIPS_GCTL0_CF (_ULCAST_(1) << MIPS_GCTL0_CF_SHIFT) +#define MIPS_GCTL0_G1_SHIFT 22 +#define MIPS_GCTL0_G1 (_ULCAST_(1) << MIPS_GCTL0_G1_SHIFT) +#define MIPS_GCTL0_G0E_SHIFT 19 +#define MIPS_GCTL0_G0E (_ULCAST_(1) << MIPS_GCTL0_G0E_SHIFT) +#define MIPS_GCTL0_PT_SHIFT 18 +#define MIPS_GCTL0_PT (_ULCAST_(1) << MIPS_GCTL0_PT_SHIFT) +#define MIPS_GCTL0_RAD_SHIFT 9 +#define MIPS_GCTL0_RAD (_ULCAST_(1) << MIPS_GCTL0_RAD_SHIFT) +#define MIPS_GCTL0_DRG_SHIFT 8 +#define MIPS_GCTL0_DRG (_ULCAST_(1) << MIPS_GCTL0_DRG_SHIFT) +#define MIPS_GCTL0_G2_SHIFT 7 +#define MIPS_GCTL0_G2 (_ULCAST_(1) << MIPS_GCTL0_G2_SHIFT) +#define MIPS_GCTL0_GEXC_SHIFT 2 +#define MIPS_GCTL0_GEXC (_ULCAST_(0x1f) << MIPS_GCTL0_GEXC_SHIFT) +#define MIPS_GCTL0_SFC2_SHIFT 1 +#define MIPS_GCTL0_SFC2 (_ULCAST_(1) << MIPS_GCTL0_SFC2_SHIFT) +#define MIPS_GCTL0_SFC1_SHIFT 0 +#define MIPS_GCTL0_SFC1 (_ULCAST_(1) << MIPS_GCTL0_SFC1_SHIFT) + +/* GuestCtl0.AT Guest address translation control */ +#define MIPS_GCTL0_AT_ROOT 1 /* Guest MMU under Root control */ +#define MIPS_GCTL0_AT_GUEST 3 /* Guest MMU under Guest control */ + +/* GuestCtl0.GExcCode Hypervisor exception cause codes */ +#define MIPS_GCTL0_GEXC_GPSI 0 /* Guest Privileged Sensitive Instruction */ +#define MIPS_GCTL0_GEXC_GSFC 1 /* Guest Software Field Change */ +#define MIPS_GCTL0_GEXC_HC 2 /* Hypercall */ +#define MIPS_GCTL0_GEXC_GRR 3 /* Guest Reserved Instruction Redirect */ +#define MIPS_GCTL0_GEXC_GVA 8 /* Guest Virtual Address available */ +#define MIPS_GCTL0_GEXC_GHFC 9 /* Guest Hardware Field Change */ +#define MIPS_GCTL0_GEXC_GPA 10 /* Guest Physical Address available */ + +/* GuestCtl0Ext fields */ +#define MIPS_GCTL0EXT_RPW_SHIFT 8 +#define MIPS_GCTL0EXT_RPW (_ULCAST_(0x3) << MIPS_GCTL0EXT_RPW_SHIFT) +#define MIPS_GCTL0EXT_NCC_SHIFT 6 +#define MIPS_GCTL0EXT_NCC (_ULCAST_(0x3) << MIPS_GCTL0EXT_NCC_SHIFT) +#define MIPS_GCTL0EXT_CGI_SHIFT 4 +#define MIPS_GCTL0EXT_CGI (_ULCAST_(1) << MIPS_GCTL0EXT_CGI_SHIFT) +#define MIPS_GCTL0EXT_FCD_SHIFT 3 +#define MIPS_GCTL0EXT_FCD (_ULCAST_(1) << MIPS_GCTL0EXT_FCD_SHIFT) +#define MIPS_GCTL0EXT_OG_SHIFT 2 +#define MIPS_GCTL0EXT_OG (_ULCAST_(1) << MIPS_GCTL0EXT_OG_SHIFT) +#define MIPS_GCTL0EXT_BG_SHIFT 1 +#define MIPS_GCTL0EXT_BG (_ULCAST_(1) << MIPS_GCTL0EXT_BG_SHIFT) +#define MIPS_GCTL0EXT_MG_SHIFT 0 +#define MIPS_GCTL0EXT_MG (_ULCAST_(1) << MIPS_GCTL0EXT_MG_SHIFT) + +/* GuestCtl0Ext.RPW Root page walk configuration */ +#define MIPS_GCTL0EXT_RPW_BOTH 0 /* Root PW for GPA->RPA and RVA->RPA */ +#define MIPS_GCTL0EXT_RPW_GPA 2 /* Root PW for GPA->RPA */ +#define MIPS_GCTL0EXT_RPW_RVA 3 /* Root PW for RVA->RPA */ + +/* GuestCtl0Ext.NCC Nested cache coherency attributes */ +#define MIPS_GCTL0EXT_NCC_IND 0 /* Guest CCA independent of Root CCA */ +#define MIPS_GCTL0EXT_NCC_MOD 1 /* Guest CCA modified by Root CCA */ + +/* GuestCtl1 fields */ +#define MIPS_GCTL1_ID_SHIFT 0 +#define MIPS_GCTL1_ID_WIDTH 8 +#define MIPS_GCTL1_ID (_ULCAST_(0xff) << MIPS_GCTL1_ID_SHIFT) +#define MIPS_GCTL1_RID_SHIFT 16 +#define MIPS_GCTL1_RID_WIDTH 8 +#define MIPS_GCTL1_RID (_ULCAST_(0xff) << MIPS_GCTL1_RID_SHIFT) +#define MIPS_GCTL1_EID_SHIFT 24 +#define MIPS_GCTL1_EID_WIDTH 8 +#define MIPS_GCTL1_EID (_ULCAST_(0xff) << MIPS_GCTL1_EID_SHIFT) + +/* GuestID reserved for root context */ +#define MIPS_GCTL1_ROOT_GUESTID 0 + /* CDMMBase register bit definitions */ #define MIPS_CDMMBASE_SIZE_SHIFT 0 #define MIPS_CDMMBASE_SIZE (_ULCAST_(511) << MIPS_CDMMBASE_SIZE_SHIFT) @@ -757,6 +885,15 @@ /* Disable Branch Return Cache */ #define R10K_DIAG_D_BRC (_ULCAST_(1) << 22) +/* Flush ITLB */ +#define LOONGSON_DIAG_ITLB (_ULCAST_(1) << 2) +/* Flush DTLB */ +#define LOONGSON_DIAG_DTLB (_ULCAST_(1) << 3) +/* Flush VTLB */ +#define LOONGSON_DIAG_VTLB (_ULCAST_(1) << 12) +/* Flush FTLB */ +#define LOONGSON_DIAG_FTLB (_ULCAST_(1) << 13) + /* * Coprocessor 1 (FPU) register names */ @@ -1186,9 +1323,15 @@ do { \ #define read_c0_context() __read_ulong_c0_register($4, 0) #define write_c0_context(val) __write_ulong_c0_register($4, 0, val) +#define read_c0_contextconfig() __read_32bit_c0_register($4, 1) +#define write_c0_contextconfig(val) __write_32bit_c0_register($4, 1, val) + #define read_c0_userlocal() __read_ulong_c0_register($4, 2) #define write_c0_userlocal(val) __write_ulong_c0_register($4, 2, val) +#define read_c0_xcontextconfig() __read_ulong_c0_register($4, 3) +#define write_c0_xcontextconfig(val) __write_ulong_c0_register($4, 3, val) + #define read_c0_pagemask() __read_32bit_c0_register($5, 0) #define write_c0_pagemask(val) __write_32bit_c0_register($5, 0, val) @@ -1206,6 +1349,9 @@ do { \ #define read_c0_badvaddr() __read_ulong_c0_register($8, 0) #define write_c0_badvaddr(val) __write_ulong_c0_register($8, 0, val) +#define read_c0_badinstr() __read_32bit_c0_register($8, 1) +#define read_c0_badinstrp() __read_32bit_c0_register($8, 2) + #define read_c0_count() __read_32bit_c0_register($9, 0) #define write_c0_count(val) __write_32bit_c0_register($9, 0, val) @@ -1218,9 +1364,21 @@ do { \ #define read_c0_entryhi() __read_ulong_c0_register($10, 0) #define write_c0_entryhi(val) __write_ulong_c0_register($10, 0, val) +#define read_c0_guestctl1() __read_32bit_c0_register($10, 4) +#define write_c0_guestctl1(val) __write_32bit_c0_register($10, 4, val) + +#define read_c0_guestctl2() __read_32bit_c0_register($10, 5) +#define write_c0_guestctl2(val) __write_32bit_c0_register($10, 5, val) + +#define read_c0_guestctl3() __read_32bit_c0_register($10, 6) +#define write_c0_guestctl3(val) __write_32bit_c0_register($10, 6, val) + #define read_c0_compare() __read_32bit_c0_register($11, 0) #define write_c0_compare(val) __write_32bit_c0_register($11, 0, val) +#define read_c0_guestctl0ext() __read_32bit_c0_register($11, 4) +#define write_c0_guestctl0ext(val) __write_32bit_c0_register($11, 4, val) + #define read_c0_compare2() __read_32bit_c0_register($11, 6) /* pnx8550 */ #define write_c0_compare2(val) __write_32bit_c0_register($11, 6, val) @@ -1231,6 +1389,12 @@ do { \ #define write_c0_status(val) __write_32bit_c0_register($12, 0, val) +#define read_c0_guestctl0() __read_32bit_c0_register($12, 6) +#define write_c0_guestctl0(val) __write_32bit_c0_register($12, 6, val) + +#define read_c0_gtoffset() __read_32bit_c0_register($12, 7) +#define write_c0_gtoffset(val) __write_32bit_c0_register($12, 7, val) + #define read_c0_cause() __read_32bit_c0_register($13, 0) #define write_c0_cause(val) __write_32bit_c0_register($13, 0, val) @@ -1416,6 +1580,9 @@ do { \ #define read_c0_ebase() __read_32bit_c0_register($15, 1) #define write_c0_ebase(val) __write_32bit_c0_register($15, 1, val) +#define read_c0_ebase_64() __read_64bit_c0_register($15, 1) +#define write_c0_ebase_64(val) __write_64bit_c0_register($15, 1, val) + #define read_c0_cdmmbase() __read_ulong_c0_register($15, 2) #define write_c0_cdmmbase(val) __write_ulong_c0_register($15, 2, val) @@ -1442,6 +1609,12 @@ do { \ #define read_c0_pwctl() __read_32bit_c0_register($6, 6) #define write_c0_pwctl(val) __write_32bit_c0_register($6, 6, val) +#define read_c0_pgd() __read_64bit_c0_register($9, 7) +#define write_c0_pgd(val) __write_64bit_c0_register($9, 7, val) + +#define read_c0_kpgd() __read_64bit_c0_register($31, 7) +#define write_c0_kpgd(val) __write_64bit_c0_register($31, 7, val) + /* Cavium OCTEON (cnMIPS) */ #define read_c0_cvmcount() __read_ulong_c0_register($9, 6) #define write_c0_cvmcount(val) __write_ulong_c0_register($9, 6, val) @@ -1507,6 +1680,317 @@ do { \ #define write_c0_brcm_sleepcount(val) __write_32bit_c0_register($22, 7, val) /* + * Macros to access the guest system control coprocessor + */ + +#ifdef TOOLCHAIN_SUPPORTS_VIRT + +#define __read_32bit_gc0_register(source, sel) \ +({ int __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips32r2\n\t" \ + ".set\tvirt\n\t" \ + "mfgc0\t%0, $%1, %2\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (source), "i" (sel)); \ + __res; \ +}) + +#define __read_64bit_gc0_register(source, sel) \ +({ unsigned long long __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips64r2\n\t" \ + ".set\tvirt\n\t" \ + "dmfgc0\t%0, $%1, %2\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (source), "i" (sel)); \ + __res; \ +}) + +#define __write_32bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips32r2\n\t" \ + ".set\tvirt\n\t" \ + "mtgc0\t%z0, $%1, %2\n\t" \ + ".set\tpop" \ + : : "Jr" ((unsigned int)(value)), \ + "i" (register), "i" (sel)); \ +} while (0) + +#define __write_64bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips64r2\n\t" \ + ".set\tvirt\n\t" \ + "dmtgc0\t%z0, $%1, %2\n\t" \ + ".set\tpop" \ + : : "Jr" (value), \ + "i" (register), "i" (sel)); \ +} while (0) + +#else /* TOOLCHAIN_SUPPORTS_VIRT */ + +#define __read_32bit_gc0_register(source, sel) \ +({ int __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tnoat\n\t" \ + "# mfgc0\t$1, $%1, %2\n\t" \ + ".word\t(0x40610000 | %1 << 11 | %2)\n\t" \ + "move\t%0, $1\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (source), "i" (sel)); \ + __res; \ +}) + +#define __read_64bit_gc0_register(source, sel) \ +({ unsigned long long __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tnoat\n\t" \ + "# dmfgc0\t$1, $%1, %2\n\t" \ + ".word\t(0x40610100 | %1 << 11 | %2)\n\t" \ + "move\t%0, $1\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (source), "i" (sel)); \ + __res; \ +}) + +#define __write_32bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tnoat\n\t" \ + "move\t$1, %0\n\t" \ + "# mtgc0\t$1, $%1, %2\n\t" \ + ".word\t(0x40610200 | %1 << 11 | %2)\n\t" \ + ".set\tpop" \ + : : "Jr" ((unsigned int)(value)), \ + "i" (register), "i" (sel)); \ +} while (0) + +#define __write_64bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tnoat\n\t" \ + "move\t$1, %0\n\t" \ + "# dmtgc0\t$1, $%1, %2\n\t" \ + ".word\t(0x40610300 | %1 << 11 | %2)\n\t" \ + ".set\tpop" \ + : : "Jr" (value), \ + "i" (register), "i" (sel)); \ +} while (0) + +#endif /* !TOOLCHAIN_SUPPORTS_VIRT */ + +#define __read_ulong_gc0_register(reg, sel) \ + ((sizeof(unsigned long) == 4) ? \ + (unsigned long) __read_32bit_gc0_register(reg, sel) : \ + (unsigned long) __read_64bit_gc0_register(reg, sel)) + +#define __write_ulong_gc0_register(reg, sel, val) \ +do { \ + if (sizeof(unsigned long) == 4) \ + __write_32bit_gc0_register(reg, sel, val); \ + else \ + __write_64bit_gc0_register(reg, sel, val); \ +} while (0) + +#define read_gc0_index() __read_32bit_gc0_register(0, 0) +#define write_gc0_index(val) __write_32bit_gc0_register(0, 0, val) + +#define read_gc0_entrylo0() __read_ulong_gc0_register(2, 0) +#define write_gc0_entrylo0(val) __write_ulong_gc0_register(2, 0, val) + +#define read_gc0_entrylo1() __read_ulong_gc0_register(3, 0) +#define write_gc0_entrylo1(val) __write_ulong_gc0_register(3, 0, val) + +#define read_gc0_context() __read_ulong_gc0_register(4, 0) +#define write_gc0_context(val) __write_ulong_gc0_register(4, 0, val) + +#define read_gc0_contextconfig() __read_32bit_gc0_register(4, 1) +#define write_gc0_contextconfig(val) __write_32bit_gc0_register(4, 1, val) + +#define read_gc0_userlocal() __read_ulong_gc0_register(4, 2) +#define write_gc0_userlocal(val) __write_ulong_gc0_register(4, 2, val) + +#define read_gc0_xcontextconfig() __read_ulong_gc0_register(4, 3) +#define write_gc0_xcontextconfig(val) __write_ulong_gc0_register(4, 3, val) + +#define read_gc0_pagemask() __read_32bit_gc0_register(5, 0) +#define write_gc0_pagemask(val) __write_32bit_gc0_register(5, 0, val) + +#define read_gc0_pagegrain() __read_32bit_gc0_register(5, 1) +#define write_gc0_pagegrain(val) __write_32bit_gc0_register(5, 1, val) + +#define read_gc0_segctl0() __read_ulong_gc0_register(5, 2) +#define write_gc0_segctl0(val) __write_ulong_gc0_register(5, 2, val) + +#define read_gc0_segctl1() __read_ulong_gc0_register(5, 3) +#define write_gc0_segctl1(val) __write_ulong_gc0_register(5, 3, val) + +#define read_gc0_segctl2() __read_ulong_gc0_register(5, 4) +#define write_gc0_segctl2(val) __write_ulong_gc0_register(5, 4, val) + +#define read_gc0_pwbase() __read_ulong_gc0_register(5, 5) +#define write_gc0_pwbase(val) __write_ulong_gc0_register(5, 5, val) + +#define read_gc0_pwfield() __read_ulong_gc0_register(5, 6) +#define write_gc0_pwfield(val) __write_ulong_gc0_register(5, 6, val) + +#define read_gc0_pwsize() __read_ulong_gc0_register(5, 7) +#define write_gc0_pwsize(val) __write_ulong_gc0_register(5, 7, val) + +#define read_gc0_wired() __read_32bit_gc0_register(6, 0) +#define write_gc0_wired(val) __write_32bit_gc0_register(6, 0, val) + +#define read_gc0_pwctl() __read_32bit_gc0_register(6, 6) +#define write_gc0_pwctl(val) __write_32bit_gc0_register(6, 6, val) + +#define read_gc0_hwrena() __read_32bit_gc0_register(7, 0) +#define write_gc0_hwrena(val) __write_32bit_gc0_register(7, 0, val) + +#define read_gc0_badvaddr() __read_ulong_gc0_register(8, 0) +#define write_gc0_badvaddr(val) __write_ulong_gc0_register(8, 0, val) + +#define read_gc0_badinstr() __read_32bit_gc0_register(8, 1) +#define write_gc0_badinstr(val) __write_32bit_gc0_register(8, 1, val) + +#define read_gc0_badinstrp() __read_32bit_gc0_register(8, 2) +#define write_gc0_badinstrp(val) __write_32bit_gc0_register(8, 2, val) + +#define read_gc0_count() __read_32bit_gc0_register(9, 0) + +#define read_gc0_entryhi() __read_ulong_gc0_register(10, 0) +#define write_gc0_entryhi(val) __write_ulong_gc0_register(10, 0, val) + +#define read_gc0_compare() __read_32bit_gc0_register(11, 0) +#define write_gc0_compare(val) __write_32bit_gc0_register(11, 0, val) + +#define read_gc0_status() __read_32bit_gc0_register(12, 0) +#define write_gc0_status(val) __write_32bit_gc0_register(12, 0, val) + +#define read_gc0_intctl() __read_32bit_gc0_register(12, 1) +#define write_gc0_intctl(val) __write_32bit_gc0_register(12, 1, val) + +#define read_gc0_cause() __read_32bit_gc0_register(13, 0) +#define write_gc0_cause(val) __write_32bit_gc0_register(13, 0, val) + +#define read_gc0_epc() __read_ulong_gc0_register(14, 0) +#define write_gc0_epc(val) __write_ulong_gc0_register(14, 0, val) + +#define read_gc0_ebase() __read_32bit_gc0_register(15, 1) +#define write_gc0_ebase(val) __write_32bit_gc0_register(15, 1, val) + +#define read_gc0_ebase_64() __read_64bit_gc0_register(15, 1) +#define write_gc0_ebase_64(val) __write_64bit_gc0_register(15, 1, val) + +#define read_gc0_config() __read_32bit_gc0_register(16, 0) +#define read_gc0_config1() __read_32bit_gc0_register(16, 1) +#define read_gc0_config2() __read_32bit_gc0_register(16, 2) +#define read_gc0_config3() __read_32bit_gc0_register(16, 3) +#define read_gc0_config4() __read_32bit_gc0_register(16, 4) +#define read_gc0_config5() __read_32bit_gc0_register(16, 5) +#define read_gc0_config6() __read_32bit_gc0_register(16, 6) +#define read_gc0_config7() __read_32bit_gc0_register(16, 7) +#define write_gc0_config(val) __write_32bit_gc0_register(16, 0, val) +#define write_gc0_config1(val) __write_32bit_gc0_register(16, 1, val) +#define write_gc0_config2(val) __write_32bit_gc0_register(16, 2, val) +#define write_gc0_config3(val) __write_32bit_gc0_register(16, 3, val) +#define write_gc0_config4(val) __write_32bit_gc0_register(16, 4, val) +#define write_gc0_config5(val) __write_32bit_gc0_register(16, 5, val) +#define write_gc0_config6(val) __write_32bit_gc0_register(16, 6, val) +#define write_gc0_config7(val) __write_32bit_gc0_register(16, 7, val) + +#define read_gc0_watchlo0() __read_ulong_gc0_register(18, 0) +#define read_gc0_watchlo1() __read_ulong_gc0_register(18, 1) +#define read_gc0_watchlo2() __read_ulong_gc0_register(18, 2) +#define read_gc0_watchlo3() __read_ulong_gc0_register(18, 3) +#define read_gc0_watchlo4() __read_ulong_gc0_register(18, 4) +#define read_gc0_watchlo5() __read_ulong_gc0_register(18, 5) +#define read_gc0_watchlo6() __read_ulong_gc0_register(18, 6) +#define read_gc0_watchlo7() __read_ulong_gc0_register(18, 7) +#define write_gc0_watchlo0(val) __write_ulong_gc0_register(18, 0, val) +#define write_gc0_watchlo1(val) __write_ulong_gc0_register(18, 1, val) +#define write_gc0_watchlo2(val) __write_ulong_gc0_register(18, 2, val) +#define write_gc0_watchlo3(val) __write_ulong_gc0_register(18, 3, val) +#define write_gc0_watchlo4(val) __write_ulong_gc0_register(18, 4, val) +#define write_gc0_watchlo5(val) __write_ulong_gc0_register(18, 5, val) +#define write_gc0_watchlo6(val) __write_ulong_gc0_register(18, 6, val) +#define write_gc0_watchlo7(val) __write_ulong_gc0_register(18, 7, val) + +#define read_gc0_watchhi0() __read_32bit_gc0_register(19, 0) +#define read_gc0_watchhi1() __read_32bit_gc0_register(19, 1) +#define read_gc0_watchhi2() __read_32bit_gc0_register(19, 2) +#define read_gc0_watchhi3() __read_32bit_gc0_register(19, 3) +#define read_gc0_watchhi4() __read_32bit_gc0_register(19, 4) +#define read_gc0_watchhi5() __read_32bit_gc0_register(19, 5) +#define read_gc0_watchhi6() __read_32bit_gc0_register(19, 6) +#define read_gc0_watchhi7() __read_32bit_gc0_register(19, 7) +#define write_gc0_watchhi0(val) __write_32bit_gc0_register(19, 0, val) +#define write_gc0_watchhi1(val) __write_32bit_gc0_register(19, 1, val) +#define write_gc0_watchhi2(val) __write_32bit_gc0_register(19, 2, val) +#define write_gc0_watchhi3(val) __write_32bit_gc0_register(19, 3, val) +#define write_gc0_watchhi4(val) __write_32bit_gc0_register(19, 4, val) +#define write_gc0_watchhi5(val) __write_32bit_gc0_register(19, 5, val) +#define write_gc0_watchhi6(val) __write_32bit_gc0_register(19, 6, val) +#define write_gc0_watchhi7(val) __write_32bit_gc0_register(19, 7, val) + +#define read_gc0_xcontext() __read_ulong_gc0_register(20, 0) +#define write_gc0_xcontext(val) __write_ulong_gc0_register(20, 0, val) + +#define read_gc0_perfctrl0() __read_32bit_gc0_register(25, 0) +#define write_gc0_perfctrl0(val) __write_32bit_gc0_register(25, 0, val) +#define read_gc0_perfcntr0() __read_32bit_gc0_register(25, 1) +#define write_gc0_perfcntr0(val) __write_32bit_gc0_register(25, 1, val) +#define read_gc0_perfcntr0_64() __read_64bit_gc0_register(25, 1) +#define write_gc0_perfcntr0_64(val) __write_64bit_gc0_register(25, 1, val) +#define read_gc0_perfctrl1() __read_32bit_gc0_register(25, 2) +#define write_gc0_perfctrl1(val) __write_32bit_gc0_register(25, 2, val) +#define read_gc0_perfcntr1() __read_32bit_gc0_register(25, 3) +#define write_gc0_perfcntr1(val) __write_32bit_gc0_register(25, 3, val) +#define read_gc0_perfcntr1_64() __read_64bit_gc0_register(25, 3) +#define write_gc0_perfcntr1_64(val) __write_64bit_gc0_register(25, 3, val) +#define read_gc0_perfctrl2() __read_32bit_gc0_register(25, 4) +#define write_gc0_perfctrl2(val) __write_32bit_gc0_register(25, 4, val) +#define read_gc0_perfcntr2() __read_32bit_gc0_register(25, 5) +#define write_gc0_perfcntr2(val) __write_32bit_gc0_register(25, 5, val) +#define read_gc0_perfcntr2_64() __read_64bit_gc0_register(25, 5) +#define write_gc0_perfcntr2_64(val) __write_64bit_gc0_register(25, 5, val) +#define read_gc0_perfctrl3() __read_32bit_gc0_register(25, 6) +#define write_gc0_perfctrl3(val) __write_32bit_gc0_register(25, 6, val) +#define read_gc0_perfcntr3() __read_32bit_gc0_register(25, 7) +#define write_gc0_perfcntr3(val) __write_32bit_gc0_register(25, 7, val) +#define read_gc0_perfcntr3_64() __read_64bit_gc0_register(25, 7) +#define write_gc0_perfcntr3_64(val) __write_64bit_gc0_register(25, 7, val) + +#define read_gc0_errorepc() __read_ulong_gc0_register(30, 0) +#define write_gc0_errorepc(val) __write_ulong_gc0_register(30, 0, val) + +#define read_gc0_kscratch1() __read_ulong_gc0_register(31, 2) +#define read_gc0_kscratch2() __read_ulong_gc0_register(31, 3) +#define read_gc0_kscratch3() __read_ulong_gc0_register(31, 4) +#define read_gc0_kscratch4() __read_ulong_gc0_register(31, 5) +#define read_gc0_kscratch5() __read_ulong_gc0_register(31, 6) +#define read_gc0_kscratch6() __read_ulong_gc0_register(31, 7) +#define write_gc0_kscratch1(val) __write_ulong_gc0_register(31, 2, val) +#define write_gc0_kscratch2(val) __write_ulong_gc0_register(31, 3, val) +#define write_gc0_kscratch3(val) __write_ulong_gc0_register(31, 4, val) +#define write_gc0_kscratch4(val) __write_ulong_gc0_register(31, 5, val) +#define write_gc0_kscratch5(val) __write_ulong_gc0_register(31, 6, val) +#define write_gc0_kscratch6(val) __write_ulong_gc0_register(31, 7, val) + +/* * Macros to access the floating point coprocessor control registers */ #define _read_32bit_cp1_register(source, gas_hardfloat) \ @@ -2001,47 +2485,159 @@ static inline void tlb_write_random(void) ".set reorder"); } +#ifdef TOOLCHAIN_SUPPORTS_VIRT + /* - * Manipulate bits in a c0 register. + * Guest TLB operations. + * + * It is responsibility of the caller to take care of any TLB hazards. */ -#define __BUILD_SET_C0(name) \ +static inline void guest_tlb_probe(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbgp\n\t" + ".set pop"); +} + +static inline void guest_tlb_read(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbgr\n\t" + ".set pop"); +} + +static inline void guest_tlb_write_indexed(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbgwi\n\t" + ".set pop"); +} + +static inline void guest_tlb_write_random(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbgwr\n\t" + ".set pop"); +} + +/* + * Guest TLB Invalidate Flush + */ +static inline void guest_tlbinvf(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbginvf\n\t" + ".set pop"); +} + +#else /* TOOLCHAIN_SUPPORTS_VIRT */ + +/* + * Guest TLB operations. + * + * It is responsibility of the caller to take care of any TLB hazards. + */ +static inline void guest_tlb_probe(void) +{ + __asm__ __volatile__( + "# tlbgp\n\t" + ".word 0x42000010"); +} + +static inline void guest_tlb_read(void) +{ + __asm__ __volatile__( + "# tlbgr\n\t" + ".word 0x42000009"); +} + +static inline void guest_tlb_write_indexed(void) +{ + __asm__ __volatile__( + "# tlbgwi\n\t" + ".word 0x4200000a"); +} + +static inline void guest_tlb_write_random(void) +{ + __asm__ __volatile__( + "# tlbgwr\n\t" + ".word 0x4200000e"); +} + +/* + * Guest TLB Invalidate Flush + */ +static inline void guest_tlbinvf(void) +{ + __asm__ __volatile__( + "# tlbginvf\n\t" + ".word 0x4200000c"); +} + +#endif /* !TOOLCHAIN_SUPPORTS_VIRT */ + +/* + * Manipulate bits in a register. + */ +#define __BUILD_SET_COMMON(name) \ static inline unsigned int \ -set_c0_##name(unsigned int set) \ +set_##name(unsigned int set) \ { \ unsigned int res, new; \ \ - res = read_c0_##name(); \ + res = read_##name(); \ new = res | set; \ - write_c0_##name(new); \ + write_##name(new); \ \ return res; \ } \ \ static inline unsigned int \ -clear_c0_##name(unsigned int clear) \ +clear_##name(unsigned int clear) \ { \ unsigned int res, new; \ \ - res = read_c0_##name(); \ + res = read_##name(); \ new = res & ~clear; \ - write_c0_##name(new); \ + write_##name(new); \ \ return res; \ } \ \ static inline unsigned int \ -change_c0_##name(unsigned int change, unsigned int val) \ +change_##name(unsigned int change, unsigned int val) \ { \ unsigned int res, new; \ \ - res = read_c0_##name(); \ + res = read_##name(); \ new = res & ~change; \ new |= (val & change); \ - write_c0_##name(new); \ + write_##name(new); \ \ return res; \ } +/* + * Manipulate bits in a c0 register. + */ +#define __BUILD_SET_C0(name) __BUILD_SET_COMMON(c0_##name) + __BUILD_SET_C0(status) __BUILD_SET_C0(cause) __BUILD_SET_C0(config) @@ -2050,6 +2646,11 @@ __BUILD_SET_C0(intcontrol) __BUILD_SET_C0(intctl) __BUILD_SET_C0(srsmap) __BUILD_SET_C0(pagegrain) +__BUILD_SET_C0(guestctl0) +__BUILD_SET_C0(guestctl0ext) +__BUILD_SET_C0(guestctl1) +__BUILD_SET_C0(guestctl2) +__BUILD_SET_C0(guestctl3) __BUILD_SET_C0(brcm_config_0) __BUILD_SET_C0(brcm_bus_pll) __BUILD_SET_C0(brcm_reset) @@ -2059,12 +2660,21 @@ __BUILD_SET_C0(brcm_config) __BUILD_SET_C0(brcm_mode) /* + * Manipulate bits in a guest c0 register. + */ +#define __BUILD_SET_GC0(name) __BUILD_SET_COMMON(gc0_##name) + +__BUILD_SET_GC0(status) +__BUILD_SET_GC0(cause) +__BUILD_SET_GC0(ebase) + +/* * Return low 10 bits of ebase. * Note that under KVM (MIPSVZ) this returns vcpu id. */ static inline unsigned int get_ebase_cpunum(void) { - return read_c0_ebase() & 0x3ff; + return read_c0_ebase() & MIPS_EBASE_CPUNUM; } #endif /* !__ASSEMBLY__ */ diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index 45914b5..fc57e13 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h @@ -65,37 +65,32 @@ extern unsigned long pgd_current[]; back_to_back_c0_hazard(); \ TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) #endif /* CONFIG_MIPS_PGD_C0_CONTEXT*/ -#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) -#define ASID_INC 0x40 -#define ASID_MASK 0xfc0 - -#elif defined(CONFIG_CPU_R8000) - -#define ASID_INC 0x10 -#define ASID_MASK 0xff0 - -#else /* FIXME: not correct for R6000 */ +/* + * All unused by hardware upper bits will be considered + * as a software asid extension. + */ +static unsigned long asid_version_mask(unsigned int cpu) +{ + unsigned long asid_mask = cpu_asid_mask(&cpu_data[cpu]); -#define ASID_INC 0x1 -#define ASID_MASK 0xff + return ~(asid_mask | (asid_mask - 1)); +} -#endif +static unsigned long asid_first_version(unsigned int cpu) +{ + return ~asid_version_mask(cpu) + 1; +} #define cpu_context(cpu, mm) ((mm)->context.asid[cpu]) -#define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) #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 void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } -/* - * All unused by hardware upper bits will be considered - * as a software asid extension. - */ -#define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1))) -#define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1) /* Normal, classic MIPS get_new_mmu_context */ static inline void @@ -104,7 +99,7 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) extern void kvm_local_flush_tlb_all(void); unsigned long asid = asid_cache(cpu); - if (! ((asid += ASID_INC) & ASID_MASK) ) { + if (!((asid += cpu_asid_inc()) & cpu_asid_mask(&cpu_data[cpu]))) { if (cpu_has_vtag_icache) flush_icache_all(); #ifdef CONFIG_KVM @@ -113,7 +108,7 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) local_flush_tlb_all(); /* start new asid cycle */ #endif if (!asid) /* fix version if needed */ - asid = ASID_FIRST_VERSION; + asid = asid_first_version(cpu); } cpu_context(cpu, mm) = asid_cache(cpu) = asid; @@ -145,7 +140,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, htw_stop(); /* Check if our ASID is of an older version and thus invalid */ - if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK) + if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & asid_version_mask(cpu)) get_new_mmu_context(next, cpu); write_c0_entryhi(cpu_asid(cpu, next)); TLBMISS_HANDLER_SETUP_PGD(next->pgd); diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h index bbb85fe..6e4effa 100644 --- a/arch/mips/include/asm/msa.h +++ b/arch/mips/include/asm/msa.h @@ -147,6 +147,19 @@ static inline void restore_msa(struct task_struct *t) _restore_msa(t); } +static inline void init_msa_upper(void) +{ + /* + * Check cpu_has_msa only if it's a constant. This will allow the + * compiler to optimise out code for CPUs without MSA without adding + * an extra redundant check for CPUs with MSA. + */ + if (__builtin_constant_p(cpu_has_msa) && !cpu_has_msa) + return; + + _init_msa_upper(); +} + #ifdef TOOLCHAIN_SUPPORTS_MSA #define __BUILD_MSA_CTL_REG(name, cs) \ diff --git a/arch/mips/include/asm/octeon/cvmx-bootinfo.h b/arch/mips/include/asm/octeon/cvmx-bootinfo.h index d92cf59..6278776 100644 --- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h +++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h @@ -32,6 +32,8 @@ #ifndef __CVMX_BOOTINFO_H__ #define __CVMX_BOOTINFO_H__ +#include "cvmx-coremask.h" + /* * Current major and minor versions of the CVMX bootinfo block that is * passed from the bootloader to the application. This is versioned @@ -39,7 +41,7 @@ * versions. */ #define CVMX_BOOTINFO_MAJ_VER 1 -#define CVMX_BOOTINFO_MIN_VER 3 +#define CVMX_BOOTINFO_MIN_VER 4 #if (CVMX_BOOTINFO_MAJ_VER == 1) #define CVMX_BOOTINFO_OCTEON_SERIAL_LEN 20 @@ -124,6 +126,13 @@ struct cvmx_bootinfo { */ uint64_t fdt_addr; #endif +#if (CVMX_BOOTINFO_MIN_VER >= 4) + /* + * Coremask used for processors with more than 32 cores + * or with OCI. This replaces core_mask. + */ + struct cvmx_coremask ext_core_mask; +#endif #else /* __BIG_ENDIAN */ /* * Little-Endian: When the CPU mode is switched to @@ -177,6 +186,9 @@ struct cvmx_bootinfo { #if (CVMX_BOOTINFO_MIN_VER >= 3) uint64_t fdt_addr; #endif +#if (CVMX_BOOTINFO_MIN_VER >= 4) + struct cvmx_coremask ext_core_mask; +#endif #endif }; @@ -388,7 +400,7 @@ static inline const char *cvmx_board_type_to_string(enum ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX) } - return "Unsupported Board"; + return NULL; } #define ENUM_CHIP_TYPE_CASE(x) \ diff --git a/arch/mips/include/asm/octeon/cvmx-ciu3-defs.h b/arch/mips/include/asm/octeon/cvmx-ciu3-defs.h new file mode 100644 index 0000000..547f778 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-ciu3-defs.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2003-2016 Cavium Inc. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, Version 2, as + * published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + */ + +#ifndef __CVMX_CIU3_DEFS_H__ +#define __CVMX_CIU3_DEFS_H__ + +#define CVMX_CIU3_FUSE CVMX_ADD_IO_SEG(0x00010100000001A0ull) +#define CVMX_CIU3_BIST CVMX_ADD_IO_SEG(0x00010100000001C0ull) +#define CVMX_CIU3_CONST CVMX_ADD_IO_SEG(0x0001010000000220ull) +#define CVMX_CIU3_CTL CVMX_ADD_IO_SEG(0x00010100000000E0ull) +#define CVMX_CIU3_DESTX_IO_INT(offset) (CVMX_ADD_IO_SEG(0x0001010000210000ull) + ((offset) & 7) * 8) +#define CVMX_CIU3_DESTX_PP_INT(offset) (CVMX_ADD_IO_SEG(0x0001010000200000ull) + ((offset) & 255) * 8) +#define CVMX_CIU3_GSTOP CVMX_ADD_IO_SEG(0x0001010000000140ull) +#define CVMX_CIU3_IDTX_CTL(offset) (CVMX_ADD_IO_SEG(0x0001010000110000ull) + ((offset) & 255) * 8) +#define CVMX_CIU3_IDTX_IO(offset) (CVMX_ADD_IO_SEG(0x0001010000130000ull) + ((offset) & 255) * 8) +#define CVMX_CIU3_IDTX_PPX(offset, block_id) (CVMX_ADD_IO_SEG(0x0001010000120000ull) + ((block_id) & 255) * 0x20ull) +#define CVMX_CIU3_INTR_RAM_ECC_CTL CVMX_ADD_IO_SEG(0x0001010000000260ull) +#define CVMX_CIU3_INTR_RAM_ECC_ST CVMX_ADD_IO_SEG(0x0001010000000280ull) +#define CVMX_CIU3_INTR_READY CVMX_ADD_IO_SEG(0x00010100000002A0ull) +#define CVMX_CIU3_INTR_SLOWDOWN CVMX_ADD_IO_SEG(0x0001010000000240ull) +#define CVMX_CIU3_ISCX_CTL(offset) (CVMX_ADD_IO_SEG(0x0001010080000000ull) + ((offset) & 1048575) * 8) +#define CVMX_CIU3_ISCX_W1C(offset) (CVMX_ADD_IO_SEG(0x0001010090000000ull) + ((offset) & 1048575) * 8) +#define CVMX_CIU3_ISCX_W1S(offset) (CVMX_ADD_IO_SEG(0x00010100A0000000ull) + ((offset) & 1048575) * 8) +#define CVMX_CIU3_NMI CVMX_ADD_IO_SEG(0x0001010000000160ull) +#define CVMX_CIU3_SISCX(offset) (CVMX_ADD_IO_SEG(0x0001010000220000ull) + ((offset) & 255) * 8) +#define CVMX_CIU3_TIMX(offset) (CVMX_ADD_IO_SEG(0x0001010000010000ull) + ((offset) & 15) * 8) + +union cvmx_ciu3_bist { + uint64_t u64; + struct cvmx_ciu3_bist_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_9_63 : 55; + uint64_t bist : 9; +#else + uint64_t bist : 9; + uint64_t reserved_9_63 : 55; +#endif + } s; +}; + +union cvmx_ciu3_const { + uint64_t u64; + struct cvmx_ciu3_const_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t dests_io : 16; + uint64_t pintsn : 16; + uint64_t dests_pp : 16; + uint64_t idt : 16; +#else + uint64_t idt : 16; + uint64_t dests_pp : 16; + uint64_t pintsn : 16; + uint64_t dests_io : 16; +#endif + } s; +}; + +union cvmx_ciu3_ctl { + uint64_t u64; + struct cvmx_ciu3_ctl_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_5_63 : 59; + uint64_t mcd_sel : 2; + uint64_t iscmem_le : 1; + uint64_t seq_dis : 1; + uint64_t cclk_dis : 1; +#else + uint64_t cclk_dis : 1; + uint64_t seq_dis : 1; + uint64_t iscmem_le : 1; + uint64_t mcd_sel : 2; + uint64_t reserved_5_63 : 59; +#endif + } s; +}; + +union cvmx_ciu3_destx_io_int { + uint64_t u64; + struct cvmx_ciu3_destx_io_int_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_52_63 : 12; + uint64_t intsn : 20; + uint64_t reserved_10_31 : 22; + uint64_t intidt : 8; + uint64_t newint : 1; + uint64_t intr : 1; +#else + uint64_t intr : 1; + uint64_t newint : 1; + uint64_t intidt : 8; + uint64_t reserved_10_31 : 22; + uint64_t intsn : 20; + uint64_t reserved_52_63 : 12; +#endif + } s; +}; + +union cvmx_ciu3_destx_pp_int { + uint64_t u64; + struct cvmx_ciu3_destx_pp_int_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_52_63 : 12; + uint64_t intsn : 20; + uint64_t reserved_10_31 : 22; + uint64_t intidt : 8; + uint64_t newint : 1; + uint64_t intr : 1; +#else + uint64_t intr : 1; + uint64_t newint : 1; + uint64_t intidt : 8; + uint64_t reserved_10_31 : 22; + uint64_t intsn : 20; + uint64_t reserved_52_63 : 12; +#endif + } s; +}; + +union cvmx_ciu3_gstop { + uint64_t u64; + struct cvmx_ciu3_gstop_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_1_63 : 63; + uint64_t gstop : 1; +#else + uint64_t gstop : 1; + uint64_t reserved_1_63 : 63; +#endif + } s; +}; + +union cvmx_ciu3_idtx_ctl { + uint64_t u64; + struct cvmx_ciu3_idtx_ctl_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_52_63 : 12; + uint64_t intsn : 20; + uint64_t reserved_4_31 : 28; + uint64_t intr : 1; + uint64_t newint : 1; + uint64_t ip_num : 2; +#else + uint64_t ip_num : 2; + uint64_t newint : 1; + uint64_t intr : 1; + uint64_t reserved_4_31 : 28; + uint64_t intsn : 20; + uint64_t reserved_52_63 : 12; +#endif + } s; +}; + +union cvmx_ciu3_idtx_io { + uint64_t u64; + struct cvmx_ciu3_idtx_io_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_5_63 : 59; + uint64_t io : 5; +#else + uint64_t io : 5; + uint64_t reserved_5_63 : 59; +#endif + } s; +}; + +union cvmx_ciu3_idtx_ppx { + uint64_t u64; + struct cvmx_ciu3_idtx_ppx_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_48_63 : 16; + uint64_t pp : 48; +#else + uint64_t pp : 48; + uint64_t reserved_48_63 : 16; +#endif + } s; +}; + +union cvmx_ciu3_intr_ram_ecc_ctl { + uint64_t u64; + struct cvmx_ciu3_intr_ram_ecc_ctl_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_3_63 : 61; + uint64_t flip_synd : 2; + uint64_t ecc_ena : 1; +#else + uint64_t ecc_ena : 1; + uint64_t flip_synd : 2; + uint64_t reserved_3_63 : 61; +#endif + } s; +}; + +union cvmx_ciu3_intr_ram_ecc_st { + uint64_t u64; + struct cvmx_ciu3_intr_ram_ecc_st_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_52_63 : 12; + uint64_t addr : 20; + uint64_t reserved_6_31 : 26; + uint64_t sisc_dbe : 1; + uint64_t sisc_sbe : 1; + uint64_t idt_dbe : 1; + uint64_t idt_sbe : 1; + uint64_t isc_dbe : 1; + uint64_t isc_sbe : 1; +#else + uint64_t isc_sbe : 1; + uint64_t isc_dbe : 1; + uint64_t idt_sbe : 1; + uint64_t idt_dbe : 1; + uint64_t sisc_sbe : 1; + uint64_t sisc_dbe : 1; + uint64_t reserved_6_31 : 26; + uint64_t addr : 20; + uint64_t reserved_52_63 : 12; +#endif + } s; +}; + +union cvmx_ciu3_intr_ready { + uint64_t u64; + struct cvmx_ciu3_intr_ready_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_46_63 : 18; + uint64_t index : 14; + uint64_t reserved_1_31 : 31; + uint64_t ready : 1; +#else + uint64_t ready : 1; + uint64_t reserved_1_31 : 31; + uint64_t index : 14; + uint64_t reserved_46_63 : 18; +#endif + } s; +}; + +union cvmx_ciu3_intr_slowdown { + uint64_t u64; + struct cvmx_ciu3_intr_slowdown_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_3_63 : 61; + uint64_t ctl : 3; +#else + uint64_t ctl : 3; + uint64_t reserved_3_63 : 61; +#endif + } s; +}; + +union cvmx_ciu3_iscx_ctl { + uint64_t u64; + struct cvmx_ciu3_iscx_ctl_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_24_63 : 40; + uint64_t idt : 8; + uint64_t imp : 1; + uint64_t reserved_2_14 : 13; + uint64_t en : 1; + uint64_t raw : 1; +#else + uint64_t raw : 1; + uint64_t en : 1; + uint64_t reserved_2_14 : 13; + uint64_t imp : 1; + uint64_t idt : 8; + uint64_t reserved_24_63 : 40; +#endif + } s; +}; + +union cvmx_ciu3_iscx_w1c { + uint64_t u64; + struct cvmx_ciu3_iscx_w1c_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_2_63 : 62; + uint64_t en : 1; + uint64_t raw : 1; +#else + uint64_t raw : 1; + uint64_t en : 1; + uint64_t reserved_2_63 : 62; +#endif + } s; +}; + +union cvmx_ciu3_iscx_w1s { + uint64_t u64; + struct cvmx_ciu3_iscx_w1s_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_2_63 : 62; + uint64_t en : 1; + uint64_t raw : 1; +#else + uint64_t raw : 1; + uint64_t en : 1; + uint64_t reserved_2_63 : 62; +#endif + } s; +}; + +union cvmx_ciu3_nmi { + uint64_t u64; + struct cvmx_ciu3_nmi_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_48_63 : 16; + uint64_t nmi : 48; +#else + uint64_t nmi : 48; + uint64_t reserved_48_63 : 16; +#endif + } s; +}; + +union cvmx_ciu3_siscx { + uint64_t u64; + struct cvmx_ciu3_siscx_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t en : 64; +#else + uint64_t en : 64; +#endif + } s; +}; + +union cvmx_ciu3_timx { + uint64_t u64; + struct cvmx_ciu3_timx_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_37_63 : 27; + uint64_t one_shot : 1; + uint64_t len : 36; +#else + uint64_t len : 36; + uint64_t one_shot : 1; + uint64_t reserved_37_63 : 27; +#endif + } s; +}; + +#endif diff --git a/arch/mips/include/asm/octeon/cvmx-coremask.h b/arch/mips/include/asm/octeon/cvmx-coremask.h new file mode 100644 index 0000000..097dc09 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-coremask.h @@ -0,0 +1,89 @@ +/* + * 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. + * + * Copyright (c) 2016 Cavium Inc. (support@cavium.com). + * + */ + +/* + * Module to support operations on bitmap of cores. Coremask can be used to + * select a specific core, a group of cores, or all available cores, for + * initialization and differentiation of roles within a single shared binary + * executable image. + * + * The core numbers used in this file are the same value as what is found in + * the COP0_EBASE register and the rdhwr 0 instruction. + * + * For the CN78XX and other multi-node environments the core numbers are not + * contiguous. The core numbers for the CN78XX are as follows: + * + * Node 0: Cores 0 - 47 + * Node 1: Cores 128 - 175 + * Node 2: Cores 256 - 303 + * Node 3: Cores 384 - 431 + * + */ + +#ifndef __CVMX_COREMASK_H__ +#define __CVMX_COREMASK_H__ + +#define CVMX_MIPS_MAX_CORES 1024 +/* bits per holder */ +#define CVMX_COREMASK_ELTSZ 64 + +/* cvmx_coremask_t's size in u64 */ +#define CVMX_COREMASK_BMPSZ (CVMX_MIPS_MAX_CORES / CVMX_COREMASK_ELTSZ) + + +/* cvmx_coremask_t */ +struct cvmx_coremask { + u64 coremask_bitmap[CVMX_COREMASK_BMPSZ]; +}; + +/* + * Is ``core'' set in the coremask? + */ +static inline bool cvmx_coremask_is_core_set(const struct cvmx_coremask *pcm, + int core) +{ + int n, i; + + n = core % CVMX_COREMASK_ELTSZ; + i = core / CVMX_COREMASK_ELTSZ; + + return (pcm->coremask_bitmap[i] & ((u64)1 << n)) != 0; +} + +/* + * Make a copy of a coremask + */ +static inline void cvmx_coremask_copy(struct cvmx_coremask *dest, + const struct cvmx_coremask *src) +{ + memcpy(dest, src, sizeof(*dest)); +} + +/* + * Set the lower 64-bit of the coremask. + */ +static inline void cvmx_coremask_set64(struct cvmx_coremask *pcm, + uint64_t coremask_64) +{ + pcm->coremask_bitmap[0] = coremask_64; +} + +/* + * Clear ``core'' from the coremask. + */ +static inline void cvmx_coremask_clear_core(struct cvmx_coremask *pcm, int core) +{ + int n, i; + + n = core % CVMX_COREMASK_ELTSZ; + i = core / CVMX_COREMASK_ELTSZ; + pcm->coremask_bitmap[i] &= ~(1ull << n); +} + +#endif /* __CVMX_COREMASK_H__ */ diff --git a/arch/mips/include/asm/octeon/cvmx-fpa-defs.h b/arch/mips/include/asm/octeon/cvmx-fpa-defs.h index 1d79e3c..887ff8e 100644 --- a/arch/mips/include/asm/octeon/cvmx-fpa-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-fpa-defs.h @@ -66,6 +66,7 @@ #define CVMX_FPA_WART_CTL (CVMX_ADD_IO_SEG(0x00011800280000D8ull)) #define CVMX_FPA_WART_STATUS (CVMX_ADD_IO_SEG(0x00011800280000E0ull)) #define CVMX_FPA_WQE_THRESHOLD (CVMX_ADD_IO_SEG(0x0001180028000468ull)) +#define CVMX_FPA_CLK_COUNT (CVMX_ADD_IO_SEG(0x00012800000000F0ull)) union cvmx_fpa_addr_range_error { uint64_t u64; diff --git a/arch/mips/include/asm/octeon/cvmx-mio-defs.h b/arch/mips/include/asm/octeon/cvmx-mio-defs.h index bb0ae33..5196c04 100644 --- a/arch/mips/include/asm/octeon/cvmx-mio-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-mio-defs.h @@ -1481,7 +1481,9 @@ union cvmx_mio_fus_dat2 { uint64_t u64; struct cvmx_mio_fus_dat2_s { #ifdef __BIG_ENDIAN_BITFIELD - uint64_t reserved_48_63:16; + uint64_t reserved_59_63:5; + uint64_t run_platform:3; + uint64_t gbl_pwr_throttle:8; uint64_t fus118:1; uint64_t rom_info:10; uint64_t power_limit:2; @@ -1513,7 +1515,9 @@ union cvmx_mio_fus_dat2 { uint64_t power_limit:2; uint64_t rom_info:10; uint64_t fus118:1; - uint64_t reserved_48_63:16; + uint64_t gbl_pwr_throttle:8; + uint64_t run_platform:3; + uint64_t reserved_59_63:5; #endif } s; struct cvmx_mio_fus_dat2_cn30xx { @@ -1837,50 +1841,192 @@ union cvmx_mio_fus_dat2 { #endif } cn68xx; struct cvmx_mio_fus_dat2_cn68xx cn68xxp1; + struct cvmx_mio_fus_dat2_cn70xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_48_63:16; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_31_29:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_25_24:2; + uint64_t chip_id:8; + uint64_t reserved_15_0:16; +#else + uint64_t reserved_15_0:16; + uint64_t chip_id:8; + uint64_t reserved_25_24:2; + uint64_t nocrypto:1; + uint64_t nomul:1; + uint64_t nodfa_cp2:1; + uint64_t reserved_31_29:3; + uint64_t raid_en:1; + uint64_t fus318:1; + uint64_t dorm_crypto:1; + uint64_t power_limit:2; + uint64_t rom_info:10; + uint64_t fus118:1; + uint64_t reserved_48_63:16; +#endif + } cn70xx; + struct cvmx_mio_fus_dat2_cn70xx cn70xxp1; + struct cvmx_mio_fus_dat2_cn73xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_59_63:5; + uint64_t run_platform:3; + uint64_t gbl_pwr_throttle:8; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_31_29:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_25_24:2; + uint64_t chip_id:8; + uint64_t reserved_15_0:16; +#else + uint64_t reserved_15_0:16; + uint64_t chip_id:8; + uint64_t reserved_25_24:2; + uint64_t nocrypto:1; + uint64_t nomul:1; + uint64_t nodfa_cp2:1; + uint64_t reserved_31_29:3; + uint64_t raid_en:1; + uint64_t fus318:1; + uint64_t dorm_crypto:1; + uint64_t power_limit:2; + uint64_t rom_info:10; + uint64_t fus118:1; + uint64_t gbl_pwr_throttle:8; + uint64_t run_platform:3; + uint64_t reserved_59_63:5; +#endif + } cn73xx; + struct cvmx_mio_fus_dat2_cn78xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_59_63:5; + uint64_t run_platform:3; + uint64_t reserved_48_55:8; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_31_29:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_25_24:2; + uint64_t chip_id:8; + uint64_t reserved_0_15:16; +#else + uint64_t reserved_0_15:16; + uint64_t chip_id:8; + uint64_t reserved_25_24:2; + uint64_t nocrypto:1; + uint64_t nomul:1; + uint64_t nodfa_cp2:1; + uint64_t reserved_31_29:3; + uint64_t raid_en:1; + uint64_t fus318:1; + uint64_t dorm_crypto:1; + uint64_t power_limit:2; + uint64_t rom_info:10; + uint64_t fus118:1; + uint64_t reserved_48_55:8; + uint64_t run_platform:3; + uint64_t reserved_59_63:5; +#endif + } cn78xx; + struct cvmx_mio_fus_dat2_cn78xxp2 { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_59_63:5; + uint64_t run_platform:3; + uint64_t gbl_pwr_throttle:8; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_31_29:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_25_24:2; + uint64_t chip_id:8; + uint64_t reserved_0_15:16; +#else + uint64_t reserved_0_15:16; + uint64_t chip_id:8; + uint64_t reserved_25_24:2; + uint64_t nocrypto:1; + uint64_t nomul:1; + uint64_t nodfa_cp2:1; + uint64_t reserved_31_29:3; + uint64_t raid_en:1; + uint64_t fus318:1; + uint64_t dorm_crypto:1; + uint64_t power_limit:2; + uint64_t rom_info:10; + uint64_t fus118:1; + uint64_t gbl_pwr_throttle:8; + uint64_t run_platform:3; + uint64_t reserved_59_63:5; +#endif + } cn78xxp2; struct cvmx_mio_fus_dat2_cn61xx cnf71xx; + struct cvmx_mio_fus_dat2_cn73xx cnf75xx; }; union cvmx_mio_fus_dat3 { uint64_t u64; struct cvmx_mio_fus_dat3_s { #ifdef __BIG_ENDIAN_BITFIELD - uint64_t reserved_58_63:6; + uint64_t ema0:6; uint64_t pll_ctl:10; uint64_t dfa_info_dte:3; uint64_t dfa_info_clm:4; - uint64_t reserved_40_40:1; - uint64_t ema:2; + uint64_t pll_alt_matrix:1; + uint64_t reserved_38_39:2; uint64_t efus_lck_rsv:1; uint64_t efus_lck_man:1; uint64_t pll_half_dis:1; uint64_t l2c_crip:3; - uint64_t pll_div4:1; - uint64_t reserved_29_30:2; - uint64_t bar2_en:1; + uint64_t reserved_28_31:4; uint64_t efus_lck:1; uint64_t efus_ign:1; uint64_t nozip:1; uint64_t nodfa_dte:1; - uint64_t icache:24; + uint64_t reserved_0_23:24; #else - uint64_t icache:24; + uint64_t reserved_0_23:24; uint64_t nodfa_dte:1; uint64_t nozip:1; uint64_t efus_ign:1; uint64_t efus_lck:1; - uint64_t bar2_en:1; - uint64_t reserved_29_30:2; - uint64_t pll_div4:1; + uint64_t reserved_28_31:4; uint64_t l2c_crip:3; uint64_t pll_half_dis:1; uint64_t efus_lck_man:1; uint64_t efus_lck_rsv:1; - uint64_t ema:2; - uint64_t reserved_40_40:1; + uint64_t reserved_38_39:2; + uint64_t pll_alt_matrix:1; uint64_t dfa_info_clm:4; uint64_t dfa_info_dte:3; uint64_t pll_ctl:10; - uint64_t reserved_58_63:6; + uint64_t ema0:6; #endif } s; struct cvmx_mio_fus_dat3_cn30xx { @@ -2022,7 +2168,239 @@ union cvmx_mio_fus_dat3 { struct cvmx_mio_fus_dat3_cn61xx cn66xx; struct cvmx_mio_fus_dat3_cn61xx cn68xx; struct cvmx_mio_fus_dat3_cn61xx cn68xxp1; + struct cvmx_mio_fus_dat3_cn70xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t pll_alt_matrix:1; + uint64_t pll_bwadj_denom:2; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t use_int_refclk:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t reserved_0_17:18; +#else + uint64_t reserved_0_17:18; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t use_int_refclk:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t pll_bwadj_denom:2; + uint64_t pll_alt_matrix:1; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cn70xx; + struct cvmx_mio_fus_dat3_cn70xxp1 { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t reserved_38_40:3; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t reserved_31_31:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t reserved_0_17:18; +#else + uint64_t reserved_0_17:18; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t reserved_31_31:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t reserved_38_40:3; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cn70xxp1; + struct cvmx_mio_fus_dat3_cn73xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t pll_alt_matrix:1; + uint64_t pll_bwadj_denom:2; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t use_int_refclk:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t nohna_dte:1; + uint64_t hna_info_dte:3; + uint64_t hna_info_clm:4; + uint64_t reserved_9_9:1; + uint64_t core_pll_mul:5; + uint64_t pnr_pll_mul:4; +#else + uint64_t pnr_pll_mul:4; + uint64_t core_pll_mul:5; + uint64_t reserved_9_9:1; + uint64_t hna_info_clm:4; + uint64_t hna_info_dte:3; + uint64_t nohna_dte:1; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t use_int_refclk:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t pll_bwadj_denom:2; + uint64_t pll_alt_matrix:1; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cn73xx; + struct cvmx_mio_fus_dat3_cn78xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t reserved_38_40:3; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t reserved_31_31:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t nohna_dte:1; + uint64_t hna_info_dte:3; + uint64_t hna_info_clm:4; + uint64_t reserved_0_9:10; +#else + uint64_t reserved_0_9:10; + uint64_t hna_info_clm:4; + uint64_t hna_info_dte:3; + uint64_t nohna_dte:1; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t reserved_31_31:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t reserved_38_40:3; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cn78xx; + struct cvmx_mio_fus_dat3_cn73xx cn78xxp2; struct cvmx_mio_fus_dat3_cn61xx cnf71xx; + struct cvmx_mio_fus_dat3_cnf75xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t pll_alt_matrix:1; + uint64_t pll_bwadj_denom:2; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t use_int_refclk:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t reserved_9_17:9; + uint64_t core_pll_mul:5; + uint64_t pnr_pll_mul:4; +#else + uint64_t pnr_pll_mul:4; + uint64_t core_pll_mul:5; + uint64_t reserved_9_17:9; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t use_int_refclk:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t pll_bwadj_denom:2; + uint64_t pll_alt_matrix:1; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cnf75xx; }; union cvmx_mio_fus_ema { diff --git a/arch/mips/include/asm/octeon/cvmx-sysinfo.h b/arch/mips/include/asm/octeon/cvmx-sysinfo.h index 2131197..c6c3ee3 100644 --- a/arch/mips/include/asm/octeon/cvmx-sysinfo.h +++ b/arch/mips/include/asm/octeon/cvmx-sysinfo.h @@ -4,7 +4,7 @@ * Contact: support@caviumnetworks.com * This file is part of the OCTEON SDK * - * Copyright (c) 2003-2008 Cavium Networks + * Copyright (c) 2003-2016 Cavium, Inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 2, as @@ -32,6 +32,8 @@ #ifndef __CVMX_SYSINFO_H__ #define __CVMX_SYSINFO_H__ +#include "cvmx-coremask.h" + #define OCTEON_SERIAL_LEN 20 /** * Structure describing application specific information. @@ -50,8 +52,7 @@ struct cvmx_sysinfo { uint64_t system_dram_size; /* ptr to memory descriptor block */ - void *phy_mem_desc_ptr; - + uint64_t phy_mem_desc_addr; /* Application image specific variables */ /* stack top address (virtual) */ @@ -63,7 +64,7 @@ struct cvmx_sysinfo { /* heap size in bytes */ uint32_t heap_size; /* coremask defining cores running application */ - uint32_t core_mask; + struct cvmx_coremask core_mask; /* Deprecated, use cvmx_coremask_first_core() to select init core */ uint32_t init_core; @@ -121,32 +122,4 @@ struct cvmx_sysinfo { extern struct cvmx_sysinfo *cvmx_sysinfo_get(void); -/** - * This function is used in non-simple executive environments (such as - * Linux kernel, u-boot, etc.) to configure the minimal fields that - * are required to use simple executive files directly. - * - * Locking (if required) must be handled outside of this - * function - * - * @phy_mem_desc_ptr: Pointer to global physical memory descriptor - * (bootmem descriptor) @board_type: Octeon board - * type enumeration - * - * @board_rev_major: - * Board major revision - * @board_rev_minor: - * Board minor revision - * @cpu_clock_hz: - * CPU clock freqency in hertz - * - * Returns 0: Failure - * 1: success - */ -extern int cvmx_sysinfo_minimal_initialize(void *phy_mem_desc_ptr, - uint16_t board_type, - uint8_t board_rev_major, - uint8_t board_rev_minor, - uint32_t cpu_clock_hz); - #endif /* __CVMX_SYSINFO_H__ */ diff --git a/arch/mips/include/asm/octeon/cvmx.h b/arch/mips/include/asm/octeon/cvmx.h index 3e982e0..2530e87 100644 --- a/arch/mips/include/asm/octeon/cvmx.h +++ b/arch/mips/include/asm/octeon/cvmx.h @@ -57,6 +57,7 @@ enum cvmx_mips_space { #include <asm/octeon/cvmx-sysinfo.h> #include <asm/octeon/cvmx-ciu-defs.h> +#include <asm/octeon/cvmx-ciu3-defs.h> #include <asm/octeon/cvmx-gpio-defs.h> #include <asm/octeon/cvmx-iob-defs.h> #include <asm/octeon/cvmx-ipd-defs.h> @@ -341,6 +342,21 @@ static inline unsigned int cvmx_get_core_num(void) return core_num; } +/* Maximum # of bits to define core in node */ +#define CVMX_NODE_NO_SHIFT 7 +#define CVMX_NODE_MASK 0x3 +static inline unsigned int cvmx_get_node_num(void) +{ + unsigned int core_num = cvmx_get_core_num(); + + return (core_num >> CVMX_NODE_NO_SHIFT) & CVMX_NODE_MASK; +} + +static inline unsigned int cvmx_get_local_core_num(void) +{ + return cvmx_get_core_num() & ((1 << CVMX_NODE_NO_SHIFT) - 1); +} + /** * Returns the number of bits set in the provided value. * Simple wrapper for POP instruction. @@ -448,8 +464,15 @@ static inline uint64_t cvmx_get_cycle_global(void) /* Return the number of cores available in the chip */ static inline uint32_t cvmx_octeon_num_cores(void) { - uint32_t ciu_fuse = (uint32_t) cvmx_read_csr(CVMX_CIU_FUSE) & 0xffff; - return cvmx_pop(ciu_fuse); + u64 ciu_fuse_reg; + u64 ciu_fuse; + + if (OCTEON_IS_OCTEON3() && !OCTEON_IS_MODEL(OCTEON_CN70XX)) + ciu_fuse_reg = CVMX_CIU3_FUSE; + else + ciu_fuse_reg = CVMX_CIU_FUSE; + ciu_fuse = cvmx_read_csr(ciu_fuse_reg); + return cvmx_dpop(ciu_fuse); } #endif /* __CVMX_H__ */ diff --git a/arch/mips/include/asm/octeon/octeon-feature.h b/arch/mips/include/asm/octeon/octeon-feature.h index 3ed10a8..a19ca3b 100644 --- a/arch/mips/include/asm/octeon/octeon-feature.h +++ b/arch/mips/include/asm/octeon/octeon-feature.h @@ -81,6 +81,10 @@ enum octeon_feature { OCTEON_FEATURE_HFA, OCTEON_FEATURE_DFM, OCTEON_FEATURE_CIU2, + OCTEON_FEATURE_CIU3, + /* Octeon has FPA first seen on 78XX */ + OCTEON_FEATURE_FPA3, + OCTEON_FEATURE_FAU, OCTEON_MAX_FEATURE }; @@ -110,7 +114,7 @@ static inline int octeon_has_crypto(void) * Returns Non zero if the feature exists. Zero if the feature does not * exist. */ -static inline int octeon_has_feature(enum octeon_feature feature) +static inline bool octeon_has_feature(enum octeon_feature feature) { switch (feature) { case OCTEON_FEATURE_SAAD: @@ -122,7 +126,7 @@ static inline int octeon_has_feature(enum octeon_feature feature) fus_2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); return !fus_2.s.nocrypto && !fus_2.s.nomul && fus_2.s.dorm_crypto; } else { - return 0; + return false; } case OCTEON_FEATURE_PCIE: @@ -190,11 +194,20 @@ static inline int octeon_has_feature(enum octeon_feature feature) case OCTEON_FEATURE_CIU2: return OCTEON_IS_MODEL(OCTEON_CN68XX); + case OCTEON_FEATURE_CIU3: + case OCTEON_FEATURE_FPA3: + return OCTEON_IS_MODEL(OCTEON_CN78XX) + || OCTEON_IS_MODEL(OCTEON_CNF75XX) + || OCTEON_IS_MODEL(OCTEON_CN73XX); + case OCTEON_FEATURE_FAU: + return !(OCTEON_IS_MODEL(OCTEON_CN78XX) + || OCTEON_IS_MODEL(OCTEON_CNF75XX) + || OCTEON_IS_MODEL(OCTEON_CN73XX)); default: break; } - return 0; + return false; } #endif /* __OCTEON_FEATURE_H__ */ diff --git a/arch/mips/include/asm/octeon/octeon-model.h b/arch/mips/include/asm/octeon/octeon-model.h index 92b377e..6c68517 100644 --- a/arch/mips/include/asm/octeon/octeon-model.h +++ b/arch/mips/include/asm/octeon/octeon-model.h @@ -74,7 +74,12 @@ * CN7XXX models with new revision encoding */ +#define OCTEON_CNF75XX_PASS1_0 0x000d9800 +#define OCTEON_CNF75XX (OCTEON_CNF75XX_PASS1_0 | OM_IGNORE_REVISION) +#define OCTEON_CNF75XX_PASS1_X (OCTEON_CNF75XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) + #define OCTEON_CN73XX_PASS1_0 0x000d9700 +#define OCTEON_CN73XX_PASS1_1 0x000d9701 #define OCTEON_CN73XX (OCTEON_CN73XX_PASS1_0 | OM_IGNORE_REVISION) #define OCTEON_CN73XX_PASS1_X (OCTEON_CN73XX_PASS1_0 | \ OM_IGNORE_MINOR_REVISION) diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index de9f74e..07c0516 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h @@ -299,6 +299,31 @@ static inline void octeon_npi_write32(uint64_t address, uint32_t val) cvmx_read64_uint32(address ^ 4); } +#ifdef CONFIG_SMP +void octeon_setup_smp(void); +#else +static inline void octeon_setup_smp(void) {} +#endif + +struct irq_domain; +struct device_node; +struct irq_data; +struct irq_chip; +void octeon_ciu3_mbox_send(int cpu, unsigned int mbox); +int octeon_irq_ciu3_xlat(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type); +void octeon_irq_ciu3_enable(struct irq_data *data); +void octeon_irq_ciu3_disable(struct irq_data *data); +void octeon_irq_ciu3_ack(struct irq_data *data); +void octeon_irq_ciu3_mask(struct irq_data *data); +void octeon_irq_ciu3_mask_ack(struct irq_data *data); +int octeon_irq_ciu3_mapx(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw, struct irq_chip *chip); + /* Octeon multiplier save/restore routines from octeon_switch.S */ void octeon_mult_save(void); void octeon_mult_restore(void); diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 8c16fb7..86b239d 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -43,8 +43,6 @@ struct pci_controller { and XFree86. Eventually will be removed. */ unsigned int need_domain_info; - int iommu; - /* Optional access methods for reading/writing the bus number of the PCI controller */ int (*get_busno)(void); @@ -106,11 +104,11 @@ static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, struct pci_dev; /* - * The PCI address space does equal the physical memory address space. The - * networking and block device layers use this boolean for bounce buffer - * decisions. This is set if any hose does not have an IOMMU. + * The PCI address space does equal the physical memory address space. + * The networking and block device layers use this boolean for bounce + * buffer decisions. */ -extern unsigned int PCI_DMA_BUS_IS_PHYS; +#define PCI_DMA_BUS_IS_PHYS (1) #ifdef CONFIG_PCI_DOMAINS #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h index 832e216..d21f3da 100644 --- a/arch/mips/include/asm/pgtable-32.h +++ b/arch/mips/include/asm/pgtable-32.h @@ -103,8 +103,8 @@ static inline void pmd_clear(pmd_t *pmdp) pmd_val(*pmdp) = ((unsigned long) invalid_pte_table); } -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) -#define pte_page(x) pfn_to_page(pte_pfn(x)) +#if defined(CONFIG_XPA) + #define pte_pfn(x) (((unsigned long)((x).pte_high >> _PFN_SHIFT)) | (unsigned long)((x).pte_low << _PAGE_PRESENT_SHIFT)) static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) @@ -118,9 +118,21 @@ pfn_pte(unsigned long pfn, pgprot_t prot) return pte; } -#else +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) -#define pte_page(x) pfn_to_page(pte_pfn(x)) +#define pte_pfn(x) ((unsigned long)((x).pte_high >> 6)) + +static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) +{ + pte_t pte; + + pte.pte_high = (pfn << 6) | (pgprot_val(prot) & 0x3f); + pte.pte_low = pgprot_val(prot); + + return pte; +} + +#else #ifdef CONFIG_CPU_VR41XX #define pte_pfn(x) ((unsigned long)((x).pte >> (PAGE_SHIFT + 2))) @@ -131,6 +143,8 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #endif #endif /* defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) */ +#define pte_page(x) pfn_to_page(pte_pfn(x)) + #define __pgd_offset(address) pgd_index(address) #define __pud_offset(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) #define __pmd_offset(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) @@ -166,7 +180,7 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #else -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_XPA) /* Swap entries must have VALID and GLOBAL bits cleared. */ #define __swp_type(x) (((x).val >> 4) & 0x1f) @@ -175,6 +189,15 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high }) #define __swp_entry_to_pte(x) ((pte_t) { 0, (x).val }) +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) + +/* Swap entries must have VALID and GLOBAL bits cleared. */ +#define __swp_type(x) (((x).val >> 2) & 0x1f) +#define __swp_offset(x) ((x).val >> 7) +#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 7) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high }) +#define __swp_entry_to_pte(x) ((pte_t) { 0, (x).val }) + #else /* * Constraints: diff --git a/arch/mips/include/asm/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h index cf661a2..514cbc0 100644 --- a/arch/mips/include/asm/pgtable-64.h +++ b/arch/mips/include/asm/pgtable-64.h @@ -17,7 +17,7 @@ #include <asm/cachectl.h> #include <asm/fixmap.h> -#ifdef CONFIG_PAGE_SIZE_64KB +#if defined(CONFIG_PAGE_SIZE_64KB) && !defined(CONFIG_MIPS_VA_BITS_48) #include <asm-generic/pgtable-nopmd.h> #else #include <asm-generic/pgtable-nopud.h> @@ -90,7 +90,11 @@ #define PTE_ORDER 0 #endif #ifdef CONFIG_PAGE_SIZE_16KB -#define PGD_ORDER 0 +#ifdef CONFIG_MIPS_VA_BITS_48 +#define PGD_ORDER 1 +#else +#define PGD_ORDER 0 +#endif #define PUD_ORDER aieeee_attempt_to_allocate_pud #define PMD_ORDER 0 #define PTE_ORDER 0 @@ -104,7 +108,11 @@ #ifdef CONFIG_PAGE_SIZE_64KB #define PGD_ORDER 0 #define PUD_ORDER aieeee_attempt_to_allocate_pud +#ifdef CONFIG_MIPS_VA_BITS_48 +#define PMD_ORDER 0 +#else #define PMD_ORDER aieeee_attempt_to_allocate_pmd +#endif #define PTE_ORDER 0 #endif @@ -114,11 +122,7 @@ #endif #define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t)) -#if PGDIR_SIZE >= TASK_SIZE64 -#define USER_PTRS_PER_PGD (1) -#else -#define USER_PTRS_PER_PGD (TASK_SIZE64 / PGDIR_SIZE) -#endif +#define USER_PTRS_PER_PGD ((TASK_SIZE64 / PGDIR_SIZE)?(TASK_SIZE64 / PGDIR_SIZE):1) #define FIRST_USER_ADDRESS 0UL /* diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index 97b3138..f88a48c 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -32,149 +32,132 @@ * unpredictable things. The code (when it is written) to deal with * this problem will be in the update_mmu_cache() code for the r4k. */ -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_XPA) /* - * The following bits are implemented by the TLB hardware + * Page table bit offsets used for 64 bit physical addressing on + * MIPS32r5 with XPA. */ -#define _PAGE_NO_EXEC_SHIFT 0 -#define _PAGE_NO_EXEC (1 << _PAGE_NO_EXEC_SHIFT) -#define _PAGE_NO_READ_SHIFT (_PAGE_NO_EXEC_SHIFT + 1) -#define _PAGE_NO_READ (1 << _PAGE_NO_READ_SHIFT) -#define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1) -#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) -#define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) -#define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) -#define _PAGE_DIRTY_SHIFT (_PAGE_VALID_SHIFT + 1) -#define _PAGE_DIRTY (1 << _PAGE_DIRTY_SHIFT) -#define _CACHE_SHIFT (_PAGE_DIRTY_SHIFT + 1) -#define _CACHE_MASK (7 << _CACHE_SHIFT) - -/* - * The following bits are implemented in software - */ -#define _PAGE_PRESENT_SHIFT (24) -#define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) -#define _PAGE_READ_SHIFT (_PAGE_PRESENT_SHIFT + 1) -#define _PAGE_READ (1 << _PAGE_READ_SHIFT) -#define _PAGE_WRITE_SHIFT (_PAGE_READ_SHIFT + 1) -#define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT) -#define _PAGE_ACCESSED_SHIFT (_PAGE_WRITE_SHIFT + 1) -#define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT) -#define _PAGE_MODIFIED_SHIFT (_PAGE_ACCESSED_SHIFT + 1) -#define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) - -#define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) +enum pgtable_bits { + /* Used by TLB hardware (placed in EntryLo*) */ + _PAGE_NO_EXEC_SHIFT, + _PAGE_NO_READ_SHIFT, + _PAGE_GLOBAL_SHIFT, + _PAGE_VALID_SHIFT, + _PAGE_DIRTY_SHIFT, + _CACHE_SHIFT, + + /* Used only by software (masked out before writing EntryLo*) */ + _PAGE_PRESENT_SHIFT = 24, + _PAGE_WRITE_SHIFT, + _PAGE_ACCESSED_SHIFT, + _PAGE_MODIFIED_SHIFT, +}; /* * Bits for extended EntryLo0/EntryLo1 registers */ #define _PFNX_MASK 0xffffff -#elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) /* - * The following bits are implemented in software + * Page table bit offsets used for 36 bit physical addressing on MIPS32, + * for example with Alchemy or Netlogic XLP/XLR. */ -#define _PAGE_PRESENT_SHIFT (0) -#define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) -#define _PAGE_READ_SHIFT (_PAGE_PRESENT_SHIFT + 1) -#define _PAGE_READ (1 << _PAGE_READ_SHIFT) -#define _PAGE_WRITE_SHIFT (_PAGE_READ_SHIFT + 1) -#define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT) -#define _PAGE_ACCESSED_SHIFT (_PAGE_WRITE_SHIFT + 1) -#define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT) -#define _PAGE_MODIFIED_SHIFT (_PAGE_ACCESSED_SHIFT + 1) -#define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) +enum pgtable_bits { + /* Used by TLB hardware (placed in EntryLo*) */ + _PAGE_GLOBAL_SHIFT, + _PAGE_VALID_SHIFT, + _PAGE_DIRTY_SHIFT, + _CACHE_SHIFT, + + /* Used only by software (masked out before writing EntryLo*) */ + _PAGE_PRESENT_SHIFT = _CACHE_SHIFT + 3, + _PAGE_NO_READ_SHIFT, + _PAGE_WRITE_SHIFT, + _PAGE_ACCESSED_SHIFT, + _PAGE_MODIFIED_SHIFT, +}; -/* - * The following bits are implemented by the TLB hardware - */ -#define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 4) -#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) -#define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) -#define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) -#define _PAGE_DIRTY_SHIFT (_PAGE_VALID_SHIFT + 1) -#define _PAGE_DIRTY (1 << _PAGE_DIRTY_SHIFT) -#define _CACHE_UNCACHED_SHIFT (_PAGE_DIRTY_SHIFT + 1) -#define _CACHE_UNCACHED (1 << _CACHE_UNCACHED_SHIFT) -#define _CACHE_MASK _CACHE_UNCACHED +#elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) -#define _PFN_SHIFT PAGE_SHIFT +/* Page table bits used for r3k systems */ +enum pgtable_bits { + /* Used only by software (writes to EntryLo ignored) */ + _PAGE_PRESENT_SHIFT, + _PAGE_NO_READ_SHIFT, + _PAGE_WRITE_SHIFT, + _PAGE_ACCESSED_SHIFT, + _PAGE_MODIFIED_SHIFT, + + /* Used by TLB hardware (placed in EntryLo) */ + _PAGE_GLOBAL_SHIFT = 8, + _PAGE_VALID_SHIFT, + _PAGE_DIRTY_SHIFT, + _CACHE_UNCACHED_SHIFT, +}; #else -/* - * Below are the "Normal" R4K cases - */ -/* - * The following bits are implemented in software - */ -#define _PAGE_PRESENT_SHIFT 0 +/* Page table bits used for r4k systems */ +enum pgtable_bits { + /* Used only by software (masked out before writing EntryLo*) */ + _PAGE_PRESENT_SHIFT, +#if !defined(CONFIG_CPU_HAS_RIXI) + _PAGE_NO_READ_SHIFT, +#endif + _PAGE_WRITE_SHIFT, + _PAGE_ACCESSED_SHIFT, + _PAGE_MODIFIED_SHIFT, +#if defined(CONFIG_64BIT) && defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) + _PAGE_HUGE_SHIFT, +#endif + + /* Used by TLB hardware (placed in EntryLo*) */ +#if defined(CONFIG_CPU_HAS_RIXI) + _PAGE_NO_EXEC_SHIFT, + _PAGE_NO_READ_SHIFT, +#endif + _PAGE_GLOBAL_SHIFT, + _PAGE_VALID_SHIFT, + _PAGE_DIRTY_SHIFT, + _CACHE_SHIFT, +}; + +#endif /* defined(CONFIG_PHYS_ADDR_T_64BIT && defined(CONFIG_CPU_MIPS32) */ + +/* Used only by software */ #define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) -/* R2 or later cores check for RI/XI support to determine _PAGE_READ */ -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) -#define _PAGE_WRITE_SHIFT (_PAGE_PRESENT_SHIFT + 1) -#define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT) -#else -#define _PAGE_READ_SHIFT (_PAGE_PRESENT_SHIFT + 1) -#define _PAGE_READ (1 << _PAGE_READ_SHIFT) -#define _PAGE_WRITE_SHIFT (_PAGE_READ_SHIFT + 1) #define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT) -#endif -#define _PAGE_ACCESSED_SHIFT (_PAGE_WRITE_SHIFT + 1) #define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT) -#define _PAGE_MODIFIED_SHIFT (_PAGE_ACCESSED_SHIFT + 1) #define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) - #if defined(CONFIG_64BIT) && defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) -/* Huge TLB page */ -#define _PAGE_HUGE_SHIFT (_PAGE_MODIFIED_SHIFT + 1) -#define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) -#endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */ - -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) -/* XI - page cannot be executed */ -#ifdef _PAGE_HUGE_SHIFT -#define _PAGE_NO_EXEC_SHIFT (_PAGE_HUGE_SHIFT + 1) -#else -#define _PAGE_NO_EXEC_SHIFT (_PAGE_MODIFIED_SHIFT + 1) +# define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) #endif -#define _PAGE_NO_EXEC (cpu_has_rixi ? (1 << _PAGE_NO_EXEC_SHIFT) : 0) - -/* RI - page cannot be read */ -#define _PAGE_READ_SHIFT (_PAGE_NO_EXEC_SHIFT + 1) -#define _PAGE_READ (cpu_has_rixi ? 0 : (1 << _PAGE_READ_SHIFT)) -#define _PAGE_NO_READ_SHIFT _PAGE_READ_SHIFT -#define _PAGE_NO_READ (cpu_has_rixi ? (1 << _PAGE_READ_SHIFT) : 0) -#endif /* defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) */ - -#if defined(_PAGE_NO_READ_SHIFT) -#define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1) -#elif defined(_PAGE_HUGE_SHIFT) -#define _PAGE_GLOBAL_SHIFT (_PAGE_HUGE_SHIFT + 1) -#else -#define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1) + +/* Used by TLB hardware (placed in EntryLo*) */ +#if defined(CONFIG_XPA) +# define _PAGE_NO_EXEC (1 << _PAGE_NO_EXEC_SHIFT) +#elif defined(CONFIG_CPU_HAS_RIXI) +# define _PAGE_NO_EXEC (cpu_has_rixi ? (1 << _PAGE_NO_EXEC_SHIFT) : 0) #endif +#define _PAGE_NO_READ (1 << _PAGE_NO_READ_SHIFT) #define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) - -#define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) #define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) -#define _PAGE_DIRTY_SHIFT (_PAGE_VALID_SHIFT + 1) #define _PAGE_DIRTY (1 << _PAGE_DIRTY_SHIFT) -#define _CACHE_SHIFT (_PAGE_DIRTY_SHIFT + 1) -#define _CACHE_MASK (7 << _CACHE_SHIFT) - -#define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) - -#endif /* defined(CONFIG_PHYS_ADDR_T_64BIT && defined(CONFIG_CPU_MIPS32) */ +#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) +# define _CACHE_UNCACHED (1 << _CACHE_UNCACHED_SHIFT) +# define _CACHE_MASK _CACHE_UNCACHED +# define _PFN_SHIFT PAGE_SHIFT +#else +# define _CACHE_MASK (7 << _CACHE_SHIFT) +# define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) +#endif #ifndef _PAGE_NO_EXEC #define _PAGE_NO_EXEC 0 #endif -#ifndef _PAGE_NO_READ -#define _PAGE_NO_READ 0 -#endif #define _PAGE_SILENT_READ _PAGE_VALID #define _PAGE_SILENT_WRITE _PAGE_DIRTY @@ -191,14 +174,13 @@ */ -#ifndef __ASSEMBLY__ /* * pte_to_entrylo converts a page table entry (PTE) into a Mips * entrylo0/1 value. */ static inline uint64_t pte_to_entrylo(unsigned long pte_val) { -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) +#ifdef CONFIG_CPU_HAS_RIXI if (cpu_has_rixi) { int sa; #ifdef CONFIG_32BIT @@ -218,7 +200,6 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) return pte_val >> _PAGE_GLOBAL_SHIFT; } -#endif /* * Cache attributes @@ -274,7 +255,7 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) #define _CACHE_UNCACHED_ACCELERATED (7<<_CACHE_SHIFT) #endif -#define __READABLE (_PAGE_SILENT_READ | _PAGE_READ | _PAGE_ACCESSED) +#define __READABLE (_PAGE_SILENT_READ | _PAGE_ACCESSED) #define __WRITEABLE (_PAGE_SILENT_WRITE | _PAGE_WRITE | _PAGE_MODIFIED) #define _PAGE_CHG_MASK (_PAGE_ACCESSED | _PAGE_MODIFIED | \ diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index f53a7e3a4..a6b611f 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -23,18 +23,19 @@ struct mm_struct; struct vm_area_struct; -#define PAGE_NONE __pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_NONCOHERENT) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_WRITE | _PAGE_READ | \ +#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_NO_READ | \ + _CACHE_CACHABLE_NONCOHERENT) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_WRITE | \ _page_cachable_default) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_NO_EXEC | \ +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_NO_EXEC | \ _page_cachable_default) -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_READ | \ +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | \ _page_cachable_default) #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ _PAGE_GLOBAL | _page_cachable_default) #define PAGE_KERNEL_NC __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ _PAGE_GLOBAL | _CACHE_CACHABLE_NONCOHERENT) -#define PAGE_USERIO __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ +#define PAGE_USERIO __pgprot(_PAGE_PRESENT | _PAGE_WRITE | \ _page_cachable_default) #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | \ __WRITEABLE | _PAGE_GLOBAL | _CACHE_UNCACHED) @@ -127,10 +128,19 @@ do { \ } \ } while(0) +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval); + #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) -#define pte_none(pte) (!(((pte).pte_high) & ~_PAGE_GLOBAL)) +#ifdef CONFIG_XPA +# define pte_none(pte) (!(((pte).pte_high) & ~_PAGE_GLOBAL)) +#else +# define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL)) +#endif + #define pte_present(pte) ((pte).pte_low & _PAGE_PRESENT) +#define pte_no_exec(pte) ((pte).pte_low & _PAGE_NO_EXEC) static inline void set_pte(pte_t *ptep, pte_t pte) { @@ -138,17 +148,23 @@ static inline void set_pte(pte_t *ptep, pte_t pte) smp_wmb(); ptep->pte_low = pte.pte_low; +#ifdef CONFIG_XPA if (pte.pte_high & _PAGE_GLOBAL) { +#else + if (pte.pte_low & _PAGE_GLOBAL) { +#endif pte_t *buddy = ptep_buddy(ptep); /* * Make sure the buddy is global too (if it's !none, * it better already be global) */ - if (pte_none(*buddy)) + if (pte_none(*buddy)) { + if (!config_enabled(CONFIG_XPA)) + buddy->pte_low |= _PAGE_GLOBAL; buddy->pte_high |= _PAGE_GLOBAL; + } } } -#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { @@ -156,8 +172,13 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt htw_stop(); /* Preserve global status for the pair */ - if (ptep_buddy(ptep)->pte_high & _PAGE_GLOBAL) - null.pte_high = _PAGE_GLOBAL; + if (config_enabled(CONFIG_XPA)) { + if (ptep_buddy(ptep)->pte_high & _PAGE_GLOBAL) + null.pte_high = _PAGE_GLOBAL; + } else { + if (ptep_buddy(ptep)->pte_low & _PAGE_GLOBAL) + null.pte_low = null.pte_high = _PAGE_GLOBAL; + } set_pte_at(mm, addr, ptep, null); htw_start(); @@ -166,6 +187,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt #define pte_none(pte) (!(pte_val(pte) & ~_PAGE_GLOBAL)) #define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) +#define pte_no_exec(pte) (pte_val(pte) & _PAGE_NO_EXEC) /* * Certain architectures need to do special things when pte's @@ -187,30 +209,42 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) * For SMP, multiple CPUs can race, so we need to do * this atomically. */ -#ifdef CONFIG_64BIT -#define LL_INSN "lld" -#define SC_INSN "scd" -#else /* CONFIG_32BIT */ -#define LL_INSN "ll" -#define SC_INSN "sc" -#endif unsigned long page_global = _PAGE_GLOBAL; unsigned long tmp; - __asm__ __volatile__ ( - " .set push\n" - " .set noreorder\n" - "1: " LL_INSN " %[tmp], %[buddy]\n" - " bnez %[tmp], 2f\n" - " or %[tmp], %[tmp], %[global]\n" - " " SC_INSN " %[tmp], %[buddy]\n" - " beqz %[tmp], 1b\n" - " nop\n" - "2:\n" - " .set pop" - : [buddy] "+m" (buddy->pte), - [tmp] "=&r" (tmp) + if (kernel_uses_llsc && R10000_LLSC_WAR) { + __asm__ __volatile__ ( + " .set arch=r4000 \n" + " .set push \n" + " .set noreorder \n" + "1:" __LL "%[tmp], %[buddy] \n" + " bnez %[tmp], 2f \n" + " or %[tmp], %[tmp], %[global] \n" + __SC "%[tmp], %[buddy] \n" + " beqzl %[tmp], 1b \n" + " nop \n" + "2: \n" + " .set pop \n" + " .set mips0 \n" + : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp) + : [global] "r" (page_global)); + } else if (kernel_uses_llsc) { + __asm__ __volatile__ ( + " .set "MIPS_ISA_ARCH_LEVEL" \n" + " .set push \n" + " .set noreorder \n" + "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" + " .set pop \n" + " .set mips0 \n" + : [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; @@ -218,7 +252,6 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) } #endif } -#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { @@ -234,6 +267,22 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt } #endif +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval) +{ + extern void __update_cache(unsigned long address, pte_t pte); + + if (!pte_present(pteval)) + goto cache_sync_done; + + if (pte_present(*ptep) && (pte_pfn(*ptep) == pte_pfn(pteval))) + goto cache_sync_done; + + __update_cache(addr, pteval); +cache_sync_done: + set_pte(ptep, pteval); +} + /* * (pmds are folded into puds so this doesn't get actually called, * but the define is needed for a generic inline function.) @@ -270,6 +319,8 @@ static inline int pte_young(pte_t pte) { return pte.pte_low & _PAGE_ACCESSED; } static inline pte_t pte_wrprotect(pte_t pte) { pte.pte_low &= ~_PAGE_WRITE; + if (!config_enabled(CONFIG_XPA)) + pte.pte_low &= ~_PAGE_SILENT_WRITE; pte.pte_high &= ~_PAGE_SILENT_WRITE; return pte; } @@ -277,6 +328,8 @@ static inline pte_t pte_wrprotect(pte_t pte) static inline pte_t pte_mkclean(pte_t pte) { pte.pte_low &= ~_PAGE_MODIFIED; + if (!config_enabled(CONFIG_XPA)) + pte.pte_low &= ~_PAGE_SILENT_WRITE; pte.pte_high &= ~_PAGE_SILENT_WRITE; return pte; } @@ -284,6 +337,8 @@ static inline pte_t pte_mkclean(pte_t pte) static inline pte_t pte_mkold(pte_t pte) { pte.pte_low &= ~_PAGE_ACCESSED; + if (!config_enabled(CONFIG_XPA)) + pte.pte_low &= ~_PAGE_SILENT_READ; pte.pte_high &= ~_PAGE_SILENT_READ; return pte; } @@ -291,24 +346,33 @@ static inline pte_t pte_mkold(pte_t pte) static inline pte_t pte_mkwrite(pte_t pte) { pte.pte_low |= _PAGE_WRITE; - if (pte.pte_low & _PAGE_MODIFIED) + if (pte.pte_low & _PAGE_MODIFIED) { + if (!config_enabled(CONFIG_XPA)) + pte.pte_low |= _PAGE_SILENT_WRITE; pte.pte_high |= _PAGE_SILENT_WRITE; + } return pte; } static inline pte_t pte_mkdirty(pte_t pte) { pte.pte_low |= _PAGE_MODIFIED; - if (pte.pte_low & _PAGE_WRITE) + if (pte.pte_low & _PAGE_WRITE) { + if (!config_enabled(CONFIG_XPA)) + pte.pte_low |= _PAGE_SILENT_WRITE; pte.pte_high |= _PAGE_SILENT_WRITE; + } return pte; } static inline pte_t pte_mkyoung(pte_t pte) { pte.pte_low |= _PAGE_ACCESSED; - if (pte.pte_low & _PAGE_READ) + if (!(pte.pte_low & _PAGE_NO_READ)) { + if (!config_enabled(CONFIG_XPA)) + pte.pte_low |= _PAGE_SILENT_READ; pte.pte_high |= _PAGE_SILENT_READ; + } return pte; } #else @@ -353,13 +417,8 @@ static inline pte_t pte_mkdirty(pte_t pte) static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) if (!(pte_val(pte) & _PAGE_NO_READ)) pte_val(pte) |= _PAGE_SILENT_READ; - else -#endif - if (pte_val(pte) & _PAGE_READ) - pte_val(pte) |= _PAGE_SILENT_READ; return pte; } @@ -411,7 +470,7 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot) */ #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_XPA) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte.pte_low &= (_PAGE_MODIFIED | _PAGE_ACCESSED | _PFNX_MASK); @@ -420,6 +479,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) pte.pte_high |= pgprot_val(newprot) & ~_PFN_MASK; return pte; } +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte.pte_low &= _PAGE_CHG_MASK; + pte.pte_high &= (_PFN_MASK | _CACHE_MASK); + pte.pte_low |= pgprot_val(newprot); + pte.pte_high |= pgprot_val(newprot) & ~(_PFN_MASK | _CACHE_MASK); + return pte; +} #else static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { @@ -430,15 +498,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) extern void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte); -extern void __update_cache(struct vm_area_struct *vma, unsigned long address, - pte_t pte); static inline void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { pte_t pte = *ptep; __update_tlb(vma, address, pte); - __update_cache(vma, address, pte); } static inline void update_mmu_cache_pmd(struct vm_area_struct *vma, @@ -543,13 +608,8 @@ static inline pmd_t pmd_mkyoung(pmd_t pmd) { pmd_val(pmd) |= _PAGE_ACCESSED; -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) if (!(pmd_val(pmd) & _PAGE_NO_READ)) pmd_val(pmd) |= _PAGE_SILENT_READ; - else -#endif - if (pmd_val(pmd) & _PAGE_READ) - pmd_val(pmd) |= _PAGE_SILENT_READ; return pmd; } diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 041153f..7e78b62 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -63,7 +63,11 @@ extern unsigned int vced_count, vcei_count; * 8192EB ... */ #define TASK_SIZE32 0x7fff8000UL -#define TASK_SIZE64 0x10000000000UL +#ifdef CONFIG_MIPS_VA_BITS_48 +#define TASK_SIZE64 (0x1UL << ((cpu_data[0].vmbits>48)?48:cpu_data[0].vmbits)) +#else +#define TASK_SIZE64 0x10000000000UL +#endif #define TASK_SIZE (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE64) #define STACK_TOP_MAX TASK_SIZE64 @@ -355,6 +359,10 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk); */ 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) + \ diff --git a/arch/mips/include/asm/seccomp.h b/arch/mips/include/asm/seccomp.h index 1d8a2e2..684fb3a 100644 --- a/arch/mips/include/asm/seccomp.h +++ b/arch/mips/include/asm/seccomp.h @@ -2,27 +2,32 @@ #include <linux/unistd.h> -/* - * Kludge alert: - * - * The generic seccomp code currently allows only a single compat ABI. Until - * this is fixed we priorize O32 as the compat ABI over N32. - */ -#ifdef CONFIG_MIPS32_O32 - -#define __NR_seccomp_read_32 4003 -#define __NR_seccomp_write_32 4004 -#define __NR_seccomp_exit_32 4001 -#define __NR_seccomp_sigreturn_32 4193 /* rt_sigreturn */ - -#elif defined(CONFIG_MIPS32_N32) - -#define __NR_seccomp_read_32 6000 -#define __NR_seccomp_write_32 6001 -#define __NR_seccomp_exit_32 6058 -#define __NR_seccomp_sigreturn_32 6211 /* rt_sigreturn */ - -#endif /* CONFIG_MIPS32_O32 */ +#ifdef CONFIG_COMPAT +static inline const int *get_compat_mode1_syscalls(void) +{ + static const int syscalls_O32[] = { + __NR_O32_Linux + 3, __NR_O32_Linux + 4, + __NR_O32_Linux + 1, __NR_O32_Linux + 193, + 0, /* null terminated */ + }; + static const int syscalls_N32[] = { + __NR_N32_Linux + 0, __NR_N32_Linux + 1, + __NR_N32_Linux + 58, __NR_N32_Linux + 211, + 0, /* null terminated */ + }; + + if (config_enabled(CONFIG_MIPS32_O32) && test_thread_flag(TIF_32BIT_REGS)) + return syscalls_O32; + + if (config_enabled(CONFIG_MIPS32_N32)) + return syscalls_N32; + + BUG(); +} + +#define get_compat_mode1_syscalls get_compat_mode1_syscalls + +#endif /* CONFIG_COMPAT */ #include <asm-generic/seccomp.h> diff --git a/arch/mips/include/asm/sibyte/bcm1480_regs.h b/arch/mips/include/asm/sibyte/bcm1480_regs.h index ec0dacf..32a8483 100644 --- a/arch/mips/include/asm/sibyte/bcm1480_regs.h +++ b/arch/mips/include/asm/sibyte/bcm1480_regs.h @@ -415,8 +415,8 @@ (cpu)*BCM1480_IMR_ALIAS_MAILBOX_SPACING) #define A_BCM1480_IMR_ALIAS_MAILBOX_REGISTER(cpu, reg) (A_BCM1480_IMR_ALIAS_MAILBOX(cpu)+(reg)) -#define R_BCM1480_IMR_ALIAS_MAILBOX_0 0x0000 /* 0x0x0 */ -#define R_BCM1480_IMR_ALIAS_MAILBOX_0_SET 0x0008 /* 0x0x8 */ +#define R_BCM1480_IMR_ALIAS_MAILBOX_0 0x0000 +#define R_BCM1480_IMR_ALIAS_MAILBOX_0_SET 0x0008 /* * these macros work together to build the address of a mailbox diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h index 003e273..2292373 100644 --- a/arch/mips/include/asm/signal.h +++ b/arch/mips/include/asm/signal.h @@ -11,11 +11,17 @@ #include <uapi/asm/signal.h> +#ifdef CONFIG_MIPS32_COMPAT +extern struct mips_abi mips_abi_32; -#ifdef CONFIG_TRAD_SIGNALS -#define sig_uses_siginfo(ka) ((ka)->sa.sa_flags & SA_SIGINFO) +#define sig_uses_siginfo(ka, abi) \ + ((abi != &mips_abi_32) ? 1 : \ + ((ka)->sa.sa_flags & SA_SIGINFO)) #else -#define sig_uses_siginfo(ka) (1) +#define sig_uses_siginfo(ka, abi) \ + (config_enabled(CONFIG_64BIT) ? 1 : \ + (config_enabled(CONFIG_TRAD_SIGNALS) ? \ + ((ka)->sa.sa_flags & SA_SIGINFO) : 1) ) #endif #include <asm/sigcontext.h> diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h index 326c16e..2ae1f61 100644 --- a/arch/mips/include/asm/smp-cps.h +++ b/arch/mips/include/asm/smp-cps.h @@ -29,7 +29,7 @@ extern struct core_boot_config *mips_cps_core_bootcfg; extern void mips_cps_core_entry(void); extern void mips_cps_core_init(void); -extern struct vpe_boot_config *mips_cps_boot_vpes(void); +extern void mips_cps_boot_vpes(struct core_boot_config *cfg, unsigned vpe); extern void mips_cps_pm_save(void); extern void mips_cps_pm_restore(void); diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index 28b5d84a..ebb5c0f 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -105,7 +105,7 @@ do { \ __clear_software_ll_bit(); \ if (cpu_has_userlocal) \ write_c0_userlocal(task_thread_info(next)->tp_value); \ - __restore_watch(); \ + __restore_watch(next); \ (last) = resume(prev, next, task_thread_info(next)); \ } while (0) diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index fc1cdd2..b6ecfee 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h @@ -171,7 +171,8 @@ Ip_u2u1(_wsbh); Ip_u3u1u2(_xor); Ip_u2u1u3(_xori); Ip_u2u1(_yield); - +Ip_u1u2(_ldpte); +Ip_u2u1u3(_lddir); /* Handle labels. */ struct uasm_label { diff --git a/arch/mips/include/asm/watch.h b/arch/mips/include/asm/watch.h index 20126ec..6ffe3ea 100644 --- a/arch/mips/include/asm/watch.h +++ b/arch/mips/include/asm/watch.h @@ -12,21 +12,21 @@ #include <asm/mipsregs.h> -void mips_install_watch_registers(void); +void mips_install_watch_registers(struct task_struct *t); void mips_read_watch_registers(void); void mips_clear_watch_registers(void); void mips_probe_watch_registers(struct cpuinfo_mips *c); #ifdef CONFIG_HARDWARE_WATCHPOINTS -#define __restore_watch() do { \ +#define __restore_watch(task) do { \ if (unlikely(test_bit(TIF_LOAD_WATCH, \ - ¤t_thread_info()->flags))) { \ - mips_install_watch_registers(); \ + &task_thread_info(task)->flags))) { \ + mips_install_watch_registers(task); \ } \ } while (0) #else -#define __restore_watch() do {} while (0) +#define __restore_watch(task) do {} while (0) #endif #endif /* _ASM_WATCH_H */ diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index ddea53e..8051f9a 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -167,6 +167,7 @@ enum cop1_sdw_func { fceill_op = 0x0a, ffloorl_op = 0x0b, fround_op = 0x0c, ftrunc_op = 0x0d, fceil_op = 0x0e, ffloor_op = 0x0f, + fsel_op = 0x10, fmovc_op = 0x11, fmovz_op = 0x12, fmovn_op = 0x13, fseleqz_op = 0x14, frecip_op = 0x15, frsqrt_op = 0x16, @@ -204,6 +205,16 @@ enum mad_func { }; /* + * func field for page table walker (Loongson-3). + */ +enum ptw_func { + lwdir_op = 0x00, + lwpte_op = 0x01, + lddir_op = 0x02, + ldpte_op = 0x03, +}; + +/* * func field for special3 lx opcodes (Cavium Octeon). */ enum lx_func { diff --git a/arch/mips/include/uapi/asm/siginfo.h b/arch/mips/include/uapi/asm/siginfo.h index cc49dc2..8069cf7 100644 --- a/arch/mips/include/uapi/asm/siginfo.h +++ b/arch/mips/include/uapi/asm/siginfo.h @@ -28,7 +28,7 @@ #define __ARCH_SIGSYS -#include <uapi/asm-generic/siginfo.h> +#include <asm-generic/siginfo.h> /* We can't use generic siginfo_t, because our si_code and si_errno are swapped */ typedef struct siginfo { @@ -42,13 +42,13 @@ typedef struct siginfo { /* kill() */ struct { - pid_t _pid; /* sender's pid */ + __kernel_pid_t _pid; /* sender's pid */ __ARCH_SI_UID_T _uid; /* sender's uid */ } _kill; /* POSIX.1b timers */ struct { - timer_t _tid; /* timer id */ + __kernel_timer_t _tid; /* timer id */ int _overrun; /* overrun count */ char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)]; sigval_t _sigval; /* same as below */ @@ -57,26 +57,26 @@ typedef struct siginfo { /* POSIX.1b signals */ struct { - pid_t _pid; /* sender's pid */ + __kernel_pid_t _pid; /* sender's pid */ __ARCH_SI_UID_T _uid; /* sender's uid */ sigval_t _sigval; } _rt; /* SIGCHLD */ struct { - pid_t _pid; /* which child */ + __kernel_pid_t _pid; /* which child */ __ARCH_SI_UID_T _uid; /* sender's uid */ int _status; /* exit code */ - clock_t _utime; - clock_t _stime; + __kernel_clock_t _utime; + __kernel_clock_t _stime; } _sigchld; /* IRIX SIGCHLD */ struct { - pid_t _pid; /* which child */ - clock_t _utime; + __kernel_pid_t _pid; /* which child */ + __kernel_clock_t _utime; int _status; /* exit code */ - clock_t _stime; + __kernel_clock_t _stime; } _irix_sigchld; /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ @@ -123,6 +123,4 @@ typedef struct siginfo { #define SI_TIMER __SI_CODE(__SI_TIMER, -3) /* sent by timer expiration */ #define SI_MESGQ __SI_CODE(__SI_MESGQ, -4) /* sent by real time mesq state change */ -#include <asm-generic/siginfo.h> - #endif /* _UAPI_ASM_SIGINFO_H */ diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 934b15b..4e3f9b7a 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -39,8 +39,6 @@ #include "clock.h" -static bool is_avt2; - /* GPIOs */ #define QI_LB60_GPIO_SD_CD JZ_GPIO_PORTD(0) #define QI_LB60_GPIO_SD_VCC_EN_N JZ_GPIO_PORTD(2) @@ -367,43 +365,12 @@ static struct jz4740_mmc_platform_data qi_lb60_mmc_pdata = { .power_active_low = 1, }; -/* OHCI */ -static struct regulator_consumer_supply avt2_usb_regulator_consumer = - REGULATOR_SUPPLY("vbus", "jz4740-ohci"); - -static struct regulator_init_data avt2_usb_regulator_init_data = { - .num_consumer_supplies = 1, - .consumer_supplies = &avt2_usb_regulator_consumer, - .constraints = { - .name = "USB power", - .min_uV = 5000000, - .max_uV = 5000000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .valid_ops_mask = REGULATOR_CHANGE_STATUS, - }, -}; - -static struct fixed_voltage_config avt2_usb_regulator_data = { - .supply_name = "USB power", - .microvolts = 5000000, - .gpio = JZ_GPIO_PORTB(17), - .init_data = &avt2_usb_regulator_init_data, -}; - -static struct platform_device avt2_usb_regulator_device = { - .name = "reg-fixed-voltage", - .id = -1, - .dev = { - .platform_data = &avt2_usb_regulator_data, - } -}; - +/* beeper */ static struct pwm_lookup qi_lb60_pwm_lookup[] = { PWM_LOOKUP("jz4740-pwm", 4, "pwm-beeper", NULL, 0, PWM_POLARITY_NORMAL), }; -/* beeper */ static struct platform_device qi_lb60_pwm_beeper = { .name = "pwm-beeper", .id = -1, @@ -487,11 +454,6 @@ static int __init qi_lb60_init_platform_devices(void) spi_register_board_info(qi_lb60_spi_board_info, ARRAY_SIZE(qi_lb60_spi_board_info)); - if (is_avt2) { - platform_device_register(&avt2_usb_regulator_device); - platform_device_register(&jz4740_usb_ohci_device); - } - pwm_add_table(qi_lb60_pwm_lookup, ARRAY_SIZE(qi_lb60_pwm_lookup)); return platform_add_devices(jz_platform_devices, @@ -499,19 +461,9 @@ static int __init qi_lb60_init_platform_devices(void) } -static __init int board_avt2(char *str) -{ - qi_lb60_mmc_pdata.card_detect_active_low = 1; - is_avt2 = true; - - return 1; -} -__setup("avt2", board_avt2); - static int __init qi_lb60_board_setup(void) { - printk(KERN_INFO "Qi Hardware JZ4740 QI %s setup\n", - is_avt2 ? "AVT2" : "LB60"); + printk(KERN_INFO "Qi Hardware JZ4740 QI LB60 setup\n"); board_gpio_setup(); diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c index e8a463b..2f1dab3 100644 --- a/arch/mips/jz4740/platform.c +++ b/arch/mips/jz4740/platform.c @@ -32,31 +32,6 @@ #include "clock.h" -/* OHCI controller */ -static struct resource jz4740_usb_ohci_resources[] = { - { - .start = JZ4740_UHC_BASE_ADDR, - .end = JZ4740_UHC_BASE_ADDR + 0x1000 - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = JZ4740_IRQ_UHC, - .end = JZ4740_IRQ_UHC, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device jz4740_usb_ohci_device = { - .name = "jz4740-ohci", - .id = -1, - .dev = { - .dma_mask = &jz4740_usb_ohci_device.dev.coherent_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = ARRAY_SIZE(jz4740_usb_ohci_resources), - .resource = jz4740_usb_ohci_resources, -}; - /* USB Device Controller */ struct platform_device jz4740_udc_xceiv_device = { .name = "usb_phy_generic", diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index b0988fd..e6053d0 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -44,7 +44,7 @@ obj-$(CONFIG_CPU_CAVIUM_OCTEON) += r4k_fpu.o octeon_switch.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP_UP) += smp-up.o -obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o +obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o bmips_5xxx_init.o obj-$(CONFIG_MIPS_MT) += mips-mt.o obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o @@ -83,6 +83,8 @@ obj-$(CONFIG_I8253) += i8253.o obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o +obj-$(CONFIG_RELOCATABLE) += relocate.o + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 154e203..1ea973b 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -14,6 +14,7 @@ #include <linux/mm.h> #include <linux/kbuild.h> #include <linux/suspend.h> +#include <asm/cpu-info.h> #include <asm/pm.h> #include <asm/ptrace.h> #include <asm/processor.h> @@ -338,6 +339,15 @@ void output_pm_defines(void) } #endif +void output_cpuinfo_defines(void) +{ + COMMENT(" MIPS cpuinfo offsets. "); + DEFINE(CPUINFO_SIZE, sizeof(struct cpuinfo_mips)); +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + OFFSET(CPUINFO_ASID_MASK, cpuinfo_mips, asid_mask); +#endif +} + void output_kvm_defines(void) { COMMENT(" KVM/MIPS Specfic offsets. "); diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c index 1b992c6..58ad63d 100644 --- a/arch/mips/kernel/binfmt_elfn32.c +++ b/arch/mips/kernel/binfmt_elfn32.c @@ -30,21 +30,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; /* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(hdr) \ -({ \ - int __res = 1; \ - struct elfhdr *__h = (hdr); \ - \ - if (!mips_elf_check_machine(__h)) \ - __res = 0; \ - if (__h->e_ident[EI_CLASS] != ELFCLASS32) \ - __res = 0; \ - if (((__h->e_flags & EF_MIPS_ABI2) == 0) || \ - ((__h->e_flags & EF_MIPS_ABI) != 0)) \ - __res = 0; \ - \ - __res; \ -}) +#define elf_check_arch elfn32_check_arch #define TASK32_SIZE 0x7fff8000UL #undef ELF_ET_DYN_BASE diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index abd3aff..49fb881 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -28,39 +28,9 @@ typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; /* - * In order to be sure that we don't attempt to execute an O32 binary which - * requires 64 bit FP (FR=1) on a system which does not support it we refuse - * to execute any binary which has bits specified by the following macro set - * in its ELF header flags. - */ -#ifdef CONFIG_MIPS_O32_FP64_SUPPORT -# define __MIPS_O32_FP64_MUST_BE_ZERO 0 -#else -# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64 -#endif - -/* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(hdr) \ -({ \ - int __res = 1; \ - struct elfhdr *__h = (hdr); \ - \ - if (!mips_elf_check_machine(__h)) \ - __res = 0; \ - if (__h->e_ident[EI_CLASS] != ELFCLASS32) \ - __res = 0; \ - if ((__h->e_flags & EF_MIPS_ABI2) != 0) \ - __res = 0; \ - if (((__h->e_flags & EF_MIPS_ABI) != 0) && \ - ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \ - __res = 0; \ - if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \ - __res = 0; \ - \ - __res; \ -}) +#define elf_check_arch elfo32_check_arch #ifdef CONFIG_KVM_GUEST #define TASK32_SIZE 0x3fff8000UL diff --git a/arch/mips/kernel/bmips_5xxx_init.S b/arch/mips/kernel/bmips_5xxx_init.S new file mode 100644 index 0000000..adaa82e --- /dev/null +++ b/arch/mips/kernel/bmips_5xxx_init.S @@ -0,0 +1,753 @@ + +/* + * 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. + * + * Copyright (C) 2011-2012 by Broadcom Corporation + * + * Init for bmips 5000. + * Used to init second core in dual core 5000's. + */ + +#include <linux/init.h> + +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/cacheops.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/stackframe.h> +#include <asm/addrspace.h> +#include <asm/hazards.h> +#include <asm/bmips.h> + +#ifdef CONFIG_CPU_BMIPS5000 + + +#define cacheop(kva, size, linesize, op) \ + .set noreorder ; \ + addu t1, kva, size ; \ + subu t2, linesize, 1 ; \ + not t2 ; \ + and t0, kva, t2 ; \ + addiu t1, t1, -1 ; \ + and t1, t2 ; \ +9: cache op, 0(t0) ; \ + bne t0, t1, 9b ; \ + addu t0, linesize ; \ + .set reorder ; + + + +#define IS_SHIFT 22 +#define IL_SHIFT 19 +#define IA_SHIFT 16 +#define DS_SHIFT 13 +#define DL_SHIFT 10 +#define DA_SHIFT 7 +#define IS_MASK 7 +#define IL_MASK 7 +#define IA_MASK 7 +#define DS_MASK 7 +#define DL_MASK 7 +#define DA_MASK 7 +#define ICE_MASK 0x80000000 +#define DCE_MASK 0x40000000 + +#define CP0_BRCM_CONFIG0 $22, 0 +#define CP0_BRCM_MODE $22, 1 +#define CP0_CONFIG_K0_MASK 7 + +#define CP0_ICACHE_TAG_LO $28 +#define CP0_ICACHE_DATA_LO $28, 1 +#define CP0_DCACHE_TAG_LO $28, 2 +#define CP0_D_SEC_CACHE_DATA_LO $28, 3 +#define CP0_ICACHE_TAG_HI $29 +#define CP0_ICACHE_DATA_HI $29, 1 +#define CP0_DCACHE_TAG_HI $29, 2 + +#define CP0_BRCM_MODE_Luc_MASK (1 << 11) +#define CP0_BRCM_CONFIG0_CWF_MASK (1 << 20) +#define CP0_BRCM_CONFIG0_TSE_MASK (1 << 19) +#define CP0_BRCM_MODE_SET_MASK (1 << 7) +#define CP0_BRCM_MODE_ClkRATIO_MASK (7 << 4) +#define CP0_BRCM_MODE_BrPRED_MASK (3 << 24) +#define CP0_BRCM_MODE_BrPRED_SHIFT 24 +#define CP0_BRCM_MODE_BrHIST_MASK (0x1f << 20) +#define CP0_BRCM_MODE_BrHIST_SHIFT 20 + +/* ZSC L2 Cache Register Access Register Definitions */ +#define BRCM_ZSC_ALL_REGS_SELECT 0x7 << 24 + +#define BRCM_ZSC_CONFIG_REG 0 << 3 +#define BRCM_ZSC_REQ_BUFFER_REG 2 << 3 +#define BRCM_ZSC_RBUS_ADDR_MAPPING_REG0 4 << 3 +#define BRCM_ZSC_RBUS_ADDR_MAPPING_REG1 6 << 3 +#define BRCM_ZSC_RBUS_ADDR_MAPPING_REG2 8 << 3 + +#define BRCM_ZSC_SCB0_ADDR_MAPPING_REG0 0xa << 3 +#define BRCM_ZSC_SCB0_ADDR_MAPPING_REG1 0xc << 3 + +#define BRCM_ZSC_SCB1_ADDR_MAPPING_REG0 0xe << 3 +#define BRCM_ZSC_SCB1_ADDR_MAPPING_REG1 0x10 << 3 + +#define BRCM_ZSC_CONFIG_LMB1En 1 << (15) +#define BRCM_ZSC_CONFIG_LMB0En 1 << (14) + +/* branch predition values */ + +#define BRCM_BrPRED_ALL_TAKEN (0x0) +#define BRCM_BrPRED_ALL_NOT_TAKEN (0x1) +#define BRCM_BrPRED_BHT_ENABLE (0x2) +#define BRCM_BrPRED_PREDICT_BACKWARD (0x3) + + + +.align 2 +/* + * Function: size_i_cache + * Arguments: None + * Returns: v0 = i cache size, v1 = I cache line size + * Description: compute the I-cache size and I-cache line size + * Trashes: v0, v1, a0, t0 + * + * pseudo code: + * + */ + +LEAF(size_i_cache) + .set noreorder + + mfc0 a0, CP0_CONFIG, 1 + move t0, a0 + + /* + * Determine sets per way: IS + * + * This field contains the number of sets (i.e., indices) per way of + * the instruction cache: + * i) 0x0: 64, ii) 0x1: 128, iii) 0x2: 256, iv) 0x3: 512, v) 0x4: 1k + * vi) 0x5 - 0x7: Reserved. + */ + + srl a0, a0, IS_SHIFT + and a0, a0, IS_MASK + + /* sets per way = (64<<IS) */ + + li v0, 0x40 + sllv v0, v0, a0 + + /* + * Determine line size + * + * This field contains the line size of the instruction cache: + * i) 0x0: No I-cache present, i) 0x3: 16 bytes, ii) 0x4: 32 bytes, iii) + * 0x5: 64 bytes, iv) the rest: Reserved. + */ + + move a0, t0 + + srl a0, a0, IL_SHIFT + and a0, a0, IL_MASK + + beqz a0, no_i_cache + nop + + /* line size = 2 ^ (IL+1) */ + + addi a0, a0, 1 + li v1, 1 + sll v1, v1, a0 + + /* v0 now have sets per way, multiply it by line size now + * that will give the set size + */ + + sll v0, v0, a0 + + /* + * Determine set associativity + * + * This field contains the set associativity of the instruction cache. + * i) 0x0: Direct mapped, ii) 0x1: 2-way, iii) 0x2: 3-way, iv) 0x3: + * 4-way, v) 0x4 - 0x7: Reserved. + */ + + move a0, t0 + + srl a0, a0, IA_SHIFT + and a0, a0, IA_MASK + addi a0, a0, 0x1 + + /* v0 has the set size, multiply it by + * set associativiy, to get the cache size + */ + + multu v0, a0 /*multu is interlocked, so no need to insert nops */ + mflo v0 + b 1f + nop + +no_i_cache: + move v0, zero + move v1, zero +1: + jr ra + nop + .set reorder + +END(size_i_cache) + +/* + * Function: size_d_cache + * Arguments: None + * Returns: v0 = d cache size, v1 = d cache line size + * Description: compute the D-cache size and D-cache line size. + * Trashes: v0, v1, a0, t0 + * + */ + +LEAF(size_d_cache) + .set noreorder + + mfc0 a0, CP0_CONFIG, 1 + move t0, a0 + + /* + * Determine sets per way: IS + * + * This field contains the number of sets (i.e., indices) per way of + * the instruction cache: + * i) 0x0: 64, ii) 0x1: 128, iii) 0x2: 256, iv) 0x3: 512, v) 0x4: 1k + * vi) 0x5 - 0x7: Reserved. + */ + + srl a0, a0, DS_SHIFT + and a0, a0, DS_MASK + + /* sets per way = (64<<IS) */ + + li v0, 0x40 + sllv v0, v0, a0 + + /* + * Determine line size + * + * This field contains the line size of the instruction cache: + * i) 0x0: No I-cache present, i) 0x3: 16 bytes, ii) 0x4: 32 bytes, iii) + * 0x5: 64 bytes, iv) the rest: Reserved. + */ + move a0, t0 + + srl a0, a0, DL_SHIFT + and a0, a0, DL_MASK + + beqz a0, no_d_cache + nop + + /* line size = 2 ^ (IL+1) */ + + addi a0, a0, 1 + li v1, 1 + sll v1, v1, a0 + + /* v0 now have sets per way, multiply it by line size now + * that will give the set size + */ + + sll v0, v0, a0 + + /* determine set associativity + * + * This field contains the set associativity of the instruction cache. + * i) 0x0: Direct mapped, ii) 0x1: 2-way, iii) 0x2: 3-way, iv) 0x3: + * 4-way, v) 0x4 - 0x7: Reserved. + */ + + move a0, t0 + + srl a0, a0, DA_SHIFT + and a0, a0, DA_MASK + addi a0, a0, 0x1 + + /* v0 has the set size, multiply it by + * set associativiy, to get the cache size + */ + + multu v0, a0 /*multu is interlocked, so no need to insert nops */ + mflo v0 + + b 1f + nop + +no_d_cache: + move v0, zero + move v1, zero +1: + jr ra + nop + .set reorder + +END(size_d_cache) + + +/* + * Function: enable_ID + * Arguments: None + * Returns: None + * Description: Enable I and D caches, initialize I and D-caches, also set + * hardware delay for d-cache (TP0). + * Trashes: t0 + * + */ + .global enable_ID + .ent enable_ID + .set noreorder +enable_ID: + mfc0 t0, CP0_BRCM_CONFIG0 + or t0, t0, (ICE_MASK | DCE_MASK) + mtc0 t0, CP0_BRCM_CONFIG0 + jr ra + nop + + .end enable_ID + .set reorder + + +/* + * Function: l1_init + * Arguments: None + * Returns: None + * Description: Enable I and D caches, and initialize I and D-caches + * Trashes: a0, v0, v1, t0, t1, t2, t8 + * + */ + .globl l1_init + .ent l1_init + .set noreorder +l1_init: + + /* save return address */ + move t8, ra + + + /* initialize I and D cache Data and Tag registers. */ + mtc0 zero, CP0_ICACHE_TAG_LO + mtc0 zero, CP0_ICACHE_TAG_HI + mtc0 zero, CP0_ICACHE_DATA_LO + mtc0 zero, CP0_ICACHE_DATA_HI + mtc0 zero, CP0_DCACHE_TAG_LO + mtc0 zero, CP0_DCACHE_TAG_HI + + /* Enable Caches before Clearing. If the caches are disabled + * then the cache operations to clear the cache will be ignored + */ + + jal enable_ID + nop + + jal size_i_cache /* v0 = i-cache size, v1 = i-cache line size */ + nop + + /* run uncached in kseg 1 */ + la k0, 1f + lui k1, 0x2000 + or k0, k1, k0 + jr k0 + nop +1: + + /* + * set K0 cache mode + */ + + mfc0 t0, CP0_CONFIG + and t0, t0, ~CP0_CONFIG_K0_MASK + or t0, t0, 3 /* Write Back mode */ + mtc0 t0, CP0_CONFIG + + /* + * Initialize instruction cache. + */ + + li a0, KSEG0 + cacheop(a0, v0, v1, Index_Store_Tag_I) + + /* + * Now we can run from I-$, kseg 0 + */ + la k0, 1f + lui k1, 0x2000 + or k0, k1, k0 + xor k0, k1, k0 + jr k0 + nop +1: + /* + * Initialize data cache. + */ + + jal size_d_cache /* v0 = d-cache size, v1 = d-cache line size */ + nop + + + li a0, KSEG0 + cacheop(a0, v0, v1, Index_Store_Tag_D) + + jr t8 + nop + + .end l1_init + .set reorder + + +/* + * Function: set_other_config + * Arguments: none + * Returns: None + * Description: initialize other remainder configuration to defaults. + * Trashes: t0, t1 + * + * pseudo code: + * + */ +LEAF(set_other_config) + .set noreorder + + /* enable Bus error for I-fetch */ + mfc0 t0, CP0_CACHEERR, 0 + li t1, 0x4 + or t0, t1 + mtc0 t0, CP0_CACHEERR, 0 + + /* enable Bus error for Load */ + mfc0 t0, CP0_CACHEERR, 1 + li t1, 0x4 + or t0, t1 + mtc0 t0, CP0_CACHEERR, 1 + + /* enable Bus Error for Store */ + mfc0 t0, CP0_CACHEERR, 2 + li t1, 0x4 + or t0, t1 + mtc0 t0, CP0_CACHEERR, 2 + + jr ra + nop + .set reorder +END(set_other_config) + +/* + * Function: set_branch_pred + * Arguments: none + * Returns: None + * Description: + * Trashes: t0, t1 + * + * pseudo code: + * + */ + +LEAF(set_branch_pred) + .set noreorder + mfc0 t0, CP0_BRCM_MODE + li t1, ~(CP0_BRCM_MODE_BrPRED_MASK | CP0_BRCM_MODE_BrHIST_MASK ) + and t0, t0, t1 + + /* enable Branch prediction */ + li t1, BRCM_BrPRED_BHT_ENABLE + sll t1, CP0_BRCM_MODE_BrPRED_SHIFT + or t0, t0, t1 + + /* set history count to 8 */ + li t1, 8 + sll t1, CP0_BRCM_MODE_BrHIST_SHIFT + or t0, t0, t1 + + mtc0 t0, CP0_BRCM_MODE + jr ra + nop + .set reorder +END(set_branch_pred) + + +/* + * Function: set_luc + * Arguments: set link uncached. + * Returns: None + * Description: + * Trashes: t0, t1 + * + */ +LEAF(set_luc) + .set noreorder + mfc0 t0, CP0_BRCM_MODE + li t1, ~(CP0_BRCM_MODE_Luc_MASK) + and t0, t0, t1 + + /* set Luc */ + ori t0, t0, CP0_BRCM_MODE_Luc_MASK + + mtc0 t0, CP0_BRCM_MODE + jr ra + nop + .set reorder +END(set_luc) + +/* + * Function: set_cwf_tse + * Arguments: set CWF and TSE bits + * Returns: None + * Description: + * Trashes: t0, t1 + * + */ +LEAF(set_cwf_tse) + .set noreorder + mfc0 t0, CP0_BRCM_CONFIG0 + li t1, (CP0_BRCM_CONFIG0_CWF_MASK | CP0_BRCM_CONFIG0_TSE_MASK) + or t0, t0, t1 + + mtc0 t0, CP0_BRCM_CONFIG0 + jr ra + nop + .set reorder +END(set_cwf_tse) + +/* + * Function: set_clock_ratio + * Arguments: set clock ratio specified by a0 + * Returns: None + * Description: + * Trashes: v0, v1, a0, a1 + * + * pseudo code: + * + */ +LEAF(set_clock_ratio) + .set noreorder + + mfc0 t0, CP0_BRCM_MODE + li t1, ~(CP0_BRCM_MODE_SET_MASK | CP0_BRCM_MODE_ClkRATIO_MASK) + and t0, t0, t1 + li t1, CP0_BRCM_MODE_SET_MASK + or t0, t0, t1 + or t0, t0, a0 + mtc0 t0, CP0_BRCM_MODE + jr ra + nop + .set reorder +END(set_clock_ratio) +/* + * Function: set_zephyr + * Arguments: None + * Returns: None + * Description: Set any zephyr bits + * Trashes: t0 & t1 + * + */ +LEAF(set_zephyr) + .set noreorder + + /* enable read/write of CP0 #22 sel. 8 */ + li t0, 0x5a455048 + .word 0x4088b00f /* mtc0 t0, $22, 15 */ + + .word 0x4008b008 /* mfc0 t0, $22, 8 */ + li t1, 0x09008000 /* turn off pref, jtb */ + or t0, t0, t1 + .word 0x4088b008 /* mtc0 t0, $22, 8 */ + sync + + /* disable read/write of CP0 #22 sel 8 */ + li t0, 0x0 + .word 0x4088b00f /* mtc0 t0, $22, 15 */ + + + jr ra + nop + .set reorder + +END(set_zephyr) + + +/* + * Function: set_llmb + * Arguments: a0=0 disable llmb, a0=1 enables llmb + * Returns: None + * Description: + * Trashes: t0, t1, t2 + * + * pseudo code: + * + */ +LEAF(set_llmb) + .set noreorder + + li t2, 0x90000000 | BRCM_ZSC_ALL_REGS_SELECT | BRCM_ZSC_CONFIG_REG + sync + cache 0x7, 0x0(t2) + sync + mfc0 t0, CP0_D_SEC_CACHE_DATA_LO + li t1, ~(BRCM_ZSC_CONFIG_LMB1En | BRCM_ZSC_CONFIG_LMB0En) + and t0, t0, t1 + + beqz a0, svlmb + nop + +enable_lmb: + li t1, (BRCM_ZSC_CONFIG_LMB1En | BRCM_ZSC_CONFIG_LMB0En) + or t0, t0, t1 + +svlmb: + mtc0 t0, CP0_D_SEC_CACHE_DATA_LO + sync + cache 0xb, 0x0(t2) + sync + + jr ra + nop + .set reorder + +END(set_llmb) +/* + * Function: core_init + * Arguments: none + * Returns: None + * Description: initialize core related configuration + * Trashes: v0,v1,a0,a1,t8 + * + * pseudo code: + * + */ + .globl core_init + .ent core_init + .set noreorder +core_init: + move t8, ra + + /* set Zephyr bits. */ + bal set_zephyr + nop + +#if ENABLE_FPU==1 + /* initialize the Floating point unit (both TPs) */ + bal init_fpu + nop +#endif + + /* set low latency memory bus */ + li a0, 1 + bal set_llmb + nop + + /* set branch prediction (TP0 only) */ + bal set_branch_pred + nop + + /* set link uncached */ + bal set_luc + nop + + /* set CWF and TSE */ + bal set_cwf_tse + nop + + /* + *set clock ratio by setting 1 to 'set' + * and 0 to ClkRatio, (TP0 only) + */ + li a0, 0 + bal set_clock_ratio + nop + + /* set other configuration to defaults */ + bal set_other_config + nop + + move ra, t8 + jr ra + nop + + .set reorder + .end core_init + +/* + * Function: clear_jump_target_buffer + * Arguments: None + * Returns: None + * Description: + * Trashes: t0, t1, t2 + * + */ +#define RESET_CALL_RETURN_STACK_THIS_THREAD (0x06<<16) +#define RESET_JUMP_TARGET_BUFFER_THIS_THREAD (0x04<<16) +#define JTB_CS_CNTL_MASK (0xFF<<16) + + .globl clear_jump_target_buffer + .ent clear_jump_target_buffer + .set noreorder +clear_jump_target_buffer: + + mfc0 t0, $22, 2 + nop + nop + + li t1, ~JTB_CS_CNTL_MASK + and t0, t0, t1 + li t2, RESET_CALL_RETURN_STACK_THIS_THREAD + or t0, t0, t2 + mtc0 t0, $22, 2 + nop + nop + + and t0, t0, t1 + li t2, RESET_JUMP_TARGET_BUFFER_THIS_THREAD + or t0, t0, t2 + mtc0 t0, $22, 2 + nop + nop + jr ra + nop + + .end clear_jump_target_buffer + .set reorder +/* + * Function: bmips_cache_init + * Arguments: None + * Returns: None + * Description: Enable I and D caches, and initialize I and D-caches + * Trashes: v0, v1, t0, t1, t2, t5, t7, t8 + * + */ + .globl bmips_5xxx_init + .ent bmips_5xxx_init + .set noreorder +bmips_5xxx_init: + + /* save return address and A0 */ + move t7, ra + move t5, a0 + + jal l1_init + nop + + jal core_init + nop + + jal clear_jump_target_buffer + nop + + mtc0 zero, CP0_CAUSE + + move a0, t5 + jr t7 + nop + + .end bmips_5xxx_init + .set reorder + + +#endif diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S index 8649507..921a5fa 100644 --- a/arch/mips/kernel/bmips_vec.S +++ b/arch/mips/kernel/bmips_vec.S @@ -88,12 +88,13 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp) li k1, (1 << 19) mfc0 k0, CP0_STATUS and k0, k1 - beqz k0, bmips_smp_entry + beqz k0, soft_reset #if defined(CONFIG_CPU_BMIPS5000) mfc0 k0, CP0_PRID li k1, PRID_IMP_BMIPS5000 - andi k0, 0xff00 + /* mask with PRID_IMP_BMIPS5000 to cover both variants */ + andi k0, PRID_IMP_BMIPS5000 bne k0, k1, 1f /* if we're not on core 0, this must be the SMP boot signal */ @@ -125,13 +126,48 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp) .set arch=r4000 eret +#ifdef CONFIG_SMP +soft_reset: + +#if defined(CONFIG_CPU_BMIPS5000) + mfc0 k0, CP0_PRID + andi k0, 0xff00 + li k1, PRID_IMP_BMIPS5200 + bne k0, k1, bmips_smp_entry + + /* if running on TP 1, jump to bmips_smp_entry */ + mfc0 k0, $22 + li k1, (1 << 24) + and k1, k0 + bnez k1, bmips_smp_entry + nop + + /* + * running on TP0, can not be core 0 (the boot core). + * Check for soft reset. Indicates a warm boot + */ + mfc0 k0, $12 + li k1, (1 << 20) + and k0, k1 + beqz k0, bmips_smp_entry + + /* + * Warm boot. + * Cache init is only done on TP0 + */ + la k0, bmips_5xxx_init + jalr k0 + nop + + b bmips_smp_entry + nop +#endif + /*********************************************************************** * CPU1 reset vector (used for the initial boot only) * This is still part of bmips_reset_nmi_vec(). ***********************************************************************/ -#ifdef CONFIG_SMP - bmips_smp_entry: /* set up CP0 STATUS; enable FPU */ @@ -166,10 +202,12 @@ bmips_smp_entry: 2: #endif /* CONFIG_CPU_BMIPS4350 || CONFIG_CPU_BMIPS4380 */ #if defined(CONFIG_CPU_BMIPS5000) - /* set exception vector base */ + /* mask with PRID_IMP_BMIPS5000 to cover both variants */ li k1, PRID_IMP_BMIPS5000 + andi k0, PRID_IMP_BMIPS5000 bne k0, k1, 3f + /* set exception vector base */ la k0, ebase lw k0, 0(k0) mtc0 k0, $15, 1 @@ -263,6 +301,8 @@ LEAF(bmips_enable_xks01) #endif /* CONFIG_CPU_BMIPS4380 */ #if defined(CONFIG_CPU_BMIPS5000) li t1, PRID_IMP_BMIPS5000 + /* mask with PRID_IMP_BMIPS5000 to cover both variants */ + andi t2, PRID_IMP_BMIPS5000 bne t2, t1, 2f mfc0 t0, $22, 5 diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index d8f9b35..ceca6cc 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -688,21 +688,9 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, } lose_fpu(1); /* Save FPU state for the emulator. */ reg = insn.i_format.rt; - bit = 0; - switch (insn.i_format.rs) { - case bc1eqz_op: - /* Test bit 0 */ - if (get_fpr32(¤t->thread.fpu.fpr[reg], 0) - & 0x1) - bit = 1; - break; - case bc1nez_op: - /* Test bit 0 */ - if (!(get_fpr32(¤t->thread.fpu.fpr[reg], 0) - & 0x1)) - bit = 1; - break; - } + bit = get_fpr32(¤t->thread.fpu.fpr[reg], 0) & 0x1; + if (insn.i_format.rs == bc1eqz_op) + bit = !bit; own_fpu(1); if (bit) epc = epc + 4 + diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 8dfe6a6..e4c21bb 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -28,6 +28,83 @@ static int mips_next_event(unsigned long delta, return res; } +/** + * calculate_min_delta() - Calculate a good minimum delta for mips_next_event(). + * + * Running under virtualisation can introduce overhead into mips_next_event() in + * the form of hypervisor emulation of CP0_Count/CP0_Compare registers, + * potentially with an unnatural frequency, which makes a fixed min_delta_ns + * value inappropriate as it may be too small. + * + * It can also introduce occasional latency from the guest being descheduled. + * + * This function calculates a good minimum delta based roughly on the 75th + * percentile of the time taken to do the mips_next_event() sequence, in order + * to handle potentially higher overhead while also eliminating outliers due to + * unpredictable hypervisor latency (which can be handled by retries). + * + * Return: An appropriate minimum delta for the clock event device. + */ +static unsigned int calculate_min_delta(void) +{ + unsigned int cnt, i, j, k, l; + unsigned int buf1[4], buf2[3]; + unsigned int min_delta; + + /* + * Calculate the median of 5 75th percentiles of 5 samples of how long + * it takes to set CP0_Compare = CP0_Count + delta. + */ + for (i = 0; i < 5; ++i) { + for (j = 0; j < 5; ++j) { + /* + * This is like the code in mips_next_event(), and + * directly measures the borderline "safe" delta. + */ + cnt = read_c0_count(); + write_c0_compare(cnt); + cnt = read_c0_count() - cnt; + + /* Sorted insert into buf1 */ + for (k = 0; k < j; ++k) { + if (cnt < buf1[k]) { + l = min_t(unsigned int, + j, ARRAY_SIZE(buf1) - 1); + for (; l > k; --l) + buf1[l] = buf1[l - 1]; + break; + } + } + if (k < ARRAY_SIZE(buf1)) + buf1[k] = cnt; + } + + /* Sorted insert of 75th percentile into buf2 */ + for (k = 0; k < i; ++k) { + if (buf1[ARRAY_SIZE(buf1) - 1] < buf2[k]) { + l = min_t(unsigned int, + i, ARRAY_SIZE(buf2) - 1); + for (; l > k; --l) + buf2[l] = buf2[l - 1]; + break; + } + } + if (k < ARRAY_SIZE(buf2)) + buf2[k] = buf1[ARRAY_SIZE(buf1) - 1]; + } + + /* Use 2 * median of 75th percentiles */ + min_delta = buf2[ARRAY_SIZE(buf2) - 1] * 2; + + /* Don't go too low */ + if (min_delta < 0x300) + min_delta = 0x300; + + pr_debug("%s: median 75th percentile=%#x, min_delta=%#x\n", + __func__, buf2[ARRAY_SIZE(buf2) - 1], min_delta); + return min_delta; +} + DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); int cp0_timer_irq_installed; @@ -177,7 +254,7 @@ int r4k_clockevent_init(void) { unsigned int cpu = smp_processor_id(); struct clock_event_device *cd; - unsigned int irq; + unsigned int irq, min_delta; if (!cpu_has_counter || !mips_hpt_frequency) return -ENXIO; @@ -203,7 +280,8 @@ int r4k_clockevent_init(void) /* Calculate the min / max delta */ cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); - cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + min_delta = calculate_min_delta(); + cd->min_delta_ns = clockevent_delta2ns(min_delta, cd); cd->rating = 300; cd->irq = irq; diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index ac81edd..51b98dc 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -18,9 +18,12 @@ #include <asm/mipsmtregs.h> #include <asm/pm.h> +#define GCR_CPC_BASE_OFS 0x0088 #define GCR_CL_COHERENCE_OFS 0x2008 #define GCR_CL_ID_OFS 0x2028 +#define CPC_CL_VC_RUN_OFS 0x2028 + .extern mips_cm_base .set noreorder @@ -60,6 +63,37 @@ nop .endm + /* + * Set dest to non-zero if the core supports MIPSr6 multithreading + * (ie. VPs), else zero. If MIPSr6 multithreading is not supported then + * branch to nomt. + */ + .macro has_vp dest, nomt + mfc0 \dest, CP0_CONFIG, 1 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 2 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 3 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 4 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 5 + andi \dest, \dest, MIPS_CONF5_VP + beqz \dest, \nomt + nop + .endm + + /* Calculate an uncached address for the CM GCRs */ + .macro cmgcrb dest + .set push + .set noat + MFC0 $1, CP0_CMGCRBASE + PTR_SLL $1, $1, 4 + PTR_LI \dest, UNCAC_BASE + PTR_ADDU \dest, \dest, $1 + .set pop + .endm + .section .text.cps-vec .balign 0x1000 @@ -90,120 +124,64 @@ not_nmi: li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS mtc0 t0, CP0_STATUS - /* - * Clear the bits used to index the caches. Note that the architecture - * dictates that writing to any of TagLo or TagHi selects 0 or 2 should - * be valid for all MIPS32 CPUs, even those for which said writes are - * unnecessary. - */ - mtc0 zero, CP0_TAGLO, 0 - mtc0 zero, CP0_TAGHI, 0 - mtc0 zero, CP0_TAGLO, 2 - mtc0 zero, CP0_TAGHI, 2 - ehb - - /* Primary cache configuration is indicated by Config1 */ - mfc0 v0, CP0_CONFIG, 1 - - /* Detect I-cache line size */ - _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ - beqz t0, icache_done - li t1, 2 - sllv t0, t1, t0 - - /* Detect I-cache size */ - _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ - xori t2, t1, 0x7 - beqz t2, 1f - li t3, 32 - addiu t1, t1, 1 - sllv t1, t3, t1 -1: /* At this point t1 == I-cache sets per way */ - _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ - addiu t2, t2, 1 - mul t1, t1, t0 - mul t1, t1, t2 - - li a0, CKSEG0 - PTR_ADD a1, a0, t1 -1: cache Index_Store_Tag_I, 0(a0) - PTR_ADD a0, a0, t0 - bne a0, a1, 1b + /* Skip cache & coherence setup if we're already coherent */ + cmgcrb v1 + lw s7, GCR_CL_COHERENCE_OFS(v1) + bnez s7, 1f nop -icache_done: - /* Detect D-cache line size */ - _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ - beqz t0, dcache_done - li t1, 2 - sllv t0, t1, t0 - - /* Detect D-cache size */ - _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ - xori t2, t1, 0x7 - beqz t2, 1f - li t3, 32 - addiu t1, t1, 1 - sllv t1, t3, t1 -1: /* At this point t1 == D-cache sets per way */ - _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ - addiu t2, t2, 1 - mul t1, t1, t0 - mul t1, t1, t2 + /* Initialize the L1 caches */ + jal mips_cps_cache_init + nop - li a0, CKSEG0 - PTR_ADDU a1, a0, t1 - PTR_SUBU a1, a1, t0 -1: cache Index_Store_Tag_D, 0(a0) - bne a0, a1, 1b - PTR_ADD a0, a0, t0 -dcache_done: + /* Enter the coherent domain */ + li t0, 0xff + sw t0, GCR_CL_COHERENCE_OFS(v1) + ehb /* Set Kseg0 CCA to that in s0 */ - mfc0 t0, CP0_CONFIG +1: mfc0 t0, CP0_CONFIG ori t0, 0x7 xori t0, 0x7 or t0, t0, s0 mtc0 t0, CP0_CONFIG ehb - /* Calculate an uncached address for the CM GCRs */ - MFC0 v1, CP0_CMGCRBASE - PTR_SLL v1, v1, 4 - PTR_LI t0, UNCAC_BASE - PTR_ADDU v1, v1, t0 - - /* Enter the coherent domain */ - li t0, 0xff - sw t0, GCR_CL_COHERENCE_OFS(v1) - ehb - /* Jump to kseg0 */ PTR_LA t0, 1f jr t0 nop /* - * We're up, cached & coherent. Perform any further required core-level - * initialisation. + * We're up, cached & coherent. Perform any EVA initialization necessary + * before we access memory. */ -1: jal mips_cps_core_init +1: eva_init + + /* Retrieve boot configuration pointers */ + jal mips_cps_get_bootcfg nop - /* Do any EVA initialization if necessary */ - eva_init + /* Skip core-level init if we started up coherent */ + bnez s7, 1f + nop + + /* Perform any further required core-level initialisation */ + jal mips_cps_core_init + nop /* * Boot any other VPEs within this core that should be online, and * deactivate this VPE if it should be offline. */ + move a1, t9 jal mips_cps_boot_vpes - nop + move a0, v0 /* Off we go! */ - PTR_L t1, VPEBOOTCFG_PC(v0) - PTR_L gp, VPEBOOTCFG_GP(v0) - PTR_L sp, VPEBOOTCFG_SP(v0) +1: PTR_L t1, VPEBOOTCFG_PC(v1) + PTR_L gp, VPEBOOTCFG_GP(v1) + PTR_L sp, VPEBOOTCFG_SP(v1) jr t1 nop END(mips_cps_core_entry) @@ -245,7 +223,6 @@ LEAF(excep_intex) .org 0x480 LEAF(excep_ejtag) - DUMP_EXCEP("EJTAG") PTR_LA k0, ejtag_debug_handler jr k0 nop @@ -323,22 +300,35 @@ LEAF(mips_cps_core_init) nop END(mips_cps_core_init) -LEAF(mips_cps_boot_vpes) - /* Retrieve CM base address */ - PTR_LA t0, mips_cm_base - PTR_L t0, 0(t0) - +/** + * mips_cps_get_bootcfg() - retrieve boot configuration pointers + * + * Returns: pointer to struct core_boot_config in v0, pointer to + * struct vpe_boot_config in v1, VPE ID in t9 + */ +LEAF(mips_cps_get_bootcfg) /* Calculate a pointer to this cores struct core_boot_config */ + cmgcrb t0 lw t0, GCR_CL_ID_OFS(t0) li t1, COREBOOTCFG_SIZE mul t0, t0, t1 PTR_LA t1, mips_cps_core_bootcfg PTR_L t1, 0(t1) - PTR_ADDU t0, t0, t1 + PTR_ADDU v0, t0, t1 /* Calculate this VPEs ID. If the core doesn't support MT use 0 */ li t9, 0 -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_CPU_MIPSR6) + has_vp ta2, 1f + + /* + * Assume non-contiguous numbering. Perhaps some day we'll need + * to handle contiguous VP numbering, but no such systems yet + * exist. + */ + mfc0 t9, $3, 1 + andi t9, t9, 0xff +#elif defined(CONFIG_MIPS_MT_SMP) has_mt ta2, 1f /* Find the number of VPEs present in the core */ @@ -362,22 +352,43 @@ LEAF(mips_cps_boot_vpes) 1: /* Calculate a pointer to this VPEs struct vpe_boot_config */ li t1, VPEBOOTCFG_SIZE - mul v0, t9, t1 - PTR_L ta3, COREBOOTCFG_VPECONFIG(t0) - PTR_ADDU v0, v0, ta3 - -#ifdef CONFIG_MIPS_MT_SMP + mul v1, t9, t1 + PTR_L ta3, COREBOOTCFG_VPECONFIG(v0) + PTR_ADDU v1, v1, ta3 - /* If the core doesn't support MT then return */ - bnez ta2, 1f - nop jr ra nop + END(mips_cps_get_bootcfg) + +LEAF(mips_cps_boot_vpes) + PTR_L ta2, COREBOOTCFG_VPEMASK(a0) + PTR_L ta3, COREBOOTCFG_VPECONFIG(a0) + +#if defined(CONFIG_CPU_MIPSR6) + + has_vp t0, 5f + + /* Find base address of CPC */ + cmgcrb t3 + PTR_L t1, GCR_CPC_BASE_OFS(t3) + PTR_LI t2, ~0x7fff + and t1, t1, t2 + PTR_LI t2, UNCAC_BASE + PTR_ADD t1, t1, t2 + + /* Set VC_RUN to the VPE mask */ + PTR_S ta2, CPC_CL_VC_RUN_OFS(t1) + ehb + +#elif defined(CONFIG_MIPS_MT) .set push .set mt -1: /* Enter VPE configuration state */ + /* If the core doesn't support MT then return */ + has_mt t0, 5f + + /* Enter VPE configuration state */ dvpe PTR_LA t1, 1f jr.hb t1 @@ -388,7 +399,6 @@ LEAF(mips_cps_boot_vpes) ehb /* Loop through each VPE */ - PTR_L ta2, COREBOOTCFG_VPEMASK(t0) move t8, ta2 li ta1, 0 @@ -465,7 +475,7 @@ LEAF(mips_cps_boot_vpes) /* Check whether this VPE is meant to be running */ li t0, 1 - sll t0, t0, t9 + sll t0, t0, a1 and t0, t0, t8 bnez t0, 2f nop @@ -482,10 +492,84 @@ LEAF(mips_cps_boot_vpes) #endif /* CONFIG_MIPS_MT_SMP */ /* Return */ - jr ra +5: jr ra nop END(mips_cps_boot_vpes) +LEAF(mips_cps_cache_init) + /* + * Clear the bits used to index the caches. Note that the architecture + * dictates that writing to any of TagLo or TagHi selects 0 or 2 should + * be valid for all MIPS32 CPUs, even those for which said writes are + * unnecessary. + */ + mtc0 zero, CP0_TAGLO, 0 + mtc0 zero, CP0_TAGHI, 0 + mtc0 zero, CP0_TAGLO, 2 + mtc0 zero, CP0_TAGHI, 2 + ehb + + /* Primary cache configuration is indicated by Config1 */ + mfc0 v0, CP0_CONFIG, 1 + + /* Detect I-cache line size */ + _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ + beqz t0, icache_done + li t1, 2 + sllv t0, t1, t0 + + /* Detect I-cache size */ + _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ + xori t2, t1, 0x7 + beqz t2, 1f + li t3, 32 + addiu t1, t1, 1 + sllv t1, t3, t1 +1: /* At this point t1 == I-cache sets per way */ + _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ + addiu t2, t2, 1 + mul t1, t1, t0 + mul t1, t1, t2 + + li a0, CKSEG0 + PTR_ADD a1, a0, t1 +1: cache Index_Store_Tag_I, 0(a0) + PTR_ADD a0, a0, t0 + bne a0, a1, 1b + nop +icache_done: + + /* Detect D-cache line size */ + _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ + beqz t0, dcache_done + li t1, 2 + sllv t0, t1, t0 + + /* Detect D-cache size */ + _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ + xori t2, t1, 0x7 + beqz t2, 1f + li t3, 32 + addiu t1, t1, 1 + sllv t1, t3, t1 +1: /* At this point t1 == D-cache sets per way */ + _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ + addiu t2, t2, 1 + mul t1, t1, t0 + mul t1, t1, t2 + + li a0, CKSEG0 + PTR_ADDU a1, a0, t1 + PTR_SUBU a1, a1, t0 +1: cache Index_Store_Tag_D, 0(a0) + bne a0, a1, 1b + PTR_ADD a0, a0, t0 +dcache_done: + + jr ra + nop + END(mips_cps_cache_init) + #if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM) /* Calculate a pointer to this CPUs struct mips_static_suspend_state */ diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index b725b71..5ac5c3e 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -539,6 +539,7 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, int enable) switch (c->cputype) { case CPU_PROAPTIV: case CPU_P5600: + case CPU_P6600: /* proAptiv & related cores use Config6 to enable the FTLB */ config = read_c0_config6(); /* Clear the old probability value */ @@ -561,6 +562,19 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, int enable) write_c0_config7(config | (calculate_ftlb_probability(c) << MIPS_CONF7_FTLBP_SHIFT)); break; + case CPU_LOONGSON3: + /* Flush ITLB, DTLB, VTLB and FTLB */ + write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB | + LOONGSON_DIAG_VTLB | LOONGSON_DIAG_FTLB); + /* Loongson-3 cores use Config6 to enable the FTLB */ + config = read_c0_config6(); + if (enable) + /* Enable FTLB */ + write_c0_config6(config & ~MIPS_CONF6_FTLBDIS); + else + /* Disable FTLB */ + write_c0_config6(config | MIPS_CONF6_FTLBDIS); + break; default: return 1; } @@ -634,6 +648,8 @@ static inline unsigned int decode_config1(struct cpuinfo_mips *c) if (config1 & MIPS_CONF1_MD) c->ases |= MIPS_ASE_MDMX; + if (config1 & MIPS_CONF1_PC) + c->options |= MIPS_CPU_PERF; if (config1 & MIPS_CONF1_WR) c->options |= MIPS_CPU_WATCH; if (config1 & MIPS_CONF1_CA) @@ -673,18 +689,25 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) if (config3 & MIPS_CONF3_SM) { c->ases |= MIPS_ASE_SMARTMIPS; - c->options |= MIPS_CPU_RIXI; + c->options |= MIPS_CPU_RIXI | MIPS_CPU_CTXTC; } if (config3 & MIPS_CONF3_RXI) c->options |= MIPS_CPU_RIXI; + if (config3 & MIPS_CONF3_CTXTC) + c->options |= MIPS_CPU_CTXTC; if (config3 & MIPS_CONF3_DSP) c->ases |= MIPS_ASE_DSP; - if (config3 & MIPS_CONF3_DSP2P) + if (config3 & MIPS_CONF3_DSP2P) { c->ases |= MIPS_ASE_DSP2P; + if (cpu_has_mips_r6) + c->ases |= MIPS_ASE_DSP3; + } if (config3 & MIPS_CONF3_VINT) c->options |= MIPS_CPU_VINT; if (config3 & MIPS_CONF3_VEIC) c->options |= MIPS_CPU_VEIC; + if (config3 & MIPS_CONF3_LPA) + c->options |= MIPS_CPU_LPA; if (config3 & MIPS_CONF3_MT) c->ases |= MIPS_ASE_MIPSMT; if (config3 & MIPS_CONF3_ULRI) @@ -695,6 +718,10 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->ases |= MIPS_ASE_VZ; if (config3 & MIPS_CONF3_SC) c->options |= MIPS_CPU_SEGMENTS; + if (config3 & MIPS_CONF3_BI) + c->options |= MIPS_CPU_BADINSTR; + if (config3 & MIPS_CONF3_BP) + c->options |= MIPS_CPU_BADINSTRP; if (config3 & MIPS_CONF3_MSA) c->ases |= MIPS_ASE_MSA; if (config3 & MIPS_CONF3_PW) { @@ -715,6 +742,7 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) unsigned int newcf4; unsigned int mmuextdef; unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE; + unsigned long asid_mask; config4 = read_c0_config4(); @@ -773,7 +801,20 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) } } - c->kscratch_mask = (config4 >> 16) & 0xff; + c->kscratch_mask = (config4 & MIPS_CONF4_KSCREXIST) + >> MIPS_CONF4_KSCREXIST_SHIFT; + + asid_mask = MIPS_ENTRYHI_ASID; + if (config4 & MIPS_CONF4_AE) + asid_mask |= MIPS_ENTRYHI_ASIDX; + set_cpu_asid_mask(c, asid_mask); + + /* + * Warn if the computed ASID mask doesn't match the mask the kernel + * is built for. This may indicate either a serious problem or an + * easy optimisation opportunity, but either way should be addressed. + */ + WARN_ON(asid_mask != cpu_asid_mask(c)); return config4 & MIPS_CONF_M; } @@ -796,6 +837,8 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c) if (config5 & MIPS_CONF5_MVH) c->options |= MIPS_CPU_XPA; #endif + if (cpu_has_mips_r6 && (config5 & MIPS_CONF5_VP)) + c->options |= MIPS_CPU_VP; return config5 & MIPS_CONF_M; } @@ -826,17 +869,43 @@ static void decode_configs(struct cpuinfo_mips *c) if (ok) ok = decode_config5(c); - mips_probe_watch_registers(c); - - if (cpu_has_rixi) { - /* Enable the RIXI exceptions */ - set_c0_pagegrain(PG_IEC); - back_to_back_c0_hazard(); - /* Verify the IEC bit is set */ - if (read_c0_pagegrain() & PG_IEC) - c->options |= MIPS_CPU_RIXIEX; + /* Probe the EBase.WG bit */ + if (cpu_has_mips_r2_r6) { + u64 ebase; + unsigned int status; + + /* {read,write}_c0_ebase_64() may be UNDEFINED prior to r6 */ + ebase = cpu_has_mips64r6 ? read_c0_ebase_64() + : (s32)read_c0_ebase(); + if (ebase & MIPS_EBASE_WG) { + /* WG bit already set, we can avoid the clumsy probe */ + c->options |= MIPS_CPU_EBASE_WG; + } else { + /* Its UNDEFINED to change EBase while BEV=0 */ + status = read_c0_status(); + write_c0_status(status | ST0_BEV); + irq_enable_hazard(); + /* + * On pre-r6 cores, this may well clobber the upper bits + * of EBase. This is hard to avoid without potentially + * hitting UNDEFINED dm*c0 behaviour if EBase is 32-bit. + */ + if (cpu_has_mips64r6) + write_c0_ebase_64(ebase | MIPS_EBASE_WG); + else + write_c0_ebase(ebase | MIPS_EBASE_WG); + back_to_back_c0_hazard(); + /* Restore BEV */ + write_c0_status(status); + if (read_c0_ebase() & MIPS_EBASE_WG) { + c->options |= MIPS_CPU_EBASE_WG; + write_c0_ebase(ebase); + } + } } + mips_probe_watch_registers(c); + #ifndef CONFIG_MIPS_CPS if (cpu_has_mips_r2_r6) { c->core = get_ebase_cpunum(); @@ -846,6 +915,235 @@ static void decode_configs(struct cpuinfo_mips *c) #endif } +/* + * Probe for certain guest capabilities by writing config bits and reading back. + * Finally write back the original value. + */ +#define probe_gc0_config(name, maxconf, bits) \ +do { \ + unsigned int tmp; \ + tmp = read_gc0_##name(); \ + write_gc0_##name(tmp | (bits)); \ + back_to_back_c0_hazard(); \ + maxconf = read_gc0_##name(); \ + write_gc0_##name(tmp); \ +} while (0) + +/* + * Probe for dynamic guest capabilities by changing certain config bits and + * reading back to see if they change. Finally write back the original value. + */ +#define probe_gc0_config_dyn(name, maxconf, dynconf, bits) \ +do { \ + maxconf = read_gc0_##name(); \ + write_gc0_##name(maxconf ^ (bits)); \ + back_to_back_c0_hazard(); \ + dynconf = maxconf ^ read_gc0_##name(); \ + write_gc0_##name(maxconf); \ + maxconf |= dynconf; \ +} while (0) + +static inline unsigned int decode_guest_config0(struct cpuinfo_mips *c) +{ + unsigned int config0; + + probe_gc0_config(config, config0, MIPS_CONF_M); + + if (config0 & MIPS_CONF_M) + c->guest.conf |= BIT(1); + return config0 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config1(struct cpuinfo_mips *c) +{ + unsigned int config1, config1_dyn; + + probe_gc0_config_dyn(config1, config1, config1_dyn, + MIPS_CONF_M | MIPS_CONF1_PC | MIPS_CONF1_WR | + MIPS_CONF1_FP); + + if (config1 & MIPS_CONF1_FP) + c->guest.options |= MIPS_CPU_FPU; + if (config1_dyn & MIPS_CONF1_FP) + c->guest.options_dyn |= MIPS_CPU_FPU; + + if (config1 & MIPS_CONF1_WR) + c->guest.options |= MIPS_CPU_WATCH; + if (config1_dyn & MIPS_CONF1_WR) + c->guest.options_dyn |= MIPS_CPU_WATCH; + + if (config1 & MIPS_CONF1_PC) + c->guest.options |= MIPS_CPU_PERF; + if (config1_dyn & MIPS_CONF1_PC) + c->guest.options_dyn |= MIPS_CPU_PERF; + + if (config1 & MIPS_CONF_M) + c->guest.conf |= BIT(2); + return config1 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config2(struct cpuinfo_mips *c) +{ + unsigned int config2; + + probe_gc0_config(config2, config2, MIPS_CONF_M); + + if (config2 & MIPS_CONF_M) + c->guest.conf |= BIT(3); + return config2 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config3(struct cpuinfo_mips *c) +{ + unsigned int config3, config3_dyn; + + probe_gc0_config_dyn(config3, config3, config3_dyn, + MIPS_CONF_M | MIPS_CONF3_MSA | MIPS_CONF3_CTXTC); + + if (config3 & MIPS_CONF3_CTXTC) + c->guest.options |= MIPS_CPU_CTXTC; + if (config3_dyn & MIPS_CONF3_CTXTC) + c->guest.options_dyn |= MIPS_CPU_CTXTC; + + if (config3 & MIPS_CONF3_PW) + c->guest.options |= MIPS_CPU_HTW; + + if (config3 & MIPS_CONF3_SC) + c->guest.options |= MIPS_CPU_SEGMENTS; + + if (config3 & MIPS_CONF3_BI) + c->guest.options |= MIPS_CPU_BADINSTR; + if (config3 & MIPS_CONF3_BP) + c->guest.options |= MIPS_CPU_BADINSTRP; + + if (config3 & MIPS_CONF3_MSA) + c->guest.ases |= MIPS_ASE_MSA; + if (config3_dyn & MIPS_CONF3_MSA) + c->guest.ases_dyn |= MIPS_ASE_MSA; + + if (config3 & MIPS_CONF_M) + c->guest.conf |= BIT(4); + return config3 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config4(struct cpuinfo_mips *c) +{ + unsigned int config4; + + probe_gc0_config(config4, config4, + MIPS_CONF_M | MIPS_CONF4_KSCREXIST); + + c->guest.kscratch_mask = (config4 & MIPS_CONF4_KSCREXIST) + >> MIPS_CONF4_KSCREXIST_SHIFT; + + if (config4 & MIPS_CONF_M) + c->guest.conf |= BIT(5); + return config4 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config5(struct cpuinfo_mips *c) +{ + unsigned int config5, config5_dyn; + + probe_gc0_config_dyn(config5, config5, config5_dyn, + MIPS_CONF_M | MIPS_CONF5_MRP); + + if (config5 & MIPS_CONF5_MRP) + c->guest.options |= MIPS_CPU_MAAR; + if (config5_dyn & MIPS_CONF5_MRP) + c->guest.options_dyn |= MIPS_CPU_MAAR; + + if (config5 & MIPS_CONF5_LLB) + c->guest.options |= MIPS_CPU_RW_LLB; + + if (config5 & MIPS_CONF_M) + c->guest.conf |= BIT(6); + return config5 & MIPS_CONF_M; +} + +static inline void decode_guest_configs(struct cpuinfo_mips *c) +{ + unsigned int ok; + + ok = decode_guest_config0(c); + if (ok) + ok = decode_guest_config1(c); + if (ok) + ok = decode_guest_config2(c); + if (ok) + ok = decode_guest_config3(c); + if (ok) + ok = decode_guest_config4(c); + if (ok) + decode_guest_config5(c); +} + +static inline void cpu_probe_guestctl0(struct cpuinfo_mips *c) +{ + unsigned int guestctl0, temp; + + guestctl0 = read_c0_guestctl0(); + + if (guestctl0 & MIPS_GCTL0_G0E) + c->options |= MIPS_CPU_GUESTCTL0EXT; + if (guestctl0 & MIPS_GCTL0_G1) + c->options |= MIPS_CPU_GUESTCTL1; + if (guestctl0 & MIPS_GCTL0_G2) + c->options |= MIPS_CPU_GUESTCTL2; + if (!(guestctl0 & MIPS_GCTL0_RAD)) { + c->options |= MIPS_CPU_GUESTID; + + /* + * Probe for Direct Root to Guest (DRG). Set GuestCtl1.RID = 0 + * first, otherwise all data accesses will be fully virtualised + * as if they were performed by guest mode. + */ + write_c0_guestctl1(0); + tlbw_use_hazard(); + + write_c0_guestctl0(guestctl0 | MIPS_GCTL0_DRG); + back_to_back_c0_hazard(); + temp = read_c0_guestctl0(); + + if (temp & MIPS_GCTL0_DRG) { + write_c0_guestctl0(guestctl0); + c->options |= MIPS_CPU_DRG; + } + } +} + +static inline void cpu_probe_guestctl1(struct cpuinfo_mips *c) +{ + if (cpu_has_guestid) { + /* determine the number of bits of GuestID available */ + write_c0_guestctl1(MIPS_GCTL1_ID); + back_to_back_c0_hazard(); + c->guestid_mask = (read_c0_guestctl1() & MIPS_GCTL1_ID) + >> MIPS_GCTL1_ID_SHIFT; + write_c0_guestctl1(0); + } +} + +static inline void cpu_probe_gtoffset(struct cpuinfo_mips *c) +{ + /* determine the number of bits of GTOffset available */ + write_c0_gtoffset(0xffffffff); + back_to_back_c0_hazard(); + c->gtoffset_mask = read_c0_gtoffset(); + write_c0_gtoffset(0); +} + +static inline void cpu_probe_vz(struct cpuinfo_mips *c) +{ + cpu_probe_guestctl0(c); + if (cpu_has_guestctl1) + cpu_probe_guestctl1(c); + + cpu_probe_gtoffset(c); + + decode_guest_configs(c); +} + #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \ | MIPS_CPU_COUNTER) @@ -1172,7 +1470,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) set_isa(c, MIPS_CPU_ISA_III); c->fpu_msk31 |= FPU_CSR_CONDX; break; - case PRID_REV_LOONGSON3A: + case PRID_REV_LOONGSON3A_R1: c->cputype = CPU_LOONGSON3; __cpu_name[cpu] = "ICT Loongson-3"; set_elf_platform(cpu, "loongson3a"); @@ -1314,6 +1612,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_P5600; __cpu_name[cpu] = "MIPS P5600"; break; + case PRID_IMP_P6600: + c->cputype = CPU_P6600; + __cpu_name[cpu] = "MIPS P6600"; + break; case PRID_IMP_I6400: c->cputype = CPU_I6400; __cpu_name[cpu] = "MIPS I6400"; @@ -1322,6 +1624,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_M5150; __cpu_name[cpu] = "MIPS M5150"; break; + case PRID_IMP_M6250: + c->cputype = CPU_M6250; + __cpu_name[cpu] = "MIPS M6250"; + break; } decode_configs(c); @@ -1435,6 +1741,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_BMIPS4380; __cpu_name[cpu] = "Broadcom BMIPS4380"; set_elf_platform(cpu, "bmips4380"); + c->options |= MIPS_CPU_RIXI; } else { c->cputype = CPU_BMIPS4350; __cpu_name[cpu] = "Broadcom BMIPS4350"; @@ -1445,9 +1752,12 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) case PRID_IMP_BMIPS5000: case PRID_IMP_BMIPS5200: c->cputype = CPU_BMIPS5000; - __cpu_name[cpu] = "Broadcom BMIPS5000"; + if ((c->processor_id & PRID_IMP_MASK) == PRID_IMP_BMIPS5200) + __cpu_name[cpu] = "Broadcom BMIPS5200"; + else + __cpu_name[cpu] = "Broadcom BMIPS5000"; set_elf_platform(cpu, "bmips5000"); - c->options |= MIPS_CPU_ULRI; + c->options |= MIPS_CPU_ULRI | MIPS_CPU_RIXI; break; } } @@ -1481,6 +1791,8 @@ platform: set_elf_platform(cpu, "octeon2"); break; case PRID_IMP_CAVIUM_CN70XX: + case PRID_IMP_CAVIUM_CN73XX: + case PRID_IMP_CAVIUM_CNF75XX: case PRID_IMP_CAVIUM_CN78XX: c->cputype = CPU_CAVIUM_OCTEON3; __cpu_name[cpu] = "Cavium Octeon III"; @@ -1493,6 +1805,29 @@ platform: } } +static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) +{ + switch (c->processor_id & PRID_IMP_MASK) { + case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */ + switch (c->processor_id & PRID_REV_MASK) { + case PRID_REV_LOONGSON3A_R2: + c->cputype = CPU_LOONGSON3; + __cpu_name[cpu] = "ICT Loongson-3"; + set_elf_platform(cpu, "loongson3a"); + set_isa(c, MIPS_CPU_ISA_M64R2); + break; + } + + decode_configs(c); + c->options |= MIPS_CPU_TLBINV | MIPS_CPU_LDPTE; + c->writecombine = _CACHE_UNCACHED_ACCELERATED; + break; + default: + panic("Unknown Loongson Processor ID!"); + break; + } +} + static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) { decode_configs(c); @@ -1640,6 +1975,9 @@ void cpu_probe(void) case PRID_COMP_CAVIUM: cpu_probe_cavium(c, cpu); break; + case PRID_COMP_LOONGSON: + cpu_probe_loongson(c, cpu); + break; case PRID_COMP_INGENIC_D0: case PRID_COMP_INGENIC_D1: case PRID_COMP_INGENIC_E1: @@ -1660,6 +1998,15 @@ void cpu_probe(void) */ BUG_ON(current_cpu_type() != c->cputype); + if (cpu_has_rixi) { + /* Enable the RIXI exceptions */ + set_c0_pagegrain(PG_IEC); + back_to_back_c0_hazard(); + /* Verify the IEC bit is set */ + if (read_c0_pagegrain() & PG_IEC) + c->options |= MIPS_CPU_RIXIEX; + } + if (mips_fpu_disabled) c->options &= ~MIPS_CPU_FPU; @@ -1699,6 +2046,9 @@ void cpu_probe(void) elf_hwcap |= HWCAP_MIPS_MSA; } + if (cpu_has_vz) + cpu_probe_vz(c); + cpu_probe_vmbits(c); #ifdef CONFIG_64BIT diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index d434d5d..610f0f3 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -14,12 +14,22 @@ static int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; #ifdef CONFIG_SMP -static void crash_shutdown_secondary(void *ignore) +static void crash_shutdown_secondary(void *passed_regs) { - struct pt_regs *regs; + struct pt_regs *regs = passed_regs; int cpu = smp_processor_id(); - regs = task_pt_regs(current); + /* + * If we are passed registers, use those. Otherwise get the + * regs from the last interrupt, which should be correct, as + * we are in an interrupt. But if the regs are not there, + * pull them from the top of the stack. They are probably + * wrong, but we need something to keep from crashing again. + */ + if (!regs) + regs = get_irq_regs(); + if (!regs) + regs = task_pt_regs(current); if (!cpu_online(cpu)) return; diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index baa7b6f..17326a9 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -130,7 +130,7 @@ LEAF(__r4k_wait) /* end of rollback region (the region size must be power of two) */ 1: jr ra - nop + nop .set pop END(__r4k_wait) @@ -172,7 +172,7 @@ NESTED(handle_int, PT_SIZE, sp) mfc0 k0, CP0_EPC .set noreorder j k0 - rfe + rfe #else and k0, ST0_IE bnez k0, 1f @@ -189,7 +189,7 @@ NESTED(handle_int, PT_SIZE, sp) LONG_L s0, TI_REGS($28) LONG_S sp, TI_REGS($28) PTR_LA ra, ret_from_irq - PTR_LA v0, plat_irq_dispatch + PTR_LA v0, plat_irq_dispatch jr v0 #ifdef CONFIG_CPU_MICROMIPS nop @@ -292,7 +292,7 @@ ejtag_return: MFC0 k0, CP0_DESAVE .set mips32 deret - .set pop + .set pop END(ejtag_debug_handler) /* @@ -329,10 +329,10 @@ NESTED(nmi_handler, PT_SIZE, sp) * Clear BEV - required for page fault exception handler to work */ mfc0 k0, CP0_STATUS - ori k0, k0, ST0_EXL + ori k0, k0, ST0_EXL li k1, ~(ST0_BEV | ST0_ERL) - and k0, k0, k1 - mtc0 k0, CP0_STATUS + and k0, k0, k1 + mtc0 k0, CP0_STATUS _ehb SAVE_ALL move a0, sp @@ -396,7 +396,7 @@ NESTED(nmi_handler, PT_SIZE, sp) .macro __BUILD_count exception LONG_L t0,exception_count_\exception - LONG_ADDIU t0, 1 + LONG_ADDIU t0, 1 LONG_S t0,exception_count_\exception .comm exception_count\exception, 8, 8 .endm @@ -455,10 +455,10 @@ NESTED(nmi_handler, PT_SIZE, sp) .set noreorder /* check if TLB contains a entry for EPC */ MFC0 k1, CP0_ENTRYHI - andi k1, 0xff /* ASID_MASK */ + andi k1, MIPS_ENTRYHI_ASID | MIPS_ENTRYHI_ASIDX MFC0 k0, CP0_EPC - PTR_SRL k0, _PAGE_SHIFT + 1 - PTR_SLL k0, _PAGE_SHIFT + 1 + PTR_SRL k0, _PAGE_SHIFT + 1 + PTR_SLL k0, _PAGE_SHIFT + 1 or k1, k0 MTC0 k1, CP0_ENTRYHI mtc0_tlbw_hazard @@ -478,27 +478,27 @@ NESTED(nmi_handler, PT_SIZE, sp) /* microMIPS: 0x007d6b3c: rdhwr v1,$29 */ MFC0 k1, CP0_EPC #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS64_R2) - and k0, k1, 1 - beqz k0, 1f - xor k1, k0 - lhu k0, (k1) - lhu k1, 2(k1) - ins k1, k0, 16, 16 - lui k0, 0x007d - b docheck - ori k0, 0x6b3c + and k0, k1, 1 + beqz k0, 1f + xor k1, k0 + lhu k0, (k1) + lhu k1, 2(k1) + ins k1, k0, 16, 16 + lui k0, 0x007d + b docheck + ori k0, 0x6b3c 1: - lui k0, 0x7c03 - lw k1, (k1) - ori k0, 0xe83b + lui k0, 0x7c03 + lw k1, (k1) + ori k0, 0xe83b #else - andi k0, k1, 1 - bnez k0, handle_ri - lui k0, 0x7c03 - lw k1, (k1) - ori k0, 0xe83b + andi k0, k1, 1 + bnez k0, handle_ri + lui k0, 0x7c03 + lw k1, (k1) + ori k0, 0xe83b #endif - .set reorder + .set reorder docheck: bne k0, k1, handle_ri /* if not ours */ diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 4e4cc5b..56e8fed 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -21,7 +21,6 @@ #include <asm/asmmacro.h> #include <asm/irqflags.h> #include <asm/regdef.h> -#include <asm/pgtable-bits.h> #include <asm/mipsregs.h> #include <asm/stackframe.h> @@ -132,7 +131,27 @@ not_found: set_saved_sp sp, t0, t1 PTR_SUBU sp, 4 * SZREG # init stack pointer +#ifdef CONFIG_RELOCATABLE + /* Copy kernel and apply the relocations */ + jal relocate_kernel + + /* Repoint the sp into the new kernel image */ + PTR_LI sp, _THREAD_SIZE - 32 - PT_SIZE + PTR_ADDU sp, $28 + set_saved_sp sp, t0, t1 + PTR_SUBU sp, 4 * SZREG # init stack pointer + + /* + * relocate_kernel returns the entry point either + * in the relocated kernel or the original if for + * some reason relocation failed - jump there now + * with instruction hazard barrier because of the + * newly sync'd icache. + */ + jr.hb v0 +#else j start_kernel +#endif END(kernel_entry) #ifdef CONFIG_SMP diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index 46794d6..60ab4c4 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -181,6 +181,11 @@ void __init check_wait(void) case CPU_XLP: cpu_wait = r4k_wait; break; + case CPU_LOONGSON3: + if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON3A_R2) + cpu_wait = r4k_wait; + break; + case CPU_BMIPS5000: cpu_wait = r4k_wait_irqoff; break; diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index 3fff89a..625ee77 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -28,6 +28,7 @@ #include <asm/inst.h> #include <asm/mips-r2-to-r6-emul.h> #include <asm/local.h> +#include <asm/mipsregs.h> #include <asm/ptrace.h> #include <asm/uaccess.h> @@ -1251,10 +1252,10 @@ fpu_emul: " j 10b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1326,10 +1327,10 @@ fpu_emul: " j 10b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1397,10 +1398,10 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1467,10 +1468,10 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1582,14 +1583,14 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" - " .word 5b,8b\n" - " .word 6b,8b\n" - " .word 7b,8b\n" - " .word 0b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" + STR(PTR) " 5b,8b\n" + STR(PTR) " 6b,8b\n" + STR(PTR) " 7b,8b\n" + STR(PTR) " 0b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1701,14 +1702,14 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" - " .word 5b,8b\n" - " .word 6b,8b\n" - " .word 7b,8b\n" - " .word 0b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" + STR(PTR) " 5b,8b\n" + STR(PTR) " 6b,8b\n" + STR(PTR) " 7b,8b\n" + STR(PTR) " 0b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1820,14 +1821,14 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" - " .word 5b,8b\n" - " .word 6b,8b\n" - " .word 7b,8b\n" - " .word 0b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" + STR(PTR) " 5b,8b\n" + STR(PTR) " 6b,8b\n" + STR(PTR) " 7b,8b\n" + STR(PTR) " 0b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1938,14 +1939,14 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" - " .word 5b,8b\n" - " .word 6b,8b\n" - " .word 7b,8b\n" - " .word 0b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" + STR(PTR) " 5b,8b\n" + STR(PTR) " 6b,8b\n" + STR(PTR) " 7b,8b\n" + STR(PTR) " 0b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -2000,7 +2001,7 @@ fpu_emul: "j 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" - ".word 1b, 3b\n" + STR(PTR) " 1b,3b\n" ".previous\n" : "=&r"(res), "+&r"(err) : "r"(vaddr), "i"(SIGSEGV) @@ -2058,7 +2059,7 @@ fpu_emul: "j 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" - ".word 1b, 3b\n" + STR(PTR) " 1b,3b\n" ".previous\n" : "+&r"(res), "+&r"(err) : "r"(vaddr), "i"(SIGSEGV)); @@ -2119,7 +2120,7 @@ fpu_emul: "j 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" - ".word 1b, 3b\n" + STR(PTR) " 1b,3b\n" ".previous\n" : "=&r"(res), "+&r"(err) : "r"(vaddr), "i"(SIGSEGV) @@ -2182,7 +2183,7 @@ fpu_emul: "j 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" - ".word 1b, 3b\n" + STR(PTR) " 1b,3b\n" ".previous\n" : "+&r"(res), "+&r"(err) : "r"(vaddr), "i"(SIGSEGV)); diff --git a/arch/mips/kernel/module-rela.c b/arch/mips/kernel/module-rela.c index 9083d63..7811688 100644 --- a/arch/mips/kernel/module-rela.c +++ b/arch/mips/kernel/module-rela.c @@ -16,6 +16,7 @@ * Copyright (C) 2001 Rusty Russell. * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2005 Thiemo Seufer + * Copyright (C) 2015 Imagination Technologies Ltd. */ #include <linux/elf.h> @@ -35,15 +36,13 @@ static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v) static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v) { if (v % 4) { - pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n", + pr_err("module %s: dangerous R_MIPS_26 RELA relocation\n", me->name); return -ENOEXEC; } if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { - printk(KERN_ERR - "module %s: relocation overflow\n", - me->name); + pr_err("module %s: relocation overflow\n", me->name); return -ENOEXEC; } @@ -67,6 +66,48 @@ static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v) return 0; } +static int apply_r_mips_pc_rela(struct module *me, u32 *location, Elf_Addr v, + unsigned bits) +{ + unsigned long mask = GENMASK(bits - 1, 0); + unsigned long se_bits; + long offset; + + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_PC%u RELA relocation\n", + me->name, bits); + return -ENOEXEC; + } + + offset = ((long)v - (long)location) >> 2; + + /* check the sign bit onwards are identical - ie. we didn't overflow */ + se_bits = (offset & BIT(bits - 1)) ? ~0ul : 0; + if ((offset & ~mask) != (se_bits & ~mask)) { + pr_err("module %s: relocation overflow\n", me->name); + return -ENOEXEC; + } + + *location = (*location & ~mask) | (offset & mask); + + return 0; +} + +static int apply_r_mips_pc16_rela(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rela(me, location, v, 16); +} + +static int apply_r_mips_pc21_rela(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rela(me, location, v, 21); +} + +static int apply_r_mips_pc26_rela(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rela(me, location, v, 26); +} + static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v) { *(Elf_Addr *)location = v; @@ -99,9 +140,12 @@ static int (*reloc_handlers_rela[]) (struct module *me, u32 *location, [R_MIPS_26] = apply_r_mips_26_rela, [R_MIPS_HI16] = apply_r_mips_hi16_rela, [R_MIPS_LO16] = apply_r_mips_lo16_rela, + [R_MIPS_PC16] = apply_r_mips_pc16_rela, [R_MIPS_64] = apply_r_mips_64_rela, [R_MIPS_HIGHER] = apply_r_mips_higher_rela, - [R_MIPS_HIGHEST] = apply_r_mips_highest_rela + [R_MIPS_HIGHEST] = apply_r_mips_highest_rela, + [R_MIPS_PC21_S2] = apply_r_mips_pc21_rela, + [R_MIPS_PC26_S2] = apply_r_mips_pc26_rela, }; int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, @@ -126,11 +170,11 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, /* This is the symbol it is referring to */ sym = (Elf_Sym *)sechdrs[symindex].sh_addr + ELF_MIPS_R_SYM(rel[i]); - if (IS_ERR_VALUE(sym->st_value)) { + if (sym->st_value >= -MAX_ERRNO) { /* Ignore unresolved weak symbol */ if (ELF_ST_BIND(sym->st_info) == STB_WEAK) continue; - printk(KERN_WARNING "%s: Unknown symbol %s\n", + pr_warn("%s: Unknown symbol %s\n", me->name, strtab + sym->st_name); return -ENOENT; } diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index f9b2936..79850e3 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c @@ -73,8 +73,7 @@ static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) } if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { - printk(KERN_ERR - "module %s: relocation overflow\n", + pr_err("module %s: relocation overflow\n", me->name); return -ENOEXEC; } @@ -183,13 +182,62 @@ out_danger: return -ENOEXEC; } +static int apply_r_mips_pc_rel(struct module *me, u32 *location, Elf_Addr v, + unsigned bits) +{ + unsigned long mask = GENMASK(bits - 1, 0); + unsigned long se_bits; + long offset; + + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_PC%u REL relocation\n", + me->name, bits); + return -ENOEXEC; + } + + /* retrieve & sign extend implicit addend */ + offset = *location & mask; + offset |= (offset & BIT(bits - 1)) ? ~mask : 0; + + offset += ((long)v - (long)location) >> 2; + + /* check the sign bit onwards are identical - ie. we didn't overflow */ + se_bits = (offset & BIT(bits - 1)) ? ~0ul : 0; + if ((offset & ~mask) != (se_bits & ~mask)) { + pr_err("module %s: relocation overflow\n", me->name); + return -ENOEXEC; + } + + *location = (*location & ~mask) | (offset & mask); + + return 0; +} + +static int apply_r_mips_pc16_rel(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rel(me, location, v, 16); +} + +static int apply_r_mips_pc21_rel(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rel(me, location, v, 21); +} + +static int apply_r_mips_pc26_rel(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rel(me, location, v, 26); +} + static int (*reloc_handlers_rel[]) (struct module *me, u32 *location, Elf_Addr v) = { [R_MIPS_NONE] = apply_r_mips_none, [R_MIPS_32] = apply_r_mips_32_rel, [R_MIPS_26] = apply_r_mips_26_rel, [R_MIPS_HI16] = apply_r_mips_hi16_rel, - [R_MIPS_LO16] = apply_r_mips_lo16_rel + [R_MIPS_LO16] = apply_r_mips_lo16_rel, + [R_MIPS_PC16] = apply_r_mips_pc16_rel, + [R_MIPS_PC21_S2] = apply_r_mips_pc21_rel, + [R_MIPS_PC26_S2] = apply_r_mips_pc26_rel, }; int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, @@ -215,12 +263,12 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, /* This is the symbol it is referring to */ sym = (Elf_Sym *)sechdrs[symindex].sh_addr + ELF_MIPS_R_SYM(rel[i]); - if (IS_ERR_VALUE(sym->st_value)) { + if (sym->st_value >= -MAX_ERRNO) { /* Ignore unresolved weak symbol */ if (ELF_ST_BIND(sym->st_info) == STB_WEAK) continue; - printk(KERN_WARNING "%s: Unknown symbol %s\n", - me->name, strtab + sym->st_name); + pr_warn("%s: Unknown symbol %s\n", + me->name, strtab + sym->st_name); return -ENOENT; } diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index 9bc1191..d3ba9f4 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -101,8 +101,6 @@ struct mips_pmu { static struct mips_pmu mipspmu; -#define M_CONFIG1_PC (1 << 4) - #define M_PERFCTL_EXL (1 << 0) #define M_PERFCTL_KERNEL (1 << 1) #define M_PERFCTL_SUPERVISOR (1 << 2) @@ -754,7 +752,7 @@ static void handle_associated_event(struct cpu_hw_events *cpuc, static int __n_counters(void) { - if (!(read_c0_config1() & M_CONFIG1_PC)) + if (!cpu_has_perf) return 0; if (!(read_c0_perfctrl0() & M_PERFCTL_MORE)) return 1; @@ -825,6 +823,16 @@ static const struct mips_perf_event mipsxxcore_event_map2 [PERF_COUNT_HW_BRANCH_MISSES] = { 0x27, CNTR_ODD, T }, }; +static const struct mips_perf_event i6400_event_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD }, + [PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD }, + /* These only count dcache, not icache */ + [PERF_COUNT_HW_CACHE_REFERENCES] = { 0x45, CNTR_EVEN | CNTR_ODD }, + [PERF_COUNT_HW_CACHE_MISSES] = { 0x48, CNTR_EVEN | CNTR_ODD }, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x15, CNTR_EVEN | CNTR_ODD }, + [PERF_COUNT_HW_BRANCH_MISSES] = { 0x16, CNTR_EVEN | CNTR_ODD }, +}; + static const struct mips_perf_event loongson3_event_map[PERF_COUNT_HW_MAX] = { [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN }, [PERF_COUNT_HW_INSTRUCTIONS] = { 0x00, CNTR_ODD }, @@ -1015,6 +1023,46 @@ static const struct mips_perf_event mipsxxcore_cache_map2 }, }; +static const struct mips_perf_event i6400_cache_map + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { +[C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x46, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x49, CNTR_EVEN | CNTR_ODD }, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { 0x47, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x4a, CNTR_EVEN | CNTR_ODD }, + }, +}, +[C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x84, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x85, CNTR_EVEN | CNTR_ODD }, + }, +}, +[C(DTLB)] = { + /* Can't distinguish read & write */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x40, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x41, CNTR_EVEN | CNTR_ODD }, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { 0x40, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x41, CNTR_EVEN | CNTR_ODD }, + }, +}, +[C(BPU)] = { + /* Conditional branches / mispredicted */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x15, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x16, CNTR_EVEN | CNTR_ODD }, + }, +}, +}; + static const struct mips_perf_event loongson3_cache_map [PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_OP_MAX] @@ -1556,6 +1604,7 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) #endif break; case CPU_P5600: + case CPU_P6600: case CPU_I6400: /* 8-bit event numbers */ raw_id = config & 0x1ff; @@ -1718,11 +1767,16 @@ init_hw_perf_events(void) mipspmu.general_event_map = &mipsxxcore_event_map2; mipspmu.cache_event_map = &mipsxxcore_cache_map2; break; - case CPU_I6400: - mipspmu.name = "mips/I6400"; + case CPU_P6600: + mipspmu.name = "mips/P6600"; mipspmu.general_event_map = &mipsxxcore_event_map2; mipspmu.cache_event_map = &mipsxxcore_cache_map2; break; + case CPU_I6400: + mipspmu.name = "mips/I6400"; + mipspmu.general_event_map = &i6400_event_map; + mipspmu.cache_event_map = &i6400_cache_map; + break; case CPU_1004K: mipspmu.name = "mips/1004K"; mipspmu.general_event_map = &mipsxxcore_event_map; diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index fa3f9eb..adda3ff 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -224,11 +224,18 @@ static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, uasm_build_label(pl, *pp, lbl); /* Generate the cache ops */ - for (i = 0; i < unroll_lines; i++) - uasm_i_cache(pp, op, i * cache->linesz, t0); + for (i = 0; i < unroll_lines; i++) { + if (cpu_has_mips_r6) { + uasm_i_cache(pp, op, 0, t0); + uasm_i_addiu(pp, t0, t0, cache->linesz); + } else { + uasm_i_cache(pp, op, i * cache->linesz, t0); + } + } - /* Update the base address */ - uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz); + if (!cpu_has_mips_r6) + /* Update the base address */ + uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz); /* Loop if we haven't reached the end address yet */ uasm_il_bne(pp, pr, t0, t1, lbl); diff --git a/arch/mips/kernel/pm.c b/arch/mips/kernel/pm.c index fefdf39..dc81489 100644 --- a/arch/mips/kernel/pm.c +++ b/arch/mips/kernel/pm.c @@ -56,7 +56,7 @@ static void mips_cpu_restore(void) write_c0_userlocal(current_thread_info()->tp_value); /* Restore watch registers */ - __restore_watch(); + __restore_watch(current); } /** diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 298b2b7..97dc01b 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -114,6 +114,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (cpu_has_smartmips) seq_printf(m, "%s", " smartmips"); if (cpu_has_dsp) seq_printf(m, "%s", " dsp"); if (cpu_has_dsp2) seq_printf(m, "%s", " dsp2"); + if (cpu_has_dsp3) seq_printf(m, "%s", " dsp3"); if (cpu_has_mipsmt) seq_printf(m, "%s", " mt"); if (cpu_has_mmips) seq_printf(m, "%s", " micromips"); if (cpu_has_vz) seq_printf(m, "%s", " vz"); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 92880ce..a6b3dc5 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -77,10 +77,6 @@ void exit_thread(void) { } -void flush_thread(void) -{ -} - int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { /* @@ -455,7 +451,7 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page, *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) { regs = (struct pt_regs *)*sp; pc = regs->cp0_epc; - if (__kernel_text_address(pc)) { + if (!user_mode(regs) && __kernel_text_address(pc)) { *sp = regs->regs[29]; *ra = regs->regs[31]; return pc; @@ -580,11 +576,19 @@ int mips_get_process_fp_mode(struct task_struct *task) return value; } +static void prepare_for_fp_mode_switch(void *info) +{ + struct mm_struct *mm = info; + + if (current->mm == mm) + lose_fpu(1); +} + int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) { const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE; - unsigned long switch_count; struct task_struct *t; + int max_users; /* Check the value is valid */ if (value & ~known_bits) @@ -601,6 +605,9 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) if (!(value & PR_FP_MODE_FR) && cpu_has_fpu && cpu_has_mips_r6) return -EOPNOTSUPP; + /* Proceed with the mode switch */ + preempt_disable(); + /* Save FP & vector context, then disable FPU & MSA */ if (task->signal == current->signal) lose_fpu(1); @@ -610,31 +617,17 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) smp_mb__after_atomic(); /* - * If there are multiple online CPUs then wait until all threads whose - * FP mode is about to change have been context switched. This approach - * allows us to only worry about whether an FP mode switch is in - * progress when FP is first used in a tasks time slice. Pretty much all - * of the mode switch overhead can thus be confined to cases where mode - * switches are actually occurring. That is, to here. However for the - * thread performing the mode switch it may take a while... + * If there are multiple online CPUs then force any which are running + * threads in this process to lose their FPU context, which they can't + * regain until fp_mode_switching is cleared later. */ if (num_online_cpus() > 1) { - spin_lock_irq(&task->sighand->siglock); - - for_each_thread(task, t) { - if (t == current) - continue; - - switch_count = t->nvcsw + t->nivcsw; + /* No need to send an IPI for the local CPU */ + max_users = (task->mm == current->mm) ? 1 : 0; - do { - spin_unlock_irq(&task->sighand->siglock); - cond_resched(); - spin_lock_irq(&task->sighand->siglock); - } while ((t->nvcsw + t->nivcsw) == switch_count); - } - - spin_unlock_irq(&task->sighand->siglock); + if (atomic_read(¤t->mm->mm_users) > max_users) + smp_call_function(prepare_for_fp_mode_switch, + (void *)current->mm, 1); } /* @@ -659,6 +652,7 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) /* Allow threads to use FP again */ atomic_set(&task->mm->context.fp_mode_switching, 0); + preempt_enable(); return 0; } diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index a5279b2..0dcf691 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -57,8 +57,7 @@ static void init_fp_ctx(struct task_struct *target) /* Begin with data registers set to all 1s... */ memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr)); - /* ...and FCSR zeroed */ - target->thread.fpu.fcr31 = 0; + /* FCSR has been preset by `mips_set_personality_nan'. */ /* * Record that the target has "used" math, such that the context @@ -80,6 +79,22 @@ void ptrace_disable(struct task_struct *child) } /* + * Poke at FCSR according to its mask. Don't set the cause bits as + * this is currently not handled correctly in FP context restoration + * and will cause an oops if a corresponding enable bit is set. + */ +static void ptrace_setfcr31(struct task_struct *child, u32 value) +{ + u32 fcr31; + u32 mask; + + value &= ~FPU_CSR_ALL_X; + fcr31 = child->thread.fpu.fcr31; + mask = boot_cpu_data.fpu_msk31; + child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask); +} + +/* * Read a general register set. We always use the 64-bit format, even * for 32-bit kernels and for 32-bit processes on a 64-bit kernel. * Registers are sign extended to fill the available space. @@ -159,9 +174,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) { union fpureg *fregs; u64 fpr_val; - u32 fcr31; u32 value; - u32 mask; int i; if (!access_ok(VERIFY_READ, data, 33 * 8)) @@ -176,9 +189,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) } __get_user(value, data + 64); - fcr31 = child->thread.fpu.fcr31; - mask = boot_cpu_data.fpu_msk31; - child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask); + ptrace_setfcr31(child, value); /* FIR may not be written. */ @@ -210,7 +221,8 @@ int ptrace_get_watch_regs(struct task_struct *child, for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) { __put_user(child->thread.watch.mips3264.watchlo[i], &addr->WATCH_STYLE.watchlo[i]); - __put_user(child->thread.watch.mips3264.watchhi[i] & 0xfff, + __put_user(child->thread.watch.mips3264.watchhi[i] & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW), &addr->WATCH_STYLE.watchhi[i]); __put_user(boot_cpu_data.watch_reg_masks[i], &addr->WATCH_STYLE.watch_masks[i]); @@ -252,12 +264,12 @@ int ptrace_set_watch_regs(struct task_struct *child, } #endif __get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]); - if (ht[i] & ~0xff8) + if (ht[i] & ~MIPS_WATCHHI_MASK) return -EINVAL; } /* Install them. */ for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) { - if (lt[i] & 7) + if (lt[i] & MIPS_WATCHLO_IRW) watch_active = 1; child->thread.watch.mips3264.watchlo[i] = lt[i]; /* Set the G bit. */ @@ -805,7 +817,7 @@ long arch_ptrace(struct task_struct *child, long request, break; #endif case FPC_CSR: - child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X; + ptrace_setfcr31(child, data); break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 17732f8..56d86b0 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -244,17 +244,17 @@ LEAF(\name) .set push .set noat #ifdef CONFIG_64BIT - copy_u_d \wr, 1 + copy_s_d \wr, 1 EX sd $1, \off(\base) #elif defined(CONFIG_CPU_LITTLE_ENDIAN) - copy_u_w \wr, 2 + copy_s_w \wr, 2 EX sw $1, \off(\base) - copy_u_w \wr, 3 + copy_s_w \wr, 3 EX sw $1, (\off+4)(\base) #else /* CONFIG_CPU_BIG_ENDIAN */ - copy_u_w \wr, 2 + copy_s_w \wr, 2 EX sw $1, (\off+4)(\base) - copy_u_w \wr, 3 + copy_s_w \wr, 3 EX sw $1, \off(\base) #endif .set pop diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 92cd051..2f0a3b2 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -15,7 +15,6 @@ #include <asm/fpregdef.h> #include <asm/mipsregs.h> #include <asm/asm-offsets.h> -#include <asm/pgtable-bits.h> #include <asm/regdef.h> #include <asm/stackframe.h> #include <asm/thread_info.h> diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c new file mode 100644 index 0000000..ca1cc30 --- /dev/null +++ b/arch/mips/kernel/relocate.c @@ -0,0 +1,386 @@ +/* + * 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. + * + * Support for Kernel relocation at boot time + * + * Copyright (C) 2015, Imagination Technologies Ltd. + * Authors: Matt Redfearn (matt.redfearn@imgtec.com) + */ +#include <asm/bootinfo.h> +#include <asm/cacheflush.h> +#include <asm/fw/fw.h> +#include <asm/sections.h> +#include <asm/setup.h> +#include <asm/timex.h> +#include <linux/elf.h> +#include <linux/kernel.h> +#include <linux/libfdt.h> +#include <linux/of_fdt.h> +#include <linux/sched.h> +#include <linux/start_kernel.h> +#include <linux/string.h> +#include <linux/printk.h> + +#define RELOCATED(x) ((void *)((long)x + offset)) + +extern u32 _relocation_start[]; /* End kernel image / start relocation table */ +extern u32 _relocation_end[]; /* End relocation table */ + +extern long __start___ex_table; /* Start exception table */ +extern long __stop___ex_table; /* End exception table */ + +static inline u32 __init get_synci_step(void) +{ + u32 res; + + __asm__("rdhwr %0, $1" : "=r" (res)); + + return res; +} + +static void __init sync_icache(void *kbase, unsigned long kernel_length) +{ + void *kend = kbase + kernel_length; + u32 step = get_synci_step(); + + do { + __asm__ __volatile__( + "synci 0(%0)" + : /* no output */ + : "r" (kbase)); + + kbase += step; + } while (kbase < kend); + + /* Completion barrier */ + __sync(); +} + +static int __init apply_r_mips_64_rel(u32 *loc_orig, u32 *loc_new, long offset) +{ + *(u64 *)loc_new += offset; + + return 0; +} + +static int __init apply_r_mips_32_rel(u32 *loc_orig, u32 *loc_new, long offset) +{ + *loc_new += offset; + + return 0; +} + +static int __init apply_r_mips_26_rel(u32 *loc_orig, u32 *loc_new, long offset) +{ + unsigned long target_addr = (*loc_orig) & 0x03ffffff; + + if (offset % 4) { + pr_err("Dangerous R_MIPS_26 REL relocation\n"); + return -ENOEXEC; + } + + /* Original target address */ + target_addr <<= 2; + target_addr += (unsigned long)loc_orig & ~0x03ffffff; + + /* Get the new target address */ + target_addr += offset; + + if ((target_addr & 0xf0000000) != ((unsigned long)loc_new & 0xf0000000)) { + pr_err("R_MIPS_26 REL relocation overflow\n"); + return -ENOEXEC; + } + + target_addr -= (unsigned long)loc_new & ~0x03ffffff; + target_addr >>= 2; + + *loc_new = (*loc_new & ~0x03ffffff) | (target_addr & 0x03ffffff); + + return 0; +} + + +static int __init apply_r_mips_hi16_rel(u32 *loc_orig, u32 *loc_new, long offset) +{ + unsigned long insn = *loc_orig; + unsigned long target = (insn & 0xffff) << 16; /* high 16bits of target */ + + target += offset; + + *loc_new = (insn & ~0xffff) | ((target >> 16) & 0xffff); + return 0; +} + +static int (*reloc_handlers_rel[]) (u32 *, u32 *, long) __initdata = { + [R_MIPS_64] = apply_r_mips_64_rel, + [R_MIPS_32] = apply_r_mips_32_rel, + [R_MIPS_26] = apply_r_mips_26_rel, + [R_MIPS_HI16] = apply_r_mips_hi16_rel, +}; + +int __init do_relocations(void *kbase_old, void *kbase_new, long offset) +{ + u32 *r; + u32 *loc_orig; + u32 *loc_new; + int type; + int res; + + for (r = _relocation_start; r < _relocation_end; r++) { + /* Sentinel for last relocation */ + if (*r == 0) + break; + + type = (*r >> 24) & 0xff; + loc_orig = (void *)(kbase_old + ((*r & 0x00ffffff) << 2)); + loc_new = RELOCATED(loc_orig); + + if (reloc_handlers_rel[type] == NULL) { + /* Unsupported relocation */ + pr_err("Unhandled relocation type %d at 0x%pK\n", + type, loc_orig); + return -ENOEXEC; + } + + res = reloc_handlers_rel[type](loc_orig, loc_new, offset); + if (res) + return res; + } + + return 0; +} + +/* + * The exception table is filled in by the relocs tool after vmlinux is linked. + * It must be relocated separately since there will not be any relocation + * information for it filled in by the linker. + */ +static int __init relocate_exception_table(long offset) +{ + unsigned long *etable_start, *etable_end, *e; + + etable_start = RELOCATED(&__start___ex_table); + etable_end = RELOCATED(&__stop___ex_table); + + for (e = etable_start; e < etable_end; e++) + *e += offset; + + return 0; +} + +#ifdef CONFIG_RANDOMIZE_BASE + +static inline __init unsigned long rotate_xor(unsigned long hash, + const void *area, size_t size) +{ + size_t i; + unsigned long *ptr = (unsigned long *)area; + + for (i = 0; i < size / sizeof(hash); i++) { + /* Rotate by odd number of bits and XOR. */ + hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7); + hash ^= ptr[i]; + } + + return hash; +} + +static inline __init unsigned long get_random_boot(void) +{ + unsigned long entropy = random_get_entropy(); + unsigned long hash = 0; + + /* Attempt to create a simple but unpredictable starting entropy. */ + hash = rotate_xor(hash, linux_banner, strlen(linux_banner)); + + /* Add in any runtime entropy we can get */ + hash = rotate_xor(hash, &entropy, sizeof(entropy)); + +#if defined(CONFIG_USE_OF) + /* Get any additional entropy passed in device tree */ + { + int node, len; + u64 *prop; + + node = fdt_path_offset(initial_boot_params, "/chosen"); + if (node >= 0) { + prop = fdt_getprop_w(initial_boot_params, node, + "kaslr-seed", &len); + if (prop && (len == sizeof(u64))) + hash = rotate_xor(hash, prop, sizeof(*prop)); + } + } +#endif /* CONFIG_USE_OF */ + + return hash; +} + +static inline __init bool kaslr_disabled(void) +{ + char *str; + +#if defined(CONFIG_CMDLINE_BOOL) + const char *builtin_cmdline = CONFIG_CMDLINE; + + str = strstr(builtin_cmdline, "nokaslr"); + if (str == builtin_cmdline || + (str > builtin_cmdline && *(str - 1) == ' ')) + return true; +#endif + str = strstr(arcs_cmdline, "nokaslr"); + if (str == arcs_cmdline || (str > arcs_cmdline && *(str - 1) == ' ')) + return true; + + return false; +} + +static inline void __init *determine_relocation_address(void) +{ + /* Choose a new address for the kernel */ + unsigned long kernel_length; + void *dest = &_text; + unsigned long offset; + + if (kaslr_disabled()) + return dest; + + kernel_length = (long)_end - (long)(&_text); + + offset = get_random_boot() << 16; + offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1); + if (offset < kernel_length) + offset += ALIGN(kernel_length, 0xffff); + + return RELOCATED(dest); +} + +#else + +static inline void __init *determine_relocation_address(void) +{ + /* + * Choose a new address for the kernel + * For now we'll hard code the destination + */ + return (void *)0xffffffff81000000; +} + +#endif + +static inline int __init relocation_addr_valid(void *loc_new) +{ + if ((unsigned long)loc_new & 0x0000ffff) { + /* Inappropriately aligned new location */ + return 0; + } + if ((unsigned long)loc_new < (unsigned long)&_end) { + /* New location overlaps original kernel */ + return 0; + } + return 1; +} + +void *__init relocate_kernel(void) +{ + void *loc_new; + unsigned long kernel_length; + unsigned long bss_length; + long offset = 0; + int res = 1; + /* Default to original kernel entry point */ + void *kernel_entry = start_kernel; + + /* Get the command line */ + fw_init_cmdline(); +#if defined(CONFIG_USE_OF) + /* Deal with the device tree */ + early_init_dt_scan(plat_get_fdt()); + if (boot_command_line[0]) { + /* Boot command line was passed in device tree */ + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); + } +#endif /* CONFIG_USE_OF */ + + kernel_length = (long)(&_relocation_start) - (long)(&_text); + bss_length = (long)&__bss_stop - (long)&__bss_start; + + loc_new = determine_relocation_address(); + + /* Sanity check relocation address */ + if (relocation_addr_valid(loc_new)) + offset = (unsigned long)loc_new - (unsigned long)(&_text); + + /* Reset the command line now so we don't end up with a duplicate */ + arcs_cmdline[0] = '\0'; + + if (offset) { + /* Copy the kernel to it's new location */ + memcpy(loc_new, &_text, kernel_length); + + /* Perform relocations on the new kernel */ + res = do_relocations(&_text, loc_new, offset); + if (res < 0) + goto out; + + /* Sync the caches ready for execution of new kernel */ + sync_icache(loc_new, kernel_length); + + res = relocate_exception_table(offset); + if (res < 0) + goto out; + + /* + * The original .bss has already been cleared, and + * some variables such as command line parameters + * stored to it so make a copy in the new location. + */ + memcpy(RELOCATED(&__bss_start), &__bss_start, bss_length); + + /* The current thread is now within the relocated image */ + __current_thread_info = RELOCATED(&init_thread_union); + + /* Return the new kernel's entry point */ + kernel_entry = RELOCATED(start_kernel); + } +out: + return kernel_entry; +} + +/* + * Show relocation information on panic. + */ +void show_kernel_relocation(const char *level) +{ + unsigned long offset; + + offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS); + + if (IS_ENABLED(CONFIG_RELOCATABLE) && offset > 0) { + printk(level); + pr_cont("Kernel relocated by 0x%pK\n", (void *)offset); + pr_cont(" .text @ 0x%pK\n", _text); + pr_cont(" .data @ 0x%pK\n", _sdata); + pr_cont(" .bss @ 0x%pK\n", __bss_start); + } +} + +static int kernel_location_notifier_fn(struct notifier_block *self, + unsigned long v, void *p) +{ + show_kernel_relocation(KERN_EMERG); + return NOTIFY_DONE; +} + +static struct notifier_block kernel_location_notifier = { + .notifier_call = kernel_location_notifier_fn +}; + +static int __init register_kernel_offset_dumper(void) +{ + atomic_notifier_chain_register(&panic_notifier_list, + &kernel_location_notifier); + return 0; +} +__initcall(register_kernel_offset_dumper); diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index d01fe53..c8e43e0 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -35,7 +35,6 @@ NESTED(handle_sys, PT_SIZE, sp) lw t1, PT_EPC(sp) # skip syscall on return - subu v0, v0, __NR_O32_Linux # check syscall number addiu t1, 4 # skip to next instruction sw t1, PT_EPC(sp) @@ -89,6 +88,7 @@ loads_done: and t0, t1 bnez t0, syscall_trace_entry # -> yes syscall_common: + subu v0, v0, __NR_O32_Linux # check syscall number sltiu t0, v0, __NR_O32_Linux_syscalls + 1 beqz t0, illegal_syscall @@ -118,24 +118,23 @@ o32_syscall_exit: syscall_trace_entry: SAVE_STATIC - move s0, v0 move a0, sp /* * syscall number is in v0 unless we called syscall(__NR_###) * where the real syscall number is in a0 */ - addiu a1, v0, __NR_O32_Linux - bnez v0, 1f /* __NR_syscall at offset 0 */ + move a1, v0 + subu t2, v0, __NR_O32_Linux + bnez t2, 1f /* __NR_syscall at offset 0 */ lw a1, PT_R4(sp) 1: jal syscall_trace_enter bltz v0, 1f # seccomp failed? Skip syscall - move v0, s0 # restore syscall - RESTORE_STATIC + lw v0, PT_R2(sp) # Restore syscall (maybe modified) lw a0, PT_R4(sp) # Restore argument registers lw a1, PT_R5(sp) lw a2, PT_R6(sp) diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 6b73ecc..e6ede12 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -82,15 +82,14 @@ n64_syscall_exit: syscall_trace_entry: SAVE_STATIC - move s0, v0 move a0, sp move a1, v0 jal syscall_trace_enter bltz v0, 1f # seccomp failed? Skip syscall - move v0, s0 RESTORE_STATIC + ld v0, PT_R2(sp) # Restore syscall (maybe modified) ld a0, PT_R4(sp) # Restore argument registers ld a1, PT_R5(sp) ld a2, PT_R6(sp) diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 71f99d5..9c0b387 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -42,9 +42,6 @@ NESTED(handle_sysn32, PT_SIZE, sp) #endif beqz t0, not_n32_scall - dsll t0, v0, 3 # offset into table - ld t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0) - sd a3, PT_R26(sp) # save a3 for syscall restarting li t1, _TIF_WORK_SYSCALL_ENTRY @@ -53,6 +50,9 @@ NESTED(handle_sysn32, PT_SIZE, sp) bnez t0, n32_syscall_trace_entry syscall_common: + dsll t0, v0, 3 # offset into table + ld t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0) + jalr t2 # Do The Real Thing (TM) li t0, -EMAXERRNO - 1 # error? @@ -71,21 +71,25 @@ syscall_common: n32_syscall_trace_entry: SAVE_STATIC - move s0, t2 move a0, sp move a1, v0 jal syscall_trace_enter bltz v0, 1f # seccomp failed? Skip syscall - move t2, s0 RESTORE_STATIC + ld v0, PT_R2(sp) # Restore syscall (maybe modified) ld a0, PT_R4(sp) # Restore argument registers ld a1, PT_R5(sp) ld a2, PT_R6(sp) ld a3, PT_R7(sp) ld a4, PT_R8(sp) ld a5, PT_R9(sp) + + dsubu t2, v0, __NR_N32_Linux # check (new) syscall number + sltiu t0, t2, __NR_N32_Linux_syscalls + 1 + beqz t0, not_n32_scall + j syscall_common 1: j syscall_exit diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 91b43ee..f4f28b1 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -52,9 +52,6 @@ NESTED(handle_sys, PT_SIZE, sp) sll a2, a2, 0 sll a3, a3, 0 - dsll t0, v0, 3 # offset into table - ld t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0) - sd a3, PT_R26(sp) # save a3 for syscall restarting /* @@ -88,6 +85,9 @@ loads_done: bnez t0, trace_a_syscall syscall_common: + dsll t0, v0, 3 # offset into table + ld t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0) + jalr t2 # Do The Real Thing (TM) li t0, -EMAXERRNO - 1 # error? @@ -112,7 +112,6 @@ trace_a_syscall: sd a6, PT_R10(sp) sd a7, PT_R11(sp) # For indirect syscalls - move s0, t2 # Save syscall pointer move a0, sp /* * absolute syscall number is in v0 unless we called syscall(__NR_###) @@ -133,8 +132,8 @@ trace_a_syscall: bltz v0, 1f # seccomp failed? Skip syscall - move t2, s0 RESTORE_STATIC + ld v0, PT_R2(sp) # Restore syscall (maybe modified) ld a0, PT_R4(sp) # Restore argument registers ld a1, PT_R5(sp) ld a2, PT_R6(sp) @@ -143,6 +142,11 @@ trace_a_syscall: ld a5, PT_R9(sp) ld a6, PT_R10(sp) ld a7, PT_R11(sp) # For indirect syscalls + + dsubu t0, v0, __NR_O32_Linux # check (new) syscall number + sltiu t0, t0, __NR_O32_Linux_syscalls + 1 + beqz t0, not_o32_scall + j syscall_common 1: j syscall_exit diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 4f60734..ef408a0 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -26,6 +26,7 @@ #include <linux/sizes.h> #include <linux/device.h> #include <linux/dma-contiguous.h> +#include <linux/decompress/generic.h> #include <asm/addrspace.h> #include <asm/bootinfo.h> @@ -52,13 +53,6 @@ struct screen_info screen_info; #endif /* - * Despite it's name this variable is even if we don't have PCI - */ -unsigned int PCI_DMA_BUS_IS_PHYS; - -EXPORT_SYMBOL(PCI_DMA_BUS_IS_PHYS); - -/* * Setup information * * These are initialized so they are in the .data section @@ -250,6 +244,35 @@ disable: return 0; } +/* In some conditions (e.g. big endian bootloader with a little endian + kernel), the initrd might appear byte swapped. Try to detect this and + byte swap it if needed. */ +static void __init maybe_bswap_initrd(void) +{ +#if defined(CONFIG_CPU_CAVIUM_OCTEON) + u64 buf; + + /* Check for CPIO signature */ + if (!memcmp((void *)initrd_start, "070701", 6)) + return; + + /* Check for compressed initrd */ + if (decompress_method((unsigned char *)initrd_start, 8, NULL)) + return; + + /* Try again with a byte swapped header */ + buf = swab64p((u64 *)initrd_start); + if (!memcmp(&buf, "070701", 6) || + decompress_method((unsigned char *)(&buf), 8, NULL)) { + unsigned long i; + + pr_info("Byteswapped initrd detected\n"); + for (i = initrd_start; i < ALIGN(initrd_end, 8); i += 8) + swab64s((u64 *)i); + } +#endif +} + static void __init finalize_initrd(void) { unsigned long size = initrd_end - initrd_start; @@ -263,6 +286,8 @@ static void __init finalize_initrd(void) goto disable; } + maybe_bswap_initrd(); + reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT); initrd_below_start_ok = 1; @@ -469,6 +494,29 @@ static void __init bootmem_init(void) */ reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT); +#ifdef CONFIG_RELOCATABLE + /* + * The kernel reserves all memory below its _end symbol as bootmem, + * but the kernel may now be at a much higher address. The memory + * between the original and new locations may be returned to the system. + */ + if (__pa_symbol(_text) > __pa_symbol(VMLINUX_LOAD_ADDRESS)) { + unsigned long offset; + extern void show_kernel_relocation(const char *level); + + offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS); + free_bootmem(__pa_symbol(VMLINUX_LOAD_ADDRESS), offset); + +#if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO) + /* + * This information is necessary when debugging the kernel + * But is a security vulnerability otherwise! + */ + show_kernel_relocation(KERN_INFO); +#endif + } +#endif + /* * Reserve initrd memory if needed. */ @@ -624,6 +672,8 @@ static void __init request_crashkernel(struct resource *res) #define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER) #define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB) #define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND) +#define BUILTIN_EXTEND_WITH_PROM \ + IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND) static void __init arch_mem_init(char **cmdline_p) { @@ -657,15 +707,23 @@ static void __init arch_mem_init(char **cmdline_p) strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); if (EXTEND_WITH_PROM && arcs_cmdline[0]) { - strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + if (boot_command_line[0]) + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); } #if defined(CONFIG_CMDLINE_BOOL) if (builtin_cmdline[0]) { - strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + if (boot_command_line[0]) + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); } + + if (BUILTIN_EXTEND_WITH_PROM && arcs_cmdline[0]) { + if (boot_command_line[0]) + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); + } #endif #endif strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); @@ -706,6 +764,9 @@ static void __init arch_mem_init(char **cmdline_p) for_each_memblock(reserved, reg) if (reg->size != 0) reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT); + + reserve_bootmem_region(__pa_symbol(&__nosave_begin), + __pa_symbol(&__nosave_end)); /* Reserve for hibernation */ } static void __init resource_init(void) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index bf792e2..ab04229 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -195,6 +195,9 @@ static int restore_msa_extcontext(void __user *buf, unsigned int size) unsigned int csr; int i, err; + if (!config_enabled(CONFIG_CPU_HAS_MSA)) + return SIGSYS; + if (size != sizeof(*msa)) return -EINVAL; @@ -398,8 +401,8 @@ int protected_restore_fp_context(void __user *sc) } fp_done: - if (used & USED_EXTCONTEXT) - err |= restore_extcontext(sc_to_extcontext(sc)); + if (!err && (used & USED_EXTCONTEXT)) + err = restore_extcontext(sc_to_extcontext(sc)); return err ?: sig; } @@ -798,7 +801,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) regs->regs[0] = 0; /* Don't deal with this again. */ } - if (sig_uses_siginfo(&ksig->ka)) + if (sig_uses_siginfo(&ksig->ka, abi)) ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn, ksig, regs, oldset); else diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 4909639..78c8349 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -227,6 +227,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_int, &to->si_int); break; + case __SI_SYS >> 16: + err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr, + sizeof(compat_uptr_t)); + err |= __put_user(from->si_syscall, &to->si_syscall); + err |= __put_user(from->si_arch, &to->si_arch); + break; } } return err; diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 78cf8c2..e02addc 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -243,6 +243,7 @@ static void bmips_init_secondary(void) break; case CPU_BMIPS5000: write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); + current_cpu_data.core = (read_c0_brcm_config() >> 25) & 3; break; } } @@ -565,3 +566,90 @@ asmlinkage void __weak plat_wired_tlb_setup(void) * once the wired entries are present. */ } + +void __init bmips_cpu_setup(void) +{ + void __iomem __maybe_unused *cbr = BMIPS_GET_CBR(); + u32 __maybe_unused cfg; + + switch (current_cpu_type()) { + case CPU_BMIPS3300: + /* Set BIU to async mode */ + set_c0_brcm_bus_pll(BIT(22)); + __sync(); + + /* put the BIU back in sync mode */ + clear_c0_brcm_bus_pll(BIT(22)); + + /* clear BHTD to enable branch history table */ + clear_c0_brcm_reset(BIT(16)); + + /* Flush and enable RAC */ + cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG); + __raw_writel(cfg | 0x100, BMIPS_RAC_CONFIG); + __raw_readl(cbr + BMIPS_RAC_CONFIG); + + cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG); + __raw_writel(cfg | 0xf, BMIPS_RAC_CONFIG); + __raw_readl(cbr + BMIPS_RAC_CONFIG); + + cfg = __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE); + __raw_writel(cfg | 0x0fff0000, cbr + BMIPS_RAC_ADDRESS_RANGE); + __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE); + break; + + case CPU_BMIPS4380: + /* CBG workaround for early BMIPS4380 CPUs */ + switch (read_c0_prid()) { + case 0x2a040: + case 0x2a042: + case 0x2a044: + case 0x2a060: + cfg = __raw_readl(cbr + BMIPS_L2_CONFIG); + __raw_writel(cfg & ~0x07000000, cbr + BMIPS_L2_CONFIG); + __raw_readl(cbr + BMIPS_L2_CONFIG); + } + + /* clear BHTD to enable branch history table */ + clear_c0_brcm_config_0(BIT(21)); + + /* XI/ROTR enable */ + set_c0_brcm_config_0(BIT(23)); + set_c0_brcm_cmt_ctrl(BIT(15)); + break; + + case CPU_BMIPS5000: + /* enable RDHWR, BRDHWR */ + set_c0_brcm_config(BIT(17) | BIT(21)); + + /* Disable JTB */ + __asm__ __volatile__( + " .set noreorder\n" + " li $8, 0x5a455048\n" + " .word 0x4088b00f\n" /* mtc0 t0, $22, 15 */ + " .word 0x4008b008\n" /* mfc0 t0, $22, 8 */ + " li $9, 0x00008000\n" + " or $8, $8, $9\n" + " .word 0x4088b008\n" /* mtc0 t0, $22, 8 */ + " sync\n" + " li $8, 0x0\n" + " .word 0x4088b00f\n" /* mtc0 t0, $22, 15 */ + " .set reorder\n" + : : : "$8", "$9"); + + /* XI enable */ + set_c0_brcm_config(BIT(27)); + + /* enable MIPS32R2 ROR instruction for XI TLB handlers */ + __asm__ __volatile__( + " li $8, 0x5a455048\n" + " .word 0x4088b00f\n" /* mtc0 $8, $22, 15 */ + " nop; nop; nop\n" + " .word 0x4008b008\n" /* mfc0 $8, $22, 8 */ + " lui $9, 0x0100\n" + " or $8, $9\n" + " .word 0x4088b008\n" /* mtc0 $8, $22, 8 */ + : : : "$8", "$9"); + break; + } +} diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 253e140..1061bd2 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -27,15 +27,27 @@ #include <asm/time.h> #include <asm/uasm.h> +static bool threads_disabled; static DECLARE_BITMAP(core_power, NR_CPUS); struct core_boot_config *mips_cps_core_bootcfg; +static int __init setup_nothreads(char *s) +{ + threads_disabled = true; + return 0; +} +early_param("nothreads", setup_nothreads); + static unsigned core_vpe_count(unsigned core) { unsigned cfg; - if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) + if (threads_disabled) + return 1; + + if ((!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) + && (!config_enabled(CONFIG_CPU_MIPSR6) || !cpu_has_vp)) return 1; mips_cm_lock_other(core, 0); @@ -47,11 +59,12 @@ static unsigned core_vpe_count(unsigned core) static void __init cps_smp_setup(void) { unsigned int ncores, nvpes, core_vpes; + unsigned long core_entry; int c, v; /* Detect & record VPE topology */ ncores = mips_cm_numcores(); - pr_info("VPE topology "); + pr_info("%s topology ", cpu_has_mips_r6 ? "VP" : "VPE"); for (c = nvpes = 0; c < ncores; c++) { core_vpes = core_vpe_count(c); pr_cont("%c%u", c ? ',' : '{', core_vpes); @@ -62,7 +75,7 @@ static void __init cps_smp_setup(void) for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) { cpu_data[nvpes + v].core = c; -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) cpu_data[nvpes + v].vpe_id = v; #endif } @@ -91,6 +104,11 @@ static void __init cps_smp_setup(void) /* Make core 0 coherent with everything */ write_gcr_cl_coherence(0xff); + if (mips_cm_revision() >= CM_REV_CM3) { + core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry); + write_gcr_bev_base(core_entry); + } + #ifdef CONFIG_MIPS_MT_FPAFF /* If we have an FPU, enroll ourselves in the FPU-full mask */ if (cpu_has_fpu) @@ -213,6 +231,18 @@ static void boot_core(unsigned core) if (mips_cpc_present()) { /* Reset the core */ mips_cpc_lock_other(core); + + if (mips_cm_revision() >= CM_REV_CM3) { + /* Run VP0 following the reset */ + write_cpc_co_vp_run(0x1); + + /* + * Ensure that the VP_RUN register is written before the + * core leaves reset. + */ + wmb(); + } + write_cpc_co_cmd(CPC_Cx_CMD_RESET); timeout = 100; @@ -250,7 +280,10 @@ static void boot_core(unsigned core) static void remote_vpe_boot(void *dummy) { - mips_cps_boot_vpes(); + unsigned core = current_cpu_data.core; + struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core]; + + mips_cps_boot_vpes(core_cfg, cpu_vpe_id(¤t_cpu_data)); } static void cps_boot_secondary(int cpu, struct task_struct *idle) @@ -259,6 +292,7 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]); struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core]; struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id]; + unsigned long core_entry; unsigned int remote; int err; @@ -276,6 +310,13 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) goto out; } + if (cpu_has_vp) { + mips_cm_lock_other(core, vpe_id); + core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry); + write_gcr_co_reset_base(core_entry); + mips_cm_unlock_other(); + } + if (core != current_cpu_data.core) { /* Boot a VPE on another powered up core */ for (remote = 0; remote < NR_CPUS; remote++) { @@ -293,10 +334,10 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) goto out; } - BUG_ON(!cpu_has_mipsmt); + BUG_ON(!cpu_has_mipsmt && !cpu_has_vp); /* Boot a VPE on this core */ - mips_cps_boot_vpes(); + mips_cps_boot_vpes(core_cfg, vpe_id); out: preempt_enable(); } @@ -307,6 +348,17 @@ static void cps_init_secondary(void) if (cpu_has_mipsmt) dmt(); + if (mips_cm_revision() >= CM_REV_CM3) { + unsigned ident = gic_read_local_vp_id(); + + /* + * Ensure that our calculation of the VP ID matches up with + * what the GIC reports, otherwise we'll have configured + * interrupts incorrectly. + */ + BUG_ON(ident != mips_cm_vp_id(smp_processor_id())); + } + change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); } diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 27cb638..f9d01e9 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -243,18 +243,6 @@ static int __init mips_smp_ipi_init(void) struct irq_domain *ipidomain; struct device_node *node; - /* - * In some cases like qemu-malta, it is desired to try SMP with - * a single core. Qemu-malta has no GIC, so an attempt to set any IPIs - * would cause a BUG_ON() to be triggered since there's no ipidomain. - * - * Since for a single core system IPIs aren't required really, skip the - * initialisation which should generally keep any such configurations - * happy and only fail hard when trying to truely run SMP. - */ - if (cpumask_weight(cpu_possible_mask) == 1) - return 0; - node = of_irq_find_parent(of_root); ipidomain = irq_find_matching_host(node, DOMAIN_BUS_IPI); @@ -266,7 +254,17 @@ static int __init mips_smp_ipi_init(void) if (node && !ipidomain) ipidomain = irq_find_matching_host(NULL, DOMAIN_BUS_IPI); - BUG_ON(!ipidomain); + /* + * There are systems which only use IPI domains some of the time, + * depending upon configuration we don't know until runtime. An + * example is Malta where we may compile in support for GIC & the + * MT ASE, but run on a system which has multiple VPEs in a single + * core and doesn't include a GIC. Until all IPI implementations + * have been converted to use IPI domains the best we can do here + * is to return & hope some other code sets up the IPIs. + */ + if (!ipidomain) + return 0; call_virq = irq_reserve_ipi(ipidomain, cpu_possible_mask); BUG_ON(!call_virq); diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c index 8489c88..d6e6cf7 100644 --- a/arch/mips/kernel/spram.c +++ b/arch/mips/kernel/spram.c @@ -210,6 +210,7 @@ void spram_config(void) case CPU_P5600: case CPU_QEMU_GENERIC: case CPU_I6400: + case CPU_P6600: config0 = read_c0_config(); /* FIXME: addresses are Malta specific */ if (config0 & (1<<24)) { diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index ae0c89d..4a1712b 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -145,7 +145,7 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs) if (!task) task = current; - if (raw_show_trace || !__kernel_text_address(pc)) { + if (raw_show_trace || user_mode(regs) || !__kernel_text_address(pc)) { show_raw_backtrace(sp); return; } @@ -399,11 +399,8 @@ void __noreturn die(const char *str, struct pt_regs *regs) if (in_interrupt()) panic("Fatal exception in interrupt"); - if (panic_on_oops) { - printk(KERN_EMERG "Fatal exception: panic in 5 seconds"); - ssleep(5); + if (panic_on_oops) panic("Fatal exception"); - } if (regs && kexec_should_crash(current)) crash_kexec(regs); @@ -1249,7 +1246,7 @@ static int enable_restore_fp_context(int msa) err = init_fpu(); if (msa && !err) { enable_msa(); - _init_msa_upper(); + init_msa_upper(); set_thread_flag(TIF_USEDMSA); set_thread_flag(TIF_MSA_CTX_LIVE); } @@ -1312,7 +1309,7 @@ static int enable_restore_fp_context(int msa) */ prior_msa = test_and_set_thread_flag(TIF_MSA_CTX_LIVE); if (!prior_msa && was_fpu_owner) { - _init_msa_upper(); + init_msa_upper(); goto out; } @@ -1329,7 +1326,7 @@ static int enable_restore_fp_context(int msa) * of each vector register such that it cannot see data left * behind by another task. */ - _init_msa_upper(); + init_msa_upper(); } else { /* We need to restore the vector context. */ restore_msa(current); @@ -1356,7 +1353,6 @@ asmlinkage void do_cpu(struct pt_regs *regs) unsigned long fcr31; unsigned int cpid; int status, err; - unsigned long __maybe_unused flags; int sig; prev_state = exception_enter(); @@ -1501,16 +1497,13 @@ asmlinkage void do_watch(struct pt_regs *regs) { siginfo_t info = { .si_signo = SIGTRAP, .si_code = TRAP_HWBKPT }; enum ctx_state prev_state; - u32 cause; prev_state = exception_enter(); /* * Clear WP (bit 22) bit of cause register so we don't loop * forever. */ - cause = read_c0_cause(); - cause &= ~(1 << 22); - write_c0_cause(cause); + clear_c0_cause(CAUSEF_WP); /* * If the current thread has the watch registers loaded, save @@ -1647,6 +1640,7 @@ static inline void parity_protection_init(void) case CPU_P5600: case CPU_QEMU_GENERIC: case CPU_I6400: + case CPU_P6600: { #define ERRCTL_PE 0x80000000 #define ERRCTL_L2P 0x00800000 @@ -1777,7 +1771,8 @@ asmlinkage void do_ftlb(void) /* For the moment, report the problem and hang. */ if ((cpu_has_mips_r2_r6) && - ((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS)) { + (((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS) || + ((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_LOONGSON))) { pr_err("FTLB error exception, cp0_ecc=0x%08x:\n", read_c0_ecc()); pr_err("cp0_errorepc == %0*lx\n", field, read_c0_errorepc()); @@ -2119,6 +2114,13 @@ void per_cpu_trap_init(bool is_boot_cpu) * o read IntCtl.IPFDC to determine the fast debug channel interrupt */ if (cpu_has_mips_r2_r6) { + /* + * We shouldn't trust a secondary core has a sane EBASE register + * so use the one calculated by the boot CPU. + */ + if (!is_boot_cpu) + write_c0_ebase(ebase); + cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP; cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7; cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7; @@ -2134,7 +2136,7 @@ void per_cpu_trap_init(bool is_boot_cpu) } if (!cpu_data[cpu].asid_cache) - cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; + cpu_data[cpu].asid_cache = asid_first_version(cpu); atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 5c62065..28b3af7 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -1191,6 +1191,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, case ldc1_op: case swc1_op: case sdc1_op: + case cop1x_op: die_if_kernel("Unaligned FP access in kernel code", regs); BUG_ON(!used_math()); diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 54d653e..a82c178 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -136,6 +136,27 @@ SECTIONS #ifdef CONFIG_SMP PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT) #endif + +#ifdef CONFIG_RELOCATABLE + . = ALIGN(4); + + .data.reloc : { + _relocation_start = .; + /* + * Space for relocation table + * This needs to be filled so that the + * relocs tool can overwrite the content. + * An invalid value is left at the start of the + * section to abort relocation if the table + * has not been filled in. + */ + LONG(0xFFFFFFFF); + FILL(0); + . += CONFIG_RELOCATION_TABLE_SIZE - 4; + _relocation_end = .; + } +#endif + #ifdef CONFIG_MIPS_RAW_APPENDED_DTB __appended_dtb = .; /* leave space for appended DTB */ diff --git a/arch/mips/kernel/watch.c b/arch/mips/kernel/watch.c index 2a03abb..19fcab7 100644 --- a/arch/mips/kernel/watch.c +++ b/arch/mips/kernel/watch.c @@ -15,10 +15,9 @@ * Install the watch registers for the current thread. A maximum of * four registers are installed although the machine may have more. */ -void mips_install_watch_registers(void) +void mips_install_watch_registers(struct task_struct *t) { - struct mips3264_watch_reg_state *watches = - ¤t->thread.watch.mips3264; + struct mips3264_watch_reg_state *watches = &t->thread.watch.mips3264; switch (current_cpu_data.watch_reg_use_cnt) { default: BUG(); @@ -26,16 +25,20 @@ void mips_install_watch_registers(void) write_c0_watchlo3(watches->watchlo[3]); /* Write 1 to the I, R, and W bits to clear them, and 1 to G so all ASIDs are trapped. */ - write_c0_watchhi3(0x40000007 | watches->watchhi[3]); + write_c0_watchhi3(MIPS_WATCHHI_G | MIPS_WATCHHI_IRW | + watches->watchhi[3]); case 3: write_c0_watchlo2(watches->watchlo[2]); - write_c0_watchhi2(0x40000007 | watches->watchhi[2]); + write_c0_watchhi2(MIPS_WATCHHI_G | MIPS_WATCHHI_IRW | + watches->watchhi[2]); case 2: write_c0_watchlo1(watches->watchlo[1]); - write_c0_watchhi1(0x40000007 | watches->watchhi[1]); + write_c0_watchhi1(MIPS_WATCHHI_G | MIPS_WATCHHI_IRW | + watches->watchhi[1]); case 1: write_c0_watchlo0(watches->watchlo[0]); - write_c0_watchhi0(0x40000007 | watches->watchhi[0]); + write_c0_watchhi0(MIPS_WATCHHI_G | MIPS_WATCHHI_IRW | + watches->watchhi[0]); } } @@ -52,22 +55,26 @@ void mips_read_watch_registers(void) default: BUG(); case 4: - watches->watchhi[3] = (read_c0_watchhi3() & 0x0fff); + watches->watchhi[3] = (read_c0_watchhi3() & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW)); case 3: - watches->watchhi[2] = (read_c0_watchhi2() & 0x0fff); + watches->watchhi[2] = (read_c0_watchhi2() & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW)); case 2: - watches->watchhi[1] = (read_c0_watchhi1() & 0x0fff); + watches->watchhi[1] = (read_c0_watchhi1() & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW)); case 1: - watches->watchhi[0] = (read_c0_watchhi0() & 0x0fff); + watches->watchhi[0] = (read_c0_watchhi0() & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW)); } if (current_cpu_data.watch_reg_use_cnt == 1 && - (watches->watchhi[0] & 7) == 0) { + (watches->watchhi[0] & MIPS_WATCHHI_IRW) == 0) { /* Pathological case of release 1 architecture that * doesn't set the condition bits. We assume that * since we got here, the watch condition was met and * signal that the conditions requested in watchlo * were met. */ - watches->watchhi[0] |= (watches->watchlo[0] & 7); + watches->watchhi[0] |= (watches->watchlo[0] & MIPS_WATCHHI_IRW); } } @@ -110,86 +117,86 @@ void mips_probe_watch_registers(struct cpuinfo_mips *c) * Check which of the I,R and W bits are supported, then * disable the register. */ - write_c0_watchlo0(7); + write_c0_watchlo0(MIPS_WATCHLO_IRW); back_to_back_c0_hazard(); t = read_c0_watchlo0(); write_c0_watchlo0(0); - c->watch_reg_masks[0] = t & 7; + c->watch_reg_masks[0] = t & MIPS_WATCHLO_IRW; /* Write the mask bits and read them back to determine which * can be used. */ c->watch_reg_count = 1; c->watch_reg_use_cnt = 1; t = read_c0_watchhi0(); - write_c0_watchhi0(t | 0xff8); + write_c0_watchhi0(t | MIPS_WATCHHI_MASK); back_to_back_c0_hazard(); t = read_c0_watchhi0(); - c->watch_reg_masks[0] |= (t & 0xff8); - if ((t & 0x80000000) == 0) + c->watch_reg_masks[0] |= (t & MIPS_WATCHHI_MASK); + if ((t & MIPS_WATCHHI_M) == 0) return; - write_c0_watchlo1(7); + write_c0_watchlo1(MIPS_WATCHLO_IRW); back_to_back_c0_hazard(); t = read_c0_watchlo1(); write_c0_watchlo1(0); - c->watch_reg_masks[1] = t & 7; + c->watch_reg_masks[1] = t & MIPS_WATCHLO_IRW; c->watch_reg_count = 2; c->watch_reg_use_cnt = 2; t = read_c0_watchhi1(); - write_c0_watchhi1(t | 0xff8); + write_c0_watchhi1(t | MIPS_WATCHHI_MASK); back_to_back_c0_hazard(); t = read_c0_watchhi1(); - c->watch_reg_masks[1] |= (t & 0xff8); - if ((t & 0x80000000) == 0) + c->watch_reg_masks[1] |= (t & MIPS_WATCHHI_MASK); + if ((t & MIPS_WATCHHI_M) == 0) return; - write_c0_watchlo2(7); + write_c0_watchlo2(MIPS_WATCHLO_IRW); back_to_back_c0_hazard(); t = read_c0_watchlo2(); write_c0_watchlo2(0); - c->watch_reg_masks[2] = t & 7; + c->watch_reg_masks[2] = t & MIPS_WATCHLO_IRW; c->watch_reg_count = 3; c->watch_reg_use_cnt = 3; t = read_c0_watchhi2(); - write_c0_watchhi2(t | 0xff8); + write_c0_watchhi2(t | MIPS_WATCHHI_MASK); back_to_back_c0_hazard(); t = read_c0_watchhi2(); - c->watch_reg_masks[2] |= (t & 0xff8); - if ((t & 0x80000000) == 0) + c->watch_reg_masks[2] |= (t & MIPS_WATCHHI_MASK); + if ((t & MIPS_WATCHHI_M) == 0) return; - write_c0_watchlo3(7); + write_c0_watchlo3(MIPS_WATCHLO_IRW); back_to_back_c0_hazard(); t = read_c0_watchlo3(); write_c0_watchlo3(0); - c->watch_reg_masks[3] = t & 7; + c->watch_reg_masks[3] = t & MIPS_WATCHLO_IRW; c->watch_reg_count = 4; c->watch_reg_use_cnt = 4; t = read_c0_watchhi3(); - write_c0_watchhi3(t | 0xff8); + write_c0_watchhi3(t | MIPS_WATCHHI_MASK); back_to_back_c0_hazard(); t = read_c0_watchhi3(); - c->watch_reg_masks[3] |= (t & 0xff8); - if ((t & 0x80000000) == 0) + c->watch_reg_masks[3] |= (t & MIPS_WATCHHI_MASK); + if ((t & MIPS_WATCHHI_M) == 0) return; /* We use at most 4, but probe and report up to 8. */ c->watch_reg_count = 5; t = read_c0_watchhi4(); - if ((t & 0x80000000) == 0) + if ((t & MIPS_WATCHHI_M) == 0) return; c->watch_reg_count = 6; t = read_c0_watchhi5(); - if ((t & 0x80000000) == 0) + if ((t & MIPS_WATCHHI_M) == 0) return; c->watch_reg_count = 7; t = read_c0_watchhi6(); - if ((t & 0x80000000) == 0) + if ((t & MIPS_WATCHHI_M) == 0) return; c->watch_reg_count = 8; diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index b37954c..396df6e 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c @@ -302,12 +302,31 @@ static inline ktime_t kvm_mips_count_time(struct kvm_vcpu *vcpu) */ static uint32_t kvm_mips_read_count_running(struct kvm_vcpu *vcpu, ktime_t now) { - ktime_t expires; + struct mips_coproc *cop0 = vcpu->arch.cop0; + ktime_t expires, threshold; + uint32_t count, compare; int running; - /* Is the hrtimer pending? */ + /* Calculate the biased and scaled guest CP0_Count */ + count = vcpu->arch.count_bias + kvm_mips_ktime_to_count(vcpu, now); + compare = kvm_read_c0_guest_compare(cop0); + + /* + * Find whether CP0_Count has reached the closest timer interrupt. If + * not, we shouldn't inject it. + */ + if ((int32_t)(count - compare) < 0) + return count; + + /* + * The CP0_Count we're going to return has already reached the closest + * timer interrupt. Quickly check if it really is a new interrupt by + * looking at whether the interval until the hrtimer expiry time is + * less than 1/4 of the timer period. + */ expires = hrtimer_get_expires(&vcpu->arch.comparecount_timer); - if (ktime_compare(now, expires) >= 0) { + threshold = ktime_add_ns(now, vcpu->arch.count_period / 4); + if (ktime_before(expires, threshold)) { /* * Cancel it while we handle it so there's no chance of * interference with the timeout handler. @@ -329,8 +348,7 @@ static uint32_t kvm_mips_read_count_running(struct kvm_vcpu *vcpu, ktime_t now) } } - /* Return the biased and scaled guest CP0_Count */ - return vcpu->arch.count_bias + kvm_mips_ktime_to_count(vcpu, now); + return count; } /** @@ -420,32 +438,6 @@ static void kvm_mips_resume_hrtimer(struct kvm_vcpu *vcpu, } /** - * kvm_mips_update_hrtimer() - Update next expiry time of hrtimer. - * @vcpu: Virtual CPU. - * - * Recalculates and updates the expiry time of the hrtimer. This can be used - * after timer parameters have been altered which do not depend on the time that - * the change occurs (in those cases kvm_mips_freeze_hrtimer() and - * kvm_mips_resume_hrtimer() are used directly). - * - * It is guaranteed that no timer interrupts will be lost in the process. - * - * Assumes !kvm_mips_count_disabled(@vcpu) (guest CP0_Count timer is running). - */ -static void kvm_mips_update_hrtimer(struct kvm_vcpu *vcpu) -{ - ktime_t now; - uint32_t count; - - /* - * freeze_hrtimer takes care of a timer interrupts <= count, and - * resume_hrtimer the hrtimer takes care of a timer interrupts > count. - */ - now = kvm_mips_freeze_hrtimer(vcpu, &count); - kvm_mips_resume_hrtimer(vcpu, now, count); -} - -/** * kvm_mips_write_count() - Modify the count and update timer. * @vcpu: Virtual CPU. * @count: Guest CP0_Count value to set. @@ -540,23 +532,42 @@ int kvm_mips_set_count_hz(struct kvm_vcpu *vcpu, s64 count_hz) * kvm_mips_write_compare() - Modify compare and update timer. * @vcpu: Virtual CPU. * @compare: New CP0_Compare value. + * @ack: Whether to acknowledge timer interrupt. * * Update CP0_Compare to a new value and update the timeout. + * If @ack, atomically acknowledge any pending timer interrupt, otherwise ensure + * any pending timer interrupt is preserved. */ -void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare) +void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare, bool ack) { struct mips_coproc *cop0 = vcpu->arch.cop0; + int dc; + u32 old_compare = kvm_read_c0_guest_compare(cop0); + ktime_t now; + uint32_t count; /* if unchanged, must just be an ack */ - if (kvm_read_c0_guest_compare(cop0) == compare) + if (old_compare == compare) { + if (!ack) + return; + kvm_mips_callbacks->dequeue_timer_int(vcpu); + kvm_write_c0_guest_compare(cop0, compare); return; + } + + /* freeze_hrtimer() takes care of timer interrupts <= count */ + dc = kvm_mips_count_disabled(vcpu); + if (!dc) + now = kvm_mips_freeze_hrtimer(vcpu, &count); + + if (ack) + kvm_mips_callbacks->dequeue_timer_int(vcpu); - /* Update compare */ kvm_write_c0_guest_compare(cop0, compare); - /* Update timeout if count enabled */ - if (!kvm_mips_count_disabled(vcpu)) - kvm_mips_update_hrtimer(vcpu); + /* resume_hrtimer() takes care of timer interrupts > count */ + if (!dc) + kvm_mips_resume_hrtimer(vcpu, now, count); } /** @@ -1068,15 +1079,15 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, kvm_read_c0_guest_ebase(cop0)); } else if (rd == MIPS_CP0_TLB_HI && sel == 0) { uint32_t nasid = - vcpu->arch.gprs[rt] & ASID_MASK; + vcpu->arch.gprs[rt] & KVM_ENTRYHI_ASID; if ((KSEGX(vcpu->arch.gprs[rt]) != CKSEG0) && ((kvm_read_c0_guest_entryhi(cop0) & - ASID_MASK) != nasid)) { + KVM_ENTRYHI_ASID) != nasid)) { kvm_debug("MTCz, change ASID from %#lx to %#lx\n", kvm_read_c0_guest_entryhi(cop0) - & ASID_MASK, + & KVM_ENTRYHI_ASID, vcpu->arch.gprs[rt] - & ASID_MASK); + & KVM_ENTRYHI_ASID); /* Blow away the shadow host TLBs */ kvm_mips_flush_host_tlb(1); @@ -1095,9 +1106,9 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, /* If we are writing to COMPARE */ /* Clear pending timer interrupt, if any */ - kvm_mips_callbacks->dequeue_timer_int(vcpu); kvm_mips_write_compare(vcpu, - vcpu->arch.gprs[rt]); + vcpu->arch.gprs[rt], + true); } else if ((rd == MIPS_CP0_STATUS) && (sel == 0)) { unsigned int old_val, val, change; @@ -1620,7 +1631,7 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc, */ index = kvm_mips_guest_tlb_lookup(vcpu, (va & VPN2_MASK) | (kvm_read_c0_guest_entryhi - (cop0) & ASID_MASK)); + (cop0) & KVM_ENTRYHI_ASID)); if (index < 0) { vcpu->arch.host_cp0_entryhi = (va & VPN2_MASK); @@ -1786,7 +1797,7 @@ enum emulation_result kvm_mips_emulate_tlbmiss_ld(unsigned long cause, struct mips_coproc *cop0 = vcpu->arch.cop0; struct kvm_vcpu_arch *arch = &vcpu->arch; unsigned long entryhi = (vcpu->arch. host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { /* save old pc */ @@ -1833,7 +1844,7 @@ enum emulation_result kvm_mips_emulate_tlbinv_ld(unsigned long cause, struct kvm_vcpu_arch *arch = &vcpu->arch; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { /* save old pc */ @@ -1878,7 +1889,7 @@ enum emulation_result kvm_mips_emulate_tlbmiss_st(unsigned long cause, struct mips_coproc *cop0 = vcpu->arch.cop0; struct kvm_vcpu_arch *arch = &vcpu->arch; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { /* save old pc */ @@ -1922,7 +1933,7 @@ enum emulation_result kvm_mips_emulate_tlbinv_st(unsigned long cause, struct mips_coproc *cop0 = vcpu->arch.cop0; struct kvm_vcpu_arch *arch = &vcpu->arch; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { /* save old pc */ @@ -1967,7 +1978,7 @@ enum emulation_result kvm_mips_handle_tlbmod(unsigned long cause, uint32_t *opc, #ifdef DEBUG struct mips_coproc *cop0 = vcpu->arch.cop0; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); int index; /* If address not in the guest TLB, then we are in trouble */ @@ -1994,7 +2005,7 @@ enum emulation_result kvm_mips_emulate_tlbmod(unsigned long cause, { struct mips_coproc *cop0 = vcpu->arch.cop0; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); struct kvm_vcpu_arch *arch = &vcpu->arch; if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { @@ -2569,7 +2580,8 @@ enum emulation_result kvm_mips_handle_tlbmiss(unsigned long cause, */ index = kvm_mips_guest_tlb_lookup(vcpu, (va & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(vcpu->arch.cop0) & ASID_MASK)); + (kvm_read_c0_guest_entryhi(vcpu->arch.cop0) & + KVM_ENTRYHI_ASID)); if (index < 0) { if (exccode == EXCCODE_TLBL) { er = kvm_mips_emulate_tlbmiss_ld(cause, opc, run, vcpu); diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/locore.S index 81687ab..3ef0300 100644 --- a/arch/mips/kvm/locore.S +++ b/arch/mips/kvm/locore.S @@ -32,7 +32,6 @@ EXPORT(x); /* Overload, Danger Will Robinson!! */ -#define PT_HOST_ASID PT_BVADDR #define PT_HOST_USERLOCAL PT_EPC #define CP0_DDATA_LO $28,3 @@ -49,45 +48,18 @@ * a1: vcpu */ .set noreorder - .set noat FEXPORT(__kvm_mips_vcpu_run) /* k0/k1 not being used in host kernel context */ INT_ADDIU k1, sp, -PT_SIZE - LONG_S $0, PT_R0(k1) - LONG_S $1, PT_R1(k1) - LONG_S $2, PT_R2(k1) - LONG_S $3, PT_R3(k1) - - LONG_S $4, PT_R4(k1) - LONG_S $5, PT_R5(k1) - LONG_S $6, PT_R6(k1) - LONG_S $7, PT_R7(k1) - - LONG_S $8, PT_R8(k1) - LONG_S $9, PT_R9(k1) - LONG_S $10, PT_R10(k1) - LONG_S $11, PT_R11(k1) - LONG_S $12, PT_R12(k1) - LONG_S $13, PT_R13(k1) - LONG_S $14, PT_R14(k1) - LONG_S $15, PT_R15(k1) LONG_S $16, PT_R16(k1) LONG_S $17, PT_R17(k1) - LONG_S $18, PT_R18(k1) LONG_S $19, PT_R19(k1) LONG_S $20, PT_R20(k1) LONG_S $21, PT_R21(k1) LONG_S $22, PT_R22(k1) LONG_S $23, PT_R23(k1) - LONG_S $24, PT_R24(k1) - LONG_S $25, PT_R25(k1) - - /* - * XXXKYMA k0/k1 not saved, not being used if we got here through - * an ioctl() - */ LONG_S $28, PT_R28(k1) LONG_S $29, PT_R29(k1) @@ -104,11 +76,6 @@ FEXPORT(__kvm_mips_vcpu_run) mfc0 v0, CP0_STATUS LONG_S v0, PT_STATUS(k1) - /* Save host ASID, shove it into the BVADDR location */ - mfc0 v1, CP0_ENTRYHI - andi v1, 0xff - LONG_S v1, PT_HOST_ASID(k1) - /* Save DDATA_LO, will be used to store pointer to vcpu */ mfc0 v1, CP0_DDATA_LO LONG_S v1, PT_HOST_USERLOCAL(k1) @@ -170,13 +137,21 @@ FEXPORT(__kvm_mips_load_asid) INT_SLL t2, t2, 2 /* x4 */ REG_ADDU t3, t1, t2 LONG_L k0, (t3) - andi k0, k0, 0xff +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + li t3, CPUINFO_SIZE/4 + mul t2, t2, t3 /* x sizeof(struct cpuinfo_mips)/4 */ + LONG_L t2, (cpu_data + CPUINFO_ASID_MASK)(t2) + and k0, k0, t2 +#else + andi k0, k0, MIPS_ENTRYHI_ASID +#endif mtc0 k0, CP0_ENTRYHI ehb /* Disable RDHWR access */ mtc0 zero, CP0_HWRENA + .set noat /* Now load up the Guest Context from VCPU */ LONG_L $1, VCPU_R1(k1) LONG_L $2, VCPU_R2(k1) @@ -288,6 +263,8 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) LONG_S $30, VCPU_R30(k1) LONG_S $31, VCPU_R31(k1) + .set at + /* We need to save hi/lo and restore them on the way out */ mfhi t0 LONG_S t0, VCPU_HI(k1) @@ -339,9 +316,7 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) /* load up the host EBASE */ mfc0 v0, CP0_STATUS - .set at or k0, v0, ST0_BEV - .set noat mtc0 k0, CP0_STATUS ehb @@ -353,7 +328,6 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) * If FPU is enabled, save FCR31 and clear it so that later ctc1's don't * trigger FPE for pending exceptions. */ - .set at and v1, v0, ST0_CU1 beqz v1, 1f nop @@ -363,7 +337,6 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) sw t0, VCPU_FCR31(k1) ctc1 zero,fcr31 .set pop - .set noat 1: #ifdef CONFIG_CPU_HAS_MSA @@ -386,10 +359,8 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) #endif /* Now that the new EBASE has been loaded, unset BEV and KSU_USER */ - .set at and v0, v0, ~(ST0_EXL | KSU_USER | ST0_IE) or v0, v0, ST0_CU0 - .set noat mtc0 v0, CP0_STATUS ehb @@ -456,18 +427,14 @@ __kvm_mips_return_to_guest: /* Switch EBASE back to the one used by KVM */ mfc0 v1, CP0_STATUS - .set at or k0, v1, ST0_BEV - .set noat mtc0 k0, CP0_STATUS ehb mtc0 t0, CP0_EBASE /* Setup status register for running guest in UM */ - .set at or v1, v1, (ST0_EXL | KSU_USER | ST0_IE) and v1, v1, ~(ST0_CU0 | ST0_MX) - .set noat mtc0 v1, CP0_STATUS ehb @@ -489,13 +456,21 @@ __kvm_mips_return_to_guest: INT_SLL t2, t2, 2 /* x4 */ REG_ADDU t3, t1, t2 LONG_L k0, (t3) - andi k0, k0, 0xff +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + li t3, CPUINFO_SIZE/4 + mul t2, t2, t3 /* x sizeof(struct cpuinfo_mips)/4 */ + LONG_L t2, (cpu_data + CPUINFO_ASID_MASK)(t2) + and k0, k0, t2 +#else + andi k0, k0, MIPS_ENTRYHI_ASID +#endif mtc0 k0, CP0_ENTRYHI ehb /* Disable RDHWR access */ mtc0 zero, CP0_HWRENA + .set noat /* load the guest context from VCPU and return */ LONG_L $0, VCPU_R0(k1) LONG_L $1, VCPU_R1(k1) @@ -541,6 +516,7 @@ FEXPORT(__kvm_mips_skip_guest_restore) LONG_L k1, VCPU_R27(k1) eret + .set at __kvm_mips_return_to_host: /* EBASE is already pointing to Linux */ @@ -551,16 +527,6 @@ __kvm_mips_return_to_host: LONG_L k0, PT_HOST_USERLOCAL(k1) mtc0 k0, CP0_DDATA_LO - /* Restore host ASID */ - LONG_L k0, PT_HOST_ASID(sp) - andi k0, 0xff - mtc0 k0,CP0_ENTRYHI - ehb - - /* Load context saved on the host stack */ - LONG_L $0, PT_R0(k1) - LONG_L $1, PT_R1(k1) - /* * r2/v0 is the return code, shift it down by 2 (arithmetic) * to recover the err code @@ -568,19 +534,7 @@ __kvm_mips_return_to_host: INT_SRA k0, v0, 2 move $2, k0 - LONG_L $3, PT_R3(k1) - LONG_L $4, PT_R4(k1) - LONG_L $5, PT_R5(k1) - LONG_L $6, PT_R6(k1) - LONG_L $7, PT_R7(k1) - LONG_L $8, PT_R8(k1) - LONG_L $9, PT_R9(k1) - LONG_L $10, PT_R10(k1) - LONG_L $11, PT_R11(k1) - LONG_L $12, PT_R12(k1) - LONG_L $13, PT_R13(k1) - LONG_L $14, PT_R14(k1) - LONG_L $15, PT_R15(k1) + /* Load context saved on the host stack */ LONG_L $16, PT_R16(k1) LONG_L $17, PT_R17(k1) LONG_L $18, PT_R18(k1) @@ -589,10 +543,6 @@ __kvm_mips_return_to_host: LONG_L $21, PT_R21(k1) LONG_L $22, PT_R22(k1) LONG_L $23, PT_R23(k1) - LONG_L $24, PT_R24(k1) - LONG_L $25, PT_R25(k1) - - /* Host k0/k1 were not saved */ LONG_L $28, PT_R28(k1) LONG_L $29, PT_R29(k1) diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 70ef1a4..dc052fb 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -56,6 +56,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "flush_dcache", VCPU_STAT(flush_dcache_exits), KVM_STAT_VCPU }, { "halt_successful_poll", VCPU_STAT(halt_successful_poll), KVM_STAT_VCPU }, { "halt_attempted_poll", VCPU_STAT(halt_attempted_poll), KVM_STAT_VCPU }, + { "halt_poll_invalid", VCPU_STAT(halt_poll_invalid), KVM_STAT_VCPU }, { "halt_wakeup", VCPU_STAT(halt_wakeup), KVM_STAT_VCPU }, {NULL} }; @@ -1079,7 +1080,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = KVM_COALESCED_MMIO_PAGE_OFFSET; break; case KVM_CAP_MIPS_FPU: - r = !!cpu_has_fpu; + /* We don't handle systems with inconsistent cpu_has_fpu */ + r = !!raw_cpu_has_fpu; break; case KVM_CAP_MIPS_MSA: /* @@ -1555,8 +1557,10 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu) /* Disable MSA & FPU */ disable_msa(); - if (vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) + if (vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) { clear_c0_status(ST0_CU1 | ST0_FR); + disable_fpu_hazard(); + } vcpu->arch.fpu_inuse &= ~(KVM_MIPS_FPU_FPU | KVM_MIPS_FPU_MSA); } else if (vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) { set_c0_status(ST0_CU1); @@ -1567,6 +1571,7 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu) /* Disable FPU */ clear_c0_status(ST0_CU1 | ST0_FR); + disable_fpu_hazard(); } preempt_enable(); } diff --git a/arch/mips/kvm/tlb.c b/arch/mips/kvm/tlb.c index e0e1d0a..ed021ae 100644 --- a/arch/mips/kvm/tlb.c +++ b/arch/mips/kvm/tlb.c @@ -49,12 +49,18 @@ EXPORT_SYMBOL_GPL(kvm_mips_is_error_pfn); uint32_t kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu) { - return vcpu->arch.guest_kernel_asid[smp_processor_id()] & ASID_MASK; + int cpu = smp_processor_id(); + + return vcpu->arch.guest_kernel_asid[cpu] & + cpu_asid_mask(&cpu_data[cpu]); } uint32_t kvm_mips_get_user_asid(struct kvm_vcpu *vcpu) { - return vcpu->arch.guest_user_asid[smp_processor_id()] & ASID_MASK; + int cpu = smp_processor_id(); + + return vcpu->arch.guest_user_asid[cpu] & + cpu_asid_mask(&cpu_data[cpu]); } inline uint32_t kvm_mips_get_commpage_asid(struct kvm_vcpu *vcpu) @@ -78,7 +84,8 @@ void kvm_mips_dump_host_tlbs(void) old_pagemask = read_c0_pagemask(); kvm_info("HOST TLBs:\n"); - kvm_info("ASID: %#lx\n", read_c0_entryhi() & ASID_MASK); + kvm_info("ASID: %#lx\n", read_c0_entryhi() & + cpu_asid_mask(¤t_cpu_data)); for (i = 0; i < current_cpu_data.tlbsize; i++) { write_c0_index(i); @@ -268,6 +275,7 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr, int even; struct kvm *kvm = vcpu->kvm; const int flush_dcache_mask = 0; + int ret; if (KVM_GUEST_KSEGX(badvaddr) != KVM_GUEST_KSEG0) { kvm_err("%s: Invalid BadVaddr: %#lx\n", __func__, badvaddr); @@ -299,14 +307,18 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr, pfn1 = kvm->arch.guest_pmap[gfn]; } - entryhi = (vaddr | kvm_mips_get_kernel_asid(vcpu)); entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) | (0x3 << 3) | (1 << 2) | (0x1 << 1); entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) | (0x3 << 3) | (1 << 2) | (0x1 << 1); - return kvm_mips_host_tlb_write(vcpu, entryhi, entrylo0, entrylo1, - flush_dcache_mask); + preempt_disable(); + entryhi = (vaddr | kvm_mips_get_kernel_asid(vcpu)); + ret = kvm_mips_host_tlb_write(vcpu, entryhi, entrylo0, entrylo1, + flush_dcache_mask); + preempt_enable(); + + return ret; } EXPORT_SYMBOL_GPL(kvm_mips_handle_kseg0_tlb_fault); @@ -361,6 +373,7 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu, unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0; struct kvm *kvm = vcpu->kvm; kvm_pfn_t pfn0, pfn1; + int ret; if ((tlb->tlb_hi & VPN2_MASK) == 0) { pfn0 = 0; @@ -387,9 +400,6 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu, *hpa1 = pfn1 << PAGE_SHIFT; /* Get attributes from the Guest TLB */ - entryhi = (tlb->tlb_hi & VPN2_MASK) | (KVM_GUEST_KERNEL_MODE(vcpu) ? - kvm_mips_get_kernel_asid(vcpu) : - kvm_mips_get_user_asid(vcpu)); entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) | (0x3 << 3) | (tlb->tlb_lo0 & MIPS3_PG_D) | (tlb->tlb_lo0 & MIPS3_PG_V); entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) | (0x3 << 3) | @@ -398,8 +408,15 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu, kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc, tlb->tlb_lo0, tlb->tlb_lo1); - return kvm_mips_host_tlb_write(vcpu, entryhi, entrylo0, entrylo1, - tlb->tlb_mask); + preempt_disable(); + entryhi = (tlb->tlb_hi & VPN2_MASK) | (KVM_GUEST_KERNEL_MODE(vcpu) ? + kvm_mips_get_kernel_asid(vcpu) : + kvm_mips_get_user_asid(vcpu)); + ret = kvm_mips_host_tlb_write(vcpu, entryhi, entrylo0, entrylo1, + tlb->tlb_mask); + preempt_enable(); + + return ret; } EXPORT_SYMBOL_GPL(kvm_mips_handle_mapped_seg_tlb_fault); @@ -564,15 +581,15 @@ void kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu, { unsigned long asid = asid_cache(cpu); - asid += ASID_INC; - if (!(asid & ASID_MASK)) { + asid += cpu_asid_inc(); + if (!(asid & cpu_asid_mask(&cpu_data[cpu]))) { if (cpu_has_vtag_icache) flush_icache_all(); kvm_local_flush_tlb_all(); /* start new asid cycle */ if (!asid) /* fix version if needed */ - asid = ASID_FIRST_VERSION; + asid = asid_first_version(cpu); } cpu_context(cpu, mm) = asid_cache(cpu) = asid; @@ -627,6 +644,7 @@ static void kvm_mips_migrate_count(struct kvm_vcpu *vcpu) /* Restore ASID once we are scheduled back after preemption */ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { + unsigned long asid_mask = cpu_asid_mask(&cpu_data[cpu]); unsigned long flags; int newasid = 0; @@ -637,7 +655,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) local_irq_save(flags); if ((vcpu->arch.guest_kernel_asid[cpu] ^ asid_cache(cpu)) & - ASID_VERSION_MASK) { + asid_version_mask(cpu)) { kvm_get_new_mmu_context(&vcpu->arch.guest_kernel_mm, cpu, vcpu); vcpu->arch.guest_kernel_asid[cpu] = vcpu->arch.guest_kernel_mm.context.asid[cpu]; @@ -672,7 +690,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) */ if (current->flags & PF_VCPU) { write_c0_entryhi(vcpu->arch. - preempt_entryhi & ASID_MASK); + preempt_entryhi & asid_mask); ehb(); } } else { @@ -687,11 +705,11 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (KVM_GUEST_KERNEL_MODE(vcpu)) write_c0_entryhi(vcpu->arch. guest_kernel_asid[cpu] & - ASID_MASK); + asid_mask); else write_c0_entryhi(vcpu->arch. guest_user_asid[cpu] & - ASID_MASK); + asid_mask); ehb(); } } @@ -721,7 +739,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_mips_callbacks->vcpu_get_regs(vcpu); if (((cpu_context(cpu, current->mm) ^ asid_cache(cpu)) & - ASID_VERSION_MASK)) { + asid_version_mask(cpu))) { kvm_debug("%s: Dropping MMU Context: %#lx\n", __func__, cpu_context(cpu, current->mm)); drop_mmu_context(current->mm, cpu); @@ -748,7 +766,8 @@ uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu) inst = *(opc); } else { vpn2 = (unsigned long) opc & VPN2_MASK; - asid = kvm_read_c0_guest_entryhi(cop0) & ASID_MASK; + asid = kvm_read_c0_guest_entryhi(cop0) & + KVM_ENTRYHI_ASID; index = kvm_mips_guest_tlb_lookup(vcpu, vpn2 | asid); if (index < 0) { kvm_err("%s: get_user_failed for %p, vcpu: %p, ASID: %#lx\n", diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c index c4038d2..6ba0faf 100644 --- a/arch/mips/kvm/trap_emul.c +++ b/arch/mips/kvm/trap_emul.c @@ -505,7 +505,8 @@ static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu) kvm_write_c0_guest_intctl(cop0, 0xFC000000); /* Put in vcpu id as CPUNum into Ebase Reg to handle SMP Guests */ - kvm_write_c0_guest_ebase(cop0, KVM_GUEST_KSEG0 | (vcpu_id & 0xFF)); + kvm_write_c0_guest_ebase(cop0, KVM_GUEST_KSEG0 | + (vcpu_id & MIPS_EBASE_CPUNUM)); return 0; } @@ -546,7 +547,7 @@ static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu, kvm_mips_write_count(vcpu, v); break; case KVM_REG_MIPS_CP0_COMPARE: - kvm_mips_write_compare(vcpu, v); + kvm_mips_write_compare(vcpu, v, false); break; case KVM_REG_MIPS_CP0_CAUSE: /* diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig index e10d333..177769d 100644 --- a/arch/mips/lantiq/Kconfig +++ b/arch/mips/lantiq/Kconfig @@ -25,7 +25,17 @@ config SOC_FALCON endchoice choice - prompt "Devicetree" + prompt "Built-in device tree" + help + Legacy bootloaders do not pass a DTB pointer to the kernel, so + if a "wrapper" is not being used, the kernel will need to include + a device tree that matches the target board. + + The builtin DTB will only be used if the firmware does not supply + a valid DTB. + +config LANTIQ_DT_NONE + bool "None" config DT_EASY50712 bool "Easy50712" diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile index 690257a..2718652 100644 --- a/arch/mips/lantiq/Makefile +++ b/arch/mips/lantiq/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 2010 John Crispin <blogic@openwrt.org> +# Copyright (C) 2010 John Crispin <john@phrozen.org> # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 as published diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c index a0706fd..149f051 100644 --- a/arch/mips/lantiq/clk.c +++ b/arch/mips/lantiq/clk.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/io.h> #include <linux/export.h> diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h index 7376ce8..e806e04 100644 --- a/arch/mips/lantiq/clk.h +++ b/arch/mips/lantiq/clk.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_CLK_H__ diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c index 9b28d09..44bccae 100644 --- a/arch/mips/lantiq/early_printk.c +++ b/arch/mips/lantiq/early_printk.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/cpu.h> diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c index aa94979..75315c0 100644 --- a/arch/mips/lantiq/falcon/prom.c +++ b/arch/mips/lantiq/falcon/prom.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com> - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/lantiq/falcon/reset.c b/arch/mips/lantiq/falcon/reset.c index 5682482..7a535d7 100644 --- a/arch/mips/lantiq/falcon/reset.c +++ b/arch/mips/lantiq/falcon/reset.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com> - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/init.h> diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c index 7edcd49..2a1b302 100644 --- a/arch/mips/lantiq/falcon/sysctrl.c +++ b/arch/mips/lantiq/falcon/sysctrl.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com> - * Copyright (C) 2011 John Crispin <blogic@openwrt.org> + * Copyright (C) 2011 John Crispin <john@phrozen.org> */ #include <linux/ioport.h> diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index 2e7f60c..ff17669e 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> */ diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c index 297bcaa..5f693ac7 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/export.h> @@ -65,6 +65,8 @@ static void __init prom_init_cmdline(void) void __init plat_mem_setup(void) { + void *dtb; + ioport_resource.start = IOPORT_RESOURCE_START; ioport_resource.end = IOPORT_RESOURCE_END; iomem_resource.start = IOMEM_RESOURCE_START; @@ -72,11 +74,18 @@ void __init plat_mem_setup(void) set_io_port_base((unsigned long) KSEG1); + if (fw_arg0 == -2) /* UHI interface */ + dtb = (void *)fw_arg1; + else if (__dtb_start != __dtb_end) + dtb = (void *)__dtb_start; + else + panic("no dtb found"); + /* - * Load the builtin devicetree. This causes the chosen node to be + * Load the devicetree. This causes the chosen node to be * parsed resulting in our memory appearing */ - __dt_setup_arch(__dtb_start); + __dt_setup_arch(dtb); } void __init device_tree_init(void) diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h index bfd2d58..4b6576c 100644 --- a/arch/mips/lantiq/prom.h +++ b/arch/mips/lantiq/prom.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_PROM_H__ diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c index 07f6d5b..41fc30d 100644 --- a/arch/mips/lantiq/xway/clk.c +++ b/arch/mips/lantiq/xway/clk.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ diff --git a/arch/mips/lantiq/xway/dcdc.c b/arch/mips/lantiq/xway/dcdc.c index ae8e930..08f7aba 100644 --- a/arch/mips/lantiq/xway/dcdc.c +++ b/arch/mips/lantiq/xway/dcdc.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> * Copyright (C) 2010 Sameer Ahmad, Lantiq GmbH */ diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c index 34a116e..cef8117 100644 --- a/arch/mips/lantiq/xway/dma.c +++ b/arch/mips/lantiq/xway/dma.c @@ -12,7 +12,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2011 John Crispin <blogic@openwrt.org> + * Copyright (C) 2011 John Crispin <john@phrozen.org> */ #include <linux/init.h> diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c index f1492b2..0f1bbea 100644 --- a/arch/mips/lantiq/xway/gptu.c +++ b/arch/mips/lantiq/xway/gptu.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> * Copyright (C) 2012 Lantiq GmbH */ diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c index 8f6e02f..9475b25 100644 --- a/arch/mips/lantiq/xway/prom.c +++ b/arch/mips/lantiq/xway/prom.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c index bc29bb3..83fd65d 100644 --- a/arch/mips/lantiq/xway/reset.c +++ b/arch/mips/lantiq/xway/reset.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ @@ -258,7 +258,7 @@ static int ltq_reset_device(struct reset_controller_dev *rcdev, return ltq_deassert_device(rcdev, id); } -static struct reset_control_ops reset_ops = { +static const struct reset_control_ops reset_ops = { .reset = ltq_reset_device, .assert = ltq_assert_device, .deassert = ltq_deassert_device, diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 80554e8..236193b 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2011-2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2011-2012 John Crispin <john@phrozen.org> * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ diff --git a/arch/mips/lantiq/xway/vmmc.c b/arch/mips/lantiq/xway/vmmc.c index d001bc3..4625495 100644 --- a/arch/mips/lantiq/xway/vmmc.c +++ b/arch/mips/lantiq/xway/vmmc.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/module.h> diff --git a/arch/mips/lantiq/xway/xrx200_phy_fw.c b/arch/mips/lantiq/xway/xrx200_phy_fw.c index 199094a..71e518c 100644 --- a/arch/mips/lantiq/xway/xrx200_phy_fw.c +++ b/arch/mips/lantiq/xway/xrx200_phy_fw.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/delay.h> @@ -112,6 +112,6 @@ static struct platform_driver xway_phy_driver = { module_platform_driver(xway_phy_driver); -MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +MODULE_AUTHOR("John Crispin <john@phrozen.org>"); MODULE_DESCRIPTION("Lantiq XRX200 PHY Firmware Loader"); MODULE_LICENSE("GPL"); diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 92a3731..0f80b93 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -19,6 +19,8 @@ void dump_tlb_regs(void) pr_info("Index : %0x\n", read_c0_index()); pr_info("PageMask : %0x\n", read_c0_pagemask()); + if (cpu_has_guestid) + pr_info("GuestCtl1: %0x\n", read_c0_guestctl1()); pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi()); pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); @@ -72,7 +74,10 @@ static void dump_tlb(int first, int last) { unsigned long s_entryhi, entryhi, asid; unsigned long long entrylo0, entrylo1, pa; - unsigned int s_index, s_pagemask, pagemask, c0, c1, i; + unsigned int s_index, s_pagemask, s_guestctl1 = 0; + unsigned int pagemask, guestctl1 = 0, c0, c1, i; + unsigned long asidmask = cpu_asid_mask(¤t_cpu_data); + int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4); #ifdef CONFIG_32BIT bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA); int pwidth = xpa ? 11 : 8; @@ -86,7 +91,9 @@ static void dump_tlb(int first, int last) s_pagemask = read_c0_pagemask(); s_entryhi = read_c0_entryhi(); s_index = read_c0_index(); - asid = s_entryhi & 0xff; + asid = s_entryhi & asidmask; + if (cpu_has_guestid) + s_guestctl1 = read_c0_guestctl1(); for (i = first; i <= last; i++) { write_c0_index(i); @@ -97,6 +104,8 @@ static void dump_tlb(int first, int last) entryhi = read_c0_entryhi(); entrylo0 = read_c0_entrylo0(); entrylo1 = read_c0_entrylo1(); + if (cpu_has_guestid) + guestctl1 = read_c0_guestctl1(); /* EHINV bit marks entire entry as invalid */ if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV) @@ -115,7 +124,7 @@ static void dump_tlb(int first, int last) * due to duplicate TLB entry. */ if (!((entrylo0 | entrylo1) & ENTRYLO_G) && - (entryhi & 0xff) != asid) + (entryhi & asidmask) != asid) continue; /* @@ -126,15 +135,19 @@ static void dump_tlb(int first, int last) c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; - printk("va=%0*lx asid=%02lx\n", + printk("va=%0*lx asid=%0*lx", vwidth, (entryhi & ~0x1fffUL), - entryhi & 0xff); + asidwidth, entryhi & asidmask); + if (cpu_has_guestid) + printk(" gid=%02lx", + (guestctl1 & MIPS_GCTL1_RID) + >> MIPS_GCTL1_RID_SHIFT); /* RI/XI are in awkward places, so mask them off separately */ pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); if (xpa) pa |= (unsigned long long)readx_c0_entrylo0() << 30; pa = (pa << 6) & PAGE_MASK; - printk("\t["); + printk("\n\t["); if (cpu_has_rixi) printk("ri=%d xi=%d ", (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0, @@ -164,6 +177,8 @@ static void dump_tlb(int first, int last) write_c0_entryhi(s_entryhi); write_c0_index(s_index); write_c0_pagemask(s_pagemask); + if (cpu_has_guestid) + write_c0_guestctl1(s_guestctl1); } void dump_tlb_all(void) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 8f0019a..18a1ccd 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -228,10 +228,12 @@ .hidden __memset .endif +#ifdef CONFIG_CPU_MIPSR6 .Lbyte_fixup\@: PTR_SUBU a2, $0, t0 jr ra PTR_ADDIU a2, 1 +#endif /* CONFIG_CPU_MIPSR6 */ .Lfirst_fixup\@: jr ra diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c index cfcbb52..744f4a7 100644 --- a/arch/mips/lib/r3k_dump_tlb.c +++ b/arch/mips/lib/r3k_dump_tlb.c @@ -29,9 +29,10 @@ static void dump_tlb(int first, int last) { int i; unsigned int asid; - unsigned long entryhi, entrylo0; + unsigned long entryhi, entrylo0, asid_mask; - asid = read_c0_entryhi() & ASID_MASK; + asid_mask = cpu_asid_mask(¤t_cpu_data); + asid = read_c0_entryhi() & asid_mask; for (i = first; i <= last; i++) { write_c0_index(i<<8); @@ -46,7 +47,7 @@ static void dump_tlb(int first, int last) /* Unused entries have a virtual address of KSEG0. */ if ((entryhi & PAGE_MASK) != KSEG0 && (entrylo0 & R3K_ENTRYLO_G || - (entryhi & ASID_MASK) == asid)) { + (entryhi & asid_mask) == asid)) { /* * Only print entries in use */ @@ -55,7 +56,7 @@ static void dump_tlb(int first, int last) printk("va=%08lx asid=%08lx" " [pa=%06lx n=%d d=%d v=%d g=%d]", entryhi & PAGE_MASK, - entryhi & ASID_MASK, + entryhi & asid_mask, entrylo0 & PAGE_MASK, (entrylo0 & R3K_ENTRYLO_N) ? 1 : 0, (entrylo0 & R3K_ENTRYLO_D) ? 1 : 0, diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c index ddf1d4c..f2c714d 100644 --- a/arch/mips/loongson32/common/platform.c +++ b/arch/mips/loongson32/common/platform.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -10,14 +10,17 @@ #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/err.h> +#include <linux/mtd/partitions.h> +#include <linux/sizes.h> #include <linux/phy.h> #include <linux/serial_8250.h> #include <linux/stmmac.h> #include <linux/usb/ehci_pdriver.h> -#include <asm-generic/sizes.h> -#include <cpufreq.h> #include <loongson1.h> +#include <cpufreq.h> +#include <dma.h> +#include <nand.h> /* 8250/16550 compatible UART */ #define LS1X_UART(_id) \ @@ -45,7 +48,7 @@ struct platform_device ls1x_uart_pdev = { }, }; -void __init ls1x_serial_setup(struct platform_device *pdev) +void __init ls1x_serial_set_uartclk(struct platform_device *pdev) { struct clk *clk; struct plat_serial8250_port *p; @@ -77,6 +80,42 @@ struct platform_device ls1x_cpufreq_pdev = { }, }; +/* DMA */ +static struct resource ls1x_dma_resources[] = { + [0] = { + .start = LS1X_DMAC_BASE, + .end = LS1X_DMAC_BASE + SZ_4 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = LS1X_DMA0_IRQ, + .end = LS1X_DMA0_IRQ, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = LS1X_DMA1_IRQ, + .end = LS1X_DMA1_IRQ, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = LS1X_DMA2_IRQ, + .end = LS1X_DMA2_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device ls1x_dma_pdev = { + .name = "ls1x-dma", + .id = -1, + .num_resources = ARRAY_SIZE(ls1x_dma_resources), + .resource = ls1x_dma_resources, +}; + +void __init ls1x_dma_set_platdata(struct plat_ls1x_dma *pdata) +{ + ls1x_dma_pdev.dev.platform_data = pdata; +} + /* Synopsys Ethernet GMAC */ static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = { .phy_mask = 0, @@ -198,6 +237,64 @@ struct platform_device ls1x_eth1_pdev = { }, }; +/* GPIO */ +static struct resource ls1x_gpio0_resources[] = { + [0] = { + .start = LS1X_GPIO0_BASE, + .end = LS1X_GPIO0_BASE + SZ_4 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device ls1x_gpio0_pdev = { + .name = "ls1x-gpio", + .id = 0, + .num_resources = ARRAY_SIZE(ls1x_gpio0_resources), + .resource = ls1x_gpio0_resources, +}; + +static struct resource ls1x_gpio1_resources[] = { + [0] = { + .start = LS1X_GPIO1_BASE, + .end = LS1X_GPIO1_BASE + SZ_4 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device ls1x_gpio1_pdev = { + .name = "ls1x-gpio", + .id = 1, + .num_resources = ARRAY_SIZE(ls1x_gpio1_resources), + .resource = ls1x_gpio1_resources, +}; + +/* NAND Flash */ +static struct resource ls1x_nand_resources[] = { + [0] = { + .start = LS1X_NAND_BASE, + .end = LS1X_NAND_BASE + SZ_32 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* DMA channel 0 is dedicated to NAND */ + .start = LS1X_DMA_CHANNEL0, + .end = LS1X_DMA_CHANNEL0, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device ls1x_nand_pdev = { + .name = "ls1x-nand", + .id = -1, + .num_resources = ARRAY_SIZE(ls1x_nand_resources), + .resource = ls1x_nand_resources, +}; + +void __init ls1x_nand_set_platdata(struct plat_ls1x_nand *pdata) +{ + ls1x_nand_pdev.dev.platform_data = pdata; +} + /* USB EHCI */ static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32); diff --git a/arch/mips/loongson32/common/reset.c b/arch/mips/loongson32/common/reset.c index c41e4ca..8a1d9cc 100644 --- a/arch/mips/loongson32/common/reset.c +++ b/arch/mips/loongson32/common/reset.c @@ -9,12 +9,13 @@ #include <linux/io.h> #include <linux/pm.h> +#include <linux/sizes.h> #include <asm/idle.h> #include <asm/reboot.h> #include <loongson1.h> -static void __iomem *wdt_base; +static void __iomem *wdt_reg_base; static void ls1x_halt(void) { @@ -26,9 +27,9 @@ static void ls1x_halt(void) static void ls1x_restart(char *command) { - __raw_writel(0x1, wdt_base + WDT_EN); - __raw_writel(0x1, wdt_base + WDT_TIMER); - __raw_writel(0x1, wdt_base + WDT_SET); + __raw_writel(0x1, wdt_reg_base + WDT_EN); + __raw_writel(0x1, wdt_reg_base + WDT_TIMER); + __raw_writel(0x1, wdt_reg_base + WDT_SET); ls1x_halt(); } @@ -40,8 +41,8 @@ static void ls1x_power_off(void) static int __init ls1x_reboot_setup(void) { - wdt_base = ioremap_nocache(LS1X_WDT_BASE, 0x0f); - if (!wdt_base) + wdt_reg_base = ioremap_nocache(LS1X_WDT_BASE, (SZ_4 + SZ_8)); + if (!wdt_reg_base) panic("Failed to remap watchdog registers"); _machine_restart = ls1x_restart; diff --git a/arch/mips/loongson32/common/time.c b/arch/mips/loongson32/common/time.c index 0996b02..ff224f0 100644 --- a/arch/mips/loongson32/common/time.c +++ b/arch/mips/loongson32/common/time.c @@ -9,6 +9,7 @@ #include <linux/clk.h> #include <linux/interrupt.h> +#include <linux/sizes.h> #include <asm/time.h> #include <loongson1.h> @@ -35,25 +36,25 @@ DEFINE_RAW_SPINLOCK(ls1x_timer_lock); -static void __iomem *timer_base; +static void __iomem *timer_reg_base; static uint32_t ls1x_jiffies_per_tick; static inline void ls1x_pwmtimer_set_period(uint32_t period) { - __raw_writel(period, timer_base + PWM_HRC); - __raw_writel(period, timer_base + PWM_LRC); + __raw_writel(period, timer_reg_base + PWM_HRC); + __raw_writel(period, timer_reg_base + PWM_LRC); } static inline void ls1x_pwmtimer_restart(void) { - __raw_writel(0x0, timer_base + PWM_CNT); - __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); + __raw_writel(0x0, timer_reg_base + PWM_CNT); + __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); } void __init ls1x_pwmtimer_init(void) { - timer_base = ioremap(LS1X_TIMER_BASE, 0xf); - if (!timer_base) + timer_reg_base = ioremap_nocache(LS1X_TIMER_BASE, SZ_16); + if (!timer_reg_base) panic("Failed to remap timer registers"); ls1x_jiffies_per_tick = DIV_ROUND_CLOSEST(mips_hpt_frequency, HZ); @@ -86,7 +87,7 @@ static cycle_t ls1x_clocksource_read(struct clocksource *cs) */ jifs = jiffies; /* read the count */ - count = __raw_readl(timer_base + PWM_CNT); + count = __raw_readl(timer_reg_base + PWM_CNT); /* * It's possible for count to appear to go the wrong way for this @@ -131,7 +132,7 @@ static int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) raw_spin_lock(&ls1x_timer_lock); ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); ls1x_pwmtimer_restart(); - __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); + __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); raw_spin_unlock(&ls1x_timer_lock); return 0; @@ -140,7 +141,7 @@ static int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) static int ls1x_clockevent_tick_resume(struct clock_event_device *cd) { raw_spin_lock(&ls1x_timer_lock); - __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); + __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); raw_spin_unlock(&ls1x_timer_lock); return 0; @@ -149,8 +150,8 @@ static int ls1x_clockevent_tick_resume(struct clock_event_device *cd) static int ls1x_clockevent_set_state_shutdown(struct clock_event_device *cd) { raw_spin_lock(&ls1x_timer_lock); - __raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN, - timer_base + PWM_CTRL); + __raw_writel(__raw_readl(timer_reg_base + PWM_CTRL) & ~CNT_EN, + timer_reg_base + PWM_CTRL); raw_spin_unlock(&ls1x_timer_lock); return 0; @@ -220,7 +221,7 @@ void __init plat_time_init(void) #ifdef CONFIG_CEVT_CSRC_LS1X /* setup LS1X PWM timer */ - clk = clk_get(NULL, "ls1x_pwmtimer"); + clk = clk_get(NULL, "ls1x-pwmtimer"); if (IS_ERR(clk)) panic("unable to get timer clock, err=%ld", PTR_ERR(clk)); diff --git a/arch/mips/loongson32/ls1b/board.c b/arch/mips/loongson32/ls1b/board.c index 58daeea..38a1d40 100644 --- a/arch/mips/loongson32/ls1b/board.c +++ b/arch/mips/loongson32/ls1b/board.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -7,26 +7,83 @@ * option) any later version. */ +#include <linux/leds.h> +#include <linux/mtd/partitions.h> +#include <linux/sizes.h> + +#include <loongson1.h> +#include <dma.h> +#include <nand.h> #include <platform.h> +struct plat_ls1x_dma ls1x_dma_pdata = { + .nr_channels = 3, +}; + +static struct mtd_partition ls1x_nand_parts[] = { + { + .name = "kernel", + .offset = 0, + .size = SZ_16M, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +struct plat_ls1x_nand ls1x_nand_pdata = { + .parts = ls1x_nand_parts, + .nr_parts = ARRAY_SIZE(ls1x_nand_parts), + .hold_cycle = 0x2, + .wait_cycle = 0xc, +}; + +static const struct gpio_led ls1x_gpio_leds[] __initconst = { + { + .name = "LED9", + .default_trigger = "heartbeat", + .gpio = 38, + .active_low = 1, + .default_state = LEDS_GPIO_DEFSTATE_OFF, + }, { + .name = "LED6", + .default_trigger = "nand-disk", + .gpio = 39, + .active_low = 1, + .default_state = LEDS_GPIO_DEFSTATE_OFF, + }, +}; + +static const struct gpio_led_platform_data ls1x_led_pdata __initconst = { + .num_leds = ARRAY_SIZE(ls1x_gpio_leds), + .leds = ls1x_gpio_leds, +}; + static struct platform_device *ls1b_platform_devices[] __initdata = { &ls1x_uart_pdev, &ls1x_cpufreq_pdev, + &ls1x_dma_pdev, &ls1x_eth0_pdev, &ls1x_eth1_pdev, &ls1x_ehci_pdev, + &ls1x_gpio0_pdev, + &ls1x_gpio1_pdev, + &ls1x_nand_pdev, &ls1x_rtc_pdev, }; static int __init ls1b_platform_init(void) { - int err; + ls1x_serial_set_uartclk(&ls1x_uart_pdev); + ls1x_dma_set_platdata(&ls1x_dma_pdata); + ls1x_nand_set_platdata(&ls1x_nand_pdata); - ls1x_serial_setup(&ls1x_uart_pdev); + gpio_led_register_device(-1, &ls1x_led_pdata); - err = platform_add_devices(ls1b_platform_devices, + return platform_add_devices(ls1b_platform_devices, ARRAY_SIZE(ls1b_platform_devices)); - return err; } arch_initcall(ls1b_platform_init); diff --git a/arch/mips/loongson64/Platform b/arch/mips/loongson64/Platform index 85d8089..0fce460 100644 --- a/arch/mips/loongson64/Platform +++ b/arch/mips/loongson64/Platform @@ -31,7 +31,7 @@ cflags-$(CONFIG_CPU_LOONGSON3) += -Wa,--trap # can't easily be used safely within the kbuild framework. # ifeq ($(call cc-ifversion, -ge, 0409, y), y) - ifeq ($(call ld-ifversion, -ge, 22500000, y), y) + ifeq ($(call ld-ifversion, -ge, 225000000, y), y) cflags-$(CONFIG_CPU_LOONGSON3) += \ $(call cc-option,-march=loongson3a -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) else diff --git a/arch/mips/loongson64/common/env.c b/arch/mips/loongson64/common/env.c index d6d07ad..57d590a 100644 --- a/arch/mips/loongson64/common/env.c +++ b/arch/mips/loongson64/common/env.c @@ -105,6 +105,10 @@ void __init prom_init_env(void) loongson_chiptemp[1] = 0x900010001fe0019c; loongson_chiptemp[2] = 0x900020001fe0019c; loongson_chiptemp[3] = 0x900030001fe0019c; + loongson_freqctrl[0] = 0x900000001fe001d0; + loongson_freqctrl[1] = 0x900010001fe001d0; + loongson_freqctrl[2] = 0x900020001fe001d0; + loongson_freqctrl[3] = 0x900030001fe001d0; loongson_sysconf.ht_control_base = 0x90000EFDFB000000; loongson_sysconf.workarounds = WORKAROUND_CPUFREQ; } else if (ecpu->cputype == Loongson_3B) { @@ -187,7 +191,8 @@ void __init prom_init_env(void) case PRID_REV_LOONGSON2F: cpu_clock_freq = 797000000; break; - case PRID_REV_LOONGSON3A: + case PRID_REV_LOONGSON3A_R1: + case PRID_REV_LOONGSON3A_R2: cpu_clock_freq = 900000000; break; case PRID_REV_LOONGSON3B_R1: diff --git a/arch/mips/loongson64/loongson-3/Makefile b/arch/mips/loongson64/loongson-3/Makefile index 622fead..44bc148 100644 --- a/arch/mips/loongson64/loongson-3/Makefile +++ b/arch/mips/loongson64/loongson-3/Makefile @@ -1,7 +1,7 @@ # # Makefile for Loongson-3 family machines # -obj-y += irq.o cop2-ex.o platform.o +obj-y += irq.o cop2-ex.o platform.o acpi_init.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/mips/loongson64/loongson-3/acpi_init.c b/arch/mips/loongson64/loongson-3/acpi_init.c new file mode 100644 index 0000000..dbdad79 --- /dev/null +++ b/arch/mips/loongson64/loongson-3/acpi_init.c @@ -0,0 +1,150 @@ +#include <linux/io.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/export.h> + +#define SBX00_ACPI_IO_BASE 0x800 +#define SBX00_ACPI_IO_SIZE 0x100 + +#define ACPI_PM_EVT_BLK (SBX00_ACPI_IO_BASE + 0x00) /* 4 bytes */ +#define ACPI_PM_CNT_BLK (SBX00_ACPI_IO_BASE + 0x04) /* 2 bytes */ +#define ACPI_PMA_CNT_BLK (SBX00_ACPI_IO_BASE + 0x0F) /* 1 byte */ +#define ACPI_PM_TMR_BLK (SBX00_ACPI_IO_BASE + 0x18) /* 4 bytes */ +#define ACPI_GPE0_BLK (SBX00_ACPI_IO_BASE + 0x10) /* 8 bytes */ +#define ACPI_END (SBX00_ACPI_IO_BASE + 0x80) + +#define PM_INDEX 0xCD6 +#define PM_DATA 0xCD7 +#define PM2_INDEX 0xCD0 +#define PM2_DATA 0xCD1 + +/* + * SCI interrupt need acpi space, allocate here + */ + +static int __init register_acpi_resource(void) +{ + request_region(SBX00_ACPI_IO_BASE, SBX00_ACPI_IO_SIZE, "acpi"); + return 0; +} + +static void pmio_write_index(u16 index, u8 reg, u8 value) +{ + outb(reg, index); + outb(value, index + 1); +} + +static u8 pmio_read_index(u16 index, u8 reg) +{ + outb(reg, index); + return inb(index + 1); +} + +void pm_iowrite(u8 reg, u8 value) +{ + pmio_write_index(PM_INDEX, reg, value); +} +EXPORT_SYMBOL(pm_iowrite); + +u8 pm_ioread(u8 reg) +{ + return pmio_read_index(PM_INDEX, reg); +} +EXPORT_SYMBOL(pm_ioread); + +void pm2_iowrite(u8 reg, u8 value) +{ + pmio_write_index(PM2_INDEX, reg, value); +} +EXPORT_SYMBOL(pm2_iowrite); + +u8 pm2_ioread(u8 reg) +{ + return pmio_read_index(PM2_INDEX, reg); +} +EXPORT_SYMBOL(pm2_ioread); + +static void acpi_hw_clear_status(void) +{ + u16 value; + + /* PMStatus: Clear WakeStatus/PwrBtnStatus */ + value = inw(ACPI_PM_EVT_BLK); + value |= (1 << 8 | 1 << 15); + outw(value, ACPI_PM_EVT_BLK); + + /* GPEStatus: Clear all generated events */ + outl(inl(ACPI_GPE0_BLK), ACPI_GPE0_BLK); +} + +void acpi_registers_setup(void) +{ + u32 value; + + /* PM Status Base */ + pm_iowrite(0x20, ACPI_PM_EVT_BLK & 0xff); + pm_iowrite(0x21, ACPI_PM_EVT_BLK >> 8); + + /* PM Control Base */ + pm_iowrite(0x22, ACPI_PM_CNT_BLK & 0xff); + pm_iowrite(0x23, ACPI_PM_CNT_BLK >> 8); + + /* GPM Base */ + pm_iowrite(0x28, ACPI_GPE0_BLK & 0xff); + pm_iowrite(0x29, ACPI_GPE0_BLK >> 8); + + /* ACPI End */ + pm_iowrite(0x2e, ACPI_END & 0xff); + pm_iowrite(0x2f, ACPI_END >> 8); + + /* IO Decode: When AcpiDecodeEnable set, South-Bridge uses the contents + * of the PM registers at index 0x20~0x2B to decode ACPI I/O address. */ + pm_iowrite(0x0e, 1 << 3); + + /* SCI_EN set */ + outw(1, ACPI_PM_CNT_BLK); + + /* Enable to generate SCI */ + pm_iowrite(0x10, pm_ioread(0x10) | 1); + + /* GPM3/GPM9 enable */ + value = inl(ACPI_GPE0_BLK + 4); + outl(value | (1 << 14) | (1 << 22), ACPI_GPE0_BLK + 4); + + /* Set GPM9 as input */ + pm_iowrite(0x8d, pm_ioread(0x8d) & (~(1 << 1))); + + /* Set GPM9 as non-output */ + pm_iowrite(0x94, pm_ioread(0x94) | (1 << 3)); + + /* GPM3 config ACPI trigger SCIOUT */ + pm_iowrite(0x33, pm_ioread(0x33) & (~(3 << 4))); + + /* GPM9 config ACPI trigger SCIOUT */ + pm_iowrite(0x3d, pm_ioread(0x3d) & (~(3 << 2))); + + /* GPM3 config falling edge trigger */ + pm_iowrite(0x37, pm_ioread(0x37) & (~(1 << 6))); + + /* No wait for STPGNT# in ACPI Sx state */ + pm_iowrite(0x7c, pm_ioread(0x7c) | (1 << 6)); + + /* Set GPM3 pull-down enable */ + value = pm2_ioread(0xf6); + value |= ((1 << 7) | (1 << 3)); + pm2_iowrite(0xf6, value); + + /* Set GPM9 pull-down enable */ + value = pm2_ioread(0xf8); + value |= ((1 << 5) | (1 << 1)); + pm2_iowrite(0xf8, value); +} + +int __init sbx00_acpi_init(void) +{ + register_acpi_resource(); + acpi_registers_setup(); + acpi_hw_clear_status(); + + return 0; +} diff --git a/arch/mips/loongson64/loongson-3/irq.c b/arch/mips/loongson64/loongson-3/irq.c index 0f75b6b..8e76490 100644 --- a/arch/mips/loongson64/loongson-3/irq.c +++ b/arch/mips/loongson64/loongson-3/irq.c @@ -24,19 +24,21 @@ static void ht_irqdispatch(void) } } +#define UNUSED_IPS (CAUSEF_IP5 | CAUSEF_IP4 | CAUSEF_IP1 | CAUSEF_IP0) + void mach_irq_dispatch(unsigned int pending) { if (pending & CAUSEF_IP7) do_IRQ(LOONGSON_TIMER_IRQ); #if defined(CONFIG_SMP) - else if (pending & CAUSEF_IP6) + if (pending & CAUSEF_IP6) loongson3_ipi_interrupt(NULL); #endif - else if (pending & CAUSEF_IP3) + if (pending & CAUSEF_IP3) ht_irqdispatch(); - else if (pending & CAUSEF_IP2) + if (pending & CAUSEF_IP2) do_IRQ(LOONGSON_UART_IRQ); - else { + if (pending & UNUSED_IPS) { pr_err("%s : spurious interrupt\n", __func__); spurious_interrupt(); } diff --git a/arch/mips/loongson64/loongson-3/numa.c b/arch/mips/loongson64/loongson-3/numa.c index 6f9e010..282c5a8 100644 --- a/arch/mips/loongson64/loongson-3/numa.c +++ b/arch/mips/loongson64/loongson-3/numa.c @@ -213,10 +213,10 @@ static void __init node_mem_init(unsigned int node) BOOTMEM_DEFAULT); if (node == 0 && node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) { - /* Reserve 0xff800000~0xffffffff for RS780E integrated GPU */ + /* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */ reserve_bootmem_node(NODE_DATA(node), - (node_addrspace_offset | 0xff800000), - 8 << 20, BOOTMEM_DEFAULT); + (node_addrspace_offset | 0xfe000000), + 32 << 20, BOOTMEM_DEFAULT); } sparse_memory_present_with_active_regions(node); diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c index 509832a9..e59759a 100644 --- a/arch/mips/loongson64/loongson-3/smp.c +++ b/arch/mips/loongson64/loongson-3/smp.c @@ -421,7 +421,6 @@ static int loongson3_cpu_disable(void) local_irq_save(flags); fixup_irqs(); local_irq_restore(flags); - flush_cache_all(); local_flush_tlb_all(); return 0; @@ -440,7 +439,7 @@ static void loongson3_cpu_die(unsigned int cpu) * flush all L1 entries at first. Then, another core (usually Core 0) can * safely disable the clock of the target core. loongson3_play_dead() is * called via CKSEG1 (uncached and unmmaped) */ -static void loongson3a_play_dead(int *state_addr) +static void loongson3a_r1_play_dead(int *state_addr) { register int val; register long cpuid, core, node, count; @@ -502,6 +501,89 @@ static void loongson3a_play_dead(int *state_addr) : "a1"); } +static void loongson3a_r2_play_dead(int *state_addr) +{ + register int val; + register long cpuid, core, node, count; + register void *addr, *base, *initfunc; + + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " li %[addr], 0x80000000 \n" /* KSEG0 */ + "1: cache 0, 0(%[addr]) \n" /* flush L1 ICache */ + " cache 0, 1(%[addr]) \n" + " cache 0, 2(%[addr]) \n" + " cache 0, 3(%[addr]) \n" + " cache 1, 0(%[addr]) \n" /* flush L1 DCache */ + " cache 1, 1(%[addr]) \n" + " cache 1, 2(%[addr]) \n" + " cache 1, 3(%[addr]) \n" + " addiu %[sets], %[sets], -1 \n" + " bnez %[sets], 1b \n" + " addiu %[addr], %[addr], 0x40 \n" + " li %[addr], 0x80000000 \n" /* KSEG0 */ + "2: cache 2, 0(%[addr]) \n" /* flush L1 VCache */ + " cache 2, 1(%[addr]) \n" + " cache 2, 2(%[addr]) \n" + " cache 2, 3(%[addr]) \n" + " cache 2, 4(%[addr]) \n" + " cache 2, 5(%[addr]) \n" + " cache 2, 6(%[addr]) \n" + " cache 2, 7(%[addr]) \n" + " cache 2, 8(%[addr]) \n" + " cache 2, 9(%[addr]) \n" + " cache 2, 10(%[addr]) \n" + " cache 2, 11(%[addr]) \n" + " cache 2, 12(%[addr]) \n" + " cache 2, 13(%[addr]) \n" + " cache 2, 14(%[addr]) \n" + " cache 2, 15(%[addr]) \n" + " addiu %[vsets], %[vsets], -1 \n" + " bnez %[vsets], 2b \n" + " addiu %[addr], %[addr], 0x40 \n" + " li %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */ + " sw %[val], (%[state_addr]) \n" + " sync \n" + " cache 21, (%[state_addr]) \n" /* flush entry of *state_addr */ + " .set pop \n" + : [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)); + + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " .set mips64 \n" + " mfc0 %[cpuid], $15, 1 \n" + " andi %[cpuid], 0x3ff \n" + " dli %[base], 0x900000003ff01000 \n" + " andi %[core], %[cpuid], 0x3 \n" + " sll %[core], 8 \n" /* get core id */ + " or %[base], %[base], %[core] \n" + " andi %[node], %[cpuid], 0xc \n" + " dsll %[node], 42 \n" /* get node id */ + " or %[base], %[base], %[node] \n" + "1: li %[count], 0x100 \n" /* wait for init loop */ + "2: bnez %[count], 2b \n" /* limit mailbox access */ + " addiu %[count], -1 \n" + " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */ + " beqz %[initfunc], 1b \n" + " nop \n" + " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */ + " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */ + " ld $a1, 0x38(%[base]) \n" + " jr %[initfunc] \n" /* jump to initial PC */ + " nop \n" + " .set pop \n" + : [core] "=&r" (core), [node] "=&r" (node), + [base] "=&r" (base), [cpuid] "=&r" (cpuid), + [count] "=&r" (count), [initfunc] "=&r" (initfunc) + : /* No Input */ + : "a1"); +} + static void loongson3b_play_dead(int *state_addr) { register int val; @@ -573,13 +655,18 @@ void play_dead(void) void (*play_dead_at_ckseg1)(int *); idle_task_exit(); - switch (loongson_sysconf.cputype) { - case Loongson_3A: + switch (read_c0_prid() & PRID_REV_MASK) { + case PRID_REV_LOONGSON3A_R1: default: play_dead_at_ckseg1 = - (void *)CKSEG1ADDR((unsigned long)loongson3a_play_dead); + (void *)CKSEG1ADDR((unsigned long)loongson3a_r1_play_dead); + break; + case PRID_REV_LOONGSON3A_R2: + play_dead_at_ckseg1 = + (void *)CKSEG1ADDR((unsigned long)loongson3a_r2_play_dead); break; - case Loongson_3B: + case PRID_REV_LOONGSON3B_R1: + case PRID_REV_LOONGSON3B_R2: play_dead_at_ckseg1 = (void *)CKSEG1ADDR((unsigned long)loongson3b_play_dead); break; @@ -594,9 +681,9 @@ void loongson3_disable_clock(int cpu) uint64_t core_id = cpu_data[cpu].core; uint64_t package_id = cpu_data[cpu].package; - if (loongson_sysconf.cputype == Loongson_3A) { + if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) { LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id)); - } else if (loongson_sysconf.cputype == Loongson_3B) { + } else { if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG)) LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3)); } @@ -607,9 +694,9 @@ void loongson3_enable_clock(int cpu) uint64_t core_id = cpu_data[cpu].core; uint64_t package_id = cpu_data[cpu].package; - if (loongson_sysconf.cputype == Loongson_3A) { + if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) { LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id); - } else if (loongson_sysconf.cputype == Loongson_3B) { + } else { if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG)) LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3); } diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index a19641d..e9bbc2a 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o dp_fmax.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_2008class.o dp_fmin.o dp_fmax.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o sp_fmax.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_2008class.o sp_fmin.o sp_fmax.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index cdfd44f..d96e912b 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -445,9 +445,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case spec_op: switch (insn.r_format.func) { case jalr_op: - regs->regs[insn.r_format.rd] = - regs->cp0_epc + dec_insn.pc_inc + - dec_insn.next_pc_inc; + if (insn.r_format.rd != 0) { + regs->regs[insn.r_format.rd] = + regs->cp0_epc + dec_insn.pc_inc + + dec_insn.next_pc_inc; + } /* Fall through */ case jr_op: /* For R6, JR already emulated in jalr_op */ @@ -973,9 +975,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, struct mm_decoded_insn dec_insn, void *__user *fault_addr) { unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; - unsigned int cond, cbit; + unsigned int cond, cbit, bit0; mips_instruction ir; int likely, pc_inc; + union fpureg *fpr; u32 __user *wva; u64 __user *dva; u32 wval; @@ -1187,14 +1190,14 @@ emul: return SIGILL; cond = likely = 0; + fpr = ¤t->thread.fpu.fpr[MIPSInst_RT(ir)]; + bit0 = get_fpr32(fpr, 0) & 0x1; switch (MIPSInst_RS(ir)) { case bc1eqz_op: - if (get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1) - cond = 1; + cond = bit0 == 0; break; case bc1nez_op: - if (!(get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)) - cond = 1; + cond = bit0 != 0; break; } goto branch_common; @@ -1674,7 +1677,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, union ieee754sp(*b) (union ieee754sp, union ieee754sp); union ieee754sp(*u) (union ieee754sp); } handler; - union ieee754sp fs, ft; + union ieee754sp fd, fs, ft; switch (MIPSInst_FUNC(ir)) { /* binary ops */ @@ -1945,6 +1948,17 @@ copcsr: rfmt = w_fmt; goto copcsr; + case fsel_op: + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(fd, MIPSInst_FD(ir)); + if (fd.bits & 0x1) + SPFROMREG(rv.s, MIPSInst_FT(ir)); + else + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fcvtl_op: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; @@ -1993,7 +2007,7 @@ copcsr: } case d_fmt: { - union ieee754dp fs, ft; + union ieee754dp fd, fs, ft; union { union ieee754dp(*b) (union ieee754dp, union ieee754dp); union ieee754dp(*u) (union ieee754dp); @@ -2243,6 +2257,17 @@ dcopuop: rfmt = w_fmt; goto copcsr; + case fsel_op: + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(fd, MIPSInst_FD(ir)); + if (fd.bits & 0x1) + DPFROMREG(rv.d, MIPSInst_FT(ir)); + else + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fcvtl_op: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 119eda9..4a2d03c 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -14,8 +14,12 @@ #include "ieee754dp.h" -union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, - union ieee754dp y) +enum maddf_flags { + maddf_negate_product = 1 << 0, +}; + +static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y, enum maddf_flags flags) { int re; int rs; @@ -32,16 +36,15 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, COMPXDP; COMPYDP; - - u64 zm; int ze; int zs __maybe_unused; int zc; + COMPZDP; EXPLODEXDP; EXPLODEYDP; - EXPLODEDP(z, zc, zs, ze, zm) + EXPLODEZDP; FLUSHXDP; FLUSHYDP; - FLUSHDP(z, zc, zs, ze, zm); + FLUSHZDP; ieee754_clearcx(); @@ -50,7 +53,7 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754dp_nanxcpt(z); case IEEE754_CLASS_DNORM: - DPDNORMx(zm, ze); + DPDNORMZ; /* QNAN is handled separately below */ } @@ -154,13 +157,15 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, re = xe + ye; rs = xs ^ ys; + if (flags & maddf_negate_product) + rs ^= 1; /* shunt to top of word */ xm <<= 64 - (DP_FBITS + 1); ym <<= 64 - (DP_FBITS + 1); /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + * Multiply 64 bits xm, ym to give high 64 bits rm with stickness. */ /* 32 * 32 => 64 */ @@ -198,7 +203,7 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, if ((s64) rm < 0) { rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | ((rm << (DP_FBITS + 1 + 3)) != 0); - re++; + re++; } else { rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); @@ -263,3 +268,15 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, return ieee754dp_format(zs, ze, zm); } + +union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + return _dp_maddf(z, x, y, 0); +} + +union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + return _dp_maddf(z, x, y, maddf_negate_product); +} diff --git a/arch/mips/math-emu/dp_msubf.c b/arch/mips/math-emu/dp_msubf.c deleted file mode 100644 index 1224126..0000000 --- a/arch/mips/math-emu/dp_msubf.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * IEEE754 floating point arithmetic - * double precision: MSUB.f (Fused Multiply Subtract) - * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) - * - * MIPS floating point support - * Copyright (C) 2015 Imagination Technologies, Ltd. - * Author: Markos Chandras <markos.chandras@imgtec.com> - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License. - */ - -#include "ieee754dp.h" - -union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, - union ieee754dp y) -{ - int re; - int rs; - u64 rm; - unsigned lxm; - unsigned hxm; - unsigned lym; - unsigned hym; - u64 lrm; - u64 hrm; - u64 t; - u64 at; - int s; - - COMPXDP; - COMPYDP; - - u64 zm; int ze; int zs __maybe_unused; int zc; - - EXPLODEXDP; - EXPLODEYDP; - EXPLODEDP(z, zc, zs, ze, zm) - - FLUSHXDP; - FLUSHYDP; - FLUSHDP(z, zc, zs, ze, zm); - - ieee754_clearcx(); - - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - DPDNORMx(zm, ze); - /* QNAN is handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754dp_nanxcpt(x); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): - return y; - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; - - - /* - * Infinity handling - */ - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754dp_indef(); - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - return ieee754dp_inf(xs ^ ys); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - /* Multiplication is 0 so just return z */ - return z; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): - DPDNORMX; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - DPDNORMY; - break; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - DPDNORMX; - break; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - /* fall through to real computations */ - } - - /* Finally get to do some computation */ - - /* - * Do the multiplication bit first - * - * rm = xm * ym, re = xe + ye basically - * - * At this point xm and ym should have been normalized. - */ - assert(xm & DP_HIDDEN_BIT); - assert(ym & DP_HIDDEN_BIT); - - re = xe + ye; - rs = xs ^ ys; - - /* shunt to top of word */ - xm <<= 64 - (DP_FBITS + 1); - ym <<= 64 - (DP_FBITS + 1); - - /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. - */ - - /* 32 * 32 => 64 */ -#define DPXMULT(x, y) ((u64)(x) * (u64)y) - - lxm = xm; - hxm = xm >> 32; - lym = ym; - hym = ym >> 32; - - lrm = DPXMULT(lxm, lym); - hrm = DPXMULT(hxm, hym); - - t = DPXMULT(lxm, hym); - - at = lrm + (t << 32); - hrm += at < lrm; - lrm = at; - - hrm = hrm + (t >> 32); - - t = DPXMULT(hxm, lym); - - at = lrm + (t << 32); - hrm += at < lrm; - lrm = at; - - hrm = hrm + (t >> 32); - - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((s64) rm < 0) { - rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | - ((rm << (DP_FBITS + 1 + 3)) != 0); - re++; - } else { - rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | - ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); - } - assert(rm & (DP_HIDDEN_BIT << 3)); - - /* And now the subtraction */ - - /* flip sign of r and handle as add */ - rs ^= 1; - - assert(zm & DP_HIDDEN_BIT); - - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; - - if (ze > re) { - /* - * Have to shift y fraction right to align. - */ - s = ze - re; - rm = XDPSRS(rm, s); - re += s; - } else if (re > ze) { - /* - * Have to shift x fraction right to align. - */ - s = re - ze; - zm = XDPSRS(zm, s); - ze += s; - } - assert(ze == re); - assert(ze <= DP_EMAX); - - if (zs == rs) { - /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in xm, xs and xe. - */ - zm = zm + rm; - - if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ - zm = XDPSRS1(zm); - ze++; - } - } else { - if (zm >= rm) { - zm = zm - rm; - } else { - zm = rm - zm; - zs = rs; - } - if (zm == 0) - return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); - - /* - * Normalize to rounding precision. - */ - while ((zm >> (DP_FBITS + 3)) == 0) { - zm <<= 1; - ze--; - } - } - - return ieee754dp_format(zs, ze, zm); -} diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index d0901f0..87d0b44 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c @@ -125,7 +125,7 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) ym <<= 64 - (DP_FBITS + 1); /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + * Multiply 64 bits xm, ym to give high 64 bits rm with stickness. */ /* 32 * 32 => 64 */ @@ -163,7 +163,7 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) if ((s64) rm < 0) { rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | ((rm << (DP_FBITS + 1 + 3)) != 0); - re++; + re++; } else { rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 46b964d..d4ceacd 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -60,7 +60,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) unsigned int rs; s32 v; - rs = (((insn.mm_a_format.rs + 0x1e) & 0xf) + 2); + rs = (((insn.mm_a_format.rs + 0xe) & 0xf) + 2); v = regs->cp0_epc & ~3; v += insn.mm_a_format.simmediate << 2; regs->regs[rs] = (long)v; diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c index 47d26c8..465a034 100644 --- a/arch/mips/math-emu/ieee754dp.c +++ b/arch/mips/math-emu/ieee754dp.c @@ -54,10 +54,13 @@ union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r) assert(ieee754dp_issnan(r)); ieee754_setcx(IEEE754_INVALID_OPERATION); - if (ieee754_csr.nan2008) + if (ieee754_csr.nan2008) { DPMANT(r) |= DP_MBIT(DP_FBITS - 1); - else - r = ieee754dp_indef(); + } else { + DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1); + if (!ieee754dp_isnan(r)) + DPMANT(r) |= DP_MBIT(DP_FBITS - 2); + } return r; } diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h index e2babd9..9ba0230 100644 --- a/arch/mips/math-emu/ieee754dp.h +++ b/arch/mips/math-emu/ieee754dp.h @@ -60,6 +60,7 @@ static inline int ieee754dp_finite(union ieee754dp x) while ((m >> DP_FBITS) == 0) { m <<= 1; e--; } #define DPDNORMX DPDNORMx(xm, xe) #define DPDNORMY DPDNORMx(ym, ye) +#define DPDNORMZ DPDNORMx(zm, ze) static inline union ieee754dp builddp(int s, int bx, u64 m) { diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index ed7bb27..8bc2f69 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -55,6 +55,9 @@ static inline int ieee754_class_nan(int xc) #define COMPYSP \ unsigned ym; int ye; int ys; int yc +#define COMPZSP \ + unsigned zm; int ze; int zs; int zc + #define EXPLODESP(v, vc, vs, ve, vm) \ { \ vs = SPSIGN(v); \ @@ -81,6 +84,7 @@ static inline int ieee754_class_nan(int xc) } #define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm) #define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym) +#define EXPLODEZSP EXPLODESP(z, zc, zs, ze, zm) #define COMPXDP \ @@ -89,6 +93,9 @@ static inline int ieee754_class_nan(int xc) #define COMPYDP \ u64 ym; int ye; int ys; int yc +#define COMPZDP \ + u64 zm; int ze; int zs; int zc + #define EXPLODEDP(v, vc, vs, ve, vm) \ { \ vm = DPMANT(v); \ @@ -115,6 +122,7 @@ static inline int ieee754_class_nan(int xc) } #define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm) #define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym) +#define EXPLODEZDP EXPLODEDP(z, zc, zs, ze, zm) #define FLUSHDP(v, vc, vs, ve, vm) \ if (vc==IEEE754_CLASS_DNORM) { \ @@ -140,7 +148,9 @@ static inline int ieee754_class_nan(int xc) #define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm) #define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym) +#define FLUSHZDP FLUSHDP(z, zc, zs, ze, zm) #define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm) #define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym) +#define FLUSHZSP FLUSHSP(z, zc, zs, ze, zm) #endif /* __IEEE754INT_H */ diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index e0b2c45..260e6896 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c @@ -54,10 +54,13 @@ union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r) assert(ieee754sp_issnan(r)); ieee754_setcx(IEEE754_INVALID_OPERATION); - if (ieee754_csr.nan2008) + if (ieee754_csr.nan2008) { SPMANT(r) |= SP_MBIT(SP_FBITS - 1); - else - r = ieee754sp_indef(); + } else { + SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1); + if (!ieee754sp_isnan(r)) + SPMANT(r) |= SP_MBIT(SP_FBITS - 2); + } return r; } @@ -138,7 +141,8 @@ union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) } else { /* sticky right shift es bits */ - SPXSRSXn(es); + xm = XSPSRS(xm, es); + xe += es; assert((xm & (SP_HIDDEN_BIT << 3)) == 0); assert(xe == SP_EMIN); } diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 374a3f0..8476067 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -46,25 +46,24 @@ static inline int ieee754sp_finite(union ieee754sp x) } /* 3bit extended single precision sticky right shift */ -#define SPXSRSXn(rs) \ - (xe += rs, \ - xm = (rs > (SP_FBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) +#define XSPSRS(v, rs) \ + ((rs > (SP_FBITS+3))?1:((v) >> (rs)) | ((v) << (32-(rs)) != 0)) -#define SPXSRSX1() \ - (xe++, (xm = (xm >> 1) | (xm & 1))) +#define XSPSRS1(m) \ + ((m >> 1) | (m & 1)) -#define SPXSRSYn(rs) \ - (ye+=rs, \ - ym = (rs > (SP_FBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) +#define SPXSRSX1() \ + (xe++, (xm = XSPSRS1(xm))) #define SPXSRSY1() \ - (ye++, (ym = (ym >> 1) | (ym & 1))) + (ye++, (ym = XSPSRS1(ym))) /* convert denormal to normalized with extended exponent */ #define SPDNORMx(m,e) \ while ((m >> SP_FBITS) == 0) { m <<= 1; e--; } #define SPDNORMX SPDNORMx(xm, xe) #define SPDNORMY SPDNORMx(ym, ye) +#define SPDNORMZ SPDNORMx(zm, ze) static inline union ieee754sp buildsp(int s, int bx, unsigned m) { diff --git a/arch/mips/math-emu/sp_add.c b/arch/mips/math-emu/sp_add.c index f1c87b0..c55c0c0 100644 --- a/arch/mips/math-emu/sp_add.c +++ b/arch/mips/math-emu/sp_add.c @@ -132,13 +132,15 @@ union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y) * Have to shift y fraction right to align. */ s = xe - ye; - SPXSRSYn(s); + ym = XSPSRS(ym, s); + ye += s; } else if (ye > xe) { /* * Have to shift x fraction right to align. */ s = ye - xe; - SPXSRSXn(s); + xm = XSPSRS(xm, s); + xe += s; } assert(xe == ye); assert(xe <= SP_EMAX); diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index dd1dd83..a8cd8b4 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -14,8 +14,12 @@ #include "ieee754sp.h" -union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, - union ieee754sp y) +enum maddf_flags { + maddf_negate_product = 1 << 0, +}; + +static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y, enum maddf_flags flags) { int re; int rs; @@ -32,15 +36,15 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, COMPXSP; COMPYSP; - u32 zm; int ze; int zs __maybe_unused; int zc; + COMPZSP; EXPLODEXSP; EXPLODEYSP; - EXPLODESP(z, zc, zs, ze, zm) + EXPLODEZSP; FLUSHXSP; FLUSHYSP; - FLUSHSP(z, zc, zs, ze, zm); + FLUSHZSP; ieee754_clearcx(); @@ -49,7 +53,7 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754sp_nanxcpt(z); case IEEE754_CLASS_DNORM: - SPDNORMx(zm, ze); + SPDNORMZ; /* QNAN is handled separately below */ } @@ -154,6 +158,8 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, re = xe + ye; rs = xs ^ ys; + if (flags & maddf_negate_product) + rs ^= 1; /* shunt to top of word */ xm <<= 32 - (SP_FBITS + 1); @@ -208,16 +214,18 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, if (ze > re) { /* - * Have to shift y fraction right to align. + * Have to shift r fraction right to align. */ s = ze - re; - SPXSRSYn(s); + rm = XSPSRS(rm, s); + re += s; } else if (re > ze) { /* - * Have to shift x fraction right to align. + * Have to shift z fraction right to align. */ s = re - ze; - SPXSRSYn(s); + zm = XSPSRS(zm, s); + ze += s; } assert(ze == re); assert(ze <= SP_EMAX); @@ -230,7 +238,8 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, zm = zm + rm; if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ - SPXSRSX1(); + zm = XSPSRS1(zm); + ze++; } } else { if (zm >= rm) { @@ -253,3 +262,15 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, } return ieee754sp_format(zs, ze, zm); } + +union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + return _sp_maddf(z, x, y, 0); +} + +union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + return _sp_maddf(z, x, y, maddf_negate_product); +} diff --git a/arch/mips/math-emu/sp_msubf.c b/arch/mips/math-emu/sp_msubf.c deleted file mode 100644 index 81c38b980..0000000 --- a/arch/mips/math-emu/sp_msubf.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * IEEE754 floating point arithmetic - * single precision: MSUB.f (Fused Multiply Subtract) - * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) - * - * MIPS floating point support - * Copyright (C) 2015 Imagination Technologies, Ltd. - * Author: Markos Chandras <markos.chandras@imgtec.com> - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License. - */ - -#include "ieee754sp.h" - -union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, - union ieee754sp y) -{ - int re; - int rs; - unsigned rm; - unsigned short lxm; - unsigned short hxm; - unsigned short lym; - unsigned short hym; - unsigned lrm; - unsigned hrm; - unsigned t; - unsigned at; - int s; - - COMPXSP; - COMPYSP; - u32 zm; int ze; int zs __maybe_unused; int zc; - - EXPLODEXSP; - EXPLODEYSP; - EXPLODESP(z, zc, zs, ze, zm) - - FLUSHXSP; - FLUSHYSP; - FLUSHSP(z, zc, zs, ze, zm); - - ieee754_clearcx(); - - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - SPDNORMx(zm, ze); - /* QNAN is handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754sp_nanxcpt(x); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): - return y; - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; - - /* - * Infinity handling - */ - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754sp_indef(); - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - return ieee754sp_inf(xs ^ ys); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - /* Multiplication is 0 so just return z */ - return z; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): - SPDNORMX; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - SPDNORMY; - break; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - SPDNORMX; - break; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - /* fall through to real compuation */ - } - - /* Finally get to do some computation */ - - /* - * Do the multiplication bit first - * - * rm = xm * ym, re = xe + ye basically - * - * At this point xm and ym should have been normalized. - */ - - /* rm = xm * ym, re = xe+ye basically */ - assert(xm & SP_HIDDEN_BIT); - assert(ym & SP_HIDDEN_BIT); - - re = xe + ye; - rs = xs ^ ys; - - /* shunt to top of word */ - xm <<= 32 - (SP_FBITS + 1); - ym <<= 32 - (SP_FBITS + 1); - - /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. - */ - lxm = xm & 0xffff; - hxm = xm >> 16; - lym = ym & 0xffff; - hym = ym >> 16; - - lrm = lxm * lym; /* 16 * 16 => 32 */ - hrm = hxm * hym; /* 16 * 16 => 32 */ - - t = lxm * hym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); - - t = hxm * lym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); - - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((int) rm < 0) { - rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | - ((rm << (SP_FBITS + 1 + 3)) != 0); - re++; - } else { - rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | - ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); - } - assert(rm & (SP_HIDDEN_BIT << 3)); - - /* And now the subtraction */ - - /* Flip sign of r and handle as add */ - rs ^= 1; - - assert(zm & SP_HIDDEN_BIT); - - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; - - if (ze > re) { - /* - * Have to shift y fraction right to align. - */ - s = ze - re; - SPXSRSYn(s); - } else if (re > ze) { - /* - * Have to shift x fraction right to align. - */ - s = re - ze; - SPXSRSYn(s); - } - assert(ze == re); - assert(ze <= SP_EMAX); - - if (zs == rs) { - /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in zm, zs and ze. - */ - zm = zm + rm; - - if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ - SPXSRSX1(); /* shift preserving sticky */ - } - } else { - if (zm >= rm) { - zm = zm - rm; - } else { - zm = rm - zm; - zs = rs; - } - if (zm == 0) - return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); - - /* - * Normalize in extended single precision - */ - while ((zm >> (SP_MBITS + 3)) == 0) { - zm <<= 1; - ze--; - } - - } - return ieee754sp_format(zs, ze, zm); -} diff --git a/arch/mips/math-emu/sp_sub.c b/arch/mips/math-emu/sp_sub.c index ec5f937..dc998ed 100644 --- a/arch/mips/math-emu/sp_sub.c +++ b/arch/mips/math-emu/sp_sub.c @@ -134,13 +134,15 @@ union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y) * have to shift y fraction right to align */ s = xe - ye; - SPXSRSYn(s); + ym = XSPSRS(ym, s); + ye += s; } else if (ye > xe) { /* * have to shift x fraction right to align */ s = ye - xe; - SPXSRSXn(s); + xm = XSPSRS(xm, s); + xe += s; } assert(xe == ye); assert(xe <= SP_EMAX); diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index caac3d7..ef7f925 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -77,6 +77,7 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info) */ 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; /* @@ -447,6 +448,11 @@ static inline void local_r4k___flush_cache_all(void * args) r4k_blast_scache(); break; + case CPU_BMIPS5000: + r4k_blast_scache(); + __sync(); + break; + default: r4k_blast_dcache(); r4k_blast_icache(); @@ -492,7 +498,14 @@ static inline void local_r4k_flush_cache_range(void * args) if (!(has_valid_asid(vma->vm_mm))) return; - r4k_blast_dcache(); + /* + * If dcache can alias, we must blast it since mapping is changing. + * If executable, we must ensure any dirty lines are written back far + * enough to be visible to icache. + */ + if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) + r4k_blast_dcache(); + /* If executable, blast stale lines from icache */ if (exec) r4k_blast_icache(); } @@ -502,7 +515,7 @@ static void r4k_flush_cache_range(struct vm_area_struct *vma, { int exec = vma->vm_flags & VM_EXEC; - if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) + if (cpu_has_dc_aliases || exec) r4k_on_each_cpu(local_r4k_flush_cache_range, vma); } @@ -1148,6 +1161,8 @@ static void probe_pcache(void) c->dcache.ways * c->dcache.linesz; c->dcache.waybit = 0; + if ((prid & PRID_REV_MASK) >= PRID_REV_LOONGSON3A_R2) + c->options |= MIPS_CPU_PREFETCH; break; case CPU_CAVIUM_OCTEON3: @@ -1278,6 +1293,8 @@ static void probe_pcache(void) case CPU_M5150: case CPU_QEMU_GENERIC: case CPU_I6400: + case CPU_P6600: + case CPU_M6250: if (!(read_c0_config7() & MIPS_CONF7_IAR) && (c->icache.waysize > PAGE_SIZE)) c->icache.flags |= MIPS_CACHE_ALIASES; @@ -1304,7 +1321,14 @@ static void probe_pcache(void) break; case CPU_ALCHEMY: + case CPU_I6400: + c->icache.flags |= MIPS_CACHE_IC_F_DC; + break; + + case CPU_BMIPS5000: c->icache.flags |= MIPS_CACHE_IC_F_DC; + /* Cache aliases are handled in hardware; allow HIGHMEM */ + c->dcache.flags &= ~MIPS_CACHE_ALIASES; break; case CPU_LOONGSON2: @@ -1328,6 +1352,31 @@ static void probe_pcache(void) c->dcache.linesz); } +static void probe_vcache(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int config2, lsize; + + if (current_cpu_type() != CPU_LOONGSON3) + return; + + config2 = read_c0_config2(); + if ((lsize = ((config2 >> 20) & 15))) + c->vcache.linesz = 2 << lsize; + else + c->vcache.linesz = lsize; + + c->vcache.sets = 64 << ((config2 >> 24) & 15); + c->vcache.ways = 1 + ((config2 >> 16) & 15); + + vcache_size = c->vcache.sets * c->vcache.ways * c->vcache.linesz; + + c->vcache.waybit = 0; + + pr_info("Unified victim cache %ldkB %s, linesize %d bytes.\n", + vcache_size >> 10, way_string[c->vcache.ways], c->vcache.linesz); +} + /* * If you even _breathe_ on this function, look at the gcc output and make sure * it does not pop things on and off the stack for the cache sizing loop that @@ -1650,6 +1699,7 @@ void r4k_cache_init(void) struct cpuinfo_mips *c = ¤t_cpu_data; probe_pcache(); + probe_vcache(); setup_scache(); r4k_blast_dcache_page_setup(); @@ -1671,7 +1721,7 @@ void r4k_cache_init(void) * This code supports virtually indexed processors and will be * unnecessarily inefficient on physically indexed processors. */ - if (c->dcache.linesz) + if (c->dcache.linesz && cpu_has_dc_aliases) shm_align_mask = max_t( unsigned long, c->dcache.sets * c->dcache.linesz - 1, PAGE_SIZE - 1); @@ -1744,12 +1794,24 @@ void r4k_cache_init(void) flush_icache_range = (void *)b5k_instruction_hazard; local_flush_icache_range = (void *)b5k_instruction_hazard; - /* Cache aliases are handled in hardware; allow HIGHMEM */ - current_cpu_data.dcache.flags &= ~MIPS_CACHE_ALIASES; /* Optimization: an L2 flush implicitly flushes the L1 */ current_cpu_data.options |= MIPS_CPU_INCLUSIVE_CACHES; break; + case CPU_LOONGSON3: + /* Loongson-3 maintains cache coherency by hardware */ + __flush_cache_all = cache_noop; + __flush_cache_vmap = cache_noop; + __flush_cache_vunmap = cache_noop; + __flush_kernel_vmap_range = (void *)cache_noop; + flush_cache_mm = (void *)cache_noop; + flush_cache_page = (void *)cache_noop; + flush_cache_range = (void *)cache_noop; + flush_cache_sigtramp = (void *)cache_noop; + flush_icache_all = (void *)cache_noop; + flush_data_cache_page = (void *)cache_noop; + local_flush_data_cache_page = (void *)cache_noop; + break; } } diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 3f159ca..bf04c6c 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -16,6 +16,7 @@ #include <linux/mm.h> #include <asm/cacheflush.h> +#include <asm/highmem.h> #include <asm/processor.h> #include <asm/cpu.h> #include <asm/cpu-features.h> @@ -83,8 +84,6 @@ void __flush_dcache_page(struct page *page) struct address_space *mapping = page_mapping(page); unsigned long addr; - if (PageHighMem(page)) - return; if (mapping && !mapping_mapped(mapping)) { SetPageDcacheDirty(page); return; @@ -95,8 +94,15 @@ void __flush_dcache_page(struct page *page) * case is for exec env/arg pages and those are %99 certainly going to * get faulted into the tlb (and thus flushed) anyways. */ - addr = (unsigned long) page_address(page); + if (PageHighMem(page)) + addr = (unsigned long)kmap_atomic(page); + else + addr = (unsigned long)page_address(page); + flush_data_cache_page(addr); + + if (PageHighMem(page)) + __kunmap_atomic((void *)addr); } EXPORT_SYMBOL(__flush_dcache_page); @@ -119,33 +125,28 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) EXPORT_SYMBOL(__flush_anon_page); -void __flush_icache_page(struct vm_area_struct *vma, struct page *page) -{ - unsigned long addr; - - if (PageHighMem(page)) - return; - - addr = (unsigned long) page_address(page); - flush_data_cache_page(addr); -} -EXPORT_SYMBOL_GPL(__flush_icache_page); - -void __update_cache(struct vm_area_struct *vma, unsigned long address, - pte_t pte) +void __update_cache(unsigned long address, pte_t pte) { struct page *page; unsigned long pfn, addr; - int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc; + int exec = !pte_no_exec(pte) && !cpu_has_ic_fills_f_dc; pfn = pte_pfn(pte); if (unlikely(!pfn_valid(pfn))) return; page = pfn_to_page(pfn); - if (page_mapping(page) && Page_dcache_dirty(page)) { - addr = (unsigned long) page_address(page); + if (Page_dcache_dirty(page)) { + if (PageHighMem(page)) + addr = (unsigned long)kmap_atomic(page); + else + addr = (unsigned long)page_address(page); + if (exec || pages_do_alias(addr, address & PAGE_MASK)) flush_data_cache_page(addr); + + if (PageHighMem(page)) + __kunmap_atomic((void *)addr); + ClearPageDcacheDirty(page); } } diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 730d394..cb557d2 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -88,19 +88,20 @@ static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp) else #endif #if defined(CONFIG_ZONE_DMA32) && defined(CONFIG_ZONE_DMA) - if (dev->coherent_dma_mask < DMA_BIT_MASK(32)) + if (dev == NULL || dev->coherent_dma_mask < DMA_BIT_MASK(32)) dma_flag = __GFP_DMA; else if (dev->coherent_dma_mask < DMA_BIT_MASK(64)) dma_flag = __GFP_DMA32; else #endif #if defined(CONFIG_ZONE_DMA32) && !defined(CONFIG_ZONE_DMA) - if (dev->coherent_dma_mask < DMA_BIT_MASK(64)) + if (dev == NULL || dev->coherent_dma_mask < DMA_BIT_MASK(64)) dma_flag = __GFP_DMA32; else #endif #if defined(CONFIG_ZONE_DMA) && !defined(CONFIG_ZONE_DMA32) - if (dev->coherent_dma_mask < DMA_BIT_MASK(sizeof(phys_addr_t) * 8)) + if (dev == NULL || + dev->coherent_dma_mask < DMA_BIT_MASK(sizeof(phys_addr_t) * 8)) dma_flag = __GFP_DMA; else #endif diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 7e5fa09..9b58eb5 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -98,8 +98,10 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot) idx += in_interrupt() ? FIX_N_COLOURS : 0; vaddr = __fix_to_virt(FIX_CMAP_END - idx); pte = mk_pte(page, prot); -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_XPA) entrylo = pte_to_entrylo(pte.pte_high); +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) + entrylo = pte.pte_high; #else entrylo = pte_to_entrylo(pte_val(pte)); #endif @@ -110,9 +112,11 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot) write_c0_entrylo0(entrylo); write_c0_entrylo1(entrylo); #ifdef CONFIG_XPA - entrylo = (pte.pte_low & _PFNX_MASK); - writex_c0_entrylo0(entrylo); - writex_c0_entrylo1(entrylo); + if (cpu_has_xpa) { + entrylo = (pte.pte_low & _PFNX_MASK); + writex_c0_entrylo0(entrylo); + writex_c0_entrylo1(entrylo); + } #endif tlbidx = read_c0_wired(); write_c0_wired(tlbidx + 1); @@ -196,7 +200,7 @@ void copy_to_user_page(struct vm_area_struct *vma, if (cpu_has_dc_aliases) SetPageDcacheDirty(page); } - if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) + if (vma->vm_flags & VM_EXEC) flush_cache_page(vma, vaddr, page_to_pfn(page)); } diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c index 885d73f..c41953c 100644 --- a/arch/mips/mm/page.c +++ b/arch/mips/mm/page.c @@ -188,6 +188,15 @@ static void set_prefetch_parameters(void) } break; + case CPU_LOONGSON3: + /* Loongson-3 only support the Pref_Load/Pref_Store. */ + pref_bias_clear_store = 128; + pref_bias_copy_load = 128; + pref_bias_copy_store = 128; + pref_src_mode = Pref_Load; + pref_dst_mode = Pref_Store; + break; + default: pref_bias_clear_store = 128; pref_bias_copy_load = 256; diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 91dec32..286a4d5 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -141,6 +141,7 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c) case CPU_P5600: case CPU_BMIPS5000: case CPU_QEMU_GENERIC: + case CPU_P6600: if (config2 & (1 << 12)) return 0; } diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c index b4f366f..1290b99 100644 --- a/arch/mips/mm/tlb-r3k.c +++ b/arch/mips/mm/tlb-r3k.c @@ -43,7 +43,7 @@ static void local_flush_tlb_from(int entry) { unsigned long old_ctx; - old_ctx = read_c0_entryhi() & ASID_MASK; + old_ctx = read_c0_entryhi() & cpu_asid_mask(¤t_cpu_data); write_c0_entrylo0(0); while (entry < current_cpu_data.tlbsize) { write_c0_index(entry << 8); @@ -81,6 +81,7 @@ void local_flush_tlb_mm(struct mm_struct *mm) void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { + unsigned long asid_mask = cpu_asid_mask(¤t_cpu_data); struct mm_struct *mm = vma->vm_mm; int cpu = smp_processor_id(); @@ -89,13 +90,13 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, #ifdef DEBUG_TLB printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", - cpu_context(cpu, mm) & ASID_MASK, start, end); + cpu_context(cpu, mm) & asid_mask, start, end); #endif local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (size <= current_cpu_data.tlbsize) { - int oldpid = read_c0_entryhi() & ASID_MASK; - int newpid = cpu_context(cpu, mm) & ASID_MASK; + int oldpid = read_c0_entryhi() & asid_mask; + int newpid = cpu_context(cpu, mm) & asid_mask; start &= PAGE_MASK; end += PAGE_SIZE - 1; @@ -159,6 +160,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { + unsigned long asid_mask = cpu_asid_mask(¤t_cpu_data); int cpu = smp_processor_id(); if (cpu_context(cpu, vma->vm_mm) != 0) { @@ -168,10 +170,10 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) #ifdef DEBUG_TLB printk("[tlbpage<%lu,0x%08lx>]", cpu_context(cpu, vma->vm_mm), page); #endif - newpid = cpu_context(cpu, vma->vm_mm) & ASID_MASK; + newpid = cpu_context(cpu, vma->vm_mm) & asid_mask; page &= PAGE_MASK; local_irq_save(flags); - oldpid = read_c0_entryhi() & ASID_MASK; + oldpid = read_c0_entryhi() & asid_mask; write_c0_entryhi(page | newpid); BARRIER; tlb_probe(); @@ -190,6 +192,7 @@ finish: void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) { + unsigned long asid_mask = cpu_asid_mask(¤t_cpu_data); unsigned long flags; int idx, pid; @@ -199,10 +202,10 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) if (current->active_mm != vma->vm_mm) return; - pid = read_c0_entryhi() & ASID_MASK; + pid = read_c0_entryhi() & asid_mask; #ifdef DEBUG_TLB - if ((pid != (cpu_context(cpu, vma->vm_mm) & ASID_MASK)) || (cpu_context(cpu, vma->vm_mm) == 0)) { + if ((pid != (cpu_context(cpu, vma->vm_mm) & asid_mask)) || (cpu_context(cpu, vma->vm_mm) == 0)) { printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n", (cpu_context(cpu, vma->vm_mm)), pid); } @@ -228,6 +231,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask) { + unsigned long asid_mask = cpu_asid_mask(¤t_cpu_data); unsigned long flags; unsigned long old_ctx; static unsigned long wired = 0; @@ -243,7 +247,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, local_irq_save(flags); /* Save old context and create impossible VPN2 value */ - old_ctx = read_c0_entryhi() & ASID_MASK; + old_ctx = read_c0_entryhi() & asid_mask; old_pagemask = read_c0_pagemask(); w = read_c0_wired(); write_c0_wired(w + 1); @@ -266,7 +270,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, #endif local_irq_save(flags); - old_ctx = read_c0_entryhi() & ASID_MASK; + old_ctx = read_c0_entryhi() & asid_mask; write_c0_entrylo0(entrylo0); write_c0_entryhi(entryhi); write_c0_index(wired); diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 2d93b63..e8b335c 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -28,25 +28,28 @@ extern void build_tlb_refill_handler(void); /* - * LOONGSON2/3 has a 4 entry itlb which is a subset of dtlb, - * unfortunately, itlb is not totally transparent to software. + * LOONGSON-2 has a 4 entry itlb which is a subset of jtlb, LOONGSON-3 has + * a 4 entry itlb and a 4 entry dtlb which are subsets of jtlb. Unfortunately, + * itlb/dtlb are not totally transparent to software. */ -static inline void flush_itlb(void) +static inline void flush_micro_tlb(void) { switch (current_cpu_type()) { case CPU_LOONGSON2: + write_c0_diag(LOONGSON_DIAG_ITLB); + break; case CPU_LOONGSON3: - write_c0_diag(4); + write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB); break; default: break; } } -static inline void flush_itlb_vm(struct vm_area_struct *vma) +static inline void flush_micro_tlb_vm(struct vm_area_struct *vma) { if (vma->vm_flags & VM_EXEC) - flush_itlb(); + flush_micro_tlb(); } void local_flush_tlb_all(void) @@ -93,7 +96,7 @@ void local_flush_tlb_all(void) tlbw_use_hazard(); write_c0_entryhi(old_ctx); htw_start(); - flush_itlb(); + flush_micro_tlb(); local_irq_restore(flags); } EXPORT_SYMBOL(local_flush_tlb_all); @@ -159,7 +162,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, } else { drop_mmu_context(mm, cpu); } - flush_itlb(); + flush_micro_tlb(); local_irq_restore(flags); } } @@ -205,7 +208,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) } else { local_flush_tlb_all(); } - flush_itlb(); + flush_micro_tlb(); local_irq_restore(flags); } @@ -240,7 +243,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) finish: write_c0_entryhi(oldpid); htw_start(); - flush_itlb_vm(vma); + flush_micro_tlb_vm(vma); local_irq_restore(flags); } } @@ -274,7 +277,7 @@ void local_flush_tlb_one(unsigned long page) } write_c0_entryhi(oldpid); htw_start(); - flush_itlb(); + flush_micro_tlb(); local_irq_restore(flags); } @@ -301,7 +304,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) local_irq_save(flags); htw_stop(); - pid = read_c0_entryhi() & ASID_MASK; + pid = read_c0_entryhi() & cpu_asid_mask(¤t_cpu_data); address &= (PAGE_MASK << 1); write_c0_entryhi(address | pid); pgdp = pgd_offset(vma->vm_mm, address); @@ -336,10 +339,12 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) #ifdef CONFIG_XPA write_c0_entrylo0(pte_to_entrylo(ptep->pte_high)); - writex_c0_entrylo0(ptep->pte_low & _PFNX_MASK); + if (cpu_has_xpa) + writex_c0_entrylo0(ptep->pte_low & _PFNX_MASK); ptep++; write_c0_entrylo1(pte_to_entrylo(ptep->pte_high)); - writex_c0_entrylo1(ptep->pte_low & _PFNX_MASK); + if (cpu_has_xpa) + writex_c0_entrylo1(ptep->pte_low & _PFNX_MASK); #else write_c0_entrylo0(ptep->pte_high); ptep++; @@ -357,7 +362,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) } tlbw_use_hazard(); htw_start(); - flush_itlb_vm(vma); + flush_micro_tlb_vm(vma); local_irq_restore(flags); } diff --git a/arch/mips/mm/tlb-r8k.c b/arch/mips/mm/tlb-r8k.c index 138a2ec..e86e2e5 100644 --- a/arch/mips/mm/tlb-r8k.c +++ b/arch/mips/mm/tlb-r8k.c @@ -194,7 +194,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) if (current->active_mm != vma->vm_mm) return; - pid = read_c0_entryhi() & ASID_MASK; + pid = read_c0_entryhi() & cpu_asid_mask(¤t_cpu_data); local_irq_save(flags); address &= PAGE_MASK; diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 84c6e3f..274da90 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -234,20 +234,16 @@ static void output_pgtable_bits_defines(void) pr_debug("\n"); pr_define("_PAGE_PRESENT_SHIFT %d\n", _PAGE_PRESENT_SHIFT); - pr_define("_PAGE_READ_SHIFT %d\n", _PAGE_READ_SHIFT); + pr_define("_PAGE_NO_READ_SHIFT %d\n", _PAGE_NO_READ_SHIFT); pr_define("_PAGE_WRITE_SHIFT %d\n", _PAGE_WRITE_SHIFT); pr_define("_PAGE_ACCESSED_SHIFT %d\n", _PAGE_ACCESSED_SHIFT); pr_define("_PAGE_MODIFIED_SHIFT %d\n", _PAGE_MODIFIED_SHIFT); #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT pr_define("_PAGE_HUGE_SHIFT %d\n", _PAGE_HUGE_SHIFT); #endif -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) - if (cpu_has_rixi) { #ifdef _PAGE_NO_EXEC_SHIFT + if (cpu_has_rixi) pr_define("_PAGE_NO_EXEC_SHIFT %d\n", _PAGE_NO_EXEC_SHIFT); - pr_define("_PAGE_NO_READ_SHIFT %d\n", _PAGE_NO_READ_SHIFT); -#endif - } #endif pr_define("_PAGE_GLOBAL_SHIFT %d\n", _PAGE_GLOBAL_SHIFT); pr_define("_PAGE_VALID_SHIFT %d\n", _PAGE_VALID_SHIFT); @@ -284,7 +280,12 @@ static inline void dump_handler(const char *symbol, const u32 *handler, int coun #define C0_ENTRYLO1 3, 0 #define C0_CONTEXT 4, 0 #define C0_PAGEMASK 5, 0 +#define C0_PWBASE 5, 5 +#define C0_PWFIELD 5, 6 +#define C0_PWSIZE 5, 7 +#define C0_PWCTL 6, 6 #define C0_BADVADDR 8, 0 +#define C0_PGD 9, 7 #define C0_ENTRYHI 10, 0 #define C0_EPC 14, 0 #define C0_XCONTEXT 20, 0 @@ -630,6 +631,11 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l, static __maybe_unused void build_convert_pte_to_entrylo(u32 **p, unsigned int reg) { + if (_PAGE_GLOBAL_SHIFT == 0) { + /* pte_t is already in EntryLo format */ + return; + } + if (cpu_has_rixi && _PAGE_NO_EXEC) { if (fill_includes_sw_bits) { UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL)); @@ -808,7 +814,10 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, if (pgd_reg != -1) { /* pgd is in pgd_reg */ - UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg); + if (cpu_has_ldpte) + UASM_i_MFC0(p, ptr, C0_PWBASE); + else + UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg); } else { #if defined(CONFIG_MIPS_PGD_C0_CONTEXT) /* @@ -1007,39 +1016,40 @@ static void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr) static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep) { - /* - * 64bit address support (36bit on a 32bit CPU) in a 32bit - * Kernel is a special case. Only a few CPUs use it. - */ - if (config_enabled(CONFIG_PHYS_ADDR_T_64BIT) && !cpu_has_64bits) { - int pte_off_even = sizeof(pte_t) / 2; - int pte_off_odd = pte_off_even + sizeof(pte_t); -#ifdef CONFIG_XPA - const int scratch = 1; /* Our extra working register */ + int pte_off_even = 0; + int pte_off_odd = sizeof(pte_t); - uasm_i_addu(p, scratch, 0, ptep); +#if defined(CONFIG_CPU_MIPS32) && defined(CONFIG_PHYS_ADDR_T_64BIT) + /* The low 32 bits of EntryLo is stored in pte_high */ + pte_off_even += offsetof(pte_t, pte_high); + pte_off_odd += offsetof(pte_t, pte_high); #endif + + if (config_enabled(CONFIG_XPA)) { uasm_i_lw(p, tmp, pte_off_even, ptep); /* even pte */ - uasm_i_lw(p, ptep, pte_off_odd, ptep); /* odd pte */ UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); - UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); UASM_i_MTC0(p, tmp, C0_ENTRYLO0); - UASM_i_MTC0(p, ptep, C0_ENTRYLO1); -#ifdef CONFIG_XPA - uasm_i_lw(p, tmp, 0, scratch); - uasm_i_lw(p, ptep, sizeof(pte_t), scratch); - uasm_i_lui(p, scratch, 0xff); - uasm_i_ori(p, scratch, scratch, 0xffff); - uasm_i_and(p, tmp, scratch, tmp); - uasm_i_and(p, ptep, scratch, ptep); - uasm_i_mthc0(p, tmp, C0_ENTRYLO0); - uasm_i_mthc0(p, ptep, C0_ENTRYLO1); -#endif + + if (cpu_has_xpa && !mips_xpa_disabled) { + uasm_i_lw(p, tmp, 0, ptep); + uasm_i_ext(p, tmp, tmp, 0, 24); + uasm_i_mthc0(p, tmp, C0_ENTRYLO0); + } + + uasm_i_lw(p, tmp, pte_off_odd, ptep); /* odd pte */ + UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); + UASM_i_MTC0(p, tmp, C0_ENTRYLO1); + + if (cpu_has_xpa && !mips_xpa_disabled) { + uasm_i_lw(p, tmp, sizeof(pte_t), ptep); + uasm_i_ext(p, tmp, tmp, 0, 24); + uasm_i_mthc0(p, tmp, C0_ENTRYLO1); + } return; } - UASM_i_LW(p, tmp, 0, ptep); /* get even pte */ - UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */ + UASM_i_LW(p, tmp, pte_off_even, ptep); /* get even pte */ + UASM_i_LW(p, ptep, pte_off_odd, ptep); /* get odd pte */ if (r45k_bvahwbug()) build_tlb_probe_entry(p); build_convert_pte_to_entrylo(p, tmp); @@ -1421,6 +1431,108 @@ static void build_r4000_tlb_refill_handler(void) dump_handler("r4000_tlb_refill", (u32 *)ebase, 64); } +static void setup_pw(void) +{ + unsigned long pgd_i, pgd_w; +#ifndef __PAGETABLE_PMD_FOLDED + unsigned long pmd_i, pmd_w; +#endif + unsigned long pt_i, pt_w; + unsigned long pte_i, pte_w; +#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT + unsigned long psn; + + psn = ilog2(_PAGE_HUGE); /* bit used to indicate huge page */ +#endif + pgd_i = PGDIR_SHIFT; /* 1st level PGD */ +#ifndef __PAGETABLE_PMD_FOLDED + pgd_w = PGDIR_SHIFT - PMD_SHIFT + PGD_ORDER; + + pmd_i = PMD_SHIFT; /* 2nd level PMD */ + pmd_w = PMD_SHIFT - PAGE_SHIFT; +#else + pgd_w = PGDIR_SHIFT - PAGE_SHIFT + PGD_ORDER; +#endif + + pt_i = PAGE_SHIFT; /* 3rd level PTE */ + pt_w = PAGE_SHIFT - 3; + + pte_i = ilog2(_PAGE_GLOBAL); + pte_w = 0; + +#ifndef __PAGETABLE_PMD_FOLDED + write_c0_pwfield(pgd_i << 24 | pmd_i << 12 | pt_i << 6 | pte_i); + write_c0_pwsize(1 << 30 | pgd_w << 24 | pmd_w << 12 | pt_w << 6 | pte_w); +#else + write_c0_pwfield(pgd_i << 24 | pt_i << 6 | pte_i); + write_c0_pwsize(1 << 30 | pgd_w << 24 | pt_w << 6 | pte_w); +#endif + +#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT + write_c0_pwctl(1 << 6 | psn); +#endif + write_c0_kpgd(swapper_pg_dir); + kscratch_used_mask |= (1 << 7); /* KScratch6 is used for KPGD */ +} + +static void build_loongson3_tlb_refill_handler(void) +{ + u32 *p = tlb_handler; + struct uasm_label *l = labels; + struct uasm_reloc *r = relocs; + + memset(labels, 0, sizeof(labels)); + memset(relocs, 0, sizeof(relocs)); + memset(tlb_handler, 0, sizeof(tlb_handler)); + + if (check_for_high_segbits) { + uasm_i_dmfc0(&p, K0, C0_BADVADDR); + uasm_i_dsrl_safe(&p, K1, K0, PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3); + uasm_il_beqz(&p, &r, K1, label_vmalloc); + uasm_i_nop(&p); + + uasm_il_bgez(&p, &r, K0, label_large_segbits_fault); + uasm_i_nop(&p); + uasm_l_vmalloc(&l, p); + } + + uasm_i_dmfc0(&p, K1, C0_PGD); + + uasm_i_lddir(&p, K0, K1, 3); /* global page dir */ +#ifndef __PAGETABLE_PMD_FOLDED + uasm_i_lddir(&p, K1, K0, 1); /* middle page dir */ +#endif + uasm_i_ldpte(&p, K1, 0); /* even */ + uasm_i_ldpte(&p, K1, 1); /* odd */ + uasm_i_tlbwr(&p); + + /* restore page mask */ + if (PM_DEFAULT_MASK >> 16) { + uasm_i_lui(&p, K0, PM_DEFAULT_MASK >> 16); + uasm_i_ori(&p, K0, K0, PM_DEFAULT_MASK & 0xffff); + uasm_i_mtc0(&p, K0, C0_PAGEMASK); + } else if (PM_DEFAULT_MASK) { + uasm_i_ori(&p, K0, 0, PM_DEFAULT_MASK); + uasm_i_mtc0(&p, K0, C0_PAGEMASK); + } else { + uasm_i_mtc0(&p, 0, C0_PAGEMASK); + } + + uasm_i_eret(&p); + + if (check_for_high_segbits) { + uasm_l_large_segbits_fault(&l, p); + UASM_i_LA(&p, K1, (unsigned long)tlb_do_page_fault_0); + uasm_i_jr(&p, K1); + uasm_i_nop(&p); + } + + uasm_resolve_relocs(relocs, labels); + memcpy((void *)(ebase + 0x80), tlb_handler, 0x80); + local_flush_icache_range(ebase + 0x80, ebase + 0x100); + dump_handler("loongson3_tlb_refill", (u32 *)(ebase + 0x80), 32); +} + extern u32 handle_tlbl[], handle_tlbl_end[]; extern u32 handle_tlbs[], handle_tlbs_end[]; extern u32 handle_tlbm[], handle_tlbm_end[]; @@ -1468,7 +1580,10 @@ static void build_setup_pgd(void) } else { /* PGD in c0_KScratch */ uasm_i_jr(&p, 31); - UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); + if (cpu_has_ldpte) + UASM_i_MTC0(&p, a0, C0_PWBASE); + else + UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); } #else #ifdef CONFIG_SMP @@ -1523,19 +1638,19 @@ iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) static void iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, - unsigned int mode) + unsigned int mode, unsigned int scratch) { -#ifdef CONFIG_PHYS_ADDR_T_64BIT unsigned int hwmode = mode & (_PAGE_VALID | _PAGE_DIRTY); + unsigned int swmode = mode & ~hwmode; - if (!cpu_has_64bits) { - const int scratch = 1; /* Our extra working register */ - - uasm_i_lui(p, scratch, (mode >> 16)); + if (config_enabled(CONFIG_XPA) && !cpu_has_64bits) { + uasm_i_lui(p, scratch, swmode >> 16); uasm_i_or(p, pte, pte, scratch); - } else -#endif - uasm_i_ori(p, pte, pte, mode); + BUG_ON(swmode & 0xffff); + } else { + uasm_i_ori(p, pte, pte, mode); + } + #ifdef CONFIG_SMP # ifdef CONFIG_PHYS_ADDR_T_64BIT if (cpu_has_64bits) @@ -1554,6 +1669,7 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, /* no uasm_i_nop needed */ uasm_i_ll(p, pte, sizeof(pte_t) / 2, ptr); uasm_i_ori(p, pte, pte, hwmode); + BUG_ON(hwmode & ~0xffff); uasm_i_sc(p, pte, sizeof(pte_t) / 2, ptr); uasm_il_beqz(p, r, pte, label_smp_pgtable_change); /* no uasm_i_nop needed */ @@ -1575,6 +1691,7 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, if (!cpu_has_64bits) { uasm_i_lw(p, pte, sizeof(pte_t) / 2, ptr); uasm_i_ori(p, pte, pte, hwmode); + BUG_ON(hwmode & ~0xffff); uasm_i_sw(p, pte, sizeof(pte_t) / 2, ptr); uasm_i_lw(p, pte, 0, ptr); } @@ -1615,9 +1732,8 @@ build_pte_present(u32 **p, struct uasm_reloc **r, cur = t; } uasm_i_andi(p, t, cur, - (_PAGE_PRESENT | _PAGE_READ) >> _PAGE_PRESENT_SHIFT); - uasm_i_xori(p, t, t, - (_PAGE_PRESENT | _PAGE_READ) >> _PAGE_PRESENT_SHIFT); + (_PAGE_PRESENT | _PAGE_NO_READ) >> _PAGE_PRESENT_SHIFT); + uasm_i_xori(p, t, t, _PAGE_PRESENT >> _PAGE_PRESENT_SHIFT); uasm_il_bnez(p, r, t, lid); if (pte == t) /* You lose the SMP race :-(*/ @@ -1628,11 +1744,11 @@ build_pte_present(u32 **p, struct uasm_reloc **r, /* Make PTE valid, store result in PTR. */ static void build_make_valid(u32 **p, struct uasm_reloc **r, unsigned int pte, - unsigned int ptr) + unsigned int ptr, unsigned int scratch) { unsigned int mode = _PAGE_VALID | _PAGE_ACCESSED; - iPTE_SW(p, r, pte, ptr, mode); + iPTE_SW(p, r, pte, ptr, mode, scratch); } /* @@ -1668,12 +1784,12 @@ build_pte_writable(u32 **p, struct uasm_reloc **r, */ static void build_make_write(u32 **p, struct uasm_reloc **r, unsigned int pte, - unsigned int ptr) + unsigned int ptr, unsigned int scratch) { unsigned int mode = (_PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY); - iPTE_SW(p, r, pte, ptr, mode); + iPTE_SW(p, r, pte, ptr, mode, scratch); } /* @@ -1778,7 +1894,7 @@ static void build_r3000_tlb_load_handler(void) build_r3000_tlbchange_handler_head(&p, K0, K1); build_pte_present(&p, &r, K0, K1, -1, label_nopage_tlbl); uasm_i_nop(&p); /* load delay */ - build_make_valid(&p, &r, K0, K1); + build_make_valid(&p, &r, K0, K1, -1); build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); uasm_l_nopage_tlbl(&l, p); @@ -1809,7 +1925,7 @@ static void build_r3000_tlb_store_handler(void) build_r3000_tlbchange_handler_head(&p, K0, K1); build_pte_writable(&p, &r, K0, K1, -1, label_nopage_tlbs); uasm_i_nop(&p); /* load delay */ - build_make_write(&p, &r, K0, K1); + build_make_write(&p, &r, K0, K1, -1); build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); uasm_l_nopage_tlbs(&l, p); @@ -1840,7 +1956,7 @@ static void build_r3000_tlb_modify_handler(void) build_r3000_tlbchange_handler_head(&p, K0, K1); build_pte_modifiable(&p, &r, K0, K1, -1, label_nopage_tlbm); uasm_i_nop(&p); /* load delay */ - build_make_write(&p, &r, K0, K1); + build_make_write(&p, &r, K0, K1, -1); build_r3000_pte_reload_tlbwi(&p, K0, K1); uasm_l_nopage_tlbm(&l, p); @@ -2008,7 +2124,7 @@ static void build_r4000_tlb_load_handler(void) } uasm_l_tlbl_goaround1(&l, p); } - build_make_valid(&p, &r, wr.r1, wr.r2); + build_make_valid(&p, &r, wr.r1, wr.r2, wr.r3); build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2); #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT @@ -2122,7 +2238,7 @@ static void build_r4000_tlb_store_handler(void) build_pte_writable(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbs); if (m4kc_tlbp_war()) build_tlb_probe_entry(&p); - build_make_write(&p, &r, wr.r1, wr.r2); + build_make_write(&p, &r, wr.r1, wr.r2, wr.r3); build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2); #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT @@ -2178,7 +2294,7 @@ static void build_r4000_tlb_modify_handler(void) if (m4kc_tlbp_war()) build_tlb_probe_entry(&p); /* Present and writable bits set, set accessed and dirty bits. */ - build_make_write(&p, &r, wr.r1, wr.r2); + build_make_write(&p, &r, wr.r1, wr.r2, wr.r3); build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2); #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT @@ -2311,9 +2427,7 @@ static void config_htw_params(void) if (CONFIG_PGTABLE_LEVELS >= 3) pwsize |= ilog2(PTRS_PER_PMD) << MIPS_PWSIZE_MDW_SHIFT; - /* If XPA has been enabled, PTEs are 64-bit in size. */ - if (config_enabled(CONFIG_64BITS) || (read_c0_pagegrain() & PG_ELPA)) - pwsize |= 1; + pwsize |= ilog2(sizeof(pte_t)/4) << MIPS_PWSIZE_PTEW_SHIFT; write_c0_pwsize(pwsize); @@ -2394,6 +2508,9 @@ void build_tlb_refill_handler(void) */ static int run_once = 0; + if (config_enabled(CONFIG_XPA) && !cpu_has_rixi) + panic("Kernels supporting XPA currently require CPUs with RIXI"); + output_pgtable_bits_defines(); check_pabits(); @@ -2437,13 +2554,18 @@ void build_tlb_refill_handler(void) break; default: + if (cpu_has_ldpte) + setup_pw(); + if (!run_once) { scratch_reg = allocate_kscratch(); build_setup_pgd(); build_r4000_tlb_load_handler(); build_r4000_tlb_store_handler(); build_r4000_tlb_modify_handler(); - if (!cpu_has_local_ebase) + if (cpu_has_ldpte) + build_loongson3_tlb_refill_handler(); + else if (!cpu_has_local_ebase) build_r4000_tlb_refill_handler(); flush_tlb_handlers(); run_once++; diff --git a/arch/mips/mm/uasm-mips.c b/arch/mips/mm/uasm-mips.c index b4a83789..9c2220a 100644 --- a/arch/mips/mm/uasm-mips.c +++ b/arch/mips/mm/uasm-mips.c @@ -153,6 +153,8 @@ static struct insn insn_table[] = { { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, { insn_yield, M(spec3_op, 0, 0, 0, 0, yield_op), RS | RD }, + { insn_ldpte, M(lwc2_op, 0, 0, 0, ldpte_op, mult_op), RS | RD }, + { insn_lddir, M(lwc2_op, 0, 0, 0, lddir_op, mult_op), RS | RT | RD }, { insn_invalid, 0, 0 } }; diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 319051c..ad718de 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -60,6 +60,7 @@ enum opcode { insn_sltiu, insn_sltu, insn_sra, insn_srl, insn_srlv, insn_subu, insn_sw, insn_sync, insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait, insn_wsbh, insn_xor, insn_xori, insn_yield, + insn_lddir, insn_ldpte, }; struct insn { @@ -335,6 +336,8 @@ I_u1u2s3(_bbit0); I_u1u2s3(_bbit1); I_u3u1u2(_lwx) I_u3u1u2(_ldx) +I_u1u2(_ldpte) +I_u2u1u3(_lddir) #ifdef CONFIG_CPU_CAVIUM_OCTEON #include <asm/octeon/octeon.h> diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c index 4740c82..33d5ff5 100644 --- a/arch/mips/mti-malta/malta-setup.c +++ b/arch/mips/mti-malta/malta-setup.c @@ -248,10 +248,15 @@ static void __init bonito_quirks_setup(void) #endif } +void __init *plat_get_fdt(void) +{ + return (void *)__dtb_start; +} + void __init plat_mem_setup(void) { unsigned int i; - void *fdt = __dtb_start; + void *fdt = plat_get_fdt(); fdt = malta_dt_shim(fdt); __dt_setup_arch(fdt); diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index b7bf721..7407da0 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -21,6 +21,7 @@ #include <linux/i8253.h> #include <linux/init.h> #include <linux/kernel_stat.h> +#include <linux/math64.h> #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/interrupt.h> @@ -72,6 +73,8 @@ static void __init estimate_frequencies(void) { unsigned long flags; unsigned int count, start; + unsigned char secs1, secs2, ctrl; + int secs; cycle_t giccount = 0, gicstart = 0; #if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ @@ -81,32 +84,51 @@ static void __init estimate_frequencies(void) local_irq_save(flags); - /* Start counter exactly on falling edge of update flag. */ + if (gic_present) + gic_start_count(); + + /* + * Read counters exactly on rising edge of update flag. + * This helps get an accurate reading under virtualisation. + */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - - /* Initialize counters. */ start = read_c0_count(); - if (gic_present) { - gic_start_count(); + if (gic_present) gicstart = gic_read_count(); - } - /* Read counter exactly on falling edge of update flag. */ + /* Wait for falling edge before reading RTC. */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); - while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + secs1 = CMOS_READ(RTC_SECONDS); + /* Read counters again exactly on rising edge of update flag. */ + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); count = read_c0_count(); if (gic_present) giccount = gic_read_count(); + /* Wait for falling edge before reading RTC again. */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + secs2 = CMOS_READ(RTC_SECONDS); + + ctrl = CMOS_READ(RTC_CONTROL); + local_irq_restore(flags); + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + secs1 = bcd2bin(secs1); + secs2 = bcd2bin(secs2); + } + secs = secs2 - secs1; + if (secs < 1) + secs += 60; + count -= start; + count /= secs; mips_hpt_frequency = count; if (gic_present) { - giccount -= gicstart; + giccount = div_u64(giccount - gicstart, secs); gic_frequency = giccount; } } diff --git a/arch/mips/mti-sead3/sead3-setup.c b/arch/mips/mti-sead3/sead3-setup.c index e43f480..9f2f9b2 100644 --- a/arch/mips/mti-sead3/sead3-setup.c +++ b/arch/mips/mti-sead3/sead3-setup.c @@ -83,6 +83,11 @@ static void __init parse_memsize_param(void) } } +void __init *plat_get_fdt(void) +{ + return (void *)__dtb_start; +} + void __init plat_mem_setup(void) { /* allow command line/bootloader env to override memory size in DT */ diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S index edbab9b..c474981 100644 --- a/arch/mips/netlogic/common/reset.S +++ b/arch/mips/netlogic/common/reset.S @@ -50,7 +50,6 @@ #include <asm/netlogic/xlp-hal/sys.h> #include <asm/netlogic/xlp-hal/cpucontrol.h> -#define CP0_EBASE $15 #define SYS_CPU_COHERENT_BASE CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \ SYS_CPU_NONCOHERENT_MODE * 4 @@ -92,7 +91,7 @@ * registers. On XLPII CPUs, usual cache instructions work. */ .macro xlp_flush_l1_dcache - mfc0 t0, CP0_EBASE, 0 + mfc0 t0, CP0_PRID andi t0, t0, PRID_IMP_MASK slt t1, t0, 0x1200 beqz t1, 15f @@ -171,7 +170,7 @@ FEXPORT(nlm_reset_entry) nop 1: /* Entry point on core wakeup */ - mfc0 t0, CP0_EBASE, 0 /* processor ID */ + mfc0 t0, CP0_PRID /* processor ID */ andi t0, PRID_IMP_MASK li t1, 0x1500 /* XLP 9xx */ beq t0, t1, 2f /* does not need to set coherent */ @@ -182,8 +181,8 @@ FEXPORT(nlm_reset_entry) nop /* set bit in SYS coherent register for the core */ - mfc0 t0, CP0_EBASE, 1 - mfc0 t1, CP0_EBASE, 1 + mfc0 t0, CP0_EBASE + mfc0 t1, CP0_EBASE srl t1, 5 andi t1, 0x3 /* t1 <- node */ li t2, 0x40000 @@ -232,7 +231,7 @@ EXPORT(nlm_boot_siblings) * NOTE: All GPR contents are lost after the mtcr above! */ - mfc0 v0, CP0_EBASE, 1 + mfc0 v0, CP0_EBASE andi v0, 0x3ff /* v0 <- node/core */ /* diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index 805355b..f0cc4c9 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -48,8 +48,6 @@ #include <asm/netlogic/xlp-hal/sys.h> #include <asm/netlogic/xlp-hal/cpucontrol.h> -#define CP0_EBASE $15 - .set noreorder .set noat .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ @@ -86,7 +84,7 @@ NESTED(nlm_boot_secondary_cpus, 16, sp) PTR_L gp, 0(t1) /* a0 has the processor id */ - mfc0 a0, CP0_EBASE, 1 + mfc0 a0, CP0_EBASE andi a0, 0x3ff /* a0 <- node/core */ PTR_LA t0, nlm_early_init_secondary jalr t0 diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index 80ec929..25ee694 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -58,7 +58,7 @@ void nlm_node_init(int node) nodep->coremask = 1; /* node 0, boot cpu */ nodep->sysbase = nlm_get_sys_regbase(node); nodep->picbase = nlm_get_pic_regbase(node); - nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); + nodep->ebase = read_c0_ebase() & MIPS_EBASE_BASE; if (cpu_is_xlp9xx()) nodep->socbus = xlp9xx_get_socbus(node); else diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c index d118b9a..72ceddc 100644 --- a/arch/mips/netlogic/xlr/setup.c +++ b/arch/mips/netlogic/xlr/setup.c @@ -168,7 +168,7 @@ static void nlm_init_node(void) nodep = nlm_current_node(); nodep->picbase = nlm_mmio_base(NETLOGIC_IO_PIC_OFFSET); - nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); + nodep->ebase = read_c0_ebase() & MIPS_EBASE_BASE; spin_lock_init(&nodep->piclock); } diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index 3c9ec3d..2f33992 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -77,7 +77,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) struct op_mips_model *lmodel = NULL; int res; - switch (current_cpu_type()) { + switch (boot_cpu_type()) { case CPU_5KC: case CPU_M14KC: case CPU_M14KEC: diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 8f988a6..45cb274 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -269,11 +269,9 @@ static int mipsxx_perfcount_handler(void) return handled; } -#define M_CONFIG1_PC (1 << 4) - static inline int __n_counters(void) { - if (!(read_c0_config1() & M_CONFIG1_PC)) + if (!cpu_has_perf) return 0; if (!(read_c0_perfctrl0() & M_PERFCTL_MORE)) return 1; diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c index c2ce41e..2b5427d 100644 --- a/arch/mips/pci/fixup-lantiq.c +++ b/arch/mips/pci/fixup-lantiq.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/of_irq.h> diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c index e5738ee..f51e108 100644 --- a/arch/mips/pci/ops-lantiq.c +++ b/arch/mips/pci/ops-lantiq.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/types.h> diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c index 2895263..c8994c1 100644 --- a/arch/mips/pci/pci-alchemy.c +++ b/arch/mips/pci/pci-alchemy.c @@ -76,7 +76,7 @@ static void mod_wired_entry(int entry, unsigned long entrylo0, unsigned long old_ctx; /* Save old context and create impossible VPN2 value */ - old_ctx = read_c0_entryhi() & 0xff; + old_ctx = read_c0_entryhi() & MIPS_ENTRYHI_ASID; old_pagemask = read_c0_pagemask(); write_c0_index(entry); write_c0_pagemask(pagemask); diff --git a/arch/mips/pci/pci-ip32.c b/arch/mips/pci/pci-ip32.c index b1e061f..7ae89d0 100644 --- a/arch/mips/pci/pci-ip32.c +++ b/arch/mips/pci/pci-ip32.c @@ -116,7 +116,6 @@ static struct pci_controller mace_pci_controller = { .pci_ops = &mace_pci_ops, .mem_resource = &mace_pci_mem_resource, .io_resource = &mace_pci_io_resource, - .iommu = 0, .mem_offset = MACE_PCI_MEM_OFFSET, .io_offset = 0, .io_map_base = CKSEG1ADDR(MACEPCI_LOW_IO), diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index 6a15dbd..b9deab1 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/types.h> diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h index 66bf6cd..0cc7125 100644 --- a/arch/mips/pci/pci-lantiq.h +++ b/arch/mips/pci/pci-lantiq.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_PCI_H__ diff --git a/arch/mips/pci/pci-mt7620.c b/arch/mips/pci/pci-mt7620.c index 1ae932c2..6ce8162 100644 --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c @@ -2,7 +2,7 @@ * Ralink MT7620A SoC PCI support * * Copyright (C) 2007-2013 Bruce Chang (Mediatek) - * Copyright (C) 2013-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013-2016 John Crispin <john@phrozen.org> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c index a245cad..f2a1050 100644 --- a/arch/mips/pci/pci-rt2880.c +++ b/arch/mips/pci/pci-rt2880.c @@ -1,7 +1,7 @@ /* * Ralink RT288x SoC PCI register definitions * - * Copyright (C) 2009 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009 John Crispin <john@phrozen.org> * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> * * Parts of this file are based on Ralink's 2.6.21 BSP diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index b8a0bf5..f1b11f0 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -83,9 +83,6 @@ static void pcibios_scanbus(struct pci_controller *hose) LIST_HEAD(resources); struct pci_bus *bus; - if (!hose->iommu) - PCI_DMA_BUS_IS_PHYS = 1; - if (hose->get_busno && pci_has_flag(PCI_PROBE_ONLY)) next_busno = (*hose->get_busno)(); diff --git a/arch/mips/pic32/pic32mzda/time.c b/arch/mips/pic32/pic32mzda/time.c index ca6a62b..62a0a78 100644 --- a/arch/mips/pic32/pic32mzda/time.c +++ b/arch/mips/pic32/pic32mzda/time.c @@ -11,13 +11,12 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ -#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/clocksource.h> #include <linux/init.h> +#include <linux/irqdomain.h> #include <linux/of.h> #include <linux/of_irq.h> -#include <linux/irqdomain.h> #include <asm/time.h> @@ -58,16 +57,12 @@ unsigned int get_c0_compare_int(void) void __init plat_time_init(void) { - struct clk *clk; + unsigned long rate = pic32_get_pbclk(7); of_clk_init(NULL); - clk = clk_get_sys("cpu_clk", NULL); - if (IS_ERR(clk)) - panic("unable to get CPU clock, err=%ld", PTR_ERR(clk)); - clk_prepare_enable(clk); - pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); - mips_hpt_frequency = clk_get_rate(clk) / 2; + pr_info("CPU Clock: %ldMHz\n", rate / 1000000); + mips_hpt_frequency = rate / 2; clocksource_probe(); } diff --git a/arch/mips/pistachio/init.c b/arch/mips/pistachio/init.c index 96ba2cc..956c92e 100644 --- a/arch/mips/pistachio/init.c +++ b/arch/mips/pistachio/init.c @@ -2,6 +2,7 @@ * Pistachio platform setup * * Copyright (C) 2014 Google, Inc. + * Copyright (C) 2016 Imagination Technologies * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -9,6 +10,7 @@ */ #include <linux/init.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/of_address.h> #include <linux/of_fdt.h> @@ -24,9 +26,38 @@ #include <asm/smp-ops.h> #include <asm/traps.h> +/* + * Core revision register decoding + * Bits 23 to 20: Major rev + * Bits 15 to 8: Minor rev + * Bits 7 to 0: Maintenance rev + */ +#define PISTACHIO_CORE_REV_REG 0xB81483D0 +#define PISTACHIO_CORE_REV_A1 0x00100006 +#define PISTACHIO_CORE_REV_B0 0x00100106 + const char *get_system_type(void) { - return "IMG Pistachio SoC"; + u32 core_rev; + const char *sys_type; + + core_rev = __raw_readl((const void *)PISTACHIO_CORE_REV_REG); + + switch (core_rev) { + case PISTACHIO_CORE_REV_B0: + sys_type = "IMG Pistachio SoC (B0)"; + break; + + case PISTACHIO_CORE_REV_A1: + sys_type = "IMG Pistachio SoC (A1)"; + break; + + default: + sys_type = "IMG Pistachio SoC"; + break; + } + + return sys_type; } static void __init plat_setup_iocoherency(void) @@ -109,6 +140,8 @@ void __init prom_init(void) mips_cm_probe(); mips_cpc_probe(); register_cps_smp_ops(); + + pr_info("SoC Type: %s\n", get_system_type()); } void __init prom_free_prom_memory(void) diff --git a/arch/mips/pmcs-msp71xx/msp_setup.c b/arch/mips/pmcs-msp71xx/msp_setup.c index 9d293b3..a63b736 100644 --- a/arch/mips/pmcs-msp71xx/msp_setup.c +++ b/arch/mips/pmcs-msp71xx/msp_setup.c @@ -118,7 +118,7 @@ void msp_restart(char *command) /* No chip-specific reset code, just jump to the ROM reset vector */ set_c0_status(ST0_BEV | ST0_ERL); change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); - flush_cache_all(); + __flush_cache_all(); write_c0_wired(0); __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); diff --git a/arch/mips/pnx833x/common/setup.c b/arch/mips/pnx833x/common/setup.c index 99b4d94..8a7443b 100644 --- a/arch/mips/pnx833x/common/setup.c +++ b/arch/mips/pnx833x/common/setup.c @@ -38,9 +38,6 @@ extern void pnx833x_machine_power_off(void); int __init plat_mem_setup(void) { - /* fake pci bus to avoid bounce buffers */ - PCI_DMA_BUS_IS_PHYS = 1; - /* set mips clock to 320MHz */ #if defined(CONFIG_SOC_PNX8335) PNX8335_WRITEFIELD(0x17, CLOCK_PLL_CPU_CTL, FREQ); diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile index 0d1795a..fe34715 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile @@ -4,7 +4,7 @@ # Makefile for the Ralink common stuff # # Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> -# Copyright (C) 2013 John Crispin <blogic@openwrt.org> +# Copyright (C) 2013 John Crispin <john@phrozen.org> obj-y := prom.o of.o reset.o diff --git a/arch/mips/ralink/bootrom.c b/arch/mips/ralink/bootrom.c index 5403468..e1fa597 100644 --- a/arch/mips/ralink/bootrom.c +++ b/arch/mips/ralink/bootrom.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/debugfs.h> diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c index e46f91f..3ad0b07 100644 --- a/arch/mips/ralink/cevt-rt3352.c +++ b/arch/mips/ralink/cevt-rt3352.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2013 by John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 by John Crispin <john@phrozen.org> */ #include <linux/clockchips.h> diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c index 25c4a61..ebaa7cc 100644 --- a/arch/mips/ralink/clk.c +++ b/arch/mips/ralink/clk.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h index 8e7d8e6..b8245d0 100644 --- a/arch/mips/ralink/common.h +++ b/arch/mips/ralink/common.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #ifndef _RALINK_COMMON_H__ diff --git a/arch/mips/ralink/ill_acc.c b/arch/mips/ralink/ill_acc.c index e10d10b..765d5ba 100644 --- a/arch/mips/ralink/ill_acc.c +++ b/arch/mips/ralink/ill_acc.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/interrupt.h> diff --git a/arch/mips/ralink/irq-gic.c b/arch/mips/ralink/irq-gic.c index 50d6c55..2058280 100644 --- a/arch/mips/ralink/irq-gic.c +++ b/arch/mips/ralink/irq-gic.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2015 Nikolay Martynov <mar.kolya@gmail.com> - * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2015 John Crispin <john@phrozen.org> */ #include <linux/init.h> diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c index 4cf77f3..4911c14 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/io.h> diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index 0d3d1a9..88b82fe 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> @@ -581,11 +581,14 @@ void prom_soc_init(struct ralink_soc_info *soc_info) (rev & CHIP_REV_ECO_MASK)); cfg0 = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG0); - if (is_mt76x8()) + if (is_mt76x8()) { dram_type = cfg0 & DRAM_TYPE_MT7628_MASK; - else + } else { dram_type = (cfg0 >> SYSCFG0_DRAM_TYPE_SHIFT) & SYSCFG0_DRAM_TYPE_MASK; + if (dram_type == SYSCFG0_DRAM_TYPE_UNKNOWN) + dram_type = SYSCFG0_DRAM_TYPE_SDRAM; + } soc_info->mem_base = MT7620_DRAM_BASE; if (is_mt76x8()) diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c index e9b9fa3..a45bbbe 100644 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2015 Nikolay Martynov <mar.kolya@gmail.com> - * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2015 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c index f9eda5d..0aa67a2 100644 --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c @@ -5,7 +5,7 @@ * * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/io.h> diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c index 39a9142f..5a73c5e 100644 --- a/arch/mips/ralink/prom.c +++ b/arch/mips/ralink/prom.c @@ -5,7 +5,7 @@ * * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2010 Joonas Lahtinen <joonas.lahtinen@gmail.com> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/string.h> diff --git a/arch/mips/ralink/reset.c b/arch/mips/ralink/reset.c index ee117c4..64543d6 100644 --- a/arch/mips/ralink/reset.c +++ b/arch/mips/ralink/reset.c @@ -5,7 +5,7 @@ * * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/pm.h> @@ -61,7 +61,7 @@ static int ralink_reset_device(struct reset_controller_dev *rcdev, return ralink_deassert_device(rcdev, id); } -static struct reset_control_ops reset_ops = { +static const struct reset_control_ops reset_ops = { .reset = ralink_reset_device, .assert = ralink_assert_device, .deassert = ralink_deassert_device, diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index 3c84166..285796e 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index d7c4ba4..c8a28c4b 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index fafec94..4cef916 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -7,7 +7,7 @@ * * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/timer-gic.c b/arch/mips/ralink/timer-gic.c index 5b4f186..069771d 100644 --- a/arch/mips/ralink/timer-gic.c +++ b/arch/mips/ralink/timer-gic.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2015 Nikolay Martynov <mar.kolya@gmail.com> - * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2015 John Crispin <john@phrozen.org> */ #include <linux/init.h> diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c index 82c72a1..b0343ff 100644 --- a/arch/mips/ralink/timer.c +++ b/arch/mips/ralink/timer.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/module.h> @@ -180,5 +180,5 @@ static struct platform_driver rt_timer_driver = { module_platform_driver(rt_timer_driver); MODULE_DESCRIPTION("Ralink RT2880 timer"); -MODULE_AUTHOR("John Crispin <blogic@openwrt.org"); +MODULE_AUTHOR("John Crispin <john@phrozen.org"); MODULE_LICENSE("GPL"); diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig index cb9a095..707b884 100644 --- a/arch/mips/sibyte/Kconfig +++ b/arch/mips/sibyte/Kconfig @@ -143,7 +143,8 @@ config SIBYTE_CFE_CONSOLE config SIBYTE_BUS_WATCHER bool "Support for Bus Watcher statistics" depends on SIBYTE_SB1xxx_SOC && \ - (SIBYTE_BCM112X || SIBYTE_SB1250) + (SIBYTE_BCM112X || SIBYTE_SB1250 || \ + SIBYTE_BCM1x55 || SIBYTE_BCM1x80) help Handle and keep statistics on the bus error interrupts (COR_ECC, BAD_ECC, IO_BUS). diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index ee3617c..b369509 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -50,13 +50,17 @@ quiet_cmd_vdsold = VDSO $@ cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \ -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@ +# Strip rule for the raw .so files +$(obj)/%.so.raw: OBJCOPYFLAGS := -S +$(obj)/%.so.raw: $(obj)/%.so.dbg.raw FORCE + $(call if_changed,objcopy) + hostprogs-y := genvdso quiet_cmd_genvdso = GENVDSO $@ define cmd_genvdso - cp $< $(<:%.dbg=%) && \ - $(OBJCOPY) -S $< $(<:%.dbg=%) && \ - $(obj)/genvdso $< $(<:%.dbg=%) $@ $(VDSO_NAME) + $(foreach file,$(filter %.raw,$^),cp $(file) $(file:%.raw=%) &&) \ + $(obj)/genvdso $(<:%.raw=%) $(<:%.dbg.raw=%) $@ $(VDSO_NAME) endef # @@ -66,7 +70,10 @@ endef native-abi := $(filter -mabi=%,$(KBUILD_CFLAGS)) targets += $(obj-vdso-y) -targets += vdso.lds vdso.so.dbg vdso.so vdso-image.c +targets += vdso.lds +targets += vdso.so.dbg.raw vdso.so.raw +targets += vdso.so.dbg vdso.so +targets += vdso-image.c obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o) @@ -75,10 +82,11 @@ $(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi) $(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi) -$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE +$(obj)/vdso.so.dbg.raw: $(obj)/vdso.lds $(obj-vdso) FORCE $(call if_changed,vdsold) -$(obj)/vdso-image.c: $(obj)/vdso.so.dbg $(obj)/genvdso FORCE +$(obj)/vdso-image.c: $(obj)/vdso.so.dbg.raw $(obj)/vdso.so.raw \ + $(obj)/genvdso FORCE $(call if_changed,genvdso) obj-y += vdso-image.o @@ -89,7 +97,10 @@ obj-y += vdso-image.o # Define these outside the ifdef to ensure they are picked up by clean. targets += $(obj-vdso-y:%.o=%-o32.o) -targets += vdso-o32.lds vdso-o32.so.dbg vdso-o32.so vdso-o32-image.c +targets += vdso-o32.lds +targets += vdso-o32.so.dbg.raw vdso-o32.so.raw +targets += vdso-o32.so.dbg vdso-o32.so +targets += vdso-o32-image.c ifdef CONFIG_MIPS32_O32 @@ -109,11 +120,12 @@ $(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := -mabi=32 $(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE $(call if_changed_dep,cpp_lds_S) -$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE +$(obj)/vdso-o32.so.dbg.raw: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE $(call if_changed,vdsold) $(obj)/vdso-o32-image.c: VDSO_NAME := o32 -$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg $(obj)/genvdso FORCE +$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg.raw $(obj)/vdso-o32.so.raw \ + $(obj)/genvdso FORCE $(call if_changed,genvdso) obj-y += vdso-o32-image.o @@ -125,7 +137,10 @@ endif # targets += $(obj-vdso-y:%.o=%-n32.o) -targets += vdso-n32.lds vdso-n32.so.dbg vdso-n32.so vdso-n32-image.c +targets += vdso-n32.lds +targets += vdso-n32.so.dbg.raw vdso-n32.so.raw +targets += vdso-n32.so.dbg vdso-n32.so +targets += vdso-n32-image.c ifdef CONFIG_MIPS32_N32 @@ -145,11 +160,12 @@ $(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := -mabi=n32 $(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE $(call if_changed_dep,cpp_lds_S) -$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE +$(obj)/vdso-n32.so.dbg.raw: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE $(call if_changed,vdsold) $(obj)/vdso-n32-image.c: VDSO_NAME := n32 -$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg $(obj)/genvdso FORCE +$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg.raw $(obj)/vdso-n32.so.raw \ + $(obj)/genvdso FORCE $(call if_changed,genvdso) obj-y += vdso-n32-image.o diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c index d7f7558..39a0db3 100644 --- a/arch/mips/vr41xx/common/pmu.c +++ b/arch/mips/vr41xx/common/pmu.c @@ -73,7 +73,7 @@ static inline void software_reset(void) default: set_c0_status(ST0_BEV | ST0_ERL); change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); - flush_cache_all(); + __flush_cache_all(); write_c0_wired(0); __asm__("jr %0"::"r"(0xbfc00000)); break; diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index d7b3431..ec35af3 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -40,6 +40,9 @@ #define KVM_MAX_VCORES NR_CPUS #define KVM_USER_MEM_SLOTS 512 +#include <asm/cputhreads.h> +#define KVM_MAX_VCPU_ID (threads_per_subcore * KVM_MAX_VCORES) + #ifdef CONFIG_KVM_MMIO #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 #endif @@ -113,6 +116,7 @@ struct kvm_vcpu_stat { u32 ext_intr_exits; u32 halt_successful_poll; u32 halt_attempted_poll; + u32 halt_poll_invalid; u32 halt_wakeup; u32 dbell_exits; u32 gdbell_exits; @@ -724,5 +728,6 @@ static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arch_exit(void) {} static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} +static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {} #endif /* __POWERPC_KVM_HOST_H__ */ diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index b34220d..47018fc 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -54,6 +54,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "queue_intr", VCPU_STAT(queue_intr) }, { "halt_successful_poll", VCPU_STAT(halt_successful_poll), }, { "halt_attempted_poll", VCPU_STAT(halt_attempted_poll), }, + { "halt_poll_invalid", VCPU_STAT(halt_poll_invalid) }, { "halt_wakeup", VCPU_STAT(halt_wakeup) }, { "pf_storage", VCPU_STAT(pf_storage) }, { "sp_storage", VCPU_STAT(sp_storage) }, diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 84fb4fc..9324355 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -27,6 +27,7 @@ #include <linux/export.h> #include <linux/fs.h> #include <linux/anon_inodes.h> +#include <linux/cpu.h> #include <linux/cpumask.h> #include <linux/spinlock.h> #include <linux/page-flags.h> diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 95bceca..8129b0d 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -882,6 +882,24 @@ void kvmppc_set_fscr(struct kvm_vcpu *vcpu, u64 fscr) } #endif +static void kvmppc_setup_debug(struct kvm_vcpu *vcpu) +{ + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + u64 msr = kvmppc_get_msr(vcpu); + + kvmppc_set_msr(vcpu, msr | MSR_SE); + } +} + +static void kvmppc_clear_debug(struct kvm_vcpu *vcpu) +{ + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + u64 msr = kvmppc_get_msr(vcpu); + + kvmppc_set_msr(vcpu, msr & ~MSR_SE); + } +} + int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu, unsigned int exit_nr) { @@ -1207,10 +1225,18 @@ program_interrupt: break; #endif case BOOK3S_INTERRUPT_MACHINE_CHECK: - case BOOK3S_INTERRUPT_TRACE: kvmppc_book3s_queue_irqprio(vcpu, exit_nr); r = RESUME_GUEST; break; + case BOOK3S_INTERRUPT_TRACE: + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + run->exit_reason = KVM_EXIT_DEBUG; + r = RESUME_HOST; + } else { + kvmppc_book3s_queue_irqprio(vcpu, exit_nr); + r = RESUME_GUEST; + } + break; default: { ulong shadow_srr1 = vcpu->arch.shadow_srr1; @@ -1479,6 +1505,8 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) goto out; } + kvmppc_setup_debug(vcpu); + /* * Interrupts could be timers for the guest which we have to inject * again, so let's postpone them until we're in the guest and if we @@ -1501,6 +1529,8 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) ret = __kvmppc_vcpu_run(kvm_run, vcpu); + kvmppc_clear_debug(vcpu); + /* No need for kvm_guest_exit. It's done in handle_exit. We also get here with interrupts enabled. */ diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index 46871d5..a75ba38 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -92,7 +92,7 @@ static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level) * we are the only setter, thus concurrent access is undefined * to begin with. */ - if (level == 1 || level == KVM_INTERRUPT_SET_LEVEL) + if ((level == 1 && state->lsi) || level == KVM_INTERRUPT_SET_LEVEL) state->asserted = 1; else if (level == 0 || level == KVM_INTERRUPT_UNSET) { state->asserted = 0; @@ -280,7 +280,7 @@ static inline bool icp_try_update(struct kvmppc_icp *icp, if (!success) goto bail; - XICS_DBG("UPD [%04x] - C:%02x M:%02x PP: %02x PI:%06x R:%d O:%d\n", + XICS_DBG("UPD [%04lx] - C:%02x M:%02x PP: %02x PI:%06x R:%d O:%d\n", icp->server_num, old.cppr, old.mfrr, old.pending_pri, old.xisr, old.need_resend, old.out_ee); @@ -336,7 +336,7 @@ static bool icp_try_to_deliver(struct kvmppc_icp *icp, u32 irq, u8 priority, union kvmppc_icp_state old_state, new_state; bool success; - XICS_DBG("try deliver %#x(P:%#x) to server %#x\n", irq, priority, + XICS_DBG("try deliver %#x(P:%#x) to server %#lx\n", irq, priority, icp->server_num); do { @@ -1174,9 +1174,11 @@ static int xics_get_source(struct kvmppc_xics *xics, long irq, u64 addr) prio = irqp->saved_priority; } val |= prio << KVM_XICS_PRIORITY_SHIFT; - if (irqp->asserted) - val |= KVM_XICS_LEVEL_SENSITIVE | KVM_XICS_PENDING; - else if (irqp->masked_pending || irqp->resend) + if (irqp->lsi) { + val |= KVM_XICS_LEVEL_SENSITIVE; + if (irqp->asserted) + val |= KVM_XICS_PENDING; + } else if (irqp->masked_pending || irqp->resend) val |= KVM_XICS_PENDING; ret = 0; } @@ -1228,9 +1230,13 @@ static int xics_set_source(struct kvmppc_xics *xics, long irq, u64 addr) irqp->priority = prio; irqp->resend = 0; irqp->masked_pending = 0; + irqp->lsi = 0; irqp->asserted = 0; - if ((val & KVM_XICS_PENDING) && (val & KVM_XICS_LEVEL_SENSITIVE)) - irqp->asserted = 1; + if (val & KVM_XICS_LEVEL_SENSITIVE) { + irqp->lsi = 1; + if (val & KVM_XICS_PENDING) + irqp->asserted = 1; + } irqp->exists = 1; arch_spin_unlock(&ics->lock); local_irq_restore(flags); @@ -1249,11 +1255,10 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, return ics_deliver_irq(xics, irq, level); } -int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm, - int irq_source_id, int level, bool line_status) +int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *irq_entry, + struct kvm *kvm, int irq_source_id, + int level, bool line_status) { - if (!level) - return -1; return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi, level, line_status); } diff --git a/arch/powerpc/kvm/book3s_xics.h b/arch/powerpc/kvm/book3s_xics.h index 56ea44f..a46b954 100644 --- a/arch/powerpc/kvm/book3s_xics.h +++ b/arch/powerpc/kvm/book3s_xics.h @@ -39,6 +39,7 @@ struct ics_irq_state { u8 saved_priority; u8 resend; u8 masked_pending; + u8 lsi; /* level-sensitive interrupt */ u8 asserted; /* Only for LSI */ u8 exists; }; diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 4d66f44..4afae69 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -64,6 +64,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "ext_intr", VCPU_STAT(ext_intr_exits) }, { "halt_successful_poll", VCPU_STAT(halt_successful_poll) }, { "halt_attempted_poll", VCPU_STAT(halt_attempted_poll) }, + { "halt_poll_invalid", VCPU_STAT(halt_poll_invalid) }, { "halt_wakeup", VCPU_STAT(halt_wakeup) }, { "doorbell", VCPU_STAT(dbell_exits) }, { "guest doorbell", VCPU_STAT(gdbell_exits) }, diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 6a68730..02416fe 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -800,9 +800,9 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu, } } -int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int rt, unsigned int bytes, - int is_default_endian) +static int __kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, + unsigned int rt, unsigned int bytes, + int is_default_endian, int sign_extend) { int idx, ret; bool host_swabbed; @@ -827,7 +827,7 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, vcpu->arch.mmio_host_swabbed = host_swabbed; vcpu->mmio_needed = 1; vcpu->mmio_is_write = 0; - vcpu->arch.mmio_sign_extend = 0; + vcpu->arch.mmio_sign_extend = sign_extend; idx = srcu_read_lock(&vcpu->kvm->srcu); @@ -844,6 +844,13 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, return EMULATE_DO_MMIO; } + +int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, + unsigned int rt, unsigned int bytes, + int is_default_endian) +{ + return __kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian, 0); +} EXPORT_SYMBOL_GPL(kvmppc_handle_load); /* Same as above, but sign extends */ @@ -851,12 +858,7 @@ int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, unsigned int rt, unsigned int bytes, int is_default_endian) { - int r; - - vcpu->arch.mmio_sign_extend = 1; - r = kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian); - - return r; + return __kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian, 1); } int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 6da41fa..37b9017 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -38,7 +38,7 @@ */ #define KVM_NR_IRQCHIPS 1 #define KVM_IRQCHIP_NUM_PINS 4096 -#define KVM_HALT_POLL_NS_DEFAULT 0 +#define KVM_HALT_POLL_NS_DEFAULT 80000 /* s390-specific vcpu->requests bit members */ #define KVM_REQ_ENABLE_IBS 8 @@ -247,6 +247,7 @@ struct kvm_vcpu_stat { u32 exit_instruction; u32 halt_successful_poll; u32 halt_attempted_poll; + u32 halt_poll_invalid; u32 halt_wakeup; u32 instruction_lctl; u32 instruction_lctlg; @@ -544,10 +545,6 @@ struct kvm_vcpu_arch { struct kvm_s390_local_interrupt local_int; struct hrtimer ckc_timer; struct kvm_s390_pgm_info pgm; - union { - struct cpuid cpu_id; - u64 stidp_data; - }; struct gmap *gmap; struct kvm_guestdbg_info_arch guestdbg; unsigned long pfault_token; @@ -605,7 +602,7 @@ struct kvm_s390_cpu_model { __u64 fac_mask[S390_ARCH_FAC_LIST_SIZE_U64]; /* facility list requested by guest (in dma page) */ __u64 *fac_list; - struct cpuid cpu_id; + u64 cpuid; unsigned short ibc; }; @@ -700,4 +697,6 @@ static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm, static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} +void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu); + #endif diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index bd7893d..e4f6f73 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -69,6 +69,7 @@ struct sclp_info { unsigned int max_cores; unsigned long hsa_size; unsigned long facilities; + unsigned int hmfai; }; extern struct sclp_info sclp; diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h index ec60cf7..1c8f33f 100644 --- a/arch/s390/include/asm/sigp.h +++ b/arch/s390/include/asm/sigp.h @@ -27,6 +27,7 @@ /* SIGP cpu status bits */ +#define SIGP_STATUS_INVALID_ORDER 0x00000002UL #define SIGP_STATUS_CHECK_STOP 0x00000010UL #define SIGP_STATUS_STOPPED 0x00000040UL #define SIGP_STATUS_EXT_CALL_PENDING 0x00000080UL diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index 347fe5a..3b8e99e 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -25,6 +25,7 @@ #define KVM_DEV_FLIC_APF_DISABLE_WAIT 5 #define KVM_DEV_FLIC_ADAPTER_REGISTER 6 #define KVM_DEV_FLIC_ADAPTER_MODIFY 7 +#define KVM_DEV_FLIC_CLEAR_IO_IRQ 8 /* * We can have up to 4*64k pending subchannels + 8 adapter interrupts, * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts. diff --git a/arch/s390/include/uapi/asm/sie.h b/arch/s390/include/uapi/asm/sie.h index 5dbaa72..8fb5d4a 100644 --- a/arch/s390/include/uapi/asm/sie.h +++ b/arch/s390/include/uapi/asm/sie.h @@ -16,14 +16,19 @@ { 0x01, "SIGP sense" }, \ { 0x02, "SIGP external call" }, \ { 0x03, "SIGP emergency signal" }, \ + { 0x04, "SIGP start" }, \ { 0x05, "SIGP stop" }, \ { 0x06, "SIGP restart" }, \ { 0x09, "SIGP stop and store status" }, \ { 0x0b, "SIGP initial cpu reset" }, \ + { 0x0c, "SIGP cpu reset" }, \ { 0x0d, "SIGP set prefix" }, \ { 0x0e, "SIGP store status at address" }, \ { 0x12, "SIGP set architecture" }, \ - { 0x15, "SIGP sense running" } + { 0x13, "SIGP conditional emergency signal" }, \ + { 0x15, "SIGP sense running" }, \ + { 0x16, "SIGP set multithreading"}, \ + { 0x17, "SIGP store additional status ait address"} #define icpt_prog_codes \ { 0x0001, "Prog Operation" }, \ diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 5ea5af3..b190023 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -28,6 +28,7 @@ config KVM select HAVE_KVM_IRQCHIP select HAVE_KVM_IRQFD select HAVE_KVM_IRQ_ROUTING + select HAVE_KVM_INVALID_WAKEUPS select SRCU select KVM_VFIO ---help--- diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 84efc2b..5a80af7 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -977,6 +977,11 @@ no_timer: void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu) { + /* + * We cannot move this into the if, as the CPU might be already + * in kvm_vcpu_block without having the waitqueue set (polling) + */ + vcpu->valid_wakeup = true; if (swait_active(&vcpu->wq)) { /* * The vcpu gave up the cpu voluntarily, mark it as a good @@ -2034,6 +2039,27 @@ static int modify_io_adapter(struct kvm_device *dev, return ret; } +static int clear_io_irq(struct kvm *kvm, struct kvm_device_attr *attr) + +{ + const u64 isc_mask = 0xffUL << 24; /* all iscs set */ + u32 schid; + + if (attr->flags) + return -EINVAL; + if (attr->attr != sizeof(schid)) + return -EINVAL; + if (copy_from_user(&schid, (void __user *) attr->addr, sizeof(schid))) + return -EFAULT; + kfree(kvm_s390_get_io_int(kvm, isc_mask, schid)); + /* + * If userspace is conforming to the architecture, we can have at most + * one pending I/O interrupt per subchannel, so this is effectively a + * clear all. + */ + return 0; +} + static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { int r = 0; @@ -2067,6 +2093,9 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) case KVM_DEV_FLIC_ADAPTER_MODIFY: r = modify_io_adapter(dev, attr); break; + case KVM_DEV_FLIC_CLEAR_IO_IRQ: + r = clear_io_irq(dev->kvm, attr); + break; default: r = -EINVAL; } @@ -2074,6 +2103,23 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) return r; } +static int flic_has_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) +{ + switch (attr->group) { + case KVM_DEV_FLIC_GET_ALL_IRQS: + case KVM_DEV_FLIC_ENQUEUE: + case KVM_DEV_FLIC_CLEAR_IRQS: + case KVM_DEV_FLIC_APF_ENABLE: + case KVM_DEV_FLIC_APF_DISABLE_WAIT: + case KVM_DEV_FLIC_ADAPTER_REGISTER: + case KVM_DEV_FLIC_ADAPTER_MODIFY: + case KVM_DEV_FLIC_CLEAR_IO_IRQ: + return 0; + } + return -ENXIO; +} + static int flic_create(struct kvm_device *dev, u32 type) { if (!dev) @@ -2095,6 +2141,7 @@ struct kvm_device_ops kvm_flic_ops = { .name = "kvm-flic", .get_attr = flic_get_attr, .set_attr = flic_set_attr, + .has_attr = flic_has_attr, .create = flic_create, .destroy = flic_destroy, }; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 668c087..6d8ec3a 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -65,6 +65,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) }, { "halt_successful_poll", VCPU_STAT(halt_successful_poll) }, { "halt_attempted_poll", VCPU_STAT(halt_attempted_poll) }, + { "halt_poll_invalid", VCPU_STAT(halt_poll_invalid) }, { "halt_wakeup", VCPU_STAT(halt_wakeup) }, { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, { "instruction_lctl", VCPU_STAT(instruction_lctl) }, @@ -118,9 +119,9 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { }; /* upper facilities limit for kvm */ -unsigned long kvm_s390_fac_list_mask[] = { - 0xffe6fffbfcfdfc40UL, - 0x005e800000000000UL, +unsigned long kvm_s390_fac_list_mask[16] = { + 0xffe6000000000000UL, + 0x005e000000000000UL, }; unsigned long kvm_s390_fac_list_mask_size(void) @@ -638,6 +639,7 @@ static int kvm_s390_get_tod(struct kvm *kvm, struct kvm_device_attr *attr) static int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr) { struct kvm_s390_vm_cpu_processor *proc; + u16 lowest_ibc, unblocked_ibc; int ret = 0; mutex_lock(&kvm->lock); @@ -652,9 +654,17 @@ static int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr) } if (!copy_from_user(proc, (void __user *)attr->addr, sizeof(*proc))) { - memcpy(&kvm->arch.model.cpu_id, &proc->cpuid, - sizeof(struct cpuid)); - kvm->arch.model.ibc = proc->ibc; + kvm->arch.model.cpuid = proc->cpuid; + lowest_ibc = sclp.ibc >> 16 & 0xfff; + unblocked_ibc = sclp.ibc & 0xfff; + if (lowest_ibc) { + if (proc->ibc > unblocked_ibc) + kvm->arch.model.ibc = unblocked_ibc; + else if (proc->ibc < lowest_ibc) + kvm->arch.model.ibc = lowest_ibc; + else + kvm->arch.model.ibc = proc->ibc; + } memcpy(kvm->arch.model.fac_list, proc->fac_list, S390_ARCH_FAC_LIST_SIZE_BYTE); } else @@ -687,7 +697,7 @@ static int kvm_s390_get_processor(struct kvm *kvm, struct kvm_device_attr *attr) ret = -ENOMEM; goto out; } - memcpy(&proc->cpuid, &kvm->arch.model.cpu_id, sizeof(struct cpuid)); + proc->cpuid = kvm->arch.model.cpuid; proc->ibc = kvm->arch.model.ibc; memcpy(&proc->fac_list, kvm->arch.model.fac_list, S390_ARCH_FAC_LIST_SIZE_BYTE); @@ -1081,10 +1091,13 @@ static void kvm_s390_set_crycb_format(struct kvm *kvm) kvm->arch.crypto.crycbd |= CRYCB_FORMAT1; } -static void kvm_s390_get_cpu_id(struct cpuid *cpu_id) +static u64 kvm_s390_get_initial_cpuid(void) { - get_cpu_id(cpu_id); - cpu_id->version = 0xff; + struct cpuid cpuid; + + get_cpu_id(&cpuid); + cpuid.version = 0xff; + return *((u64 *) &cpuid); } static void kvm_s390_crypto_init(struct kvm *kvm) @@ -1175,7 +1188,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) memcpy(kvm->arch.model.fac_list, kvm->arch.model.fac_mask, S390_ARCH_FAC_LIST_SIZE_BYTE); - kvm_s390_get_cpu_id(&kvm->arch.model.cpu_id); + kvm->arch.model.cpuid = kvm_s390_get_initial_cpuid(); kvm->arch.model.ibc = sclp.ibc & 0x0fff; kvm_s390_crypto_init(kvm); @@ -1624,7 +1637,6 @@ static void kvm_s390_vcpu_setup_model(struct kvm_vcpu *vcpu) { struct kvm_s390_cpu_model *model = &vcpu->kvm->arch.model; - vcpu->arch.cpu_id = model->cpu_id; vcpu->arch.sie_block->ibc = model->ibc; if (test_kvm_facility(vcpu->kvm, 7)) vcpu->arch.sie_block->fac = (u32)(u64) model->fac_list; @@ -1645,11 +1657,14 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) kvm_s390_vcpu_setup_model(vcpu); - vcpu->arch.sie_block->ecb = 6; + vcpu->arch.sie_block->ecb = 0x02; + if (test_kvm_facility(vcpu->kvm, 9)) + vcpu->arch.sie_block->ecb |= 0x04; if (test_kvm_facility(vcpu->kvm, 50) && test_kvm_facility(vcpu->kvm, 73)) vcpu->arch.sie_block->ecb |= 0x10; - vcpu->arch.sie_block->ecb2 = 8; + if (test_kvm_facility(vcpu->kvm, 8)) + vcpu->arch.sie_block->ecb2 |= 0x08; vcpu->arch.sie_block->eca = 0xC1002000U; if (sclp.has_siif) vcpu->arch.sie_block->eca |= 1; @@ -2971,13 +2986,31 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, return; } +static inline unsigned long nonhyp_mask(int i) +{ + unsigned int nonhyp_fai = (sclp.hmfai << i * 2) >> 30; + + return 0x0000ffffffffffffUL >> (nonhyp_fai << 4); +} + +void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) +{ + vcpu->valid_wakeup = false; +} + static int __init kvm_s390_init(void) { + int i; + if (!sclp.has_sief2) { pr_info("SIE not available\n"); return -ENODEV; } + for (i = 0; i < 16; i++) + kvm_s390_fac_list_mask[i] |= + S390_lowcore.stfle_fac_list[i] & nonhyp_mask(i); + return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); } diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 0a1591d..95916fa 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -439,7 +439,7 @@ static int handle_lpswe(struct kvm_vcpu *vcpu) static int handle_stidp(struct kvm_vcpu *vcpu) { - u64 stidp_data = vcpu->arch.stidp_data; + u64 stidp_data = vcpu->kvm->arch.model.cpuid; u64 operand2; int rc; ar_t ar; @@ -670,8 +670,9 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) if (vcpu->run->s.regs.gprs[reg1] & PFMF_RESERVED) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - /* Only provide non-quiescing support if the host supports it */ - if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ && !test_facility(14)) + /* Only provide non-quiescing support if enabled for the guest */ + if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ && + !test_kvm_facility(vcpu->kvm, 14)) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); /* No support for conditional-SSKE */ @@ -744,7 +745,7 @@ static int handle_essa(struct kvm_vcpu *vcpu) { /* entries expected to be 1FF */ int entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3; - unsigned long *cbrlo, cbrle; + unsigned long *cbrlo; struct gmap *gmap; int i; @@ -765,17 +766,9 @@ static int handle_essa(struct kvm_vcpu *vcpu) vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */ cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo); down_read(&gmap->mm->mmap_sem); - for (i = 0; i < entries; ++i) { - cbrle = cbrlo[i]; - if (unlikely(cbrle & ~PAGE_MASK || cbrle < 2 * PAGE_SIZE)) - /* invalid entry */ - break; - /* try to free backing */ - __gmap_zap(gmap, cbrle); - } + for (i = 0; i < entries; ++i) + __gmap_zap(gmap, cbrlo[i]); up_read(&gmap->mm->mmap_sem); - if (i < entries) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); return 0; } diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 77c22d6..28ea0ca 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -240,6 +240,12 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu, struct kvm_s390_local_interrupt *li; int rc; + if (!test_kvm_facility(vcpu->kvm, 9)) { + *reg &= 0xffffffff00000000UL; + *reg |= SIGP_STATUS_INVALID_ORDER; + return SIGP_CC_STATUS_STORED; + } + li = &dst_vcpu->arch.local_int; if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) { /* running */ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index b7e3944..e0fbe7e 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -562,7 +562,6 @@ struct kvm_vcpu_arch { struct { u64 msr_val; u64 last_steal; - u64 accum_steal; struct gfn_to_hva_cache stime; struct kvm_steal_time steal; } st; @@ -774,6 +773,11 @@ struct kvm_arch { u8 nr_reserved_ioapic_pins; bool disabled_lapic_found; + + /* Struct members for AVIC */ + u32 ldr_mode; + struct page *avic_logical_id_table_page; + struct page *avic_physical_id_table_page; }; struct kvm_vm_stat { @@ -804,6 +808,7 @@ struct kvm_vcpu_stat { u32 halt_exits; u32 halt_successful_poll; u32 halt_attempted_poll; + u32 halt_poll_invalid; u32 halt_wakeup; u32 request_irq_exits; u32 irq_exits; @@ -848,6 +853,9 @@ struct kvm_x86_ops { bool (*cpu_has_high_real_mode_segbase)(void); void (*cpuid_update)(struct kvm_vcpu *vcpu); + int (*vm_init)(struct kvm *kvm); + void (*vm_destroy)(struct kvm *kvm); + /* Create, but do not attach this VCPU */ struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id); void (*vcpu_free)(struct kvm_vcpu *vcpu); @@ -914,7 +922,7 @@ struct kvm_x86_ops { bool (*get_enable_apicv)(void); void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu); void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr); - void (*hwapic_isr_update)(struct kvm *kvm, int isr); + void (*hwapic_isr_update)(struct kvm_vcpu *vcpu, int isr); void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); void (*set_virtual_x2apic_mode)(struct kvm_vcpu *vcpu, bool set); void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu, hpa_t hpa); @@ -990,8 +998,13 @@ struct kvm_x86_ops { */ int (*pre_block)(struct kvm_vcpu *vcpu); void (*post_block)(struct kvm_vcpu *vcpu); + + void (*vcpu_blocking)(struct kvm_vcpu *vcpu); + void (*vcpu_unblocking)(struct kvm_vcpu *vcpu); + int (*update_pi_irte)(struct kvm *kvm, unsigned int host_irq, uint32_t guest_irq, bool set); + void (*apicv_post_state_restore)(struct kvm_vcpu *vcpu); }; struct kvm_arch_async_pf { @@ -1341,7 +1354,18 @@ bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq, void kvm_set_msi_irq(struct kvm_kernel_irq_routing_entry *e, struct kvm_lapic_irq *irq); -static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} -static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} +static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) +{ + if (kvm_x86_ops->vcpu_blocking) + kvm_x86_ops->vcpu_blocking(vcpu); +} + +static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) +{ + if (kvm_x86_ops->vcpu_unblocking) + kvm_x86_ops->vcpu_unblocking(vcpu); +} + +static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {} #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 6136d99..d0fe23e 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -78,7 +78,8 @@ struct __attribute__ ((__packed__)) vmcb_control_area { u32 exit_int_info; u32 exit_int_info_err; u64 nested_ctl; - u8 reserved_4[16]; + u64 avic_vapic_bar; + u8 reserved_4[8]; u32 event_inj; u32 event_inj_err; u64 nested_cr3; @@ -88,7 +89,11 @@ struct __attribute__ ((__packed__)) vmcb_control_area { u64 next_rip; u8 insn_len; u8 insn_bytes[15]; - u8 reserved_6[800]; + u64 avic_backing_page; /* Offset 0xe0 */ + u8 reserved_6[8]; /* Offset 0xe8 */ + u64 avic_logical_id; /* Offset 0xf0 */ + u64 avic_physical_id; /* Offset 0xf8 */ + u8 reserved_7[768]; }; @@ -111,6 +116,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area { #define V_INTR_MASKING_SHIFT 24 #define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) +#define AVIC_ENABLE_SHIFT 31 +#define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT) + #define SVM_INTERRUPT_SHADOW_MASK 1 #define SVM_IOIO_STR_SHIFT 2 diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index cd54147..739c0c5 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -216,9 +216,9 @@ struct kvm_cpuid_entry2 { __u32 padding[3]; }; -#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX BIT(0) -#define KVM_CPUID_FLAG_STATEFUL_FUNC BIT(1) -#define KVM_CPUID_FLAG_STATE_READ_NEXT BIT(2) +#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX (1 << 0) +#define KVM_CPUID_FLAG_STATEFUL_FUNC (1 << 1) +#define KVM_CPUID_FLAG_STATE_READ_NEXT (1 << 2) /* for KVM_SET_CPUID2 */ struct kvm_cpuid2 { diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h index 8a4add8..b9e9bb2 100644 --- a/arch/x86/include/uapi/asm/svm.h +++ b/arch/x86/include/uapi/asm/svm.h @@ -73,6 +73,8 @@ #define SVM_EXIT_MWAIT_COND 0x08c #define SVM_EXIT_XSETBV 0x08d #define SVM_EXIT_NPF 0x400 +#define SVM_EXIT_AVIC_INCOMPLETE_IPI 0x401 +#define SVM_EXIT_AVIC_UNACCELERATED_ACCESS 0x402 #define SVM_EXIT_ERR -1 @@ -107,8 +109,10 @@ { SVM_EXIT_SMI, "smi" }, \ { SVM_EXIT_INIT, "init" }, \ { SVM_EXIT_VINTR, "vintr" }, \ + { SVM_EXIT_CR0_SEL_WRITE, "cr0_sel_write" }, \ { SVM_EXIT_CPUID, "cpuid" }, \ { SVM_EXIT_INVD, "invd" }, \ + { SVM_EXIT_PAUSE, "pause" }, \ { SVM_EXIT_HLT, "hlt" }, \ { SVM_EXIT_INVLPG, "invlpg" }, \ { SVM_EXIT_INVLPGA, "invlpga" }, \ @@ -127,7 +131,10 @@ { SVM_EXIT_MONITOR, "monitor" }, \ { SVM_EXIT_MWAIT, "mwait" }, \ { SVM_EXIT_XSETBV, "xsetbv" }, \ - { SVM_EXIT_NPF, "npf" } + { SVM_EXIT_NPF, "npf" }, \ + { SVM_EXIT_RSM, "rsm" }, \ + { SVM_EXIT_AVIC_INCOMPLETE_IPI, "avic_incomplete_ipi" }, \ + { SVM_EXIT_AVIC_UNACCELERATED_ACCESS, "avic_unaccelerated_access" } #endif /* _UAPI__SVM_H */ diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index 2af478e..f2356bd 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c @@ -19,8 +19,7 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/efi.h> -#include <linux/verify_pefile.h> -#include <keys/system_keyring.h> +#include <linux/verification.h> #include <asm/bootparam.h> #include <asm/setup.h> @@ -529,18 +528,9 @@ static int bzImage64_cleanup(void *loader_data) #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) { - bool trusted; - int ret; - - ret = verify_pefile_signature(kernel, kernel_len, - system_trusted_keyring, - VERIFYING_KEXEC_PE_SIGNATURE, - &trusted); - if (ret < 0) - return ret; - if (!trusted) - return -EKEYREJECTED; - return 0; + return verify_pefile_signature(kernel, kernel_len, + NULL, + VERIFYING_KEXEC_PE_SIGNATURE); } #endif diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 9db47090..5f42d03 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -443,7 +443,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, spin_lock(&ioapic->lock); if (trigger_mode != IOAPIC_LEVEL_TRIG || - kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) + kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) continue; ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index 54ead79..dfb4c64 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c @@ -382,9 +382,6 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u32 i, nr_ioapic_pins; int idx; - /* kvm->irq_routing must be read after clearing - * KVM_SCAN_IOAPIC. */ - smp_mb(); idx = srcu_read_lock(&kvm->irq_srcu); table = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); nr_ioapic_pins = min_t(u32, table->nr_rt_entries, diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 1a2da0e..bbb5b28 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -59,9 +59,8 @@ /* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ #define apic_debug(fmt, arg...) -#define APIC_LVT_NUM 6 /* 14 is the version for Xeon and Pentium 8.4.8*/ -#define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16)) +#define APIC_VERSION (0x14UL | ((KVM_APIC_LVT_NUM - 1) << 16)) #define LAPIC_MMIO_LENGTH (1 << 12) /* followed define is not in apicdef.h */ #define APIC_SHORT_MASK 0xc0000 @@ -73,14 +72,6 @@ #define APIC_BROADCAST 0xFF #define X2APIC_BROADCAST 0xFFFFFFFFul -#define VEC_POS(v) ((v) & (32 - 1)) -#define REG_POS(v) (((v) >> 5) << 4) - -static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) -{ - *((u32 *) (apic->regs + reg_off)) = val; -} - static inline int apic_test_vector(int vec, void *bitmap) { return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); @@ -94,11 +85,6 @@ bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector) apic_test_vector(vector, apic->regs + APIC_IRR); } -static inline void apic_set_vector(int vec, void *bitmap) -{ - set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); -} - static inline void apic_clear_vector(int vec, void *bitmap) { clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); @@ -173,7 +159,7 @@ static void recalculate_apic_map(struct kvm *kvm) continue; aid = kvm_apic_id(apic); - ldr = kvm_apic_get_reg(apic, APIC_LDR); + ldr = kvm_lapic_get_reg(apic, APIC_LDR); if (aid < ARRAY_SIZE(new->phys_map)) new->phys_map[aid] = apic; @@ -182,7 +168,7 @@ static void recalculate_apic_map(struct kvm *kvm) new->mode |= KVM_APIC_MODE_X2APIC; } else if (ldr) { ldr = GET_APIC_LOGICAL_ID(ldr); - if (kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_FLAT) + if (kvm_lapic_get_reg(apic, APIC_DFR) == APIC_DFR_FLAT) new->mode |= KVM_APIC_MODE_XAPIC_FLAT; else new->mode |= KVM_APIC_MODE_XAPIC_CLUSTER; @@ -212,7 +198,7 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) { bool enabled = val & APIC_SPIV_APIC_ENABLED; - apic_set_reg(apic, APIC_SPIV, val); + kvm_lapic_set_reg(apic, APIC_SPIV, val); if (enabled != apic->sw_enabled) { apic->sw_enabled = enabled; @@ -226,13 +212,13 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) static inline void kvm_apic_set_id(struct kvm_lapic *apic, u8 id) { - apic_set_reg(apic, APIC_ID, id << 24); + kvm_lapic_set_reg(apic, APIC_ID, id << 24); recalculate_apic_map(apic->vcpu->kvm); } static inline void kvm_apic_set_ldr(struct kvm_lapic *apic, u32 id) { - apic_set_reg(apic, APIC_LDR, id); + kvm_lapic_set_reg(apic, APIC_LDR, id); recalculate_apic_map(apic->vcpu->kvm); } @@ -240,19 +226,19 @@ static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u8 id) { u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf)); - apic_set_reg(apic, APIC_ID, id << 24); - apic_set_reg(apic, APIC_LDR, ldr); + kvm_lapic_set_reg(apic, APIC_ID, id << 24); + kvm_lapic_set_reg(apic, APIC_LDR, ldr); recalculate_apic_map(apic->vcpu->kvm); } static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type) { - return !(kvm_apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); + return !(kvm_lapic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); } static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type) { - return kvm_apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; + return kvm_lapic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; } static inline int apic_lvtt_oneshot(struct kvm_lapic *apic) @@ -287,10 +273,10 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu) feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0); if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31)))) v |= APIC_LVR_DIRECTED_EOI; - apic_set_reg(apic, APIC_LVR, v); + kvm_lapic_set_reg(apic, APIC_LVR, v); } -static const unsigned int apic_lvt_mask[APIC_LVT_NUM] = { +static const unsigned int apic_lvt_mask[KVM_APIC_LVT_NUM] = { LVT_MASK , /* part LVTT mask, timer mode mask added at runtime */ LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ LVT_MASK | APIC_MODE_MASK, /* LVTPC */ @@ -349,16 +335,6 @@ void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir) } EXPORT_SYMBOL_GPL(kvm_apic_update_irr); -static inline void apic_set_irr(int vec, struct kvm_lapic *apic) -{ - apic_set_vector(vec, apic->regs + APIC_IRR); - /* - * irr_pending must be true if any interrupt is pending; set it after - * APIC_IRR to avoid race with apic_clear_irr - */ - apic->irr_pending = true; -} - static inline int apic_search_irr(struct kvm_lapic *apic) { return find_highest_vector(apic->regs + APIC_IRR); @@ -416,7 +392,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic) * just set SVI. */ if (unlikely(vcpu->arch.apicv_active)) - kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec); + kvm_x86_ops->hwapic_isr_update(vcpu, vec); else { ++apic->isr_count; BUG_ON(apic->isr_count > MAX_APIC_VECTOR); @@ -464,7 +440,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic) * and must be left alone. */ if (unlikely(vcpu->arch.apicv_active)) - kvm_x86_ops->hwapic_isr_update(vcpu->kvm, + kvm_x86_ops->hwapic_isr_update(vcpu, apic_find_highest_isr(apic)); else { --apic->isr_count; @@ -549,8 +525,8 @@ static void apic_update_ppr(struct kvm_lapic *apic) u32 tpr, isrv, ppr, old_ppr; int isr; - old_ppr = kvm_apic_get_reg(apic, APIC_PROCPRI); - tpr = kvm_apic_get_reg(apic, APIC_TASKPRI); + old_ppr = kvm_lapic_get_reg(apic, APIC_PROCPRI); + tpr = kvm_lapic_get_reg(apic, APIC_TASKPRI); isr = apic_find_highest_isr(apic); isrv = (isr != -1) ? isr : 0; @@ -563,7 +539,7 @@ static void apic_update_ppr(struct kvm_lapic *apic) apic, ppr, isr, isrv); if (old_ppr != ppr) { - apic_set_reg(apic, APIC_PROCPRI, ppr); + kvm_lapic_set_reg(apic, APIC_PROCPRI, ppr); if (ppr < old_ppr) kvm_make_request(KVM_REQ_EVENT, apic->vcpu); } @@ -571,7 +547,7 @@ static void apic_update_ppr(struct kvm_lapic *apic) static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) { - apic_set_reg(apic, APIC_TASKPRI, tpr); + kvm_lapic_set_reg(apic, APIC_TASKPRI, tpr); apic_update_ppr(apic); } @@ -601,7 +577,7 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda) if (kvm_apic_broadcast(apic, mda)) return true; - logical_id = kvm_apic_get_reg(apic, APIC_LDR); + logical_id = kvm_lapic_get_reg(apic, APIC_LDR); if (apic_x2apic_mode(apic)) return ((logical_id >> 16) == (mda >> 16)) @@ -610,7 +586,7 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda) logical_id = GET_APIC_LOGICAL_ID(logical_id); mda = GET_APIC_DEST_FIELD(mda); - switch (kvm_apic_get_reg(apic, APIC_DFR)) { + switch (kvm_lapic_get_reg(apic, APIC_DFR)) { case APIC_DFR_FLAT: return (logical_id & mda) != 0; case APIC_DFR_CLUSTER: @@ -618,7 +594,7 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda) && (logical_id & mda & 0xf) != 0; default: apic_debug("Bad DFR vcpu %d: %08x\n", - apic->vcpu->vcpu_id, kvm_apic_get_reg(apic, APIC_DFR)); + apic->vcpu->vcpu_id, kvm_lapic_get_reg(apic, APIC_DFR)); return false; } } @@ -668,6 +644,7 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, return false; } } +EXPORT_SYMBOL_GPL(kvm_apic_match_dest); int kvm_vector_to_index(u32 vector, u32 dest_vcpus, const unsigned long *bitmap, u32 bitmap_size) @@ -921,7 +898,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, if (apic_test_vector(vector, apic->regs + APIC_TMR) != !!trig_mode) { if (trig_mode) - apic_set_vector(vector, apic->regs + APIC_TMR); + kvm_lapic_set_vector(vector, apic->regs + APIC_TMR); else apic_clear_vector(vector, apic->regs + APIC_TMR); } @@ -929,7 +906,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, if (vcpu->arch.apicv_active) kvm_x86_ops->deliver_posted_interrupt(vcpu, vector); else { - apic_set_irr(vector, apic); + kvm_lapic_set_irr(vector, apic); kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); @@ -1073,8 +1050,8 @@ EXPORT_SYMBOL_GPL(kvm_apic_set_eoi_accelerated); static void apic_send_ipi(struct kvm_lapic *apic) { - u32 icr_low = kvm_apic_get_reg(apic, APIC_ICR); - u32 icr_high = kvm_apic_get_reg(apic, APIC_ICR2); + u32 icr_low = kvm_lapic_get_reg(apic, APIC_ICR); + u32 icr_high = kvm_lapic_get_reg(apic, APIC_ICR2); struct kvm_lapic_irq irq; irq.vector = icr_low & APIC_VECTOR_MASK; @@ -1111,7 +1088,7 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic) ASSERT(apic != NULL); /* if initial count is 0, current count should also be 0 */ - if (kvm_apic_get_reg(apic, APIC_TMICT) == 0 || + if (kvm_lapic_get_reg(apic, APIC_TMICT) == 0 || apic->lapic_timer.period == 0) return 0; @@ -1168,13 +1145,13 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) break; case APIC_PROCPRI: apic_update_ppr(apic); - val = kvm_apic_get_reg(apic, offset); + val = kvm_lapic_get_reg(apic, offset); break; case APIC_TASKPRI: report_tpr_access(apic, false); /* fall thru */ default: - val = kvm_apic_get_reg(apic, offset); + val = kvm_lapic_get_reg(apic, offset); break; } @@ -1186,7 +1163,7 @@ static inline struct kvm_lapic *to_lapic(struct kvm_io_device *dev) return container_of(dev, struct kvm_lapic, dev); } -static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len, +int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len, void *data) { unsigned char alignment = offset & 0xf; @@ -1223,6 +1200,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len, } return 0; } +EXPORT_SYMBOL_GPL(kvm_lapic_reg_read); static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr) { @@ -1240,7 +1218,7 @@ static int apic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this, if (!apic_mmio_in_range(apic, address)) return -EOPNOTSUPP; - apic_reg_read(apic, offset, len, data); + kvm_lapic_reg_read(apic, offset, len, data); return 0; } @@ -1249,7 +1227,7 @@ static void update_divide_count(struct kvm_lapic *apic) { u32 tmp1, tmp2, tdcr; - tdcr = kvm_apic_get_reg(apic, APIC_TDCR); + tdcr = kvm_lapic_get_reg(apic, APIC_TDCR); tmp1 = tdcr & 0xf; tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; apic->divide_count = 0x1 << (tmp2 & 0x7); @@ -1260,7 +1238,7 @@ static void update_divide_count(struct kvm_lapic *apic) static void apic_update_lvtt(struct kvm_lapic *apic) { - u32 timer_mode = kvm_apic_get_reg(apic, APIC_LVTT) & + u32 timer_mode = kvm_lapic_get_reg(apic, APIC_LVTT) & apic->lapic_timer.timer_mode_mask; if (apic->lapic_timer.timer_mode != timer_mode) { @@ -1296,7 +1274,7 @@ static void apic_timer_expired(struct kvm_lapic *apic) static bool lapic_timer_int_injected(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - u32 reg = kvm_apic_get_reg(apic, APIC_LVTT); + u32 reg = kvm_lapic_get_reg(apic, APIC_LVTT); if (kvm_apic_hw_enabled(apic)) { int vec = reg & APIC_VECTOR_MASK; @@ -1344,7 +1322,7 @@ static void start_apic_timer(struct kvm_lapic *apic) if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) { /* lapic timer in oneshot or periodic mode */ now = apic->lapic_timer.timer.base->get_time(); - apic->lapic_timer.period = (u64)kvm_apic_get_reg(apic, APIC_TMICT) + apic->lapic_timer.period = (u64)kvm_lapic_get_reg(apic, APIC_TMICT) * APIC_BUS_CYCLE_NS * apic->divide_count; if (!apic->lapic_timer.period) @@ -1376,7 +1354,7 @@ static void start_apic_timer(struct kvm_lapic *apic) "timer initial count 0x%x, period %lldns, " "expire @ 0x%016" PRIx64 ".\n", __func__, APIC_BUS_CYCLE_NS, ktime_to_ns(now), - kvm_apic_get_reg(apic, APIC_TMICT), + kvm_lapic_get_reg(apic, APIC_TMICT), apic->lapic_timer.period, ktime_to_ns(ktime_add_ns(now, apic->lapic_timer.period))); @@ -1425,7 +1403,7 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) } } -static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) +int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) { int ret = 0; @@ -1457,7 +1435,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_DFR: if (!apic_x2apic_mode(apic)) { - apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); + kvm_lapic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); recalculate_apic_map(apic->vcpu->kvm); } else ret = 1; @@ -1465,17 +1443,17 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_SPIV: { u32 mask = 0x3ff; - if (kvm_apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI) + if (kvm_lapic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI) mask |= APIC_SPIV_DIRECTED_EOI; apic_set_spiv(apic, val & mask); if (!(val & APIC_SPIV_APIC_ENABLED)) { int i; u32 lvt_val; - for (i = 0; i < APIC_LVT_NUM; i++) { - lvt_val = kvm_apic_get_reg(apic, + for (i = 0; i < KVM_APIC_LVT_NUM; i++) { + lvt_val = kvm_lapic_get_reg(apic, APIC_LVTT + 0x10 * i); - apic_set_reg(apic, APIC_LVTT + 0x10 * i, + kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i, lvt_val | APIC_LVT_MASKED); } apic_update_lvtt(apic); @@ -1486,14 +1464,14 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) } case APIC_ICR: /* No delay here, so we always clear the pending bit */ - apic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); + kvm_lapic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); apic_send_ipi(apic); break; case APIC_ICR2: if (!apic_x2apic_mode(apic)) val &= 0xff000000; - apic_set_reg(apic, APIC_ICR2, val); + kvm_lapic_set_reg(apic, APIC_ICR2, val); break; case APIC_LVT0: @@ -1507,7 +1485,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) val |= APIC_LVT_MASKED; val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4]; - apic_set_reg(apic, reg, val); + kvm_lapic_set_reg(apic, reg, val); break; @@ -1515,7 +1493,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) if (!kvm_apic_sw_enabled(apic)) val |= APIC_LVT_MASKED; val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask); - apic_set_reg(apic, APIC_LVTT, val); + kvm_lapic_set_reg(apic, APIC_LVTT, val); apic_update_lvtt(apic); break; @@ -1524,14 +1502,14 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) break; hrtimer_cancel(&apic->lapic_timer.timer); - apic_set_reg(apic, APIC_TMICT, val); + kvm_lapic_set_reg(apic, APIC_TMICT, val); start_apic_timer(apic); break; case APIC_TDCR: if (val & 4) apic_debug("KVM_WRITE:TDCR %x\n", val); - apic_set_reg(apic, APIC_TDCR, val); + kvm_lapic_set_reg(apic, APIC_TDCR, val); update_divide_count(apic); break; @@ -1544,7 +1522,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_SELF_IPI: if (apic_x2apic_mode(apic)) { - apic_reg_write(apic, APIC_ICR, 0x40000 | (val & 0xff)); + kvm_lapic_reg_write(apic, APIC_ICR, 0x40000 | (val & 0xff)); } else ret = 1; break; @@ -1556,6 +1534,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) apic_debug("Local APIC Write to read-only register %x\n", reg); return ret; } +EXPORT_SYMBOL_GPL(kvm_lapic_reg_write); static int apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this, gpa_t address, int len, const void *data) @@ -1585,14 +1564,14 @@ static int apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this, apic_debug("%s: offset 0x%x with length 0x%x, and value is " "0x%x\n", __func__, offset, len, val); - apic_reg_write(apic, offset & 0xff0, val); + kvm_lapic_reg_write(apic, offset & 0xff0, val); return 0; } void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu) { - apic_reg_write(vcpu->arch.apic, APIC_EOI, 0); + kvm_lapic_reg_write(vcpu->arch.apic, APIC_EOI, 0); } EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); @@ -1604,10 +1583,10 @@ void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset) /* hw has done the conditional check and inst decode */ offset &= 0xff0; - apic_reg_read(vcpu->arch.apic, offset, 4, &val); + kvm_lapic_reg_read(vcpu->arch.apic, offset, 4, &val); /* TODO: optimize to just emulate side effect w/o one more write */ - apic_reg_write(vcpu->arch.apic, offset, val); + kvm_lapic_reg_write(vcpu->arch.apic, offset, val); } EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode); @@ -1667,14 +1646,14 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) struct kvm_lapic *apic = vcpu->arch.apic; apic_set_tpr(apic, ((cr8 & 0x0f) << 4) - | (kvm_apic_get_reg(apic, APIC_TASKPRI) & 4)); + | (kvm_lapic_get_reg(apic, APIC_TASKPRI) & 4)); } u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) { u64 tpr; - tpr = (u64) kvm_apic_get_reg(vcpu->arch.apic, APIC_TASKPRI); + tpr = (u64) kvm_lapic_get_reg(vcpu->arch.apic, APIC_TASKPRI); return (tpr & 0xf0) >> 4; } @@ -1740,28 +1719,28 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) kvm_apic_set_id(apic, vcpu->vcpu_id); kvm_apic_set_version(apic->vcpu); - for (i = 0; i < APIC_LVT_NUM; i++) - apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); + for (i = 0; i < KVM_APIC_LVT_NUM; i++) + kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); apic_update_lvtt(apic); if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_LINT0_REENABLED)) - apic_set_reg(apic, APIC_LVT0, + kvm_lapic_set_reg(apic, APIC_LVT0, SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); - apic_manage_nmi_watchdog(apic, kvm_apic_get_reg(apic, APIC_LVT0)); + apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0)); - apic_set_reg(apic, APIC_DFR, 0xffffffffU); + kvm_lapic_set_reg(apic, APIC_DFR, 0xffffffffU); apic_set_spiv(apic, 0xff); - apic_set_reg(apic, APIC_TASKPRI, 0); + kvm_lapic_set_reg(apic, APIC_TASKPRI, 0); if (!apic_x2apic_mode(apic)) kvm_apic_set_ldr(apic, 0); - apic_set_reg(apic, APIC_ESR, 0); - apic_set_reg(apic, APIC_ICR, 0); - apic_set_reg(apic, APIC_ICR2, 0); - apic_set_reg(apic, APIC_TDCR, 0); - apic_set_reg(apic, APIC_TMICT, 0); + kvm_lapic_set_reg(apic, APIC_ESR, 0); + kvm_lapic_set_reg(apic, APIC_ICR, 0); + kvm_lapic_set_reg(apic, APIC_ICR2, 0); + kvm_lapic_set_reg(apic, APIC_TDCR, 0); + kvm_lapic_set_reg(apic, APIC_TMICT, 0); for (i = 0; i < 8; i++) { - apic_set_reg(apic, APIC_IRR + 0x10 * i, 0); - apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); - apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); + kvm_lapic_set_reg(apic, APIC_IRR + 0x10 * i, 0); + kvm_lapic_set_reg(apic, APIC_ISR + 0x10 * i, 0); + kvm_lapic_set_reg(apic, APIC_TMR + 0x10 * i, 0); } apic->irr_pending = vcpu->arch.apicv_active; apic->isr_count = vcpu->arch.apicv_active ? 1 : 0; @@ -1806,7 +1785,7 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu) int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type) { - u32 reg = kvm_apic_get_reg(apic, lvt_type); + u32 reg = kvm_lapic_get_reg(apic, lvt_type); int vector, mode, trig_mode; if (kvm_apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) { @@ -1901,14 +1880,14 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) apic_update_ppr(apic); highest_irr = apic_find_highest_irr(apic); if ((highest_irr == -1) || - ((highest_irr & 0xF0) <= kvm_apic_get_reg(apic, APIC_PROCPRI))) + ((highest_irr & 0xF0) <= kvm_lapic_get_reg(apic, APIC_PROCPRI))) return -1; return highest_irr; } int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu) { - u32 lvt0 = kvm_apic_get_reg(vcpu->arch.apic, APIC_LVT0); + u32 lvt0 = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LVT0); int r = 0; if (!kvm_apic_hw_enabled(vcpu->arch.apic)) @@ -1974,7 +1953,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, apic_update_ppr(apic); hrtimer_cancel(&apic->lapic_timer.timer); apic_update_lvtt(apic); - apic_manage_nmi_watchdog(apic, kvm_apic_get_reg(apic, APIC_LVT0)); + apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0)); update_divide_count(apic); start_apic_timer(apic); apic->irr_pending = true; @@ -1982,9 +1961,11 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, 1 : count_vectors(apic->regs + APIC_ISR); apic->highest_isr_cache = -1; if (vcpu->arch.apicv_active) { + if (kvm_x86_ops->apicv_post_state_restore) + kvm_x86_ops->apicv_post_state_restore(vcpu); kvm_x86_ops->hwapic_irr_update(vcpu, apic_find_highest_irr(apic)); - kvm_x86_ops->hwapic_isr_update(vcpu->kvm, + kvm_x86_ops->hwapic_isr_update(vcpu, apic_find_highest_isr(apic)); } kvm_make_request(KVM_REQ_EVENT, vcpu); @@ -2097,7 +2078,7 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention)) return; - tpr = kvm_apic_get_reg(apic, APIC_TASKPRI) & 0xff; + tpr = kvm_lapic_get_reg(apic, APIC_TASKPRI) & 0xff; max_irr = apic_find_highest_irr(apic); if (max_irr < 0) max_irr = 0; @@ -2139,8 +2120,8 @@ int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data) /* if this is ICR write vector before command */ if (reg == APIC_ICR) - apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32)); - return apic_reg_write(apic, reg, (u32)data); + kvm_lapic_reg_write(apic, APIC_ICR2, (u32)(data >> 32)); + return kvm_lapic_reg_write(apic, reg, (u32)data); } int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data) @@ -2157,10 +2138,10 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data) return 1; } - if (apic_reg_read(apic, reg, 4, &low)) + if (kvm_lapic_reg_read(apic, reg, 4, &low)) return 1; if (reg == APIC_ICR) - apic_reg_read(apic, APIC_ICR2, 4, &high); + kvm_lapic_reg_read(apic, APIC_ICR2, 4, &high); *data = (((u64)high) << 32) | low; @@ -2176,8 +2157,8 @@ int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data) /* if this is ICR write vector before command */ if (reg == APIC_ICR) - apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32)); - return apic_reg_write(apic, reg, (u32)data); + kvm_lapic_reg_write(apic, APIC_ICR2, (u32)(data >> 32)); + return kvm_lapic_reg_write(apic, reg, (u32)data); } int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data) @@ -2188,10 +2169,10 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data) if (!lapic_in_kernel(vcpu)) return 1; - if (apic_reg_read(apic, reg, 4, &low)) + if (kvm_lapic_reg_read(apic, reg, 4, &low)) return 1; if (reg == APIC_ICR) - apic_reg_read(apic, APIC_ICR2, 4, &high); + kvm_lapic_reg_read(apic, APIC_ICR2, 4, &high); *data = (((u64)high) << 32) | low; diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index f71183e..891c6da 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -7,6 +7,10 @@ #define KVM_APIC_INIT 0 #define KVM_APIC_SIPI 1 +#define KVM_APIC_LVT_NUM 6 + +#define KVM_APIC_SHORT_MASK 0xc0000 +#define KVM_APIC_DEST_MASK 0x800 struct kvm_timer { struct hrtimer timer; @@ -59,6 +63,11 @@ void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu); void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); void kvm_apic_set_version(struct kvm_vcpu *vcpu); +int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val); +int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len, + void *data); +bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, + int short_hand, unsigned int dest, int dest_mode); void __kvm_apic_update_irr(u32 *pir, void *regs); void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir); @@ -99,9 +108,32 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu) int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data); void kvm_lapic_init(void); -static inline u32 kvm_apic_get_reg(struct kvm_lapic *apic, int reg_off) +#define VEC_POS(v) ((v) & (32 - 1)) +#define REG_POS(v) (((v) >> 5) << 4) + +static inline void kvm_lapic_set_vector(int vec, void *bitmap) +{ + set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline void kvm_lapic_set_irr(int vec, struct kvm_lapic *apic) +{ + kvm_lapic_set_vector(vec, apic->regs + APIC_IRR); + /* + * irr_pending must be true if any interrupt is pending; set it after + * APIC_IRR to avoid race with apic_clear_irr + */ + apic->irr_pending = true; +} + +static inline u32 kvm_lapic_get_reg(struct kvm_lapic *apic, int reg_off) +{ + return *((u32 *) (apic->regs + reg_off)); +} + +static inline void kvm_lapic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) { - return *((u32 *) (apic->regs + reg_off)); + *((u32 *) (apic->regs + reg_off)) = val; } extern struct static_key kvm_no_apic_vcpu; @@ -169,7 +201,7 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu) static inline int kvm_apic_id(struct kvm_lapic *apic) { - return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; + return (kvm_lapic_get_reg(apic, APIC_ID) >> 24) & 0xff; } bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector); diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 38c0c32..24e8001 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1909,18 +1909,17 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm, * since it has been deleted from active_mmu_pages but still can be found * at hast list. * - * for_each_gfn_indirect_valid_sp has skipped that kind of page and - * kvm_mmu_get_page(), the only user of for_each_gfn_sp(), has skipped - * all the obsolete pages. + * for_each_gfn_valid_sp() has skipped that kind of pages. */ -#define for_each_gfn_sp(_kvm, _sp, _gfn) \ +#define for_each_gfn_valid_sp(_kvm, _sp, _gfn) \ hlist_for_each_entry(_sp, \ &(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)], hash_link) \ - if ((_sp)->gfn != (_gfn)) {} else + if ((_sp)->gfn != (_gfn) || is_obsolete_sp((_kvm), (_sp)) \ + || (_sp)->role.invalid) {} else #define for_each_gfn_indirect_valid_sp(_kvm, _sp, _gfn) \ - for_each_gfn_sp(_kvm, _sp, _gfn) \ - if ((_sp)->role.direct || (_sp)->role.invalid) {} else + for_each_gfn_valid_sp(_kvm, _sp, _gfn) \ + if ((_sp)->role.direct) {} else /* @sp->gfn should be write-protected at the call site */ static bool __kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, @@ -1961,6 +1960,11 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, int point) { } static void mmu_audit_disable(void) { } #endif +static bool is_obsolete_sp(struct kvm *kvm, struct kvm_mmu_page *sp) +{ + return unlikely(sp->mmu_valid_gen != kvm->arch.mmu_valid_gen); +} + static bool kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, struct list_head *invalid_list) { @@ -2105,11 +2109,6 @@ static void clear_sp_write_flooding_count(u64 *spte) __clear_sp_write_flooding_count(sp); } -static bool is_obsolete_sp(struct kvm *kvm, struct kvm_mmu_page *sp) -{ - return unlikely(sp->mmu_valid_gen != kvm->arch.mmu_valid_gen); -} - static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gaddr, @@ -2136,10 +2135,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; role.quadrant = quadrant; } - for_each_gfn_sp(vcpu->kvm, sp, gfn) { - if (is_obsolete_sp(vcpu->kvm, sp)) - continue; - + for_each_gfn_valid_sp(vcpu->kvm, sp, gfn) { if (!need_sync && sp->unsync) need_sync = true; diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c index 3f8c732..c146f3c 100644 --- a/arch/x86/kvm/mtrr.c +++ b/arch/x86/kvm/mtrr.c @@ -44,8 +44,6 @@ static bool msr_mtrr_valid(unsigned msr) case MSR_MTRRdefType: case MSR_IA32_CR_PAT: return true; - case 0x2f8: - return true; } return false; } diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index fafd720..2214214 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -14,6 +14,9 @@ * the COPYING file in the top-level directory. * */ + +#define pr_fmt(fmt) "SVM: " fmt + #include <linux/kvm_host.h> #include "irq.h" @@ -32,6 +35,7 @@ #include <linux/trace_events.h> #include <linux/slab.h> +#include <asm/apic.h> #include <asm/perf_event.h> #include <asm/tlbflush.h> #include <asm/desc.h> @@ -68,6 +72,8 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id); #define SVM_FEATURE_DECODE_ASSIST (1 << 7) #define SVM_FEATURE_PAUSE_FILTER (1 << 10) +#define SVM_AVIC_DOORBELL 0xc001011b + #define NESTED_EXIT_HOST 0 /* Exit handled on host level */ #define NESTED_EXIT_DONE 1 /* Exit caused nested vmexit */ #define NESTED_EXIT_CONTINUE 2 /* Further checks needed */ @@ -78,6 +84,18 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id); #define TSC_RATIO_MIN 0x0000000000000001ULL #define TSC_RATIO_MAX 0x000000ffffffffffULL +#define AVIC_HPA_MASK ~((0xFFFULL << 52) || 0xFFF) + +/* + * 0xff is broadcast, so the max index allowed for physical APIC ID + * table is 0xfe. APIC IDs above 0xff are reserved. + */ +#define AVIC_MAX_PHYSICAL_ID_COUNT 255 + +#define AVIC_UNACCEL_ACCESS_WRITE_MASK 1 +#define AVIC_UNACCEL_ACCESS_OFFSET_MASK 0xFF0 +#define AVIC_UNACCEL_ACCESS_VECTOR_MASK 0xFFFFFFFF + static bool erratum_383_found __read_mostly; static const u32 host_save_user_msrs[] = { @@ -162,8 +180,21 @@ struct vcpu_svm { /* cached guest cpuid flags for faster access */ bool nrips_enabled : 1; + + u32 ldr_reg; + struct page *avic_backing_page; + u64 *avic_physical_id_cache; + bool avic_is_running; }; +#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFF) +#define AVIC_LOGICAL_ID_ENTRY_VALID_MASK (1 << 31) + +#define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK (0xFFULL) +#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK (0xFFFFFFFFFFULL << 12) +#define AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK (1ULL << 62) +#define AVIC_PHYSICAL_ID_ENTRY_VALID_MASK (1ULL << 63) + static DEFINE_PER_CPU(u64, current_tsc_ratio); #define TSC_RATIO_DEFAULT 0x0100000000ULL @@ -205,6 +236,10 @@ module_param(npt, int, S_IRUGO); static int nested = true; module_param(nested, int, S_IRUGO); +/* enable / disable AVIC */ +static int avic; +module_param(avic, int, S_IRUGO); + static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); static void svm_flush_tlb(struct kvm_vcpu *vcpu); static void svm_complete_interrupts(struct vcpu_svm *svm); @@ -228,12 +263,18 @@ enum { VMCB_SEG, /* CS, DS, SS, ES, CPL */ VMCB_CR2, /* CR2 only */ VMCB_LBR, /* DBGCTL, BR_FROM, BR_TO, LAST_EX_FROM, LAST_EX_TO */ + VMCB_AVIC, /* AVIC APIC_BAR, AVIC APIC_BACKING_PAGE, + * AVIC PHYSICAL_TABLE pointer, + * AVIC LOGICAL_TABLE pointer + */ VMCB_DIRTY_MAX, }; /* TPR and CR2 are always written before VMRUN */ #define VMCB_ALWAYS_DIRTY_MASK ((1U << VMCB_INTR) | (1U << VMCB_CR2)) +#define VMCB_AVIC_APIC_BAR_MASK 0xFFFFFFFFFF000ULL + static inline void mark_all_dirty(struct vmcb *vmcb) { vmcb->control.clean = 0; @@ -255,6 +296,23 @@ static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) return container_of(vcpu, struct vcpu_svm, vcpu); } +static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data) +{ + svm->vmcb->control.avic_vapic_bar = data & VMCB_AVIC_APIC_BAR_MASK; + mark_dirty(svm->vmcb, VMCB_AVIC); +} + +static inline bool avic_vcpu_is_running(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + u64 *entry = svm->avic_physical_id_cache; + + if (!entry) + return false; + + return (READ_ONCE(*entry) & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK); +} + static void recalc_intercepts(struct vcpu_svm *svm) { struct vmcb_control_area *c, *h; @@ -923,6 +981,12 @@ static __init int svm_hardware_setup(void) } else kvm_disable_tdp(); + if (avic && (!npt_enabled || !boot_cpu_has(X86_FEATURE_AVIC))) + avic = false; + + if (avic) + pr_info("AVIC enabled\n"); + return 0; err: @@ -1000,6 +1064,22 @@ static void svm_adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, s64 adjustment) mark_dirty(svm->vmcb, VMCB_INTERCEPTS); } +static void avic_init_vmcb(struct vcpu_svm *svm) +{ + struct vmcb *vmcb = svm->vmcb; + struct kvm_arch *vm_data = &svm->vcpu.kvm->arch; + phys_addr_t bpa = page_to_phys(svm->avic_backing_page); + phys_addr_t lpa = page_to_phys(vm_data->avic_logical_id_table_page); + phys_addr_t ppa = page_to_phys(vm_data->avic_physical_id_table_page); + + vmcb->control.avic_backing_page = bpa & AVIC_HPA_MASK; + vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK; + vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK; + vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID_COUNT; + vmcb->control.int_ctl |= AVIC_ENABLE_MASK; + svm->vcpu.arch.apicv_active = true; +} + static void init_vmcb(struct vcpu_svm *svm) { struct vmcb_control_area *control = &svm->vmcb->control; @@ -1014,7 +1094,8 @@ static void init_vmcb(struct vcpu_svm *svm) set_cr_intercept(svm, INTERCEPT_CR0_WRITE); set_cr_intercept(svm, INTERCEPT_CR3_WRITE); set_cr_intercept(svm, INTERCEPT_CR4_WRITE); - set_cr_intercept(svm, INTERCEPT_CR8_WRITE); + if (!kvm_vcpu_apicv_active(&svm->vcpu)) + set_cr_intercept(svm, INTERCEPT_CR8_WRITE); set_dr_intercepts(svm); @@ -1110,9 +1191,197 @@ static void init_vmcb(struct vcpu_svm *svm) set_intercept(svm, INTERCEPT_PAUSE); } + if (avic) + avic_init_vmcb(svm); + mark_all_dirty(svm->vmcb); enable_gif(svm); + +} + +static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu, int index) +{ + u64 *avic_physical_id_table; + struct kvm_arch *vm_data = &vcpu->kvm->arch; + + if (index >= AVIC_MAX_PHYSICAL_ID_COUNT) + return NULL; + + avic_physical_id_table = page_address(vm_data->avic_physical_id_table_page); + + return &avic_physical_id_table[index]; +} + +/** + * Note: + * AVIC hardware walks the nested page table to check permissions, + * but does not use the SPA address specified in the leaf page + * table entry since it uses address in the AVIC_BACKING_PAGE pointer + * field of the VMCB. Therefore, we set up the + * APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (4KB) here. + */ +static int avic_init_access_page(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + int ret; + + if (kvm->arch.apic_access_page_done) + return 0; + + ret = x86_set_memory_region(kvm, + APIC_ACCESS_PAGE_PRIVATE_MEMSLOT, + APIC_DEFAULT_PHYS_BASE, + PAGE_SIZE); + if (ret) + return ret; + + kvm->arch.apic_access_page_done = true; + return 0; +} + +static int avic_init_backing_page(struct kvm_vcpu *vcpu) +{ + int ret; + u64 *entry, new_entry; + int id = vcpu->vcpu_id; + struct vcpu_svm *svm = to_svm(vcpu); + + ret = avic_init_access_page(vcpu); + if (ret) + return ret; + + if (id >= AVIC_MAX_PHYSICAL_ID_COUNT) + return -EINVAL; + + if (!svm->vcpu.arch.apic->regs) + return -EINVAL; + + svm->avic_backing_page = virt_to_page(svm->vcpu.arch.apic->regs); + + /* Setting AVIC backing page address in the phy APIC ID table */ + entry = avic_get_physical_id_entry(vcpu, id); + if (!entry) + return -EINVAL; + + new_entry = READ_ONCE(*entry); + new_entry = (page_to_phys(svm->avic_backing_page) & + AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK) | + AVIC_PHYSICAL_ID_ENTRY_VALID_MASK; + WRITE_ONCE(*entry, new_entry); + + svm->avic_physical_id_cache = entry; + + return 0; +} + +static void avic_vm_destroy(struct kvm *kvm) +{ + struct kvm_arch *vm_data = &kvm->arch; + + if (vm_data->avic_logical_id_table_page) + __free_page(vm_data->avic_logical_id_table_page); + if (vm_data->avic_physical_id_table_page) + __free_page(vm_data->avic_physical_id_table_page); +} + +static int avic_vm_init(struct kvm *kvm) +{ + int err = -ENOMEM; + struct kvm_arch *vm_data = &kvm->arch; + struct page *p_page; + struct page *l_page; + + if (!avic) + return 0; + + /* Allocating physical APIC ID table (4KB) */ + p_page = alloc_page(GFP_KERNEL); + if (!p_page) + goto free_avic; + + vm_data->avic_physical_id_table_page = p_page; + clear_page(page_address(p_page)); + + /* Allocating logical APIC ID table (4KB) */ + l_page = alloc_page(GFP_KERNEL); + if (!l_page) + goto free_avic; + + vm_data->avic_logical_id_table_page = l_page; + clear_page(page_address(l_page)); + + return 0; + +free_avic: + avic_vm_destroy(kvm); + return err; +} + +/** + * This function is called during VCPU halt/unhalt. + */ +static void avic_set_running(struct kvm_vcpu *vcpu, bool is_run) +{ + u64 entry; + int h_physical_id = __default_cpu_present_to_apicid(vcpu->cpu); + struct vcpu_svm *svm = to_svm(vcpu); + + if (!kvm_vcpu_apicv_active(vcpu)) + return; + + svm->avic_is_running = is_run; + + /* ID = 0xff (broadcast), ID > 0xff (reserved) */ + if (WARN_ON(h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)) + return; + + entry = READ_ONCE(*(svm->avic_physical_id_cache)); + WARN_ON(is_run == !!(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)); + + entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; + if (is_run) + entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; + WRITE_ONCE(*(svm->avic_physical_id_cache), entry); +} + +static void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu) +{ + u64 entry; + /* ID = 0xff (broadcast), ID > 0xff (reserved) */ + int h_physical_id = __default_cpu_present_to_apicid(cpu); + struct vcpu_svm *svm = to_svm(vcpu); + + if (!kvm_vcpu_apicv_active(vcpu)) + return; + + if (WARN_ON(h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)) + return; + + entry = READ_ONCE(*(svm->avic_physical_id_cache)); + WARN_ON(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK); + + entry &= ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK; + entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK); + + entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; + if (svm->avic_is_running) + entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; + + WRITE_ONCE(*(svm->avic_physical_id_cache), entry); +} + +static void avic_vcpu_put(struct kvm_vcpu *vcpu) +{ + u64 entry; + struct vcpu_svm *svm = to_svm(vcpu); + + if (!kvm_vcpu_apicv_active(vcpu)) + return; + + entry = READ_ONCE(*(svm->avic_physical_id_cache)); + entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; + WRITE_ONCE(*(svm->avic_physical_id_cache), entry); } static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) @@ -1131,6 +1400,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy); kvm_register_write(vcpu, VCPU_REGS_RDX, eax); + + if (kvm_vcpu_apicv_active(vcpu) && !init_event) + avic_update_vapic_bar(svm, APIC_DEFAULT_PHYS_BASE); } static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) @@ -1169,6 +1441,17 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) if (!hsave_page) goto free_page3; + if (avic) { + err = avic_init_backing_page(&svm->vcpu); + if (err) + goto free_page4; + } + + /* We initialize this flag to true to make sure that the is_running + * bit would be set the first time the vcpu is loaded. + */ + svm->avic_is_running = true; + svm->nested.hsave = page_address(hsave_page); svm->msrpm = page_address(msrpm_pages); @@ -1187,6 +1470,8 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) return &svm->vcpu; +free_page4: + __free_page(hsave_page); free_page3: __free_pages(nested_msrpm_pages, MSRPM_ALLOC_ORDER); free_page2: @@ -1243,6 +1528,8 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) /* This assumes that the kernel never uses MSR_TSC_AUX */ if (static_cpu_has(X86_FEATURE_RDTSCP)) wrmsrl(MSR_TSC_AUX, svm->tsc_aux); + + avic_vcpu_load(vcpu, cpu); } static void svm_vcpu_put(struct kvm_vcpu *vcpu) @@ -1250,6 +1537,8 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu) struct vcpu_svm *svm = to_svm(vcpu); int i; + avic_vcpu_put(vcpu); + ++vcpu->stat.host_state_reload; kvm_load_ldt(svm->host.ldt); #ifdef CONFIG_X86_64 @@ -1265,6 +1554,16 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu) wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); } +static void svm_vcpu_blocking(struct kvm_vcpu *vcpu) +{ + avic_set_running(vcpu, false); +} + +static void svm_vcpu_unblocking(struct kvm_vcpu *vcpu) +{ + avic_set_running(vcpu, true); +} + static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu) { return to_svm(vcpu)->vmcb->save.rflags; @@ -2673,10 +2972,11 @@ static int clgi_interception(struct vcpu_svm *svm) disable_gif(svm); /* After a CLGI no interrupts should come */ - svm_clear_vintr(svm); - svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; - - mark_dirty(svm->vmcb, VMCB_INTR); + if (!kvm_vcpu_apicv_active(&svm->vcpu)) { + svm_clear_vintr(svm); + svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; + mark_dirty(svm->vmcb, VMCB_INTR); + } return 1; } @@ -3212,6 +3512,10 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) case MSR_VM_IGNNE: vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data); break; + case MSR_IA32_APICBASE: + if (kvm_vcpu_apicv_active(vcpu)) + avic_update_vapic_bar(to_svm(vcpu), data); + /* Follow through */ default: return kvm_set_msr_common(vcpu, msr); } @@ -3281,6 +3585,278 @@ static int mwait_interception(struct vcpu_svm *svm) return nop_interception(svm); } +enum avic_ipi_failure_cause { + AVIC_IPI_FAILURE_INVALID_INT_TYPE, + AVIC_IPI_FAILURE_TARGET_NOT_RUNNING, + AVIC_IPI_FAILURE_INVALID_TARGET, + AVIC_IPI_FAILURE_INVALID_BACKING_PAGE, +}; + +static int avic_incomplete_ipi_interception(struct vcpu_svm *svm) +{ + u32 icrh = svm->vmcb->control.exit_info_1 >> 32; + u32 icrl = svm->vmcb->control.exit_info_1; + u32 id = svm->vmcb->control.exit_info_2 >> 32; + u32 index = svm->vmcb->control.exit_info_2 && 0xFF; + struct kvm_lapic *apic = svm->vcpu.arch.apic; + + trace_kvm_avic_incomplete_ipi(svm->vcpu.vcpu_id, icrh, icrl, id, index); + + switch (id) { + case AVIC_IPI_FAILURE_INVALID_INT_TYPE: + /* + * AVIC hardware handles the generation of + * IPIs when the specified Message Type is Fixed + * (also known as fixed delivery mode) and + * the Trigger Mode is edge-triggered. The hardware + * also supports self and broadcast delivery modes + * specified via the Destination Shorthand(DSH) + * field of the ICRL. Logical and physical APIC ID + * formats are supported. All other IPI types cause + * a #VMEXIT, which needs to emulated. + */ + kvm_lapic_reg_write(apic, APIC_ICR2, icrh); + kvm_lapic_reg_write(apic, APIC_ICR, icrl); + break; + case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING: { + int i; + struct kvm_vcpu *vcpu; + struct kvm *kvm = svm->vcpu.kvm; + struct kvm_lapic *apic = svm->vcpu.arch.apic; + + /* + * At this point, we expect that the AVIC HW has already + * set the appropriate IRR bits on the valid target + * vcpus. So, we just need to kick the appropriate vcpu. + */ + kvm_for_each_vcpu(i, vcpu, kvm) { + bool m = kvm_apic_match_dest(vcpu, apic, + icrl & KVM_APIC_SHORT_MASK, + GET_APIC_DEST_FIELD(icrh), + icrl & KVM_APIC_DEST_MASK); + + if (m && !avic_vcpu_is_running(vcpu)) + kvm_vcpu_wake_up(vcpu); + } + break; + } + case AVIC_IPI_FAILURE_INVALID_TARGET: + break; + case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE: + WARN_ONCE(1, "Invalid backing page\n"); + break; + default: + pr_err("Unknown IPI interception\n"); + } + + return 1; +} + +static u32 *avic_get_logical_id_entry(struct kvm_vcpu *vcpu, u32 ldr, bool flat) +{ + struct kvm_arch *vm_data = &vcpu->kvm->arch; + int index; + u32 *logical_apic_id_table; + int dlid = GET_APIC_LOGICAL_ID(ldr); + + if (!dlid) + return NULL; + + if (flat) { /* flat */ + index = ffs(dlid) - 1; + if (index > 7) + return NULL; + } else { /* cluster */ + int cluster = (dlid & 0xf0) >> 4; + int apic = ffs(dlid & 0x0f) - 1; + + if ((apic < 0) || (apic > 7) || + (cluster >= 0xf)) + return NULL; + index = (cluster << 2) + apic; + } + + logical_apic_id_table = (u32 *) page_address(vm_data->avic_logical_id_table_page); + + return &logical_apic_id_table[index]; +} + +static int avic_ldr_write(struct kvm_vcpu *vcpu, u8 g_physical_id, u32 ldr, + bool valid) +{ + bool flat; + u32 *entry, new_entry; + + flat = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR) == APIC_DFR_FLAT; + entry = avic_get_logical_id_entry(vcpu, ldr, flat); + if (!entry) + return -EINVAL; + + new_entry = READ_ONCE(*entry); + new_entry &= ~AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK; + new_entry |= (g_physical_id & AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK); + if (valid) + new_entry |= AVIC_LOGICAL_ID_ENTRY_VALID_MASK; + else + new_entry &= ~AVIC_LOGICAL_ID_ENTRY_VALID_MASK; + WRITE_ONCE(*entry, new_entry); + + return 0; +} + +static int avic_handle_ldr_update(struct kvm_vcpu *vcpu) +{ + int ret; + struct vcpu_svm *svm = to_svm(vcpu); + u32 ldr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LDR); + + if (!ldr) + return 1; + + ret = avic_ldr_write(vcpu, vcpu->vcpu_id, ldr, true); + if (ret && svm->ldr_reg) { + avic_ldr_write(vcpu, 0, svm->ldr_reg, false); + svm->ldr_reg = 0; + } else { + svm->ldr_reg = ldr; + } + return ret; +} + +static int avic_handle_apic_id_update(struct kvm_vcpu *vcpu) +{ + u64 *old, *new; + struct vcpu_svm *svm = to_svm(vcpu); + u32 apic_id_reg = kvm_lapic_get_reg(vcpu->arch.apic, APIC_ID); + u32 id = (apic_id_reg >> 24) & 0xff; + + if (vcpu->vcpu_id == id) + return 0; + + old = avic_get_physical_id_entry(vcpu, vcpu->vcpu_id); + new = avic_get_physical_id_entry(vcpu, id); + if (!new || !old) + return 1; + + /* We need to move physical_id_entry to new offset */ + *new = *old; + *old = 0ULL; + to_svm(vcpu)->avic_physical_id_cache = new; + + /* + * Also update the guest physical APIC ID in the logical + * APIC ID table entry if already setup the LDR. + */ + if (svm->ldr_reg) + avic_handle_ldr_update(vcpu); + + return 0; +} + +static int avic_handle_dfr_update(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct kvm_arch *vm_data = &vcpu->kvm->arch; + u32 dfr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR); + u32 mod = (dfr >> 28) & 0xf; + + /* + * We assume that all local APICs are using the same type. + * If this changes, we need to flush the AVIC logical + * APID id table. + */ + if (vm_data->ldr_mode == mod) + return 0; + + clear_page(page_address(vm_data->avic_logical_id_table_page)); + vm_data->ldr_mode = mod; + + if (svm->ldr_reg) + avic_handle_ldr_update(vcpu); + return 0; +} + +static int avic_unaccel_trap_write(struct vcpu_svm *svm) +{ + struct kvm_lapic *apic = svm->vcpu.arch.apic; + u32 offset = svm->vmcb->control.exit_info_1 & + AVIC_UNACCEL_ACCESS_OFFSET_MASK; + + switch (offset) { + case APIC_ID: + if (avic_handle_apic_id_update(&svm->vcpu)) + return 0; + break; + case APIC_LDR: + if (avic_handle_ldr_update(&svm->vcpu)) + return 0; + break; + case APIC_DFR: + avic_handle_dfr_update(&svm->vcpu); + break; + default: + break; + } + + kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset)); + + return 1; +} + +static bool is_avic_unaccelerated_access_trap(u32 offset) +{ + bool ret = false; + + switch (offset) { + case APIC_ID: + case APIC_EOI: + case APIC_RRR: + case APIC_LDR: + case APIC_DFR: + case APIC_SPIV: + case APIC_ESR: + case APIC_ICR: + case APIC_LVTT: + case APIC_LVTTHMR: + case APIC_LVTPC: + case APIC_LVT0: + case APIC_LVT1: + case APIC_LVTERR: + case APIC_TMICT: + case APIC_TDCR: + ret = true; + break; + default: + break; + } + return ret; +} + +static int avic_unaccelerated_access_interception(struct vcpu_svm *svm) +{ + int ret = 0; + u32 offset = svm->vmcb->control.exit_info_1 & + AVIC_UNACCEL_ACCESS_OFFSET_MASK; + u32 vector = svm->vmcb->control.exit_info_2 & + AVIC_UNACCEL_ACCESS_VECTOR_MASK; + bool write = (svm->vmcb->control.exit_info_1 >> 32) & + AVIC_UNACCEL_ACCESS_WRITE_MASK; + bool trap = is_avic_unaccelerated_access_trap(offset); + + trace_kvm_avic_unaccelerated_access(svm->vcpu.vcpu_id, offset, + trap, write, vector); + if (trap) { + /* Handling Trap */ + WARN_ONCE(!write, "svm: Handling trap read.\n"); + ret = avic_unaccel_trap_write(svm); + } else { + /* Handling Fault */ + ret = (emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE); + } + + return ret; +} + static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_READ_CR0] = cr_interception, [SVM_EXIT_READ_CR3] = cr_interception, @@ -3344,6 +3920,8 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_XSETBV] = xsetbv_interception, [SVM_EXIT_NPF] = pf_interception, [SVM_EXIT_RSM] = emulate_on_interception, + [SVM_EXIT_AVIC_INCOMPLETE_IPI] = avic_incomplete_ipi_interception, + [SVM_EXIT_AVIC_UNACCELERATED_ACCESS] = avic_unaccelerated_access_interception, }; static void dump_vmcb(struct kvm_vcpu *vcpu) @@ -3375,10 +3953,14 @@ static void dump_vmcb(struct kvm_vcpu *vcpu) pr_err("%-20s%08x\n", "exit_int_info_err:", control->exit_int_info_err); pr_err("%-20s%lld\n", "nested_ctl:", control->nested_ctl); pr_err("%-20s%016llx\n", "nested_cr3:", control->nested_cr3); + pr_err("%-20s%016llx\n", "avic_vapic_bar:", control->avic_vapic_bar); pr_err("%-20s%08x\n", "event_inj:", control->event_inj); pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err); pr_err("%-20s%lld\n", "lbr_ctl:", control->lbr_ctl); pr_err("%-20s%016llx\n", "next_rip:", control->next_rip); + pr_err("%-20s%016llx\n", "avic_backing_page:", control->avic_backing_page); + pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id); + pr_err("%-20s%016llx\n", "avic_physical_id:", control->avic_physical_id); pr_err("VMCB State Save Area:\n"); pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", "es:", @@ -3562,6 +4144,7 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) { struct vmcb_control_area *control; + /* The following fields are ignored when AVIC is enabled */ control = &svm->vmcb->control; control->int_vector = irq; control->int_ctl &= ~V_INTR_PRIO_MASK; @@ -3583,11 +4166,17 @@ static void svm_set_irq(struct kvm_vcpu *vcpu) SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR; } +static inline bool svm_nested_virtualize_tpr(struct kvm_vcpu *vcpu) +{ + return is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK); +} + static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) { struct vcpu_svm *svm = to_svm(vcpu); - if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK)) + if (svm_nested_virtualize_tpr(vcpu) || + kvm_vcpu_apicv_active(vcpu)) return; clr_cr_intercept(svm, INTERCEPT_CR8_WRITE); @@ -3606,11 +4195,28 @@ static void svm_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set) static bool svm_get_enable_apicv(void) { - return false; + return avic; +} + +static void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr) +{ } +static void svm_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr) +{ +} + +/* Note: Currently only used by Hyper-V. */ static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) { + struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb *vmcb = svm->vmcb; + + if (!avic) + return; + + vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK; + mark_dirty(vmcb, VMCB_INTR); } static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) @@ -3623,6 +4229,18 @@ static void svm_sync_pir_to_irr(struct kvm_vcpu *vcpu) return; } +static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec) +{ + kvm_lapic_set_irr(vec, vcpu->arch.apic); + smp_mb__after_atomic(); + + if (avic_vcpu_is_running(vcpu)) + wrmsrl(SVM_AVIC_DOORBELL, + __default_cpu_present_to_apicid(vcpu->cpu)); + else + kvm_vcpu_wake_up(vcpu); +} + static int svm_nmi_allowed(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -3677,6 +4295,9 @@ static void enable_irq_window(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); + if (kvm_vcpu_apicv_active(vcpu)) + return; + /* * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes * 1, because that's a separate STGI/VMRUN intercept. The next time we @@ -3728,7 +4349,7 @@ static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK)) + if (svm_nested_virtualize_tpr(vcpu)) return; if (!is_cr_intercept(svm, INTERCEPT_CR8_WRITE)) { @@ -3742,7 +4363,8 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) struct vcpu_svm *svm = to_svm(vcpu); u64 cr8; - if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK)) + if (svm_nested_virtualize_tpr(vcpu) || + kvm_vcpu_apicv_active(vcpu)) return; cr8 = kvm_get_cr8(vcpu); @@ -4045,14 +4667,26 @@ static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) static void svm_cpuid_update(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); + struct kvm_cpuid_entry2 *entry; /* Update nrips enabled cache */ svm->nrips_enabled = !!guest_cpuid_has_nrips(&svm->vcpu); + + if (!kvm_vcpu_apicv_active(vcpu)) + return; + + entry = kvm_find_cpuid_entry(vcpu, 1, 0); + if (entry) + entry->ecx &= ~bit(X86_FEATURE_X2APIC); } static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) { switch (func) { + case 0x1: + if (avic) + entry->ecx &= ~bit(X86_FEATURE_X2APIC); + break; case 0x80000001: if (nested) entry->ecx |= (1 << 2); /* Set SVM bit */ @@ -4307,6 +4941,15 @@ static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu) { } +static inline void avic_post_state_restore(struct kvm_vcpu *vcpu) +{ + if (avic_handle_apic_id_update(vcpu) != 0) + return; + if (avic_handle_dfr_update(vcpu) != 0) + return; + avic_handle_ldr_update(vcpu); +} + static struct kvm_x86_ops svm_x86_ops = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, @@ -4322,9 +4965,14 @@ static struct kvm_x86_ops svm_x86_ops = { .vcpu_free = svm_free_vcpu, .vcpu_reset = svm_vcpu_reset, + .vm_init = avic_vm_init, + .vm_destroy = avic_vm_destroy, + .prepare_guest_switch = svm_prepare_guest_switch, .vcpu_load = svm_vcpu_load, .vcpu_put = svm_vcpu_put, + .vcpu_blocking = svm_vcpu_blocking, + .vcpu_unblocking = svm_vcpu_unblocking, .update_bp_intercept = update_bp_intercept, .get_msr = svm_get_msr, @@ -4382,6 +5030,9 @@ static struct kvm_x86_ops svm_x86_ops = { .refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl, .load_eoi_exitmap = svm_load_eoi_exitmap, .sync_pir_to_irr = svm_sync_pir_to_irr, + .hwapic_irr_update = svm_hwapic_irr_update, + .hwapic_isr_update = svm_hwapic_isr_update, + .apicv_post_state_restore = avic_post_state_restore, .set_tss_addr = svm_set_tss_addr, .get_tdp_level = get_npt_level, @@ -4415,6 +5066,7 @@ static struct kvm_x86_ops svm_x86_ops = { .sched_in = svm_sched_in, .pmu_ops = &amd_pmu_ops, + .deliver_posted_interrupt = svm_deliver_avic_intr, }; static int __init svm_init(void) diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index b72743c..8de9250 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -1291,6 +1291,63 @@ TRACE_EVENT(kvm_hv_stimer_cleanup, __entry->vcpu_id, __entry->timer_index) ); +/* + * Tracepoint for AMD AVIC + */ +TRACE_EVENT(kvm_avic_incomplete_ipi, + TP_PROTO(u32 vcpu, u32 icrh, u32 icrl, u32 id, u32 index), + TP_ARGS(vcpu, icrh, icrl, id, index), + + TP_STRUCT__entry( + __field(u32, vcpu) + __field(u32, icrh) + __field(u32, icrl) + __field(u32, id) + __field(u32, index) + ), + + TP_fast_assign( + __entry->vcpu = vcpu; + __entry->icrh = icrh; + __entry->icrl = icrl; + __entry->id = id; + __entry->index = index; + ), + + TP_printk("vcpu=%u, icrh:icrl=%#010x:%08x, id=%u, index=%u\n", + __entry->vcpu, __entry->icrh, __entry->icrl, + __entry->id, __entry->index) +); + +TRACE_EVENT(kvm_avic_unaccelerated_access, + TP_PROTO(u32 vcpu, u32 offset, bool ft, bool rw, u32 vec), + TP_ARGS(vcpu, offset, ft, rw, vec), + + TP_STRUCT__entry( + __field(u32, vcpu) + __field(u32, offset) + __field(bool, ft) + __field(bool, rw) + __field(u32, vec) + ), + + TP_fast_assign( + __entry->vcpu = vcpu; + __entry->offset = offset; + __entry->ft = ft; + __entry->rw = rw; + __entry->vec = vec; + ), + + TP_printk("vcpu=%u, offset=%#x(%s), %s, %s, vec=%#x\n", + __entry->vcpu, + __entry->offset, + __print_symbolic(__entry->offset, kvm_trace_symbol_apic), + __entry->ft ? "trap" : "fault", + __entry->rw ? "write" : "read", + __entry->vec) +); + #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index cb47fe3..e605d1e 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -5050,8 +5050,8 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET; - vmx_set_cr0(vcpu, cr0); /* enter rmode */ vmx->vcpu.arch.cr0 = cr0; + vmx_set_cr0(vcpu, cr0); /* enter rmode */ vmx_set_cr4(vcpu, 0); vmx_set_efer(vcpu, 0); vmx_fpu_activate(vcpu); @@ -8318,19 +8318,19 @@ static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu, hpa_t hpa) vmcs_write64(APIC_ACCESS_ADDR, hpa); } -static void vmx_hwapic_isr_update(struct kvm *kvm, int isr) +static void vmx_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr) { u16 status; u8 old; - if (isr == -1) - isr = 0; + if (max_isr == -1) + max_isr = 0; status = vmcs_read16(GUEST_INTR_STATUS); old = status >> 8; - if (isr != old) { + if (max_isr != old) { status &= 0xff; - status |= isr << 8; + status |= max_isr << 8; vmcs_write16(GUEST_INTR_STATUS, status); } } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 12f33e6..c805cf4 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -161,6 +161,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "halt_exits", VCPU_STAT(halt_exits) }, { "halt_successful_poll", VCPU_STAT(halt_successful_poll) }, { "halt_attempted_poll", VCPU_STAT(halt_attempted_poll) }, + { "halt_poll_invalid", VCPU_STAT(halt_poll_invalid) }, { "halt_wakeup", VCPU_STAT(halt_wakeup) }, { "hypercalls", VCPU_STAT(hypercalls) }, { "request_irq", VCPU_STAT(request_irq_exits) }, @@ -2002,22 +2003,8 @@ static void kvmclock_reset(struct kvm_vcpu *vcpu) vcpu->arch.pv_time_enabled = false; } -static void accumulate_steal_time(struct kvm_vcpu *vcpu) -{ - u64 delta; - - if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) - return; - - delta = current->sched_info.run_delay - vcpu->arch.st.last_steal; - vcpu->arch.st.last_steal = current->sched_info.run_delay; - vcpu->arch.st.accum_steal = delta; -} - static void record_steal_time(struct kvm_vcpu *vcpu) { - accumulate_steal_time(vcpu); - if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) return; @@ -2025,9 +2012,26 @@ static void record_steal_time(struct kvm_vcpu *vcpu) &vcpu->arch.st.steal, sizeof(struct kvm_steal_time)))) return; - vcpu->arch.st.steal.steal += vcpu->arch.st.accum_steal; - vcpu->arch.st.steal.version += 2; - vcpu->arch.st.accum_steal = 0; + if (vcpu->arch.st.steal.version & 1) + vcpu->arch.st.steal.version += 1; /* first time write, random junk */ + + vcpu->arch.st.steal.version += 1; + + kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.st.stime, + &vcpu->arch.st.steal, sizeof(struct kvm_steal_time)); + + smp_wmb(); + + vcpu->arch.st.steal.steal += current->sched_info.run_delay - + vcpu->arch.st.last_steal; + vcpu->arch.st.last_steal = current->sched_info.run_delay; + + kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.st.stime, + &vcpu->arch.st.steal, sizeof(struct kvm_steal_time)); + + smp_wmb(); + + vcpu->arch.st.steal.version += 1; kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.st.stime, &vcpu->arch.st.steal, sizeof(struct kvm_steal_time)); @@ -7752,6 +7756,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm_page_track_init(kvm); kvm_mmu_init_vm(kvm); + if (kvm_x86_ops->vm_init) + return kvm_x86_ops->vm_init(kvm); + return 0; } @@ -7873,6 +7880,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm) x86_set_memory_region(kvm, IDENTITY_PAGETABLE_PRIVATE_MEMSLOT, 0, 0); x86_set_memory_region(kvm, TSS_PRIVATE_MEMSLOT, 0, 0); } + if (kvm_x86_ops->vm_destroy) + kvm_x86_ops->vm_destroy(kvm); kvm_iommu_unmap_guest(kvm); kfree(kvm->arch.vpic); kfree(kvm->arch.vioapic); @@ -8355,19 +8364,21 @@ bool kvm_arch_has_noncoherent_dma(struct kvm *kvm) } EXPORT_SYMBOL_GPL(kvm_arch_has_noncoherent_dma); +bool kvm_arch_has_irq_bypass(void) +{ + return kvm_x86_ops->update_pi_irte != NULL; +} + int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons, struct irq_bypass_producer *prod) { struct kvm_kernel_irqfd *irqfd = container_of(cons, struct kvm_kernel_irqfd, consumer); - if (kvm_x86_ops->update_pi_irte) { - irqfd->producer = prod; - return kvm_x86_ops->update_pi_irte(irqfd->kvm, - prod->irq, irqfd->gsi, 1); - } + irqfd->producer = prod; - return -EINVAL; + return kvm_x86_ops->update_pi_irte(irqfd->kvm, + prod->irq, irqfd->gsi, 1); } void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, @@ -8377,11 +8388,6 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, struct kvm_kernel_irqfd *irqfd = container_of(cons, struct kvm_kernel_irqfd, consumer); - if (!kvm_x86_ops->update_pi_irte) { - WARN_ON(irqfd->producer != NULL); - return; - } - WARN_ON(irqfd->producer != prod); irqfd->producer = NULL; @@ -8429,3 +8435,5 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_write_tsc_offset); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ple_window); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pml_full); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pi_irte_update); +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_unaccelerated_access); +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_incomplete_ipi); diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 381a43c..8196054 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -516,7 +516,7 @@ void __init pcibios_set_cache_line_size(void) int __init pcibios_init(void) { - if (!raw_pci_ops) { + if (!raw_pci_ops && !raw_pci_ext_ops) { printk(KERN_WARNING "PCI: System does not support PCI\n"); return 0; } diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index b7de192..837ea36 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -552,9 +552,16 @@ static void twinhead_reserve_killing_zone(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone); +/* + * Broadwell EP Home Agent BARs erroneously return non-zero values when read. + * + * See http://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v4-spec-update.html + * entry BDF2. + */ static void pci_bdwep_bar(struct pci_dev *dev) { dev->non_compliant_bars = 1; } +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_bdwep_bar); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_bdwep_bar); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_bdwep_bar); |