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 | 22 | | m68k: | TODO | |
| 23 | 23 | | metag: | TODO | |
| 24 | 24 | | microblaze: | TODO | |
| 25 | − | mips: | TODO | | |
| 25 | + | mips: | ok | | |
| 26 | 26 | | mn10300: | TODO | |
| 27 | 27 | | nios2: | TODO | |
| 28 | 28 | | openrisc: | TODO | |
| @@ -119,6 +119,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.: · 118 unmodified lines | ||
| 119 | 119 | |
| 120 | 120 | 'x' - Used by xmon interface on ppc/powerpc platforms. |
| 121 | 121 | Show global PMU Registers on sparc64. |
| 122 | + Dump all TLB entries on MIPS. | |
| 122 | 123 | |
| 123 | 124 | 'y' - Show global CPU Registers [SPARC-64 specific] |
| 124 | 125 | |
| @@ -1,8 +1,10 @@ | ||
| 1 | 1 | config MIPS |
| 2 | 2 | bool |
| 3 | 3 | default y |
| 4 | + select ARCH_SUPPORTS_UPROBES | |
| 4 | 5 | select ARCH_MIGHT_HAVE_PC_PARPORT |
| 5 | 6 | select ARCH_MIGHT_HAVE_PC_SERIO |
| 7 | + select ARCH_USE_CMPXCHG_LOCKREF if 64BIT | |
| 6 | 8 | select HAVE_CONTEXT_TRACKING |
| 7 | 9 | select HAVE_GENERIC_DMA_COHERENT |
| 8 | 10 | select HAVE_IDE |
| @@ -13,7 +15,6 @@ config MIPS · 4 unmodified lines | ||
| 13 | 15 | select HAVE_ARCH_SECCOMP_FILTER |
| 14 | 16 | select HAVE_ARCH_TRACEHOOK |
| 15 | 17 | select HAVE_BPF_JIT if !CPU_MICROMIPS |
| 16 | − select ARCH_HAVE_CUSTOM_GPIO_H | |
| 17 | 18 | select HAVE_FUNCTION_TRACER |
| 18 | 19 | select HAVE_DYNAMIC_FTRACE |
| 19 | 20 | select HAVE_FTRACE_MCOUNT_RECORD |
| @@ -409,6 +410,7 @@ config MIPS_MALTA · 389 unmodified lines | ||
| 409 | 410 | select CEVT_R4K |
| 410 | 411 | select CSRC_R4K |
| 411 | 412 | select CLKSRC_MIPS_GIC |
| 413 | + select COMMON_CLK | |
| 412 | 414 | select DMA_MAYBE_COHERENT |
| 413 | 415 | select GENERIC_ISA_DMA |
| 414 | 416 | select HAVE_PCSPKR_PLATFORM |
| @@ -459,6 +461,7 @@ config MIPS_SEAD3 · 44 unmodified lines | ||
| 459 | 461 | select CEVT_R4K |
| 460 | 462 | select CSRC_R4K |
| 461 | 463 | select CLKSRC_MIPS_GIC |
| 464 | + select COMMON_CLK | |
| 462 | 465 | select CPU_MIPSR2_IRQ_VI |
| 463 | 466 | select CPU_MIPSR2_IRQ_EI |
| 464 | 467 | select DMA_NONCOHERENT |
| @@ -899,6 +902,7 @@ config NLM_XLP_BOARD · 434 unmodified lines | ||
| 899 | 902 | select SYS_SUPPORTS_32BIT_KERNEL |
| 900 | 903 | select SYS_SUPPORTS_64BIT_KERNEL |
| 901 | 904 | select ARCH_PHYS_ADDR_T_64BIT |
| 905 | + select ARCH_REQUIRE_GPIOLIB | |
| 902 | 906 | select SYS_SUPPORTS_BIG_ENDIAN |
| 903 | 907 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 904 | 908 | select SYS_SUPPORTS_HIGHMEM |
| @@ -948,6 +952,7 @@ source "arch/mips/jazz/Kconfig" · 43 unmodified lines | ||
| 948 | 952 | source "arch/mips/jz4740/Kconfig" |
| 949 | 953 | source "arch/mips/lantiq/Kconfig" |
| 950 | 954 | source "arch/mips/lasat/Kconfig" |
| 955 | +source "arch/mips/pistachio/Kconfig" | |
| 951 | 956 | source "arch/mips/pmcs-msp71xx/Kconfig" |
| 952 | 957 | source "arch/mips/ralink/Kconfig" |
| 953 | 958 | source "arch/mips/sgi-ip27/Kconfig" |
| @@ -1041,6 +1046,9 @@ config FW_CFE · 87 unmodified lines | ||
| 1041 | 1046 | config ARCH_DMA_ADDR_T_64BIT |
| 1042 | 1047 | def_bool (HIGHMEM && ARCH_PHYS_ADDR_T_64BIT) || 64BIT |
| 1043 | 1048 | |
| 1049 | +config ARCH_SUPPORTS_UPROBES | |
| 1050 | + bool | |
| 1051 | + | |
| 1044 | 1052 | config DMA_MAYBE_COHERENT |
| 1045 | 1053 | select DMA_NONCOHERENT |
| 1046 | 1054 | bool |
| @@ -1364,7 +1372,7 @@ config CPU_MIPS32_R2 · 317 unmodified lines | ||
| 1364 | 1372 | otherwise CPU_MIPS32_R1 is a safe bet for any MIPS32 system. |
| 1365 | 1373 | |
| 1366 | 1374 | config CPU_MIPS32_R6 |
| 1367 | − bool "MIPS32 Release 6 (EXPERIMENTAL)" | |
| 1375 | + bool "MIPS32 Release 6" | |
| 1368 | 1376 | depends on SYS_HAS_CPU_MIPS32_R6 |
| 1369 | 1377 | select CPU_HAS_PREFETCH |
| 1370 | 1378 | select CPU_SUPPORTS_32BIT_KERNEL |
| @@ -1415,7 +1423,7 @@ config CPU_MIPS64_R2 · 44 unmodified lines | ||
| 1415 | 1423 | otherwise CPU_MIPS64_R1 is a safe bet for any MIPS64 system. |
| 1416 | 1424 | |
| 1417 | 1425 | config CPU_MIPS64_R6 |
| 1418 | − bool "MIPS64 Release 6 (EXPERIMENTAL)" | |
| 1426 | + bool "MIPS64 Release 6" | |
| 1419 | 1427 | depends on SYS_HAS_CPU_MIPS64_R6 |
| 1420 | 1428 | select CPU_HAS_PREFETCH |
| 1421 | 1429 | select CPU_SUPPORTS_32BIT_KERNEL |
| @@ -1965,6 +1973,7 @@ config 32BIT · 543 unmodified lines | ||
| 1965 | 1973 | select TRAD_SIGNALS |
| 1966 | 1974 | help |
| 1967 | 1975 | Select this option if you want to build a 32-bit kernel. |
| 1976 | + | |
| 1968 | 1977 | config 64BIT |
| 1969 | 1978 | bool "64-bit kernel" |
| 1970 | 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 | 2120 | config MIPS_MT_SMP |
| 2112 | 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 | 2123 | select CPU_MIPSR2_IRQ_VI |
| 2115 | 2124 | select CPU_MIPSR2_IRQ_EI |
| 2116 | 2125 | select SYNC_R4K |
| @@ -2211,7 +2220,7 @@ config MIPS_VPE_APSP_API_MT · 94 unmodified lines | ||
| 2211 | 2220 | |
| 2212 | 2221 | config MIPS_CMP |
| 2213 | 2222 | bool "MIPS CMP framework support (DEPRECATED)" |
| 2214 | − depends on SYS_SUPPORTS_MIPS_CMP | |
| 2223 | + depends on SYS_SUPPORTS_MIPS_CMP && !CPU_MIPSR6 | |
| 2215 | 2224 | select MIPS_GIC_IPI |
| 2216 | 2225 | select SMP |
| 2217 | 2226 | select SYNC_R4K |
| @@ -2228,7 +2237,7 @@ config MIPS_CMP · 10 unmodified lines | ||
| 2228 | 2237 | |
| 2229 | 2238 | config MIPS_CPS |
| 2230 | 2239 | bool "MIPS Coherent Processing System support" |
| 2231 | − depends on SYS_SUPPORTS_MIPS_CPS | |
| 2240 | + depends on SYS_SUPPORTS_MIPS_CPS && !CPU_MIPSR6 | |
| 2232 | 2241 | select MIPS_CM |
| 2233 | 2242 | select MIPS_CPC |
| 2234 | 2243 | select MIPS_CPS_PM if HOTPLUG_CPU |
| @@ -2303,7 +2312,7 @@ config CPU_MICROMIPS · 68 unmodified lines | ||
| 2303 | 2312 | endchoice |
| 2304 | 2313 | |
| 2305 | 2314 | config CPU_HAS_MSA |
| 2306 | − bool "Support for the MIPS SIMD Architecture (EXPERIMENTAL)" | |
| 2315 | + bool "Support for the MIPS SIMD Architecture" | |
| 2307 | 2316 | depends on CPU_SUPPORTS_MSA |
| 2308 | 2317 | depends on 64BIT || MIPS_O32_FP64_SUPPORT |
| 2309 | 2318 | help |
| @@ -2643,7 +2652,7 @@ config SECCOMP · 333 unmodified lines | ||
| 2643 | 2652 | If unsure, say Y. Only embedded should say N here. |
| 2644 | 2653 | |
| 2645 | 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 | 2656 | depends on 32BIT || MIPS32_O32 |
| 2648 | 2657 | help |
| 2649 | 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 | 87 | Select compile flags that produce code that can be processed by the |
| 88 | 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 | 90 | config DEBUG_ZBOOT |
| 100 | 91 | bool "Enable compressed kernel support debugging" |
| 101 | 92 | depends on DEBUG_KERNEL && SYS_SUPPORTS_ZBOOT |
| @@ -6,13 +6,6 @@ config ALCHEMY_GPIOINT_AU1000 · 5 unmodified lines | ||
| 6 | 6 | config ALCHEMY_GPIOINT_AU1300 |
| 7 | 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 | 9 | choice |
| 17 | 10 | prompt "Machine type" |
| 18 | 11 | depends on MIPS_ALCHEMY |
| @@ -34,6 +34,7 @@ · 33 unmodified lines | ||
| 34 | 34 | #include <asm/idle.h> |
| 35 | 35 | #include <asm/reboot.h> |
| 36 | 36 | #include <asm/mach-au1x00/au1000.h> |
| 37 | +#include <asm/mach-au1x00/gpio-au1000.h> | |
| 37 | 38 | #include <prom.h> |
| 38 | 39 | |
| 39 | 40 | const char *get_system_type(void) |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #include <asm/bootinfo.h> |
| 33 | 33 | #include <asm/reboot.h> |
| 34 | 34 | #include <asm/mach-au1x00/au1000.h> |
| 35 | +#include <asm/mach-au1x00/gpio-au1000.h> | |
| 35 | 36 | #include <asm/mach-au1x00/au1xxx_eth.h> |
| 36 | 37 | #include <prom.h> |
| 37 | 38 | |
| @@ -5,10 +5,5 @@ · 4 unmodified lines | ||
| 5 | 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 | 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 | 491 | default: |
| 492 | 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 | 496 | wmb(); |
| 497 | 497 | |
| @@ -703,7 +703,7 @@ static int au1300_gpic_settype(struct irq_data *d, unsigned int type) · 205 unmodified lines | ||
| 703 | 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 | 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 | 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 | 72 | static irqreturn_t au1x_rtcmatch2_irq(int irq, void *dev_id) |
| 78 | 73 | { |
| 79 | 74 | struct clock_event_device *cd = dev_id; |
| @@ -86,7 +81,6 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = { · 6 unmodified lines | ||
| 86 | 81 | .features = CLOCK_EVT_FEAT_ONESHOT, |
| 87 | 82 | .rating = 1500, |
| 88 | 83 | .set_next_event = au1x_rtcmatch2_set_next_event, |
| 89 | − .set_mode = au1x_rtcmatch2_set_mode, | |
| 90 | 84 | .cpumask = cpu_all_mask, |
| 91 | 85 | }; |
| 92 | 86 | |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | */ |
| 9 | 9 | |
| 10 | 10 | #include <linux/interrupt.h> |
| 11 | +#include <linux/irqchip/chained_irq.h> | |
| 11 | 12 | #include <linux/module.h> |
| 12 | 13 | #include <linux/spinlock.h> |
| 13 | 14 | #include <linux/irq.h> |
| @@ -88,10 +89,11 @@ EXPORT_SYMBOL_GPL(bcsr_mod); · 74 unmodified lines | ||
| 88 | 89 | static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d) |
| 89 | 90 | { |
| 90 | 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 | 95 | generic_handle_irq(bcsr_csc_base + __ffs(bisr)); |
| 94 | − enable_irq(irq); | |
| 96 | + chained_irq_exit(chip, d); | |
| 95 | 97 | } |
| 96 | 98 | |
| 97 | 99 | static void bcsr_irq_mask(struct irq_data *d) |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <linux/spi/spi_gpio.h> |
| 34 | 34 | #include <linux/spi/ads7846.h> |
| 35 | 35 | #include <asm/mach-au1x00/au1000.h> |
| 36 | +#include <asm/mach-au1x00/gpio-au1000.h> | |
| 36 | 37 | #include <asm/mach-au1x00/au1000_dma.h> |
| 37 | 38 | #include <asm/mach-au1x00/au1100_mmc.h> |
| 38 | 39 | #include <asm/mach-db1x00/bcsr.h> |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #include <linux/wm97xx.h> |
| 25 | 25 | |
| 26 | 26 | #include <asm/mach-au1x00/au1000.h> |
| 27 | +#include <asm/mach-au1x00/gpio-au1300.h> | |
| 27 | 28 | #include <asm/mach-au1x00/au1100_mmc.h> |
| 28 | 29 | #include <asm/mach-au1x00/au1200fb.h> |
| 29 | 30 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/spi/flash.h> |
| 21 | 21 | #include <asm/bootinfo.h> |
| 22 | 22 | #include <asm/mach-au1x00/au1000.h> |
| 23 | +#include <asm/mach-au1x00/gpio-au1000.h> | |
| 23 | 24 | #include <asm/mach-au1x00/au1xxx_eth.h> |
| 24 | 25 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
| 25 | 26 | #include <asm/mach-au1x00/au1xxx_psc.h> |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/suspend.h> |
| 10 | 10 | #include <linux/sysfs.h> |
| 11 | 11 | #include <asm/mach-au1x00/au1000.h> |
| 12 | −#include <asm/mach-au1x00/gpio.h> | |
| 12 | +#include <asm/mach-au1x00/gpio-au1000.h> | |
| 13 | 13 | #include <asm/mach-db1x00/bcsr.h> |
| 14 | 14 | |
| 15 | 15 | /* |
| @@ -21,7 +21,10 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <linux/module.h> |
| 22 | 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 | 29 | struct ar7_gpio_chip { |
| 27 | 30 | void __iomem *regs; |
| @@ -39,7 +39,6 @@ · 38 unmodified lines | ||
| 39 | 39 | |
| 40 | 40 | #include <asm/addrspace.h> |
| 41 | 41 | #include <asm/mach-ar7/ar7.h> |
| 42 | −#include <asm/mach-ar7/gpio.h> | |
| 43 | 42 | #include <asm/mach-ar7/prom.h> |
| 44 | 43 | |
| 45 | 44 | /***************************************************************************** |
| @@ -23,7 +23,6 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <asm/reboot.h> |
| 24 | 24 | #include <asm/mach-ar7/ar7.h> |
| 25 | 25 | #include <asm/mach-ar7/prom.h> |
| 26 | −#include <asm/mach-ar7/gpio.h> | |
| 27 | 26 | |
| 28 | 27 | static void ar7_machine_restart(char *command) |
| 29 | 28 | { |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | # under the terms of the GNU General Public License version 2 as published |
| 9 | 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 | 13 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
| 14 | 14 | obj-$(CONFIG_PCI) += pci.o |
| @@ -25,9 +25,6 @@ unsigned long ath79_get_sys_clk_rate(const char *id); · 24 unmodified lines | ||
| 25 | 25 | void ath79_ddr_ctrl_init(void); |
| 26 | 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 | 28 | void ath79_gpio_init(void); |
| 32 | 29 | |
| 33 | 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 | 124 | u32 status; |
| 125 | 125 | |
| 126 | − disable_irq_nosync(irq); | |
| 127 | − | |
| 128 | 126 | status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS); |
| 129 | 127 | |
| 130 | 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 | 134 | } else { |
| 137 | 135 | spurious_interrupt(); |
| 138 | 136 | } |
| 139 | − | |
| 140 | − enable_irq(irq); | |
| 141 | 137 | } |
| 142 | 138 | |
| 143 | 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 | 153 | u32 status; |
| 158 | 154 | |
| 159 | − disable_irq_nosync(irq); | |
| 160 | − | |
| 161 | 155 | status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); |
| 162 | 156 | status &= QCA955X_EXT_INT_PCIE_RC1_ALL | QCA955X_EXT_INT_WMAC_ALL; |
| 163 | 157 | |
| 164 | 158 | if (status == 0) { |
| 165 | 159 | spurious_interrupt(); |
| 166 | − goto enable; | |
| 160 | + return; | |
| 167 | 161 | } |
| 168 | 162 | |
| 169 | 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 | 169 | /* TODO: flush DDR? */ |
| 176 | 170 | generic_handle_irq(ATH79_IP2_IRQ(1)); |
| 177 | 171 | } |
| 178 | − | |
| 179 | −enable: | |
| 180 | − enable_irq(irq); | |
| 181 | 172 | } |
| 182 | 173 | |
| 183 | 174 | static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) |
| 184 | 175 | { |
| 185 | 176 | u32 status; |
| 186 | 177 | |
| 187 | − disable_irq_nosync(irq); | |
| 188 | − | |
| 189 | 178 | status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); |
| 190 | 179 | status &= QCA955X_EXT_INT_PCIE_RC2_ALL | |
| 191 | 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 | 183 | if (status == 0) { |
| 195 | 184 | spurious_interrupt(); |
| 196 | − goto enable; | |
| 185 | + return; | |
| 197 | 186 | } |
| 198 | 187 | |
| 199 | 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 | 199 | /* TODO: flush DDR? */ |
| 211 | 200 | generic_handle_irq(ATH79_IP3_IRQ(2)); |
| 212 | 201 | } |
| 213 | − | |
| 214 | −enable: | |
| 215 | − enable_irq(irq); | |
| 216 | 202 | } |
| 217 | 203 | |
| 218 | 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 | 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 | 400 | if (!bcm47xx_button_pdata.buttons) |
| 401 | 401 | return -ENOMEM; |
| 402 | − memcpy(bcm47xx_button_pdata.buttons, buttons, size); | |
| 403 | 402 | bcm47xx_button_pdata.nbuttons = nbuttons; |
| 404 | 403 | |
| 405 | 404 | return 0; |
| @@ -60,7 +60,7 @@ static inline int enable_irq_for_cpu(int cpu, struct irq_data *d, · 59 unmodified lines | ||
| 60 | 60 | if (m) |
| 61 | 61 | enable &= cpumask_test_cpu(cpu, m); |
| 62 | 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 | 64 | #endif |
| 65 | 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 | 366 | irqd_set_trigger_type(d, flow_type); |
| 367 | 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 | 369 | else |
| 370 | − __irq_set_handler_locked(d->irq, handle_edge_irq); | |
| 370 | + irq_set_handler_locked(d, handle_edge_irq); | |
| 371 | 371 | |
| 372 | 372 | return IRQ_SET_MASK_OK_NOCOPY; |
| 373 | 373 | } |
| @@ -78,7 +78,7 @@ endif · 77 unmodified lines | ||
| 78 | 78 | |
| 79 | 79 | vmlinuzobjs-y += $(obj)/piggy.o |
| 80 | 80 | |
| 81 | −quiet_cmd_zld = LD $@ | |
| 81 | +quiet_cmd_zld = LD $@ | |
| 82 | 82 | cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ |
| 83 | 83 | quiet_cmd_strip = STRIP $@ |
| 84 | 84 | cmd_strip = $(STRIP) -s $@ |
| @@ -110,6 +110,18 @@ · 109 unmodified lines | ||
| 110 | 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 | 127 | chosen { |
| @@ -110,6 +110,18 @@ · 109 unmodified lines | ||
| 110 | 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 | 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 | 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 | 85 | chosen { |
| @@ -110,6 +110,18 @@ · 109 unmodified lines | ||
| 110 | 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 | 127 | chosen { |
| @@ -195,6 +195,12 @@ int cvmx_helper_board_get_mii_address(int ipd_port) · 194 unmodified lines | ||
| 195 | 195 | return 8; |
| 196 | 196 | else |
| 197 | 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 | 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 | 95 | uint8_t *data_address; |
| 96 | 96 | uint8_t *end_of_data; |
| 97 | 97 | |
| 98 | − cvmx_dprintf("Packet Length: %u\n", work->len); | |
| 99 | − cvmx_dprintf(" Input Port: %u\n", work->ipprt); | |
| 100 | − cvmx_dprintf(" QoS: %u\n", work->qos); | |
| 98 | + cvmx_dprintf("Packet Length: %u\n", work->word1.len); | |
| 99 | + cvmx_dprintf(" Input Port: %u\n", cvmx_wqe_get_port(work)); | |
| 100 | + cvmx_dprintf(" QoS: %u\n", cvmx_wqe_get_qos(work)); | |
| 101 | 101 | cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs); |
| 102 | 102 | |
| 103 | 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 | 128 | } else |
| 129 | 129 | buffer_ptr = work->packet_ptr; |
| 130 | − remaining_bytes = work->len; | |
| 130 | + remaining_bytes = work->word1.len; | |
| 131 | 131 | |
| 132 | 132 | while (remaining_bytes) { |
| 133 | 133 | start_of_buffer = |
| @@ -382,6 +382,10 @@ int cvmx_helper_get_ipd_port(int interface, int port) · 248 unmodified lines | ||
| 382 | 382 | return port + 32; |
| 383 | 383 | case 3: |
| 384 | 384 | return port + 36; |
| 385 | + case 4: | |
| 386 | + return port + 40; | |
| 387 | + case 5: | |
| 388 | + return port + 44; | |
| 385 | 389 | } |
| 386 | 390 | return -1; |
| 387 | 391 | } |
| @@ -404,6 +408,10 @@ int cvmx_helper_get_interface_num(int ipd_port) · 16 unmodified lines | ||
| 404 | 408 | return 2; |
| 405 | 409 | else if (ipd_port < 40) |
| 406 | 410 | return 3; |
| 411 | + else if (ipd_port < 44) | |
| 412 | + return 4; | |
| 413 | + else if (ipd_port < 48) | |
| 414 | + return 5; | |
| 407 | 415 | else |
| 408 | 416 | cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD " |
| 409 | 417 | "port number\n"); |
| @@ -428,6 +436,10 @@ int cvmx_helper_get_interface_index_num(int ipd_port) · 18 unmodified lines | ||
| 428 | 436 | return ipd_port & 3; |
| 429 | 437 | else if (ipd_port < 40) |
| 430 | 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 | 443 | else |
| 432 | 444 | cvmx_dprintf("cvmx_helper_get_interface_index_num: " |
| 433 | 445 | "Illegal IPD port number\n"); |
| @@ -124,6 +124,13 @@ int __cvmx_helper_xaui_enable(int interface) · 123 unmodified lines | ||
| 124 | 124 | union cvmx_gmxx_tx_int_en gmx_tx_int_en; |
| 125 | 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 | 134 | /* (1) Interface has already been enabled. */ |
| 128 | 135 | |
| 129 | 136 | /* (2) Disable GMX. */ |
| @@ -151,7 +158,12 @@ int __cvmx_helper_xaui_enable(int interface) · 21 unmodified lines | ||
| 151 | 158 | /* (4)c Aply reset sequence */ |
| 152 | 159 | xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); |
| 153 | 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 | 167 | cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); |
| 156 | 168 | |
| 157 | 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 | 84 | int cvmx_helper_get_number_of_interfaces(void) |
| 85 | 85 | { |
| 86 | + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | |
| 87 | + return 9; | |
| 86 | 88 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) |
| 87 | 89 | return 4; |
| 88 | 90 | else |
| @@ -656,6 +658,21 @@ static int __cvmx_helper_global_setup_pko(void) · 567 unmodified lines | ||
| 656 | 658 | fau_to.s.tout_val = 0xfff; |
| 657 | 659 | fau_to.s.tout_enb = 0; |
| 658 | 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 | 676 | return 0; |
| 660 | 677 | } |
| 661 | 678 | |
| @@ -39,6 +39,143 @@ · 38 unmodified lines | ||
| 39 | 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 | 180 | * Call before any other calls to initialize the packet |
| 44 | 181 | * output system. This does chip global config, and should only be |
| @@ -47,8 +184,6 @@ · 2 unmodified lines | ||
| 47 | 184 | |
| 48 | 185 | void cvmx_pko_initialize_global(void) |
| 49 | 186 | { |
| 50 | − int i; | |
| 51 | − uint64_t priority = 8; | |
| 52 | 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 | 198 | cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); |
| 64 | 199 | |
| 65 | − for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) | |
| 66 | − cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, | |
| 67 | − &priority); | |
| 200 | + /* | |
| 201 | + * Chip-specific setup. | |
| 202 | + */ | |
| 203 | + __cvmx_pko_chip_init(); | |
| 68 | 204 | |
| 69 | 205 | /* |
| 70 | 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 | 348 | int static_priority_base = -1; |
| 213 | 349 | int static_priority_end = -1; |
| 214 | 350 | |
| 351 | + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | |
| 352 | + return CVMX_PKO_SUCCESS; | |
| 353 | + | |
| 215 | 354 | if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) |
| 216 | 355 | && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) { |
| 217 | 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 | 226 | #ifdef CONFIG_SMP |
| 227 | 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 | 230 | struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data); |
| 230 | 231 | |
| 231 | 232 | if (weight > 1) { |
| 232 | 233 | cpu = cd->current_cpu; |
| 233 | 234 | for (;;) { |
| 234 | − cpu = cpumask_next(cpu, data->affinity); | |
| 235 | + cpu = cpumask_next(cpu, mask); | |
| 235 | 236 | if (cpu >= nr_cpu_ids) { |
| 236 | 237 | cpu = -1; |
| 237 | 238 | continue; |
| @@ -240,7 +241,7 @@ static int next_cpu_for_irq(struct irq_data *data) · 2 unmodified lines | ||
| 240 | 241 | } |
| 241 | 242 | } |
| 242 | 243 | } else if (weight == 1) { |
| 243 | − cpu = cpumask_first(data->affinity); | |
| 244 | + cpu = cpumask_first(mask); | |
| 244 | 245 | } else { |
| 245 | 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 | 663 | irqd_set_trigger_type(data, t); |
| 663 | 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 | 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 | 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 | 705 | #ifdef CONFIG_SMP |
| 710 | 706 | |
| 711 | 707 | static void octeon_irq_cpu_offline_ciu(struct irq_data *data) |
| 712 | 708 | { |
| 713 | 709 | int cpu = smp_processor_id(); |
| 714 | 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 | 714 | return; |
| 718 | 715 | |
| 719 | − if (cpumask_weight(data->affinity) > 1) { | |
| 716 | + if (cpumask_weight(mask) > 1) { | |
| 720 | 717 | /* |
| 721 | 718 | * It has multi CPU affinity, just remove this CPU |
| 722 | 719 | * from the affinity set. |
| 723 | 720 | */ |
| 724 | − cpumask_copy(&new_affinity, data->affinity); | |
| 721 | + cpumask_copy(&new_affinity, mask); | |
| 725 | 722 | cpumask_clear_cpu(cpu, &new_affinity); |
| 726 | 723 | } else { |
| 727 | 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 | 1224 | octeon_irq_ciu_to_irq[line][bit] != 0) |
| 1228 | 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 | 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 | 1234 | return r; |
| 1233 | 1235 | } |
| 1234 | 1236 | |
| @@ -16,6 +16,5 @@ generic-y += sections.h · 15 unmodified lines | ||
| 16 | 16 | generic-y += segment.h |
| 17 | 17 | generic-y += serial.h |
| 18 | 18 | generic-y += trace_clock.h |
| 19 | −generic-y += ucontext.h | |
| 20 | 19 | generic-y += user.h |
| 21 | 20 | generic-y += xor.h |
| @@ -20,6 +20,10 @@ struct mips_abi { · 19 unmodified lines | ||
| 20 | 20 | struct pt_regs *regs, sigset_t *set); |
| 21 | 21 | const unsigned long rt_signal_return_offset; |
| 22 | 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 | 29 | #endif /* _ASM_ABI_H */ |
| @@ -232,6 +232,30 @@ · 231 unmodified lines | ||
| 232 | 232 | .set pop |
| 233 | 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 | 259 | .macro ld_d wd, off, base |
| 236 | 260 | .set push |
| 237 | 261 | .set mips32r2 |
| @@ -241,6 +265,30 @@ · 3 unmodified lines | ||
| 241 | 265 | .set pop |
| 242 | 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 | 292 | .macro st_d wd, off, base |
| 245 | 293 | .set push |
| 246 | 294 | .set mips32r2 |
| @@ -290,7 +338,13 @@ · 43 unmodified lines | ||
| 290 | 338 | #ifdef CONFIG_CPU_MICROMIPS |
| 291 | 339 | #define CFC_MSA_INSN 0x587e0056 |
| 292 | 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 | 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 | 348 | #define STD_MSA_INSN 0x5800083f |
| 295 | 349 | #define COPY_UW_MSA_INSN 0x58f00056 |
| 296 | 350 | #define COPY_UD_MSA_INSN 0x58f80056 |
| @@ -299,7 +353,13 @@ · 2 unmodified lines | ||
| 299 | 353 | #else |
| 300 | 354 | #define CFC_MSA_INSN 0x787e0059 |
| 301 | 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 | 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 | 363 | #define STD_MSA_INSN 0x78000827 |
| 304 | 364 | #define COPY_UW_MSA_INSN 0x78f00059 |
| 305 | 365 | #define COPY_UD_MSA_INSN 0x78f80059 |
| @@ -329,6 +389,33 @@ · 23 unmodified lines | ||
| 329 | 389 | .set pop |
| 330 | 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 | 419 | .macro ld_d wd, off, base |
| 333 | 420 | .set push |
| 334 | 421 | .set noat |
| @@ -338,6 +425,33 @@ · 3 unmodified lines | ||
| 338 | 425 | .set pop |
| 339 | 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 | 455 | .macro st_d wd, off, base |
| 342 | 456 | .set push |
| 343 | 457 | .set noat |
| @@ -53,7 +53,7 @@ struct mips_cdmm_driver { · 52 unmodified lines | ||
| 53 | 53 | * mips_cdmm_phys_base() - Choose a physical base address for CDMM region. |
| 54 | 54 | * |
| 55 | 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 | 57 | * pick a suitable value if none is configured by the bootloader. |
| 58 | 58 | * |
| 59 | 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 | 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 | 66 | extern struct bus_type mips_cdmm_bustype; |
| 67 | 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 | 22 | void mips_event_handler(struct clock_event_device *dev); |
| 23 | 23 | int c0_compare_int_usable(void); |
| 24 | −void mips_set_clock_mode(enum clock_event_mode, struct clock_event_device *); | |
| 25 | 24 | irqreturn_t c0_compare_interrupt(int, void *); |
| 26 | 25 | |
| 27 | 26 | extern struct irqaction c0_compare_irqaction; |
| @@ -411,4 +411,8 @@ · 410 unmodified lines | ||
| 411 | 411 | # define cpu_has_cdmm (cpu_data[0].options & MIPS_CPU_CDMM) |
| 412 | 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 | 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 | 78 | #endif |
| 79 | 79 | |
| 80 | +#ifdef CONFIG_SYS_HAS_CPU_MIPS64_R6 | |
| 81 | + case CPU_I6400: | |
| 82 | +#endif | |
| 83 | + | |
| 80 | 84 | #ifdef CONFIG_SYS_HAS_CPU_R3000 |
| 81 | 85 | case CPU_R2000: |
| 82 | 86 | case CPU_R3000: |
| @@ -120,6 +120,7 @@ · 119 unmodified lines | ||
| 120 | 120 | #define PRID_IMP_PROAPTIV_MP 0xa300 |
| 121 | 121 | #define PRID_IMP_M5150 0xa700 |
| 122 | 122 | #define PRID_IMP_P5600 0xa800 |
| 123 | +#define PRID_IMP_I6400 0xa900 | |
| 123 | 124 | |
| 124 | 125 | /* |
| 125 | 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 | 308 | CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, |
| 308 | 309 | CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, |
| 309 | 310 | CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, CPU_M5150, |
| 311 | + CPU_I6400, | |
| 310 | 312 | |
| 311 | 313 | /* |
| 312 | 314 | * MIPS64 class processors |
| @@ -382,6 +384,7 @@ enum cpu_type_enum { · 69 unmodified lines | ||
| 382 | 384 | #define MIPS_CPU_XPA 0x2000000000ull /* CPU supports Extended Physical Addressing */ |
| 383 | 385 | #define MIPS_CPU_CDMM 0x4000000000ull /* CPU has Common Device Memory Map */ |
| 384 | 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 | 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 | 382 | instruction set this cpu supports. This could be done in userspace, |
| 383 | 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 | 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 | 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 | 169 | if (is_msa_enabled()) { |
| 171 | 170 | if (save) { |
| 172 | − save_msa(current); | |
| 173 | − current->thread.fpu.fcr31 = | |
| 171 | + save_msa(tsk); | |
| 172 | + tsk->thread.fpu.fcr31 = | |
| 174 | 173 | read_32bit_cp1_register(CP1_STATUS); |
| 175 | 174 | } |
| 176 | 175 | disable_msa(); |
| 177 | − clear_thread_flag(TIF_USEDMSA); | |
| 176 | + clear_tsk_thread_flag(tsk, TIF_USEDMSA); | |
| 178 | 177 | __disable_fpu(); |
| 179 | 178 | } else if (is_fpu_owner()) { |
| 180 | 179 | if (save) |
| 181 | − _save_fp(current); | |
| 180 | + _save_fp(tsk); | |
| 182 | 181 | __disable_fpu(); |
| 183 | 182 | } |
| 184 | − KSTK_STATUS(current) &= ~ST0_CU1; | |
| 185 | − clear_thread_flag(TIF_USEDFPU); | |
| 183 | + KSTK_STATUS(tsk) &= ~ST0_CU1; | |
| 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 | 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 | 49 | extern int cp0_perfcount_irq; |
| 50 | 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 | 54 | void arch_trigger_all_cpu_backtrace(bool); |
| 55 | 55 | #define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace |
| @@ -11,7 +11,9 @@ enum die_val { · 10 unmodified lines | ||
| 11 | 11 | DIE_PAGE_FAULT, |
| 12 | 12 | DIE_BREAK, |
| 13 | 13 | DIE_SSTEPBP, |
| 14 | − DIE_MSAFP | |
| 14 | + DIE_MSAFP, | |
| 15 | + DIE_UPROBE, | |
| 16 | + DIE_UPROBE_XOL, | |
| 15 | 17 | }; |
| 16 | 18 | |
| 17 | 19 | #endif /* _ASM_MIPS_KDEBUG_H */ |
| @@ -5,7 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | #include <asm/asm.h> |
| 6 | 6 | #endif |
| 7 | 7 | |
| 8 | −#define __weak __attribute__((weak)) | |
| 9 | 8 | #define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall") |
| 10 | 9 | #define SYSCALL_ALIAS(alias, name) \ |
| 11 | 10 | asm ( #alias " = " #name "\n\t.globl " #alias) |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | * |
| 27 | 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 | 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 | 203 | int __init ar7_gpio_init(void); |
| 204 | 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 | 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 | 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 | 281 | * GPIO2 block macros for common linux GPIO functions. The 'gpio' |
| 271 | 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 | 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 | 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 | 73 | void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask); |
| 74 | 74 | uint32_t jz_gpio_port_get_value(int port, uint32_t mask); |
| 75 | 75 | |
| 76 | −#include <asm/mach-generic/gpio.h> | |
| 77 | − | |
| 78 | 76 | #define JZ_GPIO_PORTA(x) ((x) + 32 * 0) |
| 79 | 77 | #define JZ_GPIO_PORTB(x) ((x) + 32 * 1) |
| 80 | 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 | 13 | #ifndef _RC32434_GPIO_H_ |
| 14 | 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 | 16 | struct rb532_gpio_reg { |
| 29 | 17 | u32 gpiofunc; /* GPIO Function Register |
| 30 | 18 | * gpiofunc[x]==0 bit = gpio |
| @@ -33,6 +33,29 @@ extern void __iomem *mips_cm_l2sync_base; · 32 unmodified lines | ||
| 33 | 33 | */ |
| 34 | 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 | 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 | 114 | /* Macros to ease the creation of register access functions */ |
| 92 | 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 | 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 | 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 | 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 | 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 | 193 | BUILD_CM_RW(reg3_mask, MIPS_CM_GCB_OFS + 0xc8) |
| 145 | 194 | BUILD_CM_R_(gic_status, MIPS_CM_GCB_OFS + 0xd0) |
| 146 | 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 | 198 | /* Core Local & Core Other register accessor functions */ |
| 149 | 199 | BUILD_CM_Cx_RW(reset_release, 0x00) |
| @@ -189,6 +239,13 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) · 39 unmodified lines | ||
| 189 | 239 | #define CM_GCR_REV_MINOR_SHF 0 |
| 190 | 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 | 249 | /* GCR_ERROR_CAUSE register fields */ |
| 193 | 250 | #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27 |
| 194 | 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 | 306 | #define CM_GCR_CPC_STATUS_EX_SHF 0 |
| 250 | 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 | 319 | /* GCR_Cx_COHERENCE register fields */ |
| 253 | 320 | #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0 |
| 254 | 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 | 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 | 408 | #endif /* __MIPS_ASM_MIPS_CM_H__ */ |
| @@ -27,16 +27,6 @@ extern void __iomem *mips_cpc_base; · 26 unmodified lines | ||
| 27 | 27 | */ |
| 28 | 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 | 31 | * mips_cpc_probe - probe for a Cluster Power Controller |
| 42 | 32 | * |
| @@ -112,6 +112,30 @@ · 111 unmodified lines | ||
| 112 | 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 | 140 | * Values for PageMask register |
| 117 | 141 | */ |
| @@ -203,6 +227,9 @@ · 85 unmodified lines | ||
| 203 | 227 | #define PG_ESP (_ULCAST_(1) << 28) |
| 204 | 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 | 234 | * R4x00 interrupt enable / cause bits |
| 208 | 235 | */ |
| @@ -579,6 +606,8 @@ · 370 unmodified lines | ||
| 579 | 606 | |
| 580 | 607 | #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) |
| 581 | 608 | #define MIPS_CONF7_AR (_ULCAST_(1) << 16) |
| 609 | +/* FTLB probability bits for R6 */ | |
| 610 | +#define MIPS_CONF7_FTLBP_SHIFT (18) | |
| 582 | 611 | |
| 583 | 612 | /* MAAR bit definitions */ |
| 584 | 613 | #define MIPS_MAAR_ADDR ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12) |
| @@ -586,31 +615,6 @@ · 1 unmodified line | ||
| 586 | 615 | #define MIPS_MAAR_S (_ULCAST_(1) << 1) |
| 587 | 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 | 618 | /* CMGCRBase bit definitions */ |
| 615 | 619 | #define MIPS_CMGCRB_BASE 11 |
| 616 | 620 | #define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1)) |
| @@ -932,7 +936,7 @@ do { \ · 315 unmodified lines | ||
| 932 | 936 | */ |
| 933 | 937 | |
| 934 | 938 | #define __read_32bit_c0_register(source, sel) \ |
| 935 | −({ int __res; \ | |
| 939 | +({ unsigned int __res; \ | |
| 936 | 940 | if (sel == 0) \ |
| 937 | 941 | __asm__ __volatile__( \ |
| 938 | 942 | "mfc0\t%0, " #source "\n\t" \ |
| @@ -1014,7 +1018,7 @@ do { \ · 75 unmodified lines | ||
| 1014 | 1018 | * On RM7000/RM9000 these are uses to access cop0 set 1 registers |
| 1015 | 1019 | */ |
| 1016 | 1020 | #define __read_32bit_c0_ctrl_register(source) \ |
| 1017 | −({ int __res; \ | |
| 1021 | +({ unsigned int __res; \ | |
| 1018 | 1022 | __asm__ __volatile__( \ |
| 1019 | 1023 | "cfc0\t%0, " #source "\n\t" \ |
| 1020 | 1024 | : "=r" (__res)); \ |
| @@ -1471,7 +1475,7 @@ do { \ · 450 unmodified lines | ||
| 1471 | 1475 | */ |
| 1472 | 1476 | #define _read_32bit_cp1_register(source, gas_hardfloat) \ |
| 1473 | 1477 | ({ \ |
| 1474 | − int __res; \ | |
| 1478 | + unsigned int __res; \ | |
| 1475 | 1479 | \ |
| 1476 | 1480 | __asm__ __volatile__( \ |
| 1477 | 1481 | " .set push \n" \ |
| @@ -14,10 +14,90 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | #ifndef __ASSEMBLY__ |
| 16 | 16 | |
| 17 | +#include <asm/inst.h> | |
| 18 | + | |
| 17 | 19 | extern void _save_msa(struct task_struct *); |
| 18 | 20 | extern void _restore_msa(struct task_struct *); |
| 19 | 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 | 101 | static inline void enable_msa(void) |
| 22 | 102 | { |
| 23 | 103 | if (cpu_has_msa) { |
| @@ -284,6 +284,7 @@ enum cvmx_board_types_enum { · 283 unmodified lines | ||
| 284 | 284 | CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, |
| 285 | 285 | CVMX_BOARD_TYPE_UBNT_E100 = 20002, |
| 286 | 286 | CVMX_BOARD_TYPE_CUST_DSR1000N = 20006, |
| 287 | + CVMX_BOARD_TYPE_KONTRON_S1901 = 21901, | |
| 287 | 288 | CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, |
| 288 | 289 | |
| 289 | 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 | 385 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN) |
| 385 | 386 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100) |
| 386 | 387 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DSR1000N) |
| 388 | + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901) | |
| 387 | 389 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX) |
| 388 | 390 | } |
| 389 | 391 | return "Unsupported Board"; |
| @@ -37,7 +37,7 @@ · 36 unmodified lines | ||
| 37 | 37 | #include <asm/octeon/cvmx-fpa.h> |
| 38 | 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 | 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 | 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 | 548 | return cvmx_pko_get_base_queue_per_core(port, 0); |
| 546 | 549 | } |
| 547 | 550 | |
| @@ -52,6 +52,12 @@ · 51 unmodified lines | ||
| 52 | 52 | #define CVMX_POW_WQ_INT_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000000080ull) + ((offset) & 15) * 8) |
| 53 | 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 | 61 | union cvmx_pow_bist_stat { |
| 56 | 62 | uint64_t u64; |
| 57 | 63 | struct cvmx_pow_bist_stat_s { |
| @@ -1286,4 +1292,27 @@ union cvmx_pow_ws_pcx { · 1228 unmodified lines | ||
| 1286 | 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 | 1318 | #endif |
| @@ -1810,10 +1810,11 @@ static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, uint32_t tag, · 1809 unmodified lines | ||
| 1810 | 1810 | cvmx_addr_t ptr; |
| 1811 | 1811 | cvmx_pow_tag_req_t tag_req; |
| 1812 | 1812 | |
| 1813 | − wqp->qos = qos; | |
| 1814 | − wqp->tag = tag; | |
| 1815 | − wqp->tag_type = tag_type; | |
| 1816 | − wqp->grp = grp; | |
| 1813 | + wqp->word1.tag = tag; | |
| 1814 | + wqp->word1.tag_type = tag_type; | |
| 1815 | + | |
| 1816 | + cvmx_wqe_set_qos(wqp, qos); | |
| 1817 | + cvmx_wqe_set_grp(wqp, grp); | |
| 1817 | 1818 | |
| 1818 | 1819 | tag_req.u64 = 0; |
| 1819 | 1820 | tag_req.s.op = CVMX_POW_TAG_OP_ADDWQ; |
| @@ -193,6 +193,53 @@ typedef union { · 192 unmodified lines | ||
| 193 | 193 | uint64_t bufs:8; |
| 194 | 194 | #endif |
| 195 | 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 | 244 | /* use this to get at the 16 vlan bits */ |
| 198 | 245 | struct { |
| @@ -355,6 +402,146 @@ typedef union { · 156 unmodified lines | ||
| 355 | 402 | |
| 356 | 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 | 546 | * Work queue entry format |
| 360 | 547 | * |
| @@ -366,70 +553,13 @@ typedef struct { · 5 unmodified lines | ||
| 366 | 553 | * WORD 0 |
| 367 | 554 | * HW WRITE: the following 64 bits are filled by HW when a packet arrives |
| 368 | 555 | */ |
| 369 | − | |
| 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 | |
| 556 | + union cvmx_wqe_word0 word0; | |
| 391 | 557 | |
| 392 | 558 | /***************************************************************** |
| 393 | 559 | * WORD 1 |
| 394 | 560 | * HW WRITE: the following 64 bits are filled by HW when a packet arrives |
| 395 | 561 | */ |
| 396 | − | |
| 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 | |
| 562 | + union cvmx_wqe_word1 word1; | |
| 433 | 563 | |
| 434 | 564 | /** |
| 435 | 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 | 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 | 658 | #endif /* __CVMX_WQE_H__ */ |
| @@ -133,20 +133,13 @@ · 132 unmodified lines | ||
| 133 | 133 | #define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) |
| 134 | 134 | #define _PAGE_SPLITTING_SHIFT (_PAGE_HUGE_SHIFT + 1) |
| 135 | 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 | 136 | #endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */ |
| 146 | 137 | |
| 147 | 138 | #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) |
| 148 | 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 | 143 | #define _PAGE_NO_EXEC_SHIFT (_PAGE_MODIFIED_SHIFT + 1) |
| 151 | 144 | #endif |
| 152 | 145 | #define _PAGE_NO_EXEC (cpu_has_rixi ? (1 << _PAGE_NO_EXEC_SHIFT) : 0) |
| @@ -156,14 +149,16 @@ · 3 unmodified lines | ||
| 156 | 149 | #define _PAGE_READ (cpu_has_rixi ? 0 : (1 << _PAGE_READ_SHIFT)) |
| 157 | 150 | #define _PAGE_NO_READ_SHIFT _PAGE_READ_SHIFT |
| 158 | 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 | 155 | #define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1) |
| 161 | −#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) | |
| 162 | − | |
| 163 | −#else /* !CONFIG_CPU_MIPSR2 && !CONFIG_CPU_MIPSR6 */ | |
| 156 | +#elif defined(_PAGE_SPLITTING_SHIFT) | |
| 157 | +#define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1) | |
| 158 | +#else | |
| 164 | 159 | #define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1) |
| 160 | +#endif | |
| 165 | 161 | #define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) |
| 166 | −#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ | |
| 167 | 162 | |
| 168 | 163 | #define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) |
| 169 | 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 | 244 | #define _CACHE_CACHABLE_NONCOHERENT (3<<_CACHE_SHIFT) /* LOONGSON */ |
| 250 | 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 | 249 | /* Ingenic uses the WA bit to achieve write-combine memory writes */ |
| 255 | 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 | 393 | return __pgprot(prot); |
| 394 | 394 | } |
| 395 | 395 | |
| 396 | +#define pgprot_writecombine pgprot_writecombine | |
| 397 | + | |
| 396 | 398 | static inline pgprot_t pgprot_writecombine(pgprot_t _prot) |
| 397 | 399 | { |
| 398 | 400 | unsigned long prot = pgprot_val(_prot); |
| @@ -275,6 +275,7 @@ struct thread_struct { · 274 unmodified lines | ||
| 275 | 275 | unsigned long cp0_badvaddr; /* Last user fault */ |
| 276 | 276 | unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ |
| 277 | 277 | unsigned long error_code; |
| 278 | + unsigned long trap_nr; | |
| 278 | 279 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
| 279 | 280 | struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128))); |
| 280 | 281 | struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128))); |
| @@ -341,6 +342,7 @@ struct thread_struct { · 60 unmodified lines | ||
| 341 | 342 | .cp0_badvaddr = 0, \ |
| 342 | 343 | .cp0_baduaddr = 0, \ |
| 343 | 344 | .error_code = 0, \ |
| 345 | + .trap_nr = 0, \ | |
| 344 | 346 | /* \ |
| 345 | 347 | * Platform specific cop2 registers(null if no COP2) \ |
| 346 | 348 | */ \ |
| @@ -14,11 +14,16 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/linkage.h> |
| 15 | 15 | #include <linux/types.h> |
| 16 | 16 | #include <asm/isadep.h> |
| 17 | +#include <asm/page.h> | |
| 18 | +#include <asm/thread_info.h> | |
| 17 | 19 | #include <uapi/asm/ptrace.h> |
| 18 | 20 | |
| 19 | 21 | /* |
| 20 | 22 | * This struct defines the way the registers are stored on the stack during a |
| 21 | 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 | 28 | struct pt_regs { |
| 24 | 29 | #ifdef CONFIG_32BIT |
| @@ -43,8 +48,83 @@ struct pt_regs { · 18 unmodified lines | ||
| 43 | 48 | unsigned long long mpl[6]; /* MTM{0-5} */ |
| 44 | 49 | unsigned long long mtp[6]; /* MTP{0-5} */ |
| 45 | 50 | #endif |
| 51 | + unsigned long __last[0]; | |
| 46 | 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 | 128 | struct task_struct; |
| 49 | 129 | |
| 50 | 130 | extern int ptrace_getregs(struct task_struct *child, |
| @@ -23,4 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 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 | 29 | #endif /* _ASM_SIGNAL_H */ |
| @@ -42,6 +42,11 @@ static inline int arch_spin_is_locked(arch_spinlock_t *lock) · 41 unmodified lines | ||
| 42 | 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 | 50 | #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) |
| 46 | 51 | #define arch_spin_unlock_wait(x) \ |
| 47 | 52 | while (arch_spin_is_locked(x)) { cpu_relax(); } |
| @@ -16,29 +16,21 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <asm/watch.h> |
| 17 | 17 | #include <asm/dsp.h> |
| 18 | 18 | #include <asm/cop2.h> |
| 19 | −#include <asm/msa.h> | |
| 19 | +#include <asm/fpu.h> | |
| 20 | 20 | |
| 21 | 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 | 24 | * resume - resume execution of a task |
| 31 | 25 | * @prev: The task previously executed. |
| 32 | 26 | * @next: The task to begin executing. |
| 33 | 27 | * @next_ti: task_thread_info(next). |
| 34 | − * @fp_save: Which, if any, FP context to save for prev. | |
| 35 | 28 | * |
| 36 | 29 | * This function is used whilst scheduling to save the context of prev & load |
| 37 | 30 | * the context of next. Returns prev. |
| 38 | 31 | */ |
| 39 | 32 | extern asmlinkage struct task_struct *resume(struct task_struct *prev, |
| 40 | − struct task_struct *next, struct thread_info *next_ti, | |
| 41 | − s32 fp_save); | |
| 33 | + struct task_struct *next, struct thread_info *next_ti); | |
| 42 | 34 | |
| 43 | 35 | extern unsigned int ll_bit; |
| 44 | 36 | extern struct task_struct *ll_task; |
| @@ -91,8 +83,8 @@ do { if (cpu_has_rw_llb) { \ · 46 unmodified lines | ||
| 91 | 83 | */ |
| 92 | 84 | #define switch_to(prev, next, last) \ |
| 93 | 85 | do { \ |
| 94 | − s32 __fpsave = FP_SAVE_NONE; \ | |
| 95 | 86 | __mips_mt_fpaff_switch_to(prev); \ |
| 87 | + lose_fpu_inatomic(1, prev); \ | |
| 96 | 88 | if (cpu_has_dsp) { \ |
| 97 | 89 | __save_dsp(prev); \ |
| 98 | 90 | __restore_dsp(next); \ |
| @@ -111,15 +103,10 @@ do { \ · 12 unmodified lines | ||
| 111 | 103 | clear_c0_status(ST0_CU2); \ |
| 112 | 104 | } \ |
| 113 | 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 | 106 | if (cpu_has_userlocal) \ |
| 119 | 107 | write_c0_userlocal(task_thread_info(next)->tp_value); \ |
| 120 | 108 | __restore_watch(); \ |
| 121 | − disable_msa(); \ | |
| 122 | − (last) = resume(prev, next, task_thread_info(next), __fpsave); \ | |
| 109 | + (last) = resume(prev, next, task_thread_info(next)); \ | |
| 123 | 110 | } while (0) |
| 124 | 111 | |
| 125 | 112 | #endif /* _ASM_SWITCH_TO_H */ |
| @@ -99,6 +99,7 @@ static inline struct thread_info *current_thread_info(void) · 98 unmodified lines | ||
| 99 | 99 | #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ |
| 100 | 100 | #define TIF_SECCOMP 4 /* secure computing */ |
| 101 | 101 | #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ |
| 102 | +#define TIF_UPROBE 6 /* breakpointed or singlestepping */ | |
| 102 | 103 | #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ |
| 103 | 104 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ |
| 104 | 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 | 123 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) |
| 123 | 124 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) |
| 124 | 125 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) |
| 126 | +#define _TIF_UPROBE (1<<TIF_UPROBE) | |
| 125 | 127 | #define _TIF_USEDFPU (1<<TIF_USEDFPU) |
| 126 | 128 | #define _TIF_NOHZ (1<<TIF_NOHZ) |
| 127 | 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 | 149 | /* work to do on interrupt/exception return */ |
| 148 | 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 | 153 | /* work to do on any return to u-space */ |
| 151 | 154 | #define _TIF_ALLWORK_MASK (_TIF_NOHZ | _TIF_WORK_MASK | \ |
| 152 | 155 | _TIF_WORK_SYSCALL_EXIT | \ |
| @@ -51,7 +51,7 @@ extern int __weak get_c0_perfcount_int(void); · 50 unmodified lines | ||
| 51 | 51 | /* |
| 52 | 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 | 55 | extern int r4k_clockevent_init(void); |
| 56 | 56 | |
| 57 | 57 | static inline int mips_clockevent_init(void) |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | /* |
| 12 | 12 | * TLB debugging functions: |
| 13 | 13 | */ |
| 14 | +extern void dump_tlb_regs(void); | |
| 14 | 15 | extern void dump_tlb_all(void); |
| 15 | 16 | |
| 16 | 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 | 122 | void *alloc_progmem(unsigned long len); |
| 123 | 123 | void release_progmem(void *ptr); |
| 124 | 124 | |
| 125 | −int __weak vpe_run(struct vpe *v); | |
| 125 | +int vpe_run(struct vpe *v); | |
| 126 | 126 | void cleanup_tc(struct tc *tc); |
| 127 | 127 | |
| 128 | 128 | int __init vpe_module_init(void); |
| @@ -21,6 +21,8 @@ · 20 unmodified lines | ||
| 21 | 21 | #define BRK_DIVZERO 7 /* Divide by zero check */ |
| 22 | 22 | #define BRK_RANGE 8 /* Range error check */ |
| 23 | 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 | 26 | #define BRK_MEMU 514 /* Used by FPU emulator */ |
| 25 | 27 | #define BRK_KPROBE_BP 515 /* Kprobe break */ |
| 26 | 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 | 26 | cop0_op, cop1_op, cop2_op, cop1x_op, |
| 27 | 27 | beql_op, bnel_op, blezl_op, bgtzl_op, |
| 28 | 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 | 30 | lb_op, lh_op, lwl_op, lw_op, |
| 31 | 31 | lbu_op, lhu_op, lwr_op, lwu_op, |
| 32 | 32 | sb_op, sh_op, swl_op, sw_op, |
| @@ -167,8 +167,13 @@ enum cop1_sdw_func { · 134 unmodified lines | ||
| 167 | 167 | fround_op = 0x0c, ftrunc_op = 0x0d, |
| 168 | 168 | fceil_op = 0x0e, ffloor_op = 0x0f, |
| 169 | 169 | fmovc_op = 0x11, fmovz_op = 0x12, |
| 170 | − fmovn_op = 0x13, frecip_op = 0x15, | |
| 171 | − frsqrt_op = 0x16, fcvts_op = 0x20, | |
| 170 | + fmovn_op = 0x13, fseleqz_op = 0x14, | |
| 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 | 177 | fcvtd_op = 0x21, fcvte_op = 0x22, |
| 173 | 178 | fcvtw_op = 0x24, fcvtl_op = 0x25, |
| 174 | 179 | fcmp_op = 0x30 |
| @@ -220,6 +225,24 @@ enum bshfl_func { · 45 unmodified lines | ||
| 220 | 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 | 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 | 647 | struct spec3_format { /* SPEC3 */ |
| 615 | 648 | __BITFIELD_FIELD(unsigned int opcode:6, |
| 616 | 649 | __BITFIELD_FIELD(unsigned int rs:5, |
| @@ -888,6 +921,7 @@ union mips_instruction { · 271 unmodified lines | ||
| 888 | 921 | struct p_format p_format; |
| 889 | 922 | struct f_format f_format; |
| 890 | 923 | struct ma_format ma_format; |
| 924 | + struct msa_mi10_format msa_mi10_format; | |
| 891 | 925 | struct b_format b_format; |
| 892 | 926 | struct ps_format ps_format; |
| 893 | 927 | struct v_format v_format; |
| @@ -12,6 +12,18 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/types.h> |
| 13 | 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 | 27 | #if _MIPS_SIM == _MIPS_SIM_ABI32 |
| 16 | 28 | |
| 17 | 29 | /* |
| @@ -16,11 +16,13 @@ · 15 unmodified lines | ||
| 16 | 16 | #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) || \ |
| 17 | 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 | 22 | __asm__( |
| 22 | 23 | " .set push \n" |
| 23 | 24 | " .set arch=mips32r2 \n" |
| 25 | + " .set nomips16 \n" | |
| 24 | 26 | " wsbh %0, %1 \n" |
| 25 | 27 | " .set pop \n" |
| 26 | 28 | : "=r" (x) |
| @@ -30,11 +32,13 @@ static inline __attribute_const__ __u16 __arch_swab16(__u16 x) · 3 unmodified lines | ||
| 30 | 32 | } |
| 31 | 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 | 38 | __asm__( |
| 36 | 39 | " .set push \n" |
| 37 | 40 | " .set arch=mips32r2 \n" |
| 41 | + " .set nomips16 \n" | |
| 38 | 42 | " wsbh %0, %1 \n" |
| 39 | 43 | " rotr %0, %0, 16 \n" |
| 40 | 44 | " .set pop \n" |
| @@ -50,11 +54,13 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x) · 9 unmodified lines | ||
| 50 | 54 | * 64-bit kernel on r2 CPUs. |
| 51 | 55 | */ |
| 52 | 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 | 60 | __asm__( |
| 56 | 61 | " .set push \n" |
| 57 | 62 | " .set arch=mips64r2 \n" |
| 63 | + " .set nomips16 \n" | |
| 58 | 64 | " dsbh %0, %1 \n" |
| 59 | 65 | " dshd %0, %0 \n" |
| 60 | 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 | 113 | struct clock_event_device r4030_clockevent = { |
| 120 | 114 | .name = "r4030", |
| 121 | 115 | .features = CLOCK_EVT_FEAT_PERIODIC, |
| 122 | 116 | .rating = 300, |
| 123 | 117 | .irq = JAZZ_TIMER_IRQ, |
| 124 | − .set_mode = r4030_set_mode, | |
| 125 | 118 | }; |
| 126 | 119 | |
| 127 | 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 | 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 | 241 | int jz_gpio_port_direction_input(int port, uint32_t mask) |
| 235 | 242 | { |
| 236 | 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 | 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 | 272 | #define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f) |
| 278 | 273 | |
| 279 | 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 | 398 | .get = jz_gpio_get_value, \ |
| 404 | 399 | .direction_output = jz_gpio_direction_output, \ |
| 405 | 400 | .direction_input = jz_gpio_direction_input, \ |
| 401 | + .to_irq = jz_gpio_to_irq, \ | |
| 406 | 402 | .base = JZ4740_GPIO_BASE_ ## _bank, \ |
| 407 | 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 | 419 | chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); |
| 424 | 420 | |
| 425 | 421 | chip->irq = JZ4740_IRQ_INTC_GPIO(id); |
| 426 | − irq_set_handler_data(chip->irq, chip); | |
| 427 | − irq_set_chained_handler(chip->irq, jz_gpio_irq_demux_handler); | |
| 422 | + irq_set_chained_handler_and_data(chip->irq, | |
| 423 | + jz_gpio_irq_demux_handler, chip); | |
| 428 | 424 | |
| 429 | 425 | gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base, |
| 430 | 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 | 59 | jz4740_timer_ack_full(TIMER_CLOCKEVENT); |
| 60 | 60 | |
| 61 | − if (cd->mode != CLOCK_EVT_MODE_PERIODIC) | |
| 61 | + if (!clockevent_state_periodic(cd)) | |
| 62 | 62 | jz4740_timer_disable(TIMER_CLOCKEVENT); |
| 63 | 63 | |
| 64 | 64 | cd->event_handler(cd); |
| @@ -66,24 +66,29 @@ static irqreturn_t jz4740_clockevent_irq(int irq, void *devid) · 1 unmodified line | ||
| 66 | 66 | return IRQ_HANDLED; |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | −static void jz4740_clockevent_set_mode(enum clock_event_mode mode, | |
| 70 | − struct clock_event_device *cd) | |
| 69 | +static int jz4740_clockevent_set_periodic(struct clock_event_device *evt) | |
| 71 | 70 | { |
| 72 | − switch (mode) { | |
| 73 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 74 | − jz4740_timer_set_count(TIMER_CLOCKEVENT, 0); | |
| 75 | − jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick); | |
| 76 | − case CLOCK_EVT_MODE_RESUME: | |
| 77 | − jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); | |
| 78 | − jz4740_timer_enable(TIMER_CLOCKEVENT); | |
| 79 | − break; | |
| 80 | − case CLOCK_EVT_MODE_ONESHOT: | |
| 81 | − case CLOCK_EVT_MODE_SHUTDOWN: | |
| 82 | − jz4740_timer_disable(TIMER_CLOCKEVENT); | |
| 83 | − break; | |
| 84 | − default: | |
| 85 | − break; | |
| 86 | − } | |
| 71 | + jz4740_timer_set_count(TIMER_CLOCKEVENT, 0); | |
| 72 | + jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick); | |
| 73 | + jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); | |
| 74 | + jz4740_timer_enable(TIMER_CLOCKEVENT); | |
| 75 | + | |
| 76 | + return 0; | |
| 77 | +} | |
| 78 | + | |
| 79 | +static int jz4740_clockevent_resume(struct clock_event_device *evt) | |
| 80 | +{ | |
| 81 | + jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); | |
| 82 | + jz4740_timer_enable(TIMER_CLOCKEVENT); | |
| 83 | + | |
| 84 | + return 0; | |
| 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 | 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 | 105 | .name = "jz4740-timer", |
| 101 | 106 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
| 102 | 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 | 112 | .rating = 200, |
| 105 | 113 | #ifdef CONFIG_MACH_JZ4740 |
| 106 | 114 | .irq = JZ4740_IRQ_TCU0, |
| @@ -99,6 +99,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o · 98 unmodified lines | ||
| 99 | 99 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o |
| 100 | 100 | |
| 101 | 101 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o |
| 102 | +obj-$(CONFIG_UPROBES) += uprobes.o | |
| 102 | 103 | |
| 103 | 104 | obj-$(CONFIG_MIPS_CM) += mips-cm.o |
| 104 | 105 | obj-$(CONFIG_MIPS_CPC) += mips-cpc.o |
| @@ -128,6 +128,7 @@ void output_thread_defines(void) · 127 unmodified lines | ||
| 128 | 128 | thread.cp0_baduaddr); |
| 129 | 129 | OFFSET(THREAD_ECODE, task_struct, \ |
| 130 | 130 | thread.error_code); |
| 131 | + OFFSET(THREAD_TRAPNO, task_struct, thread.trap_nr); | |
| 131 | 132 | BLANK(); |
| 132 | 133 | } |
| 133 | 134 | |
| @@ -245,17 +246,6 @@ void output_sc_defines(void) · 111 unmodified lines | ||
| 245 | 246 | } |
| 246 | 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 | 249 | void output_signal_defined(void) |
| 260 | 250 | { |
| 261 | 251 | COMMENT("Linux signal numbers."); |
| @@ -40,8 +40,8 @@ · 39 unmodified lines | ||
| 40 | 40 | * The general purpose timer ticks at 1MHz independent if |
| 41 | 41 | * the rest of the system |
| 42 | 42 | */ |
| 43 | −static void sibyte_set_mode(enum clock_event_mode mode, | |
| 44 | − struct clock_event_device *evt) | |
| 43 | + | |
| 44 | +static int sibyte_set_periodic(struct clock_event_device *evt) | |
| 45 | 45 | { |
| 46 | 46 | unsigned int cpu = smp_processor_id(); |
| 47 | 47 | void __iomem *cfg, *init; |
| @@ -49,24 +49,22 @@ static void sibyte_set_mode(enum clock_event_mode mode, · 1 unmodified line | ||
| 49 | 49 | cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); |
| 50 | 50 | init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); |
| 51 | 51 | |
| 52 | − switch (mode) { | |
| 53 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 54 | − __raw_writeq(0, cfg); | |
| 55 | − __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); | |
| 56 | − __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | |
| 57 | − cfg); | |
| 58 | − break; | |
| 59 | − | |
| 60 | − case CLOCK_EVT_MODE_ONESHOT: | |
| 61 | − /* Stop the timer until we actually program a shot */ | |
| 62 | − case CLOCK_EVT_MODE_SHUTDOWN: | |
| 63 | − __raw_writeq(0, cfg); | |
| 64 | − break; | |
| 65 | − | |
| 66 | − case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ | |
| 67 | − case CLOCK_EVT_MODE_RESUME: | |
| 68 | − ; | |
| 69 | − } | |
| 52 | + __raw_writeq(0, cfg); | |
| 53 | + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); | |
| 54 | + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg); | |
| 55 | + return 0; | |
| 56 | +} | |
| 57 | + | |
| 58 | +static int sibyte_shutdown(struct clock_event_device *evt) | |
| 59 | +{ | |
| 60 | + unsigned int cpu = smp_processor_id(); | |
| 61 | + void __iomem *cfg; | |
| 62 | + | |
| 63 | + cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); | |
| 64 | + | |
| 65 | + /* Stop the timer until we actually program a shot */ | |
| 66 | + __raw_writeq(0, cfg); | |
| 67 | + return 0; | |
| 70 | 68 | } |
| 71 | 69 | |
| 72 | 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 | 89 | void __iomem *cfg; |
| 92 | 90 | unsigned long tmode; |
| 93 | 91 | |
| 94 | − if (cd->mode == CLOCK_EVT_MODE_PERIODIC) | |
| 92 | + if (clockevent_state_periodic(cd)) | |
| 95 | 93 | tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; |
| 96 | 94 | else |
| 97 | 95 | tmode = 0; |
| @@ -130,7 +128,9 @@ void sb1480_clockevent_init(void) · 32 unmodified lines | ||
| 130 | 128 | cd->irq = irq; |
| 131 | 129 | cd->cpumask = cpumask_of(cpu); |
| 132 | 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 | 134 | clockevents_register_device(cd); |
| 135 | 135 | |
| 136 | 136 | bcm1480_mask_irq(cpu, irq); |
| @@ -59,27 +59,32 @@ static int ds1287_set_next_event(unsigned long delta, · 58 unmodified lines | ||
| 59 | 59 | return -EINVAL; |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | −static void ds1287_set_mode(enum clock_event_mode mode, | |
| 63 | − struct clock_event_device *evt) | |
| 62 | +static int ds1287_shutdown(struct clock_event_device *evt) | |
| 64 | 63 | { |
| 65 | 64 | u8 val; |
| 66 | 65 | |
| 67 | 66 | spin_lock(&rtc_lock); |
| 68 | 67 | |
| 69 | 68 | val = CMOS_READ(RTC_REG_B); |
| 69 | + val &= ~RTC_PIE; | |
| 70 | + CMOS_WRITE(val, RTC_REG_B); | |
| 70 | 71 | |
| 71 | − switch (mode) { | |
| 72 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 73 | − val |= RTC_PIE; | |
| 74 | − break; | |
| 75 | − default: | |
| 76 | − val &= ~RTC_PIE; | |
| 77 | − break; | |
| 78 | − } | |
| 72 | + spin_unlock(&rtc_lock); | |
| 73 | + return 0; | |
| 74 | +} | |
| 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 | 84 | CMOS_WRITE(val, RTC_REG_B); |
| 81 | 85 | |
| 82 | 86 | spin_unlock(&rtc_lock); |
| 87 | + return 0; | |
| 83 | 88 | } |
| 84 | 89 | |
| 85 | 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 | 94 | static struct clock_event_device ds1287_clockevent = { |
| 90 | − .name = "ds1287", | |
| 91 | − .features = CLOCK_EVT_FEAT_PERIODIC, | |
| 92 | − .set_next_event = ds1287_set_next_event, | |
| 93 | − .set_mode = ds1287_set_mode, | |
| 94 | − .event_handler = ds1287_event_handler, | |
| 95 | + .name = "ds1287", | |
| 96 | + .features = CLOCK_EVT_FEAT_PERIODIC, | |
| 97 | + .set_next_event = ds1287_set_next_event, | |
| 98 | + .set_state_shutdown = ds1287_shutdown, | |
| 99 | + .set_state_periodic = ds1287_set_periodic, | |
| 100 | + .tick_resume = ds1287_shutdown, | |
| 101 | + .event_handler = ds1287_event_handler, | |
| 95 | 102 | }; |
| 96 | 103 | |
| 97 | 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 | 64 | return 0; |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | −static void gt641xx_timer0_set_mode(enum clock_event_mode mode, | |
| 68 | − struct clock_event_device *evt) | |
| 67 | +static int gt641xx_timer0_shutdown(struct clock_event_device *evt) | |
| 69 | 68 | { |
| 70 | 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 | 73 | ctrl = GT_READ(GT_TC_CONTROL_OFS); |
| 75 | 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) { | |
| 78 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 79 | − ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; | |
| 80 | − break; | |
| 81 | − case CLOCK_EVT_MODE_ONESHOT: | |
| 82 | − ctrl |= GT_TC_CONTROL_ENTC0_MSK; | |
| 83 | − break; | |
| 84 | − default: | |
| 85 | − break; | |
| 86 | − } | |
| 96 | +static int gt641xx_timer0_set_periodic(struct clock_event_device *evt) | |
| 97 | +{ | |
| 98 | + u32 ctrl; | |
| 99 | + | |
| 100 | + raw_spin_lock(>641xx_timer_lock); | |
| 87 | 101 | |
| 102 | + ctrl = GT_READ(GT_TC_CONTROL_OFS); | |
| 103 | + ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; | |
| 88 | 104 | GT_WRITE(GT_TC_CONTROL_OFS, ctrl); |
| 89 | 105 | |
| 90 | 106 | raw_spin_unlock(>641xx_timer_lock); |
| 107 | + return 0; | |
| 91 | 108 | } |
| 92 | 109 | |
| 93 | 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 | 114 | static struct clock_event_device gt641xx_timer0_clockevent = { |
| 98 | − .name = "gt641xx-timer0", | |
| 99 | − .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | |
| 100 | − .irq = GT641XX_TIMER0_IRQ, | |
| 101 | − .set_next_event = gt641xx_timer0_set_next_event, | |
| 102 | − .set_mode = gt641xx_timer0_set_mode, | |
| 103 | − .event_handler = gt641xx_timer0_event_handler, | |
| 115 | + .name = "gt641xx-timer0", | |
| 116 | + .features = CLOCK_EVT_FEAT_PERIODIC | | |
| 117 | + CLOCK_EVT_FEAT_ONESHOT, | |
| 118 | + .irq = GT641XX_TIMER0_IRQ, | |
| 119 | + .set_next_event = gt641xx_timer0_set_next_event, | |
| 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 | 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 | 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 | 31 | DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); |
| 38 | 32 | int cp0_timer_irq_installed; |
| 39 | 33 | |
| @@ -174,6 +168,11 @@ int c0_compare_int_usable(void) · 134 unmodified lines | ||
| 174 | 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 | 176 | int r4k_clockevent_init(void) |
| 178 | 177 | { |
| 179 | 178 | unsigned int cpu = smp_processor_id(); |
| @@ -189,11 +188,9 @@ int r4k_clockevent_init(void) · 9 unmodified lines | ||
| 189 | 188 | /* |
| 190 | 189 | * With vectored interrupts things are getting platform specific. |
| 191 | 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; | |
| 195 | − if (get_c0_compare_int) | |
| 196 | − irq = get_c0_compare_int(); | |
| 193 | + irq = get_c0_compare_int(); | |
| 197 | 194 | |
| 198 | 195 | cd = &per_cpu(mips_clockevent_device, cpu); |
| 199 | 196 | |
| @@ -212,7 +209,6 @@ int r4k_clockevent_init(void) · 12 unmodified lines | ||
| 212 | 209 | cd->irq = irq; |
| 213 | 210 | cd->cpumask = cpumask_of(cpu); |
| 214 | 211 | cd->set_next_event = mips_next_event; |
| 215 | − cd->set_mode = mips_set_clock_mode; | |
| 216 | 212 | cd->event_handler = mips_event_handler; |
| 217 | 213 | |
| 218 | 214 | clockevents_register_device(cd); |
| @@ -38,8 +38,20 @@ · 37 unmodified lines | ||
| 38 | 38 | * The general purpose timer ticks at 1MHz independent if |
| 39 | 39 | * the rest of the system |
| 40 | 40 | */ |
| 41 | −static void sibyte_set_mode(enum clock_event_mode mode, | |
| 42 | − struct clock_event_device *evt) | |
| 41 | + | |
| 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 | 56 | unsigned int cpu = smp_processor_id(); |
| 45 | 57 | void __iomem *cfg, *init; |
| @@ -47,24 +59,11 @@ static void sibyte_set_mode(enum clock_event_mode mode, · 1 unmodified line | ||
| 47 | 59 | cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); |
| 48 | 60 | init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); |
| 49 | 61 | |
| 50 | − switch (mode) { | |
| 51 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 52 | − __raw_writeq(0, cfg); | |
| 53 | − __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); | |
| 54 | − __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | |
| 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 | − } | |
| 62 | + __raw_writeq(0, cfg); | |
| 63 | + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); | |
| 64 | + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg); | |
| 65 | + | |
| 66 | + return 0; | |
| 68 | 67 | } |
| 69 | 68 | |
| 70 | 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 | 88 | void __iomem *cfg; |
| 90 | 89 | unsigned long tmode; |
| 91 | 90 | |
| 92 | − if (cd->mode == CLOCK_EVT_MODE_PERIODIC) | |
| 91 | + if (clockevent_state_periodic(cd)) | |
| 93 | 92 | tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; |
| 94 | 93 | else |
| 95 | 94 | tmode = 0; |
| @@ -129,7 +128,9 @@ void sb1250_clockevent_init(void) · 33 unmodified lines | ||
| 129 | 128 | cd->irq = irq; |
| 130 | 129 | cd->cpumask = cpumask_of(cpu); |
| 131 | 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 | 134 | clockevents_register_device(cd); |
| 134 | 135 | |
| 135 | 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 | 85 | __raw_writel(0, &tmrptr->tisr); |
| 86 | 86 | } |
| 87 | 87 | |
| 88 | −static void txx9tmr_set_mode(enum clock_event_mode mode, | |
| 89 | − struct clock_event_device *evt) | |
| 88 | +static int txx9tmr_set_state_periodic(struct clock_event_device *evt) | |
| 90 | 89 | { |
| 91 | 90 | struct txx9_clock_event_device *txx9_cd = |
| 92 | 91 | container_of(evt, struct txx9_clock_event_device, cd); |
| 93 | 92 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; |
| 94 | 93 | |
| 95 | 94 | txx9tmr_stop_and_clear(tmrptr); |
| 96 | − switch (mode) { | |
| 97 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 98 | − __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, | |
| 99 | − &tmrptr->itmr); | |
| 100 | − /* start timer */ | |
| 101 | − __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> | |
| 102 | − evt->shift, | |
| 103 | − &tmrptr->cpra); | |
| 104 | − __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); | |
| 105 | − break; | |
| 106 | − case CLOCK_EVT_MODE_SHUTDOWN: | |
| 107 | − case CLOCK_EVT_MODE_UNUSED: | |
| 108 | − __raw_writel(0, &tmrptr->itmr); | |
| 109 | − break; | |
| 110 | − case CLOCK_EVT_MODE_ONESHOT: | |
| 111 | − __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); | |
| 112 | − break; | |
| 113 | − case CLOCK_EVT_MODE_RESUME: | |
| 114 | − __raw_writel(TIMER_CCD, &tmrptr->ccdr); | |
| 115 | − __raw_writel(0, &tmrptr->itmr); | |
| 116 | − break; | |
| 117 | − } | |
| 95 | + | |
| 96 | + __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, &tmrptr->itmr); | |
| 97 | + /* start timer */ | |
| 98 | + __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> evt->shift, | |
| 99 | + &tmrptr->cpra); | |
| 100 | + __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); | |
| 101 | + return 0; | |
| 102 | +} | |
| 103 | + | |
| 104 | +static int txx9tmr_set_state_oneshot(struct clock_event_device *evt) | |
| 105 | +{ | |
| 106 | + struct txx9_clock_event_device *txx9_cd = | |
| 107 | + container_of(evt, struct txx9_clock_event_device, cd); | |
| 108 | + struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | |
| 109 | + | |
| 110 | + txx9tmr_stop_and_clear(tmrptr); | |
| 111 | + __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); | |
| 112 | + return 0; | |
| 113 | +} | |
| 114 | + | |
| 115 | +static int txx9tmr_set_state_shutdown(struct clock_event_device *evt) | |
| 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 | 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 | 152 | static struct txx9_clock_event_device txx9_clock_event_device = { |
| 135 | 153 | .cd = { |
| 136 | − .name = "TXx9", | |
| 137 | − .features = CLOCK_EVT_FEAT_PERIODIC | | |
| 138 | − CLOCK_EVT_FEAT_ONESHOT, | |
| 139 | − .rating = 200, | |
| 140 | − .set_mode = txx9tmr_set_mode, | |
| 141 | − .set_next_event = txx9tmr_set_next_event, | |
| 154 | + .name = "TXx9", | |
| 155 | + .features = CLOCK_EVT_FEAT_PERIODIC | | |
| 156 | + CLOCK_EVT_FEAT_ONESHOT, | |
| 157 | + .rating = 200, | |
| 158 | + .set_state_shutdown = txx9tmr_set_state_shutdown, | |
| 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 | 153 | /* Enter the coherent domain */ |
| 154 | 154 | li t0, 0xff |
| 155 | − PTR_S t0, GCR_CL_COHERENCE_OFS(v1) | |
| 155 | + sw t0, GCR_CL_COHERENCE_OFS(v1) | |
| 156 | 156 | ehb |
| 157 | 157 | |
| 158 | 158 | /* Jump to kseg0 */ |
| @@ -302,7 +302,7 @@ LEAF(mips_cps_boot_vpes) · 143 unmodified lines | ||
| 302 | 302 | PTR_L t0, 0(t0) |
| 303 | 303 | |
| 304 | 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 | 306 | li t1, COREBOOTCFG_SIZE |
| 307 | 307 | mul t0, t0, t1 |
| 308 | 308 | PTR_LA t1, mips_cps_core_bootcfg |
| @@ -32,6 +32,9 @@ · 31 unmodified lines | ||
| 32 | 32 | #include <asm/spram.h> |
| 33 | 33 | #include <asm/uaccess.h> |
| 34 | 34 | |
| 35 | +/* Hardware capabilities */ | |
| 36 | +unsigned int elf_hwcap __read_mostly; | |
| 37 | + | |
| 35 | 38 | /* |
| 36 | 39 | * Get the FPU Implementation/Revision. |
| 37 | 40 | */ |
| @@ -188,7 +191,7 @@ __setup("nohtw", htw_disable); · 150 unmodified lines | ||
| 188 | 191 | static int mips_ftlb_disabled; |
| 189 | 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 | 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 | 205 | return 1; |
| 203 | 206 | |
| 204 | 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 | 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 | 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 | 377 | /* It's implementation dependent how the FTLB can be enabled */ |
| 372 | 378 | switch (c->cputype) { |
| 373 | 379 | case CPU_PROAPTIV: |
| 374 | 380 | case CPU_P5600: |
| 375 | 381 | /* proAptiv & related cores use Config6 to enable the FTLB */ |
| 376 | − config6 = read_c0_config6(); | |
| 382 | + config = read_c0_config6(); | |
| 377 | 383 | /* Clear the old probability value */ |
| 378 | − config6 &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); | |
| 384 | + config &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); | |
| 379 | 385 | if (enable) |
| 380 | 386 | /* Enable FTLB */ |
| 381 | − write_c0_config6(config6 | | |
| 387 | + write_c0_config6(config | | |
| 382 | 388 | (calculate_ftlb_probability(c) |
| 383 | 389 | << MIPS_CONF6_FTLBP_SHIFT) |
| 384 | 390 | | MIPS_CONF6_FTLBEN); |
| 385 | 391 | else |
| 386 | 392 | /* Disable FTLB */ |
| 387 | − write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); | |
| 388 | − back_to_back_c0_hazard(); | |
| 393 | + write_c0_config6(config & ~MIPS_CONF6_FTLBEN); | |
| 389 | 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 | 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 | 542 | if (config3 & MIPS_CONF3_CDMM) |
| 526 | 543 | c->options |= MIPS_CPU_CDMM; |
| 544 | + if (config3 & MIPS_CONF3_SP) | |
| 545 | + c->options |= MIPS_CPU_SP; | |
| 527 | 546 | |
| 528 | 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 | 559 | if (cpu_has_tlb) { |
| 541 | 560 | if (((config4 & MIPS_CONF4_IE) >> 29) == 2) |
| 542 | 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 | 572 | switch (mmuextdef) { |
| 545 | 573 | case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT: |
| 546 | 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 | 1149 | c->cputype = CPU_P5600; |
| 1122 | 1150 | __cpu_name[cpu] = "MIPS P5600"; |
| 1123 | 1151 | break; |
| 1152 | + case PRID_IMP_I6400: | |
| 1153 | + c->cputype = CPU_I6400; | |
| 1154 | + __cpu_name[cpu] = "MIPS I6400"; | |
| 1155 | + break; | |
| 1124 | 1156 | case PRID_IMP_M5150: |
| 1125 | 1157 | c->cputype = CPU_M5150; |
| 1126 | 1158 | __cpu_name[cpu] = "MIPS M5150"; |
| @@ -1492,10 +1524,14 @@ void cpu_probe(void) · 365 unmodified lines | ||
| 1492 | 1524 | else |
| 1493 | 1525 | c->srsets = 1; |
| 1494 | 1526 | |
| 1527 | + if (cpu_has_mips_r6) | |
| 1528 | + elf_hwcap |= HWCAP_MIPS_R6; | |
| 1529 | + | |
| 1495 | 1530 | if (cpu_has_msa) { |
| 1496 | 1531 | c->msa_id = cpu_get_msa_id(); |
| 1497 | 1532 | WARN(c->msa_id & MSA_IR_WRPF, |
| 1498 | 1533 | "Vector register partitioning unimplemented!"); |
| 1534 | + elf_hwcap |= HWCAP_MIPS_MSA; | |
| 1499 | 1535 | } |
| 1500 | 1536 | |
| 1501 | 1537 | cpu_probe_vmbits(c); |
| @@ -196,6 +196,7 @@ void __init check_wait(void) · 195 unmodified lines | ||
| 196 | 196 | case CPU_INTERAPTIV: |
| 197 | 197 | case CPU_M5150: |
| 198 | 198 | case CPU_QEMU_GENERIC: |
| 199 | + case CPU_I6400: | |
| 199 | 200 | cpu_wait = r4k_wait; |
| 200 | 201 | if (read_c0_config7() & MIPS_CONF7_WII) |
| 201 | 202 | cpu_wait = r4k_wait_irqoff; |
| @@ -15,11 +15,131 @@ · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | void __iomem *mips_cm_base; |
| 17 | 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 | 139 | phys_addr_t __mips_cm_phys_base(void) |
| 20 | 140 | { |
| 21 | 141 | u32 config3 = read_c0_config3(); |
| 22 | − u32 cmgcr; | |
| 142 | + unsigned long cmgcr; | |
| 23 | 143 | |
| 24 | 144 | /* Check the CMGCRBase register is implemented */ |
| 25 | 145 | if (!(config3 & MIPS_CONF3_CMGCR)) |
| @@ -81,6 +201,13 @@ int mips_cm_probe(void) · 55 unmodified lines | ||
| 81 | 201 | phys_addr_t addr; |
| 82 | 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 | 211 | addr = mips_cm_phys_base(); |
| 85 | 212 | BUG_ON((addr & CM_GCR_BASE_GCRBASE_MSK) != addr); |
| 86 | 213 | if (!addr) |
| @@ -117,5 +244,133 @@ int mips_cm_probe(void) · 30 unmodified lines | ||
| 117 | 244 | /* probe for an L2-only sync region */ |
| 118 | 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 | 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 | 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 | 35 | if (!mips_cm_present()) |
| 29 | 36 | return 0; |
| @@ -1556,6 +1556,7 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) · 1555 unmodified lines | ||
| 1556 | 1556 | #endif |
| 1557 | 1557 | break; |
| 1558 | 1558 | case CPU_P5600: |
| 1559 | + case CPU_I6400: | |
| 1559 | 1560 | /* 8-bit event numbers */ |
| 1560 | 1561 | raw_id = config & 0x1ff; |
| 1561 | 1562 | base_id = raw_id & 0xff; |
| @@ -1717,6 +1718,11 @@ init_hw_perf_events(void) · 155 unmodified lines | ||
| 1717 | 1718 | mipspmu.general_event_map = &mipsxxcore_event_map2; |
| 1718 | 1719 | mipspmu.cache_event_map = &mipsxxcore_cache_map2; |
| 1719 | 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 | 1726 | case CPU_1004K: |
| 1721 | 1727 | mipspmu.name = "mips/1004K"; |
| 1722 | 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 | 268 | /* CPUs which do not require the workaround */ |
| 269 | 269 | case CPU_P5600: |
| 270 | + case CPU_I6400: | |
| 270 | 271 | return 0; |
| 271 | 272 | |
| 272 | 273 | default: |
| @@ -671,6 +672,7 @@ static int __init cps_pm_init(void) · 398 unmodified lines | ||
| 671 | 672 | case CPU_PROAPTIV: |
| 672 | 673 | case CPU_M5150: |
| 673 | 674 | case CPU_P5600: |
| 675 | + case CPU_I6400: | |
| 674 | 676 | stype_intervention = 0x2; |
| 675 | 677 | stype_memory = 0x3; |
| 676 | 678 | stype_ordering = 0x10; |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <linux/regset.h> |
| 26 | 26 | #include <linux/smp.h> |
| 27 | 27 | #include <linux/security.h> |
| 28 | +#include <linux/stddef.h> | |
| 28 | 29 | #include <linux/tracehook.h> |
| 29 | 30 | #include <linux/audit.h> |
| 30 | 31 | #include <linux/seccomp.h> |
| @@ -490,6 +491,93 @@ enum mips_regset { · 459 unmodified lines | ||
| 490 | 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 | 581 | #if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) |
| 494 | 582 | |
| 495 | 583 | static const struct user_regset mips_regsets[] = { |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | * Copyright (C) 1999, 2001 Silicon Graphics, Inc. |
| 14 | 14 | */ |
| 15 | 15 | #include <asm/asm.h> |
| 16 | +#include <asm/asmmacro.h> | |
| 16 | 17 | #include <asm/errno.h> |
| 17 | 18 | #include <asm/fpregdef.h> |
| 18 | 19 | #include <asm/mipsregs.h> |
| @@ -35,6 +36,14 @@ · 16 unmodified lines | ||
| 35 | 36 | |
| 36 | 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 | 47 | LEAF(_save_fp_context) |
| 39 | 48 | .set push |
| 40 | 49 | SET_HARDFLOAT |
| @@ -54,117 +63,60 @@ LEAF(_save_fp_context) · 13 unmodified lines | ||
| 54 | 63 | nop |
| 55 | 64 | #endif |
| 56 | 65 | /* Store the 16 odd double precision registers */ |
| 57 | − EX sdc1 $f1, SC_FPREGS+8(a0) | |
| 58 | − EX sdc1 $f3, SC_FPREGS+24(a0) | |
| 59 | − EX sdc1 $f5, SC_FPREGS+40(a0) | |
| 60 | − EX sdc1 $f7, SC_FPREGS+56(a0) | |
| 61 | − EX sdc1 $f9, SC_FPREGS+72(a0) | |
| 62 | − EX sdc1 $f11, SC_FPREGS+88(a0) | |
| 63 | − EX sdc1 $f13, SC_FPREGS+104(a0) | |
| 64 | − EX sdc1 $f15, SC_FPREGS+120(a0) | |
| 65 | − EX sdc1 $f17, SC_FPREGS+136(a0) | |
| 66 | − EX sdc1 $f19, SC_FPREGS+152(a0) | |
| 67 | − EX sdc1 $f21, SC_FPREGS+168(a0) | |
| 68 | − EX sdc1 $f23, SC_FPREGS+184(a0) | |
| 69 | − EX sdc1 $f25, SC_FPREGS+200(a0) | |
| 70 | − EX sdc1 $f27, SC_FPREGS+216(a0) | |
| 71 | − EX sdc1 $f29, SC_FPREGS+232(a0) | |
| 72 | − EX sdc1 $f31, SC_FPREGS+248(a0) | |
| 66 | + EX sdc1 $f1, 8(a0) | |
| 67 | + EX sdc1 $f3, 24(a0) | |
| 68 | + EX sdc1 $f5, 40(a0) | |
| 69 | + EX sdc1 $f7, 56(a0) | |
| 70 | + EX sdc1 $f9, 72(a0) | |
| 71 | + EX sdc1 $f11, 88(a0) | |
| 72 | + EX sdc1 $f13, 104(a0) | |
| 73 | + EX sdc1 $f15, 120(a0) | |
| 74 | + EX sdc1 $f17, 136(a0) | |
| 75 | + EX sdc1 $f19, 152(a0) | |
| 76 | + EX sdc1 $f21, 168(a0) | |
| 77 | + EX sdc1 $f23, 184(a0) | |
| 78 | + EX sdc1 $f25, 200(a0) | |
| 79 | + EX sdc1 $f27, 216(a0) | |
| 80 | + EX sdc1 $f29, 232(a0) | |
| 81 | + EX sdc1 $f31, 248(a0) | |
| 73 | 82 | 1: .set pop |
| 74 | 83 | #endif |
| 75 | 84 | |
| 76 | 85 | .set push |
| 77 | 86 | SET_HARDFLOAT |
| 78 | 87 | /* Store the 16 even double precision registers */ |
| 79 | − EX sdc1 $f0, SC_FPREGS+0(a0) | |
| 80 | − EX sdc1 $f2, SC_FPREGS+16(a0) | |
| 81 | − EX sdc1 $f4, SC_FPREGS+32(a0) | |
| 82 | − EX sdc1 $f6, SC_FPREGS+48(a0) | |
| 83 | − EX sdc1 $f8, SC_FPREGS+64(a0) | |
| 84 | − EX sdc1 $f10, SC_FPREGS+80(a0) | |
| 85 | − EX sdc1 $f12, SC_FPREGS+96(a0) | |
| 86 | − EX sdc1 $f14, SC_FPREGS+112(a0) | |
| 87 | − EX sdc1 $f16, SC_FPREGS+128(a0) | |
| 88 | − EX sdc1 $f18, SC_FPREGS+144(a0) | |
| 89 | − EX sdc1 $f20, SC_FPREGS+160(a0) | |
| 90 | − EX sdc1 $f22, SC_FPREGS+176(a0) | |
| 91 | − EX sdc1 $f24, SC_FPREGS+192(a0) | |
| 92 | − EX sdc1 $f26, SC_FPREGS+208(a0) | |
| 93 | − EX sdc1 $f28, SC_FPREGS+224(a0) | |
| 94 | − EX sdc1 $f30, SC_FPREGS+240(a0) | |
| 95 | − EX sw t1, SC_FPC_CSR(a0) | |
| 88 | + EX sdc1 $f0, 0(a0) | |
| 89 | + EX sdc1 $f2, 16(a0) | |
| 90 | + EX sdc1 $f4, 32(a0) | |
| 91 | + EX sdc1 $f6, 48(a0) | |
| 92 | + EX sdc1 $f8, 64(a0) | |
| 93 | + EX sdc1 $f10, 80(a0) | |
| 94 | + EX sdc1 $f12, 96(a0) | |
| 95 | + EX sdc1 $f14, 112(a0) | |
| 96 | + EX sdc1 $f16, 128(a0) | |
| 97 | + EX sdc1 $f18, 144(a0) | |
| 98 | + EX sdc1 $f20, 160(a0) | |
| 99 | + EX sdc1 $f22, 176(a0) | |
| 100 | + EX sdc1 $f24, 192(a0) | |
| 101 | + EX sdc1 $f26, 208(a0) | |
| 102 | + EX sdc1 $f28, 224(a0) | |
| 103 | + EX sdc1 $f30, 240(a0) | |
| 104 | + EX sw t1, 0(a1) | |
| 96 | 105 | jr ra |
| 97 | 106 | li v0, 0 # success |
| 98 | 107 | .set pop |
| 99 | 108 | END(_save_fp_context) |
| 100 | 109 | |
| 101 | −#ifdef CONFIG_MIPS32_COMPAT | |
| 102 | − /* Save 32-bit process floating point context */ | |
| 103 | −LEAF(_save_fp_context32) | |
| 104 | − .set push | |
| 105 | − .set MIPS_ISA_ARCH_LEVEL_RAW | |
| 106 | − SET_HARDFLOAT | |
| 107 | − cfc1 t1, fcr31 | |
| 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 | |
| 110 | +/** | |
| 111 | + * _restore_fp_context() - restore FP context to the FPU | |
| 112 | + * @a0 - pointer to fpregs field of sigcontext | |
| 113 | + * @a1 - pointer to fpc_csr field of sigcontext | |
| 114 | + * | |
| 115 | + * Restore FP context, including the 32 FP data registers and the FP | |
| 116 | + * control & status register, from signal context to the FPU. | |
| 165 | 117 | */ |
| 166 | 118 | LEAF(_restore_fp_context) |
| 167 | − EX lw t1, SC_FPC_CSR(a0) | |
| 119 | + EX lw t1, 0(a1) | |
| 168 | 120 | |
| 169 | 121 | #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ |
| 170 | 122 | defined(CONFIG_CPU_MIPS32_R6) |
| @@ -178,101 +130,231 @@ LEAF(_restore_fp_context) · 7 unmodified lines | ||
| 178 | 130 | bgez t0, 1f # skip loading odd if FR=0 |
| 179 | 131 | nop |
| 180 | 132 | #endif |
| 181 | − EX ldc1 $f1, SC_FPREGS+8(a0) | |
| 182 | − EX ldc1 $f3, SC_FPREGS+24(a0) | |
| 183 | − EX ldc1 $f5, SC_FPREGS+40(a0) | |
| 184 | − EX ldc1 $f7, SC_FPREGS+56(a0) | |
| 185 | − EX ldc1 $f9, SC_FPREGS+72(a0) | |
| 186 | − EX ldc1 $f11, SC_FPREGS+88(a0) | |
| 187 | − EX ldc1 $f13, SC_FPREGS+104(a0) | |
| 188 | − EX ldc1 $f15, SC_FPREGS+120(a0) | |
| 189 | − EX ldc1 $f17, SC_FPREGS+136(a0) | |
| 190 | − EX ldc1 $f19, SC_FPREGS+152(a0) | |
| 191 | − EX ldc1 $f21, SC_FPREGS+168(a0) | |
| 192 | − EX ldc1 $f23, SC_FPREGS+184(a0) | |
| 193 | − EX ldc1 $f25, SC_FPREGS+200(a0) | |
| 194 | − EX ldc1 $f27, SC_FPREGS+216(a0) | |
| 195 | − EX ldc1 $f29, SC_FPREGS+232(a0) | |
| 196 | − EX ldc1 $f31, SC_FPREGS+248(a0) | |
| 133 | + EX ldc1 $f1, 8(a0) | |
| 134 | + EX ldc1 $f3, 24(a0) | |
| 135 | + EX ldc1 $f5, 40(a0) | |
| 136 | + EX ldc1 $f7, 56(a0) | |
| 137 | + EX ldc1 $f9, 72(a0) | |
| 138 | + EX ldc1 $f11, 88(a0) | |
| 139 | + EX ldc1 $f13, 104(a0) | |
| 140 | + EX ldc1 $f15, 120(a0) | |
| 141 | + EX ldc1 $f17, 136(a0) | |
| 142 | + EX ldc1 $f19, 152(a0) | |
| 143 | + EX ldc1 $f21, 168(a0) | |
| 144 | + EX ldc1 $f23, 184(a0) | |
| 145 | + EX ldc1 $f25, 200(a0) | |
| 146 | + EX ldc1 $f27, 216(a0) | |
| 147 | + EX ldc1 $f29, 232(a0) | |
| 148 | + EX ldc1 $f31, 248(a0) | |
| 197 | 149 | 1: .set pop |
| 198 | 150 | #endif |
| 199 | 151 | .set push |
| 200 | 152 | SET_HARDFLOAT |
| 201 | − EX ldc1 $f0, SC_FPREGS+0(a0) | |
| 202 | − EX ldc1 $f2, SC_FPREGS+16(a0) | |
| 203 | − EX ldc1 $f4, SC_FPREGS+32(a0) | |
| 204 | − EX ldc1 $f6, SC_FPREGS+48(a0) | |
| 205 | − EX ldc1 $f8, SC_FPREGS+64(a0) | |
| 206 | − EX ldc1 $f10, SC_FPREGS+80(a0) | |
| 207 | − EX ldc1 $f12, SC_FPREGS+96(a0) | |
| 208 | − EX ldc1 $f14, SC_FPREGS+112(a0) | |
| 209 | − EX ldc1 $f16, SC_FPREGS+128(a0) | |
| 210 | − EX ldc1 $f18, SC_FPREGS+144(a0) | |
| 211 | − EX ldc1 $f20, SC_FPREGS+160(a0) | |
| 212 | − EX ldc1 $f22, SC_FPREGS+176(a0) | |
| 213 | − EX ldc1 $f24, SC_FPREGS+192(a0) | |
| 214 | − EX ldc1 $f26, SC_FPREGS+208(a0) | |
| 215 | − EX ldc1 $f28, SC_FPREGS+224(a0) | |
| 216 | − EX ldc1 $f30, SC_FPREGS+240(a0) | |
| 153 | + EX ldc1 $f0, 0(a0) | |
| 154 | + EX ldc1 $f2, 16(a0) | |
| 155 | + EX ldc1 $f4, 32(a0) | |
| 156 | + EX ldc1 $f6, 48(a0) | |
| 157 | + EX ldc1 $f8, 64(a0) | |
| 158 | + EX ldc1 $f10, 80(a0) | |
| 159 | + EX ldc1 $f12, 96(a0) | |
| 160 | + EX ldc1 $f14, 112(a0) | |
| 161 | + EX ldc1 $f16, 128(a0) | |
| 162 | + EX ldc1 $f18, 144(a0) | |
| 163 | + EX ldc1 $f20, 160(a0) | |
| 164 | + EX ldc1 $f22, 176(a0) | |
| 165 | + EX ldc1 $f24, 192(a0) | |
| 166 | + EX ldc1 $f26, 208(a0) | |
| 167 | + EX ldc1 $f28, 224(a0) | |
| 168 | + EX ldc1 $f30, 240(a0) | |
| 217 | 169 | ctc1 t1, fcr31 |
| 218 | 170 | .set pop |
| 219 | 171 | jr ra |
| 220 | 172 | li v0, 0 # success |
| 221 | 173 | END(_restore_fp_context) |
| 222 | 174 | |
| 223 | −#ifdef CONFIG_MIPS32_COMPAT | |
| 224 | −LEAF(_restore_fp_context32) | |
| 225 | − /* Restore an o32 sigcontext. */ | |
| 226 | − .set push | |
| 227 | − SET_HARDFLOAT | |
| 228 | − EX lw t1, SC32_FPC_CSR(a0) | |
| 175 | +#ifdef CONFIG_CPU_HAS_MSA | |
| 229 | 176 | |
| 230 | −#ifndef CONFIG_CPU_MIPS64_R6 | |
| 231 | − mfc0 t0, CP0_STATUS | |
| 232 | − sll t0, t0, 5 | |
| 233 | − bgez t0, 1f # skip loading odd if FR=0 | |
| 177 | + .macro op_one_wr op, idx, base | |
| 178 | + .align 4 | |
| 179 | +\idx: \op \idx, 0, \base | |
| 180 | + jr ra | |
| 234 | 181 | nop |
| 235 | −#endif | |
| 182 | + .endm | |
| 236 | 183 | |
| 237 | − EX ldc1 $f1, SC32_FPREGS+8(a0) | |
| 238 | − EX ldc1 $f3, SC32_FPREGS+24(a0) | |
| 239 | − EX ldc1 $f5, SC32_FPREGS+40(a0) | |
| 240 | − EX ldc1 $f7, SC32_FPREGS+56(a0) | |
| 241 | − EX ldc1 $f9, SC32_FPREGS+72(a0) | |
| 242 | − EX ldc1 $f11, SC32_FPREGS+88(a0) | |
| 243 | − EX ldc1 $f13, SC32_FPREGS+104(a0) | |
| 244 | − EX ldc1 $f15, SC32_FPREGS+120(a0) | |
| 245 | − EX ldc1 $f17, SC32_FPREGS+136(a0) | |
| 246 | − EX ldc1 $f19, SC32_FPREGS+152(a0) | |
| 247 | − EX ldc1 $f21, SC32_FPREGS+168(a0) | |
| 248 | − EX ldc1 $f23, SC32_FPREGS+184(a0) | |
| 249 | − EX ldc1 $f25, SC32_FPREGS+200(a0) | |
| 250 | − EX ldc1 $f27, SC32_FPREGS+216(a0) | |
| 251 | − EX ldc1 $f29, SC32_FPREGS+232(a0) | |
| 252 | − EX ldc1 $f31, SC32_FPREGS+248(a0) | |
| 184 | + .macro op_msa_wr name, op | |
| 185 | +LEAF(\name) | |
| 186 | + .set push | |
| 187 | + .set noreorder | |
| 188 | + sll t0, a0, 4 | |
| 189 | + PTR_LA t1, 0f | |
| 190 | + PTR_ADDU t0, t0, t1 | |
| 191 | + jr t0 | |
| 192 | + nop | |
| 193 | + op_one_wr \op, 0, a1 | |
| 194 | + op_one_wr \op, 1, a1 | |
| 195 | + op_one_wr \op, 2, a1 | |
| 196 | + op_one_wr \op, 3, a1 | |
| 197 | + op_one_wr \op, 4, a1 | |
| 198 | + op_one_wr \op, 5, a1 | |
| 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) | |
| 255 | − EX ldc1 $f2, SC32_FPREGS+16(a0) | |
| 256 | − EX ldc1 $f4, SC32_FPREGS+32(a0) | |
| 257 | − EX ldc1 $f6, SC32_FPREGS+48(a0) | |
| 258 | − EX ldc1 $f8, SC32_FPREGS+64(a0) | |
| 259 | − EX ldc1 $f10, SC32_FPREGS+80(a0) | |
| 260 | − EX ldc1 $f12, SC32_FPREGS+96(a0) | |
| 261 | − EX ldc1 $f14, SC32_FPREGS+112(a0) | |
| 262 | − EX ldc1 $f16, SC32_FPREGS+128(a0) | |
| 263 | − EX ldc1 $f18, SC32_FPREGS+144(a0) | |
| 264 | − EX ldc1 $f20, SC32_FPREGS+160(a0) | |
| 265 | − EX ldc1 $f22, SC32_FPREGS+176(a0) | |
| 266 | − EX ldc1 $f24, SC32_FPREGS+192(a0) | |
| 267 | − EX ldc1 $f26, SC32_FPREGS+208(a0) | |
| 268 | − EX ldc1 $f28, SC32_FPREGS+224(a0) | |
| 269 | − EX ldc1 $f30, SC32_FPREGS+240(a0) | |
| 270 | − ctc1 t1, fcr31 | |
| 229 | + op_msa_wr read_msa_wr_b, st_b | |
| 230 | + op_msa_wr read_msa_wr_h, st_h | |
| 231 | + op_msa_wr read_msa_wr_w, st_w | |
| 232 | + op_msa_wr read_msa_wr_d, st_d | |
| 233 | + | |
| 234 | + op_msa_wr write_msa_wr_b, ld_b | |
| 235 | + op_msa_wr write_msa_wr_h, ld_h | |
| 236 | + op_msa_wr write_msa_wr_w, ld_w | |
| 237 | + op_msa_wr write_msa_wr_d, ld_d | |
| 238 | + | |
| 239 | +#endif /* CONFIG_CPU_HAS_MSA */ | |
| 240 | + | |
| 241 | +#ifdef CONFIG_CPU_HAS_MSA | |
| 242 | + | |
| 243 | + .macro save_msa_upper wr, off, base | |
| 244 | + .set push | |
| 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 | 296 | jr ra |
| 272 | − li v0, 0 # success | |
| 273 | − .set pop | |
| 274 | − END(_restore_fp_context32) | |
| 297 | + li v0, 0 | |
| 298 | + END(_save_msa_all_upper) | |
| 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 | 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 | 359 | .set reorder |
| 278 | 360 | |
| @@ -34,7 +34,7 @@ · 33 unmodified lines | ||
| 34 | 34 | #ifndef USE_ALTERNATE_RESUME_IMPL |
| 35 | 35 | /* |
| 36 | 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 | 39 | .align 5 |
| 40 | 40 | LEAF(resume) |
| @@ -43,45 +43,6 @@ · 2 unmodified lines | ||
| 43 | 43 | cpu_save_nonscratch a0 |
| 44 | 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 | 46 | #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) |
| 86 | 47 | PTR_LA t8, __stack_chk_guard |
| 87 | 48 | LONG_L t9, TASK_STACK_CANARY(a1) |
| @@ -31,4 +31,13 @@ extern int fpcsr_pending(unsigned int __user *fpcsr); · 30 unmodified lines | ||
| 31 | 31 | #define lock_fpu_owner() ({ preempt_disable(); pagefault_disable(); }) |
| 32 | 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 | 43 | #endif /* __SIGNAL_COMMON_H */ |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <linux/wait.h> |
| 22 | 22 | #include <linux/ptrace.h> |
| 23 | 23 | #include <linux/unistd.h> |
| 24 | +#include <linux/uprobes.h> | |
| 24 | 25 | #include <linux/compiler.h> |
| 25 | 26 | #include <linux/syscalls.h> |
| 26 | 27 | #include <linux/uaccess.h> |
| @@ -38,20 +39,21 @@ · 11 unmodified lines | ||
| 38 | 39 | #include <asm/vdso.h> |
| 39 | 40 | #include <asm/dsp.h> |
| 40 | 41 | #include <asm/inst.h> |
| 42 | +#include <asm/msa.h> | |
| 41 | 43 | |
| 42 | 44 | #include "signal-common.h" |
| 43 | 45 | |
| 44 | −static int (*save_fp_context)(struct sigcontext __user *sc); | |
| 45 | −static int (*restore_fp_context)(struct sigcontext __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); | |
| 46 | +static int (*save_fp_context)(void __user *sc); | |
| 47 | +static int (*restore_fp_context)(void __user *sc); | |
| 49 | 48 | |
| 50 | 49 | struct sigframe { |
| 51 | 50 | u32 sf_ass[4]; /* argument save space for o32 */ |
| 52 | 51 | u32 sf_pad[2]; /* Was: signal trampoline */ |
| 52 | + | |
| 53 | + /* Matches struct ucontext from its uc_mcontext field onwards */ | |
| 53 | 54 | struct sigcontext sf_sc; |
| 54 | 55 | sigset_t sf_mask; |
| 56 | + unsigned long long sf_extcontext[0]; | |
| 55 | 57 | }; |
| 56 | 58 | |
| 57 | 59 | struct rt_sigframe { |
| @@ -65,43 +67,255 @@ struct rt_sigframe { · 7 unmodified lines | ||
| 65 | 67 | * Thread saved context copy to/from a signal context presumed to be on the |
| 66 | 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 | 75 | int i; |
| 71 | 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 | 80 | err |= |
| 75 | 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 | 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 | 94 | int i; |
| 86 | 95 | int err = 0; |
| 96 | + int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; | |
| 87 | 97 | u64 fpr_val; |
| 88 | 98 | |
| 89 | − for (i = 0; i < NUM_FPU_REGS; i++) { | |
| 90 | − err |= __get_user(fpr_val, &sc->sc_fpregs[i]); | |
| 99 | + for (i = 0; i < NUM_FPU_REGS; i += inc) { | |
| 100 | + err |= __get_user(fpr_val, &fpregs[i]); | |
| 91 | 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 | 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 | 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 | 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 | 319 | while (1) { |
| 106 | 320 | lock_fpu_owner(); |
| 107 | 321 | if (is_fpu_owner()) { |
| @@ -114,27 +328,57 @@ static int protected_save_fp_context(struct sigcontext __user *sc) · 6 unmodified lines | ||
| 114 | 328 | if (likely(!err)) |
| 115 | 329 | break; |
| 116 | 330 | /* touch the sigcontext and try again */ |
| 117 | − err = __put_user(0, &sc->sc_fpregs[0]) | | |
| 118 | − __put_user(0, &sc->sc_fpregs[31]) | | |
| 119 | − __put_user(0, &sc->sc_fpc_csr); | |
| 331 | + err = __put_user(0, &fpregs[0]) | | |
| 332 | + __put_user(0, &fpregs[31]) | | |
| 333 | + __put_user(0, csr); | |
| 120 | 334 | if (err) |
| 121 | − break; /* really bad sigcontext */ | |
| 335 | + return err; /* really bad sigcontext */ | |
| 122 | 336 | } |
| 123 | −#else | |
| 124 | − /* | |
| 125 | − * EVA does not have FPU EVA instructions so saving fpu context directly | |
| 126 | − * does not work. | |
| 127 | − */ | |
| 128 | − lose_fpu(1); | |
| 129 | − err = save_fp_context(sc); /* this might fail */ | |
| 130 | −#endif | |
| 131 | − return err; | |
| 337 | + | |
| 338 | +fp_done: | |
| 339 | + ext_sz = err = save_extcontext(sc_to_extcontext(sc)); | |
| 340 | + if (err < 0) | |
| 341 | + return err; | |
| 342 | + used |= ext_sz ? USED_EXTCONTEXT : 0; | |
| 343 | + | |
| 344 | + return __put_user(used, used_math); | |
| 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; | |
| 137 | −#ifndef CONFIG_EVA | |
| 349 | + struct mips_abi *abi = current->thread.abi; | |
| 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 | 382 | while (1) { |
| 139 | 383 | lock_fpu_owner(); |
| 140 | 384 | if (is_fpu_owner()) { |
| @@ -147,28 +391,24 @@ static int protected_restore_fp_context(struct sigcontext __user *sc) · 6 unmodified lines | ||
| 147 | 391 | if (likely(!err)) |
| 148 | 392 | break; |
| 149 | 393 | /* touch the sigcontext and try again */ |
| 150 | − err = __get_user(tmp, &sc->sc_fpregs[0]) | | |
| 151 | − __get_user(tmp, &sc->sc_fpregs[31]) | | |
| 152 | − __get_user(tmp, &sc->sc_fpc_csr); | |
| 394 | + err = __get_user(tmp, &fpregs[0]) | | |
| 395 | + __get_user(tmp, &fpregs[31]) | | |
| 396 | + __get_user(tmp, csr); | |
| 153 | 397 | if (err) |
| 154 | 398 | break; /* really bad sigcontext */ |
| 155 | 399 | } |
| 156 | −#else | |
| 157 | − /* | |
| 158 | − * EVA does not have FPU EVA instructions so restoring fpu context | |
| 159 | − * directly does not work. | |
| 160 | − */ | |
| 161 | − lose_fpu(0); | |
| 162 | − err = restore_fp_context(sc); /* this might fail */ | |
| 163 | −#endif | |
| 164 | − return err; | |
| 400 | + | |
| 401 | +fp_done: | |
| 402 | + if (used & USED_EXTCONTEXT) | |
| 403 | + err |= restore_extcontext(sc_to_extcontext(sc)); | |
| 404 | + | |
| 405 | + return err ?: sig; | |
| 165 | 406 | } |
| 166 | 407 | |
| 167 | 408 | int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) |
| 168 | 409 | { |
| 169 | 410 | int err = 0; |
| 170 | 411 | int i; |
| 171 | − unsigned int used_math; | |
| 172 | 412 | |
| 173 | 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 | 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) { | |
| 198 | − /* | |
| 199 | − * Save FPU state to signal context. Signal handler | |
| 200 | − * will "inherit" current FPU state. | |
| 201 | − */ | |
| 202 | − err |= protected_save_fp_context(sc); | |
| 203 | − } | |
| 435 | + /* | |
| 436 | + * Save FPU state to signal context. Signal handler | |
| 437 | + * will "inherit" current FPU state. | |
| 438 | + */ | |
| 439 | + err |= protected_save_fp_context(sc); | |
| 440 | + | |
| 204 | 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 | 466 | int fpcsr_pending(unsigned int __user *fpcsr) |
| 208 | 467 | { |
| 209 | 468 | int err, sig = 0; |
| @@ -223,21 +482,8 @@ int fpcsr_pending(unsigned int __user *fpcsr) · 13 unmodified lines | ||
| 223 | 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 | 485 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) |
| 239 | 486 | { |
| 240 | − unsigned int used_math; | |
| 241 | 487 | unsigned long treg; |
| 242 | 488 | int err = 0; |
| 243 | 489 | int i; |
| @@ -265,19 +511,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) · 21 unmodified lines | ||
| 265 | 511 | for (i = 1; i < 32; i++) |
| 266 | 512 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); |
| 267 | 513 | |
| 268 | − err |= __get_user(used_math, &sc->sc_used_math); | |
| 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; | |
| 514 | + return err ?: protected_restore_fp_context(sc); | |
| 281 | 515 | } |
| 282 | 516 | |
| 283 | 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 | 520 | unsigned long sp; |
| 287 | 521 | |
| 522 | + /* Leave space for potential extended context */ | |
| 523 | + frame_size += extcontext_max_size(); | |
| 524 | + | |
| 288 | 525 | /* Default to using normal stack */ |
| 289 | 526 | sp = regs->regs[29]; |
| 290 | 527 | |
| @@ -520,7 +757,11 @@ struct mips_abi mips_abi = { · 229 unmodified lines | ||
| 520 | 757 | .setup_rt_frame = setup_rt_frame, |
| 521 | 758 | .rt_signal_return_offset = |
| 522 | 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 | 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 | 858 | user_exit(); |
| 618 | 859 | |
| 860 | + if (thread_info_flags & _TIF_UPROBE) | |
| 861 | + uprobe_notify_resume(regs); | |
| 862 | + | |
| 619 | 863 | /* deal with pending signal delivery */ |
| 620 | 864 | if (thread_info_flags & _TIF_SIGPENDING) |
| 621 | 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 | 875 | #ifdef CONFIG_SMP |
| 632 | −#ifndef CONFIG_EVA | |
| 633 | −static int smp_save_fp_context(struct sigcontext __user *sc) | |
| 876 | +static int smp_save_fp_context(void __user *sc) | |
| 634 | 877 | { |
| 635 | 878 | return raw_cpu_has_fpu |
| 636 | − ? _save_fp_context(sc) | |
| 879 | + ? save_hw_fp_context(sc) | |
| 637 | 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 | 885 | return raw_cpu_has_fpu |
| 643 | − ? _restore_fp_context(sc) | |
| 886 | + ? restore_hw_fp_context(sc) | |
| 644 | 887 | : copy_fp_from_sigcontext(sc); |
| 645 | 888 | } |
| 646 | −#endif /* CONFIG_EVA */ | |
| 647 | 889 | #endif |
| 648 | 890 | |
| 649 | 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 | 903 | #ifdef CONFIG_SMP |
| 653 | 904 | /* For now just do the cpu_has_fpu check when the functions are invoked */ |
| 654 | 905 | save_fp_context = smp_save_fp_context; |
| 655 | 906 | restore_fp_context = smp_restore_fp_context; |
| 656 | 907 | #else |
| 657 | 908 | if (cpu_has_fpu) { |
| 658 | − save_fp_context = _save_fp_context; | |
| 659 | − restore_fp_context = _restore_fp_context; | |
| 909 | + save_fp_context = save_hw_fp_context; | |
| 910 | + restore_fp_context = restore_hw_fp_context; | |
| 660 | 911 | } else { |
| 661 | 912 | save_fp_context = copy_fp_to_sigcontext; |
| 662 | 913 | restore_fp_context = copy_fp_from_sigcontext; |
| 663 | 914 | } |
| 664 | 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 | 917 | return 0; |
| 671 | 918 | } |
| @@ -36,12 +36,6 @@ · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 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 | 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 | 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 | 71 | static int setup_sigcontext32(struct pt_regs *regs, |
| 165 | 72 | struct sigcontext32 __user *sc) |
| 166 | 73 | { |
| 167 | 74 | int err = 0; |
| 168 | 75 | int i; |
| 169 | − u32 used_math; | |
| 170 | 76 | |
| 171 | 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 | 92 | err |= __put_user(mflo3(), &sc->sc_lo3); |
| 187 | 93 | } |
| 188 | 94 | |
| 189 | − used_math = !!used_math(); | |
| 190 | − err |= __put_user(used_math, &sc->sc_used_math); | |
| 95 | + /* | |
| 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 | 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 | 104 | static int restore_sigcontext32(struct pt_regs *regs, |
| 215 | 105 | struct sigcontext32 __user *sc) |
| 216 | 106 | { |
| 217 | − u32 used_math; | |
| 218 | 107 | int err = 0; |
| 219 | 108 | s32 treg; |
| 220 | 109 | int i; |
| @@ -238,70 +127,7 @@ static int restore_sigcontext32(struct pt_regs *regs, · 17 unmodified lines | ||
| 238 | 127 | for (i = 1; i < 32; i++) |
| 239 | 128 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); |
| 240 | 129 | |
| 241 | − err |= __get_user(used_math, &sc->sc_used_math); | |
| 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; | |
| 130 | + return err ?: protected_restore_fp_context(sc); | |
| 305 | 131 | } |
| 306 | 132 | |
| 307 | 133 | /* |
| @@ -585,20 +411,9 @@ struct mips_abi mips_abi_32 = { · 277 unmodified lines | ||
| 585 | 411 | .setup_rt_frame = setup_rt_frame_32, |
| 586 | 412 | .rt_signal_return_offset = |
| 587 | 413 | offsetof(struct mips_vdso, o32_rt_signal_trampoline), |
| 588 | − .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 | − } | |
| 414 | + .restart = __NR_O32_restart_syscall, | |
| 600 | 415 | |
| 601 | − return 0; | |
| 602 | −} | |
| 603 | − | |
| 604 | −arch_initcall(signal32_init); | |
| 416 | + .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs), | |
| 417 | + .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), | |
| 418 | + .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), | |
| 419 | +}; | |
| @@ -153,5 +153,9 @@ struct mips_abi mips_abi_n32 = { · 152 unmodified lines | ||
| 153 | 153 | .setup_rt_frame = setup_rt_frame_n32, |
| 154 | 154 | .rt_signal_return_offset = |
| 155 | 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 | 209 | case CPU_PROAPTIV: |
| 210 | 210 | case CPU_P5600: |
| 211 | 211 | case CPU_QEMU_GENERIC: |
| 212 | + case CPU_I6400: | |
| 212 | 213 | config0 = read_c0_config(); |
| 213 | 214 | /* FIXME: addresses are Malta specific */ |
| 214 | 215 | if (config0 & (1<<24)) { |
| @@ -21,24 +21,12 @@ static DEFINE_SPINLOCK(show_lock); · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | static void sysrq_tlbdump_single(void *dummy) |
| 23 | 23 | { |
| 24 | − const int field = 2 * sizeof(unsigned long); | |
| 25 | 24 | unsigned long flags; |
| 26 | 25 | |
| 27 | 26 | spin_lock_irqsave(&show_lock, flags); |
| 28 | 27 | |
| 29 | 28 | pr_info("CPU%d:\n", smp_processor_id()); |
| 30 | − pr_info("Index : %0x\n", read_c0_index()); | |
| 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 | − } | |
| 29 | + dump_tlb_regs(); | |
| 42 | 30 | pr_info("\n"); |
| 43 | 31 | dump_tlb_all(); |
| 44 | 32 | pr_info("\n"); |
| @@ -370,11 +370,6 @@ void show_registers(struct pt_regs *regs) · 369 unmodified lines | ||
| 370 | 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 | 373 | static DEFINE_RAW_SPINLOCK(die_lock); |
| 379 | 374 | |
| 380 | 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 | 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 | 383 | SIGSEGV) == NOTIFY_STOP) |
| 389 | 384 | sig = 0; |
| 390 | 385 | |
| @@ -470,7 +465,7 @@ asmlinkage void do_be(struct pt_regs *regs) · 79 unmodified lines | ||
| 470 | 465 | printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", |
| 471 | 466 | data ? "Data" : "Instruction", |
| 472 | 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 | 469 | SIGBUS) == NOTIFY_STOP) |
| 475 | 470 | goto out; |
| 476 | 471 | |
| @@ -826,7 +821,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) · 349 unmodified lines | ||
| 826 | 821 | int sig; |
| 827 | 822 | |
| 828 | 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 | 825 | SIGFPE) == NOTIFY_STOP) |
| 831 | 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 | 877 | char b[40]; |
| 883 | 878 | |
| 884 | 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 | 882 | return; |
| 887 | 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 | 886 | SIGTRAP) == NOTIFY_STOP) |
| 891 | 887 | return; |
| 892 | 888 | |
| @@ -948,6 +944,7 @@ asmlinkage void do_bp(struct pt_regs *regs) · 55 unmodified lines | ||
| 948 | 944 | set_fs(KERNEL_DS); |
| 949 | 945 | |
| 950 | 946 | prev_state = exception_enter(); |
| 947 | + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | |
| 951 | 948 | if (get_isa16_mode(regs->cp0_epc)) { |
| 952 | 949 | u16 instr[2]; |
| 953 | 950 | |
| @@ -987,15 +984,27 @@ asmlinkage void do_bp(struct pt_regs *regs) · 33 unmodified lines | ||
| 987 | 984 | * pertain to them. |
| 988 | 985 | */ |
| 989 | 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 | 999 | case BRK_KPROBE_BP: |
| 991 | 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 | 1002 | goto out; |
| 994 | 1003 | else |
| 995 | 1004 | break; |
| 996 | 1005 | case BRK_KPROBE_SSTEPBP: |
| 997 | 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 | 1008 | goto out; |
| 1000 | 1009 | else |
| 1001 | 1010 | break; |
| @@ -1028,6 +1037,7 @@ asmlinkage void do_tr(struct pt_regs *regs) · 26 unmodified lines | ||
| 1028 | 1037 | set_fs(get_ds()); |
| 1029 | 1038 | |
| 1030 | 1039 | prev_state = exception_enter(); |
| 1040 | + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | |
| 1031 | 1041 | if (get_isa16_mode(regs->cp0_epc)) { |
| 1032 | 1042 | if (__get_user(instr[0], (u16 __user *)(epc + 0)) || |
| 1033 | 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 | 1104 | no_r2_instr: |
| 1095 | 1105 | |
| 1096 | 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 | 1110 | SIGILL) == NOTIFY_STOP) |
| 1100 | 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 | 1455 | enum ctx_state prev_state; |
| 1445 | 1456 | |
| 1446 | 1457 | prev_state = exception_enter(); |
| 1458 | + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | |
| 1447 | 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 | 1461 | goto out; |
| 1450 | 1462 | |
| 1451 | 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 | 1536 | asmlinkage void do_mcheck(struct pt_regs *regs) |
| 1525 | 1537 | { |
| 1526 | − const int field = 2 * sizeof(unsigned long); | |
| 1527 | 1538 | int multi_match = regs->cp0_status & ST0_TS; |
| 1528 | 1539 | enum ctx_state prev_state; |
| 1529 | 1540 | mm_segment_t old_fs = get_fs(); |
| @@ -1532,19 +1543,8 @@ asmlinkage void do_mcheck(struct pt_regs *regs) · 2 unmodified lines | ||
| 1532 | 1543 | show_regs(regs); |
| 1533 | 1544 | |
| 1534 | 1545 | if (multi_match) { |
| 1535 | − pr_err("Index : %0x\n", read_c0_index()); | |
| 1536 | − pr_err("Pagemask: %0x\n", read_c0_pagemask()); | |
| 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"); | |
| 1546 | + dump_tlb_regs(); | |
| 1547 | + pr_info("\n"); | |
| 1548 | 1548 | dump_tlb_all(); |
| 1549 | 1549 | } |
| 1550 | 1550 | |
| @@ -1651,6 +1651,7 @@ static inline void parity_protection_init(void) · 100 unmodified lines | ||
| 1651 | 1651 | case CPU_PROAPTIV: |
| 1652 | 1652 | case CPU_P5600: |
| 1653 | 1653 | case CPU_QEMU_GENERIC: |
| 1654 | + case CPU_I6400: | |
| 1654 | 1655 | { |
| 1655 | 1656 | #define ERRCTL_PE 0x80000000 |
| 1656 | 1657 | #define ERRCTL_L2P 0x00800000 |
| @@ -891,6 +891,9 @@ static void emulate_load_store_insn(struct pt_regs *regs, · 890 unmodified lines | ||
| 891 | 891 | #ifdef CONFIG_EVA |
| 892 | 892 | mm_segment_t seg; |
| 893 | 893 | #endif |
| 894 | + union fpureg *fpr; | |
| 895 | + enum msa_2b_fmt df; | |
| 896 | + unsigned int wd; | |
| 894 | 897 | origpc = (unsigned long)pc; |
| 895 | 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 | 1205 | break; |
| 1203 | 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 | 1277 | #ifndef CONFIG_CPU_MIPSR6 |
| 1206 | 1278 | /* |
| 1207 | 1279 | * COP2 is available to implementor for application specific use. |
| @@ -2240,5 +2312,5 @@ static int __init debugfs_unaligned(void) · 1032 unmodified lines | ||
| 2240 | 2312 | return -ENOMEM; |
| 2241 | 2313 | return 0; |
| 2242 | 2314 | } |
| 2243 | −__initcall(debugfs_unaligned); | |
| 2315 | +arch_initcall(debugfs_unaligned); | |
| 2244 | 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 | 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 | 821 | struct vpe *v; |
| 821 | 822 | Elf_Ehdr *hdr; |
| 822 | 823 | int ret = 0; |
| @@ -827,7 +828,7 @@ static int vpe_release(struct inode *inode, struct file *filp) · 4 unmodified lines | ||
| 827 | 828 | |
| 828 | 829 | hdr = (Elf_Ehdr *) v->pbuffer; |
| 829 | 830 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) { |
| 830 | − if ((vpe_elfload(v) >= 0) && vpe_run) { | |
| 831 | + if (vpe_elfload(v) >= 0) { | |
| 831 | 832 | vpe_run(v); |
| 832 | 833 | } else { |
| 833 | 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 | 851 | v->plen = 0; |
| 851 | 852 | |
| 852 | 853 | return ret; |
| 854 | +#else | |
| 855 | + pr_warn("VPE loader: ELF load failed.\n"); | |
| 856 | + return -ENOEXEC; | |
| 857 | +#endif | |
| 853 | 858 | } |
| 854 | 859 | |
| 855 | 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 | 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 | 13 | #include <asm/pgtable.h> |
| 14 | 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 | 43 | static inline const char *msk2str(unsigned int mask) |
| 17 | 44 | { |
| 18 | 45 | switch (mask) { |
| @@ -87,7 +114,7 @@ static void dump_tlb(int first, int last) · 68 unmodified lines | ||
| 87 | 114 | * leave only a single G bit set after a machine check exception |
| 88 | 115 | * due to duplicate TLB entry. |
| 89 | 116 | */ |
| 90 | − if (!((entrylo0 | entrylo1) & MIPS_ENTRYLO_G) && | |
| 117 | + if (!((entrylo0 | entrylo1) & ENTRYLO_G) && | |
| 91 | 118 | (entryhi & 0xff) != asid) |
| 92 | 119 | continue; |
| 93 | 120 | |
| @@ -96,8 +123,8 @@ static void dump_tlb(int first, int last) · 2 unmodified lines | ||
| 96 | 123 | */ |
| 97 | 124 | printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); |
| 98 | 125 | |
| 99 | − c0 = (entrylo0 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; | |
| 100 | − c1 = (entrylo1 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; | |
| 126 | + c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; | |
| 127 | + c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; | |
| 101 | 128 | |
| 102 | 129 | printk("va=%0*lx asid=%02lx\n", |
| 103 | 130 | vwidth, (entryhi & ~0x1fffUL), |
| @@ -114,9 +141,9 @@ static void dump_tlb(int first, int last) · 10 unmodified lines | ||
| 114 | 141 | (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); |
| 115 | 142 | printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", |
| 116 | 143 | pwidth, pa, c0, |
| 117 | − (entrylo0 & MIPS_ENTRYLO_D) ? 1 : 0, | |
| 118 | − (entrylo0 & MIPS_ENTRYLO_V) ? 1 : 0, | |
| 119 | − (entrylo0 & MIPS_ENTRYLO_G) ? 1 : 0); | |
| 144 | + (entrylo0 & ENTRYLO_D) ? 1 : 0, | |
| 145 | + (entrylo0 & ENTRYLO_V) ? 1 : 0, | |
| 146 | + (entrylo0 & ENTRYLO_G) ? 1 : 0); | |
| 120 | 147 | /* RI/XI are in awkward places, so mask them off separately */ |
| 121 | 148 | pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); |
| 122 | 149 | if (xpa) |
| @@ -128,9 +155,9 @@ static void dump_tlb(int first, int last) · 5 unmodified lines | ||
| 128 | 155 | (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); |
| 129 | 156 | printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", |
| 130 | 157 | pwidth, pa, c1, |
| 131 | − (entrylo1 & MIPS_ENTRYLO_D) ? 1 : 0, | |
| 132 | − (entrylo1 & MIPS_ENTRYLO_V) ? 1 : 0, | |
| 133 | − (entrylo1 & MIPS_ENTRYLO_G) ? 1 : 0); | |
| 158 | + (entrylo1 & ENTRYLO_D) ? 1 : 0, | |
| 159 | + (entrylo1 & ENTRYLO_V) ? 1 : 0, | |
| 160 | + (entrylo1 & ENTRYLO_G) ? 1 : 0); | |
| 134 | 161 | } |
| 135 | 162 | printk("\n"); |
| 136 | 163 | |
| @@ -14,6 +14,17 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <asm/pgtable.h> |
| 15 | 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 | 28 | static void dump_tlb(int first, int last) |
| 18 | 29 | { |
| 19 | 30 | int i; |
| @@ -126,26 +126,34 @@ static irqreturn_t ls1x_clockevent_isr(int irq, void *devid) · 125 unmodified lines | ||
| 126 | 126 | return IRQ_HANDLED; |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | −static void ls1x_clockevent_set_mode(enum clock_event_mode mode, | |
| 130 | − struct clock_event_device *cd) | |
| 129 | +static int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) | |
| 131 | 130 | { |
| 132 | 131 | raw_spin_lock(&ls1x_timer_lock); |
| 133 | − switch (mode) { | |
| 134 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 135 | − ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); | |
| 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 | − } | |
| 132 | + ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); | |
| 133 | + ls1x_pwmtimer_restart(); | |
| 134 | + __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); | |
| 148 | 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 | 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 | 170 | static struct clock_event_device ls1x_clockevent = { |
| 163 | − .name = "ls1x-pwmtimer", | |
| 164 | − .features = CLOCK_EVT_FEAT_PERIODIC, | |
| 165 | − .rating = 300, | |
| 166 | − .irq = LS1X_TIMER_IRQ, | |
| 167 | − .set_next_event = ls1x_clockevent_set_next, | |
| 168 | − .set_mode = ls1x_clockevent_set_mode, | |
| 171 | + .name = "ls1x-pwmtimer", | |
| 172 | + .features = CLOCK_EVT_FEAT_PERIODIC, | |
| 173 | + .rating = 300, | |
| 174 | + .irq = LS1X_TIMER_IRQ, | |
| 175 | + .set_next_event = ls1x_clockevent_set_next, | |
| 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 | 182 | static struct irqaction ls1x_pwmtimer_irqaction = { |
| @@ -51,40 +51,36 @@ void enable_mfgpt0_counter(void) · 50 unmodified lines | ||
| 51 | 51 | } |
| 52 | 52 | EXPORT_SYMBOL(enable_mfgpt0_counter); |
| 53 | 53 | |
| 54 | −static void init_mfgpt_timer(enum clock_event_mode mode, | |
| 55 | − struct clock_event_device *evt) | |
| 54 | +static int mfgpt_timer_set_periodic(struct clock_event_device *evt) | |
| 56 | 55 | { |
| 57 | 56 | raw_spin_lock(&mfgpt_lock); |
| 58 | 57 | |
| 59 | − switch (mode) { | |
| 60 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 61 | − outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */ | |
| 62 | − outw(0, MFGPT0_CNT); /* set counter to 0 */ | |
| 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 | − } | |
| 58 | + outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */ | |
| 59 | + outw(0, MFGPT0_CNT); /* set counter to 0 */ | |
| 60 | + enable_mfgpt0_counter(); | |
| 61 | + | |
| 81 | 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 | 77 | static struct clock_event_device mfgpt_clockevent = { |
| 85 | 78 | .name = "mfgpt", |
| 86 | 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 | 84 | .irq = CS5536_MFGPT_INTR, |
| 89 | 85 | }; |
| 90 | 86 | |
| @@ -78,55 +78,77 @@ static void hpet_enable_legacy_int(void) · 77 unmodified lines | ||
| 78 | 78 | /* Do nothing on Loongson-3 */ |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | −static void hpet_set_mode(enum clock_event_mode mode, | |
| 82 | − struct clock_event_device *evt) | |
| 81 | +static int hpet_set_state_periodic(struct clock_event_device *evt) | |
| 83 | 82 | { |
| 84 | − int cfg = 0; | |
| 83 | + int cfg; | |
| 85 | 84 | |
| 86 | 85 | spin_lock(&hpet_lock); |
| 87 | − switch (mode) { | |
| 88 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 89 | − pr_info("set clock event to periodic mode!\n"); | |
| 90 | − /* stop counter */ | |
| 91 | − hpet_stop_counter(); | |
| 92 | − | |
| 93 | − /* enables the timer0 to generate a periodic interrupt */ | |
| 94 | − cfg = hpet_read(HPET_T0_CFG); | |
| 95 | − cfg &= ~HPET_TN_LEVEL; | |
| 96 | − cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | | |
| 97 | − HPET_TN_SETVAL | HPET_TN_32BIT; | |
| 98 | − hpet_write(HPET_T0_CFG, cfg); | |
| 99 | − | |
| 100 | − /* set the comparator */ | |
| 101 | − hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); | |
| 102 | − udelay(1); | |
| 103 | − hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); | |
| 104 | − | |
| 105 | − /* start counter */ | |
| 106 | − hpet_start_counter(); | |
| 107 | − break; | |
| 108 | − case CLOCK_EVT_MODE_SHUTDOWN: | |
| 109 | − case CLOCK_EVT_MODE_UNUSED: | |
| 110 | − cfg = hpet_read(HPET_T0_CFG); | |
| 111 | − cfg &= ~HPET_TN_ENABLE; | |
| 112 | − hpet_write(HPET_T0_CFG, cfg); | |
| 113 | − break; | |
| 114 | − case CLOCK_EVT_MODE_ONESHOT: | |
| 115 | − pr_info("set clock event to one shot mode!\n"); | |
| 116 | − cfg = hpet_read(HPET_T0_CFG); | |
| 117 | − /* set timer0 type | |
| 118 | − * 1 : periodic interrupt | |
| 119 | − * 0 : non-periodic(oneshot) interrupt | |
| 120 | − */ | |
| 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 | − } | |
| 86 | + | |
| 87 | + pr_info("set clock event to periodic mode!\n"); | |
| 88 | + /* stop counter */ | |
| 89 | + hpet_stop_counter(); | |
| 90 | + | |
| 91 | + /* enables the timer0 to generate a periodic interrupt */ | |
| 92 | + cfg = hpet_read(HPET_T0_CFG); | |
| 93 | + cfg &= ~HPET_TN_LEVEL; | |
| 94 | + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | | |
| 95 | + HPET_TN_32BIT; | |
| 96 | + hpet_write(HPET_T0_CFG, cfg); | |
| 97 | + | |
| 98 | + /* set the comparator */ | |
| 99 | + hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); | |
| 100 | + udelay(1); | |
| 101 | + hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); | |
| 102 | + | |
| 103 | + /* start counter */ | |
| 104 | + hpet_start_counter(); | |
| 105 | + | |
| 106 | + spin_unlock(&hpet_lock); | |
| 107 | + return 0; | |
| 108 | +} | |
| 109 | + | |
| 110 | +static int hpet_set_state_shutdown(struct clock_event_device *evt) | |
| 111 | +{ | |
| 112 | + int cfg; | |
| 113 | + | |
| 114 | + spin_lock(&hpet_lock); | |
| 115 | + | |
| 116 | + cfg = hpet_read(HPET_T0_CFG); | |
| 117 | + cfg &= ~HPET_TN_ENABLE; | |
| 118 | + hpet_write(HPET_T0_CFG, cfg); | |
| 119 | + | |
| 129 | 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 | 154 | static int hpet_next_event(unsigned long delta, |
| @@ -206,7 +228,10 @@ void __init setup_hpet_timer(void) · 73 unmodified lines | ||
| 206 | 228 | cd->name = "hpet"; |
| 207 | 229 | cd->rating = 320; |
| 208 | 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 | 235 | cd->set_next_event = hpet_next_event; |
| 211 | 236 | cd->irq = HPET_T0_IRQ; |
| 212 | 237 | cd->cpumask = cpumask_of(cpu); |
| @@ -4,9 +4,9 @@ · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ |
| 6 | 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 | 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 | 10 | dsemul.o |
| 11 | 11 | |
| 12 | 12 | lib-y += ieee754d.o \ |
| @@ -1137,7 +1137,7 @@ emul: · 1136 unmodified lines | ||
| 1137 | 1137 | break; |
| 1138 | 1138 | |
| 1139 | 1139 | case mfhc_op: |
| 1140 | − if (!cpu_has_mips_r2) | |
| 1140 | + if (!cpu_has_mips_r2_r6) | |
| 1141 | 1141 | goto sigill; |
| 1142 | 1142 | |
| 1143 | 1143 | /* copregister rd -> gpr[rt] */ |
| @@ -1148,7 +1148,7 @@ emul: · 4 unmodified lines | ||
| 1148 | 1148 | break; |
| 1149 | 1149 | |
| 1150 | 1150 | case mthc_op: |
| 1151 | − if (!cpu_has_mips_r2) | |
| 1151 | + if (!cpu_has_mips_r2_r6) | |
| 1152 | 1152 | goto sigill; |
| 1153 | 1153 | |
| 1154 | 1154 | /* copregister rd <- gpr[rt] */ |
| @@ -1181,6 +1181,24 @@ emul: · 26 unmodified lines | ||
| 1181 | 1181 | } |
| 1182 | 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 | 1202 | case bc_op: |
| 1185 | 1203 | if (delay_slot(xcp)) |
| 1186 | 1204 | return SIGILL; |
| @@ -1207,7 +1225,7 @@ emul: · 20 unmodified lines | ||
| 1207 | 1225 | case bct_op: |
| 1208 | 1226 | break; |
| 1209 | 1227 | } |
| 1210 | − | |
| 1228 | +branch_common: | |
| 1211 | 1229 | set_delay_slot(xcp); |
| 1212 | 1230 | if (cond) { |
| 1213 | 1231 | /* |
| @@ -1376,6 +1394,14 @@ static const unsigned char cmptab[8] = { · 162 unmodified lines | ||
| 1376 | 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 | 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 | 1743 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
| 1718 | 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 | 1866 | case fabs_op: |
| 1721 | 1867 | handler.u = ieee754sp_abs; |
| 1722 | 1868 | goto scopuop; |
| @@ -1820,7 +1966,7 @@ copcsr: · 97 unmodified lines | ||
| 1820 | 1966 | goto copcsr; |
| 1821 | 1967 | |
| 1822 | 1968 | default: |
| 1823 | − if (MIPSInst_FUNC(ir) >= fcmp_op) { | |
| 1969 | + if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { | |
| 1824 | 1970 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
| 1825 | 1971 | union ieee754sp fs, ft; |
| 1826 | 1972 | |
| @@ -1914,6 +2060,127 @@ copcsr: · 87 unmodified lines | ||
| 1914 | 2060 | return 0; |
| 1915 | 2061 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
| 1916 | 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 | 2184 | case fabs_op: |
| 1918 | 2185 | handler.u = ieee754dp_abs; |
| 1919 | 2186 | goto dcopuop; |
| @@ -1997,7 +2264,7 @@ dcopuop: · 77 unmodified lines | ||
| 1997 | 2264 | goto copcsr; |
| 1998 | 2265 | |
| 1999 | 2266 | default: |
| 2000 | − if (MIPSInst_FUNC(ir) >= fcmp_op) { | |
| 2267 | + if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { | |
| 2001 | 2268 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
| 2002 | 2269 | union ieee754dp fs, ft; |
| 2003 | 2270 | |
| @@ -2021,8 +2288,11 @@ dcopuop: · 17 unmodified lines | ||
| 2021 | 2288 | break; |
| 2022 | 2289 | } |
| 2023 | 2290 | break; |
| 2291 | + } | |
| 2292 | + | |
| 2293 | + case w_fmt: { | |
| 2294 | + union ieee754dp fs; | |
| 2024 | 2295 | |
| 2025 | − case w_fmt: | |
| 2026 | 2296 | switch (MIPSInst_FUNC(ir)) { |
| 2027 | 2297 | case fcvts_op: |
| 2028 | 2298 | /* convert word to single precision real */ |
| @@ -2036,10 +2306,65 @@ dcopuop: · 7 unmodified lines | ||
| 2036 | 2306 | rv.d = ieee754dp_fint(fs.bits); |
| 2037 | 2307 | rfmt = d_fmt; |
| 2038 | 2308 | goto copcsr; |
| 2039 | − default: | |
| 2040 | − return SIGILL; | |
| 2309 | + default: { | |
| 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 | 2370 | case l_fmt: |
| @@ -2060,11 +2385,60 @@ dcopuop: · 14 unmodified lines | ||
| 2060 | 2385 | rv.d = ieee754dp_flong(bits); |
| 2061 | 2386 | rfmt = d_fmt; |
| 2062 | 2387 | goto copcsr; |
| 2063 | − default: | |
| 2064 | − return SIGILL; | |
| 2065 | − } | |
| 2066 | − break; | |
| 2388 | + default: { | |
| 2389 | + /* Emulating the new CMP.condn.fmt R6 instruction */ | |
| 2390 | + int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK; | |
| 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 | 2442 | default: |
| 2069 | 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 | 34 | int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) |
| 35 | 35 | { |
| 36 | − extern asmlinkage void handle_dsemulret(void); | |
| 37 | 36 | struct emuframe __user *fr; |
| 38 | 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 | 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 | 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 | 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 | 123 | /* 5 types of floating point number |
| @@ -65,8 +65,8 @@ static inline int ieee754_class_nan(int xc) · 64 unmodified lines | ||
| 65 | 65 | vc = IEEE754_CLASS_INF; \ |
| 66 | 66 | else if (vm & SP_MBIT(SP_FBITS-1)) \ |
| 67 | 67 | vc = IEEE754_CLASS_SNAN; \ |
| 68 | − else \ | |
| 69 | − vc = IEEE754_CLASS_QNAN; \ | |
| 68 | + else \ | |
| 69 | + vc = IEEE754_CLASS_QNAN; \ | |
| 70 | 70 | } else if (ve == SP_EMIN-1+SP_EBIAS) { \ |
| 71 | 71 | if (vm) { \ |
| 72 | 72 | ve = SP_EMIN; \ |
| @@ -105,8 +105,8 @@ static inline int ieee754_class_nan(int xc) · 32 unmodified lines | ||
| 105 | 105 | if (vm) { \ |
| 106 | 106 | ve = DP_EMIN; \ |
| 107 | 107 | vc = IEEE754_CLASS_DNORM; \ |
| 108 | − } else \ | |
| 109 | − vc = IEEE754_CLASS_ZERO; \ | |
| 108 | + } else \ | |
| 109 | + vc = IEEE754_CLASS_ZERO; \ | |
| 110 | 110 | } else { \ |
| 111 | 111 | ve -= DP_EBIAS; \ |
| 112 | 112 | vm |= DP_HIDDEN_BIT; \ |
| @@ -65,4 +65,4 @@ do { \ · 64 unmodified lines | ||
| 65 | 65 | |
| 66 | 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 | 1276 | case CPU_PROAPTIV: |
| 1277 | 1277 | case CPU_M5150: |
| 1278 | 1278 | case CPU_QEMU_GENERIC: |
| 1279 | + case CPU_I6400: | |
| 1279 | 1280 | if (!(read_c0_config7() & MIPS_CONF7_IAR) && |
| 1280 | 1281 | (c->icache.waysize > PAGE_SIZE)) |
| 1281 | 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 | 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 | 231 | static inline void __dma_sync_virtual(void *addr, size_t size, |
| 198 | 232 | enum dma_data_direction direction) |
| 199 | 233 | { |
| @@ -380,6 +414,7 @@ EXPORT_SYMBOL(dma_cache_sync); · 180 unmodified lines | ||
| 380 | 414 | static struct dma_map_ops mips_default_dma_map_ops = { |
| 381 | 415 | .alloc = mips_dma_alloc_coherent, |
| 382 | 416 | .free = mips_dma_free_coherent, |
| 417 | + .mmap = mips_dma_mmap, | |
| 383 | 418 | .map_page = mips_dma_map_page, |
| 384 | 419 | .unmap_page = mips_dma_unmap_page, |
| 385 | 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 | 58 | #ifdef CONFIG_KPROBES |
| 59 | 59 | /* |
| 60 | − * This is to notify the fault handler of the kprobes. The | |
| 61 | − * exception code is redundant as it is also carried in REGS, | |
| 62 | − * but we pass it anyhow. | |
| 60 | + * This is to notify the fault handler of the kprobes. | |
| 63 | 61 | */ |
| 64 | 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 | 64 | return; |
| 67 | 65 | #endif |
| 68 | 66 | |
| @@ -224,6 +222,7 @@ bad_area_nosemaphore: · 155 unmodified lines | ||
| 224 | 222 | print_vma_addr(" ", regs->regs[31]); |
| 225 | 223 | pr_info("\n"); |
| 226 | 224 | } |
| 225 | + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | |
| 227 | 226 | info.si_signo = SIGSEGV; |
| 228 | 227 | info.si_errno = 0; |
| 229 | 228 | /* info.si_code has been set above */ |
| @@ -282,6 +281,7 @@ do_sigbus: · 52 unmodified lines | ||
| 282 | 281 | field, (unsigned long) regs->cp0_epc, |
| 283 | 282 | field, (unsigned long) regs->regs[31]); |
| 284 | 283 | #endif |
| 284 | + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; | |
| 285 | 285 | tsk->thread.cp0_badvaddr = address; |
| 286 | 286 | info.si_signo = SIGBUS; |
| 287 | 287 | info.si_errno = 0; |
| @@ -37,6 +37,7 @@ · 36 unmodified lines | ||
| 37 | 37 | #include <asm/cpu.h> |
| 38 | 38 | #include <asm/dma.h> |
| 39 | 39 | #include <asm/kmap_types.h> |
| 40 | +#include <asm/maar.h> | |
| 40 | 41 | #include <asm/mmu_context.h> |
| 41 | 42 | #include <asm/sections.h> |
| 42 | 43 | #include <asm/pgtable.h> |
| @@ -333,9 +334,40 @@ static inline void mem_init_free_highmem(void) · 290 unmodified lines | ||
| 333 | 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 | 373 | static void maar_init(void) |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <asm/pgtable.h> |
| 15 | 15 | #include <asm/mmu_context.h> |
| 16 | 16 | #include <asm/r4kcache.h> |
| 17 | +#include <asm/mips-cm.h> | |
| 17 | 18 | |
| 18 | 19 | /* |
| 19 | 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 | 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 | 130 | static inline int __init mips_sc_probe(void) |
| 98 | 131 | { |
| 99 | 132 | struct cpuinfo_mips *c = ¤t_cpu_data; |
| @@ -103,6 +136,15 @@ static inline int __init mips_sc_probe(void) · 3 unmodified lines | ||
| 103 | 136 | /* Mark as not present until probe completed */ |
| 104 | 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 | 148 | /* Ignore anything but MIPSxx processors */ |
| 107 | 149 | if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | |
| 108 | 150 | MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | |
| @@ -36,7 +36,7 @@ extern void build_tlb_refill_handler(void); · 35 unmodified lines | ||
| 36 | 36 | "nop\n\t" \ |
| 37 | 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 | 41 | /* TLB operations. */ |
| 42 | 42 | static void local_flush_tlb_from(int entry) |
| @@ -303,3 +303,10 @@ mips_pci_controller: · 302 unmodified lines | ||
| 303 | 303 | if (!register_vsmp_smp_ops()) |
| 304 | 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 | 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 | 385 | int malta_be_handler(struct pt_regs *regs, int is_fixup) |
| 445 | 386 | { |
| 446 | 387 | /* This duplicates the handling in do_be which seems wrong */ |
| 447 | 388 | int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; |
| 448 | 389 | |
| 449 | − if (mips_cm_present()) { | |
| 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 | − } | |
| 390 | + mips_cm_error_report(); | |
| 501 | 391 | |
| 502 | 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 | 182 | phys_addr_t mips_cdmm_phys_base(void) |
| 208 | 183 | { |
| 209 | 184 | /* This address is "typically unused" */ |
| @@ -87,7 +87,7 @@ struct nlm_pic_irq { · 86 unmodified lines | ||
| 87 | 87 | static void xlp_pic_enable(struct irq_data *d) |
| 88 | 88 | { |
| 89 | 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 | 92 | BUG_ON(!pd); |
| 93 | 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 | 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 | 101 | unsigned long flags; |
| 102 | 102 | |
| 103 | 103 | BUG_ON(!pd); |
| @@ -108,7 +108,7 @@ static void xlp_pic_disable(struct irq_data *d) · 4 unmodified lines | ||
| 108 | 108 | |
| 109 | 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 | 113 | clear_c0_eimr(pd->picirq); |
| 114 | 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 | 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 | 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 | 193 | pic_data->picirq = picirq; |
| 194 | 194 | pic_data->node = nlm_get_node(node); |
| 195 | 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 | 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 | 202 | int xirq; |
| 203 | 203 | |
| 204 | 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 | 206 | if (WARN_ON(!pic_data)) |
| 207 | 207 | return; |
| 208 | 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 | 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 | 88 | clear_c0_eimr(irq); |
| 88 | 89 | ack_c0_eirr(irq); |
| 89 | 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 | 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 | 98 | clear_c0_eimr(irq); |
| 97 | 99 | ack_c0_eirr(irq); |
| 98 | 100 | scheduler_ipi(); |
| @@ -152,7 +152,7 @@ static const u8 sata_phy_config1[] = { · 151 unmodified lines | ||
| 152 | 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 | 156 | static const u8 sata_phy_config2[] = { |
| 157 | 157 | 0xAA, 0x00, 0x4C, 0xC9, 0xC9, 0x07, 0x07, 0x18, |
| 158 | 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 | 91 | return 134; |
| 92 | 92 | case PIC_SATA_IRQ: |
| 93 | 93 | return 143; |
| 94 | + case PIC_NAND_IRQ: | |
| 95 | + return 151; | |
| 94 | 96 | case PIC_SPI_IRQ: |
| 95 | 97 | return 152; |
| 96 | 98 | case PIC_MMC_IRQ: |
| @@ -91,6 +91,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) · 90 unmodified lines | ||
| 91 | 91 | case CPU_INTERAPTIV: |
| 92 | 92 | case CPU_PROAPTIV: |
| 93 | 93 | case CPU_P5600: |
| 94 | + case CPU_I6400: | |
| 94 | 95 | case CPU_M5150: |
| 95 | 96 | case CPU_LOONGSON1: |
| 96 | 97 | case CPU_SB1: |
| @@ -392,6 +392,10 @@ static int __init mipsxx_init(void) · 391 unmodified lines | ||
| 392 | 392 | op_model_mipsxx_ops.cpu_type = "mips/P5600"; |
| 393 | 393 | break; |
| 394 | 394 | |
| 395 | + case CPU_I6400: | |
| 396 | + op_model_mipsxx_ops.cpu_type = "mips/I6400"; | |
| 397 | + break; | |
| 398 | + | |
| 395 | 399 | case CPU_M5150: |
| 396 | 400 | op_model_mipsxx_ops.cpu_type = "mips/M5150"; |
| 397 | 401 | break; |
| @@ -131,7 +131,7 @@ struct xlp_msi_data { · 130 unmodified lines | ||
| 131 | 131 | */ |
| 132 | 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 | 135 | unsigned long flags; |
| 136 | 136 | int vec; |
| 137 | 137 | |
| @@ -148,7 +148,7 @@ static void xlp_msi_enable(struct irq_data *d) · 10 unmodified lines | ||
| 148 | 148 | |
| 149 | 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 | 152 | unsigned long flags; |
| 153 | 153 | int vec; |
| 154 | 154 | |
| @@ -165,7 +165,7 @@ static void xlp_msi_disable(struct irq_data *d) · 10 unmodified lines | ||
| 165 | 165 | |
| 166 | 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 | 169 | int link, vec; |
| 170 | 170 | |
| 171 | 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 | 211 | msixvec = nlm_irq_msixvec(d->irq); |
| 212 | 212 | link = nlm_irq_msixlink(msixvec); |
| 213 | 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 | 216 | /* Ack MSI on bridge */ |
| 217 | 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 | 302 | /* Get MSI data for the link */ |
| 303 | 303 | lirq = PIC_PCIE_LINK_MSI_IRQ(link); |
| 304 | 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 | 306 | msiaddr = MSI_LINK_ADDR(node, link); |
| 307 | 307 | |
| 308 | 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 | 409 | /* Get MSI data for the link */ |
| 410 | 410 | lirq = PIC_PCIE_MSIX_IRQ(link); |
| 411 | 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 | 413 | msixaddr = MSIX_LINK_ADDR(node, link); |
| 414 | 414 | |
| 415 | 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 | 485 | irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); |
| 486 | 486 | for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) { |
| 487 | 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 | 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 | 508 | /* Initialize MSI-X extended irq space for the link */ |
| 509 | 509 | irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); |
| 510 | 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 | 521 | link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; |
| 522 | 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 | 524 | if (cpu_is_xlp9xx()) |
| 525 | 525 | status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) & |
| 526 | 526 | md->msi_enabled_mask; |
| @@ -550,7 +550,7 @@ void nlm_dispatch_msix(int node, int lirq) · 23 unmodified lines | ||
| 550 | 550 | |
| 551 | 551 | link = lirq - PIC_PCIE_MSIX_IRQ_BASE; |
| 552 | 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 | 554 | if (cpu_is_xlp9xx()) |
| 555 | 555 | status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link)); |
| 556 | 556 | else |
| @@ -25,7 +25,6 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <linux/types.h> |
| 26 | 26 | |
| 27 | 27 | #include <asm/addrspace.h> |
| 28 | −#include <asm/debug.h> | |
| 29 | 28 | |
| 30 | 29 | #include <asm/emma/emma2rh.h> |
| 31 | 30 | |
| @@ -40,10 +39,9 @@ · 8 unmodified lines | ||
| 40 | 39 | static int check_args(struct pci_bus *bus, u32 devfn, u32 * bus_num) |
| 41 | 40 | { |
| 42 | 41 | /* check if the bus is top-level */ |
| 43 | − if (bus->parent != NULL) { | |
| 42 | + if (bus->parent != NULL) | |
| 44 | 43 | *bus_num = bus->number; |
| 45 | − db_assert(bus_num != NULL); | |
| 46 | − } else | |
| 44 | + else | |
| 47 | 45 | *bus_num = 0; |
| 48 | 46 | |
| 49 | 47 | if (*bus_num == 0) { |
| @@ -312,8 +312,8 @@ static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc) · 311 unmodified lines | ||
| 312 | 312 | irq_set_chip_data(i, apc); |
| 313 | 313 | } |
| 314 | 314 | |
| 315 | − irq_set_handler_data(apc->irq, apc); | |
| 316 | − irq_set_chained_handler(apc->irq, ar71xx_pci_irq_handler); | |
| 315 | + irq_set_chained_handler_and_data(apc->irq, ar71xx_pci_irq_handler, | |
| 316 | + apc); | |
| 317 | 317 | } |
| 318 | 318 | |
| 319 | 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 | 321 | irq_set_chip_data(i, apc); |
| 322 | 322 | } |
| 323 | 323 | |
| 324 | − irq_set_handler_data(apc->irq, apc); | |
| 325 | − irq_set_chained_handler(apc->irq, ar724x_pci_irq_handler); | |
| 324 | + irq_set_chained_handler_and_data(apc->irq, ar724x_pci_irq_handler, | |
| 325 | + apc); | |
| 326 | 326 | } |
| 327 | 327 | |
| 328 | 328 | static int ar724x_pci_probe(struct platform_device *pdev) |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/of_irq.h> |
| 21 | 21 | #include <linux/of_pci.h> |
| 22 | 22 | |
| 23 | −#include <asm/gpio.h> | |
| 24 | 23 | #include <asm/addrspace.h> |
| 25 | 24 | |
| 26 | 25 | #include <lantiq_soc.h> |
| @@ -129,7 +129,7 @@ static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc, · 128 unmodified lines | ||
| 129 | 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 | 134 | struct rt3883_pci_controller *rpc; |
| 135 | 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 | 147 | while (pending) { |
| 148 | − unsigned bit = __ffs(pending); | |
| 148 | + unsigned irq, bit = __ffs(pending); | |
| 149 | 149 | |
| 150 | 150 | irq = irq_find_mapping(rpc->irq_domain, bit); |
| 151 | 151 | generic_handle_irq(irq); |
| @@ -225,8 +225,7 @@ static int rt3883_pci_irq_init(struct device *dev, · 73 unmodified lines | ||
| 225 | 225 | return -ENODEV; |
| 226 | 226 | } |
| 227 | 227 | |
| 228 | − irq_set_handler_data(irq, rpc); | |
| 229 | − irq_set_chained_handler(irq, rt3883_pci_irq_handler); | |
| 228 | + irq_set_chained_handler_and_data(irq, rt3883_pci_irq_handler, rpc); | |
| 230 | 229 | |
| 231 | 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 | 88 | * Make sure we have IRQ affinity. It may have changed while |
| 89 | 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 | 93 | return; |
| 93 | 94 | #endif |
| 94 | 95 | |
| @@ -36,8 +36,8 @@ struct systick_device { · 35 unmodified lines | ||
| 36 | 36 | int freq_scale; |
| 37 | 37 | }; |
| 38 | 38 | |
| 39 | −static void systick_set_clock_mode(enum clock_event_mode mode, | |
| 40 | − struct clock_event_device *evt); | |
| 39 | +static int systick_set_oneshot(struct clock_event_device *evt); | |
| 40 | +static int systick_shutdown(struct clock_event_device *evt); | |
| 41 | 41 | |
| 42 | 42 | static int systick_next_event(unsigned long delta, |
| 43 | 43 | struct clock_event_device *evt) |
| @@ -73,11 +73,12 @@ static struct systick_device systick = { · 29 unmodified lines | ||
| 73 | 73 | * cevt-r4k uses 300, make sure systick |
| 74 | 74 | * gets used if available |
| 75 | 75 | */ |
| 76 | − .rating = 310, | |
| 77 | − .features = CLOCK_EVT_FEAT_ONESHOT, | |
| 78 | − .set_next_event = systick_next_event, | |
| 79 | − .set_mode = systick_set_clock_mode, | |
| 80 | − .event_handler = systick_event_handler, | |
| 76 | + .rating = 310, | |
| 77 | + .features = CLOCK_EVT_FEAT_ONESHOT, | |
| 78 | + .set_next_event = systick_next_event, | |
| 79 | + .set_state_shutdown = systick_shutdown, | |
| 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 | 88 | .dev_id = &systick.dev, |
| 88 | 89 | }; |
| 89 | 90 | |
| 90 | −static void systick_set_clock_mode(enum clock_event_mode mode, | |
| 91 | − struct clock_event_device *evt) | |
| 91 | +static int systick_shutdown(struct clock_event_device *evt) | |
| 92 | 92 | { |
| 93 | 93 | struct systick_device *sdev; |
| 94 | 94 | |
| 95 | 95 | sdev = container_of(evt, struct systick_device, dev); |
| 96 | 96 | |
| 97 | − switch (mode) { | |
| 98 | − case CLOCK_EVT_MODE_ONESHOT: | |
| 99 | − if (!sdev->irq_requested) | |
| 100 | − setup_irq(systick.dev.irq, &systick_irqaction); | |
| 101 | − sdev->irq_requested = 1; | |
| 102 | − iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, | |
| 103 | − systick.membase + SYSTICK_CONFIG); | |
| 104 | − break; | |
| 105 | − | |
| 106 | − case CLOCK_EVT_MODE_SHUTDOWN: | |
| 107 | − if (sdev->irq_requested) | |
| 108 | − free_irq(systick.dev.irq, &systick_irqaction); | |
| 109 | − sdev->irq_requested = 0; | |
| 110 | − iowrite32(0, systick.membase + SYSTICK_CONFIG); | |
| 111 | − break; | |
| 112 | − | |
| 113 | − default: | |
| 114 | − pr_err("%s: Unhandeled mips clock_mode\n", systick.dev.name); | |
| 115 | − break; | |
| 116 | − } | |
| 97 | + if (sdev->irq_requested) | |
| 98 | + free_irq(systick.dev.irq, &systick_irqaction); | |
| 99 | + sdev->irq_requested = 0; | |
| 100 | + iowrite32(0, systick.membase + SYSTICK_CONFIG); | |
| 101 | + | |
| 102 | + return 0; | |
| 103 | +} | |
| 104 | + | |
| 105 | +static int systick_set_oneshot(struct clock_event_device *evt) | |
| 106 | +{ | |
| 107 | + struct systick_device *sdev; | |
| 108 | + | |
| 109 | + sdev = container_of(evt, struct systick_device, dev); | |
| 110 | + | |
| 111 | + if (!sdev->irq_requested) | |
| 112 | + setup_irq(systick.dev.irq, &systick_irqaction); | |
| 113 | + sdev->irq_requested = 1; | |
| 114 | + iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, | |
| 115 | + systick.membase + SYSTICK_CONFIG); | |
| 116 | + | |
| 117 | + return 0; | |
| 117 | 118 | } |
| 118 | 119 | |
| 119 | 120 | static void __init ralink_systick_init(struct device_node *np) |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <linux/mtd/nand.h> |
| 24 | 24 | #include <linux/mtd/mtd.h> |
| 25 | 25 | #include <linux/mtd/partitions.h> |
| 26 | +#include <linux/gpio.h> | |
| 26 | 27 | #include <linux/gpio_keys.h> |
| 27 | 28 | #include <linux/input.h> |
| 28 | 29 | #include <linux/serial_8250.h> |
| @@ -140,6 +140,11 @@ static int rb532_gpio_direction_output(struct gpio_chip *chip, · 139 unmodified lines | ||
| 140 | 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 | 148 | static struct rb532_gpio_chip rb532_gpio_chip[] = { |
| 144 | 149 | [0] = { |
| 145 | 150 | .chip = { |
| @@ -148,6 +153,7 @@ static struct rb532_gpio_chip rb532_gpio_chip[] = { · 2 unmodified lines | ||
| 148 | 153 | .direction_output = rb532_gpio_direction_output, |
| 149 | 154 | .get = rb532_gpio_get, |
| 150 | 155 | .set = rb532_gpio_set, |
| 156 | + .to_irq = rb532_gpio_to_irq, | |
| 151 | 157 | .base = 0, |
| 152 | 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 | 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 | 67 | unsigned int rt_timer_irq; |
| 74 | 68 | |
| 75 | 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 | 118 | cd->irq = irq; |
| 125 | 119 | cd->cpumask = cpumask_of(cpu); |
| 126 | 120 | cd->set_next_event = rt_next_event; |
| 127 | − cd->set_mode = rt_set_mode; | |
| 128 | 121 | clockevents_register_device(cd); |
| 129 | 122 | } |
| 130 | 123 | |
| @@ -250,4 +250,4 @@ int __init sibyte_bus_watcher(void) · 249 unmodified lines | ||
| 250 | 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 | 14 | #define SNI_COUNTER2_DIV 64 |
| 15 | 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, | |
| 18 | − struct clock_event_device *evt) | |
| 17 | +static int a20r_set_periodic(struct clock_event_device *evt) | |
| 19 | 18 | { |
| 20 | − switch (mode) { | |
| 21 | − case CLOCK_EVT_MODE_PERIODIC: | |
| 22 | − *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; | |
| 23 | − wmb(); | |
| 24 | − *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV; | |
| 25 | − 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(); | |
| 19 | + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; | |
| 20 | + wmb(); | |
| 21 | + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV; | |
| 22 | + wmb(); | |
| 23 | + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8; | |
| 24 | + wmb(); | |
| 35 | 25 | |
| 36 | − break; | |
| 37 | − case CLOCK_EVT_MODE_ONESHOT: | |
| 38 | − case CLOCK_EVT_MODE_UNUSED: | |
| 39 | − case CLOCK_EVT_MODE_SHUTDOWN: | |
| 40 | − break; | |
| 41 | − case CLOCK_EVT_MODE_RESUME: | |
| 42 | − break; | |
| 43 | − } | |
| 26 | + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; | |
| 27 | + wmb(); | |
| 28 | + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV; | |
| 29 | + wmb(); | |
| 30 | + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8; | |
| 31 | + wmb(); | |
| 32 | + return 0; | |
| 44 | 33 | } |
| 45 | 34 | |
| 46 | 35 | static struct clock_event_device a20r_clockevent_device = { |
| 47 | − .name = "a20r-timer", | |
| 48 | − .features = CLOCK_EVT_FEAT_PERIODIC, | |
| 36 | + .name = "a20r-timer", | |
| 37 | + .features = CLOCK_EVT_FEAT_PERIODIC, | |
| 49 | 38 | |
| 50 | 39 | /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ |
| 51 | 40 | |
| 52 | − .rating = 300, | |
| 53 | − .irq = SNI_A20R_IRQ_TIMER, | |
| 54 | − .set_mode = a20r_set_mode, | |
| 41 | + .rating = 300, | |
| 42 | + .irq = SNI_A20R_IRQ_TIMER, | |
| 43 | + .set_state_periodic = a20r_set_periodic, | |
| 55 | 44 | }; |
| 56 | 45 | |
| 57 | 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 | 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 | 120 | #define BOARD_VEC(board) extern struct txx9_board_vec board; |
| 137 | 121 | #include <asm/txx9/boards.h> |
| 138 | 122 | #undef BOARD_VEC |
| @@ -27,12 +27,11 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <linux/io.h> |
| 28 | 28 | #include <linux/interrupt.h> |
| 29 | 29 | #include <linux/irq.h> |
| 30 | +#include <linux/gpio.h> | |
| 30 | 31 | |
| 31 | 32 | #include <linux/libata.h> |
| 32 | 33 | #include <scsi/scsi_host.h> |
| 33 | 34 | |
| 34 | −#include <asm/gpio.h> | |
| 35 | − | |
| 36 | 35 | #define DRV_NAME "pata-rb532-cf" |
| 37 | 36 | #define DRV_VERSION "0.1.0" |
| 38 | 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 | 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 | 347 | * mips_cdmm_setup() - Ensure the CDMM bus is initialised and usable. |
| 336 | 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 | 380 | if (!bus->phys) |
| 369 | 381 | bus->phys = mips_cdmm_cur_base(); |
| 370 | 382 | /* Otherwise, ask platform code for suggestions */ |
| 371 | − if (!bus->phys && mips_cdmm_phys_base) | |
| 383 | + if (!bus->phys) | |
| 372 | 384 | bus->phys = mips_cdmm_phys_base(); |
| 373 | 385 | /* Otherwise, copy what other CPUs have done */ |
| 374 | 386 | if (!bus->phys) |
| @@ -111,6 +111,10 @@ config CLKSRC_LPC32XX · 110 unmodified lines | ||
| 111 | 111 | select CLKSRC_MMIO |
| 112 | 112 | select CLKSRC_OF |
| 113 | 113 | |
| 114 | +config CLKSRC_PISTACHIO | |
| 115 | + bool | |
| 116 | + select CLKSRC_OF | |
| 117 | + | |
| 114 | 118 | config CLKSRC_STM32 |
| 115 | 119 | bool "Clocksource for STM32 SoCs" if !ARCH_STM32 |
| 116 | 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 | 44 | obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o |
| 45 | 45 | obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o |
| 46 | 46 | obj-$(CONFIG_MTK_TIMER) += mtk_timer.o |
| 47 | +obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o | |
| 47 | 48 | |
| 48 | 49 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o |
| 49 | 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 | 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 | 82 | static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, |
| 76 | 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 | 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 | 109 | static struct notifier_block gic_cpu_nb = { |
| 91 | 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 | 117 | static int gic_clockevent_init(void) |
| 95 | 118 | { |
| 119 | + int ret; | |
| 120 | + | |
| 96 | 121 | if (!cpu_has_counter || !gic_frequency) |
| 97 | 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 | 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 | 148 | static void __init __gic_clocksource_init(void) |
| 120 | 149 | { |
| 150 | + int ret; | |
| 151 | + | |
| 121 | 152 | /* Set clocksource mask. */ |
| 122 | 153 | gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); |
| 123 | 154 | |
| 124 | 155 | /* Calculate a somewhat reasonable rating value. */ |
| 125 | 156 | gic_clocksource.rating = 200 + gic_frequency / 10000000; |
| 126 | 157 | |
| 127 | − clocksource_register_hz(&gic_clocksource, gic_frequency); | |
| 128 | − | |
| 129 | − gic_clockevent_init(); | |
| 130 | − | |
| 131 | − /* And finally start the counter */ | |
| 132 | − gic_start_count(); | |
| 158 | + ret = clocksource_register_hz(&gic_clocksource, gic_frequency); | |
| 159 | + if (ret < 0) | |
| 160 | + pr_warn("GIC: Unable to register clocksource\n"); | |
| 133 | 161 | } |
| 134 | 162 | |
| 135 | 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 | 167 | GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); |
| 140 | 168 | |
| 141 | 169 | __gic_clocksource_init(); |
| 170 | + gic_clockevent_init(); | |
| 171 | + | |
| 172 | + /* And finally start the counter */ | |
| 173 | + gic_start_count(); | |
| 142 | 174 | } |
| 143 | 175 | |
| 144 | 176 | static void __init gic_clocksource_of_init(struct device_node *node) |
| 145 | 177 | { |
| 146 | 178 | struct clk *clk; |
| 179 | + int ret; | |
| 147 | 180 | |
| 148 | 181 | if (WARN_ON(!gic_present || !node->parent || |
| 149 | 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 | 185 | clk = of_clk_get(node, 0); |
| 153 | 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 | 193 | gic_frequency = clk_get_rate(clk); |
| 155 | − clk_put(clk); | |
| 156 | 194 | } else if (of_property_read_u32(node, "clock-frequency", |
| 157 | 195 | &gic_frequency)) { |
| 158 | 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 | 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 | 216 | CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", |
| 170 | 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 | 20 | obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o |
| 21 | 21 | obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o |
| 22 | 22 | obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o |
| 23 | +obj-$(CONFIG_ATH79) += gpio-ath79.o | |
| 23 | 24 | obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o |
| 24 | 25 | obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o |
| 25 | 26 | obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o |
| @@ -24,8 +24,6 @@ · 23 unmodified lines | ||
| 24 | 24 | #include <linux/of_device.h> |
| 25 | 25 | |
| 26 | 26 | #include <asm/mach-ath79/ar71xx_regs.h> |
| 27 | −#include <asm/mach-ath79/ath79.h> | |
| 28 | −#include "common.h" | |
| 29 | 27 | |
| 30 | 28 | static void __iomem *ath79_gpio_base; |
| 31 | 29 | static u32 ath79_gpio_count; |
| @@ -139,47 +137,6 @@ static struct gpio_chip ath79_gpio_chip = { · 107 unmodified lines | ||
| 139 | 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 | 140 | static const struct of_device_id ath79_gpio_of_match[] = { |
| 184 | 141 | { .compatible = "qca,ar7100-gpio" }, |
| 185 | 142 | { .compatible = "qca,ar9340-gpio" }, |
| @@ -245,35 +202,3 @@ static struct platform_driver ath79_gpio_driver = { · 59 unmodified lines | ||
| 245 | 202 | }; |
| 246 | 203 | |
| 247 | 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 | 7 | #include <linux/input-polldev.h> |
| 8 | 8 | #include <linux/module.h> |
| 9 | 9 | #include <linux/platform_device.h> |
| 10 | +#include <linux/gpio.h> | |
| 10 | 11 | |
| 11 | 12 | #include <asm/mach-rc32434/gpio.h> |
| 12 | 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 | 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 | 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, | |
| 55 | − unsigned int val) | |
| 54 | +static inline unsigned long gic_read(unsigned int reg) | |
| 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 | 85 | regval = gic_read(reg); |
| 60 | 86 | regval &= ~mask; |
| @@ -65,40 +91,40 @@ static inline void gic_update_bits(unsigned int reg, unsigned int mask, · 4 unmodified lines | ||
| 65 | 91 | static inline void gic_reset_mask(unsigned int intr) |
| 66 | 92 | { |
| 67 | 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 | 97 | static inline void gic_set_mask(unsigned int intr) |
| 72 | 98 | { |
| 73 | 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 | 103 | static inline void gic_set_polarity(unsigned int intr, unsigned int pol) |
| 78 | 104 | { |
| 79 | 105 | gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) + |
| 80 | − GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), | |
| 81 | − pol << GIC_INTR_BIT(intr)); | |
| 106 | + GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), | |
| 107 | + (unsigned long)pol << GIC_INTR_BIT(intr)); | |
| 82 | 108 | } |
| 83 | 109 | |
| 84 | 110 | static inline void gic_set_trigger(unsigned int intr, unsigned int trig) |
| 85 | 111 | { |
| 86 | 112 | gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) + |
| 87 | − GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), | |
| 88 | − trig << GIC_INTR_BIT(intr)); | |
| 113 | + GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), | |
| 114 | + (unsigned long)trig << GIC_INTR_BIT(intr)); | |
| 89 | 115 | } |
| 90 | 116 | |
| 91 | 117 | static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual) |
| 92 | 118 | { |
| 93 | 119 | gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr), |
| 94 | − 1 << GIC_INTR_BIT(intr), | |
| 95 | − dual << GIC_INTR_BIT(intr)); | |
| 120 | + 1ul << GIC_INTR_BIT(intr), | |
| 121 | + (unsigned long)dual << GIC_INTR_BIT(intr)); | |
| 96 | 122 | } |
| 97 | 123 | |
| 98 | 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) + | |
| 101 | − GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); | |
| 126 | + gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + | |
| 127 | + GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); | |
| 102 | 128 | } |
| 103 | 129 | |
| 104 | 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 | 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 | 145 | do { |
| 117 | − hi = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); | |
| 118 | − lo = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); | |
| 119 | − hi2 = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); | |
| 146 | + hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); | |
| 147 | + lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); | |
| 148 | + hi2 = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); | |
| 120 | 149 | } while (hi2 != hi); |
| 121 | 150 | |
| 122 | 151 | return (((cycle_t) hi) << 32) + lo; |
| @@ -135,10 +164,14 @@ unsigned int gic_get_count_width(void) · 12 unmodified lines | ||
| 135 | 164 | |
| 136 | 165 | void gic_write_compare(cycle_t cnt) |
| 137 | 166 | { |
| 138 | − gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), | |
| 139 | − (int)(cnt >> 32)); | |
| 140 | − gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), | |
| 141 | − (int)(cnt & 0xffffffff)); | |
| 167 | + if (mips_cm_is64) { | |
| 168 | + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE), cnt); | |
| 169 | + } else { | |
| 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 | 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 | 181 | local_irq_save(flags); |
| 149 | 182 | |
| 150 | 183 | gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); |
| 151 | − gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), | |
| 152 | − (int)(cnt >> 32)); | |
| 153 | − gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), | |
| 154 | − (int)(cnt & 0xffffffff)); | |
| 184 | + | |
| 185 | + if (mips_cm_is64) { | |
| 186 | + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt); | |
| 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 | 194 | local_irq_restore(flags); |
| 157 | 195 | } |
| @@ -160,8 +198,11 @@ cycle_t gic_read_compare(void) · 2 unmodified lines | ||
| 160 | 198 | { |
| 161 | 199 | unsigned int hi, lo; |
| 162 | 200 | |
| 163 | − hi = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); | |
| 164 | − lo = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); | |
| 201 | + if (mips_cm_is64) | |
| 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 | 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 | 237 | if (cpu_has_veic) |
| 197 | 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 | 241 | switch (intr) { |
| 201 | 242 | case GIC_LOCAL_INT_TIMER: |
| 202 | 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 | 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 | 307 | unsigned long *pcpu_mask; |
| 267 | 308 | unsigned long pending_reg, intrmask_reg; |
| 268 | 309 | DECLARE_BITMAP(pending, GIC_MAX_INTRS); |
| @@ -277,8 +318,8 @@ static void gic_handle_shared_int(bool chained) · 8 unmodified lines | ||
| 277 | 318 | for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) { |
| 278 | 319 | pending[i] = gic_read(pending_reg); |
| 279 | 320 | intrmask[i] = gic_read(intrmask_reg); |
| 280 | − pending_reg += 0x4; | |
| 281 | − intrmask_reg += 0x4; | |
| 321 | + pending_reg += gic_reg_step; | |
| 322 | + intrmask_reg += gic_reg_step; | |
| 282 | 323 | } |
| 283 | 324 | |
| 284 | 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 | 466 | unsigned long pending, masked; |
| 426 | 467 | unsigned int intr, virq; |
| 427 | 468 | |
| 428 | − pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); | |
| 429 | − masked = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); | |
| 469 | + pending = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); | |
| 470 | + masked = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); | |
| 430 | 471 | |
| 431 | 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 | 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 | 496 | static void gic_unmask_local_irq(struct irq_data *d) |
| 456 | 497 | { |
| 457 | 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 | 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 | 515 | spin_lock_irqsave(&gic_lock, flags); |
| 475 | 516 | for (i = 0; i < gic_vpes; i++) { |
| 476 | 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 | 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 | 529 | spin_lock_irqsave(&gic_lock, flags); |
| 489 | 530 | for (i = 0; i < gic_vpes; i++) { |
| 490 | 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 | 534 | spin_unlock_irqrestore(&gic_lock, flags); |
| 494 | 535 | } |
| @@ -608,7 +649,7 @@ static void __init gic_basic_init(void) · 113 unmodified lines | ||
| 608 | 649 | for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { |
| 609 | 650 | if (!gic_local_irq_is_routable(j)) |
| 610 | 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 | 695 | switch (intr) { |
| 655 | 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 | 698 | break; |
| 658 | 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 | 702 | break; |
| 661 | 703 | case GIC_LOCAL_INT_TIMER: |
| 662 | 704 | /* CONFIG_MIPS_CMP workaround (see __gic_init) */ |
| 663 | 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 | 708 | break; |
| 666 | 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 | 712 | break; |
| 669 | 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 | 716 | break; |
| 672 | 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 | 720 | break; |
| 675 | 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 | 723 | break; |
| 678 | 724 | default: |
| 679 | 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 | 825 | if (IS_ENABLED(CONFIG_MIPS_CMP) && |
| 780 | 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 | 828 | GIC_VPE_TIMER_MAP)) & |
| 783 | 829 | GIC_MAP_MSK; |
| 784 | 830 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + |
| @@ -41,6 +41,8 @@ · 40 unmodified lines | ||
| 41 | 41 | #include <linux/gpio.h> |
| 42 | 42 | #include <linux/atomic.h> |
| 43 | 43 | |
| 44 | +#include <asm/mach-ar7/ar7.h> | |
| 45 | + | |
| 44 | 46 | MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>"); |
| 45 | 47 | MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); |
| 46 | 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 | 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 | 82 | * Ignore length errors on min size packets. Some |
| 76 | 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 | 94 | * packet to determine if we can remove a non spec |
| 88 | 95 | * preamble and generate a correct packet. |
| 89 | 96 | */ |
| 90 | − int interface = cvmx_helper_get_interface_num(work->ipprt); | |
| 91 | − int index = cvmx_helper_get_interface_index_num(work->ipprt); | |
| 97 | + int interface = cvmx_helper_get_interface_num(port); | |
| 98 | + int index = cvmx_helper_get_interface_index_num(port); | |
| 92 | 99 | union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; |
| 93 | 100 | |
| 94 | 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 | 106 | cvmx_phys_to_ptr(work->packet_ptr.s.addr); |
| 100 | 107 | int i = 0; |
| 101 | 108 | |
| 102 | − while (i < work->len - 1) { | |
| 109 | + while (i < work->word1.len - 1) { | |
| 103 | 110 | if (*ptr != 0x55) |
| 104 | 111 | break; |
| 105 | 112 | ptr++; |
| @@ -109,18 +116,18 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) · 3 unmodified lines | ||
| 109 | 116 | if (*ptr == 0xd5) { |
| 110 | 117 | /* |
| 111 | 118 | printk_ratelimited("Port %d received 0xd5 preamble\n", |
| 112 | − work->ipprt); | |
| 119 | + port); | |
| 113 | 120 | */ |
| 114 | 121 | work->packet_ptr.s.addr += i + 1; |
| 115 | − work->len -= i + 5; | |
| 122 | + work->word1.len -= i + 5; | |
| 116 | 123 | } else if ((*ptr & 0xf) == 0xd) { |
| 117 | 124 | /* |
| 118 | 125 | printk_ratelimited("Port %d received 0x?d preamble\n", |
| 119 | − work->ipprt); | |
| 126 | + port); | |
| 120 | 127 | */ |
| 121 | 128 | work->packet_ptr.s.addr += i; |
| 122 | − work->len -= i + 4; | |
| 123 | − for (i = 0; i < work->len; i++) { | |
| 129 | + work->word1.len -= i + 4; | |
| 130 | + for (i = 0; i < work->word1.len; i++) { | |
| 124 | 131 | *ptr = |
| 125 | 132 | ((*ptr & 0xf0) >> 4) | |
| 126 | 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 | 136 | } else { |
| 130 | 137 | printk_ratelimited("Port %d unknown preamble, packet dropped\n", |
| 131 | − work->ipprt); | |
| 138 | + port); | |
| 132 | 139 | /* |
| 133 | 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 | 146 | } else { |
| 140 | 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 | 149 | cvm_oct_free_work(work); |
| 143 | 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 | 181 | /* Only allow work for our group (and preserve priorities) */ |
| 175 | − old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); | |
| 176 | − cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), | |
| 177 | − (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); | |
| 182 | + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { | |
| 183 | + old_group_mask = cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); | |
| 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 | 193 | if (USE_ASYNC_IOBDMA) { |
| 180 | 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 | 200 | struct sk_buff **pskb = NULL; |
| 187 | 201 | int skb_in_hw; |
| 188 | 202 | cvmx_wqe_t *work; |
| 203 | + int port; | |
| 189 | 204 | |
| 190 | 205 | if (USE_ASYNC_IOBDMA && did_work_request) |
| 191 | 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 | 210 | prefetch(work); |
| 196 | 211 | did_work_request = 0; |
| 197 | 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; | |
| 201 | − wq_int.s.iq_dis = 1 << pow_receive_group; | |
| 202 | − wq_int.s.wq_int = 1 << pow_receive_group; | |
| 203 | − cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); | |
| 221 | + wq_int.u64 = 0; | |
| 222 | + wq_int.s.iq_dis = 1 << pow_receive_group; | |
| 223 | + wq_int.s.wq_int = 1 << pow_receive_group; | |
| 224 | + cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); | |
| 225 | + } | |
| 204 | 226 | break; |
| 205 | 227 | } |
| 206 | 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 | 242 | prefetch(&skb->head); |
| 221 | 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 | 253 | /* Immediately throw away all packets with receive errors */ |
| 226 | 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 | 265 | skb->data = skb->head + work->packet_ptr.s.addr - |
| 238 | 266 | cvmx_ptr_to_phys(skb->head); |
| 239 | 267 | prefetch(skb->data); |
| 240 | − skb->len = work->len; | |
| 268 | + skb->len = work->word1.len; | |
| 241 | 269 | skb_set_tail_pointer(skb, skb->len); |
| 242 | 270 | packet_not_copied = 1; |
| 243 | 271 | } else { |
| @@ -245,7 +273,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 1 unmodified line | ||
| 245 | 273 | * We have to copy the packet. First allocate |
| 246 | 274 | * an skbuff for it. |
| 247 | 275 | */ |
| 248 | − skb = dev_alloc_skb(work->len); | |
| 276 | + skb = dev_alloc_skb(work->word1.len); | |
| 249 | 277 | if (!skb) { |
| 250 | 278 | cvm_oct_free_work(work); |
| 251 | 279 | continue; |
| @@ -268,13 +296,14 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) · 16 unmodified lines | ||
| 268 | 296 | else |
| 269 | 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 | 301 | /* No packet buffers to free */ |
| 273 | 302 | } else { |
| 274 | 303 | int segments = work->word2.s.bufs; |
| 275 | 304 | union cvmx_buf_ptr segment_ptr = |
| 276 | 305 | work->packet_ptr; |
| 277 | − int len = work->len; | |
| 306 | + int len = work->word1.len; | |
| 278 | 307 | |
| 279 | 308 | while (segments--) { |
| 280 | 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 | 340 | packet_not_copied = 0; |
| 312 | 341 | } |
| 313 | − | |
| 314 | − if (likely((work->ipprt < TOTAL_NUMBER_OF_PORTS) && | |
| 315 | − cvm_oct_device[work->ipprt])) { | |
| 316 | − struct net_device *dev = cvm_oct_device[work->ipprt]; | |
| 342 | + if (likely((port < TOTAL_NUMBER_OF_PORTS) && | |
| 343 | + cvm_oct_device[port])) { | |
| 344 | + struct net_device *dev = cvm_oct_device[port]; | |
| 317 | 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 | 361 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 334 | 362 | |
| 335 | 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 | 365 | #ifdef CONFIG_64BIT |
| 338 | 366 | atomic64_add(1, |
| 339 | 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 | 396 | * doesn't exist. |
| 369 | 397 | */ |
| 370 | 398 | printk_ratelimited("Port %d not controlled by Linux, packet dropped\n", |
| 371 | − work->ipprt); | |
| 399 | + port); | |
| 372 | 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 | 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 | 428 | if (USE_ASYNC_IOBDMA) { |
| 395 | 429 | /* Restore the scratch area */ |
| 396 | 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 | 457 | int i; |
| 424 | 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 | 460 | for (i = 0; i < TOTAL_NUMBER_OF_PORTS; i++) { |
| 429 | 461 | if (cvm_oct_device[i]) { |
| @@ -449,15 +481,34 @@ void cvm_oct_rx_initialize(void) · 19 unmodified lines | ||
| 449 | 481 | |
| 450 | 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 | 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); | |
| 457 | − | |
| 458 | − int_pc.u64 = 0; | |
| 459 | − int_pc.s.pc_thr = 5; | |
| 460 | − cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64); | |
| 485 | + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { | |
| 486 | + union cvmx_sso_wq_int_thrx int_thr; | |
| 487 | + union cvmx_pow_wq_int_pc int_pc; | |
| 488 | + | |
| 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 | 513 | /* Schedule NAPI now. This will indirectly enable the interrupt. */ |
| 463 | 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 | 591 | * Fill in some of the work queue fields. We may need to add |
| 592 | 592 | * more if the software at the other end needs them. |
| 593 | 593 | */ |
| 594 | − work->hw_chksum = skb->csum; | |
| 595 | − work->len = skb->len; | |
| 596 | − work->ipprt = priv->port; | |
| 597 | − work->qos = priv->port & 0x7; | |
| 598 | − work->grp = pow_send_group; | |
| 599 | − work->tag_type = CVMX_HELPER_INPUT_TAG_TYPE; | |
| 600 | − work->tag = pow_send_group; /* FIXME */ | |
| 594 | + if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) | |
| 595 | + work->word0.pip.cn38xx.hw_chksum = skb->csum; | |
| 596 | + work->word1.len = skb->len; | |
| 597 | + cvmx_wqe_set_port(work, priv->port); | |
| 598 | + cvmx_wqe_set_qos(work, priv->port & 0x7); | |
| 599 | + cvmx_wqe_set_grp(work, pow_send_group); | |
| 600 | + work->word1.tag_type = CVMX_HELPER_INPUT_TAG_TYPE; | |
| 601 | + work->word1.tag = pow_send_group; /* FIXME */ | |
| 601 | 602 | /* Default to zero. Sets of zero later are commented out */ |
| 602 | 603 | work->word2.u64 = 0; |
| 603 | 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 | 680 | /* Submit the packet to the POW */ |
| 680 | − cvmx_pow_work_submit(work, work->tag, work->tag_type, work->qos, | |
| 681 | − work->grp); | |
| 681 | + cvmx_pow_work_submit(work, work->word1.tag, work->word1.tag_type, | |
| 682 | + cvmx_wqe_get_qos(work), cvmx_wqe_get_grp(work)); | |
| 682 | 683 | priv->stats.tx_packets++; |
| 683 | 684 | priv->stats.tx_bytes += skb->len; |
| 684 | 685 | dev_consume_skb_any(skb); |
| @@ -8,6 +8,10 @@ · 7 unmodified lines | ||
| 8 | 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 | 16 | * cvm_oct_get_buffer_ptr - convert packet data address to pointer |
| 13 | 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 | 33 | static inline int INTERFACE(int ipd_port) |
| 30 | 34 | { |
| 31 | − if (ipd_port < 32) /* Interface 0 or 1 for RGMII,GMII,SPI, etc */ | |
| 32 | − return ipd_port >> 4; | |
| 33 | − else if (ipd_port < 36) /* Interface 2 for NPI */ | |
| 34 | − return 2; | |
| 35 | − else if (ipd_port < 40) /* Interface 3 for loopback */ | |
| 36 | − return 3; | |
| 37 | − else if (ipd_port == 40) /* Non existent interface for POW0 */ | |
| 38 | − return 4; | |
| 35 | + int interface = cvmx_helper_get_interface_num(ipd_port); | |
| 36 | + | |
| 37 | + if (interface >= 0) | |
| 38 | + return interface; | |
| 39 | + else if (ipd_port == CVMX_PIP_NUM_INPUT_PORTS) | |
| 40 | + return 10; | |
| 39 | 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 | 50 | static inline int INDEX(int ipd_port) |
| 49 | 51 | { |
| 50 | − if (ipd_port < 32) | |
| 51 | − return ipd_port & 15; | |
| 52 | − return ipd_port & 3; | |
| 52 | + return cvmx_helper_get_interface_index_num(ipd_port); | |
| 53 | 53 | } |
| @@ -152,7 +152,7 @@ static void cvm_oct_configure_common_hw(void) · 151 unmodified lines | ||
| 152 | 152 | num_packet_buffers); |
| 153 | 153 | if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) |
| 154 | 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 | 157 | #ifdef __LITTLE_ENDIAN |
| 158 | 158 | { |
| @@ -860,7 +860,10 @@ static int cvm_oct_remove(struct platform_device *pdev) · 701 unmodified lines | ||
| 860 | 860 | int port; |
| 861 | 861 | |
| 862 | 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 | 868 | cvmx_ipd_disable(); |
| 866 | 869 | |
| @@ -879,6 +879,11 @@ static const struct tty_operations mips_ejtag_fdc_tty_ops = { · 878 unmodified lines | ||
| 879 | 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 | 887 | static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) |
| 883 | 888 | { |
| 884 | 889 | int ret, nport; |
| @@ -967,9 +972,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) · 82 unmodified lines | ||
| 967 | 972 | wake_up_process(priv->thread); |
| 968 | 973 | |
| 969 | 974 | /* Look for an FDC IRQ */ |
| 970 | − priv->irq = -1; | |
| 971 | − if (get_c0_fdc_int) | |
| 972 | − priv->irq = get_c0_fdc_int(); | |
| 975 | + priv->irq = get_c0_fdc_int(); | |
| 973 | 976 | |
| 974 | 977 | /* Try requesting the IRQ */ |
| 975 | 978 | if (priv->irq >= 0) { |
| @@ -41,12 +41,20 @@ · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | /* Shared Global Counter */ |
| 43 | 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 | 46 | #define GIC_SH_COUNTER_63_32_OFS 0x0014 |
| 45 | 47 | #define GIC_SH_REVISIONID_OFS 0x0020 |
| 46 | 48 | |
| 47 | 49 | /* Convert an interrupt number to a byte offset/bit for multi-word registers */ |
| 48 | −#define GIC_INTR_OFS(intr) (((intr) / 32) * 4) | |
| 49 | −#define GIC_INTR_BIT(intr) ((intr) % 32) | |
| 50 | +#define GIC_INTR_OFS(intr) ({ \ | |
| 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 | 59 | /* Polarity : Reset Value is always 0 */ |
| 52 | 60 | #define GIC_SH_SET_POLARITY_OFS 0x0100 |
| @@ -98,6 +106,8 @@ · 45 unmodified lines | ||
| 98 | 106 | #define GIC_VPE_WD_COUNT0_OFS 0x0094 |
| 99 | 107 | #define GIC_VPE_WD_INITIAL0_OFS 0x0098 |
| 100 | 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 | 111 | #define GIC_VPE_COMPARE_HI_OFS 0x00a4 |
| 102 | 112 | |
| 103 | 113 | #define GIC_VPE_EIC_SHADOW_SET_BASE_OFS 0x0100 |