diff options
Diffstat (limited to 'arch/arc')
63 files changed, 1967 insertions, 323 deletions
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 12d0284a46e5..8894f7e7e3de 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,13 +31,16 @@ 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 select OF select OF_EARLY_FLATTREE + select OF_RESERVED_MEM select PERF_USE_VMALLOC select HAVE_DEBUG_STACKOVERFLOW + select HAVE_GENERIC_DMA_COHERENT config MIGHT_HAVE_PCI bool @@ -56,6 +60,9 @@ config GENERIC_CSUM config RWSEM_GENERIC_SPINLOCK def_bool y +config ARCH_DISCONTIGMEM_ENABLE + def_bool y + config ARCH_FLATMEM_ENABLE def_bool y @@ -90,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 @@ -345,6 +353,15 @@ config ARC_HUGEPAGE_16M endchoice +config NODES_SHIFT + int "Maximum NUMA Nodes (as a power of 2)" + default "1" if !DISCONTIGMEM + default "2" if DISCONTIGMEM + depends on NEED_MULTIPLE_NODES + ---help--- + Accessing memory beyond 1GB (with or w/o PAE) requires 2 memory + zones. + if ISA_ARCOMPACT config ARC_COMPACT_IRQ_LEVELS @@ -453,6 +470,7 @@ config LINUX_LINK_BASE config HIGHMEM bool "High Memory Support" + select DISCONTIGMEM help With ARC 2G:2G address split, only upper 2G is directly addressable by kernel. Enable this to potentially allow access to rest of 2G and PAE @@ -475,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 def69e347b2d..02fabef2891c 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 cfb5052239a1..663671f22680 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>; diff --git a/arch/arc/boot/dts/axc001.dtsi b/arch/arc/boot/dts/axc001.dtsi index 420dcfde289f..40bcecfc3687 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 f90fadf7f94e..cabe0deeb2d8 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 06a9f294a2e6..ed1674b16e82 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 44a578c10732..68c84a2fc1e4 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 000000000000..b89f6c3eb352 --- /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 105a0017023f..5d5e373e0ebc 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 f46633eeb06b..bf05fe5f67b0 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 46ab31975612..99eabe1a2bf6 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 d94b4ce516ad..b5b060adce8a 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 034a3139c1e2..325e73090a18 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 8a1297e02540..ee03d7126581 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 296d371a335c..3a10cc633e2b 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 000000000000..71fd308a9298 --- /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 000000000000..d1cb25a66989 --- /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 84226bd48baf..ad4ee43bd2ac 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 31f0fb5fc91d..a3cb6263c581 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 000000000000..ede625c76216 --- /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 7730d302cadb..5f3dcbbc0cc9 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 a7209983ee64..b1e327495c7d 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 0352fb8d21b9..8da87feec59a 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 bf9d29f5bd53..000000000000 --- 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 a444be67cd53..d819de1c5d10 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 1d8f57cd6057..e0e1faf03c50 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/io.h b/arch/arc/include/asm/io.h index 17f85c9c73cf..c22b181e8206 100644 --- a/arch/arc/include/asm/io.h +++ b/arch/arc/include/asm/io.h @@ -13,6 +13,15 @@ #include <asm/byteorder.h> #include <asm/page.h> +#ifdef CONFIG_ISA_ARCV2 +#include <asm/barrier.h> +#define __iormb() rmb() +#define __iowmb() wmb() +#else +#define __iormb() do { } while (0) +#define __iowmb() do { } while (0) +#endif + extern void __iomem *ioremap(phys_addr_t paddr, unsigned long size); extern void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size, unsigned long flags); @@ -31,6 +40,15 @@ extern void iounmap(const void __iomem *addr); #define ioremap_wc(phy, sz) ioremap(phy, sz) #define ioremap_wt(phy, sz) ioremap(phy, sz) +/* + * io{read,write}{16,32}be() macros + */ +#define ioread16be(p) ({ u16 __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; }) +#define ioread32be(p) ({ u32 __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; }) + +#define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force u16)cpu_to_be16(v), p); }) +#define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force u32)cpu_to_be32(v), p); }) + /* Change struct page to physical address */ #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) @@ -108,15 +126,6 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr) } -#ifdef CONFIG_ISA_ARCV2 -#include <asm/barrier.h> -#define __iormb() rmb() -#define __iowmb() wmb() -#else -#define __iormb() do { } while (0) -#define __iowmb() do { } while (0) -#endif - /* * MMIO can also get buffered/optimized in micro-arch, so barriers needed * Based on ARM model for the typical use case diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index 49014f0ef36d..c0fa0d2de400 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/irqflags-arcv2.h b/arch/arc/include/asm/irqflags-arcv2.h index 37c2f751eebf..d1ec7f6b31e0 100644 --- a/arch/arc/include/asm/irqflags-arcv2.h +++ b/arch/arc/include/asm/irqflags-arcv2.h @@ -18,6 +18,12 @@ #define STATUS_AD_MASK (1<<STATUS_AD_BIT) #define STATUS_IE_MASK (1<<STATUS_IE_BIT) +/* status32 Bits as encoded/expected by CLRI/SETI */ +#define CLRI_STATUS_IE_BIT 4 + +#define CLRI_STATUS_E_MASK 0xF +#define CLRI_STATUS_IE_MASK (1 << CLRI_STATUS_IE_BIT) + #define AUX_USER_SP 0x00D #define AUX_IRQ_CTRL 0x00E #define AUX_IRQ_ACT 0x043 /* Active Intr across all levels */ @@ -100,6 +106,13 @@ static inline long arch_local_save_flags(void) : : "memory"); + /* To be compatible with irq_save()/irq_restore() + * encode the irq bits as expected by CLRI/SETI + * (this was needed to make CONFIG_TRACE_IRQFLAGS work) + */ + temp = (1 << 5) | + ((!!(temp & STATUS_IE_MASK)) << CLRI_STATUS_IE_BIT) | + (temp & CLRI_STATUS_E_MASK); return temp; } @@ -108,7 +121,7 @@ static inline long arch_local_save_flags(void) */ static inline int arch_irqs_disabled_flags(unsigned long flags) { - return !(flags & (STATUS_IE_MASK)); + return !(flags & CLRI_STATUS_IE_MASK); } static inline int arch_irqs_disabled(void) @@ -128,11 +141,32 @@ static inline void arc_softirq_clear(int irq) #else +#ifdef CONFIG_TRACE_IRQFLAGS + +.macro TRACE_ASM_IRQ_DISABLE + bl trace_hardirqs_off +.endm + +.macro TRACE_ASM_IRQ_ENABLE + bl trace_hardirqs_on +.endm + +#else + +.macro TRACE_ASM_IRQ_DISABLE +.endm + +.macro TRACE_ASM_IRQ_ENABLE +.endm + +#endif .macro IRQ_DISABLE scratch clri + TRACE_ASM_IRQ_DISABLE .endm .macro IRQ_ENABLE scratch + TRACE_ASM_IRQ_ENABLE seti .endm diff --git a/arch/arc/include/asm/mmzone.h b/arch/arc/include/asm/mmzone.h new file mode 100644 index 000000000000..8e97136413d9 --- /dev/null +++ b/arch/arc/include/asm/mmzone.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#ifndef _ASM_ARC_MMZONE_H +#define _ASM_ARC_MMZONE_H + +#ifdef CONFIG_DISCONTIGMEM + +extern struct pglist_data node_data[]; +#define NODE_DATA(nid) (&node_data[nid]) + +static inline int pfn_to_nid(unsigned long pfn) +{ + int is_end_low = 1; + + if (IS_ENABLED(CONFIG_ARC_HAS_PAE40)) + is_end_low = pfn <= virt_to_pfn(0xFFFFFFFFUL); + + /* + * node 0: lowmem: 0x8000_0000 to 0xFFFF_FFFF + * node 1: HIGHMEM w/o PAE40: 0x0 to 0x7FFF_FFFF + * HIGHMEM with PAE40: 0x1_0000_0000 to ... + */ + if (pfn >= ARCH_PFN_OFFSET && is_end_low) + return 0; + + return 1; +} + +static inline int pfn_valid(unsigned long pfn) +{ + int nid = pfn_to_nid(pfn); + + return (pfn <= node_end_pfn(nid)); +} +#endif /* CONFIG_DISCONTIGMEM */ + +#endif diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 36da89e2c853..296c3426a6ad 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; @@ -72,11 +76,20 @@ typedef unsigned long pgprot_t; typedef pte_t * pgtable_t; +/* + * Use virt_to_pfn with caution: + * If used in pte or paddr related macros, it could cause truncation + * in PAE40 builds + * As a rule of thumb, only use it in helpers starting with virt_ + * You have been warned ! + */ #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) #define ARCH_PFN_OFFSET virt_to_pfn(CONFIG_LINUX_LINK_BASE) +#ifdef CONFIG_FLATMEM #define pfn_valid(pfn) (((pfn) - ARCH_PFN_OFFSET) < max_mapnr) +#endif /* * __pa, __va, virt_to_page (ALERT: deprecated, don't use them) @@ -85,12 +98,10 @@ typedef pte_t * pgtable_t; * virt here means link-address/program-address as embedded in object code. * And for ARC, link-addr = physical address */ -#define __pa(vaddr) ((unsigned long)vaddr) +#define __pa(vaddr) ((unsigned long)(vaddr)) #define __va(paddr) ((void *)((unsigned long)(paddr))) -#define virt_to_page(kaddr) \ - (mem_map + virt_to_pfn((kaddr) - CONFIG_LINUX_LINK_BASE)) - +#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr)) #define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr)) /* Default Permissions for stack/heaps pages (Non Executable) */ diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 7d6c93e63adf..034bbdc0ff61 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) @@ -278,14 +278,13 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep) #define pmd_present(x) (pmd_val(x)) #define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) -#define pte_page(pte) \ - (mem_map + virt_to_pfn(pte_val(pte) - CONFIG_LINUX_LINK_BASE)) - +#define pte_page(pte) pfn_to_page(pte_pfn(pte)) #define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot) -#define pte_pfn(pte) virt_to_pfn(pte_val(pte)) -#define pfn_pte(pfn, prot) (__pte(((pte_t)(pfn) << PAGE_SHIFT) | \ - pgprot_val(prot))) -#define __pte_index(addr) (virt_to_pfn(addr) & (PTRS_PER_PTE - 1)) +#define pfn_pte(pfn, prot) (__pte(((pte_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) + +/* Don't use virt_to_pfn for macros below: could cause truncations for PAE40*/ +#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) +#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) /* * pte_offset gets a @ptr to PMD entry (PGD in our 2-tier paging system) diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h index 1d694c1ef6d6..f9048994b22f 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 307846691be6..48b37c693db3 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 db8c59d1eaeb..800e7c430ca5 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 9da71d415c38..ea5ca444c7e3 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 1bc2036b19d7..cfcdedf52ff8 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 10c7b0b5a079..000000000000 --- 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 5d446df2c413..6f4cb0dab1b9 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 7e844fd8213f..f1e07c2344f8 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/entry-arcv2.S b/arch/arc/kernel/entry-arcv2.S index c1264607bbff..7a1c124ff021 100644 --- a/arch/arc/kernel/entry-arcv2.S +++ b/arch/arc/kernel/entry-arcv2.S @@ -69,8 +69,11 @@ ENTRY(handle_interrupt) clri ; To make status32.IE agree with CPU internal state - lr r0, [ICAUSE] +#ifdef CONFIG_TRACE_IRQFLAGS + TRACE_ASM_IRQ_DISABLE +#endif + lr r0, [ICAUSE] mov blink, ret_from_exception b.d arch_do_IRQ @@ -169,6 +172,11 @@ END(EV_TLBProtV) .Lrestore_regs: + # Interrpts are actually disabled from this point on, but will get + # reenabled after we return from interrupt/exception. + # But irq tracer needs to be told now... + TRACE_ASM_IRQ_ENABLE + ld r0, [sp, PT_status32] ; U/K mode at time of entry lr r10, [AUX_IRQ_ACT] diff --git a/arch/arc/kernel/entry-compact.S b/arch/arc/kernel/entry-compact.S index 431433929189..0cb0abaa0479 100644 --- a/arch/arc/kernel/entry-compact.S +++ b/arch/arc/kernel/entry-compact.S @@ -341,6 +341,9 @@ END(call_do_page_fault) .Lrestore_regs: + # Interrpts are actually disabled from this point on, but will get + # reenabled after we return from interrupt/exception. + # But irq tracer needs to be told now... TRACE_ASM_IRQ_ENABLE lr r10, [status32] diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 942526322ae7..6c24faf48b16 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 224d1c3aa9c4..c5cceca36118 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 ba17f85285cf..538b36afe89e 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 c41c364b926c..72f9179b1a24 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 151acf0c9383..f63b8bfefb0c 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 4cb3add77c75..f183cc648851 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 7d9a736fc7e5..4549ab255dd1 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/init.c b/arch/arc/mm/init.c index 7d2c4fbf4f22..8be930394750 100644 --- a/arch/arc/mm/init.c +++ b/arch/arc/mm/init.c @@ -13,6 +13,7 @@ #ifdef CONFIG_BLK_DEV_INITRD #include <linux/initrd.h> #endif +#include <linux/of_fdt.h> #include <linux/swap.h> #include <linux/module.h> #include <linux/highmem.h> @@ -29,11 +30,16 @@ static const unsigned long low_mem_start = CONFIG_LINUX_LINK_BASE; static unsigned long low_mem_sz; #ifdef CONFIG_HIGHMEM -static unsigned long min_high_pfn; +static unsigned long min_high_pfn, max_high_pfn; static u64 high_mem_start; static u64 high_mem_sz; #endif +#ifdef CONFIG_DISCONTIGMEM +struct pglist_data node_data[MAX_NUMNODES] __read_mostly; +EXPORT_SYMBOL(node_data); +#endif + /* User can over-ride above with "mem=nnn[KkMm]" in cmdline */ static int __init setup_mem_sz(char *str) { @@ -108,13 +114,11 @@ void __init setup_arch_memory(void) /* Last usable page of low mem */ max_low_pfn = max_pfn = PFN_DOWN(low_mem_start + low_mem_sz); -#ifdef CONFIG_HIGHMEM - min_high_pfn = PFN_DOWN(high_mem_start); - max_pfn = PFN_DOWN(high_mem_start + high_mem_sz); +#ifdef CONFIG_FLATMEM + /* pfn_valid() uses this */ + max_mapnr = max_low_pfn - min_low_pfn; #endif - max_mapnr = max_pfn - min_low_pfn; - /*------------- bootmem allocator setup -----------------------*/ /* @@ -128,7 +132,7 @@ void __init setup_arch_memory(void) * the crash */ - memblock_add(low_mem_start, low_mem_sz); + memblock_add_node(low_mem_start, low_mem_sz, 0); memblock_reserve(low_mem_start, __pa(_end) - low_mem_start); #ifdef CONFIG_BLK_DEV_INITRD @@ -136,6 +140,9 @@ void __init setup_arch_memory(void) memblock_reserve(__pa(initrd_start), initrd_end - initrd_start); #endif + early_init_fdt_reserve_self(); + early_init_fdt_scan_reserved_mem(); + memblock_dump_all(); /*----------------- node/zones setup --------------------------*/ @@ -145,13 +152,6 @@ void __init setup_arch_memory(void) zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn; zones_holes[ZONE_NORMAL] = 0; -#ifdef CONFIG_HIGHMEM - zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn; - - /* This handles the peripheral address space hole */ - zones_holes[ZONE_HIGHMEM] = min_high_pfn - max_low_pfn; -#endif - /* * We can't use the helper free_area_init(zones[]) because it uses * PAGE_OFFSET to compute the @min_low_pfn which would be wrong @@ -164,6 +164,34 @@ void __init setup_arch_memory(void) zones_holes); /* holes */ #ifdef CONFIG_HIGHMEM + /* + * Populate a new node with highmem + * + * On ARC (w/o PAE) HIGHMEM addresses are actually smaller (0 based) + * than addresses in normal ala low memory (0x8000_0000 based). + * Even with PAE, the huge peripheral space hole would waste a lot of + * mem with single mem_map[]. This warrants a mem_map per region design. + * Thus HIGHMEM on ARC is imlemented with DISCONTIGMEM. + * + * DISCONTIGMEM in turns requires multiple nodes. node 0 above is + * populated with normal memory zone while node 1 only has highmem + */ + node_set_online(1); + + min_high_pfn = PFN_DOWN(high_mem_start); + max_high_pfn = PFN_DOWN(high_mem_start + high_mem_sz); + + zones_size[ZONE_NORMAL] = 0; + zones_holes[ZONE_NORMAL] = 0; + + zones_size[ZONE_HIGHMEM] = max_high_pfn - min_high_pfn; + zones_holes[ZONE_HIGHMEM] = 0; + + free_area_init_node(1, /* node-id */ + zones_size, /* num pages per zone */ + min_high_pfn, /* first pfn of node */ + zones_holes); /* holes */ + high_memory = (void *)(min_high_pfn << PAGE_SHIFT); kmap_init(); #endif @@ -181,7 +209,7 @@ void __init mem_init(void) unsigned long tmp; reset_all_zones_managed_pages(); - for (tmp = min_high_pfn; tmp < max_pfn; tmp++) + for (tmp = min_high_pfn; tmp < max_high_pfn; tmp++) free_highmem_page(pfn_to_page(tmp)); #endif diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index 7046c12c58ed..ec868a9081a1 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/Kconfig b/arch/arc/plat-axs10x/Kconfig index 426ac4b8bb39..c54d1ae57fe0 100644 --- a/arch/arc/plat-axs10x/Kconfig +++ b/arch/arc/plat-axs10x/Kconfig @@ -13,7 +13,7 @@ menuconfig ARC_PLAT_AXS10X select OF_GPIO select MIGHT_HAVE_PCI select GENERIC_IRQ_CHIP - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB help Support for the ARC AXS10x Software Development Platforms. diff --git a/arch/arc/plat-axs10x/axs10x.c b/arch/arc/plat-axs10x/axs10x.c index 1b0f0f458a2b..86548701023c 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 000000000000..1d175cc6ad6d --- /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 000000000000..21091b199df0 --- /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 000000000000..328261c27cda --- /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 000000000000..9d6718c1a199 --- /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 000000000000..29b91b553bf9 --- /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 000000000000..06b59bd13a95 --- /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 000000000000..aaaaffd3d940 --- /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 000000000000..7ad6d2b8f12a --- /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 000000000000..5e901f86e4bd --- /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/arc/plat-tb10x/Kconfig b/arch/arc/plat-tb10x/Kconfig index d14b3d3c5dfd..149e0917645d 100644 --- a/arch/arc/plat-tb10x/Kconfig +++ b/arch/arc/plat-tb10x/Kconfig @@ -21,7 +21,7 @@ menuconfig ARC_PLAT_TB10X select PINCTRL select PINCTRL_TB10X select PINMUX - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select GPIO_TB10X select TB10X_IRQC help |