Pull MIPS updates from Ralf Baechle: "This is the main pull request for 4.3 for MIPS. Here's the summary: Three fixes that didn't make 4.2-stable: - a -Os build might compile the kernel using the MIPS16 instruction set but the R2 optimized inline functions in <uapi/asm/swab.h> are implemented using 32-bit wide instructions which is invalid. - a build error in pgtable-bits.h for a particular kernel configuration. - accessing registers of the CM GCR might have been compiled to use 64 bit accesses but these registers are onl 32 bit wide. And also a few new bits: - move the ATH79 GPIO driver to drivers/gpio - the definition of IRQCHIP_DECLARE has moved to linux/irqchip.h, change ATH79 accordingly. - fix definition of pgprot_writecombine - add an implementation of dma_map_ops.mmap - fix alignment of quiet build output for vmlinuz link - BCM47xx: Use kmemdup rather than duplicating its implementation - Netlogic: Fix 0x0x prefixes of constants. - merge Bjorn Helgaas' series to remove most of the weak keywords from function declarations. - CP0 and CP1 registers are best considered treated as unsigned values to avoid large values from becoming negative values. - improve support for the MIPS GIC timer. - enable common clock framework for Malta and SEAD3. - a number of improvments and fixes to dump_tlb(). - document the MIPS TLB dump functionality in Magic SysRq. - Cavium Octeon CN68XX improvments. - NetLogic improvments. - irq: Use access helper irq_data_get_affinity_mask. - handle MSA unaligned accesses. - a number of R6-related math-emu fixes. - support for I6400. - improvments to MSA support. - add uprobes support. - move from deprecated __initcall to arch_initcall. - remove finish_arch_switch(). - IRQ cleanups by Thomas Gleixner. - migrate to new 'set-state' interface. - random small cleanups" * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (148 commits) MIPS: UAPI: Fix unrecognized opcode WSBH/DSBH/DSHD when using MIPS16. MIPS: Fix alignment of quiet build output for vmlinuz link MIPS: math-emu: Remove unused handle_dsemul function declaration MIPS: math-emu: Add support for the MIPS R6 MAX{, A} FPU instruction MIPS: math-emu: Add support for the MIPS R6 MIN{, A} FPU instruction MIPS: math-emu: Add support for the MIPS R6 CLASS FPU instruction MIPS: math-emu: Add support for the MIPS R6 RINT FPU instruction MIPS: math-emu: Add support for the MIPS R6 MSUBF FPU instruction MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction MIPS: math-emu: Add support for the MIPS R6 SELNEZ FPU instruction MIPS: math-emu: Add support for the MIPS R6 SELEQZ FPU instruction MIPS: math-emu: Add support for the CMP.condn.fmt R6 instruction MIPS: inst.h: Add new MIPS R6 FPU opcodes MIPS: Octeon: Fix management port MII address on Kontron S1901 MIPS: BCM47xx: Use kmemdup rather than duplicating its implementation STAGING: Octeon: Use common helpers for determining interface and port MIPS: Octeon: Support interfaces 4 and 5 MIPS: Octeon: Set up 1:1 mapping between CN68XX PKO queues and ports MIPS: Octeon: Initialize CN68XX PKO STAGING: Octeon: Support CN68XX style WQE ...
Unified · Split
| @@ -0,0 +1,28 @@ | |||
| 1 | * Pistachio general-purpose timer based clocksource | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: "img,pistachio-gptimer". | ||
| 5 | - reg: Address range of the timer registers. | ||
| 6 | - interrupts: An interrupt for each of the four timers | ||
| 7 | - clocks: Should contain a clock specifier for each entry in clock-names | ||
| 8 | - clock-names: Should contain the following entries: | ||
| 9 | "sys", interface clock | ||
| 10 | "slow", slow counter clock | ||
| 11 | "fast", fast counter clock | ||
| 12 | - img,cr-periph: Must contain a phandle to the peripheral control | ||
| 13 | syscon node. | ||
| 14 | |||
| 15 | Example: | ||
| 16 | timer: timer@18102000 { | ||
| 17 | compatible = "img,pistachio-gptimer"; | ||
| 18 | reg = <0x18102000 0x100>; | ||
| 19 | interrupts = <GIC_SHARED 60 IRQ_TYPE_LEVEL_HIGH>, | ||
| 20 | <GIC_SHARED 61 IRQ_TYPE_LEVEL_HIGH>, | ||
| 21 | <GIC_SHARED 62 IRQ_TYPE_LEVEL_HIGH>, | ||
| 22 | <GIC_SHARED 63 IRQ_TYPE_LEVEL_HIGH>; | ||
| 23 | clocks = <&clk_periph PERIPH_CLK_COUNTER_FAST>, | ||
| 24 | <&clk_periph PERIPH_CLK_COUNTER_SLOW>, | ||
| 25 | <&cr_periph SYS_CLK_TIMER>; | ||
| 26 | clock-names = "fast", "slow", "sys"; | ||
| 27 | img,cr-periph = <&cr_periph>; | ||
| 28 | }; | ||
| @@ -22,7 +22,7 @@ · 21 unmodified lines | |||
| 22 | | m68k: | TODO | | 22 | | m68k: | TODO | |
| 23 | | metag: | TODO | | 23 | | metag: | TODO | |
| 24 | | microblaze: | TODO | | 24 | | microblaze: | TODO | |
| 25 | | mips: | TODO | | 25 | | mips: | ok | |
| 26 | | mn10300: | TODO | | 26 | | mn10300: | TODO | |
| 27 | | nios2: | TODO | | 27 | | nios2: | TODO | |
| 28 | | openrisc: | TODO | | 28 | | openrisc: | TODO | |
| @@ -119,6 +119,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.: · 118 unmodified lines | |||
| 119 | 119 | ||
| 120 | 'x' - Used by xmon interface on ppc/powerpc platforms. | 120 | 'x' - Used by xmon interface on ppc/powerpc platforms. |
| 121 | Show global PMU Registers on sparc64. | 121 | Show global PMU Registers on sparc64. |
| 122 | Dump all TLB entries on MIPS. | ||
| 122 | 123 | ||
| 123 | 'y' - Show global CPU Registers [SPARC-64 specific] | 124 | 'y' - Show global CPU Registers [SPARC-64 specific] |
| 124 | 125 | ||
| @@ -1,8 +1,10 @@ | |||
| 1 | config MIPS | 1 | config MIPS |
| 2 | bool | 2 | bool |
| 3 | default y | 3 | default y |
| 4 | select ARCH_SUPPORTS_UPROBES | ||
| 4 | select ARCH_MIGHT_HAVE_PC_PARPORT | 5 | select ARCH_MIGHT_HAVE_PC_PARPORT |
| 5 | select ARCH_MIGHT_HAVE_PC_SERIO | 6 | select ARCH_MIGHT_HAVE_PC_SERIO |
| 7 | select ARCH_USE_CMPXCHG_LOCKREF if 64BIT | ||
| 6 | select HAVE_CONTEXT_TRACKING | 8 | select HAVE_CONTEXT_TRACKING |
| 7 | select HAVE_GENERIC_DMA_COHERENT | 9 | select HAVE_GENERIC_DMA_COHERENT |
| 8 | select HAVE_IDE | 10 | select HAVE_IDE |
| @@ -13,7 +15,6 @@ config MIPS · 4 unmodified lines | |||
| 13 | select HAVE_ARCH_SECCOMP_FILTER | 15 | select HAVE_ARCH_SECCOMP_FILTER |
| 14 | select HAVE_ARCH_TRACEHOOK | 16 | select HAVE_ARCH_TRACEHOOK |
| 15 | select HAVE_BPF_JIT if !CPU_MICROMIPS | 17 | select HAVE_BPF_JIT if !CPU_MICROMIPS |
| 16 | select ARCH_HAVE_CUSTOM_GPIO_H | ||
| 17 | select HAVE_FUNCTION_TRACER | 18 | select HAVE_FUNCTION_TRACER |
| 18 | select HAVE_DYNAMIC_FTRACE | 19 | select HAVE_DYNAMIC_FTRACE |
| 19 | select HAVE_FTRACE_MCOUNT_RECORD | 20 | select HAVE_FTRACE_MCOUNT_RECORD |
| @@ -409,6 +410,7 @@ config MIPS_MALTA · 389 unmodified lines | |||
| 409 | select CEVT_R4K | 410 | select CEVT_R4K |
| 410 | select CSRC_R4K | 411 | select CSRC_R4K |
| 411 | select CLKSRC_MIPS_GIC | 412 | select CLKSRC_MIPS_GIC |
| 413 | select COMMON_CLK | ||
| 412 | select DMA_MAYBE_COHERENT | 414 | select DMA_MAYBE_COHERENT |
| 413 | select GENERIC_ISA_DMA | 415 | select GENERIC_ISA_DMA |
| 414 | select HAVE_PCSPKR_PLATFORM | 416 | select HAVE_PCSPKR_PLATFORM |
| @@ -459,6 +461,7 @@ config MIPS_SEAD3 · 44 unmodified lines | |||
| 459 | select CEVT_R4K | 461 | select CEVT_R4K |
| 460 | select CSRC_R4K | 462 | select CSRC_R4K |
| 461 | select CLKSRC_MIPS_GIC | 463 | select CLKSRC_MIPS_GIC |
| 464 | select COMMON_CLK | ||
| 462 | select CPU_MIPSR2_IRQ_VI | 465 | select CPU_MIPSR2_IRQ_VI |
| 463 | select CPU_MIPSR2_IRQ_EI | 466 | select CPU_MIPSR2_IRQ_EI |
| 464 | select DMA_NONCOHERENT | 467 | select DMA_NONCOHERENT |
| @@ -899,6 +902,7 @@ config NLM_XLP_BOARD · 434 unmodified lines | |||
| 899 | select SYS_SUPPORTS_32BIT_KERNEL | 902 | select SYS_SUPPORTS_32BIT_KERNEL |
| 900 | select SYS_SUPPORTS_64BIT_KERNEL | 903 | select SYS_SUPPORTS_64BIT_KERNEL |
| 901 | select ARCH_PHYS_ADDR_T_64BIT | 904 | select ARCH_PHYS_ADDR_T_64BIT |
| 905 | select ARCH_REQUIRE_GPIOLIB | ||
| 902 | select SYS_SUPPORTS_BIG_ENDIAN | 906 | select SYS_SUPPORTS_BIG_ENDIAN |
| 903 | select SYS_SUPPORTS_LITTLE_ENDIAN | 907 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 904 | select SYS_SUPPORTS_HIGHMEM | 908 | select SYS_SUPPORTS_HIGHMEM |
| @@ -948,6 +952,7 @@ source "arch/mips/jazz/Kconfig" · 43 unmodified lines | |||
| 948 | source "arch/mips/jz4740/Kconfig" | 952 | source "arch/mips/jz4740/Kconfig" |
| 949 | source "arch/mips/lantiq/Kconfig" | 953 | source "arch/mips/lantiq/Kconfig" |
| 950 | source "arch/mips/lasat/Kconfig" | 954 | source "arch/mips/lasat/Kconfig" |
| 955 | source "arch/mips/pistachio/Kconfig" | ||
| 951 | source "arch/mips/pmcs-msp71xx/Kconfig" | 956 | source "arch/mips/pmcs-msp71xx/Kconfig" |
| 952 | source "arch/mips/ralink/Kconfig" | 957 | source "arch/mips/ralink/Kconfig" |
| 953 | source "arch/mips/sgi-ip27/Kconfig" | 958 | source "arch/mips/sgi-ip27/Kconfig" |
| @@ -1041,6 +1046,9 @@ config FW_CFE · 87 unmodified lines | |||
| 1041 | config ARCH_DMA_ADDR_T_64BIT | 1046 | config ARCH_DMA_ADDR_T_64BIT |
| 1042 | def_bool (HIGHMEM && ARCH_PHYS_ADDR_T_64BIT) || 64BIT | 1047 | def_bool (HIGHMEM && ARCH_PHYS_ADDR_T_64BIT) || 64BIT |
| 1043 | 1048 | ||
| 1049 | config ARCH_SUPPORTS_UPROBES | ||
| 1050 | bool | ||
| 1051 | |||
| 1044 | config DMA_MAYBE_COHERENT | 1052 | config DMA_MAYBE_COHERENT |
| 1045 | select DMA_NONCOHERENT | 1053 | select DMA_NONCOHERENT |
| 1046 | bool | 1054 | bool |
| @@ -1364,7 +1372,7 @@ config CPU_MIPS32_R2 · 317 unmodified lines | |||
| 1364 | otherwise CPU_MIPS32_R1 is a safe bet for any MIPS32 system. | 1372 | otherwise CPU_MIPS32_R1 is a safe bet for any MIPS32 system. |
| 1365 | 1373 | ||
| 1366 | config CPU_MIPS32_R6 | 1374 | config CPU_MIPS32_R6 |
| 1367 | bool "MIPS32 Release 6 (EXPERIMENTAL)" | 1375 | bool "MIPS32 Release 6" |
| 1368 | depends on SYS_HAS_CPU_MIPS32_R6 | 1376 | depends on SYS_HAS_CPU_MIPS32_R6 |
| 1369 | select CPU_HAS_PREFETCH | 1377 | select CPU_HAS_PREFETCH |
| 1370 | select CPU_SUPPORTS_32BIT_KERNEL | 1378 | select CPU_SUPPORTS_32BIT_KERNEL |
| @@ -1415,7 +1423,7 @@ config CPU_MIPS64_R2 · 44 unmodified lines | |||
| 1415 | otherwise CPU_MIPS64_R1 is a safe bet for any MIPS64 system. | 1423 | otherwise CPU_MIPS64_R1 is a safe bet for any MIPS64 system. |
| 1416 | 1424 | ||
| 1417 | config CPU_MIPS64_R6 | 1425 | config CPU_MIPS64_R6 |
| 1418 | bool "MIPS64 Release 6 (EXPERIMENTAL)" | 1426 | bool "MIPS64 Release 6" |
| 1419 | depends on SYS_HAS_CPU_MIPS64_R6 | 1427 | depends on SYS_HAS_CPU_MIPS64_R6 |
| 1420 | select CPU_HAS_PREFETCH | 1428 | select CPU_HAS_PREFETCH |
| 1421 | select CPU_SUPPORTS_32BIT_KERNEL | 1429 | select CPU_SUPPORTS_32BIT_KERNEL |
| @@ -1965,6 +1973,7 @@ config 32BIT · 543 unmodified lines | |||
| 1965 | select TRAD_SIGNALS | 1973 | select TRAD_SIGNALS |
| 1966 | help | 1974 | help |
| 1967 | Select this option if you want to build a 32-bit kernel. | 1975 | Select this option if you want to build a 32-bit kernel. |
| 1976 | |||
| 1968 | config 64BIT | 1977 | config 64BIT |
| 1969 | bool "64-bit kernel" | 1978 | bool "64-bit kernel" |
| 1970 | depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL | 1979 | depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL |
| @@ -2110,7 +2119,7 @@ config CPU_R4K_CACHE_TLB · 139 unmodified lines | |||
| 2110 | 2119 | ||
| 2111 | config MIPS_MT_SMP | 2120 | config MIPS_MT_SMP |
| 2112 | bool "MIPS MT SMP support (1 TC on each available VPE)" | 2121 | bool "MIPS MT SMP support (1 TC on each available VPE)" |
| 2113 | depends on SYS_SUPPORTS_MULTITHREADING | 2122 | depends on SYS_SUPPORTS_MULTITHREADING && !CPU_MIPSR6 |
| 2114 | select CPU_MIPSR2_IRQ_VI | 2123 | select CPU_MIPSR2_IRQ_VI |
| 2115 | select CPU_MIPSR2_IRQ_EI | 2124 | select CPU_MIPSR2_IRQ_EI |
| 2116 | select SYNC_R4K | 2125 | select SYNC_R4K |
| @@ -2211,7 +2220,7 @@ config MIPS_VPE_APSP_API_MT · 94 unmodified lines | |||
| 2211 | 2220 | ||
| 2212 | config MIPS_CMP | 2221 | config MIPS_CMP |
| 2213 | bool "MIPS CMP framework support (DEPRECATED)" | 2222 | bool "MIPS CMP framework support (DEPRECATED)" |
| 2214 | depends on SYS_SUPPORTS_MIPS_CMP | 2223 | depends on SYS_SUPPORTS_MIPS_CMP && !CPU_MIPSR6 |
| 2215 | select MIPS_GIC_IPI | 2224 | select MIPS_GIC_IPI |
| 2216 | select SMP | 2225 | select SMP |
| 2217 | select SYNC_R4K | 2226 | select SYNC_R4K |
| @@ -2228,7 +2237,7 @@ config MIPS_CMP · 10 unmodified lines | |||
| 2228 | 2237 | ||
| 2229 | config MIPS_CPS | 2238 | config MIPS_CPS |
| 2230 | bool "MIPS Coherent Processing System support" | 2239 | bool "MIPS Coherent Processing System support" |
| 2231 | depends on SYS_SUPPORTS_MIPS_CPS | 2240 | depends on SYS_SUPPORTS_MIPS_CPS && !CPU_MIPSR6 |
| 2232 | select MIPS_CM | 2241 | select MIPS_CM |
| 2233 | select MIPS_CPC | 2242 | select MIPS_CPC |
| 2234 | select MIPS_CPS_PM if HOTPLUG_CPU | 2243 | select MIPS_CPS_PM if HOTPLUG_CPU |
| @@ -2303,7 +2312,7 @@ config CPU_MICROMIPS · 68 unmodified lines | |||
| 2303 | endchoice | 2312 | endchoice |
| 2304 | 2313 | ||
| 2305 | config CPU_HAS_MSA | 2314 | config CPU_HAS_MSA |
| 2306 | bool "Support for the MIPS SIMD Architecture (EXPERIMENTAL)" | 2315 | bool "Support for the MIPS SIMD Architecture" |
| 2307 | depends on CPU_SUPPORTS_MSA | 2316 | depends on CPU_SUPPORTS_MSA |
| 2308 | depends on 64BIT || MIPS_O32_FP64_SUPPORT | 2317 | depends on 64BIT || MIPS_O32_FP64_SUPPORT |
| 2309 | help | 2318 | help |
| @@ -2643,7 +2652,7 @@ config SECCOMP · 333 unmodified lines | |||
| 2643 | If unsure, say Y. Only embedded should say N here. | 2652 | If unsure, say Y. Only embedded should say N here. |
| 2644 | 2653 | ||
| 2645 | config MIPS_O32_FP64_SUPPORT | 2654 | config MIPS_O32_FP64_SUPPORT |
| 2646 | bool "Support for O32 binaries using 64-bit FP (EXPERIMENTAL)" | 2655 | bool "Support for O32 binaries using 64-bit FP" |
| 2647 | depends on 32BIT || MIPS32_O32 | 2656 | depends on 32BIT || MIPS32_O32 |
| 2648 | help | 2657 | help |
| 2649 | When this is enabled, the kernel will support use of 64-bit floating | 2658 | When this is enabled, the kernel will support use of 64-bit floating |
| @@ -87,15 +87,6 @@ config SB1XXX_CORELIS · 86 unmodified lines | |||
| 87 | Select compile flags that produce code that can be processed by the | 87 | Select compile flags that produce code that can be processed by the |
| 88 | Corelis mksym utility and UDB Emulator. | 88 | Corelis mksym utility and UDB Emulator. |
| 89 | 89 | ||
| 90 | config RUNTIME_DEBUG | ||
| 91 | bool "Enable run-time debugging" | ||
| 92 | depends on DEBUG_KERNEL | ||
| 93 | help | ||
| 94 | If you say Y here, some debugging macros will do run-time checking. | ||
| 95 | If you say N here, those macros will mostly turn to no-ops. See | ||
| 96 | arch/mips/include/asm/debug.h for debugging macros. | ||
| 97 | If unsure, say N. | ||
| 98 | |||
| 99 | config DEBUG_ZBOOT | 90 | config DEBUG_ZBOOT |
| 100 | bool "Enable compressed kernel support debugging" | 91 | bool "Enable compressed kernel support debugging" |
| 101 | depends on DEBUG_KERNEL && SYS_SUPPORTS_ZBOOT | 92 | depends on DEBUG_KERNEL && SYS_SUPPORTS_ZBOOT |
| @@ -6,13 +6,6 @@ config ALCHEMY_GPIOINT_AU1000 · 5 unmodified lines | |||
| 6 | config ALCHEMY_GPIOINT_AU1300 | 6 | config ALCHEMY_GPIOINT_AU1300 |
| 7 | bool | 7 | bool |
| 8 | 8 | ||
| 9 | # select this in your board config if you don't want to use the gpio | ||
| 10 | # namespace as documented in the manuals. In this case however you need | ||
| 11 | # to create the necessary gpio_* functions in your board code/headers! | ||
| 12 | # see arch/mips/include/asm/mach-au1x00/gpio.h for more information. | ||
| 13 | config ALCHEMY_GPIO_INDIRECT | ||
| 14 | def_bool n | ||
| 15 | |||
| 16 | choice | 9 | choice |
| 17 | prompt "Machine type" | 10 | prompt "Machine type" |
| 18 | depends on MIPS_ALCHEMY | 11 | depends on MIPS_ALCHEMY |
| @@ -34,6 +34,7 @@ · 33 unmodified lines | |||
| 34 | #include <asm/idle.h> | 34 | #include <asm/idle.h> |
| 35 | #include <asm/reboot.h> | 35 | #include <asm/reboot.h> |
| 36 | #include <asm/mach-au1x00/au1000.h> | 36 | #include <asm/mach-au1x00/au1000.h> |
| 37 | #include <asm/mach-au1x00/gpio-au1000.h> | ||
| 37 | #include <prom.h> | 38 | #include <prom.h> |
| 38 | 39 | ||
| 39 | const char *get_system_type(void) | 40 | const char *get_system_type(void) |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | |||
| 32 | #include <asm/bootinfo.h> | 32 | #include <asm/bootinfo.h> |
| 33 | #include <asm/reboot.h> | 33 | #include <asm/reboot.h> |
| 34 | #include <asm/mach-au1x00/au1000.h> | 34 | #include <asm/mach-au1x00/au1000.h> |
| 35 | #include <asm/mach-au1x00/gpio-au1000.h> | ||
| 35 | #include <asm/mach-au1x00/au1xxx_eth.h> | 36 | #include <asm/mach-au1x00/au1xxx_eth.h> |
| 36 | #include <prom.h> | 37 | #include <prom.h> |
| 37 | 38 | ||
| @@ -5,10 +5,5 @@ · 4 unmodified lines | |||
| 5 | # Makefile for the Alchemy Au1xx0 CPUs, generic files. | 5 | # Makefile for the Alchemy Au1xx0 CPUs, generic files. |
| 6 | # | 6 | # |
| 7 | 7 | ||
| 8 | obj-y += prom.o time.o clock.o platform.o power.o \ | 8 | obj-y += prom.o time.o clock.o platform.o power.o gpiolib.o \ |
| 9 | setup.o sleeper.o dma.o dbdma.o vss.o irq.o usb.o | 9 | setup.o sleeper.o dma.o dbdma.o vss.o irq.o usb.o |
| 10 | |||
| 11 | # optional gpiolib support | ||
| 12 | ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) | ||
| 13 | obj-$(CONFIG_GPIOLIB) += gpiolib.o | ||
| 14 | endif | ||
| @@ -491,7 +491,7 @@ static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) · 490 unmodified lines | |||
| 491 | default: | 491 | default: |
| 492 | ret = -EINVAL; | 492 | ret = -EINVAL; |
| 493 | } | 493 | } |
| 494 | __irq_set_chip_handler_name_locked(d->irq, chip, handler, name); | 494 | irq_set_chip_handler_name_locked(d, chip, handler, name); |
| 495 | 495 | ||
| 496 | wmb(); | 496 | wmb(); |
| 497 | 497 | ||
| @@ -703,7 +703,7 @@ static int au1300_gpic_settype(struct irq_data *d, unsigned int type) · 205 unmodified lines | |||
| 703 | return -EINVAL; | 703 | return -EINVAL; |
| 704 | } | 704 | } |
| 705 | 705 | ||
| 706 | __irq_set_chip_handler_name_locked(d->irq, &au1300_gpic, hdl, name); | 706 | irq_set_chip_handler_name_locked(d, &au1300_gpic, hdl, name); |
| 707 | 707 | ||
| 708 | au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s); | 708 | au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s); |
| 709 | 709 | ||
| @@ -69,11 +69,6 @@ static int au1x_rtcmatch2_set_next_event(unsigned long delta, · 68 unmodified lines | |||
| 69 | return 0; | 69 | return 0; |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | static void au1x_rtcmatch2_set_mode(enum clock_event_mode mode, | ||
| 73 | struct clock_event_device *cd) | ||
| 74 | { | ||
| 75 | } | ||
| 76 | |||
| 77 | static irqreturn_t au1x_rtcmatch2_irq(int irq, void *dev_id) | 72 | static irqreturn_t au1x_rtcmatch2_irq(int irq, void *dev_id) |
| 78 | { | 73 | { |
| 79 | struct clock_event_device *cd = dev_id; | 74 | struct clock_event_device *cd = dev_id; |
| @@ -86,7 +81,6 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = { · 6 unmodified lines | |||
| 86 | .features = CLOCK_EVT_FEAT_ONESHOT, | 81 | .features = CLOCK_EVT_FEAT_ONESHOT, |
| 87 | .rating = 1500, | 82 | .rating = 1500, |
| 88 | .set_next_event = au1x_rtcmatch2_set_next_event, | 83 | .set_next_event = au1x_rtcmatch2_set_next_event, |
| 89 | .set_mode = au1x_rtcmatch2_set_mode, | ||
| 90 | .cpumask = cpu_all_mask, | 84 | .cpumask = cpu_all_mask, |
| 91 | }; | 85 | }; |
| 92 | 86 | ||
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
| 11 | #include <linux/irqchip/chained_irq.h> | ||
| 11 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 12 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
| 13 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
| @@ -88,10 +89,11 @@ EXPORT_SYMBOL_GPL(bcsr_mod); · 74 unmodified lines | |||
| 88 | static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d) | 89 | static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d) |
| 89 | { | 90 | { |
| 90 | unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT); | 91 | unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT); |
| 92 | struct irq_chip *chip = irq_desc_get_chip(d); | ||
| 91 | 93 | ||
| 92 | disable_irq_nosync(irq); | 94 | chained_irq_enter(chip, d); |
| 93 | generic_handle_irq(bcsr_csc_base + __ffs(bisr)); | 95 | generic_handle_irq(bcsr_csc_base + __ffs(bisr)); |
| 94 | enable_irq(irq); | 96 | chained_irq_exit(chip, d); |
| 95 | } | 97 | } |
| 96 | 98 | ||
| 97 | static void bcsr_irq_mask(struct irq_data *d) | 99 | static void bcsr_irq_mask(struct irq_data *d) |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | |||
| 33 | #include <linux/spi/spi_gpio.h> | 33 | #include <linux/spi/spi_gpio.h> |
| 34 | #include <linux/spi/ads7846.h> | 34 | #include <linux/spi/ads7846.h> |
| 35 | #include <asm/mach-au1x00/au1000.h> | 35 | #include <asm/mach-au1x00/au1000.h> |
| 36 | #include <asm/mach-au1x00/gpio-au1000.h> | ||
| 36 | #include <asm/mach-au1x00/au1000_dma.h> | 37 | #include <asm/mach-au1x00/au1000_dma.h> |
| 37 | #include <asm/mach-au1x00/au1100_mmc.h> | 38 | #include <asm/mach-au1x00/au1100_mmc.h> |
| 38 | #include <asm/mach-db1x00/bcsr.h> | 39 | #include <asm/mach-db1x00/bcsr.h> |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | |||
| 24 | #include <linux/wm97xx.h> | 24 | #include <linux/wm97xx.h> |
| 25 | 25 | ||
| 26 | #include <asm/mach-au1x00/au1000.h> | 26 | #include <asm/mach-au1x00/au1000.h> |
| 27 | #include <asm/mach-au1x00/gpio-au1300.h> | ||
| 27 | #include <asm/mach-au1x00/au1100_mmc.h> | 28 | #include <asm/mach-au1x00/au1100_mmc.h> |
| 28 | #include <asm/mach-au1x00/au1200fb.h> | 29 | #include <asm/mach-au1x00/au1200fb.h> |
| 29 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | 30 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include <linux/spi/flash.h> | 20 | #include <linux/spi/flash.h> |
| 21 | #include <asm/bootinfo.h> | 21 | #include <asm/bootinfo.h> |
| 22 | #include <asm/mach-au1x00/au1000.h> | 22 | #include <asm/mach-au1x00/au1000.h> |
| 23 | #include <asm/mach-au1x00/gpio-au1000.h> | ||
| 23 | #include <asm/mach-au1x00/au1xxx_eth.h> | 24 | #include <asm/mach-au1x00/au1xxx_eth.h> |
| 24 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | 25 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
| 25 | #include <asm/mach-au1x00/au1xxx_psc.h> | 26 | #include <asm/mach-au1x00/au1xxx_psc.h> |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <linux/suspend.h> | 9 | #include <linux/suspend.h> |
| 10 | #include <linux/sysfs.h> | 10 | #include <linux/sysfs.h> |
| 11 | #include <asm/mach-au1x00/au1000.h> | 11 | #include <asm/mach-au1x00/au1000.h> |
| 12 | #include <asm/mach-au1x00/gpio.h> | 12 | #include <asm/mach-au1x00/gpio-au1000.h> |
| 13 | #include <asm/mach-db1x00/bcsr.h> | 13 | #include <asm/mach-db1x00/bcsr.h> |
| 14 | 14 | ||
| 15 | /* | 15 | /* |
| @@ -21,7 +21,10 @@ · 20 unmodified lines | |||
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
| 23 | 23 | ||
| 24 | #include <asm/mach-ar7/gpio.h> | 24 | #include <asm/mach-ar7/ar7.h> |
| 25 | |||
| 26 | #define AR7_GPIO_MAX 32 | ||
| 27 | #define TITAN_GPIO_MAX 51 | ||
| 25 | 28 | ||
| 26 | struct ar7_gpio_chip { | 29 | struct ar7_gpio_chip { |
| 27 | void __iomem *regs; | 30 | void __iomem *regs; |
| @@ -39,7 +39,6 @@ · 38 unmodified lines | |||
| 39 | 39 | ||
| 40 | #include <asm/addrspace.h> | 40 | #include <asm/addrspace.h> |
| 41 | #include <asm/mach-ar7/ar7.h> | 41 | #include <asm/mach-ar7/ar7.h> |
| 42 | #include <asm/mach-ar7/gpio.h> | ||
| 43 | #include <asm/mach-ar7/prom.h> | 42 | #include <asm/mach-ar7/prom.h> |
| 44 | 43 | ||
| 45 | /***************************************************************************** | 44 | /***************************************************************************** |
| @@ -23,7 +23,6 @@ · 22 unmodified lines | |||
| 23 | #include <asm/reboot.h> | 23 | #include <asm/reboot.h> |
| 24 | #include <asm/mach-ar7/ar7.h> | 24 | #include <asm/mach-ar7/ar7.h> |
| 25 | #include <asm/mach-ar7/prom.h> | 25 | #include <asm/mach-ar7/prom.h> |
| 26 | #include <asm/mach-ar7/gpio.h> | ||
| 27 | 26 | ||
| 28 | static void ar7_machine_restart(char *command) | 27 | static void ar7_machine_restart(char *command) |
| 29 | { | 28 | { |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | |||
| 8 | # under the terms of the GNU General Public License version 2 as published | 8 | # under the terms of the GNU General Public License version 2 as published |
| 9 | # by the Free Software Foundation. | 9 | # by the Free Software Foundation. |
| 10 | 10 | ||
| 11 | obj-y := prom.o setup.o irq.o common.o clock.o gpio.o | 11 | obj-y := prom.o setup.o irq.o common.o clock.o |
| 12 | 12 | ||
| 13 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 13 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
| 14 | obj-$(CONFIG_PCI) += pci.o | 14 | obj-$(CONFIG_PCI) += pci.o |
| @@ -25,9 +25,6 @@ unsigned long ath79_get_sys_clk_rate(const char *id); · 24 unmodified lines | |||
| 25 | void ath79_ddr_ctrl_init(void); | 25 | void ath79_ddr_ctrl_init(void); |
| 26 | void ath79_ddr_wb_flush(unsigned int reg); | 26 | void ath79_ddr_wb_flush(unsigned int reg); |
| 27 | 27 | ||
| 28 | void ath79_gpio_function_enable(u32 mask); | ||
| 29 | void ath79_gpio_function_disable(u32 mask); | ||
| 30 | void ath79_gpio_function_setup(u32 set, u32 clear); | ||
| 31 | void ath79_gpio_init(void); | 28 | void ath79_gpio_init(void); |
| 32 | 29 | ||
| 33 | #endif /* __ATH79_COMMON_H */ | 30 | #endif /* __ATH79_COMMON_H */ |
| @@ -123,8 +123,6 @@ static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) · 122 unmodified lines | |||
| 123 | { | 123 | { |
| 124 | u32 status; | 124 | u32 status; |
| 125 | 125 | ||
| 126 | disable_irq_nosync(irq); | ||
| 127 | |||
| 128 | status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS); | 126 | status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS); |
| 129 | 127 | ||
| 130 | if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) { | 128 | if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) { |
| @@ -136,8 +134,6 @@ static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) · 5 unmodified lines | |||
| 136 | } else { | 134 | } else { |
| 137 | spurious_interrupt(); | 135 | spurious_interrupt(); |
| 138 | } | 136 | } |
| 139 | |||
| 140 | enable_irq(irq); | ||
| 141 | } | 137 | } |
| 142 | 138 | ||
| 143 | static void ar934x_ip2_irq_init(void) | 139 | static void ar934x_ip2_irq_init(void) |
| @@ -156,14 +152,12 @@ static void qca955x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) · 12 unmodified lines | |||
| 156 | { | 152 | { |
| 157 | u32 status; | 153 | u32 status; |
| 158 | 154 | ||
| 159 | disable_irq_nosync(irq); | ||
| 160 | |||
| 161 | status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); | 155 | status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); |
| 162 | status &= QCA955X_EXT_INT_PCIE_RC1_ALL | QCA955X_EXT_INT_WMAC_ALL; | 156 | status &= QCA955X_EXT_INT_PCIE_RC1_ALL | QCA955X_EXT_INT_WMAC_ALL; |
| 163 | 157 | ||
| 164 | if (status == 0) { | 158 | if (status == 0) { |
| 165 | spurious_interrupt(); | 159 | spurious_interrupt(); |
| 166 | goto enable; | 160 | return; |
| 167 | } | 161 | } |
| 168 | 162 | ||
| 169 | if (status & QCA955X_EXT_INT_PCIE_RC1_ALL) { | 163 | if (status & QCA955X_EXT_INT_PCIE_RC1_ALL) { |
| @@ -175,17 +169,12 @@ static void qca955x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) · 5 unmodified lines | |||
| 175 | /* TODO: flush DDR? */ | 169 | /* TODO: flush DDR? */ |
| 176 | generic_handle_irq(ATH79_IP2_IRQ(1)); | 170 | generic_handle_irq(ATH79_IP2_IRQ(1)); |
| 177 | } | 171 | } |
| 178 | |||
| 179 | enable: | ||
| 180 | enable_irq(irq); | ||
| 181 | } | 172 | } |
| 182 | 173 | ||
| 183 | static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) | 174 | static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) |
| 184 | { | 175 | { |
| 185 | u32 status; | 176 | u32 status; |
| 186 | 177 | ||
| 187 | disable_irq_nosync(irq); | ||
| 188 | |||
| 189 | status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); | 178 | status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); |
| 190 | status &= QCA955X_EXT_INT_PCIE_RC2_ALL | | 179 | status &= QCA955X_EXT_INT_PCIE_RC2_ALL | |
| 191 | QCA955X_EXT_INT_USB1 | | 180 | QCA955X_EXT_INT_USB1 | |
| @@ -193,7 +182,7 @@ static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) · 1 unmodified line | |||
| 193 | 182 | ||
| 194 | if (status == 0) { | 183 | if (status == 0) { |
| 195 | spurious_interrupt(); | 184 | spurious_interrupt(); |
| 196 | goto enable; | 185 | return; |
| 197 | } | 186 | } |
| 198 | 187 | ||
| 199 | if (status & QCA955X_EXT_INT_USB1) { | 188 | if (status & QCA955X_EXT_INT_USB1) { |
| @@ -210,9 +199,6 @@ static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) · 10 unmodified lines | |||
| 210 | /* TODO: flush DDR? */ | 199 | /* TODO: flush DDR? */ |
| 211 | generic_handle_irq(ATH79_IP3_IRQ(2)); | 200 | generic_handle_irq(ATH79_IP3_IRQ(2)); |
| 212 | } | 201 | } |
| 213 | |||
| 214 | enable: | ||
| 215 | enable_irq(irq); | ||
| 216 | } | 202 | } |
| 217 | 203 | ||
| 218 | static void qca955x_irq_init(void) | 204 | static void qca955x_irq_init(void) |
| @@ -396,10 +396,9 @@ static int __init bcm47xx_buttons_copy(const struct gpio_keys_button *buttons, · 395 unmodified lines | |||
| 396 | { | 396 | { |
| 397 | size_t size = nbuttons * sizeof(*buttons); | 397 | size_t size = nbuttons * sizeof(*buttons); |
| 398 | 398 | ||
| 399 | bcm47xx_button_pdata.buttons = kmalloc(size, GFP_KERNEL); | 399 | bcm47xx_button_pdata.buttons = kmemdup(buttons, size, GFP_KERNEL); |
| 400 | if (!bcm47xx_button_pdata.buttons) | 400 | if (!bcm47xx_button_pdata.buttons) |
| 401 | return -ENOMEM; | 401 | return -ENOMEM; |
| 402 | memcpy(bcm47xx_button_pdata.buttons, buttons, size); | ||
| 403 | bcm47xx_button_pdata.nbuttons = nbuttons; | 402 | bcm47xx_button_pdata.nbuttons = nbuttons; |
| 404 | 403 | ||
| 405 | return 0; | 404 | return 0; |
| @@ -60,7 +60,7 @@ static inline int enable_irq_for_cpu(int cpu, struct irq_data *d, · 59 unmodified lines | |||
| 60 | if (m) | 60 | if (m) |
| 61 | enable &= cpumask_test_cpu(cpu, m); | 61 | enable &= cpumask_test_cpu(cpu, m); |
| 62 | else if (irqd_affinity_was_set(d)) | 62 | else if (irqd_affinity_was_set(d)) |
| 63 | enable &= cpumask_test_cpu(cpu, d->affinity); | 63 | enable &= cpumask_test_cpu(cpu, irq_data_get_affinity_mask(d)); |
| 64 | #endif | 64 | #endif |
| 65 | return enable; | 65 | return enable; |
| 66 | } | 66 | } |
| @@ -365,9 +365,9 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d, · 298 unmodified lines | |||
| 365 | 365 | ||
| 366 | irqd_set_trigger_type(d, flow_type); | 366 | irqd_set_trigger_type(d, flow_type); |
| 367 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) | 367 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) |
| 368 | __irq_set_handler_locked(d->irq, handle_level_irq); | 368 | irq_set_handler_locked(d, handle_level_irq); |
| 369 | else | 369 | else |
| 370 | __irq_set_handler_locked(d->irq, handle_edge_irq); | 370 | irq_set_handler_locked(d, handle_edge_irq); |
| 371 | 371 | ||
| 372 | return IRQ_SET_MASK_OK_NOCOPY; | 372 | return IRQ_SET_MASK_OK_NOCOPY; |
| 373 | } | 373 | } |
| @@ -78,7 +78,7 @@ endif · 77 unmodified lines | |||
| 78 | 78 | ||
| 79 | vmlinuzobjs-y += $(obj)/piggy.o | 79 | vmlinuzobjs-y += $(obj)/piggy.o |
| 80 | 80 | ||
| 81 | quiet_cmd_zld = LD $@ | 81 | quiet_cmd_zld = LD $@ |
| 82 | cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ | 82 | cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ |
| 83 | quiet_cmd_strip = STRIP $@ | 83 | quiet_cmd_strip = STRIP $@ |
| 84 | cmd_strip = $(STRIP) -s $@ | 84 | cmd_strip = $(STRIP) -s $@ |
| @@ -110,6 +110,18 @@ · 109 unmodified lines | |||
| 110 | read-only; | 110 | read-only; |
| 111 | }; | 111 | }; |
| 112 | }; | 112 | }; |
| 113 | |||
| 114 | gpio: xlp_gpio@34100 { | ||
| 115 | compatible = "netlogic,xlp832-gpio"; | ||
| 116 | reg = <0 0x34100 0x1000>; | ||
| 117 | #gpio-cells = <2>; | ||
| 118 | gpio-controller; | ||
| 119 | |||
| 120 | #interrupt-cells = <2>; | ||
| 121 | interrupt-parent = <&pic>; | ||
| 122 | interrupts = <39>; | ||
| 123 | interrupt-controller; | ||
| 124 | }; | ||
| 113 | }; | 125 | }; |
| 114 | 126 | ||
| 115 | chosen { | 127 | chosen { |
| @@ -110,6 +110,18 @@ · 109 unmodified lines | |||
| 110 | read-only; | 110 | read-only; |
| 111 | }; | 111 | }; |
| 112 | }; | 112 | }; |
| 113 | |||
| 114 | gpio: xlp_gpio@34100 { | ||
| 115 | compatible = "netlogic,xlp208-gpio"; | ||
| 116 | reg = <0 0x34100 0x1000>; | ||
| 117 | #gpio-cells = <2>; | ||
| 118 | gpio-controller; | ||
| 119 | |||
| 120 | #interrupt-cells = <2>; | ||
| 121 | interrupt-parent = <&pic>; | ||
| 122 | interrupts = <39>; | ||
| 123 | interrupt-controller; | ||
| 124 | }; | ||
| 113 | }; | 125 | }; |
| 114 | 126 | ||
| 115 | chosen { | 127 | chosen { |
| @@ -69,6 +69,17 @@ · 68 unmodified lines | |||
| 69 | }; | 69 | }; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | gpio: xlp_gpio@114100 { | ||
| 73 | compatible = "netlogic,xlp980-gpio"; | ||
| 74 | reg = <0 0x114100 0x1000>; | ||
| 75 | #gpio-cells = <2>; | ||
| 76 | gpio-controller; | ||
| 77 | |||
| 78 | #interrupt-cells = <2>; | ||
| 79 | interrupt-parent = <&pic>; | ||
| 80 | interrupts = <39>; | ||
| 81 | interrupt-controller; | ||
| 82 | }; | ||
| 72 | }; | 83 | }; |
| 73 | 84 | ||
| 74 | chosen { | 85 | chosen { |
| @@ -69,6 +69,17 @@ · 68 unmodified lines | |||
| 69 | }; | 69 | }; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | gpio: xlp_gpio@114100 { | ||
| 73 | compatible = "netlogic,xlp532-gpio"; | ||
| 74 | reg = <0 0x114100 0x1000>; | ||
| 75 | #gpio-cells = <2>; | ||
| 76 | gpio-controller; | ||
| 77 | |||
| 78 | #interrupt-cells = <2>; | ||
| 79 | interrupt-parent = <&pic>; | ||
| 80 | interrupts = <39>; | ||
| 81 | interrupt-controller; | ||
| 82 | }; | ||
| 72 | }; | 83 | }; |
| 73 | 84 | ||
| 74 | chosen { | 85 | chosen { |
| @@ -110,6 +110,18 @@ · 109 unmodified lines | |||
| 110 | read-only; | 110 | read-only; |
| 111 | }; | 111 | }; |
| 112 | }; | 112 | }; |
| 113 | |||
| 114 | gpio: xlp_gpio@34100 { | ||
| 115 | compatible = "netlogic,xlp316-gpio"; | ||
| 116 | reg = <0 0x34100 0x1000>; | ||
| 117 | #gpio-cells = <2>; | ||
| 118 | gpio-controller; | ||
| 119 | |||
| 120 | #interrupt-cells = <2>; | ||
| 121 | interrupt-parent = <&pic>; | ||
| 122 | interrupts = <39>; | ||
| 123 | interrupt-controller; | ||
| 124 | }; | ||
| 113 | }; | 125 | }; |
| 114 | 126 | ||
| 115 | chosen { | 127 | chosen { |
| @@ -195,6 +195,12 @@ int cvmx_helper_board_get_mii_address(int ipd_port) · 194 unmodified lines | |||
| 195 | return 8; | 195 | return 8; |
| 196 | else | 196 | else |
| 197 | return -1; | 197 | return -1; |
| 198 | case CVMX_BOARD_TYPE_KONTRON_S1901: | ||
| 199 | if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) | ||
| 200 | return 1; | ||
| 201 | else | ||
| 202 | return -1; | ||
| 203 | |||
| 198 | } | 204 | } |
| 199 | 205 | ||
| 200 | /* Some unknown board. Somebody forgot to update this function... */ | 206 | /* Some unknown board. Somebody forgot to update this function... */ |
| @@ -95,9 +95,9 @@ int cvmx_helper_dump_packet(cvmx_wqe_t *work) · 94 unmodified lines | |||
| 95 | uint8_t *data_address; | 95 | uint8_t *data_address; |
| 96 | uint8_t *end_of_data; | 96 | uint8_t *end_of_data; |
| 97 | 97 | ||
| 98 | cvmx_dprintf("Packet Length: %u\n", work->len); | 98 | cvmx_dprintf("Packet Length: %u\n", work->word1.len); |
| 99 | cvmx_dprintf(" Input Port: %u\n", work->ipprt); | 99 | cvmx_dprintf(" Input Port: %u\n", cvmx_wqe_get_port(work)); |
| 100 | cvmx_dprintf(" QoS: %u\n", work->qos); | 100 | cvmx_dprintf(" QoS: %u\n", cvmx_wqe_get_qos(work)); |
| 101 | cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs); | 101 | cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs); |
| 102 | 102 | ||
| 103 | if (work->word2.s.bufs == 0) { | 103 | if (work->word2.s.bufs == 0) { |
| @@ -127,7 +127,7 @@ int cvmx_helper_dump_packet(cvmx_wqe_t *work) · 23 unmodified lines | |||
| 127 | } | 127 | } |
| 128 | } else | 128 | } else |
| 129 | buffer_ptr = work->packet_ptr; | 129 | buffer_ptr = work->packet_ptr; |
| 130 | remaining_bytes = work->len; | 130 | remaining_bytes = work->word1.len; |
| 131 | 131 | ||
| 132 | while (remaining_bytes) { | 132 | while (remaining_bytes) { |
| 133 | start_of_buffer = | 133 | start_of_buffer = |
| @@ -382,6 +382,10 @@ int cvmx_helper_get_ipd_port(int interface, int port) · 248 unmodified lines | |||
| 382 | return port + 32; | 382 | return port + 32; |
| 383 | case 3: | 383 | case 3: |
| 384 | return port + 36; | 384 | return port + 36; |
| 385 | case 4: | ||
| 386 | return port + 40; | ||
| 387 | case 5: | ||
| 388 | return port + 44; | ||
| 385 | } | 389 | } |
| 386 | return -1; | 390 | return -1; |
| 387 | } | 391 | } |
| @@ -404,6 +408,10 @@ int cvmx_helper_get_interface_num(int ipd_port) · 16 unmodified lines | |||
| 404 | return 2; | 408 | return 2; |
| 405 | else if (ipd_port < 40) | 409 | else if (ipd_port < 40) |
| 406 | return 3; | 410 | return 3; |
| 411 | else if (ipd_port < 44) | ||
| 412 | return 4; | ||
| 413 | else if (ipd_port < 48) | ||
| 414 | return 5; | ||
| 407 | else | 415 | else |
| 408 | cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD " | 416 | cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD " |
| 409 | "port number\n"); | 417 | "port number\n"); |
| @@ -428,6 +436,10 @@ int cvmx_helper_get_interface_index_num(int ipd_port) · 18 unmodified lines | |||
| 428 | return ipd_port & 3; | 436 | return ipd_port & 3; |
| 429 | else if (ipd_port < 40) | 437 | else if (ipd_port < 40) |
| 430 | return ipd_port & 3; | 438 | return ipd_port & 3; |
| 439 | else if (ipd_port < 44) | ||
| 440 | return ipd_port & 3; | ||
| 441 | else if (ipd_port < 48) | ||
| 442 | return ipd_port & 3; | ||
| 431 | else | 443 | else |
| 432 | cvmx_dprintf("cvmx_helper_get_interface_index_num: " | 444 | cvmx_dprintf("cvmx_helper_get_interface_index_num: " |
| 433 | "Illegal IPD port number\n"); | 445 | "Illegal IPD port number\n"); |
| @@ -124,6 +124,13 @@ int __cvmx_helper_xaui_enable(int interface) · 123 unmodified lines | |||
| 124 | union cvmx_gmxx_tx_int_en gmx_tx_int_en; | 124 | union cvmx_gmxx_tx_int_en gmx_tx_int_en; |
| 125 | union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; | 125 | union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; |
| 126 | 126 | ||
| 127 | /* Setup PKND */ | ||
| 128 | if (octeon_has_feature(OCTEON_FEATURE_PKND)) { | ||
| 129 | gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); | ||
| 130 | gmx_cfg.s.pknd = cvmx_helper_get_ipd_port(interface, 0); | ||
| 131 | cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); | ||
| 132 | } | ||
| 133 | |||
| 127 | /* (1) Interface has already been enabled. */ | 134 | /* (1) Interface has already been enabled. */ |
| 128 | 135 | ||
| 129 | /* (2) Disable GMX. */ | 136 | /* (2) Disable GMX. */ |
| @@ -151,7 +158,12 @@ int __cvmx_helper_xaui_enable(int interface) · 21 unmodified lines | |||
| 151 | /* (4)c Aply reset sequence */ | 158 | /* (4)c Aply reset sequence */ |
| 152 | xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); | 159 | xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); |
| 153 | xauiCtl.s.lo_pwr = 0; | 160 | xauiCtl.s.lo_pwr = 0; |
| 154 | xauiCtl.s.reset = 1; | 161 | |
| 162 | /* Issuing a reset here seems to hang some CN68XX chips. */ | ||
| 163 | if (!OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X) && | ||
| 164 | !OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X)) | ||
| 165 | xauiCtl.s.reset = 1; | ||
| 166 | |||
| 155 | cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); | 167 | cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); |
| 156 | 168 | ||
| 157 | /* Wait for PCS to come out of reset */ | 169 | /* Wait for PCS to come out of reset */ |
| @@ -83,6 +83,8 @@ static cvmx_helper_link_info_t · 82 unmodified lines | |||
| 83 | */ | 83 | */ |
| 84 | int cvmx_helper_get_number_of_interfaces(void) | 84 | int cvmx_helper_get_number_of_interfaces(void) |
| 85 | { | 85 | { |
| 86 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
| 87 | return 9; | ||
| 86 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) | 88 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) |
| 87 | return 4; | 89 | return 4; |
| 88 | else | 90 | else |
| @@ -656,6 +658,21 @@ static int __cvmx_helper_global_setup_pko(void) · 567 unmodified lines | |||
| 656 | fau_to.s.tout_val = 0xfff; | 658 | fau_to.s.tout_val = 0xfff; |
| 657 | fau_to.s.tout_enb = 0; | 659 | fau_to.s.tout_enb = 0; |
| 658 | cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64); | 660 | cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64); |
| 661 | |||
| 662 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { | ||
| 663 | union cvmx_pko_reg_min_pkt min_pkt; | ||
| 664 | |||
| 665 | min_pkt.u64 = 0; | ||
| 666 | min_pkt.s.size1 = 59; | ||
| 667 | min_pkt.s.size2 = 59; | ||
| 668 | min_pkt.s.size3 = 59; | ||
| 669 | min_pkt.s.size4 = 59; | ||
| 670 | min_pkt.s.size5 = 59; | ||
| 671 | min_pkt.s.size6 = 59; | ||
| 672 | min_pkt.s.size7 = 59; | ||
| 673 | cvmx_write_csr(CVMX_PKO_REG_MIN_PKT, min_pkt.u64); | ||
| 674 | } | ||
| 675 | |||
| 659 | return 0; | 676 | return 0; |
| 660 | } | 677 | } |
| 661 | 678 | ||
| @@ -39,6 +39,143 @@ · 38 unmodified lines | |||
| 39 | * Internal state of packet output | 39 | * Internal state of packet output |
| 40 | */ | 40 | */ |
| 41 | 41 | ||
| 42 | static int __cvmx_pko_int(int interface, int index) | ||
| 43 | { | ||
| 44 | switch (interface) { | ||
| 45 | case 0: | ||
| 46 | return index; | ||
| 47 | case 1: | ||
| 48 | return 4; | ||
| 49 | case 2: | ||
| 50 | return index + 0x08; | ||
| 51 | case 3: | ||
| 52 | return index + 0x0c; | ||
| 53 | case 4: | ||
| 54 | return index + 0x10; | ||
| 55 | case 5: | ||
| 56 | return 0x1c; | ||
| 57 | case 6: | ||
| 58 | return 0x1d; | ||
| 59 | case 7: | ||
| 60 | return 0x1e; | ||
| 61 | case 8: | ||
| 62 | return 0x1f; | ||
| 63 | default: | ||
| 64 | return -1; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | static void __cvmx_pko_iport_config(int pko_port) | ||
| 69 | { | ||
| 70 | int queue; | ||
| 71 | const int num_queues = 1; | ||
| 72 | const int base_queue = pko_port; | ||
| 73 | const int static_priority_end = 1; | ||
| 74 | const int static_priority_base = 1; | ||
| 75 | |||
| 76 | for (queue = 0; queue < num_queues; queue++) { | ||
| 77 | union cvmx_pko_mem_iqueue_ptrs config; | ||
| 78 | cvmx_cmd_queue_result_t cmd_res; | ||
| 79 | uint64_t *buf_ptr; | ||
| 80 | |||
| 81 | config.u64 = 0; | ||
| 82 | config.s.index = queue; | ||
| 83 | config.s.qid = base_queue + queue; | ||
| 84 | config.s.ipid = pko_port; | ||
| 85 | config.s.tail = (queue == (num_queues - 1)); | ||
| 86 | config.s.s_tail = (queue == static_priority_end); | ||
| 87 | config.s.static_p = (static_priority_base >= 0); | ||
| 88 | config.s.static_q = (queue <= static_priority_end); | ||
| 89 | config.s.qos_mask = 0xff; | ||
| 90 | |||
| 91 | cmd_res = cvmx_cmd_queue_initialize( | ||
| 92 | CVMX_CMD_QUEUE_PKO(base_queue + queue), | ||
| 93 | CVMX_PKO_MAX_QUEUE_DEPTH, | ||
| 94 | CVMX_FPA_OUTPUT_BUFFER_POOL, | ||
| 95 | (CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - | ||
| 96 | CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST * 8)); | ||
| 97 | |||
| 98 | WARN(cmd_res, | ||
| 99 | "%s: cmd_res=%d pko_port=%d base_queue=%d num_queues=%d queue=%d\n", | ||
| 100 | __func__, (int)cmd_res, pko_port, base_queue, | ||
| 101 | num_queues, queue); | ||
| 102 | |||
| 103 | buf_ptr = (uint64_t *)cvmx_cmd_queue_buffer( | ||
| 104 | CVMX_CMD_QUEUE_PKO(base_queue + queue)); | ||
| 105 | config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr) >> 7; | ||
| 106 | CVMX_SYNCWS; | ||
| 107 | cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | static void __cvmx_pko_queue_alloc_o68(void) | ||
| 112 | { | ||
| 113 | int port; | ||
| 114 | |||
| 115 | for (port = 0; port < 48; port++) | ||
| 116 | __cvmx_pko_iport_config(port); | ||
| 117 | } | ||
| 118 | |||
| 119 | static void __cvmx_pko_port_map_o68(void) | ||
| 120 | { | ||
| 121 | int port; | ||
| 122 | int interface, index; | ||
| 123 | cvmx_helper_interface_mode_t mode; | ||
| 124 | union cvmx_pko_mem_iport_ptrs config; | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Initialize every iport with the invalid eid. | ||
| 128 | */ | ||
| 129 | config.u64 = 0; | ||
| 130 | config.s.eid = 31; /* Invalid */ | ||
| 131 | for (port = 0; port < 128; port++) { | ||
| 132 | config.s.ipid = port; | ||
| 133 | cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); | ||
| 134 | } | ||
| 135 | |||
| 136 | /* | ||
| 137 | * Set up PKO_MEM_IPORT_PTRS | ||
| 138 | */ | ||
| 139 | for (port = 0; port < 48; port++) { | ||
| 140 | interface = cvmx_helper_get_interface_num(port); | ||
| 141 | index = cvmx_helper_get_interface_index_num(port); | ||
| 142 | mode = cvmx_helper_interface_get_mode(interface); | ||
| 143 | if (mode == CVMX_HELPER_INTERFACE_MODE_DISABLED) | ||
| 144 | continue; | ||
| 145 | |||
| 146 | config.s.ipid = port; | ||
| 147 | config.s.qos_mask = 0xff; | ||
| 148 | config.s.crc = 1; | ||
| 149 | config.s.min_pkt = 1; | ||
| 150 | config.s.intr = __cvmx_pko_int(interface, index); | ||
| 151 | config.s.eid = config.s.intr; | ||
| 152 | config.s.pipe = (mode == CVMX_HELPER_INTERFACE_MODE_LOOP) ? | ||
| 153 | index : port; | ||
| 154 | cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | static void __cvmx_pko_chip_init(void) | ||
| 159 | { | ||
| 160 | int i; | ||
| 161 | |||
| 162 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { | ||
| 163 | __cvmx_pko_port_map_o68(); | ||
| 164 | __cvmx_pko_queue_alloc_o68(); | ||
| 165 | return; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* | ||
| 169 | * Initialize queues | ||
| 170 | */ | ||
| 171 | for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) { | ||
| 172 | const uint64_t priority = 8; | ||
| 173 | |||
| 174 | cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, | ||
| 175 | &priority); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 42 | /** | 179 | /** |
| 43 | * Call before any other calls to initialize the packet | 180 | * Call before any other calls to initialize the packet |
| 44 | * output system. This does chip global config, and should only be | 181 | * output system. This does chip global config, and should only be |
| @@ -47,8 +184,6 @@ · 2 unmodified lines | |||
| 47 | 184 | ||
| 48 | void cvmx_pko_initialize_global(void) | 185 | void cvmx_pko_initialize_global(void) |
| 49 | { | 186 | { |
| 50 | int i; | ||
| 51 | uint64_t priority = 8; | ||
| 52 | union cvmx_pko_reg_cmd_buf config; | 187 | union cvmx_pko_reg_cmd_buf config; |
| 53 | 188 | ||
| 54 | /* | 189 | /* |
| @@ -62,9 +197,10 @@ void cvmx_pko_initialize_global(void) · 7 unmodified lines | |||
| 62 | 197 | ||
| 63 | cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); | 198 | cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); |
| 64 | 199 | ||
| 65 | for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) | 200 | /* |
| 66 | cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, | 201 | * Chip-specific setup. |
| 67 | &priority); | 202 | */ |
| 203 | __cvmx_pko_chip_init(); | ||
| 68 | 204 | ||
| 69 | /* | 205 | /* |
| 70 | * If we aren't using all of the queues optimize PKO's | 206 | * If we aren't using all of the queues optimize PKO's |
| @@ -212,6 +348,9 @@ cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, · 141 unmodified lines | |||
| 212 | int static_priority_base = -1; | 348 | int static_priority_base = -1; |
| 213 | int static_priority_end = -1; | 349 | int static_priority_end = -1; |
| 214 | 350 | ||
| 351 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
| 352 | return CVMX_PKO_SUCCESS; | ||
| 353 | |||
| 215 | if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) | 354 | if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) |
| 216 | && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) { | 355 | && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) { |
| 217 | cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", | 356 | cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", |
| @@ -225,13 +225,14 @@ static int next_cpu_for_irq(struct irq_data *data) · 224 unmodified lines | |||
| 225 | 225 | ||
| 226 | #ifdef CONFIG_SMP | 226 | #ifdef CONFIG_SMP |
| 227 | int cpu; | 227 | int cpu; |
| 228 | int weight = cpumask_weight(data->affinity); | 228 | struct cpumask *mask = irq_data_get_affinity_mask(data); |
| 229 | int weight = cpumask_weight(mask); | ||
| 229 | struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data); | 230 | struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data); |
| 230 | 231 | ||
| 231 | if (weight > 1) { | 232 | if (weight > 1) { |
| 232 | cpu = cd->current_cpu; | 233 | cpu = cd->current_cpu; |
| 233 | for (;;) { | 234 | for (;;) { |
| 234 | cpu = cpumask_next(cpu, data->affinity); | 235 | cpu = cpumask_next(cpu, mask); |
| 235 | if (cpu >= nr_cpu_ids) { | 236 | if (cpu >= nr_cpu_ids) { |
| 236 | cpu = -1; | 237 | cpu = -1; |
| 237 | continue; | 238 | continue; |
| @@ -240,7 +241,7 @@ static int next_cpu_for_irq(struct irq_data *data) · 2 unmodified lines | |||
| 240 | } | 241 | } |
| 241 | } | 242 | } |
| 242 | } else if (weight == 1) { | 243 | } else if (weight == 1) { |
| 243 | cpu = cpumask_first(data->affinity); | 244 | cpu = cpumask_first(mask); |
| 244 | } else { | 245 | } else { |
| 245 | cpu = smp_processor_id(); | 246 | cpu = smp_processor_id(); |
| 246 | } | 247 | } |
| @@ -662,6 +663,11 @@ static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t) · 415 unmodified lines | |||
| 662 | irqd_set_trigger_type(data, t); | 663 | irqd_set_trigger_type(data, t); |
| 663 | octeon_irq_gpio_setup(data); | 664 | octeon_irq_gpio_setup(data); |
| 664 | 665 | ||
| 666 | if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH) | ||
| 667 | irq_set_handler_locked(data, handle_edge_irq); | ||
| 668 | else | ||
| 669 | irq_set_handler_locked(data, handle_level_irq); | ||
| 670 | |||
| 665 | return IRQ_SET_MASK_OK; | 671 | return IRQ_SET_MASK_OK; |
| 666 | } | 672 | } |
| 667 | 673 | ||
| @@ -696,32 +702,23 @@ static void octeon_irq_ciu_gpio_ack(struct irq_data *data) · 28 unmodified lines | |||
| 696 | cvmx_write_csr(CVMX_GPIO_INT_CLR, mask); | 702 | cvmx_write_csr(CVMX_GPIO_INT_CLR, mask); |
| 697 | } | 703 | } |
| 698 | 704 | ||
| 699 | static void octeon_irq_handle_trigger(unsigned int irq, struct irq_desc *desc) | ||
| 700 | { | ||
| 701 | struct irq_data *data = irq_desc_get_irq_data(desc); | ||
| 702 | |||
| 703 | if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH) | ||
| 704 | handle_edge_irq(irq, desc); | ||
| 705 | else | ||
| 706 | handle_level_irq(irq, desc); | ||
| 707 | } | ||
| 708 | |||
| 709 | #ifdef CONFIG_SMP | 705 | #ifdef CONFIG_SMP |
| 710 | 706 | ||
| 711 | static void octeon_irq_cpu_offline_ciu(struct irq_data *data) | 707 | static void octeon_irq_cpu_offline_ciu(struct irq_data *data) |
| 712 | { | 708 | { |
| 713 | int cpu = smp_processor_id(); | 709 | int cpu = smp_processor_id(); |
| 714 | cpumask_t new_affinity; | 710 | cpumask_t new_affinity; |
| 711 | struct cpumask *mask = irq_data_get_affinity_mask(data); | ||
| 715 | 712 | ||
| 716 | if (!cpumask_test_cpu(cpu, data->affinity)) | 713 | if (!cpumask_test_cpu(cpu, mask)) |
| 717 | return; | 714 | return; |
| 718 | 715 | ||
| 719 | if (cpumask_weight(data->affinity) > 1) { | 716 | if (cpumask_weight(mask) > 1) { |
| 720 | /* | 717 | /* |
| 721 | * It has multi CPU affinity, just remove this CPU | 718 | * It has multi CPU affinity, just remove this CPU |
| 722 | * from the affinity set. | 719 | * from the affinity set. |
| 723 | */ | 720 | */ |
| 724 | cpumask_copy(&new_affinity, data->affinity); | 721 | cpumask_copy(&new_affinity, mask); |
| 725 | cpumask_clear_cpu(cpu, &new_affinity); | 722 | cpumask_clear_cpu(cpu, &new_affinity); |
| 726 | } else { | 723 | } else { |
| 727 | /* Otherwise, put it on lowest numbered online CPU. */ | 724 | /* Otherwise, put it on lowest numbered online CPU. */ |
| @@ -1227,8 +1224,13 @@ static int octeon_irq_gpio_map(struct irq_domain *d, · 499 unmodified lines | |||
| 1227 | octeon_irq_ciu_to_irq[line][bit] != 0) | 1224 | octeon_irq_ciu_to_irq[line][bit] != 0) |
| 1228 | return -EINVAL; | 1225 | return -EINVAL; |
| 1229 | 1226 | ||
| 1227 | /* | ||
| 1228 | * Default to handle_level_irq. If the DT contains a different | ||
| 1229 | * trigger type, it will call the irq_set_type callback and | ||
| 1230 | * the handler gets updated. | ||
| 1231 | */ | ||
| 1230 | r = octeon_irq_set_ciu_mapping(virq, line, bit, hw, | 1232 | r = octeon_irq_set_ciu_mapping(virq, line, bit, hw, |
| 1231 | octeon_irq_gpio_chip, octeon_irq_handle_trigger); | 1233 | octeon_irq_gpio_chip, handle_level_irq); |
| 1232 | return r; | 1234 | return r; |
| 1233 | } | 1235 | } |
| 1234 | 1236 | ||
| @@ -16,6 +16,5 @@ generic-y += sections.h · 15 unmodified lines | |||
| 16 | generic-y += segment.h | 16 | generic-y += segment.h |
| 17 | generic-y += serial.h | 17 | generic-y += serial.h |
| 18 | generic-y += trace_clock.h | 18 | generic-y += trace_clock.h |
| 19 | generic-y += ucontext.h | ||
| 20 | generic-y += user.h | 19 | generic-y += user.h |
| 21 | generic-y += xor.h | 20 | generic-y += xor.h |
| @@ -20,6 +20,10 @@ struct mips_abi { · 19 unmodified lines | |||
| 20 | struct pt_regs *regs, sigset_t *set); | 20 | struct pt_regs *regs, sigset_t *set); |
| 21 | const unsigned long rt_signal_return_offset; | 21 | const unsigned long rt_signal_return_offset; |
| 22 | const unsigned long restart; | 22 | const unsigned long restart; |
| 23 | |||
| 24 | unsigned off_sc_fpregs; | ||
| 25 | unsigned off_sc_fpc_csr; | ||
| 26 | unsigned off_sc_used_math; | ||
| 23 | }; | 27 | }; |
| 24 | 28 | ||
| 25 | #endif /* _ASM_ABI_H */ | 29 | #endif /* _ASM_ABI_H */ |
| @@ -232,6 +232,30 @@ · 231 unmodified lines | |||
| 232 | .set pop | 232 | .set pop |
| 233 | .endm | 233 | .endm |
| 234 | 234 | ||
| 235 | .macro ld_b wd, off, base | ||
| 236 | .set push | ||
| 237 | .set mips32r2 | ||
| 238 | .set msa | ||
| 239 | ld.b $w\wd, \off(\base) | ||
| 240 | .set pop | ||
| 241 | .endm | ||
| 242 | |||
| 243 | .macro ld_h wd, off, base | ||
| 244 | .set push | ||
| 245 | .set mips32r2 | ||
| 246 | .set msa | ||
| 247 | ld.h $w\wd, \off(\base) | ||
| 248 | .set pop | ||
| 249 | .endm | ||
| 250 | |||
| 251 | .macro ld_w wd, off, base | ||
| 252 | .set push | ||
| 253 | .set mips32r2 | ||
| 254 | .set msa | ||
| 255 | ld.w $w\wd, \off(\base) | ||
| 256 | .set pop | ||
| 257 | .endm | ||
| 258 | |||
| 235 | .macro ld_d wd, off, base | 259 | .macro ld_d wd, off, base |
| 236 | .set push | 260 | .set push |
| 237 | .set mips32r2 | 261 | .set mips32r2 |
| @@ -241,6 +265,30 @@ · 3 unmodified lines | |||
| 241 | .set pop | 265 | .set pop |
| 242 | .endm | 266 | .endm |
| 243 | 267 | ||
| 268 | .macro st_b wd, off, base | ||
| 269 | .set push | ||
| 270 | .set mips32r2 | ||
| 271 | .set msa | ||
| 272 | st.b $w\wd, \off(\base) | ||
| 273 | .set pop | ||
| 274 | .endm | ||
| 275 | |||
| 276 | .macro st_h wd, off, base | ||
| 277 | .set push | ||
| 278 | .set mips32r2 | ||
| 279 | .set msa | ||
| 280 | st.h $w\wd, \off(\base) | ||
| 281 | .set pop | ||
| 282 | .endm | ||
| 283 | |||
| 284 | .macro st_w wd, off, base | ||
| 285 | .set push | ||
| 286 | .set mips32r2 | ||
| 287 | .set msa | ||
| 288 | st.w $w\wd, \off(\base) | ||
| 289 | .set pop | ||
| 290 | .endm | ||
| 291 | |||
| 244 | .macro st_d wd, off, base | 292 | .macro st_d wd, off, base |
| 245 | .set push | 293 | .set push |
| 246 | .set mips32r2 | 294 | .set mips32r2 |
| @@ -290,7 +338,13 @@ · 43 unmodified lines | |||
| 290 | #ifdef CONFIG_CPU_MICROMIPS | 338 | #ifdef CONFIG_CPU_MICROMIPS |
| 291 | #define CFC_MSA_INSN 0x587e0056 | 339 | #define CFC_MSA_INSN 0x587e0056 |
| 292 | #define CTC_MSA_INSN 0x583e0816 | 340 | #define CTC_MSA_INSN 0x583e0816 |
| 341 | #define LDB_MSA_INSN 0x58000807 | ||
| 342 | #define LDH_MSA_INSN 0x58000817 | ||
| 343 | #define LDW_MSA_INSN 0x58000827 | ||
| 293 | #define LDD_MSA_INSN 0x58000837 | 344 | #define LDD_MSA_INSN 0x58000837 |
| 345 | #define STB_MSA_INSN 0x5800080f | ||
| 346 | #define STH_MSA_INSN 0x5800081f | ||
| 347 | #define STW_MSA_INSN 0x5800082f | ||
| 294 | #define STD_MSA_INSN 0x5800083f | 348 | #define STD_MSA_INSN 0x5800083f |
| 295 | #define COPY_UW_MSA_INSN 0x58f00056 | 349 | #define COPY_UW_MSA_INSN 0x58f00056 |
| 296 | #define COPY_UD_MSA_INSN 0x58f80056 | 350 | #define COPY_UD_MSA_INSN 0x58f80056 |
| @@ -299,7 +353,13 @@ · 2 unmodified lines | |||
| 299 | #else | 353 | #else |
| 300 | #define CFC_MSA_INSN 0x787e0059 | 354 | #define CFC_MSA_INSN 0x787e0059 |
| 301 | #define CTC_MSA_INSN 0x783e0819 | 355 | #define CTC_MSA_INSN 0x783e0819 |
| 356 | #define LDB_MSA_INSN 0x78000820 | ||
| 357 | #define LDH_MSA_INSN 0x78000821 | ||
| 358 | #define LDW_MSA_INSN 0x78000822 | ||
| 302 | #define LDD_MSA_INSN 0x78000823 | 359 | #define LDD_MSA_INSN 0x78000823 |
| 360 | #define STB_MSA_INSN 0x78000824 | ||
| 361 | #define STH_MSA_INSN 0x78000825 | ||
| 362 | #define STW_MSA_INSN 0x78000826 | ||
| 303 | #define STD_MSA_INSN 0x78000827 | 363 | #define STD_MSA_INSN 0x78000827 |
| 304 | #define COPY_UW_MSA_INSN 0x78f00059 | 364 | #define COPY_UW_MSA_INSN 0x78f00059 |
| 305 | #define COPY_UD_MSA_INSN 0x78f80059 | 365 | #define COPY_UD_MSA_INSN 0x78f80059 |
| @@ -329,6 +389,33 @@ · 23 unmodified lines | |||
| 329 | .set pop | 389 | .set pop |
| 330 | .endm | 390 | .endm |
| 331 | 391 | ||
| 392 | .macro ld_b wd, off, base | ||
| 393 | .set push | ||
| 394 | .set noat | ||
| 395 | SET_HARDFLOAT | ||
| 396 | addu $1, \base, \off | ||
| 397 | .word LDB_MSA_INSN | (\wd << 6) | ||
| 398 | .set pop | ||
| 399 | .endm | ||
| 400 | |||
| 401 | .macro ld_h wd, off, base | ||
| 402 | .set push | ||
| 403 | .set noat | ||
| 404 | SET_HARDFLOAT | ||
| 405 | addu $1, \base, \off | ||
| 406 | .word LDH_MSA_INSN | (\wd << 6) | ||
| 407 | .set pop | ||
| 408 | .endm | ||
| 409 | |||
| 410 | .macro ld_w wd, off, base | ||
| 411 | .set push | ||
| 412 | .set noat | ||
| 413 | SET_HARDFLOAT | ||
| 414 | addu $1, \base, \off | ||
| 415 | .word LDW_MSA_INSN | (\wd << 6) | ||
| 416 | .set pop | ||
| 417 | .endm | ||
| 418 | |||
| 332 | .macro ld_d wd, off, base | 419 | .macro ld_d wd, off, base |
| 333 | .set push | 420 | .set push |
| 334 | .set noat | 421 | .set noat |
| @@ -338,6 +425,33 @@ · 3 unmodified lines | |||
| 338 | .set pop | 425 | .set pop |
| 339 | .endm | 426 | .endm |
| 340 | 427 | ||
| 428 | .macro st_b wd, off, base | ||
| 429 | .set push | ||
| 430 | .set noat | ||
| 431 | SET_HARDFLOAT | ||
| 432 | addu $1, \base, \off | ||
| 433 | .word STB_MSA_INSN | (\wd << 6) | ||
| 434 | .set pop | ||
| 435 | .endm | ||
| 436 | |||
| 437 | .macro st_h wd, off, base | ||
| 438 | .set push | ||
| 439 | .set noat | ||
| 440 | SET_HARDFLOAT | ||
| 441 | addu $1, \base, \off | ||
| 442 | .word STH_MSA_INSN | (\wd << 6) | ||
| 443 | .set pop | ||
| 444 | .endm | ||
| 445 | |||
| 446 | .macro st_w wd, off, base | ||
| 447 | .set push | ||
| 448 | .set noat | ||
| 449 | SET_HARDFLOAT | ||
| 450 | addu $1, \base, \off | ||
| 451 | .word STW_MSA_INSN | (\wd << 6) | ||
| 452 | .set pop | ||
| 453 | .endm | ||
| 454 | |||
| 341 | .macro st_d wd, off, base | 455 | .macro st_d wd, off, base |
| 342 | .set push | 456 | .set push |
| 343 | .set noat | 457 | .set noat |
| @@ -53,7 +53,7 @@ struct mips_cdmm_driver { · 52 unmodified lines | |||
| 53 | * mips_cdmm_phys_base() - Choose a physical base address for CDMM region. | 53 | * mips_cdmm_phys_base() - Choose a physical base address for CDMM region. |
| 54 | * | 54 | * |
| 55 | * Picking a suitable physical address at which to map the CDMM region is | 55 | * Picking a suitable physical address at which to map the CDMM region is |
| 56 | * platform specific, so this weak function can be defined by platform code to | 56 | * platform specific, so this function can be defined by platform code to |
| 57 | * pick a suitable value if none is configured by the bootloader. | 57 | * pick a suitable value if none is configured by the bootloader. |
| 58 | * | 58 | * |
| 59 | * This address must be 32kB aligned, and the region occupies a maximum of 32kB | 59 | * This address must be 32kB aligned, and the region occupies a maximum of 32kB |
| @@ -61,7 +61,7 @@ struct mips_cdmm_driver { · 1 unmodified line | |||
| 61 | * | 61 | * |
| 62 | * Returns: Physical base address for CDMM region, or 0 on failure. | 62 | * Returns: Physical base address for CDMM region, or 0 on failure. |
| 63 | */ | 63 | */ |
| 64 | phys_addr_t __weak mips_cdmm_phys_base(void); | 64 | phys_addr_t mips_cdmm_phys_base(void); |
| 65 | 65 | ||
| 66 | extern struct bus_type mips_cdmm_bustype; | 66 | extern struct bus_type mips_cdmm_bustype; |
| 67 | void __iomem *mips_cdmm_early_probe(unsigned int dev_type); | 67 | void __iomem *mips_cdmm_early_probe(unsigned int dev_type); |
| @@ -21,7 +21,6 @@ DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device); · 20 unmodified lines | |||
| 21 | 21 | ||
| 22 | void mips_event_handler(struct clock_event_device *dev); | 22 | void mips_event_handler(struct clock_event_device *dev); |
| 23 | int c0_compare_int_usable(void); | 23 | int c0_compare_int_usable(void); |
| 24 | void mips_set_clock_mode(enum clock_event_mode, struct clock_event_device *); | ||
| 25 | irqreturn_t c0_compare_interrupt(int, void *); | 24 | irqreturn_t c0_compare_interrupt(int, void *); |
| 26 | 25 | ||
| 27 | extern struct irqaction c0_compare_irqaction; | 26 | extern struct irqaction c0_compare_irqaction; |
| @@ -411,4 +411,8 @@ · 410 unmodified lines | |||
| 411 | # define cpu_has_cdmm (cpu_data[0].options & MIPS_CPU_CDMM) | 411 | # define cpu_has_cdmm (cpu_data[0].options & MIPS_CPU_CDMM) |
| 412 | #endif | 412 | #endif |
| 413 | 413 | ||
| 414 | #ifndef cpu_has_small_pages | ||
| 415 | # define cpu_has_small_pages (cpu_data[0].options & MIPS_CPU_SP) | ||
| 416 | #endif | ||
| 417 | |||
| 414 | #endif /* __ASM_CPU_FEATURES_H */ | 418 | #endif /* __ASM_CPU_FEATURES_H */ |
| @@ -77,6 +77,10 @@ static inline int __pure __get_cpu_type(const int cpu_type) · 76 unmodified lines | |||
| 77 | */ | 77 | */ |
| 78 | #endif | 78 | #endif |
| 79 | 79 | ||
| 80 | #ifdef CONFIG_SYS_HAS_CPU_MIPS64_R6 | ||
| 81 | case CPU_I6400: | ||
| 82 | #endif | ||
| 83 | |||
| 80 | #ifdef CONFIG_SYS_HAS_CPU_R3000 | 84 | #ifdef CONFIG_SYS_HAS_CPU_R3000 |
| 81 | case CPU_R2000: | 85 | case CPU_R2000: |
| 82 | case CPU_R3000: | 86 | case CPU_R3000: |
| @@ -120,6 +120,7 @@ · 119 unmodified lines | |||
| 120 | #define PRID_IMP_PROAPTIV_MP 0xa300 | 120 | #define PRID_IMP_PROAPTIV_MP 0xa300 |
| 121 | #define PRID_IMP_M5150 0xa700 | 121 | #define PRID_IMP_M5150 0xa700 |
| 122 | #define PRID_IMP_P5600 0xa800 | 122 | #define PRID_IMP_P5600 0xa800 |
| 123 | #define PRID_IMP_I6400 0xa900 | ||
| 123 | 124 | ||
| 124 | /* | 125 | /* |
| 125 | * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE | 126 | * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE |
| @@ -307,6 +308,7 @@ enum cpu_type_enum { · 181 unmodified lines | |||
| 307 | CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, | 308 | CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, |
| 308 | CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, | 309 | CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, |
| 309 | CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, CPU_M5150, | 310 | CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, CPU_M5150, |
| 311 | CPU_I6400, | ||
| 310 | 312 | ||
| 311 | /* | 313 | /* |
| 312 | * MIPS64 class processors | 314 | * MIPS64 class processors |
| @@ -382,6 +384,7 @@ enum cpu_type_enum { · 69 unmodified lines | |||
| 382 | #define MIPS_CPU_XPA 0x2000000000ull /* CPU supports Extended Physical Addressing */ | 384 | #define MIPS_CPU_XPA 0x2000000000ull /* CPU supports Extended Physical Addressing */ |
| 383 | #define MIPS_CPU_CDMM 0x4000000000ull /* CPU has Common Device Memory Map */ | 385 | #define MIPS_CPU_CDMM 0x4000000000ull /* CPU has Common Device Memory Map */ |
| 384 | #define MIPS_CPU_BP_GHIST 0x8000000000ull /* R12K+ Branch Prediction Global History */ | 386 | #define MIPS_CPU_BP_GHIST 0x8000000000ull /* R12K+ Branch Prediction Global History */ |
| 387 | #define MIPS_CPU_SP 0x10000000000ull /* Small (1KB) page support */ | ||
| 385 | 388 | ||
| 386 | /* | 389 | /* |
| 387 | * CPU ASE encodings | 390 | * CPU ASE encodings |
| @@ -1,48 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Debug macros for run-time debugging. | ||
| 3 | * Turned on/off with CONFIG_RUNTIME_DEBUG option. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2001 MontaVista Software Inc. | ||
| 6 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef _ASM_DEBUG_H | ||
| 16 | #define _ASM_DEBUG_H | ||
| 17 | |||
| 18 | |||
| 19 | /* | ||
| 20 | * run-time macros for catching spurious errors. Eable CONFIG_RUNTIME_DEBUG in | ||
| 21 | * kernel hacking config menu to use them. | ||
| 22 | * | ||
| 23 | * Use them as run-time debugging aid. NEVER USE THEM AS ERROR HANDLING CODE!!! | ||
| 24 | */ | ||
| 25 | |||
| 26 | #ifdef CONFIG_RUNTIME_DEBUG | ||
| 27 | |||
| 28 | #include <linux/kernel.h> | ||
| 29 | |||
| 30 | #define db_assert(x) if (!(x)) { \ | ||
| 31 | panic("assertion failed at %s:%d: %s", __FILE__, __LINE__, #x); } | ||
| 32 | #define db_warn(x) if (!(x)) { \ | ||
| 33 | printk(KERN_WARNING "warning at %s:%d: %s", __FILE__, __LINE__, #x); } | ||
| 34 | #define db_verify(x, y) db_assert(x y) | ||
| 35 | #define db_verify_warn(x, y) db_warn(x y) | ||
| 36 | #define db_run(x) do { x; } while (0) | ||
| 37 | |||
| 38 | #else | ||
| 39 | |||
| 40 | #define db_assert(x) | ||
| 41 | #define db_warn(x) | ||
| 42 | #define db_verify(x, y) x | ||
| 43 | #define db_verify_warn(x, y) x | ||
| 44 | #define db_run(x) | ||
| 45 | |||
| 46 | #endif | ||
| 47 | |||
| 48 | #endif /* _ASM_DEBUG_H */ | ||
| @@ -382,7 +382,9 @@ do { \ · 381 unmodified lines | |||
| 382 | instruction set this cpu supports. This could be done in userspace, | 382 | instruction set this cpu supports. This could be done in userspace, |
| 383 | but it's not easy, and we've already done it here. */ | 383 | but it's not easy, and we've already done it here. */ |
| 384 | 384 | ||
| 385 | #define ELF_HWCAP (0) | 385 | #define ELF_HWCAP (elf_hwcap) |
| 386 | extern unsigned int elf_hwcap; | ||
| 387 | #include <asm/hwcap.h> | ||
| 386 | 388 | ||
| 387 | /* | 389 | /* |
| 388 | * This yields a string that ld.so will use to load implementation | 390 | * This yields a string that ld.so will use to load implementation |
| @@ -164,25 +164,30 @@ static inline int own_fpu(int restore) · 163 unmodified lines | |||
| 164 | return ret; | 164 | return ret; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static inline void lose_fpu(int save) | 167 | static inline void lose_fpu_inatomic(int save, struct task_struct *tsk) |
| 168 | { | 168 | { |
| 169 | preempt_disable(); | ||
| 170 | if (is_msa_enabled()) { | 169 | if (is_msa_enabled()) { |
| 171 | if (save) { | 170 | if (save) { |
| 172 | save_msa(current); | 171 | save_msa(tsk); |
| 173 | current->thread.fpu.fcr31 = | 172 | tsk->thread.fpu.fcr31 = |
| 174 | read_32bit_cp1_register(CP1_STATUS); | 173 | read_32bit_cp1_register(CP1_STATUS); |
| 175 | } | 174 | } |
| 176 | disable_msa(); | 175 | disable_msa(); |
| 177 | clear_thread_flag(TIF_USEDMSA); | 176 | clear_tsk_thread_flag(tsk, TIF_USEDMSA); |
| 178 | __disable_fpu(); | 177 | __disable_fpu(); |
| 179 | } else if (is_fpu_owner()) { | 178 | } else if (is_fpu_owner()) { |
| 180 | if (save) | 179 | if (save) |
| 181 | _save_fp(current); | 180 | _save_fp(tsk); |
| 182 | __disable_fpu(); | 181 | __disable_fpu(); |
| 183 | } | 182 | } |
| 184 | KSTK_STATUS(current) &= ~ST0_CU1; | 183 | KSTK_STATUS(tsk) &= ~ST0_CU1; |
| 185 | clear_thread_flag(TIF_USEDFPU); | 184 | clear_tsk_thread_flag(tsk, TIF_USEDFPU); |
| 185 | } | ||
| 186 | |||
| 187 | static inline void lose_fpu(int save) | ||
| 188 | { | ||
| 189 | preempt_disable(); | ||
| 190 | lose_fpu_inatomic(save, current); | ||
| 186 | preempt_enable(); | 191 | preempt_enable(); |
| 187 | } | 192 | } |
| 188 | 193 | ||
| @@ -1,6 +0,0 @@ | |||
| 1 | #ifndef __ASM_MIPS_GPIO_H | ||
| 2 | #define __ASM_MIPS_GPIO_H | ||
| 3 | |||
| 4 | #include <gpio.h> | ||
| 5 | |||
| 6 | #endif /* __ASM_MIPS_GPIO_H */ | ||
| @@ -49,7 +49,7 @@ extern int cp0_compare_irq_shift; · 48 unmodified lines | |||
| 49 | extern int cp0_perfcount_irq; | 49 | extern int cp0_perfcount_irq; |
| 50 | extern int cp0_fdc_irq; | 50 | extern int cp0_fdc_irq; |
| 51 | 51 | ||
| 52 | extern int __weak get_c0_fdc_int(void); | 52 | extern int get_c0_fdc_int(void); |
| 53 | 53 | ||
| 54 | void arch_trigger_all_cpu_backtrace(bool); | 54 | void arch_trigger_all_cpu_backtrace(bool); |
| 55 | #define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace | 55 | #define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace |
| @@ -11,7 +11,9 @@ enum die_val { · 10 unmodified lines | |||
| 11 | DIE_PAGE_FAULT, | 11 | DIE_PAGE_FAULT, |
| 12 | DIE_BREAK, | 12 | DIE_BREAK, |
| 13 | DIE_SSTEPBP, | 13 | DIE_SSTEPBP, |
| 14 | DIE_MSAFP | 14 | DIE_MSAFP, |
| 15 | DIE_UPROBE, | ||
| 16 | DIE_UPROBE_XOL, | ||
| 15 | }; | 17 | }; |
| 16 | 18 | ||
| 17 | #endif /* _ASM_MIPS_KDEBUG_H */ | 19 | #endif /* _ASM_MIPS_KDEBUG_H */ |
| @@ -5,7 +5,6 @@ · 4 unmodified lines | |||
| 5 | #include <asm/asm.h> | 5 | #include <asm/asm.h> |
| 6 | #endif | 6 | #endif |
| 7 | 7 | ||
| 8 | #define __weak __attribute__((weak)) | ||
| 9 | #define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall") | 8 | #define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall") |
| 10 | #define SYSCALL_ALIAS(alias, name) \ | 9 | #define SYSCALL_ALIAS(alias, name) \ |
| 11 | asm ( #alias " = " #name "\n\t.globl " #alias) | 10 | asm ( #alias " = " #name "\n\t.globl " #alias) |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | |||
| 26 | * | 26 | * |
| 27 | * Return: The number of MAAR pairs configured. | 27 | * Return: The number of MAAR pairs configured. |
| 28 | */ | 28 | */ |
| 29 | unsigned __weak platform_maar_init(unsigned num_pairs); | 29 | unsigned platform_maar_init(unsigned num_pairs); |
| 30 | 30 | ||
| 31 | /** | 31 | /** |
| 32 | * write_maar_pair() - write to a pair of MAARs | 32 | * write_maar_pair() - write to a pair of MAARs |
| @@ -203,4 +203,8 @@ static inline void ar7_device_off(u32 bit) · 202 unmodified lines | |||
| 203 | int __init ar7_gpio_init(void); | 203 | int __init ar7_gpio_init(void); |
| 204 | void __init ar7_init_clocks(void); | 204 | void __init ar7_init_clocks(void); |
| 205 | 205 | ||
| 206 | /* Board specific GPIO functions */ | ||
| 207 | int ar7_gpio_enable(unsigned gpio); | ||
| 208 | int ar7_gpio_disable(unsigned gpio); | ||
| 209 | |||
| 206 | #endif /* __AR7_H__ */ | 210 | #endif /* __AR7_H__ */ |
| @@ -1,41 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 Florian Fainelli <florian@openwrt.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef __AR7_GPIO_H__ | ||
| 20 | #define __AR7_GPIO_H__ | ||
| 21 | |||
| 22 | #include <asm/mach-ar7/ar7.h> | ||
| 23 | |||
| 24 | #define AR7_GPIO_MAX 32 | ||
| 25 | #define TITAN_GPIO_MAX 51 | ||
| 26 | #define NR_BUILTIN_GPIO TITAN_GPIO_MAX | ||
| 27 | |||
| 28 | #define gpio_to_irq(gpio) -1 | ||
| 29 | |||
| 30 | #define gpio_get_value __gpio_get_value | ||
| 31 | #define gpio_set_value __gpio_set_value | ||
| 32 | |||
| 33 | #define gpio_cansleep __gpio_cansleep | ||
| 34 | |||
| 35 | /* Board specific GPIO functions */ | ||
| 36 | int ar7_gpio_enable(unsigned gpio); | ||
| 37 | int ar7_gpio_disable(unsigned gpio); | ||
| 38 | |||
| 39 | #include <asm-generic/gpio.h> | ||
| 40 | |||
| 41 | #endif | ||
| @@ -1,16 +0,0 @@ | |||
| 1 | #ifndef __ASM_MACH_ATH25_GPIO_H | ||
| 2 | #define __ASM_MACH_ATH25_GPIO_H | ||
| 3 | |||
| 4 | #include <asm-generic/gpio.h> | ||
| 5 | |||
| 6 | #define gpio_get_value __gpio_get_value | ||
| 7 | #define gpio_set_value __gpio_set_value | ||
| 8 | #define gpio_cansleep __gpio_cansleep | ||
| 9 | #define gpio_to_irq __gpio_to_irq | ||
| 10 | |||
| 11 | static inline int irq_to_gpio(unsigned irq) | ||
| 12 | { | ||
| 13 | return -EINVAL; | ||
| 14 | } | ||
| 15 | |||
| 16 | #endif /* __ASM_MACH_ATH25_GPIO_H */ | ||
| @@ -1,26 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR71XX/AR724X/AR913X GPIO API definitions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published | ||
| 9 | * by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef __ASM_MACH_ATH79_GPIO_H | ||
| 14 | #define __ASM_MACH_ATH79_GPIO_H | ||
| 15 | |||
| 16 | #define ARCH_NR_GPIOS 64 | ||
| 17 | #include <asm-generic/gpio.h> | ||
| 18 | |||
| 19 | int gpio_to_irq(unsigned gpio); | ||
| 20 | int irq_to_gpio(unsigned irq); | ||
| 21 | int gpio_get_value(unsigned gpio); | ||
| 22 | void gpio_set_value(unsigned gpio, int value); | ||
| 23 | |||
| 24 | #define gpio_cansleep __gpio_cansleep | ||
| 25 | |||
| 26 | #endif /* __ASM_MACH_ATH79_GPIO_H */ | ||
| @@ -266,6 +266,17 @@ static inline int alchemy_gpio1_to_irq(int gpio) · 265 unmodified lines | |||
| 266 | return -ENXIO; | 266 | return -ENXIO; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | /* On Au1000, Au1500 and Au1100 GPIOs won't work as inputs before | ||
| 270 | * SYS_PININPUTEN is written to at least once. On Au1550/Au1200/Au1300 this | ||
| 271 | * register enables use of GPIOs as wake source. | ||
| 272 | */ | ||
| 273 | static inline void alchemy_gpio1_input_enable(void) | ||
| 274 | { | ||
| 275 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); | ||
| 276 | __raw_writel(0, base + 0x110); /* the write op is key */ | ||
| 277 | wmb(); | ||
| 278 | } | ||
| 279 | |||
| 269 | /* | 280 | /* |
| 270 | * GPIO2 block macros for common linux GPIO functions. The 'gpio' | 281 | * GPIO2 block macros for common linux GPIO functions. The 'gpio' |
| 271 | * parameter must be in range of ALCHEMY_GPIO2_BASE..ALCHEMY_GPIO2_MAX. | 282 | * parameter must be in range of ALCHEMY_GPIO2_BASE..ALCHEMY_GPIO2_MAX. |
| @@ -518,141 +529,4 @@ static inline int alchemy_irq_to_gpio(int irq) · 246 unmodified lines | |||
| 518 | return -ENXIO; | 529 | return -ENXIO; |
| 519 | } | 530 | } |
| 520 | 531 | ||
| 521 | /**********************************************************************/ | ||
| 522 | |||
| 523 | /* Linux gpio framework integration. | ||
| 524 | * | ||
| 525 | * 4 use cases of Au1000-Au1200 GPIOS: | ||
| 526 | *(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y: | ||
| 527 | * Board must register gpiochips. | ||
| 528 | *(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n: | ||
| 529 | * 2 (1 for Au1000) gpio_chips are registered. | ||
| 530 | * | ||
| 531 | *(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y: | ||
| 532 | * the boards' gpio.h must provide the linux gpio wrapper functions, | ||
| 533 | * | ||
| 534 | *(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n: | ||
| 535 | * inlinable gpio functions are provided which enable access to the | ||
| 536 | * Au1000 gpios only by using the numbers straight out of the data- | ||
| 537 | * sheets. | ||
| 538 | |||
| 539 | * Cases 1 and 3 are intended for boards which want to provide their own | ||
| 540 | * GPIO namespace and -operations (i.e. for example you have 8 GPIOs | ||
| 541 | * which are in part provided by spare Au1000 GPIO pins and in part by | ||
| 542 | * an external FPGA but you still want them to be accssible in linux | ||
| 543 | * as gpio0-7. The board can of course use the alchemy_gpioX_* functions | ||
| 544 | * as required). | ||
| 545 | */ | ||
| 546 | |||
| 547 | #ifndef CONFIG_GPIOLIB | ||
| 548 | |||
| 549 | #ifdef CONFIG_ALCHEMY_GPIOINT_AU1000 | ||
| 550 | |||
| 551 | #ifndef CONFIG_ALCHEMY_GPIO_INDIRECT /* case (4) */ | ||
| 552 | |||
| 553 | static inline int gpio_direction_input(int gpio) | ||
| 554 | { | ||
| 555 | return alchemy_gpio_direction_input(gpio); | ||
| 556 | } | ||
| 557 | |||
| 558 | static inline int gpio_direction_output(int gpio, int v) | ||
| 559 | { | ||
| 560 | return alchemy_gpio_direction_output(gpio, v); | ||
| 561 | } | ||
| 562 | |||
| 563 | static inline int gpio_get_value(int gpio) | ||
| 564 | { | ||
| 565 | return alchemy_gpio_get_value(gpio); | ||
| 566 | } | ||
| 567 | |||
| 568 | static inline void gpio_set_value(int gpio, int v) | ||
| 569 | { | ||
| 570 | alchemy_gpio_set_value(gpio, v); | ||
| 571 | } | ||
| 572 | |||
| 573 | static inline int gpio_get_value_cansleep(unsigned gpio) | ||
| 574 | { | ||
| 575 | return gpio_get_value(gpio); | ||
| 576 | } | ||
| 577 | |||
| 578 | static inline void gpio_set_value_cansleep(unsigned gpio, int value) | ||
| 579 | { | ||
| 580 | gpio_set_value(gpio, value); | ||
| 581 | } | ||
| 582 | |||
| 583 | static inline int gpio_is_valid(int gpio) | ||
| 584 | { | ||
| 585 | return alchemy_gpio_is_valid(gpio); | ||
| 586 | } | ||
| 587 | |||
| 588 | static inline int gpio_cansleep(int gpio) | ||
| 589 | { | ||
| 590 | return alchemy_gpio_cansleep(gpio); | ||
| 591 | } | ||
| 592 | |||
| 593 | static inline int gpio_to_irq(int gpio) | ||
| 594 | { | ||
| 595 | return alchemy_gpio_to_irq(gpio); | ||
| 596 | } | ||
| 597 | |||
| 598 | static inline int irq_to_gpio(int irq) | ||
| 599 | { | ||
| 600 | return alchemy_irq_to_gpio(irq); | ||
| 601 | } | ||
| 602 | |||
| 603 | static inline int gpio_request(unsigned gpio, const char *label) | ||
| 604 | { | ||
| 605 | return 0; | ||
| 606 | } | ||
| 607 | |||
| 608 | static inline int gpio_request_one(unsigned gpio, | ||
| 609 | unsigned long flags, const char *label) | ||
| 610 | { | ||
| 611 | return 0; | ||
| 612 | } | ||
| 613 | |||
| 614 | static inline int gpio_request_array(struct gpio *array, size_t num) | ||
| 615 | { | ||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 619 | static inline void gpio_free(unsigned gpio) | ||
| 620 | { | ||
| 621 | } | ||
| 622 | |||
| 623 | static inline void gpio_free_array(struct gpio *array, size_t num) | ||
| 624 | { | ||
| 625 | } | ||
| 626 | |||
| 627 | static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) | ||
| 628 | { | ||
| 629 | return -ENOSYS; | ||
| 630 | } | ||
| 631 | |||
| 632 | static inline int gpio_export(unsigned gpio, bool direction_may_change) | ||
| 633 | { | ||
| 634 | return -ENOSYS; | ||
| 635 | } | ||
| 636 | |||
| 637 | static inline int gpio_export_link(struct device *dev, const char *name, | ||
| 638 | unsigned gpio) | ||
| 639 | { | ||
| 640 | return -ENOSYS; | ||
| 641 | } | ||
| 642 | |||
| 643 | static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) | ||
| 644 | { | ||
| 645 | return -ENOSYS; | ||
| 646 | } | ||
| 647 | |||
| 648 | static inline void gpio_unexport(unsigned gpio) | ||
| 649 | { | ||
| 650 | } | ||
| 651 | |||
| 652 | #endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */ | ||
| 653 | |||
| 654 | #endif /* CONFIG_ALCHEMY_GPIOINT_AU1000 */ | ||
| 655 | |||
| 656 | #endif /* !CONFIG_GPIOLIB */ | ||
| 657 | |||
| 658 | #endif /* _ALCHEMY_GPIO_AU1000_H_ */ | 532 | #endif /* _ALCHEMY_GPIO_AU1000_H_ */ |
| @@ -1,86 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Alchemy GPIO support. | ||
| 3 | * | ||
| 4 | * With CONFIG_GPIOLIB=y different types of on-chip GPIO can be supported within | ||
| 5 | * the same kernel image. | ||
| 6 | * With CONFIG_GPIOLIB=n, your board must select ALCHEMY_GPIOINT_AU1XXX for the | ||
| 7 | * appropriate CPU type (AU1000 currently). | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef _ALCHEMY_GPIO_H_ | ||
| 11 | #define _ALCHEMY_GPIO_H_ | ||
| 12 | |||
| 13 | #include <asm/mach-au1x00/au1000.h> | ||
| 14 | #include <asm/mach-au1x00/gpio-au1000.h> | ||
| 15 | #include <asm/mach-au1x00/gpio-au1300.h> | ||
| 16 | |||
| 17 | /* On Au1000, Au1500 and Au1100 GPIOs won't work as inputs before | ||
| 18 | * SYS_PININPUTEN is written to at least once. On Au1550/Au1200/Au1300 this | ||
| 19 | * register enables use of GPIOs as wake source. | ||
| 20 | */ | ||
| 21 | static inline void alchemy_gpio1_input_enable(void) | ||
| 22 | { | ||
| 23 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); | ||
| 24 | __raw_writel(0, base + 0x110); /* the write op is key */ | ||
| 25 | wmb(); | ||
| 26 | } | ||
| 27 | |||
| 28 | |||
| 29 | /* Linux gpio framework integration. | ||
| 30 | * | ||
| 31 | * 4 use cases of Alchemy GPIOS: | ||
| 32 | *(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y: | ||
| 33 | * Board must register gpiochips. | ||
| 34 | *(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n: | ||
| 35 | * A gpiochip for the 75 GPIOs is registered. | ||
| 36 | * | ||
| 37 | *(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y: | ||
| 38 | * the boards' gpio.h must provide the linux gpio wrapper functions, | ||
| 39 | * | ||
| 40 | *(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n: | ||
| 41 | * inlinable gpio functions are provided which enable access to the | ||
| 42 | * Au1300 gpios only by using the numbers straight out of the data- | ||
| 43 | * sheets. | ||
| 44 | |||
| 45 | * Cases 1 and 3 are intended for boards which want to provide their own | ||
| 46 | * GPIO namespace and -operations (i.e. for example you have 8 GPIOs | ||
| 47 | * which are in part provided by spare Au1300 GPIO pins and in part by | ||
| 48 | * an external FPGA but you still want them to be accssible in linux | ||
| 49 | * as gpio0-7. The board can of course use the alchemy_gpioX_* functions | ||
| 50 | * as required). | ||
| 51 | */ | ||
| 52 | |||
| 53 | #ifdef CONFIG_GPIOLIB | ||
| 54 | |||
| 55 | /* wraps the cpu-dependent irq_to_gpio functions */ | ||
| 56 | /* FIXME: gpiolib needs an irq_to_gpio hook */ | ||
| 57 | static inline int __au_irq_to_gpio(unsigned int irq) | ||
| 58 | { | ||
| 59 | switch (alchemy_get_cputype()) { | ||
| 60 | case ALCHEMY_CPU_AU1000...ALCHEMY_CPU_AU1200: | ||
| 61 | return alchemy_irq_to_gpio(irq); | ||
| 62 | case ALCHEMY_CPU_AU1300: | ||
| 63 | return au1300_irq_to_gpio(irq); | ||
| 64 | } | ||
| 65 | return -EINVAL; | ||
| 66 | } | ||
| 67 | |||
| 68 | |||
| 69 | /* using gpiolib to provide up to 2 gpio_chips for on-chip gpios */ | ||
| 70 | #ifndef CONFIG_ALCHEMY_GPIO_INDIRECT /* case (2) */ | ||
| 71 | |||
| 72 | /* get everything through gpiolib */ | ||
| 73 | #define gpio_to_irq __gpio_to_irq | ||
| 74 | #define gpio_get_value __gpio_get_value | ||
| 75 | #define gpio_set_value __gpio_set_value | ||
| 76 | #define gpio_cansleep __gpio_cansleep | ||
| 77 | #define irq_to_gpio __au_irq_to_gpio | ||
| 78 | |||
| 79 | #include <asm-generic/gpio.h> | ||
| 80 | |||
| 81 | #endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */ | ||
| 82 | |||
| 83 | |||
| 84 | #endif /* CONFIG_GPIOLIB */ | ||
| 85 | |||
| 86 | #endif /* _ALCHEMY_GPIO_H_ */ | ||
| @@ -1,17 +0,0 @@ | |||
| 1 | #ifndef __ASM_MIPS_MACH_BCM47XX_GPIO_H | ||
| 2 | #define __ASM_MIPS_MACH_BCM47XX_GPIO_H | ||
| 3 | |||
| 4 | #include <asm-generic/gpio.h> | ||
| 5 | |||
| 6 | #define gpio_get_value __gpio_get_value | ||
| 7 | #define gpio_set_value __gpio_set_value | ||
| 8 | |||
| 9 | #define gpio_cansleep __gpio_cansleep | ||
| 10 | #define gpio_to_irq __gpio_to_irq | ||
| 11 | |||
| 12 | static inline int irq_to_gpio(unsigned int irq) | ||
| 13 | { | ||
| 14 | return -EINVAL; | ||
| 15 | } | ||
| 16 | |||
| 17 | #endif | ||
| @@ -1,15 +0,0 @@ | |||
| 1 | #ifndef __ASM_MIPS_MACH_BCM63XX_GPIO_H | ||
| 2 | #define __ASM_MIPS_MACH_BCM63XX_GPIO_H | ||
| 3 | |||
| 4 | #include <bcm63xx_gpio.h> | ||
| 5 | |||
| 6 | #define gpio_to_irq(gpio) -1 | ||
| 7 | |||
| 8 | #define gpio_get_value __gpio_get_value | ||
| 9 | #define gpio_set_value __gpio_set_value | ||
| 10 | |||
| 11 | #define gpio_cansleep __gpio_cansleep | ||
| 12 | |||
| 13 | #include <asm-generic/gpio.h> | ||
| 14 | |||
| 15 | #endif /* __ASM_MIPS_MACH_BCM63XX_GPIO_H */ | ||
| @@ -1,21 +0,0 @@ | |||
| 1 | #ifndef __ASM_MACH_CAVIUM_OCTEON_GPIO_H | ||
| 2 | #define __ASM_MACH_CAVIUM_OCTEON_GPIO_H | ||
| 3 | |||
| 4 | #ifdef CONFIG_GPIOLIB | ||
| 5 | #define gpio_get_value __gpio_get_value | ||
| 6 | #define gpio_set_value __gpio_set_value | ||
| 7 | #define gpio_cansleep __gpio_cansleep | ||
| 8 | #else | ||
| 9 | int gpio_request(unsigned gpio, const char *label); | ||
| 10 | void gpio_free(unsigned gpio); | ||
| 11 | int gpio_direction_input(unsigned gpio); | ||
| 12 | int gpio_direction_output(unsigned gpio, int value); | ||
| 13 | int gpio_get_value(unsigned gpio); | ||
| 14 | void gpio_set_value(unsigned gpio, int value); | ||
| 15 | #endif | ||
| 16 | |||
| 17 | #include <asm-generic/gpio.h> | ||
| 18 | |||
| 19 | #define gpio_to_irq __gpio_to_irq | ||
| 20 | |||
| 21 | #endif /* __ASM_MACH_GENERIC_GPIO_H */ | ||
| @@ -1,21 +0,0 @@ | |||
| 1 | #ifndef __ASM_MACH_GENERIC_GPIO_H | ||
| 2 | #define __ASM_MACH_GENERIC_GPIO_H | ||
| 3 | |||
| 4 | #ifdef CONFIG_GPIOLIB | ||
| 5 | #define gpio_get_value __gpio_get_value | ||
| 6 | #define gpio_set_value __gpio_set_value | ||
| 7 | #define gpio_cansleep __gpio_cansleep | ||
| 8 | #else | ||
| 9 | int gpio_request(unsigned gpio, const char *label); | ||
| 10 | void gpio_free(unsigned gpio); | ||
| 11 | int gpio_direction_input(unsigned gpio); | ||
| 12 | int gpio_direction_output(unsigned gpio, int value); | ||
| 13 | int gpio_get_value(unsigned gpio); | ||
| 14 | void gpio_set_value(unsigned gpio, int value); | ||
| 15 | #endif | ||
| 16 | int gpio_to_irq(unsigned gpio); | ||
| 17 | int irq_to_gpio(unsigned irq); | ||
| 18 | |||
| 19 | #include <asm-generic/gpio.h> /* cansleep wrappers */ | ||
| 20 | |||
| 21 | #endif /* __ASM_MACH_GENERIC_GPIO_H */ | ||
| @@ -73,8 +73,6 @@ int jz_gpio_port_direction_output(int port, uint32_t mask); · 72 unmodified lines | |||
| 73 | void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask); | 73 | void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask); |
| 74 | uint32_t jz_gpio_port_get_value(int port, uint32_t mask); | 74 | uint32_t jz_gpio_port_get_value(int port, uint32_t mask); |
| 75 | 75 | ||
| 76 | #include <asm/mach-generic/gpio.h> | ||
| 77 | |||
| 78 | #define JZ_GPIO_PORTA(x) ((x) + 32 * 0) | 76 | #define JZ_GPIO_PORTA(x) ((x) + 32 * 0) |
| 79 | #define JZ_GPIO_PORTB(x) ((x) + 32 * 1) | 77 | #define JZ_GPIO_PORTB(x) ((x) + 32 * 1) |
| 80 | #define JZ_GPIO_PORTC(x) ((x) + 32 * 2) | 78 | #define JZ_GPIO_PORTC(x) ((x) + 32 * 2) |
| @@ -1,13 +0,0 @@ | |||
| 1 | #ifndef __ASM_MIPS_MACH_LANTIQ_GPIO_H | ||
| 2 | #define __ASM_MIPS_MACH_LANTIQ_GPIO_H | ||
| 3 | |||
| 4 | #define gpio_to_irq __gpio_to_irq | ||
| 5 | |||
| 6 | #define gpio_get_value __gpio_get_value | ||
| 7 | #define gpio_set_value __gpio_set_value | ||
| 8 | |||
| 9 | #define gpio_cansleep __gpio_cansleep | ||
| 10 | |||
| 11 | #include <asm-generic/gpio.h> | ||
| 12 | |||
| 13 | #endif | ||
| @@ -1,36 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Loongson GPIO Support | ||
| 3 | * | ||
| 4 | * Copyright (c) 2008 Richard Liu, STMicroelectronics <richard.liu@st.com> | ||
| 5 | * Copyright (c) 2008-2010 Arnaud Patard <apatard@mandriva.com> | ||
| 6 | * Copyright (c) 2014 Huacai Chen <chenhc@lemote.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __LOONGSON_GPIO_H | ||
| 15 | #define __LOONGSON_GPIO_H | ||
| 16 | |||
| 17 | #include <asm-generic/gpio.h> | ||
| 18 | |||
| 19 | #define gpio_get_value __gpio_get_value | ||
| 20 | #define gpio_set_value __gpio_set_value | ||
| 21 | #define gpio_cansleep __gpio_cansleep | ||
| 22 | |||
| 23 | /* The chip can do interrupt | ||
| 24 | * but it has not been tested and doc not clear | ||
| 25 | */ | ||
| 26 | static inline int gpio_to_irq(int gpio) | ||
| 27 | { | ||
| 28 | return -EINVAL; | ||
| 29 | } | ||
| 30 | |||
| 31 | static inline int irq_to_gpio(int gpio) | ||
| 32 | { | ||
| 33 | return -EINVAL; | ||
| 34 | } | ||
| 35 | |||
| 36 | #endif /* __LOONGSON_GPIO_H */ | ||
| @@ -1,21 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Pistachio IRQ setup | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Google, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef __ASM_MACH_PISTACHIO_GPIO_H | ||
| 12 | #define __ASM_MACH_PISTACHIO_GPIO_H | ||
| 13 | |||
| 14 | #include <asm-generic/gpio.h> | ||
| 15 | |||
| 16 | #define gpio_get_value __gpio_get_value | ||
| 17 | #define gpio_set_value __gpio_set_value | ||
| 18 | #define gpio_cansleep __gpio_cansleep | ||
| 19 | #define gpio_to_irq __gpio_to_irq | ||
| 20 | |||
| 21 | #endif /* __ASM_MACH_PISTACHIO_GPIO_H */ | ||
| @@ -13,18 +13,6 @@ · 12 unmodified lines | |||
| 13 | #ifndef _RC32434_GPIO_H_ | 13 | #ifndef _RC32434_GPIO_H_ |
| 14 | #define _RC32434_GPIO_H_ | 14 | #define _RC32434_GPIO_H_ |
| 15 | 15 | ||
| 16 | #include <linux/types.h> | ||
| 17 | #include <asm-generic/gpio.h> | ||
| 18 | |||
| 19 | #define NR_BUILTIN_GPIO 32 | ||
| 20 | |||
| 21 | #define gpio_get_value __gpio_get_value | ||
| 22 | #define gpio_set_value __gpio_set_value | ||
| 23 | #define gpio_cansleep __gpio_cansleep | ||
| 24 | |||
| 25 | #define gpio_to_irq(gpio) (8 + 4 * 32 + gpio) | ||
| 26 | #define irq_to_gpio(irq) (irq - (8 + 4 * 32)) | ||
| 27 | |||
| 28 | struct rb532_gpio_reg { | 16 | struct rb532_gpio_reg { |
| 29 | u32 gpiofunc; /* GPIO Function Register | 17 | u32 gpiofunc; /* GPIO Function Register |
| 30 | * gpiofunc[x]==0 bit = gpio | 18 | * gpiofunc[x]==0 bit = gpio |
| @@ -33,6 +33,29 @@ extern void __iomem *mips_cm_l2sync_base; · 32 unmodified lines | |||
| 33 | */ | 33 | */ |
| 34 | extern phys_addr_t __mips_cm_phys_base(void); | 34 | extern phys_addr_t __mips_cm_phys_base(void); |
| 35 | 35 | ||
| 36 | /* | ||
| 37 | * mips_cm_is64 - determine CM register width | ||
| 38 | * | ||
| 39 | * The CM register width is processor and CM specific. A 64-bit processor | ||
| 40 | * usually has a 64-bit CM and a 32-bit one has a 32-bit CM but a 64-bit | ||
| 41 | * processor could come with a 32-bit CM. Moreover, accesses on 64-bit CMs | ||
| 42 | * can be done either using regular 64-bit load/store instructions, or 32-bit | ||
| 43 | * load/store instruction on 32-bit register pairs. We opt for using 64-bit | ||
| 44 | * accesses on 64-bit CMs and kernels and 32-bit in any other case. | ||
| 45 | * | ||
| 46 | * It's set to 0 for 32-bit accesses and 1 for 64-bit accesses. | ||
| 47 | */ | ||
| 48 | extern int mips_cm_is64; | ||
| 49 | |||
| 50 | /** | ||
| 51 | * mips_cm_error_report - Report CM cache errors | ||
| 52 | */ | ||
| 53 | #ifdef CONFIG_MIPS_CM | ||
| 54 | extern void mips_cm_error_report(void); | ||
| 55 | #else | ||
| 56 | static inline void mips_cm_error_report(void) {} | ||
| 57 | #endif | ||
| 58 | |||
| 36 | /** | 59 | /** |
| 37 | * mips_cm_probe - probe for a Coherence Manager | 60 | * mips_cm_probe - probe for a Coherence Manager |
| 38 | * | 61 | * |
| @@ -90,20 +113,46 @@ static inline bool mips_cm_has_l2sync(void) · 51 unmodified lines | |||
| 90 | 113 | ||
| 91 | /* Macros to ease the creation of register access functions */ | 114 | /* Macros to ease the creation of register access functions */ |
| 92 | #define BUILD_CM_R_(name, off) \ | 115 | #define BUILD_CM_R_(name, off) \ |
| 93 | static inline u32 __iomem *addr_gcr_##name(void) \ | 116 | static inline unsigned long __iomem *addr_gcr_##name(void) \ |
| 94 | { \ | 117 | { \ |
| 95 | return (u32 __iomem *)(mips_cm_base + (off)); \ | 118 | return (unsigned long __iomem *)(mips_cm_base + (off)); \ |
| 96 | } \ | 119 | } \ |
| 97 | \ | 120 | \ |
| 98 | static inline u32 read_gcr_##name(void) \ | 121 | static inline u32 read32_gcr_##name(void) \ |
| 99 | { \ | 122 | { \ |
| 100 | return __raw_readl(addr_gcr_##name()); \ | 123 | return __raw_readl(addr_gcr_##name()); \ |
| 124 | } \ | ||
| 125 | \ | ||
| 126 | static inline u64 read64_gcr_##name(void) \ | ||
| 127 | { \ | ||
| 128 | return __raw_readq(addr_gcr_##name()); \ | ||
| 129 | } \ | ||
| 130 | \ | ||
| 131 | static inline unsigned long read_gcr_##name(void) \ | ||
| 132 | { \ | ||
| 133 | if (mips_cm_is64) \ | ||
| 134 | return read64_gcr_##name(); \ | ||
| 135 | else \ | ||
| 136 | return read32_gcr_##name(); \ | ||
| 101 | } | 137 | } |
| 102 | 138 | ||
| 103 | #define BUILD_CM__W(name, off) \ | 139 | #define BUILD_CM__W(name, off) \ |
| 104 | static inline void write_gcr_##name(u32 value) \ | 140 | static inline void write32_gcr_##name(u32 value) \ |
| 105 | { \ | 141 | { \ |
| 106 | __raw_writel(value, addr_gcr_##name()); \ | 142 | __raw_writel(value, addr_gcr_##name()); \ |
| 143 | } \ | ||
| 144 | \ | ||
| 145 | static inline void write64_gcr_##name(u64 value) \ | ||
| 146 | { \ | ||
| 147 | __raw_writeq(value, addr_gcr_##name()); \ | ||
| 148 | } \ | ||
| 149 | \ | ||
| 150 | static inline void write_gcr_##name(unsigned long value) \ | ||
| 151 | { \ | ||
| 152 | if (mips_cm_is64) \ | ||
| 153 | write64_gcr_##name(value); \ | ||
| 154 | else \ | ||
| 155 | write32_gcr_##name(value); \ | ||
| 107 | } | 156 | } |
| 108 | 157 | ||
| 109 | #define BUILD_CM_RW(name, off) \ | 158 | #define BUILD_CM_RW(name, off) \ |
| @@ -144,6 +193,7 @@ BUILD_CM_RW(reg3_base, MIPS_CM_GCB_OFS + 0xc0) · 34 unmodified lines | |||
| 144 | BUILD_CM_RW(reg3_mask, MIPS_CM_GCB_OFS + 0xc8) | 193 | BUILD_CM_RW(reg3_mask, MIPS_CM_GCB_OFS + 0xc8) |
| 145 | BUILD_CM_R_(gic_status, MIPS_CM_GCB_OFS + 0xd0) | 194 | BUILD_CM_R_(gic_status, MIPS_CM_GCB_OFS + 0xd0) |
| 146 | BUILD_CM_R_(cpc_status, MIPS_CM_GCB_OFS + 0xf0) | 195 | BUILD_CM_R_(cpc_status, MIPS_CM_GCB_OFS + 0xf0) |
| 196 | BUILD_CM_RW(l2_config, MIPS_CM_GCB_OFS + 0x130) | ||
| 147 | 197 | ||
| 148 | /* Core Local & Core Other register accessor functions */ | 198 | /* Core Local & Core Other register accessor functions */ |
| 149 | BUILD_CM_Cx_RW(reset_release, 0x00) | 199 | BUILD_CM_Cx_RW(reset_release, 0x00) |
| @@ -189,6 +239,13 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) · 39 unmodified lines | |||
| 189 | #define CM_GCR_REV_MINOR_SHF 0 | 239 | #define CM_GCR_REV_MINOR_SHF 0 |
| 190 | #define CM_GCR_REV_MINOR_MSK (_ULCAST_(0xff) << 0) | 240 | #define CM_GCR_REV_MINOR_MSK (_ULCAST_(0xff) << 0) |
| 191 | 241 | ||
| 242 | #define CM_ENCODE_REV(major, minor) \ | ||
| 243 | (((major) << CM_GCR_REV_MAJOR_SHF) | \ | ||
| 244 | ((minor) << CM_GCR_REV_MINOR_SHF)) | ||
| 245 | |||
| 246 | #define CM_REV_CM2 CM_ENCODE_REV(6, 0) | ||
| 247 | #define CM_REV_CM3 CM_ENCODE_REV(8, 0) | ||
| 248 | |||
| 192 | /* GCR_ERROR_CAUSE register fields */ | 249 | /* GCR_ERROR_CAUSE register fields */ |
| 193 | #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27 | 250 | #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27 |
| 194 | #define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27) | 251 | #define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27) |
| @@ -249,6 +306,16 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) · 54 unmodified lines | |||
| 249 | #define CM_GCR_CPC_STATUS_EX_SHF 0 | 306 | #define CM_GCR_CPC_STATUS_EX_SHF 0 |
| 250 | #define CM_GCR_CPC_STATUS_EX_MSK (_ULCAST_(0x1) << 0) | 307 | #define CM_GCR_CPC_STATUS_EX_MSK (_ULCAST_(0x1) << 0) |
| 251 | 308 | ||
| 309 | /* GCR_L2_CONFIG register fields */ | ||
| 310 | #define CM_GCR_L2_CONFIG_BYPASS_SHF 20 | ||
| 311 | #define CM_GCR_L2_CONFIG_BYPASS_MSK (_ULCAST_(0x1) << 20) | ||
| 312 | #define CM_GCR_L2_CONFIG_SET_SIZE_SHF 12 | ||
| 313 | #define CM_GCR_L2_CONFIG_SET_SIZE_MSK (_ULCAST_(0xf) << 12) | ||
| 314 | #define CM_GCR_L2_CONFIG_LINE_SIZE_SHF 8 | ||
| 315 | #define CM_GCR_L2_CONFIG_LINE_SIZE_MSK (_ULCAST_(0xf) << 8) | ||
| 316 | #define CM_GCR_L2_CONFIG_ASSOC_SHF 0 | ||
| 317 | #define CM_GCR_L2_CONFIG_ASSOC_MSK (_ULCAST_(0xff) << 0) | ||
| 318 | |||
| 252 | /* GCR_Cx_COHERENCE register fields */ | 319 | /* GCR_Cx_COHERENCE register fields */ |
| 253 | #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0 | 320 | #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0 |
| 254 | #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK (_ULCAST_(0xff) << 0) | 321 | #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK (_ULCAST_(0xff) << 0) |
| @@ -324,4 +391,18 @@ static inline int mips_cm_l2sync(void) · 69 unmodified lines | |||
| 324 | return 0; | 391 | return 0; |
| 325 | } | 392 | } |
| 326 | 393 | ||
| 394 | /** | ||
| 395 | * mips_cm_revision() - return CM revision | ||
| 396 | * | ||
| 397 | * Return: The revision of the CM, from GCR_REV, or 0 if no CM is present. The | ||
| 398 | * return value should be checked against the CM_REV_* macros. | ||
| 399 | */ | ||
| 400 | static inline int mips_cm_revision(void) | ||
| 401 | { | ||
| 402 | if (!mips_cm_present()) | ||
| 403 | return 0; | ||
| 404 | |||
| 405 | return read_gcr_rev(); | ||
| 406 | } | ||
| 407 | |||
| 327 | #endif /* __MIPS_ASM_MIPS_CM_H__ */ | 408 | #endif /* __MIPS_ASM_MIPS_CM_H__ */ |
| @@ -27,16 +27,6 @@ extern void __iomem *mips_cpc_base; · 26 unmodified lines | |||
| 27 | */ | 27 | */ |
| 28 | extern phys_addr_t mips_cpc_default_phys_base(void); | 28 | extern phys_addr_t mips_cpc_default_phys_base(void); |
| 29 | 29 | ||
| 30 | /** | ||
| 31 | * mips_cpc_phys_base - retrieve the physical base address of the CPC | ||
| 32 | * | ||
| 33 | * This function returns the physical base address of the Cluster Power | ||
| 34 | * Controller memory mapped registers, or 0 if no Cluster Power Controller | ||
| 35 | * is present. It may be overriden by individual platforms which determine | ||
| 36 | * this address in a different way. | ||
| 37 | */ | ||
| 38 | extern phys_addr_t __weak mips_cpc_phys_base(void); | ||
| 39 | |||
| 40 | /** | 30 | /** |
| 41 | * mips_cpc_probe - probe for a Cluster Power Controller | 31 | * mips_cpc_probe - probe for a Cluster Power Controller |
| 42 | * | 32 | * |
| @@ -112,6 +112,30 @@ · 111 unmodified lines | |||
| 112 | #define CP0_TX39_CACHE $7 | 112 | #define CP0_TX39_CACHE $7 |
| 113 | 113 | ||
| 114 | 114 | ||
| 115 | /* Generic EntryLo bit definitions */ | ||
| 116 | #define ENTRYLO_G (_ULCAST_(1) << 0) | ||
| 117 | #define ENTRYLO_V (_ULCAST_(1) << 1) | ||
| 118 | #define ENTRYLO_D (_ULCAST_(1) << 2) | ||
| 119 | #define ENTRYLO_C_SHIFT 3 | ||
| 120 | #define ENTRYLO_C (_ULCAST_(7) << ENTRYLO_C_SHIFT) | ||
| 121 | |||
| 122 | /* R3000 EntryLo bit definitions */ | ||
| 123 | #define R3K_ENTRYLO_G (_ULCAST_(1) << 8) | ||
| 124 | #define R3K_ENTRYLO_V (_ULCAST_(1) << 9) | ||
| 125 | #define R3K_ENTRYLO_D (_ULCAST_(1) << 10) | ||
| 126 | #define R3K_ENTRYLO_N (_ULCAST_(1) << 11) | ||
| 127 | |||
| 128 | /* MIPS32/64 EntryLo bit definitions */ | ||
| 129 | #ifdef CONFIG_64BIT | ||
| 130 | /* as read by dmfc0 */ | ||
| 131 | #define MIPS_ENTRYLO_XI (_ULCAST_(1) << 62) | ||
| 132 | #define MIPS_ENTRYLO_RI (_ULCAST_(1) << 63) | ||
| 133 | #else | ||
| 134 | /* as read by mfc0 */ | ||
| 135 | #define MIPS_ENTRYLO_XI (_ULCAST_(1) << 30) | ||
| 136 | #define MIPS_ENTRYLO_RI (_ULCAST_(1) << 31) | ||
| 137 | #endif | ||
| 138 | |||
| 115 | /* | 139 | /* |
| 116 | * Values for PageMask register | 140 | * Values for PageMask register |
| 117 | */ | 141 | */ |
| @@ -203,6 +227,9 @@ · 85 unmodified lines | |||
| 203 | #define PG_ESP (_ULCAST_(1) << 28) | 227 | #define PG_ESP (_ULCAST_(1) << 28) |
| 204 | #define PG_IEC (_ULCAST_(1) << 27) | 228 | #define PG_IEC (_ULCAST_(1) << 27) |
| 205 | 229 | ||
| 230 | /* MIPS32/64 EntryHI bit definitions */ | ||
| 231 | #define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) | ||
| 232 | |||
| 206 | /* | 233 | /* |
| 207 | * R4x00 interrupt enable / cause bits | 234 | * R4x00 interrupt enable / cause bits |
| 208 | */ | 235 | */ |
| @@ -579,6 +606,8 @@ · 370 unmodified lines | |||
| 579 | 606 | ||
| 580 | #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) | 607 | #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) |
| 581 | #define MIPS_CONF7_AR (_ULCAST_(1) << 16) | 608 | #define MIPS_CONF7_AR (_ULCAST_(1) << 16) |
| 609 | /* FTLB probability bits for R6 */ | ||
| 610 | #define MIPS_CONF7_FTLBP_SHIFT (18) | ||
| 582 | 611 | ||
| 583 | /* MAAR bit definitions */ | 612 | /* MAAR bit definitions */ |
| 584 | #define MIPS_MAAR_ADDR ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12) | 613 | #define MIPS_MAAR_ADDR ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12) |
| @@ -586,31 +615,6 @@ · 1 unmodified line | |||
| 586 | #define MIPS_MAAR_S (_ULCAST_(1) << 1) | 615 | #define MIPS_MAAR_S (_ULCAST_(1) << 1) |
| 587 | #define MIPS_MAAR_V (_ULCAST_(1) << 0) | 616 | #define MIPS_MAAR_V (_ULCAST_(1) << 0) |
| 588 | 617 | ||
| 589 | /* EntryHI bit definition */ | ||
| 590 | #define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) | ||
| 591 | |||
| 592 | /* R3000 EntryLo bit definitions */ | ||
| 593 | #define R3K_ENTRYLO_G (_ULCAST_(1) << 8) | ||
| 594 | #define R3K_ENTRYLO_V (_ULCAST_(1) << 9) | ||
| 595 | #define R3K_ENTRYLO_D (_ULCAST_(1) << 10) | ||
| 596 | #define R3K_ENTRYLO_N (_ULCAST_(1) << 11) | ||
| 597 | |||
| 598 | /* R4000 compatible EntryLo bit definitions */ | ||
| 599 | #define MIPS_ENTRYLO_G (_ULCAST_(1) << 0) | ||
| 600 | #define MIPS_ENTRYLO_V (_ULCAST_(1) << 1) | ||
| 601 | #define MIPS_ENTRYLO_D (_ULCAST_(1) << 2) | ||
| 602 | #define MIPS_ENTRYLO_C_SHIFT 3 | ||
| 603 | #define MIPS_ENTRYLO_C (_ULCAST_(7) << MIPS_ENTRYLO_C_SHIFT) | ||
| 604 | #ifdef CONFIG_64BIT | ||
| 605 | /* as read by dmfc0 */ | ||
| 606 | #define MIPS_ENTRYLO_XI (_ULCAST_(1) << 62) | ||
| 607 | #define MIPS_ENTRYLO_RI (_ULCAST_(1) << 63) | ||
| 608 | #else | ||
| 609 | /* as read by mfc0 */ | ||
| 610 | #define MIPS_ENTRYLO_XI (_ULCAST_(1) << 30) | ||
| 611 | #define MIPS_ENTRYLO_RI (_ULCAST_(1) << 31) | ||
| 612 | #endif | ||
| 613 | |||
| 614 | /* CMGCRBase bit definitions */ | 618 | /* CMGCRBase bit definitions */ |
| 615 | #define MIPS_CMGCRB_BASE 11 | 619 | #define MIPS_CMGCRB_BASE 11 |
| 616 | #define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1)) | 620 | #define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1)) |
| @@ -932,7 +936,7 @@ do { \ · 315 unmodified lines | |||
| 932 | */ | 936 | */ |
| 933 | 937 | ||
| 934 | #define __read_32bit_c0_register(source, sel) \ | 938 | #define __read_32bit_c0_register(source, sel) \ |
| 935 | ({ int __res; \ | 939 | ({ unsigned int __res; \ |
| 936 | if (sel == 0) \ | 940 | if (sel == 0) \ |
| 937 | __asm__ __volatile__( \ | 941 | __asm__ __volatile__( \ |
| 938 | "mfc0\t%0, " #source "\n\t" \ | 942 | "mfc0\t%0, " #source "\n\t" \ |
| @@ -1014,7 +1018,7 @@ do { \ · 75 unmodified lines | |||
| 1014 | * On RM7000/RM9000 these are uses to access cop0 set 1 registers | 1018 | * On RM7000/RM9000 these are uses to access cop0 set 1 registers |
| 1015 | */ | 1019 | */ |
| 1016 | #define __read_32bit_c0_ctrl_register(source) \ | 1020 | #define __read_32bit_c0_ctrl_register(source) \ |
| 1017 | ({ int __res; \ | 1021 | ({ unsigned int __res; \ |
| 1018 | __asm__ __volatile__( \ | 1022 | __asm__ __volatile__( \ |
| 1019 | "cfc0\t%0, " #source "\n\t" \ | 1023 | "cfc0\t%0, " #source "\n\t" \ |
| 1020 | : "=r" (__res)); \ | 1024 | : "=r" (__res)); \ |
| @@ -1471,7 +1475,7 @@ do { \ · 450 unmodified lines | |||
| 1471 | */ | 1475 | */ |
| 1472 | #define _read_32bit_cp1_register(source, gas_hardfloat) \ | 1476 | #define _read_32bit_cp1_register(source, gas_hardfloat) \ |
| 1473 | ({ \ | 1477 | ({ \ |
| 1474 | int __res; \ | 1478 | unsigned int __res; \ |
| 1475 | \ | 1479 | \ |
| 1476 | __asm__ __volatile__( \ | 1480 | __asm__ __volatile__( \ |
| 1477 | " .set push \n" \ | 1481 | " .set push \n" \ |
| @@ -14,10 +14,90 @@ · 13 unmodified lines | |||
| 14 | 14 | ||
| 15 | #ifndef __ASSEMBLY__ | 15 | #ifndef __ASSEMBLY__ |
| 16 | 16 | ||
| 17 | #include <asm/inst.h> | ||
| 18 | |||
| 17 | extern void _save_msa(struct task_struct *); | 19 | extern void _save_msa(struct task_struct *); |
| 18 | extern void _restore_msa(struct task_struct *); | 20 | extern void _restore_msa(struct task_struct *); |
| 19 | extern void _init_msa_upper(void); | 21 | extern void _init_msa_upper(void); |
| 20 | 22 | ||
| 23 | extern void read_msa_wr_b(unsigned idx, union fpureg *to); | ||
| 24 | extern void read_msa_wr_h(unsigned idx, union fpureg *to); | ||
| 25 | extern void read_msa_wr_w(unsigned idx, union fpureg *to); | ||
| 26 | extern void read_msa_wr_d(unsigned idx, union fpureg *to); | ||
| 27 | |||
| 28 | /** | ||
| 29 | * read_msa_wr() - Read a single MSA vector register | ||
| 30 | * @idx: The index of the vector register to read | ||
| 31 | * @to: The FPU register union to store the registers value in | ||
| 32 | * @fmt: The format of the data in the vector register | ||
| 33 | * | ||
| 34 | * Read the value of MSA vector register idx into the FPU register | ||
| 35 | * union to, using the format fmt. | ||
| 36 | */ | ||
| 37 | static inline void read_msa_wr(unsigned idx, union fpureg *to, | ||
| 38 | enum msa_2b_fmt fmt) | ||
| 39 | { | ||
| 40 | switch (fmt) { | ||
| 41 | case msa_fmt_b: | ||
| 42 | read_msa_wr_b(idx, to); | ||
| 43 | break; | ||
| 44 | |||
| 45 | case msa_fmt_h: | ||
| 46 | read_msa_wr_h(idx, to); | ||
| 47 | break; | ||
| 48 | |||
| 49 | case msa_fmt_w: | ||
| 50 | read_msa_wr_w(idx, to); | ||
| 51 | break; | ||
| 52 | |||
| 53 | case msa_fmt_d: | ||
| 54 | read_msa_wr_d(idx, to); | ||
| 55 | break; | ||
| 56 | |||
| 57 | default: | ||
| 58 | BUG(); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | extern void write_msa_wr_b(unsigned idx, union fpureg *from); | ||
| 63 | extern void write_msa_wr_h(unsigned idx, union fpureg *from); | ||
| 64 | extern void write_msa_wr_w(unsigned idx, union fpureg *from); | ||
| 65 | extern void write_msa_wr_d(unsigned idx, union fpureg *from); | ||
| 66 | |||
| 67 | /** | ||
| 68 | * write_msa_wr() - Write a single MSA vector register | ||
| 69 | * @idx: The index of the vector register to write | ||
| 70 | * @from: The FPU register union to take the registers value from | ||
| 71 | * @fmt: The format of the data in the vector register | ||
| 72 | * | ||
| 73 | * Write the value from the FPU register union from into MSA vector | ||
| 74 | * register idx, using the format fmt. | ||
| 75 | */ | ||
| 76 | static inline void write_msa_wr(unsigned idx, union fpureg *from, | ||
| 77 | enum msa_2b_fmt fmt) | ||
| 78 | { | ||
| 79 | switch (fmt) { | ||
| 80 | case msa_fmt_b: | ||
| 81 | write_msa_wr_b(idx, from); | ||
| 82 | break; | ||
| 83 | |||
| 84 | case msa_fmt_h: | ||
| 85 | write_msa_wr_h(idx, from); | ||
| 86 | break; | ||
| 87 | |||
| 88 | case msa_fmt_w: | ||
| 89 | write_msa_wr_w(idx, from); | ||
| 90 | break; | ||
| 91 | |||
| 92 | case msa_fmt_d: | ||
| 93 | write_msa_wr_d(idx, from); | ||
| 94 | break; | ||
| 95 | |||
| 96 | default: | ||
| 97 | BUG(); | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 21 | static inline void enable_msa(void) | 101 | static inline void enable_msa(void) |
| 22 | { | 102 | { |
| 23 | if (cpu_has_msa) { | 103 | if (cpu_has_msa) { |
| @@ -284,6 +284,7 @@ enum cvmx_board_types_enum { · 283 unmodified lines | |||
| 284 | CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, | 284 | CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, |
| 285 | CVMX_BOARD_TYPE_UBNT_E100 = 20002, | 285 | CVMX_BOARD_TYPE_UBNT_E100 = 20002, |
| 286 | CVMX_BOARD_TYPE_CUST_DSR1000N = 20006, | 286 | CVMX_BOARD_TYPE_CUST_DSR1000N = 20006, |
| 287 | CVMX_BOARD_TYPE_KONTRON_S1901 = 21901, | ||
| 287 | CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, | 288 | CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, |
| 288 | 289 | ||
| 289 | /* The remaining range is reserved for future use. */ | 290 | /* The remaining range is reserved for future use. */ |
| @@ -384,6 +385,7 @@ static inline const char *cvmx_board_type_to_string(enum · 94 unmodified lines | |||
| 384 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN) | 385 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN) |
| 385 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100) | 386 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100) |
| 386 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DSR1000N) | 387 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DSR1000N) |
| 388 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901) | ||
| 387 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX) | 389 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX) |
| 388 | } | 390 | } |
| 389 | return "Unsupported Board"; | 391 | return "Unsupported Board"; |
| @@ -37,7 +37,7 @@ · 36 unmodified lines | |||
| 37 | #include <asm/octeon/cvmx-fpa.h> | 37 | #include <asm/octeon/cvmx-fpa.h> |
| 38 | #include <asm/octeon/cvmx-pip-defs.h> | 38 | #include <asm/octeon/cvmx-pip-defs.h> |
| 39 | 39 | ||
| 40 | #define CVMX_PIP_NUM_INPUT_PORTS 40 | 40 | #define CVMX_PIP_NUM_INPUT_PORTS 48 |
| 41 | #define CVMX_PIP_NUM_WATCHERS 4 | 41 | #define CVMX_PIP_NUM_WATCHERS 4 |
| 42 | 42 | ||
| 43 | /* | 43 | /* |
| @@ -542,6 +542,9 @@ static inline int cvmx_pko_get_base_queue_per_core(int port, int core) · 541 unmodified lines | |||
| 542 | */ | 542 | */ |
| 543 | static inline int cvmx_pko_get_base_queue(int port) | 543 | static inline int cvmx_pko_get_base_queue(int port) |
| 544 | { | 544 | { |
| 545 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
| 546 | return port; | ||
| 547 | |||
| 545 | return cvmx_pko_get_base_queue_per_core(port, 0); | 548 | return cvmx_pko_get_base_queue_per_core(port, 0); |
| 546 | } | 549 | } |
| 547 | 550 | ||
| @@ -52,6 +52,12 @@ · 51 unmodified lines | |||
| 52 | #define CVMX_POW_WQ_INT_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000000080ull) + ((offset) & 15) * 8) | 52 | #define CVMX_POW_WQ_INT_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000000080ull) + ((offset) & 15) * 8) |
| 53 | #define CVMX_POW_WS_PCX(offset) (CVMX_ADD_IO_SEG(0x0001670000000280ull) + ((offset) & 15) * 8) | 53 | #define CVMX_POW_WS_PCX(offset) (CVMX_ADD_IO_SEG(0x0001670000000280ull) + ((offset) & 15) * 8) |
| 54 | 54 | ||
| 55 | #define CVMX_SSO_WQ_INT (CVMX_ADD_IO_SEG(0x0001670000001000ull)) | ||
| 56 | #define CVMX_SSO_WQ_IQ_DIS (CVMX_ADD_IO_SEG(0x0001670000001010ull)) | ||
| 57 | #define CVMX_SSO_WQ_INT_PC (CVMX_ADD_IO_SEG(0x0001670000001020ull)) | ||
| 58 | #define CVMX_SSO_PPX_GRP_MSK(offset) (CVMX_ADD_IO_SEG(0x0001670000006000ull) + ((offset) & 31) * 8) | ||
| 59 | #define CVMX_SSO_WQ_INT_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000007000ull) + ((offset) & 63) * 8) | ||
| 60 | |||
| 55 | union cvmx_pow_bist_stat { | 61 | union cvmx_pow_bist_stat { |
| 56 | uint64_t u64; | 62 | uint64_t u64; |
| 57 | struct cvmx_pow_bist_stat_s { | 63 | struct cvmx_pow_bist_stat_s { |
| @@ -1286,4 +1292,27 @@ union cvmx_pow_ws_pcx { · 1228 unmodified lines | |||
| 1286 | struct cvmx_pow_ws_pcx_s cnf71xx; | 1292 | struct cvmx_pow_ws_pcx_s cnf71xx; |
| 1287 | }; | 1293 | }; |
| 1288 | 1294 | ||
| 1295 | union cvmx_sso_wq_int_thrx { | ||
| 1296 | uint64_t u64; | ||
| 1297 | struct { | ||
| 1298 | #ifdef __BIG_ENDIAN_BITFIELD | ||
| 1299 | uint64_t reserved_33_63:31; | ||
| 1300 | uint64_t tc_en:1; | ||
| 1301 | uint64_t tc_thr:4; | ||
| 1302 | uint64_t reserved_26_27:2; | ||
| 1303 | uint64_t ds_thr:12; | ||
| 1304 | uint64_t reserved_12_13:2; | ||
| 1305 | uint64_t iq_thr:12; | ||
| 1306 | #else | ||
| 1307 | uint64_t iq_thr:12; | ||
| 1308 | uint64_t reserved_12_13:2; | ||
| 1309 | uint64_t ds_thr:12; | ||
| 1310 | uint64_t reserved_26_27:2; | ||
| 1311 | uint64_t tc_thr:4; | ||
| 1312 | uint64_t tc_en:1; | ||
| 1313 | uint64_t reserved_33_63:31; | ||
| 1314 | #endif | ||
| 1315 | } s; | ||
| 1316 | }; | ||
| 1317 | |||
| 1289 | #endif | 1318 | #endif |
| @@ -1810,10 +1810,11 @@ static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, uint32_t tag, · 1809 unmodified lines | |||
| 1810 | cvmx_addr_t ptr; | 1810 | cvmx_addr_t ptr; |
| 1811 | cvmx_pow_tag_req_t tag_req; | 1811 | cvmx_pow_tag_req_t tag_req; |
| 1812 | 1812 | ||
| 1813 | wqp->qos = qos; | 1813 | wqp->word1.tag = tag; |
| 1814 | wqp->tag = tag; | 1814 | wqp->word1.tag_type = tag_type; |
| 1815 | wqp->tag_type = tag_type; | 1815 | |
| 1816 | wqp->grp = grp; | 1816 | cvmx_wqe_set_qos(wqp, qos); |
| 1817 | cvmx_wqe_set_grp(wqp, grp); | ||
| 1817 | 1818 | ||
| 1818 | tag_req.u64 = 0; | 1819 | tag_req.u64 = 0; |
| 1819 | tag_req.s.op = CVMX_POW_TAG_OP_ADDWQ; | 1820 | tag_req.s.op = CVMX_POW_TAG_OP_ADDWQ; |
| @@ -193,6 +193,53 @@ typedef union { · 192 unmodified lines | |||
| 193 | uint64_t bufs:8; | 193 | uint64_t bufs:8; |
| 194 | #endif | 194 | #endif |
| 195 | } s; | 195 | } s; |
| 196 | struct { | ||
| 197 | #ifdef __BIG_ENDIAN_BITFIELD | ||
| 198 | uint64_t bufs:8; | ||
| 199 | uint64_t ip_offset:8; | ||
| 200 | uint64_t vlan_valid:1; | ||
| 201 | uint64_t vlan_stacked:1; | ||
| 202 | uint64_t unassigned:1; | ||
| 203 | uint64_t vlan_cfi:1; | ||
| 204 | uint64_t vlan_id:12; | ||
| 205 | uint64_t port:12; /* MAC/PIP port number. */ | ||
| 206 | uint64_t dec_ipcomp:1; | ||
| 207 | uint64_t tcp_or_udp:1; | ||
| 208 | uint64_t dec_ipsec:1; | ||
| 209 | uint64_t is_v6:1; | ||
| 210 | uint64_t software:1; | ||
| 211 | uint64_t L4_error:1; | ||
| 212 | uint64_t is_frag:1; | ||
| 213 | uint64_t IP_exc:1; | ||
| 214 | uint64_t is_bcast:1; | ||
| 215 | uint64_t is_mcast:1; | ||
| 216 | uint64_t not_IP:1; | ||
| 217 | uint64_t rcv_error:1; | ||
| 218 | uint64_t err_code:8; | ||
| 219 | #else | ||
| 220 | uint64_t err_code:8; | ||
| 221 | uint64_t rcv_error:1; | ||
| 222 | uint64_t not_IP:1; | ||
| 223 | uint64_t is_mcast:1; | ||
| 224 | uint64_t is_bcast:1; | ||
| 225 | uint64_t IP_exc:1; | ||
| 226 | uint64_t is_frag:1; | ||
| 227 | uint64_t L4_error:1; | ||
| 228 | uint64_t software:1; | ||
| 229 | uint64_t is_v6:1; | ||
| 230 | uint64_t dec_ipsec:1; | ||
| 231 | uint64_t tcp_or_udp:1; | ||
| 232 | uint64_t dec_ipcomp:1; | ||
| 233 | uint64_t port:12; | ||
| 234 | uint64_t vlan_id:12; | ||
| 235 | uint64_t vlan_cfi:1; | ||
| 236 | uint64_t unassigned:1; | ||
| 237 | uint64_t vlan_stacked:1; | ||
| 238 | uint64_t vlan_valid:1; | ||
| 239 | uint64_t ip_offset:8; | ||
| 240 | uint64_t bufs:8; | ||
| 241 | #endif | ||
| 242 | } s_cn68xx; | ||
| 196 | 243 | ||
| 197 | /* use this to get at the 16 vlan bits */ | 244 | /* use this to get at the 16 vlan bits */ |
| 198 | struct { | 245 | struct { |
| @@ -355,6 +402,146 @@ typedef union { · 156 unmodified lines | |||
| 355 | 402 | ||
| 356 | } cvmx_pip_wqe_word2; | 403 | } cvmx_pip_wqe_word2; |
| 357 | 404 | ||
| 405 | union cvmx_pip_wqe_word0 { | ||
| 406 | struct { | ||
| 407 | #ifdef __BIG_ENDIAN_BITFIELD | ||
| 408 | /** | ||
| 409 | * raw chksum result generated by the HW | ||
| 410 | */ | ||
| 411 | uint16_t hw_chksum; | ||
| 412 | /** | ||
| 413 | * Field unused by hardware - available for software | ||
| 414 | */ | ||
| 415 | uint8_t unused; | ||
| 416 | /** | ||
| 417 | * Next pointer used by hardware for list maintenance. | ||
| 418 | * May be written/read by HW before the work queue | ||
| 419 | * entry is scheduled to a PP (Only 36 bits used in | ||
| 420 | * Octeon 1) | ||
| 421 | */ | ||
| 422 | uint64_t next_ptr:40; | ||
| 423 | #else | ||
| 424 | uint64_t next_ptr:40; | ||
| 425 | uint8_t unused; | ||
| 426 | uint16_t hw_chksum; | ||
| 427 | #endif | ||
| 428 | } cn38xx; | ||
| 429 | struct { | ||
| 430 | #ifdef __BIG_ENDIAN_BITFIELD | ||
| 431 | uint64_t l4ptr:8; /* 56..63 */ | ||
| 432 | uint64_t unused0:8; /* 48..55 */ | ||
| 433 | uint64_t l3ptr:8; /* 40..47 */ | ||
| 434 | uint64_t l2ptr:8; /* 32..39 */ | ||
| 435 | uint64_t unused1:18; /* 14..31 */ | ||
| 436 | uint64_t bpid:6; /* 8..13 */ | ||
| 437 | uint64_t unused2:2; /* 6..7 */ | ||
| 438 | uint64_t pknd:6; /* 0..5 */ | ||
| 439 | #else | ||
| 440 | uint64_t pknd:6; /* 0..5 */ | ||
| 441 | uint64_t unused2:2; /* 6..7 */ | ||
| 442 | uint64_t bpid:6; /* 8..13 */ | ||
| 443 | uint64_t unused1:18; /* 14..31 */ | ||
| 444 | uint64_t l2ptr:8; /* 32..39 */ | ||
| 445 | uint64_t l3ptr:8; /* 40..47 */ | ||
| 446 | uint64_t unused0:8; /* 48..55 */ | ||
| 447 | uint64_t l4ptr:8; /* 56..63 */ | ||
| 448 | #endif | ||
| 449 | } cn68xx; | ||
| 450 | }; | ||
| 451 | |||
| 452 | union cvmx_wqe_word0 { | ||
| 453 | uint64_t u64; | ||
| 454 | union cvmx_pip_wqe_word0 pip; | ||
| 455 | }; | ||
| 456 | |||
| 457 | union cvmx_wqe_word1 { | ||
| 458 | uint64_t u64; | ||
| 459 | struct { | ||
| 460 | #ifdef __BIG_ENDIAN_BITFIELD | ||
| 461 | uint64_t len:16; | ||
| 462 | uint64_t varies:14; | ||
| 463 | /** | ||
| 464 | * the type of the tag (ORDERED, ATOMIC, NULL) | ||
| 465 | */ | ||
| 466 | uint64_t tag_type:2; | ||
| 467 | uint64_t tag:32; | ||
| 468 | #else | ||
| 469 | uint64_t tag:32; | ||
| 470 | uint64_t tag_type:2; | ||
| 471 | uint64_t varies:14; | ||
| 472 | uint64_t len:16; | ||
| 473 | #endif | ||
| 474 | }; | ||
| 475 | struct { | ||
| 476 | #ifdef __BIG_ENDIAN_BITFIELD | ||
| 477 | uint64_t len:16; | ||
| 478 | uint64_t zero_0:1; | ||
| 479 | /** | ||
| 480 | * HW sets this to what it thought the priority of | ||
| 481 | * the input packet was | ||
| 482 | */ | ||
| 483 | uint64_t qos:3; | ||
| 484 | |||
| 485 | uint64_t zero_1:1; | ||
| 486 | /** | ||
| 487 | * the group that the work queue entry will be scheduled to | ||
| 488 | */ | ||
| 489 | uint64_t grp:6; | ||
| 490 | uint64_t zero_2:3; | ||
| 491 | uint64_t tag_type:2; | ||
| 492 | uint64_t tag:32; | ||
| 493 | #else | ||
| 494 | uint64_t tag:32; | ||
| 495 | uint64_t tag_type:2; | ||
| 496 | uint64_t zero_2:3; | ||
| 497 | uint64_t grp:6; | ||
| 498 | uint64_t zero_1:1; | ||
| 499 | uint64_t qos:3; | ||
| 500 | uint64_t zero_0:1; | ||
| 501 | uint64_t len:16; | ||
| 502 | #endif | ||
| 503 | } cn68xx; | ||
| 504 | struct { | ||
| 505 | #ifdef __BIG_ENDIAN_BITFIELD | ||
| 506 | /** | ||
| 507 | * HW sets to the total number of bytes in the packet | ||
| 508 | */ | ||
| 509 | uint64_t len:16; | ||
| 510 | /** | ||
| 511 | * HW sets this to input physical port | ||
| 512 | */ | ||
| 513 | uint64_t ipprt:6; | ||
| 514 | |||
| 515 | /** | ||
| 516 | * HW sets this to what it thought the priority of | ||
| 517 | * the input packet was | ||
| 518 | */ | ||
| 519 | uint64_t qos:3; | ||
| 520 | |||
| 521 | /** | ||
| 522 | * the group that the work queue entry will be scheduled to | ||
| 523 | */ | ||
| 524 | uint64_t grp:4; | ||
| 525 | /** | ||
| 526 | * the type of the tag (ORDERED, ATOMIC, NULL) | ||
| 527 | */ | ||
| 528 | uint64_t tag_type:3; | ||
| 529 | /** | ||
| 530 | * the synchronization/ordering tag | ||
| 531 | */ | ||
| 532 | uint64_t tag:32; | ||
| 533 | #else | ||
| 534 | uint64_t tag:32; | ||
| 535 | uint64_t tag_type:2; | ||
| 536 | uint64_t zero_2:1; | ||
| 537 | uint64_t grp:4; | ||
| 538 | uint64_t qos:3; | ||
| 539 | uint64_t ipprt:6; | ||
| 540 | uint64_t len:16; | ||
| 541 | #endif | ||
| 542 | } cn38xx; | ||
| 543 | }; | ||
| 544 | |||
| 358 | /** | 545 | /** |
| 359 | * Work queue entry format | 546 | * Work queue entry format |
| 360 | * | 547 | * |
| @@ -366,70 +553,13 @@ typedef struct { · 5 unmodified lines | |||
| 366 | * WORD 0 | 553 | * WORD 0 |
| 367 | * HW WRITE: the following 64 bits are filled by HW when a packet arrives | 554 | * HW WRITE: the following 64 bits are filled by HW when a packet arrives |
| 368 | */ | 555 | */ |
| 369 | 556 | union cvmx_wqe_word0 word0; | |
| 370 | #ifdef __BIG_ENDIAN_BITFIELD | ||
| 371 | /** | ||
| 372 | * raw chksum result generated by the HW | ||
| 373 | */ | ||
| 374 | uint16_t hw_chksum; | ||
| 375 | /** | ||
| 376 | * Field unused by hardware - available for software | ||
| 377 | */ | ||
| 378 | uint8_t unused; | ||
| 379 | /** | ||
| 380 | * Next pointer used by hardware for list maintenance. | ||
| 381 | * May be written/read by HW before the work queue | ||
| 382 | * entry is scheduled to a PP | ||
| 383 | * (Only 36 bits used in Octeon 1) | ||
| 384 | */ | ||
| 385 | uint64_t next_ptr:40; | ||
| 386 | #else | ||
| 387 | uint64_t next_ptr:40; | ||
| 388 | uint8_t unused; | ||
| 389 | uint16_t hw_chksum; | ||
| 390 | #endif | ||
| 391 | 557 | ||
| 392 | /***************************************************************** | 558 | /***************************************************************** |
| 393 | * WORD 1 | 559 | * WORD 1 |
| 394 | * HW WRITE: the following 64 bits are filled by HW when a packet arrives | 560 | * HW WRITE: the following 64 bits are filled by HW when a packet arrives |
| 395 | */ | 561 | */ |
| 396 | 562 | union cvmx_wqe_word1 word1; | |
| 397 | #ifdef __BIG_ENDIAN_BITFIELD | ||
| 398 | /** | ||
| 399 | * HW sets to the total number of bytes in the packet | ||
| 400 | */ | ||
| 401 | uint64_t len:16; | ||
| 402 | /** | ||
| 403 | * HW sets this to input physical port | ||
| 404 | */ | ||
| 405 | uint64_t ipprt:6; | ||
| 406 | |||
| 407 | /** | ||
| 408 | * HW sets this to what it thought the priority of the input packet was | ||
| 409 | */ | ||
| 410 | uint64_t qos:3; | ||
| 411 | |||
| 412 | /** | ||
| 413 | * the group that the work queue entry will be scheduled to | ||
| 414 | */ | ||
| 415 | uint64_t grp:4; | ||
| 416 | /** | ||
| 417 | * the type of the tag (ORDERED, ATOMIC, NULL) | ||
| 418 | */ | ||
| 419 | uint64_t tag_type:3; | ||
| 420 | /** | ||
| 421 | * the synchronization/ordering tag | ||
| 422 | */ | ||
| 423 | uint64_t tag:32; | ||
| 424 | #else | ||
| 425 | uint64_t tag:32; | ||
| 426 | uint64_t tag_type:2; | ||
| 427 | uint64_t zero_2:1; | ||
| 428 | uint64_t grp:4; | ||
| 429 | uint64_t qos:3; | ||
| 430 | uint64_t ipprt:6; | ||
| 431 | uint64_t len:16; | ||
| 432 | #endif | ||
| 433 | 563 | ||
| 434 | /** | 564 | /** |
| 435 | * WORD 2 HW WRITE: the following 64-bits are filled in by | 565 | * WORD 2 HW WRITE: the following 64-bits are filled in by |
| @@ -465,4 +595,64 @@ typedef struct { · 29 unmodified lines | |||
| 465 | 595 | ||
| 466 | } CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t; | 596 | } CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t; |
| 467 | 597 | ||
| 598 | static inline int cvmx_wqe_get_port(cvmx_wqe_t *work) | ||
| 599 | { | ||
| 600 | int port; | ||
| 601 | |||
| 602 | if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) | ||
| 603 | port = work->word2.s_cn68xx.port; | ||
| 604 | else | ||
| 605 | port = work->word1.cn38xx.ipprt; | ||
| 606 | |||
| 607 | return port; | ||
| 608 | } | ||
| 609 | |||
| 610 | static inline void cvmx_wqe_set_port(cvmx_wqe_t *work, int port) | ||
| 611 | { | ||
| 612 | if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) | ||
| 613 | work->word2.s_cn68xx.port = port; | ||
| 614 | else | ||
| 615 | work->word1.cn38xx.ipprt = port; | ||
| 616 | } | ||
| 617 | |||
| 618 | static inline int cvmx_wqe_get_grp(cvmx_wqe_t *work) | ||
| 619 | { | ||
| 620 | int grp; | ||
| 621 | |||
| 622 | if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) | ||
| 623 | grp = work->word1.cn68xx.grp; | ||
| 624 | else | ||
| 625 | grp = work->word1.cn38xx.grp; | ||
| 626 | |||
| 627 | return grp; | ||
| 628 | } | ||
| 629 | |||
| 630 | static inline void cvmx_wqe_set_grp(cvmx_wqe_t *work, int grp) | ||
| 631 | { | ||
| 632 | if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) | ||
| 633 | work->word1.cn68xx.grp = grp; | ||
| 634 | else | ||
| 635 | work->word1.cn38xx.grp = grp; | ||
| 636 | } | ||
| 637 | |||
| 638 | static inline int cvmx_wqe_get_qos(cvmx_wqe_t *work) | ||
| 639 | { | ||
| 640 | int qos; | ||
| 641 | |||
| 642 | if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) | ||
| 643 | qos = work->word1.cn68xx.qos; | ||
| 644 | else | ||
| 645 | qos = work->word1.cn38xx.qos; | ||
| 646 | |||
| 647 | return qos; | ||
| 648 | } | ||
| 649 | |||
| 650 | static inline void cvmx_wqe_set_qos(cvmx_wqe_t *work, int qos) | ||
| 651 | { | ||
| 652 | if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) | ||
| 653 | work->word1.cn68xx.qos = qos; | ||
| 654 | else | ||
| 655 | work->word1.cn38xx.qos = qos; | ||
| 656 | } | ||
| 657 | |||
| 468 | #endif /* __CVMX_WQE_H__ */ | 658 | #endif /* __CVMX_WQE_H__ */ |
| @@ -133,20 +133,13 @@ · 132 unmodified lines | |||
| 133 | #define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) | 133 | #define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) |
| 134 | #define _PAGE_SPLITTING_SHIFT (_PAGE_HUGE_SHIFT + 1) | 134 | #define _PAGE_SPLITTING_SHIFT (_PAGE_HUGE_SHIFT + 1) |
| 135 | #define _PAGE_SPLITTING (1 << _PAGE_SPLITTING_SHIFT) | 135 | #define _PAGE_SPLITTING (1 << _PAGE_SPLITTING_SHIFT) |
| 136 | |||
| 137 | /* Only R2 or newer cores have the XI bit */ | ||
| 138 | #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) | ||
| 139 | #define _PAGE_NO_EXEC_SHIFT (_PAGE_SPLITTING_SHIFT + 1) | ||
| 140 | #else | ||
| 141 | #define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1) | ||
| 142 | #define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) | ||
| 143 | #endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ | ||
| 144 | |||
| 145 | #endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */ | 136 | #endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */ |
| 146 | 137 | ||
| 147 | #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) | 138 | #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) |
| 148 | /* XI - page cannot be executed */ | 139 | /* XI - page cannot be executed */ |
| 149 | #ifndef _PAGE_NO_EXEC_SHIFT | 140 | #ifdef _PAGE_SPLITTING_SHIFT |
| 141 | #define _PAGE_NO_EXEC_SHIFT (_PAGE_SPLITTING_SHIFT + 1) | ||
| 142 | #else | ||
| 150 | #define _PAGE_NO_EXEC_SHIFT (_PAGE_MODIFIED_SHIFT + 1) | 143 | #define _PAGE_NO_EXEC_SHIFT (_PAGE_MODIFIED_SHIFT + 1) |
| 151 | #endif | 144 | #endif |
| 152 | #define _PAGE_NO_EXEC (cpu_has_rixi ? (1 << _PAGE_NO_EXEC_SHIFT) : 0) | 145 | #define _PAGE_NO_EXEC (cpu_has_rixi ? (1 << _PAGE_NO_EXEC_SHIFT) : 0) |
| @@ -156,14 +149,16 @@ · 3 unmodified lines | |||
| 156 | #define _PAGE_READ (cpu_has_rixi ? 0 : (1 << _PAGE_READ_SHIFT)) | 149 | #define _PAGE_READ (cpu_has_rixi ? 0 : (1 << _PAGE_READ_SHIFT)) |
| 157 | #define _PAGE_NO_READ_SHIFT _PAGE_READ_SHIFT | 150 | #define _PAGE_NO_READ_SHIFT _PAGE_READ_SHIFT |
| 158 | #define _PAGE_NO_READ (cpu_has_rixi ? (1 << _PAGE_READ_SHIFT) : 0) | 151 | #define _PAGE_NO_READ (cpu_has_rixi ? (1 << _PAGE_READ_SHIFT) : 0) |
| 152 | #endif /* defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) */ | ||
| 159 | 153 | ||
| 154 | #if defined(_PAGE_NO_READ_SHIFT) | ||
| 160 | #define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1) | 155 | #define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1) |
| 161 | #define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) | 156 | #elif defined(_PAGE_SPLITTING_SHIFT) |
| 162 | 157 | #define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1) | |
| 163 | #else /* !CONFIG_CPU_MIPSR2 && !CONFIG_CPU_MIPSR6 */ | 158 | #else |
| 164 | #define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1) | 159 | #define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1) |
| 160 | #endif | ||
| 165 | #define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) | 161 | #define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) |
| 166 | #endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ | ||
| 167 | 162 | ||
| 168 | #define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) | 163 | #define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) |
| 169 | #define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) | 164 | #define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) |
| @@ -249,7 +244,7 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) · 79 unmodified lines | |||
| 249 | #define _CACHE_CACHABLE_NONCOHERENT (3<<_CACHE_SHIFT) /* LOONGSON */ | 244 | #define _CACHE_CACHABLE_NONCOHERENT (3<<_CACHE_SHIFT) /* LOONGSON */ |
| 250 | #define _CACHE_CACHABLE_COHERENT (3<<_CACHE_SHIFT) /* LOONGSON-3 */ | 245 | #define _CACHE_CACHABLE_COHERENT (3<<_CACHE_SHIFT) /* LOONGSON-3 */ |
| 251 | 246 | ||
| 252 | #elif defined(CONFIG_MACH_JZ4740) | 247 | #elif defined(CONFIG_MACH_INGENIC) |
| 253 | 248 | ||
| 254 | /* Ingenic uses the WA bit to achieve write-combine memory writes */ | 249 | /* Ingenic uses the WA bit to achieve write-combine memory writes */ |
| 255 | #define _CACHE_UNCACHED_ACCELERATED (1<<_CACHE_SHIFT) | 250 | #define _CACHE_UNCACHED_ACCELERATED (1<<_CACHE_SHIFT) |
| @@ -393,6 +393,8 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot) · 392 unmodified lines | |||
| 393 | return __pgprot(prot); | 393 | return __pgprot(prot); |
| 394 | } | 394 | } |
| 395 | 395 | ||
| 396 | #define pgprot_writecombine pgprot_writecombine | ||
| 397 | |||
| 396 | static inline pgprot_t pgprot_writecombine(pgprot_t _prot) | 398 | static inline pgprot_t pgprot_writecombine(pgprot_t _prot) |
| 397 | { | 399 | { |
| 398 | unsigned long prot = pgprot_val(_prot); | 400 | unsigned long prot = pgprot_val(_prot); |
| @@ -275,6 +275,7 @@ struct thread_struct { · 274 unmodified lines | |||
| 275 | unsigned long cp0_badvaddr; /* Last user fault */ | 275 | unsigned long cp0_badvaddr; /* Last user fault */ |
| 276 | unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ | 276 | unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ |
| 277 | unsigned long error_code; | 277 | unsigned long error_code; |
| 278 | unsigned long trap_nr; | ||
| 278 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 279 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
| 279 | struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128))); | 280 | struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128))); |
| 280 | struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128))); | 281 | struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128))); |
| @@ -341,6 +342,7 @@ struct thread_struct { · 60 unmodified lines | |||
| 341 | .cp0_badvaddr = 0, \ | 342 | .cp0_badvaddr = 0, \ |
| 342 | .cp0_baduaddr = 0, \ | 343 | .cp0_baduaddr = 0, \ |
| 343 | .error_code = 0, \ | 344 | .error_code = 0, \ |
| 345 | .trap_nr = 0, \ | ||
| 344 | /* \ | 346 | /* \ |
| 345 | * Platform specific cop2 registers(null if no COP2) \ | 347 | * Platform specific cop2 registers(null if no COP2) \ |
| 346 | */ \ | 348 | */ \ |
| @@ -14,11 +14,16 @@ · 13 unmodified lines | |||
| 14 | #include <linux/linkage.h> | 14 | #include <linux/linkage.h> |
| 15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
| 16 | #include <asm/isadep.h> | 16 | #include <asm/isadep.h> |
| 17 | #include <asm/page.h> | ||
| 18 | #include <asm/thread_info.h> | ||
| 17 | #include <uapi/asm/ptrace.h> | 19 | #include <uapi/asm/ptrace.h> |
| 18 | 20 | ||
| 19 | /* | 21 | /* |
| 20 | * This struct defines the way the registers are stored on the stack during a | 22 | * This struct defines the way the registers are stored on the stack during a |
| 21 | * system call/exception. As usual the registers k0/k1 aren't being saved. | 23 | * system call/exception. As usual the registers k0/k1 aren't being saved. |
| 24 | * | ||
| 25 | * If you add a register here, also add it to regoffset_table[] in | ||
| 26 | * arch/mips/kernel/ptrace.c. | ||
| 22 | */ | 27 | */ |
| 23 | struct pt_regs { | 28 | struct pt_regs { |
| 24 | #ifdef CONFIG_32BIT | 29 | #ifdef CONFIG_32BIT |
| @@ -43,8 +48,83 @@ struct pt_regs { · 18 unmodified lines | |||
| 43 | unsigned long long mpl[6]; /* MTM{0-5} */ | 48 | unsigned long long mpl[6]; /* MTM{0-5} */ |
| 44 | unsigned long long mtp[6]; /* MTP{0-5} */ | 49 | unsigned long long mtp[6]; /* MTP{0-5} */ |
| 45 | #endif | 50 | #endif |
| 51 | unsigned long __last[0]; | ||
| 46 | } __aligned(8); | 52 | } __aligned(8); |
| 47 | 53 | ||
| 54 | static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) | ||
| 55 | { | ||
| 56 | return regs->regs[31]; | ||
| 57 | } | ||
| 58 | |||
| 59 | /* | ||
| 60 | * Don't use asm-generic/ptrace.h it defines FP accessors that don't make | ||
| 61 | * sense on MIPS. We rather want an error if they get invoked. | ||
| 62 | */ | ||
| 63 | |||
| 64 | static inline void instruction_pointer_set(struct pt_regs *regs, | ||
| 65 | unsigned long val) | ||
| 66 | { | ||
| 67 | regs->cp0_epc = val; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* Query offset/name of register from its name/offset */ | ||
| 71 | extern int regs_query_register_offset(const char *name); | ||
| 72 | #define MAX_REG_OFFSET (offsetof(struct pt_regs, __last)) | ||
| 73 | |||
| 74 | /** | ||
| 75 | * regs_get_register() - get register value from its offset | ||
| 76 | * @regs: pt_regs from which register value is gotten. | ||
| 77 | * @offset: offset number of the register. | ||
| 78 | * | ||
| 79 | * regs_get_register returns the value of a register. The @offset is the | ||
| 80 | * offset of the register in struct pt_regs address which specified by @regs. | ||
| 81 | * If @offset is bigger than MAX_REG_OFFSET, this returns 0. | ||
| 82 | */ | ||
| 83 | static inline unsigned long regs_get_register(struct pt_regs *regs, | ||
| 84 | unsigned int offset) | ||
| 85 | { | ||
| 86 | if (unlikely(offset > MAX_REG_OFFSET)) | ||
| 87 | return 0; | ||
| 88 | |||
| 89 | return *(unsigned long *)((unsigned long)regs + offset); | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * regs_within_kernel_stack() - check the address in the stack | ||
| 94 | * @regs: pt_regs which contains kernel stack pointer. | ||
| 95 | * @addr: address which is checked. | ||
| 96 | * | ||
| 97 | * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). | ||
| 98 | * If @addr is within the kernel stack, it returns true. If not, returns false. | ||
| 99 | */ | ||
| 100 | static inline int regs_within_kernel_stack(struct pt_regs *regs, | ||
| 101 | unsigned long addr) | ||
| 102 | { | ||
| 103 | return ((addr & ~(THREAD_SIZE - 1)) == | ||
| 104 | (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); | ||
| 105 | } | ||
| 106 | |||
| 107 | /** | ||
| 108 | * regs_get_kernel_stack_nth() - get Nth entry of the stack | ||
| 109 | * @regs: pt_regs which contains kernel stack pointer. | ||
| 110 | * @n: stack entry number. | ||
| 111 | * | ||
| 112 | * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which | ||
| 113 | * is specified by @regs. If the @n th entry is NOT in the kernel stack, | ||
| 114 | * this returns 0. | ||
| 115 | */ | ||
| 116 | static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, | ||
| 117 | unsigned int n) | ||
| 118 | { | ||
| 119 | unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); | ||
| 120 | |||
| 121 | addr += n; | ||
| 122 | if (regs_within_kernel_stack(regs, (unsigned long)addr)) | ||
| 123 | return *addr; | ||
| 124 | else | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 48 | struct task_struct; | 128 | struct task_struct; |
| 49 | 129 | ||
| 50 | extern int ptrace_getregs(struct task_struct *child, | 130 | extern int ptrace_getregs(struct task_struct *child, |
| @@ -23,4 +23,7 @@ · 22 unmodified lines | |||
| 23 | 23 | ||
| 24 | #define __ARCH_HAS_IRIX_SIGACTION | 24 | #define __ARCH_HAS_IRIX_SIGACTION |
| 25 | 25 | ||
| 26 | extern int protected_save_fp_context(void __user *sc); | ||
| 27 | extern int protected_restore_fp_context(void __user *sc); | ||
| 28 | |||
| 26 | #endif /* _ASM_SIGNAL_H */ | 29 | #endif /* _ASM_SIGNAL_H */ |
| @@ -42,6 +42,11 @@ static inline int arch_spin_is_locked(arch_spinlock_t *lock) · 41 unmodified lines | |||
| 42 | return ((counters >> 16) ^ counters) & 0xffff; | 42 | return ((counters >> 16) ^ counters) & 0xffff; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static inline int arch_spin_value_unlocked(arch_spinlock_t lock) | ||
| 46 | { | ||
| 47 | return lock.h.serving_now == lock.h.ticket; | ||
| 48 | } | ||
| 49 | |||
| 45 | #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) | 50 | #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) |
| 46 | #define arch_spin_unlock_wait(x) \ | 51 | #define arch_spin_unlock_wait(x) \ |
| 47 | while (arch_spin_is_locked(x)) { cpu_relax(); } | 52 | while (arch_spin_is_locked(x)) { cpu_relax(); } |
| @@ -16,29 +16,21 @@ · 15 unmodified lines | |||
| 16 | #include <asm/watch.h> | 16 | #include <asm/watch.h> |
| 17 | #include <asm/dsp.h> | 17 | #include <asm/dsp.h> |
| 18 | #include <asm/cop2.h> | 18 | #include <asm/cop2.h> |
| 19 | #include <asm/msa.h> | 19 | #include <asm/fpu.h> |
| 20 | 20 | ||
| 21 | struct task_struct; | 21 | struct task_struct; |
| 22 | 22 | ||
| 23 | enum { | ||
| 24 | FP_SAVE_NONE = 0, | ||
| 25 | FP_SAVE_VECTOR = -1, | ||
| 26 | FP_SAVE_SCALAR = 1, | ||
| 27 | }; | ||
| 28 | |||
| 29 | /** | 23 | /** |
| 30 | * resume - resume execution of a task | 24 | * resume - resume execution of a task |
| 31 | * @prev: The task previously executed. | 25 | * @prev: The task previously executed. |
| 32 | * @next: The task to begin executing. | 26 | * @next: The task to begin executing. |
| 33 | * @next_ti: task_thread_info(next). | 27 | * @next_ti: task_thread_info(next). |
| 34 | * @fp_save: Which, if any, FP context to save for prev. | ||
| 35 | * | 28 | * |
| 36 | * This function is used whilst scheduling to save the context of prev & load | 29 | * This function is used whilst scheduling to save the context of prev & load |
| 37 | * the context of next. Returns prev. | 30 | * the context of next. Returns prev. |
| 38 | */ | 31 | */ |
| 39 | extern asmlinkage struct task_struct *resume(struct task_struct *prev, | 32 | extern asmlinkage struct task_struct *resume(struct task_struct *prev, |
| 40 | struct task_struct *next, struct thread_info *next_ti, | 33 | struct task_struct *next, struct thread_info *next_ti); |
| 41 | s32 fp_save); | ||
| 42 | 34 | ||
| 43 | extern unsigned int ll_bit; | 35 | extern unsigned int ll_bit; |
| 44 | extern struct task_struct *ll_task; | 36 | extern struct task_struct *ll_task; |
| @@ -91,8 +83,8 @@ do { if (cpu_has_rw_llb) { \ · 46 unmodified lines | |||
| 91 | */ | 83 | */ |
| 92 | #define switch_to(prev, next, last) \ | 84 | #define switch_to(prev, next, last) \ |
| 93 | do { \ | 85 | do { \ |
| 94 | s32 __fpsave = FP_SAVE_NONE; \ | ||
| 95 | __mips_mt_fpaff_switch_to(prev); \ | 86 | __mips_mt_fpaff_switch_to(prev); \ |
| 87 | lose_fpu_inatomic(1, prev); \ | ||
| 96 | if (cpu_has_dsp) { \ | 88 | if (cpu_has_dsp) { \ |
| 97 | __save_dsp(prev); \ | 89 | __save_dsp(prev); \ |
| 98 | __restore_dsp(next); \ | 90 | __restore_dsp(next); \ |
| @@ -111,15 +103,10 @@ do { \ · 12 unmodified lines | |||
| 111 | clear_c0_status(ST0_CU2); \ | 103 | clear_c0_status(ST0_CU2); \ |
| 112 | } \ | 104 | } \ |
| 113 | __clear_software_ll_bit(); \ | 105 | __clear_software_ll_bit(); \ |
| 114 | if (test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU)) \ | ||
| 115 | __fpsave = FP_SAVE_SCALAR; \ | ||
| 116 | if (test_and_clear_tsk_thread_flag(prev, TIF_USEDMSA)) \ | ||
| 117 | __fpsave = FP_SAVE_VECTOR; \ | ||
| 118 | if (cpu_has_userlocal) \ | 106 | if (cpu_has_userlocal) \ |
| 119 | write_c0_userlocal(task_thread_info(next)->tp_value); \ | 107 | write_c0_userlocal(task_thread_info(next)->tp_value); \ |
| 120 | __restore_watch(); \ | 108 | __restore_watch(); \ |
| 121 | disable_msa(); \ | 109 | (last) = resume(prev, next, task_thread_info(next)); \ |
| 122 | (last) = resume(prev, next, task_thread_info(next), __fpsave); \ | ||
| 123 | } while (0) | 110 | } while (0) |
| 124 | 111 | ||
| 125 | #endif /* _ASM_SWITCH_TO_H */ | 112 | #endif /* _ASM_SWITCH_TO_H */ |
| @@ -99,6 +99,7 @@ static inline struct thread_info *current_thread_info(void) · 98 unmodified lines | |||
| 99 | #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ | 99 | #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ |
| 100 | #define TIF_SECCOMP 4 /* secure computing */ | 100 | #define TIF_SECCOMP 4 /* secure computing */ |
| 101 | #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ | 101 | #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ |
| 102 | #define TIF_UPROBE 6 /* breakpointed or singlestepping */ | ||
| 102 | #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ | 103 | #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ |
| 103 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ | 104 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ |
| 104 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ | 105 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ |
| @@ -122,6 +123,7 @@ static inline struct thread_info *current_thread_info(void) · 17 unmodified lines | |||
| 122 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) | 123 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) |
| 123 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) | 124 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) |
| 124 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) | 125 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) |
| 126 | #define _TIF_UPROBE (1<<TIF_UPROBE) | ||
| 125 | #define _TIF_USEDFPU (1<<TIF_USEDFPU) | 127 | #define _TIF_USEDFPU (1<<TIF_USEDFPU) |
| 126 | #define _TIF_NOHZ (1<<TIF_NOHZ) | 128 | #define _TIF_NOHZ (1<<TIF_NOHZ) |
| 127 | #define _TIF_FIXADE (1<<TIF_FIXADE) | 129 | #define _TIF_FIXADE (1<<TIF_FIXADE) |
| @@ -146,7 +148,8 @@ static inline struct thread_info *current_thread_info(void) · 18 unmodified lines | |||
| 146 | 148 | ||
| 147 | /* work to do on interrupt/exception return */ | 149 | /* work to do on interrupt/exception return */ |
| 148 | #define _TIF_WORK_MASK \ | 150 | #define _TIF_WORK_MASK \ |
| 149 | (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME) | 151 | (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME | \ |
| 152 | _TIF_UPROBE) | ||
| 150 | /* work to do on any return to u-space */ | 153 | /* work to do on any return to u-space */ |
| 151 | #define _TIF_ALLWORK_MASK (_TIF_NOHZ | _TIF_WORK_MASK | \ | 154 | #define _TIF_ALLWORK_MASK (_TIF_NOHZ | _TIF_WORK_MASK | \ |
| 152 | _TIF_WORK_SYSCALL_EXIT | \ | 155 | _TIF_WORK_SYSCALL_EXIT | \ |
| @@ -51,7 +51,7 @@ extern int __weak get_c0_perfcount_int(void); · 50 unmodified lines | |||
| 51 | /* | 51 | /* |
| 52 | * Initialize the calling CPU's compare interrupt as clockevent device | 52 | * Initialize the calling CPU's compare interrupt as clockevent device |
| 53 | */ | 53 | */ |
| 54 | extern unsigned int __weak get_c0_compare_int(void); | 54 | extern unsigned int get_c0_compare_int(void); |
| 55 | extern int r4k_clockevent_init(void); | 55 | extern int r4k_clockevent_init(void); |
| 56 | 56 | ||
| 57 | static inline int mips_clockevent_init(void) | 57 | static inline int mips_clockevent_init(void) |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | /* | 11 | /* |
| 12 | * TLB debugging functions: | 12 | * TLB debugging functions: |
| 13 | */ | 13 | */ |
| 14 | extern void dump_tlb_regs(void); | ||
| 14 | extern void dump_tlb_all(void); | 15 | extern void dump_tlb_all(void); |
| 15 | 16 | ||
| 16 | #endif /* __ASM_TLBDEBUG_H */ | 17 | #endif /* __ASM_TLBDEBUG_H */ |
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | */ | ||
| 6 | #ifndef __ASM_UPROBES_H | ||
| 7 | #define __ASM_UPROBES_H | ||
| 8 | |||
| 9 | #include <linux/notifier.h> | ||
| 10 | #include <linux/types.h> | ||
| 11 | |||
| 12 | #include <asm/break.h> | ||
| 13 | #include <asm/inst.h> | ||
| 14 | |||
| 15 | /* | ||
| 16 | * We want this to be defined as union mips_instruction but that makes the | ||
| 17 | * generic code blow up. | ||
| 18 | */ | ||
| 19 | typedef u32 uprobe_opcode_t; | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Classic MIPS (note this implementation doesn't consider microMIPS yet) | ||
| 23 | * instructions are always 4 bytes but in order to deal with branches and | ||
| 24 | * their delay slots, we treat instructions as having 8 bytes maximum. | ||
| 25 | */ | ||
| 26 | #define MAX_UINSN_BYTES 8 | ||
| 27 | #define UPROBE_XOL_SLOT_BYTES 128 /* Max. cache line size */ | ||
| 28 | |||
| 29 | #define UPROBE_BRK_UPROBE 0x000d000d /* break 13 */ | ||
| 30 | #define UPROBE_BRK_UPROBE_XOL 0x000e000d /* break 14 */ | ||
| 31 | |||
| 32 | #define UPROBE_SWBP_INSN UPROBE_BRK_UPROBE | ||
| 33 | #define UPROBE_SWBP_INSN_SIZE 4 | ||
| 34 | |||
| 35 | struct arch_uprobe { | ||
| 36 | unsigned long resume_epc; | ||
| 37 | u32 insn[2]; | ||
| 38 | u32 ixol[2]; | ||
| 39 | union mips_instruction orig_inst[MAX_UINSN_BYTES / 4]; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct arch_uprobe_task { | ||
| 43 | unsigned long saved_trap_nr; | ||
| 44 | }; | ||
| 45 | |||
| 46 | extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, | ||
| 47 | struct mm_struct *mm, unsigned long addr); | ||
| 48 | extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); | ||
| 49 | extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); | ||
| 50 | extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); | ||
| 51 | extern int arch_uprobe_exception_notify(struct notifier_block *self, | ||
| 52 | unsigned long val, void *data); | ||
| 53 | extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, | ||
| 54 | struct pt_regs *regs); | ||
| 55 | extern unsigned long arch_uretprobe_hijack_return_addr( | ||
| 56 | unsigned long trampoline_vaddr, struct pt_regs *regs); | ||
| 57 | |||
| 58 | #endif /* __ASM_UPROBES_H */ | ||
| @@ -122,7 +122,7 @@ void release_vpe(struct vpe *v); · 121 unmodified lines | |||
| 122 | void *alloc_progmem(unsigned long len); | 122 | void *alloc_progmem(unsigned long len); |
| 123 | void release_progmem(void *ptr); | 123 | void release_progmem(void *ptr); |
| 124 | 124 | ||
| 125 | int __weak vpe_run(struct vpe *v); | 125 | int vpe_run(struct vpe *v); |
| 126 | void cleanup_tc(struct tc *tc); | 126 | void cleanup_tc(struct tc *tc); |
| 127 | 127 | ||
| 128 | int __init vpe_module_init(void); | 128 | int __init vpe_module_init(void); |
| @@ -21,6 +21,8 @@ · 20 unmodified lines | |||
| 21 | #define BRK_DIVZERO 7 /* Divide by zero check */ | 21 | #define BRK_DIVZERO 7 /* Divide by zero check */ |
| 22 | #define BRK_RANGE 8 /* Range error check */ | 22 | #define BRK_RANGE 8 /* Range error check */ |
| 23 | #define BRK_BUG 12 /* Used by BUG() */ | 23 | #define BRK_BUG 12 /* Used by BUG() */ |
| 24 | #define BRK_UPROBE 13 /* See <asm/uprobes.h> */ | ||
| 25 | #define BRK_UPROBE_XOL 14 /* See <asm/uprobes.h> */ | ||
| 24 | #define BRK_MEMU 514 /* Used by FPU emulator */ | 26 | #define BRK_MEMU 514 /* Used by FPU emulator */ |
| 25 | #define BRK_KPROBE_BP 515 /* Kprobe break */ | 27 | #define BRK_KPROBE_BP 515 /* Kprobe break */ |
| 26 | #define BRK_KPROBE_SSTEPBP 516 /* Kprobe single step software implementation */ | 28 | #define BRK_KPROBE_SSTEPBP 516 /* Kprobe single step software implementation */ |
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef _UAPI_ASM_HWCAP_H | ||
| 2 | #define _UAPI_ASM_HWCAP_H | ||
| 3 | |||
| 4 | /* HWCAP flags */ | ||
| 5 | #define HWCAP_MIPS_R6 (1 << 0) | ||
| 6 | #define HWCAP_MIPS_MSA (1 << 1) | ||
| 7 | |||
| 8 | #endif /* _UAPI_ASM_HWCAP_H */ | ||
| @@ -26,7 +26,7 @@ enum major_op { · 25 unmodified lines | |||
| 26 | cop0_op, cop1_op, cop2_op, cop1x_op, | 26 | cop0_op, cop1_op, cop2_op, cop1x_op, |
| 27 | beql_op, bnel_op, blezl_op, bgtzl_op, | 27 | beql_op, bnel_op, blezl_op, bgtzl_op, |
| 28 | daddi_op, cbcond1_op = daddi_op, daddiu_op, ldl_op, ldr_op, | 28 | daddi_op, cbcond1_op = daddi_op, daddiu_op, ldl_op, ldr_op, |
| 29 | spec2_op, jalx_op, mdmx_op, spec3_op, | 29 | spec2_op, jalx_op, mdmx_op, msa_op = mdmx_op, spec3_op, |
| 30 | lb_op, lh_op, lwl_op, lw_op, | 30 | lb_op, lh_op, lwl_op, lw_op, |
| 31 | lbu_op, lhu_op, lwr_op, lwu_op, | 31 | lbu_op, lhu_op, lwr_op, lwu_op, |
| 32 | sb_op, sh_op, swl_op, sw_op, | 32 | sb_op, sh_op, swl_op, sw_op, |
| @@ -167,8 +167,13 @@ enum cop1_sdw_func { · 134 unmodified lines | |||
| 167 | fround_op = 0x0c, ftrunc_op = 0x0d, | 167 | fround_op = 0x0c, ftrunc_op = 0x0d, |
| 168 | fceil_op = 0x0e, ffloor_op = 0x0f, | 168 | fceil_op = 0x0e, ffloor_op = 0x0f, |
| 169 | fmovc_op = 0x11, fmovz_op = 0x12, | 169 | fmovc_op = 0x11, fmovz_op = 0x12, |
| 170 | fmovn_op = 0x13, frecip_op = 0x15, | 170 | fmovn_op = 0x13, fseleqz_op = 0x14, |
| 171 | frsqrt_op = 0x16, fcvts_op = 0x20, | 171 | frecip_op = 0x15, frsqrt_op = 0x16, |
| 172 | fselnez_op = 0x17, fmaddf_op = 0x18, | ||
| 173 | fmsubf_op = 0x19, frint_op = 0x1a, | ||
| 174 | fclass_op = 0x1b, fmin_op = 0x1c, | ||
| 175 | fmina_op = 0x1d, fmax_op = 0x1e, | ||
| 176 | fmaxa_op = 0x1f, fcvts_op = 0x20, | ||
| 172 | fcvtd_op = 0x21, fcvte_op = 0x22, | 177 | fcvtd_op = 0x21, fcvte_op = 0x22, |
| 173 | fcvtw_op = 0x24, fcvtl_op = 0x25, | 178 | fcvtw_op = 0x24, fcvtl_op = 0x25, |
| 174 | fcmp_op = 0x30 | 179 | fcmp_op = 0x30 |
| @@ -220,6 +225,24 @@ enum bshfl_func { · 45 unmodified lines | |||
| 220 | seh_op = 0x18, | 225 | seh_op = 0x18, |
| 221 | }; | 226 | }; |
| 222 | 227 | ||
| 228 | /* | ||
| 229 | * func field for MSA MI10 format. | ||
| 230 | */ | ||
| 231 | enum msa_mi10_func { | ||
| 232 | msa_ld_op = 8, | ||
| 233 | msa_st_op = 9, | ||
| 234 | }; | ||
| 235 | |||
| 236 | /* | ||
| 237 | * MSA 2 bit format fields. | ||
| 238 | */ | ||
| 239 | enum msa_2b_fmt { | ||
| 240 | msa_fmt_b = 0, | ||
| 241 | msa_fmt_h = 1, | ||
| 242 | msa_fmt_w = 2, | ||
| 243 | msa_fmt_d = 3, | ||
| 244 | }; | ||
| 245 | |||
| 223 | /* | 246 | /* |
| 224 | * (microMIPS) Major opcodes. | 247 | * (microMIPS) Major opcodes. |
| 225 | */ | 248 | */ |
| @@ -611,6 +634,16 @@ struct v_format { /* MDMX vector format */ · 385 unmodified lines | |||
| 611 | ;))))))) | 634 | ;))))))) |
| 612 | }; | 635 | }; |
| 613 | 636 | ||
| 637 | struct msa_mi10_format { /* MSA MI10 */ | ||
| 638 | __BITFIELD_FIELD(unsigned int opcode : 6, | ||
| 639 | __BITFIELD_FIELD(signed int s10 : 10, | ||
| 640 | __BITFIELD_FIELD(unsigned int rs : 5, | ||
| 641 | __BITFIELD_FIELD(unsigned int wd : 5, | ||
| 642 | __BITFIELD_FIELD(unsigned int func : 4, | ||
| 643 | __BITFIELD_FIELD(unsigned int df : 2, | ||
| 644 | ;)))))) | ||
| 645 | }; | ||
| 646 | |||
| 614 | struct spec3_format { /* SPEC3 */ | 647 | struct spec3_format { /* SPEC3 */ |
| 615 | __BITFIELD_FIELD(unsigned int opcode:6, | 648 | __BITFIELD_FIELD(unsigned int opcode:6, |
| 616 | __BITFIELD_FIELD(unsigned int rs:5, | 649 | __BITFIELD_FIELD(unsigned int rs:5, |
| @@ -888,6 +921,7 @@ union mips_instruction { · 271 unmodified lines | |||
| 888 | struct p_format p_format; | 921 | struct p_format p_format; |
| 889 | struct f_format f_format; | 922 | struct f_format f_format; |
| 890 | struct ma_format ma_format; | 923 | struct ma_format ma_format; |
| 924 | struct msa_mi10_format msa_mi10_format; | ||
| 891 | struct b_format b_format; | 925 | struct b_format b_format; |
| 892 | struct ps_format ps_format; | 926 | struct ps_format ps_format; |
| 893 | struct v_format v_format; | 927 | struct v_format v_format; |
| @@ -12,6 +12,18 @@ · 11 unmodified lines | |||
| 12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
| 13 | #include <asm/sgidefs.h> | 13 | #include <asm/sgidefs.h> |
| 14 | 14 | ||
| 15 | /* scalar FP context was used */ | ||
| 16 | #define USED_FP (1 << 0) | ||
| 17 | |||
| 18 | /* the value of Status.FR when context was saved */ | ||
| 19 | #define USED_FR1 (1 << 1) | ||
| 20 | |||
| 21 | /* FR=1, but with odd singles in bits 63:32 of preceding even double */ | ||
| 22 | #define USED_HYBRID_FPRS (1 << 2) | ||
| 23 | |||
| 24 | /* extended context was used, see struct extcontext for details */ | ||
| 25 | #define USED_EXTCONTEXT (1 << 3) | ||
| 26 | |||
| 15 | #if _MIPS_SIM == _MIPS_SIM_ABI32 | 27 | #if _MIPS_SIM == _MIPS_SIM_ABI32 |
| 16 | 28 | ||
| 17 | /* | 29 | /* |
| @@ -16,11 +16,13 @@ · 15 unmodified lines | |||
| 16 | #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) || \ | 16 | #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) || \ |
| 17 | defined(_MIPS_ARCH_LOONGSON3A) | 17 | defined(_MIPS_ARCH_LOONGSON3A) |
| 18 | 18 | ||
| 19 | static inline __attribute_const__ __u16 __arch_swab16(__u16 x) | 19 | static inline __attribute__((nomips16)) __attribute_const__ |
| 20 | __u16 __arch_swab16(__u16 x) | ||
| 20 | { | 21 | { |
| 21 | __asm__( | 22 | __asm__( |
| 22 | " .set push \n" | 23 | " .set push \n" |
| 23 | " .set arch=mips32r2 \n" | 24 | " .set arch=mips32r2 \n" |
| 25 | " .set nomips16 \n" | ||
| 24 | " wsbh %0, %1 \n" | 26 | " wsbh %0, %1 \n" |
| 25 | " .set pop \n" | 27 | " .set pop \n" |
| 26 | : "=r" (x) | 28 | : "=r" (x) |
| @@ -30,11 +32,13 @@ static inline __attribute_const__ __u16 __arch_swab16(__u16 x) · 3 unmodified lines | |||
| 30 | } | 32 | } |
| 31 | #define __arch_swab16 __arch_swab16 | 33 | #define __arch_swab16 __arch_swab16 |
| 32 | 34 | ||
| 33 | static inline __attribute_const__ __u32 __arch_swab32(__u32 x) | 35 | static inline __attribute__((nomips16)) __attribute_const__ |
| 36 | __u32 __arch_swab32(__u32 x) | ||
| 34 | { | 37 | { |
| 35 | __asm__( | 38 | __asm__( |
| 36 | " .set push \n" | 39 | " .set push \n" |
| 37 | " .set arch=mips32r2 \n" | 40 | " .set arch=mips32r2 \n" |
| 41 | " .set nomips16 \n" | ||
| 38 | " wsbh %0, %1 \n" | 42 | " wsbh %0, %1 \n" |
| 39 | " rotr %0, %0, 16 \n" | 43 | " rotr %0, %0, 16 \n" |
| 40 | " .set pop \n" | 44 | " .set pop \n" |
| @@ -50,11 +54,13 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x) · 9 unmodified lines | |||
| 50 | * 64-bit kernel on r2 CPUs. | 54 | * 64-bit kernel on r2 CPUs. |
| 51 | */ | 55 | */ |
| 52 | #ifdef __mips64 | 56 | #ifdef __mips64 |
| 53 | static inline __attribute_const__ __u64 __arch_swab64(__u64 x) | 57 | static inline __attribute__((nomips16)) __attribute_const__ |
| 58 | __u64 __arch_swab64(__u64 x) | ||
| 54 | { | 59 | { |
| 55 | __asm__( | 60 | __asm__( |
| 56 | " .set push \n" | 61 | " .set push \n" |
| 57 | " .set arch=mips64r2 \n" | 62 | " .set arch=mips64r2 \n" |
| 63 | " .set nomips16 \n" | ||
| 58 | " dsbh %0, %1 \n" | 64 | " dsbh %0, %1 \n" |
| 59 | " dshd %0, %0 \n" | 65 | " dshd %0, %0 \n" |
| 60 | " .set pop \n" | 66 | " .set pop \n" |
| @@ -0,0 +1,65 @@ | |||
| 1 | #ifndef __MIPS_UAPI_ASM_UCONTEXT_H | ||
| 2 | #define __MIPS_UAPI_ASM_UCONTEXT_H | ||
| 3 | |||
| 4 | /** | ||
| 5 | * struct extcontext - extended context header structure | ||
| 6 | * @magic: magic value identifying the type of extended context | ||
| 7 | * @size: the size in bytes of the enclosing structure | ||
| 8 | * | ||
| 9 | * Extended context structures provide context which does not fit within struct | ||
| 10 | * sigcontext. They are placed sequentially in memory at the end of struct | ||
| 11 | * ucontext and struct sigframe, with each extended context structure beginning | ||
| 12 | * with a header defined by this struct. The type of context represented is | ||
| 13 | * indicated by the magic field. Userland may check each extended context | ||
| 14 | * structure against magic values that it recognises. The size field allows any | ||
| 15 | * unrecognised context to be skipped, allowing for future expansion. The end | ||
| 16 | * of the extended context data is indicated by the magic value | ||
| 17 | * END_EXTCONTEXT_MAGIC. | ||
| 18 | */ | ||
| 19 | struct extcontext { | ||
| 20 | unsigned int magic; | ||
| 21 | unsigned int size; | ||
| 22 | }; | ||
| 23 | |||
| 24 | /** | ||
| 25 | * struct msa_extcontext - MSA extended context structure | ||
| 26 | * @ext: the extended context header, with magic == MSA_EXTCONTEXT_MAGIC | ||
| 27 | * @wr: the most significant 64 bits of each MSA vector register | ||
| 28 | * @csr: the value of the MSA control & status register | ||
| 29 | * | ||
| 30 | * If MSA context is live for a task at the time a signal is delivered to it, | ||
| 31 | * this structure will hold the MSA context of the task as it was prior to the | ||
| 32 | * signal delivery. | ||
| 33 | */ | ||
| 34 | struct msa_extcontext { | ||
| 35 | struct extcontext ext; | ||
| 36 | #define MSA_EXTCONTEXT_MAGIC 0x784d5341 /* xMSA */ | ||
| 37 | |||
| 38 | unsigned long long wr[32]; | ||
| 39 | unsigned int csr; | ||
| 40 | }; | ||
| 41 | |||
| 42 | #define END_EXTCONTEXT_MAGIC 0x78454e44 /* xEND */ | ||
| 43 | |||
| 44 | /** | ||
| 45 | * struct ucontext - user context structure | ||
| 46 | * @uc_flags: | ||
| 47 | * @uc_link: | ||
| 48 | * @uc_stack: | ||
| 49 | * @uc_mcontext: holds basic processor state | ||
| 50 | * @uc_sigmask: | ||
| 51 | * @uc_extcontext: holds extended processor state | ||
| 52 | */ | ||
| 53 | struct ucontext { | ||
| 54 | /* Historic fields matching asm-generic */ | ||
| 55 | unsigned long uc_flags; | ||
| 56 | struct ucontext *uc_link; | ||
| 57 | stack_t uc_stack; | ||
| 58 | struct sigcontext uc_mcontext; | ||
| 59 | sigset_t uc_sigmask; | ||
| 60 | |||
| 61 | /* Extended context structures may follow ucontext */ | ||
| 62 | unsigned long long uc_extcontext[0]; | ||
| 63 | }; | ||
| 64 | |||
| 65 | #endif /* __MIPS_UAPI_ASM_UCONTEXT_H */ | ||
| @@ -110,18 +110,11 @@ asmlinkage void plat_irq_dispatch(void) · 109 unmodified lines | |||
| 110 | } | 110 | } |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | static void r4030_set_mode(enum clock_event_mode mode, | ||
| 114 | struct clock_event_device *evt) | ||
| 115 | { | ||
| 116 | /* Nothing to do ... */ | ||
| 117 | } | ||
| 118 | |||
| 119 | struct clock_event_device r4030_clockevent = { | 113 | struct clock_event_device r4030_clockevent = { |
| 120 | .name = "r4030", | 114 | .name = "r4030", |
| 121 | .features = CLOCK_EVT_FEAT_PERIODIC, | 115 | .features = CLOCK_EVT_FEAT_PERIODIC, |
| 122 | .rating = 300, | 116 | .rating = 300, |
| 123 | .irq = JAZZ_TIMER_IRQ, | 117 | .irq = JAZZ_TIMER_IRQ, |
| 124 | .set_mode = r4030_set_mode, | ||
| 125 | }; | 118 | }; |
| 126 | 119 | ||
| 127 | static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) | 120 | static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) |
| @@ -231,6 +231,13 @@ static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) · 230 unmodified lines | |||
| 231 | return 0; | 231 | return 0; |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) | ||
| 235 | { | ||
| 236 | struct jz_gpio_chip *jz_gpio = gpio_chip_to_jz_gpio_chip(chip); | ||
| 237 | |||
| 238 | return jz_gpio->irq_base + gpio; | ||
| 239 | } | ||
| 240 | |||
| 234 | int jz_gpio_port_direction_input(int port, uint32_t mask) | 241 | int jz_gpio_port_direction_input(int port, uint32_t mask) |
| 235 | { | 242 | { |
| 236 | writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR)); | 243 | writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR)); |
| @@ -262,18 +269,6 @@ uint32_t jz_gpio_port_get_value(int port, uint32_t mask) · 25 unmodified lines | |||
| 262 | } | 269 | } |
| 263 | EXPORT_SYMBOL(jz_gpio_port_get_value); | 270 | EXPORT_SYMBOL(jz_gpio_port_get_value); |
| 264 | 271 | ||
| 265 | int gpio_to_irq(unsigned gpio) | ||
| 266 | { | ||
| 267 | return JZ4740_IRQ_GPIO(0) + gpio; | ||
| 268 | } | ||
| 269 | EXPORT_SYMBOL_GPL(gpio_to_irq); | ||
| 270 | |||
| 271 | int irq_to_gpio(unsigned irq) | ||
| 272 | { | ||
| 273 | return irq - JZ4740_IRQ_GPIO(0); | ||
| 274 | } | ||
| 275 | EXPORT_SYMBOL_GPL(irq_to_gpio); | ||
| 276 | |||
| 277 | #define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f) | 272 | #define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f) |
| 278 | 273 | ||
| 279 | static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq) | 274 | static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq) |
| @@ -403,6 +398,7 @@ static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on) · 123 unmodified lines | |||
| 403 | .get = jz_gpio_get_value, \ | 398 | .get = jz_gpio_get_value, \ |
| 404 | .direction_output = jz_gpio_direction_output, \ | 399 | .direction_output = jz_gpio_direction_output, \ |
| 405 | .direction_input = jz_gpio_direction_input, \ | 400 | .direction_input = jz_gpio_direction_input, \ |
| 401 | .to_irq = jz_gpio_to_irq, \ | ||
| 406 | .base = JZ4740_GPIO_BASE_ ## _bank, \ | 402 | .base = JZ4740_GPIO_BASE_ ## _bank, \ |
| 407 | .ngpio = JZ4740_GPIO_NUM_ ## _bank, \ | 403 | .ngpio = JZ4740_GPIO_NUM_ ## _bank, \ |
| 408 | }, \ | 404 | }, \ |
| @@ -423,8 +419,8 @@ static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) · 14 unmodified lines | |||
| 423 | chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); | 419 | chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); |
| 424 | 420 | ||
| 425 | chip->irq = JZ4740_IRQ_INTC_GPIO(id); | 421 | chip->irq = JZ4740_IRQ_INTC_GPIO(id); |
| 426 | irq_set_handler_data(chip->irq, chip); | 422 | irq_set_chained_handler_and_data(chip->irq, |
| 427 | irq_set_chained_handler(chip->irq, jz_gpio_irq_demux_handler); | 423 | jz_gpio_irq_demux_handler, chip); |
| 428 | 424 | ||
| 429 | gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base, | 425 | gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base, |
| 430 | chip->base, handle_level_irq); | 426 | chip->base, handle_level_irq); |
| @@ -58,7 +58,7 @@ static irqreturn_t jz4740_clockevent_irq(int irq, void *devid) · 57 unmodified lines | |||
| 58 | 58 | ||
| 59 | jz4740_timer_ack_full(TIMER_CLOCKEVENT); | 59 | jz4740_timer_ack_full(TIMER_CLOCKEVENT); |
| 60 | 60 | ||
| 61 | if (cd->mode != CLOCK_EVT_MODE_PERIODIC) | 61 | if (!clockevent_state_periodic(cd)) |
| 62 | jz4740_timer_disable(TIMER_CLOCKEVENT); | 62 | jz4740_timer_disable(TIMER_CLOCKEVENT); |
| 63 | 63 | ||
| 64 | cd->event_handler(cd); | 64 | cd->event_handler(cd); |
| @@ -66,24 +66,29 @@ static irqreturn_t jz4740_clockevent_irq(int irq, void *devid) · 1 unmodified line | |||
| 66 | return IRQ_HANDLED; | 66 | return IRQ_HANDLED; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | static void jz4740_clockevent_set_mode(enum clock_event_mode mode, | 69 | static int jz4740_clockevent_set_periodic(struct clock_event_device *evt) |
| 70 | struct clock_event_device *cd) | ||
| 71 | { | 70 | { |
| 72 | switch (mode) { | 71 | jz4740_timer_set_count(TIMER_CLOCKEVENT, 0); |
| 73 | case CLOCK_EVT_MODE_PERIODIC: | 72 | jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick); |
| 74 | jz4740_timer_set_count(TIMER_CLOCKEVENT, 0); | 73 | jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); |
| 75 | jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick); | 74 | jz4740_timer_enable(TIMER_CLOCKEVENT); |
| 76 | case CLOCK_EVT_MODE_RESUME: | 75 | |
| 77 | jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); | 76 | return 0; |
| 78 | jz4740_timer_enable(TIMER_CLOCKEVENT); | 77 | } |
| 79 | break; | 78 | |
| 80 | case CLOCK_EVT_MODE_ONESHOT: | 79 | static int jz4740_clockevent_resume(struct clock_event_device *evt) |
| 81 | case CLOCK_EVT_MODE_SHUTDOWN: | 80 | { |
| 82 | jz4740_timer_disable(TIMER_CLOCKEVENT); | 81 | jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); |
| 83 | break; | 82 | jz4740_timer_enable(TIMER_CLOCKEVENT); |
| 84 | default: | 83 | |
| 85 | break; | 84 | return 0; |
| 86 | } | 85 | } |
| 86 | |||
| 87 | static int jz4740_clockevent_shutdown(struct clock_event_device *evt) | ||
| 88 | { | ||
| 89 | jz4740_timer_disable(TIMER_CLOCKEVENT); | ||
| 90 | |||
| 91 | return 0; | ||
| 87 | } | 92 | } |
| 88 | 93 | ||
| 89 | static int jz4740_clockevent_set_next(unsigned long evt, | 94 | static int jz4740_clockevent_set_next(unsigned long evt, |
| @@ -100,7 +105,10 @@ static struct clock_event_device jz4740_clockevent = { · 10 unmodified lines | |||
| 100 | .name = "jz4740-timer", | 105 | .name = "jz4740-timer", |
| 101 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 106 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
| 102 | .set_next_event = jz4740_clockevent_set_next, | 107 | .set_next_event = jz4740_clockevent_set_next, |
| 103 | .set_mode = jz4740_clockevent_set_mode, | 108 | .set_state_shutdown = jz4740_clockevent_shutdown, |
| 109 | .set_state_periodic = jz4740_clockevent_set_periodic, | ||
| 110 | .set_state_oneshot = jz4740_clockevent_shutdown, | ||
| 111 | .tick_resume = jz4740_clockevent_resume, | ||
| 104 | .rating = 200, | 112 | .rating = 200, |
| 105 | #ifdef CONFIG_MACH_JZ4740 | 113 | #ifdef CONFIG_MACH_JZ4740 |
| 106 | .irq = JZ4740_IRQ_TCU0, | 114 | .irq = JZ4740_IRQ_TCU0, |
| @@ -99,6 +99,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o · 98 unmodified lines | |||
| 99 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o | 99 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o |
| 100 | 100 | ||
| 101 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o | 101 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o |
| 102 | obj-$(CONFIG_UPROBES) += uprobes.o | ||
| 102 | 103 | ||
| 103 | obj-$(CONFIG_MIPS_CM) += mips-cm.o | 104 | obj-$(CONFIG_MIPS_CM) += mips-cm.o |
| 104 | obj-$(CONFIG_MIPS_CPC) += mips-cpc.o | 105 | obj-$(CONFIG_MIPS_CPC) += mips-cpc.o |
| @@ -128,6 +128,7 @@ void output_thread_defines(void) · 127 unmodified lines | |||
| 128 | thread.cp0_baduaddr); | 128 | thread.cp0_baduaddr); |
| 129 | OFFSET(THREAD_ECODE, task_struct, \ | 129 | OFFSET(THREAD_ECODE, task_struct, \ |
| 130 | thread.error_code); | 130 | thread.error_code); |
| 131 | OFFSET(THREAD_TRAPNO, task_struct, thread.trap_nr); | ||
| 131 | BLANK(); | 132 | BLANK(); |
| 132 | } | 133 | } |
| 133 | 134 | ||
| @@ -245,17 +246,6 @@ void output_sc_defines(void) · 111 unmodified lines | |||
| 245 | } | 246 | } |
| 246 | #endif | 247 | #endif |
| 247 | 248 | ||
| 248 | #ifdef CONFIG_MIPS32_COMPAT | ||
| 249 | void output_sc32_defines(void) | ||
| 250 | { | ||
| 251 | COMMENT("Linux 32-bit sigcontext offsets."); | ||
| 252 | OFFSET(SC32_FPREGS, sigcontext32, sc_fpregs); | ||
| 253 | OFFSET(SC32_FPC_CSR, sigcontext32, sc_fpc_csr); | ||
| 254 | OFFSET(SC32_FPC_EIR, sigcontext32, sc_fpc_eir); | ||
| 255 | BLANK(); | ||
| 256 | } | ||
| 257 | #endif | ||
| 258 | |||
| 259 | void output_signal_defined(void) | 249 | void output_signal_defined(void) |
| 260 | { | 250 | { |
| 261 | COMMENT("Linux signal numbers."); | 251 | COMMENT("Linux signal numbers."); |
| @@ -40,8 +40,8 @@ · 39 unmodified lines | |||
| 40 | * The general purpose timer ticks at 1MHz independent if | 40 | * The general purpose timer ticks at 1MHz independent if |
| 41 | * the rest of the system | 41 | * the rest of the system |
| 42 | */ | 42 | */ |
| 43 | static void sibyte_set_mode(enum clock_event_mode mode, | 43 | |
| 44 | struct clock_event_device *evt) | 44 | static int sibyte_set_periodic(struct clock_event_device *evt) |
| 45 | { | 45 | { |
| 46 | unsigned int cpu = smp_processor_id(); | 46 | unsigned int cpu = smp_processor_id(); |
| 47 | void __iomem *cfg, *init; | 47 | void __iomem *cfg, *init; |
| @@ -49,24 +49,22 @@ static void sibyte_set_mode(enum clock_event_mode mode, · 1 unmodified line | |||
| 49 | cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); | 49 | cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); |
| 50 | init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); | 50 | init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); |
| 51 | 51 | ||
| 52 | switch (mode) { | 52 | __raw_writeq(0, cfg); |
| 53 | case CLOCK_EVT_MODE_PERIODIC: | 53 | __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); |
| 54 | __raw_writeq(0, cfg); | 54 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg); |
| 55 | __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); | 55 | return 0; |
| 56 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | 56 | } |
| 57 | cfg); | 57 | |
| 58 | break; | 58 | static int sibyte_shutdown(struct clock_event_device *evt) |
| 59 | 59 | { | |
| 60 | case CLOCK_EVT_MODE_ONESHOT: | 60 | unsigned int cpu = smp_processor_id(); |
| 61 | /* Stop the timer until we actually program a shot */ | 61 | void __iomem *cfg; |
| 62 | case CLOCK_EVT_MODE_SHUTDOWN: | 62 | |
| 63 | __raw_writeq(0, cfg); | 63 | cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); |
| 64 | break; | 64 | |
| 65 | 65 | /* Stop the timer until we actually program a shot */ | |
| 66 | case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ | 66 | __raw_writeq(0, cfg); |
| 67 | case CLOCK_EVT_MODE_RESUME: | 67 | return 0; |
| 68 | ; | ||
| 69 | } | ||
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) | 70 | static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) |
| @@ -91,7 +89,7 @@ static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) · 18 unmodified lines | |||
| 91 | void __iomem *cfg; | 89 | void __iomem *cfg; |
| 92 | unsigned long tmode; | 90 | unsigned long tmode; |
| 93 | 91 | ||
| 94 | if (cd->mode == CLOCK_EVT_MODE_PERIODIC) | 92 | if (clockevent_state_periodic(cd)) |
| 95 | tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; | 93 | tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; |
| 96 | else | 94 | else |
| 97 | tmode = 0; | 95 | tmode = 0; |
| @@ -130,7 +128,9 @@ void sb1480_clockevent_init(void) · 32 unmodified lines | |||
| 130 | cd->irq = irq; | 128 | cd->irq = irq; |
| 131 | cd->cpumask = cpumask_of(cpu); | 129 | cd->cpumask = cpumask_of(cpu); |
| 132 | cd->set_next_event = sibyte_next_event; | 130 | cd->set_next_event = sibyte_next_event; |
| 133 | cd->set_mode = sibyte_set_mode; | 131 | cd->set_state_shutdown = sibyte_shutdown; |
| 132 | cd->set_state_periodic = sibyte_set_periodic; | ||
| 133 | cd->set_state_oneshot = sibyte_shutdown; | ||
| 134 | clockevents_register_device(cd); | 134 | clockevents_register_device(cd); |
| 135 | 135 | ||
| 136 | bcm1480_mask_irq(cpu, irq); | 136 | bcm1480_mask_irq(cpu, irq); |
| @@ -59,27 +59,32 @@ static int ds1287_set_next_event(unsigned long delta, · 58 unmodified lines | |||
| 59 | return -EINVAL; | 59 | return -EINVAL; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static void ds1287_set_mode(enum clock_event_mode mode, | 62 | static int ds1287_shutdown(struct clock_event_device *evt) |
| 63 | struct clock_event_device *evt) | ||
| 64 | { | 63 | { |
| 65 | u8 val; | 64 | u8 val; |
| 66 | 65 | ||
| 67 | spin_lock(&rtc_lock); | 66 | spin_lock(&rtc_lock); |
| 68 | 67 | ||
| 69 | val = CMOS_READ(RTC_REG_B); | 68 | val = CMOS_READ(RTC_REG_B); |
| 69 | val &= ~RTC_PIE; | ||
| 70 | CMOS_WRITE(val, RTC_REG_B); | ||
| 70 | 71 | ||
| 71 | switch (mode) { | 72 | spin_unlock(&rtc_lock); |
| 72 | case CLOCK_EVT_MODE_PERIODIC: | 73 | return 0; |
| 73 | val |= RTC_PIE; | 74 | } |
| 74 | break; | ||
| 75 | default: | ||
| 76 | val &= ~RTC_PIE; | ||
| 77 | break; | ||
| 78 | } | ||
| 79 | 75 | ||
| 76 | static int ds1287_set_periodic(struct clock_event_device *evt) | ||
| 77 | { | ||
| 78 | u8 val; | ||
| 79 | |||
| 80 | spin_lock(&rtc_lock); | ||
| 81 | |||
| 82 | val = CMOS_READ(RTC_REG_B); | ||
| 83 | val |= RTC_PIE; | ||
| 80 | CMOS_WRITE(val, RTC_REG_B); | 84 | CMOS_WRITE(val, RTC_REG_B); |
| 81 | 85 | ||
| 82 | spin_unlock(&rtc_lock); | 86 | spin_unlock(&rtc_lock); |
| 87 | return 0; | ||
| 83 | } | 88 | } |
| 84 | 89 | ||
| 85 | static void ds1287_event_handler(struct clock_event_device *dev) | 90 | static void ds1287_event_handler(struct clock_event_device *dev) |
| @@ -87,11 +92,13 @@ static void ds1287_event_handler(struct clock_event_device *dev) · 1 unmodified line | |||
| 87 | } | 92 | } |
| 88 | 93 | ||
| 89 | static struct clock_event_device ds1287_clockevent = { | 94 | static struct clock_event_device ds1287_clockevent = { |
| 90 | .name = "ds1287", | 95 | .name = "ds1287", |
| 91 | .features = CLOCK_EVT_FEAT_PERIODIC, | 96 | .features = CLOCK_EVT_FEAT_PERIODIC, |
| 92 | .set_next_event = ds1287_set_next_event, | 97 | .set_next_event = ds1287_set_next_event, |
| 93 | .set_mode = ds1287_set_mode, | 98 | .set_state_shutdown = ds1287_shutdown, |
| 94 | .event_handler = ds1287_event_handler, | 99 | .set_state_periodic = ds1287_set_periodic, |
| 100 | .tick_resume = ds1287_shutdown, | ||
| 101 | .event_handler = ds1287_event_handler, | ||
| 95 | }; | 102 | }; |
| 96 | 103 | ||
| 97 | static irqreturn_t ds1287_interrupt(int irq, void *dev_id) | 104 | static irqreturn_t ds1287_interrupt(int irq, void *dev_id) |
| @@ -64,8 +64,7 @@ static int gt641xx_timer0_set_next_event(unsigned long delta, · 63 unmodified lines | |||
| 64 | return 0; | 64 | return 0; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static void gt641xx_timer0_set_mode(enum clock_event_mode mode, | 67 | static int gt641xx_timer0_shutdown(struct clock_event_device *evt) |
| 68 | struct clock_event_device *evt) | ||
| 69 | { | 68 | { |
| 70 | u32 ctrl; | 69 | u32 ctrl; |
| 71 | 70 | ||
| @@ -73,21 +72,39 @@ static void gt641xx_timer0_set_mode(enum clock_event_mode mode, · 1 unmodified line | |||
| 73 | 72 | ||
| 74 | ctrl = GT_READ(GT_TC_CONTROL_OFS); | 73 | ctrl = GT_READ(GT_TC_CONTROL_OFS); |
| 75 | ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); | 74 | ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); |
| 75 | GT_WRITE(GT_TC_CONTROL_OFS, ctrl); | ||
| 76 | |||
| 77 | raw_spin_unlock(>641xx_timer_lock); | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | static int gt641xx_timer0_set_oneshot(struct clock_event_device *evt) | ||
| 82 | { | ||
| 83 | u32 ctrl; | ||
| 84 | |||
| 85 | raw_spin_lock(>641xx_timer_lock); | ||
| 86 | |||
| 87 | ctrl = GT_READ(GT_TC_CONTROL_OFS); | ||
| 88 | ctrl &= ~GT_TC_CONTROL_SELTC0_MSK; | ||
| 89 | ctrl |= GT_TC_CONTROL_ENTC0_MSK; | ||
| 90 | GT_WRITE(GT_TC_CONTROL_OFS, ctrl); | ||
| 91 | |||
| 92 | raw_spin_unlock(>641xx_timer_lock); | ||
| 93 | return 0; | ||
| 94 | } | ||
| 76 | 95 | ||
| 77 | switch (mode) { | 96 | static int gt641xx_timer0_set_periodic(struct clock_event_device *evt) |
| 78 | case CLOCK_EVT_MODE_PERIODIC: | 97 | { |
| 79 | ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; | 98 | u32 ctrl; |
| 80 | break; | 99 | |
| 81 | case CLOCK_EVT_MODE_ONESHOT: | 100 | raw_spin_lock(>641xx_timer_lock); |
| 82 | ctrl |= GT_TC_CONTROL_ENTC0_MSK; | ||
| 83 | break; | ||
| 84 | default: | ||
| 85 | break; | ||
| 86 | } | ||
| 87 | 101 | ||
| 102 | ctrl = GT_READ(GT_TC_CONTROL_OFS); | ||
| 103 | ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; | ||
| 88 | GT_WRITE(GT_TC_CONTROL_OFS, ctrl); | 104 | GT_WRITE(GT_TC_CONTROL_OFS, ctrl); |
| 89 | 105 | ||
| 90 | raw_spin_unlock(>641xx_timer_lock); | 106 | raw_spin_unlock(>641xx_timer_lock); |
| 107 | return 0; | ||
| 91 | } | 108 | } |
| 92 | 109 | ||
| 93 | static void gt641xx_timer0_event_handler(struct clock_event_device *dev) | 110 | static void gt641xx_timer0_event_handler(struct clock_event_device *dev) |
| @@ -95,12 +112,16 @@ static void gt641xx_timer0_event_handler(struct clock_event_device *dev) · 1 unmodified line | |||
| 95 | } | 112 | } |
| 96 | 113 | ||
| 97 | static struct clock_event_device gt641xx_timer0_clockevent = { | 114 | static struct clock_event_device gt641xx_timer0_clockevent = { |
| 98 | .name = "gt641xx-timer0", | 115 | .name = "gt641xx-timer0", |
| 99 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 116 | .features = CLOCK_EVT_FEAT_PERIODIC | |
| 100 | .irq = GT641XX_TIMER0_IRQ, | 117 | CLOCK_EVT_FEAT_ONESHOT, |
| 101 | .set_next_event = gt641xx_timer0_set_next_event, | 118 | .irq = GT641XX_TIMER0_IRQ, |
| 102 | .set_mode = gt641xx_timer0_set_mode, | 119 | .set_next_event = gt641xx_timer0_set_next_event, |
| 103 | .event_handler = gt641xx_timer0_event_handler, | 120 | .set_state_shutdown = gt641xx_timer0_shutdown, |
| 121 | .set_state_periodic = gt641xx_timer0_set_periodic, | ||
| 122 | .set_state_oneshot = gt641xx_timer0_set_oneshot, | ||
| 123 | .tick_resume = gt641xx_timer0_shutdown, | ||
| 124 | .event_handler = gt641xx_timer0_event_handler, | ||
| 104 | }; | 125 | }; |
| 105 | 126 | ||
| 106 | static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id) | 127 | static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id) |
| @@ -28,12 +28,6 @@ static int mips_next_event(unsigned long delta, · 27 unmodified lines | |||
| 28 | return res; | 28 | return res; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | void mips_set_clock_mode(enum clock_event_mode mode, | ||
| 32 | struct clock_event_device *evt) | ||
| 33 | { | ||
| 34 | /* Nothing to do ... */ | ||
| 35 | } | ||
| 36 | |||
| 37 | DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); | 31 | DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); |
| 38 | int cp0_timer_irq_installed; | 32 | int cp0_timer_irq_installed; |
| 39 | 33 | ||
| @@ -174,6 +168,11 @@ int c0_compare_int_usable(void) · 134 unmodified lines | |||
| 174 | return 1; | 168 | return 1; |
| 175 | } | 169 | } |
| 176 | 170 | ||
| 171 | unsigned int __weak get_c0_compare_int(void) | ||
| 172 | { | ||
| 173 | return MIPS_CPU_IRQ_BASE + cp0_compare_irq; | ||
| 174 | } | ||
| 175 | |||
| 177 | int r4k_clockevent_init(void) | 176 | int r4k_clockevent_init(void) |
| 178 | { | 177 | { |
| 179 | unsigned int cpu = smp_processor_id(); | 178 | unsigned int cpu = smp_processor_id(); |
| @@ -189,11 +188,9 @@ int r4k_clockevent_init(void) · 9 unmodified lines | |||
| 189 | /* | 188 | /* |
| 190 | * With vectored interrupts things are getting platform specific. | 189 | * With vectored interrupts things are getting platform specific. |
| 191 | * get_c0_compare_int is a hook to allow a platform to return the | 190 | * get_c0_compare_int is a hook to allow a platform to return the |
| 192 | * interrupt number of it's liking. | 191 | * interrupt number of its liking. |
| 193 | */ | 192 | */ |
| 194 | irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; | 193 | irq = get_c0_compare_int(); |
| 195 | if (get_c0_compare_int) | ||
| 196 | irq = get_c0_compare_int(); | ||
| 197 | 194 | ||
| 198 | cd = &per_cpu(mips_clockevent_device, cpu); | 195 | cd = &per_cpu(mips_clockevent_device, cpu); |
| 199 | 196 | ||
| @@ -212,7 +209,6 @@ int r4k_clockevent_init(void) · 12 unmodified lines | |||
| 212 | cd->irq = irq; | 209 | cd->irq = irq; |
| 213 | cd->cpumask = cpumask_of(cpu); | 210 | cd->cpumask = cpumask_of(cpu); |
| 214 | cd->set_next_event = mips_next_event; | 211 | cd->set_next_event = mips_next_event; |
| 215 | cd->set_mode = mips_set_clock_mode; | ||
| 216 | cd->event_handler = mips_event_handler; | 212 | cd->event_handler = mips_event_handler; |
| 217 | 213 | ||
| 218 | clockevents_register_device(cd); | 214 | clockevents_register_device(cd); |
| @@ -38,8 +38,20 @@ · 37 unmodified lines | |||
| 38 | * The general purpose timer ticks at 1MHz independent if | 38 | * The general purpose timer ticks at 1MHz independent if |
| 39 | * the rest of the system | 39 | * the rest of the system |
| 40 | */ | 40 | */ |
| 41 | static void sibyte_set_mode(enum clock_event_mode mode, | 41 | |
| 42 | struct clock_event_device *evt) | 42 | static int sibyte_shutdown(struct clock_event_device *evt) |
| 43 | { | ||
| 44 | void __iomem *cfg; | ||
| 45 | |||
| 46 | cfg = IOADDR(A_SCD_TIMER_REGISTER(smp_processor_id(), R_SCD_TIMER_CFG)); | ||
| 47 | |||
| 48 | /* Stop the timer until we actually program a shot */ | ||
| 49 | __raw_writeq(0, cfg); | ||
| 50 | |||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | static int sibyte_set_periodic(struct clock_event_device *evt) | ||
| 43 | { | 55 | { |
| 44 | unsigned int cpu = smp_processor_id(); | 56 | unsigned int cpu = smp_processor_id(); |
| 45 | void __iomem *cfg, *init; | 57 | void __iomem *cfg, *init; |
| @@ -47,24 +59,11 @@ static void sibyte_set_mode(enum clock_event_mode mode, · 1 unmodified line | |||
| 47 | cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); | 59 | cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); |
| 48 | init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); | 60 | init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); |
| 49 | 61 | ||
| 50 | switch (mode) { | 62 | __raw_writeq(0, cfg); |
| 51 | case CLOCK_EVT_MODE_PERIODIC: | 63 | __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); |
| 52 | __raw_writeq(0, cfg); | 64 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg); |
| 53 | __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); | 65 | |
| 54 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | 66 | return 0; |
| 55 | cfg); | ||
| 56 | break; | ||
| 57 | |||
| 58 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 59 | /* Stop the timer until we actually program a shot */ | ||
| 60 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 61 | __raw_writeq(0, cfg); | ||
| 62 | break; | ||
| 63 | |||
| 64 | case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ | ||
| 65 | case CLOCK_EVT_MODE_RESUME: | ||
| 66 | ; | ||
| 67 | } | ||
| 68 | } | 67 | } |
| 69 | 68 | ||
| 70 | static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) | 69 | static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) |
| @@ -89,7 +88,7 @@ static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) · 18 unmodified lines | |||
| 89 | void __iomem *cfg; | 88 | void __iomem *cfg; |
| 90 | unsigned long tmode; | 89 | unsigned long tmode; |
| 91 | 90 | ||
| 92 | if (cd->mode == CLOCK_EVT_MODE_PERIODIC) | 91 | if (clockevent_state_periodic(cd)) |
| 93 | tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; | 92 | tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; |
| 94 | else | 93 | else |
| 95 | tmode = 0; | 94 | tmode = 0; |
| @@ -129,7 +128,9 @@ void sb1250_clockevent_init(void) · 33 unmodified lines | |||
| 129 | cd->irq = irq; | 128 | cd->irq = irq; |
| 130 | cd->cpumask = cpumask_of(cpu); | 129 | cd->cpumask = cpumask_of(cpu); |
| 131 | cd->set_next_event = sibyte_next_event; | 130 | cd->set_next_event = sibyte_next_event; |
| 132 | cd->set_mode = sibyte_set_mode; | 131 | cd->set_state_shutdown = sibyte_shutdown; |
| 132 | cd->set_state_periodic = sibyte_set_periodic; | ||
| 133 | cd->set_state_oneshot = sibyte_shutdown; | ||
| 133 | clockevents_register_device(cd); | 134 | clockevents_register_device(cd); |
| 134 | 135 | ||
| 135 | sb1250_mask_irq(cpu, irq); | 136 | sb1250_mask_irq(cpu, irq); |
| @@ -85,36 +85,54 @@ static void txx9tmr_stop_and_clear(struct txx9_tmr_reg __iomem *tmrptr) · 84 unmodified lines | |||
| 85 | __raw_writel(0, &tmrptr->tisr); | 85 | __raw_writel(0, &tmrptr->tisr); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static void txx9tmr_set_mode(enum clock_event_mode mode, | 88 | static int txx9tmr_set_state_periodic(struct clock_event_device *evt) |
| 89 | struct clock_event_device *evt) | ||
| 90 | { | 89 | { |
| 91 | struct txx9_clock_event_device *txx9_cd = | 90 | struct txx9_clock_event_device *txx9_cd = |
| 92 | container_of(evt, struct txx9_clock_event_device, cd); | 91 | container_of(evt, struct txx9_clock_event_device, cd); |
| 93 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | 92 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; |
| 94 | 93 | ||
| 95 | txx9tmr_stop_and_clear(tmrptr); | 94 | txx9tmr_stop_and_clear(tmrptr); |
| 96 | switch (mode) { | 95 | |
| 97 | case CLOCK_EVT_MODE_PERIODIC: | 96 | __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, &tmrptr->itmr); |
| 98 | __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, | 97 | /* start timer */ |
| 99 | &tmrptr->itmr); | 98 | __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> evt->shift, |
| 100 | /* start timer */ | 99 | &tmrptr->cpra); |
| 101 | __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> | 100 | __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); |
| 102 | evt->shift, | 101 | return 0; |
| 103 | &tmrptr->cpra); | 102 | } |
| 104 | __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); | 103 | |
| 105 | break; | 104 | static int txx9tmr_set_state_oneshot(struct clock_event_device *evt) |
| 106 | case CLOCK_EVT_MODE_SHUTDOWN: | 105 | { |
| 107 | case CLOCK_EVT_MODE_UNUSED: | 106 | struct txx9_clock_event_device *txx9_cd = |
| 108 | __raw_writel(0, &tmrptr->itmr); | 107 | container_of(evt, struct txx9_clock_event_device, cd); |
| 109 | break; | 108 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; |
| 110 | case CLOCK_EVT_MODE_ONESHOT: | 109 | |
| 111 | __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); | 110 | txx9tmr_stop_and_clear(tmrptr); |
| 112 | break; | 111 | __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); |
| 113 | case CLOCK_EVT_MODE_RESUME: | 112 | return 0; |
| 114 | __raw_writel(TIMER_CCD, &tmrptr->ccdr); | 113 | } |
| 115 | __raw_writel(0, &tmrptr->itmr); | 114 | |
| 116 | break; | 115 | static int txx9tmr_set_state_shutdown(struct clock_event_device *evt) |
| 117 | } | 116 | { |
| 117 | struct txx9_clock_event_device *txx9_cd = | ||
| 118 | container_of(evt, struct txx9_clock_event_device, cd); | ||
| 119 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | ||
| 120 | |||
| 121 | txx9tmr_stop_and_clear(tmrptr); | ||
| 122 | __raw_writel(0, &tmrptr->itmr); | ||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | static int txx9tmr_tick_resume(struct clock_event_device *evt) | ||
| 127 | { | ||
| 128 | struct txx9_clock_event_device *txx9_cd = | ||
| 129 | container_of(evt, struct txx9_clock_event_device, cd); | ||
| 130 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | ||
| 131 | |||
| 132 | txx9tmr_stop_and_clear(tmrptr); | ||
| 133 | __raw_writel(TIMER_CCD, &tmrptr->ccdr); | ||
| 134 | __raw_writel(0, &tmrptr->itmr); | ||
| 135 | return 0; | ||
| 118 | } | 136 | } |
| 119 | 137 | ||
| 120 | static int txx9tmr_set_next_event(unsigned long delta, | 138 | static int txx9tmr_set_next_event(unsigned long delta, |
| @@ -133,12 +151,15 @@ static int txx9tmr_set_next_event(unsigned long delta, · 12 unmodified lines | |||
| 133 | 151 | ||
| 134 | static struct txx9_clock_event_device txx9_clock_event_device = { | 152 | static struct txx9_clock_event_device txx9_clock_event_device = { |
| 135 | .cd = { | 153 | .cd = { |
| 136 | .name = "TXx9", | 154 | .name = "TXx9", |
| 137 | .features = CLOCK_EVT_FEAT_PERIODIC | | 155 | .features = CLOCK_EVT_FEAT_PERIODIC | |
| 138 | CLOCK_EVT_FEAT_ONESHOT, | 156 | CLOCK_EVT_FEAT_ONESHOT, |
| 139 | .rating = 200, | 157 | .rating = 200, |
| 140 | .set_mode = txx9tmr_set_mode, | 158 | .set_state_shutdown = txx9tmr_set_state_shutdown, |
| 141 | .set_next_event = txx9tmr_set_next_event, | 159 | .set_state_periodic = txx9tmr_set_state_periodic, |
| 160 | .set_state_oneshot = txx9tmr_set_state_oneshot, | ||
| 161 | .tick_resume = txx9tmr_tick_resume, | ||
| 162 | .set_next_event = txx9tmr_set_next_event, | ||
| 142 | }, | 163 | }, |
| 143 | }; | 164 | }; |
| 144 | 165 | ||
| @@ -152,7 +152,7 @@ dcache_done: · 151 unmodified lines | |||
| 152 | 152 | ||
| 153 | /* Enter the coherent domain */ | 153 | /* Enter the coherent domain */ |
| 154 | li t0, 0xff | 154 | li t0, 0xff |
| 155 | PTR_S t0, GCR_CL_COHERENCE_OFS(v1) | 155 | sw t0, GCR_CL_COHERENCE_OFS(v1) |
| 156 | ehb | 156 | ehb |
| 157 | 157 | ||
| 158 | /* Jump to kseg0 */ | 158 | /* Jump to kseg0 */ |
| @@ -302,7 +302,7 @@ LEAF(mips_cps_boot_vpes) · 143 unmodified lines | |||
| 302 | PTR_L t0, 0(t0) | 302 | PTR_L t0, 0(t0) |
| 303 | 303 | ||
| 304 | /* Calculate a pointer to this cores struct core_boot_config */ | 304 | /* Calculate a pointer to this cores struct core_boot_config */ |
| 305 | PTR_L t0, GCR_CL_ID_OFS(t0) | 305 | lw t0, GCR_CL_ID_OFS(t0) |
| 306 | li t1, COREBOOTCFG_SIZE | 306 | li t1, COREBOOTCFG_SIZE |
| 307 | mul t0, t0, t1 | 307 | mul t0, t0, t1 |
| 308 | PTR_LA t1, mips_cps_core_bootcfg | 308 | PTR_LA t1, mips_cps_core_bootcfg |
| @@ -32,6 +32,9 @@ · 31 unmodified lines | |||
| 32 | #include <asm/spram.h> | 32 | #include <asm/spram.h> |
| 33 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
| 34 | 34 | ||
| 35 | /* Hardware capabilities */ | ||
| 36 | unsigned int elf_hwcap __read_mostly; | ||
| 37 | |||
| 35 | /* | 38 | /* |
| 36 | * Get the FPU Implementation/Revision. | 39 | * Get the FPU Implementation/Revision. |
| 37 | */ | 40 | */ |
| @@ -188,7 +191,7 @@ __setup("nohtw", htw_disable); · 150 unmodified lines | |||
| 188 | static int mips_ftlb_disabled; | 191 | static int mips_ftlb_disabled; |
| 189 | static int mips_has_ftlb_configured; | 192 | static int mips_has_ftlb_configured; |
| 190 | 193 | ||
| 191 | static void set_ftlb_enable(struct cpuinfo_mips *c, int enable); | 194 | static int set_ftlb_enable(struct cpuinfo_mips *c, int enable); |
| 192 | 195 | ||
| 193 | static int __init ftlb_disable(char *s) | 196 | static int __init ftlb_disable(char *s) |
| 194 | { | 197 | { |
| @@ -202,7 +205,10 @@ static int __init ftlb_disable(char *s) · 7 unmodified lines | |||
| 202 | return 1; | 205 | return 1; |
| 203 | 206 | ||
| 204 | /* Disable it in the boot cpu */ | 207 | /* Disable it in the boot cpu */ |
| 205 | set_ftlb_enable(&cpu_data[0], 0); | 208 | if (set_ftlb_enable(&cpu_data[0], 0)) { |
| 209 | pr_warn("Can't turn FTLB off\n"); | ||
| 210 | return 1; | ||
| 211 | } | ||
| 206 | 212 | ||
| 207 | back_to_back_c0_hazard(); | 213 | back_to_back_c0_hazard(); |
| 208 | 214 | ||
| @@ -364,30 +370,41 @@ static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c) · 155 unmodified lines | |||
| 364 | return 3; | 370 | return 3; |
| 365 | } | 371 | } |
| 366 | 372 | ||
| 367 | static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) | 373 | static int set_ftlb_enable(struct cpuinfo_mips *c, int enable) |
| 368 | { | 374 | { |
| 369 | unsigned int config6; | 375 | unsigned int config; |
| 370 | 376 | ||
| 371 | /* It's implementation dependent how the FTLB can be enabled */ | 377 | /* It's implementation dependent how the FTLB can be enabled */ |
| 372 | switch (c->cputype) { | 378 | switch (c->cputype) { |
| 373 | case CPU_PROAPTIV: | 379 | case CPU_PROAPTIV: |
| 374 | case CPU_P5600: | 380 | case CPU_P5600: |
| 375 | /* proAptiv & related cores use Config6 to enable the FTLB */ | 381 | /* proAptiv & related cores use Config6 to enable the FTLB */ |
| 376 | config6 = read_c0_config6(); | 382 | config = read_c0_config6(); |
| 377 | /* Clear the old probability value */ | 383 | /* Clear the old probability value */ |
| 378 | config6 &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); | 384 | config &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); |
| 379 | if (enable) | 385 | if (enable) |
| 380 | /* Enable FTLB */ | 386 | /* Enable FTLB */ |
| 381 | write_c0_config6(config6 | | 387 | write_c0_config6(config | |
| 382 | (calculate_ftlb_probability(c) | 388 | (calculate_ftlb_probability(c) |
| 383 | << MIPS_CONF6_FTLBP_SHIFT) | 389 | << MIPS_CONF6_FTLBP_SHIFT) |
| 384 | | MIPS_CONF6_FTLBEN); | 390 | | MIPS_CONF6_FTLBEN); |
| 385 | else | 391 | else |
| 386 | /* Disable FTLB */ | 392 | /* Disable FTLB */ |
| 387 | write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); | 393 | write_c0_config6(config & ~MIPS_CONF6_FTLBEN); |
| 388 | back_to_back_c0_hazard(); | ||
| 389 | break; | 394 | break; |
| 395 | case CPU_I6400: | ||
| 396 | /* I6400 & related cores use Config7 to configure FTLB */ | ||
| 397 | config = read_c0_config7(); | ||
| 398 | /* Clear the old probability value */ | ||
| 399 | config &= ~(3 << MIPS_CONF7_FTLBP_SHIFT); | ||
| 400 | write_c0_config7(config | (calculate_ftlb_probability(c) | ||
| 401 | << MIPS_CONF7_FTLBP_SHIFT)); | ||
| 402 | break; | ||
| 403 | default: | ||
| 404 | return 1; | ||
| 390 | } | 405 | } |
| 406 | |||
| 407 | return 0; | ||
| 391 | } | 408 | } |
| 392 | 409 | ||
| 393 | static inline unsigned int decode_config0(struct cpuinfo_mips *c) | 410 | static inline unsigned int decode_config0(struct cpuinfo_mips *c) |
| @@ -524,6 +541,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) · 130 unmodified lines | |||
| 524 | } | 541 | } |
| 525 | if (config3 & MIPS_CONF3_CDMM) | 542 | if (config3 & MIPS_CONF3_CDMM) |
| 526 | c->options |= MIPS_CPU_CDMM; | 543 | c->options |= MIPS_CPU_CDMM; |
| 544 | if (config3 & MIPS_CONF3_SP) | ||
| 545 | c->options |= MIPS_CPU_SP; | ||
| 527 | 546 | ||
| 528 | return config3 & MIPS_CONF_M; | 547 | return config3 & MIPS_CONF_M; |
| 529 | } | 548 | } |
| @@ -540,7 +559,16 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) · 10 unmodified lines | |||
| 540 | if (cpu_has_tlb) { | 559 | if (cpu_has_tlb) { |
| 541 | if (((config4 & MIPS_CONF4_IE) >> 29) == 2) | 560 | if (((config4 & MIPS_CONF4_IE) >> 29) == 2) |
| 542 | c->options |= MIPS_CPU_TLBINV; | 561 | c->options |= MIPS_CPU_TLBINV; |
| 543 | mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; | 562 | /* |
| 563 | * This is a bit ugly. R6 has dropped that field from | ||
| 564 | * config4 and the only valid configuration is VTLB+FTLB so | ||
| 565 | * set a good value for mmuextdef for that case. | ||
| 566 | */ | ||
| 567 | if (cpu_has_mips_r6) | ||
| 568 | mmuextdef = MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT; | ||
| 569 | else | ||
| 570 | mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; | ||
| 571 | |||
| 544 | switch (mmuextdef) { | 572 | switch (mmuextdef) { |
| 545 | case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT: | 573 | case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT: |
| 546 | c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; | 574 | c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; |
| @@ -1121,6 +1149,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) · 574 unmodified lines | |||
| 1121 | c->cputype = CPU_P5600; | 1149 | c->cputype = CPU_P5600; |
| 1122 | __cpu_name[cpu] = "MIPS P5600"; | 1150 | __cpu_name[cpu] = "MIPS P5600"; |
| 1123 | break; | 1151 | break; |
| 1152 | case PRID_IMP_I6400: | ||
| 1153 | c->cputype = CPU_I6400; | ||
| 1154 | __cpu_name[cpu] = "MIPS I6400"; | ||
| 1155 | break; | ||
| 1124 | case PRID_IMP_M5150: | 1156 | case PRID_IMP_M5150: |
| 1125 | c->cputype = CPU_M5150; | 1157 | c->cputype = CPU_M5150; |
| 1126 | __cpu_name[cpu] = "MIPS M5150"; | 1158 | __cpu_name[cpu] = "MIPS M5150"; |
| @@ -1492,10 +1524,14 @@ void cpu_probe(void) · 365 unmodified lines | |||
| 1492 | else | 1524 | else |
| 1493 | c->srsets = 1; | 1525 | c->srsets = 1; |
| 1494 | 1526 | ||
| 1527 | if (cpu_has_mips_r6) | ||
| 1528 | elf_hwcap |= HWCAP_MIPS_R6; | ||
| 1529 | |||
| 1495 | if (cpu_has_msa) { | 1530 | if (cpu_has_msa) { |
| 1496 | c->msa_id = cpu_get_msa_id(); | 1531 | c->msa_id = cpu_get_msa_id(); |
| 1497 | WARN(c->msa_id & MSA_IR_WRPF, | 1532 | WARN(c->msa_id & MSA_IR_WRPF, |
| 1498 | "Vector register partitioning unimplemented!"); | 1533 | "Vector register partitioning unimplemented!"); |
| 1534 | elf_hwcap |= HWCAP_MIPS_MSA; | ||
| 1499 | } | 1535 | } |
| 1500 | 1536 | ||
| 1501 | cpu_probe_vmbits(c); | 1537 | cpu_probe_vmbits(c); |
| @@ -196,6 +196,7 @@ void __init check_wait(void) · 195 unmodified lines | |||
| 196 | case CPU_INTERAPTIV: | 196 | case CPU_INTERAPTIV: |
| 197 | case CPU_M5150: | 197 | case CPU_M5150: |
| 198 | case CPU_QEMU_GENERIC: | 198 | case CPU_QEMU_GENERIC: |
| 199 | case CPU_I6400: | ||
| 199 | cpu_wait = r4k_wait; | 200 | cpu_wait = r4k_wait; |
| 200 | if (read_c0_config7() & MIPS_CONF7_WII) | 201 | if (read_c0_config7() & MIPS_CONF7_WII) |
| 201 | cpu_wait = r4k_wait_irqoff; | 202 | cpu_wait = r4k_wait_irqoff; |
| @@ -15,11 +15,131 @@ · 14 unmodified lines | |||
| 15 | 15 | ||
| 16 | void __iomem *mips_cm_base; | 16 | void __iomem *mips_cm_base; |
| 17 | void __iomem *mips_cm_l2sync_base; | 17 | void __iomem *mips_cm_l2sync_base; |
| 18 | int mips_cm_is64; | ||
| 19 | |||
| 20 | static char *cm2_tr[8] = { | ||
| 21 | "mem", "gcr", "gic", "mmio", | ||
| 22 | "0x04", "cpc", "0x06", "0x07" | ||
| 23 | }; | ||
| 24 | |||
| 25 | /* CM3 Tag ECC transation type */ | ||
| 26 | static char *cm3_tr[16] = { | ||
| 27 | [0x0] = "ReqNoData", | ||
| 28 | [0x1] = "0x1", | ||
| 29 | [0x2] = "ReqWData", | ||
| 30 | [0x3] = "0x3", | ||
| 31 | [0x4] = "IReqNoResp", | ||
| 32 | [0x5] = "IReqWResp", | ||
| 33 | [0x6] = "IReqNoRespDat", | ||
| 34 | [0x7] = "IReqWRespDat", | ||
| 35 | [0x8] = "RespNoData", | ||
| 36 | [0x9] = "RespDataFol", | ||
| 37 | [0xa] = "RespWData", | ||
| 38 | [0xb] = "RespDataOnly", | ||
| 39 | [0xc] = "IRespNoData", | ||
| 40 | [0xd] = "IRespDataFol", | ||
| 41 | [0xe] = "IRespWData", | ||
| 42 | [0xf] = "IRespDataOnly" | ||
| 43 | }; | ||
| 44 | |||
| 45 | static char *cm2_cmd[32] = { | ||
| 46 | [0x00] = "0x00", | ||
| 47 | [0x01] = "Legacy Write", | ||
| 48 | [0x02] = "Legacy Read", | ||
| 49 | [0x03] = "0x03", | ||
| 50 | [0x04] = "0x04", | ||
| 51 | [0x05] = "0x05", | ||
| 52 | [0x06] = "0x06", | ||
| 53 | [0x07] = "0x07", | ||
| 54 | [0x08] = "Coherent Read Own", | ||
| 55 | [0x09] = "Coherent Read Share", | ||
| 56 | [0x0a] = "Coherent Read Discard", | ||
| 57 | [0x0b] = "Coherent Ready Share Always", | ||
| 58 | [0x0c] = "Coherent Upgrade", | ||
| 59 | [0x0d] = "Coherent Writeback", | ||
| 60 | [0x0e] = "0x0e", | ||
| 61 | [0x0f] = "0x0f", | ||
| 62 | [0x10] = "Coherent Copyback", | ||
| 63 | [0x11] = "Coherent Copyback Invalidate", | ||
| 64 | [0x12] = "Coherent Invalidate", | ||
| 65 | [0x13] = "Coherent Write Invalidate", | ||
| 66 | [0x14] = "Coherent Completion Sync", | ||
| 67 | [0x15] = "0x15", | ||
| 68 | [0x16] = "0x16", | ||
| 69 | [0x17] = "0x17", | ||
| 70 | [0x18] = "0x18", | ||
| 71 | [0x19] = "0x19", | ||
| 72 | [0x1a] = "0x1a", | ||
| 73 | [0x1b] = "0x1b", | ||
| 74 | [0x1c] = "0x1c", | ||
| 75 | [0x1d] = "0x1d", | ||
| 76 | [0x1e] = "0x1e", | ||
| 77 | [0x1f] = "0x1f" | ||
| 78 | }; | ||
| 79 | |||
| 80 | /* CM3 Tag ECC command type */ | ||
| 81 | static char *cm3_cmd[16] = { | ||
| 82 | [0x0] = "Legacy Read", | ||
| 83 | [0x1] = "Legacy Write", | ||
| 84 | [0x2] = "Coherent Read Own", | ||
| 85 | [0x3] = "Coherent Read Share", | ||
| 86 | [0x4] = "Coherent Read Discard", | ||
| 87 | [0x5] = "Coherent Evicted", | ||
| 88 | [0x6] = "Coherent Upgrade", | ||
| 89 | [0x7] = "Coherent Upgrade for Store Conditional", | ||
| 90 | [0x8] = "Coherent Writeback", | ||
| 91 | [0x9] = "Coherent Write Invalidate", | ||
| 92 | [0xa] = "0xa", | ||
| 93 | [0xb] = "0xb", | ||
| 94 | [0xc] = "0xc", | ||
| 95 | [0xd] = "0xd", | ||
| 96 | [0xe] = "0xe", | ||
| 97 | [0xf] = "0xf" | ||
| 98 | }; | ||
| 99 | |||
| 100 | /* CM3 Tag ECC command group */ | ||
| 101 | static char *cm3_cmd_group[8] = { | ||
| 102 | [0x0] = "Normal", | ||
| 103 | [0x1] = "Registers", | ||
| 104 | [0x2] = "TLB", | ||
| 105 | [0x3] = "0x3", | ||
| 106 | [0x4] = "L1I", | ||
| 107 | [0x5] = "L1D", | ||
| 108 | [0x6] = "L3", | ||
| 109 | [0x7] = "L2" | ||
| 110 | }; | ||
| 111 | |||
| 112 | static char *cm2_core[8] = { | ||
| 113 | "Invalid/OK", "Invalid/Data", | ||
| 114 | "Shared/OK", "Shared/Data", | ||
| 115 | "Modified/OK", "Modified/Data", | ||
| 116 | "Exclusive/OK", "Exclusive/Data" | ||
| 117 | }; | ||
| 118 | |||
| 119 | static char *cm2_causes[32] = { | ||
| 120 | "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", | ||
| 121 | "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", | ||
| 122 | "0x08", "0x09", "0x0a", "0x0b", | ||
| 123 | "0x0c", "0x0d", "0x0e", "0x0f", | ||
| 124 | "0x10", "0x11", "0x12", "0x13", | ||
| 125 | "0x14", "0x15", "0x16", "INTVN_WR_ERR", | ||
| 126 | "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", | ||
| 127 | "0x1c", "0x1d", "0x1e", "0x1f" | ||
| 128 | }; | ||
| 129 | |||
| 130 | static char *cm3_causes[32] = { | ||
| 131 | "0x0", "MP_CORRECTABLE_ECC_ERR", "MP_REQUEST_DECODE_ERR", | ||
| 132 | "MP_UNCORRECTABLE_ECC_ERR", "MP_PARITY_ERR", "MP_COHERENCE_ERR", | ||
| 133 | "CMBIU_REQUEST_DECODE_ERR", "CMBIU_PARITY_ERR", "CMBIU_AXI_RESP_ERR", | ||
| 134 | "0x9", "RBI_BUS_ERR", "0xb", "0xc", "0xd", "0xe", "0xf", "0x10", | ||
| 135 | "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", | ||
| 136 | "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f" | ||
| 137 | }; | ||
| 18 | 138 | ||
| 19 | phys_addr_t __mips_cm_phys_base(void) | 139 | phys_addr_t __mips_cm_phys_base(void) |
| 20 | { | 140 | { |
| 21 | u32 config3 = read_c0_config3(); | 141 | u32 config3 = read_c0_config3(); |
| 22 | u32 cmgcr; | 142 | unsigned long cmgcr; |
| 23 | 143 | ||
| 24 | /* Check the CMGCRBase register is implemented */ | 144 | /* Check the CMGCRBase register is implemented */ |
| 25 | if (!(config3 & MIPS_CONF3_CMGCR)) | 145 | if (!(config3 & MIPS_CONF3_CMGCR)) |
| @@ -81,6 +201,13 @@ int mips_cm_probe(void) · 55 unmodified lines | |||
| 81 | phys_addr_t addr; | 201 | phys_addr_t addr; |
| 82 | u32 base_reg; | 202 | u32 base_reg; |
| 83 | 203 | ||
| 204 | /* | ||
| 205 | * No need to probe again if we have already been | ||
| 206 | * here before. | ||
| 207 | */ | ||
| 208 | if (mips_cm_base) | ||
| 209 | return 0; | ||
| 210 | |||
| 84 | addr = mips_cm_phys_base(); | 211 | addr = mips_cm_phys_base(); |
| 85 | BUG_ON((addr & CM_GCR_BASE_GCRBASE_MSK) != addr); | 212 | BUG_ON((addr & CM_GCR_BASE_GCRBASE_MSK) != addr); |
| 86 | if (!addr) | 213 | if (!addr) |
| @@ -117,5 +244,133 @@ int mips_cm_probe(void) · 30 unmodified lines | |||
| 117 | /* probe for an L2-only sync region */ | 244 | /* probe for an L2-only sync region */ |
| 118 | mips_cm_probe_l2sync(); | 245 | mips_cm_probe_l2sync(); |
| 119 | 246 | ||
| 247 | /* determine register width for this CM */ | ||
| 248 | mips_cm_is64 = config_enabled(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3); | ||
| 249 | |||
| 120 | return 0; | 250 | return 0; |
| 121 | } | 251 | } |
| 252 | |||
| 253 | void mips_cm_error_report(void) | ||
| 254 | { | ||
| 255 | unsigned long revision = mips_cm_revision(); | ||
| 256 | /* | ||
| 257 | * CM3 has a 64-bit Error cause register with 0:57 containing the error | ||
| 258 | * info and 63:58 the error type. For old CMs, everything is contained | ||
| 259 | * in a single 32-bit register (0:26 and 31:27 respectively). Even | ||
| 260 | * though the cm_error is u64, we will simply ignore the upper word | ||
| 261 | * for CM2. | ||
| 262 | */ | ||
| 263 | u64 cm_error = read_gcr_error_cause(); | ||
| 264 | int cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF + | ||
| 265 | ((revision >= CM_REV_CM3) ? 31 : 0); | ||
| 266 | unsigned long cm_addr = read_gcr_error_addr(); | ||
| 267 | unsigned long cm_other = read_gcr_error_mult(); | ||
| 268 | int ocause, cause; | ||
| 269 | char buf[256]; | ||
| 270 | |||
| 271 | if (!mips_cm_present()) | ||
| 272 | return; | ||
| 273 | |||
| 274 | cause = cm_error >> cm_error_cause_sft; | ||
| 275 | |||
| 276 | if (!cause) | ||
| 277 | /* All good */ | ||
| 278 | return; | ||
| 279 | |||
| 280 | ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; | ||
| 281 | if (revision < CM_REV_CM3) { /* CM2 */ | ||
| 282 | if (cause < 16) { | ||
| 283 | unsigned long cca_bits = (cm_error >> 15) & 7; | ||
| 284 | unsigned long tr_bits = (cm_error >> 12) & 7; | ||
| 285 | unsigned long cmd_bits = (cm_error >> 7) & 0x1f; | ||
| 286 | unsigned long stag_bits = (cm_error >> 3) & 15; | ||
| 287 | unsigned long sport_bits = (cm_error >> 0) & 7; | ||
| 288 | |||
| 289 | snprintf(buf, sizeof(buf), | ||
| 290 | "CCA=%lu TR=%s MCmd=%s STag=%lu " | ||
| 291 | "SPort=%lu\n", cca_bits, cm2_tr[tr_bits], | ||
| 292 | cm2_cmd[cmd_bits], stag_bits, sport_bits); | ||
| 293 | } else { | ||
| 294 | /* glob state & sresp together */ | ||
| 295 | unsigned long c3_bits = (cm_error >> 18) & 7; | ||
| 296 | unsigned long c2_bits = (cm_error >> 15) & 7; | ||
| 297 | unsigned long c1_bits = (cm_error >> 12) & 7; | ||
| 298 | unsigned long c0_bits = (cm_error >> 9) & 7; | ||
| 299 | unsigned long sc_bit = (cm_error >> 8) & 1; | ||
| 300 | unsigned long cmd_bits = (cm_error >> 3) & 0x1f; | ||
| 301 | unsigned long sport_bits = (cm_error >> 0) & 7; | ||
| 302 | |||
| 303 | snprintf(buf, sizeof(buf), | ||
| 304 | "C3=%s C2=%s C1=%s C0=%s SC=%s " | ||
| 305 | "MCmd=%s SPort=%lu\n", | ||
| 306 | cm2_core[c3_bits], cm2_core[c2_bits], | ||
| 307 | cm2_core[c1_bits], cm2_core[c0_bits], | ||
| 308 | sc_bit ? "True" : "False", | ||
| 309 | cm2_cmd[cmd_bits], sport_bits); | ||
| 310 | } | ||
| 311 | pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, | ||
| 312 | cm2_causes[cause], buf); | ||
| 313 | pr_err("CM_ADDR =%08lx\n", cm_addr); | ||
| 314 | pr_err("CM_OTHER=%08lx %s\n", cm_other, cm2_causes[ocause]); | ||
| 315 | } else { /* CM3 */ | ||
| 316 | /* Used by cause == {1,2,3} */ | ||
| 317 | unsigned long core_id_bits = (cm_error >> 22) & 0xf; | ||
| 318 | unsigned long vp_id_bits = (cm_error >> 18) & 0xf; | ||
| 319 | unsigned long cmd_bits = (cm_error >> 14) & 0xf; | ||
| 320 | unsigned long cmd_group_bits = (cm_error >> 11) & 0xf; | ||
| 321 | unsigned long cm3_cca_bits = (cm_error >> 8) & 7; | ||
| 322 | unsigned long mcp_bits = (cm_error >> 5) & 0xf; | ||
| 323 | unsigned long cm3_tr_bits = (cm_error >> 1) & 0xf; | ||
| 324 | unsigned long sched_bit = cm_error & 0x1; | ||
| 325 | |||
| 326 | if (cause == 1 || cause == 3) { /* Tag ECC */ | ||
| 327 | unsigned long tag_ecc = (cm_error >> 57) & 0x1; | ||
| 328 | unsigned long tag_way_bits = (cm_error >> 29) & 0xffff; | ||
| 329 | unsigned long dword_bits = (cm_error >> 49) & 0xff; | ||
| 330 | unsigned long data_way_bits = (cm_error >> 45) & 0xf; | ||
| 331 | unsigned long data_sets_bits = (cm_error >> 29) & 0xfff; | ||
| 332 | unsigned long bank_bit = (cm_error >> 28) & 0x1; | ||
| 333 | snprintf(buf, sizeof(buf), | ||
| 334 | "%s ECC Error: Way=%lu (DWORD=%lu, Sets=%lu)" | ||
| 335 | "Bank=%lu CoreID=%lu VPID=%lu Command=%s" | ||
| 336 | "Command Group=%s CCA=%lu MCP=%d" | ||
| 337 | "Transaction type=%s Scheduler=%lu\n", | ||
| 338 | tag_ecc ? "TAG" : "DATA", | ||
| 339 | tag_ecc ? (unsigned long)ffs(tag_way_bits) - 1 : | ||
| 340 | data_way_bits, bank_bit, dword_bits, | ||
| 341 | data_sets_bits, | ||
| 342 | core_id_bits, vp_id_bits, | ||
| 343 | cm3_cmd[cmd_bits], | ||
| 344 | cm3_cmd_group[cmd_group_bits], | ||
| 345 | cm3_cca_bits, 1 << mcp_bits, | ||
| 346 | cm3_tr[cm3_tr_bits], sched_bit); | ||
| 347 | } else if (cause == 2) { | ||
| 348 | unsigned long data_error_type = (cm_error >> 41) & 0xfff; | ||
| 349 | unsigned long data_decode_cmd = (cm_error >> 37) & 0xf; | ||
| 350 | unsigned long data_decode_group = (cm_error >> 34) & 0x7; | ||
| 351 | unsigned long data_decode_destination_id = (cm_error >> 28) & 0x3f; | ||
| 352 | |||
| 353 | snprintf(buf, sizeof(buf), | ||
| 354 | "Decode Request Error: Type=%lu, Command=%lu" | ||
| 355 | "Command Group=%lu Destination ID=%lu" | ||
| 356 | "CoreID=%lu VPID=%lu Command=%s" | ||
| 357 | "Command Group=%s CCA=%lu MCP=%d" | ||
| 358 | "Transaction type=%s Scheduler=%lu\n", | ||
| 359 | data_error_type, data_decode_cmd, | ||
| 360 | data_decode_group, data_decode_destination_id, | ||
| 361 | core_id_bits, vp_id_bits, | ||
| 362 | cm3_cmd[cmd_bits], | ||
| 363 | cm3_cmd_group[cmd_group_bits], | ||
| 364 | cm3_cca_bits, 1 << mcp_bits, | ||
| 365 | cm3_tr[cm3_tr_bits], sched_bit); | ||
| 366 | } | ||
| 367 | |||
| 368 | pr_err("CM_ERROR=%llx %s <%s>\n", cm_error, | ||
| 369 | cm3_causes[cause], buf); | ||
| 370 | pr_err("CM_ADDR =%lx\n", cm_addr); | ||
| 371 | pr_err("CM_OTHER=%lx %s\n", cm_other, cm3_causes[ocause]); | ||
| 372 | } | ||
| 373 | |||
| 374 | /* reprime cause register */ | ||
| 375 | write_gcr_error_cause(0); | ||
| 376 | } | ||
| @@ -21,9 +21,16 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock); · 20 unmodified lines | |||
| 21 | 21 | ||
| 22 | static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); | 22 | static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); |
| 23 | 23 | ||
| 24 | phys_addr_t __weak mips_cpc_phys_base(void) | 24 | /** |
| 25 | * mips_cpc_phys_base - retrieve the physical base address of the CPC | ||
| 26 | * | ||
| 27 | * This function returns the physical base address of the Cluster Power | ||
| 28 | * Controller memory mapped registers, or 0 if no Cluster Power Controller | ||
| 29 | * is present. | ||
| 30 | */ | ||
| 31 | static phys_addr_t mips_cpc_phys_base(void) | ||
| 25 | { | 32 | { |
| 26 | u32 cpc_base; | 33 | unsigned long cpc_base; |
| 27 | 34 | ||
| 28 | if (!mips_cm_present()) | 35 | if (!mips_cm_present()) |
| 29 | return 0; | 36 | return 0; |
| @@ -1556,6 +1556,7 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) · 1555 unmodified lines | |||
| 1556 | #endif | 1556 | #endif |
| 1557 | break; | 1557 | break; |
| 1558 | case CPU_P5600: | 1558 | case CPU_P5600: |
| 1559 | case CPU_I6400: | ||
| 1559 | /* 8-bit event numbers */ | 1560 | /* 8-bit event numbers */ |
| 1560 | raw_id = config & 0x1ff; | 1561 | raw_id = config & 0x1ff; |
| 1561 | base_id = raw_id & 0xff; | 1562 | base_id = raw_id & 0xff; |
| @@ -1717,6 +1718,11 @@ init_hw_perf_events(void) · 155 unmodified lines | |||
| 1717 | mipspmu.general_event_map = &mipsxxcore_event_map2; | 1718 | mipspmu.general_event_map = &mipsxxcore_event_map2; |
| 1718 | mipspmu.cache_event_map = &mipsxxcore_cache_map2; | 1719 | mipspmu.cache_event_map = &mipsxxcore_cache_map2; |
| 1719 | break; | 1720 | break; |
| 1721 | case CPU_I6400: | ||
| 1722 | mipspmu.name = "mips/I6400"; | ||
| 1723 | mipspmu.general_event_map = &mipsxxcore_event_map2; | ||
| 1724 | mipspmu.cache_event_map = &mipsxxcore_cache_map2; | ||
| 1725 | break; | ||
| 1720 | case CPU_1004K: | 1726 | case CPU_1004K: |
| 1721 | mipspmu.name = "mips/1004K"; | 1727 | mipspmu.name = "mips/1004K"; |
| 1722 | mipspmu.general_event_map = &mipsxxcore_event_map; | 1728 | mipspmu.general_event_map = &mipsxxcore_event_map; |
| @@ -267,6 +267,7 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, · 266 unmodified lines | |||
| 267 | 267 | ||
| 268 | /* CPUs which do not require the workaround */ | 268 | /* CPUs which do not require the workaround */ |
| 269 | case CPU_P5600: | 269 | case CPU_P5600: |
| 270 | case CPU_I6400: | ||
| 270 | return 0; | 271 | return 0; |
| 271 | 272 | ||
| 272 | default: | 273 | default: |
| @@ -671,6 +672,7 @@ static int __init cps_pm_init(void) · 398 unmodified lines | |||
| 671 | case CPU_PROAPTIV: | 672 | case CPU_PROAPTIV: |
| 672 | case CPU_M5150: | 673 | case CPU_M5150: |
| 673 | case CPU_P5600: | 674 | case CPU_P5600: |
| 675 | case CPU_I6400: | ||
| 674 | stype_intervention = 0x2; | 676 | stype_intervention = 0x2; |
| 675 | stype_memory = 0x3; | 677 | stype_memory = 0x3; |
| 676 | stype_ordering = 0x10; | 678 | stype_ordering = 0x10; |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include <linux/regset.h> | 25 | #include <linux/regset.h> |
| 26 | #include <linux/smp.h> | 26 | #include <linux/smp.h> |
| 27 | #include <linux/security.h> | 27 | #include <linux/security.h> |
| 28 | #include <linux/stddef.h> | ||
| 28 | #include <linux/tracehook.h> | 29 | #include <linux/tracehook.h> |
| 29 | #include <linux/audit.h> | 30 | #include <linux/audit.h> |
| 30 | #include <linux/seccomp.h> | 31 | #include <linux/seccomp.h> |
| @@ -490,6 +491,93 @@ enum mips_regset { · 459 unmodified lines | |||
| 490 | REGSET_FPR, | 491 | REGSET_FPR, |
| 491 | }; | 492 | }; |
| 492 | 493 | ||
| 494 | struct pt_regs_offset { | ||
| 495 | const char *name; | ||
| 496 | int offset; | ||
| 497 | }; | ||
| 498 | |||
| 499 | #define REG_OFFSET_NAME(reg, r) { \ | ||
| 500 | .name = #reg, \ | ||
| 501 | .offset = offsetof(struct pt_regs, r) \ | ||
| 502 | } | ||
| 503 | |||
| 504 | #define REG_OFFSET_END { \ | ||
| 505 | .name = NULL, \ | ||
| 506 | .offset = 0 \ | ||
| 507 | } | ||
| 508 | |||
| 509 | static const struct pt_regs_offset regoffset_table[] = { | ||
| 510 | REG_OFFSET_NAME(r0, regs[0]), | ||
| 511 | REG_OFFSET_NAME(r1, regs[1]), | ||
| 512 | REG_OFFSET_NAME(r2, regs[2]), | ||
| 513 | REG_OFFSET_NAME(r3, regs[3]), | ||
| 514 | REG_OFFSET_NAME(r4, regs[4]), | ||
| 515 | REG_OFFSET_NAME(r5, regs[5]), | ||
| 516 | REG_OFFSET_NAME(r6, regs[6]), | ||
| 517 | REG_OFFSET_NAME(r7, regs[7]), | ||
| 518 | REG_OFFSET_NAME(r8, regs[8]), | ||
| 519 | REG_OFFSET_NAME(r9, regs[9]), | ||
| 520 | REG_OFFSET_NAME(r10, regs[10]), | ||
| 521 | REG_OFFSET_NAME(r11, regs[11]), | ||
| 522 | REG_OFFSET_NAME(r12, regs[12]), | ||
| 523 | REG_OFFSET_NAME(r13, regs[13]), | ||
| 524 | REG_OFFSET_NAME(r14, regs[14]), | ||
| 525 | REG_OFFSET_NAME(r15, regs[15]), | ||
| 526 | REG_OFFSET_NAME(r16, regs[16]), | ||
| 527 | REG_OFFSET_NAME(r17, regs[17]), | ||
| 528 | REG_OFFSET_NAME(r18, regs[18]), | ||
| 529 | REG_OFFSET_NAME(r19, regs[19]), | ||
| 530 | REG_OFFSET_NAME(r20, regs[20]), | ||
| 531 | REG_OFFSET_NAME(r21, regs[21]), | ||
| 532 | REG_OFFSET_NAME(r22, regs[22]), | ||
| 533 | REG_OFFSET_NAME(r23, regs[23]), | ||
| 534 | REG_OFFSET_NAME(r24, regs[24]), | ||
| 535 | REG_OFFSET_NAME(r25, regs[25]), | ||
| 536 | REG_OFFSET_NAME(r26, regs[26]), | ||
| 537 | REG_OFFSET_NAME(r27, regs[27]), | ||
| 538 | REG_OFFSET_NAME(r28, regs[28]), | ||
| 539 | REG_OFFSET_NAME(r29, regs[29]), | ||
| 540 | REG_OFFSET_NAME(r30, regs[30]), | ||
| 541 | REG_OFFSET_NAME(r31, regs[31]), | ||
| 542 | REG_OFFSET_NAME(c0_status, cp0_status), | ||
| 543 | REG_OFFSET_NAME(hi, hi), | ||
| 544 | REG_OFFSET_NAME(lo, lo), | ||
| 545 | #ifdef CONFIG_CPU_HAS_SMARTMIPS | ||
| 546 | REG_OFFSET_NAME(acx, acx), | ||
| 547 | #endif | ||
| 548 | REG_OFFSET_NAME(c0_badvaddr, cp0_badvaddr), | ||
| 549 | REG_OFFSET_NAME(c0_cause, cp0_cause), | ||
| 550 | REG_OFFSET_NAME(c0_epc, cp0_epc), | ||
| 551 | #ifdef CONFIG_MIPS_MT_SMTC | ||
| 552 | REG_OFFSET_NAME(c0_tcstatus, cp0_tcstatus), | ||
| 553 | #endif | ||
| 554 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | ||
| 555 | REG_OFFSET_NAME(mpl0, mpl[0]), | ||
| 556 | REG_OFFSET_NAME(mpl1, mpl[1]), | ||
| 557 | REG_OFFSET_NAME(mpl2, mpl[2]), | ||
| 558 | REG_OFFSET_NAME(mtp0, mtp[0]), | ||
| 559 | REG_OFFSET_NAME(mtp1, mtp[1]), | ||
| 560 | REG_OFFSET_NAME(mtp2, mtp[2]), | ||
| 561 | #endif | ||
| 562 | REG_OFFSET_END, | ||
| 563 | }; | ||
| 564 | |||
| 565 | /** | ||
| 566 | * regs_query_register_offset() - query register offset from its name | ||
| 567 | * @name: the name of a register | ||
| 568 | * | ||
| 569 | * regs_query_register_offset() returns the offset of a register in struct | ||
| 570 | * pt_regs from its name. If the name is invalid, this returns -EINVAL; | ||
| 571 | */ | ||
| 572 | int regs_query_register_offset(const char *name) | ||
| 573 | { | ||
| 574 | const struct pt_regs_offset *roff; | ||
| 575 | for (roff = regoffset_table; roff->name != NULL; roff++) | ||
| 576 | if (!strcmp(roff->name, name)) | ||
| 577 | return roff->offset; | ||
| 578 | return -EINVAL; | ||
| 579 | } | ||
| 580 | |||
| 493 | #if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) | 581 | #if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) |
| 494 | 582 | ||
| 495 | static const struct user_regset mips_regsets[] = { | 583 | static const struct user_regset mips_regsets[] = { |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | * Copyright (C) 1999, 2001 Silicon Graphics, Inc. | 13 | * Copyright (C) 1999, 2001 Silicon Graphics, Inc. |
| 14 | */ | 14 | */ |
| 15 | #include <asm/asm.h> | 15 | #include <asm/asm.h> |
| 16 | #include <asm/asmmacro.h> | ||
| 16 | #include <asm/errno.h> | 17 | #include <asm/errno.h> |
| 17 | #include <asm/fpregdef.h> | 18 | #include <asm/fpregdef.h> |
| 18 | #include <asm/mipsregs.h> | 19 | #include <asm/mipsregs.h> |
| @@ -35,6 +36,14 @@ · 16 unmodified lines | |||
| 35 | 36 | ||
| 36 | .set noreorder | 37 | .set noreorder |
| 37 | 38 | ||
| 39 | /** | ||
| 40 | * _save_fp_context() - save FP context from the FPU | ||
| 41 | * @a0 - pointer to fpregs field of sigcontext | ||
| 42 | * @a1 - pointer to fpc_csr field of sigcontext | ||
| 43 | * | ||
| 44 | * Save FP context, including the 32 FP data registers and the FP | ||
| 45 | * control & status register, from the FPU to signal context. | ||
| 46 | */ | ||
| 38 | LEAF(_save_fp_context) | 47 | LEAF(_save_fp_context) |
| 39 | .set push | 48 | .set push |
| 40 | SET_HARDFLOAT | 49 | SET_HARDFLOAT |
| @@ -54,117 +63,60 @@ LEAF(_save_fp_context) · 13 unmodified lines | |||
| 54 | nop | 63 | nop |
| 55 | #endif | 64 | #endif |
| 56 | /* Store the 16 odd double precision registers */ | 65 | /* Store the 16 odd double precision registers */ |
| 57 | EX sdc1 $f1, SC_FPREGS+8(a0) | 66 | EX sdc1 $f1, 8(a0) |
| 58 | EX sdc1 $f3, SC_FPREGS+24(a0) | 67 | EX sdc1 $f3, 24(a0) |
| 59 | EX sdc1 $f5, SC_FPREGS+40(a0) | 68 | EX sdc1 $f5, 40(a0) |
| 60 | EX sdc1 $f7, SC_FPREGS+56(a0) | 69 | EX sdc1 $f7, 56(a0) |
| 61 | EX sdc1 $f9, SC_FPREGS+72(a0) | 70 | EX sdc1 $f9, 72(a0) |
| 62 | EX sdc1 $f11, SC_FPREGS+88(a0) | 71 | EX sdc1 $f11, 88(a0) |
| 63 | EX sdc1 $f13, SC_FPREGS+104(a0) | 72 | EX sdc1 $f13, 104(a0) |
| 64 | EX sdc1 $f15, SC_FPREGS+120(a0) | 73 | EX sdc1 $f15, 120(a0) |
| 65 | EX sdc1 $f17, SC_FPREGS+136(a0) | 74 | EX sdc1 $f17, 136(a0) |
| 66 | EX sdc1 $f19, SC_FPREGS+152(a0) | 75 | EX sdc1 $f19, 152(a0) |
| 67 | EX sdc1 $f21, SC_FPREGS+168(a0) | 76 | EX sdc1 $f21, 168(a0) |
| 68 | EX sdc1 $f23, SC_FPREGS+184(a0) | 77 | EX sdc1 $f23, 184(a0) |
| 69 | EX sdc1 $f25, SC_FPREGS+200(a0) | 78 | EX sdc1 $f25, 200(a0) |
| 70 | EX sdc1 $f27, SC_FPREGS+216(a0) | 79 | EX sdc1 $f27, 216(a0) |
| 71 | EX sdc1 $f29, SC_FPREGS+232(a0) | 80 | EX sdc1 $f29, 232(a0) |
| 72 | EX sdc1 $f31, SC_FPREGS+248(a0) | 81 | EX sdc1 $f31, 248(a0) |
| 73 | 1: .set pop | 82 | 1: .set pop |
| 74 | #endif | 83 | #endif |
| 75 | 84 | ||
| 76 | .set push | 85 | .set push |
| 77 | SET_HARDFLOAT | 86 | SET_HARDFLOAT |
| 78 | /* Store the 16 even double precision registers */ | 87 | /* Store the 16 even double precision registers */ |
| 79 | EX sdc1 $f0, SC_FPREGS+0(a0) | 88 | EX sdc1 $f0, 0(a0) |
| 80 | EX sdc1 $f2, SC_FPREGS+16(a0) | 89 | EX sdc1 $f2, 16(a0) |
| 81 | EX sdc1 $f4, SC_FPREGS+32(a0) | 90 | EX sdc1 $f4, 32(a0) |
| 82 | EX sdc1 $f6, SC_FPREGS+48(a0) | 91 | EX sdc1 $f6, 48(a0) |
| 83 | EX sdc1 $f8, SC_FPREGS+64(a0) | 92 | EX sdc1 $f8, 64(a0) |
| 84 | EX sdc1 $f10, SC_FPREGS+80(a0) | 93 | EX sdc1 $f10, 80(a0) |
| 85 | EX sdc1 $f12, SC_FPREGS+96(a0) | 94 | EX sdc1 $f12, 96(a0) |
| 86 | EX sdc1 $f14, SC_FPREGS+112(a0) | 95 | EX sdc1 $f14, 112(a0) |
| 87 | EX sdc1 $f16, SC_FPREGS+128(a0) | 96 | EX sdc1 $f16, 128(a0) |
| 88 | EX sdc1 $f18, SC_FPREGS+144(a0) | 97 | EX sdc1 $f18, 144(a0) |
| 89 | EX sdc1 $f20, SC_FPREGS+160(a0) | 98 | EX sdc1 $f20, 160(a0) |
| 90 | EX sdc1 $f22, SC_FPREGS+176(a0) | 99 | EX sdc1 $f22, 176(a0) |
| 91 | EX sdc1 $f24, SC_FPREGS+192(a0) | 100 | EX sdc1 $f24, 192(a0) |
| 92 | EX sdc1 $f26, SC_FPREGS+208(a0) | 101 | EX sdc1 $f26, 208(a0) |
| 93 | EX sdc1 $f28, SC_FPREGS+224(a0) | 102 | EX sdc1 $f28, 224(a0) |
| 94 | EX sdc1 $f30, SC_FPREGS+240(a0) | 103 | EX sdc1 $f30, 240(a0) |
| 95 | EX sw t1, SC_FPC_CSR(a0) | 104 | EX sw t1, 0(a1) |
| 96 | jr ra | 105 | jr ra |
| 97 | li v0, 0 # success | 106 | li v0, 0 # success |
| 98 | .set pop | 107 | .set pop |
| 99 | END(_save_fp_context) | 108 | END(_save_fp_context) |
| 100 | 109 | ||
| 101 | #ifdef CONFIG_MIPS32_COMPAT | 110 | /** |
| 102 | /* Save 32-bit process floating point context */ | 111 | * _restore_fp_context() - restore FP context to the FPU |
| 103 | LEAF(_save_fp_context32) | 112 | * @a0 - pointer to fpregs field of sigcontext |
| 104 | .set push | 113 | * @a1 - pointer to fpc_csr field of sigcontext |
| 105 | .set MIPS_ISA_ARCH_LEVEL_RAW | 114 | * |
| 106 | SET_HARDFLOAT | 115 | * Restore FP context, including the 32 FP data registers and the FP |
| 107 | cfc1 t1, fcr31 | 116 | * control & status register, from signal context to the FPU. |
| 108 | |||
| 109 | #ifndef CONFIG_CPU_MIPS64_R6 | ||
| 110 | mfc0 t0, CP0_STATUS | ||
| 111 | sll t0, t0, 5 | ||
| 112 | bgez t0, 1f # skip storing odd if FR=0 | ||
| 113 | nop | ||
| 114 | #endif | ||
| 115 | |||
| 116 | /* Store the 16 odd double precision registers */ | ||
| 117 | EX sdc1 $f1, SC32_FPREGS+8(a0) | ||
| 118 | EX sdc1 $f3, SC32_FPREGS+24(a0) | ||
| 119 | EX sdc1 $f5, SC32_FPREGS+40(a0) | ||
| 120 | EX sdc1 $f7, SC32_FPREGS+56(a0) | ||
| 121 | EX sdc1 $f9, SC32_FPREGS+72(a0) | ||
| 122 | EX sdc1 $f11, SC32_FPREGS+88(a0) | ||
| 123 | EX sdc1 $f13, SC32_FPREGS+104(a0) | ||
| 124 | EX sdc1 $f15, SC32_FPREGS+120(a0) | ||
| 125 | EX sdc1 $f17, SC32_FPREGS+136(a0) | ||
| 126 | EX sdc1 $f19, SC32_FPREGS+152(a0) | ||
| 127 | EX sdc1 $f21, SC32_FPREGS+168(a0) | ||
| 128 | EX sdc1 $f23, SC32_FPREGS+184(a0) | ||
| 129 | EX sdc1 $f25, SC32_FPREGS+200(a0) | ||
| 130 | EX sdc1 $f27, SC32_FPREGS+216(a0) | ||
| 131 | EX sdc1 $f29, SC32_FPREGS+232(a0) | ||
| 132 | EX sdc1 $f31, SC32_FPREGS+248(a0) | ||
| 133 | |||
| 134 | /* Store the 16 even double precision registers */ | ||
| 135 | 1: EX sdc1 $f0, SC32_FPREGS+0(a0) | ||
| 136 | EX sdc1 $f2, SC32_FPREGS+16(a0) | ||
| 137 | EX sdc1 $f4, SC32_FPREGS+32(a0) | ||
| 138 | EX sdc1 $f6, SC32_FPREGS+48(a0) | ||
| 139 | EX sdc1 $f8, SC32_FPREGS+64(a0) | ||
| 140 | EX sdc1 $f10, SC32_FPREGS+80(a0) | ||
| 141 | EX sdc1 $f12, SC32_FPREGS+96(a0) | ||
| 142 | EX sdc1 $f14, SC32_FPREGS+112(a0) | ||
| 143 | EX sdc1 $f16, SC32_FPREGS+128(a0) | ||
| 144 | EX sdc1 $f18, SC32_FPREGS+144(a0) | ||
| 145 | EX sdc1 $f20, SC32_FPREGS+160(a0) | ||
| 146 | EX sdc1 $f22, SC32_FPREGS+176(a0) | ||
| 147 | EX sdc1 $f24, SC32_FPREGS+192(a0) | ||
| 148 | EX sdc1 $f26, SC32_FPREGS+208(a0) | ||
| 149 | EX sdc1 $f28, SC32_FPREGS+224(a0) | ||
| 150 | EX sdc1 $f30, SC32_FPREGS+240(a0) | ||
| 151 | EX sw t1, SC32_FPC_CSR(a0) | ||
| 152 | cfc1 t0, $0 # implementation/version | ||
| 153 | EX sw t0, SC32_FPC_EIR(a0) | ||
| 154 | .set pop | ||
| 155 | |||
| 156 | jr ra | ||
| 157 | li v0, 0 # success | ||
| 158 | END(_save_fp_context32) | ||
| 159 | #endif | ||
| 160 | |||
| 161 | /* | ||
| 162 | * Restore FPU state: | ||
| 163 | * - fp gp registers | ||
| 164 | * - cp1 status/control register | ||
| 165 | */ | 117 | */ |
| 166 | LEAF(_restore_fp_context) | 118 | LEAF(_restore_fp_context) |
| 167 | EX lw t1, SC_FPC_CSR(a0) | 119 | EX lw t1, 0(a1) |
| 168 | 120 | ||
| 169 | #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ | 121 | #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ |
| 170 | defined(CONFIG_CPU_MIPS32_R6) | 122 | defined(CONFIG_CPU_MIPS32_R6) |
| @@ -178,101 +130,231 @@ LEAF(_restore_fp_context) · 7 unmodified lines | |||
| 178 | bgez t0, 1f # skip loading odd if FR=0 | 130 | bgez t0, 1f # skip loading odd if FR=0 |
| 179 | nop | 131 | nop |
| 180 | #endif | 132 | #endif |
| 181 | EX ldc1 $f1, SC_FPREGS+8(a0) | 133 | EX ldc1 $f1, 8(a0) |
| 182 | EX ldc1 $f3, SC_FPREGS+24(a0) | 134 | EX ldc1 $f3, 24(a0) |
| 183 | EX ldc1 $f5, SC_FPREGS+40(a0) | 135 | EX ldc1 $f5, 40(a0) |
| 184 | EX ldc1 $f7, SC_FPREGS+56(a0) | 136 | EX ldc1 $f7, 56(a0) |
| 185 | EX ldc1 $f9, SC_FPREGS+72(a0) | 137 | EX ldc1 $f9, 72(a0) |
| 186 | EX ldc1 $f11, SC_FPREGS+88(a0) | 138 | EX ldc1 $f11, 88(a0) |
| 187 | EX ldc1 $f13, SC_FPREGS+104(a0) | 139 | EX ldc1 $f13, 104(a0) |
| 188 | EX ldc1 $f15, SC_FPREGS+120(a0) | 140 | EX ldc1 $f15, 120(a0) |
| 189 | EX ldc1 $f17, SC_FPREGS+136(a0) | 141 | EX ldc1 $f17, 136(a0) |
| 190 | EX ldc1 $f19, SC_FPREGS+152(a0) | 142 | EX ldc1 $f19, 152(a0) |
| 191 | EX ldc1 $f21, SC_FPREGS+168(a0) | 143 | EX ldc1 $f21, 168(a0) |
| 192 | EX ldc1 $f23, SC_FPREGS+184(a0) | 144 | EX ldc1 $f23, 184(a0) |
| 193 | EX ldc1 $f25, SC_FPREGS+200(a0) | 145 | EX ldc1 $f25, 200(a0) |
| 194 | EX ldc1 $f27, SC_FPREGS+216(a0) | 146 | EX ldc1 $f27, 216(a0) |
| 195 | EX ldc1 $f29, SC_FPREGS+232(a0) | 147 | EX ldc1 $f29, 232(a0) |
| 196 | EX ldc1 $f31, SC_FPREGS+248(a0) | 148 | EX ldc1 $f31, 248(a0) |
| 197 | 1: .set pop | 149 | 1: .set pop |
| 198 | #endif | 150 | #endif |
| 199 | .set push | 151 | .set push |
| 200 | SET_HARDFLOAT | 152 | SET_HARDFLOAT |
| 201 | EX ldc1 $f0, SC_FPREGS+0(a0) | 153 | EX ldc1 $f0, 0(a0) |
| 202 | EX ldc1 $f2, SC_FPREGS+16(a0) | 154 | EX ldc1 $f2, 16(a0) |
| 203 | EX ldc1 $f4, SC_FPREGS+32(a0) | 155 | EX ldc1 $f4, 32(a0) |
| 204 | EX ldc1 $f6, SC_FPREGS+48(a0) | 156 | EX ldc1 $f6, 48(a0) |
| 205 | EX ldc1 $f8, SC_FPREGS+64(a0) | 157 | EX ldc1 $f8, 64(a0) |
| 206 | EX ldc1 $f10, SC_FPREGS+80(a0) | 158 | EX ldc1 $f10, 80(a0) |
| 207 | EX ldc1 $f12, SC_FPREGS+96(a0) | 159 | EX ldc1 $f12, 96(a0) |
| 208 | EX ldc1 $f14, SC_FPREGS+112(a0) | 160 | EX ldc1 $f14, 112(a0) |
| 209 | EX ldc1 $f16, SC_FPREGS+128(a0) | 161 | EX ldc1 $f16, 128(a0) |
| 210 | EX ldc1 $f18, SC_FPREGS+144(a0) | 162 | EX ldc1 $f18, 144(a0) |
| 211 | EX ldc1 $f20, SC_FPREGS+160(a0) | 163 | EX ldc1 $f20, 160(a0) |
| 212 | EX ldc1 $f22, SC_FPREGS+176(a0) | 164 | EX ldc1 $f22, 176(a0) |
| 213 | EX ldc1 $f24, SC_FPREGS+192(a0) | 165 | EX ldc1 $f24, 192(a0) |
| 214 | EX ldc1 $f26, SC_FPREGS+208(a0) | 166 | EX ldc1 $f26, 208(a0) |
| 215 | EX ldc1 $f28, SC_FPREGS+224(a0) | 167 | EX ldc1 $f28, 224(a0) |
| 216 | EX ldc1 $f30, SC_FPREGS+240(a0) | 168 | EX ldc1 $f30, 240(a0) |
| 217 | ctc1 t1, fcr31 | 169 | ctc1 t1, fcr31 |
| 218 | .set pop | 170 | .set pop |
| 219 | jr ra | 171 | jr ra |
| 220 | li v0, 0 # success | 172 | li v0, 0 # success |
| 221 | END(_restore_fp_context) | 173 | END(_restore_fp_context) |
| 222 | 174 | ||
| 223 | #ifdef CONFIG_MIPS32_COMPAT | 175 | #ifdef CONFIG_CPU_HAS_MSA |
| 224 | LEAF(_restore_fp_context32) | ||
| 225 | /* Restore an o32 sigcontext. */ | ||
| 226 | .set push | ||
| 227 | SET_HARDFLOAT | ||
| 228 | EX lw t1, SC32_FPC_CSR(a0) | ||
| 229 | 176 | ||
| 230 | #ifndef CONFIG_CPU_MIPS64_R6 | 177 | .macro op_one_wr op, idx, base |
| 231 | mfc0 t0, CP0_STATUS | 178 | .align 4 |
| 232 | sll t0, t0, 5 | 179 | \idx: \op \idx, 0, \base |
| 233 | bgez t0, 1f # skip loading odd if FR=0 | 180 | jr ra |
| 234 | nop | 181 | nop |
| 235 | #endif | 182 | .endm |
| 236 | 183 | ||
| 237 | EX ldc1 $f1, SC32_FPREGS+8(a0) | 184 | .macro op_msa_wr name, op |
| 238 | EX ldc1 $f3, SC32_FPREGS+24(a0) | 185 | LEAF(\name) |
| 239 | EX ldc1 $f5, SC32_FPREGS+40(a0) | 186 | .set push |
| 240 | EX ldc1 $f7, SC32_FPREGS+56(a0) | 187 | .set noreorder |
| 241 | EX ldc1 $f9, SC32_FPREGS+72(a0) | 188 | sll t0, a0, 4 |
| 242 | EX ldc1 $f11, SC32_FPREGS+88(a0) | 189 | PTR_LA t1, 0f |
| 243 | EX ldc1 $f13, SC32_FPREGS+104(a0) | 190 | PTR_ADDU t0, t0, t1 |
| 244 | EX ldc1 $f15, SC32_FPREGS+120(a0) | 191 | jr t0 |
| 245 | EX ldc1 $f17, SC32_FPREGS+136(a0) | 192 | nop |
| 246 | EX ldc1 $f19, SC32_FPREGS+152(a0) | 193 | op_one_wr \op, 0, a1 |
| 247 | EX ldc1 $f21, SC32_FPREGS+168(a0) | 194 | op_one_wr \op, 1, a1 |
| 248 | EX ldc1 $f23, SC32_FPREGS+184(a0) | 195 | op_one_wr \op, 2, a1 |
| 249 | EX ldc1 $f25, SC32_FPREGS+200(a0) | 196 | op_one_wr \op, 3, a1 |
| 250 | EX ldc1 $f27, SC32_FPREGS+216(a0) | 197 | op_one_wr \op, 4, a1 |
| 251 | EX ldc1 $f29, SC32_FPREGS+232(a0) | 198 | op_one_wr \op, 5, a1 |
| 252 | EX ldc1 $f31, SC32_FPREGS+248(a0) | 199 | op_one_wr \op, 6, a1 |
| 200 | op_one_wr \op, 7, a1 | ||
| 201 | op_one_wr \op, 8, a1 | ||
| 202 | op_one_wr \op, 9, a1 | ||
| 203 | op_one_wr \op, 10, a1 | ||
| 204 | op_one_wr \op, 11, a1 | ||
| 205 | op_one_wr \op, 12, a1 | ||
| 206 | op_one_wr \op, 13, a1 | ||
| 207 | op_one_wr \op, 14, a1 | ||
| 208 | op_one_wr \op, 15, a1 | ||
| 209 | op_one_wr \op, 16, a1 | ||
| 210 | op_one_wr \op, 17, a1 | ||
| 211 | op_one_wr \op, 18, a1 | ||
| 212 | op_one_wr \op, 19, a1 | ||
| 213 | op_one_wr \op, 20, a1 | ||
| 214 | op_one_wr \op, 21, a1 | ||
| 215 | op_one_wr \op, 22, a1 | ||
| 216 | op_one_wr \op, 23, a1 | ||
| 217 | op_one_wr \op, 24, a1 | ||
| 218 | op_one_wr \op, 25, a1 | ||
| 219 | op_one_wr \op, 26, a1 | ||
| 220 | op_one_wr \op, 27, a1 | ||
| 221 | op_one_wr \op, 28, a1 | ||
| 222 | op_one_wr \op, 29, a1 | ||
| 223 | op_one_wr \op, 30, a1 | ||
| 224 | op_one_wr \op, 31, a1 | ||
| 225 | .set pop | ||
| 226 | END(\name) | ||
| 227 | .endm | ||
| 253 | 228 | ||
| 254 | 1: EX ldc1 $f0, SC32_FPREGS+0(a0) | 229 | op_msa_wr read_msa_wr_b, st_b |
| 255 | EX ldc1 $f2, SC32_FPREGS+16(a0) | 230 | op_msa_wr read_msa_wr_h, st_h |
| 256 | EX ldc1 $f4, SC32_FPREGS+32(a0) | 231 | op_msa_wr read_msa_wr_w, st_w |
| 257 | EX ldc1 $f6, SC32_FPREGS+48(a0) | 232 | op_msa_wr read_msa_wr_d, st_d |
| 258 | EX ldc1 $f8, SC32_FPREGS+64(a0) | 233 | |
| 259 | EX ldc1 $f10, SC32_FPREGS+80(a0) | 234 | op_msa_wr write_msa_wr_b, ld_b |
| 260 | EX ldc1 $f12, SC32_FPREGS+96(a0) | 235 | op_msa_wr write_msa_wr_h, ld_h |
| 261 | EX ldc1 $f14, SC32_FPREGS+112(a0) | 236 | op_msa_wr write_msa_wr_w, ld_w |
| 262 | EX ldc1 $f16, SC32_FPREGS+128(a0) | 237 | op_msa_wr write_msa_wr_d, ld_d |
| 263 | EX ldc1 $f18, SC32_FPREGS+144(a0) | 238 | |
| 264 | EX ldc1 $f20, SC32_FPREGS+160(a0) | 239 | #endif /* CONFIG_CPU_HAS_MSA */ |
| 265 | EX ldc1 $f22, SC32_FPREGS+176(a0) | 240 | |
| 266 | EX ldc1 $f24, SC32_FPREGS+192(a0) | 241 | #ifdef CONFIG_CPU_HAS_MSA |
| 267 | EX ldc1 $f26, SC32_FPREGS+208(a0) | 242 | |
| 268 | EX ldc1 $f28, SC32_FPREGS+224(a0) | 243 | .macro save_msa_upper wr, off, base |
| 269 | EX ldc1 $f30, SC32_FPREGS+240(a0) | 244 | .set push |
| 270 | ctc1 t1, fcr31 | 245 | .set noat |
| 246 | #ifdef CONFIG_64BIT | ||
| 247 | copy_u_d \wr, 1 | ||
| 248 | EX sd $1, \off(\base) | ||
| 249 | #elif defined(CONFIG_CPU_LITTLE_ENDIAN) | ||
| 250 | copy_u_w \wr, 2 | ||
| 251 | EX sw $1, \off(\base) | ||
| 252 | copy_u_w \wr, 3 | ||
| 253 | EX sw $1, (\off+4)(\base) | ||
| 254 | #else /* CONFIG_CPU_BIG_ENDIAN */ | ||
| 255 | copy_u_w \wr, 2 | ||
| 256 | EX sw $1, (\off+4)(\base) | ||
| 257 | copy_u_w \wr, 3 | ||
| 258 | EX sw $1, \off(\base) | ||
| 259 | #endif | ||
| 260 | .set pop | ||
| 261 | .endm | ||
| 262 | |||
| 263 | LEAF(_save_msa_all_upper) | ||
| 264 | save_msa_upper 0, 0x00, a0 | ||
| 265 | save_msa_upper 1, 0x08, a0 | ||
| 266 | save_msa_upper 2, 0x10, a0 | ||
| 267 | save_msa_upper 3, 0x18, a0 | ||
| 268 | save_msa_upper 4, 0x20, a0 | ||
| 269 | save_msa_upper 5, 0x28, a0 | ||
| 270 | save_msa_upper 6, 0x30, a0 | ||
| 271 | save_msa_upper 7, 0x38, a0 | ||
| 272 | save_msa_upper 8, 0x40, a0 | ||
| 273 | save_msa_upper 9, 0x48, a0 | ||
| 274 | save_msa_upper 10, 0x50, a0 | ||
| 275 | save_msa_upper 11, 0x58, a0 | ||
| 276 | save_msa_upper 12, 0x60, a0 | ||
| 277 | save_msa_upper 13, 0x68, a0 | ||
| 278 | save_msa_upper 14, 0x70, a0 | ||
| 279 | save_msa_upper 15, 0x78, a0 | ||
| 280 | save_msa_upper 16, 0x80, a0 | ||
| 281 | save_msa_upper 17, 0x88, a0 | ||
| 282 | save_msa_upper 18, 0x90, a0 | ||
| 283 | save_msa_upper 19, 0x98, a0 | ||
| 284 | save_msa_upper 20, 0xa0, a0 | ||
| 285 | save_msa_upper 21, 0xa8, a0 | ||
| 286 | save_msa_upper 22, 0xb0, a0 | ||
| 287 | save_msa_upper 23, 0xb8, a0 | ||
| 288 | save_msa_upper 24, 0xc0, a0 | ||
| 289 | save_msa_upper 25, 0xc8, a0 | ||
| 290 | save_msa_upper 26, 0xd0, a0 | ||
| 291 | save_msa_upper 27, 0xd8, a0 | ||
| 292 | save_msa_upper 28, 0xe0, a0 | ||
| 293 | save_msa_upper 29, 0xe8, a0 | ||
| 294 | save_msa_upper 30, 0xf0, a0 | ||
| 295 | save_msa_upper 31, 0xf8, a0 | ||
| 271 | jr ra | 296 | jr ra |
| 272 | li v0, 0 # success | 297 | li v0, 0 |
| 273 | .set pop | 298 | END(_save_msa_all_upper) |
| 274 | END(_restore_fp_context32) | 299 | |
| 300 | .macro restore_msa_upper wr, off, base | ||
| 301 | .set push | ||
| 302 | .set noat | ||
| 303 | #ifdef CONFIG_64BIT | ||
| 304 | EX ld $1, \off(\base) | ||
| 305 | insert_d \wr, 1 | ||
| 306 | #elif defined(CONFIG_CPU_LITTLE_ENDIAN) | ||
| 307 | EX lw $1, \off(\base) | ||
| 308 | insert_w \wr, 2 | ||
| 309 | EX lw $1, (\off+4)(\base) | ||
| 310 | insert_w \wr, 3 | ||
| 311 | #else /* CONFIG_CPU_BIG_ENDIAN */ | ||
| 312 | EX lw $1, (\off+4)(\base) | ||
| 313 | insert_w \wr, 2 | ||
| 314 | EX lw $1, \off(\base) | ||
| 315 | insert_w \wr, 3 | ||
| 275 | #endif | 316 | #endif |
| 317 | .set pop | ||
| 318 | .endm | ||
| 319 | |||
| 320 | LEAF(_restore_msa_all_upper) | ||
| 321 | restore_msa_upper 0, 0x00, a0 | ||
| 322 | restore_msa_upper 1, 0x08, a0 | ||
| 323 | restore_msa_upper 2, 0x10, a0 | ||
| 324 | restore_msa_upper 3, 0x18, a0 | ||
| 325 | restore_msa_upper 4, 0x20, a0 | ||
| 326 | restore_msa_upper 5, 0x28, a0 | ||
| 327 | restore_msa_upper 6, 0x30, a0 | ||
| 328 | restore_msa_upper 7, 0x38, a0 | ||
| 329 | restore_msa_upper 8, 0x40, a0 | ||
| 330 | restore_msa_upper 9, 0x48, a0 | ||
| 331 | restore_msa_upper 10, 0x50, a0 | ||
| 332 | restore_msa_upper 11, 0x58, a0 | ||
| 333 | restore_msa_upper 12, 0x60, a0 | ||
| 334 | restore_msa_upper 13, 0x68, a0 | ||
| 335 | restore_msa_upper 14, 0x70, a0 | ||
| 336 | restore_msa_upper 15, 0x78, a0 | ||
| 337 | restore_msa_upper 16, 0x80, a0 | ||
| 338 | restore_msa_upper 17, 0x88, a0 | ||
| 339 | restore_msa_upper 18, 0x90, a0 | ||
| 340 | restore_msa_upper 19, 0x98, a0 | ||
| 341 | restore_msa_upper 20, 0xa0, a0 | ||
| 342 | restore_msa_upper 21, 0xa8, a0 | ||
| 343 | restore_msa_upper 22, 0xb0, a0 | ||
| 344 | restore_msa_upper 23, 0xb8, a0 | ||
| 345 | restore_msa_upper 24, 0xc0, a0 | ||
| 346 | restore_msa_upper 25, 0xc8, a0 | ||
| 347 | restore_msa_upper 26, 0xd0, a0 | ||
| 348 | restore_msa_upper 27, 0xd8, a0 | ||
| 349 | restore_msa_upper 28, 0xe0, a0 | ||
| 350 | restore_msa_upper 29, 0xe8, a0 | ||
| 351 | restore_msa_upper 30, 0xf0, a0 | ||
| 352 | restore_msa_upper 31, 0xf8, a0 | ||
| 353 | jr ra | ||
| 354 | li v0, 0 | ||
| 355 | END(_restore_msa_all_upper) | ||
| 356 | |||
| 357 | #endif /* CONFIG_CPU_HAS_MSA */ | ||
| 276 | 358 | ||
| 277 | .set reorder | 359 | .set reorder |
| 278 | 360 | ||
| @@ -34,7 +34,7 @@ · 33 unmodified lines | |||
| 34 | #ifndef USE_ALTERNATE_RESUME_IMPL | 34 | #ifndef USE_ALTERNATE_RESUME_IMPL |
| 35 | /* | 35 | /* |
| 36 | * task_struct *resume(task_struct *prev, task_struct *next, | 36 | * task_struct *resume(task_struct *prev, task_struct *next, |
| 37 | * struct thread_info *next_ti, s32 fp_save) | 37 | * struct thread_info *next_ti) |
| 38 | */ | 38 | */ |
| 39 | .align 5 | 39 | .align 5 |
| 40 | LEAF(resume) | 40 | LEAF(resume) |
| @@ -43,45 +43,6 @@ · 2 unmodified lines | |||
| 43 | cpu_save_nonscratch a0 | 43 | cpu_save_nonscratch a0 |
| 44 | LONG_S ra, THREAD_REG31(a0) | 44 | LONG_S ra, THREAD_REG31(a0) |
| 45 | 45 | ||
| 46 | /* | ||
| 47 | * Check whether we need to save any FP context. FP context is saved | ||
| 48 | * iff the process has used the context with the scalar FPU or the MSA | ||
| 49 | * ASE in the current time slice, as indicated by _TIF_USEDFPU and | ||
| 50 | * _TIF_USEDMSA respectively. switch_to will have set fp_save | ||
| 51 | * accordingly to an FP_SAVE_ enum value. | ||
| 52 | */ | ||
| 53 | beqz a3, 2f | ||
| 54 | |||
| 55 | /* | ||
| 56 | * We do. Clear the saved CU1 bit for prev, such that next time it is | ||
| 57 | * scheduled it will start in userland with the FPU disabled. If the | ||
| 58 | * task uses the FPU then it will be enabled again via the do_cpu trap. | ||
| 59 | * This allows us to lazily restore the FP context. | ||
| 60 | */ | ||
| 61 | PTR_L t3, TASK_THREAD_INFO(a0) | ||
| 62 | LONG_L t0, ST_OFF(t3) | ||
| 63 | li t1, ~ST0_CU1 | ||
| 64 | and t0, t0, t1 | ||
| 65 | LONG_S t0, ST_OFF(t3) | ||
| 66 | |||
| 67 | /* Check whether we're saving scalar or vector context. */ | ||
| 68 | bgtz a3, 1f | ||
| 69 | |||
| 70 | /* Save 128b MSA vector context + scalar FP control & status. */ | ||
| 71 | .set push | ||
| 72 | SET_HARDFLOAT | ||
| 73 | cfc1 t1, fcr31 | ||
| 74 | msa_save_all a0 | ||
| 75 | .set pop /* SET_HARDFLOAT */ | ||
| 76 | |||
| 77 | sw t1, THREAD_FCR31(a0) | ||
| 78 | b 2f | ||
| 79 | |||
| 80 | 1: /* Save 32b/64b scalar FP context. */ | ||
| 81 | fpu_save_double a0 t0 t1 # c0_status passed in t0 | ||
| 82 | # clobbers t1 | ||
| 83 | 2: | ||
| 84 | |||
| 85 | #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) | 46 | #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) |
| 86 | PTR_LA t8, __stack_chk_guard | 47 | PTR_LA t8, __stack_chk_guard |
| 87 | LONG_L t9, TASK_STACK_CANARY(a1) | 48 | LONG_L t9, TASK_STACK_CANARY(a1) |
| @@ -31,4 +31,13 @@ extern int fpcsr_pending(unsigned int __user *fpcsr); · 30 unmodified lines | |||
| 31 | #define lock_fpu_owner() ({ preempt_disable(); pagefault_disable(); }) | 31 | #define lock_fpu_owner() ({ preempt_disable(); pagefault_disable(); }) |
| 32 | #define unlock_fpu_owner() ({ pagefault_enable(); preempt_enable(); }) | 32 | #define unlock_fpu_owner() ({ pagefault_enable(); preempt_enable(); }) |
| 33 | 33 | ||
| 34 | /* Assembly functions to move context to/from the FPU */ | ||
| 35 | extern asmlinkage int | ||
| 36 | _save_fp_context(void __user *fpregs, void __user *csr); | ||
| 37 | extern asmlinkage int | ||
| 38 | _restore_fp_context(void __user *fpregs, void __user *csr); | ||
| 39 | |||
| 40 | extern asmlinkage int _save_msa_all_upper(void __user *buf); | ||
| 41 | extern asmlinkage int _restore_msa_all_upper(void __user *buf); | ||
| 42 | |||
| 34 | #endif /* __SIGNAL_COMMON_H */ | 43 | #endif /* __SIGNAL_COMMON_H */ |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include <linux/wait.h> | 21 | #include <linux/wait.h> |
| 22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
| 23 | #include <linux/unistd.h> | 23 | #include <linux/unistd.h> |
| 24 | #include <linux/uprobes.h> | ||
| 24 | #include <linux/compiler.h> | 25 | #include <linux/compiler.h> |
| 25 | #include <linux/syscalls.h> | 26 | #include <linux/syscalls.h> |
| 26 | #include <linux/uaccess.h> | 27 | #include <linux/uaccess.h> |
| @@ -38,20 +39,21 @@ · 11 unmodified lines | |||
| 38 | #include <asm/vdso.h> | 39 | #include <asm/vdso.h> |
| 39 | #include <asm/dsp.h> | 40 | #include <asm/dsp.h> |
| 40 | #include <asm/inst.h> | 41 | #include <asm/inst.h> |
| 42 | #include <asm/msa.h> | ||
| 41 | 43 | ||
| 42 | #include "signal-common.h" | 44 | #include "signal-common.h" |
| 43 | 45 | ||
| 44 | static int (*save_fp_context)(struct sigcontext __user *sc); | 46 | static int (*save_fp_context)(void __user *sc); |
| 45 | static int (*restore_fp_context)(struct sigcontext __user *sc); | 47 | static int (*restore_fp_context)(void __user *sc); |
| 46 | |||
| 47 | extern asmlinkage int _save_fp_context(struct sigcontext __user *sc); | ||
| 48 | extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc); | ||
| 49 | 48 | ||
| 50 | struct sigframe { | 49 | struct sigframe { |
| 51 | u32 sf_ass[4]; /* argument save space for o32 */ | 50 | u32 sf_ass[4]; /* argument save space for o32 */ |
| 52 | u32 sf_pad[2]; /* Was: signal trampoline */ | 51 | u32 sf_pad[2]; /* Was: signal trampoline */ |
| 52 | |||
| 53 | /* Matches struct ucontext from its uc_mcontext field onwards */ | ||
| 53 | struct sigcontext sf_sc; | 54 | struct sigcontext sf_sc; |
| 54 | sigset_t sf_mask; | 55 | sigset_t sf_mask; |
| 56 | unsigned long long sf_extcontext[0]; | ||
| 55 | }; | 57 | }; |
| 56 | 58 | ||
| 57 | struct rt_sigframe { | 59 | struct rt_sigframe { |
| @@ -65,43 +67,255 @@ struct rt_sigframe { · 7 unmodified lines | |||
| 65 | * Thread saved context copy to/from a signal context presumed to be on the | 67 | * Thread saved context copy to/from a signal context presumed to be on the |
| 66 | * user stack, and therefore accessed with appropriate macros from uaccess.h. | 68 | * user stack, and therefore accessed with appropriate macros from uaccess.h. |
| 67 | */ | 69 | */ |
| 68 | static int copy_fp_to_sigcontext(struct sigcontext __user *sc) | 70 | static int copy_fp_to_sigcontext(void __user *sc) |
| 69 | { | 71 | { |
| 72 | struct mips_abi *abi = current->thread.abi; | ||
| 73 | uint64_t __user *fpregs = sc + abi->off_sc_fpregs; | ||
| 74 | uint32_t __user *csr = sc + abi->off_sc_fpc_csr; | ||
| 70 | int i; | 75 | int i; |
| 71 | int err = 0; | 76 | int err = 0; |
| 77 | int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; | ||
| 72 | 78 | ||
| 73 | for (i = 0; i < NUM_FPU_REGS; i++) { | 79 | for (i = 0; i < NUM_FPU_REGS; i += inc) { |
| 74 | err |= | 80 | err |= |
| 75 | __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), | 81 | __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), |
| 76 | &sc->sc_fpregs[i]); | 82 | &fpregs[i]); |
| 77 | } | 83 | } |
| 78 | err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); | 84 | err |= __put_user(current->thread.fpu.fcr31, csr); |
| 79 | 85 | ||
| 80 | return err; | 86 | return err; |
| 81 | } | 87 | } |
| 82 | 88 | ||
| 83 | static int copy_fp_from_sigcontext(struct sigcontext __user *sc) | 89 | static int copy_fp_from_sigcontext(void __user *sc) |
| 84 | { | 90 | { |
| 91 | struct mips_abi *abi = current->thread.abi; | ||
| 92 | uint64_t __user *fpregs = sc + abi->off_sc_fpregs; | ||
| 93 | uint32_t __user *csr = sc + abi->off_sc_fpc_csr; | ||
| 85 | int i; | 94 | int i; |
| 86 | int err = 0; | 95 | int err = 0; |
| 96 | int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; | ||
| 87 | u64 fpr_val; | 97 | u64 fpr_val; |
| 88 | 98 | ||
| 89 | for (i = 0; i < NUM_FPU_REGS; i++) { | 99 | for (i = 0; i < NUM_FPU_REGS; i += inc) { |
| 90 | err |= __get_user(fpr_val, &sc->sc_fpregs[i]); | 100 | err |= __get_user(fpr_val, &fpregs[i]); |
| 91 | set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); | 101 | set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); |
| 92 | } | 102 | } |
| 93 | err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); | 103 | err |= __get_user(current->thread.fpu.fcr31, csr); |
| 94 | 104 | ||
| 95 | return err; | 105 | return err; |
| 96 | } | 106 | } |
| 97 | 107 | ||
| 108 | /* | ||
| 109 | * Wrappers for the assembly _{save,restore}_fp_context functions. | ||
| 110 | */ | ||
| 111 | static int save_hw_fp_context(void __user *sc) | ||
| 112 | { | ||
| 113 | struct mips_abi *abi = current->thread.abi; | ||
| 114 | uint64_t __user *fpregs = sc + abi->off_sc_fpregs; | ||
| 115 | uint32_t __user *csr = sc + abi->off_sc_fpc_csr; | ||
| 116 | |||
| 117 | return _save_fp_context(fpregs, csr); | ||
| 118 | } | ||
| 119 | |||
| 120 | static int restore_hw_fp_context(void __user *sc) | ||
| 121 | { | ||
| 122 | struct mips_abi *abi = current->thread.abi; | ||
| 123 | uint64_t __user *fpregs = sc + abi->off_sc_fpregs; | ||
| 124 | uint32_t __user *csr = sc + abi->off_sc_fpc_csr; | ||
| 125 | |||
| 126 | return _restore_fp_context(fpregs, csr); | ||
| 127 | } | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Extended context handling. | ||
| 131 | */ | ||
| 132 | |||
| 133 | static inline void __user *sc_to_extcontext(void __user *sc) | ||
| 134 | { | ||
| 135 | struct ucontext __user *uc; | ||
| 136 | |||
| 137 | /* | ||
| 138 | * We can just pretend the sigcontext is always embedded in a struct | ||
| 139 | * ucontext here, because the offset from sigcontext to extended | ||
| 140 | * context is the same in the struct sigframe case. | ||
| 141 | */ | ||
| 142 | uc = container_of(sc, struct ucontext, uc_mcontext); | ||
| 143 | return &uc->uc_extcontext; | ||
| 144 | } | ||
| 145 | |||
| 146 | static int save_msa_extcontext(void __user *buf) | ||
| 147 | { | ||
| 148 | struct msa_extcontext __user *msa = buf; | ||
| 149 | uint64_t val; | ||
| 150 | int i, err; | ||
| 151 | |||
| 152 | if (!thread_msa_context_live()) | ||
| 153 | return 0; | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Ensure that we can't lose the live MSA context between checking | ||
| 157 | * for it & writing it to memory. | ||
| 158 | */ | ||
| 159 | preempt_disable(); | ||
| 160 | |||
| 161 | if (is_msa_enabled()) { | ||
| 162 | /* | ||
| 163 | * There are no EVA versions of the vector register load/store | ||
| 164 | * instructions, so MSA context has to be saved to kernel memory | ||
| 165 | * and then copied to user memory. The save to kernel memory | ||
| 166 | * should already have been done when handling scalar FP | ||
| 167 | * context. | ||
| 168 | */ | ||
| 169 | BUG_ON(config_enabled(CONFIG_EVA)); | ||
| 170 | |||
| 171 | err = __put_user(read_msa_csr(), &msa->csr); | ||
| 172 | err |= _save_msa_all_upper(&msa->wr); | ||
| 173 | |||
| 174 | preempt_enable(); | ||
| 175 | } else { | ||
| 176 | preempt_enable(); | ||
| 177 | |||
| 178 | err = __put_user(current->thread.fpu.msacsr, &msa->csr); | ||
| 179 | |||
| 180 | for (i = 0; i < NUM_FPU_REGS; i++) { | ||
| 181 | val = get_fpr64(¤t->thread.fpu.fpr[i], 1); | ||
| 182 | err |= __put_user(val, &msa->wr[i]); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | err |= __put_user(MSA_EXTCONTEXT_MAGIC, &msa->ext.magic); | ||
| 187 | err |= __put_user(sizeof(*msa), &msa->ext.size); | ||
| 188 | |||
| 189 | return err ? -EFAULT : sizeof(*msa); | ||
| 190 | } | ||
| 191 | |||
| 192 | static int restore_msa_extcontext(void __user *buf, unsigned int size) | ||
| 193 | { | ||
| 194 | struct msa_extcontext __user *msa = buf; | ||
| 195 | unsigned long long val; | ||
| 196 | unsigned int csr; | ||
| 197 | int i, err; | ||
| 198 | |||
| 199 | if (size != sizeof(*msa)) | ||
| 200 | return -EINVAL; | ||
| 201 | |||
| 202 | err = get_user(csr, &msa->csr); | ||
| 203 | if (err) | ||
| 204 | return err; | ||
| 205 | |||
| 206 | preempt_disable(); | ||
| 207 | |||
| 208 | if (is_msa_enabled()) { | ||
| 209 | /* | ||
| 210 | * There are no EVA versions of the vector register load/store | ||
| 211 | * instructions, so MSA context has to be copied to kernel | ||
| 212 | * memory and later loaded to registers. The same is true of | ||
| 213 | * scalar FP context, so FPU & MSA should have already been | ||
| 214 | * disabled whilst handling scalar FP context. | ||
| 215 | */ | ||
| 216 | BUG_ON(config_enabled(CONFIG_EVA)); | ||
| 217 | |||
| 218 | write_msa_csr(csr); | ||
| 219 | err |= _restore_msa_all_upper(&msa->wr); | ||
| 220 | preempt_enable(); | ||
| 221 | } else { | ||
| 222 | preempt_enable(); | ||
| 223 | |||
| 224 | current->thread.fpu.msacsr = csr; | ||
| 225 | |||
| 226 | for (i = 0; i < NUM_FPU_REGS; i++) { | ||
| 227 | err |= __get_user(val, &msa->wr[i]); | ||
| 228 | set_fpr64(¤t->thread.fpu.fpr[i], 1, val); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | return err; | ||
| 233 | } | ||
| 234 | |||
| 235 | static int save_extcontext(void __user *buf) | ||
| 236 | { | ||
| 237 | int sz; | ||
| 238 | |||
| 239 | sz = save_msa_extcontext(buf); | ||
| 240 | if (sz < 0) | ||
| 241 | return sz; | ||
| 242 | buf += sz; | ||
| 243 | |||
| 244 | /* If no context was saved then trivially return */ | ||
| 245 | if (!sz) | ||
| 246 | return 0; | ||
| 247 | |||
| 248 | /* Write the end marker */ | ||
| 249 | if (__put_user(END_EXTCONTEXT_MAGIC, (u32 *)buf)) | ||
| 250 | return -EFAULT; | ||
| 251 | |||
| 252 | sz += sizeof(((struct extcontext *)NULL)->magic); | ||
| 253 | return sz; | ||
| 254 | } | ||
| 255 | |||
| 256 | static int restore_extcontext(void __user *buf) | ||
| 257 | { | ||
| 258 | struct extcontext ext; | ||
| 259 | int err; | ||
| 260 | |||
| 261 | while (1) { | ||
| 262 | err = __get_user(ext.magic, (unsigned int *)buf); | ||
| 263 | if (err) | ||
| 264 | return err; | ||
| 265 | |||
| 266 | if (ext.magic == END_EXTCONTEXT_MAGIC) | ||
| 267 | return 0; | ||
| 268 | |||
| 269 | err = __get_user(ext.size, (unsigned int *)(buf | ||
| 270 | + offsetof(struct extcontext, size))); | ||
| 271 | if (err) | ||
| 272 | return err; | ||
| 273 | |||
| 274 | switch (ext.magic) { | ||
| 275 | case MSA_EXTCONTEXT_MAGIC: | ||
| 276 | err = restore_msa_extcontext(buf, ext.size); | ||
| 277 | break; | ||
| 278 | |||
| 279 | default: | ||
| 280 | err = -EINVAL; | ||
| 281 | break; | ||
| 282 | } | ||
| 283 | |||
| 284 | if (err) | ||
| 285 | return err; | ||
| 286 | |||
| 287 | buf += ext.size; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 98 | /* | 291 | /* |
| 99 | * Helper routines | 292 | * Helper routines |
| 100 | */ | 293 | */ |
| 101 | static int protected_save_fp_context(struct sigcontext __user *sc) | 294 | int protected_save_fp_context(void __user *sc) |
| 102 | { | 295 | { |
| 296 | struct mips_abi *abi = current->thread.abi; | ||
| 297 | uint64_t __user *fpregs = sc + abi->off_sc_fpregs; | ||
| 298 | uint32_t __user *csr = sc + abi->off_sc_fpc_csr; | ||
| 299 | uint32_t __user *used_math = sc + abi->off_sc_used_math; | ||
| 300 | unsigned int used, ext_sz; | ||
| 103 | int err; | 301 | int err; |
| 104 | #ifndef CONFIG_EVA | 302 | |
| 303 | used = used_math() ? USED_FP : 0; | ||
| 304 | if (!used) | ||
| 305 | goto fp_done; | ||
| 306 | |||
| 307 | if (!test_thread_flag(TIF_32BIT_FPREGS)) | ||
| 308 | used |= USED_FR1; | ||
| 309 | if (test_thread_flag(TIF_HYBRID_FPREGS)) | ||
| 310 | used |= USED_HYBRID_FPRS; | ||
| 311 | |||
| 312 | /* | ||
| 313 | * EVA does not have userland equivalents of ldc1 or sdc1, so | ||
| 314 | * save to the kernel FP context & copy that to userland below. | ||
| 315 | */ | ||
| 316 | if (config_enabled(CONFIG_EVA)) | ||
| 317 | lose_fpu(1); | ||
| 318 | |||
| 105 | while (1) { | 319 | while (1) { |
| 106 | lock_fpu_owner(); | 320 | lock_fpu_owner(); |
| 107 | if (is_fpu_owner()) { | 321 | if (is_fpu_owner()) { |
| @@ -114,27 +328,57 @@ static int protected_save_fp_context(struct sigcontext __user *sc) · 6 unmodified lines | |||
| 114 | if (likely(!err)) | 328 | if (likely(!err)) |
| 115 | break; | 329 | break; |
| 116 | /* touch the sigcontext and try again */ | 330 | /* touch the sigcontext and try again */ |
| 117 | err = __put_user(0, &sc->sc_fpregs[0]) | | 331 | err = __put_user(0, &fpregs[0]) | |
| 118 | __put_user(0, &sc->sc_fpregs[31]) | | 332 | __put_user(0, &fpregs[31]) | |
| 119 | __put_user(0, &sc->sc_fpc_csr); | 333 | __put_user(0, csr); |
| 120 | if (err) | 334 | if (err) |
| 121 | break; /* really bad sigcontext */ | 335 | return err; /* really bad sigcontext */ |
| 122 | } | 336 | } |
| 123 | #else | 337 | |
| 124 | /* | 338 | fp_done: |
| 125 | * EVA does not have FPU EVA instructions so saving fpu context directly | 339 | ext_sz = err = save_extcontext(sc_to_extcontext(sc)); |
| 126 | * does not work. | 340 | if (err < 0) |
| 127 | */ | 341 | return err; |
| 128 | lose_fpu(1); | 342 | used |= ext_sz ? USED_EXTCONTEXT : 0; |
| 129 | err = save_fp_context(sc); /* this might fail */ | 343 | |
| 130 | #endif | 344 | return __put_user(used, used_math); |
| 131 | return err; | ||
| 132 | } | 345 | } |
| 133 | 346 | ||
| 134 | static int protected_restore_fp_context(struct sigcontext __user *sc) | 347 | int protected_restore_fp_context(void __user *sc) |
| 135 | { | 348 | { |
| 136 | int err, tmp __maybe_unused; | 349 | struct mips_abi *abi = current->thread.abi; |
| 137 | #ifndef CONFIG_EVA | 350 | uint64_t __user *fpregs = sc + abi->off_sc_fpregs; |
| 351 | uint32_t __user *csr = sc + abi->off_sc_fpc_csr; | ||
| 352 | uint32_t __user *used_math = sc + abi->off_sc_used_math; | ||
| 353 | unsigned int used; | ||
| 354 | int err, sig = 0, tmp __maybe_unused; | ||
| 355 | |||
| 356 | err = __get_user(used, used_math); | ||
| 357 | conditional_used_math(used & USED_FP); | ||
| 358 | |||
| 359 | /* | ||
| 360 | * The signal handler may have used FPU; give it up if the program | ||
| 361 | * doesn't want it following sigreturn. | ||
| 362 | */ | ||
| 363 | if (err || !(used & USED_FP)) | ||
| 364 | lose_fpu(0); | ||
| 365 | if (err) | ||
| 366 | return err; | ||
| 367 | if (!(used & USED_FP)) | ||
| 368 | goto fp_done; | ||
| 369 | |||
| 370 | err = sig = fpcsr_pending(csr); | ||
| 371 | if (err < 0) | ||
| 372 | return err; | ||
| 373 | |||
| 374 | /* | ||
| 375 | * EVA does not have userland equivalents of ldc1 or sdc1, so we | ||
| 376 | * disable the FPU here such that the code below simply copies to | ||
| 377 | * the kernel FP context. | ||
| 378 | */ | ||
| 379 | if (config_enabled(CONFIG_EVA)) | ||
| 380 | lose_fpu(0); | ||
| 381 | |||
| 138 | while (1) { | 382 | while (1) { |
| 139 | lock_fpu_owner(); | 383 | lock_fpu_owner(); |
| 140 | if (is_fpu_owner()) { | 384 | if (is_fpu_owner()) { |
| @@ -147,28 +391,24 @@ static int protected_restore_fp_context(struct sigcontext __user *sc) · 6 unmodified lines | |||
| 147 | if (likely(!err)) | 391 | if (likely(!err)) |
| 148 | break; | 392 | break; |
| 149 | /* touch the sigcontext and try again */ | 393 | /* touch the sigcontext and try again */ |
| 150 | err = __get_user(tmp, &sc->sc_fpregs[0]) | | 394 | err = __get_user(tmp, &fpregs[0]) | |
| 151 | __get_user(tmp, &sc->sc_fpregs[31]) | | 395 | __get_user(tmp, &fpregs[31]) | |
| 152 | __get_user(tmp, &sc->sc_fpc_csr); | 396 | __get_user(tmp, csr); |
| 153 | if (err) | 397 | if (err) |
| 154 | break; /* really bad sigcontext */ | 398 | break; /* really bad sigcontext */ |
| 155 | } | 399 | } |
| 156 | #else | 400 | |
| 157 | /* | 401 | fp_done: |
| 158 | * EVA does not have FPU EVA instructions so restoring fpu context | 402 | if (used & USED_EXTCONTEXT) |
| 159 | * directly does not work. | 403 | err |= restore_extcontext(sc_to_extcontext(sc)); |
| 160 | */ | 404 | |
| 161 | lose_fpu(0); | 405 | return err ?: sig; |
| 162 | err = restore_fp_context(sc); /* this might fail */ | ||
| 163 | #endif | ||
| 164 | return err; | ||
| 165 | } | 406 | } |
| 166 | 407 | ||
| 167 | int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | 408 | int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) |
| 168 | { | 409 | { |
| 169 | int err = 0; | 410 | int err = 0; |
| 170 | int i; | 411 | int i; |
| 171 | unsigned int used_math; | ||
| 172 | 412 | ||
| 173 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); | 413 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); |
| 174 | 414 | ||
| @@ -191,19 +431,38 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) · 16 unmodified lines | |||
| 191 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); | 431 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); |
| 192 | } | 432 | } |
| 193 | 433 | ||
| 194 | used_math = !!used_math(); | ||
| 195 | err |= __put_user(used_math, &sc->sc_used_math); | ||
| 196 | 434 | ||
| 197 | if (used_math) { | 435 | /* |
| 198 | /* | 436 | * Save FPU state to signal context. Signal handler |
| 199 | * Save FPU state to signal context. Signal handler | 437 | * will "inherit" current FPU state. |
| 200 | * will "inherit" current FPU state. | 438 | */ |
| 201 | */ | 439 | err |= protected_save_fp_context(sc); |
| 202 | err |= protected_save_fp_context(sc); | 440 | |
| 203 | } | ||
| 204 | return err; | 441 | return err; |
| 205 | } | 442 | } |
| 206 | 443 | ||
| 444 | static size_t extcontext_max_size(void) | ||
| 445 | { | ||
| 446 | size_t sz = 0; | ||
| 447 | |||
| 448 | /* | ||
| 449 | * The assumption here is that between this point & the point at which | ||
| 450 | * the extended context is saved the size of the context should only | ||
| 451 | * ever be able to shrink (if the task is preempted), but never grow. | ||
| 452 | * That is, what this function returns is an upper bound on the size of | ||
| 453 | * the extended context for the current task at the current time. | ||
| 454 | */ | ||
| 455 | |||
| 456 | if (thread_msa_context_live()) | ||
| 457 | sz += sizeof(struct msa_extcontext); | ||
| 458 | |||
| 459 | /* If any context is saved then we'll append the end marker */ | ||
| 460 | if (sz) | ||
| 461 | sz += sizeof(((struct extcontext *)NULL)->magic); | ||
| 462 | |||
| 463 | return sz; | ||
| 464 | } | ||
| 465 | |||
| 207 | int fpcsr_pending(unsigned int __user *fpcsr) | 466 | int fpcsr_pending(unsigned int __user *fpcsr) |
| 208 | { | 467 | { |
| 209 | int err, sig = 0; | 468 | int err, sig = 0; |
| @@ -223,21 +482,8 @@ int fpcsr_pending(unsigned int __user *fpcsr) · 13 unmodified lines | |||
| 223 | return err ?: sig; | 482 | return err ?: sig; |
| 224 | } | 483 | } |
| 225 | 484 | ||
| 226 | static int | ||
| 227 | check_and_restore_fp_context(struct sigcontext __user *sc) | ||
| 228 | { | ||
| 229 | int err, sig; | ||
| 230 | |||
| 231 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | ||
| 232 | if (err > 0) | ||
| 233 | err = 0; | ||
| 234 | err |= protected_restore_fp_context(sc); | ||
| 235 | return err ?: sig; | ||
| 236 | } | ||
| 237 | |||
| 238 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | 485 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) |
| 239 | { | 486 | { |
| 240 | unsigned int used_math; | ||
| 241 | unsigned long treg; | 487 | unsigned long treg; |
| 242 | int err = 0; | 488 | int err = 0; |
| 243 | int i; | 489 | int i; |
| @@ -265,19 +511,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) · 21 unmodified lines | |||
| 265 | for (i = 1; i < 32; i++) | 511 | for (i = 1; i < 32; i++) |
| 266 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); | 512 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); |
| 267 | 513 | ||
| 268 | err |= __get_user(used_math, &sc->sc_used_math); | 514 | return err ?: protected_restore_fp_context(sc); |
| 269 | conditional_used_math(used_math); | ||
| 270 | |||
| 271 | if (used_math) { | ||
| 272 | /* restore fpu context if we have used it before */ | ||
| 273 | if (!err) | ||
| 274 | err = check_and_restore_fp_context(sc); | ||
| 275 | } else { | ||
| 276 | /* signal handler may have used FPU. Give it up. */ | ||
| 277 | lose_fpu(0); | ||
| 278 | } | ||
| 279 | |||
| 280 | return err; | ||
| 281 | } | 515 | } |
| 282 | 516 | ||
| 283 | void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, | 517 | void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, |
| @@ -285,6 +519,9 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, · 1 unmodified line | |||
| 285 | { | 519 | { |
| 286 | unsigned long sp; | 520 | unsigned long sp; |
| 287 | 521 | ||
| 522 | /* Leave space for potential extended context */ | ||
| 523 | frame_size += extcontext_max_size(); | ||
| 524 | |||
| 288 | /* Default to using normal stack */ | 525 | /* Default to using normal stack */ |
| 289 | sp = regs->regs[29]; | 526 | sp = regs->regs[29]; |
| 290 | 527 | ||
| @@ -520,7 +757,11 @@ struct mips_abi mips_abi = { · 229 unmodified lines | |||
| 520 | .setup_rt_frame = setup_rt_frame, | 757 | .setup_rt_frame = setup_rt_frame, |
| 521 | .rt_signal_return_offset = | 758 | .rt_signal_return_offset = |
| 522 | offsetof(struct mips_vdso, rt_signal_trampoline), | 759 | offsetof(struct mips_vdso, rt_signal_trampoline), |
| 523 | .restart = __NR_restart_syscall | 760 | .restart = __NR_restart_syscall, |
| 761 | |||
| 762 | .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), | ||
| 763 | .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), | ||
| 764 | .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), | ||
| 524 | }; | 765 | }; |
| 525 | 766 | ||
| 526 | static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) | 767 | static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) |
| @@ -616,6 +857,9 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, · 89 unmodified lines | |||
| 616 | 857 | ||
| 617 | user_exit(); | 858 | user_exit(); |
| 618 | 859 | ||
| 860 | if (thread_info_flags & _TIF_UPROBE) | ||
| 861 | uprobe_notify_resume(regs); | ||
| 862 | |||
| 619 | /* deal with pending signal delivery */ | 863 | /* deal with pending signal delivery */ |
| 620 | if (thread_info_flags & _TIF_SIGPENDING) | 864 | if (thread_info_flags & _TIF_SIGPENDING) |
| 621 | do_signal(regs); | 865 | do_signal(regs); |
| @@ -629,43 +873,46 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, · 7 unmodified lines | |||
| 629 | } | 873 | } |
| 630 | 874 | ||
| 631 | #ifdef CONFIG_SMP | 875 | #ifdef CONFIG_SMP |
| 632 | #ifndef CONFIG_EVA | 876 | static int smp_save_fp_context(void __user *sc) |
| 633 | static int smp_save_fp_context(struct sigcontext __user *sc) | ||
| 634 | { | 877 | { |
| 635 | return raw_cpu_has_fpu | 878 | return raw_cpu_has_fpu |
| 636 | ? _save_fp_context(sc) | 879 | ? save_hw_fp_context(sc) |
| 637 | : copy_fp_to_sigcontext(sc); | 880 | : copy_fp_to_sigcontext(sc); |
| 638 | } | 881 | } |
| 639 | 882 | ||
| 640 | static int smp_restore_fp_context(struct sigcontext __user *sc) | 883 | static int smp_restore_fp_context(void __user *sc) |
| 641 | { | 884 | { |
| 642 | return raw_cpu_has_fpu | 885 | return raw_cpu_has_fpu |
| 643 | ? _restore_fp_context(sc) | 886 | ? restore_hw_fp_context(sc) |
| 644 | : copy_fp_from_sigcontext(sc); | 887 | : copy_fp_from_sigcontext(sc); |
| 645 | } | 888 | } |
| 646 | #endif /* CONFIG_EVA */ | ||
| 647 | #endif | 889 | #endif |
| 648 | 890 | ||
| 649 | static int signal_setup(void) | 891 | static int signal_setup(void) |
| 650 | { | 892 | { |
| 651 | #ifndef CONFIG_EVA | 893 | /* |
| 894 | * The offset from sigcontext to extended context should be the same | ||
| 895 | * regardless of the type of signal, such that userland can always know | ||
| 896 | * where to look if it wishes to find the extended context structures. | ||
| 897 | */ | ||
| 898 | BUILD_BUG_ON((offsetof(struct sigframe, sf_extcontext) - | ||
| 899 | offsetof(struct sigframe, sf_sc)) != | ||
| 900 | (offsetof(struct rt_sigframe, rs_uc.uc_extcontext) - | ||
| 901 | offsetof(struct rt_sigframe, rs_uc.uc_mcontext))); | ||
| 902 | |||
| 652 | #ifdef CONFIG_SMP | 903 | #ifdef CONFIG_SMP |
| 653 | /* For now just do the cpu_has_fpu check when the functions are invoked */ | 904 | /* For now just do the cpu_has_fpu check when the functions are invoked */ |
| 654 | save_fp_context = smp_save_fp_context; | 905 | save_fp_context = smp_save_fp_context; |
| 655 | restore_fp_context = smp_restore_fp_context; | 906 | restore_fp_context = smp_restore_fp_context; |
| 656 | #else | 907 | #else |
| 657 | if (cpu_has_fpu) { | 908 | if (cpu_has_fpu) { |
| 658 | save_fp_context = _save_fp_context; | 909 | save_fp_context = save_hw_fp_context; |
| 659 | restore_fp_context = _restore_fp_context; | 910 | restore_fp_context = restore_hw_fp_context; |
| 660 | } else { | 911 | } else { |
| 661 | save_fp_context = copy_fp_to_sigcontext; | 912 | save_fp_context = copy_fp_to_sigcontext; |
| 662 | restore_fp_context = copy_fp_from_sigcontext; | 913 | restore_fp_context = copy_fp_from_sigcontext; |
| 663 | } | 914 | } |
| 664 | #endif /* CONFIG_SMP */ | 915 | #endif /* CONFIG_SMP */ |
| 665 | #else | ||
| 666 | save_fp_context = copy_fp_to_sigcontext; | ||
| 667 | restore_fp_context = copy_fp_from_sigcontext; | ||
| 668 | #endif | ||
| 669 | 916 | ||
| 670 | return 0; | 917 | return 0; |
| 671 | } | 918 | } |
| @@ -36,12 +36,6 @@ · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | #include "signal-common.h" | 37 | #include "signal-common.h" |
| 38 | 38 | ||
| 39 | static int (*save_fp_context32)(struct sigcontext32 __user *sc); | ||
| 40 | static int (*restore_fp_context32)(struct sigcontext32 __user *sc); | ||
| 41 | |||
| 42 | extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); | ||
| 43 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); | ||
| 44 | |||
| 45 | /* | 39 | /* |
| 46 | * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... | 40 | * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... |
| 47 | */ | 41 | */ |
| @@ -74,99 +68,11 @@ struct rt_sigframe32 { · 26 unmodified lines | |||
| 74 | struct ucontext32 rs_uc; | 68 | struct ucontext32 rs_uc; |
| 75 | }; | 69 | }; |
| 76 | 70 | ||
| 77 | /* | ||
| 78 | * Thread saved context copy to/from a signal context presumed to be on the | ||
| 79 | * user stack, and therefore accessed with appropriate macros from uaccess.h. | ||
| 80 | */ | ||
| 81 | static int copy_fp_to_sigcontext32(struct sigcontext32 __user *sc) | ||
| 82 | { | ||
| 83 | int i; | ||
| 84 | int err = 0; | ||
| 85 | int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; | ||
| 86 | |||
| 87 | for (i = 0; i < NUM_FPU_REGS; i += inc) { | ||
| 88 | err |= | ||
| 89 | __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), | ||
| 90 | &sc->sc_fpregs[i]); | ||
| 91 | } | ||
| 92 | err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); | ||
| 93 | |||
| 94 | return err; | ||
| 95 | } | ||
| 96 | |||
| 97 | static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc) | ||
| 98 | { | ||
| 99 | int i; | ||
| 100 | int err = 0; | ||
| 101 | int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; | ||
| 102 | u64 fpr_val; | ||
| 103 | |||
| 104 | for (i = 0; i < NUM_FPU_REGS; i += inc) { | ||
| 105 | err |= __get_user(fpr_val, &sc->sc_fpregs[i]); | ||
| 106 | set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); | ||
| 107 | } | ||
| 108 | err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); | ||
| 109 | |||
| 110 | return err; | ||
| 111 | } | ||
| 112 | |||
| 113 | /* | ||
| 114 | * sigcontext handlers | ||
| 115 | */ | ||
| 116 | static int protected_save_fp_context32(struct sigcontext32 __user *sc) | ||
| 117 | { | ||
| 118 | int err; | ||
| 119 | while (1) { | ||
| 120 | lock_fpu_owner(); | ||
| 121 | if (is_fpu_owner()) { | ||
| 122 | err = save_fp_context32(sc); | ||
| 123 | unlock_fpu_owner(); | ||
| 124 | } else { | ||
| 125 | unlock_fpu_owner(); | ||
| 126 | err = copy_fp_to_sigcontext32(sc); | ||
| 127 | } | ||
| 128 | if (likely(!err)) | ||
| 129 | break; | ||
| 130 | /* touch the sigcontext and try again */ | ||
| 131 | err = __put_user(0, &sc->sc_fpregs[0]) | | ||
| 132 | __put_user(0, &sc->sc_fpregs[31]) | | ||
| 133 | __put_user(0, &sc->sc_fpc_csr); | ||
| 134 | if (err) | ||
| 135 | break; /* really bad sigcontext */ | ||
| 136 | } | ||
| 137 | return err; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int protected_restore_fp_context32(struct sigcontext32 __user *sc) | ||
| 141 | { | ||
| 142 | int err, tmp __maybe_unused; | ||
| 143 | while (1) { | ||
| 144 | lock_fpu_owner(); | ||
| 145 | if (is_fpu_owner()) { | ||
| 146 | err = restore_fp_context32(sc); | ||
| 147 | unlock_fpu_owner(); | ||
| 148 | } else { | ||
| 149 | unlock_fpu_owner(); | ||
| 150 | err = copy_fp_from_sigcontext32(sc); | ||
| 151 | } | ||
| 152 | if (likely(!err)) | ||
| 153 | break; | ||
| 154 | /* touch the sigcontext and try again */ | ||
| 155 | err = __get_user(tmp, &sc->sc_fpregs[0]) | | ||
| 156 | __get_user(tmp, &sc->sc_fpregs[31]) | | ||
| 157 | __get_user(tmp, &sc->sc_fpc_csr); | ||
| 158 | if (err) | ||
| 159 | break; /* really bad sigcontext */ | ||
| 160 | } | ||
| 161 | return err; | ||
| 162 | } | ||
| 163 | |||
| 164 | static int setup_sigcontext32(struct pt_regs *regs, | 71 | static int setup_sigcontext32(struct pt_regs *regs, |
| 165 | struct sigcontext32 __user *sc) | 72 | struct sigcontext32 __user *sc) |
| 166 | { | 73 | { |
| 167 | int err = 0; | 74 | int err = 0; |
| 168 | int i; | 75 | int i; |
| 169 | u32 used_math; | ||
| 170 | 76 | ||
| 171 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); | 77 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); |
| 172 | 78 | ||
| @@ -186,35 +92,18 @@ static int setup_sigcontext32(struct pt_regs *regs, · 13 unmodified lines | |||
| 186 | err |= __put_user(mflo3(), &sc->sc_lo3); | 92 | err |= __put_user(mflo3(), &sc->sc_lo3); |
| 187 | } | 93 | } |
| 188 | 94 | ||
| 189 | used_math = !!used_math(); | 95 | /* |
| 190 | err |= __put_user(used_math, &sc->sc_used_math); | 96 | * Save FPU state to signal context. Signal handler |
| 97 | * will "inherit" current FPU state. | ||
| 98 | */ | ||
| 99 | err |= protected_save_fp_context(sc); | ||
| 191 | 100 | ||
| 192 | if (used_math) { | ||
| 193 | /* | ||
| 194 | * Save FPU state to signal context. Signal handler | ||
| 195 | * will "inherit" current FPU state. | ||
| 196 | */ | ||
| 197 | err |= protected_save_fp_context32(sc); | ||
| 198 | } | ||
| 199 | return err; | 101 | return err; |
| 200 | } | 102 | } |
| 201 | 103 | ||
| 202 | static int | ||
| 203 | check_and_restore_fp_context32(struct sigcontext32 __user *sc) | ||
| 204 | { | ||
| 205 | int err, sig; | ||
| 206 | |||
| 207 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | ||
| 208 | if (err > 0) | ||
| 209 | err = 0; | ||
| 210 | err |= protected_restore_fp_context32(sc); | ||
| 211 | return err ?: sig; | ||
| 212 | } | ||
| 213 | |||
| 214 | static int restore_sigcontext32(struct pt_regs *regs, | 104 | static int restore_sigcontext32(struct pt_regs *regs, |
| 215 | struct sigcontext32 __user *sc) | 105 | struct sigcontext32 __user *sc) |
| 216 | { | 106 | { |
| 217 | u32 used_math; | ||
| 218 | int err = 0; | 107 | int err = 0; |
| 219 | s32 treg; | 108 | s32 treg; |
| 220 | int i; | 109 | int i; |
| @@ -238,70 +127,7 @@ static int restore_sigcontext32(struct pt_regs *regs, · 17 unmodified lines | |||
| 238 | for (i = 1; i < 32; i++) | 127 | for (i = 1; i < 32; i++) |
| 239 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); | 128 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); |
| 240 | 129 | ||
| 241 | err |= __get_user(used_math, &sc->sc_used_math); | 130 | return err ?: protected_restore_fp_context(sc); |
| 242 | conditional_used_math(used_math); | ||
| 243 | |||
| 244 | if (used_math) { | ||
| 245 | /* restore fpu context if we have used it before */ | ||
| 246 | if (!err) | ||
| 247 | err = check_and_restore_fp_context32(sc); | ||
| 248 | } else { | ||
| 249 | /* signal handler may have used FPU. Give it up. */ | ||
| 250 | lose_fpu(0); | ||
| 251 | } | ||
| 252 | |||
| 253 | return err; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* | ||
| 257 | * | ||
| 258 | */ | ||
| 259 | extern void __put_sigset_unknown_nsig(void); | ||
| 260 | extern void __get_sigset_unknown_nsig(void); | ||
| 261 | |||
| 262 | static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf) | ||
| 263 | { | ||
| 264 | int err = 0; | ||
| 265 | |||
| 266 | if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) | ||
| 267 | return -EFAULT; | ||
| 268 | |||
| 269 | switch (_NSIG_WORDS) { | ||
| 270 | default: | ||
| 271 | __put_sigset_unknown_nsig(); | ||
| 272 | case 2: | ||
| 273 | err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]); | ||
| 274 | err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); | ||
| 275 | case 1: | ||
| 276 | err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]); | ||
| 277 | err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); | ||
| 278 | } | ||
| 279 | |||
| 280 | return err; | ||
| 281 | } | ||
| 282 | |||
| 283 | static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) | ||
| 284 | { | ||
| 285 | int err = 0; | ||
| 286 | unsigned long sig[4]; | ||
| 287 | |||
| 288 | if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf))) | ||
| 289 | return -EFAULT; | ||
| 290 | |||
| 291 | switch (_NSIG_WORDS) { | ||
| 292 | default: | ||
| 293 | __get_sigset_unknown_nsig(); | ||
| 294 | case 2: | ||
| 295 | err |= __get_user(sig[3], &ubuf->sig[3]); | ||
| 296 | err |= __get_user(sig[2], &ubuf->sig[2]); | ||
| 297 | kbuf->sig[1] = sig[2] | (sig[3] << 32); | ||
| 298 | case 1: | ||
| 299 | err |= __get_user(sig[1], &ubuf->sig[1]); | ||
| 300 | err |= __get_user(sig[0], &ubuf->sig[0]); | ||
| 301 | kbuf->sig[0] = sig[0] | (sig[1] << 32); | ||
| 302 | } | ||
| 303 | |||
| 304 | return err; | ||
| 305 | } | 131 | } |
| 306 | 132 | ||
| 307 | /* | 133 | /* |
| @@ -585,20 +411,9 @@ struct mips_abi mips_abi_32 = { · 277 unmodified lines | |||
| 585 | .setup_rt_frame = setup_rt_frame_32, | 411 | .setup_rt_frame = setup_rt_frame_32, |
| 586 | .rt_signal_return_offset = | 412 | .rt_signal_return_offset = |
| 587 | offsetof(struct mips_vdso, o32_rt_signal_trampoline), | 413 | offsetof(struct mips_vdso, o32_rt_signal_trampoline), |
| 588 | .restart = __NR_O32_restart_syscall | 414 | .restart = __NR_O32_restart_syscall, |
| 589 | }; | ||
| 590 | |||
| 591 | static int signal32_init(void) | ||
| 592 | { | ||
| 593 | if (cpu_has_fpu) { | ||
| 594 | save_fp_context32 = _save_fp_context32; | ||
| 595 | restore_fp_context32 = _restore_fp_context32; | ||
| 596 | } else { | ||
| 597 | save_fp_context32 = copy_fp_to_sigcontext32; | ||
| 598 | restore_fp_context32 = copy_fp_from_sigcontext32; | ||
| 599 | } | ||
| 600 | 415 | ||
| 601 | return 0; | 416 | .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs), |
| 602 | } | 417 | .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), |
| 603 | 418 | .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), | |
| 604 | arch_initcall(signal32_init); | 419 | }; |
| @@ -153,5 +153,9 @@ struct mips_abi mips_abi_n32 = { · 152 unmodified lines | |||
| 153 | .setup_rt_frame = setup_rt_frame_n32, | 153 | .setup_rt_frame = setup_rt_frame_n32, |
| 154 | .rt_signal_return_offset = | 154 | .rt_signal_return_offset = |
| 155 | offsetof(struct mips_vdso, n32_rt_signal_trampoline), | 155 | offsetof(struct mips_vdso, n32_rt_signal_trampoline), |
| 156 | .restart = __NR_N32_restart_syscall | 156 | .restart = __NR_N32_restart_syscall, |
| 157 | |||
| 158 | .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), | ||
| 159 | .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), | ||
| 160 | .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), | ||
| 157 | }; | 161 | }; |
| @@ -209,6 +209,7 @@ void spram_config(void) · 208 unmodified lines | |||
| 209 | case CPU_PROAPTIV: | 209 | case CPU_PROAPTIV: |
| 210 | case CPU_P5600: | 210 | case CPU_P5600: |
| 211 | case CPU_QEMU_GENERIC: | 211 | case CPU_QEMU_GENERIC: |
| 212 | case CPU_I6400: | ||
| 212 | config0 = read_c0_config(); | 213 | config0 = read_c0_config(); |
| 213 | /* FIXME: addresses are Malta specific */ | 214 | /* FIXME: addresses are Malta specific */ |
| 214 | if (config0 & (1<<24)) { | 215 | if (config0 & (1<<24)) { |
| @@ -21,24 +21,12 @@ static DEFINE_SPINLOCK(show_lock); · 20 unmodified lines | |||
| 21 | 21 | ||
| 22 | static void sysrq_tlbdump_single(void *dummy) | 22 | static void sysrq_tlbdump_single(void *dummy) |
| 23 | { | 23 | { |
| 24 | const int field = 2 * sizeof(unsigned long); | ||
| 25 | unsigned long flags; | 24 | unsigned long flags; |
| 26 | 25 | ||
| 27 | spin_lock_irqsave(&show_lock, flags); | 26 | spin_lock_irqsave(&show_lock, flags); |
| 28 | 27 | ||
| 29 | pr_info("CPU%d:\n", smp_processor_id()); | 28 | pr_info("CPU%d:\n", smp_processor_id()); |
| 30 | pr_info("Index : %0x\n", read_c0_index()); | 29 | dump_tlb_regs(); |
| 31 | pr_info("Pagemask: %0x\n", read_c0_pagemask()); | ||
| 32 | pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi()); | ||
| 33 | pr_info("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); | ||
| 34 | pr_info("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); | ||
| 35 | pr_info("Wired : %0x\n", read_c0_wired()); | ||
| 36 | pr_info("Pagegrain: %0x\n", read_c0_pagegrain()); | ||
| 37 | if (cpu_has_htw) { | ||
| 38 | pr_info("PWField : %0*lx\n", field, read_c0_pwfield()); | ||
| 39 | pr_info("PWSize : %0*lx\n", field, read_c0_pwsize()); | ||
| 40 | pr_info("PWCtl : %0x\n", read_c0_pwctl()); | ||
| 41 | } | ||
| 42 | pr_info("\n"); | 30 | pr_info("\n"); |
| 43 | dump_tlb_all(); | 31 | dump_tlb_all(); |
| 44 | pr_info("\n"); | 32 | pr_info("\n"); |
| @@ -370,11 +370,6 @@ void show_registers(struct pt_regs *regs) · 369 unmodified lines | |||
| 370 | set_fs(old_fs); | 370 | set_fs(old_fs); |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | static int regs_to_trapnr(struct pt_regs *regs) | ||
| 374 | { | ||
| 375 | return (regs->cp0_cause >> 2) & 0x1f; | ||
| 376 | } | ||
| 377 | |||
| 378 | static DEFINE_RAW_SPINLOCK(die_lock); | 373 | static DEFINE_RAW_SPINLOCK(die_lock); |
| 379 | 374 | ||
| 380 | void __noreturn die(const char *str, struct pt_regs *regs) | 375 | void __noreturn die(const char *str, struct pt_regs *regs) |
| @@ -384,7 +379,7 @@ void __noreturn die(const char *str, struct pt_regs *regs) · 3 unmodified lines | |||
| 384 | 379 | ||
| 385 | oops_enter(); | 380 | oops_enter(); |
| 386 | 381 | ||
| 387 | if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), | 382 | if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_nr, |
| 388 | SIGSEGV) == NOTIFY_STOP) | 383 | SIGSEGV) == NOTIFY_STOP) |
| 389 | sig = 0; | 384 | sig = 0; |
| 390 | 385 | ||
| @@ -470,7 +465,7 @@ asmlinkage void do_be(struct pt_regs *regs) · 79 unmodified lines | |||
| 470 | printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", | 465 | printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", |
| 471 | data ? "Data" : "Instruction", | 466 | data ? "Data" : "Instruction", |
| 472 | field, regs->cp0_epc, field, regs->regs[31]); | 467 | field, regs->cp0_epc, field, regs->regs[31]); |
| 473 | if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), | 468 | if (notify_die(DIE_OOPS, "bus error", regs, 0, current->thread.trap_nr, |
| 474 | SIGBUS) == NOTIFY_STOP) | 469 | SIGBUS) == NOTIFY_STOP) |
| 475 | goto out; | 470 | goto out; |
| 476 | 471 | ||
| @@ -826,7 +821,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) · 349 unmodified lines | |||
| 826 | int sig; | 821 | int sig; |
| 827 | 822 | ||
| 828 | prev_state = exception_enter(); | 823 | prev_state = exception_enter(); |
| 829 | if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), | 824 | if (notify_die(DIE_FP, "FP exception", regs, 0, current->thread.trap_nr, |
| 830 | SIGFPE) == NOTIFY_STOP) | 825 | SIGFPE) == NOTIFY_STOP) |
| 831 | goto out; | 826 | goto out; |
| 832 | 827 | ||
| @@ -882,11 +877,12 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code, · 49 unmodified lines | |||
| 882 | char b[40]; | 877 | char b[40]; |
| 883 | 878 | ||
| 884 | #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP | 879 | #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP |
| 885 | if (kgdb_ll_trap(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) | 880 | if (kgdb_ll_trap(DIE_TRAP, str, regs, code, current->thread.trap_nr, |
| 881 | SIGTRAP) == NOTIFY_STOP) | ||
| 886 | return; | 882 | return; |
| 887 | #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ | 883 | #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ |
| 888 | 884 | ||
| 889 | if (notify_die(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), | 885 | if (notify_die(DIE_TRAP, str, regs, code, current->thread.trap_nr, |
| 890 | SIGTRAP) == NOTIFY_STOP) | 886 | SIGTRAP) == NOTIFY_STOP) |
| 891 | return; | 887 | return; |
| 892 | 888 | ||
| @@ -948,6 +944,7 @@ asmlinkage void do_bp(struct pt_regs *regs) · 55 unmodified lines | |||
| 948 | set_fs(KERNEL_DS); | 944 | set_fs(KERNEL_DS); |
| 949 | 945 | ||
| 950 | prev_state = exception_enter(); | 946 | prev_state = exception_enter(); |
| 947 | current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | ||
| 951 | if (get_isa16_mode(regs->cp0_epc)) { | 948 | if (get_isa16_mode(regs->cp0_epc)) { |
| 952 | u16 instr[2]; | 949 | u16 instr[2]; |
| 953 | 950 | ||
| @@ -987,15 +984,27 @@ asmlinkage void do_bp(struct pt_regs *regs) · 33 unmodified lines | |||
| 987 | * pertain to them. | 984 | * pertain to them. |
| 988 | */ | 985 | */ |
| 989 | switch (bcode) { | 986 | switch (bcode) { |
| 987 | case BRK_UPROBE: | ||
| 988 | if (notify_die(DIE_UPROBE, "uprobe", regs, bcode, | ||
| 989 | current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) | ||
| 990 | goto out; | ||
| 991 | else | ||
| 992 | break; | ||
| 993 | case BRK_UPROBE_XOL: | ||
| 994 | if (notify_die(DIE_UPROBE_XOL, "uprobe_xol", regs, bcode, | ||
| 995 | current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) | ||
| 996 | goto out; | ||
| 997 | else | ||
| 998 | break; | ||
| 990 | case BRK_KPROBE_BP: | 999 | case BRK_KPROBE_BP: |
| 991 | if (notify_die(DIE_BREAK, "debug", regs, bcode, | 1000 | if (notify_die(DIE_BREAK, "debug", regs, bcode, |
| 992 | regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) | 1001 | current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) |
| 993 | goto out; | 1002 | goto out; |
| 994 | else | 1003 | else |
| 995 | break; | 1004 | break; |
| 996 | case BRK_KPROBE_SSTEPBP: | 1005 | case BRK_KPROBE_SSTEPBP: |
| 997 | if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, | 1006 | if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, |
| 998 | regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) | 1007 | current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) |
| 999 | goto out; | 1008 | goto out; |
| 1000 | else | 1009 | else |
| 1001 | break; | 1010 | break; |
| @@ -1028,6 +1037,7 @@ asmlinkage void do_tr(struct pt_regs *regs) · 26 unmodified lines | |||
| 1028 | set_fs(get_ds()); | 1037 | set_fs(get_ds()); |
| 1029 | 1038 | ||
| 1030 | prev_state = exception_enter(); | 1039 | prev_state = exception_enter(); |
| 1040 | current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | ||
| 1031 | if (get_isa16_mode(regs->cp0_epc)) { | 1041 | if (get_isa16_mode(regs->cp0_epc)) { |
| 1032 | if (__get_user(instr[0], (u16 __user *)(epc + 0)) || | 1042 | if (__get_user(instr[0], (u16 __user *)(epc + 0)) || |
| 1033 | __get_user(instr[1], (u16 __user *)(epc + 2))) | 1043 | __get_user(instr[1], (u16 __user *)(epc + 2))) |
| @@ -1094,8 +1104,9 @@ asmlinkage void do_ri(struct pt_regs *regs) · 60 unmodified lines | |||
| 1094 | no_r2_instr: | 1104 | no_r2_instr: |
| 1095 | 1105 | ||
| 1096 | prev_state = exception_enter(); | 1106 | prev_state = exception_enter(); |
| 1107 | current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | ||
| 1097 | 1108 | ||
| 1098 | if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), | 1109 | if (notify_die(DIE_RI, "RI Fault", regs, 0, current->thread.trap_nr, |
| 1099 | SIGILL) == NOTIFY_STOP) | 1110 | SIGILL) == NOTIFY_STOP) |
| 1100 | goto out; | 1111 | goto out; |
| 1101 | 1112 | ||
| @@ -1444,8 +1455,9 @@ asmlinkage void do_msa_fpe(struct pt_regs *regs, unsigned int msacsr) · 342 unmodified lines | |||
| 1444 | enum ctx_state prev_state; | 1455 | enum ctx_state prev_state; |
| 1445 | 1456 | ||
| 1446 | prev_state = exception_enter(); | 1457 | prev_state = exception_enter(); |
| 1458 | current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | ||
| 1447 | if (notify_die(DIE_MSAFP, "MSA FP exception", regs, 0, | 1459 | if (notify_die(DIE_MSAFP, "MSA FP exception", regs, 0, |
| 1448 | regs_to_trapnr(regs), SIGFPE) == NOTIFY_STOP) | 1460 | current->thread.trap_nr, SIGFPE) == NOTIFY_STOP) |
| 1449 | goto out; | 1461 | goto out; |
| 1450 | 1462 | ||
| 1451 | /* Clear MSACSR.Cause before enabling interrupts */ | 1463 | /* Clear MSACSR.Cause before enabling interrupts */ |
| @@ -1523,7 +1535,6 @@ asmlinkage void do_watch(struct pt_regs *regs) · 71 unmodified lines | |||
| 1523 | 1535 | ||
| 1524 | asmlinkage void do_mcheck(struct pt_regs *regs) | 1536 | asmlinkage void do_mcheck(struct pt_regs *regs) |
| 1525 | { | 1537 | { |
| 1526 | const int field = 2 * sizeof(unsigned long); | ||
| 1527 | int multi_match = regs->cp0_status & ST0_TS; | 1538 | int multi_match = regs->cp0_status & ST0_TS; |
| 1528 | enum ctx_state prev_state; | 1539 | enum ctx_state prev_state; |
| 1529 | mm_segment_t old_fs = get_fs(); | 1540 | mm_segment_t old_fs = get_fs(); |
| @@ -1532,19 +1543,8 @@ asmlinkage void do_mcheck(struct pt_regs *regs) · 2 unmodified lines | |||
| 1532 | show_regs(regs); | 1543 | show_regs(regs); |
| 1533 | 1544 | ||
| 1534 | if (multi_match) { | 1545 | if (multi_match) { |
| 1535 | pr_err("Index : %0x\n", read_c0_index()); | 1546 | dump_tlb_regs(); |
| 1536 | pr_err("Pagemask: %0x\n", read_c0_pagemask()); | 1547 | pr_info("\n"); |
| 1537 | pr_err("EntryHi : %0*lx\n", field, read_c0_entryhi()); | ||
| 1538 | pr_err("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); | ||
| 1539 | pr_err("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); | ||
| 1540 | pr_err("Wired : %0x\n", read_c0_wired()); | ||
| 1541 | pr_err("Pagegrain: %0x\n", read_c0_pagegrain()); | ||
| 1542 | if (cpu_has_htw) { | ||
| 1543 | pr_err("PWField : %0*lx\n", field, read_c0_pwfield()); | ||
| 1544 | pr_err("PWSize : %0*lx\n", field, read_c0_pwsize()); | ||
| 1545 | pr_err("PWCtl : %0x\n", read_c0_pwctl()); | ||
| 1546 | } | ||
| 1547 | pr_err("\n"); | ||
| 1548 | dump_tlb_all(); | 1548 | dump_tlb_all(); |
| 1549 | } | 1549 | } |
| 1550 | 1550 | ||
| @@ -1651,6 +1651,7 @@ static inline void parity_protection_init(void) · 100 unmodified lines | |||
| 1651 | case CPU_PROAPTIV: | 1651 | case CPU_PROAPTIV: |
| 1652 | case CPU_P5600: | 1652 | case CPU_P5600: |
| 1653 | case CPU_QEMU_GENERIC: | 1653 | case CPU_QEMU_GENERIC: |
| 1654 | case CPU_I6400: | ||
| 1654 | { | 1655 | { |
| 1655 | #define ERRCTL_PE 0x80000000 | 1656 | #define ERRCTL_PE 0x80000000 |
| 1656 | #define ERRCTL_L2P 0x00800000 | 1657 | #define ERRCTL_L2P 0x00800000 |
| @@ -891,6 +891,9 @@ static void emulate_load_store_insn(struct pt_regs *regs, · 890 unmodified lines | |||
| 891 | #ifdef CONFIG_EVA | 891 | #ifdef CONFIG_EVA |
| 892 | mm_segment_t seg; | 892 | mm_segment_t seg; |
| 893 | #endif | 893 | #endif |
| 894 | union fpureg *fpr; | ||
| 895 | enum msa_2b_fmt df; | ||
| 896 | unsigned int wd; | ||
| 894 | origpc = (unsigned long)pc; | 897 | origpc = (unsigned long)pc; |
| 895 | orig31 = regs->regs[31]; | 898 | orig31 = regs->regs[31]; |
| 896 | 899 | ||
| @@ -1202,6 +1205,75 @@ static void emulate_load_store_insn(struct pt_regs *regs, · 305 unmodified lines | |||
| 1202 | break; | 1205 | break; |
| 1203 | return; | 1206 | return; |
| 1204 | 1207 | ||
| 1208 | case msa_op: | ||
| 1209 | if (!cpu_has_msa) | ||
| 1210 | goto sigill; | ||
| 1211 | |||
| 1212 | /* | ||
| 1213 | * If we've reached this point then userland should have taken | ||
| 1214 | * the MSA disabled exception & initialised vector context at | ||
| 1215 | * some point in the past. | ||
| 1216 | */ | ||
| 1217 | BUG_ON(!thread_msa_context_live()); | ||
| 1218 | |||
| 1219 | df = insn.msa_mi10_format.df; | ||
| 1220 | wd = insn.msa_mi10_format.wd; | ||
| 1221 | fpr = ¤t->thread.fpu.fpr[wd]; | ||
| 1222 | |||
| 1223 | switch (insn.msa_mi10_format.func) { | ||
| 1224 | case msa_ld_op: | ||
| 1225 | if (!access_ok(VERIFY_READ, addr, sizeof(*fpr))) | ||
| 1226 | goto sigbus; | ||
| 1227 | |||
| 1228 | /* | ||
| 1229 | * Disable preemption to avoid a race between copying | ||
| 1230 | * state from userland, migrating to another CPU and | ||
| 1231 | * updating the hardware vector register below. | ||
| 1232 | */ | ||
| 1233 | preempt_disable(); | ||
| 1234 | |||
| 1235 | res = __copy_from_user_inatomic(fpr, addr, | ||
| 1236 | sizeof(*fpr)); | ||
| 1237 | if (res) | ||
| 1238 | goto fault; | ||
| 1239 | |||
| 1240 | /* | ||
| 1241 | * Update the hardware register if it is in use by the | ||
| 1242 | * task in this quantum, in order to avoid having to | ||
| 1243 | * save & restore the whole vector context. | ||
| 1244 | */ | ||
| 1245 | if (test_thread_flag(TIF_USEDMSA)) | ||
| 1246 | write_msa_wr(wd, fpr, df); | ||
| 1247 | |||
| 1248 | preempt_enable(); | ||
| 1249 | break; | ||
| 1250 | |||
| 1251 | case msa_st_op: | ||
| 1252 | if (!access_ok(VERIFY_WRITE, addr, sizeof(*fpr))) | ||
| 1253 | goto sigbus; | ||
| 1254 | |||
| 1255 | /* | ||
| 1256 | * Update from the hardware register if it is in use by | ||
| 1257 | * the task in this quantum, in order to avoid having to | ||
| 1258 | * save & restore the whole vector context. | ||
| 1259 | */ | ||
| 1260 | preempt_disable(); | ||
| 1261 | if (test_thread_flag(TIF_USEDMSA)) | ||
| 1262 | read_msa_wr(wd, fpr, df); | ||
| 1263 | preempt_enable(); | ||
| 1264 | |||
| 1265 | res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr)); | ||
| 1266 | if (res) | ||
| 1267 | goto fault; | ||
| 1268 | break; | ||
| 1269 | |||
| 1270 | default: | ||
| 1271 | goto sigbus; | ||
| 1272 | } | ||
| 1273 | |||
| 1274 | compute_return_epc(regs); | ||
| 1275 | break; | ||
| 1276 | |||
| 1205 | #ifndef CONFIG_CPU_MIPSR6 | 1277 | #ifndef CONFIG_CPU_MIPSR6 |
| 1206 | /* | 1278 | /* |
| 1207 | * COP2 is available to implementor for application specific use. | 1279 | * COP2 is available to implementor for application specific use. |
| @@ -2240,5 +2312,5 @@ static int __init debugfs_unaligned(void) · 1032 unmodified lines | |||
| 2240 | return -ENOMEM; | 2312 | return -ENOMEM; |
| 2241 | return 0; | 2313 | return 0; |
| 2242 | } | 2314 | } |
| 2243 | __initcall(debugfs_unaligned); | 2315 | arch_initcall(debugfs_unaligned); |
| 2244 | #endif | 2316 | #endif |
| @@ -0,0 +1,341 @@ | |||
| 1 | #include <linux/highmem.h> | ||
| 2 | #include <linux/kdebug.h> | ||
| 3 | #include <linux/types.h> | ||
| 4 | #include <linux/notifier.h> | ||
| 5 | #include <linux/sched.h> | ||
| 6 | #include <linux/uprobes.h> | ||
| 7 | |||
| 8 | #include <asm/branch.h> | ||
| 9 | #include <asm/cpu-features.h> | ||
| 10 | #include <asm/ptrace.h> | ||
| 11 | #include <asm/inst.h> | ||
| 12 | |||
| 13 | static inline int insn_has_delay_slot(const union mips_instruction insn) | ||
| 14 | { | ||
| 15 | switch (insn.i_format.opcode) { | ||
| 16 | /* | ||
| 17 | * jr and jalr are in r_format format. | ||
| 18 | */ | ||
| 19 | case spec_op: | ||
| 20 | switch (insn.r_format.func) { | ||
| 21 | case jalr_op: | ||
| 22 | case jr_op: | ||
| 23 | return 1; | ||
| 24 | } | ||
| 25 | break; | ||
| 26 | |||
| 27 | /* | ||
| 28 | * This group contains: | ||
| 29 | * bltz_op, bgez_op, bltzl_op, bgezl_op, | ||
| 30 | * bltzal_op, bgezal_op, bltzall_op, bgezall_op. | ||
| 31 | */ | ||
| 32 | case bcond_op: | ||
| 33 | switch (insn.i_format.rt) { | ||
| 34 | case bltz_op: | ||
| 35 | case bltzl_op: | ||
| 36 | case bgez_op: | ||
| 37 | case bgezl_op: | ||
| 38 | case bltzal_op: | ||
| 39 | case bltzall_op: | ||
| 40 | case bgezal_op: | ||
| 41 | case bgezall_op: | ||
| 42 | case bposge32_op: | ||
| 43 | return 1; | ||
| 44 | } | ||
| 45 | break; | ||
| 46 | |||
| 47 | /* | ||
| 48 | * These are unconditional and in j_format. | ||
| 49 | */ | ||
| 50 | case jal_op: | ||
| 51 | case j_op: | ||
| 52 | case beq_op: | ||
| 53 | case beql_op: | ||
| 54 | case bne_op: | ||
| 55 | case bnel_op: | ||
| 56 | case blez_op: /* not really i_format */ | ||
| 57 | case blezl_op: | ||
| 58 | case bgtz_op: | ||
| 59 | case bgtzl_op: | ||
| 60 | return 1; | ||
| 61 | |||
| 62 | /* | ||
| 63 | * And now the FPA/cp1 branch instructions. | ||
| 64 | */ | ||
| 65 | case cop1_op: | ||
| 66 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | ||
| 67 | case lwc2_op: /* This is bbit0 on Octeon */ | ||
| 68 | case ldc2_op: /* This is bbit032 on Octeon */ | ||
| 69 | case swc2_op: /* This is bbit1 on Octeon */ | ||
| 70 | case sdc2_op: /* This is bbit132 on Octeon */ | ||
| 71 | #endif | ||
| 72 | return 1; | ||
| 73 | } | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | /** | ||
| 79 | * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. | ||
| 80 | * @mm: the probed address space. | ||
| 81 | * @arch_uprobe: the probepoint information. | ||
| 82 | * @addr: virtual address at which to install the probepoint | ||
| 83 | * Return 0 on success or a -ve number on error. | ||
| 84 | */ | ||
| 85 | int arch_uprobe_analyze_insn(struct arch_uprobe *aup, | ||
| 86 | struct mm_struct *mm, unsigned long addr) | ||
| 87 | { | ||
| 88 | union mips_instruction inst; | ||
| 89 | |||
| 90 | /* | ||
| 91 | * For the time being this also blocks attempts to use uprobes with | ||
| 92 | * MIPS16 and microMIPS. | ||
| 93 | */ | ||
| 94 | if (addr & 0x03) | ||
| 95 | return -EINVAL; | ||
| 96 | |||
| 97 | inst.word = aup->insn[0]; | ||
| 98 | aup->ixol[0] = aup->insn[insn_has_delay_slot(inst)]; | ||
| 99 | aup->ixol[1] = UPROBE_BRK_UPROBE_XOL; /* NOP */ | ||
| 100 | |||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * is_trap_insn - check if the instruction is a trap variant | ||
| 106 | * @insn: instruction to be checked. | ||
| 107 | * Returns true if @insn is a trap variant. | ||
| 108 | * | ||
| 109 | * This definition overrides the weak definition in kernel/events/uprobes.c. | ||
| 110 | * and is needed for the case where an architecture has multiple trap | ||
| 111 | * instructions (like PowerPC or MIPS). We treat BREAK just like the more | ||
| 112 | * modern conditional trap instructions. | ||
| 113 | */ | ||
| 114 | bool is_trap_insn(uprobe_opcode_t *insn) | ||
| 115 | { | ||
| 116 | union mips_instruction inst; | ||
| 117 | |||
| 118 | inst.word = *insn; | ||
| 119 | |||
| 120 | switch (inst.i_format.opcode) { | ||
| 121 | case spec_op: | ||
| 122 | switch (inst.r_format.func) { | ||
| 123 | case break_op: | ||
| 124 | case teq_op: | ||
| 125 | case tge_op: | ||
| 126 | case tgeu_op: | ||
| 127 | case tlt_op: | ||
| 128 | case tltu_op: | ||
| 129 | case tne_op: | ||
| 130 | return 1; | ||
| 131 | } | ||
| 132 | break; | ||
| 133 | |||
| 134 | case bcond_op: /* Yes, really ... */ | ||
| 135 | switch (inst.u_format.rt) { | ||
| 136 | case teqi_op: | ||
| 137 | case tgei_op: | ||
| 138 | case tgeiu_op: | ||
| 139 | case tlti_op: | ||
| 140 | case tltiu_op: | ||
| 141 | case tnei_op: | ||
| 142 | return 1; | ||
| 143 | } | ||
| 144 | break; | ||
| 145 | } | ||
| 146 | |||
| 147 | return 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | #define UPROBE_TRAP_NR ULONG_MAX | ||
| 151 | |||
| 152 | /* | ||
| 153 | * arch_uprobe_pre_xol - prepare to execute out of line. | ||
| 154 | * @auprobe: the probepoint information. | ||
| 155 | * @regs: reflects the saved user state of current task. | ||
| 156 | */ | ||
| 157 | int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs) | ||
| 158 | { | ||
| 159 | struct uprobe_task *utask = current->utask; | ||
| 160 | union mips_instruction insn; | ||
| 161 | |||
| 162 | /* | ||
| 163 | * Now find the EPC where to resume after the breakpoint has been | ||
| 164 | * dealt with. This may require emulation of a branch. | ||
| 165 | */ | ||
| 166 | aup->resume_epc = regs->cp0_epc + 4; | ||
| 167 | if (insn_has_delay_slot((union mips_instruction) aup->insn[0])) { | ||
| 168 | unsigned long epc; | ||
| 169 | |||
| 170 | epc = regs->cp0_epc; | ||
| 171 | __compute_return_epc_for_insn(regs, insn); | ||
| 172 | aup->resume_epc = regs->cp0_epc; | ||
| 173 | } | ||
| 174 | |||
| 175 | utask->autask.saved_trap_nr = current->thread.trap_nr; | ||
| 176 | current->thread.trap_nr = UPROBE_TRAP_NR; | ||
| 177 | regs->cp0_epc = current->utask->xol_vaddr; | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs) | ||
| 183 | { | ||
| 184 | struct uprobe_task *utask = current->utask; | ||
| 185 | |||
| 186 | current->thread.trap_nr = utask->autask.saved_trap_nr; | ||
| 187 | regs->cp0_epc = aup->resume_epc; | ||
| 188 | |||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | /* | ||
| 193 | * If xol insn itself traps and generates a signal(Say, | ||
| 194 | * SIGILL/SIGSEGV/etc), then detect the case where a singlestepped | ||
| 195 | * instruction jumps back to its own address. It is assumed that anything | ||
| 196 | * like do_page_fault/do_trap/etc sets thread.trap_nr != -1. | ||
| 197 | * | ||
| 198 | * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr, | ||
| 199 | * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to | ||
| 200 | * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol(). | ||
| 201 | */ | ||
| 202 | bool arch_uprobe_xol_was_trapped(struct task_struct *tsk) | ||
| 203 | { | ||
| 204 | if (tsk->thread.trap_nr != UPROBE_TRAP_NR) | ||
| 205 | return true; | ||
| 206 | |||
| 207 | return false; | ||
| 208 | } | ||
| 209 | |||
| 210 | int arch_uprobe_exception_notify(struct notifier_block *self, | ||
| 211 | unsigned long val, void *data) | ||
| 212 | { | ||
| 213 | struct die_args *args = data; | ||
| 214 | struct pt_regs *regs = args->regs; | ||
| 215 | |||
| 216 | /* regs == NULL is a kernel bug */ | ||
| 217 | if (WARN_ON(!regs)) | ||
| 218 | return NOTIFY_DONE; | ||
| 219 | |||
| 220 | /* We are only interested in userspace traps */ | ||
| 221 | if (!user_mode(regs)) | ||
| 222 | return NOTIFY_DONE; | ||
| 223 | |||
| 224 | switch (val) { | ||
| 225 | case DIE_BREAK: | ||
| 226 | if (uprobe_pre_sstep_notifier(regs)) | ||
| 227 | return NOTIFY_STOP; | ||
| 228 | break; | ||
| 229 | case DIE_UPROBE_XOL: | ||
| 230 | if (uprobe_post_sstep_notifier(regs)) | ||
| 231 | return NOTIFY_STOP; | ||
| 232 | default: | ||
| 233 | break; | ||
| 234 | } | ||
| 235 | |||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | /* | ||
| 240 | * This function gets called when XOL instruction either gets trapped or | ||
| 241 | * the thread has a fatal signal. Reset the instruction pointer to its | ||
| 242 | * probed address for the potential restart or for post mortem analysis. | ||
| 243 | */ | ||
| 244 | void arch_uprobe_abort_xol(struct arch_uprobe *aup, | ||
| 245 | struct pt_regs *regs) | ||
| 246 | { | ||
| 247 | struct uprobe_task *utask = current->utask; | ||
| 248 | |||
| 249 | instruction_pointer_set(regs, utask->vaddr); | ||
| 250 | } | ||
| 251 | |||
| 252 | unsigned long arch_uretprobe_hijack_return_addr( | ||
| 253 | unsigned long trampoline_vaddr, struct pt_regs *regs) | ||
| 254 | { | ||
| 255 | unsigned long ra; | ||
| 256 | |||
| 257 | ra = regs->regs[31]; | ||
| 258 | |||
| 259 | /* Replace the return address with the trampoline address */ | ||
| 260 | regs->regs[31] = ra; | ||
| 261 | |||
| 262 | return ra; | ||
| 263 | } | ||
| 264 | |||
| 265 | /** | ||
| 266 | * set_swbp - store breakpoint at a given address. | ||
| 267 | * @auprobe: arch specific probepoint information. | ||
| 268 | * @mm: the probed process address space. | ||
| 269 | * @vaddr: the virtual address to insert the opcode. | ||
| 270 | * | ||
| 271 | * For mm @mm, store the breakpoint instruction at @vaddr. | ||
| 272 | * Return 0 (success) or a negative errno. | ||
| 273 | * | ||
| 274 | * This version overrides the weak version in kernel/events/uprobes.c. | ||
| 275 | * It is required to handle MIPS16 and microMIPS. | ||
| 276 | */ | ||
| 277 | int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, | ||
| 278 | unsigned long vaddr) | ||
| 279 | { | ||
| 280 | return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN); | ||
| 281 | } | ||
| 282 | |||
| 283 | /** | ||
| 284 | * set_orig_insn - Restore the original instruction. | ||
| 285 | * @mm: the probed process address space. | ||
| 286 | * @auprobe: arch specific probepoint information. | ||
| 287 | * @vaddr: the virtual address to insert the opcode. | ||
| 288 | * | ||
| 289 | * For mm @mm, restore the original opcode (opcode) at @vaddr. | ||
| 290 | * Return 0 (success) or a negative errno. | ||
| 291 | * | ||
| 292 | * This overrides the weak version in kernel/events/uprobes.c. | ||
| 293 | */ | ||
| 294 | int set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | ||
| 295 | unsigned long vaddr) | ||
| 296 | { | ||
| 297 | return uprobe_write_opcode(mm, vaddr, | ||
| 298 | *(uprobe_opcode_t *)&auprobe->orig_inst[0].word); | ||
| 299 | } | ||
| 300 | |||
| 301 | void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, | ||
| 302 | void *src, unsigned long len) | ||
| 303 | { | ||
| 304 | void *kaddr; | ||
| 305 | |||
| 306 | /* Initialize the slot */ | ||
| 307 | kaddr = kmap_atomic(page); | ||
| 308 | memcpy(kaddr + (vaddr & ~PAGE_MASK), src, len); | ||
| 309 | kunmap_atomic(kaddr); | ||
| 310 | |||
| 311 | /* | ||
| 312 | * The MIPS version of flush_icache_range will operate safely on | ||
| 313 | * user space addresses and more importantly, it doesn't require a | ||
| 314 | * VMA argument. | ||
| 315 | */ | ||
| 316 | flush_icache_range(vaddr, vaddr + len); | ||
| 317 | } | ||
| 318 | |||
| 319 | /** | ||
| 320 | * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs | ||
| 321 | * @regs: Reflects the saved state of the task after it has hit a breakpoint | ||
| 322 | * instruction. | ||
| 323 | * Return the address of the breakpoint instruction. | ||
| 324 | * | ||
| 325 | * This overrides the weak version in kernel/events/uprobes.c. | ||
| 326 | */ | ||
| 327 | unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) | ||
| 328 | { | ||
| 329 | return instruction_pointer(regs); | ||
| 330 | } | ||
| 331 | |||
| 332 | /* | ||
| 333 | * See if the instruction can be emulated. | ||
| 334 | * Returns true if instruction was emulated, false otherwise. | ||
| 335 | * | ||
| 336 | * For now we always emulate so this function just returns 0. | ||
| 337 | */ | ||
| 338 | bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | ||
| 339 | { | ||
| 340 | return 0; | ||
| 341 | } | ||
| @@ -817,6 +817,7 @@ static int vpe_open(struct inode *inode, struct file *filp) · 816 unmodified lines | |||
| 817 | 817 | ||
| 818 | static int vpe_release(struct inode *inode, struct file *filp) | 818 | static int vpe_release(struct inode *inode, struct file *filp) |
| 819 | { | 819 | { |
| 820 | #if defined(CONFIG_MIPS_VPE_LOADER_MT) || defined(CONFIG_MIPS_VPE_LOADER_CMP) | ||
| 820 | struct vpe *v; | 821 | struct vpe *v; |
| 821 | Elf_Ehdr *hdr; | 822 | Elf_Ehdr *hdr; |
| 822 | int ret = 0; | 823 | int ret = 0; |
| @@ -827,7 +828,7 @@ static int vpe_release(struct inode *inode, struct file *filp) · 4 unmodified lines | |||
| 827 | 828 | ||
| 828 | hdr = (Elf_Ehdr *) v->pbuffer; | 829 | hdr = (Elf_Ehdr *) v->pbuffer; |
| 829 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) { | 830 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) { |
| 830 | if ((vpe_elfload(v) >= 0) && vpe_run) { | 831 | if (vpe_elfload(v) >= 0) { |
| 831 | vpe_run(v); | 832 | vpe_run(v); |
| 832 | } else { | 833 | } else { |
| 833 | pr_warn("VPE loader: ELF load failed.\n"); | 834 | pr_warn("VPE loader: ELF load failed.\n"); |
| @@ -850,6 +851,10 @@ static int vpe_release(struct inode *inode, struct file *filp) · 16 unmodified lines | |||
| 850 | v->plen = 0; | 851 | v->plen = 0; |
| 851 | 852 | ||
| 852 | return ret; | 853 | return ret; |
| 854 | #else | ||
| 855 | pr_warn("VPE loader: ELF load failed.\n"); | ||
| 856 | return -ENOEXEC; | ||
| 857 | #endif | ||
| 853 | } | 858 | } |
| 854 | 859 | ||
| 855 | static ssize_t vpe_write(struct file *file, const char __user *buffer, | 860 | static ssize_t vpe_write(struct file *file, const char __user *buffer, |
| @@ -270,4 +270,4 @@ static int __init lasat_register_sysctl(void) · 269 unmodified lines | |||
| 270 | return 0; | 270 | return 0; |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | __initcall(lasat_register_sysctl); | 273 | arch_initcall(lasat_register_sysctl); |
| @@ -13,6 +13,33 @@ · 12 unmodified lines | |||
| 13 | #include <asm/pgtable.h> | 13 | #include <asm/pgtable.h> |
| 14 | #include <asm/tlbdebug.h> | 14 | #include <asm/tlbdebug.h> |
| 15 | 15 | ||
| 16 | void dump_tlb_regs(void) | ||
| 17 | { | ||
| 18 | const int field = 2 * sizeof(unsigned long); | ||
| 19 | |||
| 20 | pr_info("Index : %0x\n", read_c0_index()); | ||
| 21 | pr_info("PageMask : %0x\n", read_c0_pagemask()); | ||
| 22 | pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi()); | ||
| 23 | pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); | ||
| 24 | pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); | ||
| 25 | pr_info("Wired : %0x\n", read_c0_wired()); | ||
| 26 | switch (current_cpu_type()) { | ||
| 27 | case CPU_R10000: | ||
| 28 | case CPU_R12000: | ||
| 29 | case CPU_R14000: | ||
| 30 | case CPU_R16000: | ||
| 31 | pr_info("FrameMask: %0x\n", read_c0_framemask()); | ||
| 32 | break; | ||
| 33 | } | ||
| 34 | if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa) | ||
| 35 | pr_info("PageGrain: %0x\n", read_c0_pagegrain()); | ||
| 36 | if (cpu_has_htw) { | ||
| 37 | pr_info("PWField : %0*lx\n", field, read_c0_pwfield()); | ||
| 38 | pr_info("PWSize : %0*lx\n", field, read_c0_pwsize()); | ||
| 39 | pr_info("PWCtl : %0x\n", read_c0_pwctl()); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 16 | static inline const char *msk2str(unsigned int mask) | 43 | static inline const char *msk2str(unsigned int mask) |
| 17 | { | 44 | { |
| 18 | switch (mask) { | 45 | switch (mask) { |
| @@ -87,7 +114,7 @@ static void dump_tlb(int first, int last) · 68 unmodified lines | |||
| 87 | * leave only a single G bit set after a machine check exception | 114 | * leave only a single G bit set after a machine check exception |
| 88 | * due to duplicate TLB entry. | 115 | * due to duplicate TLB entry. |
| 89 | */ | 116 | */ |
| 90 | if (!((entrylo0 | entrylo1) & MIPS_ENTRYLO_G) && | 117 | if (!((entrylo0 | entrylo1) & ENTRYLO_G) && |
| 91 | (entryhi & 0xff) != asid) | 118 | (entryhi & 0xff) != asid) |
| 92 | continue; | 119 | continue; |
| 93 | 120 | ||
| @@ -96,8 +123,8 @@ static void dump_tlb(int first, int last) · 2 unmodified lines | |||
| 96 | */ | 123 | */ |
| 97 | printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); | 124 | printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); |
| 98 | 125 | ||
| 99 | c0 = (entrylo0 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; | 126 | c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; |
| 100 | c1 = (entrylo1 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; | 127 | c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; |
| 101 | 128 | ||
| 102 | printk("va=%0*lx asid=%02lx\n", | 129 | printk("va=%0*lx asid=%02lx\n", |
| 103 | vwidth, (entryhi & ~0x1fffUL), | 130 | vwidth, (entryhi & ~0x1fffUL), |
| @@ -114,9 +141,9 @@ static void dump_tlb(int first, int last) · 10 unmodified lines | |||
| 114 | (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); | 141 | (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); |
| 115 | printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", | 142 | printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", |
| 116 | pwidth, pa, c0, | 143 | pwidth, pa, c0, |
| 117 | (entrylo0 & MIPS_ENTRYLO_D) ? 1 : 0, | 144 | (entrylo0 & ENTRYLO_D) ? 1 : 0, |
| 118 | (entrylo0 & MIPS_ENTRYLO_V) ? 1 : 0, | 145 | (entrylo0 & ENTRYLO_V) ? 1 : 0, |
| 119 | (entrylo0 & MIPS_ENTRYLO_G) ? 1 : 0); | 146 | (entrylo0 & ENTRYLO_G) ? 1 : 0); |
| 120 | /* RI/XI are in awkward places, so mask them off separately */ | 147 | /* RI/XI are in awkward places, so mask them off separately */ |
| 121 | pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); | 148 | pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); |
| 122 | if (xpa) | 149 | if (xpa) |
| @@ -128,9 +155,9 @@ static void dump_tlb(int first, int last) · 5 unmodified lines | |||
| 128 | (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); | 155 | (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); |
| 129 | printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", | 156 | printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", |
| 130 | pwidth, pa, c1, | 157 | pwidth, pa, c1, |
| 131 | (entrylo1 & MIPS_ENTRYLO_D) ? 1 : 0, | 158 | (entrylo1 & ENTRYLO_D) ? 1 : 0, |
| 132 | (entrylo1 & MIPS_ENTRYLO_V) ? 1 : 0, | 159 | (entrylo1 & ENTRYLO_V) ? 1 : 0, |
| 133 | (entrylo1 & MIPS_ENTRYLO_G) ? 1 : 0); | 160 | (entrylo1 & ENTRYLO_G) ? 1 : 0); |
| 134 | } | 161 | } |
| 135 | printk("\n"); | 162 | printk("\n"); |
| 136 | 163 | ||
| @@ -14,6 +14,17 @@ · 13 unmodified lines | |||
| 14 | #include <asm/pgtable.h> | 14 | #include <asm/pgtable.h> |
| 15 | #include <asm/tlbdebug.h> | 15 | #include <asm/tlbdebug.h> |
| 16 | 16 | ||
| 17 | extern int r3k_have_wired_reg; | ||
| 18 | |||
| 19 | void dump_tlb_regs(void) | ||
| 20 | { | ||
| 21 | pr_info("Index : %0x\n", read_c0_index()); | ||
| 22 | pr_info("EntryHi : %0lx\n", read_c0_entryhi()); | ||
| 23 | pr_info("EntryLo : %0lx\n", read_c0_entrylo0()); | ||
| 24 | if (r3k_have_wired_reg) | ||
| 25 | pr_info("Wired : %0x\n", read_c0_wired()); | ||
| 26 | } | ||
| 27 | |||
| 17 | static void dump_tlb(int first, int last) | 28 | static void dump_tlb(int first, int last) |
| 18 | { | 29 | { |
| 19 | int i; | 30 | int i; |
| @@ -126,26 +126,34 @@ static irqreturn_t ls1x_clockevent_isr(int irq, void *devid) · 125 unmodified lines | |||
| 126 | return IRQ_HANDLED; | 126 | return IRQ_HANDLED; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | static void ls1x_clockevent_set_mode(enum clock_event_mode mode, | 129 | static int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) |
| 130 | struct clock_event_device *cd) | ||
| 131 | { | 130 | { |
| 132 | raw_spin_lock(&ls1x_timer_lock); | 131 | raw_spin_lock(&ls1x_timer_lock); |
| 133 | switch (mode) { | 132 | ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); |
| 134 | case CLOCK_EVT_MODE_PERIODIC: | 133 | ls1x_pwmtimer_restart(); |
| 135 | ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); | 134 | __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); |
| 136 | ls1x_pwmtimer_restart(); | ||
| 137 | case CLOCK_EVT_MODE_RESUME: | ||
| 138 | __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); | ||
| 139 | break; | ||
| 140 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 141 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 142 | __raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN, | ||
| 143 | timer_base + PWM_CTRL); | ||
| 144 | break; | ||
| 145 | default: | ||
| 146 | break; | ||
| 147 | } | ||
| 148 | raw_spin_unlock(&ls1x_timer_lock); | 135 | raw_spin_unlock(&ls1x_timer_lock); |
| 136 | |||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int ls1x_clockevent_tick_resume(struct clock_event_device *cd) | ||
| 141 | { | ||
| 142 | raw_spin_lock(&ls1x_timer_lock); | ||
| 143 | __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); | ||
| 144 | raw_spin_unlock(&ls1x_timer_lock); | ||
| 145 | |||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | static int ls1x_clockevent_set_state_shutdown(struct clock_event_device *cd) | ||
| 150 | { | ||
| 151 | raw_spin_lock(&ls1x_timer_lock); | ||
| 152 | __raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN, | ||
| 153 | timer_base + PWM_CTRL); | ||
| 154 | raw_spin_unlock(&ls1x_timer_lock); | ||
| 155 | |||
| 156 | return 0; | ||
| 149 | } | 157 | } |
| 150 | 158 | ||
| 151 | static int ls1x_clockevent_set_next(unsigned long evt, | 159 | static int ls1x_clockevent_set_next(unsigned long evt, |
| @@ -160,12 +168,15 @@ static int ls1x_clockevent_set_next(unsigned long evt, · 8 unmodified lines | |||
| 160 | } | 168 | } |
| 161 | 169 | ||
| 162 | static struct clock_event_device ls1x_clockevent = { | 170 | static struct clock_event_device ls1x_clockevent = { |
| 163 | .name = "ls1x-pwmtimer", | 171 | .name = "ls1x-pwmtimer", |
| 164 | .features = CLOCK_EVT_FEAT_PERIODIC, | 172 | .features = CLOCK_EVT_FEAT_PERIODIC, |
| 165 | .rating = 300, | 173 | .rating = 300, |
| 166 | .irq = LS1X_TIMER_IRQ, | 174 | .irq = LS1X_TIMER_IRQ, |
| 167 | .set_next_event = ls1x_clockevent_set_next, | 175 | .set_next_event = ls1x_clockevent_set_next, |
| 168 | .set_mode = ls1x_clockevent_set_mode, | 176 | .set_state_shutdown = ls1x_clockevent_set_state_shutdown, |
| 177 | .set_state_periodic = ls1x_clockevent_set_state_periodic, | ||
| 178 | .set_state_oneshot = ls1x_clockevent_set_state_shutdown, | ||
| 179 | .tick_resume = ls1x_clockevent_tick_resume, | ||
| 169 | }; | 180 | }; |
| 170 | 181 | ||
| 171 | static struct irqaction ls1x_pwmtimer_irqaction = { | 182 | static struct irqaction ls1x_pwmtimer_irqaction = { |
| @@ -51,40 +51,36 @@ void enable_mfgpt0_counter(void) · 50 unmodified lines | |||
| 51 | } | 51 | } |
| 52 | EXPORT_SYMBOL(enable_mfgpt0_counter); | 52 | EXPORT_SYMBOL(enable_mfgpt0_counter); |
| 53 | 53 | ||
| 54 | static void init_mfgpt_timer(enum clock_event_mode mode, | 54 | static int mfgpt_timer_set_periodic(struct clock_event_device *evt) |
| 55 | struct clock_event_device *evt) | ||
| 56 | { | 55 | { |
| 57 | raw_spin_lock(&mfgpt_lock); | 56 | raw_spin_lock(&mfgpt_lock); |
| 58 | 57 | ||
| 59 | switch (mode) { | 58 | outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */ |
| 60 | case CLOCK_EVT_MODE_PERIODIC: | 59 | outw(0, MFGPT0_CNT); /* set counter to 0 */ |
| 61 | outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */ | 60 | enable_mfgpt0_counter(); |
| 62 | outw(0, MFGPT0_CNT); /* set counter to 0 */ | 61 | |
| 63 | enable_mfgpt0_counter(); | ||
| 64 | break; | ||
| 65 | |||
| 66 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 67 | case CLOCK_EVT_MODE_UNUSED: | ||
| 68 | if (evt->mode == CLOCK_EVT_MODE_PERIODIC || | ||
| 69 | evt->mode == CLOCK_EVT_MODE_ONESHOT) | ||
| 70 | disable_mfgpt0_counter(); | ||
| 71 | break; | ||
| 72 | |||
| 73 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 74 | /* The oneshot mode have very high deviation, Not use it! */ | ||
| 75 | break; | ||
| 76 | |||
| 77 | case CLOCK_EVT_MODE_RESUME: | ||
| 78 | /* Nothing to do here */ | ||
| 79 | break; | ||
| 80 | } | ||
| 81 | raw_spin_unlock(&mfgpt_lock); | 62 | raw_spin_unlock(&mfgpt_lock); |
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static int mfgpt_timer_shutdown(struct clock_event_device *evt) | ||
| 67 | { | ||
| 68 | if (clockevent_state_periodic(evt) || clockevent_state_oneshot(evt)) { | ||
| 69 | raw_spin_lock(&mfgpt_lock); | ||
| 70 | disable_mfgpt0_counter(); | ||
| 71 | raw_spin_unlock(&mfgpt_lock); | ||
| 72 | } | ||
| 73 | |||
| 74 | return 0; | ||
| 82 | } | 75 | } |
| 83 | 76 | ||
| 84 | static struct clock_event_device mfgpt_clockevent = { | 77 | static struct clock_event_device mfgpt_clockevent = { |
| 85 | .name = "mfgpt", | 78 | .name = "mfgpt", |
| 86 | .features = CLOCK_EVT_FEAT_PERIODIC, | 79 | .features = CLOCK_EVT_FEAT_PERIODIC, |
| 87 | .set_mode = init_mfgpt_timer, | 80 | |
| 81 | /* The oneshot mode have very high deviation, don't use it! */ | ||
| 82 | .set_state_shutdown = mfgpt_timer_shutdown, | ||
| 83 | .set_state_periodic = mfgpt_timer_set_periodic, | ||
| 88 | .irq = CS5536_MFGPT_INTR, | 84 | .irq = CS5536_MFGPT_INTR, |
| 89 | }; | 85 | }; |
| 90 | 86 | ||
| @@ -78,55 +78,77 @@ static void hpet_enable_legacy_int(void) · 77 unmodified lines | |||
| 78 | /* Do nothing on Loongson-3 */ | 78 | /* Do nothing on Loongson-3 */ |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static void hpet_set_mode(enum clock_event_mode mode, | 81 | static int hpet_set_state_periodic(struct clock_event_device *evt) |
| 82 | struct clock_event_device *evt) | ||
| 83 | { | 82 | { |
| 84 | int cfg = 0; | 83 | int cfg; |
| 85 | 84 | ||
| 86 | spin_lock(&hpet_lock); | 85 | spin_lock(&hpet_lock); |
| 87 | switch (mode) { | 86 | |
| 88 | case CLOCK_EVT_MODE_PERIODIC: | 87 | pr_info("set clock event to periodic mode!\n"); |
| 89 | pr_info("set clock event to periodic mode!\n"); | 88 | /* stop counter */ |
| 90 | /* stop counter */ | 89 | hpet_stop_counter(); |
| 91 | hpet_stop_counter(); | 90 | |
| 92 | 91 | /* enables the timer0 to generate a periodic interrupt */ | |
| 93 | /* enables the timer0 to generate a periodic interrupt */ | 92 | cfg = hpet_read(HPET_T0_CFG); |
| 94 | cfg = hpet_read(HPET_T0_CFG); | 93 | cfg &= ~HPET_TN_LEVEL; |
| 95 | cfg &= ~HPET_TN_LEVEL; | 94 | cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | |
| 96 | cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | | 95 | HPET_TN_32BIT; |
| 97 | HPET_TN_SETVAL | HPET_TN_32BIT; | 96 | hpet_write(HPET_T0_CFG, cfg); |
| 98 | hpet_write(HPET_T0_CFG, cfg); | 97 | |
| 99 | 98 | /* set the comparator */ | |
| 100 | /* set the comparator */ | 99 | hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); |
| 101 | hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); | 100 | udelay(1); |
| 102 | udelay(1); | 101 | hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); |
| 103 | hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); | 102 | |
| 104 | 103 | /* start counter */ | |
| 105 | /* start counter */ | 104 | hpet_start_counter(); |
| 106 | hpet_start_counter(); | 105 | |
| 107 | break; | 106 | spin_unlock(&hpet_lock); |
| 108 | case CLOCK_EVT_MODE_SHUTDOWN: | 107 | return 0; |
| 109 | case CLOCK_EVT_MODE_UNUSED: | 108 | } |
| 110 | cfg = hpet_read(HPET_T0_CFG); | 109 | |
| 111 | cfg &= ~HPET_TN_ENABLE; | 110 | static int hpet_set_state_shutdown(struct clock_event_device *evt) |
| 112 | hpet_write(HPET_T0_CFG, cfg); | 111 | { |
| 113 | break; | 112 | int cfg; |
| 114 | case CLOCK_EVT_MODE_ONESHOT: | 113 | |
| 115 | pr_info("set clock event to one shot mode!\n"); | 114 | spin_lock(&hpet_lock); |
| 116 | cfg = hpet_read(HPET_T0_CFG); | 115 | |
| 117 | /* set timer0 type | 116 | cfg = hpet_read(HPET_T0_CFG); |
| 118 | * 1 : periodic interrupt | 117 | cfg &= ~HPET_TN_ENABLE; |
| 119 | * 0 : non-periodic(oneshot) interrupt | 118 | hpet_write(HPET_T0_CFG, cfg); |
| 120 | */ | 119 | |
| 121 | cfg &= ~HPET_TN_PERIODIC; | ||
| 122 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; | ||
| 123 | hpet_write(HPET_T0_CFG, cfg); | ||
| 124 | break; | ||
| 125 | case CLOCK_EVT_MODE_RESUME: | ||
| 126 | hpet_enable_legacy_int(); | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | spin_unlock(&hpet_lock); | 120 | spin_unlock(&hpet_lock); |
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | static int hpet_set_state_oneshot(struct clock_event_device *evt) | ||
| 125 | { | ||
| 126 | int cfg; | ||
| 127 | |||
| 128 | spin_lock(&hpet_lock); | ||
| 129 | |||
| 130 | pr_info("set clock event to one shot mode!\n"); | ||
| 131 | cfg = hpet_read(HPET_T0_CFG); | ||
| 132 | /* | ||
| 133 | * set timer0 type | ||
| 134 | * 1 : periodic interrupt | ||
| 135 | * 0 : non-periodic(oneshot) interrupt | ||
| 136 | */ | ||
| 137 | cfg &= ~HPET_TN_PERIODIC; | ||
| 138 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; | ||
| 139 | hpet_write(HPET_T0_CFG, cfg); | ||
| 140 | |||
| 141 | spin_unlock(&hpet_lock); | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | static int hpet_tick_resume(struct clock_event_device *evt) | ||
| 146 | { | ||
| 147 | spin_lock(&hpet_lock); | ||
| 148 | hpet_enable_legacy_int(); | ||
| 149 | spin_unlock(&hpet_lock); | ||
| 150 | |||
| 151 | return 0; | ||
| 130 | } | 152 | } |
| 131 | 153 | ||
| 132 | static int hpet_next_event(unsigned long delta, | 154 | static int hpet_next_event(unsigned long delta, |
| @@ -206,7 +228,10 @@ void __init setup_hpet_timer(void) · 73 unmodified lines | |||
| 206 | cd->name = "hpet"; | 228 | cd->name = "hpet"; |
| 207 | cd->rating = 320; | 229 | cd->rating = 320; |
| 208 | cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | 230 | cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; |
| 209 | cd->set_mode = hpet_set_mode; | 231 | cd->set_state_shutdown = hpet_set_state_shutdown; |
| 232 | cd->set_state_periodic = hpet_set_state_periodic; | ||
| 233 | cd->set_state_oneshot = hpet_set_state_oneshot; | ||
| 234 | cd->tick_resume = hpet_tick_resume; | ||
| 210 | cd->set_next_event = hpet_next_event; | 235 | cd->set_next_event = hpet_next_event; |
| 211 | cd->irq = HPET_T0_IRQ; | 236 | cd->irq = HPET_T0_IRQ; |
| 212 | cd->cpumask = cpumask_of(cpu); | 237 | cd->cpumask = cpumask_of(cpu); |
| @@ -4,9 +4,9 @@ · 3 unmodified lines | |||
| 4 | 4 | ||
| 5 | obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ | 5 | obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ |
| 6 | dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ | 6 | dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ |
| 7 | dp_tint.o dp_fint.o \ | 7 | dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o dp_fmax.o \ |
| 8 | sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ | 8 | sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ |
| 9 | sp_tint.o sp_fint.o \ | 9 | sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o sp_fmax.o \ |
| 10 | dsemul.o | 10 | dsemul.o |
| 11 | 11 | ||
| 12 | lib-y += ieee754d.o \ | 12 | lib-y += ieee754d.o \ |
| @@ -1137,7 +1137,7 @@ emul: · 1136 unmodified lines | |||
| 1137 | break; | 1137 | break; |
| 1138 | 1138 | ||
| 1139 | case mfhc_op: | 1139 | case mfhc_op: |
| 1140 | if (!cpu_has_mips_r2) | 1140 | if (!cpu_has_mips_r2_r6) |
| 1141 | goto sigill; | 1141 | goto sigill; |
| 1142 | 1142 | ||
| 1143 | /* copregister rd -> gpr[rt] */ | 1143 | /* copregister rd -> gpr[rt] */ |
| @@ -1148,7 +1148,7 @@ emul: · 4 unmodified lines | |||
| 1148 | break; | 1148 | break; |
| 1149 | 1149 | ||
| 1150 | case mthc_op: | 1150 | case mthc_op: |
| 1151 | if (!cpu_has_mips_r2) | 1151 | if (!cpu_has_mips_r2_r6) |
| 1152 | goto sigill; | 1152 | goto sigill; |
| 1153 | 1153 | ||
| 1154 | /* copregister rd <- gpr[rt] */ | 1154 | /* copregister rd <- gpr[rt] */ |
| @@ -1181,6 +1181,24 @@ emul: · 26 unmodified lines | |||
| 1181 | } | 1181 | } |
| 1182 | break; | 1182 | break; |
| 1183 | 1183 | ||
| 1184 | case bc1eqz_op: | ||
| 1185 | case bc1nez_op: | ||
| 1186 | if (!cpu_has_mips_r6 || delay_slot(xcp)) | ||
| 1187 | return SIGILL; | ||
| 1188 | |||
| 1189 | cond = likely = 0; | ||
| 1190 | switch (MIPSInst_RS(ir)) { | ||
| 1191 | case bc1eqz_op: | ||
| 1192 | if (get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1) | ||
| 1193 | cond = 1; | ||
| 1194 | break; | ||
| 1195 | case bc1nez_op: | ||
| 1196 | if (!(get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)) | ||
| 1197 | cond = 1; | ||
| 1198 | break; | ||
| 1199 | } | ||
| 1200 | goto branch_common; | ||
| 1201 | |||
| 1184 | case bc_op: | 1202 | case bc_op: |
| 1185 | if (delay_slot(xcp)) | 1203 | if (delay_slot(xcp)) |
| 1186 | return SIGILL; | 1204 | return SIGILL; |
| @@ -1207,7 +1225,7 @@ emul: · 20 unmodified lines | |||
| 1207 | case bct_op: | 1225 | case bct_op: |
| 1208 | break; | 1226 | break; |
| 1209 | } | 1227 | } |
| 1210 | 1228 | branch_common: | |
| 1211 | set_delay_slot(xcp); | 1229 | set_delay_slot(xcp); |
| 1212 | if (cond) { | 1230 | if (cond) { |
| 1213 | /* | 1231 | /* |
| @@ -1376,6 +1394,14 @@ static const unsigned char cmptab[8] = { · 162 unmodified lines | |||
| 1376 | IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ | 1394 | IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ |
| 1377 | }; | 1395 | }; |
| 1378 | 1396 | ||
| 1397 | static const unsigned char negative_cmptab[8] = { | ||
| 1398 | 0, /* Reserved */ | ||
| 1399 | IEEE754_CLT | IEEE754_CGT | IEEE754_CEQ, | ||
| 1400 | IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, | ||
| 1401 | IEEE754_CLT | IEEE754_CGT, | ||
| 1402 | /* Reserved */ | ||
| 1403 | }; | ||
| 1404 | |||
| 1379 | 1405 | ||
| 1380 | /* | 1406 | /* |
| 1381 | * Additional MIPS4 instructions | 1407 | * Additional MIPS4 instructions |
| @@ -1717,6 +1743,126 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 335 unmodified lines | |||
| 1717 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | 1743 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
| 1718 | break; | 1744 | break; |
| 1719 | 1745 | ||
| 1746 | case fseleqz_op: | ||
| 1747 | if (!cpu_has_mips_r6) | ||
| 1748 | return SIGILL; | ||
| 1749 | |||
| 1750 | SPFROMREG(rv.s, MIPSInst_FT(ir)); | ||
| 1751 | if (rv.w & 0x1) | ||
| 1752 | rv.w = 0; | ||
| 1753 | else | ||
| 1754 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | ||
| 1755 | break; | ||
| 1756 | |||
| 1757 | case fselnez_op: | ||
| 1758 | if (!cpu_has_mips_r6) | ||
| 1759 | return SIGILL; | ||
| 1760 | |||
| 1761 | SPFROMREG(rv.s, MIPSInst_FT(ir)); | ||
| 1762 | if (rv.w & 0x1) | ||
| 1763 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | ||
| 1764 | else | ||
| 1765 | rv.w = 0; | ||
| 1766 | break; | ||
| 1767 | |||
| 1768 | case fmaddf_op: { | ||
| 1769 | union ieee754sp ft, fs, fd; | ||
| 1770 | |||
| 1771 | if (!cpu_has_mips_r6) | ||
| 1772 | return SIGILL; | ||
| 1773 | |||
| 1774 | SPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 1775 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 1776 | SPFROMREG(fd, MIPSInst_FD(ir)); | ||
| 1777 | rv.s = ieee754sp_maddf(fd, fs, ft); | ||
| 1778 | break; | ||
| 1779 | } | ||
| 1780 | |||
| 1781 | case fmsubf_op: { | ||
| 1782 | union ieee754sp ft, fs, fd; | ||
| 1783 | |||
| 1784 | if (!cpu_has_mips_r6) | ||
| 1785 | return SIGILL; | ||
| 1786 | |||
| 1787 | SPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 1788 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 1789 | SPFROMREG(fd, MIPSInst_FD(ir)); | ||
| 1790 | rv.s = ieee754sp_msubf(fd, fs, ft); | ||
| 1791 | break; | ||
| 1792 | } | ||
| 1793 | |||
| 1794 | case frint_op: { | ||
| 1795 | union ieee754sp fs; | ||
| 1796 | |||
| 1797 | if (!cpu_has_mips_r6) | ||
| 1798 | return SIGILL; | ||
| 1799 | |||
| 1800 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 1801 | rv.l = ieee754sp_tlong(fs); | ||
| 1802 | rv.s = ieee754sp_flong(rv.l); | ||
| 1803 | goto copcsr; | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | case fclass_op: { | ||
| 1807 | union ieee754sp fs; | ||
| 1808 | |||
| 1809 | if (!cpu_has_mips_r6) | ||
| 1810 | return SIGILL; | ||
| 1811 | |||
| 1812 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 1813 | rv.w = ieee754sp_2008class(fs); | ||
| 1814 | rfmt = w_fmt; | ||
| 1815 | break; | ||
| 1816 | } | ||
| 1817 | |||
| 1818 | case fmin_op: { | ||
| 1819 | union ieee754sp fs, ft; | ||
| 1820 | |||
| 1821 | if (!cpu_has_mips_r6) | ||
| 1822 | return SIGILL; | ||
| 1823 | |||
| 1824 | SPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 1825 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 1826 | rv.s = ieee754sp_fmin(fs, ft); | ||
| 1827 | break; | ||
| 1828 | } | ||
| 1829 | |||
| 1830 | case fmina_op: { | ||
| 1831 | union ieee754sp fs, ft; | ||
| 1832 | |||
| 1833 | if (!cpu_has_mips_r6) | ||
| 1834 | return SIGILL; | ||
| 1835 | |||
| 1836 | SPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 1837 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 1838 | rv.s = ieee754sp_fmina(fs, ft); | ||
| 1839 | break; | ||
| 1840 | } | ||
| 1841 | |||
| 1842 | case fmax_op: { | ||
| 1843 | union ieee754sp fs, ft; | ||
| 1844 | |||
| 1845 | if (!cpu_has_mips_r6) | ||
| 1846 | return SIGILL; | ||
| 1847 | |||
| 1848 | SPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 1849 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 1850 | rv.s = ieee754sp_fmax(fs, ft); | ||
| 1851 | break; | ||
| 1852 | } | ||
| 1853 | |||
| 1854 | case fmaxa_op: { | ||
| 1855 | union ieee754sp fs, ft; | ||
| 1856 | |||
| 1857 | if (!cpu_has_mips_r6) | ||
| 1858 | return SIGILL; | ||
| 1859 | |||
| 1860 | SPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 1861 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 1862 | rv.s = ieee754sp_fmaxa(fs, ft); | ||
| 1863 | break; | ||
| 1864 | } | ||
| 1865 | |||
| 1720 | case fabs_op: | 1866 | case fabs_op: |
| 1721 | handler.u = ieee754sp_abs; | 1867 | handler.u = ieee754sp_abs; |
| 1722 | goto scopuop; | 1868 | goto scopuop; |
| @@ -1820,7 +1966,7 @@ copcsr: · 97 unmodified lines | |||
| 1820 | goto copcsr; | 1966 | goto copcsr; |
| 1821 | 1967 | ||
| 1822 | default: | 1968 | default: |
| 1823 | if (MIPSInst_FUNC(ir) >= fcmp_op) { | 1969 | if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { |
| 1824 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; | 1970 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
| 1825 | union ieee754sp fs, ft; | 1971 | union ieee754sp fs, ft; |
| 1826 | 1972 | ||
| @@ -1914,6 +2060,127 @@ copcsr: · 87 unmodified lines | |||
| 1914 | return 0; | 2060 | return 0; |
| 1915 | DPFROMREG(rv.d, MIPSInst_FS(ir)); | 2061 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
| 1916 | break; | 2062 | break; |
| 2063 | |||
| 2064 | case fseleqz_op: | ||
| 2065 | if (!cpu_has_mips_r6) | ||
| 2066 | return SIGILL; | ||
| 2067 | |||
| 2068 | DPFROMREG(rv.d, MIPSInst_FT(ir)); | ||
| 2069 | if (rv.l & 0x1) | ||
| 2070 | rv.l = 0; | ||
| 2071 | else | ||
| 2072 | DPFROMREG(rv.d, MIPSInst_FS(ir)); | ||
| 2073 | break; | ||
| 2074 | |||
| 2075 | case fselnez_op: | ||
| 2076 | if (!cpu_has_mips_r6) | ||
| 2077 | return SIGILL; | ||
| 2078 | |||
| 2079 | DPFROMREG(rv.d, MIPSInst_FT(ir)); | ||
| 2080 | if (rv.l & 0x1) | ||
| 2081 | DPFROMREG(rv.d, MIPSInst_FS(ir)); | ||
| 2082 | else | ||
| 2083 | rv.l = 0; | ||
| 2084 | break; | ||
| 2085 | |||
| 2086 | case fmaddf_op: { | ||
| 2087 | union ieee754dp ft, fs, fd; | ||
| 2088 | |||
| 2089 | if (!cpu_has_mips_r6) | ||
| 2090 | return SIGILL; | ||
| 2091 | |||
| 2092 | DPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 2093 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2094 | DPFROMREG(fd, MIPSInst_FD(ir)); | ||
| 2095 | rv.d = ieee754dp_maddf(fd, fs, ft); | ||
| 2096 | break; | ||
| 2097 | } | ||
| 2098 | |||
| 2099 | case fmsubf_op: { | ||
| 2100 | union ieee754dp ft, fs, fd; | ||
| 2101 | |||
| 2102 | if (!cpu_has_mips_r6) | ||
| 2103 | return SIGILL; | ||
| 2104 | |||
| 2105 | DPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 2106 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2107 | DPFROMREG(fd, MIPSInst_FD(ir)); | ||
| 2108 | rv.d = ieee754dp_msubf(fd, fs, ft); | ||
| 2109 | break; | ||
| 2110 | } | ||
| 2111 | |||
| 2112 | case frint_op: { | ||
| 2113 | union ieee754dp fs; | ||
| 2114 | |||
| 2115 | if (!cpu_has_mips_r6) | ||
| 2116 | return SIGILL; | ||
| 2117 | |||
| 2118 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2119 | rv.l = ieee754dp_tlong(fs); | ||
| 2120 | rv.d = ieee754dp_flong(rv.l); | ||
| 2121 | goto copcsr; | ||
| 2122 | } | ||
| 2123 | |||
| 2124 | case fclass_op: { | ||
| 2125 | union ieee754dp fs; | ||
| 2126 | |||
| 2127 | if (!cpu_has_mips_r6) | ||
| 2128 | return SIGILL; | ||
| 2129 | |||
| 2130 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2131 | rv.w = ieee754dp_2008class(fs); | ||
| 2132 | rfmt = w_fmt; | ||
| 2133 | break; | ||
| 2134 | } | ||
| 2135 | |||
| 2136 | case fmin_op: { | ||
| 2137 | union ieee754dp fs, ft; | ||
| 2138 | |||
| 2139 | if (!cpu_has_mips_r6) | ||
| 2140 | return SIGILL; | ||
| 2141 | |||
| 2142 | DPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 2143 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2144 | rv.d = ieee754dp_fmin(fs, ft); | ||
| 2145 | break; | ||
| 2146 | } | ||
| 2147 | |||
| 2148 | case fmina_op: { | ||
| 2149 | union ieee754dp fs, ft; | ||
| 2150 | |||
| 2151 | if (!cpu_has_mips_r6) | ||
| 2152 | return SIGILL; | ||
| 2153 | |||
| 2154 | DPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 2155 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2156 | rv.d = ieee754dp_fmina(fs, ft); | ||
| 2157 | break; | ||
| 2158 | } | ||
| 2159 | |||
| 2160 | case fmax_op: { | ||
| 2161 | union ieee754dp fs, ft; | ||
| 2162 | |||
| 2163 | if (!cpu_has_mips_r6) | ||
| 2164 | return SIGILL; | ||
| 2165 | |||
| 2166 | DPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 2167 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2168 | rv.d = ieee754dp_fmax(fs, ft); | ||
| 2169 | break; | ||
| 2170 | } | ||
| 2171 | |||
| 2172 | case fmaxa_op: { | ||
| 2173 | union ieee754dp fs, ft; | ||
| 2174 | |||
| 2175 | if (!cpu_has_mips_r6) | ||
| 2176 | return SIGILL; | ||
| 2177 | |||
| 2178 | DPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 2179 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2180 | rv.d = ieee754dp_fmaxa(fs, ft); | ||
| 2181 | break; | ||
| 2182 | } | ||
| 2183 | |||
| 1917 | case fabs_op: | 2184 | case fabs_op: |
| 1918 | handler.u = ieee754dp_abs; | 2185 | handler.u = ieee754dp_abs; |
| 1919 | goto dcopuop; | 2186 | goto dcopuop; |
| @@ -1997,7 +2264,7 @@ dcopuop: · 77 unmodified lines | |||
| 1997 | goto copcsr; | 2264 | goto copcsr; |
| 1998 | 2265 | ||
| 1999 | default: | 2266 | default: |
| 2000 | if (MIPSInst_FUNC(ir) >= fcmp_op) { | 2267 | if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { |
| 2001 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; | 2268 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
| 2002 | union ieee754dp fs, ft; | 2269 | union ieee754dp fs, ft; |
| 2003 | 2270 | ||
| @@ -2021,8 +2288,11 @@ dcopuop: · 17 unmodified lines | |||
| 2021 | break; | 2288 | break; |
| 2022 | } | 2289 | } |
| 2023 | break; | 2290 | break; |
| 2291 | } | ||
| 2292 | |||
| 2293 | case w_fmt: { | ||
| 2294 | union ieee754dp fs; | ||
| 2024 | 2295 | ||
| 2025 | case w_fmt: | ||
| 2026 | switch (MIPSInst_FUNC(ir)) { | 2296 | switch (MIPSInst_FUNC(ir)) { |
| 2027 | case fcvts_op: | 2297 | case fcvts_op: |
| 2028 | /* convert word to single precision real */ | 2298 | /* convert word to single precision real */ |
| @@ -2036,10 +2306,65 @@ dcopuop: · 7 unmodified lines | |||
| 2036 | rv.d = ieee754dp_fint(fs.bits); | 2306 | rv.d = ieee754dp_fint(fs.bits); |
| 2037 | rfmt = d_fmt; | 2307 | rfmt = d_fmt; |
| 2038 | goto copcsr; | 2308 | goto copcsr; |
| 2039 | default: | 2309 | default: { |
| 2040 | return SIGILL; | 2310 | /* Emulating the new CMP.condn.fmt R6 instruction */ |
| 2311 | #define CMPOP_MASK 0x7 | ||
| 2312 | #define SIGN_BIT (0x1 << 3) | ||
| 2313 | #define PREDICATE_BIT (0x1 << 4) | ||
| 2314 | |||
| 2315 | int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK; | ||
| 2316 | int sig = MIPSInst_FUNC(ir) & SIGN_BIT; | ||
| 2317 | union ieee754sp fs, ft; | ||
| 2318 | |||
| 2319 | /* This is an R6 only instruction */ | ||
| 2320 | if (!cpu_has_mips_r6 || | ||
| 2321 | (MIPSInst_FUNC(ir) & 0x20)) | ||
| 2322 | return SIGILL; | ||
| 2323 | |||
| 2324 | /* fmt is w_fmt for single precision so fix it */ | ||
| 2325 | rfmt = s_fmt; | ||
| 2326 | /* default to false */ | ||
| 2327 | rv.w = 0; | ||
| 2328 | |||
| 2329 | /* CMP.condn.S */ | ||
| 2330 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2331 | SPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 2332 | |||
| 2333 | /* positive predicates */ | ||
| 2334 | if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { | ||
| 2335 | if (ieee754sp_cmp(fs, ft, cmptab[cmpop], | ||
| 2336 | sig)) | ||
| 2337 | rv.w = -1; /* true, all 1s */ | ||
| 2338 | if ((sig) && | ||
| 2339 | ieee754_cxtest(IEEE754_INVALID_OPERATION)) | ||
| 2340 | rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; | ||
| 2341 | else | ||
| 2342 | goto copcsr; | ||
| 2343 | } else { | ||
| 2344 | /* negative predicates */ | ||
| 2345 | switch (cmpop) { | ||
| 2346 | case 1: | ||
| 2347 | case 2: | ||
| 2348 | case 3: | ||
| 2349 | if (ieee754sp_cmp(fs, ft, | ||
| 2350 | negative_cmptab[cmpop], | ||
| 2351 | sig)) | ||
| 2352 | rv.w = -1; /* true, all 1s */ | ||
| 2353 | if (sig && | ||
| 2354 | ieee754_cxtest(IEEE754_INVALID_OPERATION)) | ||
| 2355 | rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; | ||
| 2356 | else | ||
| 2357 | goto copcsr; | ||
| 2358 | break; | ||
| 2359 | default: | ||
| 2360 | /* Reserved R6 ops */ | ||
| 2361 | pr_err("Reserved MIPS R6 CMP.condn.S operation\n"); | ||
| 2362 | return SIGILL; | ||
| 2363 | } | ||
| 2364 | } | ||
| 2365 | break; | ||
| 2366 | } | ||
| 2041 | } | 2367 | } |
| 2042 | break; | ||
| 2043 | } | 2368 | } |
| 2044 | 2369 | ||
| 2045 | case l_fmt: | 2370 | case l_fmt: |
| @@ -2060,11 +2385,60 @@ dcopuop: · 14 unmodified lines | |||
| 2060 | rv.d = ieee754dp_flong(bits); | 2385 | rv.d = ieee754dp_flong(bits); |
| 2061 | rfmt = d_fmt; | 2386 | rfmt = d_fmt; |
| 2062 | goto copcsr; | 2387 | goto copcsr; |
| 2063 | default: | 2388 | default: { |
| 2064 | return SIGILL; | 2389 | /* Emulating the new CMP.condn.fmt R6 instruction */ |
| 2065 | } | 2390 | int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK; |
| 2066 | break; | 2391 | int sig = MIPSInst_FUNC(ir) & SIGN_BIT; |
| 2392 | union ieee754dp fs, ft; | ||
| 2393 | |||
| 2394 | if (!cpu_has_mips_r6 || | ||
| 2395 | (MIPSInst_FUNC(ir) & 0x20)) | ||
| 2396 | return SIGILL; | ||
| 2397 | |||
| 2398 | /* fmt is l_fmt for double precision so fix it */ | ||
| 2399 | rfmt = d_fmt; | ||
| 2400 | /* default to false */ | ||
| 2401 | rv.l = 0; | ||
| 2067 | 2402 | ||
| 2403 | /* CMP.condn.D */ | ||
| 2404 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
| 2405 | DPFROMREG(ft, MIPSInst_FT(ir)); | ||
| 2406 | |||
| 2407 | /* positive predicates */ | ||
| 2408 | if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { | ||
| 2409 | if (ieee754dp_cmp(fs, ft, | ||
| 2410 | cmptab[cmpop], sig)) | ||
| 2411 | rv.l = -1LL; /* true, all 1s */ | ||
| 2412 | if (sig && | ||
| 2413 | ieee754_cxtest(IEEE754_INVALID_OPERATION)) | ||
| 2414 | rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; | ||
| 2415 | else | ||
| 2416 | goto copcsr; | ||
| 2417 | } else { | ||
| 2418 | /* negative predicates */ | ||
| 2419 | switch (cmpop) { | ||
| 2420 | case 1: | ||
| 2421 | case 2: | ||
| 2422 | case 3: | ||
| 2423 | if (ieee754dp_cmp(fs, ft, | ||
| 2424 | negative_cmptab[cmpop], | ||
| 2425 | sig)) | ||
| 2426 | rv.l = -1LL; /* true, all 1s */ | ||
| 2427 | if (sig && | ||
| 2428 | ieee754_cxtest(IEEE754_INVALID_OPERATION)) | ||
| 2429 | rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; | ||
| 2430 | else | ||
| 2431 | goto copcsr; | ||
| 2432 | break; | ||
| 2433 | default: | ||
| 2434 | /* Reserved R6 ops */ | ||
| 2435 | pr_err("Reserved MIPS R6 CMP.condn.D operation\n"); | ||
| 2436 | return SIGILL; | ||
| 2437 | } | ||
| 2438 | } | ||
| 2439 | break; | ||
| 2440 | } | ||
| 2441 | } | ||
| 2068 | default: | 2442 | default: |
| 2069 | return SIGILL; | 2443 | return SIGILL; |
| 2070 | } | 2444 | } |
| @@ -0,0 +1,55 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * double precision: CLASS.f | ||
| 4 | * FPR[fd] = class(FPR[fs]) | ||
| 5 | * | ||
| 6 | * MIPS floating point support | ||
| 7 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 8 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can distribute it and/or modify it | ||
| 11 | * under the terms of the GNU General Public License as published by the | ||
| 12 | * Free Software Foundation; version 2 of the License. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include "ieee754dp.h" | ||
| 16 | |||
| 17 | int ieee754dp_2008class(union ieee754dp x) | ||
| 18 | { | ||
| 19 | COMPXDP; | ||
| 20 | |||
| 21 | EXPLODEXDP; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * 10 bit mask as follows: | ||
| 25 | * | ||
| 26 | * bit0 = SNAN | ||
| 27 | * bit1 = QNAN | ||
| 28 | * bit2 = -INF | ||
| 29 | * bit3 = -NORM | ||
| 30 | * bit4 = -DNORM | ||
| 31 | * bit5 = -ZERO | ||
| 32 | * bit6 = INF | ||
| 33 | * bit7 = NORM | ||
| 34 | * bit8 = DNORM | ||
| 35 | * bit9 = ZERO | ||
| 36 | */ | ||
| 37 | |||
| 38 | switch(xc) { | ||
| 39 | case IEEE754_CLASS_SNAN: | ||
| 40 | return 0x01; | ||
| 41 | case IEEE754_CLASS_QNAN: | ||
| 42 | return 0x02; | ||
| 43 | case IEEE754_CLASS_INF: | ||
| 44 | return 0x04 << (xs ? 0 : 4); | ||
| 45 | case IEEE754_CLASS_NORM: | ||
| 46 | return 0x08 << (xs ? 0 : 4); | ||
| 47 | case IEEE754_CLASS_DNORM: | ||
| 48 | return 0x10 << (xs ? 0 : 4); | ||
| 49 | case IEEE754_CLASS_ZERO: | ||
| 50 | return 0x20 << (xs ? 0 : 4); | ||
| 51 | default: | ||
| 52 | pr_err("Unknown class: %d\n", xc); | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | } | ||
| @@ -0,0 +1,213 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * double precision: MIN{,A}.f | ||
| 4 | * MIN : Scalar Floating-Point Minimum | ||
| 5 | * MINA: Scalar Floating-Point argument with Minimum Absolute Value | ||
| 6 | * | ||
| 7 | * MIN.D : FPR[fd] = minNum(FPR[fs],FPR[ft]) | ||
| 8 | * MINA.D: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) | ||
| 9 | * | ||
| 10 | * MIPS floating point support | ||
| 11 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 12 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 13 | * | ||
| 14 | * This program is free software; you can distribute it and/or modify it | ||
| 15 | * under the terms of the GNU General Public License as published by the | ||
| 16 | * Free Software Foundation; version 2 of the License. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include "ieee754dp.h" | ||
| 20 | |||
| 21 | union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y) | ||
| 22 | { | ||
| 23 | COMPXDP; | ||
| 24 | COMPYDP; | ||
| 25 | |||
| 26 | EXPLODEXDP; | ||
| 27 | EXPLODEYDP; | ||
| 28 | |||
| 29 | FLUSHXDP; | ||
| 30 | FLUSHYDP; | ||
| 31 | |||
| 32 | ieee754_clearcx(); | ||
| 33 | |||
| 34 | switch (CLPAIR(xc, yc)) { | ||
| 35 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 36 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 37 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 38 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 39 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 40 | return ieee754dp_nanxcpt(y); | ||
| 41 | |||
| 42 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 43 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 44 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 45 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 46 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 47 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 48 | return ieee754dp_nanxcpt(x); | ||
| 49 | |||
| 50 | /* numbers are preferred to NaNs */ | ||
| 51 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 52 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 53 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 54 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 55 | return x; | ||
| 56 | |||
| 57 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 58 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 59 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 60 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 61 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 62 | return y; | ||
| 63 | |||
| 64 | /* | ||
| 65 | * Infinity and zero handling | ||
| 66 | */ | ||
| 67 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 68 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 69 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 70 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 71 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 72 | return xs ? y : x; | ||
| 73 | |||
| 74 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 75 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 76 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 77 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 79 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 80 | return ys ? x : y; | ||
| 81 | |||
| 82 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 83 | if (xs == ys) | ||
| 84 | return x; | ||
| 85 | return ieee754dp_zero(1); | ||
| 86 | |||
| 87 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 88 | DPDNORMX; | ||
| 89 | |||
| 90 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 91 | DPDNORMY; | ||
| 92 | break; | ||
| 93 | |||
| 94 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 95 | DPDNORMX; | ||
| 96 | } | ||
| 97 | |||
| 98 | /* Finally get to do some computation */ | ||
| 99 | |||
| 100 | assert(xm & DP_HIDDEN_BIT); | ||
| 101 | assert(ym & DP_HIDDEN_BIT); | ||
| 102 | |||
| 103 | /* Compare signs */ | ||
| 104 | if (xs > ys) | ||
| 105 | return y; | ||
| 106 | else if (xs < ys) | ||
| 107 | return x; | ||
| 108 | |||
| 109 | /* Compare exponent */ | ||
| 110 | if (xe > ye) | ||
| 111 | return x; | ||
| 112 | else if (xe < ye) | ||
| 113 | return y; | ||
| 114 | |||
| 115 | /* Compare mantissa */ | ||
| 116 | if (xm <= ym) | ||
| 117 | return y; | ||
| 118 | return x; | ||
| 119 | } | ||
| 120 | |||
| 121 | union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) | ||
| 122 | { | ||
| 123 | COMPXDP; | ||
| 124 | COMPYDP; | ||
| 125 | |||
| 126 | EXPLODEXDP; | ||
| 127 | EXPLODEYDP; | ||
| 128 | |||
| 129 | FLUSHXDP; | ||
| 130 | FLUSHYDP; | ||
| 131 | |||
| 132 | ieee754_clearcx(); | ||
| 133 | |||
| 134 | switch (CLPAIR(xc, yc)) { | ||
| 135 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 136 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 137 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 138 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 139 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 140 | return ieee754dp_nanxcpt(y); | ||
| 141 | |||
| 142 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 143 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 144 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 145 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 146 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 147 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 148 | return ieee754dp_nanxcpt(x); | ||
| 149 | |||
| 150 | /* numbers are preferred to NaNs */ | ||
| 151 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 152 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 153 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 154 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 155 | return x; | ||
| 156 | |||
| 157 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 158 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 159 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 160 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 161 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 162 | return y; | ||
| 163 | |||
| 164 | /* | ||
| 165 | * Infinity and zero handling | ||
| 166 | */ | ||
| 167 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 168 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 169 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 170 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 171 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 172 | return x; | ||
| 173 | |||
| 174 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 175 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 176 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 177 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 178 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 179 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 180 | return y; | ||
| 181 | |||
| 182 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 183 | if (xs == ys) | ||
| 184 | return x; | ||
| 185 | return ieee754dp_zero(1); | ||
| 186 | |||
| 187 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 188 | DPDNORMX; | ||
| 189 | |||
| 190 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 191 | DPDNORMY; | ||
| 192 | break; | ||
| 193 | |||
| 194 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 195 | DPDNORMX; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* Finally get to do some computation */ | ||
| 199 | |||
| 200 | assert(xm & DP_HIDDEN_BIT); | ||
| 201 | assert(ym & DP_HIDDEN_BIT); | ||
| 202 | |||
| 203 | /* Compare exponent */ | ||
| 204 | if (xe > ye) | ||
| 205 | return x; | ||
| 206 | else if (xe < ye) | ||
| 207 | return y; | ||
| 208 | |||
| 209 | /* Compare mantissa */ | ||
| 210 | if (xm <= ym) | ||
| 211 | return y; | ||
| 212 | return x; | ||
| 213 | } | ||
| @@ -0,0 +1,213 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * double precision: MIN{,A}.f | ||
| 4 | * MIN : Scalar Floating-Point Minimum | ||
| 5 | * MINA: Scalar Floating-Point argument with Minimum Absolute Value | ||
| 6 | * | ||
| 7 | * MIN.D : FPR[fd] = minNum(FPR[fs],FPR[ft]) | ||
| 8 | * MINA.D: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) | ||
| 9 | * | ||
| 10 | * MIPS floating point support | ||
| 11 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 12 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 13 | * | ||
| 14 | * This program is free software; you can distribute it and/or modify it | ||
| 15 | * under the terms of the GNU General Public License as published by the | ||
| 16 | * Free Software Foundation; version 2 of the License. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include "ieee754dp.h" | ||
| 20 | |||
| 21 | union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y) | ||
| 22 | { | ||
| 23 | COMPXDP; | ||
| 24 | COMPYDP; | ||
| 25 | |||
| 26 | EXPLODEXDP; | ||
| 27 | EXPLODEYDP; | ||
| 28 | |||
| 29 | FLUSHXDP; | ||
| 30 | FLUSHYDP; | ||
| 31 | |||
| 32 | ieee754_clearcx(); | ||
| 33 | |||
| 34 | switch (CLPAIR(xc, yc)) { | ||
| 35 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 36 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 37 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 38 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 39 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 40 | return ieee754dp_nanxcpt(y); | ||
| 41 | |||
| 42 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 43 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 44 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 45 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 46 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 47 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 48 | return ieee754dp_nanxcpt(x); | ||
| 49 | |||
| 50 | /* numbers are preferred to NaNs */ | ||
| 51 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 52 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 53 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 54 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 55 | return x; | ||
| 56 | |||
| 57 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 58 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 59 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 60 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 61 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 62 | return y; | ||
| 63 | |||
| 64 | /* | ||
| 65 | * Infinity and zero handling | ||
| 66 | */ | ||
| 67 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 68 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 69 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 70 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 71 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 72 | return xs ? x : y; | ||
| 73 | |||
| 74 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 75 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 76 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 77 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 79 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 80 | return ys ? y : x; | ||
| 81 | |||
| 82 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 83 | if (xs == ys) | ||
| 84 | return x; | ||
| 85 | return ieee754dp_zero(1); | ||
| 86 | |||
| 87 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 88 | DPDNORMX; | ||
| 89 | |||
| 90 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 91 | DPDNORMY; | ||
| 92 | break; | ||
| 93 | |||
| 94 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 95 | DPDNORMX; | ||
| 96 | } | ||
| 97 | |||
| 98 | /* Finally get to do some computation */ | ||
| 99 | |||
| 100 | assert(xm & DP_HIDDEN_BIT); | ||
| 101 | assert(ym & DP_HIDDEN_BIT); | ||
| 102 | |||
| 103 | /* Compare signs */ | ||
| 104 | if (xs > ys) | ||
| 105 | return x; | ||
| 106 | else if (xs < ys) | ||
| 107 | return y; | ||
| 108 | |||
| 109 | /* Compare exponent */ | ||
| 110 | if (xe > ye) | ||
| 111 | return y; | ||
| 112 | else if (xe < ye) | ||
| 113 | return x; | ||
| 114 | |||
| 115 | /* Compare mantissa */ | ||
| 116 | if (xm <= ym) | ||
| 117 | return x; | ||
| 118 | return y; | ||
| 119 | } | ||
| 120 | |||
| 121 | union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y) | ||
| 122 | { | ||
| 123 | COMPXDP; | ||
| 124 | COMPYDP; | ||
| 125 | |||
| 126 | EXPLODEXDP; | ||
| 127 | EXPLODEYDP; | ||
| 128 | |||
| 129 | FLUSHXDP; | ||
| 130 | FLUSHYDP; | ||
| 131 | |||
| 132 | ieee754_clearcx(); | ||
| 133 | |||
| 134 | switch (CLPAIR(xc, yc)) { | ||
| 135 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 136 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 137 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 138 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 139 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 140 | return ieee754dp_nanxcpt(y); | ||
| 141 | |||
| 142 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 143 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 144 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 145 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 146 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 147 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 148 | return ieee754dp_nanxcpt(x); | ||
| 149 | |||
| 150 | /* numbers are preferred to NaNs */ | ||
| 151 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 152 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 153 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 154 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 155 | return x; | ||
| 156 | |||
| 157 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 158 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 159 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 160 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 161 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 162 | return y; | ||
| 163 | |||
| 164 | /* | ||
| 165 | * Infinity and zero handling | ||
| 166 | */ | ||
| 167 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 168 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 169 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 170 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 171 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 172 | return x; | ||
| 173 | |||
| 174 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 175 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 176 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 177 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 178 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 179 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 180 | return y; | ||
| 181 | |||
| 182 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 183 | if (xs == ys) | ||
| 184 | return x; | ||
| 185 | return ieee754dp_zero(1); | ||
| 186 | |||
| 187 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 188 | DPDNORMX; | ||
| 189 | |||
| 190 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 191 | DPDNORMY; | ||
| 192 | break; | ||
| 193 | |||
| 194 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 195 | DPDNORMX; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* Finally get to do some computation */ | ||
| 199 | |||
| 200 | assert(xm & DP_HIDDEN_BIT); | ||
| 201 | assert(ym & DP_HIDDEN_BIT); | ||
| 202 | |||
| 203 | /* Compare exponent */ | ||
| 204 | if (xe > ye) | ||
| 205 | return y; | ||
| 206 | else if (xe < ye) | ||
| 207 | return x; | ||
| 208 | |||
| 209 | /* Compare mantissa */ | ||
| 210 | if (xm <= ym) | ||
| 211 | return x; | ||
| 212 | return y; | ||
| 213 | } | ||
| @@ -0,0 +1,265 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * double precision: MADDF.f (Fused Multiply Add) | ||
| 4 | * MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft]) | ||
| 5 | * | ||
| 6 | * MIPS floating point support | ||
| 7 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 8 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can distribute it and/or modify it | ||
| 11 | * under the terms of the GNU General Public License as published by the | ||
| 12 | * Free Software Foundation; version 2 of the License. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include "ieee754dp.h" | ||
| 16 | |||
| 17 | union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, | ||
| 18 | union ieee754dp y) | ||
| 19 | { | ||
| 20 | int re; | ||
| 21 | int rs; | ||
| 22 | u64 rm; | ||
| 23 | unsigned lxm; | ||
| 24 | unsigned hxm; | ||
| 25 | unsigned lym; | ||
| 26 | unsigned hym; | ||
| 27 | u64 lrm; | ||
| 28 | u64 hrm; | ||
| 29 | u64 t; | ||
| 30 | u64 at; | ||
| 31 | int s; | ||
| 32 | |||
| 33 | COMPXDP; | ||
| 34 | COMPYDP; | ||
| 35 | |||
| 36 | u64 zm; int ze; int zs __maybe_unused; int zc; | ||
| 37 | |||
| 38 | EXPLODEXDP; | ||
| 39 | EXPLODEYDP; | ||
| 40 | EXPLODEDP(z, zc, zs, ze, zm) | ||
| 41 | |||
| 42 | FLUSHXDP; | ||
| 43 | FLUSHYDP; | ||
| 44 | FLUSHDP(z, zc, zs, ze, zm); | ||
| 45 | |||
| 46 | ieee754_clearcx(); | ||
| 47 | |||
| 48 | switch (zc) { | ||
| 49 | case IEEE754_CLASS_SNAN: | ||
| 50 | ieee754_setcx(IEEE754_INVALID_OPERATION); | ||
| 51 | return ieee754dp_nanxcpt(z); | ||
| 52 | case IEEE754_CLASS_DNORM: | ||
| 53 | DPDNORMx(zm, ze); | ||
| 54 | /* QNAN is handled separately below */ | ||
| 55 | } | ||
| 56 | |||
| 57 | switch (CLPAIR(xc, yc)) { | ||
| 58 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 59 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 60 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 61 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 62 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 63 | return ieee754dp_nanxcpt(y); | ||
| 64 | |||
| 65 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 66 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 67 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 68 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 69 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 70 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 71 | return ieee754dp_nanxcpt(x); | ||
| 72 | |||
| 73 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 74 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 75 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 76 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 77 | return y; | ||
| 78 | |||
| 79 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 80 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 81 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 82 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 83 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 84 | return x; | ||
| 85 | |||
| 86 | |||
| 87 | /* | ||
| 88 | * Infinity handling | ||
| 89 | */ | ||
| 90 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 91 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 92 | if (zc == IEEE754_CLASS_QNAN) | ||
| 93 | return z; | ||
| 94 | ieee754_setcx(IEEE754_INVALID_OPERATION); | ||
| 95 | return ieee754dp_indef(); | ||
| 96 | |||
| 97 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 98 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 99 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 100 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 101 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 102 | if (zc == IEEE754_CLASS_QNAN) | ||
| 103 | return z; | ||
| 104 | return ieee754dp_inf(xs ^ ys); | ||
| 105 | |||
| 106 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 107 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 108 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 109 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 110 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 111 | if (zc == IEEE754_CLASS_INF) | ||
| 112 | return ieee754dp_inf(zs); | ||
| 113 | /* Multiplication is 0 so just return z */ | ||
| 114 | return z; | ||
| 115 | |||
| 116 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 117 | DPDNORMX; | ||
| 118 | |||
| 119 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 120 | if (zc == IEEE754_CLASS_QNAN) | ||
| 121 | return z; | ||
| 122 | else if (zc == IEEE754_CLASS_INF) | ||
| 123 | return ieee754dp_inf(zs); | ||
| 124 | DPDNORMY; | ||
| 125 | break; | ||
| 126 | |||
| 127 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 128 | if (zc == IEEE754_CLASS_QNAN) | ||
| 129 | return z; | ||
| 130 | else if (zc == IEEE754_CLASS_INF) | ||
| 131 | return ieee754dp_inf(zs); | ||
| 132 | DPDNORMX; | ||
| 133 | break; | ||
| 134 | |||
| 135 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): | ||
| 136 | if (zc == IEEE754_CLASS_QNAN) | ||
| 137 | return z; | ||
| 138 | else if (zc == IEEE754_CLASS_INF) | ||
| 139 | return ieee754dp_inf(zs); | ||
| 140 | /* fall through to real computations */ | ||
| 141 | } | ||
| 142 | |||
| 143 | /* Finally get to do some computation */ | ||
| 144 | |||
| 145 | /* | ||
| 146 | * Do the multiplication bit first | ||
| 147 | * | ||
| 148 | * rm = xm * ym, re = xe + ye basically | ||
| 149 | * | ||
| 150 | * At this point xm and ym should have been normalized. | ||
| 151 | */ | ||
| 152 | assert(xm & DP_HIDDEN_BIT); | ||
| 153 | assert(ym & DP_HIDDEN_BIT); | ||
| 154 | |||
| 155 | re = xe + ye; | ||
| 156 | rs = xs ^ ys; | ||
| 157 | |||
| 158 | /* shunt to top of word */ | ||
| 159 | xm <<= 64 - (DP_FBITS + 1); | ||
| 160 | ym <<= 64 - (DP_FBITS + 1); | ||
| 161 | |||
| 162 | /* | ||
| 163 | * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. | ||
| 164 | */ | ||
| 165 | |||
| 166 | /* 32 * 32 => 64 */ | ||
| 167 | #define DPXMULT(x, y) ((u64)(x) * (u64)y) | ||
| 168 | |||
| 169 | lxm = xm; | ||
| 170 | hxm = xm >> 32; | ||
| 171 | lym = ym; | ||
| 172 | hym = ym >> 32; | ||
| 173 | |||
| 174 | lrm = DPXMULT(lxm, lym); | ||
| 175 | hrm = DPXMULT(hxm, hym); | ||
| 176 | |||
| 177 | t = DPXMULT(lxm, hym); | ||
| 178 | |||
| 179 | at = lrm + (t << 32); | ||
| 180 | hrm += at < lrm; | ||
| 181 | lrm = at; | ||
| 182 | |||
| 183 | hrm = hrm + (t >> 32); | ||
| 184 | |||
| 185 | t = DPXMULT(hxm, lym); | ||
| 186 | |||
| 187 | at = lrm + (t << 32); | ||
| 188 | hrm += at < lrm; | ||
| 189 | lrm = at; | ||
| 190 | |||
| 191 | hrm = hrm + (t >> 32); | ||
| 192 | |||
| 193 | rm = hrm | (lrm != 0); | ||
| 194 | |||
| 195 | /* | ||
| 196 | * Sticky shift down to normal rounding precision. | ||
| 197 | */ | ||
| 198 | if ((s64) rm < 0) { | ||
| 199 | rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | | ||
| 200 | ((rm << (DP_FBITS + 1 + 3)) != 0); | ||
| 201 | re++; | ||
| 202 | } else { | ||
| 203 | rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | | ||
| 204 | ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); | ||
| 205 | } | ||
| 206 | assert(rm & (DP_HIDDEN_BIT << 3)); | ||
| 207 | |||
| 208 | /* And now the addition */ | ||
| 209 | assert(zm & DP_HIDDEN_BIT); | ||
| 210 | |||
| 211 | /* | ||
| 212 | * Provide guard,round and stick bit space. | ||
| 213 | */ | ||
| 214 | zm <<= 3; | ||
| 215 | |||
| 216 | if (ze > re) { | ||
| 217 | /* | ||
| 218 | * Have to shift y fraction right to align. | ||
| 219 | */ | ||
| 220 | s = ze - re; | ||
| 221 | rm = XDPSRS(rm, s); | ||
| 222 | re += s; | ||
| 223 | } else if (re > ze) { | ||
| 224 | /* | ||
| 225 | * Have to shift x fraction right to align. | ||
| 226 | */ | ||
| 227 | s = re - ze; | ||
| 228 | zm = XDPSRS(zm, s); | ||
| 229 | ze += s; | ||
| 230 | } | ||
| 231 | assert(ze == re); | ||
| 232 | assert(ze <= DP_EMAX); | ||
| 233 | |||
| 234 | if (zs == rs) { | ||
| 235 | /* | ||
| 236 | * Generate 28 bit result of adding two 27 bit numbers | ||
| 237 | * leaving result in xm, xs and xe. | ||
| 238 | */ | ||
| 239 | zm = zm + rm; | ||
| 240 | |||
| 241 | if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ | ||
| 242 | zm = XDPSRS1(zm); | ||
| 243 | ze++; | ||
| 244 | } | ||
| 245 | } else { | ||
| 246 | if (zm >= rm) { | ||
| 247 | zm = zm - rm; | ||
| 248 | } else { | ||
| 249 | zm = rm - zm; | ||
| 250 | zs = rs; | ||
| 251 | } | ||
| 252 | if (zm == 0) | ||
| 253 | return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); | ||
| 254 | |||
| 255 | /* | ||
| 256 | * Normalize to rounding precision. | ||
| 257 | */ | ||
| 258 | while ((zm >> (DP_FBITS + 3)) == 0) { | ||
| 259 | zm <<= 1; | ||
| 260 | ze--; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | return ieee754dp_format(zs, ze, zm); | ||
| 265 | } | ||
| @@ -0,0 +1,269 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * double precision: MSUB.f (Fused Multiply Subtract) | ||
| 4 | * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) | ||
| 5 | * | ||
| 6 | * MIPS floating point support | ||
| 7 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 8 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can distribute it and/or modify it | ||
| 11 | * under the terms of the GNU General Public License as published by the | ||
| 12 | * Free Software Foundation; version 2 of the License. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include "ieee754dp.h" | ||
| 16 | |||
| 17 | union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, | ||
| 18 | union ieee754dp y) | ||
| 19 | { | ||
| 20 | int re; | ||
| 21 | int rs; | ||
| 22 | u64 rm; | ||
| 23 | unsigned lxm; | ||
| 24 | unsigned hxm; | ||
| 25 | unsigned lym; | ||
| 26 | unsigned hym; | ||
| 27 | u64 lrm; | ||
| 28 | u64 hrm; | ||
| 29 | u64 t; | ||
| 30 | u64 at; | ||
| 31 | int s; | ||
| 32 | |||
| 33 | COMPXDP; | ||
| 34 | COMPYDP; | ||
| 35 | |||
| 36 | u64 zm; int ze; int zs __maybe_unused; int zc; | ||
| 37 | |||
| 38 | EXPLODEXDP; | ||
| 39 | EXPLODEYDP; | ||
| 40 | EXPLODEDP(z, zc, zs, ze, zm) | ||
| 41 | |||
| 42 | FLUSHXDP; | ||
| 43 | FLUSHYDP; | ||
| 44 | FLUSHDP(z, zc, zs, ze, zm); | ||
| 45 | |||
| 46 | ieee754_clearcx(); | ||
| 47 | |||
| 48 | switch (zc) { | ||
| 49 | case IEEE754_CLASS_SNAN: | ||
| 50 | ieee754_setcx(IEEE754_INVALID_OPERATION); | ||
| 51 | return ieee754dp_nanxcpt(z); | ||
| 52 | case IEEE754_CLASS_DNORM: | ||
| 53 | DPDNORMx(zm, ze); | ||
| 54 | /* QNAN is handled separately below */ | ||
| 55 | } | ||
| 56 | |||
| 57 | switch (CLPAIR(xc, yc)) { | ||
| 58 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 59 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 60 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 61 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 62 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 63 | return ieee754dp_nanxcpt(y); | ||
| 64 | |||
| 65 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 66 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 67 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 68 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 69 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 70 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 71 | return ieee754dp_nanxcpt(x); | ||
| 72 | |||
| 73 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 74 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 75 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 76 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 77 | return y; | ||
| 78 | |||
| 79 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 80 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 81 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 82 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 83 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 84 | return x; | ||
| 85 | |||
| 86 | |||
| 87 | /* | ||
| 88 | * Infinity handling | ||
| 89 | */ | ||
| 90 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 91 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 92 | if (zc == IEEE754_CLASS_QNAN) | ||
| 93 | return z; | ||
| 94 | ieee754_setcx(IEEE754_INVALID_OPERATION); | ||
| 95 | return ieee754dp_indef(); | ||
| 96 | |||
| 97 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 98 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 99 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 100 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 101 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 102 | if (zc == IEEE754_CLASS_QNAN) | ||
| 103 | return z; | ||
| 104 | return ieee754dp_inf(xs ^ ys); | ||
| 105 | |||
| 106 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 107 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 108 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 109 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 110 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 111 | if (zc == IEEE754_CLASS_INF) | ||
| 112 | return ieee754dp_inf(zs); | ||
| 113 | /* Multiplication is 0 so just return z */ | ||
| 114 | return z; | ||
| 115 | |||
| 116 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 117 | DPDNORMX; | ||
| 118 | |||
| 119 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 120 | if (zc == IEEE754_CLASS_QNAN) | ||
| 121 | return z; | ||
| 122 | else if (zc == IEEE754_CLASS_INF) | ||
| 123 | return ieee754dp_inf(zs); | ||
| 124 | DPDNORMY; | ||
| 125 | break; | ||
| 126 | |||
| 127 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 128 | if (zc == IEEE754_CLASS_QNAN) | ||
| 129 | return z; | ||
| 130 | else if (zc == IEEE754_CLASS_INF) | ||
| 131 | return ieee754dp_inf(zs); | ||
| 132 | DPDNORMX; | ||
| 133 | break; | ||
| 134 | |||
| 135 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): | ||
| 136 | if (zc == IEEE754_CLASS_QNAN) | ||
| 137 | return z; | ||
| 138 | else if (zc == IEEE754_CLASS_INF) | ||
| 139 | return ieee754dp_inf(zs); | ||
| 140 | /* fall through to real computations */ | ||
| 141 | } | ||
| 142 | |||
| 143 | /* Finally get to do some computation */ | ||
| 144 | |||
| 145 | /* | ||
| 146 | * Do the multiplication bit first | ||
| 147 | * | ||
| 148 | * rm = xm * ym, re = xe + ye basically | ||
| 149 | * | ||
| 150 | * At this point xm and ym should have been normalized. | ||
| 151 | */ | ||
| 152 | assert(xm & DP_HIDDEN_BIT); | ||
| 153 | assert(ym & DP_HIDDEN_BIT); | ||
| 154 | |||
| 155 | re = xe + ye; | ||
| 156 | rs = xs ^ ys; | ||
| 157 | |||
| 158 | /* shunt to top of word */ | ||
| 159 | xm <<= 64 - (DP_FBITS + 1); | ||
| 160 | ym <<= 64 - (DP_FBITS + 1); | ||
| 161 | |||
| 162 | /* | ||
| 163 | * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. | ||
| 164 | */ | ||
| 165 | |||
| 166 | /* 32 * 32 => 64 */ | ||
| 167 | #define DPXMULT(x, y) ((u64)(x) * (u64)y) | ||
| 168 | |||
| 169 | lxm = xm; | ||
| 170 | hxm = xm >> 32; | ||
| 171 | lym = ym; | ||
| 172 | hym = ym >> 32; | ||
| 173 | |||
| 174 | lrm = DPXMULT(lxm, lym); | ||
| 175 | hrm = DPXMULT(hxm, hym); | ||
| 176 | |||
| 177 | t = DPXMULT(lxm, hym); | ||
| 178 | |||
| 179 | at = lrm + (t << 32); | ||
| 180 | hrm += at < lrm; | ||
| 181 | lrm = at; | ||
| 182 | |||
| 183 | hrm = hrm + (t >> 32); | ||
| 184 | |||
| 185 | t = DPXMULT(hxm, lym); | ||
| 186 | |||
| 187 | at = lrm + (t << 32); | ||
| 188 | hrm += at < lrm; | ||
| 189 | lrm = at; | ||
| 190 | |||
| 191 | hrm = hrm + (t >> 32); | ||
| 192 | |||
| 193 | rm = hrm | (lrm != 0); | ||
| 194 | |||
| 195 | /* | ||
| 196 | * Sticky shift down to normal rounding precision. | ||
| 197 | */ | ||
| 198 | if ((s64) rm < 0) { | ||
| 199 | rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | | ||
| 200 | ((rm << (DP_FBITS + 1 + 3)) != 0); | ||
| 201 | re++; | ||
| 202 | } else { | ||
| 203 | rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | | ||
| 204 | ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); | ||
| 205 | } | ||
| 206 | assert(rm & (DP_HIDDEN_BIT << 3)); | ||
| 207 | |||
| 208 | /* And now the subtraction */ | ||
| 209 | |||
| 210 | /* flip sign of r and handle as add */ | ||
| 211 | rs ^= 1; | ||
| 212 | |||
| 213 | assert(zm & DP_HIDDEN_BIT); | ||
| 214 | |||
| 215 | /* | ||
| 216 | * Provide guard,round and stick bit space. | ||
| 217 | */ | ||
| 218 | zm <<= 3; | ||
| 219 | |||
| 220 | if (ze > re) { | ||
| 221 | /* | ||
| 222 | * Have to shift y fraction right to align. | ||
| 223 | */ | ||
| 224 | s = ze - re; | ||
| 225 | rm = XDPSRS(rm, s); | ||
| 226 | re += s; | ||
| 227 | } else if (re > ze) { | ||
| 228 | /* | ||
| 229 | * Have to shift x fraction right to align. | ||
| 230 | */ | ||
| 231 | s = re - ze; | ||
| 232 | zm = XDPSRS(zm, s); | ||
| 233 | ze += s; | ||
| 234 | } | ||
| 235 | assert(ze == re); | ||
| 236 | assert(ze <= DP_EMAX); | ||
| 237 | |||
| 238 | if (zs == rs) { | ||
| 239 | /* | ||
| 240 | * Generate 28 bit result of adding two 27 bit numbers | ||
| 241 | * leaving result in xm, xs and xe. | ||
| 242 | */ | ||
| 243 | zm = zm + rm; | ||
| 244 | |||
| 245 | if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ | ||
| 246 | zm = XDPSRS1(zm); | ||
| 247 | ze++; | ||
| 248 | } | ||
| 249 | } else { | ||
| 250 | if (zm >= rm) { | ||
| 251 | zm = zm - rm; | ||
| 252 | } else { | ||
| 253 | zm = rm - zm; | ||
| 254 | zs = rs; | ||
| 255 | } | ||
| 256 | if (zm == 0) | ||
| 257 | return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); | ||
| 258 | |||
| 259 | /* | ||
| 260 | * Normalize to rounding precision. | ||
| 261 | */ | ||
| 262 | while ((zm >> (DP_FBITS + 3)) == 0) { | ||
| 263 | zm <<= 1; | ||
| 264 | ze--; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | return ieee754dp_format(zs, ze, zm); | ||
| 269 | } | ||
| @@ -33,7 +33,6 @@ struct emuframe { · 32 unmodified lines | |||
| 33 | 33 | ||
| 34 | int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) | 34 | int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) |
| 35 | { | 35 | { |
| 36 | extern asmlinkage void handle_dsemulret(void); | ||
| 37 | struct emuframe __user *fr; | 36 | struct emuframe __user *fr; |
| 38 | int err; | 37 | int err; |
| 39 | 38 | ||
| @@ -75,6 +75,16 @@ int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cop, int sig); · 74 unmodified lines | |||
| 75 | 75 | ||
| 76 | union ieee754sp ieee754sp_sqrt(union ieee754sp x); | 76 | union ieee754sp ieee754sp_sqrt(union ieee754sp x); |
| 77 | 77 | ||
| 78 | union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, | ||
| 79 | union ieee754sp y); | ||
| 80 | union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, | ||
| 81 | union ieee754sp y); | ||
| 82 | int ieee754sp_2008class(union ieee754sp x); | ||
| 83 | union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y); | ||
| 84 | union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y); | ||
| 85 | union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y); | ||
| 86 | union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y); | ||
| 87 | |||
| 78 | /* | 88 | /* |
| 79 | * double precision (often aka double) | 89 | * double precision (often aka double) |
| 80 | */ | 90 | */ |
| @@ -99,6 +109,15 @@ int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cop, int sig); · 18 unmodified lines | |||
| 99 | 109 | ||
| 100 | union ieee754dp ieee754dp_sqrt(union ieee754dp x); | 110 | union ieee754dp ieee754dp_sqrt(union ieee754dp x); |
| 101 | 111 | ||
| 112 | union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, | ||
| 113 | union ieee754dp y); | ||
| 114 | union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, | ||
| 115 | union ieee754dp y); | ||
| 116 | int ieee754dp_2008class(union ieee754dp x); | ||
| 117 | union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y); | ||
| 118 | union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y); | ||
| 119 | union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y); | ||
| 120 | union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y); | ||
| 102 | 121 | ||
| 103 | 122 | ||
| 104 | /* 5 types of floating point number | 123 | /* 5 types of floating point number |
| @@ -65,8 +65,8 @@ static inline int ieee754_class_nan(int xc) · 64 unmodified lines | |||
| 65 | vc = IEEE754_CLASS_INF; \ | 65 | vc = IEEE754_CLASS_INF; \ |
| 66 | else if (vm & SP_MBIT(SP_FBITS-1)) \ | 66 | else if (vm & SP_MBIT(SP_FBITS-1)) \ |
| 67 | vc = IEEE754_CLASS_SNAN; \ | 67 | vc = IEEE754_CLASS_SNAN; \ |
| 68 | else \ | 68 | else \ |
| 69 | vc = IEEE754_CLASS_QNAN; \ | 69 | vc = IEEE754_CLASS_QNAN; \ |
| 70 | } else if (ve == SP_EMIN-1+SP_EBIAS) { \ | 70 | } else if (ve == SP_EMIN-1+SP_EBIAS) { \ |
| 71 | if (vm) { \ | 71 | if (vm) { \ |
| 72 | ve = SP_EMIN; \ | 72 | ve = SP_EMIN; \ |
| @@ -105,8 +105,8 @@ static inline int ieee754_class_nan(int xc) · 32 unmodified lines | |||
| 105 | if (vm) { \ | 105 | if (vm) { \ |
| 106 | ve = DP_EMIN; \ | 106 | ve = DP_EMIN; \ |
| 107 | vc = IEEE754_CLASS_DNORM; \ | 107 | vc = IEEE754_CLASS_DNORM; \ |
| 108 | } else \ | 108 | } else \ |
| 109 | vc = IEEE754_CLASS_ZERO; \ | 109 | vc = IEEE754_CLASS_ZERO; \ |
| 110 | } else { \ | 110 | } else { \ |
| 111 | ve -= DP_EBIAS; \ | 111 | ve -= DP_EBIAS; \ |
| 112 | vm |= DP_HIDDEN_BIT; \ | 112 | vm |= DP_HIDDEN_BIT; \ |
| @@ -65,4 +65,4 @@ do { \ · 64 unmodified lines | |||
| 65 | 65 | ||
| 66 | return 0; | 66 | return 0; |
| 67 | } | 67 | } |
| 68 | __initcall(debugfs_fpuemu); | 68 | arch_initcall(debugfs_fpuemu); |
| @@ -0,0 +1,55 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * single precision: CLASS.f | ||
| 4 | * FPR[fd] = class(FPR[fs]) | ||
| 5 | * | ||
| 6 | * MIPS floating point support | ||
| 7 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 8 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can distribute it and/or modify it | ||
| 11 | * under the terms of the GNU General Public License as published by the | ||
| 12 | * Free Software Foundation; version 2 of the License. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include "ieee754sp.h" | ||
| 16 | |||
| 17 | int ieee754sp_2008class(union ieee754sp x) | ||
| 18 | { | ||
| 19 | COMPXSP; | ||
| 20 | |||
| 21 | EXPLODEXSP; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * 10 bit mask as follows: | ||
| 25 | * | ||
| 26 | * bit0 = SNAN | ||
| 27 | * bit1 = QNAN | ||
| 28 | * bit2 = -INF | ||
| 29 | * bit3 = -NORM | ||
| 30 | * bit4 = -DNORM | ||
| 31 | * bit5 = -ZERO | ||
| 32 | * bit6 = INF | ||
| 33 | * bit7 = NORM | ||
| 34 | * bit8 = DNORM | ||
| 35 | * bit9 = ZERO | ||
| 36 | */ | ||
| 37 | |||
| 38 | switch(xc) { | ||
| 39 | case IEEE754_CLASS_SNAN: | ||
| 40 | return 0x01; | ||
| 41 | case IEEE754_CLASS_QNAN: | ||
| 42 | return 0x02; | ||
| 43 | case IEEE754_CLASS_INF: | ||
| 44 | return 0x04 << (xs ? 0 : 4); | ||
| 45 | case IEEE754_CLASS_NORM: | ||
| 46 | return 0x08 << (xs ? 0 : 4); | ||
| 47 | case IEEE754_CLASS_DNORM: | ||
| 48 | return 0x10 << (xs ? 0 : 4); | ||
| 49 | case IEEE754_CLASS_ZERO: | ||
| 50 | return 0x20 << (xs ? 0 : 4); | ||
| 51 | default: | ||
| 52 | pr_err("Unknown class: %d\n", xc); | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | } | ||
| @@ -0,0 +1,213 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * single precision: MAX{,A}.f | ||
| 4 | * MAX : Scalar Floating-Point Maximum | ||
| 5 | * MAXA: Scalar Floating-Point argument with Maximum Absolute Value | ||
| 6 | * | ||
| 7 | * MAX.S : FPR[fd] = maxNum(FPR[fs],FPR[ft]) | ||
| 8 | * MAXA.S: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) | ||
| 9 | * | ||
| 10 | * MIPS floating point support | ||
| 11 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 12 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 13 | * | ||
| 14 | * This program is free software; you can distribute it and/or modify it | ||
| 15 | * under the terms of the GNU General Public License as published by the | ||
| 16 | * Free Software Foundation; version 2 of the License. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include "ieee754sp.h" | ||
| 20 | |||
| 21 | union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y) | ||
| 22 | { | ||
| 23 | COMPXSP; | ||
| 24 | COMPYSP; | ||
| 25 | |||
| 26 | EXPLODEXSP; | ||
| 27 | EXPLODEYSP; | ||
| 28 | |||
| 29 | FLUSHXSP; | ||
| 30 | FLUSHYSP; | ||
| 31 | |||
| 32 | ieee754_clearcx(); | ||
| 33 | |||
| 34 | switch (CLPAIR(xc, yc)) { | ||
| 35 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 36 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 37 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 38 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 39 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 40 | return ieee754sp_nanxcpt(y); | ||
| 41 | |||
| 42 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 43 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 44 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 45 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 46 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 47 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 48 | return ieee754sp_nanxcpt(x); | ||
| 49 | |||
| 50 | /* numbers are preferred to NaNs */ | ||
| 51 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 52 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 53 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 54 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 55 | return x; | ||
| 56 | |||
| 57 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 58 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 59 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 60 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 61 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 62 | return y; | ||
| 63 | |||
| 64 | /* | ||
| 65 | * Infinity and zero handling | ||
| 66 | */ | ||
| 67 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 68 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 69 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 70 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 71 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 72 | return xs ? y : x; | ||
| 73 | |||
| 74 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 75 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 76 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 77 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 79 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 80 | return ys ? x : y; | ||
| 81 | |||
| 82 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 83 | if (xs == ys) | ||
| 84 | return x; | ||
| 85 | return ieee754sp_zero(1); | ||
| 86 | |||
| 87 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 88 | SPDNORMX; | ||
| 89 | |||
| 90 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 91 | SPDNORMY; | ||
| 92 | break; | ||
| 93 | |||
| 94 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 95 | SPDNORMX; | ||
| 96 | } | ||
| 97 | |||
| 98 | /* Finally get to do some computation */ | ||
| 99 | |||
| 100 | assert(xm & SP_HIDDEN_BIT); | ||
| 101 | assert(ym & SP_HIDDEN_BIT); | ||
| 102 | |||
| 103 | /* Compare signs */ | ||
| 104 | if (xs > ys) | ||
| 105 | return y; | ||
| 106 | else if (xs < ys) | ||
| 107 | return x; | ||
| 108 | |||
| 109 | /* Compare exponent */ | ||
| 110 | if (xe > ye) | ||
| 111 | return x; | ||
| 112 | else if (xe < ye) | ||
| 113 | return y; | ||
| 114 | |||
| 115 | /* Compare mantissa */ | ||
| 116 | if (xm <= ym) | ||
| 117 | return y; | ||
| 118 | return x; | ||
| 119 | } | ||
| 120 | |||
| 121 | union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) | ||
| 122 | { | ||
| 123 | COMPXSP; | ||
| 124 | COMPYSP; | ||
| 125 | |||
| 126 | EXPLODEXSP; | ||
| 127 | EXPLODEYSP; | ||
| 128 | |||
| 129 | FLUSHXSP; | ||
| 130 | FLUSHYSP; | ||
| 131 | |||
| 132 | ieee754_clearcx(); | ||
| 133 | |||
| 134 | switch (CLPAIR(xc, yc)) { | ||
| 135 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 136 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 137 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 138 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 139 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 140 | return ieee754sp_nanxcpt(y); | ||
| 141 | |||
| 142 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 143 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 144 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 145 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 146 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 147 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 148 | return ieee754sp_nanxcpt(x); | ||
| 149 | |||
| 150 | /* numbers are preferred to NaNs */ | ||
| 151 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 152 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 153 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 154 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 155 | return x; | ||
| 156 | |||
| 157 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 158 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 159 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 160 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 161 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 162 | return y; | ||
| 163 | |||
| 164 | /* | ||
| 165 | * Infinity and zero handling | ||
| 166 | */ | ||
| 167 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 168 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 169 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 170 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 171 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 172 | return x; | ||
| 173 | |||
| 174 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 175 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 176 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 177 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 178 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 179 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 180 | return y; | ||
| 181 | |||
| 182 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 183 | if (xs == ys) | ||
| 184 | return x; | ||
| 185 | return ieee754sp_zero(1); | ||
| 186 | |||
| 187 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 188 | SPDNORMX; | ||
| 189 | |||
| 190 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 191 | SPDNORMY; | ||
| 192 | break; | ||
| 193 | |||
| 194 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 195 | SPDNORMX; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* Finally get to do some computation */ | ||
| 199 | |||
| 200 | assert(xm & SP_HIDDEN_BIT); | ||
| 201 | assert(ym & SP_HIDDEN_BIT); | ||
| 202 | |||
| 203 | /* Compare exponent */ | ||
| 204 | if (xe > ye) | ||
| 205 | return x; | ||
| 206 | else if (xe < ye) | ||
| 207 | return y; | ||
| 208 | |||
| 209 | /* Compare mantissa */ | ||
| 210 | if (xm <= ym) | ||
| 211 | return y; | ||
| 212 | return x; | ||
| 213 | } | ||
| @@ -0,0 +1,213 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * single precision: MIN{,A}.f | ||
| 4 | * MIN : Scalar Floating-Point Minimum | ||
| 5 | * MINA: Scalar Floating-Point argument with Minimum Absolute Value | ||
| 6 | * | ||
| 7 | * MIN.S : FPR[fd] = minNum(FPR[fs],FPR[ft]) | ||
| 8 | * MINA.S: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) | ||
| 9 | * | ||
| 10 | * MIPS floating point support | ||
| 11 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 12 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 13 | * | ||
| 14 | * This program is free software; you can distribute it and/or modify it | ||
| 15 | * under the terms of the GNU General Public License as published by the | ||
| 16 | * Free Software Foundation; version 2 of the License. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include "ieee754sp.h" | ||
| 20 | |||
| 21 | union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y) | ||
| 22 | { | ||
| 23 | COMPXSP; | ||
| 24 | COMPYSP; | ||
| 25 | |||
| 26 | EXPLODEXSP; | ||
| 27 | EXPLODEYSP; | ||
| 28 | |||
| 29 | FLUSHXSP; | ||
| 30 | FLUSHYSP; | ||
| 31 | |||
| 32 | ieee754_clearcx(); | ||
| 33 | |||
| 34 | switch (CLPAIR(xc, yc)) { | ||
| 35 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 36 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 37 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 38 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 39 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 40 | return ieee754sp_nanxcpt(y); | ||
| 41 | |||
| 42 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 43 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 44 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 45 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 46 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 47 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 48 | return ieee754sp_nanxcpt(x); | ||
| 49 | |||
| 50 | /* numbers are preferred to NaNs */ | ||
| 51 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 52 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 53 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 54 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 55 | return x; | ||
| 56 | |||
| 57 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 58 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 59 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 60 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 61 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 62 | return y; | ||
| 63 | |||
| 64 | /* | ||
| 65 | * Infinity and zero handling | ||
| 66 | */ | ||
| 67 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 68 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 69 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 70 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 71 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 72 | return xs ? x : y; | ||
| 73 | |||
| 74 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 75 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 76 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 77 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 79 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 80 | return ys ? y : x; | ||
| 81 | |||
| 82 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 83 | if (xs == ys) | ||
| 84 | return x; | ||
| 85 | return ieee754sp_zero(1); | ||
| 86 | |||
| 87 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 88 | SPDNORMX; | ||
| 89 | |||
| 90 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 91 | SPDNORMY; | ||
| 92 | break; | ||
| 93 | |||
| 94 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 95 | SPDNORMX; | ||
| 96 | } | ||
| 97 | |||
| 98 | /* Finally get to do some computation */ | ||
| 99 | |||
| 100 | assert(xm & SP_HIDDEN_BIT); | ||
| 101 | assert(ym & SP_HIDDEN_BIT); | ||
| 102 | |||
| 103 | /* Compare signs */ | ||
| 104 | if (xs > ys) | ||
| 105 | return x; | ||
| 106 | else if (xs < ys) | ||
| 107 | return y; | ||
| 108 | |||
| 109 | /* Compare exponent */ | ||
| 110 | if (xe > ye) | ||
| 111 | return y; | ||
| 112 | else if (xe < ye) | ||
| 113 | return x; | ||
| 114 | |||
| 115 | /* Compare mantissa */ | ||
| 116 | if (xm <= ym) | ||
| 117 | return x; | ||
| 118 | return y; | ||
| 119 | } | ||
| 120 | |||
| 121 | union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y) | ||
| 122 | { | ||
| 123 | COMPXSP; | ||
| 124 | COMPYSP; | ||
| 125 | |||
| 126 | EXPLODEXSP; | ||
| 127 | EXPLODEYSP; | ||
| 128 | |||
| 129 | FLUSHXSP; | ||
| 130 | FLUSHYSP; | ||
| 131 | |||
| 132 | ieee754_clearcx(); | ||
| 133 | |||
| 134 | switch (CLPAIR(xc, yc)) { | ||
| 135 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 136 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 137 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 138 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 139 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 140 | return ieee754sp_nanxcpt(y); | ||
| 141 | |||
| 142 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 143 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 144 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 145 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 146 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 147 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 148 | return ieee754sp_nanxcpt(x); | ||
| 149 | |||
| 150 | /* numbers are preferred to NaNs */ | ||
| 151 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 152 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 153 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 154 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 155 | return x; | ||
| 156 | |||
| 157 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 158 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 159 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 160 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 161 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 162 | return y; | ||
| 163 | |||
| 164 | /* | ||
| 165 | * Infinity and zero handling | ||
| 166 | */ | ||
| 167 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 168 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 169 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 170 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 171 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 172 | return x; | ||
| 173 | |||
| 174 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 175 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 176 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 177 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 178 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 179 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 180 | return y; | ||
| 181 | |||
| 182 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 183 | if (xs == ys) | ||
| 184 | return x; | ||
| 185 | return ieee754sp_zero(1); | ||
| 186 | |||
| 187 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 188 | SPDNORMX; | ||
| 189 | |||
| 190 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 191 | SPDNORMY; | ||
| 192 | break; | ||
| 193 | |||
| 194 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 195 | SPDNORMX; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* Finally get to do some computation */ | ||
| 199 | |||
| 200 | assert(xm & SP_HIDDEN_BIT); | ||
| 201 | assert(ym & SP_HIDDEN_BIT); | ||
| 202 | |||
| 203 | /* Compare exponent */ | ||
| 204 | if (xe > ye) | ||
| 205 | return y; | ||
| 206 | else if (xe < ye) | ||
| 207 | return x; | ||
| 208 | |||
| 209 | /* Compare mantissa */ | ||
| 210 | if (xm <= ym) | ||
| 211 | return x; | ||
| 212 | return y; | ||
| 213 | } | ||
| @@ -0,0 +1,255 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * single precision: MADDF.f (Fused Multiply Add) | ||
| 4 | * MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft]) | ||
| 5 | * | ||
| 6 | * MIPS floating point support | ||
| 7 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 8 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can distribute it and/or modify it | ||
| 11 | * under the terms of the GNU General Public License as published by the | ||
| 12 | * Free Software Foundation; version 2 of the License. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include "ieee754sp.h" | ||
| 16 | |||
| 17 | union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, | ||
| 18 | union ieee754sp y) | ||
| 19 | { | ||
| 20 | int re; | ||
| 21 | int rs; | ||
| 22 | unsigned rm; | ||
| 23 | unsigned short lxm; | ||
| 24 | unsigned short hxm; | ||
| 25 | unsigned short lym; | ||
| 26 | unsigned short hym; | ||
| 27 | unsigned lrm; | ||
| 28 | unsigned hrm; | ||
| 29 | unsigned t; | ||
| 30 | unsigned at; | ||
| 31 | int s; | ||
| 32 | |||
| 33 | COMPXSP; | ||
| 34 | COMPYSP; | ||
| 35 | u32 zm; int ze; int zs __maybe_unused; int zc; | ||
| 36 | |||
| 37 | EXPLODEXSP; | ||
| 38 | EXPLODEYSP; | ||
| 39 | EXPLODESP(z, zc, zs, ze, zm) | ||
| 40 | |||
| 41 | FLUSHXSP; | ||
| 42 | FLUSHYSP; | ||
| 43 | FLUSHSP(z, zc, zs, ze, zm); | ||
| 44 | |||
| 45 | ieee754_clearcx(); | ||
| 46 | |||
| 47 | switch (zc) { | ||
| 48 | case IEEE754_CLASS_SNAN: | ||
| 49 | ieee754_setcx(IEEE754_INVALID_OPERATION); | ||
| 50 | return ieee754sp_nanxcpt(z); | ||
| 51 | case IEEE754_CLASS_DNORM: | ||
| 52 | SPDNORMx(zm, ze); | ||
| 53 | /* QNAN is handled separately below */ | ||
| 54 | } | ||
| 55 | |||
| 56 | switch (CLPAIR(xc, yc)) { | ||
| 57 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 58 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 59 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 60 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 61 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 62 | return ieee754sp_nanxcpt(y); | ||
| 63 | |||
| 64 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 65 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 66 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 67 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 68 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 69 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 70 | return ieee754sp_nanxcpt(x); | ||
| 71 | |||
| 72 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 73 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 74 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 75 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 76 | return y; | ||
| 77 | |||
| 78 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 79 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 80 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 81 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 82 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 83 | return x; | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Infinity handling | ||
| 87 | */ | ||
| 88 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 89 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 90 | if (zc == IEEE754_CLASS_QNAN) | ||
| 91 | return z; | ||
| 92 | ieee754_setcx(IEEE754_INVALID_OPERATION); | ||
| 93 | return ieee754sp_indef(); | ||
| 94 | |||
| 95 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 96 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 97 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 98 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 99 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 100 | if (zc == IEEE754_CLASS_QNAN) | ||
| 101 | return z; | ||
| 102 | return ieee754sp_inf(xs ^ ys); | ||
| 103 | |||
| 104 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 105 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 106 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 107 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 108 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 109 | if (zc == IEEE754_CLASS_INF) | ||
| 110 | return ieee754sp_inf(zs); | ||
| 111 | /* Multiplication is 0 so just return z */ | ||
| 112 | return z; | ||
| 113 | |||
| 114 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 115 | SPDNORMX; | ||
| 116 | |||
| 117 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 118 | if (zc == IEEE754_CLASS_QNAN) | ||
| 119 | return z; | ||
| 120 | else if (zc == IEEE754_CLASS_INF) | ||
| 121 | return ieee754sp_inf(zs); | ||
| 122 | SPDNORMY; | ||
| 123 | break; | ||
| 124 | |||
| 125 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 126 | if (zc == IEEE754_CLASS_QNAN) | ||
| 127 | return z; | ||
| 128 | else if (zc == IEEE754_CLASS_INF) | ||
| 129 | return ieee754sp_inf(zs); | ||
| 130 | SPDNORMX; | ||
| 131 | break; | ||
| 132 | |||
| 133 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): | ||
| 134 | if (zc == IEEE754_CLASS_QNAN) | ||
| 135 | return z; | ||
| 136 | else if (zc == IEEE754_CLASS_INF) | ||
| 137 | return ieee754sp_inf(zs); | ||
| 138 | /* fall through to real computations */ | ||
| 139 | } | ||
| 140 | |||
| 141 | /* Finally get to do some computation */ | ||
| 142 | |||
| 143 | /* | ||
| 144 | * Do the multiplication bit first | ||
| 145 | * | ||
| 146 | * rm = xm * ym, re = xe + ye basically | ||
| 147 | * | ||
| 148 | * At this point xm and ym should have been normalized. | ||
| 149 | */ | ||
| 150 | |||
| 151 | /* rm = xm * ym, re = xe+ye basically */ | ||
| 152 | assert(xm & SP_HIDDEN_BIT); | ||
| 153 | assert(ym & SP_HIDDEN_BIT); | ||
| 154 | |||
| 155 | re = xe + ye; | ||
| 156 | rs = xs ^ ys; | ||
| 157 | |||
| 158 | /* shunt to top of word */ | ||
| 159 | xm <<= 32 - (SP_FBITS + 1); | ||
| 160 | ym <<= 32 - (SP_FBITS + 1); | ||
| 161 | |||
| 162 | /* | ||
| 163 | * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. | ||
| 164 | */ | ||
| 165 | lxm = xm & 0xffff; | ||
| 166 | hxm = xm >> 16; | ||
| 167 | lym = ym & 0xffff; | ||
| 168 | hym = ym >> 16; | ||
| 169 | |||
| 170 | lrm = lxm * lym; /* 16 * 16 => 32 */ | ||
| 171 | hrm = hxm * hym; /* 16 * 16 => 32 */ | ||
| 172 | |||
| 173 | t = lxm * hym; /* 16 * 16 => 32 */ | ||
| 174 | at = lrm + (t << 16); | ||
| 175 | hrm += at < lrm; | ||
| 176 | lrm = at; | ||
| 177 | hrm = hrm + (t >> 16); | ||
| 178 | |||
| 179 | t = hxm * lym; /* 16 * 16 => 32 */ | ||
| 180 | at = lrm + (t << 16); | ||
| 181 | hrm += at < lrm; | ||
| 182 | lrm = at; | ||
| 183 | hrm = hrm + (t >> 16); | ||
| 184 | |||
| 185 | rm = hrm | (lrm != 0); | ||
| 186 | |||
| 187 | /* | ||
| 188 | * Sticky shift down to normal rounding precision. | ||
| 189 | */ | ||
| 190 | if ((int) rm < 0) { | ||
| 191 | rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | | ||
| 192 | ((rm << (SP_FBITS + 1 + 3)) != 0); | ||
| 193 | re++; | ||
| 194 | } else { | ||
| 195 | rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | | ||
| 196 | ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); | ||
| 197 | } | ||
| 198 | assert(rm & (SP_HIDDEN_BIT << 3)); | ||
| 199 | |||
| 200 | /* And now the addition */ | ||
| 201 | |||
| 202 | assert(zm & SP_HIDDEN_BIT); | ||
| 203 | |||
| 204 | /* | ||
| 205 | * Provide guard,round and stick bit space. | ||
| 206 | */ | ||
| 207 | zm <<= 3; | ||
| 208 | |||
| 209 | if (ze > re) { | ||
| 210 | /* | ||
| 211 | * Have to shift y fraction right to align. | ||
| 212 | */ | ||
| 213 | s = ze - re; | ||
| 214 | SPXSRSYn(s); | ||
| 215 | } else if (re > ze) { | ||
| 216 | /* | ||
| 217 | * Have to shift x fraction right to align. | ||
| 218 | */ | ||
| 219 | s = re - ze; | ||
| 220 | SPXSRSYn(s); | ||
| 221 | } | ||
| 222 | assert(ze == re); | ||
| 223 | assert(ze <= SP_EMAX); | ||
| 224 | |||
| 225 | if (zs == rs) { | ||
| 226 | /* | ||
| 227 | * Generate 28 bit result of adding two 27 bit numbers | ||
| 228 | * leaving result in zm, zs and ze. | ||
| 229 | */ | ||
| 230 | zm = zm + rm; | ||
| 231 | |||
| 232 | if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ | ||
| 233 | SPXSRSX1(); | ||
| 234 | } | ||
| 235 | } else { | ||
| 236 | if (zm >= rm) { | ||
| 237 | zm = zm - rm; | ||
| 238 | } else { | ||
| 239 | zm = rm - zm; | ||
| 240 | zs = rs; | ||
| 241 | } | ||
| 242 | if (zm == 0) | ||
| 243 | return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); | ||
| 244 | |||
| 245 | /* | ||
| 246 | * Normalize in extended single precision | ||
| 247 | */ | ||
| 248 | while ((zm >> (SP_MBITS + 3)) == 0) { | ||
| 249 | zm <<= 1; | ||
| 250 | ze--; | ||
| 251 | } | ||
| 252 | |||
| 253 | } | ||
| 254 | return ieee754sp_format(zs, ze, zm); | ||
| 255 | } | ||
| @@ -0,0 +1,258 @@ | |||
| 1 | /* | ||
| 2 | * IEEE754 floating point arithmetic | ||
| 3 | * single precision: MSUB.f (Fused Multiply Subtract) | ||
| 4 | * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) | ||
| 5 | * | ||
| 6 | * MIPS floating point support | ||
| 7 | * Copyright (C) 2015 Imagination Technologies, Ltd. | ||
| 8 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can distribute it and/or modify it | ||
| 11 | * under the terms of the GNU General Public License as published by the | ||
| 12 | * Free Software Foundation; version 2 of the License. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include "ieee754sp.h" | ||
| 16 | |||
| 17 | union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, | ||
| 18 | union ieee754sp y) | ||
| 19 | { | ||
| 20 | int re; | ||
| 21 | int rs; | ||
| 22 | unsigned rm; | ||
| 23 | unsigned short lxm; | ||
| 24 | unsigned short hxm; | ||
| 25 | unsigned short lym; | ||
| 26 | unsigned short hym; | ||
| 27 | unsigned lrm; | ||
| 28 | unsigned hrm; | ||
| 29 | unsigned t; | ||
| 30 | unsigned at; | ||
| 31 | int s; | ||
| 32 | |||
| 33 | COMPXSP; | ||
| 34 | COMPYSP; | ||
| 35 | u32 zm; int ze; int zs __maybe_unused; int zc; | ||
| 36 | |||
| 37 | EXPLODEXSP; | ||
| 38 | EXPLODEYSP; | ||
| 39 | EXPLODESP(z, zc, zs, ze, zm) | ||
| 40 | |||
| 41 | FLUSHXSP; | ||
| 42 | FLUSHYSP; | ||
| 43 | FLUSHSP(z, zc, zs, ze, zm); | ||
| 44 | |||
| 45 | ieee754_clearcx(); | ||
| 46 | |||
| 47 | switch (zc) { | ||
| 48 | case IEEE754_CLASS_SNAN: | ||
| 49 | ieee754_setcx(IEEE754_INVALID_OPERATION); | ||
| 50 | return ieee754sp_nanxcpt(z); | ||
| 51 | case IEEE754_CLASS_DNORM: | ||
| 52 | SPDNORMx(zm, ze); | ||
| 53 | /* QNAN is handled separately below */ | ||
| 54 | } | ||
| 55 | |||
| 56 | switch (CLPAIR(xc, yc)) { | ||
| 57 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): | ||
| 58 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): | ||
| 59 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): | ||
| 60 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): | ||
| 61 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): | ||
| 62 | return ieee754sp_nanxcpt(y); | ||
| 63 | |||
| 64 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): | ||
| 65 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): | ||
| 66 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): | ||
| 67 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | ||
| 68 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | ||
| 69 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | ||
| 70 | return ieee754sp_nanxcpt(x); | ||
| 71 | |||
| 72 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | ||
| 73 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | ||
| 74 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): | ||
| 75 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): | ||
| 76 | return y; | ||
| 77 | |||
| 78 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): | ||
| 79 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): | ||
| 80 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): | ||
| 81 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): | ||
| 82 | case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): | ||
| 83 | return x; | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Infinity handling | ||
| 87 | */ | ||
| 88 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | ||
| 89 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | ||
| 90 | if (zc == IEEE754_CLASS_QNAN) | ||
| 91 | return z; | ||
| 92 | ieee754_setcx(IEEE754_INVALID_OPERATION); | ||
| 93 | return ieee754sp_indef(); | ||
| 94 | |||
| 95 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | ||
| 96 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | ||
| 97 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): | ||
| 98 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | ||
| 99 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | ||
| 100 | if (zc == IEEE754_CLASS_QNAN) | ||
| 101 | return z; | ||
| 102 | return ieee754sp_inf(xs ^ ys); | ||
| 103 | |||
| 104 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | ||
| 105 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | ||
| 106 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | ||
| 107 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | ||
| 108 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | ||
| 109 | if (zc == IEEE754_CLASS_INF) | ||
| 110 | return ieee754sp_inf(zs); | ||
| 111 | /* Multiplication is 0 so just return z */ | ||
| 112 | return z; | ||
| 113 | |||
| 114 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | ||
| 115 | SPDNORMX; | ||
| 116 | |||
| 117 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | ||
| 118 | if (zc == IEEE754_CLASS_QNAN) | ||
| 119 | return z; | ||
| 120 | else if (zc == IEEE754_CLASS_INF) | ||
| 121 | return ieee754sp_inf(zs); | ||
| 122 | SPDNORMY; | ||
| 123 | break; | ||
| 124 | |||
| 125 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): | ||
| 126 | if (zc == IEEE754_CLASS_QNAN) | ||
| 127 | return z; | ||
| 128 | else if (zc == IEEE754_CLASS_INF) | ||
| 129 | return ieee754sp_inf(zs); | ||
| 130 | SPDNORMX; | ||
| 131 | break; | ||
| 132 | |||
| 133 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): | ||
| 134 | if (zc == IEEE754_CLASS_QNAN) | ||
| 135 | return z; | ||
| 136 | else if (zc == IEEE754_CLASS_INF) | ||
| 137 | return ieee754sp_inf(zs); | ||
| 138 | /* fall through to real compuation */ | ||
| 139 | } | ||
| 140 | |||
| 141 | /* Finally get to do some computation */ | ||
| 142 | |||
| 143 | /* | ||
| 144 | * Do the multiplication bit first | ||
| 145 | * | ||
| 146 | * rm = xm * ym, re = xe + ye basically | ||
| 147 | * | ||
| 148 | * At this point xm and ym should have been normalized. | ||
| 149 | */ | ||
| 150 | |||
| 151 | /* rm = xm * ym, re = xe+ye basically */ | ||
| 152 | assert(xm & SP_HIDDEN_BIT); | ||
| 153 | assert(ym & SP_HIDDEN_BIT); | ||
| 154 | |||
| 155 | re = xe + ye; | ||
| 156 | rs = xs ^ ys; | ||
| 157 | |||
| 158 | /* shunt to top of word */ | ||
| 159 | xm <<= 32 - (SP_FBITS + 1); | ||
| 160 | ym <<= 32 - (SP_FBITS + 1); | ||
| 161 | |||
| 162 | /* | ||
| 163 | * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. | ||
| 164 | */ | ||
| 165 | lxm = xm & 0xffff; | ||
| 166 | hxm = xm >> 16; | ||
| 167 | lym = ym & 0xffff; | ||
| 168 | hym = ym >> 16; | ||
| 169 | |||
| 170 | lrm = lxm * lym; /* 16 * 16 => 32 */ | ||
| 171 | hrm = hxm * hym; /* 16 * 16 => 32 */ | ||
| 172 | |||
| 173 | t = lxm * hym; /* 16 * 16 => 32 */ | ||
| 174 | at = lrm + (t << 16); | ||
| 175 | hrm += at < lrm; | ||
| 176 | lrm = at; | ||
| 177 | hrm = hrm + (t >> 16); | ||
| 178 | |||
| 179 | t = hxm * lym; /* 16 * 16 => 32 */ | ||
| 180 | at = lrm + (t << 16); | ||
| 181 | hrm += at < lrm; | ||
| 182 | lrm = at; | ||
| 183 | hrm = hrm + (t >> 16); | ||
| 184 | |||
| 185 | rm = hrm | (lrm != 0); | ||
| 186 | |||
| 187 | /* | ||
| 188 | * Sticky shift down to normal rounding precision. | ||
| 189 | */ | ||
| 190 | if ((int) rm < 0) { | ||
| 191 | rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | | ||
| 192 | ((rm << (SP_FBITS + 1 + 3)) != 0); | ||
| 193 | re++; | ||
| 194 | } else { | ||
| 195 | rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | | ||
| 196 | ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); | ||
| 197 | } | ||
| 198 | assert(rm & (SP_HIDDEN_BIT << 3)); | ||
| 199 | |||
| 200 | /* And now the subtraction */ | ||
| 201 | |||
| 202 | /* Flip sign of r and handle as add */ | ||
| 203 | rs ^= 1; | ||
| 204 | |||
| 205 | assert(zm & SP_HIDDEN_BIT); | ||
| 206 | |||
| 207 | /* | ||
| 208 | * Provide guard,round and stick bit space. | ||
| 209 | */ | ||
| 210 | zm <<= 3; | ||
| 211 | |||
| 212 | if (ze > re) { | ||
| 213 | /* | ||
| 214 | * Have to shift y fraction right to align. | ||
| 215 | */ | ||
| 216 | s = ze - re; | ||
| 217 | SPXSRSYn(s); | ||
| 218 | } else if (re > ze) { | ||
| 219 | /* | ||
| 220 | * Have to shift x fraction right to align. | ||
| 221 | */ | ||
| 222 | s = re - ze; | ||
| 223 | SPXSRSYn(s); | ||
| 224 | } | ||
| 225 | assert(ze == re); | ||
| 226 | assert(ze <= SP_EMAX); | ||
| 227 | |||
| 228 | if (zs == rs) { | ||
| 229 | /* | ||
| 230 | * Generate 28 bit result of adding two 27 bit numbers | ||
| 231 | * leaving result in zm, zs and ze. | ||
| 232 | */ | ||
| 233 | zm = zm + rm; | ||
| 234 | |||
| 235 | if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ | ||
| 236 | SPXSRSX1(); /* shift preserving sticky */ | ||
| 237 | } | ||
| 238 | } else { | ||
| 239 | if (zm >= rm) { | ||
| 240 | zm = zm - rm; | ||
| 241 | } else { | ||
| 242 | zm = rm - zm; | ||
| 243 | zs = rs; | ||
| 244 | } | ||
| 245 | if (zm == 0) | ||
| 246 | return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); | ||
| 247 | |||
| 248 | /* | ||
| 249 | * Normalize in extended single precision | ||
| 250 | */ | ||
| 251 | while ((zm >> (SP_MBITS + 3)) == 0) { | ||
| 252 | zm <<= 1; | ||
| 253 | ze--; | ||
| 254 | } | ||
| 255 | |||
| 256 | } | ||
| 257 | return ieee754sp_format(zs, ze, zm); | ||
| 258 | } | ||
| @@ -1276,6 +1276,7 @@ static void probe_pcache(void) · 1275 unmodified lines | |||
| 1276 | case CPU_PROAPTIV: | 1276 | case CPU_PROAPTIV: |
| 1277 | case CPU_M5150: | 1277 | case CPU_M5150: |
| 1278 | case CPU_QEMU_GENERIC: | 1278 | case CPU_QEMU_GENERIC: |
| 1279 | case CPU_I6400: | ||
| 1279 | if (!(read_c0_config7() & MIPS_CONF7_IAR) && | 1280 | if (!(read_c0_config7() & MIPS_CONF7_IAR) && |
| 1280 | (c->icache.waysize > PAGE_SIZE)) | 1281 | (c->icache.waysize > PAGE_SIZE)) |
| 1281 | c->icache.flags |= MIPS_CACHE_ALIASES; | 1282 | c->icache.flags |= MIPS_CACHE_ALIASES; |
| @@ -194,6 +194,40 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, · 193 unmodified lines | |||
| 194 | __free_pages(page, get_order(size)); | 194 | __free_pages(page, get_order(size)); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma, | ||
| 198 | void *cpu_addr, dma_addr_t dma_addr, size_t size, | ||
| 199 | struct dma_attrs *attrs) | ||
| 200 | { | ||
| 201 | unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
| 202 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; | ||
| 203 | unsigned long addr = (unsigned long)cpu_addr; | ||
| 204 | unsigned long off = vma->vm_pgoff; | ||
| 205 | unsigned long pfn; | ||
| 206 | int ret = -ENXIO; | ||
| 207 | |||
| 208 | if (!plat_device_is_coherent(dev) && !hw_coherentio) | ||
| 209 | addr = CAC_ADDR(addr); | ||
| 210 | |||
| 211 | pfn = page_to_pfn(virt_to_page((void *)addr)); | ||
| 212 | |||
| 213 | if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs)) | ||
| 214 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
| 215 | else | ||
| 216 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
| 217 | |||
| 218 | if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) | ||
| 219 | return ret; | ||
| 220 | |||
| 221 | if (off < count && user_count <= (count - off)) { | ||
| 222 | ret = remap_pfn_range(vma, vma->vm_start, | ||
| 223 | pfn + off, | ||
| 224 | user_count << PAGE_SHIFT, | ||
| 225 | vma->vm_page_prot); | ||
| 226 | } | ||
| 227 | |||
| 228 | return ret; | ||
| 229 | } | ||
| 230 | |||
| 197 | static inline void __dma_sync_virtual(void *addr, size_t size, | 231 | static inline void __dma_sync_virtual(void *addr, size_t size, |
| 198 | enum dma_data_direction direction) | 232 | enum dma_data_direction direction) |
| 199 | { | 233 | { |
| @@ -380,6 +414,7 @@ EXPORT_SYMBOL(dma_cache_sync); · 180 unmodified lines | |||
| 380 | static struct dma_map_ops mips_default_dma_map_ops = { | 414 | static struct dma_map_ops mips_default_dma_map_ops = { |
| 381 | .alloc = mips_dma_alloc_coherent, | 415 | .alloc = mips_dma_alloc_coherent, |
| 382 | .free = mips_dma_free_coherent, | 416 | .free = mips_dma_free_coherent, |
| 417 | .mmap = mips_dma_mmap, | ||
| 383 | .map_page = mips_dma_map_page, | 418 | .map_page = mips_dma_map_page, |
| 384 | .unmap_page = mips_dma_unmap_page, | 419 | .unmap_page = mips_dma_unmap_page, |
| 385 | .map_sg = mips_dma_map_sg, | 420 | .map_sg = mips_dma_map_sg, |
| @@ -57,12 +57,10 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write, · 56 unmodified lines | |||
| 57 | 57 | ||
| 58 | #ifdef CONFIG_KPROBES | 58 | #ifdef CONFIG_KPROBES |
| 59 | /* | 59 | /* |
| 60 | * This is to notify the fault handler of the kprobes. The | 60 | * This is to notify the fault handler of the kprobes. |
| 61 | * exception code is redundant as it is also carried in REGS, | ||
| 62 | * but we pass it anyhow. | ||
| 63 | */ | 61 | */ |
| 64 | if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, | 62 | if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, |
| 65 | (regs->cp0_cause >> 2) & 0x1f, SIGSEGV) == NOTIFY_STOP) | 63 | current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP) |
| 66 | return; | 64 | return; |
| 67 | #endif | 65 | #endif |
| 68 | 66 | ||
| @@ -224,6 +222,7 @@ bad_area_nosemaphore: · 155 unmodified lines | |||
| 224 | print_vma_addr(" ", regs->regs[31]); | 222 | print_vma_addr(" ", regs->regs[31]); |
| 225 | pr_info("\n"); | 223 | pr_info("\n"); |
| 226 | } | 224 | } |
| 225 | current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | ||
| 227 | info.si_signo = SIGSEGV; | 226 | info.si_signo = SIGSEGV; |
| 228 | info.si_errno = 0; | 227 | info.si_errno = 0; |
| 229 | /* info.si_code has been set above */ | 228 | /* info.si_code has been set above */ |
| @@ -282,6 +281,7 @@ do_sigbus: · 52 unmodified lines | |||
| 282 | field, (unsigned long) regs->cp0_epc, | 281 | field, (unsigned long) regs->cp0_epc, |
| 283 | field, (unsigned long) regs->regs[31]); | 282 | field, (unsigned long) regs->regs[31]); |
| 284 | #endif | 283 | #endif |
| 284 | current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | ||
| 285 | tsk->thread.cp0_badvaddr = address; | 285 | tsk->thread.cp0_badvaddr = address; |
| 286 | info.si_signo = SIGBUS; | 286 | info.si_signo = SIGBUS; |
| 287 | info.si_errno = 0; | 287 | info.si_errno = 0; |
| @@ -37,6 +37,7 @@ · 36 unmodified lines | |||
| 37 | #include <asm/cpu.h> | 37 | #include <asm/cpu.h> |
| 38 | #include <asm/dma.h> | 38 | #include <asm/dma.h> |
| 39 | #include <asm/kmap_types.h> | 39 | #include <asm/kmap_types.h> |
| 40 | #include <asm/maar.h> | ||
| 40 | #include <asm/mmu_context.h> | 41 | #include <asm/mmu_context.h> |
| 41 | #include <asm/sections.h> | 42 | #include <asm/sections.h> |
| 42 | #include <asm/pgtable.h> | 43 | #include <asm/pgtable.h> |
| @@ -333,9 +334,40 @@ static inline void mem_init_free_highmem(void) · 290 unmodified lines | |||
| 333 | #endif | 334 | #endif |
| 334 | } | 335 | } |
| 335 | 336 | ||
| 336 | unsigned __weak platform_maar_init(unsigned num_maars) | 337 | unsigned __weak platform_maar_init(unsigned num_pairs) |
| 337 | { | 338 | { |
| 338 | return 0; | 339 | struct maar_config cfg[BOOT_MEM_MAP_MAX]; |
| 340 | unsigned i, num_configured, num_cfg = 0; | ||
| 341 | phys_addr_t skip; | ||
| 342 | |||
| 343 | for (i = 0; i < boot_mem_map.nr_map; i++) { | ||
| 344 | switch (boot_mem_map.map[i].type) { | ||
| 345 | case BOOT_MEM_RAM: | ||
| 346 | case BOOT_MEM_INIT_RAM: | ||
| 347 | break; | ||
| 348 | default: | ||
| 349 | continue; | ||
| 350 | } | ||
| 351 | |||
| 352 | skip = 0x10000 - (boot_mem_map.map[i].addr & 0xffff); | ||
| 353 | |||
| 354 | cfg[num_cfg].lower = boot_mem_map.map[i].addr; | ||
| 355 | cfg[num_cfg].lower += skip; | ||
| 356 | |||
| 357 | cfg[num_cfg].upper = cfg[num_cfg].lower; | ||
| 358 | cfg[num_cfg].upper += boot_mem_map.map[i].size - 1; | ||
| 359 | cfg[num_cfg].upper -= skip; | ||
| 360 | |||
| 361 | cfg[num_cfg].attrs = MIPS_MAAR_S; | ||
| 362 | num_cfg++; | ||
| 363 | } | ||
| 364 | |||
| 365 | num_configured = maar_config(cfg, num_cfg, num_pairs); | ||
| 366 | if (num_configured < num_cfg) | ||
| 367 | pr_warn("Not enough MAAR pairs (%u) for all bootmem regions (%u)\n", | ||
| 368 | num_pairs, num_cfg); | ||
| 369 | |||
| 370 | return num_configured; | ||
| 339 | } | 371 | } |
| 340 | 372 | ||
| 341 | static void maar_init(void) | 373 | static void maar_init(void) |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <asm/pgtable.h> | 14 | #include <asm/pgtable.h> |
| 15 | #include <asm/mmu_context.h> | 15 | #include <asm/mmu_context.h> |
| 16 | #include <asm/r4kcache.h> | 16 | #include <asm/r4kcache.h> |
| 17 | #include <asm/mips-cm.h> | ||
| 17 | 18 | ||
| 18 | /* | 19 | /* |
| 19 | * MIPS32/MIPS64 L2 cache handling | 20 | * MIPS32/MIPS64 L2 cache handling |
| @@ -94,6 +95,38 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c) · 74 unmodified lines | |||
| 94 | return 1; | 95 | return 1; |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 98 | static int __init mips_sc_probe_cm3(void) | ||
| 99 | { | ||
| 100 | struct cpuinfo_mips *c = ¤t_cpu_data; | ||
| 101 | unsigned long cfg = read_gcr_l2_config(); | ||
| 102 | unsigned long sets, line_sz, assoc; | ||
| 103 | |||
| 104 | if (cfg & CM_GCR_L2_CONFIG_BYPASS_MSK) | ||
| 105 | return 0; | ||
| 106 | |||
| 107 | sets = cfg & CM_GCR_L2_CONFIG_SET_SIZE_MSK; | ||
| 108 | sets >>= CM_GCR_L2_CONFIG_SET_SIZE_SHF; | ||
| 109 | c->scache.sets = 64 << sets; | ||
| 110 | |||
| 111 | line_sz = cfg & CM_GCR_L2_CONFIG_LINE_SIZE_MSK; | ||
| 112 | line_sz >>= CM_GCR_L2_CONFIG_LINE_SIZE_SHF; | ||
| 113 | c->scache.linesz = 2 << line_sz; | ||
| 114 | |||
| 115 | assoc = cfg & CM_GCR_L2_CONFIG_ASSOC_MSK; | ||
| 116 | assoc >>= CM_GCR_L2_CONFIG_ASSOC_SHF; | ||
| 117 | c->scache.ways = assoc + 1; | ||
| 118 | c->scache.waysize = c->scache.sets * c->scache.linesz; | ||
| 119 | c->scache.waybit = __ffs(c->scache.waysize); | ||
| 120 | |||
| 121 | c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; | ||
| 122 | |||
| 123 | return 1; | ||
| 124 | } | ||
| 125 | |||
| 126 | void __weak platform_early_l2_init(void) | ||
| 127 | { | ||
| 128 | } | ||
| 129 | |||
| 97 | static inline int __init mips_sc_probe(void) | 130 | static inline int __init mips_sc_probe(void) |
| 98 | { | 131 | { |
| 99 | struct cpuinfo_mips *c = ¤t_cpu_data; | 132 | struct cpuinfo_mips *c = ¤t_cpu_data; |
| @@ -103,6 +136,15 @@ static inline int __init mips_sc_probe(void) · 3 unmodified lines | |||
| 103 | /* Mark as not present until probe completed */ | 136 | /* Mark as not present until probe completed */ |
| 104 | c->scache.flags |= MIPS_CACHE_NOT_PRESENT; | 137 | c->scache.flags |= MIPS_CACHE_NOT_PRESENT; |
| 105 | 138 | ||
| 139 | /* | ||
| 140 | * Do we need some platform specific probing before | ||
| 141 | * we configure L2? | ||
| 142 | */ | ||
| 143 | platform_early_l2_init(); | ||
| 144 | |||
| 145 | if (mips_cm_revision() >= CM_REV_CM3) | ||
| 146 | return mips_sc_probe_cm3(); | ||
| 147 | |||
| 106 | /* Ignore anything but MIPSxx processors */ | 148 | /* Ignore anything but MIPSxx processors */ |
| 107 | if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | | 149 | if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | |
| 108 | MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | | 150 | MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | |
| @@ -36,7 +36,7 @@ extern void build_tlb_refill_handler(void); · 35 unmodified lines | |||
| 36 | "nop\n\t" \ | 36 | "nop\n\t" \ |
| 37 | ".set pop\n\t") | 37 | ".set pop\n\t") |
| 38 | 38 | ||
| 39 | static int r3k_have_wired_reg; /* Should be in cpu_data? */ | 39 | int r3k_have_wired_reg; /* Should be in cpu_data? */ |
| 40 | 40 | ||
| 41 | /* TLB operations. */ | 41 | /* TLB operations. */ |
| 42 | static void local_flush_tlb_from(int entry) | 42 | static void local_flush_tlb_from(int entry) |
| @@ -303,3 +303,10 @@ mips_pci_controller: · 302 unmodified lines | |||
| 303 | if (!register_vsmp_smp_ops()) | 303 | if (!register_vsmp_smp_ops()) |
| 304 | return; | 304 | return; |
| 305 | } | 305 | } |
| 306 | |||
| 307 | void platform_early_l2_init(void) | ||
| 308 | { | ||
| 309 | /* L2 configuration lives in the CM3 */ | ||
| 310 | if (mips_cm_revision() >= CM_REV_CM3) | ||
| 311 | mips_cm_probe(); | ||
| 312 | } | ||
| @@ -382,122 +382,12 @@ void malta_be_init(void) · 381 unmodified lines | |||
| 382 | /* Could change CM error mask register. */ | 382 | /* Could change CM error mask register. */ |
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | |||
| 386 | static char *tr[8] = { | ||
| 387 | "mem", "gcr", "gic", "mmio", | ||
| 388 | "0x04", "0x05", "0x06", "0x07" | ||
| 389 | }; | ||
| 390 | |||
| 391 | static char *mcmd[32] = { | ||
| 392 | [0x00] = "0x00", | ||
| 393 | [0x01] = "Legacy Write", | ||
| 394 | [0x02] = "Legacy Read", | ||
| 395 | [0x03] = "0x03", | ||
| 396 | [0x04] = "0x04", | ||
| 397 | [0x05] = "0x05", | ||
| 398 | [0x06] = "0x06", | ||
| 399 | [0x07] = "0x07", | ||
| 400 | [0x08] = "Coherent Read Own", | ||
| 401 | [0x09] = "Coherent Read Share", | ||
| 402 | [0x0a] = "Coherent Read Discard", | ||
| 403 | [0x0b] = "Coherent Ready Share Always", | ||
| 404 | [0x0c] = "Coherent Upgrade", | ||
| 405 | [0x0d] = "Coherent Writeback", | ||
| 406 | [0x0e] = "0x0e", | ||
| 407 | [0x0f] = "0x0f", | ||
| 408 | [0x10] = "Coherent Copyback", | ||
| 409 | [0x11] = "Coherent Copyback Invalidate", | ||
| 410 | [0x12] = "Coherent Invalidate", | ||
| 411 | [0x13] = "Coherent Write Invalidate", | ||
| 412 | [0x14] = "Coherent Completion Sync", | ||
| 413 | [0x15] = "0x15", | ||
| 414 | [0x16] = "0x16", | ||
| 415 | [0x17] = "0x17", | ||
| 416 | [0x18] = "0x18", | ||
| 417 | [0x19] = "0x19", | ||
| 418 | [0x1a] = "0x1a", | ||
| 419 | [0x1b] = "0x1b", | ||
| 420 | [0x1c] = "0x1c", | ||
| 421 | [0x1d] = "0x1d", | ||
| 422 | [0x1e] = "0x1e", | ||
| 423 | [0x1f] = "0x1f" | ||
| 424 | }; | ||
| 425 | |||
| 426 | static char *core[8] = { | ||
| 427 | "Invalid/OK", "Invalid/Data", | ||
| 428 | "Shared/OK", "Shared/Data", | ||
| 429 | "Modified/OK", "Modified/Data", | ||
| 430 | "Exclusive/OK", "Exclusive/Data" | ||
| 431 | }; | ||
| 432 | |||
| 433 | static char *causes[32] = { | ||
| 434 | "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", | ||
| 435 | "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", | ||
| 436 | "0x08", "0x09", "0x0a", "0x0b", | ||
| 437 | "0x0c", "0x0d", "0x0e", "0x0f", | ||
| 438 | "0x10", "0x11", "0x12", "0x13", | ||
| 439 | "0x14", "0x15", "0x16", "INTVN_WR_ERR", | ||
| 440 | "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", | ||
| 441 | "0x1c", "0x1d", "0x1e", "0x1f" | ||
| 442 | }; | ||
| 443 | |||
| 444 | int malta_be_handler(struct pt_regs *regs, int is_fixup) | 385 | int malta_be_handler(struct pt_regs *regs, int is_fixup) |
| 445 | { | 386 | { |
| 446 | /* This duplicates the handling in do_be which seems wrong */ | 387 | /* This duplicates the handling in do_be which seems wrong */ |
| 447 | int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; | 388 | int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; |
| 448 | 389 | ||
| 449 | if (mips_cm_present()) { | 390 | mips_cm_error_report(); |
| 450 | unsigned long cm_error = read_gcr_error_cause(); | ||
| 451 | unsigned long cm_addr = read_gcr_error_addr(); | ||
| 452 | unsigned long cm_other = read_gcr_error_mult(); | ||
| 453 | unsigned long cause, ocause; | ||
| 454 | char buf[256]; | ||
| 455 | |||
| 456 | cause = cm_error & CM_GCR_ERROR_CAUSE_ERRTYPE_MSK; | ||
| 457 | if (cause != 0) { | ||
| 458 | cause >>= CM_GCR_ERROR_CAUSE_ERRTYPE_SHF; | ||
| 459 | if (cause < 16) { | ||
| 460 | unsigned long cca_bits = (cm_error >> 15) & 7; | ||
| 461 | unsigned long tr_bits = (cm_error >> 12) & 7; | ||
| 462 | unsigned long cmd_bits = (cm_error >> 7) & 0x1f; | ||
| 463 | unsigned long stag_bits = (cm_error >> 3) & 15; | ||
| 464 | unsigned long sport_bits = (cm_error >> 0) & 7; | ||
| 465 | |||
| 466 | snprintf(buf, sizeof(buf), | ||
| 467 | "CCA=%lu TR=%s MCmd=%s STag=%lu " | ||
| 468 | "SPort=%lu\n", | ||
| 469 | cca_bits, tr[tr_bits], mcmd[cmd_bits], | ||
| 470 | stag_bits, sport_bits); | ||
| 471 | } else { | ||
| 472 | /* glob state & sresp together */ | ||
| 473 | unsigned long c3_bits = (cm_error >> 18) & 7; | ||
| 474 | unsigned long c2_bits = (cm_error >> 15) & 7; | ||
| 475 | unsigned long c1_bits = (cm_error >> 12) & 7; | ||
| 476 | unsigned long c0_bits = (cm_error >> 9) & 7; | ||
| 477 | unsigned long sc_bit = (cm_error >> 8) & 1; | ||
| 478 | unsigned long cmd_bits = (cm_error >> 3) & 0x1f; | ||
| 479 | unsigned long sport_bits = (cm_error >> 0) & 7; | ||
| 480 | snprintf(buf, sizeof(buf), | ||
| 481 | "C3=%s C2=%s C1=%s C0=%s SC=%s " | ||
| 482 | "MCmd=%s SPort=%lu\n", | ||
| 483 | core[c3_bits], core[c2_bits], | ||
| 484 | core[c1_bits], core[c0_bits], | ||
| 485 | sc_bit ? "True" : "False", | ||
| 486 | mcmd[cmd_bits], sport_bits); | ||
| 487 | } | ||
| 488 | |||
| 489 | ocause = (cm_other & CM_GCR_ERROR_MULT_ERR2ND_MSK) >> | ||
| 490 | CM_GCR_ERROR_MULT_ERR2ND_SHF; | ||
| 491 | |||
| 492 | pr_err("CM_ERROR=%08lx %s <%s>\n", cm_error, | ||
| 493 | causes[cause], buf); | ||
| 494 | pr_err("CM_ADDR =%08lx\n", cm_addr); | ||
| 495 | pr_err("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]); | ||
| 496 | |||
| 497 | /* reprime cause register */ | ||
| 498 | write_gcr_error_cause(0); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | 391 | ||
| 502 | return retval; | 392 | return retval; |
| 503 | } | 393 | } |
| @@ -179,31 +179,6 @@ void __init prom_free_prom_memory(void) · 178 unmodified lines | |||
| 179 | } | 179 | } |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | unsigned platform_maar_init(unsigned num_pairs) | ||
| 183 | { | ||
| 184 | phys_addr_t mem_end = (physical_memsize & ~0xffffull) - 1; | ||
| 185 | struct maar_config cfg[] = { | ||
| 186 | /* DRAM preceding I/O */ | ||
| 187 | { 0x00000000, 0x0fffffff, MIPS_MAAR_S }, | ||
| 188 | |||
| 189 | /* DRAM following I/O */ | ||
| 190 | { 0x20000000, mem_end, MIPS_MAAR_S }, | ||
| 191 | |||
| 192 | /* DRAM alias in upper half of physical */ | ||
| 193 | { 0x80000000, 0x80000000 + mem_end, MIPS_MAAR_S }, | ||
| 194 | }; | ||
| 195 | unsigned i, num_cfg = ARRAY_SIZE(cfg); | ||
| 196 | |||
| 197 | /* If DRAM fits before I/O, drop the region following it */ | ||
| 198 | if (physical_memsize <= 0x10000000) { | ||
| 199 | num_cfg--; | ||
| 200 | for (i = 1; i < num_cfg; i++) | ||
| 201 | cfg[i] = cfg[i + 1]; | ||
| 202 | } | ||
| 203 | |||
| 204 | return maar_config(cfg, num_cfg, num_pairs); | ||
| 205 | } | ||
| 206 | |||
| 207 | phys_addr_t mips_cdmm_phys_base(void) | 182 | phys_addr_t mips_cdmm_phys_base(void) |
| 208 | { | 183 | { |
| 209 | /* This address is "typically unused" */ | 184 | /* This address is "typically unused" */ |
| @@ -87,7 +87,7 @@ struct nlm_pic_irq { · 86 unmodified lines | |||
| 87 | static void xlp_pic_enable(struct irq_data *d) | 87 | static void xlp_pic_enable(struct irq_data *d) |
| 88 | { | 88 | { |
| 89 | unsigned long flags; | 89 | unsigned long flags; |
| 90 | struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); | 90 | struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); |
| 91 | 91 | ||
| 92 | BUG_ON(!pd); | 92 | BUG_ON(!pd); |
| 93 | spin_lock_irqsave(&pd->node->piclock, flags); | 93 | spin_lock_irqsave(&pd->node->piclock, flags); |
| @@ -97,7 +97,7 @@ static void xlp_pic_enable(struct irq_data *d) · 3 unmodified lines | |||
| 97 | 97 | ||
| 98 | static void xlp_pic_disable(struct irq_data *d) | 98 | static void xlp_pic_disable(struct irq_data *d) |
| 99 | { | 99 | { |
| 100 | struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); | 100 | struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); |
| 101 | unsigned long flags; | 101 | unsigned long flags; |
| 102 | 102 | ||
| 103 | BUG_ON(!pd); | 103 | BUG_ON(!pd); |
| @@ -108,7 +108,7 @@ static void xlp_pic_disable(struct irq_data *d) · 4 unmodified lines | |||
| 108 | 108 | ||
| 109 | static void xlp_pic_mask_ack(struct irq_data *d) | 109 | static void xlp_pic_mask_ack(struct irq_data *d) |
| 110 | { | 110 | { |
| 111 | struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); | 111 | struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); |
| 112 | 112 | ||
| 113 | clear_c0_eimr(pd->picirq); | 113 | clear_c0_eimr(pd->picirq); |
| 114 | ack_c0_eirr(pd->picirq); | 114 | ack_c0_eirr(pd->picirq); |
| @@ -116,7 +116,7 @@ static void xlp_pic_mask_ack(struct irq_data *d) · 1 unmodified line | |||
| 116 | 116 | ||
| 117 | static void xlp_pic_unmask(struct irq_data *d) | 117 | static void xlp_pic_unmask(struct irq_data *d) |
| 118 | { | 118 | { |
| 119 | struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); | 119 | struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); |
| 120 | 120 | ||
| 121 | BUG_ON(!pd); | 121 | BUG_ON(!pd); |
| 122 | 122 | ||
| @@ -193,7 +193,7 @@ void nlm_setup_pic_irq(int node, int picirq, int irq, int irt) · 70 unmodified lines | |||
| 193 | pic_data->picirq = picirq; | 193 | pic_data->picirq = picirq; |
| 194 | pic_data->node = nlm_get_node(node); | 194 | pic_data->node = nlm_get_node(node); |
| 195 | irq_set_chip_and_handler(xirq, &xlp_pic, handle_level_irq); | 195 | irq_set_chip_and_handler(xirq, &xlp_pic, handle_level_irq); |
| 196 | irq_set_handler_data(xirq, pic_data); | 196 | irq_set_chip_data(xirq, pic_data); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) | 199 | void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) |
| @@ -202,7 +202,7 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) · 2 unmodified lines | |||
| 202 | int xirq; | 202 | int xirq; |
| 203 | 203 | ||
| 204 | xirq = nlm_irq_to_xirq(node, irq); | 204 | xirq = nlm_irq_to_xirq(node, irq); |
| 205 | pic_data = irq_get_handler_data(xirq); | 205 | pic_data = irq_get_chip_data(xirq); |
| 206 | if (WARN_ON(!pic_data)) | 206 | if (WARN_ON(!pic_data)) |
| 207 | return; | 207 | return; |
| 208 | pic_data->extra_ack = xack; | 208 | pic_data->extra_ack = xack; |
| @@ -82,8 +82,9 @@ void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) · 81 unmodified lines | |||
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | /* IRQ_IPI_SMP_FUNCTION Handler */ | 84 | /* IRQ_IPI_SMP_FUNCTION Handler */ |
| 85 | void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) | 85 | void nlm_smp_function_ipi_handler(unsigned int __irq, struct irq_desc *desc) |
| 86 | { | 86 | { |
| 87 | unsigned int irq = irq_desc_get_irq(desc); | ||
| 87 | clear_c0_eimr(irq); | 88 | clear_c0_eimr(irq); |
| 88 | ack_c0_eirr(irq); | 89 | ack_c0_eirr(irq); |
| 89 | generic_smp_call_function_interrupt(); | 90 | generic_smp_call_function_interrupt(); |
| @@ -91,8 +92,9 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) · 1 unmodified line | |||
| 91 | } | 92 | } |
| 92 | 93 | ||
| 93 | /* IRQ_IPI_SMP_RESCHEDULE handler */ | 94 | /* IRQ_IPI_SMP_RESCHEDULE handler */ |
| 94 | void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) | 95 | void nlm_smp_resched_ipi_handler(unsigned int __irq, struct irq_desc *desc) |
| 95 | { | 96 | { |
| 97 | unsigned int irq = irq_desc_get_irq(desc); | ||
| 96 | clear_c0_eimr(irq); | 98 | clear_c0_eimr(irq); |
| 97 | ack_c0_eirr(irq); | 99 | ack_c0_eirr(irq); |
| 98 | scheduler_ipi(); | 100 | scheduler_ipi(); |
| @@ -152,7 +152,7 @@ static const u8 sata_phy_config1[] = { · 151 unmodified lines | |||
| 152 | 0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x01, 0x01, 0x22, 0x00 | 152 | 0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x01, 0x01, 0x22, 0x00 |
| 153 | }; | 153 | }; |
| 154 | 154 | ||
| 155 | /* SATA PHY config for register block 2 0x0x8065 .. 0x0x80A4 */ | 155 | /* SATA PHY config for register block 2 0x8065 .. 0x80A4 */ |
| 156 | static const u8 sata_phy_config2[] = { | 156 | static const u8 sata_phy_config2[] = { |
| 157 | 0xAA, 0x00, 0x4C, 0xC9, 0xC9, 0x07, 0x07, 0x18, | 157 | 0xAA, 0x00, 0x4C, 0xC9, 0xC9, 0x07, 0x07, 0x18, |
| 158 | 0x18, 0x05, 0x0C, 0x10, 0x00, 0x10, 0x00, 0xFF, | 158 | 0x18, 0x05, 0x0C, 0x10, 0x00, 0x10, 0x00, 0xFF, |
| @@ -91,6 +91,8 @@ static int xlp9xx_irq_to_irt(int irq) · 90 unmodified lines | |||
| 91 | return 134; | 91 | return 134; |
| 92 | case PIC_SATA_IRQ: | 92 | case PIC_SATA_IRQ: |
| 93 | return 143; | 93 | return 143; |
| 94 | case PIC_NAND_IRQ: | ||
| 95 | return 151; | ||
| 94 | case PIC_SPI_IRQ: | 96 | case PIC_SPI_IRQ: |
| 95 | return 152; | 97 | return 152; |
| 96 | case PIC_MMC_IRQ: | 98 | case PIC_MMC_IRQ: |
| @@ -91,6 +91,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) · 90 unmodified lines | |||
| 91 | case CPU_INTERAPTIV: | 91 | case CPU_INTERAPTIV: |
| 92 | case CPU_PROAPTIV: | 92 | case CPU_PROAPTIV: |
| 93 | case CPU_P5600: | 93 | case CPU_P5600: |
| 94 | case CPU_I6400: | ||
| 94 | case CPU_M5150: | 95 | case CPU_M5150: |
| 95 | case CPU_LOONGSON1: | 96 | case CPU_LOONGSON1: |
| 96 | case CPU_SB1: | 97 | case CPU_SB1: |
| @@ -392,6 +392,10 @@ static int __init mipsxx_init(void) · 391 unmodified lines | |||
| 392 | op_model_mipsxx_ops.cpu_type = "mips/P5600"; | 392 | op_model_mipsxx_ops.cpu_type = "mips/P5600"; |
| 393 | break; | 393 | break; |
| 394 | 394 | ||
| 395 | case CPU_I6400: | ||
| 396 | op_model_mipsxx_ops.cpu_type = "mips/I6400"; | ||
| 397 | break; | ||
| 398 | |||
| 395 | case CPU_M5150: | 399 | case CPU_M5150: |
| 396 | op_model_mipsxx_ops.cpu_type = "mips/M5150"; | 400 | op_model_mipsxx_ops.cpu_type = "mips/M5150"; |
| 397 | break; | 401 | break; |
| @@ -131,7 +131,7 @@ struct xlp_msi_data { · 130 unmodified lines | |||
| 131 | */ | 131 | */ |
| 132 | static void xlp_msi_enable(struct irq_data *d) | 132 | static void xlp_msi_enable(struct irq_data *d) |
| 133 | { | 133 | { |
| 134 | struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); | 134 | struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); |
| 135 | unsigned long flags; | 135 | unsigned long flags; |
| 136 | int vec; | 136 | int vec; |
| 137 | 137 | ||
| @@ -148,7 +148,7 @@ static void xlp_msi_enable(struct irq_data *d) · 10 unmodified lines | |||
| 148 | 148 | ||
| 149 | static void xlp_msi_disable(struct irq_data *d) | 149 | static void xlp_msi_disable(struct irq_data *d) |
| 150 | { | 150 | { |
| 151 | struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); | 151 | struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); |
| 152 | unsigned long flags; | 152 | unsigned long flags; |
| 153 | int vec; | 153 | int vec; |
| 154 | 154 | ||
| @@ -165,7 +165,7 @@ static void xlp_msi_disable(struct irq_data *d) · 10 unmodified lines | |||
| 165 | 165 | ||
| 166 | static void xlp_msi_mask_ack(struct irq_data *d) | 166 | static void xlp_msi_mask_ack(struct irq_data *d) |
| 167 | { | 167 | { |
| 168 | struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); | 168 | struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); |
| 169 | int link, vec; | 169 | int link, vec; |
| 170 | 170 | ||
| 171 | link = nlm_irq_msilink(d->irq); | 171 | link = nlm_irq_msilink(d->irq); |
| @@ -211,7 +211,7 @@ static void xlp_msix_mask_ack(struct irq_data *d) · 39 unmodified lines | |||
| 211 | msixvec = nlm_irq_msixvec(d->irq); | 211 | msixvec = nlm_irq_msixvec(d->irq); |
| 212 | link = nlm_irq_msixlink(msixvec); | 212 | link = nlm_irq_msixlink(msixvec); |
| 213 | pci_msi_mask_irq(d); | 213 | pci_msi_mask_irq(d); |
| 214 | md = irq_data_get_irq_handler_data(d); | 214 | md = irq_data_get_irq_chip_data(d); |
| 215 | 215 | ||
| 216 | /* Ack MSI on bridge */ | 216 | /* Ack MSI on bridge */ |
| 217 | if (cpu_is_xlp9xx()) { | 217 | if (cpu_is_xlp9xx()) { |
| @@ -302,7 +302,7 @@ static int xlp_setup_msi(uint64_t lnkbase, int node, int link, · 84 unmodified lines | |||
| 302 | /* Get MSI data for the link */ | 302 | /* Get MSI data for the link */ |
| 303 | lirq = PIC_PCIE_LINK_MSI_IRQ(link); | 303 | lirq = PIC_PCIE_LINK_MSI_IRQ(link); |
| 304 | xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); | 304 | xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); |
| 305 | md = irq_get_handler_data(xirq); | 305 | md = irq_get_chip_data(xirq); |
| 306 | msiaddr = MSI_LINK_ADDR(node, link); | 306 | msiaddr = MSI_LINK_ADDR(node, link); |
| 307 | 307 | ||
| 308 | spin_lock_irqsave(&md->msi_lock, flags); | 308 | spin_lock_irqsave(&md->msi_lock, flags); |
| @@ -409,7 +409,7 @@ static int xlp_setup_msix(uint64_t lnkbase, int node, int link, · 100 unmodified lines | |||
| 409 | /* Get MSI data for the link */ | 409 | /* Get MSI data for the link */ |
| 410 | lirq = PIC_PCIE_MSIX_IRQ(link); | 410 | lirq = PIC_PCIE_MSIX_IRQ(link); |
| 411 | xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); | 411 | xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); |
| 412 | md = irq_get_handler_data(xirq); | 412 | md = irq_get_chip_data(xirq); |
| 413 | msixaddr = MSIX_LINK_ADDR(node, link); | 413 | msixaddr = MSIX_LINK_ADDR(node, link); |
| 414 | 414 | ||
| 415 | spin_lock_irqsave(&md->msi_lock, flags); | 415 | spin_lock_irqsave(&md->msi_lock, flags); |
| @@ -485,7 +485,7 @@ void __init xlp_init_node_msi_irqs(int node, int link) · 69 unmodified lines | |||
| 485 | irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); | 485 | irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); |
| 486 | for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) { | 486 | for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) { |
| 487 | irq_set_chip_and_handler(i, &xlp_msi_chip, handle_level_irq); | 487 | irq_set_chip_and_handler(i, &xlp_msi_chip, handle_level_irq); |
| 488 | irq_set_handler_data(i, md); | 488 | irq_set_chip_data(i, md); |
| 489 | } | 489 | } |
| 490 | 490 | ||
| 491 | for (i = 0; i < XLP_MSIXVEC_PER_LINK ; i++) { | 491 | for (i = 0; i < XLP_MSIXVEC_PER_LINK ; i++) { |
| @@ -508,7 +508,7 @@ void __init xlp_init_node_msi_irqs(int node, int link) · 16 unmodified lines | |||
| 508 | /* Initialize MSI-X extended irq space for the link */ | 508 | /* Initialize MSI-X extended irq space for the link */ |
| 509 | irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); | 509 | irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); |
| 510 | irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); | 510 | irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); |
| 511 | irq_set_handler_data(irq, md); | 511 | irq_set_chip_data(irq, md); |
| 512 | } | 512 | } |
| 513 | } | 513 | } |
| 514 | 514 | ||
| @@ -520,7 +520,7 @@ void nlm_dispatch_msi(int node, int lirq) · 5 unmodified lines | |||
| 520 | 520 | ||
| 521 | link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; | 521 | link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; |
| 522 | irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); | 522 | irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); |
| 523 | md = irq_get_handler_data(irqbase); | 523 | md = irq_get_chip_data(irqbase); |
| 524 | if (cpu_is_xlp9xx()) | 524 | if (cpu_is_xlp9xx()) |
| 525 | status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) & | 525 | status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) & |
| 526 | md->msi_enabled_mask; | 526 | md->msi_enabled_mask; |
| @@ -550,7 +550,7 @@ void nlm_dispatch_msix(int node, int lirq) · 23 unmodified lines | |||
| 550 | 550 | ||
| 551 | link = lirq - PIC_PCIE_MSIX_IRQ_BASE; | 551 | link = lirq - PIC_PCIE_MSIX_IRQ_BASE; |
| 552 | irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); | 552 | irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); |
| 553 | md = irq_get_handler_data(irqbase); | 553 | md = irq_get_chip_data(irqbase); |
| 554 | if (cpu_is_xlp9xx()) | 554 | if (cpu_is_xlp9xx()) |
| 555 | status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link)); | 555 | status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link)); |
| 556 | else | 556 | else |
| @@ -25,7 +25,6 @@ · 24 unmodified lines | |||
| 25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
| 26 | 26 | ||
| 27 | #include <asm/addrspace.h> | 27 | #include <asm/addrspace.h> |
| 28 | #include <asm/debug.h> | ||
| 29 | 28 | ||
| 30 | #include <asm/emma/emma2rh.h> | 29 | #include <asm/emma/emma2rh.h> |
| 31 | 30 | ||
| @@ -40,10 +39,9 @@ · 8 unmodified lines | |||
| 40 | static int check_args(struct pci_bus *bus, u32 devfn, u32 * bus_num) | 39 | static int check_args(struct pci_bus *bus, u32 devfn, u32 * bus_num) |
| 41 | { | 40 | { |
| 42 | /* check if the bus is top-level */ | 41 | /* check if the bus is top-level */ |
| 43 | if (bus->parent != NULL) { | 42 | if (bus->parent != NULL) |
| 44 | *bus_num = bus->number; | 43 | *bus_num = bus->number; |
| 45 | db_assert(bus_num != NULL); | 44 | else |
| 46 | } else | ||
| 47 | *bus_num = 0; | 45 | *bus_num = 0; |
| 48 | 46 | ||
| 49 | if (*bus_num == 0) { | 47 | if (*bus_num == 0) { |
| @@ -312,8 +312,8 @@ static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc) · 311 unmodified lines | |||
| 312 | irq_set_chip_data(i, apc); | 312 | irq_set_chip_data(i, apc); |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | irq_set_handler_data(apc->irq, apc); | 315 | irq_set_chained_handler_and_data(apc->irq, ar71xx_pci_irq_handler, |
| 316 | irq_set_chained_handler(apc->irq, ar71xx_pci_irq_handler); | 316 | apc); |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | static void ar71xx_pci_reset(void) | 319 | static void ar71xx_pci_reset(void) |
| @@ -321,8 +321,8 @@ static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc, · 320 unmodified lines | |||
| 321 | irq_set_chip_data(i, apc); | 321 | irq_set_chip_data(i, apc); |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | irq_set_handler_data(apc->irq, apc); | 324 | irq_set_chained_handler_and_data(apc->irq, ar724x_pci_irq_handler, |
| 325 | irq_set_chained_handler(apc->irq, ar724x_pci_irq_handler); | 325 | apc); |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | static int ar724x_pci_probe(struct platform_device *pdev) | 328 | static int ar724x_pci_probe(struct platform_device *pdev) |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | #include <linux/of_irq.h> | 20 | #include <linux/of_irq.h> |
| 21 | #include <linux/of_pci.h> | 21 | #include <linux/of_pci.h> |
| 22 | 22 | ||
| 23 | #include <asm/gpio.h> | ||
| 24 | #include <asm/addrspace.h> | 23 | #include <asm/addrspace.h> |
| 25 | 24 | ||
| 26 | #include <lantiq_soc.h> | 25 | #include <lantiq_soc.h> |
| @@ -129,7 +129,7 @@ static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc, · 128 unmodified lines | |||
| 129 | rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA); | 129 | rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) | 132 | static void rt3883_pci_irq_handler(unsigned int __irq, struct irq_desc *desc) |
| 133 | { | 133 | { |
| 134 | struct rt3883_pci_controller *rpc; | 134 | struct rt3883_pci_controller *rpc; |
| 135 | u32 pending; | 135 | u32 pending; |
| @@ -145,7 +145,7 @@ static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) · 9 unmodified lines | |||
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | while (pending) { | 147 | while (pending) { |
| 148 | unsigned bit = __ffs(pending); | 148 | unsigned irq, bit = __ffs(pending); |
| 149 | 149 | ||
| 150 | irq = irq_find_mapping(rpc->irq_domain, bit); | 150 | irq = irq_find_mapping(rpc->irq_domain, bit); |
| 151 | generic_handle_irq(irq); | 151 | generic_handle_irq(irq); |
| @@ -225,8 +225,7 @@ static int rt3883_pci_irq_init(struct device *dev, · 73 unmodified lines | |||
| 225 | return -ENODEV; | 225 | return -ENODEV; |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | irq_set_handler_data(irq, rpc); | 228 | irq_set_chained_handler_and_data(irq, rt3883_pci_irq_handler, rpc); |
| 229 | irq_set_chained_handler(irq, rt3883_pci_irq_handler); | ||
| 230 | 229 | ||
| 231 | return 0; | 230 | return 0; |
| 232 | } | 231 | } |
| @@ -0,0 +1,13 @@ | |||
| 1 | config PISTACHIO_GPTIMER_CLKSRC | ||
| 2 | bool "Enable General Purpose Timer based clocksource" | ||
| 3 | depends on MACH_PISTACHIO | ||
| 4 | select CLKSRC_PISTACHIO | ||
| 5 | select MIPS_EXTERNAL_TIMER | ||
| 6 | help | ||
| 7 | This option enables a clocksource driver based on a Pistachio | ||
| 8 | SoC General Purpose external timer. | ||
| 9 | |||
| 10 | If you want to enable the CPUFreq, you need to enable | ||
| 11 | this option. | ||
| 12 | |||
| 13 | If you don't want to enable CPUFreq, you can leave this disabled. | ||
| @@ -88,7 +88,8 @@ static void unmask_cic_irq(struct irq_data *d) · 87 unmodified lines | |||
| 88 | * Make sure we have IRQ affinity. It may have changed while | 88 | * Make sure we have IRQ affinity. It may have changed while |
| 89 | * we were processing the IRQ. | 89 | * we were processing the IRQ. |
| 90 | */ | 90 | */ |
| 91 | if (!cpumask_test_cpu(smp_processor_id(), d->affinity)) | 91 | if (!cpumask_test_cpu(smp_processor_id(), |
| 92 | irq_data_get_affinity_mask(d))) | ||
| 92 | return; | 93 | return; |
| 93 | #endif | 94 | #endif |
| 94 | 95 | ||
| @@ -36,8 +36,8 @@ struct systick_device { · 35 unmodified lines | |||
| 36 | int freq_scale; | 36 | int freq_scale; |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | static void systick_set_clock_mode(enum clock_event_mode mode, | 39 | static int systick_set_oneshot(struct clock_event_device *evt); |
| 40 | struct clock_event_device *evt); | 40 | static int systick_shutdown(struct clock_event_device *evt); |
| 41 | 41 | ||
| 42 | static int systick_next_event(unsigned long delta, | 42 | static int systick_next_event(unsigned long delta, |
| 43 | struct clock_event_device *evt) | 43 | struct clock_event_device *evt) |
| @@ -73,11 +73,12 @@ static struct systick_device systick = { · 29 unmodified lines | |||
| 73 | * cevt-r4k uses 300, make sure systick | 73 | * cevt-r4k uses 300, make sure systick |
| 74 | * gets used if available | 74 | * gets used if available |
| 75 | */ | 75 | */ |
| 76 | .rating = 310, | 76 | .rating = 310, |
| 77 | .features = CLOCK_EVT_FEAT_ONESHOT, | 77 | .features = CLOCK_EVT_FEAT_ONESHOT, |
| 78 | .set_next_event = systick_next_event, | 78 | .set_next_event = systick_next_event, |
| 79 | .set_mode = systick_set_clock_mode, | 79 | .set_state_shutdown = systick_shutdown, |
| 80 | .event_handler = systick_event_handler, | 80 | .set_state_oneshot = systick_set_oneshot, |
| 81 | .event_handler = systick_event_handler, | ||
| 81 | }, | 82 | }, |
| 82 | }; | 83 | }; |
| 83 | 84 | ||
| @@ -87,33 +88,33 @@ static struct irqaction systick_irqaction = { · 3 unmodified lines | |||
| 87 | .dev_id = &systick.dev, | 88 | .dev_id = &systick.dev, |
| 88 | }; | 89 | }; |
| 89 | 90 | ||
| 90 | static void systick_set_clock_mode(enum clock_event_mode mode, | 91 | static int systick_shutdown(struct clock_event_device *evt) |
| 91 | struct clock_event_device *evt) | ||
| 92 | { | 92 | { |
| 93 | struct systick_device *sdev; | 93 | struct systick_device *sdev; |
| 94 | 94 | ||
| 95 | sdev = container_of(evt, struct systick_device, dev); | 95 | sdev = container_of(evt, struct systick_device, dev); |
| 96 | 96 | ||
| 97 | switch (mode) { | 97 | if (sdev->irq_requested) |
| 98 | case CLOCK_EVT_MODE_ONESHOT: | 98 | free_irq(systick.dev.irq, &systick_irqaction); |
| 99 | if (!sdev->irq_requested) | 99 | sdev->irq_requested = 0; |
| 100 | setup_irq(systick.dev.irq, &systick_irqaction); | 100 | iowrite32(0, systick.membase + SYSTICK_CONFIG); |
| 101 | sdev->irq_requested = 1; | 101 | |
| 102 | iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, | 102 | return 0; |
| 103 | systick.membase + SYSTICK_CONFIG); | 103 | } |
| 104 | break; | 104 | |
| 105 | 105 | static int systick_set_oneshot(struct clock_event_device *evt) | |
| 106 | case CLOCK_EVT_MODE_SHUTDOWN: | 106 | { |
| 107 | if (sdev->irq_requested) | 107 | struct systick_device *sdev; |
| 108 | free_irq(systick.dev.irq, &systick_irqaction); | 108 | |
| 109 | sdev->irq_requested = 0; | 109 | sdev = container_of(evt, struct systick_device, dev); |
| 110 | iowrite32(0, systick.membase + SYSTICK_CONFIG); | 110 | |
| 111 | break; | 111 | if (!sdev->irq_requested) |
| 112 | 112 | setup_irq(systick.dev.irq, &systick_irqaction); | |
| 113 | default: | 113 | sdev->irq_requested = 1; |
| 114 | pr_err("%s: Unhandeled mips clock_mode\n", systick.dev.name); | 114 | iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, |
| 115 | break; | 115 | systick.membase + SYSTICK_CONFIG); |
| 116 | } | 116 | |
| 117 | return 0; | ||
| 117 | } | 118 | } |
| 118 | 119 | ||
| 119 | static void __init ralink_systick_init(struct device_node *np) | 120 | static void __init ralink_systick_init(struct device_node *np) |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | |||
| 23 | #include <linux/mtd/nand.h> | 23 | #include <linux/mtd/nand.h> |
| 24 | #include <linux/mtd/mtd.h> | 24 | #include <linux/mtd/mtd.h> |
| 25 | #include <linux/mtd/partitions.h> | 25 | #include <linux/mtd/partitions.h> |
| 26 | #include <linux/gpio.h> | ||
| 26 | #include <linux/gpio_keys.h> | 27 | #include <linux/gpio_keys.h> |
| 27 | #include <linux/input.h> | 28 | #include <linux/input.h> |
| 28 | #include <linux/serial_8250.h> | 29 | #include <linux/serial_8250.h> |
| @@ -140,6 +140,11 @@ static int rb532_gpio_direction_output(struct gpio_chip *chip, · 139 unmodified lines | |||
| 140 | return 0; | 140 | return 0; |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | static int rb532_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) | ||
| 144 | { | ||
| 145 | return 8 + 4 * 32 + gpio; | ||
| 146 | } | ||
| 147 | |||
| 143 | static struct rb532_gpio_chip rb532_gpio_chip[] = { | 148 | static struct rb532_gpio_chip rb532_gpio_chip[] = { |
| 144 | [0] = { | 149 | [0] = { |
| 145 | .chip = { | 150 | .chip = { |
| @@ -148,6 +153,7 @@ static struct rb532_gpio_chip rb532_gpio_chip[] = { · 2 unmodified lines | |||
| 148 | .direction_output = rb532_gpio_direction_output, | 153 | .direction_output = rb532_gpio_direction_output, |
| 149 | .get = rb532_gpio_get, | 154 | .get = rb532_gpio_get, |
| 150 | .set = rb532_gpio_set, | 155 | .set = rb532_gpio_set, |
| 156 | .to_irq = rb532_gpio_to_irq, | ||
| 151 | .base = 0, | 157 | .base = 0, |
| 152 | .ngpio = 32, | 158 | .ngpio = 32, |
| 153 | }, | 159 | }, |
| @@ -64,12 +64,6 @@ static int rt_next_event(unsigned long delta, struct clock_event_device *evt) · 63 unmodified lines | |||
| 64 | return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; | 64 | return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static void rt_set_mode(enum clock_event_mode mode, | ||
| 68 | struct clock_event_device *evt) | ||
| 69 | { | ||
| 70 | /* Nothing to do ... */ | ||
| 71 | } | ||
| 72 | |||
| 73 | unsigned int rt_timer_irq; | 67 | unsigned int rt_timer_irq; |
| 74 | 68 | ||
| 75 | static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent); | 69 | static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent); |
| @@ -124,7 +118,6 @@ void hub_rt_clock_event_init(void) · 48 unmodified lines | |||
| 124 | cd->irq = irq; | 118 | cd->irq = irq; |
| 125 | cd->cpumask = cpumask_of(cpu); | 119 | cd->cpumask = cpumask_of(cpu); |
| 126 | cd->set_next_event = rt_next_event; | 120 | cd->set_next_event = rt_next_event; |
| 127 | cd->set_mode = rt_set_mode; | ||
| 128 | clockevents_register_device(cd); | 121 | clockevents_register_device(cd); |
| 129 | } | 122 | } |
| 130 | 123 | ||
| @@ -250,4 +250,4 @@ int __init sibyte_bus_watcher(void) · 249 unmodified lines | |||
| 250 | return 0; | 250 | return 0; |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | __initcall(sibyte_bus_watcher); | 253 | device_initcall(sibyte_bus_watcher); |
| @@ -14,44 +14,33 @@ · 13 unmodified lines | |||
| 14 | #define SNI_COUNTER2_DIV 64 | 14 | #define SNI_COUNTER2_DIV 64 |
| 15 | #define SNI_COUNTER0_DIV ((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ) | 15 | #define SNI_COUNTER0_DIV ((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ) |
| 16 | 16 | ||
| 17 | static void a20r_set_mode(enum clock_event_mode mode, | 17 | static int a20r_set_periodic(struct clock_event_device *evt) |
| 18 | struct clock_event_device *evt) | ||
| 19 | { | 18 | { |
| 20 | switch (mode) { | 19 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; |
| 21 | case CLOCK_EVT_MODE_PERIODIC: | 20 | wmb(); |
| 22 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; | 21 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV; |
| 23 | wmb(); | 22 | wmb(); |
| 24 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV; | 23 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8; |
| 25 | wmb(); | 24 | wmb(); |
| 26 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8; | ||
| 27 | wmb(); | ||
| 28 | |||
| 29 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; | ||
| 30 | wmb(); | ||
| 31 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV; | ||
| 32 | wmb(); | ||
| 33 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8; | ||
| 34 | wmb(); | ||
| 35 | 25 | ||
| 36 | break; | 26 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; |
| 37 | case CLOCK_EVT_MODE_ONESHOT: | 27 | wmb(); |
| 38 | case CLOCK_EVT_MODE_UNUSED: | 28 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV; |
| 39 | case CLOCK_EVT_MODE_SHUTDOWN: | 29 | wmb(); |
| 40 | break; | 30 | *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8; |
| 41 | case CLOCK_EVT_MODE_RESUME: | 31 | wmb(); |
| 42 | break; | 32 | return 0; |
| 43 | } | ||
| 44 | } | 33 | } |
| 45 | 34 | ||
| 46 | static struct clock_event_device a20r_clockevent_device = { | 35 | static struct clock_event_device a20r_clockevent_device = { |
| 47 | .name = "a20r-timer", | 36 | .name = "a20r-timer", |
| 48 | .features = CLOCK_EVT_FEAT_PERIODIC, | 37 | .features = CLOCK_EVT_FEAT_PERIODIC, |
| 49 | 38 | ||
| 50 | /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ | 39 | /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ |
| 51 | 40 | ||
| 52 | .rating = 300, | 41 | .rating = 300, |
| 53 | .irq = SNI_A20R_IRQ_TIMER, | 42 | .irq = SNI_A20R_IRQ_TIMER, |
| 54 | .set_mode = a20r_set_mode, | 43 | .set_state_periodic = a20r_set_periodic, |
| 55 | }; | 44 | }; |
| 56 | 45 | ||
| 57 | static irqreturn_t a20r_interrupt(int irq, void *dev_id) | 46 | static irqreturn_t a20r_interrupt(int irq, void *dev_id) |
| @@ -117,22 +117,6 @@ void clk_put(struct clk *clk) · 116 unmodified lines | |||
| 117 | } | 117 | } |
| 118 | EXPORT_SYMBOL(clk_put); | 118 | EXPORT_SYMBOL(clk_put); |
| 119 | 119 | ||
| 120 | /* GPIO support */ | ||
| 121 | |||
| 122 | #ifdef CONFIG_GPIOLIB | ||
| 123 | int gpio_to_irq(unsigned gpio) | ||
| 124 | { | ||
| 125 | return -EINVAL; | ||
| 126 | } | ||
| 127 | EXPORT_SYMBOL(gpio_to_irq); | ||
| 128 | |||
| 129 | int irq_to_gpio(unsigned irq) | ||
| 130 | { | ||
| 131 | return -EINVAL; | ||
| 132 | } | ||
| 133 | EXPORT_SYMBOL(irq_to_gpio); | ||
| 134 | #endif | ||
| 135 | |||
| 136 | #define BOARD_VEC(board) extern struct txx9_board_vec board; | 120 | #define BOARD_VEC(board) extern struct txx9_board_vec board; |
| 137 | #include <asm/txx9/boards.h> | 121 | #include <asm/txx9/boards.h> |
| 138 | #undef BOARD_VEC | 122 | #undef BOARD_VEC |
| @@ -27,12 +27,11 @@ · 26 unmodified lines | |||
| 27 | #include <linux/io.h> | 27 | #include <linux/io.h> |
| 28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
| 29 | #include <linux/irq.h> | 29 | #include <linux/irq.h> |
| 30 | #include <linux/gpio.h> | ||
| 30 | 31 | ||
| 31 | #include <linux/libata.h> | 32 | #include <linux/libata.h> |
| 32 | #include <scsi/scsi_host.h> | 33 | #include <scsi/scsi_host.h> |
| 33 | 34 | ||
| 34 | #include <asm/gpio.h> | ||
| 35 | |||
| 36 | #define DRV_NAME "pata-rb532-cf" | 35 | #define DRV_NAME "pata-rb532-cf" |
| 37 | #define DRV_VERSION "0.1.0" | 36 | #define DRV_VERSION "0.1.0" |
| 38 | #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" | 37 | #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" |
| @@ -331,6 +331,18 @@ static phys_addr_t mips_cdmm_cur_base(void) · 330 unmodified lines | |||
| 331 | << MIPS_CDMMBASE_ADDR_START; | 331 | << MIPS_CDMMBASE_ADDR_START; |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | /** | ||
| 335 | * mips_cdmm_phys_base() - Choose a physical base address for CDMM region. | ||
| 336 | * | ||
| 337 | * Picking a suitable physical address at which to map the CDMM region is | ||
| 338 | * platform specific, so this weak function can be overridden by platform | ||
| 339 | * code to pick a suitable value if none is configured by the bootloader. | ||
| 340 | */ | ||
| 341 | phys_addr_t __weak mips_cdmm_phys_base(void) | ||
| 342 | { | ||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 334 | /** | 346 | /** |
| 335 | * mips_cdmm_setup() - Ensure the CDMM bus is initialised and usable. | 347 | * mips_cdmm_setup() - Ensure the CDMM bus is initialised and usable. |
| 336 | * @bus: Pointer to bus information for current CPU. | 348 | * @bus: Pointer to bus information for current CPU. |
| @@ -368,7 +380,7 @@ static int mips_cdmm_setup(struct mips_cdmm_bus *bus) · 31 unmodified lines | |||
| 368 | if (!bus->phys) | 380 | if (!bus->phys) |
| 369 | bus->phys = mips_cdmm_cur_base(); | 381 | bus->phys = mips_cdmm_cur_base(); |
| 370 | /* Otherwise, ask platform code for suggestions */ | 382 | /* Otherwise, ask platform code for suggestions */ |
| 371 | if (!bus->phys && mips_cdmm_phys_base) | 383 | if (!bus->phys) |
| 372 | bus->phys = mips_cdmm_phys_base(); | 384 | bus->phys = mips_cdmm_phys_base(); |
| 373 | /* Otherwise, copy what other CPUs have done */ | 385 | /* Otherwise, copy what other CPUs have done */ |
| 374 | if (!bus->phys) | 386 | if (!bus->phys) |
| @@ -111,6 +111,10 @@ config CLKSRC_LPC32XX · 110 unmodified lines | |||
| 111 | select CLKSRC_MMIO | 111 | select CLKSRC_MMIO |
| 112 | select CLKSRC_OF | 112 | select CLKSRC_OF |
| 113 | 113 | ||
| 114 | config CLKSRC_PISTACHIO | ||
| 115 | bool | ||
| 116 | select CLKSRC_OF | ||
| 117 | |||
| 114 | config CLKSRC_STM32 | 118 | config CLKSRC_STM32 |
| 115 | bool "Clocksource for STM32 SoCs" if !ARCH_STM32 | 119 | bool "Clocksource for STM32 SoCs" if !ARCH_STM32 |
| 116 | depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) | 120 | depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) |
| @@ -44,6 +44,7 @@ obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o · 43 unmodified lines | |||
| 44 | obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o | 44 | obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o |
| 45 | obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o | 45 | obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o |
| 46 | obj-$(CONFIG_MTK_TIMER) += mtk_timer.o | 46 | obj-$(CONFIG_MTK_TIMER) += mtk_timer.o |
| 47 | obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o | ||
| 47 | 48 | ||
| 48 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o | 49 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o |
| 49 | obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o | 50 | obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o |
| @@ -72,6 +72,13 @@ static void gic_clockevent_cpu_exit(struct clock_event_device *cd) · 71 unmodified lines | |||
| 72 | disable_percpu_irq(gic_timer_irq); | 72 | disable_percpu_irq(gic_timer_irq); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | static void gic_update_frequency(void *data) | ||
| 76 | { | ||
| 77 | unsigned long rate = (unsigned long)data; | ||
| 78 | |||
| 79 | clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate); | ||
| 80 | } | ||
| 81 | |||
| 75 | static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, | 82 | static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, |
| 76 | void *data) | 83 | void *data) |
| 77 | { | 84 | { |
| @@ -87,18 +94,40 @@ static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, · 9 unmodified lines | |||
| 87 | return NOTIFY_OK; | 94 | return NOTIFY_OK; |
| 88 | } | 95 | } |
| 89 | 96 | ||
| 97 | static int gic_clk_notifier(struct notifier_block *nb, unsigned long action, | ||
| 98 | void *data) | ||
| 99 | { | ||
| 100 | struct clk_notifier_data *cnd = data; | ||
| 101 | |||
| 102 | if (action == POST_RATE_CHANGE) | ||
| 103 | on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1); | ||
| 104 | |||
| 105 | return NOTIFY_OK; | ||
| 106 | } | ||
| 107 | |||
| 108 | |||
| 90 | static struct notifier_block gic_cpu_nb = { | 109 | static struct notifier_block gic_cpu_nb = { |
| 91 | .notifier_call = gic_cpu_notifier, | 110 | .notifier_call = gic_cpu_notifier, |
| 92 | }; | 111 | }; |
| 93 | 112 | ||
| 113 | static struct notifier_block gic_clk_nb = { | ||
| 114 | .notifier_call = gic_clk_notifier, | ||
| 115 | }; | ||
| 116 | |||
| 94 | static int gic_clockevent_init(void) | 117 | static int gic_clockevent_init(void) |
| 95 | { | 118 | { |
| 119 | int ret; | ||
| 120 | |||
| 96 | if (!cpu_has_counter || !gic_frequency) | 121 | if (!cpu_has_counter || !gic_frequency) |
| 97 | return -ENXIO; | 122 | return -ENXIO; |
| 98 | 123 | ||
| 99 | setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); | 124 | ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); |
| 125 | if (ret < 0) | ||
| 126 | return ret; | ||
| 100 | 127 | ||
| 101 | register_cpu_notifier(&gic_cpu_nb); | 128 | ret = register_cpu_notifier(&gic_cpu_nb); |
| 129 | if (ret < 0) | ||
| 130 | pr_warn("GIC: Unable to register CPU notifier\n"); | ||
| 102 | 131 | ||
| 103 | gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device)); | 132 | gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device)); |
| 104 | 133 | ||
| @@ -118,18 +147,17 @@ static struct clocksource gic_clocksource = { · 13 unmodified lines | |||
| 118 | 147 | ||
| 119 | static void __init __gic_clocksource_init(void) | 148 | static void __init __gic_clocksource_init(void) |
| 120 | { | 149 | { |
| 150 | int ret; | ||
| 151 | |||
| 121 | /* Set clocksource mask. */ | 152 | /* Set clocksource mask. */ |
| 122 | gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); | 153 | gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); |
| 123 | 154 | ||
| 124 | /* Calculate a somewhat reasonable rating value. */ | 155 | /* Calculate a somewhat reasonable rating value. */ |
| 125 | gic_clocksource.rating = 200 + gic_frequency / 10000000; | 156 | gic_clocksource.rating = 200 + gic_frequency / 10000000; |
| 126 | 157 | ||
| 127 | clocksource_register_hz(&gic_clocksource, gic_frequency); | 158 | ret = clocksource_register_hz(&gic_clocksource, gic_frequency); |
| 128 | 159 | if (ret < 0) | |
| 129 | gic_clockevent_init(); | 160 | pr_warn("GIC: Unable to register clocksource\n"); |
| 130 | |||
| 131 | /* And finally start the counter */ | ||
| 132 | gic_start_count(); | ||
| 133 | } | 161 | } |
| 134 | 162 | ||
| 135 | void __init gic_clocksource_init(unsigned int frequency) | 163 | void __init gic_clocksource_init(unsigned int frequency) |
| @@ -139,11 +167,16 @@ void __init gic_clocksource_init(unsigned int frequency) · 3 unmodified lines | |||
| 139 | GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); | 167 | GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); |
| 140 | 168 | ||
| 141 | __gic_clocksource_init(); | 169 | __gic_clocksource_init(); |
| 170 | gic_clockevent_init(); | ||
| 171 | |||
| 172 | /* And finally start the counter */ | ||
| 173 | gic_start_count(); | ||
| 142 | } | 174 | } |
| 143 | 175 | ||
| 144 | static void __init gic_clocksource_of_init(struct device_node *node) | 176 | static void __init gic_clocksource_of_init(struct device_node *node) |
| 145 | { | 177 | { |
| 146 | struct clk *clk; | 178 | struct clk *clk; |
| 179 | int ret; | ||
| 147 | 180 | ||
| 148 | if (WARN_ON(!gic_present || !node->parent || | 181 | if (WARN_ON(!gic_present || !node->parent || |
| 149 | !of_device_is_compatible(node->parent, "mti,gic"))) | 182 | !of_device_is_compatible(node->parent, "mti,gic"))) |
| @@ -151,8 +184,13 @@ static void __init gic_clocksource_of_init(struct device_node *node) · 1 unmodified line | |||
| 151 | 184 | ||
| 152 | clk = of_clk_get(node, 0); | 185 | clk = of_clk_get(node, 0); |
| 153 | if (!IS_ERR(clk)) { | 186 | if (!IS_ERR(clk)) { |
| 187 | if (clk_prepare_enable(clk) < 0) { | ||
| 188 | pr_err("GIC failed to enable clock\n"); | ||
| 189 | clk_put(clk); | ||
| 190 | return; | ||
| 191 | } | ||
| 192 | |||
| 154 | gic_frequency = clk_get_rate(clk); | 193 | gic_frequency = clk_get_rate(clk); |
| 155 | clk_put(clk); | ||
| 156 | } else if (of_property_read_u32(node, "clock-frequency", | 194 | } else if (of_property_read_u32(node, "clock-frequency", |
| 157 | &gic_frequency)) { | 195 | &gic_frequency)) { |
| 158 | pr_err("GIC frequency not specified.\n"); | 196 | pr_err("GIC frequency not specified.\n"); |
| @@ -165,6 +203,15 @@ static void __init gic_clocksource_of_init(struct device_node *node) · 6 unmodified lines | |||
| 165 | } | 203 | } |
| 166 | 204 | ||
| 167 | __gic_clocksource_init(); | 205 | __gic_clocksource_init(); |
| 206 | |||
| 207 | ret = gic_clockevent_init(); | ||
| 208 | if (!ret && !IS_ERR(clk)) { | ||
| 209 | if (clk_notifier_register(clk, &gic_clk_nb) < 0) | ||
| 210 | pr_warn("GIC: Unable to register clock notifier\n"); | ||
| 211 | } | ||
| 212 | |||
| 213 | /* And finally start the counter */ | ||
| 214 | gic_start_count(); | ||
| 168 | } | 215 | } |
| 169 | CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", | 216 | CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", |
| 170 | gic_clocksource_of_init); | 217 | gic_clocksource_of_init); |
| @@ -0,0 +1,217 @@ | |||
| 1 | /* | ||
| 2 | * Pistachio clocksource based on general-purpose timers | ||
| 3 | * | ||
| 4 | * Copyright (C) 2015 Imagination Technologies | ||
| 5 | * | ||
| 6 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 7 | * License. See the file "COPYING" in the main directory of this archive | ||
| 8 | * for more details. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #define pr_fmt(fmt) "%s: " fmt, __func__ | ||
| 12 | |||
| 13 | #include <linux/clk.h> | ||
| 14 | #include <linux/clocksource.h> | ||
| 15 | #include <linux/clockchips.h> | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/err.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/spinlock.h> | ||
| 20 | #include <linux/mfd/syscon.h> | ||
| 21 | #include <linux/of.h> | ||
| 22 | #include <linux/of_address.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/regmap.h> | ||
| 25 | #include <linux/sched_clock.h> | ||
| 26 | #include <linux/time.h> | ||
| 27 | |||
| 28 | /* Top level reg */ | ||
| 29 | #define CR_TIMER_CTRL_CFG 0x00 | ||
| 30 | #define TIMER_ME_GLOBAL BIT(0) | ||
| 31 | #define CR_TIMER_REV 0x10 | ||
| 32 | |||
| 33 | /* Timer specific registers */ | ||
| 34 | #define TIMER_CFG 0x20 | ||
| 35 | #define TIMER_ME_LOCAL BIT(0) | ||
| 36 | #define TIMER_RELOAD_VALUE 0x24 | ||
| 37 | #define TIMER_CURRENT_VALUE 0x28 | ||
| 38 | #define TIMER_CURRENT_OVERFLOW_VALUE 0x2C | ||
| 39 | #define TIMER_IRQ_STATUS 0x30 | ||
| 40 | #define TIMER_IRQ_CLEAR 0x34 | ||
| 41 | #define TIMER_IRQ_MASK 0x38 | ||
| 42 | |||
| 43 | #define PERIP_TIMER_CONTROL 0x90 | ||
| 44 | |||
| 45 | /* Timer specific configuration Values */ | ||
| 46 | #define RELOAD_VALUE 0xffffffff | ||
| 47 | |||
| 48 | struct pistachio_clocksource { | ||
| 49 | void __iomem *base; | ||
| 50 | raw_spinlock_t lock; | ||
| 51 | struct clocksource cs; | ||
| 52 | }; | ||
| 53 | |||
| 54 | static struct pistachio_clocksource pcs_gpt; | ||
| 55 | |||
| 56 | #define to_pistachio_clocksource(cs) \ | ||
| 57 | container_of(cs, struct pistachio_clocksource, cs) | ||
| 58 | |||
| 59 | static inline u32 gpt_readl(void __iomem *base, u32 offset, u32 gpt_id) | ||
| 60 | { | ||
| 61 | return readl(base + 0x20 * gpt_id + offset); | ||
| 62 | } | ||
| 63 | |||
| 64 | static inline void gpt_writel(void __iomem *base, u32 value, u32 offset, | ||
| 65 | u32 gpt_id) | ||
| 66 | { | ||
| 67 | writel(value, base + 0x20 * gpt_id + offset); | ||
| 68 | } | ||
| 69 | |||
| 70 | static cycle_t pistachio_clocksource_read_cycles(struct clocksource *cs) | ||
| 71 | { | ||
| 72 | struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); | ||
| 73 | u32 counter, overflw; | ||
| 74 | unsigned long flags; | ||
| 75 | |||
| 76 | /* | ||
| 77 | * The counter value is only refreshed after the overflow value is read. | ||
| 78 | * And they must be read in strict order, hence raw spin lock added. | ||
| 79 | */ | ||
| 80 | |||
| 81 | raw_spin_lock_irqsave(&pcs->lock, flags); | ||
| 82 | overflw = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0); | ||
| 83 | counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0); | ||
| 84 | raw_spin_unlock_irqrestore(&pcs->lock, flags); | ||
| 85 | |||
| 86 | return ~(cycle_t)counter; | ||
| 87 | } | ||
| 88 | |||
| 89 | static u64 notrace pistachio_read_sched_clock(void) | ||
| 90 | { | ||
| 91 | return pistachio_clocksource_read_cycles(&pcs_gpt.cs); | ||
| 92 | } | ||
| 93 | |||
| 94 | static void pistachio_clksrc_set_mode(struct clocksource *cs, int timeridx, | ||
| 95 | int enable) | ||
| 96 | { | ||
| 97 | struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); | ||
| 98 | u32 val; | ||
| 99 | |||
| 100 | val = gpt_readl(pcs->base, TIMER_CFG, timeridx); | ||
| 101 | if (enable) | ||
| 102 | val |= TIMER_ME_LOCAL; | ||
| 103 | else | ||
| 104 | val &= ~TIMER_ME_LOCAL; | ||
| 105 | |||
| 106 | gpt_writel(pcs->base, val, TIMER_CFG, timeridx); | ||
| 107 | } | ||
| 108 | |||
| 109 | static void pistachio_clksrc_enable(struct clocksource *cs, int timeridx) | ||
| 110 | { | ||
| 111 | struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); | ||
| 112 | |||
| 113 | /* Disable GPT local before loading reload value */ | ||
| 114 | pistachio_clksrc_set_mode(cs, timeridx, false); | ||
| 115 | gpt_writel(pcs->base, RELOAD_VALUE, TIMER_RELOAD_VALUE, timeridx); | ||
| 116 | pistachio_clksrc_set_mode(cs, timeridx, true); | ||
| 117 | } | ||
| 118 | |||
| 119 | static void pistachio_clksrc_disable(struct clocksource *cs, int timeridx) | ||
| 120 | { | ||
| 121 | /* Disable GPT local */ | ||
| 122 | pistachio_clksrc_set_mode(cs, timeridx, false); | ||
| 123 | } | ||
| 124 | |||
| 125 | static int pistachio_clocksource_enable(struct clocksource *cs) | ||
| 126 | { | ||
| 127 | pistachio_clksrc_enable(cs, 0); | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static void pistachio_clocksource_disable(struct clocksource *cs) | ||
| 132 | { | ||
| 133 | pistachio_clksrc_disable(cs, 0); | ||
| 134 | } | ||
| 135 | |||
| 136 | /* Desirable clock source for pistachio platform */ | ||
| 137 | static struct pistachio_clocksource pcs_gpt = { | ||
| 138 | .cs = { | ||
| 139 | .name = "gptimer", | ||
| 140 | .rating = 300, | ||
| 141 | .enable = pistachio_clocksource_enable, | ||
| 142 | .disable = pistachio_clocksource_disable, | ||
| 143 | .read = pistachio_clocksource_read_cycles, | ||
| 144 | .mask = CLOCKSOURCE_MASK(32), | ||
| 145 | .flags = CLOCK_SOURCE_IS_CONTINUOUS | | ||
| 146 | CLOCK_SOURCE_SUSPEND_NONSTOP, | ||
| 147 | }, | ||
| 148 | }; | ||
| 149 | |||
| 150 | static void __init pistachio_clksrc_of_init(struct device_node *node) | ||
| 151 | { | ||
| 152 | struct clk *sys_clk, *fast_clk; | ||
| 153 | struct regmap *periph_regs; | ||
| 154 | unsigned long rate; | ||
| 155 | int ret; | ||
| 156 | |||
| 157 | pcs_gpt.base = of_iomap(node, 0); | ||
| 158 | if (!pcs_gpt.base) { | ||
| 159 | pr_err("cannot iomap\n"); | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | periph_regs = syscon_regmap_lookup_by_phandle(node, "img,cr-periph"); | ||
| 164 | if (IS_ERR(periph_regs)) { | ||
| 165 | pr_err("cannot get peripheral regmap (%lu)\n", | ||
| 166 | PTR_ERR(periph_regs)); | ||
| 167 | return; | ||
| 168 | } | ||
| 169 | |||
| 170 | /* Switch to using the fast counter clock */ | ||
| 171 | ret = regmap_update_bits(periph_regs, PERIP_TIMER_CONTROL, | ||
| 172 | 0xf, 0x0); | ||
| 173 | if (ret) | ||
| 174 | return; | ||
| 175 | |||
| 176 | sys_clk = of_clk_get_by_name(node, "sys"); | ||
| 177 | if (IS_ERR(sys_clk)) { | ||
| 178 | pr_err("clock get failed (%lu)\n", PTR_ERR(sys_clk)); | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | |||
| 182 | fast_clk = of_clk_get_by_name(node, "fast"); | ||
| 183 | if (IS_ERR(fast_clk)) { | ||
| 184 | pr_err("clock get failed (%lu)\n", PTR_ERR(fast_clk)); | ||
| 185 | return; | ||
| 186 | } | ||
| 187 | |||
| 188 | ret = clk_prepare_enable(sys_clk); | ||
| 189 | if (ret < 0) { | ||
| 190 | pr_err("failed to enable clock (%d)\n", ret); | ||
| 191 | return; | ||
| 192 | } | ||
| 193 | |||
| 194 | ret = clk_prepare_enable(fast_clk); | ||
| 195 | if (ret < 0) { | ||
| 196 | pr_err("failed to enable clock (%d)\n", ret); | ||
| 197 | clk_disable_unprepare(sys_clk); | ||
| 198 | return; | ||
| 199 | } | ||
| 200 | |||
| 201 | rate = clk_get_rate(fast_clk); | ||
| 202 | |||
| 203 | /* Disable irq's for clocksource usage */ | ||
| 204 | gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 0); | ||
| 205 | gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 1); | ||
| 206 | gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 2); | ||
| 207 | gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 3); | ||
| 208 | |||
| 209 | /* Enable timer block */ | ||
| 210 | writel(TIMER_ME_GLOBAL, pcs_gpt.base); | ||
| 211 | |||
| 212 | raw_spin_lock_init(&pcs_gpt.lock); | ||
| 213 | sched_clock_register(pistachio_read_sched_clock, 32, rate); | ||
| 214 | clocksource_register_hz(&pcs_gpt.cs, rate); | ||
| 215 | } | ||
| 216 | CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", | ||
| 217 | pistachio_clksrc_of_init); | ||
| @@ -20,6 +20,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o · 19 unmodified lines | |||
| 20 | obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o | 20 | obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o |
| 21 | obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o | 21 | obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o |
| 22 | obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o | 22 | obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o |
| 23 | obj-$(CONFIG_ATH79) += gpio-ath79.o | ||
| 23 | obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o | 24 | obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o |
| 24 | obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o | 25 | obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o |
| 25 | obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o | 26 | obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o |
| @@ -24,8 +24,6 @@ · 23 unmodified lines | |||
| 24 | #include <linux/of_device.h> | 24 | #include <linux/of_device.h> |
| 25 | 25 | ||
| 26 | #include <asm/mach-ath79/ar71xx_regs.h> | 26 | #include <asm/mach-ath79/ar71xx_regs.h> |
| 27 | #include <asm/mach-ath79/ath79.h> | ||
| 28 | #include "common.h" | ||
| 29 | 27 | ||
| 30 | static void __iomem *ath79_gpio_base; | 28 | static void __iomem *ath79_gpio_base; |
| 31 | static u32 ath79_gpio_count; | 29 | static u32 ath79_gpio_count; |
| @@ -139,47 +137,6 @@ static struct gpio_chip ath79_gpio_chip = { · 107 unmodified lines | |||
| 139 | .base = 0, | 137 | .base = 0, |
| 140 | }; | 138 | }; |
| 141 | 139 | ||
| 142 | static void __iomem *ath79_gpio_get_function_reg(void) | ||
| 143 | { | ||
| 144 | u32 reg = 0; | ||
| 145 | |||
| 146 | if (soc_is_ar71xx() || | ||
| 147 | soc_is_ar724x() || | ||
| 148 | soc_is_ar913x() || | ||
| 149 | soc_is_ar933x()) | ||
| 150 | reg = AR71XX_GPIO_REG_FUNC; | ||
| 151 | else if (soc_is_ar934x()) | ||
| 152 | reg = AR934X_GPIO_REG_FUNC; | ||
| 153 | else | ||
| 154 | BUG(); | ||
| 155 | |||
| 156 | return ath79_gpio_base + reg; | ||
| 157 | } | ||
| 158 | |||
| 159 | void ath79_gpio_function_setup(u32 set, u32 clear) | ||
| 160 | { | ||
| 161 | void __iomem *reg = ath79_gpio_get_function_reg(); | ||
| 162 | unsigned long flags; | ||
| 163 | |||
| 164 | spin_lock_irqsave(&ath79_gpio_lock, flags); | ||
| 165 | |||
| 166 | __raw_writel((__raw_readl(reg) & ~clear) | set, reg); | ||
| 167 | /* flush write */ | ||
| 168 | __raw_readl(reg); | ||
| 169 | |||
| 170 | spin_unlock_irqrestore(&ath79_gpio_lock, flags); | ||
| 171 | } | ||
| 172 | |||
| 173 | void ath79_gpio_function_enable(u32 mask) | ||
| 174 | { | ||
| 175 | ath79_gpio_function_setup(mask, 0); | ||
| 176 | } | ||
| 177 | |||
| 178 | void ath79_gpio_function_disable(u32 mask) | ||
| 179 | { | ||
| 180 | ath79_gpio_function_setup(0, mask); | ||
| 181 | } | ||
| 182 | |||
| 183 | static const struct of_device_id ath79_gpio_of_match[] = { | 140 | static const struct of_device_id ath79_gpio_of_match[] = { |
| 184 | { .compatible = "qca,ar7100-gpio" }, | 141 | { .compatible = "qca,ar7100-gpio" }, |
| 185 | { .compatible = "qca,ar9340-gpio" }, | 142 | { .compatible = "qca,ar9340-gpio" }, |
| @@ -245,35 +202,3 @@ static struct platform_driver ath79_gpio_driver = { · 59 unmodified lines | |||
| 245 | }; | 202 | }; |
| 246 | 203 | ||
| 247 | module_platform_driver(ath79_gpio_driver); | 204 | module_platform_driver(ath79_gpio_driver); |
| 248 | |||
| 249 | int gpio_get_value(unsigned gpio) | ||
| 250 | { | ||
| 251 | if (gpio < ath79_gpio_count) | ||
| 252 | return __ath79_gpio_get_value(gpio); | ||
| 253 | |||
| 254 | return __gpio_get_value(gpio); | ||
| 255 | } | ||
| 256 | EXPORT_SYMBOL(gpio_get_value); | ||
| 257 | |||
| 258 | void gpio_set_value(unsigned gpio, int value) | ||
| 259 | { | ||
| 260 | if (gpio < ath79_gpio_count) | ||
| 261 | __ath79_gpio_set_value(gpio, value); | ||
| 262 | else | ||
| 263 | __gpio_set_value(gpio, value); | ||
| 264 | } | ||
| 265 | EXPORT_SYMBOL(gpio_set_value); | ||
| 266 | |||
| 267 | int gpio_to_irq(unsigned gpio) | ||
| 268 | { | ||
| 269 | /* FIXME */ | ||
| 270 | return -EINVAL; | ||
| 271 | } | ||
| 272 | EXPORT_SYMBOL(gpio_to_irq); | ||
| 273 | |||
| 274 | int irq_to_gpio(unsigned irq) | ||
| 275 | { | ||
| 276 | /* FIXME */ | ||
| 277 | return -EINVAL; | ||
| 278 | } | ||
| 279 | EXPORT_SYMBOL(irq_to_gpio); | ||
| @@ -7,6 +7,7 @@ · 6 unmodified lines | |||
| 7 | #include <linux/input-polldev.h> | 7 | #include <linux/input-polldev.h> |
| 8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 9 | #include <linux/platform_device.h> | 9 | #include <linux/platform_device.h> |
| 10 | #include <linux/gpio.h> | ||
| 10 | 11 | ||
| 11 | #include <asm/mach-rc32434/gpio.h> | 12 | #include <asm/mach-rc32434/gpio.h> |
| 12 | #include <asm/mach-rc32434/rb.h> | 13 | #include <asm/mach-rc32434/rb.h> |
| @@ -41,20 +41,46 @@ static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; · 40 unmodified lines | |||
| 41 | 41 | ||
| 42 | static void __gic_irq_dispatch(void); | 42 | static void __gic_irq_dispatch(void); |
| 43 | 43 | ||
| 44 | static inline unsigned int gic_read(unsigned int reg) | 44 | static inline u32 gic_read32(unsigned int reg) |
| 45 | { | 45 | { |
| 46 | return __raw_readl(gic_base + reg); | 46 | return __raw_readl(gic_base + reg); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | static inline void gic_write(unsigned int reg, unsigned int val) | 49 | static inline u64 gic_read64(unsigned int reg) |
| 50 | { | 50 | { |
| 51 | __raw_writel(val, gic_base + reg); | 51 | return __raw_readq(gic_base + reg); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | static inline void gic_update_bits(unsigned int reg, unsigned int mask, | 54 | static inline unsigned long gic_read(unsigned int reg) |
| 55 | unsigned int val) | ||
| 56 | { | 55 | { |
| 57 | unsigned int regval; | 56 | if (!mips_cm_is64) |
| 57 | return gic_read32(reg); | ||
| 58 | else | ||
| 59 | return gic_read64(reg); | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline void gic_write32(unsigned int reg, u32 val) | ||
| 63 | { | ||
| 64 | return __raw_writel(val, gic_base + reg); | ||
| 65 | } | ||
| 66 | |||
| 67 | static inline void gic_write64(unsigned int reg, u64 val) | ||
| 68 | { | ||
| 69 | return __raw_writeq(val, gic_base + reg); | ||
| 70 | } | ||
| 71 | |||
| 72 | static inline void gic_write(unsigned int reg, unsigned long val) | ||
| 73 | { | ||
| 74 | if (!mips_cm_is64) | ||
| 75 | return gic_write32(reg, (u32)val); | ||
| 76 | else | ||
| 77 | return gic_write64(reg, (u64)val); | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline void gic_update_bits(unsigned int reg, unsigned long mask, | ||
| 81 | unsigned long val) | ||
| 82 | { | ||
| 83 | unsigned long regval; | ||
| 58 | 84 | ||
| 59 | regval = gic_read(reg); | 85 | regval = gic_read(reg); |
| 60 | regval &= ~mask; | 86 | regval &= ~mask; |
| @@ -65,40 +91,40 @@ static inline void gic_update_bits(unsigned int reg, unsigned int mask, · 4 unmodified lines | |||
| 65 | static inline void gic_reset_mask(unsigned int intr) | 91 | static inline void gic_reset_mask(unsigned int intr) |
| 66 | { | 92 | { |
| 67 | gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr), | 93 | gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr), |
| 68 | 1 << GIC_INTR_BIT(intr)); | 94 | 1ul << GIC_INTR_BIT(intr)); |
| 69 | } | 95 | } |
| 70 | 96 | ||
| 71 | static inline void gic_set_mask(unsigned int intr) | 97 | static inline void gic_set_mask(unsigned int intr) |
| 72 | { | 98 | { |
| 73 | gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr), | 99 | gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr), |
| 74 | 1 << GIC_INTR_BIT(intr)); | 100 | 1ul << GIC_INTR_BIT(intr)); |
| 75 | } | 101 | } |
| 76 | 102 | ||
| 77 | static inline void gic_set_polarity(unsigned int intr, unsigned int pol) | 103 | static inline void gic_set_polarity(unsigned int intr, unsigned int pol) |
| 78 | { | 104 | { |
| 79 | gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) + | 105 | gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) + |
| 80 | GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), | 106 | GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), |
| 81 | pol << GIC_INTR_BIT(intr)); | 107 | (unsigned long)pol << GIC_INTR_BIT(intr)); |
| 82 | } | 108 | } |
| 83 | 109 | ||
| 84 | static inline void gic_set_trigger(unsigned int intr, unsigned int trig) | 110 | static inline void gic_set_trigger(unsigned int intr, unsigned int trig) |
| 85 | { | 111 | { |
| 86 | gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) + | 112 | gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) + |
| 87 | GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), | 113 | GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), |
| 88 | trig << GIC_INTR_BIT(intr)); | 114 | (unsigned long)trig << GIC_INTR_BIT(intr)); |
| 89 | } | 115 | } |
| 90 | 116 | ||
| 91 | static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual) | 117 | static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual) |
| 92 | { | 118 | { |
| 93 | gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr), | 119 | gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr), |
| 94 | 1 << GIC_INTR_BIT(intr), | 120 | 1ul << GIC_INTR_BIT(intr), |
| 95 | dual << GIC_INTR_BIT(intr)); | 121 | (unsigned long)dual << GIC_INTR_BIT(intr)); |
| 96 | } | 122 | } |
| 97 | 123 | ||
| 98 | static inline void gic_map_to_pin(unsigned int intr, unsigned int pin) | 124 | static inline void gic_map_to_pin(unsigned int intr, unsigned int pin) |
| 99 | { | 125 | { |
| 100 | gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + | 126 | gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + |
| 101 | GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); | 127 | GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); |
| 102 | } | 128 | } |
| 103 | 129 | ||
| 104 | static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe) | 130 | static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe) |
| @@ -113,10 +139,13 @@ cycle_t gic_read_count(void) · 8 unmodified lines | |||
| 113 | { | 139 | { |
| 114 | unsigned int hi, hi2, lo; | 140 | unsigned int hi, hi2, lo; |
| 115 | 141 | ||
| 142 | if (mips_cm_is64) | ||
| 143 | return (cycle_t)gic_read(GIC_REG(SHARED, GIC_SH_COUNTER)); | ||
| 144 | |||
| 116 | do { | 145 | do { |
| 117 | hi = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); | 146 | hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); |
| 118 | lo = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); | 147 | lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); |
| 119 | hi2 = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); | 148 | hi2 = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); |
| 120 | } while (hi2 != hi); | 149 | } while (hi2 != hi); |
| 121 | 150 | ||
| 122 | return (((cycle_t) hi) << 32) + lo; | 151 | return (((cycle_t) hi) << 32) + lo; |
| @@ -135,10 +164,14 @@ unsigned int gic_get_count_width(void) · 12 unmodified lines | |||
| 135 | 164 | ||
| 136 | void gic_write_compare(cycle_t cnt) | 165 | void gic_write_compare(cycle_t cnt) |
| 137 | { | 166 | { |
| 138 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), | 167 | if (mips_cm_is64) { |
| 139 | (int)(cnt >> 32)); | 168 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE), cnt); |
| 140 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), | 169 | } else { |
| 141 | (int)(cnt & 0xffffffff)); | 170 | gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), |
| 171 | (int)(cnt >> 32)); | ||
| 172 | gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), | ||
| 173 | (int)(cnt & 0xffffffff)); | ||
| 174 | } | ||
| 142 | } | 175 | } |
| 143 | 176 | ||
| 144 | void gic_write_cpu_compare(cycle_t cnt, int cpu) | 177 | void gic_write_cpu_compare(cycle_t cnt, int cpu) |
| @@ -148,10 +181,15 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu) · 3 unmodified lines | |||
| 148 | local_irq_save(flags); | 181 | local_irq_save(flags); |
| 149 | 182 | ||
| 150 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); | 183 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); |
| 151 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), | 184 | |
| 152 | (int)(cnt >> 32)); | 185 | if (mips_cm_is64) { |
| 153 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), | 186 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt); |
| 154 | (int)(cnt & 0xffffffff)); | 187 | } else { |
| 188 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), | ||
| 189 | (int)(cnt >> 32)); | ||
| 190 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), | ||
| 191 | (int)(cnt & 0xffffffff)); | ||
| 192 | } | ||
| 155 | 193 | ||
| 156 | local_irq_restore(flags); | 194 | local_irq_restore(flags); |
| 157 | } | 195 | } |
| @@ -160,8 +198,11 @@ cycle_t gic_read_compare(void) · 2 unmodified lines | |||
| 160 | { | 198 | { |
| 161 | unsigned int hi, lo; | 199 | unsigned int hi, lo; |
| 162 | 200 | ||
| 163 | hi = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); | 201 | if (mips_cm_is64) |
| 164 | lo = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); | 202 | return (cycle_t)gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE)); |
| 203 | |||
| 204 | hi = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); | ||
| 205 | lo = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); | ||
| 165 | 206 | ||
| 166 | return (((cycle_t) hi) << 32) + lo; | 207 | return (((cycle_t) hi) << 32) + lo; |
| 167 | } | 208 | } |
| @@ -196,7 +237,7 @@ static bool gic_local_irq_is_routable(int intr) · 28 unmodified lines | |||
| 196 | if (cpu_has_veic) | 237 | if (cpu_has_veic) |
| 197 | return true; | 238 | return true; |
| 198 | 239 | ||
| 199 | vpe_ctl = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_CTL)); | 240 | vpe_ctl = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_CTL)); |
| 200 | switch (intr) { | 241 | switch (intr) { |
| 201 | case GIC_LOCAL_INT_TIMER: | 242 | case GIC_LOCAL_INT_TIMER: |
| 202 | return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK; | 243 | return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK; |
| @@ -262,7 +303,7 @@ int gic_get_c0_fdc_int(void) · 59 unmodified lines | |||
| 262 | 303 | ||
| 263 | static void gic_handle_shared_int(bool chained) | 304 | static void gic_handle_shared_int(bool chained) |
| 264 | { | 305 | { |
| 265 | unsigned int i, intr, virq; | 306 | unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4; |
| 266 | unsigned long *pcpu_mask; | 307 | unsigned long *pcpu_mask; |
| 267 | unsigned long pending_reg, intrmask_reg; | 308 | unsigned long pending_reg, intrmask_reg; |
| 268 | DECLARE_BITMAP(pending, GIC_MAX_INTRS); | 309 | DECLARE_BITMAP(pending, GIC_MAX_INTRS); |
| @@ -277,8 +318,8 @@ static void gic_handle_shared_int(bool chained) · 8 unmodified lines | |||
| 277 | for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) { | 318 | for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) { |
| 278 | pending[i] = gic_read(pending_reg); | 319 | pending[i] = gic_read(pending_reg); |
| 279 | intrmask[i] = gic_read(intrmask_reg); | 320 | intrmask[i] = gic_read(intrmask_reg); |
| 280 | pending_reg += 0x4; | 321 | pending_reg += gic_reg_step; |
| 281 | intrmask_reg += 0x4; | 322 | intrmask_reg += gic_reg_step; |
| 282 | } | 323 | } |
| 283 | 324 | ||
| 284 | bitmap_and(pending, pending, intrmask, gic_shared_intrs); | 325 | bitmap_and(pending, pending, intrmask, gic_shared_intrs); |
| @@ -425,8 +466,8 @@ static void gic_handle_local_int(bool chained) · 140 unmodified lines | |||
| 425 | unsigned long pending, masked; | 466 | unsigned long pending, masked; |
| 426 | unsigned int intr, virq; | 467 | unsigned int intr, virq; |
| 427 | 468 | ||
| 428 | pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); | 469 | pending = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); |
| 429 | masked = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); | 470 | masked = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); |
| 430 | 471 | ||
| 431 | bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS); | 472 | bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS); |
| 432 | 473 | ||
| @@ -449,14 +490,14 @@ static void gic_mask_local_irq(struct irq_data *d) · 16 unmodified lines | |||
| 449 | { | 490 | { |
| 450 | int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); | 491 | int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); |
| 451 | 492 | ||
| 452 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); | 493 | gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); |
| 453 | } | 494 | } |
| 454 | 495 | ||
| 455 | static void gic_unmask_local_irq(struct irq_data *d) | 496 | static void gic_unmask_local_irq(struct irq_data *d) |
| 456 | { | 497 | { |
| 457 | int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); | 498 | int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); |
| 458 | 499 | ||
| 459 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); | 500 | gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); |
| 460 | } | 501 | } |
| 461 | 502 | ||
| 462 | static struct irq_chip gic_local_irq_controller = { | 503 | static struct irq_chip gic_local_irq_controller = { |
| @@ -474,7 +515,7 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d) · 11 unmodified lines | |||
| 474 | spin_lock_irqsave(&gic_lock, flags); | 515 | spin_lock_irqsave(&gic_lock, flags); |
| 475 | for (i = 0; i < gic_vpes; i++) { | 516 | for (i = 0; i < gic_vpes; i++) { |
| 476 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); | 517 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); |
| 477 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); | 518 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); |
| 478 | } | 519 | } |
| 479 | spin_unlock_irqrestore(&gic_lock, flags); | 520 | spin_unlock_irqrestore(&gic_lock, flags); |
| 480 | } | 521 | } |
| @@ -488,7 +529,7 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d) · 7 unmodified lines | |||
| 488 | spin_lock_irqsave(&gic_lock, flags); | 529 | spin_lock_irqsave(&gic_lock, flags); |
| 489 | for (i = 0; i < gic_vpes; i++) { | 530 | for (i = 0; i < gic_vpes; i++) { |
| 490 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); | 531 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); |
| 491 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); | 532 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); |
| 492 | } | 533 | } |
| 493 | spin_unlock_irqrestore(&gic_lock, flags); | 534 | spin_unlock_irqrestore(&gic_lock, flags); |
| 494 | } | 535 | } |
| @@ -608,7 +649,7 @@ static void __init gic_basic_init(void) · 113 unmodified lines | |||
| 608 | for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { | 649 | for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { |
| 609 | if (!gic_local_irq_is_routable(j)) | 650 | if (!gic_local_irq_is_routable(j)) |
| 610 | continue; | 651 | continue; |
| 611 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); | 652 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); |
| 612 | } | 653 | } |
| 613 | } | 654 | } |
| 614 | } | 655 | } |
| @@ -653,27 +694,32 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, · 38 unmodified lines | |||
| 653 | 694 | ||
| 654 | switch (intr) { | 695 | switch (intr) { |
| 655 | case GIC_LOCAL_INT_WD: | 696 | case GIC_LOCAL_INT_WD: |
| 656 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); | 697 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); |
| 657 | break; | 698 | break; |
| 658 | case GIC_LOCAL_INT_COMPARE: | 699 | case GIC_LOCAL_INT_COMPARE: |
| 659 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val); | 700 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), |
| 701 | val); | ||
| 660 | break; | 702 | break; |
| 661 | case GIC_LOCAL_INT_TIMER: | 703 | case GIC_LOCAL_INT_TIMER: |
| 662 | /* CONFIG_MIPS_CMP workaround (see __gic_init) */ | 704 | /* CONFIG_MIPS_CMP workaround (see __gic_init) */ |
| 663 | val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin; | 705 | val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin; |
| 664 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val); | 706 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), |
| 707 | val); | ||
| 665 | break; | 708 | break; |
| 666 | case GIC_LOCAL_INT_PERFCTR: | 709 | case GIC_LOCAL_INT_PERFCTR: |
| 667 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), val); | 710 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), |
| 711 | val); | ||
| 668 | break; | 712 | break; |
| 669 | case GIC_LOCAL_INT_SWINT0: | 713 | case GIC_LOCAL_INT_SWINT0: |
| 670 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), val); | 714 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), |
| 715 | val); | ||
| 671 | break; | 716 | break; |
| 672 | case GIC_LOCAL_INT_SWINT1: | 717 | case GIC_LOCAL_INT_SWINT1: |
| 673 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), val); | 718 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), |
| 719 | val); | ||
| 674 | break; | 720 | break; |
| 675 | case GIC_LOCAL_INT_FDC: | 721 | case GIC_LOCAL_INT_FDC: |
| 676 | gic_write(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); | 722 | gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); |
| 677 | break; | 723 | break; |
| 678 | default: | 724 | default: |
| 679 | pr_err("Invalid local IRQ %d\n", intr); | 725 | pr_err("Invalid local IRQ %d\n", intr); |
| @@ -778,7 +824,7 @@ static void __init __gic_init(unsigned long gic_base_addr, · 98 unmodified lines | |||
| 778 | */ | 824 | */ |
| 779 | if (IS_ENABLED(CONFIG_MIPS_CMP) && | 825 | if (IS_ENABLED(CONFIG_MIPS_CMP) && |
| 780 | gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { | 826 | gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { |
| 781 | timer_cpu_pin = gic_read(GIC_REG(VPE_LOCAL, | 827 | timer_cpu_pin = gic_read32(GIC_REG(VPE_LOCAL, |
| 782 | GIC_VPE_TIMER_MAP)) & | 828 | GIC_VPE_TIMER_MAP)) & |
| 783 | GIC_MAP_MSK; | 829 | GIC_MAP_MSK; |
| 784 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + | 830 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + |
| @@ -41,6 +41,8 @@ · 40 unmodified lines | |||
| 41 | #include <linux/gpio.h> | 41 | #include <linux/gpio.h> |
| 42 | #include <linux/atomic.h> | 42 | #include <linux/atomic.h> |
| 43 | 43 | ||
| 44 | #include <asm/mach-ar7/ar7.h> | ||
| 45 | |||
| 44 | MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>"); | 46 | MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>"); |
| 45 | MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); | 47 | MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); |
| 46 | MODULE_LICENSE("GPL"); | 48 | MODULE_LICENSE("GPL"); |
| @@ -70,7 +70,14 @@ static irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id) · 69 unmodified lines | |||
| 70 | */ | 70 | */ |
| 71 | static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) | 71 | static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) |
| 72 | { | 72 | { |
| 73 | if ((work->word2.snoip.err_code == 10) && (work->len <= 64)) { | 73 | int port; |
| 74 | |||
| 75 | if (octeon_has_feature(OCTEON_FEATURE_PKND)) | ||
| 76 | port = work->word0.pip.cn68xx.pknd; | ||
| 77 | else | ||
| 78 | port = work->word1.cn38xx.ipprt; | ||
| 79 | |||
| 80 | if ((work->word2.snoip.err_code == 10) && (work->word1.len <= 64)) { | ||
| 74 | /* | 81 | /* |
| 75 | * Ignore length errors on min size packets. Some | 82 | * Ignore length errors on min size packets. Some |
| 76 | * equipment incorrectly pads packets to 64+4FCS | 83 | * equipment incorrectly pads packets to 64+4FCS |
| @@ -87,8 +94,8 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) · 10 unmodified lines | |||
| 87 | * packet to determine if we can remove a non spec | 94 | * packet to determine if we can remove a non spec |
| 88 | * preamble and generate a correct packet. | 95 | * preamble and generate a correct packet. |
| 89 | */ | 96 | */ |
| 90 | int interface = cvmx_helper_get_interface_num(work->ipprt); | 97 | int interface = cvmx_helper_get_interface_num(port); |
| 91 | int index = cvmx_helper_get_interface_index_num(work->ipprt); | 98 | int index = cvmx_helper_get_interface_index_num(port); |
| 92 | union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; | 99 | union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; |
| 93 | 100 | ||
| 94 | gmxx_rxx_frm_ctl.u64 = | 101 | gmxx_rxx_frm_ctl.u64 = |
| @@ -99,7 +106,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) · 4 unmodified lines | |||
| 99 | cvmx_phys_to_ptr(work->packet_ptr.s.addr); | 106 | cvmx_phys_to_ptr(work->packet_ptr.s.addr); |
| 100 | int i = 0; | 107 | int i = 0; |
| 101 | 108 | ||
| 102 | while (i < work->len - 1) { | 109 | while (i < work->word1.len - 1) { |
| 103 | if (*ptr != 0x55) | 110 | if (*ptr != 0x55) |
| 104 | break; | 111 | break; |
| 105 | ptr++; | 112 | ptr++; |
| @@ -109,18 +116,18 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) · 3 unmodified lines | |||
| 109 | if (*ptr == 0xd5) { | 116 | if (*ptr == 0xd5) { |
| 110 | /* | 117 | /* |
| 111 | printk_ratelimited("Port %d received 0xd5 preamble\n", | 118 | printk_ratelimited("Port %d received 0xd5 preamble\n", |
| 112 | work->ipprt); | 119 | port); |
| 113 | */ | 120 | */ |
| 114 | work->packet_ptr.s.addr += i + 1; | 121 | work->packet_ptr.s.addr += i + 1; |
| 115 | work->len -= i + 5; | 122 | work->word1.len -= i + 5; |
| 116 | } else if ((*ptr & 0xf) == 0xd) { | 123 | } else if ((*ptr & 0xf) == 0xd) { |
| 117 | /* | 124 | /* |
| 118 | printk_ratelimited("Port %d received 0x?d preamble\n", | 125 | printk_ratelimited("Port %d received 0x?d preamble\n", |
| 119 | work->ipprt); | 126 | port); |
| 120 | */ | 127 | */ |
| 121 | work->packet_ptr.s.addr += i; | 128 | work->packet_ptr.s.addr += i; |
| 122 | work->len -= i + 4; | 129 | work->word1.len -= i + 4; |
| 123 | for (i = 0; i < work->len; i++) { | 130 | for (i = 0; i < work->word1.len; i++) { |
| 124 | *ptr = | 131 | *ptr = |
| 125 | ((*ptr & 0xf0) >> 4) | | 132 | ((*ptr & 0xf0) >> 4) | |
| 126 | ((*(ptr + 1) & 0xf) << 4); | 133 | ((*(ptr + 1) & 0xf) << 4); |
| @@ -128,7 +135,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) · 1 unmodified line | |||
| 128 | } | 135 | } |
| 129 | } else { | 136 | } else { |
| 130 | printk_ratelimited("Port %d unknown preamble, packet dropped\n", | 137 | printk_ratelimited("Port %d unknown preamble, packet dropped\n", |
| 131 | work->ipprt); | 138 | port); |
| 132 | /* | 139 | /* |
| 133 | cvmx_helper_dump_packet(work); | 140 | cvmx_helper_dump_packet(work); |
| 134 | */ | 141 | */ |
| @@ -138,7 +145,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) · 3 unmodified lines | |||
| 138 | } | 145 | } |
| 139 | } else { | 146 | } else { |
| 140 | printk_ratelimited("Port %d receive error code %d, packet dropped\n", | 147 | printk_ratelimited("Port %d receive error code %d, packet dropped\n", |
| 141 | work->ipprt, work->word2.snoip.err_code); | 148 | port, work->word2.snoip.err_code); |
| 142 | cvm_oct_free_work(work); | 149 | cvm_oct_free_work(work); |
| 143 | return 1; | 150 | return 1; |
| 144 | } | 151 | } |
| @@ -172,9 +179,16 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 27 unmodified lines | |||
| 172 | } | 179 | } |
| 173 | 180 | ||
| 174 | /* Only allow work for our group (and preserve priorities) */ | 181 | /* Only allow work for our group (and preserve priorities) */ |
| 175 | old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); | 182 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { |
| 176 | cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), | 183 | old_group_mask = cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); |
| 177 | (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); | 184 | cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid), |
| 185 | 1ull << pow_receive_group); | ||
| 186 | cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */ | ||
| 187 | } else { | ||
| 188 | old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); | ||
| 189 | cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), | ||
| 190 | (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); | ||
| 191 | } | ||
| 178 | 192 | ||
| 179 | if (USE_ASYNC_IOBDMA) { | 193 | if (USE_ASYNC_IOBDMA) { |
| 180 | cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT); | 194 | cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT); |
| @@ -186,6 +200,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 5 unmodified lines | |||
| 186 | struct sk_buff **pskb = NULL; | 200 | struct sk_buff **pskb = NULL; |
| 187 | int skb_in_hw; | 201 | int skb_in_hw; |
| 188 | cvmx_wqe_t *work; | 202 | cvmx_wqe_t *work; |
| 203 | int port; | ||
| 189 | 204 | ||
| 190 | if (USE_ASYNC_IOBDMA && did_work_request) | 205 | if (USE_ASYNC_IOBDMA && did_work_request) |
| 191 | work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH); | 206 | work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH); |
| @@ -195,12 +210,19 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 3 unmodified lines | |||
| 195 | prefetch(work); | 210 | prefetch(work); |
| 196 | did_work_request = 0; | 211 | did_work_request = 0; |
| 197 | if (work == NULL) { | 212 | if (work == NULL) { |
| 198 | union cvmx_pow_wq_int wq_int; | 213 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { |
| 214 | cvmx_write_csr(CVMX_SSO_WQ_IQ_DIS, | ||
| 215 | 1ull << pow_receive_group); | ||
| 216 | cvmx_write_csr(CVMX_SSO_WQ_INT, | ||
| 217 | 1ull << pow_receive_group); | ||
| 218 | } else { | ||
| 219 | union cvmx_pow_wq_int wq_int; | ||
| 199 | 220 | ||
| 200 | wq_int.u64 = 0; | 221 | wq_int.u64 = 0; |
| 201 | wq_int.s.iq_dis = 1 << pow_receive_group; | 222 | wq_int.s.iq_dis = 1 << pow_receive_group; |
| 202 | wq_int.s.wq_int = 1 << pow_receive_group; | 223 | wq_int.s.wq_int = 1 << pow_receive_group; |
| 203 | cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); | 224 | cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); |
| 225 | } | ||
| 204 | break; | 226 | break; |
| 205 | } | 227 | } |
| 206 | pskb = (struct sk_buff **)(cvm_oct_get_buffer_ptr(work->packet_ptr) - | 228 | pskb = (struct sk_buff **)(cvm_oct_get_buffer_ptr(work->packet_ptr) - |
| @@ -220,7 +242,13 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 13 unmodified lines | |||
| 220 | prefetch(&skb->head); | 242 | prefetch(&skb->head); |
| 221 | prefetch(&skb->len); | 243 | prefetch(&skb->len); |
| 222 | } | 244 | } |
| 223 | prefetch(cvm_oct_device[work->ipprt]); | 245 | |
| 246 | if (octeon_has_feature(OCTEON_FEATURE_PKND)) | ||
| 247 | port = work->word0.pip.cn68xx.pknd; | ||
| 248 | else | ||
| 249 | port = work->word1.cn38xx.ipprt; | ||
| 250 | |||
| 251 | prefetch(cvm_oct_device[port]); | ||
| 224 | 252 | ||
| 225 | /* Immediately throw away all packets with receive errors */ | 253 | /* Immediately throw away all packets with receive errors */ |
| 226 | if (unlikely(work->word2.snoip.rcv_error)) { | 254 | if (unlikely(work->word2.snoip.rcv_error)) { |
| @@ -237,7 +265,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 10 unmodified lines | |||
| 237 | skb->data = skb->head + work->packet_ptr.s.addr - | 265 | skb->data = skb->head + work->packet_ptr.s.addr - |
| 238 | cvmx_ptr_to_phys(skb->head); | 266 | cvmx_ptr_to_phys(skb->head); |
| 239 | prefetch(skb->data); | 267 | prefetch(skb->data); |
| 240 | skb->len = work->len; | 268 | skb->len = work->word1.len; |
| 241 | skb_set_tail_pointer(skb, skb->len); | 269 | skb_set_tail_pointer(skb, skb->len); |
| 242 | packet_not_copied = 1; | 270 | packet_not_copied = 1; |
| 243 | } else { | 271 | } else { |
| @@ -245,7 +273,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 1 unmodified line | |||
| 245 | * We have to copy the packet. First allocate | 273 | * We have to copy the packet. First allocate |
| 246 | * an skbuff for it. | 274 | * an skbuff for it. |
| 247 | */ | 275 | */ |
| 248 | skb = dev_alloc_skb(work->len); | 276 | skb = dev_alloc_skb(work->word1.len); |
| 249 | if (!skb) { | 277 | if (!skb) { |
| 250 | cvm_oct_free_work(work); | 278 | cvm_oct_free_work(work); |
| 251 | continue; | 279 | continue; |
| @@ -268,13 +296,14 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 16 unmodified lines | |||
| 268 | else | 296 | else |
| 269 | ptr += 6; | 297 | ptr += 6; |
| 270 | } | 298 | } |
| 271 | memcpy(skb_put(skb, work->len), ptr, work->len); | 299 | memcpy(skb_put(skb, work->word1.len), ptr, |
| 300 | work->word1.len); | ||
| 272 | /* No packet buffers to free */ | 301 | /* No packet buffers to free */ |
| 273 | } else { | 302 | } else { |
| 274 | int segments = work->word2.s.bufs; | 303 | int segments = work->word2.s.bufs; |
| 275 | union cvmx_buf_ptr segment_ptr = | 304 | union cvmx_buf_ptr segment_ptr = |
| 276 | work->packet_ptr; | 305 | work->packet_ptr; |
| 277 | int len = work->len; | 306 | int len = work->word1.len; |
| 278 | 307 | ||
| 279 | while (segments--) { | 308 | while (segments--) { |
| 280 | union cvmx_buf_ptr next_ptr = | 309 | union cvmx_buf_ptr next_ptr = |
| @@ -310,10 +339,9 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 29 unmodified lines | |||
| 310 | } | 339 | } |
| 311 | packet_not_copied = 0; | 340 | packet_not_copied = 0; |
| 312 | } | 341 | } |
| 313 | 342 | if (likely((port < TOTAL_NUMBER_OF_PORTS) && | |
| 314 | if (likely((work->ipprt < TOTAL_NUMBER_OF_PORTS) && | 343 | cvm_oct_device[port])) { |
| 315 | cvm_oct_device[work->ipprt])) { | 344 | struct net_device *dev = cvm_oct_device[port]; |
| 316 | struct net_device *dev = cvm_oct_device[work->ipprt]; | ||
| 317 | struct octeon_ethernet *priv = netdev_priv(dev); | 345 | struct octeon_ethernet *priv = netdev_priv(dev); |
| 318 | 346 | ||
| 319 | /* | 347 | /* |
| @@ -333,7 +361,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 13 unmodified lines | |||
| 333 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 361 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 334 | 362 | ||
| 335 | /* Increment RX stats for virtual ports */ | 363 | /* Increment RX stats for virtual ports */ |
| 336 | if (work->ipprt >= CVMX_PIP_NUM_INPUT_PORTS) { | 364 | if (port >= CVMX_PIP_NUM_INPUT_PORTS) { |
| 337 | #ifdef CONFIG_64BIT | 365 | #ifdef CONFIG_64BIT |
| 338 | atomic64_add(1, | 366 | atomic64_add(1, |
| 339 | (atomic64_t *)&priv->stats.rx_packets); | 367 | (atomic64_t *)&priv->stats.rx_packets); |
| @@ -368,7 +396,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 28 unmodified lines | |||
| 368 | * doesn't exist. | 396 | * doesn't exist. |
| 369 | */ | 397 | */ |
| 370 | printk_ratelimited("Port %d not controlled by Linux, packet dropped\n", | 398 | printk_ratelimited("Port %d not controlled by Linux, packet dropped\n", |
| 371 | work->ipprt); | 399 | port); |
| 372 | dev_kfree_skb_irq(skb); | 400 | dev_kfree_skb_irq(skb); |
| 373 | } | 401 | } |
| 374 | /* | 402 | /* |
| @@ -390,7 +418,13 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 15 unmodified lines | |||
| 390 | } | 418 | } |
| 391 | } | 419 | } |
| 392 | /* Restore the original POW group mask */ | 420 | /* Restore the original POW group mask */ |
| 393 | cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask); | 421 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { |
| 422 | cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid), old_group_mask); | ||
| 423 | cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */ | ||
| 424 | } else { | ||
| 425 | cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask); | ||
| 426 | } | ||
| 427 | |||
| 394 | if (USE_ASYNC_IOBDMA) { | 428 | if (USE_ASYNC_IOBDMA) { |
| 395 | /* Restore the scratch area */ | 429 | /* Restore the scratch area */ |
| 396 | cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch); | 430 | cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch); |
| @@ -422,8 +456,6 @@ void cvm_oct_rx_initialize(void) · 25 unmodified lines | |||
| 422 | { | 456 | { |
| 423 | int i; | 457 | int i; |
| 424 | struct net_device *dev_for_napi = NULL; | 458 | struct net_device *dev_for_napi = NULL; |
| 425 | union cvmx_pow_wq_int_thrx int_thr; | ||
| 426 | union cvmx_pow_wq_int_pc int_pc; | ||
| 427 | 459 | ||
| 428 | for (i = 0; i < TOTAL_NUMBER_OF_PORTS; i++) { | 460 | for (i = 0; i < TOTAL_NUMBER_OF_PORTS; i++) { |
| 429 | if (cvm_oct_device[i]) { | 461 | if (cvm_oct_device[i]) { |
| @@ -449,15 +481,34 @@ void cvm_oct_rx_initialize(void) · 19 unmodified lines | |||
| 449 | 481 | ||
| 450 | disable_irq_nosync(OCTEON_IRQ_WORKQ0 + pow_receive_group); | 482 | disable_irq_nosync(OCTEON_IRQ_WORKQ0 + pow_receive_group); |
| 451 | 483 | ||
| 452 | int_thr.u64 = 0; | ||
| 453 | int_thr.s.tc_en = 1; | ||
| 454 | int_thr.s.tc_thr = 1; | ||
| 455 | /* Enable POW interrupt when our port has at least one packet */ | 484 | /* Enable POW interrupt when our port has at least one packet */ |
| 456 | cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), int_thr.u64); | 485 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { |
| 457 | 486 | union cvmx_sso_wq_int_thrx int_thr; | |
| 458 | int_pc.u64 = 0; | 487 | union cvmx_pow_wq_int_pc int_pc; |
| 459 | int_pc.s.pc_thr = 5; | 488 | |
| 460 | cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64); | 489 | int_thr.u64 = 0; |
| 490 | int_thr.s.tc_en = 1; | ||
| 491 | int_thr.s.tc_thr = 1; | ||
| 492 | cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), | ||
| 493 | int_thr.u64); | ||
| 494 | |||
| 495 | int_pc.u64 = 0; | ||
| 496 | int_pc.s.pc_thr = 5; | ||
| 497 | cvmx_write_csr(CVMX_SSO_WQ_INT_PC, int_pc.u64); | ||
| 498 | } else { | ||
| 499 | union cvmx_pow_wq_int_thrx int_thr; | ||
| 500 | union cvmx_pow_wq_int_pc int_pc; | ||
| 501 | |||
| 502 | int_thr.u64 = 0; | ||
| 503 | int_thr.s.tc_en = 1; | ||
| 504 | int_thr.s.tc_thr = 1; | ||
| 505 | cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), | ||
| 506 | int_thr.u64); | ||
| 507 | |||
| 508 | int_pc.u64 = 0; | ||
| 509 | int_pc.s.pc_thr = 5; | ||
| 510 | cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64); | ||
| 511 | } | ||
| 461 | 512 | ||
| 462 | /* Schedule NAPI now. This will indirectly enable the interrupt. */ | 513 | /* Schedule NAPI now. This will indirectly enable the interrupt. */ |
| 463 | napi_schedule(&cvm_oct_napi); | 514 | napi_schedule(&cvm_oct_napi); |
| @@ -591,13 +591,14 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) · 590 unmodified lines | |||
| 591 | * Fill in some of the work queue fields. We may need to add | 591 | * Fill in some of the work queue fields. We may need to add |
| 592 | * more if the software at the other end needs them. | 592 | * more if the software at the other end needs them. |
| 593 | */ | 593 | */ |
| 594 | work->hw_chksum = skb->csum; | 594 | if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) |
| 595 | work->len = skb->len; | 595 | work->word0.pip.cn38xx.hw_chksum = skb->csum; |
| 596 | work->ipprt = priv->port; | 596 | work->word1.len = skb->len; |
| 597 | work->qos = priv->port & 0x7; | 597 | cvmx_wqe_set_port(work, priv->port); |
| 598 | work->grp = pow_send_group; | 598 | cvmx_wqe_set_qos(work, priv->port & 0x7); |
| 599 | work->tag_type = CVMX_HELPER_INPUT_TAG_TYPE; | 599 | cvmx_wqe_set_grp(work, pow_send_group); |
| 600 | work->tag = pow_send_group; /* FIXME */ | 600 | work->word1.tag_type = CVMX_HELPER_INPUT_TAG_TYPE; |
| 601 | work->word1.tag = pow_send_group; /* FIXME */ | ||
| 601 | /* Default to zero. Sets of zero later are commented out */ | 602 | /* Default to zero. Sets of zero later are commented out */ |
| 602 | work->word2.u64 = 0; | 603 | work->word2.u64 = 0; |
| 603 | work->word2.s.bufs = 1; | 604 | work->word2.s.bufs = 1; |
| @@ -677,8 +678,8 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) · 73 unmodified lines | |||
| 677 | } | 678 | } |
| 678 | 679 | ||
| 679 | /* Submit the packet to the POW */ | 680 | /* Submit the packet to the POW */ |
| 680 | cvmx_pow_work_submit(work, work->tag, work->tag_type, work->qos, | 681 | cvmx_pow_work_submit(work, work->word1.tag, work->word1.tag_type, |
| 681 | work->grp); | 682 | cvmx_wqe_get_qos(work), cvmx_wqe_get_grp(work)); |
| 682 | priv->stats.tx_packets++; | 683 | priv->stats.tx_packets++; |
| 683 | priv->stats.tx_bytes += skb->len; | 684 | priv->stats.tx_bytes += skb->len; |
| 684 | dev_consume_skb_any(skb); | 685 | dev_consume_skb_any(skb); |
| @@ -8,6 +8,10 @@ · 7 unmodified lines | |||
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <asm/octeon/cvmx-pip.h> | ||
| 12 | #include <asm/octeon/cvmx-helper.h> | ||
| 13 | #include <asm/octeon/cvmx-helper-util.h> | ||
| 14 | |||
| 11 | /** | 15 | /** |
| 12 | * cvm_oct_get_buffer_ptr - convert packet data address to pointer | 16 | * cvm_oct_get_buffer_ptr - convert packet data address to pointer |
| 13 | * @packet_ptr: Packet data hardware address | 17 | * @packet_ptr: Packet data hardware address |
| @@ -28,14 +32,12 @@ static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr) · 14 unmodified lines | |||
| 28 | */ | 32 | */ |
| 29 | static inline int INTERFACE(int ipd_port) | 33 | static inline int INTERFACE(int ipd_port) |
| 30 | { | 34 | { |
| 31 | if (ipd_port < 32) /* Interface 0 or 1 for RGMII,GMII,SPI, etc */ | 35 | int interface = cvmx_helper_get_interface_num(ipd_port); |
| 32 | return ipd_port >> 4; | 36 | |
| 33 | else if (ipd_port < 36) /* Interface 2 for NPI */ | 37 | if (interface >= 0) |
| 34 | return 2; | 38 | return interface; |
| 35 | else if (ipd_port < 40) /* Interface 3 for loopback */ | 39 | else if (ipd_port == CVMX_PIP_NUM_INPUT_PORTS) |
| 36 | return 3; | 40 | return 10; |
| 37 | else if (ipd_port == 40) /* Non existent interface for POW0 */ | ||
| 38 | return 4; | ||
| 39 | panic("Illegal ipd_port %d passed to INTERFACE\n", ipd_port); | 41 | panic("Illegal ipd_port %d passed to INTERFACE\n", ipd_port); |
| 40 | } | 42 | } |
| 41 | 43 | ||
| @@ -47,7 +49,5 @@ static inline int INTERFACE(int ipd_port) · 5 unmodified lines | |||
| 47 | */ | 49 | */ |
| 48 | static inline int INDEX(int ipd_port) | 50 | static inline int INDEX(int ipd_port) |
| 49 | { | 51 | { |
| 50 | if (ipd_port < 32) | 52 | return cvmx_helper_get_interface_index_num(ipd_port); |
| 51 | return ipd_port & 15; | ||
| 52 | return ipd_port & 3; | ||
| 53 | } | 53 | } |
| @@ -152,7 +152,7 @@ static void cvm_oct_configure_common_hw(void) · 151 unmodified lines | |||
| 152 | num_packet_buffers); | 152 | num_packet_buffers); |
| 153 | if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) | 153 | if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) |
| 154 | cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, | 154 | cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, |
| 155 | CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); | 155 | CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 1024); |
| 156 | 156 | ||
| 157 | #ifdef __LITTLE_ENDIAN | 157 | #ifdef __LITTLE_ENDIAN |
| 158 | { | 158 | { |
| @@ -860,7 +860,10 @@ static int cvm_oct_remove(struct platform_device *pdev) · 701 unmodified lines | |||
| 860 | int port; | 860 | int port; |
| 861 | 861 | ||
| 862 | /* Disable POW interrupt */ | 862 | /* Disable POW interrupt */ |
| 863 | cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); | 863 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) |
| 864 | cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), 0); | ||
| 865 | else | ||
| 866 | cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); | ||
| 864 | 867 | ||
| 865 | cvmx_ipd_disable(); | 868 | cvmx_ipd_disable(); |
| 866 | 869 | ||
| @@ -879,6 +879,11 @@ static const struct tty_operations mips_ejtag_fdc_tty_ops = { · 878 unmodified lines | |||
| 879 | .chars_in_buffer = mips_ejtag_fdc_tty_chars_in_buffer, | 879 | .chars_in_buffer = mips_ejtag_fdc_tty_chars_in_buffer, |
| 880 | }; | 880 | }; |
| 881 | 881 | ||
| 882 | int __weak get_c0_fdc_int(void) | ||
| 883 | { | ||
| 884 | return -1; | ||
| 885 | } | ||
| 886 | |||
| 882 | static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) | 887 | static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) |
| 883 | { | 888 | { |
| 884 | int ret, nport; | 889 | int ret, nport; |
| @@ -967,9 +972,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) · 82 unmodified lines | |||
| 967 | wake_up_process(priv->thread); | 972 | wake_up_process(priv->thread); |
| 968 | 973 | ||
| 969 | /* Look for an FDC IRQ */ | 974 | /* Look for an FDC IRQ */ |
| 970 | priv->irq = -1; | 975 | priv->irq = get_c0_fdc_int(); |
| 971 | if (get_c0_fdc_int) | ||
| 972 | priv->irq = get_c0_fdc_int(); | ||
| 973 | 976 | ||
| 974 | /* Try requesting the IRQ */ | 977 | /* Try requesting the IRQ */ |
| 975 | if (priv->irq >= 0) { | 978 | if (priv->irq >= 0) { |
| @@ -41,12 +41,20 @@ · 40 unmodified lines | |||
| 41 | 41 | ||
| 42 | /* Shared Global Counter */ | 42 | /* Shared Global Counter */ |
| 43 | #define GIC_SH_COUNTER_31_00_OFS 0x0010 | 43 | #define GIC_SH_COUNTER_31_00_OFS 0x0010 |
| 44 | /* 64-bit counter register for CM3 */ | ||
| 45 | #define GIC_SH_COUNTER_OFS GIC_SH_COUNTER_31_00_OFS | ||
| 44 | #define GIC_SH_COUNTER_63_32_OFS 0x0014 | 46 | #define GIC_SH_COUNTER_63_32_OFS 0x0014 |
| 45 | #define GIC_SH_REVISIONID_OFS 0x0020 | 47 | #define GIC_SH_REVISIONID_OFS 0x0020 |
| 46 | 48 | ||
| 47 | /* Convert an interrupt number to a byte offset/bit for multi-word registers */ | 49 | /* Convert an interrupt number to a byte offset/bit for multi-word registers */ |
| 48 | #define GIC_INTR_OFS(intr) (((intr) / 32) * 4) | 50 | #define GIC_INTR_OFS(intr) ({ \ |
| 49 | #define GIC_INTR_BIT(intr) ((intr) % 32) | 51 | unsigned bits = mips_cm_is64 ? 64 : 32; \ |
| 52 | unsigned reg_idx = (intr) / bits; \ | ||
| 53 | unsigned reg_width = bits / 8; \ | ||
| 54 | \ | ||
| 55 | reg_idx * reg_width; \ | ||
| 56 | }) | ||
| 57 | #define GIC_INTR_BIT(intr) ((intr) % (mips_cm_is64 ? 64 : 32)) | ||
| 50 | 58 | ||
| 51 | /* Polarity : Reset Value is always 0 */ | 59 | /* Polarity : Reset Value is always 0 */ |
| 52 | #define GIC_SH_SET_POLARITY_OFS 0x0100 | 60 | #define GIC_SH_SET_POLARITY_OFS 0x0100 |
| @@ -98,6 +106,8 @@ · 45 unmodified lines | |||
| 98 | #define GIC_VPE_WD_COUNT0_OFS 0x0094 | 106 | #define GIC_VPE_WD_COUNT0_OFS 0x0094 |
| 99 | #define GIC_VPE_WD_INITIAL0_OFS 0x0098 | 107 | #define GIC_VPE_WD_INITIAL0_OFS 0x0098 |
| 100 | #define GIC_VPE_COMPARE_LO_OFS 0x00a0 | 108 | #define GIC_VPE_COMPARE_LO_OFS 0x00a0 |
| 109 | /* 64-bit Compare register on CM3 */ | ||
| 110 | #define GIC_VPE_COMPARE_OFS GIC_VPE_COMPARE_LO_OFS | ||
| 101 | #define GIC_VPE_COMPARE_HI_OFS 0x00a4 | 111 | #define GIC_VPE_COMPARE_HI_OFS 0x00a4 |
| 102 | 112 | ||
| 103 | #define GIC_VPE_EIC_SHADOW_SET_BASE_OFS 0x0100 | 113 | #define GIC_VPE_EIC_SHADOW_SET_BASE_OFS 0x0100 |