diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-09 21:10:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-09 21:10:34 -0400 |
commit | 82abb273d838318424644d8f02825db0fbbd400a (patch) | |
tree | e1ea8a92db4ba68f347249986ffe3a25ffbf8219 /arch/mips | |
parent | 9b651cc2277b5e4883012ebab0fea2bcda4cbafa (diff) | |
parent | f8647b506d7116a1a3accd8d618184096e85f50b (diff) |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
- three fixes for 3.15 that didn't make it in time
- limited Octeon 3 support.
- paravirtualization support
- improvment to platform support for Netlogix SOCs.
- add support for powering down the Malta eval board in software
- add many instructions to the in-kernel microassembler.
- add support for the BPF JIT.
- minor cleanups of the BCM47xx code.
- large cleanup of math emu code resulting in significant code size
reduction, better readability of the code and more accurate
emulation.
- improvments to the MIPS CPS code.
- support C3 power status for the R4k count/compare clock device.
- improvments to the GIO support for older SGI workstations.
- increase number of supported CPUs to 256; this can be reached on
certain embedded multithreaded ccNUMA configurations.
- various small cleanups, updates and fixes
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (173 commits)
MIPS: IP22/IP28: Improve GIO support
MIPS: Octeon: Add twsi interrupt initialization for OCTEON 3XXX, 5XXX, 63XX
DEC: Document the R4k MB ASIC mini interrupt controller
DEC: Add self as the maintainer
MIPS: Add microMIPS MSA support.
MIPS: Replace calls to obsolete strict_strto call with kstrto* equivalents.
MIPS: Replace obsolete strict_strto call with kstrto
MIPS: BFP: Simplify code slightly.
MIPS: Call find_vma with the mmap_sem held
MIPS: Fix 'write_msa_##' inline macro.
MIPS: Fix MSA toolchain support detection.
mips: Update the email address of Geert Uytterhoeven
MIPS: Add minimal defconfig for mips_paravirt
MIPS: Enable build for new system 'paravirt'
MIPS: paravirt: Add pci controller for virtio
MIPS: Add code for new system 'paravirt'
MIPS: Add functions for hypervisor call
MIPS: OCTEON: Add OCTEON3 to __get_cpu_type
MIPS: Add function get_ebase_cpunum
MIPS: Add minimal support for OCTEON3 to c-r4k.c
...
Diffstat (limited to 'arch/mips')
248 files changed, 8337 insertions, 7865 deletions
diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild index d2cfe45f332b..dd295335891a 100644 --- a/arch/mips/Kbuild +++ b/arch/mips/Kbuild | |||
@@ -16,7 +16,7 @@ obj- := $(platform-) | |||
16 | 16 | ||
17 | obj-y += kernel/ | 17 | obj-y += kernel/ |
18 | obj-y += mm/ | 18 | obj-y += mm/ |
19 | obj-y += math-emu/ | 19 | obj-y += net/ |
20 | 20 | ||
21 | ifdef CONFIG_KVM | 21 | ifdef CONFIG_KVM |
22 | obj-y += kvm/ | 22 | obj-y += kvm/ |
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 6e239123d6fe..f5e18bf3275e 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms | |||
@@ -18,6 +18,7 @@ platforms += loongson1 | |||
18 | platforms += mti-malta | 18 | platforms += mti-malta |
19 | platforms += mti-sead3 | 19 | platforms += mti-sead3 |
20 | platforms += netlogic | 20 | platforms += netlogic |
21 | platforms += paravirt | ||
21 | platforms += pmcs-msp71xx | 22 | platforms += pmcs-msp71xx |
22 | platforms += pnx833x | 23 | platforms += pnx833x |
23 | platforms += ralink | 24 | platforms += ralink |
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5e0014e864f3..7a469acee33c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -12,6 +12,7 @@ config MIPS | |||
12 | select HAVE_ARCH_KGDB | 12 | select HAVE_ARCH_KGDB |
13 | select HAVE_ARCH_SECCOMP_FILTER | 13 | select HAVE_ARCH_SECCOMP_FILTER |
14 | select HAVE_ARCH_TRACEHOOK | 14 | select HAVE_ARCH_TRACEHOOK |
15 | select HAVE_BPF_JIT if !CPU_MICROMIPS | ||
15 | select ARCH_HAVE_CUSTOM_GPIO_H | 16 | select ARCH_HAVE_CUSTOM_GPIO_H |
16 | select HAVE_FUNCTION_TRACER | 17 | select HAVE_FUNCTION_TRACER |
17 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | 18 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST |
@@ -50,6 +51,8 @@ config MIPS | |||
50 | select CLONE_BACKWARDS | 51 | select CLONE_BACKWARDS |
51 | select HAVE_DEBUG_STACKOVERFLOW | 52 | select HAVE_DEBUG_STACKOVERFLOW |
52 | select HAVE_CC_STACKPROTECTOR | 53 | select HAVE_CC_STACKPROTECTOR |
54 | select CPU_PM if CPU_IDLE | ||
55 | select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST | ||
53 | 56 | ||
54 | menu "Machine selection" | 57 | menu "Machine selection" |
55 | 58 | ||
@@ -83,6 +86,7 @@ config AR7 | |||
83 | select SYS_HAS_EARLY_PRINTK | 86 | select SYS_HAS_EARLY_PRINTK |
84 | select SYS_SUPPORTS_32BIT_KERNEL | 87 | select SYS_SUPPORTS_32BIT_KERNEL |
85 | select SYS_SUPPORTS_LITTLE_ENDIAN | 88 | select SYS_SUPPORTS_LITTLE_ENDIAN |
89 | select SYS_SUPPORTS_MIPS16 | ||
86 | select SYS_SUPPORTS_ZBOOT_UART16550 | 90 | select SYS_SUPPORTS_ZBOOT_UART16550 |
87 | select ARCH_REQUIRE_GPIOLIB | 91 | select ARCH_REQUIRE_GPIOLIB |
88 | select VLYNQ | 92 | select VLYNQ |
@@ -106,6 +110,7 @@ config ATH79 | |||
106 | select SYS_HAS_EARLY_PRINTK | 110 | select SYS_HAS_EARLY_PRINTK |
107 | select SYS_SUPPORTS_32BIT_KERNEL | 111 | select SYS_SUPPORTS_32BIT_KERNEL |
108 | select SYS_SUPPORTS_BIG_ENDIAN | 112 | select SYS_SUPPORTS_BIG_ENDIAN |
113 | select SYS_SUPPORTS_MIPS16 | ||
109 | help | 114 | help |
110 | Support for the Atheros AR71XX/AR724X/AR913X SoCs. | 115 | Support for the Atheros AR71XX/AR724X/AR913X SoCs. |
111 | 116 | ||
@@ -122,6 +127,7 @@ config BCM47XX | |||
122 | select NO_EXCEPT_FILL | 127 | select NO_EXCEPT_FILL |
123 | select SYS_SUPPORTS_32BIT_KERNEL | 128 | select SYS_SUPPORTS_32BIT_KERNEL |
124 | select SYS_SUPPORTS_LITTLE_ENDIAN | 129 | select SYS_SUPPORTS_LITTLE_ENDIAN |
130 | select SYS_SUPPORTS_MIPS16 | ||
125 | select SYS_HAS_EARLY_PRINTK | 131 | select SYS_HAS_EARLY_PRINTK |
126 | select USE_GENERIC_EARLY_PRINTK_8250 | 132 | select USE_GENERIC_EARLY_PRINTK_8250 |
127 | help | 133 | help |
@@ -168,9 +174,9 @@ config MACH_DECSTATION | |||
168 | bool "DECstations" | 174 | bool "DECstations" |
169 | select BOOT_ELF32 | 175 | select BOOT_ELF32 |
170 | select CEVT_DS1287 | 176 | select CEVT_DS1287 |
171 | select CEVT_R4K | 177 | select CEVT_R4K if CPU_R4X00 |
172 | select CSRC_IOASIC | 178 | select CSRC_IOASIC |
173 | select CSRC_R4K | 179 | select CSRC_R4K if CPU_R4X00 |
174 | select CPU_DADDI_WORKAROUNDS if 64BIT | 180 | select CPU_DADDI_WORKAROUNDS if 64BIT |
175 | select CPU_R4000_WORKAROUNDS if 64BIT | 181 | select CPU_R4000_WORKAROUNDS if 64BIT |
176 | select CPU_R4400_WORKAROUNDS if 64BIT | 182 | select CPU_R4400_WORKAROUNDS if 64BIT |
@@ -248,6 +254,7 @@ config LANTIQ | |||
248 | select SYS_HAS_CPU_MIPS32_R2 | 254 | select SYS_HAS_CPU_MIPS32_R2 |
249 | select SYS_SUPPORTS_BIG_ENDIAN | 255 | select SYS_SUPPORTS_BIG_ENDIAN |
250 | select SYS_SUPPORTS_32BIT_KERNEL | 256 | select SYS_SUPPORTS_32BIT_KERNEL |
257 | select SYS_SUPPORTS_MIPS16 | ||
251 | select SYS_SUPPORTS_MULTITHREADING | 258 | select SYS_SUPPORTS_MULTITHREADING |
252 | select SYS_HAS_EARLY_PRINTK | 259 | select SYS_HAS_EARLY_PRINTK |
253 | select ARCH_REQUIRE_GPIOLIB | 260 | select ARCH_REQUIRE_GPIOLIB |
@@ -330,6 +337,7 @@ config MIPS_MALTA | |||
330 | select SYS_SUPPORTS_LITTLE_ENDIAN | 337 | select SYS_SUPPORTS_LITTLE_ENDIAN |
331 | select SYS_SUPPORTS_MIPS_CMP | 338 | select SYS_SUPPORTS_MIPS_CMP |
332 | select SYS_SUPPORTS_MIPS_CPS | 339 | select SYS_SUPPORTS_MIPS_CPS |
340 | select SYS_SUPPORTS_MIPS16 | ||
333 | select SYS_SUPPORTS_MULTITHREADING | 341 | select SYS_SUPPORTS_MULTITHREADING |
334 | select SYS_SUPPORTS_SMARTMIPS | 342 | select SYS_SUPPORTS_SMARTMIPS |
335 | select SYS_SUPPORTS_ZBOOT | 343 | select SYS_SUPPORTS_ZBOOT |
@@ -361,6 +369,7 @@ config MIPS_SEAD3 | |||
361 | select SYS_SUPPORTS_LITTLE_ENDIAN | 369 | select SYS_SUPPORTS_LITTLE_ENDIAN |
362 | select SYS_SUPPORTS_SMARTMIPS | 370 | select SYS_SUPPORTS_SMARTMIPS |
363 | select SYS_SUPPORTS_MICROMIPS | 371 | select SYS_SUPPORTS_MICROMIPS |
372 | select SYS_SUPPORTS_MIPS16 | ||
364 | select USB_EHCI_BIG_ENDIAN_DESC | 373 | select USB_EHCI_BIG_ENDIAN_DESC |
365 | select USB_EHCI_BIG_ENDIAN_MMIO | 374 | select USB_EHCI_BIG_ENDIAN_MMIO |
366 | select USE_OF | 375 | select USE_OF |
@@ -380,6 +389,7 @@ config MACH_VR41XX | |||
380 | select CEVT_R4K | 389 | select CEVT_R4K |
381 | select CSRC_R4K | 390 | select CSRC_R4K |
382 | select SYS_HAS_CPU_VR41XX | 391 | select SYS_HAS_CPU_VR41XX |
392 | select SYS_SUPPORTS_MIPS16 | ||
383 | select ARCH_REQUIRE_GPIOLIB | 393 | select ARCH_REQUIRE_GPIOLIB |
384 | 394 | ||
385 | config NXP_STB220 | 395 | config NXP_STB220 |
@@ -407,6 +417,7 @@ config PMC_MSP | |||
407 | select SYS_HAS_CPU_MIPS32_R2 | 417 | select SYS_HAS_CPU_MIPS32_R2 |
408 | select SYS_SUPPORTS_32BIT_KERNEL | 418 | select SYS_SUPPORTS_32BIT_KERNEL |
409 | select SYS_SUPPORTS_BIG_ENDIAN | 419 | select SYS_SUPPORTS_BIG_ENDIAN |
420 | select SYS_SUPPORTS_MIPS16 | ||
410 | select IRQ_CPU | 421 | select IRQ_CPU |
411 | select SERIAL_8250 | 422 | select SERIAL_8250 |
412 | select SERIAL_8250_CONSOLE | 423 | select SERIAL_8250_CONSOLE |
@@ -430,6 +441,7 @@ config RALINK | |||
430 | select SYS_HAS_CPU_MIPS32_R2 | 441 | select SYS_HAS_CPU_MIPS32_R2 |
431 | select SYS_SUPPORTS_32BIT_KERNEL | 442 | select SYS_SUPPORTS_32BIT_KERNEL |
432 | select SYS_SUPPORTS_LITTLE_ENDIAN | 443 | select SYS_SUPPORTS_LITTLE_ENDIAN |
444 | select SYS_SUPPORTS_MIPS16 | ||
433 | select SYS_HAS_EARLY_PRINTK | 445 | select SYS_HAS_EARLY_PRINTK |
434 | select HAVE_MACH_CLKDEV | 446 | select HAVE_MACH_CLKDEV |
435 | select CLKDEV_LOOKUP | 447 | select CLKDEV_LOOKUP |
@@ -674,7 +686,6 @@ config SNI_RM | |||
674 | select SYS_SUPPORTS_BIG_ENDIAN | 686 | select SYS_SUPPORTS_BIG_ENDIAN |
675 | select SYS_SUPPORTS_HIGHMEM | 687 | select SYS_SUPPORTS_HIGHMEM |
676 | select SYS_SUPPORTS_LITTLE_ENDIAN | 688 | select SYS_SUPPORTS_LITTLE_ENDIAN |
677 | select USE_GENERIC_EARLY_PRINTK_8250 | ||
678 | help | 689 | help |
679 | The SNI RM200/300/400 are MIPS-based machines manufactured by | 690 | The SNI RM200/300/400 are MIPS-based machines manufactured by |
680 | Siemens Nixdorf Informationssysteme (SNI), parent company of Pyramid | 691 | Siemens Nixdorf Informationssysteme (SNI), parent company of Pyramid |
@@ -721,6 +732,11 @@ config CAVIUM_OCTEON_SOC | |||
721 | select ZONE_DMA32 | 732 | select ZONE_DMA32 |
722 | select HOLES_IN_ZONE | 733 | select HOLES_IN_ZONE |
723 | select ARCH_REQUIRE_GPIOLIB | 734 | select ARCH_REQUIRE_GPIOLIB |
735 | select LIBFDT | ||
736 | select USE_OF | ||
737 | select ARCH_SPARSEMEM_ENABLE | ||
738 | select SYS_SUPPORTS_SMP | ||
739 | select NR_CPUS_DEFAULT_16 | ||
724 | help | 740 | help |
725 | This option supports all of the Octeon reference boards from Cavium | 741 | This option supports all of the Octeon reference boards from Cavium |
726 | Networks. It builds a kernel that dynamically determines the Octeon | 742 | Networks. It builds a kernel that dynamically determines the Octeon |
@@ -789,6 +805,25 @@ config NLM_XLP_BOARD | |||
789 | This board is based on Netlogic XLP Processor. | 805 | This board is based on Netlogic XLP Processor. |
790 | Say Y here if you have a XLP based board. | 806 | Say Y here if you have a XLP based board. |
791 | 807 | ||
808 | config MIPS_PARAVIRT | ||
809 | bool "Para-Virtualized guest system" | ||
810 | select CEVT_R4K | ||
811 | select CSRC_R4K | ||
812 | select DMA_COHERENT | ||
813 | select SYS_SUPPORTS_64BIT_KERNEL | ||
814 | select SYS_SUPPORTS_32BIT_KERNEL | ||
815 | select SYS_SUPPORTS_BIG_ENDIAN | ||
816 | select SYS_SUPPORTS_SMP | ||
817 | select NR_CPUS_DEFAULT_4 | ||
818 | select SYS_HAS_EARLY_PRINTK | ||
819 | select SYS_HAS_CPU_MIPS32_R2 | ||
820 | select SYS_HAS_CPU_MIPS64_R2 | ||
821 | select SYS_HAS_CPU_CAVIUM_OCTEON | ||
822 | select HW_HAS_PCI | ||
823 | select SWAP_IO_SPACE | ||
824 | help | ||
825 | This option supports guest running under ???? | ||
826 | |||
792 | endchoice | 827 | endchoice |
793 | 828 | ||
794 | source "arch/mips/alchemy/Kconfig" | 829 | source "arch/mips/alchemy/Kconfig" |
@@ -809,6 +844,7 @@ source "arch/mips/cavium-octeon/Kconfig" | |||
809 | source "arch/mips/loongson/Kconfig" | 844 | source "arch/mips/loongson/Kconfig" |
810 | source "arch/mips/loongson1/Kconfig" | 845 | source "arch/mips/loongson1/Kconfig" |
811 | source "arch/mips/netlogic/Kconfig" | 846 | source "arch/mips/netlogic/Kconfig" |
847 | source "arch/mips/paravirt/Kconfig" | ||
812 | 848 | ||
813 | endmenu | 849 | endmenu |
814 | 850 | ||
@@ -1059,6 +1095,7 @@ config SOC_PNX833X | |||
1059 | select SYS_SUPPORTS_32BIT_KERNEL | 1095 | select SYS_SUPPORTS_32BIT_KERNEL |
1060 | select SYS_SUPPORTS_LITTLE_ENDIAN | 1096 | select SYS_SUPPORTS_LITTLE_ENDIAN |
1061 | select SYS_SUPPORTS_BIG_ENDIAN | 1097 | select SYS_SUPPORTS_BIG_ENDIAN |
1098 | select SYS_SUPPORTS_MIPS16 | ||
1062 | select CPU_MIPSR2_IRQ_VI | 1099 | select CPU_MIPSR2_IRQ_VI |
1063 | 1100 | ||
1064 | config SOC_PNX8335 | 1101 | config SOC_PNX8335 |
@@ -1398,16 +1435,11 @@ config CPU_SB1 | |||
1398 | config CPU_CAVIUM_OCTEON | 1435 | config CPU_CAVIUM_OCTEON |
1399 | bool "Cavium Octeon processor" | 1436 | bool "Cavium Octeon processor" |
1400 | depends on SYS_HAS_CPU_CAVIUM_OCTEON | 1437 | depends on SYS_HAS_CPU_CAVIUM_OCTEON |
1401 | select ARCH_SPARSEMEM_ENABLE | ||
1402 | select CPU_HAS_PREFETCH | 1438 | select CPU_HAS_PREFETCH |
1403 | select CPU_SUPPORTS_64BIT_KERNEL | 1439 | select CPU_SUPPORTS_64BIT_KERNEL |
1404 | select SYS_SUPPORTS_SMP | ||
1405 | select NR_CPUS_DEFAULT_16 | ||
1406 | select WEAK_ORDERING | 1440 | select WEAK_ORDERING |
1407 | select CPU_SUPPORTS_HIGHMEM | 1441 | select CPU_SUPPORTS_HIGHMEM |
1408 | select CPU_SUPPORTS_HUGEPAGES | 1442 | select CPU_SUPPORTS_HUGEPAGES |
1409 | select LIBFDT | ||
1410 | select USE_OF | ||
1411 | select USB_EHCI_BIG_ENDIAN_MMIO | 1443 | select USB_EHCI_BIG_ENDIAN_MMIO |
1412 | select MIPS_L1_CACHE_SHIFT_7 | 1444 | select MIPS_L1_CACHE_SHIFT_7 |
1413 | help | 1445 | help |
@@ -1659,6 +1691,12 @@ config SYS_HAS_CPU_XLR | |||
1659 | config SYS_HAS_CPU_XLP | 1691 | config SYS_HAS_CPU_XLP |
1660 | bool | 1692 | bool |
1661 | 1693 | ||
1694 | config MIPS_MALTA_PM | ||
1695 | depends on MIPS_MALTA | ||
1696 | depends on PCI | ||
1697 | bool | ||
1698 | default y | ||
1699 | |||
1662 | # | 1700 | # |
1663 | # CPU may reorder R->R, R->W, W->R, W->W | 1701 | # CPU may reorder R->R, R->W, W->R, W->W |
1664 | # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC | 1702 | # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC |
@@ -1842,7 +1880,7 @@ config FORCE_MAX_ZONEORDER | |||
1842 | 1880 | ||
1843 | config CEVT_GIC | 1881 | config CEVT_GIC |
1844 | bool "Use GIC global counter for clock events" | 1882 | bool "Use GIC global counter for clock events" |
1845 | depends on IRQ_GIC && !(MIPS_SEAD3 || MIPS_MT_SMTC) | 1883 | depends on IRQ_GIC && !MIPS_SEAD3 |
1846 | help | 1884 | help |
1847 | Use the GIC global counter for the clock events. The R4K clock | 1885 | Use the GIC global counter for the clock events. The R4K clock |
1848 | event driver is always present, so if the platform ends up not | 1886 | event driver is always present, so if the platform ends up not |
@@ -1895,19 +1933,8 @@ config CPU_R4K_CACHE_TLB | |||
1895 | bool | 1933 | bool |
1896 | default y if !(CPU_R3000 || CPU_R8000 || CPU_SB1 || CPU_TX39XX || CPU_CAVIUM_OCTEON) | 1934 | default y if !(CPU_R3000 || CPU_R8000 || CPU_SB1 || CPU_TX39XX || CPU_CAVIUM_OCTEON) |
1897 | 1935 | ||
1898 | choice | ||
1899 | prompt "MIPS MT options" | ||
1900 | |||
1901 | config MIPS_MT_DISABLED | ||
1902 | bool "Disable multithreading support" | ||
1903 | help | ||
1904 | Use this option if your platform does not support the MT ASE | ||
1905 | which is hardware multithreading support. On systems without | ||
1906 | an MT-enabled processor, this will be the only option that is | ||
1907 | available in this menu. | ||
1908 | |||
1909 | config MIPS_MT_SMP | 1936 | config MIPS_MT_SMP |
1910 | bool "Use 1 TC on each available VPE for SMP" | 1937 | bool "MIPS MT SMP support (1 TC on each available VPE)" |
1911 | depends on SYS_SUPPORTS_MULTITHREADING | 1938 | depends on SYS_SUPPORTS_MULTITHREADING |
1912 | select CPU_MIPSR2_IRQ_VI | 1939 | select CPU_MIPSR2_IRQ_VI |
1913 | select CPU_MIPSR2_IRQ_EI | 1940 | select CPU_MIPSR2_IRQ_EI |
@@ -1926,26 +1953,6 @@ config MIPS_MT_SMP | |||
1926 | Intel Hyperthreading feature. For further information go to | 1953 | Intel Hyperthreading feature. For further information go to |
1927 | <http://www.imgtec.com/mips/mips-multithreading.asp>. | 1954 | <http://www.imgtec.com/mips/mips-multithreading.asp>. |
1928 | 1955 | ||
1929 | config MIPS_MT_SMTC | ||
1930 | bool "Use all TCs on all VPEs for SMP (DEPRECATED)" | ||
1931 | depends on CPU_MIPS32_R2 | ||
1932 | depends on SYS_SUPPORTS_MULTITHREADING | ||
1933 | depends on !MIPS_CPS | ||
1934 | select CPU_MIPSR2_IRQ_VI | ||
1935 | select CPU_MIPSR2_IRQ_EI | ||
1936 | select MIPS_MT | ||
1937 | select SMP | ||
1938 | select SMP_UP | ||
1939 | select SYS_SUPPORTS_SMP | ||
1940 | select NR_CPUS_DEFAULT_8 | ||
1941 | help | ||
1942 | This is a kernel model which is known as SMTC. This is | ||
1943 | supported on cores with the MT ASE and presents all TCs | ||
1944 | available on all VPEs to support SMP. For further | ||
1945 | information see <http://www.linux-mips.org/wiki/34K#SMTC>. | ||
1946 | |||
1947 | endchoice | ||
1948 | |||
1949 | config MIPS_MT | 1956 | config MIPS_MT |
1950 | bool | 1957 | bool |
1951 | 1958 | ||
@@ -1967,7 +1974,7 @@ config SYS_SUPPORTS_MULTITHREADING | |||
1967 | config MIPS_MT_FPAFF | 1974 | config MIPS_MT_FPAFF |
1968 | bool "Dynamic FPU affinity for FP-intensive threads" | 1975 | bool "Dynamic FPU affinity for FP-intensive threads" |
1969 | default y | 1976 | default y |
1970 | depends on MIPS_MT_SMP || MIPS_MT_SMTC | 1977 | depends on MIPS_MT_SMP |
1971 | 1978 | ||
1972 | config MIPS_VPE_LOADER | 1979 | config MIPS_VPE_LOADER |
1973 | bool "VPE loader support." | 1980 | bool "VPE loader support." |
@@ -1989,29 +1996,6 @@ config MIPS_VPE_LOADER_MT | |||
1989 | default "y" | 1996 | default "y" |
1990 | depends on MIPS_VPE_LOADER && !MIPS_CMP | 1997 | depends on MIPS_VPE_LOADER && !MIPS_CMP |
1991 | 1998 | ||
1992 | config MIPS_MT_SMTC_IM_BACKSTOP | ||
1993 | bool "Use per-TC register bits as backstop for inhibited IM bits" | ||
1994 | depends on MIPS_MT_SMTC | ||
1995 | default n | ||
1996 | help | ||
1997 | To support multiple TC microthreads acting as "CPUs" within | ||
1998 | a VPE, VPE-wide interrupt mask bits must be specially manipulated | ||
1999 | during interrupt handling. To support legacy drivers and interrupt | ||
2000 | controller management code, SMTC has a "backstop" to track and | ||
2001 | if necessary restore the interrupt mask. This has some performance | ||
2002 | impact on interrupt service overhead. | ||
2003 | |||
2004 | config MIPS_MT_SMTC_IRQAFF | ||
2005 | bool "Support IRQ affinity API" | ||
2006 | depends on MIPS_MT_SMTC | ||
2007 | default n | ||
2008 | help | ||
2009 | Enables SMP IRQ affinity API (/proc/irq/*/smp_affinity, etc.) | ||
2010 | for SMTC Linux kernel. Requires platform support, of which | ||
2011 | an example can be found in the MIPS kernel i8259 and Malta | ||
2012 | platform code. Adds some overhead to interrupt dispatch, and | ||
2013 | should be used only if you know what you are doing. | ||
2014 | |||
2015 | config MIPS_VPE_LOADER_TOM | 1999 | config MIPS_VPE_LOADER_TOM |
2016 | bool "Load VPE program into memory hidden from linux" | 2000 | bool "Load VPE program into memory hidden from linux" |
2017 | depends on MIPS_VPE_LOADER | 2001 | depends on MIPS_VPE_LOADER |
@@ -2039,7 +2023,7 @@ config MIPS_VPE_APSP_API_MT | |||
2039 | 2023 | ||
2040 | config MIPS_CMP | 2024 | config MIPS_CMP |
2041 | bool "MIPS CMP framework support (DEPRECATED)" | 2025 | bool "MIPS CMP framework support (DEPRECATED)" |
2042 | depends on SYS_SUPPORTS_MIPS_CMP && !MIPS_MT_SMTC | 2026 | depends on SYS_SUPPORTS_MIPS_CMP |
2043 | select MIPS_GIC_IPI | 2027 | select MIPS_GIC_IPI |
2044 | select SYNC_R4K | 2028 | select SYNC_R4K |
2045 | select WEAK_ORDERING | 2029 | select WEAK_ORDERING |
@@ -2057,9 +2041,11 @@ config MIPS_CPS | |||
2057 | depends on SYS_SUPPORTS_MIPS_CPS | 2041 | depends on SYS_SUPPORTS_MIPS_CPS |
2058 | select MIPS_CM | 2042 | select MIPS_CM |
2059 | select MIPS_CPC | 2043 | select MIPS_CPC |
2044 | select MIPS_CPS_PM if HOTPLUG_CPU | ||
2060 | select MIPS_GIC_IPI | 2045 | select MIPS_GIC_IPI |
2061 | select SMP | 2046 | select SMP |
2062 | select SYNC_R4K if (CEVT_R4K || CSRC_R4K) | 2047 | select SYNC_R4K if (CEVT_R4K || CSRC_R4K) |
2048 | select SYS_SUPPORTS_HOTPLUG_CPU | ||
2063 | select SYS_SUPPORTS_SMP | 2049 | select SYS_SUPPORTS_SMP |
2064 | select WEAK_ORDERING | 2050 | select WEAK_ORDERING |
2065 | help | 2051 | help |
@@ -2069,6 +2055,9 @@ config MIPS_CPS | |||
2069 | no external assistance. It is safe to enable this when hardware | 2055 | no external assistance. It is safe to enable this when hardware |
2070 | support is unavailable. | 2056 | support is unavailable. |
2071 | 2057 | ||
2058 | config MIPS_CPS_PM | ||
2059 | bool | ||
2060 | |||
2072 | config MIPS_GIC_IPI | 2061 | config MIPS_GIC_IPI |
2073 | bool | 2062 | bool |
2074 | 2063 | ||
@@ -2199,6 +2188,13 @@ config SYS_SUPPORTS_SMARTMIPS | |||
2199 | config SYS_SUPPORTS_MICROMIPS | 2188 | config SYS_SUPPORTS_MICROMIPS |
2200 | bool | 2189 | bool |
2201 | 2190 | ||
2191 | config SYS_SUPPORTS_MIPS16 | ||
2192 | bool | ||
2193 | help | ||
2194 | This option must be set if a kernel might be executed on a MIPS16- | ||
2195 | enabled CPU even if MIPS16 is not actually being used. In other | ||
2196 | words, it makes the kernel MIPS16-tolerant. | ||
2197 | |||
2202 | config CPU_SUPPORTS_MSA | 2198 | config CPU_SUPPORTS_MSA |
2203 | bool | 2199 | bool |
2204 | 2200 | ||
@@ -2239,7 +2235,7 @@ config NODES_SHIFT | |||
2239 | 2235 | ||
2240 | config HW_PERF_EVENTS | 2236 | config HW_PERF_EVENTS |
2241 | bool "Enable hardware performance counter support for perf events" | 2237 | bool "Enable hardware performance counter support for perf events" |
2242 | depends on PERF_EVENTS && !MIPS_MT_SMTC && OPROFILE=n && (CPU_MIPS32 || CPU_MIPS64 || CPU_R10000 || CPU_SB1 || CPU_CAVIUM_OCTEON || CPU_XLP) | 2238 | depends on PERF_EVENTS && OPROFILE=n && (CPU_MIPS32 || CPU_MIPS64 || CPU_R10000 || CPU_SB1 || CPU_CAVIUM_OCTEON || CPU_XLP) |
2243 | default y | 2239 | default y |
2244 | help | 2240 | help |
2245 | Enable hardware performance counter support for perf events. If | 2241 | Enable hardware performance counter support for perf events. If |
@@ -2297,8 +2293,8 @@ config NR_CPUS_DEFAULT_64 | |||
2297 | bool | 2293 | bool |
2298 | 2294 | ||
2299 | config NR_CPUS | 2295 | config NR_CPUS |
2300 | int "Maximum number of CPUs (2-64)" | 2296 | int "Maximum number of CPUs (2-256)" |
2301 | range 2 64 | 2297 | range 2 256 |
2302 | depends on SMP | 2298 | depends on SMP |
2303 | default "4" if NR_CPUS_DEFAULT_4 | 2299 | default "4" if NR_CPUS_DEFAULT_4 |
2304 | default "8" if NR_CPUS_DEFAULT_8 | 2300 | default "8" if NR_CPUS_DEFAULT_8 |
@@ -2671,12 +2667,16 @@ endmenu | |||
2671 | config MIPS_EXTERNAL_TIMER | 2667 | config MIPS_EXTERNAL_TIMER |
2672 | bool | 2668 | bool |
2673 | 2669 | ||
2674 | if CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER | ||
2675 | menu "CPU Power Management" | 2670 | menu "CPU Power Management" |
2671 | |||
2672 | if CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER | ||
2676 | source "drivers/cpufreq/Kconfig" | 2673 | source "drivers/cpufreq/Kconfig" |
2677 | endmenu | ||
2678 | endif | 2674 | endif |
2679 | 2675 | ||
2676 | source "drivers/cpuidle/Kconfig" | ||
2677 | |||
2678 | endmenu | ||
2679 | |||
2680 | source "net/Kconfig" | 2680 | source "net/Kconfig" |
2681 | 2681 | ||
2682 | source "drivers/Kconfig" | 2682 | source "drivers/Kconfig" |
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index 25de29211d76..3a2b775e8458 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug | |||
@@ -79,15 +79,6 @@ config CMDLINE_OVERRIDE | |||
79 | 79 | ||
80 | Normally, you will choose 'N' here. | 80 | Normally, you will choose 'N' here. |
81 | 81 | ||
82 | config SMTC_IDLE_HOOK_DEBUG | ||
83 | bool "Enable additional debug checks before going into CPU idle loop" | ||
84 | depends on DEBUG_KERNEL && MIPS_MT_SMTC | ||
85 | help | ||
86 | This option enables Enable additional debug checks before going into | ||
87 | CPU idle loop. For details on these checks, see | ||
88 | arch/mips/kernel/smtc.c. This debugging option result in significant | ||
89 | overhead so should be disabled in production kernels. | ||
90 | |||
91 | config SB1XXX_CORELIS | 82 | config SB1XXX_CORELIS |
92 | bool "Corelis Debugger" | 83 | bool "Corelis Debugger" |
93 | depends on SIBYTE_SB1xxx_SOC | 84 | depends on SIBYTE_SB1xxx_SOC |
diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 60a359cfa328..a8521de14791 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile | |||
@@ -120,7 +120,7 @@ cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \ | |||
120 | -fno-omit-frame-pointer | 120 | -fno-omit-frame-pointer |
121 | 121 | ||
122 | ifeq ($(CONFIG_CPU_HAS_MSA),y) | 122 | ifeq ($(CONFIG_CPU_HAS_MSA),y) |
123 | toolchain-msa := $(call cc-option-yn,-mhard-float -mfp64 -mmsa) | 123 | toolchain-msa := $(call cc-option-yn,-mhard-float -mfp64 -Wa$(comma)-mmsa) |
124 | cflags-$(toolchain-msa) += -DTOOLCHAIN_SUPPORTS_MSA | 124 | cflags-$(toolchain-msa) += -DTOOLCHAIN_SUPPORTS_MSA |
125 | endif | 125 | endif |
126 | 126 | ||
@@ -251,6 +251,7 @@ OBJCOPYFLAGS += --remove-section=.reginfo | |||
251 | head-y := arch/mips/kernel/head.o | 251 | head-y := arch/mips/kernel/head.o |
252 | 252 | ||
253 | libs-y += arch/mips/lib/ | 253 | libs-y += arch/mips/lib/ |
254 | libs-y += arch/mips/math-emu/ | ||
254 | 255 | ||
255 | # See arch/mips/Kbuild for content of core part of the kernel | 256 | # See arch/mips/Kbuild for content of core part of the kernel |
256 | core-y += arch/mips/ | 257 | core-y += arch/mips/ |
diff --git a/arch/mips/alchemy/board-xxs1500.c b/arch/mips/alchemy/board-xxs1500.c index bd5513650293..3fb814be0e91 100644 --- a/arch/mips/alchemy/board-xxs1500.c +++ b/arch/mips/alchemy/board-xxs1500.c | |||
@@ -49,7 +49,7 @@ void __init prom_init(void) | |||
49 | prom_init_cmdline(); | 49 | prom_init_cmdline(); |
50 | 50 | ||
51 | memsize_str = prom_getenv("memsize"); | 51 | memsize_str = prom_getenv("memsize"); |
52 | if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize)) | 52 | if (!memsize_str || kstrtoul(memsize_str, 0, &memsize)) |
53 | memsize = 0x04000000; | 53 | memsize = 0x04000000; |
54 | 54 | ||
55 | add_memory_region(0, memsize, BOOT_MEM_RAM); | 55 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 566a1743f685..8267e3c97721 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c | |||
@@ -67,6 +67,12 @@ void __init plat_mem_setup(void) | |||
67 | case ALCHEMY_CPU_AU1500: | 67 | case ALCHEMY_CPU_AU1500: |
68 | case ALCHEMY_CPU_AU1100: | 68 | case ALCHEMY_CPU_AU1100: |
69 | coherentio = 0; | 69 | coherentio = 0; |
70 | break; | ||
71 | case ALCHEMY_CPU_AU1200: | ||
72 | /* Au1200 AB USB does not support coherent memory */ | ||
73 | if (0 == (read_c0_prid() & PRID_REV_MASK)) | ||
74 | coherentio = 0; | ||
75 | break; | ||
70 | } | 76 | } |
71 | 77 | ||
72 | board_setup(); /* board specific setup */ | 78 | board_setup(); /* board specific setup */ |
diff --git a/arch/mips/alchemy/common/usb.c b/arch/mips/alchemy/common/usb.c index 2adc7edda49c..d193dbea84a1 100644 --- a/arch/mips/alchemy/common/usb.c +++ b/arch/mips/alchemy/common/usb.c | |||
@@ -355,47 +355,25 @@ static inline void __au1200_udc_control(void __iomem *base, int enable) | |||
355 | } | 355 | } |
356 | } | 356 | } |
357 | 357 | ||
358 | static inline int au1200_coherency_bug(void) | ||
359 | { | ||
360 | #if defined(CONFIG_DMA_COHERENT) | ||
361 | /* Au1200 AB USB does not support coherent memory */ | ||
362 | if (!(read_c0_prid() & PRID_REV_MASK)) { | ||
363 | printk(KERN_INFO "Au1200 USB: this is chip revision AB !!\n"); | ||
364 | printk(KERN_INFO "Au1200 USB: update your board or re-configure" | ||
365 | " the kernel\n"); | ||
366 | return -ENODEV; | ||
367 | } | ||
368 | #endif | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static inline int au1200_usb_control(int block, int enable) | 358 | static inline int au1200_usb_control(int block, int enable) |
373 | { | 359 | { |
374 | void __iomem *base = | 360 | void __iomem *base = |
375 | (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); | 361 | (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); |
376 | int ret = 0; | ||
377 | 362 | ||
378 | switch (block) { | 363 | switch (block) { |
379 | case ALCHEMY_USB_OHCI0: | 364 | case ALCHEMY_USB_OHCI0: |
380 | ret = au1200_coherency_bug(); | ||
381 | if (ret && enable) | ||
382 | goto out; | ||
383 | __au1200_ohci_control(base, enable); | 365 | __au1200_ohci_control(base, enable); |
384 | break; | 366 | break; |
385 | case ALCHEMY_USB_UDC0: | 367 | case ALCHEMY_USB_UDC0: |
386 | __au1200_udc_control(base, enable); | 368 | __au1200_udc_control(base, enable); |
387 | break; | 369 | break; |
388 | case ALCHEMY_USB_EHCI0: | 370 | case ALCHEMY_USB_EHCI0: |
389 | ret = au1200_coherency_bug(); | ||
390 | if (ret && enable) | ||
391 | goto out; | ||
392 | __au1200_ehci_control(base, enable); | 371 | __au1200_ehci_control(base, enable); |
393 | break; | 372 | break; |
394 | default: | 373 | default: |
395 | ret = -ENODEV; | 374 | return -ENODEV; |
396 | } | 375 | } |
397 | out: | 376 | return 0; |
398 | return ret; | ||
399 | } | 377 | } |
400 | 378 | ||
401 | 379 | ||
diff --git a/arch/mips/alchemy/devboards/pm.c b/arch/mips/alchemy/devboards/pm.c index b86bff31d1d3..61e90fe9eab1 100644 --- a/arch/mips/alchemy/devboards/pm.c +++ b/arch/mips/alchemy/devboards/pm.c | |||
@@ -158,7 +158,7 @@ static ssize_t db1x_pmattr_store(struct kobject *kobj, | |||
158 | int tmp; | 158 | int tmp; |
159 | 159 | ||
160 | if (ATTRCMP(timer_timeout)) { | 160 | if (ATTRCMP(timer_timeout)) { |
161 | tmp = strict_strtoul(instr, 0, &l); | 161 | tmp = kstrtoul(instr, 0, &l); |
162 | if (tmp) | 162 | if (tmp) |
163 | return tmp; | 163 | return tmp; |
164 | 164 | ||
@@ -181,7 +181,7 @@ static ssize_t db1x_pmattr_store(struct kobject *kobj, | |||
181 | } | 181 | } |
182 | 182 | ||
183 | } else if (ATTRCMP(wakemsk)) { | 183 | } else if (ATTRCMP(wakemsk)) { |
184 | tmp = strict_strtoul(instr, 0, &l); | 184 | tmp = kstrtoul(instr, 0, &l); |
185 | if (tmp) | 185 | if (tmp) |
186 | return tmp; | 186 | return tmp; |
187 | 187 | ||
diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c index 0af808dfd1ca..1a03a2f43496 100644 --- a/arch/mips/bcm47xx/prom.c +++ b/arch/mips/bcm47xx/prom.c | |||
@@ -69,15 +69,18 @@ static __init void prom_init_mem(void) | |||
69 | * BCM47XX uses 128MB for addressing the ram, if the system contains | 69 | * BCM47XX uses 128MB for addressing the ram, if the system contains |
70 | * less that that amount of ram it remaps the ram more often into the | 70 | * less that that amount of ram it remaps the ram more often into the |
71 | * available space. | 71 | * available space. |
72 | * Accessing memory after 128MB will cause an exception. | ||
73 | * max contains the biggest possible address supported by the platform. | ||
74 | * If the method wants to try something above we assume 128MB ram. | ||
75 | */ | 72 | */ |
76 | off = (unsigned long)prom_init; | 73 | |
77 | max = off | ((128 << 20) - 1); | 74 | /* Physical address, without mapping to any kernel segment */ |
78 | for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { | 75 | off = CPHYSADDR((unsigned long)prom_init); |
79 | if ((off + mem) > max) { | 76 | |
80 | mem = (128 << 20); | 77 | /* Accessing memory after 128 MiB will cause an exception */ |
78 | max = 128 << 20; | ||
79 | |||
80 | for (mem = 1 << 20; mem < max; mem += 1 << 20) { | ||
81 | /* Loop condition may be not enough, off may be over 1 MiB */ | ||
82 | if (off + mem >= max) { | ||
83 | mem = max; | ||
81 | printk(KERN_DEBUG "assume 128MB RAM\n"); | 84 | printk(KERN_DEBUG "assume 128MB RAM\n"); |
82 | break; | 85 | break; |
83 | } | 86 | } |
diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig index 227705d9d5ae..602866657938 100644 --- a/arch/mips/cavium-octeon/Kconfig +++ b/arch/mips/cavium-octeon/Kconfig | |||
@@ -10,6 +10,17 @@ config CAVIUM_CN63XXP1 | |||
10 | non-CN63XXP1 hardware, so it is recommended to select "n" | 10 | non-CN63XXP1 hardware, so it is recommended to select "n" |
11 | unless it is known the workarounds are needed. | 11 | unless it is known the workarounds are needed. |
12 | 12 | ||
13 | config CAVIUM_OCTEON_CVMSEG_SIZE | ||
14 | int "Number of L1 cache lines reserved for CVMSEG memory" | ||
15 | range 0 54 | ||
16 | default 1 | ||
17 | help | ||
18 | CVMSEG LM is a segment that accesses portions of the dcache as a | ||
19 | local memory; the larger CVMSEG is, the smaller the cache is. | ||
20 | This selects the size of CVMSEG LM, which is in cache blocks. The | ||
21 | legally range is from zero to 54 cache blocks (i.e. CVMSEG LM is | ||
22 | between zero and 6192 bytes). | ||
23 | |||
13 | endif # CPU_CAVIUM_OCTEON | 24 | endif # CPU_CAVIUM_OCTEON |
14 | 25 | ||
15 | if CAVIUM_OCTEON_SOC | 26 | if CAVIUM_OCTEON_SOC |
@@ -23,17 +34,6 @@ config CAVIUM_OCTEON_2ND_KERNEL | |||
23 | with this option to be run at the same time as one built without this | 34 | with this option to be run at the same time as one built without this |
24 | option. | 35 | option. |
25 | 36 | ||
26 | config CAVIUM_OCTEON_CVMSEG_SIZE | ||
27 | int "Number of L1 cache lines reserved for CVMSEG memory" | ||
28 | range 0 54 | ||
29 | default 1 | ||
30 | help | ||
31 | CVMSEG LM is a segment that accesses portions of the dcache as a | ||
32 | local memory; the larger CVMSEG is, the smaller the cache is. | ||
33 | This selects the size of CVMSEG LM, which is in cache blocks. The | ||
34 | legally range is from zero to 54 cache blocks (i.e. CVMSEG LM is | ||
35 | between zero and 6192 bytes). | ||
36 | |||
37 | config CAVIUM_OCTEON_LOCK_L2 | 37 | config CAVIUM_OCTEON_LOCK_L2 |
38 | bool "Lock often used kernel code in the L2" | 38 | bool "Lock often used kernel code in the L2" |
39 | default "y" | 39 | default "y" |
@@ -86,7 +86,6 @@ config SWIOTLB | |||
86 | select IOMMU_HELPER | 86 | select IOMMU_HELPER |
87 | select NEED_SG_DMA_LENGTH | 87 | select NEED_SG_DMA_LENGTH |
88 | 88 | ||
89 | |||
90 | config OCTEON_ILM | 89 | config OCTEON_ILM |
91 | tristate "Module to measure interrupt latency using Octeon CIU Timer" | 90 | tristate "Module to measure interrupt latency using Octeon CIU Timer" |
92 | help | 91 | help |
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index 8553ad5c72b6..7e5cf7a5e2f3 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c | |||
@@ -106,6 +106,158 @@ int cvmx_helper_ports_on_interface(int interface) | |||
106 | EXPORT_SYMBOL_GPL(cvmx_helper_ports_on_interface); | 106 | EXPORT_SYMBOL_GPL(cvmx_helper_ports_on_interface); |
107 | 107 | ||
108 | /** | 108 | /** |
109 | * @INTERNAL | ||
110 | * Return interface mode for CN68xx. | ||
111 | */ | ||
112 | static cvmx_helper_interface_mode_t __cvmx_get_mode_cn68xx(int interface) | ||
113 | { | ||
114 | union cvmx_mio_qlmx_cfg qlm_cfg; | ||
115 | switch (interface) { | ||
116 | case 0: | ||
117 | qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(0)); | ||
118 | /* QLM is disabled when QLM SPD is 15. */ | ||
119 | if (qlm_cfg.s.qlm_spd == 15) | ||
120 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
121 | |||
122 | if (qlm_cfg.s.qlm_cfg == 2) | ||
123 | return CVMX_HELPER_INTERFACE_MODE_SGMII; | ||
124 | else if (qlm_cfg.s.qlm_cfg == 3) | ||
125 | return CVMX_HELPER_INTERFACE_MODE_XAUI; | ||
126 | else | ||
127 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
128 | case 2: | ||
129 | case 3: | ||
130 | case 4: | ||
131 | qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(interface)); | ||
132 | /* QLM is disabled when QLM SPD is 15. */ | ||
133 | if (qlm_cfg.s.qlm_spd == 15) | ||
134 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
135 | |||
136 | if (qlm_cfg.s.qlm_cfg == 2) | ||
137 | return CVMX_HELPER_INTERFACE_MODE_SGMII; | ||
138 | else if (qlm_cfg.s.qlm_cfg == 3) | ||
139 | return CVMX_HELPER_INTERFACE_MODE_XAUI; | ||
140 | else | ||
141 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
142 | case 7: | ||
143 | qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(3)); | ||
144 | /* QLM is disabled when QLM SPD is 15. */ | ||
145 | if (qlm_cfg.s.qlm_spd == 15) { | ||
146 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
147 | } else if (qlm_cfg.s.qlm_cfg != 0) { | ||
148 | qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(1)); | ||
149 | if (qlm_cfg.s.qlm_cfg != 0) | ||
150 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
151 | } | ||
152 | return CVMX_HELPER_INTERFACE_MODE_NPI; | ||
153 | case 8: | ||
154 | return CVMX_HELPER_INTERFACE_MODE_LOOP; | ||
155 | default: | ||
156 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * @INTERNAL | ||
162 | * Return interface mode for an Octeon II | ||
163 | */ | ||
164 | static cvmx_helper_interface_mode_t __cvmx_get_mode_octeon2(int interface) | ||
165 | { | ||
166 | union cvmx_gmxx_inf_mode mode; | ||
167 | |||
168 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
169 | return __cvmx_get_mode_cn68xx(interface); | ||
170 | |||
171 | if (interface == 2) | ||
172 | return CVMX_HELPER_INTERFACE_MODE_NPI; | ||
173 | |||
174 | if (interface == 3) | ||
175 | return CVMX_HELPER_INTERFACE_MODE_LOOP; | ||
176 | |||
177 | /* Only present in CN63XX & CN66XX Octeon model */ | ||
178 | if ((OCTEON_IS_MODEL(OCTEON_CN63XX) && | ||
179 | (interface == 4 || interface == 5)) || | ||
180 | (OCTEON_IS_MODEL(OCTEON_CN66XX) && | ||
181 | interface >= 4 && interface <= 7)) { | ||
182 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
183 | } | ||
184 | |||
185 | if (OCTEON_IS_MODEL(OCTEON_CN66XX)) { | ||
186 | union cvmx_mio_qlmx_cfg mio_qlm_cfg; | ||
187 | |||
188 | /* QLM2 is SGMII0 and QLM1 is SGMII1 */ | ||
189 | if (interface == 0) | ||
190 | mio_qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(2)); | ||
191 | else if (interface == 1) | ||
192 | mio_qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(1)); | ||
193 | else | ||
194 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
195 | |||
196 | if (mio_qlm_cfg.s.qlm_spd == 15) | ||
197 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
198 | |||
199 | if (mio_qlm_cfg.s.qlm_cfg == 9) | ||
200 | return CVMX_HELPER_INTERFACE_MODE_SGMII; | ||
201 | else if (mio_qlm_cfg.s.qlm_cfg == 11) | ||
202 | return CVMX_HELPER_INTERFACE_MODE_XAUI; | ||
203 | else | ||
204 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
205 | } else if (OCTEON_IS_MODEL(OCTEON_CN61XX)) { | ||
206 | union cvmx_mio_qlmx_cfg qlm_cfg; | ||
207 | |||
208 | if (interface == 0) { | ||
209 | qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(2)); | ||
210 | if (qlm_cfg.s.qlm_cfg == 2) | ||
211 | return CVMX_HELPER_INTERFACE_MODE_SGMII; | ||
212 | else if (qlm_cfg.s.qlm_cfg == 3) | ||
213 | return CVMX_HELPER_INTERFACE_MODE_XAUI; | ||
214 | else | ||
215 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
216 | } else if (interface == 1) { | ||
217 | qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(0)); | ||
218 | if (qlm_cfg.s.qlm_cfg == 2) | ||
219 | return CVMX_HELPER_INTERFACE_MODE_SGMII; | ||
220 | else if (qlm_cfg.s.qlm_cfg == 3) | ||
221 | return CVMX_HELPER_INTERFACE_MODE_XAUI; | ||
222 | else | ||
223 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
224 | } | ||
225 | } else if (OCTEON_IS_MODEL(OCTEON_CNF71XX)) { | ||
226 | if (interface == 0) { | ||
227 | union cvmx_mio_qlmx_cfg qlm_cfg; | ||
228 | qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(0)); | ||
229 | if (qlm_cfg.s.qlm_cfg == 2) | ||
230 | return CVMX_HELPER_INTERFACE_MODE_SGMII; | ||
231 | } | ||
232 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
233 | } | ||
234 | |||
235 | if (interface == 1 && OCTEON_IS_MODEL(OCTEON_CN63XX)) | ||
236 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
237 | |||
238 | mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); | ||
239 | |||
240 | if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { | ||
241 | switch (mode.cn63xx.mode) { | ||
242 | case 0: | ||
243 | return CVMX_HELPER_INTERFACE_MODE_SGMII; | ||
244 | case 1: | ||
245 | return CVMX_HELPER_INTERFACE_MODE_XAUI; | ||
246 | default: | ||
247 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
248 | } | ||
249 | } else { | ||
250 | if (!mode.s.en) | ||
251 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
252 | |||
253 | if (mode.s.type) | ||
254 | return CVMX_HELPER_INTERFACE_MODE_GMII; | ||
255 | else | ||
256 | return CVMX_HELPER_INTERFACE_MODE_RGMII; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | /** | ||
109 | * Get the operating mode of an interface. Depending on the Octeon | 261 | * Get the operating mode of an interface. Depending on the Octeon |
110 | * chip and configuration, this function returns an enumeration | 262 | * chip and configuration, this function returns an enumeration |
111 | * of the type of packet I/O supported by an interface. | 263 | * of the type of packet I/O supported by an interface. |
@@ -118,6 +270,20 @@ EXPORT_SYMBOL_GPL(cvmx_helper_ports_on_interface); | |||
118 | cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface) | 270 | cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface) |
119 | { | 271 | { |
120 | union cvmx_gmxx_inf_mode mode; | 272 | union cvmx_gmxx_inf_mode mode; |
273 | |||
274 | if (interface < 0 || | ||
275 | interface >= cvmx_helper_get_number_of_interfaces()) | ||
276 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
277 | |||
278 | /* | ||
279 | * Octeon II models | ||
280 | */ | ||
281 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF71XX)) | ||
282 | return __cvmx_get_mode_octeon2(interface); | ||
283 | |||
284 | /* | ||
285 | * Octeon and Octeon Plus models | ||
286 | */ | ||
121 | if (interface == 2) | 287 | if (interface == 2) |
122 | return CVMX_HELPER_INTERFACE_MODE_NPI; | 288 | return CVMX_HELPER_INTERFACE_MODE_NPI; |
123 | 289 | ||
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 3aa5b46b2d40..1b82ac6921e0 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c | |||
@@ -1260,11 +1260,13 @@ static void __init octeon_irq_init_ciu(void) | |||
1260 | for (i = 0; i < 4; i++) | 1260 | for (i = 0; i < 4; i++) |
1261 | octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_MSI0, 0, i + 40); | 1261 | octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_MSI0, 0, i + 40); |
1262 | 1262 | ||
1263 | octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_TWSI, 0, 45); | ||
1263 | octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_RML, 0, 46); | 1264 | octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_RML, 0, 46); |
1264 | for (i = 0; i < 4; i++) | 1265 | for (i = 0; i < 4; i++) |
1265 | octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_TIMER0, 0, i + 52); | 1266 | octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_TIMER0, 0, i + 52); |
1266 | 1267 | ||
1267 | octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB0, 0, 56); | 1268 | octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB0, 0, 56); |
1269 | octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_TWSI2, 0, 59); | ||
1268 | 1270 | ||
1269 | /* CIU_1 */ | 1271 | /* CIU_1 */ |
1270 | for (i = 0; i < 16; i++) | 1272 | for (i = 0; i < 16; i++) |
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index f1bec00d5a85..008e9c8b8eac 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c | |||
@@ -729,17 +729,6 @@ void __init prom_init(void) | |||
729 | octeon_write_lcd("Linux"); | 729 | octeon_write_lcd("Linux"); |
730 | #endif | 730 | #endif |
731 | 731 | ||
732 | #ifdef CONFIG_CAVIUM_GDB | ||
733 | /* | ||
734 | * When debugging the linux kernel, force the cores to enter | ||
735 | * the debug exception handler to break in. | ||
736 | */ | ||
737 | if (octeon_get_boot_debug_flag()) { | ||
738 | cvmx_write_csr(CVMX_CIU_DINT, 1 << cvmx_get_core_num()); | ||
739 | cvmx_read_csr(CVMX_CIU_DINT); | ||
740 | } | ||
741 | #endif | ||
742 | |||
743 | octeon_setup_delays(); | 732 | octeon_setup_delays(); |
744 | 733 | ||
745 | /* | 734 | /* |
@@ -779,12 +768,6 @@ void __init prom_init(void) | |||
779 | MAX_MEMORY = 32ull << 30; | 768 | MAX_MEMORY = 32ull << 30; |
780 | if (*p == '@') | 769 | if (*p == '@') |
781 | RESERVE_LOW_MEM = memparse(p + 1, &p); | 770 | RESERVE_LOW_MEM = memparse(p + 1, &p); |
782 | } else if (strcmp(arg, "ecc_verbose") == 0) { | ||
783 | #ifdef CONFIG_CAVIUM_REPORT_SINGLE_BIT_ECC | ||
784 | __cvmx_interrupt_ecc_report_single_bit_errors = 1; | ||
785 | pr_notice("Reporting of single bit ECC errors is " | ||
786 | "turned on\n"); | ||
787 | #endif | ||
788 | #ifdef CONFIG_KEXEC | 771 | #ifdef CONFIG_KEXEC |
789 | } else if (strncmp(arg, "crashkernel=", 12) == 0) { | 772 | } else if (strncmp(arg, "crashkernel=", 12) == 0) { |
790 | crashk_size = memparse(arg+12, &p); | 773 | crashk_size = memparse(arg+12, &p); |
diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 67a078ffc464..a7b3ae104d8c 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c | |||
@@ -218,15 +218,6 @@ void octeon_prepare_cpus(unsigned int max_cpus) | |||
218 | */ | 218 | */ |
219 | static void octeon_smp_finish(void) | 219 | static void octeon_smp_finish(void) |
220 | { | 220 | { |
221 | #ifdef CONFIG_CAVIUM_GDB | ||
222 | unsigned long tmp; | ||
223 | /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0 | ||
224 | to be not masked by this core so we know the signal is received by | ||
225 | someone */ | ||
226 | asm volatile ("dmfc0 %0, $22\n" | ||
227 | "ori %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp)); | ||
228 | #endif | ||
229 | |||
230 | octeon_user_io_init(); | 221 | octeon_user_io_init(); |
231 | 222 | ||
232 | /* to generate the first CPU timer interrupt */ | 223 | /* to generate the first CPU timer interrupt */ |
@@ -234,21 +225,6 @@ static void octeon_smp_finish(void) | |||
234 | local_irq_enable(); | 225 | local_irq_enable(); |
235 | } | 226 | } |
236 | 227 | ||
237 | /** | ||
238 | * Hook for after all CPUs are online | ||
239 | */ | ||
240 | static void octeon_cpus_done(void) | ||
241 | { | ||
242 | #ifdef CONFIG_CAVIUM_GDB | ||
243 | unsigned long tmp; | ||
244 | /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0 | ||
245 | to be not masked by this core so we know the signal is received by | ||
246 | someone */ | ||
247 | asm volatile ("dmfc0 %0, $22\n" | ||
248 | "ori %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp)); | ||
249 | #endif | ||
250 | } | ||
251 | |||
252 | #ifdef CONFIG_HOTPLUG_CPU | 228 | #ifdef CONFIG_HOTPLUG_CPU |
253 | 229 | ||
254 | /* State of each CPU. */ | 230 | /* State of each CPU. */ |
@@ -405,7 +381,6 @@ struct plat_smp_ops octeon_smp_ops = { | |||
405 | .send_ipi_mask = octeon_send_ipi_mask, | 381 | .send_ipi_mask = octeon_send_ipi_mask, |
406 | .init_secondary = octeon_init_secondary, | 382 | .init_secondary = octeon_init_secondary, |
407 | .smp_finish = octeon_smp_finish, | 383 | .smp_finish = octeon_smp_finish, |
408 | .cpus_done = octeon_cpus_done, | ||
409 | .boot_secondary = octeon_boot_secondary, | 384 | .boot_secondary = octeon_boot_secondary, |
410 | .smp_setup = octeon_smp_setup, | 385 | .smp_setup = octeon_smp_setup, |
411 | .prepare_cpus = octeon_prepare_cpus, | 386 | .prepare_cpus = octeon_prepare_cpus, |
diff --git a/arch/mips/configs/ath79_defconfig b/arch/mips/configs/ath79_defconfig index e3a3836508ec..134879c1310a 100644 --- a/arch/mips/configs/ath79_defconfig +++ b/arch/mips/configs/ath79_defconfig | |||
@@ -46,7 +46,6 @@ CONFIG_MTD=y | |||
46 | CONFIG_MTD_REDBOOT_PARTS=y | 46 | CONFIG_MTD_REDBOOT_PARTS=y |
47 | CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2 | 47 | CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2 |
48 | CONFIG_MTD_CMDLINE_PARTS=y | 48 | CONFIG_MTD_CMDLINE_PARTS=y |
49 | CONFIG_MTD_CHAR=y | ||
50 | CONFIG_MTD_BLOCK=y | 49 | CONFIG_MTD_BLOCK=y |
51 | CONFIG_MTD_CFI=y | 50 | CONFIG_MTD_CFI=y |
52 | CONFIG_MTD_JEDECPROBE=y | 51 | CONFIG_MTD_JEDECPROBE=y |
@@ -54,7 +53,7 @@ CONFIG_MTD_CFI_AMDSTD=y | |||
54 | CONFIG_MTD_COMPLEX_MAPPINGS=y | 53 | CONFIG_MTD_COMPLEX_MAPPINGS=y |
55 | CONFIG_MTD_PHYSMAP=y | 54 | CONFIG_MTD_PHYSMAP=y |
56 | CONFIG_MTD_M25P80=y | 55 | CONFIG_MTD_M25P80=y |
57 | # CONFIG_M25PXX_USE_FAST_READ is not set | 56 | CONFIG_MTD_SPI_NOR=y |
58 | CONFIG_NETDEVICES=y | 57 | CONFIG_NETDEVICES=y |
59 | # CONFIG_NET_PACKET_ENGINE is not set | 58 | # CONFIG_NET_PACKET_ENGINE is not set |
60 | CONFIG_ATH_COMMON=m | 59 | CONFIG_ATH_COMMON=m |
diff --git a/arch/mips/configs/db1xxx_defconfig b/arch/mips/configs/db1xxx_defconfig index c99b6eeda90b..a64b30b96a0d 100644 --- a/arch/mips/configs/db1xxx_defconfig +++ b/arch/mips/configs/db1xxx_defconfig | |||
@@ -113,6 +113,7 @@ CONFIG_MTD_NAND=y | |||
113 | CONFIG_MTD_NAND_ECC_BCH=y | 113 | CONFIG_MTD_NAND_ECC_BCH=y |
114 | CONFIG_MTD_NAND_AU1550=y | 114 | CONFIG_MTD_NAND_AU1550=y |
115 | CONFIG_MTD_NAND_PLATFORM=y | 115 | CONFIG_MTD_NAND_PLATFORM=y |
116 | CONFIG_MTD_SPI_NOR=y | ||
116 | CONFIG_EEPROM_AT24=y | 117 | CONFIG_EEPROM_AT24=y |
117 | CONFIG_EEPROM_AT25=y | 118 | CONFIG_EEPROM_AT25=y |
118 | CONFIG_SCSI_TGT=y | 119 | CONFIG_SCSI_TGT=y |
diff --git a/arch/mips/configs/maltasmtc_defconfig b/arch/mips/configs/maltasmtc_defconfig deleted file mode 100644 index eb316447588c..000000000000 --- a/arch/mips/configs/maltasmtc_defconfig +++ /dev/null | |||
@@ -1,196 +0,0 @@ | |||
1 | CONFIG_MIPS_MALTA=y | ||
2 | CONFIG_CPU_LITTLE_ENDIAN=y | ||
3 | CONFIG_CPU_MIPS32_R2=y | ||
4 | CONFIG_PAGE_SIZE_16KB=y | ||
5 | CONFIG_MIPS_MT_SMTC=y | ||
6 | # CONFIG_MIPS_MT_FPAFF is not set | ||
7 | CONFIG_NR_CPUS=9 | ||
8 | CONFIG_HZ_48=y | ||
9 | CONFIG_LOCALVERSION="smtc" | ||
10 | CONFIG_SYSVIPC=y | ||
11 | CONFIG_POSIX_MQUEUE=y | ||
12 | CONFIG_AUDIT=y | ||
13 | CONFIG_IKCONFIG=y | ||
14 | CONFIG_IKCONFIG_PROC=y | ||
15 | CONFIG_LOG_BUF_SHIFT=15 | ||
16 | CONFIG_SYSCTL_SYSCALL=y | ||
17 | CONFIG_EMBEDDED=y | ||
18 | CONFIG_SLAB=y | ||
19 | CONFIG_MODULES=y | ||
20 | CONFIG_MODULE_UNLOAD=y | ||
21 | CONFIG_MODVERSIONS=y | ||
22 | CONFIG_MODULE_SRCVERSION_ALL=y | ||
23 | # CONFIG_BLK_DEV_BSG is not set | ||
24 | CONFIG_PCI=y | ||
25 | # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set | ||
26 | CONFIG_NET=y | ||
27 | CONFIG_PACKET=y | ||
28 | CONFIG_UNIX=y | ||
29 | CONFIG_XFRM_USER=m | ||
30 | CONFIG_NET_KEY=y | ||
31 | CONFIG_INET=y | ||
32 | CONFIG_IP_MULTICAST=y | ||
33 | CONFIG_IP_ADVANCED_ROUTER=y | ||
34 | CONFIG_IP_MULTIPLE_TABLES=y | ||
35 | CONFIG_IP_ROUTE_MULTIPATH=y | ||
36 | CONFIG_IP_ROUTE_VERBOSE=y | ||
37 | CONFIG_IP_PNP=y | ||
38 | CONFIG_IP_PNP_DHCP=y | ||
39 | CONFIG_IP_PNP_BOOTP=y | ||
40 | CONFIG_NET_IPIP=m | ||
41 | CONFIG_IP_MROUTE=y | ||
42 | CONFIG_IP_PIMSM_V1=y | ||
43 | CONFIG_IP_PIMSM_V2=y | ||
44 | CONFIG_SYN_COOKIES=y | ||
45 | CONFIG_INET_AH=m | ||
46 | CONFIG_INET_ESP=m | ||
47 | CONFIG_INET_IPCOMP=m | ||
48 | # CONFIG_INET_LRO is not set | ||
49 | CONFIG_INET6_AH=m | ||
50 | CONFIG_INET6_ESP=m | ||
51 | CONFIG_INET6_IPCOMP=m | ||
52 | CONFIG_IPV6_TUNNEL=m | ||
53 | CONFIG_BRIDGE=m | ||
54 | CONFIG_VLAN_8021Q=m | ||
55 | CONFIG_ATALK=m | ||
56 | CONFIG_DEV_APPLETALK=m | ||
57 | CONFIG_IPDDP=m | ||
58 | CONFIG_IPDDP_ENCAP=y | ||
59 | CONFIG_NET_SCHED=y | ||
60 | CONFIG_NET_SCH_CBQ=m | ||
61 | CONFIG_NET_SCH_HTB=m | ||
62 | CONFIG_NET_SCH_HFSC=m | ||
63 | CONFIG_NET_SCH_PRIO=m | ||
64 | CONFIG_NET_SCH_RED=m | ||
65 | CONFIG_NET_SCH_SFQ=m | ||
66 | CONFIG_NET_SCH_TEQL=m | ||
67 | CONFIG_NET_SCH_TBF=m | ||
68 | CONFIG_NET_SCH_GRED=m | ||
69 | CONFIG_NET_SCH_DSMARK=m | ||
70 | CONFIG_NET_SCH_NETEM=m | ||
71 | CONFIG_NET_SCH_INGRESS=m | ||
72 | CONFIG_NET_CLS_BASIC=m | ||
73 | CONFIG_NET_CLS_TCINDEX=m | ||
74 | CONFIG_NET_CLS_ROUTE4=m | ||
75 | CONFIG_NET_CLS_FW=m | ||
76 | CONFIG_NET_CLS_U32=m | ||
77 | CONFIG_NET_CLS_RSVP=m | ||
78 | CONFIG_NET_CLS_RSVP6=m | ||
79 | CONFIG_NET_CLS_ACT=y | ||
80 | CONFIG_NET_ACT_POLICE=y | ||
81 | CONFIG_NET_CLS_IND=y | ||
82 | # CONFIG_WIRELESS is not set | ||
83 | CONFIG_DEVTMPFS=y | ||
84 | CONFIG_BLK_DEV_LOOP=y | ||
85 | CONFIG_BLK_DEV_CRYPTOLOOP=m | ||
86 | CONFIG_IDE=y | ||
87 | # CONFIG_IDE_PROC_FS is not set | ||
88 | # CONFIG_IDEPCI_PCIBUS_ORDER is not set | ||
89 | CONFIG_BLK_DEV_GENERIC=y | ||
90 | CONFIG_BLK_DEV_PIIX=y | ||
91 | CONFIG_SCSI=y | ||
92 | CONFIG_BLK_DEV_SD=y | ||
93 | CONFIG_CHR_DEV_SG=y | ||
94 | # CONFIG_SCSI_LOWLEVEL is not set | ||
95 | CONFIG_NETDEVICES=y | ||
96 | # CONFIG_NET_VENDOR_3COM is not set | ||
97 | # CONFIG_NET_VENDOR_ADAPTEC is not set | ||
98 | # CONFIG_NET_VENDOR_ALTEON is not set | ||
99 | CONFIG_PCNET32=y | ||
100 | # CONFIG_NET_VENDOR_ATHEROS is not set | ||
101 | # CONFIG_NET_VENDOR_BROADCOM is not set | ||
102 | # CONFIG_NET_VENDOR_BROCADE is not set | ||
103 | # CONFIG_NET_VENDOR_CHELSIO is not set | ||
104 | # CONFIG_NET_VENDOR_CISCO is not set | ||
105 | # CONFIG_NET_VENDOR_DEC is not set | ||
106 | # CONFIG_NET_VENDOR_DLINK is not set | ||
107 | # CONFIG_NET_VENDOR_EMULEX is not set | ||
108 | # CONFIG_NET_VENDOR_EXAR is not set | ||
109 | # CONFIG_NET_VENDOR_HP is not set | ||
110 | # CONFIG_NET_VENDOR_INTEL is not set | ||
111 | # CONFIG_NET_VENDOR_MARVELL is not set | ||
112 | # CONFIG_NET_VENDOR_MELLANOX is not set | ||
113 | # CONFIG_NET_VENDOR_MICREL is not set | ||
114 | # CONFIG_NET_VENDOR_MYRI is not set | ||
115 | # CONFIG_NET_VENDOR_NATSEMI is not set | ||
116 | # CONFIG_NET_VENDOR_NVIDIA is not set | ||
117 | # CONFIG_NET_VENDOR_OKI is not set | ||
118 | # CONFIG_NET_PACKET_ENGINE is not set | ||
119 | # CONFIG_NET_VENDOR_QLOGIC is not set | ||
120 | # CONFIG_NET_VENDOR_REALTEK is not set | ||
121 | # CONFIG_NET_VENDOR_RDC is not set | ||
122 | # CONFIG_NET_VENDOR_SEEQ is not set | ||
123 | # CONFIG_NET_VENDOR_SILAN is not set | ||
124 | # CONFIG_NET_VENDOR_SIS is not set | ||
125 | # CONFIG_NET_VENDOR_SMSC is not set | ||
126 | # CONFIG_NET_VENDOR_STMICRO is not set | ||
127 | # CONFIG_NET_VENDOR_SUN is not set | ||
128 | # CONFIG_NET_VENDOR_TEHUTI is not set | ||
129 | # CONFIG_NET_VENDOR_TI is not set | ||
130 | # CONFIG_NET_VENDOR_TOSHIBA is not set | ||
131 | # CONFIG_NET_VENDOR_VIA is not set | ||
132 | # CONFIG_WLAN is not set | ||
133 | # CONFIG_VT is not set | ||
134 | CONFIG_LEGACY_PTY_COUNT=16 | ||
135 | CONFIG_SERIAL_8250=y | ||
136 | CONFIG_SERIAL_8250_CONSOLE=y | ||
137 | CONFIG_HW_RANDOM=y | ||
138 | # CONFIG_HWMON is not set | ||
139 | CONFIG_VIDEO_OUTPUT_CONTROL=m | ||
140 | CONFIG_FB=y | ||
141 | CONFIG_FIRMWARE_EDID=y | ||
142 | CONFIG_FB_MATROX=y | ||
143 | CONFIG_FB_MATROX_G=y | ||
144 | CONFIG_USB=y | ||
145 | CONFIG_USB_EHCI_HCD=y | ||
146 | # CONFIG_USB_EHCI_TT_NEWSCHED is not set | ||
147 | CONFIG_USB_UHCI_HCD=y | ||
148 | CONFIG_USB_STORAGE=y | ||
149 | CONFIG_NEW_LEDS=y | ||
150 | CONFIG_LEDS_CLASS=y | ||
151 | CONFIG_LEDS_TRIGGERS=y | ||
152 | CONFIG_LEDS_TRIGGER_TIMER=y | ||
153 | CONFIG_LEDS_TRIGGER_IDE_DISK=y | ||
154 | CONFIG_LEDS_TRIGGER_HEARTBEAT=y | ||
155 | CONFIG_LEDS_TRIGGER_BACKLIGHT=y | ||
156 | CONFIG_LEDS_TRIGGER_DEFAULT_ON=y | ||
157 | CONFIG_RTC_CLASS=y | ||
158 | CONFIG_RTC_DRV_CMOS=y | ||
159 | CONFIG_EXT2_FS=y | ||
160 | CONFIG_EXT3_FS=y | ||
161 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set | ||
162 | CONFIG_XFS_FS=y | ||
163 | CONFIG_XFS_QUOTA=y | ||
164 | CONFIG_XFS_POSIX_ACL=y | ||
165 | CONFIG_QUOTA=y | ||
166 | CONFIG_QFMT_V2=y | ||
167 | CONFIG_MSDOS_FS=m | ||
168 | CONFIG_VFAT_FS=m | ||
169 | CONFIG_PROC_KCORE=y | ||
170 | CONFIG_TMPFS=y | ||
171 | CONFIG_NFS_FS=y | ||
172 | CONFIG_ROOT_NFS=y | ||
173 | CONFIG_CIFS=m | ||
174 | CONFIG_CIFS_WEAK_PW_HASH=y | ||
175 | CONFIG_CIFS_XATTR=y | ||
176 | CONFIG_CIFS_POSIX=y | ||
177 | CONFIG_NLS_CODEPAGE_437=m | ||
178 | CONFIG_NLS_ISO8859_1=m | ||
179 | # CONFIG_FTRACE is not set | ||
180 | CONFIG_CRYPTO_NULL=m | ||
181 | CONFIG_CRYPTO_PCBC=m | ||
182 | CONFIG_CRYPTO_HMAC=y | ||
183 | CONFIG_CRYPTO_MICHAEL_MIC=m | ||
184 | CONFIG_CRYPTO_SHA512=m | ||
185 | CONFIG_CRYPTO_TGR192=m | ||
186 | CONFIG_CRYPTO_WP512=m | ||
187 | CONFIG_CRYPTO_ANUBIS=m | ||
188 | CONFIG_CRYPTO_BLOWFISH=m | ||
189 | CONFIG_CRYPTO_CAST5=m | ||
190 | CONFIG_CRYPTO_CAST6=m | ||
191 | CONFIG_CRYPTO_KHAZAD=m | ||
192 | CONFIG_CRYPTO_SERPENT=m | ||
193 | CONFIG_CRYPTO_TEA=m | ||
194 | CONFIG_CRYPTO_TWOFISH=m | ||
195 | # CONFIG_CRYPTO_ANSI_CPRNG is not set | ||
196 | # CONFIG_CRYPTO_HW is not set | ||
diff --git a/arch/mips/configs/maltasmvp_defconfig b/arch/mips/configs/maltasmvp_defconfig index 10ef3bed5f43..f8a32315bb38 100644 --- a/arch/mips/configs/maltasmvp_defconfig +++ b/arch/mips/configs/maltasmvp_defconfig | |||
@@ -4,10 +4,9 @@ CONFIG_CPU_MIPS32_R2=y | |||
4 | CONFIG_PAGE_SIZE_16KB=y | 4 | CONFIG_PAGE_SIZE_16KB=y |
5 | CONFIG_MIPS_MT_SMP=y | 5 | CONFIG_MIPS_MT_SMP=y |
6 | CONFIG_SCHED_SMT=y | 6 | CONFIG_SCHED_SMT=y |
7 | CONFIG_MIPS_CMP=y | 7 | CONFIG_MIPS_CPS=y |
8 | CONFIG_NR_CPUS=8 | 8 | CONFIG_NR_CPUS=8 |
9 | CONFIG_HZ_100=y | 9 | CONFIG_HZ_100=y |
10 | CONFIG_LOCALVERSION="cmp" | ||
11 | CONFIG_SYSVIPC=y | 10 | CONFIG_SYSVIPC=y |
12 | CONFIG_POSIX_MQUEUE=y | 11 | CONFIG_POSIX_MQUEUE=y |
13 | CONFIG_AUDIT=y | 12 | CONFIG_AUDIT=y |
diff --git a/arch/mips/configs/maltasmvp_eva_defconfig b/arch/mips/configs/maltasmvp_eva_defconfig index 2d3002cba102..c83338a39917 100644 --- a/arch/mips/configs/maltasmvp_eva_defconfig +++ b/arch/mips/configs/maltasmvp_eva_defconfig | |||
@@ -5,10 +5,9 @@ CONFIG_CPU_MIPS32_3_5_FEATURES=y | |||
5 | CONFIG_PAGE_SIZE_16KB=y | 5 | CONFIG_PAGE_SIZE_16KB=y |
6 | CONFIG_MIPS_MT_SMP=y | 6 | CONFIG_MIPS_MT_SMP=y |
7 | CONFIG_SCHED_SMT=y | 7 | CONFIG_SCHED_SMT=y |
8 | CONFIG_MIPS_CMP=y | 8 | CONFIG_MIPS_CPS=y |
9 | CONFIG_NR_CPUS=8 | 9 | CONFIG_NR_CPUS=8 |
10 | CONFIG_HZ_100=y | 10 | CONFIG_HZ_100=y |
11 | CONFIG_LOCALVERSION="cmp" | ||
12 | CONFIG_SYSVIPC=y | 11 | CONFIG_SYSVIPC=y |
13 | CONFIG_POSIX_MQUEUE=y | 12 | CONFIG_POSIX_MQUEUE=y |
14 | CONFIG_AUDIT=y | 13 | CONFIG_AUDIT=y |
diff --git a/arch/mips/configs/mips_paravirt_defconfig b/arch/mips/configs/mips_paravirt_defconfig new file mode 100644 index 000000000000..84cfcb4bf2ea --- /dev/null +++ b/arch/mips/configs/mips_paravirt_defconfig | |||
@@ -0,0 +1,103 @@ | |||
1 | CONFIG_MIPS_PARAVIRT=y | ||
2 | CONFIG_CPU_MIPS64_R2=y | ||
3 | CONFIG_64BIT=y | ||
4 | CONFIG_TRANSPARENT_HUGEPAGE=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_HZ_1000=y | ||
7 | CONFIG_PREEMPT=y | ||
8 | CONFIG_SYSVIPC=y | ||
9 | CONFIG_BSD_PROCESS_ACCT=y | ||
10 | CONFIG_BSD_PROCESS_ACCT_V3=y | ||
11 | CONFIG_IKCONFIG=y | ||
12 | CONFIG_IKCONFIG_PROC=y | ||
13 | CONFIG_LOG_BUF_SHIFT=14 | ||
14 | CONFIG_RELAY=y | ||
15 | CONFIG_BLK_DEV_INITRD=y | ||
16 | CONFIG_EXPERT=y | ||
17 | CONFIG_SLAB=y | ||
18 | CONFIG_MODULES=y | ||
19 | CONFIG_MODULE_UNLOAD=y | ||
20 | # CONFIG_BLK_DEV_BSG is not set | ||
21 | CONFIG_PCI=y | ||
22 | CONFIG_MIPS32_COMPAT=y | ||
23 | CONFIG_MIPS32_O32=y | ||
24 | CONFIG_MIPS32_N32=y | ||
25 | CONFIG_NET=y | ||
26 | CONFIG_PACKET=y | ||
27 | CONFIG_UNIX=y | ||
28 | CONFIG_INET=y | ||
29 | CONFIG_IP_MULTICAST=y | ||
30 | CONFIG_IP_ADVANCED_ROUTER=y | ||
31 | CONFIG_IP_MULTIPLE_TABLES=y | ||
32 | CONFIG_IP_ROUTE_MULTIPATH=y | ||
33 | CONFIG_IP_ROUTE_VERBOSE=y | ||
34 | CONFIG_IP_PNP=y | ||
35 | CONFIG_IP_PNP_DHCP=y | ||
36 | CONFIG_IP_PNP_BOOTP=y | ||
37 | CONFIG_IP_PNP_RARP=y | ||
38 | CONFIG_IP_MROUTE=y | ||
39 | CONFIG_IP_PIMSM_V1=y | ||
40 | CONFIG_IP_PIMSM_V2=y | ||
41 | CONFIG_SYN_COOKIES=y | ||
42 | # CONFIG_INET_LRO is not set | ||
43 | CONFIG_IPV6=y | ||
44 | # CONFIG_WIRELESS is not set | ||
45 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | ||
46 | # CONFIG_FW_LOADER is not set | ||
47 | CONFIG_BLK_DEV_LOOP=y | ||
48 | CONFIG_VIRTIO_BLK=y | ||
49 | CONFIG_SCSI=y | ||
50 | CONFIG_BLK_DEV_SD=y | ||
51 | CONFIG_NETDEVICES=y | ||
52 | CONFIG_VIRTIO_NET=y | ||
53 | # CONFIG_NET_VENDOR_BROADCOM is not set | ||
54 | # CONFIG_NET_VENDOR_INTEL is not set | ||
55 | # CONFIG_NET_VENDOR_MARVELL is not set | ||
56 | # CONFIG_NET_VENDOR_MICREL is not set | ||
57 | # CONFIG_NET_VENDOR_NATSEMI is not set | ||
58 | # CONFIG_NET_VENDOR_SMSC is not set | ||
59 | # CONFIG_NET_VENDOR_STMICRO is not set | ||
60 | # CONFIG_NET_VENDOR_WIZNET is not set | ||
61 | CONFIG_PHYLIB=y | ||
62 | CONFIG_MARVELL_PHY=y | ||
63 | CONFIG_BROADCOM_PHY=y | ||
64 | CONFIG_BCM87XX_PHY=y | ||
65 | # CONFIG_WLAN is not set | ||
66 | # CONFIG_INPUT is not set | ||
67 | # CONFIG_SERIO is not set | ||
68 | # CONFIG_VT is not set | ||
69 | CONFIG_VIRTIO_CONSOLE=y | ||
70 | # CONFIG_HW_RANDOM is not set | ||
71 | # CONFIG_HWMON is not set | ||
72 | # CONFIG_USB_SUPPORT is not set | ||
73 | CONFIG_VIRTIO_PCI=y | ||
74 | CONFIG_VIRTIO_BALLOON=y | ||
75 | CONFIG_VIRTIO_MMIO=y | ||
76 | # CONFIG_IOMMU_SUPPORT is not set | ||
77 | CONFIG_EXT4_FS=y | ||
78 | CONFIG_EXT4_FS_POSIX_ACL=y | ||
79 | CONFIG_EXT4_FS_SECURITY=y | ||
80 | CONFIG_MSDOS_FS=y | ||
81 | CONFIG_VFAT_FS=y | ||
82 | CONFIG_PROC_KCORE=y | ||
83 | CONFIG_TMPFS=y | ||
84 | CONFIG_HUGETLBFS=y | ||
85 | # CONFIG_MISC_FILESYSTEMS is not set | ||
86 | CONFIG_NFS_FS=y | ||
87 | CONFIG_NFS_V4=y | ||
88 | CONFIG_NFS_V4_1=y | ||
89 | CONFIG_ROOT_NFS=y | ||
90 | CONFIG_NLS_CODEPAGE_437=y | ||
91 | CONFIG_NLS_ASCII=y | ||
92 | CONFIG_NLS_ISO8859_1=y | ||
93 | CONFIG_NLS_UTF8=y | ||
94 | CONFIG_DEBUG_INFO=y | ||
95 | CONFIG_DEBUG_FS=y | ||
96 | CONFIG_MAGIC_SYSRQ=y | ||
97 | # CONFIG_SCHED_DEBUG is not set | ||
98 | # CONFIG_FTRACE is not set | ||
99 | CONFIG_CRYPTO_CBC=y | ||
100 | CONFIG_CRYPTO_HMAC=y | ||
101 | CONFIG_CRYPTO_MD5=y | ||
102 | CONFIG_CRYPTO_DES=y | ||
103 | # CONFIG_CRYPTO_ANSI_CPRNG is not set | ||
diff --git a/arch/mips/configs/rt305x_defconfig b/arch/mips/configs/rt305x_defconfig index d1741bcf8949..d14ae2fa7d13 100644 --- a/arch/mips/configs/rt305x_defconfig +++ b/arch/mips/configs/rt305x_defconfig | |||
@@ -81,7 +81,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | |||
81 | # CONFIG_FIRMWARE_IN_KERNEL is not set | 81 | # CONFIG_FIRMWARE_IN_KERNEL is not set |
82 | CONFIG_MTD=y | 82 | CONFIG_MTD=y |
83 | CONFIG_MTD_CMDLINE_PARTS=y | 83 | CONFIG_MTD_CMDLINE_PARTS=y |
84 | CONFIG_MTD_CHAR=y | ||
85 | CONFIG_MTD_BLOCK=y | 84 | CONFIG_MTD_BLOCK=y |
86 | CONFIG_MTD_CFI=y | 85 | CONFIG_MTD_CFI=y |
87 | CONFIG_MTD_CFI_AMDSTD=y | 86 | CONFIG_MTD_CFI_AMDSTD=y |
@@ -89,6 +88,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y | |||
89 | CONFIG_MTD_PHYSMAP=y | 88 | CONFIG_MTD_PHYSMAP=y |
90 | CONFIG_MTD_PHYSMAP_OF=y | 89 | CONFIG_MTD_PHYSMAP_OF=y |
91 | CONFIG_MTD_M25P80=y | 90 | CONFIG_MTD_M25P80=y |
91 | CONFIG_MTD_SPI_NOR=y | ||
92 | CONFIG_EEPROM_93CX6=m | 92 | CONFIG_EEPROM_93CX6=m |
93 | CONFIG_SCSI=y | 93 | CONFIG_SCSI=y |
94 | CONFIG_BLK_DEV_SD=y | 94 | CONFIG_BLK_DEV_SD=y |
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index 56e6e2c23683..41bbffd9cc0e 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <asm/bootinfo.h> | 23 | #include <asm/bootinfo.h> |
24 | #include <asm/cpu.h> | 24 | #include <asm/cpu.h> |
25 | #include <asm/cpu-features.h> | 25 | #include <asm/cpu-features.h> |
26 | #include <asm/cpu-type.h> | ||
26 | #include <asm/irq.h> | 27 | #include <asm/irq.h> |
27 | #include <asm/irq_cpu.h> | 28 | #include <asm/irq_cpu.h> |
28 | #include <asm/mipsregs.h> | 29 | #include <asm/mipsregs.h> |
@@ -748,6 +749,10 @@ void __init arch_init_irq(void) | |||
748 | cpu_fpu_mask = 0; | 749 | cpu_fpu_mask = 0; |
749 | dec_interrupt[DEC_IRQ_FPU] = -1; | 750 | dec_interrupt[DEC_IRQ_FPU] = -1; |
750 | } | 751 | } |
752 | /* Free the halt interrupt unused on R4k systems. */ | ||
753 | if (current_cpu_type() == CPU_R4000SC || | ||
754 | current_cpu_type() == CPU_R4400SC) | ||
755 | dec_interrupt[DEC_IRQ_HALT] = -1; | ||
751 | 756 | ||
752 | /* Register board interrupts: FPU and cascade. */ | 757 | /* Register board interrupts: FPU and cascade. */ |
753 | if (dec_interrupt[DEC_IRQ_FPU] >= 0) | 758 | if (dec_interrupt[DEC_IRQ_FPU] >= 0) |
diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index b464b8b1147a..935543f14538 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h | |||
@@ -17,26 +17,8 @@ | |||
17 | #ifdef CONFIG_64BIT | 17 | #ifdef CONFIG_64BIT |
18 | #include <asm/asmmacro-64.h> | 18 | #include <asm/asmmacro-64.h> |
19 | #endif | 19 | #endif |
20 | #ifdef CONFIG_MIPS_MT_SMTC | ||
21 | #include <asm/mipsmtregs.h> | ||
22 | #endif | ||
23 | |||
24 | #ifdef CONFIG_MIPS_MT_SMTC | ||
25 | .macro local_irq_enable reg=t0 | ||
26 | mfc0 \reg, CP0_TCSTATUS | ||
27 | ori \reg, \reg, TCSTATUS_IXMT | ||
28 | xori \reg, \reg, TCSTATUS_IXMT | ||
29 | mtc0 \reg, CP0_TCSTATUS | ||
30 | _ehb | ||
31 | .endm | ||
32 | 20 | ||
33 | .macro local_irq_disable reg=t0 | 21 | #ifdef CONFIG_CPU_MIPSR2 |
34 | mfc0 \reg, CP0_TCSTATUS | ||
35 | ori \reg, \reg, TCSTATUS_IXMT | ||
36 | mtc0 \reg, CP0_TCSTATUS | ||
37 | _ehb | ||
38 | .endm | ||
39 | #elif defined(CONFIG_CPU_MIPSR2) | ||
40 | .macro local_irq_enable reg=t0 | 22 | .macro local_irq_enable reg=t0 |
41 | ei | 23 | ei |
42 | irq_enable_hazard | 24 | irq_enable_hazard |
@@ -71,7 +53,7 @@ | |||
71 | sw \reg, TI_PRE_COUNT($28) | 53 | sw \reg, TI_PRE_COUNT($28) |
72 | #endif | 54 | #endif |
73 | .endm | 55 | .endm |
74 | #endif /* CONFIG_MIPS_MT_SMTC */ | 56 | #endif /* CONFIG_CPU_MIPSR2 */ |
75 | 57 | ||
76 | .macro fpu_save_16even thread tmp=t0 | 58 | .macro fpu_save_16even thread tmp=t0 |
77 | cfc1 \tmp, fcr31 | 59 | cfc1 \tmp, fcr31 |
@@ -267,13 +249,35 @@ | |||
267 | .set pop | 249 | .set pop |
268 | .endm | 250 | .endm |
269 | #else | 251 | #else |
252 | |||
253 | #ifdef CONFIG_CPU_MICROMIPS | ||
254 | #define CFC_MSA_INSN 0x587e0056 | ||
255 | #define CTC_MSA_INSN 0x583e0816 | ||
256 | #define LDD_MSA_INSN 0x58000837 | ||
257 | #define STD_MSA_INSN 0x5800083f | ||
258 | #define COPY_UW_MSA_INSN 0x58f00056 | ||
259 | #define COPY_UD_MSA_INSN 0x58f80056 | ||
260 | #define INSERT_W_MSA_INSN 0x59300816 | ||
261 | #define INSERT_D_MSA_INSN 0x59380816 | ||
262 | #else | ||
263 | #define CFC_MSA_INSN 0x787e0059 | ||
264 | #define CTC_MSA_INSN 0x783e0819 | ||
265 | #define LDD_MSA_INSN 0x78000823 | ||
266 | #define STD_MSA_INSN 0x78000827 | ||
267 | #define COPY_UW_MSA_INSN 0x78f00059 | ||
268 | #define COPY_UD_MSA_INSN 0x78f80059 | ||
269 | #define INSERT_W_MSA_INSN 0x79300819 | ||
270 | #define INSERT_D_MSA_INSN 0x79380819 | ||
271 | #endif | ||
272 | |||
270 | /* | 273 | /* |
271 | * Temporary until all toolchains in use include MSA support. | 274 | * Temporary until all toolchains in use include MSA support. |
272 | */ | 275 | */ |
273 | .macro cfcmsa rd, cs | 276 | .macro cfcmsa rd, cs |
274 | .set push | 277 | .set push |
275 | .set noat | 278 | .set noat |
276 | .word 0x787e0059 | (\cs << 11) | 279 | .insn |
280 | .word CFC_MSA_INSN | (\cs << 11) | ||
277 | move \rd, $1 | 281 | move \rd, $1 |
278 | .set pop | 282 | .set pop |
279 | .endm | 283 | .endm |
@@ -282,7 +286,7 @@ | |||
282 | .set push | 286 | .set push |
283 | .set noat | 287 | .set noat |
284 | move $1, \rs | 288 | move $1, \rs |
285 | .word 0x783e0819 | (\cd << 6) | 289 | .word CTC_MSA_INSN | (\cd << 6) |
286 | .set pop | 290 | .set pop |
287 | .endm | 291 | .endm |
288 | 292 | ||
@@ -290,7 +294,7 @@ | |||
290 | .set push | 294 | .set push |
291 | .set noat | 295 | .set noat |
292 | add $1, \base, \off | 296 | add $1, \base, \off |
293 | .word 0x78000823 | (\wd << 6) | 297 | .word LDD_MSA_INSN | (\wd << 6) |
294 | .set pop | 298 | .set pop |
295 | .endm | 299 | .endm |
296 | 300 | ||
@@ -298,14 +302,15 @@ | |||
298 | .set push | 302 | .set push |
299 | .set noat | 303 | .set noat |
300 | add $1, \base, \off | 304 | add $1, \base, \off |
301 | .word 0x78000827 | (\wd << 6) | 305 | .word STD_MSA_INSN | (\wd << 6) |
302 | .set pop | 306 | .set pop |
303 | .endm | 307 | .endm |
304 | 308 | ||
305 | .macro copy_u_w rd, ws, n | 309 | .macro copy_u_w rd, ws, n |
306 | .set push | 310 | .set push |
307 | .set noat | 311 | .set noat |
308 | .word 0x78f00059 | (\n << 16) | (\ws << 11) | 312 | .insn |
313 | .word COPY_UW_MSA_INSN | (\n << 16) | (\ws << 11) | ||
309 | /* move triggers an assembler bug... */ | 314 | /* move triggers an assembler bug... */ |
310 | or \rd, $1, zero | 315 | or \rd, $1, zero |
311 | .set pop | 316 | .set pop |
@@ -314,7 +319,8 @@ | |||
314 | .macro copy_u_d rd, ws, n | 319 | .macro copy_u_d rd, ws, n |
315 | .set push | 320 | .set push |
316 | .set noat | 321 | .set noat |
317 | .word 0x78f80059 | (\n << 16) | (\ws << 11) | 322 | .insn |
323 | .word COPY_UD_MSA_INSN | (\n << 16) | (\ws << 11) | ||
318 | /* move triggers an assembler bug... */ | 324 | /* move triggers an assembler bug... */ |
319 | or \rd, $1, zero | 325 | or \rd, $1, zero |
320 | .set pop | 326 | .set pop |
@@ -325,7 +331,7 @@ | |||
325 | .set noat | 331 | .set noat |
326 | /* move triggers an assembler bug... */ | 332 | /* move triggers an assembler bug... */ |
327 | or $1, \rs, zero | 333 | or $1, \rs, zero |
328 | .word 0x79300819 | (\n << 16) | (\wd << 6) | 334 | .word INSERT_W_MSA_INSN | (\n << 16) | (\wd << 6) |
329 | .set pop | 335 | .set pop |
330 | .endm | 336 | .endm |
331 | 337 | ||
@@ -334,7 +340,7 @@ | |||
334 | .set noat | 340 | .set noat |
335 | /* move triggers an assembler bug... */ | 341 | /* move triggers an assembler bug... */ |
336 | or $1, \rs, zero | 342 | or $1, \rs, zero |
337 | .word 0x79380819 | (\n << 16) | (\wd << 6) | 343 | .word INSERT_D_MSA_INSN | (\n << 16) | (\wd << 6) |
338 | .set pop | 344 | .set pop |
339 | .endm | 345 | .endm |
340 | #endif | 346 | #endif |
diff --git a/arch/mips/include/asm/branch.h b/arch/mips/include/asm/branch.h index e28a3e0eb3cb..de781cf54bc7 100644 --- a/arch/mips/include/asm/branch.h +++ b/arch/mips/include/asm/branch.h | |||
@@ -8,6 +8,8 @@ | |||
8 | #ifndef _ASM_BRANCH_H | 8 | #ifndef _ASM_BRANCH_H |
9 | #define _ASM_BRANCH_H | 9 | #define _ASM_BRANCH_H |
10 | 10 | ||
11 | #include <asm/cpu-features.h> | ||
12 | #include <asm/mipsregs.h> | ||
11 | #include <asm/ptrace.h> | 13 | #include <asm/ptrace.h> |
12 | #include <asm/inst.h> | 14 | #include <asm/inst.h> |
13 | 15 | ||
@@ -18,12 +20,40 @@ extern int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
18 | extern int __microMIPS_compute_return_epc(struct pt_regs *regs); | 20 | extern int __microMIPS_compute_return_epc(struct pt_regs *regs); |
19 | extern int __MIPS16e_compute_return_epc(struct pt_regs *regs); | 21 | extern int __MIPS16e_compute_return_epc(struct pt_regs *regs); |
20 | 22 | ||
23 | /* | ||
24 | * microMIPS bitfields | ||
25 | */ | ||
26 | #define MM_POOL32A_MINOR_MASK 0x3f | ||
27 | #define MM_POOL32A_MINOR_SHIFT 0x6 | ||
28 | #define MM_MIPS32_COND_FC 0x30 | ||
29 | |||
30 | extern int __mm_isBranchInstr(struct pt_regs *regs, | ||
31 | struct mm_decoded_insn dec_insn, unsigned long *contpc); | ||
32 | |||
33 | static inline int mm_isBranchInstr(struct pt_regs *regs, | ||
34 | struct mm_decoded_insn dec_insn, unsigned long *contpc) | ||
35 | { | ||
36 | if (!cpu_has_mmips) | ||
37 | return 0; | ||
38 | |||
39 | return __mm_isBranchInstr(regs, dec_insn, contpc); | ||
40 | } | ||
21 | 41 | ||
22 | static inline int delay_slot(struct pt_regs *regs) | 42 | static inline int delay_slot(struct pt_regs *regs) |
23 | { | 43 | { |
24 | return regs->cp0_cause & CAUSEF_BD; | 44 | return regs->cp0_cause & CAUSEF_BD; |
25 | } | 45 | } |
26 | 46 | ||
47 | static inline void clear_delay_slot(struct pt_regs *regs) | ||
48 | { | ||
49 | regs->cp0_cause &= ~CAUSEF_BD; | ||
50 | } | ||
51 | |||
52 | static inline void set_delay_slot(struct pt_regs *regs) | ||
53 | { | ||
54 | regs->cp0_cause |= CAUSEF_BD; | ||
55 | } | ||
56 | |||
27 | static inline unsigned long exception_epc(struct pt_regs *regs) | 57 | static inline unsigned long exception_epc(struct pt_regs *regs) |
28 | { | 58 | { |
29 | if (likely(!delay_slot(regs))) | 59 | if (likely(!delay_slot(regs))) |
diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h index 69468ded2828..e08381a37f8b 100644 --- a/arch/mips/include/asm/cacheflush.h +++ b/arch/mips/include/asm/cacheflush.h | |||
@@ -113,6 +113,12 @@ unsigned long run_uncached(void *func); | |||
113 | 113 | ||
114 | extern void *kmap_coherent(struct page *page, unsigned long addr); | 114 | extern void *kmap_coherent(struct page *page, unsigned long addr); |
115 | extern void kunmap_coherent(void); | 115 | extern void kunmap_coherent(void); |
116 | extern void *kmap_noncoherent(struct page *page, unsigned long addr); | ||
117 | |||
118 | static inline void kunmap_noncoherent(void) | ||
119 | { | ||
120 | kunmap_coherent(); | ||
121 | } | ||
116 | 122 | ||
117 | #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE | 123 | #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE |
118 | static inline void flush_kernel_dcache_page(struct page *page) | 124 | static inline void flush_kernel_dcache_page(struct page *page) |
diff --git a/arch/mips/include/asm/cmp.h b/arch/mips/include/asm/cmp.h index 89a73fb93ae6..033d97303c85 100644 --- a/arch/mips/include/asm/cmp.h +++ b/arch/mips/include/asm/cmp.h | |||
@@ -10,7 +10,6 @@ extern void cmp_smp_setup(void); | |||
10 | extern void cmp_smp_finish(void); | 10 | extern void cmp_smp_finish(void); |
11 | extern void cmp_boot_secondary(int cpu, struct task_struct *t); | 11 | extern void cmp_boot_secondary(int cpu, struct task_struct *t); |
12 | extern void cmp_init_secondary(void); | 12 | extern void cmp_init_secondary(void); |
13 | extern void cmp_cpus_done(void); | ||
14 | extern void cmp_prepare_cpus(unsigned int max_cpus); | 13 | extern void cmp_prepare_cpus(unsigned int max_cpus); |
15 | 14 | ||
16 | /* This is platform specific */ | 15 | /* This is platform specific */ |
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index f56cc975b92f..c7d8c997d93e 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h | |||
@@ -110,9 +110,15 @@ | |||
110 | #ifndef cpu_has_smartmips | 110 | #ifndef cpu_has_smartmips |
111 | #define cpu_has_smartmips (cpu_data[0].ases & MIPS_ASE_SMARTMIPS) | 111 | #define cpu_has_smartmips (cpu_data[0].ases & MIPS_ASE_SMARTMIPS) |
112 | #endif | 112 | #endif |
113 | |||
113 | #ifndef cpu_has_rixi | 114 | #ifndef cpu_has_rixi |
114 | #define cpu_has_rixi (cpu_data[0].options & MIPS_CPU_RIXI) | 115 | # ifdef CONFIG_64BIT |
116 | # define cpu_has_rixi (cpu_data[0].options & MIPS_CPU_RIXI) | ||
117 | # else /* CONFIG_32BIT */ | ||
118 | # define cpu_has_rixi ((cpu_data[0].options & MIPS_CPU_RIXI) && !cpu_has_64bits) | ||
119 | # endif | ||
115 | #endif | 120 | #endif |
121 | |||
116 | #ifndef cpu_has_mmips | 122 | #ifndef cpu_has_mmips |
117 | # ifdef CONFIG_SYS_SUPPORTS_MICROMIPS | 123 | # ifdef CONFIG_SYS_SUPPORTS_MICROMIPS |
118 | # define cpu_has_mmips (cpu_data[0].options & MIPS_CPU_MICROMIPS) | 124 | # define cpu_has_mmips (cpu_data[0].options & MIPS_CPU_MICROMIPS) |
@@ -120,6 +126,7 @@ | |||
120 | # define cpu_has_mmips 0 | 126 | # define cpu_has_mmips 0 |
121 | # endif | 127 | # endif |
122 | #endif | 128 | #endif |
129 | |||
123 | #ifndef cpu_has_vtag_icache | 130 | #ifndef cpu_has_vtag_icache |
124 | #define cpu_has_vtag_icache (cpu_data[0].icache.flags & MIPS_CACHE_VTAG) | 131 | #define cpu_has_vtag_icache (cpu_data[0].icache.flags & MIPS_CACHE_VTAG) |
125 | #endif | 132 | #endif |
@@ -183,6 +190,17 @@ | |||
183 | /* | 190 | /* |
184 | * Shortcuts ... | 191 | * Shortcuts ... |
185 | */ | 192 | */ |
193 | #define cpu_has_mips_2_3_4_5 (cpu_has_mips_2 | cpu_has_mips_3_4_5) | ||
194 | #define cpu_has_mips_3_4_5 (cpu_has_mips_3 | cpu_has_mips_4_5) | ||
195 | #define cpu_has_mips_4_5 (cpu_has_mips_4 | cpu_has_mips_5) | ||
196 | |||
197 | #define cpu_has_mips_2_3_4_5_r (cpu_has_mips_2 | cpu_has_mips_3_4_5_r) | ||
198 | #define cpu_has_mips_3_4_5_r (cpu_has_mips_3 | cpu_has_mips_4_5_r) | ||
199 | #define cpu_has_mips_4_5_r (cpu_has_mips_4 | cpu_has_mips_5_r) | ||
200 | #define cpu_has_mips_5_r (cpu_has_mips_5 | cpu_has_mips_r) | ||
201 | |||
202 | #define cpu_has_mips_4_5_r2 (cpu_has_mips_4_5 | cpu_has_mips_r2) | ||
203 | |||
186 | #define cpu_has_mips32 (cpu_has_mips32r1 | cpu_has_mips32r2) | 204 | #define cpu_has_mips32 (cpu_has_mips32r1 | cpu_has_mips32r2) |
187 | #define cpu_has_mips64 (cpu_has_mips64r1 | cpu_has_mips64r2) | 205 | #define cpu_has_mips64 (cpu_has_mips64r1 | cpu_has_mips64r2) |
188 | #define cpu_has_mips_r1 (cpu_has_mips32r1 | cpu_has_mips64r1) | 206 | #define cpu_has_mips_r1 (cpu_has_mips32r1 | cpu_has_mips64r1) |
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index ff2707ab3295..47d5967ce7ef 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h | |||
@@ -65,18 +65,13 @@ struct cpuinfo_mips { | |||
65 | #ifdef CONFIG_64BIT | 65 | #ifdef CONFIG_64BIT |
66 | int vmbits; /* Virtual memory size in bits */ | 66 | int vmbits; /* Virtual memory size in bits */ |
67 | #endif | 67 | #endif |
68 | #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) | 68 | #ifdef CONFIG_MIPS_MT_SMP |
69 | /* | 69 | /* |
70 | * In the MIPS MT "SMTC" model, each TC is considered | 70 | * There is not necessarily a 1:1 mapping of VPE num to CPU number |
71 | * to be a "CPU" for the purposes of scheduling, but | 71 | * in particular on multi-core systems. |
72 | * exception resources, ASID spaces, etc, are common | ||
73 | * to all TCs within the same VPE. | ||
74 | */ | 72 | */ |
75 | int vpe_id; /* Virtual Processor number */ | 73 | int vpe_id; /* Virtual Processor number */ |
76 | #endif | 74 | #endif |
77 | #ifdef CONFIG_MIPS_MT_SMTC | ||
78 | int tc_id; /* Thread Context number */ | ||
79 | #endif | ||
80 | void *data; /* Additional data */ | 75 | void *data; /* Additional data */ |
81 | unsigned int watch_reg_count; /* Number that exist */ | 76 | unsigned int watch_reg_count; /* Number that exist */ |
82 | unsigned int watch_reg_use_cnt; /* Usable by ptrace */ | 77 | unsigned int watch_reg_use_cnt; /* Usable by ptrace */ |
@@ -117,7 +112,7 @@ struct proc_cpuinfo_notifier_args { | |||
117 | unsigned long n; | 112 | unsigned long n; |
118 | }; | 113 | }; |
119 | 114 | ||
120 | #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) | 115 | #ifdef CONFIG_MIPS_MT_SMP |
121 | # define cpu_vpe_id(cpuinfo) ((cpuinfo)->vpe_id) | 116 | # define cpu_vpe_id(cpuinfo) ((cpuinfo)->vpe_id) |
122 | #else | 117 | #else |
123 | # define cpu_vpe_id(cpuinfo) 0 | 118 | # define cpu_vpe_id(cpuinfo) 0 |
diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h index 721906130a57..b4e2bd87df50 100644 --- a/arch/mips/include/asm/cpu-type.h +++ b/arch/mips/include/asm/cpu-type.h | |||
@@ -155,9 +155,6 @@ static inline int __pure __get_cpu_type(const int cpu_type) | |||
155 | case CPU_RM7000: | 155 | case CPU_RM7000: |
156 | case CPU_SR71000: | 156 | case CPU_SR71000: |
157 | #endif | 157 | #endif |
158 | #ifdef CONFIG_SYS_HAS_CPU_RM9000 | ||
159 | case CPU_RM9000: | ||
160 | #endif | ||
161 | #ifdef CONFIG_SYS_HAS_CPU_SB1 | 158 | #ifdef CONFIG_SYS_HAS_CPU_SB1 |
162 | case CPU_SB1: | 159 | case CPU_SB1: |
163 | case CPU_SB1A: | 160 | case CPU_SB1A: |
@@ -166,6 +163,7 @@ static inline int __pure __get_cpu_type(const int cpu_type) | |||
166 | case CPU_CAVIUM_OCTEON: | 163 | case CPU_CAVIUM_OCTEON: |
167 | case CPU_CAVIUM_OCTEON_PLUS: | 164 | case CPU_CAVIUM_OCTEON_PLUS: |
168 | case CPU_CAVIUM_OCTEON2: | 165 | case CPU_CAVIUM_OCTEON2: |
166 | case CPU_CAVIUM_OCTEON3: | ||
169 | #endif | 167 | #endif |
170 | 168 | ||
171 | #if defined(CONFIG_SYS_HAS_CPU_BMIPS32_3300) || \ | 169 | #if defined(CONFIG_SYS_HAS_CPU_BMIPS32_3300) || \ |
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 530eb8b3a68e..129d08701e91 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h | |||
@@ -201,6 +201,7 @@ | |||
201 | #define PRID_IMP_NETLOGIC_XLP3XX 0x1100 | 201 | #define PRID_IMP_NETLOGIC_XLP3XX 0x1100 |
202 | #define PRID_IMP_NETLOGIC_XLP2XX 0x1200 | 202 | #define PRID_IMP_NETLOGIC_XLP2XX 0x1200 |
203 | #define PRID_IMP_NETLOGIC_XLP9XX 0x1500 | 203 | #define PRID_IMP_NETLOGIC_XLP9XX 0x1500 |
204 | #define PRID_IMP_NETLOGIC_XLP5XX 0x1300 | ||
204 | 205 | ||
205 | /* | 206 | /* |
206 | * Particular Revision values for bits 7:0 of the PRId register. | 207 | * Particular Revision values for bits 7:0 of the PRId register. |
@@ -281,7 +282,7 @@ enum cpu_type_enum { | |||
281 | CPU_R4700, CPU_R5000, CPU_R5500, CPU_NEVADA, CPU_R5432, CPU_R10000, | 282 | CPU_R4700, CPU_R5000, CPU_R5500, CPU_NEVADA, CPU_R5432, CPU_R10000, |
282 | CPU_R12000, CPU_R14000, CPU_VR41XX, CPU_VR4111, CPU_VR4121, CPU_VR4122, | 283 | CPU_R12000, CPU_R14000, CPU_VR41XX, CPU_VR4111, CPU_VR4121, CPU_VR4122, |
283 | CPU_VR4131, CPU_VR4133, CPU_VR4181, CPU_VR4181A, CPU_RM7000, | 284 | CPU_VR4131, CPU_VR4133, CPU_VR4181, CPU_VR4181A, CPU_RM7000, |
284 | CPU_SR71000, CPU_RM9000, CPU_TX49XX, | 285 | CPU_SR71000, CPU_TX49XX, |
285 | 286 | ||
286 | /* | 287 | /* |
287 | * R8000 class processors | 288 | * R8000 class processors |
diff --git a/arch/mips/include/asm/dec/kn05.h b/arch/mips/include/asm/dec/kn05.h index 56d22dc8803a..8e14f677e5ef 100644 --- a/arch/mips/include/asm/dec/kn05.h +++ b/arch/mips/include/asm/dec/kn05.h | |||
@@ -49,12 +49,20 @@ | |||
49 | #define KN4K_RES_15 (15*IOASIC_SLOT_SIZE) /* unused? */ | 49 | #define KN4K_RES_15 (15*IOASIC_SLOT_SIZE) /* unused? */ |
50 | 50 | ||
51 | /* | 51 | /* |
52 | * MB ASIC interrupt bits. | ||
53 | */ | ||
54 | #define KN4K_MB_INR_MB 4 /* ??? */ | ||
55 | #define KN4K_MB_INR_MT 3 /* memory, I/O bus read/write errors */ | ||
56 | #define KN4K_MB_INR_RES_2 2 /* unused */ | ||
57 | #define KN4K_MB_INR_RTC 1 /* RTC */ | ||
58 | #define KN4K_MB_INR_TC 0 /* I/O ASIC cascade */ | ||
59 | |||
60 | /* | ||
52 | * Bits for the MB interrupt register. | 61 | * Bits for the MB interrupt register. |
53 | * The register appears read-only. | 62 | * The register appears read-only. |
54 | */ | 63 | */ |
55 | #define KN4K_MB_INT_TC (1<<0) /* TURBOchannel? */ | 64 | #define KN4K_MB_INT_IRQ (0x1f<<0) /* CPU Int[4:0] status. */ |
56 | #define KN4K_MB_INT_RTC (1<<1) /* RTC? */ | 65 | #define KN4K_MB_INT_IRQ_N(n) (1<<(n)) /* Individual status bits. */ |
57 | #define KN4K_MB_INT_MT (1<<3) /* I/O ASIC cascade */ | ||
58 | 66 | ||
59 | /* | 67 | /* |
60 | * Bits for the MB control & status register. | 68 | * Bits for the MB control & status register. |
@@ -70,6 +78,7 @@ | |||
70 | #define KN4K_MB_CSR_NC (1<<14) /* ??? */ | 78 | #define KN4K_MB_CSR_NC (1<<14) /* ??? */ |
71 | #define KN4K_MB_CSR_EE (1<<15) /* (bus) Exception Enable? */ | 79 | #define KN4K_MB_CSR_EE (1<<15) /* (bus) Exception Enable? */ |
72 | #define KN4K_MB_CSR_MSK (0x1f<<16) /* CPU Int[4:0] mask */ | 80 | #define KN4K_MB_CSR_MSK (0x1f<<16) /* CPU Int[4:0] mask */ |
81 | #define KN4K_MB_CSR_MSK_N(n) (1<<((n)+16)) /* Individual mask bits. */ | ||
73 | #define KN4K_MB_CSR_FW (1<<21) /* ??? */ | 82 | #define KN4K_MB_CSR_FW (1<<21) /* ??? */ |
74 | #define KN4K_MB_CSR_W (1<<31) /* ??? */ | 83 | #define KN4K_MB_CSR_W (1<<31) /* ??? */ |
75 | 84 | ||
diff --git a/arch/mips/include/asm/fixmap.h b/arch/mips/include/asm/fixmap.h index 8c012af2f451..6842ffafd1e7 100644 --- a/arch/mips/include/asm/fixmap.h +++ b/arch/mips/include/asm/fixmap.h | |||
@@ -48,11 +48,7 @@ | |||
48 | enum fixed_addresses { | 48 | enum fixed_addresses { |
49 | #define FIX_N_COLOURS 8 | 49 | #define FIX_N_COLOURS 8 |
50 | FIX_CMAP_BEGIN, | 50 | FIX_CMAP_BEGIN, |
51 | #ifdef CONFIG_MIPS_MT_SMTC | ||
52 | FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS * 2), | ||
53 | #else | ||
54 | FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * 2), | 51 | FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * 2), |
55 | #endif | ||
56 | #ifdef CONFIG_HIGHMEM | 52 | #ifdef CONFIG_HIGHMEM |
57 | /* reserved pte's for temporary kernel mappings */ | 53 | /* reserved pte's for temporary kernel mappings */ |
58 | FIX_KMAP_BEGIN = FIX_CMAP_END + 1, | 54 | FIX_KMAP_BEGIN = FIX_CMAP_END + 1, |
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index 4d86b72750c7..a939574f8293 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <asm/mipsregs.h> | 17 | #include <asm/mipsregs.h> |
18 | #include <asm/cpu.h> | 18 | #include <asm/cpu.h> |
19 | #include <asm/cpu-features.h> | 19 | #include <asm/cpu-features.h> |
20 | #include <asm/fpu_emulator.h> | ||
20 | #include <asm/hazards.h> | 21 | #include <asm/hazards.h> |
21 | #include <asm/processor.h> | 22 | #include <asm/processor.h> |
22 | #include <asm/current.h> | 23 | #include <asm/current.h> |
@@ -28,7 +29,6 @@ | |||
28 | struct sigcontext; | 29 | struct sigcontext; |
29 | struct sigcontext32; | 30 | struct sigcontext32; |
30 | 31 | ||
31 | extern void fpu_emulator_init_fpu(void); | ||
32 | extern void _init_fpu(void); | 32 | extern void _init_fpu(void); |
33 | extern void _save_fp(struct task_struct *); | 33 | extern void _save_fp(struct task_struct *); |
34 | extern void _restore_fp(struct task_struct *); | 34 | extern void _restore_fp(struct task_struct *); |
@@ -156,15 +156,16 @@ static inline int init_fpu(void) | |||
156 | int ret = 0; | 156 | int ret = 0; |
157 | 157 | ||
158 | preempt_disable(); | 158 | preempt_disable(); |
159 | |||
159 | if (cpu_has_fpu) { | 160 | if (cpu_has_fpu) { |
160 | ret = __own_fpu(); | 161 | ret = __own_fpu(); |
161 | if (!ret) | 162 | if (!ret) |
162 | _init_fpu(); | 163 | _init_fpu(); |
163 | } else { | 164 | } else |
164 | fpu_emulator_init_fpu(); | 165 | fpu_emulator_init_fpu(); |
165 | } | ||
166 | 166 | ||
167 | preempt_enable(); | 167 | preempt_enable(); |
168 | |||
168 | return ret; | 169 | return ret; |
169 | } | 170 | } |
170 | 171 | ||
diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h index 2abb587d5ab4..0195745b4b1b 100644 --- a/arch/mips/include/asm/fpu_emulator.h +++ b/arch/mips/include/asm/fpu_emulator.h | |||
@@ -23,9 +23,12 @@ | |||
23 | #ifndef _ASM_FPU_EMULATOR_H | 23 | #ifndef _ASM_FPU_EMULATOR_H |
24 | #define _ASM_FPU_EMULATOR_H | 24 | #define _ASM_FPU_EMULATOR_H |
25 | 25 | ||
26 | #include <linux/sched.h> | ||
26 | #include <asm/break.h> | 27 | #include <asm/break.h> |
28 | #include <asm/thread_info.h> | ||
27 | #include <asm/inst.h> | 29 | #include <asm/inst.h> |
28 | #include <asm/local.h> | 30 | #include <asm/local.h> |
31 | #include <asm/processor.h> | ||
29 | 32 | ||
30 | #ifdef CONFIG_DEBUG_FS | 33 | #ifdef CONFIG_DEBUG_FS |
31 | 34 | ||
@@ -36,6 +39,11 @@ struct mips_fpu_emulator_stats { | |||
36 | local_t cp1ops; | 39 | local_t cp1ops; |
37 | local_t cp1xops; | 40 | local_t cp1xops; |
38 | local_t errors; | 41 | local_t errors; |
42 | local_t ieee754_inexact; | ||
43 | local_t ieee754_underflow; | ||
44 | local_t ieee754_overflow; | ||
45 | local_t ieee754_zerodiv; | ||
46 | local_t ieee754_invalidop; | ||
39 | }; | 47 | }; |
40 | 48 | ||
41 | DECLARE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); | 49 | DECLARE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); |
@@ -71,4 +79,17 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
71 | */ | 79 | */ |
72 | #define BREAK_MATH (0x0000000d | (BRK_MEMU << 16)) | 80 | #define BREAK_MATH (0x0000000d | (BRK_MEMU << 16)) |
73 | 81 | ||
82 | #define SIGNALLING_NAN 0x7ff800007ff80000LL | ||
83 | |||
84 | static inline void fpu_emulator_init_fpu(void) | ||
85 | { | ||
86 | struct task_struct *t = current; | ||
87 | int i; | ||
88 | |||
89 | t->thread.fpu.fcr31 = 0; | ||
90 | |||
91 | for (i = 0; i < 32; i++) | ||
92 | set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN); | ||
93 | } | ||
94 | |||
74 | #endif /* _ASM_FPU_EMULATOR_H */ | 95 | #endif /* _ASM_FPU_EMULATOR_H */ |
diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h index 082716690589..10f6a99f92c2 100644 --- a/arch/mips/include/asm/gic.h +++ b/arch/mips/include/asm/gic.h | |||
@@ -380,6 +380,7 @@ extern unsigned int gic_compare_int (void); | |||
380 | extern cycle_t gic_read_count(void); | 380 | extern cycle_t gic_read_count(void); |
381 | extern cycle_t gic_read_compare(void); | 381 | extern cycle_t gic_read_compare(void); |
382 | extern void gic_write_compare(cycle_t cnt); | 382 | extern void gic_write_compare(cycle_t cnt); |
383 | extern void gic_write_cpu_compare(cycle_t cnt, int cpu); | ||
383 | extern void gic_send_ipi(unsigned int intr); | 384 | extern void gic_send_ipi(unsigned int intr); |
384 | extern unsigned int plat_ipi_call_int_xlate(unsigned int); | 385 | extern unsigned int plat_ipi_call_int_xlate(unsigned int); |
385 | extern unsigned int plat_ipi_resched_int_xlate(unsigned int); | 386 | extern unsigned int plat_ipi_resched_int_xlate(unsigned int); |
diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h index 0878701712f8..4be1a57cdbb0 100644 --- a/arch/mips/include/asm/gio_device.h +++ b/arch/mips/include/asm/gio_device.h | |||
@@ -50,7 +50,7 @@ static inline void gio_device_free(struct gio_device *dev) | |||
50 | extern int gio_register_driver(struct gio_driver *); | 50 | extern int gio_register_driver(struct gio_driver *); |
51 | extern void gio_unregister_driver(struct gio_driver *); | 51 | extern void gio_unregister_driver(struct gio_driver *); |
52 | 52 | ||
53 | #define gio_get_drvdata(_dev) drv_get_drvdata(&(_dev)->dev) | 53 | #define gio_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev) |
54 | #define gio_set_drvdata(_dev, data) drv_set_drvdata(&(_dev)->dev, (data)) | 54 | #define gio_set_drvdata(_dev, data) dev_set_drvdata(&(_dev)->dev, (data)) |
55 | 55 | ||
56 | extern void gio_set_master(struct gio_device *); | 56 | extern void gio_set_master(struct gio_device *); |
diff --git a/arch/mips/include/asm/idle.h b/arch/mips/include/asm/idle.h index d192158886b1..d9f932de80e9 100644 --- a/arch/mips/include/asm/idle.h +++ b/arch/mips/include/asm/idle.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef __ASM_IDLE_H | 1 | #ifndef __ASM_IDLE_H |
2 | #define __ASM_IDLE_H | 2 | #define __ASM_IDLE_H |
3 | 3 | ||
4 | #include <linux/cpuidle.h> | ||
4 | #include <linux/linkage.h> | 5 | #include <linux/linkage.h> |
5 | 6 | ||
6 | extern void (*cpu_wait)(void); | 7 | extern void (*cpu_wait)(void); |
@@ -20,4 +21,17 @@ static inline int address_is_in_r4k_wait_irqoff(unsigned long addr) | |||
20 | addr < (unsigned long)__pastwait; | 21 | addr < (unsigned long)__pastwait; |
21 | } | 22 | } |
22 | 23 | ||
24 | extern int mips_cpuidle_wait_enter(struct cpuidle_device *dev, | ||
25 | struct cpuidle_driver *drv, int index); | ||
26 | |||
27 | #define MIPS_CPUIDLE_WAIT_STATE {\ | ||
28 | .enter = mips_cpuidle_wait_enter,\ | ||
29 | .exit_latency = 1,\ | ||
30 | .target_residency = 1,\ | ||
31 | .power_usage = UINT_MAX,\ | ||
32 | .flags = CPUIDLE_FLAG_TIME_VALID,\ | ||
33 | .name = "wait",\ | ||
34 | .desc = "MIPS wait",\ | ||
35 | } | ||
36 | |||
23 | #endif /* __ASM_IDLE_H */ | 37 | #endif /* __ASM_IDLE_H */ |
diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index 7bc2cdb35057..ae1f7b24dd1a 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h | |||
@@ -26,104 +26,8 @@ static inline int irq_canonicalize(int irq) | |||
26 | #define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */ | 26 | #define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */ |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | #ifdef CONFIG_MIPS_MT_SMTC | ||
30 | |||
31 | struct irqaction; | ||
32 | |||
33 | extern unsigned long irq_hwmask[]; | ||
34 | extern int setup_irq_smtc(unsigned int irq, struct irqaction * new, | ||
35 | unsigned long hwmask); | ||
36 | |||
37 | static inline void smtc_im_ack_irq(unsigned int irq) | ||
38 | { | ||
39 | if (irq_hwmask[irq] & ST0_IM) | ||
40 | set_c0_status(irq_hwmask[irq] & ST0_IM); | ||
41 | } | ||
42 | |||
43 | #else | ||
44 | |||
45 | static inline void smtc_im_ack_irq(unsigned int irq) | ||
46 | { | ||
47 | } | ||
48 | |||
49 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
50 | |||
51 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | ||
52 | #include <linux/cpumask.h> | ||
53 | |||
54 | extern int plat_set_irq_affinity(struct irq_data *d, | ||
55 | const struct cpumask *affinity, bool force); | ||
56 | extern void smtc_forward_irq(struct irq_data *d); | ||
57 | |||
58 | /* | ||
59 | * IRQ affinity hook invoked at the beginning of interrupt dispatch | ||
60 | * if option is enabled. | ||
61 | * | ||
62 | * Up through Linux 2.6.22 (at least) cpumask operations are very | ||
63 | * inefficient on MIPS. Initial prototypes of SMTC IRQ affinity | ||
64 | * used a "fast path" per-IRQ-descriptor cache of affinity information | ||
65 | * to reduce latency. As there is a project afoot to optimize the | ||
66 | * cpumask implementations, this version is optimistically assuming | ||
67 | * that cpumask.h macro overhead is reasonable during interrupt dispatch. | ||
68 | */ | ||
69 | static inline int handle_on_other_cpu(unsigned int irq) | ||
70 | { | ||
71 | struct irq_data *d = irq_get_irq_data(irq); | ||
72 | |||
73 | if (cpumask_test_cpu(smp_processor_id(), d->affinity)) | ||
74 | return 0; | ||
75 | smtc_forward_irq(d); | ||
76 | return 1; | ||
77 | } | ||
78 | |||
79 | #else /* Not doing SMTC affinity */ | ||
80 | |||
81 | static inline int handle_on_other_cpu(unsigned int irq) { return 0; } | ||
82 | |||
83 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | ||
84 | |||
85 | #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP | ||
86 | |||
87 | static inline void smtc_im_backstop(unsigned int irq) | ||
88 | { | ||
89 | if (irq_hwmask[irq] & 0x0000ff00) | ||
90 | write_c0_tccontext(read_c0_tccontext() & | ||
91 | ~(irq_hwmask[irq] & 0x0000ff00)); | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Clear interrupt mask handling "backstop" if irq_hwmask | ||
96 | * entry so indicates. This implies that the ack() or end() | ||
97 | * functions will take over re-enabling the low-level mask. | ||
98 | * Otherwise it will be done on return from exception. | ||
99 | */ | ||
100 | static inline int smtc_handle_on_other_cpu(unsigned int irq) | ||
101 | { | ||
102 | int ret = handle_on_other_cpu(irq); | ||
103 | |||
104 | if (!ret) | ||
105 | smtc_im_backstop(irq); | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | #else | ||
110 | |||
111 | static inline void smtc_im_backstop(unsigned int irq) { } | ||
112 | static inline int smtc_handle_on_other_cpu(unsigned int irq) | ||
113 | { | ||
114 | return handle_on_other_cpu(irq); | ||
115 | } | ||
116 | |||
117 | #endif | ||
118 | |||
119 | extern void do_IRQ(unsigned int irq); | 29 | extern void do_IRQ(unsigned int irq); |
120 | 30 | ||
121 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | ||
122 | |||
123 | extern void do_IRQ_no_affinity(unsigned int irq); | ||
124 | |||
125 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | ||
126 | |||
127 | extern void arch_init_irq(void); | 31 | extern void arch_init_irq(void); |
128 | extern void spurious_interrupt(void); | 32 | extern void spurious_interrupt(void); |
129 | 33 | ||
diff --git a/arch/mips/include/asm/irqflags.h b/arch/mips/include/asm/irqflags.h index 45c00951888b..0fa5fdcd1f01 100644 --- a/arch/mips/include/asm/irqflags.h +++ b/arch/mips/include/asm/irqflags.h | |||
@@ -17,7 +17,7 @@ | |||
17 | #include <linux/stringify.h> | 17 | #include <linux/stringify.h> |
18 | #include <asm/hazards.h> | 18 | #include <asm/hazards.h> |
19 | 19 | ||
20 | #if defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_MIPS_MT_SMTC) | 20 | #ifdef CONFIG_CPU_MIPSR2 |
21 | 21 | ||
22 | static inline void arch_local_irq_disable(void) | 22 | static inline void arch_local_irq_disable(void) |
23 | { | 23 | { |
@@ -118,30 +118,15 @@ void arch_local_irq_disable(void); | |||
118 | unsigned long arch_local_irq_save(void); | 118 | unsigned long arch_local_irq_save(void); |
119 | void arch_local_irq_restore(unsigned long flags); | 119 | void arch_local_irq_restore(unsigned long flags); |
120 | void __arch_local_irq_restore(unsigned long flags); | 120 | void __arch_local_irq_restore(unsigned long flags); |
121 | #endif /* if defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_MIPS_MT_SMTC) */ | 121 | #endif /* CONFIG_CPU_MIPSR2 */ |
122 | |||
123 | |||
124 | extern void smtc_ipi_replay(void); | ||
125 | 122 | ||
126 | static inline void arch_local_irq_enable(void) | 123 | static inline void arch_local_irq_enable(void) |
127 | { | 124 | { |
128 | #ifdef CONFIG_MIPS_MT_SMTC | ||
129 | /* | ||
130 | * SMTC kernel needs to do a software replay of queued | ||
131 | * IPIs, at the cost of call overhead on each local_irq_enable() | ||
132 | */ | ||
133 | smtc_ipi_replay(); | ||
134 | #endif | ||
135 | __asm__ __volatile__( | 125 | __asm__ __volatile__( |
136 | " .set push \n" | 126 | " .set push \n" |
137 | " .set reorder \n" | 127 | " .set reorder \n" |
138 | " .set noat \n" | 128 | " .set noat \n" |
139 | #ifdef CONFIG_MIPS_MT_SMTC | 129 | #if defined(CONFIG_CPU_MIPSR2) |
140 | " mfc0 $1, $2, 1 # SMTC - clear TCStatus.IXMT \n" | ||
141 | " ori $1, 0x400 \n" | ||
142 | " xori $1, 0x400 \n" | ||
143 | " mtc0 $1, $2, 1 \n" | ||
144 | #elif defined(CONFIG_CPU_MIPSR2) | ||
145 | " ei \n" | 130 | " ei \n" |
146 | #else | 131 | #else |
147 | " mfc0 $1,$12 \n" | 132 | " mfc0 $1,$12 \n" |
@@ -163,11 +148,7 @@ static inline unsigned long arch_local_save_flags(void) | |||
163 | asm __volatile__( | 148 | asm __volatile__( |
164 | " .set push \n" | 149 | " .set push \n" |
165 | " .set reorder \n" | 150 | " .set reorder \n" |
166 | #ifdef CONFIG_MIPS_MT_SMTC | ||
167 | " mfc0 %[flags], $2, 1 \n" | ||
168 | #else | ||
169 | " mfc0 %[flags], $12 \n" | 151 | " mfc0 %[flags], $12 \n" |
170 | #endif | ||
171 | " .set pop \n" | 152 | " .set pop \n" |
172 | : [flags] "=r" (flags)); | 153 | : [flags] "=r" (flags)); |
173 | 154 | ||
@@ -177,14 +158,7 @@ static inline unsigned long arch_local_save_flags(void) | |||
177 | 158 | ||
178 | static inline int arch_irqs_disabled_flags(unsigned long flags) | 159 | static inline int arch_irqs_disabled_flags(unsigned long flags) |
179 | { | 160 | { |
180 | #ifdef CONFIG_MIPS_MT_SMTC | ||
181 | /* | ||
182 | * SMTC model uses TCStatus.IXMT to disable interrupts for a thread/CPU | ||
183 | */ | ||
184 | return flags & 0x400; | ||
185 | #else | ||
186 | return !(flags & 1); | 161 | return !(flags & 1); |
187 | #endif | ||
188 | } | 162 | } |
189 | 163 | ||
190 | #endif /* #ifndef __ASSEMBLY__ */ | 164 | #endif /* #ifndef __ASSEMBLY__ */ |
diff --git a/arch/mips/include/asm/kvm_para.h b/arch/mips/include/asm/kvm_para.h new file mode 100644 index 000000000000..5a9aa918abe6 --- /dev/null +++ b/arch/mips/include/asm/kvm_para.h | |||
@@ -0,0 +1,109 @@ | |||
1 | #ifndef _ASM_MIPS_KVM_PARA_H | ||
2 | #define _ASM_MIPS_KVM_PARA_H | ||
3 | |||
4 | #include <uapi/asm/kvm_para.h> | ||
5 | |||
6 | #define KVM_HYPERCALL ".word 0x42000028" | ||
7 | |||
8 | /* | ||
9 | * Hypercalls for KVM. | ||
10 | * | ||
11 | * Hypercall number is passed in v0. | ||
12 | * Return value will be placed in v0. | ||
13 | * Up to 3 arguments are passed in a0, a1, and a2. | ||
14 | */ | ||
15 | static inline unsigned long kvm_hypercall0(unsigned long num) | ||
16 | { | ||
17 | register unsigned long n asm("v0"); | ||
18 | register unsigned long r asm("v0"); | ||
19 | |||
20 | n = num; | ||
21 | __asm__ __volatile__( | ||
22 | KVM_HYPERCALL | ||
23 | : "=r" (r) : "r" (n) : "memory" | ||
24 | ); | ||
25 | |||
26 | return r; | ||
27 | } | ||
28 | |||
29 | static inline unsigned long kvm_hypercall1(unsigned long num, | ||
30 | unsigned long arg0) | ||
31 | { | ||
32 | register unsigned long n asm("v0"); | ||
33 | register unsigned long r asm("v0"); | ||
34 | register unsigned long a0 asm("a0"); | ||
35 | |||
36 | n = num; | ||
37 | a0 = arg0; | ||
38 | __asm__ __volatile__( | ||
39 | KVM_HYPERCALL | ||
40 | : "=r" (r) : "r" (n), "r" (a0) : "memory" | ||
41 | ); | ||
42 | |||
43 | return r; | ||
44 | } | ||
45 | |||
46 | static inline unsigned long kvm_hypercall2(unsigned long num, | ||
47 | unsigned long arg0, unsigned long arg1) | ||
48 | { | ||
49 | register unsigned long n asm("v0"); | ||
50 | register unsigned long r asm("v0"); | ||
51 | register unsigned long a0 asm("a0"); | ||
52 | register unsigned long a1 asm("a1"); | ||
53 | |||
54 | n = num; | ||
55 | a0 = arg0; | ||
56 | a1 = arg1; | ||
57 | __asm__ __volatile__( | ||
58 | KVM_HYPERCALL | ||
59 | : "=r" (r) : "r" (n), "r" (a0), "r" (a1) : "memory" | ||
60 | ); | ||
61 | |||
62 | return r; | ||
63 | } | ||
64 | |||
65 | static inline unsigned long kvm_hypercall3(unsigned long num, | ||
66 | unsigned long arg0, unsigned long arg1, unsigned long arg2) | ||
67 | { | ||
68 | register unsigned long n asm("v0"); | ||
69 | register unsigned long r asm("v0"); | ||
70 | register unsigned long a0 asm("a0"); | ||
71 | register unsigned long a1 asm("a1"); | ||
72 | register unsigned long a2 asm("a2"); | ||
73 | |||
74 | n = num; | ||
75 | a0 = arg0; | ||
76 | a1 = arg1; | ||
77 | a2 = arg2; | ||
78 | __asm__ __volatile__( | ||
79 | KVM_HYPERCALL | ||
80 | : "=r" (r) : "r" (n), "r" (a0), "r" (a1), "r" (a2) : "memory" | ||
81 | ); | ||
82 | |||
83 | return r; | ||
84 | } | ||
85 | |||
86 | static inline bool kvm_check_and_clear_guest_paused(void) | ||
87 | { | ||
88 | return false; | ||
89 | } | ||
90 | |||
91 | static inline unsigned int kvm_arch_para_features(void) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | #ifdef CONFIG_MIPS_PARAVIRT | ||
97 | static inline bool kvm_para_available(void) | ||
98 | { | ||
99 | return true; | ||
100 | } | ||
101 | #else | ||
102 | static inline bool kvm_para_available(void) | ||
103 | { | ||
104 | return false; | ||
105 | } | ||
106 | #endif | ||
107 | |||
108 | |||
109 | #endif /* _ASM_MIPS_KVM_PARA_H */ | ||
diff --git a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h index 94ed063eec92..cf8022872892 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h | |||
@@ -22,7 +22,6 @@ | |||
22 | #define cpu_has_3k_cache 0 | 22 | #define cpu_has_3k_cache 0 |
23 | #define cpu_has_4k_cache 0 | 23 | #define cpu_has_4k_cache 0 |
24 | #define cpu_has_tx39_cache 0 | 24 | #define cpu_has_tx39_cache 0 |
25 | #define cpu_has_fpu 0 | ||
26 | #define cpu_has_counter 1 | 25 | #define cpu_has_counter 1 |
27 | #define cpu_has_watch 1 | 26 | #define cpu_has_watch 1 |
28 | #define cpu_has_divec 1 | 27 | #define cpu_has_divec 1 |
diff --git a/arch/mips/include/asm/mach-cavium-octeon/irq.h b/arch/mips/include/asm/mach-cavium-octeon/irq.h index 60fc4c347c44..cceae32a0732 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/irq.h +++ b/arch/mips/include/asm/mach-cavium-octeon/irq.h | |||
@@ -35,6 +35,8 @@ enum octeon_irq { | |||
35 | OCTEON_IRQ_PCI_MSI2, | 35 | OCTEON_IRQ_PCI_MSI2, |
36 | OCTEON_IRQ_PCI_MSI3, | 36 | OCTEON_IRQ_PCI_MSI3, |
37 | 37 | ||
38 | OCTEON_IRQ_TWSI, | ||
39 | OCTEON_IRQ_TWSI2, | ||
38 | OCTEON_IRQ_RML, | 40 | OCTEON_IRQ_RML, |
39 | OCTEON_IRQ_TIMER0, | 41 | OCTEON_IRQ_TIMER0, |
40 | OCTEON_IRQ_TIMER1, | 42 | OCTEON_IRQ_TIMER1, |
diff --git a/arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h index 1bcb6421205e..1dfe47453ea4 100644 --- a/arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h | |||
@@ -39,6 +39,10 @@ | |||
39 | #define cpu_has_nofpuex 0 | 39 | #define cpu_has_nofpuex 0 |
40 | #define cpu_has_64bits 1 | 40 | #define cpu_has_64bits 1 |
41 | 41 | ||
42 | #define cpu_has_mips_2 1 | ||
43 | #define cpu_has_mips_3 1 | ||
44 | #define cpu_has_mips_5 0 | ||
45 | |||
42 | #define cpu_has_mips32r1 0 | 46 | #define cpu_has_mips32r1 0 |
43 | #define cpu_has_mips32r2 0 | 47 | #define cpu_has_mips32r2 0 |
44 | #define cpu_has_mips64r1 0 | 48 | #define cpu_has_mips64r1 0 |
diff --git a/arch/mips/include/asm/mach-malta/kernel-entry-init.h b/arch/mips/include/asm/mach-malta/kernel-entry-init.h index 7c5e17a17849..77eeda77e73c 100644 --- a/arch/mips/include/asm/mach-malta/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-malta/kernel-entry-init.h | |||
@@ -80,36 +80,6 @@ | |||
80 | .endm | 80 | .endm |
81 | 81 | ||
82 | .macro kernel_entry_setup | 82 | .macro kernel_entry_setup |
83 | #ifdef CONFIG_MIPS_MT_SMTC | ||
84 | mfc0 t0, CP0_CONFIG | ||
85 | bgez t0, 9f | ||
86 | mfc0 t0, CP0_CONFIG, 1 | ||
87 | bgez t0, 9f | ||
88 | mfc0 t0, CP0_CONFIG, 2 | ||
89 | bgez t0, 9f | ||
90 | mfc0 t0, CP0_CONFIG, 3 | ||
91 | and t0, 1<<2 | ||
92 | bnez t0, 0f | ||
93 | 9: | ||
94 | /* Assume we came from YAMON... */ | ||
95 | PTR_LA v0, 0x9fc00534 /* YAMON print */ | ||
96 | lw v0, (v0) | ||
97 | move a0, zero | ||
98 | PTR_LA a1, nonmt_processor | ||
99 | jal v0 | ||
100 | |||
101 | PTR_LA v0, 0x9fc00520 /* YAMON exit */ | ||
102 | lw v0, (v0) | ||
103 | li a0, 1 | ||
104 | jal v0 | ||
105 | |||
106 | 1: b 1b | ||
107 | |||
108 | __INITDATA | ||
109 | nonmt_processor: | ||
110 | .asciz "SMTC kernel requires the MT ASE to run\n" | ||
111 | __FINIT | ||
112 | #endif | ||
113 | 83 | ||
114 | #ifdef CONFIG_EVA | 84 | #ifdef CONFIG_EVA |
115 | sync | 85 | sync |
diff --git a/arch/mips/include/asm/mach-malta/malta-pm.h b/arch/mips/include/asm/mach-malta/malta-pm.h new file mode 100644 index 000000000000..c2c2e201013d --- /dev/null +++ b/arch/mips/include/asm/mach-malta/malta-pm.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Imagination Technologies | ||
3 | * Author: Paul Burton <paul.burton@imgtec.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #ifndef __ASM_MIPS_MACH_MALTA_PM_H__ | ||
12 | #define __ASM_MIPS_MACH_MALTA_PM_H__ | ||
13 | |||
14 | #include <asm/mips-boards/piix4.h> | ||
15 | |||
16 | #ifdef CONFIG_MIPS_MALTA_PM | ||
17 | |||
18 | /** | ||
19 | * mips_pm_suspend - enter a suspend state | ||
20 | * @state: the state to enter, one of PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_* | ||
21 | * | ||
22 | * Enters a suspend state via the Malta's PIIX4. If the state to be entered | ||
23 | * is one which loses context (eg. SOFF) then this function will never | ||
24 | * return. | ||
25 | */ | ||
26 | extern int mips_pm_suspend(unsigned state); | ||
27 | |||
28 | #else /* !CONFIG_MIPS_MALTA_PM */ | ||
29 | |||
30 | static inline int mips_pm_suspend(unsigned state) | ||
31 | { | ||
32 | return -EINVAL; | ||
33 | } | ||
34 | |||
35 | #endif /* !CONFIG_MIPS_MALTA_PM */ | ||
36 | |||
37 | #endif /* __ASM_MIPS_MACH_MALTA_PM_H__ */ | ||
diff --git a/arch/mips/include/asm/mach-netlogic/topology.h b/arch/mips/include/asm/mach-netlogic/topology.h index 0da99fa11c38..ceeb1f5e7129 100644 --- a/arch/mips/include/asm/mach-netlogic/topology.h +++ b/arch/mips/include/asm/mach-netlogic/topology.h | |||
@@ -10,10 +10,12 @@ | |||
10 | 10 | ||
11 | #include <asm/mach-netlogic/multi-node.h> | 11 | #include <asm/mach-netlogic/multi-node.h> |
12 | 12 | ||
13 | #ifdef CONFIG_SMP | ||
13 | #define topology_physical_package_id(cpu) cpu_to_node(cpu) | 14 | #define topology_physical_package_id(cpu) cpu_to_node(cpu) |
14 | #define topology_core_id(cpu) (cpu_logical_map(cpu) / NLM_THREADS_PER_CORE) | 15 | #define topology_core_id(cpu) (cpu_logical_map(cpu) / NLM_THREADS_PER_CORE) |
15 | #define topology_thread_cpumask(cpu) (&cpu_sibling_map[cpu]) | 16 | #define topology_thread_cpumask(cpu) (&cpu_sibling_map[cpu]) |
16 | #define topology_core_cpumask(cpu) cpumask_of_node(cpu_to_node(cpu)) | 17 | #define topology_core_cpumask(cpu) cpumask_of_node(cpu_to_node(cpu)) |
18 | #endif | ||
17 | 19 | ||
18 | #include <asm-generic/topology.h> | 20 | #include <asm-generic/topology.h> |
19 | 21 | ||
diff --git a/arch/mips/include/asm/mach-paravirt/cpu-feature-overrides.h b/arch/mips/include/asm/mach-paravirt/cpu-feature-overrides.h new file mode 100644 index 000000000000..725e1ed83f6a --- /dev/null +++ b/arch/mips/include/asm/mach-paravirt/cpu-feature-overrides.h | |||
@@ -0,0 +1,36 @@ | |||
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 | * Copyright (C) 2013 Cavium, Inc. | ||
7 | */ | ||
8 | #ifndef __ASM_MACH_PARAVIRT_CPU_FEATURE_OVERRIDES_H | ||
9 | #define __ASM_MACH_PARAVIRT_CPU_FEATURE_OVERRIDES_H | ||
10 | |||
11 | #define cpu_has_4kex 1 | ||
12 | #define cpu_has_3k_cache 0 | ||
13 | #define cpu_has_tx39_cache 0 | ||
14 | #define cpu_has_counter 1 | ||
15 | #define cpu_has_llsc 1 | ||
16 | /* | ||
17 | * We Disable LL/SC on non SMP systems as it is faster to disable | ||
18 | * interrupts for atomic access than a LL/SC. | ||
19 | */ | ||
20 | #ifdef CONFIG_SMP | ||
21 | # define kernel_uses_llsc 1 | ||
22 | #else | ||
23 | # define kernel_uses_llsc 0 | ||
24 | #endif | ||
25 | |||
26 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | ||
27 | #define cpu_dcache_line_size() 128 | ||
28 | #define cpu_icache_line_size() 128 | ||
29 | #define cpu_has_octeon_cache 1 | ||
30 | #define cpu_has_4k_cache 0 | ||
31 | #else | ||
32 | #define cpu_has_octeon_cache 0 | ||
33 | #define cpu_has_4k_cache 1 | ||
34 | #endif | ||
35 | |||
36 | #endif /* __ASM_MACH_PARAVIRT_CPU_FEATURE_OVERRIDES_H */ | ||
diff --git a/arch/mips/include/asm/mach-paravirt/irq.h b/arch/mips/include/asm/mach-paravirt/irq.h new file mode 100644 index 000000000000..9b4d35eca977 --- /dev/null +++ b/arch/mips/include/asm/mach-paravirt/irq.h | |||
@@ -0,0 +1,19 @@ | |||
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 | * Copyright (C) 2013 Cavium, Inc. | ||
7 | */ | ||
8 | #ifndef __ASM_MACH_PARAVIRT_IRQ_H__ | ||
9 | #define __ASM_MACH_PARAVIRT_IRQ_H__ | ||
10 | |||
11 | #define NR_IRQS 64 | ||
12 | #define MIPS_CPU_IRQ_BASE 1 | ||
13 | |||
14 | #define MIPS_IRQ_PCIA (MIPS_CPU_IRQ_BASE + 8) | ||
15 | |||
16 | #define MIPS_IRQ_MBOX0 (MIPS_CPU_IRQ_BASE + 32) | ||
17 | #define MIPS_IRQ_MBOX1 (MIPS_CPU_IRQ_BASE + 33) | ||
18 | |||
19 | #endif /* __ASM_MACH_PARAVIRT_IRQ_H__ */ | ||
diff --git a/arch/mips/include/asm/mach-paravirt/kernel-entry-init.h b/arch/mips/include/asm/mach-paravirt/kernel-entry-init.h new file mode 100644 index 000000000000..2f82bfa3a773 --- /dev/null +++ b/arch/mips/include/asm/mach-paravirt/kernel-entry-init.h | |||
@@ -0,0 +1,50 @@ | |||
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 | * Copyright (C) 2013 Cavium, Inc | ||
7 | */ | ||
8 | #ifndef __ASM_MACH_PARAVIRT_KERNEL_ENTRY_H | ||
9 | #define __ASM_MACH_PARAVIRT_KERNEL_ENTRY_H | ||
10 | |||
11 | #define CP0_EBASE $15, 1 | ||
12 | |||
13 | .macro kernel_entry_setup | ||
14 | mfc0 t0, CP0_EBASE | ||
15 | andi t0, t0, 0x3ff # CPUNum | ||
16 | beqz t0, 1f | ||
17 | # CPUs other than zero goto smp_bootstrap | ||
18 | j smp_bootstrap | ||
19 | |||
20 | 1: | ||
21 | .endm | ||
22 | |||
23 | /* | ||
24 | * Do SMP slave processor setup necessary before we can safely execute | ||
25 | * C code. | ||
26 | */ | ||
27 | .macro smp_slave_setup | ||
28 | mfc0 t0, CP0_EBASE | ||
29 | andi t0, t0, 0x3ff # CPUNum | ||
30 | slti t1, t0, NR_CPUS | ||
31 | bnez t1, 1f | ||
32 | 2: | ||
33 | di | ||
34 | wait | ||
35 | b 2b # Unknown CPU, loop forever. | ||
36 | 1: | ||
37 | PTR_LA t1, paravirt_smp_sp | ||
38 | PTR_SLL t0, PTR_SCALESHIFT | ||
39 | PTR_ADDU t1, t1, t0 | ||
40 | 3: | ||
41 | PTR_L sp, 0(t1) | ||
42 | beqz sp, 3b # Spin until told to proceed. | ||
43 | |||
44 | PTR_LA t1, paravirt_smp_gp | ||
45 | PTR_ADDU t1, t1, t0 | ||
46 | sync | ||
47 | PTR_L gp, 0(t1) | ||
48 | .endm | ||
49 | |||
50 | #endif /* __ASM_MACH_PARAVIRT_KERNEL_ENTRY_H */ | ||
diff --git a/arch/mips/include/asm/mach-paravirt/war.h b/arch/mips/include/asm/mach-paravirt/war.h new file mode 100644 index 000000000000..36d3afb98451 --- /dev/null +++ b/arch/mips/include/asm/mach-paravirt/war.h | |||
@@ -0,0 +1,25 @@ | |||
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 | * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org> | ||
7 | * Copyright (C) 2013 Cavium Networks <support@caviumnetworks.com> | ||
8 | */ | ||
9 | #ifndef __ASM_MIPS_MACH_PARAVIRT_WAR_H | ||
10 | #define __ASM_MIPS_MACH_PARAVIRT_WAR_H | ||
11 | |||
12 | #define R4600_V1_INDEX_ICACHEOP_WAR 0 | ||
13 | #define R4600_V1_HIT_CACHEOP_WAR 0 | ||
14 | #define R4600_V2_HIT_CACHEOP_WAR 0 | ||
15 | #define R5432_CP0_INTERRUPT_WAR 0 | ||
16 | #define BCM1250_M3_WAR 0 | ||
17 | #define SIBYTE_1956_WAR 0 | ||
18 | #define MIPS4K_ICACHE_REFILL_WAR 0 | ||
19 | #define MIPS_CACHE_SYNC_WAR 0 | ||
20 | #define TX49XX_ICACHE_INDEX_INV_WAR 0 | ||
21 | #define ICACHE_REFILLS_WORKAROUND_WAR 0 | ||
22 | #define R10000_LLSC_WAR 0 | ||
23 | #define MIPS34K_MISSED_ITLB_WAR 0 | ||
24 | |||
25 | #endif /* __ASM_MIPS_MACH_PARAVIRT_WAR_H */ | ||
diff --git a/arch/mips/include/asm/mach-pmcs-msp71xx/msp_usb.h b/arch/mips/include/asm/mach-pmcs-msp71xx/msp_usb.h index aa45e6a07126..fe1566f2913e 100644 --- a/arch/mips/include/asm/mach-pmcs-msp71xx/msp_usb.h +++ b/arch/mips/include/asm/mach-pmcs-msp71xx/msp_usb.h | |||
@@ -25,11 +25,7 @@ | |||
25 | #ifndef MSP_USB_H_ | 25 | #ifndef MSP_USB_H_ |
26 | #define MSP_USB_H_ | 26 | #define MSP_USB_H_ |
27 | 27 | ||
28 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
29 | #define NUM_USB_DEVS 2 | ||
30 | #else | ||
31 | #define NUM_USB_DEVS 1 | 28 | #define NUM_USB_DEVS 1 |
32 | #endif | ||
33 | 29 | ||
34 | /* Register spaces for USB host 0 */ | 30 | /* Register spaces for USB host 0 */ |
35 | #define MSP_USB0_MAB_START (MSP_USB0_BASE + 0x0) | 31 | #define MSP_USB0_MAB_START (MSP_USB0_BASE + 0x0) |
diff --git a/arch/mips/include/asm/mach-ralink/war.h b/arch/mips/include/asm/mach-ralink/war.h index a7b712cf2d28..c074b5dc1f82 100644 --- a/arch/mips/include/asm/mach-ralink/war.h +++ b/arch/mips/include/asm/mach-ralink/war.h | |||
@@ -17,7 +17,6 @@ | |||
17 | #define MIPS4K_ICACHE_REFILL_WAR 0 | 17 | #define MIPS4K_ICACHE_REFILL_WAR 0 |
18 | #define MIPS_CACHE_SYNC_WAR 0 | 18 | #define MIPS_CACHE_SYNC_WAR 0 |
19 | #define TX49XX_ICACHE_INDEX_INV_WAR 0 | 19 | #define TX49XX_ICACHE_INDEX_INV_WAR 0 |
20 | #define RM9000_CDEX_SMP_WAR 0 | ||
21 | #define ICACHE_REFILLS_WORKAROUND_WAR 0 | 20 | #define ICACHE_REFILLS_WORKAROUND_WAR 0 |
22 | #define R10000_LLSC_WAR 0 | 21 | #define R10000_LLSC_WAR 0 |
23 | #define MIPS34K_MISSED_ITLB_WAR 0 | 22 | #define MIPS34K_MISSED_ITLB_WAR 0 |
diff --git a/arch/mips/include/asm/mach-sead3/kernel-entry-init.h b/arch/mips/include/asm/mach-sead3/kernel-entry-init.h index 3dfbd8e7947f..6cccd4d558d7 100644 --- a/arch/mips/include/asm/mach-sead3/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-sead3/kernel-entry-init.h | |||
@@ -10,37 +10,6 @@ | |||
10 | #define __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H | 10 | #define __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H |
11 | 11 | ||
12 | .macro kernel_entry_setup | 12 | .macro kernel_entry_setup |
13 | #ifdef CONFIG_MIPS_MT_SMTC | ||
14 | mfc0 t0, CP0_CONFIG | ||
15 | bgez t0, 9f | ||
16 | mfc0 t0, CP0_CONFIG, 1 | ||
17 | bgez t0, 9f | ||
18 | mfc0 t0, CP0_CONFIG, 2 | ||
19 | bgez t0, 9f | ||
20 | mfc0 t0, CP0_CONFIG, 3 | ||
21 | and t0, 1<<2 | ||
22 | bnez t0, 0f | ||
23 | 9 : | ||
24 | /* Assume we came from YAMON... */ | ||
25 | PTR_LA v0, 0x9fc00534 /* YAMON print */ | ||
26 | lw v0, (v0) | ||
27 | move a0, zero | ||
28 | PTR_LA a1, nonmt_processor | ||
29 | jal v0 | ||
30 | |||
31 | PTR_LA v0, 0x9fc00520 /* YAMON exit */ | ||
32 | lw v0, (v0) | ||
33 | li a0, 1 | ||
34 | jal v0 | ||
35 | |||
36 | 1 : b 1b | ||
37 | |||
38 | __INITDATA | ||
39 | nonmt_processor : | ||
40 | .asciz "SMTC kernel requires the MT ASE to run\n" | ||
41 | __FINIT | ||
42 | 0 : | ||
43 | #endif | ||
44 | .endm | 13 | .endm |
45 | 14 | ||
46 | /* | 15 | /* |
diff --git a/arch/mips/include/asm/mips-boards/piix4.h b/arch/mips/include/asm/mips-boards/piix4.h index 9cf54041d416..9e340be52a50 100644 --- a/arch/mips/include/asm/mips-boards/piix4.h +++ b/arch/mips/include/asm/mips-boards/piix4.h | |||
@@ -55,4 +55,16 @@ | |||
55 | #define PIIX4_FUNC3_PMREGMISC 0x80 | 55 | #define PIIX4_FUNC3_PMREGMISC 0x80 |
56 | #define PIIX4_FUNC3_PMREGMISC_EN (1 << 0) | 56 | #define PIIX4_FUNC3_PMREGMISC_EN (1 << 0) |
57 | 57 | ||
58 | /* Power Management IO Space */ | ||
59 | #define PIIX4_FUNC3IO_PMSTS 0x00 | ||
60 | #define PIIX4_FUNC3IO_PMSTS_PWRBTN_STS (1 << 8) | ||
61 | #define PIIX4_FUNC3IO_PMCNTRL 0x04 | ||
62 | #define PIIX4_FUNC3IO_PMCNTRL_SUS_EN (1 << 13) | ||
63 | #define PIIX4_FUNC3IO_PMCNTRL_SUS_TYP (0x7 << 10) | ||
64 | #define PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_SOFF (0x0 << 10) | ||
65 | #define PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_STR (0x1 << 10) | ||
66 | |||
67 | /* Data for magic special PCI cycle */ | ||
68 | #define PIIX4_SUSPEND_MAGIC 0x00120002 | ||
69 | |||
58 | #endif /* __ASM_MIPS_BOARDS_PIIX4_H */ | 70 | #endif /* __ASM_MIPS_BOARDS_PIIX4_H */ |
diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h index 988507e46d42..e139a534e0fd 100644 --- a/arch/mips/include/asm/mips-cpc.h +++ b/arch/mips/include/asm/mips-cpc.h | |||
@@ -72,7 +72,12 @@ static inline bool mips_cpc_present(void) | |||
72 | #define MIPS_CPC_COCB_OFS 0x4000 | 72 | #define MIPS_CPC_COCB_OFS 0x4000 |
73 | 73 | ||
74 | /* Macros to ease the creation of register access functions */ | 74 | /* Macros to ease the creation of register access functions */ |
75 | #define BUILD_CPC_R_(name, off) \ | 75 | #define BUILD_CPC_R_(name, off) \ |
76 | static inline u32 *addr_cpc_##name(void) \ | ||
77 | { \ | ||
78 | return (u32 *)(mips_cpc_base + (off)); \ | ||
79 | } \ | ||
80 | \ | ||
76 | static inline u32 read_cpc_##name(void) \ | 81 | static inline u32 read_cpc_##name(void) \ |
77 | { \ | 82 | { \ |
78 | return __raw_readl(mips_cpc_base + (off)); \ | 83 | return __raw_readl(mips_cpc_base + (off)); \ |
@@ -147,4 +152,31 @@ BUILD_CPC_Cx_RW(other, 0x10) | |||
147 | #define CPC_Cx_OTHER_CORENUM_SHF 16 | 152 | #define CPC_Cx_OTHER_CORENUM_SHF 16 |
148 | #define CPC_Cx_OTHER_CORENUM_MSK (_ULCAST_(0xff) << 16) | 153 | #define CPC_Cx_OTHER_CORENUM_MSK (_ULCAST_(0xff) << 16) |
149 | 154 | ||
155 | #ifdef CONFIG_MIPS_CPC | ||
156 | |||
157 | /** | ||
158 | * mips_cpc_lock_other - lock access to another core | ||
159 | * core: the other core to be accessed | ||
160 | * | ||
161 | * Call before operating upon a core via the 'other' register region in | ||
162 | * order to prevent the region being moved during access. Must be followed | ||
163 | * by a call to mips_cpc_unlock_other. | ||
164 | */ | ||
165 | extern void mips_cpc_lock_other(unsigned int core); | ||
166 | |||
167 | /** | ||
168 | * mips_cpc_unlock_other - unlock access to another core | ||
169 | * | ||
170 | * Call after operating upon another core via the 'other' register region. | ||
171 | * Must be called after mips_cpc_lock_other. | ||
172 | */ | ||
173 | extern void mips_cpc_unlock_other(void); | ||
174 | |||
175 | #else /* !CONFIG_MIPS_CPC */ | ||
176 | |||
177 | static inline void mips_cpc_lock_other(unsigned int core) { } | ||
178 | static inline void mips_cpc_unlock_other(void) { } | ||
179 | |||
180 | #endif /* !CONFIG_MIPS_CPC */ | ||
181 | |||
150 | #endif /* __MIPS_ASM_MIPS_CPC_H__ */ | 182 | #endif /* __MIPS_ASM_MIPS_CPC_H__ */ |
diff --git a/arch/mips/include/asm/mips_mt.h b/arch/mips/include/asm/mips_mt.h index a3df0c3faa0e..f6ba004a7711 100644 --- a/arch/mips/include/asm/mips_mt.h +++ b/arch/mips/include/asm/mips_mt.h | |||
@@ -1,7 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Definitions and decalrations for MIPS MT support | 2 | * Definitions and decalrations for MIPS MT support that are common between |
3 | * that are common between SMTC, VSMP, and/or AP/SP | 3 | * the VSMP, and AP/SP kernel models. |
4 | * kernel models. | ||
5 | */ | 4 | */ |
6 | #ifndef __ASM_MIPS_MT_H | 5 | #ifndef __ASM_MIPS_MT_H |
7 | #define __ASM_MIPS_MT_H | 6 | #define __ASM_MIPS_MT_H |
diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h index 6efa79a27b6a..5f8052ce43bf 100644 --- a/arch/mips/include/asm/mipsmtregs.h +++ b/arch/mips/include/asm/mipsmtregs.h | |||
@@ -36,6 +36,8 @@ | |||
36 | 36 | ||
37 | #define read_c0_tcbind() __read_32bit_c0_register($2, 2) | 37 | #define read_c0_tcbind() __read_32bit_c0_register($2, 2) |
38 | 38 | ||
39 | #define write_c0_tchalt(val) __write_32bit_c0_register($2, 4, val) | ||
40 | |||
39 | #define read_c0_tccontext() __read_32bit_c0_register($2, 5) | 41 | #define read_c0_tccontext() __read_32bit_c0_register($2, 5) |
40 | #define write_c0_tccontext(val) __write_32bit_c0_register($2, 5, val) | 42 | #define write_c0_tccontext(val) __write_32bit_c0_register($2, 5, val) |
41 | 43 | ||
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 3e025b5311db..98e9754a4b6b 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h | |||
@@ -709,11 +709,18 @@ | |||
709 | #ifndef __ASSEMBLY__ | 709 | #ifndef __ASSEMBLY__ |
710 | 710 | ||
711 | /* | 711 | /* |
712 | * Macros for handling the ISA mode bit for microMIPS. | 712 | * Macros for handling the ISA mode bit for MIPS16 and microMIPS. |
713 | */ | 713 | */ |
714 | #if defined(CONFIG_SYS_SUPPORTS_MIPS16) || \ | ||
715 | defined(CONFIG_SYS_SUPPORTS_MICROMIPS) | ||
714 | #define get_isa16_mode(x) ((x) & 0x1) | 716 | #define get_isa16_mode(x) ((x) & 0x1) |
715 | #define msk_isa16_mode(x) ((x) & ~0x1) | 717 | #define msk_isa16_mode(x) ((x) & ~0x1) |
716 | #define set_isa16_mode(x) do { (x) |= 0x1; } while(0) | 718 | #define set_isa16_mode(x) do { (x) |= 0x1; } while(0) |
719 | #else | ||
720 | #define get_isa16_mode(x) 0 | ||
721 | #define msk_isa16_mode(x) (x) | ||
722 | #define set_isa16_mode(x) do { } while(0) | ||
723 | #endif | ||
717 | 724 | ||
718 | /* | 725 | /* |
719 | * microMIPS instructions can be 16-bit or 32-bit in length. This | 726 | * microMIPS instructions can be 16-bit or 32-bit in length. This |
@@ -1007,19 +1014,8 @@ do { \ | |||
1007 | #define write_c0_compare3(val) __write_32bit_c0_register($11, 7, val) | 1014 | #define write_c0_compare3(val) __write_32bit_c0_register($11, 7, val) |
1008 | 1015 | ||
1009 | #define read_c0_status() __read_32bit_c0_register($12, 0) | 1016 | #define read_c0_status() __read_32bit_c0_register($12, 0) |
1010 | #ifdef CONFIG_MIPS_MT_SMTC | 1017 | |
1011 | #define write_c0_status(val) \ | ||
1012 | do { \ | ||
1013 | __write_32bit_c0_register($12, 0, val); \ | ||
1014 | __ehb(); \ | ||
1015 | } while (0) | ||
1016 | #else | ||
1017 | /* | ||
1018 | * Legacy non-SMTC code, which may be hazardous | ||
1019 | * but which might not support EHB | ||
1020 | */ | ||
1021 | #define write_c0_status(val) __write_32bit_c0_register($12, 0, val) | 1018 | #define write_c0_status(val) __write_32bit_c0_register($12, 0, val) |
1022 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
1023 | 1019 | ||
1024 | #define read_c0_cause() __read_32bit_c0_register($13, 0) | 1020 | #define read_c0_cause() __read_32bit_c0_register($13, 0) |
1025 | #define write_c0_cause(val) __write_32bit_c0_register($13, 0, val) | 1021 | #define write_c0_cause(val) __write_32bit_c0_register($13, 0, val) |
@@ -1743,11 +1739,6 @@ static inline void tlb_write_random(void) | |||
1743 | /* | 1739 | /* |
1744 | * Manipulate bits in a c0 register. | 1740 | * Manipulate bits in a c0 register. |
1745 | */ | 1741 | */ |
1746 | #ifndef CONFIG_MIPS_MT_SMTC | ||
1747 | /* | ||
1748 | * SMTC Linux requires shutting-down microthread scheduling | ||
1749 | * during CP0 register read-modify-write sequences. | ||
1750 | */ | ||
1751 | #define __BUILD_SET_C0(name) \ | 1742 | #define __BUILD_SET_C0(name) \ |
1752 | static inline unsigned int \ | 1743 | static inline unsigned int \ |
1753 | set_c0_##name(unsigned int set) \ | 1744 | set_c0_##name(unsigned int set) \ |
@@ -1786,121 +1777,6 @@ change_c0_##name(unsigned int change, unsigned int val) \ | |||
1786 | return res; \ | 1777 | return res; \ |
1787 | } | 1778 | } |
1788 | 1779 | ||
1789 | #else /* SMTC versions that manage MT scheduling */ | ||
1790 | |||
1791 | #include <linux/irqflags.h> | ||
1792 | |||
1793 | /* | ||
1794 | * This is a duplicate of dmt() in mipsmtregs.h to avoid problems with | ||
1795 | * header file recursion. | ||
1796 | */ | ||
1797 | static inline unsigned int __dmt(void) | ||
1798 | { | ||
1799 | int res; | ||
1800 | |||
1801 | __asm__ __volatile__( | ||
1802 | " .set push \n" | ||
1803 | " .set mips32r2 \n" | ||
1804 | " .set noat \n" | ||
1805 | " .word 0x41610BC1 # dmt $1 \n" | ||
1806 | " ehb \n" | ||
1807 | " move %0, $1 \n" | ||
1808 | " .set pop \n" | ||
1809 | : "=r" (res)); | ||
1810 | |||
1811 | instruction_hazard(); | ||
1812 | |||
1813 | return res; | ||
1814 | } | ||
1815 | |||
1816 | #define __VPECONTROL_TE_SHIFT 15 | ||
1817 | #define __VPECONTROL_TE (1UL << __VPECONTROL_TE_SHIFT) | ||
1818 | |||
1819 | #define __EMT_ENABLE __VPECONTROL_TE | ||
1820 | |||
1821 | static inline void __emt(unsigned int previous) | ||
1822 | { | ||
1823 | if ((previous & __EMT_ENABLE)) | ||
1824 | __asm__ __volatile__( | ||
1825 | " .set mips32r2 \n" | ||
1826 | " .word 0x41600be1 # emt \n" | ||
1827 | " ehb \n" | ||
1828 | " .set mips0 \n"); | ||
1829 | } | ||
1830 | |||
1831 | static inline void __ehb(void) | ||
1832 | { | ||
1833 | __asm__ __volatile__( | ||
1834 | " .set mips32r2 \n" | ||
1835 | " ehb \n" " .set mips0 \n"); | ||
1836 | } | ||
1837 | |||
1838 | /* | ||
1839 | * Note that local_irq_save/restore affect TC-specific IXMT state, | ||
1840 | * not Status.IE as in non-SMTC kernel. | ||
1841 | */ | ||
1842 | |||
1843 | #define __BUILD_SET_C0(name) \ | ||
1844 | static inline unsigned int \ | ||
1845 | set_c0_##name(unsigned int set) \ | ||
1846 | { \ | ||
1847 | unsigned int res; \ | ||
1848 | unsigned int new; \ | ||
1849 | unsigned int omt; \ | ||
1850 | unsigned long flags; \ | ||
1851 | \ | ||
1852 | local_irq_save(flags); \ | ||
1853 | omt = __dmt(); \ | ||
1854 | res = read_c0_##name(); \ | ||
1855 | new = res | set; \ | ||
1856 | write_c0_##name(new); \ | ||
1857 | __emt(omt); \ | ||
1858 | local_irq_restore(flags); \ | ||
1859 | \ | ||
1860 | return res; \ | ||
1861 | } \ | ||
1862 | \ | ||
1863 | static inline unsigned int \ | ||
1864 | clear_c0_##name(unsigned int clear) \ | ||
1865 | { \ | ||
1866 | unsigned int res; \ | ||
1867 | unsigned int new; \ | ||
1868 | unsigned int omt; \ | ||
1869 | unsigned long flags; \ | ||
1870 | \ | ||
1871 | local_irq_save(flags); \ | ||
1872 | omt = __dmt(); \ | ||
1873 | res = read_c0_##name(); \ | ||
1874 | new = res & ~clear; \ | ||
1875 | write_c0_##name(new); \ | ||
1876 | __emt(omt); \ | ||
1877 | local_irq_restore(flags); \ | ||
1878 | \ | ||
1879 | return res; \ | ||
1880 | } \ | ||
1881 | \ | ||
1882 | static inline unsigned int \ | ||
1883 | change_c0_##name(unsigned int change, unsigned int newbits) \ | ||
1884 | { \ | ||
1885 | unsigned int res; \ | ||
1886 | unsigned int new; \ | ||
1887 | unsigned int omt; \ | ||
1888 | unsigned long flags; \ | ||
1889 | \ | ||
1890 | local_irq_save(flags); \ | ||
1891 | \ | ||
1892 | omt = __dmt(); \ | ||
1893 | res = read_c0_##name(); \ | ||
1894 | new = res & ~change; \ | ||
1895 | new |= (newbits & change); \ | ||
1896 | write_c0_##name(new); \ | ||
1897 | __emt(omt); \ | ||
1898 | local_irq_restore(flags); \ | ||
1899 | \ | ||
1900 | return res; \ | ||
1901 | } | ||
1902 | #endif | ||
1903 | |||
1904 | __BUILD_SET_C0(status) | 1780 | __BUILD_SET_C0(status) |
1905 | __BUILD_SET_C0(cause) | 1781 | __BUILD_SET_C0(cause) |
1906 | __BUILD_SET_C0(config) | 1782 | __BUILD_SET_C0(config) |
@@ -1916,6 +1792,15 @@ __BUILD_SET_C0(brcm_cmt_ctrl) | |||
1916 | __BUILD_SET_C0(brcm_config) | 1792 | __BUILD_SET_C0(brcm_config) |
1917 | __BUILD_SET_C0(brcm_mode) | 1793 | __BUILD_SET_C0(brcm_mode) |
1918 | 1794 | ||
1795 | /* | ||
1796 | * Return low 10 bits of ebase. | ||
1797 | * Note that under KVM (MIPSVZ) this returns vcpu id. | ||
1798 | */ | ||
1799 | static inline unsigned int get_ebase_cpunum(void) | ||
1800 | { | ||
1801 | return read_c0_ebase() & 0x3ff; | ||
1802 | } | ||
1803 | |||
1919 | #endif /* !__ASSEMBLY__ */ | 1804 | #endif /* !__ASSEMBLY__ */ |
1920 | 1805 | ||
1921 | #endif /* _ASM_MIPSREGS_H */ | 1806 | #endif /* _ASM_MIPSREGS_H */ |
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index e277bbad2871..2e373da5f8e9 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h | |||
@@ -18,10 +18,6 @@ | |||
18 | #include <asm/cacheflush.h> | 18 | #include <asm/cacheflush.h> |
19 | #include <asm/hazards.h> | 19 | #include <asm/hazards.h> |
20 | #include <asm/tlbflush.h> | 20 | #include <asm/tlbflush.h> |
21 | #ifdef CONFIG_MIPS_MT_SMTC | ||
22 | #include <asm/mipsmtregs.h> | ||
23 | #include <asm/smtc.h> | ||
24 | #endif /* SMTC */ | ||
25 | #include <asm-generic/mm_hooks.h> | 21 | #include <asm-generic/mm_hooks.h> |
26 | 22 | ||
27 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ | 23 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ |
@@ -31,11 +27,15 @@ do { \ | |||
31 | } while (0) | 27 | } while (0) |
32 | 28 | ||
33 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | 29 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT |
30 | |||
31 | #define TLBMISS_HANDLER_RESTORE() \ | ||
32 | write_c0_xcontext((unsigned long) smp_processor_id() << \ | ||
33 | SMP_CPUID_REGSHIFT) | ||
34 | |||
34 | #define TLBMISS_HANDLER_SETUP() \ | 35 | #define TLBMISS_HANDLER_SETUP() \ |
35 | do { \ | 36 | do { \ |
36 | TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir); \ | 37 | TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir); \ |
37 | write_c0_xcontext((unsigned long) smp_processor_id() << \ | 38 | TLBMISS_HANDLER_RESTORE(); \ |
38 | SMP_CPUID_REGSHIFT); \ | ||
39 | } while (0) | 39 | } while (0) |
40 | 40 | ||
41 | #else /* !CONFIG_MIPS_PGD_C0_CONTEXT: using pgd_current*/ | 41 | #else /* !CONFIG_MIPS_PGD_C0_CONTEXT: using pgd_current*/ |
@@ -47,9 +47,12 @@ do { \ | |||
47 | */ | 47 | */ |
48 | extern unsigned long pgd_current[]; | 48 | extern unsigned long pgd_current[]; |
49 | 49 | ||
50 | #define TLBMISS_HANDLER_SETUP() \ | 50 | #define TLBMISS_HANDLER_RESTORE() \ |
51 | write_c0_context((unsigned long) smp_processor_id() << \ | 51 | write_c0_context((unsigned long) smp_processor_id() << \ |
52 | SMP_CPUID_REGSHIFT); \ | 52 | SMP_CPUID_REGSHIFT) |
53 | |||
54 | #define TLBMISS_HANDLER_SETUP() \ | ||
55 | TLBMISS_HANDLER_RESTORE(); \ | ||
53 | back_to_back_c0_hazard(); \ | 56 | back_to_back_c0_hazard(); \ |
54 | TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) | 57 | TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) |
55 | #endif /* CONFIG_MIPS_PGD_C0_CONTEXT*/ | 58 | #endif /* CONFIG_MIPS_PGD_C0_CONTEXT*/ |
@@ -63,13 +66,6 @@ extern unsigned long pgd_current[]; | |||
63 | #define ASID_INC 0x10 | 66 | #define ASID_INC 0x10 |
64 | #define ASID_MASK 0xff0 | 67 | #define ASID_MASK 0xff0 |
65 | 68 | ||
66 | #elif defined(CONFIG_MIPS_MT_SMTC) | ||
67 | |||
68 | #define ASID_INC 0x1 | ||
69 | extern unsigned long smtc_asid_mask; | ||
70 | #define ASID_MASK (smtc_asid_mask) | ||
71 | #define HW_ASID_MASK 0xff | ||
72 | /* End SMTC/34K debug hack */ | ||
73 | #else /* FIXME: not correct for R6000 */ | 69 | #else /* FIXME: not correct for R6000 */ |
74 | 70 | ||
75 | #define ASID_INC 0x1 | 71 | #define ASID_INC 0x1 |
@@ -92,7 +88,6 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) | |||
92 | #define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1))) | 88 | #define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1))) |
93 | #define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1) | 89 | #define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1) |
94 | 90 | ||
95 | #ifndef CONFIG_MIPS_MT_SMTC | ||
96 | /* Normal, classic MIPS get_new_mmu_context */ | 91 | /* Normal, classic MIPS get_new_mmu_context */ |
97 | static inline void | 92 | static inline void |
98 | get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) | 93 | get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) |
@@ -115,12 +110,6 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) | |||
115 | cpu_context(cpu, mm) = asid_cache(cpu) = asid; | 110 | cpu_context(cpu, mm) = asid_cache(cpu) = asid; |
116 | } | 111 | } |
117 | 112 | ||
118 | #else /* CONFIG_MIPS_MT_SMTC */ | ||
119 | |||
120 | #define get_new_mmu_context(mm, cpu) smtc_get_new_mmu_context((mm), (cpu)) | ||
121 | |||
122 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
123 | |||
124 | /* | 113 | /* |
125 | * Initialize the context related info for a new mm_struct | 114 | * Initialize the context related info for a new mm_struct |
126 | * instance. | 115 | * instance. |
@@ -141,46 +130,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, | |||
141 | { | 130 | { |
142 | unsigned int cpu = smp_processor_id(); | 131 | unsigned int cpu = smp_processor_id(); |
143 | unsigned long flags; | 132 | unsigned long flags; |
144 | #ifdef CONFIG_MIPS_MT_SMTC | ||
145 | unsigned long oldasid; | ||
146 | unsigned long mtflags; | ||
147 | int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id; | ||
148 | local_irq_save(flags); | 133 | local_irq_save(flags); |
149 | mtflags = dvpe(); | ||
150 | #else /* Not SMTC */ | ||
151 | local_irq_save(flags); | ||
152 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
153 | 134 | ||
154 | /* Check if our ASID is of an older version and thus invalid */ | 135 | /* Check if our ASID is of an older version and thus invalid */ |
155 | if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK) | 136 | if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK) |
156 | get_new_mmu_context(next, cpu); | 137 | get_new_mmu_context(next, cpu); |
157 | #ifdef CONFIG_MIPS_MT_SMTC | ||
158 | /* | ||
159 | * If the EntryHi ASID being replaced happens to be | ||
160 | * the value flagged at ASID recycling time as having | ||
161 | * an extended life, clear the bit showing it being | ||
162 | * in use by this "CPU", and if that's the last bit, | ||
163 | * free up the ASID value for use and flush any old | ||
164 | * instances of it from the TLB. | ||
165 | */ | ||
166 | oldasid = (read_c0_entryhi() & ASID_MASK); | ||
167 | if(smtc_live_asid[mytlb][oldasid]) { | ||
168 | smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu); | ||
169 | if(smtc_live_asid[mytlb][oldasid] == 0) | ||
170 | smtc_flush_tlb_asid(oldasid); | ||
171 | } | ||
172 | /* | ||
173 | * Tread softly on EntryHi, and so long as we support | ||
174 | * having ASID_MASK smaller than the hardware maximum, | ||
175 | * make sure no "soft" bits become "hard"... | ||
176 | */ | ||
177 | write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) | | ||
178 | cpu_asid(cpu, next)); | ||
179 | ehb(); /* Make sure it propagates to TCStatus */ | ||
180 | evpe(mtflags); | ||
181 | #else | ||
182 | write_c0_entryhi(cpu_asid(cpu, next)); | 138 | write_c0_entryhi(cpu_asid(cpu, next)); |
183 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
184 | TLBMISS_HANDLER_SETUP_PGD(next->pgd); | 139 | TLBMISS_HANDLER_SETUP_PGD(next->pgd); |
185 | 140 | ||
186 | /* | 141 | /* |
@@ -213,34 +168,12 @@ activate_mm(struct mm_struct *prev, struct mm_struct *next) | |||
213 | unsigned long flags; | 168 | unsigned long flags; |
214 | unsigned int cpu = smp_processor_id(); | 169 | unsigned int cpu = smp_processor_id(); |
215 | 170 | ||
216 | #ifdef CONFIG_MIPS_MT_SMTC | ||
217 | unsigned long oldasid; | ||
218 | unsigned long mtflags; | ||
219 | int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id; | ||
220 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
221 | |||
222 | local_irq_save(flags); | 171 | local_irq_save(flags); |
223 | 172 | ||
224 | /* Unconditionally get a new ASID. */ | 173 | /* Unconditionally get a new ASID. */ |
225 | get_new_mmu_context(next, cpu); | 174 | get_new_mmu_context(next, cpu); |
226 | 175 | ||
227 | #ifdef CONFIG_MIPS_MT_SMTC | ||
228 | /* See comments for similar code above */ | ||
229 | mtflags = dvpe(); | ||
230 | oldasid = read_c0_entryhi() & ASID_MASK; | ||
231 | if(smtc_live_asid[mytlb][oldasid]) { | ||
232 | smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu); | ||
233 | if(smtc_live_asid[mytlb][oldasid] == 0) | ||
234 | smtc_flush_tlb_asid(oldasid); | ||
235 | } | ||
236 | /* See comments for similar code above */ | ||
237 | write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) | | ||
238 | cpu_asid(cpu, next)); | ||
239 | ehb(); /* Make sure it propagates to TCStatus */ | ||
240 | evpe(mtflags); | ||
241 | #else | ||
242 | write_c0_entryhi(cpu_asid(cpu, next)); | 176 | write_c0_entryhi(cpu_asid(cpu, next)); |
243 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
244 | TLBMISS_HANDLER_SETUP_PGD(next->pgd); | 177 | TLBMISS_HANDLER_SETUP_PGD(next->pgd); |
245 | 178 | ||
246 | /* mark mmu ownership change */ | 179 | /* mark mmu ownership change */ |
@@ -258,48 +191,15 @@ static inline void | |||
258 | drop_mmu_context(struct mm_struct *mm, unsigned cpu) | 191 | drop_mmu_context(struct mm_struct *mm, unsigned cpu) |
259 | { | 192 | { |
260 | unsigned long flags; | 193 | unsigned long flags; |
261 | #ifdef CONFIG_MIPS_MT_SMTC | ||
262 | unsigned long oldasid; | ||
263 | /* Can't use spinlock because called from TLB flush within DVPE */ | ||
264 | unsigned int prevvpe; | ||
265 | int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id; | ||
266 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
267 | 194 | ||
268 | local_irq_save(flags); | 195 | local_irq_save(flags); |
269 | 196 | ||
270 | if (cpumask_test_cpu(cpu, mm_cpumask(mm))) { | 197 | if (cpumask_test_cpu(cpu, mm_cpumask(mm))) { |
271 | get_new_mmu_context(mm, cpu); | 198 | get_new_mmu_context(mm, cpu); |
272 | #ifdef CONFIG_MIPS_MT_SMTC | ||
273 | /* See comments for similar code above */ | ||
274 | prevvpe = dvpe(); | ||
275 | oldasid = (read_c0_entryhi() & ASID_MASK); | ||
276 | if (smtc_live_asid[mytlb][oldasid]) { | ||
277 | smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu); | ||
278 | if(smtc_live_asid[mytlb][oldasid] == 0) | ||
279 | smtc_flush_tlb_asid(oldasid); | ||
280 | } | ||
281 | /* See comments for similar code above */ | ||
282 | write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) | ||
283 | | cpu_asid(cpu, mm)); | ||
284 | ehb(); /* Make sure it propagates to TCStatus */ | ||
285 | evpe(prevvpe); | ||
286 | #else /* not CONFIG_MIPS_MT_SMTC */ | ||
287 | write_c0_entryhi(cpu_asid(cpu, mm)); | 199 | write_c0_entryhi(cpu_asid(cpu, mm)); |
288 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
289 | } else { | 200 | } else { |
290 | /* will get a new context next time */ | 201 | /* will get a new context next time */ |
291 | #ifndef CONFIG_MIPS_MT_SMTC | ||
292 | cpu_context(cpu, mm) = 0; | 202 | cpu_context(cpu, mm) = 0; |
293 | #else /* SMTC */ | ||
294 | int i; | ||
295 | |||
296 | /* SMTC shares the TLB (and ASIDs) across VPEs */ | ||
297 | for_each_online_cpu(i) { | ||
298 | if((smtc_status & SMTC_TLB_SHARED) | ||
299 | || (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id)) | ||
300 | cpu_context(i, mm) = 0; | ||
301 | } | ||
302 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
303 | } | 203 | } |
304 | local_irq_restore(flags); | 204 | local_irq_restore(flags); |
305 | } | 205 | } |
diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h index c2edae382d5d..800fe578dc99 100644 --- a/arch/mips/include/asm/module.h +++ b/arch/mips/include/asm/module.h | |||
@@ -144,13 +144,7 @@ search_module_dbetables(unsigned long addr) | |||
144 | #define MODULE_KERNEL_TYPE "64BIT " | 144 | #define MODULE_KERNEL_TYPE "64BIT " |
145 | #endif | 145 | #endif |
146 | 146 | ||
147 | #ifdef CONFIG_MIPS_MT_SMTC | ||
148 | #define MODULE_KERNEL_SMTC "MT_SMTC " | ||
149 | #else | ||
150 | #define MODULE_KERNEL_SMTC "" | ||
151 | #endif | ||
152 | |||
153 | #define MODULE_ARCH_VERMAGIC \ | 147 | #define MODULE_ARCH_VERMAGIC \ |
154 | MODULE_PROC_FAMILY MODULE_KERNEL_TYPE MODULE_KERNEL_SMTC | 148 | MODULE_PROC_FAMILY MODULE_KERNEL_TYPE |
155 | 149 | ||
156 | #endif /* _ASM_MODULE_H */ | 150 | #endif /* _ASM_MODULE_H */ |
diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h index a2aba6c3ec05..538f6d482db8 100644 --- a/arch/mips/include/asm/msa.h +++ b/arch/mips/include/asm/msa.h | |||
@@ -84,7 +84,7 @@ static inline void write_msa_##name(unsigned int val) \ | |||
84 | __asm__ __volatile__( \ | 84 | __asm__ __volatile__( \ |
85 | " .set push\n" \ | 85 | " .set push\n" \ |
86 | " .set msa\n" \ | 86 | " .set msa\n" \ |
87 | " cfcmsa $" #cs ", %0\n" \ | 87 | " ctcmsa $" #cs ", %0\n" \ |
88 | " .set pop\n" \ | 88 | " .set pop\n" \ |
89 | : : "r"(val)); \ | 89 | : : "r"(val)); \ |
90 | } | 90 | } |
@@ -96,6 +96,13 @@ static inline void write_msa_##name(unsigned int val) \ | |||
96 | * allow compilation with toolchains that do not support MSA. Once all | 96 | * allow compilation with toolchains that do not support MSA. Once all |
97 | * toolchains in use support MSA these can be removed. | 97 | * toolchains in use support MSA these can be removed. |
98 | */ | 98 | */ |
99 | #ifdef CONFIG_CPU_MICROMIPS | ||
100 | #define CFC_MSA_INSN 0x587e0056 | ||
101 | #define CTC_MSA_INSN 0x583e0816 | ||
102 | #else | ||
103 | #define CFC_MSA_INSN 0x787e0059 | ||
104 | #define CTC_MSA_INSN 0x783e0819 | ||
105 | #endif | ||
99 | 106 | ||
100 | #define __BUILD_MSA_CTL_REG(name, cs) \ | 107 | #define __BUILD_MSA_CTL_REG(name, cs) \ |
101 | static inline unsigned int read_msa_##name(void) \ | 108 | static inline unsigned int read_msa_##name(void) \ |
@@ -104,7 +111,8 @@ static inline unsigned int read_msa_##name(void) \ | |||
104 | __asm__ __volatile__( \ | 111 | __asm__ __volatile__( \ |
105 | " .set push\n" \ | 112 | " .set push\n" \ |
106 | " .set noat\n" \ | 113 | " .set noat\n" \ |
107 | " .word 0x787e0059 | (" #cs " << 11)\n" \ | 114 | " .insn\n" \ |
115 | " .word #CFC_MSA_INSN | (" #cs " << 11)\n" \ | ||
108 | " move %0, $1\n" \ | 116 | " move %0, $1\n" \ |
109 | " .set pop\n" \ | 117 | " .set pop\n" \ |
110 | : "=r"(reg)); \ | 118 | : "=r"(reg)); \ |
@@ -117,7 +125,8 @@ static inline void write_msa_##name(unsigned int val) \ | |||
117 | " .set push\n" \ | 125 | " .set push\n" \ |
118 | " .set noat\n" \ | 126 | " .set noat\n" \ |
119 | " move $1, %0\n" \ | 127 | " move $1, %0\n" \ |
120 | " .word 0x783e0819 | (" #cs " << 6)\n" \ | 128 | " .insn\n" \ |
129 | " .word #CTC_MSA_INSN | (" #cs " << 6)\n" \ | ||
121 | " .set pop\n" \ | 130 | " .set pop\n" \ |
122 | : : "r"(val)); \ | 131 | : : "r"(val)); \ |
123 | } | 132 | } |
diff --git a/arch/mips/include/asm/netlogic/mips-extns.h b/arch/mips/include/asm/netlogic/mips-extns.h index de9aada6f4c1..06f1f75bfa9b 100644 --- a/arch/mips/include/asm/netlogic/mips-extns.h +++ b/arch/mips/include/asm/netlogic/mips-extns.h | |||
@@ -146,9 +146,10 @@ static inline int hard_smp_processor_id(void) | |||
146 | 146 | ||
147 | static inline int nlm_nodeid(void) | 147 | static inline int nlm_nodeid(void) |
148 | { | 148 | { |
149 | uint32_t prid = read_c0_prid(); | 149 | uint32_t prid = read_c0_prid() & PRID_IMP_MASK; |
150 | 150 | ||
151 | if ((prid & 0xff00) == PRID_IMP_NETLOGIC_XLP9XX) | 151 | if ((prid == PRID_IMP_NETLOGIC_XLP9XX) || |
152 | (prid == PRID_IMP_NETLOGIC_XLP5XX)) | ||
152 | return (__read_32bit_c0_register($15, 1) >> 7) & 0x7; | 153 | return (__read_32bit_c0_register($15, 1) >> 7) & 0x7; |
153 | else | 154 | else |
154 | return (__read_32bit_c0_register($15, 1) >> 5) & 0x3; | 155 | return (__read_32bit_c0_register($15, 1) >> 5) & 0x3; |
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h index 1f23dfaa7167..805bfd21f33e 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h | |||
@@ -74,6 +74,8 @@ | |||
74 | #define XLP_IO_USB_OHCI2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 4) | 74 | #define XLP_IO_USB_OHCI2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 4) |
75 | #define XLP_IO_USB_OHCI3_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 5) | 75 | #define XLP_IO_USB_OHCI3_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 5) |
76 | 76 | ||
77 | #define XLP_IO_SATA_OFFSET(node) XLP_HDR_OFFSET(node, 0, 3, 2) | ||
78 | |||
77 | /* XLP2xx has an updated USB block */ | 79 | /* XLP2xx has an updated USB block */ |
78 | #define XLP2XX_IO_USB_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 4, i) | 80 | #define XLP2XX_IO_USB_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 4, i) |
79 | #define XLP2XX_IO_USB_XHCI0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 4, 1) | 81 | #define XLP2XX_IO_USB_XHCI0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 4, 1) |
@@ -103,13 +105,11 @@ | |||
103 | #define XLP_IO_SYS_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 5) | 105 | #define XLP_IO_SYS_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 5) |
104 | #define XLP_IO_JTAG_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 6) | 106 | #define XLP_IO_JTAG_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 6) |
105 | 107 | ||
108 | /* Flash */ | ||
106 | #define XLP_IO_NOR_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 0) | 109 | #define XLP_IO_NOR_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 0) |
107 | #define XLP_IO_NAND_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 1) | 110 | #define XLP_IO_NAND_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 1) |
108 | #define XLP_IO_SPI_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 2) | 111 | #define XLP_IO_SPI_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 2) |
109 | /* SD flash */ | 112 | #define XLP_IO_MMC_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 3) |
110 | #define XLP_IO_SD_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 3) | ||
111 | #define XLP_IO_MMC_OFFSET(node, slot) \ | ||
112 | ((XLP_IO_SD_OFFSET(node))+(slot*0x100)+XLP_IO_PCI_HDRSZ) | ||
113 | 113 | ||
114 | /* Things have changed drastically in XLP 9XX */ | 114 | /* Things have changed drastically in XLP 9XX */ |
115 | #define XLP9XX_HDR_OFFSET(n, d, f) \ | 115 | #define XLP9XX_HDR_OFFSET(n, d, f) \ |
@@ -120,6 +120,8 @@ | |||
120 | #define XLP9XX_IO_UART_OFFSET(node) XLP9XX_HDR_OFFSET(node, 2, 2) | 120 | #define XLP9XX_IO_UART_OFFSET(node) XLP9XX_HDR_OFFSET(node, 2, 2) |
121 | #define XLP9XX_IO_SYS_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 0) | 121 | #define XLP9XX_IO_SYS_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 0) |
122 | #define XLP9XX_IO_FUSE_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 1) | 122 | #define XLP9XX_IO_FUSE_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 1) |
123 | #define XLP9XX_IO_CLOCK_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 2) | ||
124 | #define XLP9XX_IO_POWER_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 3) | ||
123 | #define XLP9XX_IO_JTAG_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 4) | 125 | #define XLP9XX_IO_JTAG_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 4) |
124 | 126 | ||
125 | #define XLP9XX_IO_PCIE_OFFSET(node, i) XLP9XX_HDR_OFFSET(node, 1, i) | 127 | #define XLP9XX_IO_PCIE_OFFSET(node, i) XLP9XX_HDR_OFFSET(node, 1, i) |
@@ -135,11 +137,11 @@ | |||
135 | /* XLP9XX on-chip SATA controller */ | 137 | /* XLP9XX on-chip SATA controller */ |
136 | #define XLP9XX_IO_SATA_OFFSET(node) XLP9XX_HDR_OFFSET(node, 3, 2) | 138 | #define XLP9XX_IO_SATA_OFFSET(node) XLP9XX_HDR_OFFSET(node, 3, 2) |
137 | 139 | ||
140 | /* Flash */ | ||
138 | #define XLP9XX_IO_NOR_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 0) | 141 | #define XLP9XX_IO_NOR_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 0) |
139 | #define XLP9XX_IO_NAND_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 1) | 142 | #define XLP9XX_IO_NAND_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 1) |
140 | #define XLP9XX_IO_SPI_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 2) | 143 | #define XLP9XX_IO_SPI_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 2) |
141 | /* SD flash */ | 144 | #define XLP9XX_IO_MMC_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 3) |
142 | #define XLP9XX_IO_MMCSD_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 3) | ||
143 | 145 | ||
144 | /* PCI config header register id's */ | 146 | /* PCI config header register id's */ |
145 | #define XLP_PCI_CFGREG0 0x00 | 147 | #define XLP_PCI_CFGREG0 0x00 |
@@ -186,8 +188,10 @@ | |||
186 | #define PCI_DEVICE_ID_NLM_NOR 0x1015 | 188 | #define PCI_DEVICE_ID_NLM_NOR 0x1015 |
187 | #define PCI_DEVICE_ID_NLM_NAND 0x1016 | 189 | #define PCI_DEVICE_ID_NLM_NAND 0x1016 |
188 | #define PCI_DEVICE_ID_NLM_MMC 0x1018 | 190 | #define PCI_DEVICE_ID_NLM_MMC 0x1018 |
189 | #define PCI_DEVICE_ID_NLM_XHCI 0x101d | 191 | #define PCI_DEVICE_ID_NLM_SATA 0x101A |
192 | #define PCI_DEVICE_ID_NLM_XHCI 0x101D | ||
190 | 193 | ||
194 | #define PCI_DEVICE_ID_XLP9XX_MMC 0x9018 | ||
191 | #define PCI_DEVICE_ID_XLP9XX_SATA 0x901A | 195 | #define PCI_DEVICE_ID_XLP9XX_SATA 0x901A |
192 | #define PCI_DEVICE_ID_XLP9XX_XHCI 0x901D | 196 | #define PCI_DEVICE_ID_XLP9XX_XHCI 0x901D |
193 | 197 | ||
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h index d4deb87ad069..91540f41e1e4 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h | |||
@@ -69,6 +69,20 @@ | |||
69 | #define PCIE_9XX_BYTE_SWAP_IO_BASE 0x25e | 69 | #define PCIE_9XX_BYTE_SWAP_IO_BASE 0x25e |
70 | #define PCIE_9XX_BYTE_SWAP_IO_LIM 0x25f | 70 | #define PCIE_9XX_BYTE_SWAP_IO_LIM 0x25f |
71 | 71 | ||
72 | #define PCIE_9XX_BRIDGE_MSIX_ADDR_BASE 0x264 | ||
73 | #define PCIE_9XX_BRIDGE_MSIX_ADDR_LIMIT 0x265 | ||
74 | #define PCIE_9XX_MSI_STATUS 0x283 | ||
75 | #define PCIE_9XX_MSI_EN 0x284 | ||
76 | /* 128 MSIX vectors available in 9xx */ | ||
77 | #define PCIE_9XX_MSIX_STATUS0 0x286 | ||
78 | #define PCIE_9XX_MSIX_STATUSX(n) (n + 0x286) | ||
79 | #define PCIE_9XX_MSIX_VEC 0x296 | ||
80 | #define PCIE_9XX_MSIX_VECX(n) (n + 0x296) | ||
81 | #define PCIE_9XX_INT_STATUS0 0x397 | ||
82 | #define PCIE_9XX_INT_STATUS1 0x398 | ||
83 | #define PCIE_9XX_INT_EN0 0x399 | ||
84 | #define PCIE_9XX_INT_EN1 0x39a | ||
85 | |||
72 | /* other */ | 86 | /* other */ |
73 | #define PCIE_NLINKS 4 | 87 | #define PCIE_NLINKS 4 |
74 | 88 | ||
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pic.h b/arch/mips/include/asm/netlogic/xlp-hal/pic.h index f10bf3bba58f..41cefe94f0c9 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/pic.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/pic.h | |||
@@ -199,6 +199,10 @@ | |||
199 | #define PIC_IRT_PCIE_LINK_3_INDEX 81 | 199 | #define PIC_IRT_PCIE_LINK_3_INDEX 81 |
200 | #define PIC_IRT_PCIE_LINK_INDEX(num) ((num) + PIC_IRT_PCIE_LINK_0_INDEX) | 200 | #define PIC_IRT_PCIE_LINK_INDEX(num) ((num) + PIC_IRT_PCIE_LINK_0_INDEX) |
201 | 201 | ||
202 | #define PIC_9XX_IRT_PCIE_LINK_0_INDEX 191 | ||
203 | #define PIC_9XX_IRT_PCIE_LINK_INDEX(num) \ | ||
204 | ((num) + PIC_9XX_IRT_PCIE_LINK_0_INDEX) | ||
205 | |||
202 | #define PIC_CLOCK_TIMER 7 | 206 | #define PIC_CLOCK_TIMER 7 |
203 | 207 | ||
204 | #if !defined(LOCORE) && !defined(__ASSEMBLY__) | 208 | #if !defined(LOCORE) && !defined(__ASSEMBLY__) |
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/sys.h b/arch/mips/include/asm/netlogic/xlp-hal/sys.h index d9b107ffca93..bc7bddf25be9 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/sys.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/sys.h | |||
@@ -118,6 +118,10 @@ | |||
118 | #define SYS_SCRTCH3 0x4c | 118 | #define SYS_SCRTCH3 0x4c |
119 | 119 | ||
120 | /* PLL registers XLP2XX */ | 120 | /* PLL registers XLP2XX */ |
121 | #define SYS_CPU_PLL_CTRL0(core) (0x1c0 + (core * 4)) | ||
122 | #define SYS_CPU_PLL_CTRL1(core) (0x1c1 + (core * 4)) | ||
123 | #define SYS_CPU_PLL_CTRL2(core) (0x1c2 + (core * 4)) | ||
124 | #define SYS_CPU_PLL_CTRL3(core) (0x1c3 + (core * 4)) | ||
121 | #define SYS_PLL_CTRL0 0x240 | 125 | #define SYS_PLL_CTRL0 0x240 |
122 | #define SYS_PLL_CTRL1 0x241 | 126 | #define SYS_PLL_CTRL1 0x241 |
123 | #define SYS_PLL_CTRL2 0x242 | 127 | #define SYS_PLL_CTRL2 0x242 |
@@ -147,6 +151,32 @@ | |||
147 | #define SYS_SYS_PLL_MEM_REQ 0x2a3 | 151 | #define SYS_SYS_PLL_MEM_REQ 0x2a3 |
148 | #define SYS_PLL_MEM_STAT 0x2a4 | 152 | #define SYS_PLL_MEM_STAT 0x2a4 |
149 | 153 | ||
154 | /* PLL registers XLP9XX */ | ||
155 | #define SYS_9XX_CPU_PLL_CTRL0(core) (0xc0 + (core * 4)) | ||
156 | #define SYS_9XX_CPU_PLL_CTRL1(core) (0xc1 + (core * 4)) | ||
157 | #define SYS_9XX_CPU_PLL_CTRL2(core) (0xc2 + (core * 4)) | ||
158 | #define SYS_9XX_CPU_PLL_CTRL3(core) (0xc3 + (core * 4)) | ||
159 | #define SYS_9XX_DMC_PLL_CTRL0 0x140 | ||
160 | #define SYS_9XX_DMC_PLL_CTRL1 0x141 | ||
161 | #define SYS_9XX_DMC_PLL_CTRL2 0x142 | ||
162 | #define SYS_9XX_DMC_PLL_CTRL3 0x143 | ||
163 | #define SYS_9XX_PLL_CTRL0 0x144 | ||
164 | #define SYS_9XX_PLL_CTRL1 0x145 | ||
165 | #define SYS_9XX_PLL_CTRL2 0x146 | ||
166 | #define SYS_9XX_PLL_CTRL3 0x147 | ||
167 | |||
168 | #define SYS_9XX_PLL_CTRL0_DEVX(x) (0x148 + (x) * 4) | ||
169 | #define SYS_9XX_PLL_CTRL1_DEVX(x) (0x149 + (x) * 4) | ||
170 | #define SYS_9XX_PLL_CTRL2_DEVX(x) (0x14a + (x) * 4) | ||
171 | #define SYS_9XX_PLL_CTRL3_DEVX(x) (0x14b + (x) * 4) | ||
172 | |||
173 | #define SYS_9XX_CPU_PLL_CHG_CTRL 0x188 | ||
174 | #define SYS_9XX_PLL_CHG_CTRL 0x189 | ||
175 | #define SYS_9XX_CLK_DEV_DIS 0x18a | ||
176 | #define SYS_9XX_CLK_DEV_SEL 0x18b | ||
177 | #define SYS_9XX_CLK_DEV_DIV 0x18d | ||
178 | #define SYS_9XX_CLK_DEV_CHG 0x18f | ||
179 | |||
150 | /* Registers changed on 9XX */ | 180 | /* Registers changed on 9XX */ |
151 | #define SYS_9XX_POWER_ON_RESET_CFG 0x00 | 181 | #define SYS_9XX_POWER_ON_RESET_CFG 0x00 |
152 | #define SYS_9XX_CHIP_RESET 0x01 | 182 | #define SYS_9XX_CHIP_RESET 0x01 |
@@ -170,6 +200,11 @@ | |||
170 | #define nlm_get_fuse_regbase(node) \ | 200 | #define nlm_get_fuse_regbase(node) \ |
171 | (nlm_get_fuse_pcibase(node) + XLP_IO_PCI_HDRSZ) | 201 | (nlm_get_fuse_pcibase(node) + XLP_IO_PCI_HDRSZ) |
172 | 202 | ||
203 | #define nlm_get_clock_pcibase(node) \ | ||
204 | nlm_pcicfg_base(XLP9XX_IO_CLOCK_OFFSET(node)) | ||
205 | #define nlm_get_clock_regbase(node) \ | ||
206 | (nlm_get_clock_pcibase(node) + XLP_IO_PCI_HDRSZ) | ||
207 | |||
173 | unsigned int nlm_get_pic_frequency(int node); | 208 | unsigned int nlm_get_pic_frequency(int node); |
174 | #endif | 209 | #endif |
175 | #endif | 210 | #endif |
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h index 2b0c9599ebe5..a862b93223cc 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h | |||
@@ -58,6 +58,10 @@ | |||
58 | #define PIC_I2C_1_IRQ 31 | 58 | #define PIC_I2C_1_IRQ 31 |
59 | #define PIC_I2C_2_IRQ 32 | 59 | #define PIC_I2C_2_IRQ 32 |
60 | #define PIC_I2C_3_IRQ 33 | 60 | #define PIC_I2C_3_IRQ 33 |
61 | #define PIC_SPI_IRQ 34 | ||
62 | #define PIC_NAND_IRQ 37 | ||
63 | #define PIC_SATA_IRQ 38 | ||
64 | #define PIC_GPIO_IRQ 39 | ||
61 | 65 | ||
62 | #define PIC_PCIE_LINK_MSI_IRQ_BASE 44 /* 44 - 47 MSI IRQ */ | 66 | #define PIC_PCIE_LINK_MSI_IRQ_BASE 44 /* 44 - 47 MSI IRQ */ |
63 | #define PIC_PCIE_LINK_MSI_IRQ(i) (44 + (i)) | 67 | #define PIC_PCIE_LINK_MSI_IRQ(i) (44 + (i)) |
@@ -66,8 +70,9 @@ | |||
66 | #define PIC_PCIE_MSIX_IRQ_BASE 48 /* 48 - 51 MSI-X IRQ */ | 70 | #define PIC_PCIE_MSIX_IRQ_BASE 48 /* 48 - 51 MSI-X IRQ */ |
67 | #define PIC_PCIE_MSIX_IRQ(i) (48 + (i)) | 71 | #define PIC_PCIE_MSIX_IRQ(i) (48 + (i)) |
68 | 72 | ||
69 | #define NLM_MSIX_VEC_BASE 96 /* 96 - 127 - MSIX mapped */ | 73 | /* XLP9xx and XLP8xx has 128 and 32 MSIX vectors respectively */ |
70 | #define NLM_MSI_VEC_BASE 128 /* 128 -255 - MSI mapped */ | 74 | #define NLM_MSIX_VEC_BASE 96 /* 96 - 223 - MSIX mapped */ |
75 | #define NLM_MSI_VEC_BASE 224 /* 224 -351 - MSI mapped */ | ||
71 | 76 | ||
72 | #define NLM_PIC_INDIRECT_VEC_BASE 512 | 77 | #define NLM_PIC_INDIRECT_VEC_BASE 512 |
73 | #define NLM_GPIO_VEC_BASE 768 | 78 | #define NLM_GPIO_VEC_BASE 768 |
@@ -95,17 +100,19 @@ void *xlp_dt_init(void *fdtp); | |||
95 | 100 | ||
96 | static inline int cpu_is_xlpii(void) | 101 | static inline int cpu_is_xlpii(void) |
97 | { | 102 | { |
98 | int chip = read_c0_prid() & 0xff00; | 103 | int chip = read_c0_prid() & PRID_IMP_MASK; |
99 | 104 | ||
100 | return chip == PRID_IMP_NETLOGIC_XLP2XX || | 105 | return chip == PRID_IMP_NETLOGIC_XLP2XX || |
101 | chip == PRID_IMP_NETLOGIC_XLP9XX; | 106 | chip == PRID_IMP_NETLOGIC_XLP9XX || |
107 | chip == PRID_IMP_NETLOGIC_XLP5XX; | ||
102 | } | 108 | } |
103 | 109 | ||
104 | static inline int cpu_is_xlp9xx(void) | 110 | static inline int cpu_is_xlp9xx(void) |
105 | { | 111 | { |
106 | int chip = read_c0_prid() & 0xff00; | 112 | int chip = read_c0_prid() & PRID_IMP_MASK; |
107 | 113 | ||
108 | return chip == PRID_IMP_NETLOGIC_XLP9XX; | 114 | return chip == PRID_IMP_NETLOGIC_XLP9XX || |
115 | chip == PRID_IMP_NETLOGIC_XLP5XX; | ||
109 | } | 116 | } |
110 | #endif /* !__ASSEMBLY__ */ | 117 | #endif /* !__ASSEMBLY__ */ |
111 | #endif /* _ASM_NLM_XLP_H */ | 118 | #endif /* _ASM_NLM_XLP_H */ |
diff --git a/arch/mips/include/asm/nile4.h b/arch/mips/include/asm/nile4.h index 2e2436d0e94e..99e97f8bfbca 100644 --- a/arch/mips/include/asm/nile4.h +++ b/arch/mips/include/asm/nile4.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * asm-mips/nile4.h -- NEC Vrc-5074 Nile 4 definitions | 2 | * asm-mips/nile4.h -- NEC Vrc-5074 Nile 4 definitions |
3 | * | 3 | * |
4 | * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> | 4 | * Copyright (C) 2000 Geert Uytterhoeven <geert@linux-m68k.org> |
5 | * Sony Software Development Center Europe (SDCE), Brussels | 5 | * Sony Software Development Center Europe (SDCE), Brussels |
6 | * | 6 | * |
7 | * This file is based on the following documentation: | 7 | * This file is based on the following documentation: |
diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index f5d77b91537f..d781f9e66884 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h | |||
@@ -211,7 +211,6 @@ union octeon_cvmemctl { | |||
211 | 211 | ||
212 | extern void octeon_write_lcd(const char *s); | 212 | extern void octeon_write_lcd(const char *s); |
213 | extern void octeon_check_cpu_bist(void); | 213 | extern void octeon_check_cpu_bist(void); |
214 | extern int octeon_get_boot_debug_flag(void); | ||
215 | extern int octeon_get_boot_uart(void); | 214 | extern int octeon_get_boot_uart(void); |
216 | 215 | ||
217 | struct uart_port; | 216 | struct uart_port; |
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 008324d1c261..539ddd148bbb 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h | |||
@@ -32,6 +32,8 @@ struct vm_area_struct; | |||
32 | _page_cachable_default) | 32 | _page_cachable_default) |
33 | #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ | 33 | #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ |
34 | _PAGE_GLOBAL | _page_cachable_default) | 34 | _PAGE_GLOBAL | _page_cachable_default) |
35 | #define PAGE_KERNEL_NC __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ | ||
36 | _PAGE_GLOBAL | _CACHE_CACHABLE_NONCOHERENT) | ||
35 | #define PAGE_USERIO __pgprot(_PAGE_PRESENT | (cpu_has_rixi ? 0 : _PAGE_READ) | _PAGE_WRITE | \ | 37 | #define PAGE_USERIO __pgprot(_PAGE_PRESENT | (cpu_has_rixi ? 0 : _PAGE_READ) | _PAGE_WRITE | \ |
36 | _page_cachable_default) | 38 | _page_cachable_default) |
37 | #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | \ | 39 | #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | \ |
diff --git a/arch/mips/include/asm/pm-cps.h b/arch/mips/include/asm/pm-cps.h new file mode 100644 index 000000000000..625eda53d571 --- /dev/null +++ b/arch/mips/include/asm/pm-cps.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Imagination Technologies | ||
3 | * Author: Paul Burton <paul.burton@imgtec.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #ifndef __MIPS_ASM_PM_CPS_H__ | ||
12 | #define __MIPS_ASM_PM_CPS_H__ | ||
13 | |||
14 | /* | ||
15 | * The CM & CPC can only handle coherence & power control on a per-core basis, | ||
16 | * thus in an MT system the VPEs within each core are coupled and can only | ||
17 | * enter or exit states requiring CM or CPC assistance in unison. | ||
18 | */ | ||
19 | #ifdef CONFIG_MIPS_MT | ||
20 | # define coupled_coherence cpu_has_mipsmt | ||
21 | #else | ||
22 | # define coupled_coherence 0 | ||
23 | #endif | ||
24 | |||
25 | /* Enumeration of possible PM states */ | ||
26 | enum cps_pm_state { | ||
27 | CPS_PM_NC_WAIT, /* MIPS wait instruction, non-coherent */ | ||
28 | CPS_PM_CLOCK_GATED, /* Core clock gated */ | ||
29 | CPS_PM_POWER_GATED, /* Core power gated */ | ||
30 | CPS_PM_STATE_COUNT, | ||
31 | }; | ||
32 | |||
33 | /** | ||
34 | * cps_pm_support_state - determine whether the system supports a PM state | ||
35 | * @state: the state to test for support | ||
36 | * | ||
37 | * Returns true if the system supports the given state, otherwise false. | ||
38 | */ | ||
39 | extern bool cps_pm_support_state(enum cps_pm_state state); | ||
40 | |||
41 | /** | ||
42 | * cps_pm_enter_state - enter a PM state | ||
43 | * @state: the state to enter | ||
44 | * | ||
45 | * Enter the given PM state. If coupled_coherence is non-zero then it is | ||
46 | * expected that this function be called at approximately the same time on | ||
47 | * each coupled CPU. Returns 0 on successful entry & exit, otherwise -errno. | ||
48 | */ | ||
49 | extern int cps_pm_enter_state(enum cps_pm_state state); | ||
50 | |||
51 | #endif /* __MIPS_ASM_PM_CPS_H__ */ | ||
diff --git a/arch/mips/include/asm/pm.h b/arch/mips/include/asm/pm.h new file mode 100644 index 000000000000..7c03469e043f --- /dev/null +++ b/arch/mips/include/asm/pm.h | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Imagination Technologies Ltd | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * PM helper macros for CPU power off (e.g. Suspend-to-RAM). | ||
10 | */ | ||
11 | |||
12 | #ifndef __ASM_PM_H | ||
13 | #define __ASM_PM_H | ||
14 | |||
15 | #ifdef __ASSEMBLY__ | ||
16 | |||
17 | #include <asm/asm-offsets.h> | ||
18 | #include <asm/asm.h> | ||
19 | #include <asm/mipsregs.h> | ||
20 | #include <asm/regdef.h> | ||
21 | |||
22 | /* Save CPU state to stack for suspend to RAM */ | ||
23 | .macro SUSPEND_SAVE_REGS | ||
24 | subu sp, PT_SIZE | ||
25 | /* Call preserved GPRs */ | ||
26 | LONG_S $16, PT_R16(sp) | ||
27 | LONG_S $17, PT_R17(sp) | ||
28 | LONG_S $18, PT_R18(sp) | ||
29 | LONG_S $19, PT_R19(sp) | ||
30 | LONG_S $20, PT_R20(sp) | ||
31 | LONG_S $21, PT_R21(sp) | ||
32 | LONG_S $22, PT_R22(sp) | ||
33 | LONG_S $23, PT_R23(sp) | ||
34 | LONG_S $28, PT_R28(sp) | ||
35 | LONG_S $30, PT_R30(sp) | ||
36 | LONG_S $31, PT_R31(sp) | ||
37 | /* A couple of CP0 registers with space in pt_regs */ | ||
38 | mfc0 k0, CP0_STATUS | ||
39 | LONG_S k0, PT_STATUS(sp) | ||
40 | .endm | ||
41 | |||
42 | /* Restore CPU state from stack after resume from RAM */ | ||
43 | .macro RESUME_RESTORE_REGS_RETURN | ||
44 | .set push | ||
45 | .set noreorder | ||
46 | /* A couple of CP0 registers with space in pt_regs */ | ||
47 | LONG_L k0, PT_STATUS(sp) | ||
48 | mtc0 k0, CP0_STATUS | ||
49 | /* Call preserved GPRs */ | ||
50 | LONG_L $16, PT_R16(sp) | ||
51 | LONG_L $17, PT_R17(sp) | ||
52 | LONG_L $18, PT_R18(sp) | ||
53 | LONG_L $19, PT_R19(sp) | ||
54 | LONG_L $20, PT_R20(sp) | ||
55 | LONG_L $21, PT_R21(sp) | ||
56 | LONG_L $22, PT_R22(sp) | ||
57 | LONG_L $23, PT_R23(sp) | ||
58 | LONG_L $28, PT_R28(sp) | ||
59 | LONG_L $30, PT_R30(sp) | ||
60 | LONG_L $31, PT_R31(sp) | ||
61 | /* Pop and return */ | ||
62 | jr ra | ||
63 | addiu sp, PT_SIZE | ||
64 | .set pop | ||
65 | .endm | ||
66 | |||
67 | /* Get address of static suspend state into t1 */ | ||
68 | .macro LA_STATIC_SUSPEND | ||
69 | la t1, mips_static_suspend_state | ||
70 | .endm | ||
71 | |||
72 | /* Save important CPU state for early restoration to global data */ | ||
73 | .macro SUSPEND_SAVE_STATIC | ||
74 | #ifdef CONFIG_EVA | ||
75 | /* | ||
76 | * Segment configuration is saved in global data where it can be easily | ||
77 | * reloaded without depending on the segment configuration. | ||
78 | */ | ||
79 | mfc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */ | ||
80 | LONG_S k0, SSS_SEGCTL0(t1) | ||
81 | mfc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */ | ||
82 | LONG_S k0, SSS_SEGCTL1(t1) | ||
83 | mfc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */ | ||
84 | LONG_S k0, SSS_SEGCTL2(t1) | ||
85 | #endif | ||
86 | /* save stack pointer (pointing to GPRs) */ | ||
87 | LONG_S sp, SSS_SP(t1) | ||
88 | .endm | ||
89 | |||
90 | /* Restore important CPU state early from global data */ | ||
91 | .macro RESUME_RESTORE_STATIC | ||
92 | #ifdef CONFIG_EVA | ||
93 | /* | ||
94 | * Segment configuration must be restored prior to any access to | ||
95 | * allocated memory, as it may reside outside of the legacy kernel | ||
96 | * segments. | ||
97 | */ | ||
98 | LONG_L k0, SSS_SEGCTL0(t1) | ||
99 | mtc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */ | ||
100 | LONG_L k0, SSS_SEGCTL1(t1) | ||
101 | mtc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */ | ||
102 | LONG_L k0, SSS_SEGCTL2(t1) | ||
103 | mtc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */ | ||
104 | tlbw_use_hazard | ||
105 | #endif | ||
106 | /* restore stack pointer (pointing to GPRs) */ | ||
107 | LONG_L sp, SSS_SP(t1) | ||
108 | .endm | ||
109 | |||
110 | /* flush caches to make sure context has reached memory */ | ||
111 | .macro SUSPEND_CACHE_FLUSH | ||
112 | .extern __wback_cache_all | ||
113 | .set push | ||
114 | .set noreorder | ||
115 | la t1, __wback_cache_all | ||
116 | LONG_L t0, 0(t1) | ||
117 | jalr t0 | ||
118 | nop | ||
119 | .set pop | ||
120 | .endm | ||
121 | |||
122 | /* Save suspend state and flush data caches to RAM */ | ||
123 | .macro SUSPEND_SAVE | ||
124 | SUSPEND_SAVE_REGS | ||
125 | LA_STATIC_SUSPEND | ||
126 | SUSPEND_SAVE_STATIC | ||
127 | SUSPEND_CACHE_FLUSH | ||
128 | .endm | ||
129 | |||
130 | /* Restore saved state after resume from RAM and return */ | ||
131 | .macro RESUME_RESTORE_RETURN | ||
132 | LA_STATIC_SUSPEND | ||
133 | RESUME_RESTORE_STATIC | ||
134 | RESUME_RESTORE_REGS_RETURN | ||
135 | .endm | ||
136 | |||
137 | #else /* __ASSEMBLY__ */ | ||
138 | |||
139 | /** | ||
140 | * struct mips_static_suspend_state - Core saved CPU state across S2R. | ||
141 | * @segctl: CP0 Segment control registers. | ||
142 | * @sp: Stack frame where GP register context is saved. | ||
143 | * | ||
144 | * This structure contains minimal CPU state that must be saved in static kernel | ||
145 | * data in order to be able to restore the rest of the state. This includes | ||
146 | * segmentation configuration in the case of EVA being enabled, as they must be | ||
147 | * restored prior to any kmalloc'd memory being referenced (even the stack | ||
148 | * pointer). | ||
149 | */ | ||
150 | struct mips_static_suspend_state { | ||
151 | #ifdef CONFIG_EVA | ||
152 | unsigned long segctl[3]; | ||
153 | #endif | ||
154 | unsigned long sp; | ||
155 | }; | ||
156 | |||
157 | #endif /* !__ASSEMBLY__ */ | ||
158 | |||
159 | #endif /* __ASM_PM_HELPERS_H */ | ||
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index bf1ac8d35783..7e6e682aece3 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h | |||
@@ -39,9 +39,6 @@ struct pt_regs { | |||
39 | unsigned long cp0_badvaddr; | 39 | unsigned long cp0_badvaddr; |
40 | unsigned long cp0_cause; | 40 | unsigned long cp0_cause; |
41 | unsigned long cp0_epc; | 41 | unsigned long cp0_epc; |
42 | #ifdef CONFIG_MIPS_MT_SMTC | ||
43 | unsigned long cp0_tcstatus; | ||
44 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
45 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 42 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
46 | unsigned long long mpl[3]; /* MTM{0,1,2} */ | 43 | unsigned long long mpl[3]; /* MTM{0,1,2} */ |
47 | unsigned long long mtp[3]; /* MTP{0,1,2} */ | 44 | unsigned long long mtp[3]; /* MTP{0,1,2} */ |
diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index ca64cbe44493..0b8bd28a0df1 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h | |||
@@ -43,11 +43,10 @@ | |||
43 | : "i" (op), "R" (*(unsigned char *)(addr))) | 43 | : "i" (op), "R" (*(unsigned char *)(addr))) |
44 | 44 | ||
45 | #ifdef CONFIG_MIPS_MT | 45 | #ifdef CONFIG_MIPS_MT |
46 | |||
46 | /* | 47 | /* |
47 | * Temporary hacks for SMTC debug. Optionally force single-threaded | 48 | * Optionally force single-threaded execution during I-cache flushes. |
48 | * execution during I-cache flushes. | ||
49 | */ | 49 | */ |
50 | |||
51 | #define PROTECT_CACHE_FLUSHES 1 | 50 | #define PROTECT_CACHE_FLUSHES 1 |
52 | 51 | ||
53 | #ifdef PROTECT_CACHE_FLUSHES | 52 | #ifdef PROTECT_CACHE_FLUSHES |
@@ -524,6 +523,8 @@ __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32, | |||
524 | __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64, ) | 523 | __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64, ) |
525 | __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, ) | 524 | __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, ) |
526 | __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, ) | 525 | __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, ) |
526 | __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 128, ) | ||
527 | __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 128, ) | ||
527 | __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, ) | 528 | __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, ) |
528 | 529 | ||
529 | __BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16, ) | 530 | __BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16, ) |
diff --git a/arch/mips/include/asm/sgi/ip22.h b/arch/mips/include/asm/sgi/ip22.h index 8db1a3588cf2..87ec9eaa04e3 100644 --- a/arch/mips/include/asm/sgi/ip22.h +++ b/arch/mips/include/asm/sgi/ip22.h | |||
@@ -69,6 +69,8 @@ | |||
69 | #define SGI_EISA_IRQ SGINT_LOCAL2 + 3 /* EISA interrupts */ | 69 | #define SGI_EISA_IRQ SGINT_LOCAL2 + 3 /* EISA interrupts */ |
70 | #define SGI_KEYBD_IRQ SGINT_LOCAL2 + 4 /* keyboard */ | 70 | #define SGI_KEYBD_IRQ SGINT_LOCAL2 + 4 /* keyboard */ |
71 | #define SGI_SERIAL_IRQ SGINT_LOCAL2 + 5 /* onboard serial */ | 71 | #define SGI_SERIAL_IRQ SGINT_LOCAL2 + 5 /* onboard serial */ |
72 | #define SGI_GIOEXP0_IRQ (SGINT_LOCAL2 + 6) /* Indy GIO EXP0 */ | ||
73 | #define SGI_GIOEXP1_IRQ (SGINT_LOCAL2 + 7) /* Indy GIO EXP1 */ | ||
72 | 74 | ||
73 | #define ip22_is_fullhouse() (sgioc->sysid & SGIOC_SYSID_FULLHOUSE) | 75 | #define ip22_is_fullhouse() (sgioc->sysid & SGIOC_SYSID_FULLHOUSE) |
74 | 76 | ||
diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h index d60d1a2180d1..a06a08a9afc6 100644 --- a/arch/mips/include/asm/smp-cps.h +++ b/arch/mips/include/asm/smp-cps.h | |||
@@ -13,17 +13,28 @@ | |||
13 | 13 | ||
14 | #ifndef __ASSEMBLY__ | 14 | #ifndef __ASSEMBLY__ |
15 | 15 | ||
16 | struct boot_config { | 16 | struct vpe_boot_config { |
17 | unsigned int core; | ||
18 | unsigned int vpe; | ||
19 | unsigned long pc; | 17 | unsigned long pc; |
20 | unsigned long sp; | 18 | unsigned long sp; |
21 | unsigned long gp; | 19 | unsigned long gp; |
22 | }; | 20 | }; |
23 | 21 | ||
24 | extern struct boot_config mips_cps_bootcfg; | 22 | struct core_boot_config { |
23 | atomic_t vpe_mask; | ||
24 | struct vpe_boot_config *vpe_config; | ||
25 | }; | ||
26 | |||
27 | extern struct core_boot_config *mips_cps_core_bootcfg; | ||
25 | 28 | ||
26 | extern void mips_cps_core_entry(void); | 29 | extern void mips_cps_core_entry(void); |
30 | extern void mips_cps_core_init(void); | ||
31 | |||
32 | extern struct vpe_boot_config *mips_cps_boot_vpes(void); | ||
33 | |||
34 | extern bool mips_cps_smp_in_use(void); | ||
35 | |||
36 | extern void mips_cps_pm_save(void); | ||
37 | extern void mips_cps_pm_restore(void); | ||
27 | 38 | ||
28 | #else /* __ASSEMBLY__ */ | 39 | #else /* __ASSEMBLY__ */ |
29 | 40 | ||
diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h index 73d35b18fb64..6ba1fb8b11e2 100644 --- a/arch/mips/include/asm/smp-ops.h +++ b/arch/mips/include/asm/smp-ops.h | |||
@@ -26,7 +26,6 @@ struct plat_smp_ops { | |||
26 | void (*send_ipi_mask)(const struct cpumask *mask, unsigned int action); | 26 | void (*send_ipi_mask)(const struct cpumask *mask, unsigned int action); |
27 | void (*init_secondary)(void); | 27 | void (*init_secondary)(void); |
28 | void (*smp_finish)(void); | 28 | void (*smp_finish)(void); |
29 | void (*cpus_done)(void); | ||
30 | void (*boot_secondary)(int cpu, struct task_struct *idle); | 29 | void (*boot_secondary)(int cpu, struct task_struct *idle); |
31 | void (*smp_setup)(void); | 30 | void (*smp_setup)(void); |
32 | void (*prepare_cpus)(unsigned int max_cpus); | 31 | void (*prepare_cpus)(unsigned int max_cpus); |
diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index efa02acd3dd5..b037334fca22 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h | |||
@@ -46,6 +46,9 @@ extern int __cpu_logical_map[NR_CPUS]; | |||
46 | 46 | ||
47 | extern volatile cpumask_t cpu_callin_map; | 47 | extern volatile cpumask_t cpu_callin_map; |
48 | 48 | ||
49 | /* Mask of CPUs which are currently definitely operating coherently */ | ||
50 | extern cpumask_t cpu_coherent_mask; | ||
51 | |||
49 | extern void asmlinkage smp_bootstrap(void); | 52 | extern void asmlinkage smp_bootstrap(void); |
50 | 53 | ||
51 | /* | 54 | /* |
diff --git a/arch/mips/include/asm/smtc.h b/arch/mips/include/asm/smtc.h deleted file mode 100644 index e56b439b7871..000000000000 --- a/arch/mips/include/asm/smtc.h +++ /dev/null | |||
@@ -1,78 +0,0 @@ | |||
1 | #ifndef _ASM_SMTC_MT_H | ||
2 | #define _ASM_SMTC_MT_H | ||
3 | |||
4 | /* | ||
5 | * Definitions for SMTC multitasking on MIPS MT cores | ||
6 | */ | ||
7 | |||
8 | #include <asm/mips_mt.h> | ||
9 | #include <asm/smtc_ipi.h> | ||
10 | |||
11 | /* | ||
12 | * System-wide SMTC status information | ||
13 | */ | ||
14 | |||
15 | extern unsigned int smtc_status; | ||
16 | |||
17 | #define SMTC_TLB_SHARED 0x00000001 | ||
18 | #define SMTC_MTC_ACTIVE 0x00000002 | ||
19 | |||
20 | /* | ||
21 | * TLB/ASID Management information | ||
22 | */ | ||
23 | |||
24 | #define MAX_SMTC_TLBS 2 | ||
25 | #define MAX_SMTC_ASIDS 256 | ||
26 | #if NR_CPUS <= 8 | ||
27 | typedef char asiduse; | ||
28 | #else | ||
29 | #if NR_CPUS <= 16 | ||
30 | typedef short asiduse; | ||
31 | #else | ||
32 | typedef long asiduse; | ||
33 | #endif | ||
34 | #endif | ||
35 | |||
36 | /* | ||
37 | * VPE Management information | ||
38 | */ | ||
39 | |||
40 | #define MAX_SMTC_VPES MAX_SMTC_TLBS /* FIXME: May not always be true. */ | ||
41 | |||
42 | extern asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS]; | ||
43 | |||
44 | struct mm_struct; | ||
45 | struct task_struct; | ||
46 | |||
47 | void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu); | ||
48 | void self_ipi(struct smtc_ipi *); | ||
49 | void smtc_flush_tlb_asid(unsigned long asid); | ||
50 | extern int smtc_build_cpu_map(int startslot); | ||
51 | extern void smtc_prepare_cpus(int cpus); | ||
52 | extern void smtc_smp_finish(void); | ||
53 | extern void smtc_boot_secondary(int cpu, struct task_struct *t); | ||
54 | extern void smtc_cpus_done(void); | ||
55 | extern void smtc_init_secondary(void); | ||
56 | |||
57 | |||
58 | /* | ||
59 | * Sharing the TLB between multiple VPEs means that the | ||
60 | * "random" index selection function is not allowed to | ||
61 | * select the current value of the Index register. To | ||
62 | * avoid additional TLB pressure, the Index registers | ||
63 | * are "parked" with an non-Valid value. | ||
64 | */ | ||
65 | |||
66 | #define PARKED_INDEX ((unsigned int)0x80000000) | ||
67 | |||
68 | /* | ||
69 | * Define low-level interrupt mask for IPIs, if necessary. | ||
70 | * By default, use SW interrupt 1, which requires no external | ||
71 | * hardware support, but which works only for single-core | ||
72 | * MIPS MT systems. | ||
73 | */ | ||
74 | #ifndef MIPS_CPU_IPI_IRQ | ||
75 | #define MIPS_CPU_IPI_IRQ 1 | ||
76 | #endif | ||
77 | |||
78 | #endif /* _ASM_SMTC_MT_H */ | ||
diff --git a/arch/mips/include/asm/smtc_ipi.h b/arch/mips/include/asm/smtc_ipi.h deleted file mode 100644 index 15278dbd7e79..000000000000 --- a/arch/mips/include/asm/smtc_ipi.h +++ /dev/null | |||
@@ -1,129 +0,0 @@ | |||
1 | /* | ||
2 | * Definitions used in MIPS MT SMTC "Interprocessor Interrupt" code. | ||
3 | */ | ||
4 | #ifndef __ASM_SMTC_IPI_H | ||
5 | #define __ASM_SMTC_IPI_H | ||
6 | |||
7 | #include <linux/spinlock.h> | ||
8 | |||
9 | //#define SMTC_IPI_DEBUG | ||
10 | |||
11 | #ifdef SMTC_IPI_DEBUG | ||
12 | #include <asm/mipsregs.h> | ||
13 | #include <asm/mipsmtregs.h> | ||
14 | #endif /* SMTC_IPI_DEBUG */ | ||
15 | |||
16 | /* | ||
17 | * An IPI "message" | ||
18 | */ | ||
19 | |||
20 | struct smtc_ipi { | ||
21 | struct smtc_ipi *flink; | ||
22 | int type; | ||
23 | void *arg; | ||
24 | int dest; | ||
25 | #ifdef SMTC_IPI_DEBUG | ||
26 | int sender; | ||
27 | long stamp; | ||
28 | #endif /* SMTC_IPI_DEBUG */ | ||
29 | }; | ||
30 | |||
31 | /* | ||
32 | * Defined IPI Types | ||
33 | */ | ||
34 | |||
35 | #define LINUX_SMP_IPI 1 | ||
36 | #define SMTC_CLOCK_TICK 2 | ||
37 | #define IRQ_AFFINITY_IPI 3 | ||
38 | |||
39 | /* | ||
40 | * A queue of IPI messages | ||
41 | */ | ||
42 | |||
43 | struct smtc_ipi_q { | ||
44 | struct smtc_ipi *head; | ||
45 | spinlock_t lock; | ||
46 | struct smtc_ipi *tail; | ||
47 | int depth; | ||
48 | int resched_flag; /* reschedule already queued */ | ||
49 | }; | ||
50 | |||
51 | static inline void smtc_ipi_nq(struct smtc_ipi_q *q, struct smtc_ipi *p) | ||
52 | { | ||
53 | unsigned long flags; | ||
54 | |||
55 | spin_lock_irqsave(&q->lock, flags); | ||
56 | if (q->head == NULL) | ||
57 | q->head = q->tail = p; | ||
58 | else | ||
59 | q->tail->flink = p; | ||
60 | p->flink = NULL; | ||
61 | q->tail = p; | ||
62 | q->depth++; | ||
63 | #ifdef SMTC_IPI_DEBUG | ||
64 | p->sender = read_c0_tcbind(); | ||
65 | p->stamp = read_c0_count(); | ||
66 | #endif /* SMTC_IPI_DEBUG */ | ||
67 | spin_unlock_irqrestore(&q->lock, flags); | ||
68 | } | ||
69 | |||
70 | static inline struct smtc_ipi *__smtc_ipi_dq(struct smtc_ipi_q *q) | ||
71 | { | ||
72 | struct smtc_ipi *p; | ||
73 | |||
74 | if (q->head == NULL) | ||
75 | p = NULL; | ||
76 | else { | ||
77 | p = q->head; | ||
78 | q->head = q->head->flink; | ||
79 | q->depth--; | ||
80 | /* Arguably unnecessary, but leaves queue cleaner */ | ||
81 | if (q->head == NULL) | ||
82 | q->tail = NULL; | ||
83 | } | ||
84 | |||
85 | return p; | ||
86 | } | ||
87 | |||
88 | static inline struct smtc_ipi *smtc_ipi_dq(struct smtc_ipi_q *q) | ||
89 | { | ||
90 | unsigned long flags; | ||
91 | struct smtc_ipi *p; | ||
92 | |||
93 | spin_lock_irqsave(&q->lock, flags); | ||
94 | p = __smtc_ipi_dq(q); | ||
95 | spin_unlock_irqrestore(&q->lock, flags); | ||
96 | |||
97 | return p; | ||
98 | } | ||
99 | |||
100 | static inline void smtc_ipi_req(struct smtc_ipi_q *q, struct smtc_ipi *p) | ||
101 | { | ||
102 | unsigned long flags; | ||
103 | |||
104 | spin_lock_irqsave(&q->lock, flags); | ||
105 | if (q->head == NULL) { | ||
106 | q->head = q->tail = p; | ||
107 | p->flink = NULL; | ||
108 | } else { | ||
109 | p->flink = q->head; | ||
110 | q->head = p; | ||
111 | } | ||
112 | q->depth++; | ||
113 | spin_unlock_irqrestore(&q->lock, flags); | ||
114 | } | ||
115 | |||
116 | static inline int smtc_ipi_qdepth(struct smtc_ipi_q *q) | ||
117 | { | ||
118 | unsigned long flags; | ||
119 | int retval; | ||
120 | |||
121 | spin_lock_irqsave(&q->lock, flags); | ||
122 | retval = q->depth; | ||
123 | spin_unlock_irqrestore(&q->lock, flags); | ||
124 | return retval; | ||
125 | } | ||
126 | |||
127 | extern void smtc_send_ipi(int cpu, int type, unsigned int action); | ||
128 | |||
129 | #endif /* __ASM_SMTC_IPI_H */ | ||
diff --git a/arch/mips/include/asm/smtc_proc.h b/arch/mips/include/asm/smtc_proc.h deleted file mode 100644 index 25da651f1f5f..000000000000 --- a/arch/mips/include/asm/smtc_proc.h +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | /* | ||
2 | * Definitions for SMTC /proc entries | ||
3 | * Copyright(C) 2005 MIPS Technologies Inc. | ||
4 | */ | ||
5 | #ifndef __ASM_SMTC_PROC_H | ||
6 | #define __ASM_SMTC_PROC_H | ||
7 | |||
8 | /* | ||
9 | * per-"CPU" statistics | ||
10 | */ | ||
11 | |||
12 | struct smtc_cpu_proc { | ||
13 | unsigned long timerints; | ||
14 | unsigned long selfipis; | ||
15 | }; | ||
16 | |||
17 | extern struct smtc_cpu_proc smtc_cpu_stats[NR_CPUS]; | ||
18 | |||
19 | /* Count of number of recoveries of "stolen" FPU access rights on 34K */ | ||
20 | |||
21 | extern atomic_t smtc_fpu_recoveries; | ||
22 | |||
23 | #endif /* __ASM_SMTC_PROC_H */ | ||
diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h index d301e108d5b8..b188c797565c 100644 --- a/arch/mips/include/asm/stackframe.h +++ b/arch/mips/include/asm/stackframe.h | |||
@@ -19,22 +19,12 @@ | |||
19 | #include <asm/asm-offsets.h> | 19 | #include <asm/asm-offsets.h> |
20 | #include <asm/thread_info.h> | 20 | #include <asm/thread_info.h> |
21 | 21 | ||
22 | /* | 22 | #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) |
23 | * For SMTC kernel, global IE should be left set, and interrupts | ||
24 | * controlled exclusively via IXMT. | ||
25 | */ | ||
26 | #ifdef CONFIG_MIPS_MT_SMTC | ||
27 | #define STATMASK 0x1e | ||
28 | #elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) | ||
29 | #define STATMASK 0x3f | 23 | #define STATMASK 0x3f |
30 | #else | 24 | #else |
31 | #define STATMASK 0x1f | 25 | #define STATMASK 0x1f |
32 | #endif | 26 | #endif |
33 | 27 | ||
34 | #ifdef CONFIG_MIPS_MT_SMTC | ||
35 | #include <asm/mipsmtregs.h> | ||
36 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
37 | |||
38 | .macro SAVE_AT | 28 | .macro SAVE_AT |
39 | .set push | 29 | .set push |
40 | .set noat | 30 | .set noat |
@@ -186,16 +176,6 @@ | |||
186 | mfc0 v1, CP0_STATUS | 176 | mfc0 v1, CP0_STATUS |
187 | LONG_S $2, PT_R2(sp) | 177 | LONG_S $2, PT_R2(sp) |
188 | LONG_S v1, PT_STATUS(sp) | 178 | LONG_S v1, PT_STATUS(sp) |
189 | #ifdef CONFIG_MIPS_MT_SMTC | ||
190 | /* | ||
191 | * Ideally, these instructions would be shuffled in | ||
192 | * to cover the pipeline delay. | ||
193 | */ | ||
194 | .set mips32 | ||
195 | mfc0 k0, CP0_TCSTATUS | ||
196 | .set mips0 | ||
197 | LONG_S k0, PT_TCSTATUS(sp) | ||
198 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
199 | LONG_S $4, PT_R4(sp) | 179 | LONG_S $4, PT_R4(sp) |
200 | mfc0 v1, CP0_CAUSE | 180 | mfc0 v1, CP0_CAUSE |
201 | LONG_S $5, PT_R5(sp) | 181 | LONG_S $5, PT_R5(sp) |
@@ -321,36 +301,6 @@ | |||
321 | .set push | 301 | .set push |
322 | .set reorder | 302 | .set reorder |
323 | .set noat | 303 | .set noat |
324 | #ifdef CONFIG_MIPS_MT_SMTC | ||
325 | .set mips32r2 | ||
326 | /* | ||
327 | * We need to make sure the read-modify-write | ||
328 | * of Status below isn't perturbed by an interrupt | ||
329 | * or cross-TC access, so we need to do at least a DMT, | ||
330 | * protected by an interrupt-inhibit. But setting IXMT | ||
331 | * also creates a few-cycle window where an IPI could | ||
332 | * be queued and not be detected before potentially | ||
333 | * returning to a WAIT or user-mode loop. It must be | ||
334 | * replayed. | ||
335 | * | ||
336 | * We're in the middle of a context switch, and | ||
337 | * we can't dispatch it directly without trashing | ||
338 | * some registers, so we'll try to detect this unlikely | ||
339 | * case and program a software interrupt in the VPE, | ||
340 | * as would be done for a cross-VPE IPI. To accommodate | ||
341 | * the handling of that case, we're doing a DVPE instead | ||
342 | * of just a DMT here to protect against other threads. | ||
343 | * This is a lot of cruft to cover a tiny window. | ||
344 | * If you can find a better design, implement it! | ||
345 | * | ||
346 | */ | ||
347 | mfc0 v0, CP0_TCSTATUS | ||
348 | ori v0, TCSTATUS_IXMT | ||
349 | mtc0 v0, CP0_TCSTATUS | ||
350 | _ehb | ||
351 | DVPE 5 # dvpe a1 | ||
352 | jal mips_ihb | ||
353 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
354 | mfc0 a0, CP0_STATUS | 304 | mfc0 a0, CP0_STATUS |
355 | ori a0, STATMASK | 305 | ori a0, STATMASK |
356 | xori a0, STATMASK | 306 | xori a0, STATMASK |
@@ -362,59 +312,6 @@ | |||
362 | and v0, v1 | 312 | and v0, v1 |
363 | or v0, a0 | 313 | or v0, a0 |
364 | mtc0 v0, CP0_STATUS | 314 | mtc0 v0, CP0_STATUS |
365 | #ifdef CONFIG_MIPS_MT_SMTC | ||
366 | /* | ||
367 | * Only after EXL/ERL have been restored to status can we | ||
368 | * restore TCStatus.IXMT. | ||
369 | */ | ||
370 | LONG_L v1, PT_TCSTATUS(sp) | ||
371 | _ehb | ||
372 | mfc0 a0, CP0_TCSTATUS | ||
373 | andi v1, TCSTATUS_IXMT | ||
374 | bnez v1, 0f | ||
375 | |||
376 | /* | ||
377 | * We'd like to detect any IPIs queued in the tiny window | ||
378 | * above and request an software interrupt to service them | ||
379 | * when we ERET. | ||
380 | * | ||
381 | * Computing the offset into the IPIQ array of the executing | ||
382 | * TC's IPI queue in-line would be tedious. We use part of | ||
383 | * the TCContext register to hold 16 bits of offset that we | ||
384 | * can add in-line to find the queue head. | ||
385 | */ | ||
386 | mfc0 v0, CP0_TCCONTEXT | ||
387 | la a2, IPIQ | ||
388 | srl v0, v0, 16 | ||
389 | addu a2, a2, v0 | ||
390 | LONG_L v0, 0(a2) | ||
391 | beqz v0, 0f | ||
392 | /* | ||
393 | * If we have a queue, provoke dispatch within the VPE by setting C_SW1 | ||
394 | */ | ||
395 | mfc0 v0, CP0_CAUSE | ||
396 | ori v0, v0, C_SW1 | ||
397 | mtc0 v0, CP0_CAUSE | ||
398 | 0: | ||
399 | /* | ||
400 | * This test should really never branch but | ||
401 | * let's be prudent here. Having atomized | ||
402 | * the shared register modifications, we can | ||
403 | * now EVPE, and must do so before interrupts | ||
404 | * are potentially re-enabled. | ||
405 | */ | ||
406 | andi a1, a1, MVPCONTROL_EVP | ||
407 | beqz a1, 1f | ||
408 | evpe | ||
409 | 1: | ||
410 | /* We know that TCStatua.IXMT should be set from above */ | ||
411 | xori a0, a0, TCSTATUS_IXMT | ||
412 | or a0, a0, v1 | ||
413 | mtc0 a0, CP0_TCSTATUS | ||
414 | _ehb | ||
415 | |||
416 | .set mips0 | ||
417 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
418 | LONG_L v1, PT_EPC(sp) | 315 | LONG_L v1, PT_EPC(sp) |
419 | MTC0 v1, CP0_EPC | 316 | MTC0 v1, CP0_EPC |
420 | LONG_L $31, PT_R31(sp) | 317 | LONG_L $31, PT_R31(sp) |
@@ -467,33 +364,11 @@ | |||
467 | * Set cp0 enable bit as sign that we're running on the kernel stack | 364 | * Set cp0 enable bit as sign that we're running on the kernel stack |
468 | */ | 365 | */ |
469 | .macro CLI | 366 | .macro CLI |
470 | #if !defined(CONFIG_MIPS_MT_SMTC) | ||
471 | mfc0 t0, CP0_STATUS | 367 | mfc0 t0, CP0_STATUS |
472 | li t1, ST0_CU0 | STATMASK | 368 | li t1, ST0_CU0 | STATMASK |
473 | or t0, t1 | 369 | or t0, t1 |
474 | xori t0, STATMASK | 370 | xori t0, STATMASK |
475 | mtc0 t0, CP0_STATUS | 371 | mtc0 t0, CP0_STATUS |
476 | #else /* CONFIG_MIPS_MT_SMTC */ | ||
477 | /* | ||
478 | * For SMTC, we need to set privilege | ||
479 | * and disable interrupts only for the | ||
480 | * current TC, using the TCStatus register. | ||
481 | */ | ||
482 | mfc0 t0, CP0_TCSTATUS | ||
483 | /* Fortunately CU 0 is in the same place in both registers */ | ||
484 | /* Set TCU0, TMX, TKSU (for later inversion) and IXMT */ | ||
485 | li t1, ST0_CU0 | 0x08001c00 | ||
486 | or t0, t1 | ||
487 | /* Clear TKSU, leave IXMT */ | ||
488 | xori t0, 0x00001800 | ||
489 | mtc0 t0, CP0_TCSTATUS | ||
490 | _ehb | ||
491 | /* We need to leave the global IE bit set, but clear EXL...*/ | ||
492 | mfc0 t0, CP0_STATUS | ||
493 | ori t0, ST0_EXL | ST0_ERL | ||
494 | xori t0, ST0_EXL | ST0_ERL | ||
495 | mtc0 t0, CP0_STATUS | ||
496 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
497 | irq_disable_hazard | 372 | irq_disable_hazard |
498 | .endm | 373 | .endm |
499 | 374 | ||
@@ -502,35 +377,11 @@ | |||
502 | * Set cp0 enable bit as sign that we're running on the kernel stack | 377 | * Set cp0 enable bit as sign that we're running on the kernel stack |
503 | */ | 378 | */ |
504 | .macro STI | 379 | .macro STI |
505 | #if !defined(CONFIG_MIPS_MT_SMTC) | ||
506 | mfc0 t0, CP0_STATUS | 380 | mfc0 t0, CP0_STATUS |
507 | li t1, ST0_CU0 | STATMASK | 381 | li t1, ST0_CU0 | STATMASK |
508 | or t0, t1 | 382 | or t0, t1 |
509 | xori t0, STATMASK & ~1 | 383 | xori t0, STATMASK & ~1 |
510 | mtc0 t0, CP0_STATUS | 384 | mtc0 t0, CP0_STATUS |
511 | #else /* CONFIG_MIPS_MT_SMTC */ | ||
512 | /* | ||
513 | * For SMTC, we need to set privilege | ||
514 | * and enable interrupts only for the | ||
515 | * current TC, using the TCStatus register. | ||
516 | */ | ||
517 | _ehb | ||
518 | mfc0 t0, CP0_TCSTATUS | ||
519 | /* Fortunately CU 0 is in the same place in both registers */ | ||
520 | /* Set TCU0, TKSU (for later inversion) and IXMT */ | ||
521 | li t1, ST0_CU0 | 0x08001c00 | ||
522 | or t0, t1 | ||
523 | /* Clear TKSU *and* IXMT */ | ||
524 | xori t0, 0x00001c00 | ||
525 | mtc0 t0, CP0_TCSTATUS | ||
526 | _ehb | ||
527 | /* We need to leave the global IE bit set, but clear EXL...*/ | ||
528 | mfc0 t0, CP0_STATUS | ||
529 | ori t0, ST0_EXL | ||
530 | xori t0, ST0_EXL | ||
531 | mtc0 t0, CP0_STATUS | ||
532 | /* irq_enable_hazard below should expand to EHB for 24K/34K cpus */ | ||
533 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
534 | irq_enable_hazard | 385 | irq_enable_hazard |
535 | .endm | 386 | .endm |
536 | 387 | ||
@@ -540,32 +391,6 @@ | |||
540 | * Set cp0 enable bit as sign that we're running on the kernel stack | 391 | * Set cp0 enable bit as sign that we're running on the kernel stack |
541 | */ | 392 | */ |
542 | .macro KMODE | 393 | .macro KMODE |
543 | #ifdef CONFIG_MIPS_MT_SMTC | ||
544 | /* | ||
545 | * This gets baroque in SMTC. We want to | ||
546 | * protect the non-atomic clearing of EXL | ||
547 | * with DMT/EMT, but we don't want to take | ||
548 | * an interrupt while DMT is still in effect. | ||
549 | */ | ||
550 | |||
551 | /* KMODE gets invoked from both reorder and noreorder code */ | ||
552 | .set push | ||
553 | .set mips32r2 | ||
554 | .set noreorder | ||
555 | mfc0 v0, CP0_TCSTATUS | ||
556 | andi v1, v0, TCSTATUS_IXMT | ||
557 | ori v0, TCSTATUS_IXMT | ||
558 | mtc0 v0, CP0_TCSTATUS | ||
559 | _ehb | ||
560 | DMT 2 # dmt v0 | ||
561 | /* | ||
562 | * We don't know a priori if ra is "live" | ||
563 | */ | ||
564 | move t0, ra | ||
565 | jal mips_ihb | ||
566 | nop /* delay slot */ | ||
567 | move ra, t0 | ||
568 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
569 | mfc0 t0, CP0_STATUS | 394 | mfc0 t0, CP0_STATUS |
570 | li t1, ST0_CU0 | (STATMASK & ~1) | 395 | li t1, ST0_CU0 | (STATMASK & ~1) |
571 | #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) | 396 | #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) |
@@ -576,25 +401,6 @@ | |||
576 | or t0, t1 | 401 | or t0, t1 |
577 | xori t0, STATMASK & ~1 | 402 | xori t0, STATMASK & ~1 |
578 | mtc0 t0, CP0_STATUS | 403 | mtc0 t0, CP0_STATUS |
579 | #ifdef CONFIG_MIPS_MT_SMTC | ||
580 | _ehb | ||
581 | andi v0, v0, VPECONTROL_TE | ||
582 | beqz v0, 2f | ||
583 | nop /* delay slot */ | ||
584 | emt | ||
585 | 2: | ||
586 | mfc0 v0, CP0_TCSTATUS | ||
587 | /* Clear IXMT, then OR in previous value */ | ||
588 | ori v0, TCSTATUS_IXMT | ||
589 | xori v0, TCSTATUS_IXMT | ||
590 | or v0, v1, v0 | ||
591 | mtc0 v0, CP0_TCSTATUS | ||
592 | /* | ||
593 | * irq_disable_hazard below should expand to EHB | ||
594 | * on 24K/34K CPUS | ||
595 | */ | ||
596 | .set pop | ||
597 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
598 | irq_disable_hazard | 404 | irq_disable_hazard |
599 | .endm | 405 | .endm |
600 | 406 | ||
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index d2d961d6cb86..7de865805deb 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h | |||
@@ -159,11 +159,7 @@ static inline struct thread_info *current_thread_info(void) | |||
159 | * We stash processor id into a COP0 register to retrieve it fast | 159 | * We stash processor id into a COP0 register to retrieve it fast |
160 | * at kernel exception entry. | 160 | * at kernel exception entry. |
161 | */ | 161 | */ |
162 | #if defined(CONFIG_MIPS_MT_SMTC) | 162 | #if defined(CONFIG_MIPS_PGD_C0_CONTEXT) |
163 | #define SMP_CPUID_REG 2, 2 /* TCBIND */ | ||
164 | #define ASM_SMP_CPUID_REG $2, 2 | ||
165 | #define SMP_CPUID_PTRSHIFT 19 | ||
166 | #elif defined(CONFIG_MIPS_PGD_C0_CONTEXT) | ||
167 | #define SMP_CPUID_REG 20, 0 /* XCONTEXT */ | 163 | #define SMP_CPUID_REG 20, 0 /* XCONTEXT */ |
168 | #define ASM_SMP_CPUID_REG $20 | 164 | #define ASM_SMP_CPUID_REG $20 |
169 | #define SMP_CPUID_PTRSHIFT 48 | 165 | #define SMP_CPUID_PTRSHIFT 48 |
@@ -179,13 +175,8 @@ static inline struct thread_info *current_thread_info(void) | |||
179 | #define SMP_CPUID_REGSHIFT (SMP_CPUID_PTRSHIFT + 2) | 175 | #define SMP_CPUID_REGSHIFT (SMP_CPUID_PTRSHIFT + 2) |
180 | #endif | 176 | #endif |
181 | 177 | ||
182 | #ifdef CONFIG_MIPS_MT_SMTC | ||
183 | #define ASM_CPUID_MFC0 mfc0 | ||
184 | #define UASM_i_CPUID_MFC0 uasm_i_mfc0 | ||
185 | #else | ||
186 | #define ASM_CPUID_MFC0 MFC0 | 178 | #define ASM_CPUID_MFC0 MFC0 |
187 | #define UASM_i_CPUID_MFC0 UASM_i_MFC0 | 179 | #define UASM_i_CPUID_MFC0 UASM_i_MFC0 |
188 | #endif | ||
189 | 180 | ||
190 | #endif /* __KERNEL__ */ | 181 | #endif /* __KERNEL__ */ |
191 | #endif /* _ASM_THREAD_INFO_H */ | 182 | #endif /* _ASM_THREAD_INFO_H */ |
diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h index 24f534a7fbc3..8f3047d611ee 100644 --- a/arch/mips/include/asm/time.h +++ b/arch/mips/include/asm/time.h | |||
@@ -52,14 +52,11 @@ extern int (*perf_irq)(void); | |||
52 | */ | 52 | */ |
53 | extern unsigned int __weak get_c0_compare_int(void); | 53 | extern unsigned int __weak get_c0_compare_int(void); |
54 | extern int r4k_clockevent_init(void); | 54 | extern int r4k_clockevent_init(void); |
55 | extern int smtc_clockevent_init(void); | ||
56 | extern int gic_clockevent_init(void); | 55 | extern int gic_clockevent_init(void); |
57 | 56 | ||
58 | static inline int mips_clockevent_init(void) | 57 | static inline int mips_clockevent_init(void) |
59 | { | 58 | { |
60 | #ifdef CONFIG_MIPS_MT_SMTC | 59 | #if defined(CONFIG_CEVT_GIC) |
61 | return smtc_clockevent_init(); | ||
62 | #elif defined(CONFIG_CEVT_GIC) | ||
63 | return (gic_clockevent_init() | r4k_clockevent_init()); | 60 | return (gic_clockevent_init() | r4k_clockevent_init()); |
64 | #elif defined(CONFIG_CEVT_R4K) | 61 | #elif defined(CONFIG_CEVT_R4K) |
65 | return r4k_clockevent_init(); | 62 | return r4k_clockevent_init(); |
diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h index c5424757da65..b05bb70a2e46 100644 --- a/arch/mips/include/asm/timex.h +++ b/arch/mips/include/asm/timex.h | |||
@@ -4,12 +4,16 @@ | |||
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 1998, 1999, 2003 by Ralf Baechle | 6 | * Copyright (C) 1998, 1999, 2003 by Ralf Baechle |
7 | * Copyright (C) 2014 by Maciej W. Rozycki | ||
7 | */ | 8 | */ |
8 | #ifndef _ASM_TIMEX_H | 9 | #ifndef _ASM_TIMEX_H |
9 | #define _ASM_TIMEX_H | 10 | #define _ASM_TIMEX_H |
10 | 11 | ||
11 | #ifdef __KERNEL__ | 12 | #ifdef __KERNEL__ |
12 | 13 | ||
14 | #include <linux/compiler.h> | ||
15 | |||
16 | #include <asm/cpu.h> | ||
13 | #include <asm/cpu-features.h> | 17 | #include <asm/cpu-features.h> |
14 | #include <asm/mipsregs.h> | 18 | #include <asm/mipsregs.h> |
15 | #include <asm/cpu-type.h> | 19 | #include <asm/cpu-type.h> |
@@ -45,29 +49,54 @@ typedef unsigned int cycles_t; | |||
45 | * However for now the implementaton of this function doesn't get these | 49 | * However for now the implementaton of this function doesn't get these |
46 | * fine details right. | 50 | * fine details right. |
47 | */ | 51 | */ |
48 | static inline cycles_t get_cycles(void) | 52 | static inline int can_use_mips_counter(unsigned int prid) |
49 | { | 53 | { |
50 | switch (boot_cpu_type()) { | 54 | int comp = (prid & PRID_COMP_MASK) != PRID_COMP_LEGACY; |
51 | case CPU_R4400PC: | ||
52 | case CPU_R4400SC: | ||
53 | case CPU_R4400MC: | ||
54 | if ((read_c0_prid() & 0xff) >= 0x0050) | ||
55 | return read_c0_count(); | ||
56 | break; | ||
57 | 55 | ||
58 | case CPU_R4000PC: | 56 | if (__builtin_constant_p(cpu_has_counter) && !cpu_has_counter) |
59 | case CPU_R4000SC: | 57 | return 0; |
60 | case CPU_R4000MC: | 58 | else if (__builtin_constant_p(cpu_has_mips_r) && cpu_has_mips_r) |
61 | break; | 59 | return 1; |
60 | else if (likely(!__builtin_constant_p(cpu_has_mips_r) && comp)) | ||
61 | return 1; | ||
62 | /* Make sure we don't peek at cpu_data[0].options in the fast path! */ | ||
63 | if (!__builtin_constant_p(cpu_has_counter)) | ||
64 | asm volatile("" : "=m" (cpu_data[0].options)); | ||
65 | if (likely(cpu_has_counter && | ||
66 | prid >= (PRID_IMP_R4000 | PRID_REV_ENCODE_44(5, 0)))) | ||
67 | return 1; | ||
68 | else | ||
69 | return 0; | ||
70 | } | ||
62 | 71 | ||
63 | default: | 72 | static inline cycles_t get_cycles(void) |
64 | if (cpu_has_counter) | 73 | { |
65 | return read_c0_count(); | 74 | if (can_use_mips_counter(read_c0_prid())) |
66 | break; | 75 | return read_c0_count(); |
67 | } | 76 | else |
77 | return 0; /* no usable counter */ | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * Like get_cycles - but where c0_count is not available we desperately | ||
82 | * use c0_random in an attempt to get at least a little bit of entropy. | ||
83 | * | ||
84 | * R6000 and R6000A neither have a count register nor a random register. | ||
85 | * That leaves no entropy source in the CPU itself. | ||
86 | */ | ||
87 | static inline unsigned long random_get_entropy(void) | ||
88 | { | ||
89 | unsigned int prid = read_c0_prid(); | ||
90 | unsigned int imp = prid & PRID_IMP_MASK; | ||
68 | 91 | ||
69 | return 0; /* no usable counter */ | 92 | if (can_use_mips_counter(prid)) |
93 | return read_c0_count(); | ||
94 | else if (likely(imp != PRID_IMP_R6000 && imp != PRID_IMP_R6000A)) | ||
95 | return read_c0_random(); | ||
96 | else | ||
97 | return 0; /* no usable register */ | ||
70 | } | 98 | } |
99 | #define random_get_entropy random_get_entropy | ||
71 | 100 | ||
72 | #endif /* __KERNEL__ */ | 101 | #endif /* __KERNEL__ */ |
73 | 102 | ||
diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index c33a9564fb41..f8d63b3b40b4 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h | |||
@@ -55,6 +55,9 @@ void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c) | |||
55 | #define Ip_u2u1u3(op) \ | 55 | #define Ip_u2u1u3(op) \ |
56 | void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c) | 56 | void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c) |
57 | 57 | ||
58 | #define Ip_u3u2u1(op) \ | ||
59 | void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c) | ||
60 | |||
58 | #define Ip_u3u1u2(op) \ | 61 | #define Ip_u3u1u2(op) \ |
59 | void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c) | 62 | void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c) |
60 | 63 | ||
@@ -74,6 +77,9 @@ void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c, \ | |||
74 | #define Ip_u1u2(op) \ | 77 | #define Ip_u1u2(op) \ |
75 | void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b) | 78 | void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b) |
76 | 79 | ||
80 | #define Ip_u2u1(op) \ | ||
81 | void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b) | ||
82 | |||
77 | #define Ip_u1s2(op) \ | 83 | #define Ip_u1s2(op) \ |
78 | void ISAOPC(op)(u32 **buf, unsigned int a, signed int b) | 84 | void ISAOPC(op)(u32 **buf, unsigned int a, signed int b) |
79 | 85 | ||
@@ -99,6 +105,7 @@ Ip_u2u1s3(_daddiu); | |||
99 | Ip_u3u1u2(_daddu); | 105 | Ip_u3u1u2(_daddu); |
100 | Ip_u2u1msbu3(_dins); | 106 | Ip_u2u1msbu3(_dins); |
101 | Ip_u2u1msbu3(_dinsm); | 107 | Ip_u2u1msbu3(_dinsm); |
108 | Ip_u1u2(_divu); | ||
102 | Ip_u1u2u3(_dmfc0); | 109 | Ip_u1u2u3(_dmfc0); |
103 | Ip_u1u2u3(_dmtc0); | 110 | Ip_u1u2u3(_dmtc0); |
104 | Ip_u2u1u3(_drotr); | 111 | Ip_u2u1u3(_drotr); |
@@ -114,16 +121,22 @@ Ip_u2u1msbu3(_ext); | |||
114 | Ip_u2u1msbu3(_ins); | 121 | Ip_u2u1msbu3(_ins); |
115 | Ip_u1(_j); | 122 | Ip_u1(_j); |
116 | Ip_u1(_jal); | 123 | Ip_u1(_jal); |
124 | Ip_u2u1(_jalr); | ||
117 | Ip_u1(_jr); | 125 | Ip_u1(_jr); |
126 | Ip_u2s3u1(_lb); | ||
118 | Ip_u2s3u1(_ld); | 127 | Ip_u2s3u1(_ld); |
119 | Ip_u3u1u2(_ldx); | 128 | Ip_u3u1u2(_ldx); |
129 | Ip_u2s3u1(_lh); | ||
120 | Ip_u2s3u1(_ll); | 130 | Ip_u2s3u1(_ll); |
121 | Ip_u2s3u1(_lld); | 131 | Ip_u2s3u1(_lld); |
122 | Ip_u1s2(_lui); | 132 | Ip_u1s2(_lui); |
123 | Ip_u2s3u1(_lw); | 133 | Ip_u2s3u1(_lw); |
124 | Ip_u3u1u2(_lwx); | 134 | Ip_u3u1u2(_lwx); |
125 | Ip_u1u2u3(_mfc0); | 135 | Ip_u1u2u3(_mfc0); |
136 | Ip_u1(_mfhi); | ||
137 | Ip_u1(_mflo); | ||
126 | Ip_u1u2u3(_mtc0); | 138 | Ip_u1u2u3(_mtc0); |
139 | Ip_u3u1u2(_mul); | ||
127 | Ip_u3u1u2(_or); | 140 | Ip_u3u1u2(_or); |
128 | Ip_u2u1u3(_ori); | 141 | Ip_u2u1u3(_ori); |
129 | Ip_u2s3u1(_pref); | 142 | Ip_u2s3u1(_pref); |
@@ -133,17 +146,25 @@ Ip_u2s3u1(_sc); | |||
133 | Ip_u2s3u1(_scd); | 146 | Ip_u2s3u1(_scd); |
134 | Ip_u2s3u1(_sd); | 147 | Ip_u2s3u1(_sd); |
135 | Ip_u2u1u3(_sll); | 148 | Ip_u2u1u3(_sll); |
149 | Ip_u3u2u1(_sllv); | ||
150 | Ip_u2u1s3(_sltiu); | ||
151 | Ip_u3u1u2(_sltu); | ||
136 | Ip_u2u1u3(_sra); | 152 | Ip_u2u1u3(_sra); |
137 | Ip_u2u1u3(_srl); | 153 | Ip_u2u1u3(_srl); |
154 | Ip_u3u2u1(_srlv); | ||
138 | Ip_u3u1u2(_subu); | 155 | Ip_u3u1u2(_subu); |
139 | Ip_u2s3u1(_sw); | 156 | Ip_u2s3u1(_sw); |
157 | Ip_u1(_sync); | ||
140 | Ip_u1(_syscall); | 158 | Ip_u1(_syscall); |
141 | Ip_0(_tlbp); | 159 | Ip_0(_tlbp); |
142 | Ip_0(_tlbr); | 160 | Ip_0(_tlbr); |
143 | Ip_0(_tlbwi); | 161 | Ip_0(_tlbwi); |
144 | Ip_0(_tlbwr); | 162 | Ip_0(_tlbwr); |
163 | Ip_u1(_wait); | ||
164 | Ip_u2u1(_wsbh); | ||
145 | Ip_u3u1u2(_xor); | 165 | Ip_u3u1u2(_xor); |
146 | Ip_u2u1u3(_xori); | 166 | Ip_u2u1u3(_xori); |
167 | Ip_u2u1(_yield); | ||
147 | 168 | ||
148 | 169 | ||
149 | /* Handle labels. */ | 170 | /* Handle labels. */ |
@@ -264,6 +285,8 @@ void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg, | |||
264 | unsigned int bit, int lid); | 285 | unsigned int bit, int lid); |
265 | void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg, | 286 | void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg, |
266 | unsigned int bit, int lid); | 287 | unsigned int bit, int lid); |
288 | void uasm_il_beq(u32 **p, struct uasm_reloc **r, unsigned int r1, | ||
289 | unsigned int r2, int lid); | ||
267 | void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); | 290 | void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
268 | void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); | 291 | void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
269 | void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); | 292 | void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
diff --git a/arch/mips/include/uapi/asm/Kbuild b/arch/mips/include/uapi/asm/Kbuild index be7196eacb88..96fe7395ed8d 100644 --- a/arch/mips/include/uapi/asm/Kbuild +++ b/arch/mips/include/uapi/asm/Kbuild | |||
@@ -4,6 +4,7 @@ include include/uapi/asm-generic/Kbuild.asm | |||
4 | generic-y += auxvec.h | 4 | generic-y += auxvec.h |
5 | generic-y += ipcbuf.h | 5 | generic-y += ipcbuf.h |
6 | 6 | ||
7 | header-y += bitfield.h | ||
7 | header-y += bitsperlong.h | 8 | header-y += bitsperlong.h |
8 | header-y += break.h | 9 | header-y += break.h |
9 | header-y += byteorder.h | 10 | header-y += byteorder.h |
diff --git a/arch/mips/include/uapi/asm/bitfield.h b/arch/mips/include/uapi/asm/bitfield.h new file mode 100644 index 000000000000..ad9861359cea --- /dev/null +++ b/arch/mips/include/uapi/asm/bitfield.h | |||
@@ -0,0 +1,29 @@ | |||
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 | * Copyright (C) 2014 by Ralf Baechle <ralf@linux-mips.org> | ||
7 | */ | ||
8 | #ifndef __UAPI_ASM_BITFIELD_H | ||
9 | #define __UAPI_ASM_BITFIELD_H | ||
10 | |||
11 | /* | ||
12 | * * Damn ... bitfields depend from byteorder :-( | ||
13 | * */ | ||
14 | #ifdef __MIPSEB__ | ||
15 | #define __BITFIELD_FIELD(field, more) \ | ||
16 | field; \ | ||
17 | more | ||
18 | |||
19 | #elif defined(__MIPSEL__) | ||
20 | |||
21 | #define __BITFIELD_FIELD(field, more) \ | ||
22 | more \ | ||
23 | field; | ||
24 | |||
25 | #else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */ | ||
26 | #error "MIPS but neither __MIPSEL__ nor __MIPSEB__?" | ||
27 | #endif | ||
28 | |||
29 | #endif /* __UAPI_ASM_BITFIELD_H */ | ||
diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index 3125797f2a88..4b7160259292 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h | |||
@@ -13,6 +13,8 @@ | |||
13 | #ifndef _UAPI_ASM_INST_H | 13 | #ifndef _UAPI_ASM_INST_H |
14 | #define _UAPI_ASM_INST_H | 14 | #define _UAPI_ASM_INST_H |
15 | 15 | ||
16 | #include <asm/bitfield.h> | ||
17 | |||
16 | /* | 18 | /* |
17 | * Major opcodes; before MIPS IV cop1x was called cop3. | 19 | * Major opcodes; before MIPS IV cop1x was called cop3. |
18 | */ | 20 | */ |
@@ -74,16 +76,17 @@ enum spec2_op { | |||
74 | enum spec3_op { | 76 | enum spec3_op { |
75 | ext_op, dextm_op, dextu_op, dext_op, | 77 | ext_op, dextm_op, dextu_op, dext_op, |
76 | ins_op, dinsm_op, dinsu_op, dins_op, | 78 | ins_op, dinsm_op, dinsu_op, dins_op, |
77 | lx_op = 0x0a, lwle_op = 0x19, | 79 | yield_op = 0x09, lx_op = 0x0a, |
78 | lwre_op = 0x1a, cachee_op = 0x1b, | 80 | lwle_op = 0x19, lwre_op = 0x1a, |
79 | sbe_op = 0x1c, she_op = 0x1d, | 81 | cachee_op = 0x1b, sbe_op = 0x1c, |
80 | sce_op = 0x1e, swe_op = 0x1f, | 82 | she_op = 0x1d, sce_op = 0x1e, |
81 | bshfl_op = 0x20, swle_op = 0x21, | 83 | swe_op = 0x1f, bshfl_op = 0x20, |
82 | swre_op = 0x22, prefe_op = 0x23, | 84 | swle_op = 0x21, swre_op = 0x22, |
83 | dbshfl_op = 0x24, lbue_op = 0x28, | 85 | prefe_op = 0x23, dbshfl_op = 0x24, |
84 | lhue_op = 0x29, lbe_op = 0x2c, | 86 | lbue_op = 0x28, lhue_op = 0x29, |
85 | lhe_op = 0x2d, lle_op = 0x2e, | 87 | lbe_op = 0x2c, lhe_op = 0x2d, |
86 | lwe_op = 0x2f, rdhwr_op = 0x3b | 88 | lle_op = 0x2e, lwe_op = 0x2f, |
89 | rdhwr_op = 0x3b | ||
87 | }; | 90 | }; |
88 | 91 | ||
89 | /* | 92 | /* |
@@ -125,7 +128,8 @@ enum bcop_op { | |||
125 | enum cop0_coi_func { | 128 | enum cop0_coi_func { |
126 | tlbr_op = 0x01, tlbwi_op = 0x02, | 129 | tlbr_op = 0x01, tlbwi_op = 0x02, |
127 | tlbwr_op = 0x06, tlbp_op = 0x08, | 130 | tlbwr_op = 0x06, tlbp_op = 0x08, |
128 | rfe_op = 0x10, eret_op = 0x18 | 131 | rfe_op = 0x10, eret_op = 0x18, |
132 | wait_op = 0x20, | ||
129 | }; | 133 | }; |
130 | 134 | ||
131 | /* | 135 | /* |
@@ -202,6 +206,16 @@ enum lx_func { | |||
202 | }; | 206 | }; |
203 | 207 | ||
204 | /* | 208 | /* |
209 | * BSHFL opcodes | ||
210 | */ | ||
211 | enum bshfl_func { | ||
212 | wsbh_op = 0x2, | ||
213 | dshd_op = 0x5, | ||
214 | seb_op = 0x10, | ||
215 | seh_op = 0x18, | ||
216 | }; | ||
217 | |||
218 | /* | ||
205 | * (microMIPS) Major opcodes. | 219 | * (microMIPS) Major opcodes. |
206 | */ | 220 | */ |
207 | enum mm_major_op { | 221 | enum mm_major_op { |
@@ -244,17 +258,22 @@ enum mm_32i_minor_op { | |||
244 | enum mm_32a_minor_op { | 258 | enum mm_32a_minor_op { |
245 | mm_sll32_op = 0x000, | 259 | mm_sll32_op = 0x000, |
246 | mm_ins_op = 0x00c, | 260 | mm_ins_op = 0x00c, |
261 | mm_sllv32_op = 0x010, | ||
247 | mm_ext_op = 0x02c, | 262 | mm_ext_op = 0x02c, |
248 | mm_pool32axf_op = 0x03c, | 263 | mm_pool32axf_op = 0x03c, |
249 | mm_srl32_op = 0x040, | 264 | mm_srl32_op = 0x040, |
250 | mm_sra_op = 0x080, | 265 | mm_sra_op = 0x080, |
266 | mm_srlv32_op = 0x090, | ||
251 | mm_rotr_op = 0x0c0, | 267 | mm_rotr_op = 0x0c0, |
252 | mm_lwxs_op = 0x118, | 268 | mm_lwxs_op = 0x118, |
253 | mm_addu32_op = 0x150, | 269 | mm_addu32_op = 0x150, |
254 | mm_subu32_op = 0x1d0, | 270 | mm_subu32_op = 0x1d0, |
271 | mm_wsbh_op = 0x1ec, | ||
272 | mm_mul_op = 0x210, | ||
255 | mm_and_op = 0x250, | 273 | mm_and_op = 0x250, |
256 | mm_or32_op = 0x290, | 274 | mm_or32_op = 0x290, |
257 | mm_xor32_op = 0x310, | 275 | mm_xor32_op = 0x310, |
276 | mm_sltu_op = 0x390, | ||
258 | }; | 277 | }; |
259 | 278 | ||
260 | /* | 279 | /* |
@@ -294,15 +313,20 @@ enum mm_32axf_minor_op { | |||
294 | mm_mfc0_op = 0x003, | 313 | mm_mfc0_op = 0x003, |
295 | mm_mtc0_op = 0x00b, | 314 | mm_mtc0_op = 0x00b, |
296 | mm_tlbp_op = 0x00d, | 315 | mm_tlbp_op = 0x00d, |
316 | mm_mfhi32_op = 0x035, | ||
297 | mm_jalr_op = 0x03c, | 317 | mm_jalr_op = 0x03c, |
298 | mm_tlbr_op = 0x04d, | 318 | mm_tlbr_op = 0x04d, |
319 | mm_mflo32_op = 0x075, | ||
299 | mm_jalrhb_op = 0x07c, | 320 | mm_jalrhb_op = 0x07c, |
300 | mm_tlbwi_op = 0x08d, | 321 | mm_tlbwi_op = 0x08d, |
301 | mm_tlbwr_op = 0x0cd, | 322 | mm_tlbwr_op = 0x0cd, |
302 | mm_jalrs_op = 0x13c, | 323 | mm_jalrs_op = 0x13c, |
303 | mm_jalrshb_op = 0x17c, | 324 | mm_jalrshb_op = 0x17c, |
325 | mm_sync_op = 0x1ad, | ||
304 | mm_syscall_op = 0x22d, | 326 | mm_syscall_op = 0x22d, |
327 | mm_wait_op = 0x24d, | ||
305 | mm_eret_op = 0x3cd, | 328 | mm_eret_op = 0x3cd, |
329 | mm_divu_op = 0x5dc, | ||
306 | }; | 330 | }; |
307 | 331 | ||
308 | /* | 332 | /* |
@@ -480,24 +504,6 @@ enum MIPS6e_i8_func { | |||
480 | */ | 504 | */ |
481 | #define MM_NOP16 0x0c00 | 505 | #define MM_NOP16 0x0c00 |
482 | 506 | ||
483 | /* | ||
484 | * Damn ... bitfields depend from byteorder :-( | ||
485 | */ | ||
486 | #ifdef __MIPSEB__ | ||
487 | #define __BITFIELD_FIELD(field, more) \ | ||
488 | field; \ | ||
489 | more | ||
490 | |||
491 | #elif defined(__MIPSEL__) | ||
492 | |||
493 | #define __BITFIELD_FIELD(field, more) \ | ||
494 | more \ | ||
495 | field; | ||
496 | |||
497 | #else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */ | ||
498 | #error "MIPS but neither __MIPSEL__ nor __MIPSEB__?" | ||
499 | #endif | ||
500 | |||
501 | struct j_format { | 507 | struct j_format { |
502 | __BITFIELD_FIELD(unsigned int opcode : 6, /* Jump format */ | 508 | __BITFIELD_FIELD(unsigned int opcode : 6, /* Jump format */ |
503 | __BITFIELD_FIELD(unsigned int target : 26, | 509 | __BITFIELD_FIELD(unsigned int target : 26, |
diff --git a/arch/mips/include/uapi/asm/kvm_para.h b/arch/mips/include/uapi/asm/kvm_para.h index 14fab8f0b957..7e16d7c42e65 100644 --- a/arch/mips/include/uapi/asm/kvm_para.h +++ b/arch/mips/include/uapi/asm/kvm_para.h | |||
@@ -1 +1,5 @@ | |||
1 | #include <asm-generic/kvm_para.h> | 1 | #ifndef _UAPI_ASM_MIPS_KVM_PARA_H |
2 | #define _UAPI_ASM_MIPS_KVM_PARA_H | ||
3 | |||
4 | |||
5 | #endif /* _UAPI_ASM_MIPS_KVM_PARA_H */ | ||
diff --git a/arch/mips/include/uapi/asm/types.h b/arch/mips/include/uapi/asm/types.h index 7ac9d0baad84..f3dd9ff0cc0c 100644 --- a/arch/mips/include/uapi/asm/types.h +++ b/arch/mips/include/uapi/asm/types.h | |||
@@ -14,9 +14,12 @@ | |||
14 | /* | 14 | /* |
15 | * We don't use int-l64.h for the kernel anymore but still use it for | 15 | * We don't use int-l64.h for the kernel anymore but still use it for |
16 | * userspace to avoid code changes. | 16 | * userspace to avoid code changes. |
17 | * | ||
18 | * However, some user programs (e.g. perf) may not want this. They can | ||
19 | * flag __SANE_USERSPACE_TYPES__ to get int-ll64.h here. | ||
17 | */ | 20 | */ |
18 | #ifndef __KERNEL__ | 21 | #ifndef __KERNEL__ |
19 | # if _MIPS_SZLONG == 64 | 22 | # if _MIPS_SZLONG == 64 && !defined(__SANE_USERSPACE_TYPES__) |
20 | # include <asm-generic/int-l64.h> | 23 | # include <asm-generic/int-l64.h> |
21 | # else | 24 | # else |
22 | # include <asm-generic/int-ll64.h> | 25 | # include <asm-generic/int-ll64.h> |
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 277dab301cea..008a2fed0584 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
@@ -17,7 +17,6 @@ endif | |||
17 | 17 | ||
18 | obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o | 18 | obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o |
19 | obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o | 19 | obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o |
20 | obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o | ||
21 | obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o | 20 | obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o |
22 | obj-$(CONFIG_CEVT_GIC) += cevt-gic.o | 21 | obj-$(CONFIG_CEVT_GIC) += cevt-gic.o |
23 | obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o | 22 | obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o |
@@ -42,7 +41,7 @@ obj-$(CONFIG_CPU_R4K_FPU) += r4k_fpu.o r4k_switch.o | |||
42 | obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o | 41 | obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o |
43 | obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o | 42 | obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o |
44 | obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o | 43 | obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o |
45 | obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o | 44 | obj-$(CONFIG_CPU_CAVIUM_OCTEON) += r4k_fpu.o octeon_switch.o |
46 | 45 | ||
47 | obj-$(CONFIG_SMP) += smp.o | 46 | obj-$(CONFIG_SMP) += smp.o |
48 | obj-$(CONFIG_SMP_UP) += smp-up.o | 47 | obj-$(CONFIG_SMP_UP) += smp-up.o |
@@ -50,7 +49,6 @@ obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o | |||
50 | 49 | ||
51 | obj-$(CONFIG_MIPS_MT) += mips-mt.o | 50 | obj-$(CONFIG_MIPS_MT) += mips-mt.o |
52 | obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o | 51 | obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o |
53 | obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o | ||
54 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o | 52 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o |
55 | obj-$(CONFIG_MIPS_CMP) += smp-cmp.o | 53 | obj-$(CONFIG_MIPS_CMP) += smp-cmp.o |
56 | obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o | 54 | obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o |
@@ -107,6 +105,9 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o | |||
107 | obj-$(CONFIG_MIPS_CM) += mips-cm.o | 105 | obj-$(CONFIG_MIPS_CM) += mips-cm.o |
108 | obj-$(CONFIG_MIPS_CPC) += mips-cpc.o | 106 | obj-$(CONFIG_MIPS_CPC) += mips-cpc.o |
109 | 107 | ||
108 | obj-$(CONFIG_CPU_PM) += pm.o | ||
109 | obj-$(CONFIG_MIPS_CPS_PM) += pm-cps.o | ||
110 | |||
110 | # | 111 | # |
111 | # DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not | 112 | # DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not |
112 | # safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches | 113 | # safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches |
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 0ea75c244b48..02f075df8f2e 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/kbuild.h> | 15 | #include <linux/kbuild.h> |
16 | #include <linux/suspend.h> | 16 | #include <linux/suspend.h> |
17 | #include <asm/pm.h> | ||
17 | #include <asm/ptrace.h> | 18 | #include <asm/ptrace.h> |
18 | #include <asm/processor.h> | 19 | #include <asm/processor.h> |
19 | #include <asm/smp-cps.h> | 20 | #include <asm/smp-cps.h> |
@@ -64,9 +65,6 @@ void output_ptreg_defines(void) | |||
64 | OFFSET(PT_BVADDR, pt_regs, cp0_badvaddr); | 65 | OFFSET(PT_BVADDR, pt_regs, cp0_badvaddr); |
65 | OFFSET(PT_STATUS, pt_regs, cp0_status); | 66 | OFFSET(PT_STATUS, pt_regs, cp0_status); |
66 | OFFSET(PT_CAUSE, pt_regs, cp0_cause); | 67 | OFFSET(PT_CAUSE, pt_regs, cp0_cause); |
67 | #ifdef CONFIG_MIPS_MT_SMTC | ||
68 | OFFSET(PT_TCSTATUS, pt_regs, cp0_tcstatus); | ||
69 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
70 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 68 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
71 | OFFSET(PT_MPL, pt_regs, mpl); | 69 | OFFSET(PT_MPL, pt_regs, mpl); |
72 | OFFSET(PT_MTP, pt_regs, mtp); | 70 | OFFSET(PT_MTP, pt_regs, mtp); |
@@ -404,6 +402,20 @@ void output_pbe_defines(void) | |||
404 | } | 402 | } |
405 | #endif | 403 | #endif |
406 | 404 | ||
405 | #ifdef CONFIG_CPU_PM | ||
406 | void output_pm_defines(void) | ||
407 | { | ||
408 | COMMENT(" PM offsets. "); | ||
409 | #ifdef CONFIG_EVA | ||
410 | OFFSET(SSS_SEGCTL0, mips_static_suspend_state, segctl[0]); | ||
411 | OFFSET(SSS_SEGCTL1, mips_static_suspend_state, segctl[1]); | ||
412 | OFFSET(SSS_SEGCTL2, mips_static_suspend_state, segctl[2]); | ||
413 | #endif | ||
414 | OFFSET(SSS_SP, mips_static_suspend_state, sp); | ||
415 | BLANK(); | ||
416 | } | ||
417 | #endif | ||
418 | |||
407 | void output_kvm_defines(void) | 419 | void output_kvm_defines(void) |
408 | { | 420 | { |
409 | COMMENT(" KVM/MIPS Specfic offsets. "); | 421 | COMMENT(" KVM/MIPS Specfic offsets. "); |
@@ -472,10 +484,14 @@ void output_kvm_defines(void) | |||
472 | void output_cps_defines(void) | 484 | void output_cps_defines(void) |
473 | { | 485 | { |
474 | COMMENT(" MIPS CPS offsets. "); | 486 | COMMENT(" MIPS CPS offsets. "); |
475 | OFFSET(BOOTCFG_CORE, boot_config, core); | 487 | |
476 | OFFSET(BOOTCFG_VPE, boot_config, vpe); | 488 | OFFSET(COREBOOTCFG_VPEMASK, core_boot_config, vpe_mask); |
477 | OFFSET(BOOTCFG_PC, boot_config, pc); | 489 | OFFSET(COREBOOTCFG_VPECONFIG, core_boot_config, vpe_config); |
478 | OFFSET(BOOTCFG_SP, boot_config, sp); | 490 | DEFINE(COREBOOTCFG_SIZE, sizeof(struct core_boot_config)); |
479 | OFFSET(BOOTCFG_GP, boot_config, gp); | 491 | |
492 | OFFSET(VPEBOOTCFG_PC, vpe_boot_config, pc); | ||
493 | OFFSET(VPEBOOTCFG_SP, vpe_boot_config, sp); | ||
494 | OFFSET(VPEBOOTCFG_GP, vpe_boot_config, gp); | ||
495 | DEFINE(VPEBOOTCFG_SIZE, sizeof(struct vpe_boot_config)); | ||
480 | } | 496 | } |
481 | #endif | 497 | #endif |
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 76122ff5cb5e..7b2df224f041 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c | |||
@@ -48,6 +48,202 @@ int __isa_exception_epc(struct pt_regs *regs) | |||
48 | return epc; | 48 | return epc; |
49 | } | 49 | } |
50 | 50 | ||
51 | /* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */ | ||
52 | static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; | ||
53 | |||
54 | int __mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | ||
55 | unsigned long *contpc) | ||
56 | { | ||
57 | union mips_instruction insn = (union mips_instruction)dec_insn.insn; | ||
58 | int bc_false = 0; | ||
59 | unsigned int fcr31; | ||
60 | unsigned int bit; | ||
61 | |||
62 | if (!cpu_has_mmips) | ||
63 | return 0; | ||
64 | |||
65 | switch (insn.mm_i_format.opcode) { | ||
66 | case mm_pool32a_op: | ||
67 | if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) == | ||
68 | mm_pool32axf_op) { | ||
69 | switch (insn.mm_i_format.simmediate >> | ||
70 | MM_POOL32A_MINOR_SHIFT) { | ||
71 | case mm_jalr_op: | ||
72 | case mm_jalrhb_op: | ||
73 | case mm_jalrs_op: | ||
74 | case mm_jalrshb_op: | ||
75 | if (insn.mm_i_format.rt != 0) /* Not mm_jr */ | ||
76 | regs->regs[insn.mm_i_format.rt] = | ||
77 | regs->cp0_epc + | ||
78 | dec_insn.pc_inc + | ||
79 | dec_insn.next_pc_inc; | ||
80 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
81 | return 1; | ||
82 | } | ||
83 | } | ||
84 | break; | ||
85 | case mm_pool32i_op: | ||
86 | switch (insn.mm_i_format.rt) { | ||
87 | case mm_bltzals_op: | ||
88 | case mm_bltzal_op: | ||
89 | regs->regs[31] = regs->cp0_epc + | ||
90 | dec_insn.pc_inc + | ||
91 | dec_insn.next_pc_inc; | ||
92 | /* Fall through */ | ||
93 | case mm_bltz_op: | ||
94 | if ((long)regs->regs[insn.mm_i_format.rs] < 0) | ||
95 | *contpc = regs->cp0_epc + | ||
96 | dec_insn.pc_inc + | ||
97 | (insn.mm_i_format.simmediate << 1); | ||
98 | else | ||
99 | *contpc = regs->cp0_epc + | ||
100 | dec_insn.pc_inc + | ||
101 | dec_insn.next_pc_inc; | ||
102 | return 1; | ||
103 | case mm_bgezals_op: | ||
104 | case mm_bgezal_op: | ||
105 | regs->regs[31] = regs->cp0_epc + | ||
106 | dec_insn.pc_inc + | ||
107 | dec_insn.next_pc_inc; | ||
108 | /* Fall through */ | ||
109 | case mm_bgez_op: | ||
110 | if ((long)regs->regs[insn.mm_i_format.rs] >= 0) | ||
111 | *contpc = regs->cp0_epc + | ||
112 | dec_insn.pc_inc + | ||
113 | (insn.mm_i_format.simmediate << 1); | ||
114 | else | ||
115 | *contpc = regs->cp0_epc + | ||
116 | dec_insn.pc_inc + | ||
117 | dec_insn.next_pc_inc; | ||
118 | return 1; | ||
119 | case mm_blez_op: | ||
120 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
121 | *contpc = regs->cp0_epc + | ||
122 | dec_insn.pc_inc + | ||
123 | (insn.mm_i_format.simmediate << 1); | ||
124 | else | ||
125 | *contpc = regs->cp0_epc + | ||
126 | dec_insn.pc_inc + | ||
127 | dec_insn.next_pc_inc; | ||
128 | return 1; | ||
129 | case mm_bgtz_op: | ||
130 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
131 | *contpc = regs->cp0_epc + | ||
132 | dec_insn.pc_inc + | ||
133 | (insn.mm_i_format.simmediate << 1); | ||
134 | else | ||
135 | *contpc = regs->cp0_epc + | ||
136 | dec_insn.pc_inc + | ||
137 | dec_insn.next_pc_inc; | ||
138 | return 1; | ||
139 | case mm_bc2f_op: | ||
140 | case mm_bc1f_op: | ||
141 | bc_false = 1; | ||
142 | /* Fall through */ | ||
143 | case mm_bc2t_op: | ||
144 | case mm_bc1t_op: | ||
145 | preempt_disable(); | ||
146 | if (is_fpu_owner()) | ||
147 | asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); | ||
148 | else | ||
149 | fcr31 = current->thread.fpu.fcr31; | ||
150 | preempt_enable(); | ||
151 | |||
152 | if (bc_false) | ||
153 | fcr31 = ~fcr31; | ||
154 | |||
155 | bit = (insn.mm_i_format.rs >> 2); | ||
156 | bit += (bit != 0); | ||
157 | bit += 23; | ||
158 | if (fcr31 & (1 << bit)) | ||
159 | *contpc = regs->cp0_epc + | ||
160 | dec_insn.pc_inc + | ||
161 | (insn.mm_i_format.simmediate << 1); | ||
162 | else | ||
163 | *contpc = regs->cp0_epc + | ||
164 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
165 | return 1; | ||
166 | } | ||
167 | break; | ||
168 | case mm_pool16c_op: | ||
169 | switch (insn.mm_i_format.rt) { | ||
170 | case mm_jalr16_op: | ||
171 | case mm_jalrs16_op: | ||
172 | regs->regs[31] = regs->cp0_epc + | ||
173 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
174 | /* Fall through */ | ||
175 | case mm_jr16_op: | ||
176 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
177 | return 1; | ||
178 | } | ||
179 | break; | ||
180 | case mm_beqz16_op: | ||
181 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0) | ||
182 | *contpc = regs->cp0_epc + | ||
183 | dec_insn.pc_inc + | ||
184 | (insn.mm_b1_format.simmediate << 1); | ||
185 | else | ||
186 | *contpc = regs->cp0_epc + | ||
187 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
188 | return 1; | ||
189 | case mm_bnez16_op: | ||
190 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0) | ||
191 | *contpc = regs->cp0_epc + | ||
192 | dec_insn.pc_inc + | ||
193 | (insn.mm_b1_format.simmediate << 1); | ||
194 | else | ||
195 | *contpc = regs->cp0_epc + | ||
196 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
197 | return 1; | ||
198 | case mm_b16_op: | ||
199 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
200 | (insn.mm_b0_format.simmediate << 1); | ||
201 | return 1; | ||
202 | case mm_beq32_op: | ||
203 | if (regs->regs[insn.mm_i_format.rs] == | ||
204 | regs->regs[insn.mm_i_format.rt]) | ||
205 | *contpc = regs->cp0_epc + | ||
206 | dec_insn.pc_inc + | ||
207 | (insn.mm_i_format.simmediate << 1); | ||
208 | else | ||
209 | *contpc = regs->cp0_epc + | ||
210 | dec_insn.pc_inc + | ||
211 | dec_insn.next_pc_inc; | ||
212 | return 1; | ||
213 | case mm_bne32_op: | ||
214 | if (regs->regs[insn.mm_i_format.rs] != | ||
215 | regs->regs[insn.mm_i_format.rt]) | ||
216 | *contpc = regs->cp0_epc + | ||
217 | dec_insn.pc_inc + | ||
218 | (insn.mm_i_format.simmediate << 1); | ||
219 | else | ||
220 | *contpc = regs->cp0_epc + | ||
221 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
222 | return 1; | ||
223 | case mm_jalx32_op: | ||
224 | regs->regs[31] = regs->cp0_epc + | ||
225 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
226 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
227 | *contpc >>= 28; | ||
228 | *contpc <<= 28; | ||
229 | *contpc |= (insn.j_format.target << 2); | ||
230 | return 1; | ||
231 | case mm_jals32_op: | ||
232 | case mm_jal32_op: | ||
233 | regs->regs[31] = regs->cp0_epc + | ||
234 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
235 | /* Fall through */ | ||
236 | case mm_j32_op: | ||
237 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
238 | *contpc >>= 27; | ||
239 | *contpc <<= 27; | ||
240 | *contpc |= (insn.j_format.target << 1); | ||
241 | set_isa16_mode(*contpc); | ||
242 | return 1; | ||
243 | } | ||
244 | return 0; | ||
245 | } | ||
246 | |||
51 | /* | 247 | /* |
52 | * Compute return address and emulate branch in microMIPS mode after an | 248 | * Compute return address and emulate branch in microMIPS mode after an |
53 | * exception only. It does not handle compact branches/jumps and cannot | 249 | * exception only. It does not handle compact branches/jumps and cannot |
@@ -366,7 +562,11 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
366 | case cop1_op: | 562 | case cop1_op: |
367 | preempt_disable(); | 563 | preempt_disable(); |
368 | if (is_fpu_owner()) | 564 | if (is_fpu_owner()) |
369 | asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); | 565 | asm volatile( |
566 | ".set push\n" | ||
567 | "\t.set mips1\n" | ||
568 | "\tcfc1\t%0,$31\n" | ||
569 | "\t.set pop" : "=r" (fcr31)); | ||
370 | else | 570 | else |
371 | fcr31 = current->thread.fpu.fcr31; | 571 | fcr31 = current->thread.fpu.fcr31; |
372 | preempt_enable(); | 572 | preempt_enable(); |
diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c index 594cbbf16d62..6093716980b9 100644 --- a/arch/mips/kernel/cevt-gic.c +++ b/arch/mips/kernel/cevt-gic.c | |||
@@ -26,7 +26,7 @@ static int gic_next_event(unsigned long delta, struct clock_event_device *evt) | |||
26 | 26 | ||
27 | cnt = gic_read_count(); | 27 | cnt = gic_read_count(); |
28 | cnt += (u64)delta; | 28 | cnt += (u64)delta; |
29 | gic_write_compare(cnt); | 29 | gic_write_cpu_compare(cnt, cpumask_first(evt->cpumask)); |
30 | res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0; | 30 | res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0; |
31 | return res; | 31 | return res; |
32 | } | 32 | } |
@@ -73,7 +73,8 @@ int gic_clockevent_init(void) | |||
73 | cd = &per_cpu(gic_clockevent_device, cpu); | 73 | cd = &per_cpu(gic_clockevent_device, cpu); |
74 | 74 | ||
75 | cd->name = "MIPS GIC"; | 75 | cd->name = "MIPS GIC"; |
76 | cd->features = CLOCK_EVT_FEAT_ONESHOT; | 76 | cd->features = CLOCK_EVT_FEAT_ONESHOT | |
77 | CLOCK_EVT_FEAT_C3STOP; | ||
77 | 78 | ||
78 | clockevent_set_clock(cd, gic_frequency); | 79 | clockevent_set_clock(cd, gic_frequency); |
79 | 80 | ||
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 50d3f5a8d6bb..bc127e22fdab 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c | |||
@@ -12,17 +12,10 @@ | |||
12 | #include <linux/smp.h> | 12 | #include <linux/smp.h> |
13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
14 | 14 | ||
15 | #include <asm/smtc_ipi.h> | ||
16 | #include <asm/time.h> | 15 | #include <asm/time.h> |
17 | #include <asm/cevt-r4k.h> | 16 | #include <asm/cevt-r4k.h> |
18 | #include <asm/gic.h> | 17 | #include <asm/gic.h> |
19 | 18 | ||
20 | /* | ||
21 | * The SMTC Kernel for the 34K, 1004K, et. al. replaces several | ||
22 | * of these routines with SMTC-specific variants. | ||
23 | */ | ||
24 | |||
25 | #ifndef CONFIG_MIPS_MT_SMTC | ||
26 | static int mips_next_event(unsigned long delta, | 19 | static int mips_next_event(unsigned long delta, |
27 | struct clock_event_device *evt) | 20 | struct clock_event_device *evt) |
28 | { | 21 | { |
@@ -36,8 +29,6 @@ static int mips_next_event(unsigned long delta, | |||
36 | return res; | 29 | return res; |
37 | } | 30 | } |
38 | 31 | ||
39 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
40 | |||
41 | void mips_set_clock_mode(enum clock_event_mode mode, | 32 | void mips_set_clock_mode(enum clock_event_mode mode, |
42 | struct clock_event_device *evt) | 33 | struct clock_event_device *evt) |
43 | { | 34 | { |
@@ -47,7 +38,6 @@ void mips_set_clock_mode(enum clock_event_mode mode, | |||
47 | DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); | 38 | DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); |
48 | int cp0_timer_irq_installed; | 39 | int cp0_timer_irq_installed; |
49 | 40 | ||
50 | #ifndef CONFIG_MIPS_MT_SMTC | ||
51 | irqreturn_t c0_compare_interrupt(int irq, void *dev_id) | 41 | irqreturn_t c0_compare_interrupt(int irq, void *dev_id) |
52 | { | 42 | { |
53 | const int r2 = cpu_has_mips_r2; | 43 | const int r2 = cpu_has_mips_r2; |
@@ -72,9 +62,6 @@ irqreturn_t c0_compare_interrupt(int irq, void *dev_id) | |||
72 | /* Clear Count/Compare Interrupt */ | 62 | /* Clear Count/Compare Interrupt */ |
73 | write_c0_compare(read_c0_compare()); | 63 | write_c0_compare(read_c0_compare()); |
74 | cd = &per_cpu(mips_clockevent_device, cpu); | 64 | cd = &per_cpu(mips_clockevent_device, cpu); |
75 | #ifdef CONFIG_CEVT_GIC | ||
76 | if (!gic_present) | ||
77 | #endif | ||
78 | cd->event_handler(cd); | 65 | cd->event_handler(cd); |
79 | } | 66 | } |
80 | 67 | ||
@@ -82,8 +69,6 @@ out: | |||
82 | return IRQ_HANDLED; | 69 | return IRQ_HANDLED; |
83 | } | 70 | } |
84 | 71 | ||
85 | #endif /* Not CONFIG_MIPS_MT_SMTC */ | ||
86 | |||
87 | struct irqaction c0_compare_irqaction = { | 72 | struct irqaction c0_compare_irqaction = { |
88 | .handler = c0_compare_interrupt, | 73 | .handler = c0_compare_interrupt, |
89 | .flags = IRQF_PERCPU | IRQF_TIMER, | 74 | .flags = IRQF_PERCPU | IRQF_TIMER, |
@@ -170,7 +155,6 @@ int c0_compare_int_usable(void) | |||
170 | return 1; | 155 | return 1; |
171 | } | 156 | } |
172 | 157 | ||
173 | #ifndef CONFIG_MIPS_MT_SMTC | ||
174 | int r4k_clockevent_init(void) | 158 | int r4k_clockevent_init(void) |
175 | { | 159 | { |
176 | unsigned int cpu = smp_processor_id(); | 160 | unsigned int cpu = smp_processor_id(); |
@@ -195,7 +179,9 @@ int r4k_clockevent_init(void) | |||
195 | cd = &per_cpu(mips_clockevent_device, cpu); | 179 | cd = &per_cpu(mips_clockevent_device, cpu); |
196 | 180 | ||
197 | cd->name = "MIPS"; | 181 | cd->name = "MIPS"; |
198 | cd->features = CLOCK_EVT_FEAT_ONESHOT; | 182 | cd->features = CLOCK_EVT_FEAT_ONESHOT | |
183 | CLOCK_EVT_FEAT_C3STOP | | ||
184 | CLOCK_EVT_FEAT_PERCPU; | ||
199 | 185 | ||
200 | clockevent_set_clock(cd, mips_hpt_frequency); | 186 | clockevent_set_clock(cd, mips_hpt_frequency); |
201 | 187 | ||
@@ -210,9 +196,6 @@ int r4k_clockevent_init(void) | |||
210 | cd->set_mode = mips_set_clock_mode; | 196 | cd->set_mode = mips_set_clock_mode; |
211 | cd->event_handler = mips_event_handler; | 197 | cd->event_handler = mips_event_handler; |
212 | 198 | ||
213 | #ifdef CONFIG_CEVT_GIC | ||
214 | if (!gic_present) | ||
215 | #endif | ||
216 | clockevents_register_device(cd); | 199 | clockevents_register_device(cd); |
217 | 200 | ||
218 | if (cp0_timer_irq_installed) | 201 | if (cp0_timer_irq_installed) |
@@ -225,4 +208,3 @@ int r4k_clockevent_init(void) | |||
225 | return 0; | 208 | return 0; |
226 | } | 209 | } |
227 | 210 | ||
228 | #endif /* Not CONFIG_MIPS_MT_SMTC */ | ||
diff --git a/arch/mips/kernel/cevt-smtc.c b/arch/mips/kernel/cevt-smtc.c deleted file mode 100644 index b6cf0a60d896..000000000000 --- a/arch/mips/kernel/cevt-smtc.c +++ /dev/null | |||
@@ -1,324 +0,0 @@ | |||
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 | * Copyright (C) 2007 MIPS Technologies, Inc. | ||
7 | * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org> | ||
8 | * Copyright (C) 2008 Kevin D. Kissell, Paralogos sarl | ||
9 | */ | ||
10 | #include <linux/clockchips.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/percpu.h> | ||
13 | #include <linux/smp.h> | ||
14 | #include <linux/irq.h> | ||
15 | |||
16 | #include <asm/smtc_ipi.h> | ||
17 | #include <asm/time.h> | ||
18 | #include <asm/cevt-r4k.h> | ||
19 | |||
20 | /* | ||
21 | * Variant clock event timer support for SMTC on MIPS 34K, 1004K | ||
22 | * or other MIPS MT cores. | ||
23 | * | ||
24 | * Notes on SMTC Support: | ||
25 | * | ||
26 | * SMTC has multiple microthread TCs pretending to be Linux CPUs. | ||
27 | * But there's only one Count/Compare pair per VPE, and Compare | ||
28 | * interrupts are taken opportunisitically by available TCs | ||
29 | * bound to the VPE with the Count register. The new timer | ||
30 | * framework provides for global broadcasts, but we really | ||
31 | * want VPE-level multicasts for best behavior. So instead | ||
32 | * of invoking the high-level clock-event broadcast code, | ||
33 | * this version of SMTC support uses the historical SMTC | ||
34 | * multicast mechanisms "under the hood", appearing to the | ||
35 | * generic clock layer as if the interrupts are per-CPU. | ||
36 | * | ||
37 | * The approach taken here is to maintain a set of NR_CPUS | ||
38 | * virtual timers, and track which "CPU" needs to be alerted | ||
39 | * at each event. | ||
40 | * | ||
41 | * It's unlikely that we'll see a MIPS MT core with more than | ||
42 | * 2 VPEs, but we *know* that we won't need to handle more | ||
43 | * VPEs than we have "CPUs". So NCPUs arrays of NCPUs elements | ||
44 | * is always going to be overkill, but always going to be enough. | ||
45 | */ | ||
46 | |||
47 | unsigned long smtc_nexttime[NR_CPUS][NR_CPUS]; | ||
48 | static int smtc_nextinvpe[NR_CPUS]; | ||
49 | |||
50 | /* | ||
51 | * Timestamps stored are absolute values to be programmed | ||
52 | * into Count register. Valid timestamps will never be zero. | ||
53 | * If a Zero Count value is actually calculated, it is converted | ||
54 | * to be a 1, which will introduce 1 or two CPU cycles of error | ||
55 | * roughly once every four billion events, which at 1000 HZ means | ||
56 | * about once every 50 days. If that's actually a problem, one | ||
57 | * could alternate squashing 0 to 1 and to -1. | ||
58 | */ | ||
59 | |||
60 | #define MAKEVALID(x) (((x) == 0L) ? 1L : (x)) | ||
61 | #define ISVALID(x) ((x) != 0L) | ||
62 | |||
63 | /* | ||
64 | * Time comparison is subtle, as it's really truncated | ||
65 | * modular arithmetic. | ||
66 | */ | ||
67 | |||
68 | #define IS_SOONER(a, b, reference) \ | ||
69 | (((a) - (unsigned long)(reference)) < ((b) - (unsigned long)(reference))) | ||
70 | |||
71 | /* | ||
72 | * CATCHUP_INCREMENT, used when the function falls behind the counter. | ||
73 | * Could be an increasing function instead of a constant; | ||
74 | */ | ||
75 | |||
76 | #define CATCHUP_INCREMENT 64 | ||
77 | |||
78 | static int mips_next_event(unsigned long delta, | ||
79 | struct clock_event_device *evt) | ||
80 | { | ||
81 | unsigned long flags; | ||
82 | unsigned int mtflags; | ||
83 | unsigned long timestamp, reference, previous; | ||
84 | unsigned long nextcomp = 0L; | ||
85 | int vpe = current_cpu_data.vpe_id; | ||
86 | int cpu = smp_processor_id(); | ||
87 | local_irq_save(flags); | ||
88 | mtflags = dmt(); | ||
89 | |||
90 | /* | ||
91 | * Maintain the per-TC virtual timer | ||
92 | * and program the per-VPE shared Count register | ||
93 | * as appropriate here... | ||
94 | */ | ||
95 | reference = (unsigned long)read_c0_count(); | ||
96 | timestamp = MAKEVALID(reference + delta); | ||
97 | /* | ||
98 | * To really model the clock, we have to catch the case | ||
99 | * where the current next-in-VPE timestamp is the old | ||
100 | * timestamp for the calling CPE, but the new value is | ||
101 | * in fact later. In that case, we have to do a full | ||
102 | * scan and discover the new next-in-VPE CPU id and | ||
103 | * timestamp. | ||
104 | */ | ||
105 | previous = smtc_nexttime[vpe][cpu]; | ||
106 | if (cpu == smtc_nextinvpe[vpe] && ISVALID(previous) | ||
107 | && IS_SOONER(previous, timestamp, reference)) { | ||
108 | int i; | ||
109 | int soonest = cpu; | ||
110 | |||
111 | /* | ||
112 | * Update timestamp array here, so that new | ||
113 | * value gets considered along with those of | ||
114 | * other virtual CPUs on the VPE. | ||
115 | */ | ||
116 | smtc_nexttime[vpe][cpu] = timestamp; | ||
117 | for_each_online_cpu(i) { | ||
118 | if (ISVALID(smtc_nexttime[vpe][i]) | ||
119 | && IS_SOONER(smtc_nexttime[vpe][i], | ||
120 | smtc_nexttime[vpe][soonest], reference)) { | ||
121 | soonest = i; | ||
122 | } | ||
123 | } | ||
124 | smtc_nextinvpe[vpe] = soonest; | ||
125 | nextcomp = smtc_nexttime[vpe][soonest]; | ||
126 | /* | ||
127 | * Otherwise, we don't have to process the whole array rank, | ||
128 | * we just have to see if the event horizon has gotten closer. | ||
129 | */ | ||
130 | } else { | ||
131 | if (!ISVALID(smtc_nexttime[vpe][smtc_nextinvpe[vpe]]) || | ||
132 | IS_SOONER(timestamp, | ||
133 | smtc_nexttime[vpe][smtc_nextinvpe[vpe]], reference)) { | ||
134 | smtc_nextinvpe[vpe] = cpu; | ||
135 | nextcomp = timestamp; | ||
136 | } | ||
137 | /* | ||
138 | * Since next-in-VPE may me the same as the executing | ||
139 | * virtual CPU, we update the array *after* checking | ||
140 | * its value. | ||
141 | */ | ||
142 | smtc_nexttime[vpe][cpu] = timestamp; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * It may be that, in fact, we don't need to update Compare, | ||
147 | * but if we do, we want to make sure we didn't fall into | ||
148 | * a crack just behind Count. | ||
149 | */ | ||
150 | if (ISVALID(nextcomp)) { | ||
151 | write_c0_compare(nextcomp); | ||
152 | ehb(); | ||
153 | /* | ||
154 | * We never return an error, we just make sure | ||
155 | * that we trigger the handlers as quickly as | ||
156 | * we can if we fell behind. | ||
157 | */ | ||
158 | while ((nextcomp - (unsigned long)read_c0_count()) | ||
159 | > (unsigned long)LONG_MAX) { | ||
160 | nextcomp += CATCHUP_INCREMENT; | ||
161 | write_c0_compare(nextcomp); | ||
162 | ehb(); | ||
163 | } | ||
164 | } | ||
165 | emt(mtflags); | ||
166 | local_irq_restore(flags); | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | |||
171 | void smtc_distribute_timer(int vpe) | ||
172 | { | ||
173 | unsigned long flags; | ||
174 | unsigned int mtflags; | ||
175 | int cpu; | ||
176 | struct clock_event_device *cd; | ||
177 | unsigned long nextstamp; | ||
178 | unsigned long reference; | ||
179 | |||
180 | |||
181 | repeat: | ||
182 | nextstamp = 0L; | ||
183 | for_each_online_cpu(cpu) { | ||
184 | /* | ||
185 | * Find virtual CPUs within the current VPE who have | ||
186 | * unserviced timer requests whose time is now past. | ||
187 | */ | ||
188 | local_irq_save(flags); | ||
189 | mtflags = dmt(); | ||
190 | if (cpu_data[cpu].vpe_id == vpe && | ||
191 | ISVALID(smtc_nexttime[vpe][cpu])) { | ||
192 | reference = (unsigned long)read_c0_count(); | ||
193 | if ((smtc_nexttime[vpe][cpu] - reference) | ||
194 | > (unsigned long)LONG_MAX) { | ||
195 | smtc_nexttime[vpe][cpu] = 0L; | ||
196 | emt(mtflags); | ||
197 | local_irq_restore(flags); | ||
198 | /* | ||
199 | * We don't send IPIs to ourself. | ||
200 | */ | ||
201 | if (cpu != smp_processor_id()) { | ||
202 | smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); | ||
203 | } else { | ||
204 | cd = &per_cpu(mips_clockevent_device, cpu); | ||
205 | cd->event_handler(cd); | ||
206 | } | ||
207 | } else { | ||
208 | /* Local to VPE but Valid Time not yet reached. */ | ||
209 | if (!ISVALID(nextstamp) || | ||
210 | IS_SOONER(smtc_nexttime[vpe][cpu], nextstamp, | ||
211 | reference)) { | ||
212 | smtc_nextinvpe[vpe] = cpu; | ||
213 | nextstamp = smtc_nexttime[vpe][cpu]; | ||
214 | } | ||
215 | emt(mtflags); | ||
216 | local_irq_restore(flags); | ||
217 | } | ||
218 | } else { | ||
219 | emt(mtflags); | ||
220 | local_irq_restore(flags); | ||
221 | |||
222 | } | ||
223 | } | ||
224 | /* Reprogram for interrupt at next soonest timestamp for VPE */ | ||
225 | if (ISVALID(nextstamp)) { | ||
226 | write_c0_compare(nextstamp); | ||
227 | ehb(); | ||
228 | if ((nextstamp - (unsigned long)read_c0_count()) | ||
229 | > (unsigned long)LONG_MAX) | ||
230 | goto repeat; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | |||
235 | irqreturn_t c0_compare_interrupt(int irq, void *dev_id) | ||
236 | { | ||
237 | int cpu = smp_processor_id(); | ||
238 | |||
239 | /* If we're running SMTC, we've got MIPS MT and therefore MIPS32R2 */ | ||
240 | handle_perf_irq(1); | ||
241 | |||
242 | if (read_c0_cause() & (1 << 30)) { | ||
243 | /* Clear Count/Compare Interrupt */ | ||
244 | write_c0_compare(read_c0_compare()); | ||
245 | smtc_distribute_timer(cpu_data[cpu].vpe_id); | ||
246 | } | ||
247 | return IRQ_HANDLED; | ||
248 | } | ||
249 | |||
250 | |||
251 | int smtc_clockevent_init(void) | ||
252 | { | ||
253 | uint64_t mips_freq = mips_hpt_frequency; | ||
254 | unsigned int cpu = smp_processor_id(); | ||
255 | struct clock_event_device *cd; | ||
256 | unsigned int irq; | ||
257 | int i; | ||
258 | int j; | ||
259 | |||
260 | if (!cpu_has_counter || !mips_hpt_frequency) | ||
261 | return -ENXIO; | ||
262 | if (cpu == 0) { | ||
263 | for (i = 0; i < num_possible_cpus(); i++) { | ||
264 | smtc_nextinvpe[i] = 0; | ||
265 | for (j = 0; j < num_possible_cpus(); j++) | ||
266 | smtc_nexttime[i][j] = 0L; | ||
267 | } | ||
268 | /* | ||
269 | * SMTC also can't have the usablility test | ||
270 | * run by secondary TCs once Compare is in use. | ||
271 | */ | ||
272 | if (!c0_compare_int_usable()) | ||
273 | return -ENXIO; | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * With vectored interrupts things are getting platform specific. | ||
278 | * get_c0_compare_int is a hook to allow a platform to return the | ||
279 | * interrupt number of it's liking. | ||
280 | */ | ||
281 | irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; | ||
282 | if (get_c0_compare_int) | ||
283 | irq = get_c0_compare_int(); | ||
284 | |||
285 | cd = &per_cpu(mips_clockevent_device, cpu); | ||
286 | |||
287 | cd->name = "MIPS"; | ||
288 | cd->features = CLOCK_EVT_FEAT_ONESHOT; | ||
289 | |||
290 | /* Calculate the min / max delta */ | ||
291 | cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); | ||
292 | cd->shift = 32; | ||
293 | cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); | ||
294 | cd->min_delta_ns = clockevent_delta2ns(0x300, cd); | ||
295 | |||
296 | cd->rating = 300; | ||
297 | cd->irq = irq; | ||
298 | cd->cpumask = cpumask_of(cpu); | ||
299 | cd->set_next_event = mips_next_event; | ||
300 | cd->set_mode = mips_set_clock_mode; | ||
301 | cd->event_handler = mips_event_handler; | ||
302 | |||
303 | clockevents_register_device(cd); | ||
304 | |||
305 | /* | ||
306 | * On SMTC we only want to do the data structure | ||
307 | * initialization and IRQ setup once. | ||
308 | */ | ||
309 | if (cpu) | ||
310 | return 0; | ||
311 | /* | ||
312 | * And we need the hwmask associated with the c0_compare | ||
313 | * vector to be initialized. | ||
314 | */ | ||
315 | irq_hwmask[irq] = (0x100 << cp0_compare_irq); | ||
316 | if (cp0_timer_irq_installed) | ||
317 | return 0; | ||
318 | |||
319 | cp0_timer_irq_installed = 1; | ||
320 | |||
321 | setup_irq(irq, &c0_compare_irqaction); | ||
322 | |||
323 | return 0; | ||
324 | } | ||
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index f7a46db4b161..6f4f739dad96 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S | |||
@@ -14,19 +14,43 @@ | |||
14 | #include <asm/asmmacro.h> | 14 | #include <asm/asmmacro.h> |
15 | #include <asm/cacheops.h> | 15 | #include <asm/cacheops.h> |
16 | #include <asm/mipsregs.h> | 16 | #include <asm/mipsregs.h> |
17 | #include <asm/mipsmtregs.h> | ||
18 | #include <asm/pm.h> | ||
17 | 19 | ||
18 | #define GCR_CL_COHERENCE_OFS 0x2008 | 20 | #define GCR_CL_COHERENCE_OFS 0x2008 |
21 | #define GCR_CL_ID_OFS 0x2028 | ||
22 | |||
23 | .extern mips_cm_base | ||
24 | |||
25 | .set noreorder | ||
26 | |||
27 | /* | ||
28 | * Set dest to non-zero if the core supports the MT ASE, else zero. If | ||
29 | * MT is not supported then branch to nomt. | ||
30 | */ | ||
31 | .macro has_mt dest, nomt | ||
32 | mfc0 \dest, CP0_CONFIG | ||
33 | bgez \dest, \nomt | ||
34 | mfc0 \dest, CP0_CONFIG, 1 | ||
35 | bgez \dest, \nomt | ||
36 | mfc0 \dest, CP0_CONFIG, 2 | ||
37 | bgez \dest, \nomt | ||
38 | mfc0 \dest, CP0_CONFIG, 3 | ||
39 | andi \dest, \dest, MIPS_CONF3_MT | ||
40 | beqz \dest, \nomt | ||
41 | .endm | ||
19 | 42 | ||
20 | .section .text.cps-vec | 43 | .section .text.cps-vec |
21 | .balign 0x1000 | 44 | .balign 0x1000 |
22 | .set noreorder | ||
23 | 45 | ||
24 | LEAF(mips_cps_core_entry) | 46 | LEAF(mips_cps_core_entry) |
25 | /* | 47 | /* |
26 | * These first 8 bytes will be patched by cps_smp_setup to load the | 48 | * These first 12 bytes will be patched by cps_smp_setup to load the |
27 | * base address of the CM GCRs into register v1. | 49 | * base address of the CM GCRs into register v1 and the CCA to use into |
50 | * register s0. | ||
28 | */ | 51 | */ |
29 | .quad 0 | 52 | .quad 0 |
53 | .word 0 | ||
30 | 54 | ||
31 | /* Check whether we're here due to an NMI */ | 55 | /* Check whether we're here due to an NMI */ |
32 | mfc0 k0, CP0_STATUS | 56 | mfc0 k0, CP0_STATUS |
@@ -117,10 +141,11 @@ icache_done: | |||
117 | add a0, a0, t0 | 141 | add a0, a0, t0 |
118 | dcache_done: | 142 | dcache_done: |
119 | 143 | ||
120 | /* Set Kseg0 cacheable, coherent, write-back, write-allocate */ | 144 | /* Set Kseg0 CCA to that in s0 */ |
121 | mfc0 t0, CP0_CONFIG | 145 | mfc0 t0, CP0_CONFIG |
122 | ori t0, 0x7 | 146 | ori t0, 0x7 |
123 | xori t0, 0x2 | 147 | xori t0, 0x7 |
148 | or t0, t0, s0 | ||
124 | mtc0 t0, CP0_CONFIG | 149 | mtc0 t0, CP0_CONFIG |
125 | ehb | 150 | ehb |
126 | 151 | ||
@@ -134,21 +159,24 @@ dcache_done: | |||
134 | jr t0 | 159 | jr t0 |
135 | nop | 160 | nop |
136 | 161 | ||
137 | 1: /* We're up, cached & coherent */ | 162 | /* |
163 | * We're up, cached & coherent. Perform any further required core-level | ||
164 | * initialisation. | ||
165 | */ | ||
166 | 1: jal mips_cps_core_init | ||
167 | nop | ||
138 | 168 | ||
139 | /* | 169 | /* |
140 | * TODO: We should check the VPE number we intended to boot here, and | 170 | * Boot any other VPEs within this core that should be online, and |
141 | * if non-zero we should start that VPE and stop this one. For | 171 | * deactivate this VPE if it should be offline. |
142 | * the moment this doesn't matter since CPUs are brought up | ||
143 | * sequentially and in order, but once hotplug is implemented | ||
144 | * this will need revisiting. | ||
145 | */ | 172 | */ |
173 | jal mips_cps_boot_vpes | ||
174 | nop | ||
146 | 175 | ||
147 | /* Off we go! */ | 176 | /* Off we go! */ |
148 | la t0, mips_cps_bootcfg | 177 | lw t1, VPEBOOTCFG_PC(v0) |
149 | lw t1, BOOTCFG_PC(t0) | 178 | lw gp, VPEBOOTCFG_GP(v0) |
150 | lw gp, BOOTCFG_GP(t0) | 179 | lw sp, VPEBOOTCFG_SP(v0) |
151 | lw sp, BOOTCFG_SP(t0) | ||
152 | jr t1 | 180 | jr t1 |
153 | nop | 181 | nop |
154 | END(mips_cps_core_entry) | 182 | END(mips_cps_core_entry) |
@@ -189,3 +217,271 @@ LEAF(excep_ejtag) | |||
189 | jr k0 | 217 | jr k0 |
190 | nop | 218 | nop |
191 | END(excep_ejtag) | 219 | END(excep_ejtag) |
220 | |||
221 | LEAF(mips_cps_core_init) | ||
222 | #ifdef CONFIG_MIPS_MT | ||
223 | /* Check that the core implements the MT ASE */ | ||
224 | has_mt t0, 3f | ||
225 | nop | ||
226 | |||
227 | .set push | ||
228 | .set mt | ||
229 | |||
230 | /* Only allow 1 TC per VPE to execute... */ | ||
231 | dmt | ||
232 | |||
233 | /* ...and for the moment only 1 VPE */ | ||
234 | dvpe | ||
235 | la t1, 1f | ||
236 | jr.hb t1 | ||
237 | nop | ||
238 | |||
239 | /* Enter VPE configuration state */ | ||
240 | 1: mfc0 t0, CP0_MVPCONTROL | ||
241 | ori t0, t0, MVPCONTROL_VPC | ||
242 | mtc0 t0, CP0_MVPCONTROL | ||
243 | |||
244 | /* Retrieve the number of VPEs within the core */ | ||
245 | mfc0 t0, CP0_MVPCONF0 | ||
246 | srl t0, t0, MVPCONF0_PVPE_SHIFT | ||
247 | andi t0, t0, (MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT) | ||
248 | addi t7, t0, 1 | ||
249 | |||
250 | /* If there's only 1, we're done */ | ||
251 | beqz t0, 2f | ||
252 | nop | ||
253 | |||
254 | /* Loop through each VPE within this core */ | ||
255 | li t5, 1 | ||
256 | |||
257 | 1: /* Operate on the appropriate TC */ | ||
258 | mtc0 t5, CP0_VPECONTROL | ||
259 | ehb | ||
260 | |||
261 | /* Bind TC to VPE (1:1 TC:VPE mapping) */ | ||
262 | mttc0 t5, CP0_TCBIND | ||
263 | |||
264 | /* Set exclusive TC, non-active, master */ | ||
265 | li t0, VPECONF0_MVP | ||
266 | sll t1, t5, VPECONF0_XTC_SHIFT | ||
267 | or t0, t0, t1 | ||
268 | mttc0 t0, CP0_VPECONF0 | ||
269 | |||
270 | /* Set TC non-active, non-allocatable */ | ||
271 | mttc0 zero, CP0_TCSTATUS | ||
272 | |||
273 | /* Set TC halted */ | ||
274 | li t0, TCHALT_H | ||
275 | mttc0 t0, CP0_TCHALT | ||
276 | |||
277 | /* Next VPE */ | ||
278 | addi t5, t5, 1 | ||
279 | slt t0, t5, t7 | ||
280 | bnez t0, 1b | ||
281 | nop | ||
282 | |||
283 | /* Leave VPE configuration state */ | ||
284 | 2: mfc0 t0, CP0_MVPCONTROL | ||
285 | xori t0, t0, MVPCONTROL_VPC | ||
286 | mtc0 t0, CP0_MVPCONTROL | ||
287 | |||
288 | 3: .set pop | ||
289 | #endif | ||
290 | jr ra | ||
291 | nop | ||
292 | END(mips_cps_core_init) | ||
293 | |||
294 | LEAF(mips_cps_boot_vpes) | ||
295 | /* Retrieve CM base address */ | ||
296 | la t0, mips_cm_base | ||
297 | lw t0, 0(t0) | ||
298 | |||
299 | /* Calculate a pointer to this cores struct core_boot_config */ | ||
300 | lw t0, GCR_CL_ID_OFS(t0) | ||
301 | li t1, COREBOOTCFG_SIZE | ||
302 | mul t0, t0, t1 | ||
303 | la t1, mips_cps_core_bootcfg | ||
304 | lw t1, 0(t1) | ||
305 | addu t0, t0, t1 | ||
306 | |||
307 | /* Calculate this VPEs ID. If the core doesn't support MT use 0 */ | ||
308 | has_mt t6, 1f | ||
309 | li t9, 0 | ||
310 | |||
311 | /* Find the number of VPEs present in the core */ | ||
312 | mfc0 t1, CP0_MVPCONF0 | ||
313 | srl t1, t1, MVPCONF0_PVPE_SHIFT | ||
314 | andi t1, t1, MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT | ||
315 | addi t1, t1, 1 | ||
316 | |||
317 | /* Calculate a mask for the VPE ID from EBase.CPUNum */ | ||
318 | clz t1, t1 | ||
319 | li t2, 31 | ||
320 | subu t1, t2, t1 | ||
321 | li t2, 1 | ||
322 | sll t1, t2, t1 | ||
323 | addiu t1, t1, -1 | ||
324 | |||
325 | /* Retrieve the VPE ID from EBase.CPUNum */ | ||
326 | mfc0 t9, $15, 1 | ||
327 | and t9, t9, t1 | ||
328 | |||
329 | 1: /* Calculate a pointer to this VPEs struct vpe_boot_config */ | ||
330 | li t1, VPEBOOTCFG_SIZE | ||
331 | mul v0, t9, t1 | ||
332 | lw t7, COREBOOTCFG_VPECONFIG(t0) | ||
333 | addu v0, v0, t7 | ||
334 | |||
335 | #ifdef CONFIG_MIPS_MT | ||
336 | |||
337 | /* If the core doesn't support MT then return */ | ||
338 | bnez t6, 1f | ||
339 | nop | ||
340 | jr ra | ||
341 | nop | ||
342 | |||
343 | .set push | ||
344 | .set mt | ||
345 | |||
346 | 1: /* Enter VPE configuration state */ | ||
347 | dvpe | ||
348 | la t1, 1f | ||
349 | jr.hb t1 | ||
350 | nop | ||
351 | 1: mfc0 t1, CP0_MVPCONTROL | ||
352 | ori t1, t1, MVPCONTROL_VPC | ||
353 | mtc0 t1, CP0_MVPCONTROL | ||
354 | ehb | ||
355 | |||
356 | /* Loop through each VPE */ | ||
357 | lw t6, COREBOOTCFG_VPEMASK(t0) | ||
358 | move t8, t6 | ||
359 | li t5, 0 | ||
360 | |||
361 | /* Check whether the VPE should be running. If not, skip it */ | ||
362 | 1: andi t0, t6, 1 | ||
363 | beqz t0, 2f | ||
364 | nop | ||
365 | |||
366 | /* Operate on the appropriate TC */ | ||
367 | mfc0 t0, CP0_VPECONTROL | ||
368 | ori t0, t0, VPECONTROL_TARGTC | ||
369 | xori t0, t0, VPECONTROL_TARGTC | ||
370 | or t0, t0, t5 | ||
371 | mtc0 t0, CP0_VPECONTROL | ||
372 | ehb | ||
373 | |||
374 | /* Skip the VPE if its TC is not halted */ | ||
375 | mftc0 t0, CP0_TCHALT | ||
376 | beqz t0, 2f | ||
377 | nop | ||
378 | |||
379 | /* Calculate a pointer to the VPEs struct vpe_boot_config */ | ||
380 | li t0, VPEBOOTCFG_SIZE | ||
381 | mul t0, t0, t5 | ||
382 | addu t0, t0, t7 | ||
383 | |||
384 | /* Set the TC restart PC */ | ||
385 | lw t1, VPEBOOTCFG_PC(t0) | ||
386 | mttc0 t1, CP0_TCRESTART | ||
387 | |||
388 | /* Set the TC stack pointer */ | ||
389 | lw t1, VPEBOOTCFG_SP(t0) | ||
390 | mttgpr t1, sp | ||
391 | |||
392 | /* Set the TC global pointer */ | ||
393 | lw t1, VPEBOOTCFG_GP(t0) | ||
394 | mttgpr t1, gp | ||
395 | |||
396 | /* Copy config from this VPE */ | ||
397 | mfc0 t0, CP0_CONFIG | ||
398 | mttc0 t0, CP0_CONFIG | ||
399 | |||
400 | /* Ensure no software interrupts are pending */ | ||
401 | mttc0 zero, CP0_CAUSE | ||
402 | mttc0 zero, CP0_STATUS | ||
403 | |||
404 | /* Set TC active, not interrupt exempt */ | ||
405 | mftc0 t0, CP0_TCSTATUS | ||
406 | li t1, ~TCSTATUS_IXMT | ||
407 | and t0, t0, t1 | ||
408 | ori t0, t0, TCSTATUS_A | ||
409 | mttc0 t0, CP0_TCSTATUS | ||
410 | |||
411 | /* Clear the TC halt bit */ | ||
412 | mttc0 zero, CP0_TCHALT | ||
413 | |||
414 | /* Set VPE active */ | ||
415 | mftc0 t0, CP0_VPECONF0 | ||
416 | ori t0, t0, VPECONF0_VPA | ||
417 | mttc0 t0, CP0_VPECONF0 | ||
418 | |||
419 | /* Next VPE */ | ||
420 | 2: srl t6, t6, 1 | ||
421 | addi t5, t5, 1 | ||
422 | bnez t6, 1b | ||
423 | nop | ||
424 | |||
425 | /* Leave VPE configuration state */ | ||
426 | mfc0 t1, CP0_MVPCONTROL | ||
427 | xori t1, t1, MVPCONTROL_VPC | ||
428 | mtc0 t1, CP0_MVPCONTROL | ||
429 | ehb | ||
430 | evpe | ||
431 | |||
432 | /* Check whether this VPE is meant to be running */ | ||
433 | li t0, 1 | ||
434 | sll t0, t0, t9 | ||
435 | and t0, t0, t8 | ||
436 | bnez t0, 2f | ||
437 | nop | ||
438 | |||
439 | /* This VPE should be offline, halt the TC */ | ||
440 | li t0, TCHALT_H | ||
441 | mtc0 t0, CP0_TCHALT | ||
442 | la t0, 1f | ||
443 | 1: jr.hb t0 | ||
444 | nop | ||
445 | |||
446 | 2: .set pop | ||
447 | |||
448 | #endif /* CONFIG_MIPS_MT */ | ||
449 | |||
450 | /* Return */ | ||
451 | jr ra | ||
452 | nop | ||
453 | END(mips_cps_boot_vpes) | ||
454 | |||
455 | #if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM) | ||
456 | |||
457 | /* Calculate a pointer to this CPUs struct mips_static_suspend_state */ | ||
458 | .macro psstate dest | ||
459 | .set push | ||
460 | .set noat | ||
461 | lw $1, TI_CPU(gp) | ||
462 | sll $1, $1, LONGLOG | ||
463 | la \dest, __per_cpu_offset | ||
464 | addu $1, $1, \dest | ||
465 | lw $1, 0($1) | ||
466 | la \dest, cps_cpu_state | ||
467 | addu \dest, \dest, $1 | ||
468 | .set pop | ||
469 | .endm | ||
470 | |||
471 | LEAF(mips_cps_pm_save) | ||
472 | /* Save CPU state */ | ||
473 | SUSPEND_SAVE_REGS | ||
474 | psstate t1 | ||
475 | SUSPEND_SAVE_STATIC | ||
476 | jr v0 | ||
477 | nop | ||
478 | END(mips_cps_pm_save) | ||
479 | |||
480 | LEAF(mips_cps_pm_restore) | ||
481 | /* Restore CPU state */ | ||
482 | psstate t1 | ||
483 | RESUME_RESTORE_STATIC | ||
484 | RESUME_RESTORE_REGS_RETURN | ||
485 | END(mips_cps_pm_restore) | ||
486 | |||
487 | #endif /* CONFIG_MIPS_CPS_PM && CONFIG_CPU_PM */ | ||
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 6e8fb85ce7c3..d74f957c561e 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c | |||
@@ -62,7 +62,7 @@ static inline void check_errata(void) | |||
62 | case CPU_34K: | 62 | case CPU_34K: |
63 | /* | 63 | /* |
64 | * Erratum "RPS May Cause Incorrect Instruction Execution" | 64 | * Erratum "RPS May Cause Incorrect Instruction Execution" |
65 | * This code only handles VPE0, any SMP/SMTC/RTOS code | 65 | * This code only handles VPE0, any SMP/RTOS code |
66 | * making use of VPE1 will be responsable for that VPE. | 66 | * making use of VPE1 will be responsable for that VPE. |
67 | */ | 67 | */ |
68 | if ((c->processor_id & PRID_REV_MASK) <= PRID_REV_34K_V1_0_2) | 68 | if ((c->processor_id & PRID_REV_MASK) <= PRID_REV_34K_V1_0_2) |
@@ -423,7 +423,7 @@ static void decode_configs(struct cpuinfo_mips *c) | |||
423 | 423 | ||
424 | #ifndef CONFIG_MIPS_CPS | 424 | #ifndef CONFIG_MIPS_CPS |
425 | if (cpu_has_mips_r2) { | 425 | if (cpu_has_mips_r2) { |
426 | c->core = read_c0_ebase() & 0x3ff; | 426 | c->core = get_ebase_cpunum(); |
427 | if (cpu_has_mipsmt) | 427 | if (cpu_has_mipsmt) |
428 | c->core >>= fls(core_nvpes()) - 1; | 428 | c->core >>= fls(core_nvpes()) - 1; |
429 | } | 429 | } |
@@ -684,21 +684,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) | |||
684 | */ | 684 | */ |
685 | c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48; | 685 | c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48; |
686 | break; | 686 | break; |
687 | case PRID_IMP_RM9000: | ||
688 | c->cputype = CPU_RM9000; | ||
689 | __cpu_name[cpu] = "RM9000"; | ||
690 | set_isa(c, MIPS_CPU_ISA_IV); | ||
691 | c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | | ||
692 | MIPS_CPU_LLSC; | ||
693 | /* | ||
694 | * Bit 29 in the info register of the RM9000 | ||
695 | * indicates if the TLB has 48 or 64 entries. | ||
696 | * | ||
697 | * 29 1 => 64 entry JTLB | ||
698 | * 0 => 48 entry JTLB | ||
699 | */ | ||
700 | c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48; | ||
701 | break; | ||
702 | case PRID_IMP_R8000: | 687 | case PRID_IMP_R8000: |
703 | c->cputype = CPU_R8000; | 688 | c->cputype = CPU_R8000; |
704 | __cpu_name[cpu] = "RM8000"; | 689 | __cpu_name[cpu] = "RM8000"; |
@@ -1041,6 +1026,7 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) | |||
1041 | decode_configs(c); | 1026 | decode_configs(c); |
1042 | /* JZRISC does not implement the CP0 counter. */ | 1027 | /* JZRISC does not implement the CP0 counter. */ |
1043 | c->options &= ~MIPS_CPU_COUNTER; | 1028 | c->options &= ~MIPS_CPU_COUNTER; |
1029 | BUG_ON(!__builtin_constant_p(cpu_has_counter) || cpu_has_counter); | ||
1044 | switch (c->processor_id & PRID_IMP_MASK) { | 1030 | switch (c->processor_id & PRID_IMP_MASK) { |
1045 | case PRID_IMP_JZRISC: | 1031 | case PRID_IMP_JZRISC: |
1046 | c->cputype = CPU_JZRISC; | 1032 | c->cputype = CPU_JZRISC; |
@@ -1074,6 +1060,7 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) | |||
1074 | switch (c->processor_id & PRID_IMP_MASK) { | 1060 | switch (c->processor_id & PRID_IMP_MASK) { |
1075 | case PRID_IMP_NETLOGIC_XLP2XX: | 1061 | case PRID_IMP_NETLOGIC_XLP2XX: |
1076 | case PRID_IMP_NETLOGIC_XLP9XX: | 1062 | case PRID_IMP_NETLOGIC_XLP9XX: |
1063 | case PRID_IMP_NETLOGIC_XLP5XX: | ||
1077 | c->cputype = CPU_XLP; | 1064 | c->cputype = CPU_XLP; |
1078 | __cpu_name[cpu] = "Broadcom XLPII"; | 1065 | __cpu_name[cpu] = "Broadcom XLPII"; |
1079 | break; | 1066 | break; |
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index e5786858cdb6..4353d323f017 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S | |||
@@ -16,9 +16,6 @@ | |||
16 | #include <asm/isadep.h> | 16 | #include <asm/isadep.h> |
17 | #include <asm/thread_info.h> | 17 | #include <asm/thread_info.h> |
18 | #include <asm/war.h> | 18 | #include <asm/war.h> |
19 | #ifdef CONFIG_MIPS_MT_SMTC | ||
20 | #include <asm/mipsmtregs.h> | ||
21 | #endif | ||
22 | 19 | ||
23 | #ifndef CONFIG_PREEMPT | 20 | #ifndef CONFIG_PREEMPT |
24 | #define resume_kernel restore_all | 21 | #define resume_kernel restore_all |
@@ -89,41 +86,6 @@ FEXPORT(syscall_exit) | |||
89 | bnez t0, syscall_exit_work | 86 | bnez t0, syscall_exit_work |
90 | 87 | ||
91 | restore_all: # restore full frame | 88 | restore_all: # restore full frame |
92 | #ifdef CONFIG_MIPS_MT_SMTC | ||
93 | #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP | ||
94 | /* Re-arm any temporarily masked interrupts not explicitly "acked" */ | ||
95 | mfc0 v0, CP0_TCSTATUS | ||
96 | ori v1, v0, TCSTATUS_IXMT | ||
97 | mtc0 v1, CP0_TCSTATUS | ||
98 | andi v0, TCSTATUS_IXMT | ||
99 | _ehb | ||
100 | mfc0 t0, CP0_TCCONTEXT | ||
101 | DMT 9 # dmt t1 | ||
102 | jal mips_ihb | ||
103 | mfc0 t2, CP0_STATUS | ||
104 | andi t3, t0, 0xff00 | ||
105 | or t2, t2, t3 | ||
106 | mtc0 t2, CP0_STATUS | ||
107 | _ehb | ||
108 | andi t1, t1, VPECONTROL_TE | ||
109 | beqz t1, 1f | ||
110 | EMT | ||
111 | 1: | ||
112 | mfc0 v1, CP0_TCSTATUS | ||
113 | /* We set IXMT above, XOR should clear it here */ | ||
114 | xori v1, v1, TCSTATUS_IXMT | ||
115 | or v1, v0, v1 | ||
116 | mtc0 v1, CP0_TCSTATUS | ||
117 | _ehb | ||
118 | xor t0, t0, t3 | ||
119 | mtc0 t0, CP0_TCCONTEXT | ||
120 | #endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */ | ||
121 | /* Detect and execute deferred IPI "interrupts" */ | ||
122 | LONG_L s0, TI_REGS($28) | ||
123 | LONG_S sp, TI_REGS($28) | ||
124 | jal deferred_smtc_ipi | ||
125 | LONG_S s0, TI_REGS($28) | ||
126 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
127 | .set noat | 89 | .set noat |
128 | RESTORE_TEMP | 90 | RESTORE_TEMP |
129 | RESTORE_AT | 91 | RESTORE_AT |
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index a9ce3408be25..ac35e12cb1f3 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S | |||
@@ -21,20 +21,6 @@ | |||
21 | #include <asm/war.h> | 21 | #include <asm/war.h> |
22 | #include <asm/thread_info.h> | 22 | #include <asm/thread_info.h> |
23 | 23 | ||
24 | #ifdef CONFIG_MIPS_MT_SMTC | ||
25 | #define PANIC_PIC(msg) \ | ||
26 | .set push; \ | ||
27 | .set nomicromips; \ | ||
28 | .set reorder; \ | ||
29 | PTR_LA a0,8f; \ | ||
30 | .set noat; \ | ||
31 | PTR_LA AT, panic; \ | ||
32 | jr AT; \ | ||
33 | 9: b 9b; \ | ||
34 | .set pop; \ | ||
35 | TEXT(msg) | ||
36 | #endif | ||
37 | |||
38 | __INIT | 24 | __INIT |
39 | 25 | ||
40 | /* | 26 | /* |
@@ -251,15 +237,6 @@ NESTED(except_vec_vi, 0, sp) | |||
251 | SAVE_AT | 237 | SAVE_AT |
252 | .set push | 238 | .set push |
253 | .set noreorder | 239 | .set noreorder |
254 | #ifdef CONFIG_MIPS_MT_SMTC | ||
255 | /* | ||
256 | * To keep from blindly blocking *all* interrupts | ||
257 | * during service by SMTC kernel, we also want to | ||
258 | * pass the IM value to be cleared. | ||
259 | */ | ||
260 | FEXPORT(except_vec_vi_mori) | ||
261 | ori a0, $0, 0 | ||
262 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
263 | PTR_LA v1, except_vec_vi_handler | 240 | PTR_LA v1, except_vec_vi_handler |
264 | FEXPORT(except_vec_vi_lui) | 241 | FEXPORT(except_vec_vi_lui) |
265 | lui v0, 0 /* Patched */ | 242 | lui v0, 0 /* Patched */ |
@@ -277,37 +254,10 @@ EXPORT(except_vec_vi_end) | |||
277 | NESTED(except_vec_vi_handler, 0, sp) | 254 | NESTED(except_vec_vi_handler, 0, sp) |
278 | SAVE_TEMP | 255 | SAVE_TEMP |
279 | SAVE_STATIC | 256 | SAVE_STATIC |
280 | #ifdef CONFIG_MIPS_MT_SMTC | ||
281 | /* | ||
282 | * SMTC has an interesting problem that interrupts are level-triggered, | ||
283 | * and the CLI macro will clear EXL, potentially causing a duplicate | ||
284 | * interrupt service invocation. So we need to clear the associated | ||
285 | * IM bit of Status prior to doing CLI, and restore it after the | ||
286 | * service routine has been invoked - we must assume that the | ||
287 | * service routine will have cleared the state, and any active | ||
288 | * level represents a new or otherwised unserviced event... | ||
289 | */ | ||
290 | mfc0 t1, CP0_STATUS | ||
291 | and t0, a0, t1 | ||
292 | #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP | ||
293 | mfc0 t2, CP0_TCCONTEXT | ||
294 | or t2, t0, t2 | ||
295 | mtc0 t2, CP0_TCCONTEXT | ||
296 | #endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */ | ||
297 | xor t1, t1, t0 | ||
298 | mtc0 t1, CP0_STATUS | ||
299 | _ehb | ||
300 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
301 | CLI | 257 | CLI |
302 | #ifdef CONFIG_TRACE_IRQFLAGS | 258 | #ifdef CONFIG_TRACE_IRQFLAGS |
303 | move s0, v0 | 259 | move s0, v0 |
304 | #ifdef CONFIG_MIPS_MT_SMTC | ||
305 | move s1, a0 | ||
306 | #endif | ||
307 | TRACE_IRQS_OFF | 260 | TRACE_IRQS_OFF |
308 | #ifdef CONFIG_MIPS_MT_SMTC | ||
309 | move a0, s1 | ||
310 | #endif | ||
311 | move v0, s0 | 261 | move v0, s0 |
312 | #endif | 262 | #endif |
313 | 263 | ||
@@ -496,9 +446,6 @@ NESTED(nmi_handler, PT_SIZE, sp) | |||
496 | 446 | ||
497 | .align 5 | 447 | .align 5 |
498 | LEAF(handle_ri_rdhwr_vivt) | 448 | LEAF(handle_ri_rdhwr_vivt) |
499 | #ifdef CONFIG_MIPS_MT_SMTC | ||
500 | PANIC_PIC("handle_ri_rdhwr_vivt called") | ||
501 | #else | ||
502 | .set push | 449 | .set push |
503 | .set noat | 450 | .set noat |
504 | .set noreorder | 451 | .set noreorder |
@@ -517,7 +464,6 @@ NESTED(nmi_handler, PT_SIZE, sp) | |||
517 | .set pop | 464 | .set pop |
518 | bltz k1, handle_ri /* slow path */ | 465 | bltz k1, handle_ri /* slow path */ |
519 | /* fall thru */ | 466 | /* fall thru */ |
520 | #endif | ||
521 | END(handle_ri_rdhwr_vivt) | 467 | END(handle_ri_rdhwr_vivt) |
522 | 468 | ||
523 | LEAF(handle_ri_rdhwr) | 469 | LEAF(handle_ri_rdhwr) |
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index e712dcf18b2d..95afd663cd45 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S | |||
@@ -35,33 +35,12 @@ | |||
35 | */ | 35 | */ |
36 | .macro setup_c0_status set clr | 36 | .macro setup_c0_status set clr |
37 | .set push | 37 | .set push |
38 | #ifdef CONFIG_MIPS_MT_SMTC | ||
39 | /* | ||
40 | * For SMTC, we need to set privilege and disable interrupts only for | ||
41 | * the current TC, using the TCStatus register. | ||
42 | */ | ||
43 | mfc0 t0, CP0_TCSTATUS | ||
44 | /* Fortunately CU 0 is in the same place in both registers */ | ||
45 | /* Set TCU0, TMX, TKSU (for later inversion) and IXMT */ | ||
46 | li t1, ST0_CU0 | 0x08001c00 | ||
47 | or t0, t1 | ||
48 | /* Clear TKSU, leave IXMT */ | ||
49 | xori t0, 0x00001800 | ||
50 | mtc0 t0, CP0_TCSTATUS | ||
51 | _ehb | ||
52 | /* We need to leave the global IE bit set, but clear EXL...*/ | ||
53 | mfc0 t0, CP0_STATUS | ||
54 | or t0, ST0_CU0 | ST0_EXL | ST0_ERL | \set | \clr | ||
55 | xor t0, ST0_EXL | ST0_ERL | \clr | ||
56 | mtc0 t0, CP0_STATUS | ||
57 | #else | ||
58 | mfc0 t0, CP0_STATUS | 38 | mfc0 t0, CP0_STATUS |
59 | or t0, ST0_CU0|\set|0x1f|\clr | 39 | or t0, ST0_CU0|\set|0x1f|\clr |
60 | xor t0, 0x1f|\clr | 40 | xor t0, 0x1f|\clr |
61 | mtc0 t0, CP0_STATUS | 41 | mtc0 t0, CP0_STATUS |
62 | .set noreorder | 42 | .set noreorder |
63 | sll zero,3 # ehb | 43 | sll zero,3 # ehb |
64 | #endif | ||
65 | .set pop | 44 | .set pop |
66 | .endm | 45 | .endm |
67 | 46 | ||
@@ -115,24 +94,6 @@ NESTED(kernel_entry, 16, sp) # kernel entry point | |||
115 | jr t0 | 94 | jr t0 |
116 | 0: | 95 | 0: |
117 | 96 | ||
118 | #ifdef CONFIG_MIPS_MT_SMTC | ||
119 | /* | ||
120 | * In SMTC kernel, "CLI" is thread-specific, in TCStatus. | ||
121 | * We still need to enable interrupts globally in Status, | ||
122 | * and clear EXL/ERL. | ||
123 | * | ||
124 | * TCContext is used to track interrupt levels under | ||
125 | * service in SMTC kernel. Clear for boot TC before | ||
126 | * allowing any interrupts. | ||
127 | */ | ||
128 | mtc0 zero, CP0_TCCONTEXT | ||
129 | |||
130 | mfc0 t0, CP0_STATUS | ||
131 | ori t0, t0, 0xff1f | ||
132 | xori t0, t0, 0x001e | ||
133 | mtc0 t0, CP0_STATUS | ||
134 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
135 | |||
136 | PTR_LA t0, __bss_start # clear .bss | 97 | PTR_LA t0, __bss_start # clear .bss |
137 | LONG_S zero, (t0) | 98 | LONG_S zero, (t0) |
138 | PTR_LA t1, __bss_stop - LONGSIZE | 99 | PTR_LA t1, __bss_stop - LONGSIZE |
@@ -164,25 +125,8 @@ NESTED(kernel_entry, 16, sp) # kernel entry point | |||
164 | * function after setting up the stack and gp registers. | 125 | * function after setting up the stack and gp registers. |
165 | */ | 126 | */ |
166 | NESTED(smp_bootstrap, 16, sp) | 127 | NESTED(smp_bootstrap, 16, sp) |
167 | #ifdef CONFIG_MIPS_MT_SMTC | ||
168 | /* | ||
169 | * Read-modify-writes of Status must be atomic, and this | ||
170 | * is one case where CLI is invoked without EXL being | ||
171 | * necessarily set. The CLI and setup_c0_status will | ||
172 | * in fact be redundant for all but the first TC of | ||
173 | * each VPE being booted. | ||
174 | */ | ||
175 | DMT 10 # dmt t2 /* t0, t1 are used by CLI and setup_c0_status() */ | ||
176 | jal mips_ihb | ||
177 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
178 | smp_slave_setup | 128 | smp_slave_setup |
179 | setup_c0_status_sec | 129 | setup_c0_status_sec |
180 | #ifdef CONFIG_MIPS_MT_SMTC | ||
181 | andi t2, t2, VPECONTROL_TE | ||
182 | beqz t2, 2f | ||
183 | EMT # emt | ||
184 | 2: | ||
185 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
186 | j start_secondary | 130 | j start_secondary |
187 | END(smp_bootstrap) | 131 | END(smp_bootstrap) |
188 | #endif /* CONFIG_SMP */ | 132 | #endif /* CONFIG_SMP */ |
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 2b91fe80c436..50b364897dda 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c | |||
@@ -42,9 +42,6 @@ static struct irq_chip i8259A_chip = { | |||
42 | .irq_disable = disable_8259A_irq, | 42 | .irq_disable = disable_8259A_irq, |
43 | .irq_unmask = enable_8259A_irq, | 43 | .irq_unmask = enable_8259A_irq, |
44 | .irq_mask_ack = mask_and_ack_8259A, | 44 | .irq_mask_ack = mask_and_ack_8259A, |
45 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | ||
46 | .irq_set_affinity = plat_set_irq_affinity, | ||
47 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | ||
48 | }; | 45 | }; |
49 | 46 | ||
50 | /* | 47 | /* |
@@ -180,7 +177,6 @@ handle_real_irq: | |||
180 | outb(cached_master_mask, PIC_MASTER_IMR); | 177 | outb(cached_master_mask, PIC_MASTER_IMR); |
181 | outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ | 178 | outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ |
182 | } | 179 | } |
183 | smtc_im_ack_irq(irq); | ||
184 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 180 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
185 | return; | 181 | return; |
186 | 182 | ||
diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index 837ff27950bc..09ce45980758 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c | |||
@@ -224,29 +224,26 @@ void __init check_wait(void) | |||
224 | cpu_wait = r4k_wait; | 224 | cpu_wait = r4k_wait; |
225 | */ | 225 | */ |
226 | break; | 226 | break; |
227 | case CPU_RM9000: | ||
228 | if ((c->processor_id & 0x00ff) >= 0x40) | ||
229 | cpu_wait = r4k_wait; | ||
230 | break; | ||
231 | default: | 227 | default: |
232 | break; | 228 | break; |
233 | } | 229 | } |
234 | } | 230 | } |
235 | 231 | ||
236 | static void smtc_idle_hook(void) | ||
237 | { | ||
238 | #ifdef CONFIG_MIPS_MT_SMTC | ||
239 | void smtc_idle_loop_hook(void); | ||
240 | |||
241 | smtc_idle_loop_hook(); | ||
242 | #endif | ||
243 | } | ||
244 | |||
245 | void arch_cpu_idle(void) | 232 | void arch_cpu_idle(void) |
246 | { | 233 | { |
247 | smtc_idle_hook(); | ||
248 | if (cpu_wait) | 234 | if (cpu_wait) |
249 | cpu_wait(); | 235 | cpu_wait(); |
250 | else | 236 | else |
251 | local_irq_enable(); | 237 | local_irq_enable(); |
252 | } | 238 | } |
239 | |||
240 | #ifdef CONFIG_CPU_IDLE | ||
241 | |||
242 | int mips_cpuidle_wait_enter(struct cpuidle_device *dev, | ||
243 | struct cpuidle_driver *drv, int index) | ||
244 | { | ||
245 | arch_cpu_idle(); | ||
246 | return index; | ||
247 | } | ||
248 | |||
249 | #endif | ||
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index 8520dad6d4e3..88e4c323382c 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c | |||
@@ -54,6 +54,21 @@ void gic_write_compare(cycle_t cnt) | |||
54 | (int)(cnt & 0xffffffff)); | 54 | (int)(cnt & 0xffffffff)); |
55 | } | 55 | } |
56 | 56 | ||
57 | void gic_write_cpu_compare(cycle_t cnt, int cpu) | ||
58 | { | ||
59 | unsigned long flags; | ||
60 | |||
61 | local_irq_save(flags); | ||
62 | |||
63 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); | ||
64 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), | ||
65 | (int)(cnt >> 32)); | ||
66 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), | ||
67 | (int)(cnt & 0xffffffff)); | ||
68 | |||
69 | local_irq_restore(flags); | ||
70 | } | ||
71 | |||
57 | cycle_t gic_read_compare(void) | 72 | cycle_t gic_read_compare(void) |
58 | { | 73 | { |
59 | unsigned int hi, lo; | 74 | unsigned int hi, lo; |
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index fab40f7d2e03..4858642d543d 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c | |||
@@ -53,13 +53,9 @@ static inline void unmask_msc_irq(struct irq_data *d) | |||
53 | */ | 53 | */ |
54 | static void level_mask_and_ack_msc_irq(struct irq_data *d) | 54 | static void level_mask_and_ack_msc_irq(struct irq_data *d) |
55 | { | 55 | { |
56 | unsigned int irq = d->irq; | ||
57 | |||
58 | mask_msc_irq(d); | 56 | mask_msc_irq(d); |
59 | if (!cpu_has_veic) | 57 | if (!cpu_has_veic) |
60 | MSCIC_WRITE(MSC01_IC_EOI, 0); | 58 | MSCIC_WRITE(MSC01_IC_EOI, 0); |
61 | /* This actually needs to be a call into platform code */ | ||
62 | smtc_im_ack_irq(irq); | ||
63 | } | 59 | } |
64 | 60 | ||
65 | /* | 61 | /* |
@@ -78,7 +74,6 @@ static void edge_mask_and_ack_msc_irq(struct irq_data *d) | |||
78 | MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); | 74 | MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); |
79 | MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); | 75 | MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); |
80 | } | 76 | } |
81 | smtc_im_ack_irq(irq); | ||
82 | } | 77 | } |
83 | 78 | ||
84 | /* | 79 | /* |
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 1818da4dbb85..d2bfbc2e8995 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c | |||
@@ -73,7 +73,6 @@ void free_irqno(unsigned int irq) | |||
73 | */ | 73 | */ |
74 | void ack_bad_irq(unsigned int irq) | 74 | void ack_bad_irq(unsigned int irq) |
75 | { | 75 | { |
76 | smtc_im_ack_irq(irq); | ||
77 | printk("unexpected IRQ # %d\n", irq); | 76 | printk("unexpected IRQ # %d\n", irq); |
78 | } | 77 | } |
79 | 78 | ||
@@ -142,23 +141,7 @@ void __irq_entry do_IRQ(unsigned int irq) | |||
142 | { | 141 | { |
143 | irq_enter(); | 142 | irq_enter(); |
144 | check_stack_overflow(); | 143 | check_stack_overflow(); |
145 | if (!smtc_handle_on_other_cpu(irq)) | ||
146 | generic_handle_irq(irq); | ||
147 | irq_exit(); | ||
148 | } | ||
149 | |||
150 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | ||
151 | /* | ||
152 | * To avoid inefficient and in some cases pathological re-checking of | ||
153 | * IRQ affinity, we have this variant that skips the affinity check. | ||
154 | */ | ||
155 | |||
156 | void __irq_entry do_IRQ_no_affinity(unsigned int irq) | ||
157 | { | ||
158 | irq_enter(); | ||
159 | smtc_im_backstop(irq); | ||
160 | generic_handle_irq(irq); | 144 | generic_handle_irq(irq); |
161 | irq_exit(); | 145 | irq_exit(); |
162 | } | 146 | } |
163 | 147 | ||
164 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | ||
diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index c9dc67402969..ba473608a347 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c | |||
@@ -9,12 +9,18 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
12 | #include <linux/percpu.h> | ||
13 | #include <linux/spinlock.h> | ||
12 | 14 | ||
13 | #include <asm/mips-cm.h> | 15 | #include <asm/mips-cm.h> |
14 | #include <asm/mips-cpc.h> | 16 | #include <asm/mips-cpc.h> |
15 | 17 | ||
16 | void __iomem *mips_cpc_base; | 18 | void __iomem *mips_cpc_base; |
17 | 19 | ||
20 | static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock); | ||
21 | |||
22 | static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); | ||
23 | |||
18 | phys_t __weak mips_cpc_phys_base(void) | 24 | phys_t __weak mips_cpc_phys_base(void) |
19 | { | 25 | { |
20 | u32 cpc_base; | 26 | u32 cpc_base; |
@@ -39,6 +45,10 @@ phys_t __weak mips_cpc_phys_base(void) | |||
39 | int mips_cpc_probe(void) | 45 | int mips_cpc_probe(void) |
40 | { | 46 | { |
41 | phys_t addr; | 47 | phys_t addr; |
48 | unsigned cpu; | ||
49 | |||
50 | for_each_possible_cpu(cpu) | ||
51 | spin_lock_init(&per_cpu(cpc_core_lock, cpu)); | ||
42 | 52 | ||
43 | addr = mips_cpc_phys_base(); | 53 | addr = mips_cpc_phys_base(); |
44 | if (!addr) | 54 | if (!addr) |
@@ -50,3 +60,21 @@ int mips_cpc_probe(void) | |||
50 | 60 | ||
51 | return 0; | 61 | return 0; |
52 | } | 62 | } |
63 | |||
64 | void mips_cpc_lock_other(unsigned int core) | ||
65 | { | ||
66 | unsigned curr_core; | ||
67 | preempt_disable(); | ||
68 | curr_core = current_cpu_data.core; | ||
69 | spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core), | ||
70 | per_cpu(cpc_core_lock_flags, curr_core)); | ||
71 | write_cpc_cl_other(core << CPC_Cx_OTHER_CORENUM_SHF); | ||
72 | } | ||
73 | |||
74 | void mips_cpc_unlock_other(void) | ||
75 | { | ||
76 | unsigned curr_core = current_cpu_data.core; | ||
77 | spin_unlock_irqrestore(&per_cpu(cpc_core_lock, curr_core), | ||
78 | per_cpu(cpc_core_lock_flags, curr_core)); | ||
79 | preempt_enable(); | ||
80 | } | ||
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index cb098628aee8..362bb3707e62 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * General MIPS MT support routines, usable in AP/SP, SMVP, or SMTC kernels | 2 | * General MIPS MT support routines, usable in AP/SP and SMVP. |
3 | * Copyright (C) 2005 Mips Technologies, Inc | 3 | * Copyright (C) 2005 Mips Technologies, Inc |
4 | */ | 4 | */ |
5 | #include <linux/cpu.h> | 5 | #include <linux/cpu.h> |
diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index 6ded9bd1489c..88b1ef5f868a 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * General MIPS MT support routines, usable in AP/SP, SMVP, or SMTC kernels | 2 | * General MIPS MT support routines, usable in AP/SP and SMVP. |
3 | * Copyright (C) 2005 Mips Technologies, Inc | 3 | * Copyright (C) 2005 Mips Technologies, Inc |
4 | */ | 4 | */ |
5 | 5 | ||
@@ -57,9 +57,6 @@ void mips_mt_regdump(unsigned long mvpctl) | |||
57 | int tc; | 57 | int tc; |
58 | unsigned long haltval; | 58 | unsigned long haltval; |
59 | unsigned long tcstatval; | 59 | unsigned long tcstatval; |
60 | #ifdef CONFIG_MIPS_MT_SMTC | ||
61 | void smtc_soft_dump(void); | ||
62 | #endif /* CONFIG_MIPT_MT_SMTC */ | ||
63 | 60 | ||
64 | local_irq_save(flags); | 61 | local_irq_save(flags); |
65 | vpflags = dvpe(); | 62 | vpflags = dvpe(); |
@@ -116,9 +113,6 @@ void mips_mt_regdump(unsigned long mvpctl) | |||
116 | if (!haltval) | 113 | if (!haltval) |
117 | write_tc_c0_tchalt(0); | 114 | write_tc_c0_tchalt(0); |
118 | } | 115 | } |
119 | #ifdef CONFIG_MIPS_MT_SMTC | ||
120 | smtc_soft_dump(); | ||
121 | #endif /* CONFIG_MIPT_MT_SMTC */ | ||
122 | printk("===========================\n"); | 116 | printk("===========================\n"); |
123 | evpe(vpflags); | 117 | evpe(vpflags); |
124 | local_irq_restore(flags); | 118 | local_irq_restore(flags); |
@@ -295,21 +289,11 @@ void mips_mt_set_cpuoptions(void) | |||
295 | 289 | ||
296 | void mt_cflush_lockdown(void) | 290 | void mt_cflush_lockdown(void) |
297 | { | 291 | { |
298 | #ifdef CONFIG_MIPS_MT_SMTC | ||
299 | void smtc_cflush_lockdown(void); | ||
300 | |||
301 | smtc_cflush_lockdown(); | ||
302 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
303 | /* FILL IN VSMP and AP/SP VERSIONS HERE */ | 292 | /* FILL IN VSMP and AP/SP VERSIONS HERE */ |
304 | } | 293 | } |
305 | 294 | ||
306 | void mt_cflush_release(void) | 295 | void mt_cflush_release(void) |
307 | { | 296 | { |
308 | #ifdef CONFIG_MIPS_MT_SMTC | ||
309 | void smtc_cflush_release(void); | ||
310 | |||
311 | smtc_cflush_release(); | ||
312 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
313 | /* FILL IN VSMP and AP/SP VERSIONS HERE */ | 297 | /* FILL IN VSMP and AP/SP VERSIONS HERE */ |
314 | } | 298 | } |
315 | 299 | ||
diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S index 029e002a4ea0..f6547680c81c 100644 --- a/arch/mips/kernel/octeon_switch.S +++ b/arch/mips/kernel/octeon_switch.S | |||
@@ -10,24 +10,12 @@ | |||
10 | * Copyright (C) 2000 MIPS Technologies, Inc. | 10 | * Copyright (C) 2000 MIPS Technologies, Inc. |
11 | * written by Carsten Langgaard, carstenl@mips.com | 11 | * written by Carsten Langgaard, carstenl@mips.com |
12 | */ | 12 | */ |
13 | #include <asm/asm.h> | ||
14 | #include <asm/cachectl.h> | ||
15 | #include <asm/fpregdef.h> | ||
16 | #include <asm/mipsregs.h> | ||
17 | #include <asm/asm-offsets.h> | ||
18 | #include <asm/pgtable-bits.h> | ||
19 | #include <asm/regdef.h> | ||
20 | #include <asm/stackframe.h> | ||
21 | #include <asm/thread_info.h> | ||
22 | |||
23 | #include <asm/asmmacro.h> | ||
24 | |||
25 | /* | ||
26 | * Offset to the current process status flags, the first 32 bytes of the | ||
27 | * stack are not used. | ||
28 | */ | ||
29 | #define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS) | ||
30 | 13 | ||
14 | #define USE_ALTERNATE_RESUME_IMPL 1 | ||
15 | .set push | ||
16 | .set arch=mips64r2 | ||
17 | #include "r4k_switch.S" | ||
18 | .set pop | ||
31 | /* | 19 | /* |
32 | * task_struct *resume(task_struct *prev, task_struct *next, | 20 | * task_struct *resume(task_struct *prev, task_struct *next, |
33 | * struct thread_info *next_ti, int usedfpu) | 21 | * struct thread_info *next_ti, int usedfpu) |
@@ -40,6 +28,61 @@ | |||
40 | cpu_save_nonscratch a0 | 28 | cpu_save_nonscratch a0 |
41 | LONG_S ra, THREAD_REG31(a0) | 29 | LONG_S ra, THREAD_REG31(a0) |
42 | 30 | ||
31 | /* | ||
32 | * check if we need to save FPU registers | ||
33 | */ | ||
34 | PTR_L t3, TASK_THREAD_INFO(a0) | ||
35 | LONG_L t0, TI_FLAGS(t3) | ||
36 | li t1, _TIF_USEDFPU | ||
37 | and t2, t0, t1 | ||
38 | beqz t2, 1f | ||
39 | nor t1, zero, t1 | ||
40 | |||
41 | and t0, t0, t1 | ||
42 | LONG_S t0, TI_FLAGS(t3) | ||
43 | |||
44 | /* | ||
45 | * clear saved user stack CU1 bit | ||
46 | */ | ||
47 | LONG_L t0, ST_OFF(t3) | ||
48 | li t1, ~ST0_CU1 | ||
49 | and t0, t0, t1 | ||
50 | LONG_S t0, ST_OFF(t3) | ||
51 | |||
52 | .set push | ||
53 | .set arch=mips64r2 | ||
54 | fpu_save_double a0 t0 t1 # c0_status passed in t0 | ||
55 | # clobbers t1 | ||
56 | .set pop | ||
57 | 1: | ||
58 | |||
59 | /* check if we need to save COP2 registers */ | ||
60 | PTR_L t2, TASK_THREAD_INFO(a0) | ||
61 | LONG_L t0, ST_OFF(t2) | ||
62 | bbit0 t0, 30, 1f | ||
63 | |||
64 | /* Disable COP2 in the stored process state */ | ||
65 | li t1, ST0_CU2 | ||
66 | xor t0, t1 | ||
67 | LONG_S t0, ST_OFF(t2) | ||
68 | |||
69 | /* Enable COP2 so we can save it */ | ||
70 | mfc0 t0, CP0_STATUS | ||
71 | or t0, t1 | ||
72 | mtc0 t0, CP0_STATUS | ||
73 | |||
74 | /* Save COP2 */ | ||
75 | daddu a0, THREAD_CP2 | ||
76 | jal octeon_cop2_save | ||
77 | dsubu a0, THREAD_CP2 | ||
78 | |||
79 | /* Disable COP2 now that we are done */ | ||
80 | mfc0 t0, CP0_STATUS | ||
81 | li t1, ST0_CU2 | ||
82 | xor t0, t1 | ||
83 | mtc0 t0, CP0_STATUS | ||
84 | |||
85 | 1: | ||
43 | #if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 | 86 | #if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 |
44 | /* Check if we need to store CVMSEG state */ | 87 | /* Check if we need to store CVMSEG state */ |
45 | mfc0 t0, $11,7 /* CvmMemCtl */ | 88 | mfc0 t0, $11,7 /* CvmMemCtl */ |
@@ -85,12 +128,7 @@ | |||
85 | move $28, a2 | 128 | move $28, a2 |
86 | cpu_restore_nonscratch a1 | 129 | cpu_restore_nonscratch a1 |
87 | 130 | ||
88 | #if (_THREAD_SIZE - 32) < 0x8000 | 131 | PTR_ADDU t0, $28, _THREAD_SIZE - 32 |
89 | PTR_ADDIU t0, $28, _THREAD_SIZE - 32 | ||
90 | #else | ||
91 | PTR_LI t0, _THREAD_SIZE - 32 | ||
92 | PTR_ADDU t0, $28 | ||
93 | #endif | ||
94 | set_saved_sp t0, t1, t2 | 132 | set_saved_sp t0, t1, t2 |
95 | 133 | ||
96 | mfc0 t1, CP0_STATUS /* Do we really need this? */ | 134 | mfc0 t1, CP0_STATUS /* Do we really need this? */ |
diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c new file mode 100644 index 000000000000..5aa4c6f8cf83 --- /dev/null +++ b/arch/mips/kernel/pm-cps.c | |||
@@ -0,0 +1,716 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Imagination Technologies | ||
3 | * Author: Paul Burton <paul.burton@imgtec.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/percpu.h> | ||
13 | #include <linux/slab.h> | ||
14 | |||
15 | #include <asm/asm-offsets.h> | ||
16 | #include <asm/cacheflush.h> | ||
17 | #include <asm/cacheops.h> | ||
18 | #include <asm/idle.h> | ||
19 | #include <asm/mips-cm.h> | ||
20 | #include <asm/mips-cpc.h> | ||
21 | #include <asm/mipsmtregs.h> | ||
22 | #include <asm/pm.h> | ||
23 | #include <asm/pm-cps.h> | ||
24 | #include <asm/smp-cps.h> | ||
25 | #include <asm/uasm.h> | ||
26 | |||
27 | /* | ||
28 | * cps_nc_entry_fn - type of a generated non-coherent state entry function | ||
29 | * @online: the count of online coupled VPEs | ||
30 | * @nc_ready_count: pointer to a non-coherent mapping of the core ready_count | ||
31 | * | ||
32 | * The code entering & exiting non-coherent states is generated at runtime | ||
33 | * using uasm, in order to ensure that the compiler cannot insert a stray | ||
34 | * memory access at an unfortunate time and to allow the generation of optimal | ||
35 | * core-specific code particularly for cache routines. If coupled_coherence | ||
36 | * is non-zero and this is the entry function for the CPS_PM_NC_WAIT state, | ||
37 | * returns the number of VPEs that were in the wait state at the point this | ||
38 | * VPE left it. Returns garbage if coupled_coherence is zero or this is not | ||
39 | * the entry function for CPS_PM_NC_WAIT. | ||
40 | */ | ||
41 | typedef unsigned (*cps_nc_entry_fn)(unsigned online, u32 *nc_ready_count); | ||
42 | |||
43 | /* | ||
44 | * The entry point of the generated non-coherent idle state entry/exit | ||
45 | * functions. Actually per-core rather than per-CPU. | ||
46 | */ | ||
47 | static DEFINE_PER_CPU_READ_MOSTLY(cps_nc_entry_fn[CPS_PM_STATE_COUNT], | ||
48 | nc_asm_enter); | ||
49 | |||
50 | /* Bitmap indicating which states are supported by the system */ | ||
51 | DECLARE_BITMAP(state_support, CPS_PM_STATE_COUNT); | ||
52 | |||
53 | /* | ||
54 | * Indicates the number of coupled VPEs ready to operate in a non-coherent | ||
55 | * state. Actually per-core rather than per-CPU. | ||
56 | */ | ||
57 | static DEFINE_PER_CPU_ALIGNED(u32*, ready_count); | ||
58 | static DEFINE_PER_CPU_ALIGNED(void*, ready_count_alloc); | ||
59 | |||
60 | /* Indicates online CPUs coupled with the current CPU */ | ||
61 | static DEFINE_PER_CPU_ALIGNED(cpumask_t, online_coupled); | ||
62 | |||
63 | /* | ||
64 | * Used to synchronize entry to deep idle states. Actually per-core rather | ||
65 | * than per-CPU. | ||
66 | */ | ||
67 | static DEFINE_PER_CPU_ALIGNED(atomic_t, pm_barrier); | ||
68 | |||
69 | /* Saved CPU state across the CPS_PM_POWER_GATED state */ | ||
70 | DEFINE_PER_CPU_ALIGNED(struct mips_static_suspend_state, cps_cpu_state); | ||
71 | |||
72 | /* A somewhat arbitrary number of labels & relocs for uasm */ | ||
73 | static struct uasm_label labels[32] __initdata; | ||
74 | static struct uasm_reloc relocs[32] __initdata; | ||
75 | |||
76 | /* CPU dependant sync types */ | ||
77 | static unsigned stype_intervention; | ||
78 | static unsigned stype_memory; | ||
79 | static unsigned stype_ordering; | ||
80 | |||
81 | enum mips_reg { | ||
82 | zero, at, v0, v1, a0, a1, a2, a3, | ||
83 | t0, t1, t2, t3, t4, t5, t6, t7, | ||
84 | s0, s1, s2, s3, s4, s5, s6, s7, | ||
85 | t8, t9, k0, k1, gp, sp, fp, ra, | ||
86 | }; | ||
87 | |||
88 | bool cps_pm_support_state(enum cps_pm_state state) | ||
89 | { | ||
90 | return test_bit(state, state_support); | ||
91 | } | ||
92 | |||
93 | static void coupled_barrier(atomic_t *a, unsigned online) | ||
94 | { | ||
95 | /* | ||
96 | * This function is effectively the same as | ||
97 | * cpuidle_coupled_parallel_barrier, which can't be used here since | ||
98 | * there's no cpuidle device. | ||
99 | */ | ||
100 | |||
101 | if (!coupled_coherence) | ||
102 | return; | ||
103 | |||
104 | smp_mb__before_atomic_inc(); | ||
105 | atomic_inc(a); | ||
106 | |||
107 | while (atomic_read(a) < online) | ||
108 | cpu_relax(); | ||
109 | |||
110 | if (atomic_inc_return(a) == online * 2) { | ||
111 | atomic_set(a, 0); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | while (atomic_read(a) > online) | ||
116 | cpu_relax(); | ||
117 | } | ||
118 | |||
119 | int cps_pm_enter_state(enum cps_pm_state state) | ||
120 | { | ||
121 | unsigned cpu = smp_processor_id(); | ||
122 | unsigned core = current_cpu_data.core; | ||
123 | unsigned online, left; | ||
124 | cpumask_t *coupled_mask = this_cpu_ptr(&online_coupled); | ||
125 | u32 *core_ready_count, *nc_core_ready_count; | ||
126 | void *nc_addr; | ||
127 | cps_nc_entry_fn entry; | ||
128 | struct core_boot_config *core_cfg; | ||
129 | struct vpe_boot_config *vpe_cfg; | ||
130 | |||
131 | /* Check that there is an entry function for this state */ | ||
132 | entry = per_cpu(nc_asm_enter, core)[state]; | ||
133 | if (!entry) | ||
134 | return -EINVAL; | ||
135 | |||
136 | /* Calculate which coupled CPUs (VPEs) are online */ | ||
137 | #ifdef CONFIG_MIPS_MT | ||
138 | if (cpu_online(cpu)) { | ||
139 | cpumask_and(coupled_mask, cpu_online_mask, | ||
140 | &cpu_sibling_map[cpu]); | ||
141 | online = cpumask_weight(coupled_mask); | ||
142 | cpumask_clear_cpu(cpu, coupled_mask); | ||
143 | } else | ||
144 | #endif | ||
145 | { | ||
146 | cpumask_clear(coupled_mask); | ||
147 | online = 1; | ||
148 | } | ||
149 | |||
150 | /* Setup the VPE to run mips_cps_pm_restore when started again */ | ||
151 | if (config_enabled(CONFIG_CPU_PM) && state == CPS_PM_POWER_GATED) { | ||
152 | core_cfg = &mips_cps_core_bootcfg[core]; | ||
153 | vpe_cfg = &core_cfg->vpe_config[current_cpu_data.vpe_id]; | ||
154 | vpe_cfg->pc = (unsigned long)mips_cps_pm_restore; | ||
155 | vpe_cfg->gp = (unsigned long)current_thread_info(); | ||
156 | vpe_cfg->sp = 0; | ||
157 | } | ||
158 | |||
159 | /* Indicate that this CPU might not be coherent */ | ||
160 | cpumask_clear_cpu(cpu, &cpu_coherent_mask); | ||
161 | smp_mb__after_clear_bit(); | ||
162 | |||
163 | /* Create a non-coherent mapping of the core ready_count */ | ||
164 | core_ready_count = per_cpu(ready_count, core); | ||
165 | nc_addr = kmap_noncoherent(virt_to_page(core_ready_count), | ||
166 | (unsigned long)core_ready_count); | ||
167 | nc_addr += ((unsigned long)core_ready_count & ~PAGE_MASK); | ||
168 | nc_core_ready_count = nc_addr; | ||
169 | |||
170 | /* Ensure ready_count is zero-initialised before the assembly runs */ | ||
171 | ACCESS_ONCE(*nc_core_ready_count) = 0; | ||
172 | coupled_barrier(&per_cpu(pm_barrier, core), online); | ||
173 | |||
174 | /* Run the generated entry code */ | ||
175 | left = entry(online, nc_core_ready_count); | ||
176 | |||
177 | /* Remove the non-coherent mapping of ready_count */ | ||
178 | kunmap_noncoherent(); | ||
179 | |||
180 | /* Indicate that this CPU is definitely coherent */ | ||
181 | cpumask_set_cpu(cpu, &cpu_coherent_mask); | ||
182 | |||
183 | /* | ||
184 | * If this VPE is the first to leave the non-coherent wait state then | ||
185 | * it needs to wake up any coupled VPEs still running their wait | ||
186 | * instruction so that they return to cpuidle, which can then complete | ||
187 | * coordination between the coupled VPEs & provide the governor with | ||
188 | * a chance to reflect on the length of time the VPEs were in the | ||
189 | * idle state. | ||
190 | */ | ||
191 | if (coupled_coherence && (state == CPS_PM_NC_WAIT) && (left == online)) | ||
192 | arch_send_call_function_ipi_mask(coupled_mask); | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, | ||
198 | struct uasm_reloc **pr, | ||
199 | const struct cache_desc *cache, | ||
200 | unsigned op, int lbl) | ||
201 | { | ||
202 | unsigned cache_size = cache->ways << cache->waybit; | ||
203 | unsigned i; | ||
204 | const unsigned unroll_lines = 32; | ||
205 | |||
206 | /* If the cache isn't present this function has it easy */ | ||
207 | if (cache->flags & MIPS_CACHE_NOT_PRESENT) | ||
208 | return; | ||
209 | |||
210 | /* Load base address */ | ||
211 | UASM_i_LA(pp, t0, (long)CKSEG0); | ||
212 | |||
213 | /* Calculate end address */ | ||
214 | if (cache_size < 0x8000) | ||
215 | uasm_i_addiu(pp, t1, t0, cache_size); | ||
216 | else | ||
217 | UASM_i_LA(pp, t1, (long)(CKSEG0 + cache_size)); | ||
218 | |||
219 | /* Start of cache op loop */ | ||
220 | uasm_build_label(pl, *pp, lbl); | ||
221 | |||
222 | /* Generate the cache ops */ | ||
223 | for (i = 0; i < unroll_lines; i++) | ||
224 | uasm_i_cache(pp, op, i * cache->linesz, t0); | ||
225 | |||
226 | /* Update the base address */ | ||
227 | uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz); | ||
228 | |||
229 | /* Loop if we haven't reached the end address yet */ | ||
230 | uasm_il_bne(pp, pr, t0, t1, lbl); | ||
231 | uasm_i_nop(pp); | ||
232 | } | ||
233 | |||
234 | static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, | ||
235 | struct uasm_reloc **pr, | ||
236 | const struct cpuinfo_mips *cpu_info, | ||
237 | int lbl) | ||
238 | { | ||
239 | unsigned i, fsb_size = 8; | ||
240 | unsigned num_loads = (fsb_size * 3) / 2; | ||
241 | unsigned line_stride = 2; | ||
242 | unsigned line_size = cpu_info->dcache.linesz; | ||
243 | unsigned perf_counter, perf_event; | ||
244 | unsigned revision = cpu_info->processor_id & PRID_REV_MASK; | ||
245 | |||
246 | /* | ||
247 | * Determine whether this CPU requires an FSB flush, and if so which | ||
248 | * performance counter/event reflect stalls due to a full FSB. | ||
249 | */ | ||
250 | switch (__get_cpu_type(cpu_info->cputype)) { | ||
251 | case CPU_INTERAPTIV: | ||
252 | perf_counter = 1; | ||
253 | perf_event = 51; | ||
254 | break; | ||
255 | |||
256 | case CPU_PROAPTIV: | ||
257 | /* Newer proAptiv cores don't require this workaround */ | ||
258 | if (revision >= PRID_REV_ENCODE_332(1, 1, 0)) | ||
259 | return 0; | ||
260 | |||
261 | /* On older ones it's unavailable */ | ||
262 | return -1; | ||
263 | |||
264 | /* CPUs which do not require the workaround */ | ||
265 | case CPU_P5600: | ||
266 | return 0; | ||
267 | |||
268 | default: | ||
269 | WARN_ONCE(1, "pm-cps: FSB flush unsupported for this CPU\n"); | ||
270 | return -1; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Ensure that the fill/store buffer (FSB) is not holding the results | ||
275 | * of a prefetch, since if it is then the CPC sequencer may become | ||
276 | * stuck in the D3 (ClrBus) state whilst entering a low power state. | ||
277 | */ | ||
278 | |||
279 | /* Preserve perf counter setup */ | ||
280 | uasm_i_mfc0(pp, t2, 25, (perf_counter * 2) + 0); /* PerfCtlN */ | ||
281 | uasm_i_mfc0(pp, t3, 25, (perf_counter * 2) + 1); /* PerfCntN */ | ||
282 | |||
283 | /* Setup perf counter to count FSB full pipeline stalls */ | ||
284 | uasm_i_addiu(pp, t0, zero, (perf_event << 5) | 0xf); | ||
285 | uasm_i_mtc0(pp, t0, 25, (perf_counter * 2) + 0); /* PerfCtlN */ | ||
286 | uasm_i_ehb(pp); | ||
287 | uasm_i_mtc0(pp, zero, 25, (perf_counter * 2) + 1); /* PerfCntN */ | ||
288 | uasm_i_ehb(pp); | ||
289 | |||
290 | /* Base address for loads */ | ||
291 | UASM_i_LA(pp, t0, (long)CKSEG0); | ||
292 | |||
293 | /* Start of clear loop */ | ||
294 | uasm_build_label(pl, *pp, lbl); | ||
295 | |||
296 | /* Perform some loads to fill the FSB */ | ||
297 | for (i = 0; i < num_loads; i++) | ||
298 | uasm_i_lw(pp, zero, i * line_size * line_stride, t0); | ||
299 | |||
300 | /* | ||
301 | * Invalidate the new D-cache entries so that the cache will need | ||
302 | * refilling (via the FSB) if the loop is executed again. | ||
303 | */ | ||
304 | for (i = 0; i < num_loads; i++) { | ||
305 | uasm_i_cache(pp, Hit_Invalidate_D, | ||
306 | i * line_size * line_stride, t0); | ||
307 | uasm_i_cache(pp, Hit_Writeback_Inv_SD, | ||
308 | i * line_size * line_stride, t0); | ||
309 | } | ||
310 | |||
311 | /* Completion barrier */ | ||
312 | uasm_i_sync(pp, stype_memory); | ||
313 | uasm_i_ehb(pp); | ||
314 | |||
315 | /* Check whether the pipeline stalled due to the FSB being full */ | ||
316 | uasm_i_mfc0(pp, t1, 25, (perf_counter * 2) + 1); /* PerfCntN */ | ||
317 | |||
318 | /* Loop if it didn't */ | ||
319 | uasm_il_beqz(pp, pr, t1, lbl); | ||
320 | uasm_i_nop(pp); | ||
321 | |||
322 | /* Restore perf counter 1. The count may well now be wrong... */ | ||
323 | uasm_i_mtc0(pp, t2, 25, (perf_counter * 2) + 0); /* PerfCtlN */ | ||
324 | uasm_i_ehb(pp); | ||
325 | uasm_i_mtc0(pp, t3, 25, (perf_counter * 2) + 1); /* PerfCntN */ | ||
326 | uasm_i_ehb(pp); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static void __init cps_gen_set_top_bit(u32 **pp, struct uasm_label **pl, | ||
332 | struct uasm_reloc **pr, | ||
333 | unsigned r_addr, int lbl) | ||
334 | { | ||
335 | uasm_i_lui(pp, t0, uasm_rel_hi(0x80000000)); | ||
336 | uasm_build_label(pl, *pp, lbl); | ||
337 | uasm_i_ll(pp, t1, 0, r_addr); | ||
338 | uasm_i_or(pp, t1, t1, t0); | ||
339 | uasm_i_sc(pp, t1, 0, r_addr); | ||
340 | uasm_il_beqz(pp, pr, t1, lbl); | ||
341 | uasm_i_nop(pp); | ||
342 | } | ||
343 | |||
344 | static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) | ||
345 | { | ||
346 | struct uasm_label *l = labels; | ||
347 | struct uasm_reloc *r = relocs; | ||
348 | u32 *buf, *p; | ||
349 | const unsigned r_online = a0; | ||
350 | const unsigned r_nc_count = a1; | ||
351 | const unsigned r_pcohctl = t7; | ||
352 | const unsigned max_instrs = 256; | ||
353 | unsigned cpc_cmd; | ||
354 | int err; | ||
355 | enum { | ||
356 | lbl_incready = 1, | ||
357 | lbl_poll_cont, | ||
358 | lbl_secondary_hang, | ||
359 | lbl_disable_coherence, | ||
360 | lbl_flush_fsb, | ||
361 | lbl_invicache, | ||
362 | lbl_flushdcache, | ||
363 | lbl_hang, | ||
364 | lbl_set_cont, | ||
365 | lbl_secondary_cont, | ||
366 | lbl_decready, | ||
367 | }; | ||
368 | |||
369 | /* Allocate a buffer to hold the generated code */ | ||
370 | p = buf = kcalloc(max_instrs, sizeof(u32), GFP_KERNEL); | ||
371 | if (!buf) | ||
372 | return NULL; | ||
373 | |||
374 | /* Clear labels & relocs ready for (re)use */ | ||
375 | memset(labels, 0, sizeof(labels)); | ||
376 | memset(relocs, 0, sizeof(relocs)); | ||
377 | |||
378 | if (config_enabled(CONFIG_CPU_PM) && state == CPS_PM_POWER_GATED) { | ||
379 | /* | ||
380 | * Save CPU state. Note the non-standard calling convention | ||
381 | * with the return address placed in v0 to avoid clobbering | ||
382 | * the ra register before it is saved. | ||
383 | */ | ||
384 | UASM_i_LA(&p, t0, (long)mips_cps_pm_save); | ||
385 | uasm_i_jalr(&p, v0, t0); | ||
386 | uasm_i_nop(&p); | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | * Load addresses of required CM & CPC registers. This is done early | ||
391 | * because they're needed in both the enable & disable coherence steps | ||
392 | * but in the coupled case the enable step will only run on one VPE. | ||
393 | */ | ||
394 | UASM_i_LA(&p, r_pcohctl, (long)addr_gcr_cl_coherence()); | ||
395 | |||
396 | if (coupled_coherence) { | ||
397 | /* Increment ready_count */ | ||
398 | uasm_i_sync(&p, stype_ordering); | ||
399 | uasm_build_label(&l, p, lbl_incready); | ||
400 | uasm_i_ll(&p, t1, 0, r_nc_count); | ||
401 | uasm_i_addiu(&p, t2, t1, 1); | ||
402 | uasm_i_sc(&p, t2, 0, r_nc_count); | ||
403 | uasm_il_beqz(&p, &r, t2, lbl_incready); | ||
404 | uasm_i_addiu(&p, t1, t1, 1); | ||
405 | |||
406 | /* Ordering barrier */ | ||
407 | uasm_i_sync(&p, stype_ordering); | ||
408 | |||
409 | /* | ||
410 | * If this is the last VPE to become ready for non-coherence | ||
411 | * then it should branch below. | ||
412 | */ | ||
413 | uasm_il_beq(&p, &r, t1, r_online, lbl_disable_coherence); | ||
414 | uasm_i_nop(&p); | ||
415 | |||
416 | if (state < CPS_PM_POWER_GATED) { | ||
417 | /* | ||
418 | * Otherwise this is not the last VPE to become ready | ||
419 | * for non-coherence. It needs to wait until coherence | ||
420 | * has been disabled before proceeding, which it will do | ||
421 | * by polling for the top bit of ready_count being set. | ||
422 | */ | ||
423 | uasm_i_addiu(&p, t1, zero, -1); | ||
424 | uasm_build_label(&l, p, lbl_poll_cont); | ||
425 | uasm_i_lw(&p, t0, 0, r_nc_count); | ||
426 | uasm_il_bltz(&p, &r, t0, lbl_secondary_cont); | ||
427 | uasm_i_ehb(&p); | ||
428 | uasm_i_yield(&p, zero, t1); | ||
429 | uasm_il_b(&p, &r, lbl_poll_cont); | ||
430 | uasm_i_nop(&p); | ||
431 | } else { | ||
432 | /* | ||
433 | * The core will lose power & this VPE will not continue | ||
434 | * so it can simply halt here. | ||
435 | */ | ||
436 | uasm_i_addiu(&p, t0, zero, TCHALT_H); | ||
437 | uasm_i_mtc0(&p, t0, 2, 4); | ||
438 | uasm_build_label(&l, p, lbl_secondary_hang); | ||
439 | uasm_il_b(&p, &r, lbl_secondary_hang); | ||
440 | uasm_i_nop(&p); | ||
441 | } | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | * This is the point of no return - this VPE will now proceed to | ||
446 | * disable coherence. At this point we *must* be sure that no other | ||
447 | * VPE within the core will interfere with the L1 dcache. | ||
448 | */ | ||
449 | uasm_build_label(&l, p, lbl_disable_coherence); | ||
450 | |||
451 | /* Invalidate the L1 icache */ | ||
452 | cps_gen_cache_routine(&p, &l, &r, &cpu_data[cpu].icache, | ||
453 | Index_Invalidate_I, lbl_invicache); | ||
454 | |||
455 | /* Writeback & invalidate the L1 dcache */ | ||
456 | cps_gen_cache_routine(&p, &l, &r, &cpu_data[cpu].dcache, | ||
457 | Index_Writeback_Inv_D, lbl_flushdcache); | ||
458 | |||
459 | /* Completion barrier */ | ||
460 | uasm_i_sync(&p, stype_memory); | ||
461 | uasm_i_ehb(&p); | ||
462 | |||
463 | /* | ||
464 | * Disable all but self interventions. The load from COHCTL is defined | ||
465 | * by the interAptiv & proAptiv SUMs as ensuring that the operation | ||
466 | * resulting from the preceeding store is complete. | ||
467 | */ | ||
468 | uasm_i_addiu(&p, t0, zero, 1 << cpu_data[cpu].core); | ||
469 | uasm_i_sw(&p, t0, 0, r_pcohctl); | ||
470 | uasm_i_lw(&p, t0, 0, r_pcohctl); | ||
471 | |||
472 | /* Sync to ensure previous interventions are complete */ | ||
473 | uasm_i_sync(&p, stype_intervention); | ||
474 | uasm_i_ehb(&p); | ||
475 | |||
476 | /* Disable coherence */ | ||
477 | uasm_i_sw(&p, zero, 0, r_pcohctl); | ||
478 | uasm_i_lw(&p, t0, 0, r_pcohctl); | ||
479 | |||
480 | if (state >= CPS_PM_CLOCK_GATED) { | ||
481 | err = cps_gen_flush_fsb(&p, &l, &r, &cpu_data[cpu], | ||
482 | lbl_flush_fsb); | ||
483 | if (err) | ||
484 | goto out_err; | ||
485 | |||
486 | /* Determine the CPC command to issue */ | ||
487 | switch (state) { | ||
488 | case CPS_PM_CLOCK_GATED: | ||
489 | cpc_cmd = CPC_Cx_CMD_CLOCKOFF; | ||
490 | break; | ||
491 | case CPS_PM_POWER_GATED: | ||
492 | cpc_cmd = CPC_Cx_CMD_PWRDOWN; | ||
493 | break; | ||
494 | default: | ||
495 | BUG(); | ||
496 | goto out_err; | ||
497 | } | ||
498 | |||
499 | /* Issue the CPC command */ | ||
500 | UASM_i_LA(&p, t0, (long)addr_cpc_cl_cmd()); | ||
501 | uasm_i_addiu(&p, t1, zero, cpc_cmd); | ||
502 | uasm_i_sw(&p, t1, 0, t0); | ||
503 | |||
504 | if (state == CPS_PM_POWER_GATED) { | ||
505 | /* If anything goes wrong just hang */ | ||
506 | uasm_build_label(&l, p, lbl_hang); | ||
507 | uasm_il_b(&p, &r, lbl_hang); | ||
508 | uasm_i_nop(&p); | ||
509 | |||
510 | /* | ||
511 | * There's no point generating more code, the core is | ||
512 | * powered down & if powered back up will run from the | ||
513 | * reset vector not from here. | ||
514 | */ | ||
515 | goto gen_done; | ||
516 | } | ||
517 | |||
518 | /* Completion barrier */ | ||
519 | uasm_i_sync(&p, stype_memory); | ||
520 | uasm_i_ehb(&p); | ||
521 | } | ||
522 | |||
523 | if (state == CPS_PM_NC_WAIT) { | ||
524 | /* | ||
525 | * At this point it is safe for all VPEs to proceed with | ||
526 | * execution. This VPE will set the top bit of ready_count | ||
527 | * to indicate to the other VPEs that they may continue. | ||
528 | */ | ||
529 | if (coupled_coherence) | ||
530 | cps_gen_set_top_bit(&p, &l, &r, r_nc_count, | ||
531 | lbl_set_cont); | ||
532 | |||
533 | /* | ||
534 | * VPEs which did not disable coherence will continue | ||
535 | * executing, after coherence has been disabled, from this | ||
536 | * point. | ||
537 | */ | ||
538 | uasm_build_label(&l, p, lbl_secondary_cont); | ||
539 | |||
540 | /* Now perform our wait */ | ||
541 | uasm_i_wait(&p, 0); | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * Re-enable coherence. Note that for CPS_PM_NC_WAIT all coupled VPEs | ||
546 | * will run this. The first will actually re-enable coherence & the | ||
547 | * rest will just be performing a rather unusual nop. | ||
548 | */ | ||
549 | uasm_i_addiu(&p, t0, zero, CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK); | ||
550 | uasm_i_sw(&p, t0, 0, r_pcohctl); | ||
551 | uasm_i_lw(&p, t0, 0, r_pcohctl); | ||
552 | |||
553 | /* Completion barrier */ | ||
554 | uasm_i_sync(&p, stype_memory); | ||
555 | uasm_i_ehb(&p); | ||
556 | |||
557 | if (coupled_coherence && (state == CPS_PM_NC_WAIT)) { | ||
558 | /* Decrement ready_count */ | ||
559 | uasm_build_label(&l, p, lbl_decready); | ||
560 | uasm_i_sync(&p, stype_ordering); | ||
561 | uasm_i_ll(&p, t1, 0, r_nc_count); | ||
562 | uasm_i_addiu(&p, t2, t1, -1); | ||
563 | uasm_i_sc(&p, t2, 0, r_nc_count); | ||
564 | uasm_il_beqz(&p, &r, t2, lbl_decready); | ||
565 | uasm_i_andi(&p, v0, t1, (1 << fls(smp_num_siblings)) - 1); | ||
566 | |||
567 | /* Ordering barrier */ | ||
568 | uasm_i_sync(&p, stype_ordering); | ||
569 | } | ||
570 | |||
571 | if (coupled_coherence && (state == CPS_PM_CLOCK_GATED)) { | ||
572 | /* | ||
573 | * At this point it is safe for all VPEs to proceed with | ||
574 | * execution. This VPE will set the top bit of ready_count | ||
575 | * to indicate to the other VPEs that they may continue. | ||
576 | */ | ||
577 | cps_gen_set_top_bit(&p, &l, &r, r_nc_count, lbl_set_cont); | ||
578 | |||
579 | /* | ||
580 | * This core will be reliant upon another core sending a | ||
581 | * power-up command to the CPC in order to resume operation. | ||
582 | * Thus an arbitrary VPE can't trigger the core leaving the | ||
583 | * idle state and the one that disables coherence might as well | ||
584 | * be the one to re-enable it. The rest will continue from here | ||
585 | * after that has been done. | ||
586 | */ | ||
587 | uasm_build_label(&l, p, lbl_secondary_cont); | ||
588 | |||
589 | /* Ordering barrier */ | ||
590 | uasm_i_sync(&p, stype_ordering); | ||
591 | } | ||
592 | |||
593 | /* The core is coherent, time to return to C code */ | ||
594 | uasm_i_jr(&p, ra); | ||
595 | uasm_i_nop(&p); | ||
596 | |||
597 | gen_done: | ||
598 | /* Ensure the code didn't exceed the resources allocated for it */ | ||
599 | BUG_ON((p - buf) > max_instrs); | ||
600 | BUG_ON((l - labels) > ARRAY_SIZE(labels)); | ||
601 | BUG_ON((r - relocs) > ARRAY_SIZE(relocs)); | ||
602 | |||
603 | /* Patch branch offsets */ | ||
604 | uasm_resolve_relocs(relocs, labels); | ||
605 | |||
606 | /* Flush the icache */ | ||
607 | local_flush_icache_range((unsigned long)buf, (unsigned long)p); | ||
608 | |||
609 | return buf; | ||
610 | out_err: | ||
611 | kfree(buf); | ||
612 | return NULL; | ||
613 | } | ||
614 | |||
615 | static int __init cps_gen_core_entries(unsigned cpu) | ||
616 | { | ||
617 | enum cps_pm_state state; | ||
618 | unsigned core = cpu_data[cpu].core; | ||
619 | unsigned dlinesz = cpu_data[cpu].dcache.linesz; | ||
620 | void *entry_fn, *core_rc; | ||
621 | |||
622 | for (state = CPS_PM_NC_WAIT; state < CPS_PM_STATE_COUNT; state++) { | ||
623 | if (per_cpu(nc_asm_enter, core)[state]) | ||
624 | continue; | ||
625 | if (!test_bit(state, state_support)) | ||
626 | continue; | ||
627 | |||
628 | entry_fn = cps_gen_entry_code(cpu, state); | ||
629 | if (!entry_fn) { | ||
630 | pr_err("Failed to generate core %u state %u entry\n", | ||
631 | core, state); | ||
632 | clear_bit(state, state_support); | ||
633 | } | ||
634 | |||
635 | per_cpu(nc_asm_enter, core)[state] = entry_fn; | ||
636 | } | ||
637 | |||
638 | if (!per_cpu(ready_count, core)) { | ||
639 | core_rc = kmalloc(dlinesz * 2, GFP_KERNEL); | ||
640 | if (!core_rc) { | ||
641 | pr_err("Failed allocate core %u ready_count\n", core); | ||
642 | return -ENOMEM; | ||
643 | } | ||
644 | per_cpu(ready_count_alloc, core) = core_rc; | ||
645 | |||
646 | /* Ensure ready_count is aligned to a cacheline boundary */ | ||
647 | core_rc += dlinesz - 1; | ||
648 | core_rc = (void *)((unsigned long)core_rc & ~(dlinesz - 1)); | ||
649 | per_cpu(ready_count, core) = core_rc; | ||
650 | } | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static int __init cps_pm_init(void) | ||
656 | { | ||
657 | unsigned cpu; | ||
658 | int err; | ||
659 | |||
660 | /* Detect appropriate sync types for the system */ | ||
661 | switch (current_cpu_data.cputype) { | ||
662 | case CPU_INTERAPTIV: | ||
663 | case CPU_PROAPTIV: | ||
664 | case CPU_M5150: | ||
665 | case CPU_P5600: | ||
666 | stype_intervention = 0x2; | ||
667 | stype_memory = 0x3; | ||
668 | stype_ordering = 0x10; | ||
669 | break; | ||
670 | |||
671 | default: | ||
672 | pr_warn("Power management is using heavyweight sync 0\n"); | ||
673 | } | ||
674 | |||
675 | /* A CM is required for all non-coherent states */ | ||
676 | if (!mips_cm_present()) { | ||
677 | pr_warn("pm-cps: no CM, non-coherent states unavailable\n"); | ||
678 | goto out; | ||
679 | } | ||
680 | |||
681 | /* | ||
682 | * If interrupts were enabled whilst running a wait instruction on a | ||
683 | * non-coherent core then the VPE may end up processing interrupts | ||
684 | * whilst non-coherent. That would be bad. | ||
685 | */ | ||
686 | if (cpu_wait == r4k_wait_irqoff) | ||
687 | set_bit(CPS_PM_NC_WAIT, state_support); | ||
688 | else | ||
689 | pr_warn("pm-cps: non-coherent wait unavailable\n"); | ||
690 | |||
691 | /* Detect whether a CPC is present */ | ||
692 | if (mips_cpc_present()) { | ||
693 | /* Detect whether clock gating is implemented */ | ||
694 | if (read_cpc_cl_stat_conf() & CPC_Cx_STAT_CONF_CLKGAT_IMPL_MSK) | ||
695 | set_bit(CPS_PM_CLOCK_GATED, state_support); | ||
696 | else | ||
697 | pr_warn("pm-cps: CPC does not support clock gating\n"); | ||
698 | |||
699 | /* Power gating is available with CPS SMP & any CPC */ | ||
700 | if (mips_cps_smp_in_use()) | ||
701 | set_bit(CPS_PM_POWER_GATED, state_support); | ||
702 | else | ||
703 | pr_warn("pm-cps: CPS SMP not in use, power gating unavailable\n"); | ||
704 | } else { | ||
705 | pr_warn("pm-cps: no CPC, clock & power gating unavailable\n"); | ||
706 | } | ||
707 | |||
708 | for_each_present_cpu(cpu) { | ||
709 | err = cps_gen_core_entries(cpu); | ||
710 | if (err) | ||
711 | return err; | ||
712 | } | ||
713 | out: | ||
714 | return 0; | ||
715 | } | ||
716 | arch_initcall(cps_pm_init); | ||
diff --git a/arch/mips/kernel/pm.c b/arch/mips/kernel/pm.c new file mode 100644 index 000000000000..fefdf39d3df3 --- /dev/null +++ b/arch/mips/kernel/pm.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Imagination Technologies Ltd. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * CPU PM notifiers for saving/restoring general CPU state. | ||
10 | */ | ||
11 | |||
12 | #include <linux/cpu_pm.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/dsp.h> | ||
16 | #include <asm/fpu.h> | ||
17 | #include <asm/mmu_context.h> | ||
18 | #include <asm/pm.h> | ||
19 | #include <asm/watch.h> | ||
20 | |||
21 | /* Used by PM helper macros in asm/pm.h */ | ||
22 | struct mips_static_suspend_state mips_static_suspend_state; | ||
23 | |||
24 | /** | ||
25 | * mips_cpu_save() - Save general CPU state. | ||
26 | * Ensures that general CPU context is saved, notably FPU and DSP. | ||
27 | */ | ||
28 | static int mips_cpu_save(void) | ||
29 | { | ||
30 | /* Save FPU state */ | ||
31 | lose_fpu(1); | ||
32 | |||
33 | /* Save DSP state */ | ||
34 | save_dsp(current); | ||
35 | |||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * mips_cpu_restore() - Restore general CPU state. | ||
41 | * Restores important CPU context. | ||
42 | */ | ||
43 | static void mips_cpu_restore(void) | ||
44 | { | ||
45 | unsigned int cpu = smp_processor_id(); | ||
46 | |||
47 | /* Restore ASID */ | ||
48 | if (current->mm) | ||
49 | write_c0_entryhi(cpu_asid(cpu, current->mm)); | ||
50 | |||
51 | /* Restore DSP state */ | ||
52 | restore_dsp(current); | ||
53 | |||
54 | /* Restore UserLocal */ | ||
55 | if (cpu_has_userlocal) | ||
56 | write_c0_userlocal(current_thread_info()->tp_value); | ||
57 | |||
58 | /* Restore watch registers */ | ||
59 | __restore_watch(); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * mips_pm_notifier() - Notifier for preserving general CPU context. | ||
64 | * @self: Notifier block. | ||
65 | * @cmd: CPU PM event. | ||
66 | * @v: Private data (unused). | ||
67 | * | ||
68 | * This is called when a CPU power management event occurs, and is used to | ||
69 | * ensure that important CPU context is preserved across a CPU power down. | ||
70 | */ | ||
71 | static int mips_pm_notifier(struct notifier_block *self, unsigned long cmd, | ||
72 | void *v) | ||
73 | { | ||
74 | int ret; | ||
75 | |||
76 | switch (cmd) { | ||
77 | case CPU_PM_ENTER: | ||
78 | ret = mips_cpu_save(); | ||
79 | if (ret) | ||
80 | return NOTIFY_STOP; | ||
81 | break; | ||
82 | case CPU_PM_ENTER_FAILED: | ||
83 | case CPU_PM_EXIT: | ||
84 | mips_cpu_restore(); | ||
85 | break; | ||
86 | } | ||
87 | |||
88 | return NOTIFY_OK; | ||
89 | } | ||
90 | |||
91 | static struct notifier_block mips_pm_notifier_block = { | ||
92 | .notifier_call = mips_pm_notifier, | ||
93 | }; | ||
94 | |||
95 | static int __init mips_pm_init(void) | ||
96 | { | ||
97 | return cpu_pm_register_notifier(&mips_pm_notifier_block); | ||
98 | } | ||
99 | arch_initcall(mips_pm_init); | ||
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 60e39dc7f1eb..0a1ec0f3beff 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
@@ -140,13 +140,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
140 | */ | 140 | */ |
141 | childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); | 141 | childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); |
142 | 142 | ||
143 | #ifdef CONFIG_MIPS_MT_SMTC | ||
144 | /* | ||
145 | * SMTC restores TCStatus after Status, and the CU bits | ||
146 | * are aliased there. | ||
147 | */ | ||
148 | childregs->cp0_tcstatus &= ~(ST0_CU2|ST0_CU1); | ||
149 | #endif | ||
150 | clear_tsk_thread_flag(p, TIF_USEDFPU); | 143 | clear_tsk_thread_flag(p, TIF_USEDFPU); |
151 | 144 | ||
152 | #ifdef CONFIG_MIPS_MT_FPAFF | 145 | #ifdef CONFIG_MIPS_MT_FPAFF |
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index abacac7c33ef..81ca3f70fe29 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S | |||
@@ -28,6 +28,7 @@ | |||
28 | */ | 28 | */ |
29 | #define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS) | 29 | #define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS) |
30 | 30 | ||
31 | #ifndef USE_ALTERNATE_RESUME_IMPL | ||
31 | /* | 32 | /* |
32 | * task_struct *resume(task_struct *prev, task_struct *next, | 33 | * task_struct *resume(task_struct *prev, task_struct *next, |
33 | * struct thread_info *next_ti, s32 fp_save) | 34 | * struct thread_info *next_ti, s32 fp_save) |
@@ -87,18 +88,6 @@ | |||
87 | 88 | ||
88 | PTR_ADDU t0, $28, _THREAD_SIZE - 32 | 89 | PTR_ADDU t0, $28, _THREAD_SIZE - 32 |
89 | set_saved_sp t0, t1, t2 | 90 | set_saved_sp t0, t1, t2 |
90 | #ifdef CONFIG_MIPS_MT_SMTC | ||
91 | /* Read-modify-writes of Status must be atomic on a VPE */ | ||
92 | mfc0 t2, CP0_TCSTATUS | ||
93 | ori t1, t2, TCSTATUS_IXMT | ||
94 | mtc0 t1, CP0_TCSTATUS | ||
95 | andi t2, t2, TCSTATUS_IXMT | ||
96 | _ehb | ||
97 | DMT 8 # dmt t0 | ||
98 | move t1,ra | ||
99 | jal mips_ihb | ||
100 | move ra,t1 | ||
101 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
102 | mfc0 t1, CP0_STATUS /* Do we really need this? */ | 91 | mfc0 t1, CP0_STATUS /* Do we really need this? */ |
103 | li a3, 0xff01 | 92 | li a3, 0xff01 |
104 | and t1, a3 | 93 | and t1, a3 |
@@ -107,22 +96,12 @@ | |||
107 | and a2, a3 | 96 | and a2, a3 |
108 | or a2, t1 | 97 | or a2, t1 |
109 | mtc0 a2, CP0_STATUS | 98 | mtc0 a2, CP0_STATUS |
110 | #ifdef CONFIG_MIPS_MT_SMTC | ||
111 | _ehb | ||
112 | andi t0, t0, VPECONTROL_TE | ||
113 | beqz t0, 1f | ||
114 | emt | ||
115 | 1: | ||
116 | mfc0 t1, CP0_TCSTATUS | ||
117 | xori t1, t1, TCSTATUS_IXMT | ||
118 | or t1, t1, t2 | ||
119 | mtc0 t1, CP0_TCSTATUS | ||
120 | _ehb | ||
121 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
122 | move v0, a0 | 99 | move v0, a0 |
123 | jr ra | 100 | jr ra |
124 | END(resume) | 101 | END(resume) |
125 | 102 | ||
103 | #endif /* USE_ALTERNATE_RESUME_IMPL */ | ||
104 | |||
126 | /* | 105 | /* |
127 | * Save a thread's fp context. | 106 | * Save a thread's fp context. |
128 | */ | 107 | */ |
@@ -176,19 +155,10 @@ LEAF(_restore_msa) | |||
176 | #define FPU_DEFAULT 0x00000000 | 155 | #define FPU_DEFAULT 0x00000000 |
177 | 156 | ||
178 | LEAF(_init_fpu) | 157 | LEAF(_init_fpu) |
179 | #ifdef CONFIG_MIPS_MT_SMTC | ||
180 | /* Rather than manipulate per-VPE Status, set per-TC bit in TCStatus */ | ||
181 | mfc0 t0, CP0_TCSTATUS | ||
182 | /* Bit position is the same for Status, TCStatus */ | ||
183 | li t1, ST0_CU1 | ||
184 | or t0, t1 | ||
185 | mtc0 t0, CP0_TCSTATUS | ||
186 | #else /* Normal MIPS CU1 enable */ | ||
187 | mfc0 t0, CP0_STATUS | 158 | mfc0 t0, CP0_STATUS |
188 | li t1, ST0_CU1 | 159 | li t1, ST0_CU1 |
189 | or t0, t1 | 160 | or t0, t1 |
190 | mtc0 t0, CP0_STATUS | 161 | mtc0 t0, CP0_STATUS |
191 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
192 | enable_fpu_hazard | 162 | enable_fpu_hazard |
193 | 163 | ||
194 | li t1, FPU_DEFAULT | 164 | li t1, FPU_DEFAULT |
diff --git a/arch/mips/kernel/rtlx-mt.c b/arch/mips/kernel/rtlx-mt.c index 9c1aca00fd54..5a66b975989e 100644 --- a/arch/mips/kernel/rtlx-mt.c +++ b/arch/mips/kernel/rtlx-mt.c | |||
@@ -36,7 +36,6 @@ static irqreturn_t rtlx_interrupt(int irq, void *dev_id) | |||
36 | unsigned long flags; | 36 | unsigned long flags; |
37 | int i; | 37 | int i; |
38 | 38 | ||
39 | /* Ought not to be strictly necessary for SMTC builds */ | ||
40 | local_irq_save(flags); | 39 | local_irq_save(flags); |
41 | vpeflags = dvpe(); | 40 | vpeflags = dvpe(); |
42 | set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ); | 41 | set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ); |
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index ea4c2dc31692..df9e2bd9b2c2 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c | |||
@@ -281,13 +281,6 @@ static void bmips_smp_finish(void) | |||
281 | } | 281 | } |
282 | 282 | ||
283 | /* | 283 | /* |
284 | * Runs on CPU0 after all CPUs have been booted | ||
285 | */ | ||
286 | static void bmips_cpus_done(void) | ||
287 | { | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * BMIPS5000 raceless IPIs | 284 | * BMIPS5000 raceless IPIs |
292 | * | 285 | * |
293 | * Each CPU has two inbound SW IRQs which are independent of all other CPUs. | 286 | * Each CPU has two inbound SW IRQs which are independent of all other CPUs. |
@@ -434,7 +427,6 @@ struct plat_smp_ops bmips43xx_smp_ops = { | |||
434 | .boot_secondary = bmips_boot_secondary, | 427 | .boot_secondary = bmips_boot_secondary, |
435 | .smp_finish = bmips_smp_finish, | 428 | .smp_finish = bmips_smp_finish, |
436 | .init_secondary = bmips_init_secondary, | 429 | .init_secondary = bmips_init_secondary, |
437 | .cpus_done = bmips_cpus_done, | ||
438 | .send_ipi_single = bmips43xx_send_ipi_single, | 430 | .send_ipi_single = bmips43xx_send_ipi_single, |
439 | .send_ipi_mask = bmips43xx_send_ipi_mask, | 431 | .send_ipi_mask = bmips43xx_send_ipi_mask, |
440 | #ifdef CONFIG_HOTPLUG_CPU | 432 | #ifdef CONFIG_HOTPLUG_CPU |
@@ -449,7 +441,6 @@ struct plat_smp_ops bmips5000_smp_ops = { | |||
449 | .boot_secondary = bmips_boot_secondary, | 441 | .boot_secondary = bmips_boot_secondary, |
450 | .smp_finish = bmips_smp_finish, | 442 | .smp_finish = bmips_smp_finish, |
451 | .init_secondary = bmips_init_secondary, | 443 | .init_secondary = bmips_init_secondary, |
452 | .cpus_done = bmips_cpus_done, | ||
453 | .send_ipi_single = bmips5000_send_ipi_single, | 444 | .send_ipi_single = bmips5000_send_ipi_single, |
454 | .send_ipi_mask = bmips5000_send_ipi_mask, | 445 | .send_ipi_mask = bmips5000_send_ipi_mask, |
455 | #ifdef CONFIG_HOTPLUG_CPU | 446 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c index 3ef55fb7ac03..fc8a51553426 100644 --- a/arch/mips/kernel/smp-cmp.c +++ b/arch/mips/kernel/smp-cmp.c | |||
@@ -49,14 +49,11 @@ static void cmp_init_secondary(void) | |||
49 | 49 | ||
50 | /* Enable per-cpu interrupts: platform specific */ | 50 | /* Enable per-cpu interrupts: platform specific */ |
51 | 51 | ||
52 | #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) | 52 | #ifdef CONFIG_MIPS_MT_SMP |
53 | if (cpu_has_mipsmt) | 53 | if (cpu_has_mipsmt) |
54 | c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & | 54 | c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & |
55 | TCBIND_CURVPE; | 55 | TCBIND_CURVPE; |
56 | #endif | 56 | #endif |
57 | #ifdef CONFIG_MIPS_MT_SMTC | ||
58 | c->tc_id = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT; | ||
59 | #endif | ||
60 | } | 57 | } |
61 | 58 | ||
62 | static void cmp_smp_finish(void) | 59 | static void cmp_smp_finish(void) |
@@ -75,11 +72,6 @@ static void cmp_smp_finish(void) | |||
75 | local_irq_enable(); | 72 | local_irq_enable(); |
76 | } | 73 | } |
77 | 74 | ||
78 | static void cmp_cpus_done(void) | ||
79 | { | ||
80 | pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); | ||
81 | } | ||
82 | |||
83 | /* | 75 | /* |
84 | * Setup the PC, SP, and GP of a secondary processor and start it running | 76 | * Setup the PC, SP, and GP of a secondary processor and start it running |
85 | * smp_bootstrap is the place to resume from | 77 | * smp_bootstrap is the place to resume from |
@@ -135,10 +127,6 @@ void __init cmp_smp_setup(void) | |||
135 | unsigned int mvpconf0 = read_c0_mvpconf0(); | 127 | unsigned int mvpconf0 = read_c0_mvpconf0(); |
136 | 128 | ||
137 | nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; | 129 | nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; |
138 | #elif defined(CONFIG_MIPS_MT_SMTC) | ||
139 | unsigned int mvpconf0 = read_c0_mvpconf0(); | ||
140 | |||
141 | nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; | ||
142 | #endif | 130 | #endif |
143 | smp_num_siblings = nvpe; | 131 | smp_num_siblings = nvpe; |
144 | } | 132 | } |
@@ -165,7 +153,6 @@ struct plat_smp_ops cmp_smp_ops = { | |||
165 | .send_ipi_mask = gic_send_ipi_mask, | 153 | .send_ipi_mask = gic_send_ipi_mask, |
166 | .init_secondary = cmp_init_secondary, | 154 | .init_secondary = cmp_init_secondary, |
167 | .smp_finish = cmp_smp_finish, | 155 | .smp_finish = cmp_smp_finish, |
168 | .cpus_done = cmp_cpus_done, | ||
169 | .boot_secondary = cmp_boot_secondary, | 156 | .boot_secondary = cmp_boot_secondary, |
170 | .smp_setup = cmp_smp_setup, | 157 | .smp_setup = cmp_smp_setup, |
171 | .prepare_cpus = cmp_prepare_cpus, | 158 | .prepare_cpus = cmp_prepare_cpus, |
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 536eec0d21b6..df0598d9bfdd 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c | |||
@@ -20,104 +20,43 @@ | |||
20 | #include <asm/mips-cpc.h> | 20 | #include <asm/mips-cpc.h> |
21 | #include <asm/mips_mt.h> | 21 | #include <asm/mips_mt.h> |
22 | #include <asm/mipsregs.h> | 22 | #include <asm/mipsregs.h> |
23 | #include <asm/pm-cps.h> | ||
23 | #include <asm/smp-cps.h> | 24 | #include <asm/smp-cps.h> |
24 | #include <asm/time.h> | 25 | #include <asm/time.h> |
25 | #include <asm/uasm.h> | 26 | #include <asm/uasm.h> |
26 | 27 | ||
27 | static DECLARE_BITMAP(core_power, NR_CPUS); | 28 | static DECLARE_BITMAP(core_power, NR_CPUS); |
28 | 29 | ||
29 | struct boot_config mips_cps_bootcfg; | 30 | struct core_boot_config *mips_cps_core_bootcfg; |
30 | 31 | ||
31 | static void init_core(void) | 32 | static unsigned core_vpe_count(unsigned core) |
32 | { | 33 | { |
33 | unsigned int nvpes, t; | 34 | unsigned cfg; |
34 | u32 mvpconf0, vpeconf0, vpecontrol, tcstatus, tcbind, status; | ||
35 | 35 | ||
36 | if (!cpu_has_mipsmt) | 36 | if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) |
37 | return; | 37 | return 1; |
38 | |||
39 | /* Enter VPE configuration state */ | ||
40 | dvpe(); | ||
41 | set_c0_mvpcontrol(MVPCONTROL_VPC); | ||
42 | |||
43 | /* Retrieve the count of VPEs in this core */ | ||
44 | mvpconf0 = read_c0_mvpconf0(); | ||
45 | nvpes = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; | ||
46 | smp_num_siblings = nvpes; | ||
47 | |||
48 | for (t = 1; t < nvpes; t++) { | ||
49 | /* Use a 1:1 mapping of TC index to VPE index */ | ||
50 | settc(t); | ||
51 | |||
52 | /* Bind 1 TC to this VPE */ | ||
53 | tcbind = read_tc_c0_tcbind(); | ||
54 | tcbind &= ~TCBIND_CURVPE; | ||
55 | tcbind |= t << TCBIND_CURVPE_SHIFT; | ||
56 | write_tc_c0_tcbind(tcbind); | ||
57 | |||
58 | /* Set exclusive TC, non-active, master */ | ||
59 | vpeconf0 = read_vpe_c0_vpeconf0(); | ||
60 | vpeconf0 &= ~(VPECONF0_XTC | VPECONF0_VPA); | ||
61 | vpeconf0 |= t << VPECONF0_XTC_SHIFT; | ||
62 | vpeconf0 |= VPECONF0_MVP; | ||
63 | write_vpe_c0_vpeconf0(vpeconf0); | ||
64 | |||
65 | /* Declare TC non-active, non-allocatable & interrupt exempt */ | ||
66 | tcstatus = read_tc_c0_tcstatus(); | ||
67 | tcstatus &= ~(TCSTATUS_A | TCSTATUS_DA); | ||
68 | tcstatus |= TCSTATUS_IXMT; | ||
69 | write_tc_c0_tcstatus(tcstatus); | ||
70 | |||
71 | /* Halt the TC */ | ||
72 | write_tc_c0_tchalt(TCHALT_H); | ||
73 | |||
74 | /* Allow only 1 TC to execute */ | ||
75 | vpecontrol = read_vpe_c0_vpecontrol(); | ||
76 | vpecontrol &= ~VPECONTROL_TE; | ||
77 | write_vpe_c0_vpecontrol(vpecontrol); | ||
78 | |||
79 | /* Copy (most of) Status from VPE 0 */ | ||
80 | status = read_c0_status(); | ||
81 | status &= ~(ST0_IM | ST0_IE | ST0_KSU); | ||
82 | status |= ST0_CU0; | ||
83 | write_vpe_c0_status(status); | ||
84 | |||
85 | /* Copy Config from VPE 0 */ | ||
86 | write_vpe_c0_config(read_c0_config()); | ||
87 | write_vpe_c0_config7(read_c0_config7()); | ||
88 | |||
89 | /* Ensure no software interrupts are pending */ | ||
90 | write_vpe_c0_cause(0); | ||
91 | |||
92 | /* Sync Count */ | ||
93 | write_vpe_c0_count(read_c0_count()); | ||
94 | } | ||
95 | 38 | ||
96 | /* Leave VPE configuration state */ | 39 | write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF); |
97 | clear_c0_mvpcontrol(MVPCONTROL_VPC); | 40 | cfg = read_gcr_co_config() & CM_GCR_Cx_CONFIG_PVPE_MSK; |
41 | return (cfg >> CM_GCR_Cx_CONFIG_PVPE_SHF) + 1; | ||
98 | } | 42 | } |
99 | 43 | ||
100 | static void __init cps_smp_setup(void) | 44 | static void __init cps_smp_setup(void) |
101 | { | 45 | { |
102 | unsigned int ncores, nvpes, core_vpes; | 46 | unsigned int ncores, nvpes, core_vpes; |
103 | int c, v; | 47 | int c, v; |
104 | u32 core_cfg, *entry_code; | ||
105 | 48 | ||
106 | /* Detect & record VPE topology */ | 49 | /* Detect & record VPE topology */ |
107 | ncores = mips_cm_numcores(); | 50 | ncores = mips_cm_numcores(); |
108 | pr_info("VPE topology "); | 51 | pr_info("VPE topology "); |
109 | for (c = nvpes = 0; c < ncores; c++) { | 52 | for (c = nvpes = 0; c < ncores; c++) { |
110 | if (cpu_has_mipsmt && config_enabled(CONFIG_MIPS_MT_SMP)) { | 53 | core_vpes = core_vpe_count(c); |
111 | write_gcr_cl_other(c << CM_GCR_Cx_OTHER_CORENUM_SHF); | ||
112 | core_cfg = read_gcr_co_config(); | ||
113 | core_vpes = ((core_cfg & CM_GCR_Cx_CONFIG_PVPE_MSK) >> | ||
114 | CM_GCR_Cx_CONFIG_PVPE_SHF) + 1; | ||
115 | } else { | ||
116 | core_vpes = 1; | ||
117 | } | ||
118 | |||
119 | pr_cont("%c%u", c ? ',' : '{', core_vpes); | 54 | pr_cont("%c%u", c ? ',' : '{', core_vpes); |
120 | 55 | ||
56 | /* Use the number of VPEs in core 0 for smp_num_siblings */ | ||
57 | if (!c) | ||
58 | smp_num_siblings = core_vpes; | ||
59 | |||
121 | for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) { | 60 | for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) { |
122 | cpu_data[nvpes + v].core = c; | 61 | cpu_data[nvpes + v].core = c; |
123 | #ifdef CONFIG_MIPS_MT_SMP | 62 | #ifdef CONFIG_MIPS_MT_SMP |
@@ -137,19 +76,14 @@ static void __init cps_smp_setup(void) | |||
137 | __cpu_logical_map[v] = v; | 76 | __cpu_logical_map[v] = v; |
138 | } | 77 | } |
139 | 78 | ||
79 | /* Set a coherent default CCA (CWB) */ | ||
80 | change_c0_config(CONF_CM_CMASK, 0x5); | ||
81 | |||
140 | /* Core 0 is powered up (we're running on it) */ | 82 | /* Core 0 is powered up (we're running on it) */ |
141 | bitmap_set(core_power, 0, 1); | 83 | bitmap_set(core_power, 0, 1); |
142 | 84 | ||
143 | /* Disable MT - we only want to run 1 TC per VPE */ | ||
144 | if (cpu_has_mipsmt) | ||
145 | dmt(); | ||
146 | |||
147 | /* Initialise core 0 */ | 85 | /* Initialise core 0 */ |
148 | init_core(); | 86 | mips_cps_core_init(); |
149 | |||
150 | /* Patch the start of mips_cps_core_entry to provide the CM base */ | ||
151 | entry_code = (u32 *)&mips_cps_core_entry; | ||
152 | UASM_i_LA(&entry_code, 3, (long)mips_cm_base); | ||
153 | 87 | ||
154 | /* Make core 0 coherent with everything */ | 88 | /* Make core 0 coherent with everything */ |
155 | write_gcr_cl_coherence(0xff); | 89 | write_gcr_cl_coherence(0xff); |
@@ -157,15 +91,99 @@ static void __init cps_smp_setup(void) | |||
157 | 91 | ||
158 | static void __init cps_prepare_cpus(unsigned int max_cpus) | 92 | static void __init cps_prepare_cpus(unsigned int max_cpus) |
159 | { | 93 | { |
94 | unsigned ncores, core_vpes, c, cca; | ||
95 | bool cca_unsuitable; | ||
96 | u32 *entry_code; | ||
97 | |||
160 | mips_mt_set_cpuoptions(); | 98 | mips_mt_set_cpuoptions(); |
99 | |||
100 | /* Detect whether the CCA is unsuited to multi-core SMP */ | ||
101 | cca = read_c0_config() & CONF_CM_CMASK; | ||
102 | switch (cca) { | ||
103 | case 0x4: /* CWBE */ | ||
104 | case 0x5: /* CWB */ | ||
105 | /* The CCA is coherent, multi-core is fine */ | ||
106 | cca_unsuitable = false; | ||
107 | break; | ||
108 | |||
109 | default: | ||
110 | /* CCA is not coherent, multi-core is not usable */ | ||
111 | cca_unsuitable = true; | ||
112 | } | ||
113 | |||
114 | /* Warn the user if the CCA prevents multi-core */ | ||
115 | ncores = mips_cm_numcores(); | ||
116 | if (cca_unsuitable && ncores > 1) { | ||
117 | pr_warn("Using only one core due to unsuitable CCA 0x%x\n", | ||
118 | cca); | ||
119 | |||
120 | for_each_present_cpu(c) { | ||
121 | if (cpu_data[c].core) | ||
122 | set_cpu_present(c, false); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Patch the start of mips_cps_core_entry to provide: | ||
128 | * | ||
129 | * v0 = CM base address | ||
130 | * s0 = kseg0 CCA | ||
131 | */ | ||
132 | entry_code = (u32 *)&mips_cps_core_entry; | ||
133 | UASM_i_LA(&entry_code, 3, (long)mips_cm_base); | ||
134 | uasm_i_addiu(&entry_code, 16, 0, cca); | ||
135 | dma_cache_wback_inv((unsigned long)&mips_cps_core_entry, | ||
136 | (void *)entry_code - (void *)&mips_cps_core_entry); | ||
137 | |||
138 | /* Allocate core boot configuration structs */ | ||
139 | mips_cps_core_bootcfg = kcalloc(ncores, sizeof(*mips_cps_core_bootcfg), | ||
140 | GFP_KERNEL); | ||
141 | if (!mips_cps_core_bootcfg) { | ||
142 | pr_err("Failed to allocate boot config for %u cores\n", ncores); | ||
143 | goto err_out; | ||
144 | } | ||
145 | |||
146 | /* Allocate VPE boot configuration structs */ | ||
147 | for (c = 0; c < ncores; c++) { | ||
148 | core_vpes = core_vpe_count(c); | ||
149 | mips_cps_core_bootcfg[c].vpe_config = kcalloc(core_vpes, | ||
150 | sizeof(*mips_cps_core_bootcfg[c].vpe_config), | ||
151 | GFP_KERNEL); | ||
152 | if (!mips_cps_core_bootcfg[c].vpe_config) { | ||
153 | pr_err("Failed to allocate %u VPE boot configs\n", | ||
154 | core_vpes); | ||
155 | goto err_out; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /* Mark this CPU as booted */ | ||
160 | atomic_set(&mips_cps_core_bootcfg[current_cpu_data.core].vpe_mask, | ||
161 | 1 << cpu_vpe_id(¤t_cpu_data)); | ||
162 | |||
163 | return; | ||
164 | err_out: | ||
165 | /* Clean up allocations */ | ||
166 | if (mips_cps_core_bootcfg) { | ||
167 | for (c = 0; c < ncores; c++) | ||
168 | kfree(mips_cps_core_bootcfg[c].vpe_config); | ||
169 | kfree(mips_cps_core_bootcfg); | ||
170 | mips_cps_core_bootcfg = NULL; | ||
171 | } | ||
172 | |||
173 | /* Effectively disable SMP by declaring CPUs not present */ | ||
174 | for_each_possible_cpu(c) { | ||
175 | if (c == 0) | ||
176 | continue; | ||
177 | set_cpu_present(c, false); | ||
178 | } | ||
161 | } | 179 | } |
162 | 180 | ||
163 | static void boot_core(struct boot_config *cfg) | 181 | static void boot_core(unsigned core) |
164 | { | 182 | { |
165 | u32 access; | 183 | u32 access; |
166 | 184 | ||
167 | /* Select the appropriate core */ | 185 | /* Select the appropriate core */ |
168 | write_gcr_cl_other(cfg->core << CM_GCR_Cx_OTHER_CORENUM_SHF); | 186 | write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF); |
169 | 187 | ||
170 | /* Set its reset vector */ | 188 | /* Set its reset vector */ |
171 | write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry)); | 189 | write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry)); |
@@ -175,104 +193,74 @@ static void boot_core(struct boot_config *cfg) | |||
175 | 193 | ||
176 | /* Ensure the core can access the GCRs */ | 194 | /* Ensure the core can access the GCRs */ |
177 | access = read_gcr_access(); | 195 | access = read_gcr_access(); |
178 | access |= 1 << (CM_GCR_ACCESS_ACCESSEN_SHF + cfg->core); | 196 | access |= 1 << (CM_GCR_ACCESS_ACCESSEN_SHF + core); |
179 | write_gcr_access(access); | 197 | write_gcr_access(access); |
180 | 198 | ||
181 | /* Copy cfg */ | ||
182 | mips_cps_bootcfg = *cfg; | ||
183 | |||
184 | if (mips_cpc_present()) { | 199 | if (mips_cpc_present()) { |
185 | /* Select the appropriate core */ | ||
186 | write_cpc_cl_other(cfg->core << CPC_Cx_OTHER_CORENUM_SHF); | ||
187 | |||
188 | /* Reset the core */ | 200 | /* Reset the core */ |
201 | mips_cpc_lock_other(core); | ||
189 | write_cpc_co_cmd(CPC_Cx_CMD_RESET); | 202 | write_cpc_co_cmd(CPC_Cx_CMD_RESET); |
203 | mips_cpc_unlock_other(); | ||
190 | } else { | 204 | } else { |
191 | /* Take the core out of reset */ | 205 | /* Take the core out of reset */ |
192 | write_gcr_co_reset_release(0); | 206 | write_gcr_co_reset_release(0); |
193 | } | 207 | } |
194 | 208 | ||
195 | /* The core is now powered up */ | 209 | /* The core is now powered up */ |
196 | bitmap_set(core_power, cfg->core, 1); | 210 | bitmap_set(core_power, core, 1); |
197 | } | 211 | } |
198 | 212 | ||
199 | static void boot_vpe(void *info) | 213 | static void remote_vpe_boot(void *dummy) |
200 | { | 214 | { |
201 | struct boot_config *cfg = info; | 215 | mips_cps_boot_vpes(); |
202 | u32 tcstatus, vpeconf0; | ||
203 | |||
204 | /* Enter VPE configuration state */ | ||
205 | dvpe(); | ||
206 | set_c0_mvpcontrol(MVPCONTROL_VPC); | ||
207 | |||
208 | settc(cfg->vpe); | ||
209 | |||
210 | /* Set the TC restart PC */ | ||
211 | write_tc_c0_tcrestart((unsigned long)&smp_bootstrap); | ||
212 | |||
213 | /* Activate the TC, allow interrupts */ | ||
214 | tcstatus = read_tc_c0_tcstatus(); | ||
215 | tcstatus &= ~TCSTATUS_IXMT; | ||
216 | tcstatus |= TCSTATUS_A; | ||
217 | write_tc_c0_tcstatus(tcstatus); | ||
218 | |||
219 | /* Clear the TC halt bit */ | ||
220 | write_tc_c0_tchalt(0); | ||
221 | |||
222 | /* Activate the VPE */ | ||
223 | vpeconf0 = read_vpe_c0_vpeconf0(); | ||
224 | vpeconf0 |= VPECONF0_VPA; | ||
225 | write_vpe_c0_vpeconf0(vpeconf0); | ||
226 | |||
227 | /* Set the stack & global pointer registers */ | ||
228 | write_tc_gpr_sp(cfg->sp); | ||
229 | write_tc_gpr_gp(cfg->gp); | ||
230 | |||
231 | /* Leave VPE configuration state */ | ||
232 | clear_c0_mvpcontrol(MVPCONTROL_VPC); | ||
233 | |||
234 | /* Enable other VPEs to execute */ | ||
235 | evpe(EVPE_ENABLE); | ||
236 | } | 216 | } |
237 | 217 | ||
238 | static void cps_boot_secondary(int cpu, struct task_struct *idle) | 218 | static void cps_boot_secondary(int cpu, struct task_struct *idle) |
239 | { | 219 | { |
240 | struct boot_config cfg; | 220 | unsigned core = cpu_data[cpu].core; |
221 | unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]); | ||
222 | struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core]; | ||
223 | struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id]; | ||
241 | unsigned int remote; | 224 | unsigned int remote; |
242 | int err; | 225 | int err; |
243 | 226 | ||
244 | cfg.core = cpu_data[cpu].core; | 227 | vpe_cfg->pc = (unsigned long)&smp_bootstrap; |
245 | cfg.vpe = cpu_vpe_id(&cpu_data[cpu]); | 228 | vpe_cfg->sp = __KSTK_TOS(idle); |
246 | cfg.pc = (unsigned long)&smp_bootstrap; | 229 | vpe_cfg->gp = (unsigned long)task_thread_info(idle); |
247 | cfg.sp = __KSTK_TOS(idle); | 230 | |
248 | cfg.gp = (unsigned long)task_thread_info(idle); | 231 | atomic_or(1 << cpu_vpe_id(&cpu_data[cpu]), &core_cfg->vpe_mask); |
249 | 232 | ||
250 | if (!test_bit(cfg.core, core_power)) { | 233 | preempt_disable(); |
234 | |||
235 | if (!test_bit(core, core_power)) { | ||
251 | /* Boot a VPE on a powered down core */ | 236 | /* Boot a VPE on a powered down core */ |
252 | boot_core(&cfg); | 237 | boot_core(core); |
253 | return; | 238 | goto out; |
254 | } | 239 | } |
255 | 240 | ||
256 | if (cfg.core != current_cpu_data.core) { | 241 | if (core != current_cpu_data.core) { |
257 | /* Boot a VPE on another powered up core */ | 242 | /* Boot a VPE on another powered up core */ |
258 | for (remote = 0; remote < NR_CPUS; remote++) { | 243 | for (remote = 0; remote < NR_CPUS; remote++) { |
259 | if (cpu_data[remote].core != cfg.core) | 244 | if (cpu_data[remote].core != core) |
260 | continue; | 245 | continue; |
261 | if (cpu_online(remote)) | 246 | if (cpu_online(remote)) |
262 | break; | 247 | break; |
263 | } | 248 | } |
264 | BUG_ON(remote >= NR_CPUS); | 249 | BUG_ON(remote >= NR_CPUS); |
265 | 250 | ||
266 | err = smp_call_function_single(remote, boot_vpe, &cfg, 1); | 251 | err = smp_call_function_single(remote, remote_vpe_boot, |
252 | NULL, 1); | ||
267 | if (err) | 253 | if (err) |
268 | panic("Failed to call remote CPU\n"); | 254 | panic("Failed to call remote CPU\n"); |
269 | return; | 255 | goto out; |
270 | } | 256 | } |
271 | 257 | ||
272 | BUG_ON(!cpu_has_mipsmt); | 258 | BUG_ON(!cpu_has_mipsmt); |
273 | 259 | ||
274 | /* Boot a VPE on this core */ | 260 | /* Boot a VPE on this core */ |
275 | boot_vpe(&cfg); | 261 | mips_cps_boot_vpes(); |
262 | out: | ||
263 | preempt_enable(); | ||
276 | } | 264 | } |
277 | 265 | ||
278 | static void cps_init_secondary(void) | 266 | static void cps_init_secondary(void) |
@@ -281,10 +269,6 @@ static void cps_init_secondary(void) | |||
281 | if (cpu_has_mipsmt) | 269 | if (cpu_has_mipsmt) |
282 | dmt(); | 270 | dmt(); |
283 | 271 | ||
284 | /* TODO: revisit this assumption once hotplug is implemented */ | ||
285 | if (cpu_vpe_id(¤t_cpu_data) == 0) | ||
286 | init_core(); | ||
287 | |||
288 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | | 272 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | |
289 | STATUSF_IP6 | STATUSF_IP7); | 273 | STATUSF_IP6 | STATUSF_IP7); |
290 | } | 274 | } |
@@ -302,10 +286,148 @@ static void cps_smp_finish(void) | |||
302 | local_irq_enable(); | 286 | local_irq_enable(); |
303 | } | 287 | } |
304 | 288 | ||
305 | static void cps_cpus_done(void) | 289 | #ifdef CONFIG_HOTPLUG_CPU |
290 | |||
291 | static int cps_cpu_disable(void) | ||
292 | { | ||
293 | unsigned cpu = smp_processor_id(); | ||
294 | struct core_boot_config *core_cfg; | ||
295 | |||
296 | if (!cpu) | ||
297 | return -EBUSY; | ||
298 | |||
299 | if (!cps_pm_support_state(CPS_PM_POWER_GATED)) | ||
300 | return -EINVAL; | ||
301 | |||
302 | core_cfg = &mips_cps_core_bootcfg[current_cpu_data.core]; | ||
303 | atomic_sub(1 << cpu_vpe_id(¤t_cpu_data), &core_cfg->vpe_mask); | ||
304 | smp_mb__after_atomic_dec(); | ||
305 | set_cpu_online(cpu, false); | ||
306 | cpu_clear(cpu, cpu_callin_map); | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static DECLARE_COMPLETION(cpu_death_chosen); | ||
312 | static unsigned cpu_death_sibling; | ||
313 | static enum { | ||
314 | CPU_DEATH_HALT, | ||
315 | CPU_DEATH_POWER, | ||
316 | } cpu_death; | ||
317 | |||
318 | void play_dead(void) | ||
319 | { | ||
320 | unsigned cpu, core; | ||
321 | |||
322 | local_irq_disable(); | ||
323 | idle_task_exit(); | ||
324 | cpu = smp_processor_id(); | ||
325 | cpu_death = CPU_DEATH_POWER; | ||
326 | |||
327 | if (cpu_has_mipsmt) { | ||
328 | core = cpu_data[cpu].core; | ||
329 | |||
330 | /* Look for another online VPE within the core */ | ||
331 | for_each_online_cpu(cpu_death_sibling) { | ||
332 | if (cpu_data[cpu_death_sibling].core != core) | ||
333 | continue; | ||
334 | |||
335 | /* | ||
336 | * There is an online VPE within the core. Just halt | ||
337 | * this TC and leave the core alone. | ||
338 | */ | ||
339 | cpu_death = CPU_DEATH_HALT; | ||
340 | break; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /* This CPU has chosen its way out */ | ||
345 | complete(&cpu_death_chosen); | ||
346 | |||
347 | if (cpu_death == CPU_DEATH_HALT) { | ||
348 | /* Halt this TC */ | ||
349 | write_c0_tchalt(TCHALT_H); | ||
350 | instruction_hazard(); | ||
351 | } else { | ||
352 | /* Power down the core */ | ||
353 | cps_pm_enter_state(CPS_PM_POWER_GATED); | ||
354 | } | ||
355 | |||
356 | /* This should never be reached */ | ||
357 | panic("Failed to offline CPU %u", cpu); | ||
358 | } | ||
359 | |||
360 | static void wait_for_sibling_halt(void *ptr_cpu) | ||
306 | { | 361 | { |
362 | unsigned cpu = (unsigned)ptr_cpu; | ||
363 | unsigned vpe_id = cpu_data[cpu].vpe_id; | ||
364 | unsigned halted; | ||
365 | unsigned long flags; | ||
366 | |||
367 | do { | ||
368 | local_irq_save(flags); | ||
369 | settc(vpe_id); | ||
370 | halted = read_tc_c0_tchalt(); | ||
371 | local_irq_restore(flags); | ||
372 | } while (!(halted & TCHALT_H)); | ||
373 | } | ||
374 | |||
375 | static void cps_cpu_die(unsigned int cpu) | ||
376 | { | ||
377 | unsigned core = cpu_data[cpu].core; | ||
378 | unsigned stat; | ||
379 | int err; | ||
380 | |||
381 | /* Wait for the cpu to choose its way out */ | ||
382 | if (!wait_for_completion_timeout(&cpu_death_chosen, | ||
383 | msecs_to_jiffies(5000))) { | ||
384 | pr_err("CPU%u: didn't offline\n", cpu); | ||
385 | return; | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * Now wait for the CPU to actually offline. Without doing this that | ||
390 | * offlining may race with one or more of: | ||
391 | * | ||
392 | * - Onlining the CPU again. | ||
393 | * - Powering down the core if another VPE within it is offlined. | ||
394 | * - A sibling VPE entering a non-coherent state. | ||
395 | * | ||
396 | * In the non-MT halt case (ie. infinite loop) the CPU is doing nothing | ||
397 | * with which we could race, so do nothing. | ||
398 | */ | ||
399 | if (cpu_death == CPU_DEATH_POWER) { | ||
400 | /* | ||
401 | * Wait for the core to enter a powered down or clock gated | ||
402 | * state, the latter happening when a JTAG probe is connected | ||
403 | * in which case the CPC will refuse to power down the core. | ||
404 | */ | ||
405 | do { | ||
406 | mips_cpc_lock_other(core); | ||
407 | stat = read_cpc_co_stat_conf(); | ||
408 | stat &= CPC_Cx_STAT_CONF_SEQSTATE_MSK; | ||
409 | mips_cpc_unlock_other(); | ||
410 | } while (stat != CPC_Cx_STAT_CONF_SEQSTATE_D0 && | ||
411 | stat != CPC_Cx_STAT_CONF_SEQSTATE_D2 && | ||
412 | stat != CPC_Cx_STAT_CONF_SEQSTATE_U2); | ||
413 | |||
414 | /* Indicate the core is powered off */ | ||
415 | bitmap_clear(core_power, core, 1); | ||
416 | } else if (cpu_has_mipsmt) { | ||
417 | /* | ||
418 | * Have a CPU with access to the offlined CPUs registers wait | ||
419 | * for its TC to halt. | ||
420 | */ | ||
421 | err = smp_call_function_single(cpu_death_sibling, | ||
422 | wait_for_sibling_halt, | ||
423 | (void *)cpu, 1); | ||
424 | if (err) | ||
425 | panic("Failed to call remote sibling CPU\n"); | ||
426 | } | ||
307 | } | 427 | } |
308 | 428 | ||
429 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
430 | |||
309 | static struct plat_smp_ops cps_smp_ops = { | 431 | static struct plat_smp_ops cps_smp_ops = { |
310 | .smp_setup = cps_smp_setup, | 432 | .smp_setup = cps_smp_setup, |
311 | .prepare_cpus = cps_prepare_cpus, | 433 | .prepare_cpus = cps_prepare_cpus, |
@@ -314,9 +436,18 @@ static struct plat_smp_ops cps_smp_ops = { | |||
314 | .smp_finish = cps_smp_finish, | 436 | .smp_finish = cps_smp_finish, |
315 | .send_ipi_single = gic_send_ipi_single, | 437 | .send_ipi_single = gic_send_ipi_single, |
316 | .send_ipi_mask = gic_send_ipi_mask, | 438 | .send_ipi_mask = gic_send_ipi_mask, |
317 | .cpus_done = cps_cpus_done, | 439 | #ifdef CONFIG_HOTPLUG_CPU |
440 | .cpu_disable = cps_cpu_disable, | ||
441 | .cpu_die = cps_cpu_die, | ||
442 | #endif | ||
318 | }; | 443 | }; |
319 | 444 | ||
445 | bool mips_cps_smp_in_use(void) | ||
446 | { | ||
447 | extern struct plat_smp_ops *mp_ops; | ||
448 | return mp_ops == &cps_smp_ops; | ||
449 | } | ||
450 | |||
320 | int register_cps_smp_ops(void) | 451 | int register_cps_smp_ops(void) |
321 | { | 452 | { |
322 | if (!mips_cm_present()) { | 453 | if (!mips_cm_present()) { |
diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c index 3bb1f92ab525..3b21a96d1ccb 100644 --- a/arch/mips/kernel/smp-gic.c +++ b/arch/mips/kernel/smp-gic.c | |||
@@ -15,12 +15,14 @@ | |||
15 | #include <linux/printk.h> | 15 | #include <linux/printk.h> |
16 | 16 | ||
17 | #include <asm/gic.h> | 17 | #include <asm/gic.h> |
18 | #include <asm/mips-cpc.h> | ||
18 | #include <asm/smp-ops.h> | 19 | #include <asm/smp-ops.h> |
19 | 20 | ||
20 | void gic_send_ipi_single(int cpu, unsigned int action) | 21 | void gic_send_ipi_single(int cpu, unsigned int action) |
21 | { | 22 | { |
22 | unsigned long flags; | 23 | unsigned long flags; |
23 | unsigned int intr; | 24 | unsigned int intr; |
25 | unsigned int core = cpu_data[cpu].core; | ||
24 | 26 | ||
25 | pr_debug("CPU%d: %s cpu %d action %u status %08x\n", | 27 | pr_debug("CPU%d: %s cpu %d action %u status %08x\n", |
26 | smp_processor_id(), __func__, cpu, action, read_c0_status()); | 28 | smp_processor_id(), __func__, cpu, action, read_c0_status()); |
@@ -41,6 +43,15 @@ void gic_send_ipi_single(int cpu, unsigned int action) | |||
41 | } | 43 | } |
42 | 44 | ||
43 | gic_send_ipi(intr); | 45 | gic_send_ipi(intr); |
46 | |||
47 | if (mips_cpc_present() && (core != current_cpu_data.core)) { | ||
48 | while (!cpumask_test_cpu(cpu, &cpu_coherent_mask)) { | ||
49 | mips_cpc_lock_other(core); | ||
50 | write_cpc_co_cmd(CPC_Cx_CMD_PWRUP); | ||
51 | mips_cpc_unlock_other(); | ||
52 | } | ||
53 | } | ||
54 | |||
44 | local_irq_restore(flags); | 55 | local_irq_restore(flags); |
45 | } | 56 | } |
46 | 57 | ||
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index f8e13149604d..3babf6e4f894 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c | |||
@@ -183,10 +183,6 @@ static void vsmp_smp_finish(void) | |||
183 | local_irq_enable(); | 183 | local_irq_enable(); |
184 | } | 184 | } |
185 | 185 | ||
186 | static void vsmp_cpus_done(void) | ||
187 | { | ||
188 | } | ||
189 | |||
190 | /* | 186 | /* |
191 | * Setup the PC, SP, and GP of a secondary processor and start it | 187 | * Setup the PC, SP, and GP of a secondary processor and start it |
192 | * running! | 188 | * running! |
@@ -287,7 +283,6 @@ struct plat_smp_ops vsmp_smp_ops = { | |||
287 | .send_ipi_mask = vsmp_send_ipi_mask, | 283 | .send_ipi_mask = vsmp_send_ipi_mask, |
288 | .init_secondary = vsmp_init_secondary, | 284 | .init_secondary = vsmp_init_secondary, |
289 | .smp_finish = vsmp_smp_finish, | 285 | .smp_finish = vsmp_smp_finish, |
290 | .cpus_done = vsmp_cpus_done, | ||
291 | .boot_secondary = vsmp_boot_secondary, | 286 | .boot_secondary = vsmp_boot_secondary, |
292 | .smp_setup = vsmp_smp_setup, | 287 | .smp_setup = vsmp_smp_setup, |
293 | .prepare_cpus = vsmp_prepare_cpus, | 288 | .prepare_cpus = vsmp_prepare_cpus, |
diff --git a/arch/mips/kernel/smp-up.c b/arch/mips/kernel/smp-up.c index 7fde3e4d978f..17878d71ef2b 100644 --- a/arch/mips/kernel/smp-up.c +++ b/arch/mips/kernel/smp-up.c | |||
@@ -36,11 +36,6 @@ static void up_smp_finish(void) | |||
36 | { | 36 | { |
37 | } | 37 | } |
38 | 38 | ||
39 | /* Hook for after all CPUs are online */ | ||
40 | static void up_cpus_done(void) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | /* | 39 | /* |
45 | * Firmware CPU startup hook | 40 | * Firmware CPU startup hook |
46 | */ | 41 | */ |
@@ -73,7 +68,6 @@ struct plat_smp_ops up_smp_ops = { | |||
73 | .send_ipi_mask = up_send_ipi_mask, | 68 | .send_ipi_mask = up_send_ipi_mask, |
74 | .init_secondary = up_init_secondary, | 69 | .init_secondary = up_init_secondary, |
75 | .smp_finish = up_smp_finish, | 70 | .smp_finish = up_smp_finish, |
76 | .cpus_done = up_cpus_done, | ||
77 | .boot_secondary = up_boot_secondary, | 71 | .boot_secondary = up_boot_secondary, |
78 | .smp_setup = up_smp_setup, | 72 | .smp_setup = up_smp_setup, |
79 | .prepare_cpus = up_prepare_cpus, | 73 | .prepare_cpus = up_prepare_cpus, |
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 0a022ee33b2a..9bad52ede903 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c | |||
@@ -43,10 +43,6 @@ | |||
43 | #include <asm/time.h> | 43 | #include <asm/time.h> |
44 | #include <asm/setup.h> | 44 | #include <asm/setup.h> |
45 | 45 | ||
46 | #ifdef CONFIG_MIPS_MT_SMTC | ||
47 | #include <asm/mipsmtregs.h> | ||
48 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
49 | |||
50 | volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ | 46 | volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ |
51 | 47 | ||
52 | int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ | 48 | int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ |
@@ -66,6 +62,8 @@ EXPORT_SYMBOL(cpu_sibling_map); | |||
66 | /* representing cpus for which sibling maps can be computed */ | 62 | /* representing cpus for which sibling maps can be computed */ |
67 | static cpumask_t cpu_sibling_setup_map; | 63 | static cpumask_t cpu_sibling_setup_map; |
68 | 64 | ||
65 | cpumask_t cpu_coherent_mask; | ||
66 | |||
69 | static inline void set_cpu_sibling_map(int cpu) | 67 | static inline void set_cpu_sibling_map(int cpu) |
70 | { | 68 | { |
71 | int i; | 69 | int i; |
@@ -102,12 +100,6 @@ asmlinkage void start_secondary(void) | |||
102 | { | 100 | { |
103 | unsigned int cpu; | 101 | unsigned int cpu; |
104 | 102 | ||
105 | #ifdef CONFIG_MIPS_MT_SMTC | ||
106 | /* Only do cpu_probe for first TC of CPU */ | ||
107 | if ((read_c0_tcbind() & TCBIND_CURTC) != 0) | ||
108 | __cpu_name[smp_processor_id()] = __cpu_name[0]; | ||
109 | else | ||
110 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
111 | cpu_probe(); | 103 | cpu_probe(); |
112 | cpu_report(); | 104 | cpu_report(); |
113 | per_cpu_trap_init(false); | 105 | per_cpu_trap_init(false); |
@@ -124,6 +116,7 @@ asmlinkage void start_secondary(void) | |||
124 | cpu = smp_processor_id(); | 116 | cpu = smp_processor_id(); |
125 | cpu_data[cpu].udelay_val = loops_per_jiffy; | 117 | cpu_data[cpu].udelay_val = loops_per_jiffy; |
126 | 118 | ||
119 | cpu_set(cpu, cpu_coherent_mask); | ||
127 | notify_cpu_starting(cpu); | 120 | notify_cpu_starting(cpu); |
128 | 121 | ||
129 | set_cpu_online(cpu, true); | 122 | set_cpu_online(cpu, true); |
@@ -173,7 +166,6 @@ void smp_send_stop(void) | |||
173 | 166 | ||
174 | void __init smp_cpus_done(unsigned int max_cpus) | 167 | void __init smp_cpus_done(unsigned int max_cpus) |
175 | { | 168 | { |
176 | mp_ops->cpus_done(); | ||
177 | } | 169 | } |
178 | 170 | ||
179 | /* called from main before smp_init() */ | 171 | /* called from main before smp_init() */ |
@@ -186,6 +178,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
186 | #ifndef CONFIG_HOTPLUG_CPU | 178 | #ifndef CONFIG_HOTPLUG_CPU |
187 | init_cpu_present(cpu_possible_mask); | 179 | init_cpu_present(cpu_possible_mask); |
188 | #endif | 180 | #endif |
181 | cpumask_copy(&cpu_coherent_mask, cpu_possible_mask); | ||
189 | } | 182 | } |
190 | 183 | ||
191 | /* preload SMP state for boot cpu */ | 184 | /* preload SMP state for boot cpu */ |
@@ -238,13 +231,10 @@ static void flush_tlb_mm_ipi(void *mm) | |||
238 | * o collapses to normal function call on UP kernels | 231 | * o collapses to normal function call on UP kernels |
239 | * o collapses to normal function call on systems with a single shared | 232 | * o collapses to normal function call on systems with a single shared |
240 | * primary cache. | 233 | * primary cache. |
241 | * o CONFIG_MIPS_MT_SMTC currently implies there is only one physical core. | ||
242 | */ | 234 | */ |
243 | static inline void smp_on_other_tlbs(void (*func) (void *info), void *info) | 235 | static inline void smp_on_other_tlbs(void (*func) (void *info), void *info) |
244 | { | 236 | { |
245 | #ifndef CONFIG_MIPS_MT_SMTC | ||
246 | smp_call_function(func, info, 1); | 237 | smp_call_function(func, info, 1); |
247 | #endif | ||
248 | } | 238 | } |
249 | 239 | ||
250 | static inline void smp_on_each_tlb(void (*func) (void *info), void *info) | 240 | static inline void smp_on_each_tlb(void (*func) (void *info), void *info) |
@@ -404,3 +394,46 @@ void dump_send_ipi(void (*dump_ipi_callback)(void *)) | |||
404 | } | 394 | } |
405 | EXPORT_SYMBOL(dump_send_ipi); | 395 | EXPORT_SYMBOL(dump_send_ipi); |
406 | #endif | 396 | #endif |
397 | |||
398 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | ||
399 | |||
400 | static DEFINE_PER_CPU(atomic_t, tick_broadcast_count); | ||
401 | static DEFINE_PER_CPU(struct call_single_data, tick_broadcast_csd); | ||
402 | |||
403 | void tick_broadcast(const struct cpumask *mask) | ||
404 | { | ||
405 | atomic_t *count; | ||
406 | struct call_single_data *csd; | ||
407 | int cpu; | ||
408 | |||
409 | for_each_cpu(cpu, mask) { | ||
410 | count = &per_cpu(tick_broadcast_count, cpu); | ||
411 | csd = &per_cpu(tick_broadcast_csd, cpu); | ||
412 | |||
413 | if (atomic_inc_return(count) == 1) | ||
414 | smp_call_function_single_async(cpu, csd); | ||
415 | } | ||
416 | } | ||
417 | |||
418 | static void tick_broadcast_callee(void *info) | ||
419 | { | ||
420 | int cpu = smp_processor_id(); | ||
421 | tick_receive_broadcast(); | ||
422 | atomic_set(&per_cpu(tick_broadcast_count, cpu), 0); | ||
423 | } | ||
424 | |||
425 | static int __init tick_broadcast_init(void) | ||
426 | { | ||
427 | struct call_single_data *csd; | ||
428 | int cpu; | ||
429 | |||
430 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
431 | csd = &per_cpu(tick_broadcast_csd, cpu); | ||
432 | csd->func = tick_broadcast_callee; | ||
433 | } | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | early_initcall(tick_broadcast_init); | ||
438 | |||
439 | #endif /* CONFIG_GENERIC_CLOCKEVENTS_BROADCAST */ | ||
diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S deleted file mode 100644 index 2866863a39df..000000000000 --- a/arch/mips/kernel/smtc-asm.S +++ /dev/null | |||
@@ -1,133 +0,0 @@ | |||
1 | /* | ||
2 | * Assembly Language Functions for MIPS MT SMTC support | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. */ | ||
7 | |||
8 | #include <asm/regdef.h> | ||
9 | #include <asm/asmmacro.h> | ||
10 | #include <asm/stackframe.h> | ||
11 | #include <asm/irqflags.h> | ||
12 | |||
13 | /* | ||
14 | * "Software Interrupt" linkage. | ||
15 | * | ||
16 | * This is invoked when an "Interrupt" is sent from one TC to another, | ||
17 | * where the TC to be interrupted is halted, has it's Restart address | ||
18 | * and Status values saved by the "remote control" thread, then modified | ||
19 | * to cause execution to begin here, in kenel mode. This code then | ||
20 | * disguises the TC state as that of an exception and transfers | ||
21 | * control to the general exception or vectored interrupt handler. | ||
22 | */ | ||
23 | .set noreorder | ||
24 | |||
25 | /* | ||
26 | The __smtc_ipi_vector would use k0 and k1 as temporaries and | ||
27 | 1) Set EXL (this is per-VPE, so this can't be done by proxy!) | ||
28 | 2) Restore the K/CU and IXMT bits to the pre "exception" state | ||
29 | (EXL means no interrupts and access to the kernel map). | ||
30 | 3) Set EPC to be the saved value of TCRestart. | ||
31 | 4) Jump to the exception handler entry point passed by the sender. | ||
32 | |||
33 | CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED?? | ||
34 | */ | ||
35 | |||
36 | /* | ||
37 | * Reviled and slandered vision: Set EXL and restore K/CU/IXMT | ||
38 | * state of pre-halt thread, then save everything and call | ||
39 | * thought some function pointer to imaginary_exception, which | ||
40 | * will parse a register value or memory message queue to | ||
41 | * deliver things like interprocessor interrupts. On return | ||
42 | * from that function, jump to the global ret_from_irq code | ||
43 | * to invoke the scheduler and return as appropriate. | ||
44 | */ | ||
45 | |||
46 | #define PT_PADSLOT4 (PT_R0-8) | ||
47 | #define PT_PADSLOT5 (PT_R0-4) | ||
48 | |||
49 | .text | ||
50 | .align 5 | ||
51 | FEXPORT(__smtc_ipi_vector) | ||
52 | #ifdef CONFIG_CPU_MICROMIPS | ||
53 | nop | ||
54 | #endif | ||
55 | .set noat | ||
56 | /* Disable thread scheduling to make Status update atomic */ | ||
57 | DMT 27 # dmt k1 | ||
58 | _ehb | ||
59 | /* Set EXL */ | ||
60 | mfc0 k0,CP0_STATUS | ||
61 | ori k0,k0,ST0_EXL | ||
62 | mtc0 k0,CP0_STATUS | ||
63 | _ehb | ||
64 | /* Thread scheduling now inhibited by EXL. Restore TE state. */ | ||
65 | andi k1,k1,VPECONTROL_TE | ||
66 | beqz k1,1f | ||
67 | emt | ||
68 | 1: | ||
69 | /* | ||
70 | * The IPI sender has put some information on the anticipated | ||
71 | * kernel stack frame. If we were in user mode, this will be | ||
72 | * built above the saved kernel SP. If we were already in the | ||
73 | * kernel, it will be built above the current CPU SP. | ||
74 | * | ||
75 | * Were we in kernel mode, as indicated by CU0? | ||
76 | */ | ||
77 | sll k1,k0,3 | ||
78 | .set noreorder | ||
79 | bltz k1,2f | ||
80 | move k1,sp | ||
81 | .set reorder | ||
82 | /* | ||
83 | * If previously in user mode, set CU0 and use kernel stack. | ||
84 | */ | ||
85 | li k1,ST0_CU0 | ||
86 | or k1,k1,k0 | ||
87 | mtc0 k1,CP0_STATUS | ||
88 | _ehb | ||
89 | get_saved_sp | ||
90 | /* Interrupting TC will have pre-set values in slots in the new frame */ | ||
91 | 2: subu k1,k1,PT_SIZE | ||
92 | /* Load TCStatus Value */ | ||
93 | lw k0,PT_TCSTATUS(k1) | ||
94 | /* Write it to TCStatus to restore CU/KSU/IXMT state */ | ||
95 | mtc0 k0,$2,1 | ||
96 | _ehb | ||
97 | lw k0,PT_EPC(k1) | ||
98 | mtc0 k0,CP0_EPC | ||
99 | /* Save all will redundantly recompute the SP, but use it for now */ | ||
100 | SAVE_ALL | ||
101 | CLI | ||
102 | TRACE_IRQS_OFF | ||
103 | /* Function to be invoked passed stack pad slot 5 */ | ||
104 | lw t0,PT_PADSLOT5(sp) | ||
105 | /* Argument from sender passed in stack pad slot 4 */ | ||
106 | lw a0,PT_PADSLOT4(sp) | ||
107 | LONG_L s0, TI_REGS($28) | ||
108 | LONG_S sp, TI_REGS($28) | ||
109 | PTR_LA ra, ret_from_irq | ||
110 | jr t0 | ||
111 | |||
112 | /* | ||
113 | * Called from idle loop to provoke processing of queued IPIs | ||
114 | * First IPI message in queue passed as argument. | ||
115 | */ | ||
116 | |||
117 | LEAF(self_ipi) | ||
118 | /* Before anything else, block interrupts */ | ||
119 | mfc0 t0,CP0_TCSTATUS | ||
120 | ori t1,t0,TCSTATUS_IXMT | ||
121 | mtc0 t1,CP0_TCSTATUS | ||
122 | _ehb | ||
123 | /* We know we're in kernel mode, so prepare stack frame */ | ||
124 | subu t1,sp,PT_SIZE | ||
125 | sw ra,PT_EPC(t1) | ||
126 | sw a0,PT_PADSLOT4(t1) | ||
127 | la t2,ipi_decode | ||
128 | sw t2,PT_PADSLOT5(t1) | ||
129 | /* Save pre-disable value of TCStatus */ | ||
130 | sw t0,PT_TCSTATUS(t1) | ||
131 | j __smtc_ipi_vector | ||
132 | nop | ||
133 | END(self_ipi) | ||
diff --git a/arch/mips/kernel/smtc-proc.c b/arch/mips/kernel/smtc-proc.c deleted file mode 100644 index 38635a996cbf..000000000000 --- a/arch/mips/kernel/smtc-proc.c +++ /dev/null | |||
@@ -1,102 +0,0 @@ | |||
1 | /* | ||
2 | * /proc hooks for SMTC kernel | ||
3 | * Copyright (C) 2005 Mips Technologies, Inc | ||
4 | */ | ||
5 | |||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/sched.h> | ||
8 | #include <linux/cpumask.h> | ||
9 | #include <linux/interrupt.h> | ||
10 | |||
11 | #include <asm/cpu.h> | ||
12 | #include <asm/processor.h> | ||
13 | #include <linux/atomic.h> | ||
14 | #include <asm/hardirq.h> | ||
15 | #include <asm/mmu_context.h> | ||
16 | #include <asm/mipsregs.h> | ||
17 | #include <asm/cacheflush.h> | ||
18 | #include <linux/proc_fs.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | |||
21 | #include <asm/smtc_proc.h> | ||
22 | |||
23 | /* | ||
24 | * /proc diagnostic and statistics hooks | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * Statistics gathered | ||
29 | */ | ||
30 | unsigned long selfipis[NR_CPUS]; | ||
31 | |||
32 | struct smtc_cpu_proc smtc_cpu_stats[NR_CPUS]; | ||
33 | |||
34 | atomic_t smtc_fpu_recoveries; | ||
35 | |||
36 | static int smtc_proc_show(struct seq_file *m, void *v) | ||
37 | { | ||
38 | int i; | ||
39 | extern unsigned long ebase; | ||
40 | |||
41 | seq_printf(m, "SMTC Status Word: 0x%08x\n", smtc_status); | ||
42 | seq_printf(m, "Config7: 0x%08x\n", read_c0_config7()); | ||
43 | seq_printf(m, "EBASE: 0x%08lx\n", ebase); | ||
44 | seq_printf(m, "Counter Interrupts taken per CPU (TC)\n"); | ||
45 | for (i=0; i < NR_CPUS; i++) | ||
46 | seq_printf(m, "%d: %ld\n", i, smtc_cpu_stats[i].timerints); | ||
47 | seq_printf(m, "Self-IPIs by CPU:\n"); | ||
48 | for(i = 0; i < NR_CPUS; i++) | ||
49 | seq_printf(m, "%d: %ld\n", i, smtc_cpu_stats[i].selfipis); | ||
50 | seq_printf(m, "%d Recoveries of \"stolen\" FPU\n", | ||
51 | atomic_read(&smtc_fpu_recoveries)); | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int smtc_proc_open(struct inode *inode, struct file *file) | ||
56 | { | ||
57 | return single_open(file, smtc_proc_show, NULL); | ||
58 | } | ||
59 | |||
60 | static const struct file_operations smtc_proc_fops = { | ||
61 | .open = smtc_proc_open, | ||
62 | .read = seq_read, | ||
63 | .llseek = seq_lseek, | ||
64 | .release = single_release, | ||
65 | }; | ||
66 | |||
67 | void init_smtc_stats(void) | ||
68 | { | ||
69 | int i; | ||
70 | |||
71 | for (i=0; i<NR_CPUS; i++) { | ||
72 | smtc_cpu_stats[i].timerints = 0; | ||
73 | smtc_cpu_stats[i].selfipis = 0; | ||
74 | } | ||
75 | |||
76 | atomic_set(&smtc_fpu_recoveries, 0); | ||
77 | |||
78 | proc_create("smtc", 0444, NULL, &smtc_proc_fops); | ||
79 | } | ||
80 | |||
81 | static int proc_cpuinfo_chain_call(struct notifier_block *nfb, | ||
82 | unsigned long action_unused, void *data) | ||
83 | { | ||
84 | struct proc_cpuinfo_notifier_args *pcn = data; | ||
85 | struct seq_file *m = pcn->m; | ||
86 | unsigned long n = pcn->n; | ||
87 | |||
88 | if (!cpu_has_mipsmt) | ||
89 | return NOTIFY_OK; | ||
90 | |||
91 | seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id); | ||
92 | seq_printf(m, "TC\t\t\t: %d\n", cpu_data[n].tc_id); | ||
93 | |||
94 | return NOTIFY_OK; | ||
95 | } | ||
96 | |||
97 | static int __init proc_cpuinfo_notifier_init(void) | ||
98 | { | ||
99 | return proc_cpuinfo_notifier(proc_cpuinfo_chain_call, 0); | ||
100 | } | ||
101 | |||
102 | subsys_initcall(proc_cpuinfo_notifier_init); | ||
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c deleted file mode 100644 index c1681d65dd5c..000000000000 --- a/arch/mips/kernel/smtc.c +++ /dev/null | |||
@@ -1,1528 +0,0 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or | ||
3 | * modify it under the terms of the GNU General Public License | ||
4 | * as published by the Free Software Foundation; either version 2 | ||
5 | * of the License, or (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | * | ||
16 | * Copyright (C) 2004 Mips Technologies, Inc | ||
17 | * Copyright (C) 2008 Kevin D. Kissell | ||
18 | */ | ||
19 | |||
20 | #include <linux/clockchips.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/smp.h> | ||
24 | #include <linux/cpumask.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/kernel_stat.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/ftrace.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include <asm/cpu.h> | ||
32 | #include <asm/processor.h> | ||
33 | #include <linux/atomic.h> | ||
34 | #include <asm/hardirq.h> | ||
35 | #include <asm/hazards.h> | ||
36 | #include <asm/irq.h> | ||
37 | #include <asm/idle.h> | ||
38 | #include <asm/mmu_context.h> | ||
39 | #include <asm/mipsregs.h> | ||
40 | #include <asm/cacheflush.h> | ||
41 | #include <asm/time.h> | ||
42 | #include <asm/addrspace.h> | ||
43 | #include <asm/smtc.h> | ||
44 | #include <asm/smtc_proc.h> | ||
45 | #include <asm/setup.h> | ||
46 | |||
47 | /* | ||
48 | * SMTC Kernel needs to manipulate low-level CPU interrupt mask | ||
49 | * in do_IRQ. These are passed in setup_irq_smtc() and stored | ||
50 | * in this table. | ||
51 | */ | ||
52 | unsigned long irq_hwmask[NR_IRQS]; | ||
53 | |||
54 | #define LOCK_MT_PRA() \ | ||
55 | local_irq_save(flags); \ | ||
56 | mtflags = dmt() | ||
57 | |||
58 | #define UNLOCK_MT_PRA() \ | ||
59 | emt(mtflags); \ | ||
60 | local_irq_restore(flags) | ||
61 | |||
62 | #define LOCK_CORE_PRA() \ | ||
63 | local_irq_save(flags); \ | ||
64 | mtflags = dvpe() | ||
65 | |||
66 | #define UNLOCK_CORE_PRA() \ | ||
67 | evpe(mtflags); \ | ||
68 | local_irq_restore(flags) | ||
69 | |||
70 | /* | ||
71 | * Data structures purely associated with SMTC parallelism | ||
72 | */ | ||
73 | |||
74 | |||
75 | /* | ||
76 | * Table for tracking ASIDs whose lifetime is prolonged. | ||
77 | */ | ||
78 | |||
79 | asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS]; | ||
80 | |||
81 | /* | ||
82 | * Number of InterProcessor Interrupt (IPI) message buffers to allocate | ||
83 | */ | ||
84 | |||
85 | #define IPIBUF_PER_CPU 4 | ||
86 | |||
87 | struct smtc_ipi_q IPIQ[NR_CPUS]; | ||
88 | static struct smtc_ipi_q freeIPIq; | ||
89 | |||
90 | |||
91 | /* | ||
92 | * Number of FPU contexts for each VPE | ||
93 | */ | ||
94 | |||
95 | static int smtc_nconf1[MAX_SMTC_VPES]; | ||
96 | |||
97 | |||
98 | /* Forward declarations */ | ||
99 | |||
100 | void ipi_decode(struct smtc_ipi *); | ||
101 | static void post_direct_ipi(int cpu, struct smtc_ipi *pipi); | ||
102 | static void setup_cross_vpe_interrupts(unsigned int nvpe); | ||
103 | void init_smtc_stats(void); | ||
104 | |||
105 | /* Global SMTC Status */ | ||
106 | |||
107 | unsigned int smtc_status; | ||
108 | |||
109 | /* Boot command line configuration overrides */ | ||
110 | |||
111 | static int vpe0limit; | ||
112 | static int ipibuffers; | ||
113 | static int nostlb; | ||
114 | static int asidmask; | ||
115 | unsigned long smtc_asid_mask = 0xff; | ||
116 | |||
117 | static int __init vpe0tcs(char *str) | ||
118 | { | ||
119 | get_option(&str, &vpe0limit); | ||
120 | |||
121 | return 1; | ||
122 | } | ||
123 | |||
124 | static int __init ipibufs(char *str) | ||
125 | { | ||
126 | get_option(&str, &ipibuffers); | ||
127 | return 1; | ||
128 | } | ||
129 | |||
130 | static int __init stlb_disable(char *s) | ||
131 | { | ||
132 | nostlb = 1; | ||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | static int __init asidmask_set(char *str) | ||
137 | { | ||
138 | get_option(&str, &asidmask); | ||
139 | switch (asidmask) { | ||
140 | case 0x1: | ||
141 | case 0x3: | ||
142 | case 0x7: | ||
143 | case 0xf: | ||
144 | case 0x1f: | ||
145 | case 0x3f: | ||
146 | case 0x7f: | ||
147 | case 0xff: | ||
148 | smtc_asid_mask = (unsigned long)asidmask; | ||
149 | break; | ||
150 | default: | ||
151 | printk("ILLEGAL ASID mask 0x%x from command line\n", asidmask); | ||
152 | } | ||
153 | return 1; | ||
154 | } | ||
155 | |||
156 | __setup("vpe0tcs=", vpe0tcs); | ||
157 | __setup("ipibufs=", ipibufs); | ||
158 | __setup("nostlb", stlb_disable); | ||
159 | __setup("asidmask=", asidmask_set); | ||
160 | |||
161 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG | ||
162 | |||
163 | static int hang_trig; | ||
164 | |||
165 | static int __init hangtrig_enable(char *s) | ||
166 | { | ||
167 | hang_trig = 1; | ||
168 | return 1; | ||
169 | } | ||
170 | |||
171 | |||
172 | __setup("hangtrig", hangtrig_enable); | ||
173 | |||
174 | #define DEFAULT_BLOCKED_IPI_LIMIT 32 | ||
175 | |||
176 | static int timerq_limit = DEFAULT_BLOCKED_IPI_LIMIT; | ||
177 | |||
178 | static int __init tintq(char *str) | ||
179 | { | ||
180 | get_option(&str, &timerq_limit); | ||
181 | return 1; | ||
182 | } | ||
183 | |||
184 | __setup("tintq=", tintq); | ||
185 | |||
186 | static int imstuckcount[MAX_SMTC_VPES][8]; | ||
187 | /* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */ | ||
188 | static int vpemask[MAX_SMTC_VPES][8] = { | ||
189 | {0, 0, 1, 0, 0, 0, 0, 1}, | ||
190 | {0, 0, 0, 0, 0, 0, 0, 1} | ||
191 | }; | ||
192 | int tcnoprog[NR_CPUS]; | ||
193 | static atomic_t idle_hook_initialized = ATOMIC_INIT(0); | ||
194 | static int clock_hang_reported[NR_CPUS]; | ||
195 | |||
196 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ | ||
197 | |||
198 | /* | ||
199 | * Configure shared TLB - VPC configuration bit must be set by caller | ||
200 | */ | ||
201 | |||
202 | static void smtc_configure_tlb(void) | ||
203 | { | ||
204 | int i, tlbsiz, vpes; | ||
205 | unsigned long mvpconf0; | ||
206 | unsigned long config1val; | ||
207 | |||
208 | /* Set up ASID preservation table */ | ||
209 | for (vpes=0; vpes<MAX_SMTC_TLBS; vpes++) { | ||
210 | for(i = 0; i < MAX_SMTC_ASIDS; i++) { | ||
211 | smtc_live_asid[vpes][i] = 0; | ||
212 | } | ||
213 | } | ||
214 | mvpconf0 = read_c0_mvpconf0(); | ||
215 | |||
216 | if ((vpes = ((mvpconf0 & MVPCONF0_PVPE) | ||
217 | >> MVPCONF0_PVPE_SHIFT) + 1) > 1) { | ||
218 | /* If we have multiple VPEs, try to share the TLB */ | ||
219 | if ((mvpconf0 & MVPCONF0_TLBS) && !nostlb) { | ||
220 | /* | ||
221 | * If TLB sizing is programmable, shared TLB | ||
222 | * size is the total available complement. | ||
223 | * Otherwise, we have to take the sum of all | ||
224 | * static VPE TLB entries. | ||
225 | */ | ||
226 | if ((tlbsiz = ((mvpconf0 & MVPCONF0_PTLBE) | ||
227 | >> MVPCONF0_PTLBE_SHIFT)) == 0) { | ||
228 | /* | ||
229 | * If there's more than one VPE, there had better | ||
230 | * be more than one TC, because we need one to bind | ||
231 | * to each VPE in turn to be able to read | ||
232 | * its configuration state! | ||
233 | */ | ||
234 | settc(1); | ||
235 | /* Stop the TC from doing anything foolish */ | ||
236 | write_tc_c0_tchalt(TCHALT_H); | ||
237 | mips_ihb(); | ||
238 | /* No need to un-Halt - that happens later anyway */ | ||
239 | for (i=0; i < vpes; i++) { | ||
240 | write_tc_c0_tcbind(i); | ||
241 | /* | ||
242 | * To be 100% sure we're really getting the right | ||
243 | * information, we exit the configuration state | ||
244 | * and do an IHB after each rebinding. | ||
245 | */ | ||
246 | write_c0_mvpcontrol( | ||
247 | read_c0_mvpcontrol() & ~ MVPCONTROL_VPC ); | ||
248 | mips_ihb(); | ||
249 | /* | ||
250 | * Only count if the MMU Type indicated is TLB | ||
251 | */ | ||
252 | if (((read_vpe_c0_config() & MIPS_CONF_MT) >> 7) == 1) { | ||
253 | config1val = read_vpe_c0_config1(); | ||
254 | tlbsiz += ((config1val >> 25) & 0x3f) + 1; | ||
255 | } | ||
256 | |||
257 | /* Put core back in configuration state */ | ||
258 | write_c0_mvpcontrol( | ||
259 | read_c0_mvpcontrol() | MVPCONTROL_VPC ); | ||
260 | mips_ihb(); | ||
261 | } | ||
262 | } | ||
263 | write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB); | ||
264 | ehb(); | ||
265 | |||
266 | /* | ||
267 | * Setup kernel data structures to use software total, | ||
268 | * rather than read the per-VPE Config1 value. The values | ||
269 | * for "CPU 0" gets copied to all the other CPUs as part | ||
270 | * of their initialization in smtc_cpu_setup(). | ||
271 | */ | ||
272 | |||
273 | /* MIPS32 limits TLB indices to 64 */ | ||
274 | if (tlbsiz > 64) | ||
275 | tlbsiz = 64; | ||
276 | cpu_data[0].tlbsize = current_cpu_data.tlbsize = tlbsiz; | ||
277 | smtc_status |= SMTC_TLB_SHARED; | ||
278 | local_flush_tlb_all(); | ||
279 | |||
280 | printk("TLB of %d entry pairs shared by %d VPEs\n", | ||
281 | tlbsiz, vpes); | ||
282 | } else { | ||
283 | printk("WARNING: TLB Not Sharable on SMTC Boot!\n"); | ||
284 | } | ||
285 | } | ||
286 | } | ||
287 | |||
288 | |||
289 | /* | ||
290 | * Incrementally build the CPU map out of constituent MIPS MT cores, | ||
291 | * using the specified available VPEs and TCs. Plaform code needs | ||
292 | * to ensure that each MIPS MT core invokes this routine on reset, | ||
293 | * one at a time(!). | ||
294 | * | ||
295 | * This version of the build_cpu_map and prepare_cpus routines assumes | ||
296 | * that *all* TCs of a MIPS MT core will be used for Linux, and that | ||
297 | * they will be spread across *all* available VPEs (to minimise the | ||
298 | * loss of efficiency due to exception service serialization). | ||
299 | * An improved version would pick up configuration information and | ||
300 | * possibly leave some TCs/VPEs as "slave" processors. | ||
301 | * | ||
302 | * Use c0_MVPConf0 to find out how many TCs are available, setting up | ||
303 | * cpu_possible_mask and the logical/physical mappings. | ||
304 | */ | ||
305 | |||
306 | int __init smtc_build_cpu_map(int start_cpu_slot) | ||
307 | { | ||
308 | int i, ntcs; | ||
309 | |||
310 | /* | ||
311 | * The CPU map isn't actually used for anything at this point, | ||
312 | * so it's not clear what else we should do apart from set | ||
313 | * everything up so that "logical" = "physical". | ||
314 | */ | ||
315 | ntcs = ((read_c0_mvpconf0() & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; | ||
316 | for (i=start_cpu_slot; i<NR_CPUS && i<ntcs; i++) { | ||
317 | set_cpu_possible(i, true); | ||
318 | __cpu_number_map[i] = i; | ||
319 | __cpu_logical_map[i] = i; | ||
320 | } | ||
321 | #ifdef CONFIG_MIPS_MT_FPAFF | ||
322 | /* Initialize map of CPUs with FPUs */ | ||
323 | cpus_clear(mt_fpu_cpumask); | ||
324 | #endif | ||
325 | |||
326 | /* One of those TC's is the one booting, and not a secondary... */ | ||
327 | printk("%i available secondary CPU TC(s)\n", i - 1); | ||
328 | |||
329 | return i; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Common setup before any secondaries are started | ||
334 | * Make sure all CPUs are in a sensible state before we boot any of the | ||
335 | * secondaries. | ||
336 | * | ||
337 | * For MIPS MT "SMTC" operation, we set up all TCs, spread as evenly | ||
338 | * as possible across the available VPEs. | ||
339 | */ | ||
340 | |||
341 | static void smtc_tc_setup(int vpe, int tc, int cpu) | ||
342 | { | ||
343 | static int cp1contexts[MAX_SMTC_VPES]; | ||
344 | |||
345 | /* | ||
346 | * Make a local copy of the available FPU contexts in order | ||
347 | * to keep track of TCs that can have one. | ||
348 | */ | ||
349 | if (tc == 1) | ||
350 | { | ||
351 | /* | ||
352 | * FIXME: Multi-core SMTC hasn't been tested and the | ||
353 | * maximum number of VPEs may change. | ||
354 | */ | ||
355 | cp1contexts[0] = smtc_nconf1[0] - 1; | ||
356 | cp1contexts[1] = smtc_nconf1[1]; | ||
357 | } | ||
358 | |||
359 | settc(tc); | ||
360 | write_tc_c0_tchalt(TCHALT_H); | ||
361 | mips_ihb(); | ||
362 | write_tc_c0_tcstatus((read_tc_c0_tcstatus() | ||
363 | & ~(TCSTATUS_TKSU | TCSTATUS_DA | TCSTATUS_IXMT)) | ||
364 | | TCSTATUS_A); | ||
365 | /* | ||
366 | * TCContext gets an offset from the base of the IPIQ array | ||
367 | * to be used in low-level code to detect the presence of | ||
368 | * an active IPI queue. | ||
369 | */ | ||
370 | write_tc_c0_tccontext((sizeof(struct smtc_ipi_q) * cpu) << 16); | ||
371 | |||
372 | /* Bind TC to VPE. */ | ||
373 | write_tc_c0_tcbind(vpe); | ||
374 | |||
375 | /* In general, all TCs should have the same cpu_data indications. */ | ||
376 | memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips)); | ||
377 | |||
378 | /* Check to see if there is a FPU context available for this TC. */ | ||
379 | if (!cp1contexts[vpe]) | ||
380 | cpu_data[cpu].options &= ~MIPS_CPU_FPU; | ||
381 | else | ||
382 | cp1contexts[vpe]--; | ||
383 | |||
384 | /* Store the TC and VPE into the cpu_data structure. */ | ||
385 | cpu_data[cpu].vpe_id = vpe; | ||
386 | cpu_data[cpu].tc_id = tc; | ||
387 | |||
388 | /* FIXME: Multi-core SMTC hasn't been tested, but be prepared. */ | ||
389 | cpu_data[cpu].core = (read_vpe_c0_ebase() >> 1) & 0xff; | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Tweak to get Count registers synced as closely as possible. The | ||
394 | * value seems good for 34K-class cores. | ||
395 | */ | ||
396 | |||
397 | #define CP0_SKEW 8 | ||
398 | |||
399 | void smtc_prepare_cpus(int cpus) | ||
400 | { | ||
401 | int i, vpe, tc, ntc, nvpe, tcpervpe[NR_CPUS], slop, cpu; | ||
402 | unsigned long flags; | ||
403 | unsigned long val; | ||
404 | int nipi; | ||
405 | struct smtc_ipi *pipi; | ||
406 | |||
407 | /* disable interrupts so we can disable MT */ | ||
408 | local_irq_save(flags); | ||
409 | /* disable MT so we can configure */ | ||
410 | dvpe(); | ||
411 | dmt(); | ||
412 | |||
413 | spin_lock_init(&freeIPIq.lock); | ||
414 | |||
415 | /* | ||
416 | * We probably don't have as many VPEs as we do SMP "CPUs", | ||
417 | * but it's possible - and in any case we'll never use more! | ||
418 | */ | ||
419 | for (i=0; i<NR_CPUS; i++) { | ||
420 | IPIQ[i].head = IPIQ[i].tail = NULL; | ||
421 | spin_lock_init(&IPIQ[i].lock); | ||
422 | IPIQ[i].depth = 0; | ||
423 | IPIQ[i].resched_flag = 0; /* No reschedules queued initially */ | ||
424 | } | ||
425 | |||
426 | /* cpu_data index starts at zero */ | ||
427 | cpu = 0; | ||
428 | cpu_data[cpu].vpe_id = 0; | ||
429 | cpu_data[cpu].tc_id = 0; | ||
430 | cpu_data[cpu].core = (read_c0_ebase() >> 1) & 0xff; | ||
431 | cpu++; | ||
432 | |||
433 | /* Report on boot-time options */ | ||
434 | mips_mt_set_cpuoptions(); | ||
435 | if (vpelimit > 0) | ||
436 | printk("Limit of %d VPEs set\n", vpelimit); | ||
437 | if (tclimit > 0) | ||
438 | printk("Limit of %d TCs set\n", tclimit); | ||
439 | if (nostlb) { | ||
440 | printk("Shared TLB Use Inhibited - UNSAFE for Multi-VPE Operation\n"); | ||
441 | } | ||
442 | if (asidmask) | ||
443 | printk("ASID mask value override to 0x%x\n", asidmask); | ||
444 | |||
445 | /* Temporary */ | ||
446 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG | ||
447 | if (hang_trig) | ||
448 | printk("Logic Analyser Trigger on suspected TC hang\n"); | ||
449 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ | ||
450 | |||
451 | /* Put MVPE's into 'configuration state' */ | ||
452 | write_c0_mvpcontrol( read_c0_mvpcontrol() | MVPCONTROL_VPC ); | ||
453 | |||
454 | val = read_c0_mvpconf0(); | ||
455 | nvpe = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; | ||
456 | if (vpelimit > 0 && nvpe > vpelimit) | ||
457 | nvpe = vpelimit; | ||
458 | ntc = ((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; | ||
459 | if (ntc > NR_CPUS) | ||
460 | ntc = NR_CPUS; | ||
461 | if (tclimit > 0 && ntc > tclimit) | ||
462 | ntc = tclimit; | ||
463 | slop = ntc % nvpe; | ||
464 | for (i = 0; i < nvpe; i++) { | ||
465 | tcpervpe[i] = ntc / nvpe; | ||
466 | if (slop) { | ||
467 | if((slop - i) > 0) tcpervpe[i]++; | ||
468 | } | ||
469 | } | ||
470 | /* Handle command line override for VPE0 */ | ||
471 | if (vpe0limit > ntc) vpe0limit = ntc; | ||
472 | if (vpe0limit > 0) { | ||
473 | int slopslop; | ||
474 | if (vpe0limit < tcpervpe[0]) { | ||
475 | /* Reducing TC count - distribute to others */ | ||
476 | slop = tcpervpe[0] - vpe0limit; | ||
477 | slopslop = slop % (nvpe - 1); | ||
478 | tcpervpe[0] = vpe0limit; | ||
479 | for (i = 1; i < nvpe; i++) { | ||
480 | tcpervpe[i] += slop / (nvpe - 1); | ||
481 | if(slopslop && ((slopslop - (i - 1) > 0))) | ||
482 | tcpervpe[i]++; | ||
483 | } | ||
484 | } else if (vpe0limit > tcpervpe[0]) { | ||
485 | /* Increasing TC count - steal from others */ | ||
486 | slop = vpe0limit - tcpervpe[0]; | ||
487 | slopslop = slop % (nvpe - 1); | ||
488 | tcpervpe[0] = vpe0limit; | ||
489 | for (i = 1; i < nvpe; i++) { | ||
490 | tcpervpe[i] -= slop / (nvpe - 1); | ||
491 | if(slopslop && ((slopslop - (i - 1) > 0))) | ||
492 | tcpervpe[i]--; | ||
493 | } | ||
494 | } | ||
495 | } | ||
496 | |||
497 | /* Set up shared TLB */ | ||
498 | smtc_configure_tlb(); | ||
499 | |||
500 | for (tc = 0, vpe = 0 ; (vpe < nvpe) && (tc < ntc) ; vpe++) { | ||
501 | /* Get number of CP1 contexts for each VPE. */ | ||
502 | if (tc == 0) | ||
503 | { | ||
504 | /* | ||
505 | * Do not call settc() for TC0 or the FPU context | ||
506 | * value will be incorrect. Besides, we know that | ||
507 | * we are TC0 anyway. | ||
508 | */ | ||
509 | smtc_nconf1[0] = ((read_vpe_c0_vpeconf1() & | ||
510 | VPECONF1_NCP1) >> VPECONF1_NCP1_SHIFT); | ||
511 | if (nvpe == 2) | ||
512 | { | ||
513 | settc(1); | ||
514 | smtc_nconf1[1] = ((read_vpe_c0_vpeconf1() & | ||
515 | VPECONF1_NCP1) >> VPECONF1_NCP1_SHIFT); | ||
516 | settc(0); | ||
517 | } | ||
518 | } | ||
519 | if (tcpervpe[vpe] == 0) | ||
520 | continue; | ||
521 | if (vpe != 0) | ||
522 | printk(", "); | ||
523 | printk("VPE %d: TC", vpe); | ||
524 | for (i = 0; i < tcpervpe[vpe]; i++) { | ||
525 | /* | ||
526 | * TC 0 is bound to VPE 0 at reset, | ||
527 | * and is presumably executing this | ||
528 | * code. Leave it alone! | ||
529 | */ | ||
530 | if (tc != 0) { | ||
531 | smtc_tc_setup(vpe, tc, cpu); | ||
532 | if (vpe != 0) { | ||
533 | /* | ||
534 | * Set MVP bit (possibly again). Do it | ||
535 | * here to catch CPUs that have no TCs | ||
536 | * bound to the VPE at reset. In that | ||
537 | * case, a TC must be bound to the VPE | ||
538 | * before we can set VPEControl[MVP] | ||
539 | */ | ||
540 | write_vpe_c0_vpeconf0( | ||
541 | read_vpe_c0_vpeconf0() | | ||
542 | VPECONF0_MVP); | ||
543 | } | ||
544 | cpu++; | ||
545 | } | ||
546 | printk(" %d", tc); | ||
547 | tc++; | ||
548 | } | ||
549 | if (vpe != 0) { | ||
550 | /* | ||
551 | * Allow this VPE to control others. | ||
552 | */ | ||
553 | write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | | ||
554 | VPECONF0_MVP); | ||
555 | |||
556 | /* | ||
557 | * Clear any stale software interrupts from VPE's Cause | ||
558 | */ | ||
559 | write_vpe_c0_cause(0); | ||
560 | |||
561 | /* | ||
562 | * Clear ERL/EXL of VPEs other than 0 | ||
563 | * and set restricted interrupt enable/mask. | ||
564 | */ | ||
565 | write_vpe_c0_status((read_vpe_c0_status() | ||
566 | & ~(ST0_BEV | ST0_ERL | ST0_EXL | ST0_IM)) | ||
567 | | (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP7 | ||
568 | | ST0_IE)); | ||
569 | /* | ||
570 | * set config to be the same as vpe0, | ||
571 | * particularly kseg0 coherency alg | ||
572 | */ | ||
573 | write_vpe_c0_config(read_c0_config()); | ||
574 | /* Clear any pending timer interrupt */ | ||
575 | write_vpe_c0_compare(0); | ||
576 | /* Propagate Config7 */ | ||
577 | write_vpe_c0_config7(read_c0_config7()); | ||
578 | write_vpe_c0_count(read_c0_count() + CP0_SKEW); | ||
579 | ehb(); | ||
580 | } | ||
581 | /* enable multi-threading within VPE */ | ||
582 | write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() | VPECONTROL_TE); | ||
583 | /* enable the VPE */ | ||
584 | write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); | ||
585 | } | ||
586 | |||
587 | /* | ||
588 | * Pull any physically present but unused TCs out of circulation. | ||
589 | */ | ||
590 | while (tc < (((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1)) { | ||
591 | set_cpu_possible(tc, false); | ||
592 | set_cpu_present(tc, false); | ||
593 | tc++; | ||
594 | } | ||
595 | |||
596 | /* release config state */ | ||
597 | write_c0_mvpcontrol( read_c0_mvpcontrol() & ~ MVPCONTROL_VPC ); | ||
598 | |||
599 | printk("\n"); | ||
600 | |||
601 | /* Set up coprocessor affinity CPU mask(s) */ | ||
602 | |||
603 | #ifdef CONFIG_MIPS_MT_FPAFF | ||
604 | for (tc = 0; tc < ntc; tc++) { | ||
605 | if (cpu_data[tc].options & MIPS_CPU_FPU) | ||
606 | cpu_set(tc, mt_fpu_cpumask); | ||
607 | } | ||
608 | #endif | ||
609 | |||
610 | /* set up ipi interrupts... */ | ||
611 | |||
612 | /* If we have multiple VPEs running, set up the cross-VPE interrupt */ | ||
613 | |||
614 | setup_cross_vpe_interrupts(nvpe); | ||
615 | |||
616 | /* Set up queue of free IPI "messages". */ | ||
617 | nipi = NR_CPUS * IPIBUF_PER_CPU; | ||
618 | if (ipibuffers > 0) | ||
619 | nipi = ipibuffers; | ||
620 | |||
621 | pipi = kmalloc(nipi *sizeof(struct smtc_ipi), GFP_KERNEL); | ||
622 | if (pipi == NULL) | ||
623 | panic("kmalloc of IPI message buffers failed"); | ||
624 | else | ||
625 | printk("IPI buffer pool of %d buffers\n", nipi); | ||
626 | for (i = 0; i < nipi; i++) { | ||
627 | smtc_ipi_nq(&freeIPIq, pipi); | ||
628 | pipi++; | ||
629 | } | ||
630 | |||
631 | /* Arm multithreading and enable other VPEs - but all TCs are Halted */ | ||
632 | emt(EMT_ENABLE); | ||
633 | evpe(EVPE_ENABLE); | ||
634 | local_irq_restore(flags); | ||
635 | /* Initialize SMTC /proc statistics/diagnostics */ | ||
636 | init_smtc_stats(); | ||
637 | } | ||
638 | |||
639 | |||
640 | /* | ||
641 | * Setup the PC, SP, and GP of a secondary processor and start it | ||
642 | * running! | ||
643 | * smp_bootstrap is the place to resume from | ||
644 | * __KSTK_TOS(idle) is apparently the stack pointer | ||
645 | * (unsigned long)idle->thread_info the gp | ||
646 | * | ||
647 | */ | ||
648 | void smtc_boot_secondary(int cpu, struct task_struct *idle) | ||
649 | { | ||
650 | extern u32 kernelsp[NR_CPUS]; | ||
651 | unsigned long flags; | ||
652 | int mtflags; | ||
653 | |||
654 | LOCK_MT_PRA(); | ||
655 | if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) { | ||
656 | dvpe(); | ||
657 | } | ||
658 | settc(cpu_data[cpu].tc_id); | ||
659 | |||
660 | /* pc */ | ||
661 | write_tc_c0_tcrestart((unsigned long)&smp_bootstrap); | ||
662 | |||
663 | /* stack pointer */ | ||
664 | kernelsp[cpu] = __KSTK_TOS(idle); | ||
665 | write_tc_gpr_sp(__KSTK_TOS(idle)); | ||
666 | |||
667 | /* global pointer */ | ||
668 | write_tc_gpr_gp((unsigned long)task_thread_info(idle)); | ||
669 | |||
670 | smtc_status |= SMTC_MTC_ACTIVE; | ||
671 | write_tc_c0_tchalt(0); | ||
672 | if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) { | ||
673 | evpe(EVPE_ENABLE); | ||
674 | } | ||
675 | UNLOCK_MT_PRA(); | ||
676 | } | ||
677 | |||
678 | void smtc_init_secondary(void) | ||
679 | { | ||
680 | } | ||
681 | |||
682 | void smtc_smp_finish(void) | ||
683 | { | ||
684 | int cpu = smp_processor_id(); | ||
685 | |||
686 | /* | ||
687 | * Lowest-numbered CPU per VPE starts a clock tick. | ||
688 | * Like per_cpu_trap_init() hack, this assumes that | ||
689 | * SMTC init code assigns TCs consdecutively and | ||
690 | * in ascending order across available VPEs. | ||
691 | */ | ||
692 | if (cpu > 0 && (cpu_data[cpu].vpe_id != cpu_data[cpu - 1].vpe_id)) | ||
693 | write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ); | ||
694 | |||
695 | local_irq_enable(); | ||
696 | |||
697 | printk("TC %d going on-line as CPU %d\n", | ||
698 | cpu_data[smp_processor_id()].tc_id, smp_processor_id()); | ||
699 | } | ||
700 | |||
701 | void smtc_cpus_done(void) | ||
702 | { | ||
703 | } | ||
704 | |||
705 | /* | ||
706 | * Support for SMTC-optimized driver IRQ registration | ||
707 | */ | ||
708 | |||
709 | /* | ||
710 | * SMTC Kernel needs to manipulate low-level CPU interrupt mask | ||
711 | * in do_IRQ. These are passed in setup_irq_smtc() and stored | ||
712 | * in this table. | ||
713 | */ | ||
714 | |||
715 | int setup_irq_smtc(unsigned int irq, struct irqaction * new, | ||
716 | unsigned long hwmask) | ||
717 | { | ||
718 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG | ||
719 | unsigned int vpe = current_cpu_data.vpe_id; | ||
720 | |||
721 | vpemask[vpe][irq - MIPS_CPU_IRQ_BASE] = 1; | ||
722 | #endif | ||
723 | irq_hwmask[irq] = hwmask; | ||
724 | |||
725 | return setup_irq(irq, new); | ||
726 | } | ||
727 | |||
728 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | ||
729 | /* | ||
730 | * Support for IRQ affinity to TCs | ||
731 | */ | ||
732 | |||
733 | void smtc_set_irq_affinity(unsigned int irq, cpumask_t affinity) | ||
734 | { | ||
735 | /* | ||
736 | * If a "fast path" cache of quickly decodable affinity state | ||
737 | * is maintained, this is where it gets done, on a call up | ||
738 | * from the platform affinity code. | ||
739 | */ | ||
740 | } | ||
741 | |||
742 | void smtc_forward_irq(struct irq_data *d) | ||
743 | { | ||
744 | unsigned int irq = d->irq; | ||
745 | int target; | ||
746 | |||
747 | /* | ||
748 | * OK wise guy, now figure out how to get the IRQ | ||
749 | * to be serviced on an authorized "CPU". | ||
750 | * | ||
751 | * Ideally, to handle the situation where an IRQ has multiple | ||
752 | * eligible CPUS, we would maintain state per IRQ that would | ||
753 | * allow a fair distribution of service requests. Since the | ||
754 | * expected use model is any-or-only-one, for simplicity | ||
755 | * and efficiency, we just pick the easiest one to find. | ||
756 | */ | ||
757 | |||
758 | target = cpumask_first(d->affinity); | ||
759 | |||
760 | /* | ||
761 | * We depend on the platform code to have correctly processed | ||
762 | * IRQ affinity change requests to ensure that the IRQ affinity | ||
763 | * mask has been purged of bits corresponding to nonexistent and | ||
764 | * offline "CPUs", and to TCs bound to VPEs other than the VPE | ||
765 | * connected to the physical interrupt input for the interrupt | ||
766 | * in question. Otherwise we have a nasty problem with interrupt | ||
767 | * mask management. This is best handled in non-performance-critical | ||
768 | * platform IRQ affinity setting code, to minimize interrupt-time | ||
769 | * checks. | ||
770 | */ | ||
771 | |||
772 | /* If no one is eligible, service locally */ | ||
773 | if (target >= NR_CPUS) | ||
774 | do_IRQ_no_affinity(irq); | ||
775 | else | ||
776 | smtc_send_ipi(target, IRQ_AFFINITY_IPI, irq); | ||
777 | } | ||
778 | |||
779 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | ||
780 | |||
781 | /* | ||
782 | * IPI model for SMTC is tricky, because interrupts aren't TC-specific. | ||
783 | * Within a VPE one TC can interrupt another by different approaches. | ||
784 | * The easiest to get right would probably be to make all TCs except | ||
785 | * the target IXMT and set a software interrupt, but an IXMT-based | ||
786 | * scheme requires that a handler must run before a new IPI could | ||
787 | * be sent, which would break the "broadcast" loops in MIPS MT. | ||
788 | * A more gonzo approach within a VPE is to halt the TC, extract | ||
789 | * its Restart, Status, and a couple of GPRs, and program the Restart | ||
790 | * address to emulate an interrupt. | ||
791 | * | ||
792 | * Within a VPE, one can be confident that the target TC isn't in | ||
793 | * a critical EXL state when halted, since the write to the Halt | ||
794 | * register could not have issued on the writing thread if the | ||
795 | * halting thread had EXL set. So k0 and k1 of the target TC | ||
796 | * can be used by the injection code. Across VPEs, one can't | ||
797 | * be certain that the target TC isn't in a critical exception | ||
798 | * state. So we try a two-step process of sending a software | ||
799 | * interrupt to the target VPE, which either handles the event | ||
800 | * itself (if it was the target) or injects the event within | ||
801 | * the VPE. | ||
802 | */ | ||
803 | |||
804 | static void smtc_ipi_qdump(void) | ||
805 | { | ||
806 | int i; | ||
807 | struct smtc_ipi *temp; | ||
808 | |||
809 | for (i = 0; i < NR_CPUS ;i++) { | ||
810 | pr_info("IPIQ[%d]: head = 0x%x, tail = 0x%x, depth = %d\n", | ||
811 | i, (unsigned)IPIQ[i].head, (unsigned)IPIQ[i].tail, | ||
812 | IPIQ[i].depth); | ||
813 | temp = IPIQ[i].head; | ||
814 | |||
815 | while (temp != IPIQ[i].tail) { | ||
816 | pr_debug("%d %d %d: ", temp->type, temp->dest, | ||
817 | (int)temp->arg); | ||
818 | #ifdef SMTC_IPI_DEBUG | ||
819 | pr_debug("%u %lu\n", temp->sender, temp->stamp); | ||
820 | #else | ||
821 | pr_debug("\n"); | ||
822 | #endif | ||
823 | temp = temp->flink; | ||
824 | } | ||
825 | } | ||
826 | } | ||
827 | |||
828 | /* | ||
829 | * The standard atomic.h primitives don't quite do what we want | ||
830 | * here: We need an atomic add-and-return-previous-value (which | ||
831 | * could be done with atomic_add_return and a decrement) and an | ||
832 | * atomic set/zero-and-return-previous-value (which can't really | ||
833 | * be done with the atomic.h primitives). And since this is | ||
834 | * MIPS MT, we can assume that we have LL/SC. | ||
835 | */ | ||
836 | static inline int atomic_postincrement(atomic_t *v) | ||
837 | { | ||
838 | unsigned long result; | ||
839 | |||
840 | unsigned long temp; | ||
841 | |||
842 | __asm__ __volatile__( | ||
843 | "1: ll %0, %2 \n" | ||
844 | " addu %1, %0, 1 \n" | ||
845 | " sc %1, %2 \n" | ||
846 | " beqz %1, 1b \n" | ||
847 | __WEAK_LLSC_MB | ||
848 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
849 | : "m" (v->counter) | ||
850 | : "memory"); | ||
851 | |||
852 | return result; | ||
853 | } | ||
854 | |||
855 | void smtc_send_ipi(int cpu, int type, unsigned int action) | ||
856 | { | ||
857 | int tcstatus; | ||
858 | struct smtc_ipi *pipi; | ||
859 | unsigned long flags; | ||
860 | int mtflags; | ||
861 | unsigned long tcrestart; | ||
862 | int set_resched_flag = (type == LINUX_SMP_IPI && | ||
863 | action == SMP_RESCHEDULE_YOURSELF); | ||
864 | |||
865 | if (cpu == smp_processor_id()) { | ||
866 | printk("Cannot Send IPI to self!\n"); | ||
867 | return; | ||
868 | } | ||
869 | if (set_resched_flag && IPIQ[cpu].resched_flag != 0) | ||
870 | return; /* There is a reschedule queued already */ | ||
871 | |||
872 | /* Set up a descriptor, to be delivered either promptly or queued */ | ||
873 | pipi = smtc_ipi_dq(&freeIPIq); | ||
874 | if (pipi == NULL) { | ||
875 | bust_spinlocks(1); | ||
876 | mips_mt_regdump(dvpe()); | ||
877 | panic("IPI Msg. Buffers Depleted"); | ||
878 | } | ||
879 | pipi->type = type; | ||
880 | pipi->arg = (void *)action; | ||
881 | pipi->dest = cpu; | ||
882 | if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) { | ||
883 | /* If not on same VPE, enqueue and send cross-VPE interrupt */ | ||
884 | IPIQ[cpu].resched_flag |= set_resched_flag; | ||
885 | smtc_ipi_nq(&IPIQ[cpu], pipi); | ||
886 | LOCK_CORE_PRA(); | ||
887 | settc(cpu_data[cpu].tc_id); | ||
888 | write_vpe_c0_cause(read_vpe_c0_cause() | C_SW1); | ||
889 | UNLOCK_CORE_PRA(); | ||
890 | } else { | ||
891 | /* | ||
892 | * Not sufficient to do a LOCK_MT_PRA (dmt) here, | ||
893 | * since ASID shootdown on the other VPE may | ||
894 | * collide with this operation. | ||
895 | */ | ||
896 | LOCK_CORE_PRA(); | ||
897 | settc(cpu_data[cpu].tc_id); | ||
898 | /* Halt the targeted TC */ | ||
899 | write_tc_c0_tchalt(TCHALT_H); | ||
900 | mips_ihb(); | ||
901 | |||
902 | /* | ||
903 | * Inspect TCStatus - if IXMT is set, we have to queue | ||
904 | * a message. Otherwise, we set up the "interrupt" | ||
905 | * of the other TC | ||
906 | */ | ||
907 | tcstatus = read_tc_c0_tcstatus(); | ||
908 | |||
909 | if ((tcstatus & TCSTATUS_IXMT) != 0) { | ||
910 | /* | ||
911 | * If we're in the the irq-off version of the wait | ||
912 | * loop, we need to force exit from the wait and | ||
913 | * do a direct post of the IPI. | ||
914 | */ | ||
915 | if (cpu_wait == r4k_wait_irqoff) { | ||
916 | tcrestart = read_tc_c0_tcrestart(); | ||
917 | if (address_is_in_r4k_wait_irqoff(tcrestart)) { | ||
918 | write_tc_c0_tcrestart(__pastwait); | ||
919 | tcstatus &= ~TCSTATUS_IXMT; | ||
920 | write_tc_c0_tcstatus(tcstatus); | ||
921 | goto postdirect; | ||
922 | } | ||
923 | } | ||
924 | /* | ||
925 | * Otherwise we queue the message for the target TC | ||
926 | * to pick up when he does a local_irq_restore() | ||
927 | */ | ||
928 | write_tc_c0_tchalt(0); | ||
929 | UNLOCK_CORE_PRA(); | ||
930 | IPIQ[cpu].resched_flag |= set_resched_flag; | ||
931 | smtc_ipi_nq(&IPIQ[cpu], pipi); | ||
932 | } else { | ||
933 | postdirect: | ||
934 | post_direct_ipi(cpu, pipi); | ||
935 | write_tc_c0_tchalt(0); | ||
936 | UNLOCK_CORE_PRA(); | ||
937 | } | ||
938 | } | ||
939 | } | ||
940 | |||
941 | /* | ||
942 | * Send IPI message to Halted TC, TargTC/TargVPE already having been set | ||
943 | */ | ||
944 | static void post_direct_ipi(int cpu, struct smtc_ipi *pipi) | ||
945 | { | ||
946 | struct pt_regs *kstack; | ||
947 | unsigned long tcstatus; | ||
948 | unsigned long tcrestart; | ||
949 | extern u32 kernelsp[NR_CPUS]; | ||
950 | extern void __smtc_ipi_vector(void); | ||
951 | //printk("%s: on %d for %d\n", __func__, smp_processor_id(), cpu); | ||
952 | |||
953 | /* Extract Status, EPC from halted TC */ | ||
954 | tcstatus = read_tc_c0_tcstatus(); | ||
955 | tcrestart = read_tc_c0_tcrestart(); | ||
956 | /* If TCRestart indicates a WAIT instruction, advance the PC */ | ||
957 | if ((tcrestart & 0x80000000) | ||
958 | && ((*(unsigned int *)tcrestart & 0xfe00003f) == 0x42000020)) { | ||
959 | tcrestart += 4; | ||
960 | } | ||
961 | /* | ||
962 | * Save on TC's future kernel stack | ||
963 | * | ||
964 | * CU bit of Status is indicator that TC was | ||
965 | * already running on a kernel stack... | ||
966 | */ | ||
967 | if (tcstatus & ST0_CU0) { | ||
968 | /* Note that this "- 1" is pointer arithmetic */ | ||
969 | kstack = ((struct pt_regs *)read_tc_gpr_sp()) - 1; | ||
970 | } else { | ||
971 | kstack = ((struct pt_regs *)kernelsp[cpu]) - 1; | ||
972 | } | ||
973 | |||
974 | kstack->cp0_epc = (long)tcrestart; | ||
975 | /* Save TCStatus */ | ||
976 | kstack->cp0_tcstatus = tcstatus; | ||
977 | /* Pass token of operation to be performed kernel stack pad area */ | ||
978 | kstack->pad0[4] = (unsigned long)pipi; | ||
979 | /* Pass address of function to be called likewise */ | ||
980 | kstack->pad0[5] = (unsigned long)&ipi_decode; | ||
981 | /* Set interrupt exempt and kernel mode */ | ||
982 | tcstatus |= TCSTATUS_IXMT; | ||
983 | tcstatus &= ~TCSTATUS_TKSU; | ||
984 | write_tc_c0_tcstatus(tcstatus); | ||
985 | ehb(); | ||
986 | /* Set TC Restart address to be SMTC IPI vector */ | ||
987 | write_tc_c0_tcrestart(__smtc_ipi_vector); | ||
988 | } | ||
989 | |||
990 | static void ipi_resched_interrupt(void) | ||
991 | { | ||
992 | scheduler_ipi(); | ||
993 | } | ||
994 | |||
995 | static void ipi_call_interrupt(void) | ||
996 | { | ||
997 | /* Invoke generic function invocation code in smp.c */ | ||
998 | smp_call_function_interrupt(); | ||
999 | } | ||
1000 | |||
1001 | DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device); | ||
1002 | |||
1003 | static void __irq_entry smtc_clock_tick_interrupt(void) | ||
1004 | { | ||
1005 | unsigned int cpu = smp_processor_id(); | ||
1006 | struct clock_event_device *cd; | ||
1007 | int irq = MIPS_CPU_IRQ_BASE + 1; | ||
1008 | |||
1009 | irq_enter(); | ||
1010 | kstat_incr_irq_this_cpu(irq); | ||
1011 | cd = &per_cpu(mips_clockevent_device, cpu); | ||
1012 | cd->event_handler(cd); | ||
1013 | irq_exit(); | ||
1014 | } | ||
1015 | |||
1016 | void ipi_decode(struct smtc_ipi *pipi) | ||
1017 | { | ||
1018 | void *arg_copy = pipi->arg; | ||
1019 | int type_copy = pipi->type; | ||
1020 | |||
1021 | smtc_ipi_nq(&freeIPIq, pipi); | ||
1022 | |||
1023 | switch (type_copy) { | ||
1024 | case SMTC_CLOCK_TICK: | ||
1025 | smtc_clock_tick_interrupt(); | ||
1026 | break; | ||
1027 | |||
1028 | case LINUX_SMP_IPI: | ||
1029 | switch ((int)arg_copy) { | ||
1030 | case SMP_RESCHEDULE_YOURSELF: | ||
1031 | ipi_resched_interrupt(); | ||
1032 | break; | ||
1033 | case SMP_CALL_FUNCTION: | ||
1034 | ipi_call_interrupt(); | ||
1035 | break; | ||
1036 | default: | ||
1037 | printk("Impossible SMTC IPI Argument %p\n", arg_copy); | ||
1038 | break; | ||
1039 | } | ||
1040 | break; | ||
1041 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | ||
1042 | case IRQ_AFFINITY_IPI: | ||
1043 | /* | ||
1044 | * Accept a "forwarded" interrupt that was initially | ||
1045 | * taken by a TC who doesn't have affinity for the IRQ. | ||
1046 | */ | ||
1047 | do_IRQ_no_affinity((int)arg_copy); | ||
1048 | break; | ||
1049 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | ||
1050 | default: | ||
1051 | printk("Impossible SMTC IPI Type 0x%x\n", type_copy); | ||
1052 | break; | ||
1053 | } | ||
1054 | } | ||
1055 | |||
1056 | /* | ||
1057 | * Similar to smtc_ipi_replay(), but invoked from context restore, | ||
1058 | * so it reuses the current exception frame rather than set up a | ||
1059 | * new one with self_ipi. | ||
1060 | */ | ||
1061 | |||
1062 | void deferred_smtc_ipi(void) | ||
1063 | { | ||
1064 | int cpu = smp_processor_id(); | ||
1065 | |||
1066 | /* | ||
1067 | * Test is not atomic, but much faster than a dequeue, | ||
1068 | * and the vast majority of invocations will have a null queue. | ||
1069 | * If irq_disabled when this was called, then any IPIs queued | ||
1070 | * after we test last will be taken on the next irq_enable/restore. | ||
1071 | * If interrupts were enabled, then any IPIs added after the | ||
1072 | * last test will be taken directly. | ||
1073 | */ | ||
1074 | |||
1075 | while (IPIQ[cpu].head != NULL) { | ||
1076 | struct smtc_ipi_q *q = &IPIQ[cpu]; | ||
1077 | struct smtc_ipi *pipi; | ||
1078 | unsigned long flags; | ||
1079 | |||
1080 | /* | ||
1081 | * It may be possible we'll come in with interrupts | ||
1082 | * already enabled. | ||
1083 | */ | ||
1084 | local_irq_save(flags); | ||
1085 | spin_lock(&q->lock); | ||
1086 | pipi = __smtc_ipi_dq(q); | ||
1087 | spin_unlock(&q->lock); | ||
1088 | if (pipi != NULL) { | ||
1089 | if (pipi->type == LINUX_SMP_IPI && | ||
1090 | (int)pipi->arg == SMP_RESCHEDULE_YOURSELF) | ||
1091 | IPIQ[cpu].resched_flag = 0; | ||
1092 | ipi_decode(pipi); | ||
1093 | } | ||
1094 | /* | ||
1095 | * The use of the __raw_local restore isn't | ||
1096 | * as obviously necessary here as in smtc_ipi_replay(), | ||
1097 | * but it's more efficient, given that we're already | ||
1098 | * running down the IPI queue. | ||
1099 | */ | ||
1100 | __arch_local_irq_restore(flags); | ||
1101 | } | ||
1102 | } | ||
1103 | |||
1104 | /* | ||
1105 | * Cross-VPE interrupts in the SMTC prototype use "software interrupts" | ||
1106 | * set via cross-VPE MTTR manipulation of the Cause register. It would be | ||
1107 | * in some regards preferable to have external logic for "doorbell" hardware | ||
1108 | * interrupts. | ||
1109 | */ | ||
1110 | |||
1111 | static int cpu_ipi_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_IRQ; | ||
1112 | |||
1113 | static irqreturn_t ipi_interrupt(int irq, void *dev_idm) | ||
1114 | { | ||
1115 | int my_vpe = cpu_data[smp_processor_id()].vpe_id; | ||
1116 | int my_tc = cpu_data[smp_processor_id()].tc_id; | ||
1117 | int cpu; | ||
1118 | struct smtc_ipi *pipi; | ||
1119 | unsigned long tcstatus; | ||
1120 | int sent; | ||
1121 | unsigned long flags; | ||
1122 | unsigned int mtflags; | ||
1123 | unsigned int vpflags; | ||
1124 | |||
1125 | /* | ||
1126 | * So long as cross-VPE interrupts are done via | ||
1127 | * MFTR/MTTR read-modify-writes of Cause, we need | ||
1128 | * to stop other VPEs whenever the local VPE does | ||
1129 | * anything similar. | ||
1130 | */ | ||
1131 | local_irq_save(flags); | ||
1132 | vpflags = dvpe(); | ||
1133 | clear_c0_cause(0x100 << MIPS_CPU_IPI_IRQ); | ||
1134 | set_c0_status(0x100 << MIPS_CPU_IPI_IRQ); | ||
1135 | irq_enable_hazard(); | ||
1136 | evpe(vpflags); | ||
1137 | local_irq_restore(flags); | ||
1138 | |||
1139 | /* | ||
1140 | * Cross-VPE Interrupt handler: Try to directly deliver IPIs | ||
1141 | * queued for TCs on this VPE other than the current one. | ||
1142 | * Return-from-interrupt should cause us to drain the queue | ||
1143 | * for the current TC, so we ought not to have to do it explicitly here. | ||
1144 | */ | ||
1145 | |||
1146 | for_each_online_cpu(cpu) { | ||
1147 | if (cpu_data[cpu].vpe_id != my_vpe) | ||
1148 | continue; | ||
1149 | |||
1150 | pipi = smtc_ipi_dq(&IPIQ[cpu]); | ||
1151 | if (pipi != NULL) { | ||
1152 | if (cpu_data[cpu].tc_id != my_tc) { | ||
1153 | sent = 0; | ||
1154 | LOCK_MT_PRA(); | ||
1155 | settc(cpu_data[cpu].tc_id); | ||
1156 | write_tc_c0_tchalt(TCHALT_H); | ||
1157 | mips_ihb(); | ||
1158 | tcstatus = read_tc_c0_tcstatus(); | ||
1159 | if ((tcstatus & TCSTATUS_IXMT) == 0) { | ||
1160 | post_direct_ipi(cpu, pipi); | ||
1161 | sent = 1; | ||
1162 | } | ||
1163 | write_tc_c0_tchalt(0); | ||
1164 | UNLOCK_MT_PRA(); | ||
1165 | if (!sent) { | ||
1166 | smtc_ipi_req(&IPIQ[cpu], pipi); | ||
1167 | } | ||
1168 | } else { | ||
1169 | /* | ||
1170 | * ipi_decode() should be called | ||
1171 | * with interrupts off | ||
1172 | */ | ||
1173 | local_irq_save(flags); | ||
1174 | if (pipi->type == LINUX_SMP_IPI && | ||
1175 | (int)pipi->arg == SMP_RESCHEDULE_YOURSELF) | ||
1176 | IPIQ[cpu].resched_flag = 0; | ||
1177 | ipi_decode(pipi); | ||
1178 | local_irq_restore(flags); | ||
1179 | } | ||
1180 | } | ||
1181 | } | ||
1182 | |||
1183 | return IRQ_HANDLED; | ||
1184 | } | ||
1185 | |||
1186 | static void ipi_irq_dispatch(void) | ||
1187 | { | ||
1188 | do_IRQ(cpu_ipi_irq); | ||
1189 | } | ||
1190 | |||
1191 | static struct irqaction irq_ipi = { | ||
1192 | .handler = ipi_interrupt, | ||
1193 | .flags = IRQF_PERCPU, | ||
1194 | .name = "SMTC_IPI" | ||
1195 | }; | ||
1196 | |||
1197 | static void setup_cross_vpe_interrupts(unsigned int nvpe) | ||
1198 | { | ||
1199 | if (nvpe < 1) | ||
1200 | return; | ||
1201 | |||
1202 | if (!cpu_has_vint) | ||
1203 | panic("SMTC Kernel requires Vectored Interrupt support"); | ||
1204 | |||
1205 | set_vi_handler(MIPS_CPU_IPI_IRQ, ipi_irq_dispatch); | ||
1206 | |||
1207 | setup_irq_smtc(cpu_ipi_irq, &irq_ipi, (0x100 << MIPS_CPU_IPI_IRQ)); | ||
1208 | |||
1209 | irq_set_handler(cpu_ipi_irq, handle_percpu_irq); | ||
1210 | } | ||
1211 | |||
1212 | /* | ||
1213 | * SMTC-specific hacks invoked from elsewhere in the kernel. | ||
1214 | */ | ||
1215 | |||
1216 | /* | ||
1217 | * smtc_ipi_replay is called from raw_local_irq_restore | ||
1218 | */ | ||
1219 | |||
1220 | void smtc_ipi_replay(void) | ||
1221 | { | ||
1222 | unsigned int cpu = smp_processor_id(); | ||
1223 | |||
1224 | /* | ||
1225 | * To the extent that we've ever turned interrupts off, | ||
1226 | * we may have accumulated deferred IPIs. This is subtle. | ||
1227 | * we should be OK: If we pick up something and dispatch | ||
1228 | * it here, that's great. If we see nothing, but concurrent | ||
1229 | * with this operation, another TC sends us an IPI, IXMT | ||
1230 | * is clear, and we'll handle it as a real pseudo-interrupt | ||
1231 | * and not a pseudo-pseudo interrupt. The important thing | ||
1232 | * is to do the last check for queued message *after* the | ||
1233 | * re-enabling of interrupts. | ||
1234 | */ | ||
1235 | while (IPIQ[cpu].head != NULL) { | ||
1236 | struct smtc_ipi_q *q = &IPIQ[cpu]; | ||
1237 | struct smtc_ipi *pipi; | ||
1238 | unsigned long flags; | ||
1239 | |||
1240 | /* | ||
1241 | * It's just possible we'll come in with interrupts | ||
1242 | * already enabled. | ||
1243 | */ | ||
1244 | local_irq_save(flags); | ||
1245 | |||
1246 | spin_lock(&q->lock); | ||
1247 | pipi = __smtc_ipi_dq(q); | ||
1248 | spin_unlock(&q->lock); | ||
1249 | /* | ||
1250 | ** But use a raw restore here to avoid recursion. | ||
1251 | */ | ||
1252 | __arch_local_irq_restore(flags); | ||
1253 | |||
1254 | if (pipi) { | ||
1255 | self_ipi(pipi); | ||
1256 | smtc_cpu_stats[cpu].selfipis++; | ||
1257 | } | ||
1258 | } | ||
1259 | } | ||
1260 | |||
1261 | EXPORT_SYMBOL(smtc_ipi_replay); | ||
1262 | |||
1263 | void smtc_idle_loop_hook(void) | ||
1264 | { | ||
1265 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG | ||
1266 | int im; | ||
1267 | int flags; | ||
1268 | int mtflags; | ||
1269 | int bit; | ||
1270 | int vpe; | ||
1271 | int tc; | ||
1272 | int hook_ntcs; | ||
1273 | /* | ||
1274 | * printk within DMT-protected regions can deadlock, | ||
1275 | * so buffer diagnostic messages for later output. | ||
1276 | */ | ||
1277 | char *pdb_msg; | ||
1278 | char id_ho_db_msg[768]; /* worst-case use should be less than 700 */ | ||
1279 | |||
1280 | if (atomic_read(&idle_hook_initialized) == 0) { /* fast test */ | ||
1281 | if (atomic_add_return(1, &idle_hook_initialized) == 1) { | ||
1282 | int mvpconf0; | ||
1283 | /* Tedious stuff to just do once */ | ||
1284 | mvpconf0 = read_c0_mvpconf0(); | ||
1285 | hook_ntcs = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; | ||
1286 | if (hook_ntcs > NR_CPUS) | ||
1287 | hook_ntcs = NR_CPUS; | ||
1288 | for (tc = 0; tc < hook_ntcs; tc++) { | ||
1289 | tcnoprog[tc] = 0; | ||
1290 | clock_hang_reported[tc] = 0; | ||
1291 | } | ||
1292 | for (vpe = 0; vpe < 2; vpe++) | ||
1293 | for (im = 0; im < 8; im++) | ||
1294 | imstuckcount[vpe][im] = 0; | ||
1295 | printk("Idle loop test hook initialized for %d TCs\n", hook_ntcs); | ||
1296 | atomic_set(&idle_hook_initialized, 1000); | ||
1297 | } else { | ||
1298 | /* Someone else is initializing in parallel - let 'em finish */ | ||
1299 | while (atomic_read(&idle_hook_initialized) < 1000) | ||
1300 | ; | ||
1301 | } | ||
1302 | } | ||
1303 | |||
1304 | /* Have we stupidly left IXMT set somewhere? */ | ||
1305 | if (read_c0_tcstatus() & 0x400) { | ||
1306 | write_c0_tcstatus(read_c0_tcstatus() & ~0x400); | ||
1307 | ehb(); | ||
1308 | printk("Dangling IXMT in cpu_idle()\n"); | ||
1309 | } | ||
1310 | |||
1311 | /* Have we stupidly left an IM bit turned off? */ | ||
1312 | #define IM_LIMIT 2000 | ||
1313 | local_irq_save(flags); | ||
1314 | mtflags = dmt(); | ||
1315 | pdb_msg = &id_ho_db_msg[0]; | ||
1316 | im = read_c0_status(); | ||
1317 | vpe = current_cpu_data.vpe_id; | ||
1318 | for (bit = 0; bit < 8; bit++) { | ||
1319 | /* | ||
1320 | * In current prototype, I/O interrupts | ||
1321 | * are masked for VPE > 0 | ||
1322 | */ | ||
1323 | if (vpemask[vpe][bit]) { | ||
1324 | if (!(im & (0x100 << bit))) | ||
1325 | imstuckcount[vpe][bit]++; | ||
1326 | else | ||
1327 | imstuckcount[vpe][bit] = 0; | ||
1328 | if (imstuckcount[vpe][bit] > IM_LIMIT) { | ||
1329 | set_c0_status(0x100 << bit); | ||
1330 | ehb(); | ||
1331 | imstuckcount[vpe][bit] = 0; | ||
1332 | pdb_msg += sprintf(pdb_msg, | ||
1333 | "Dangling IM %d fixed for VPE %d\n", bit, | ||
1334 | vpe); | ||
1335 | } | ||
1336 | } | ||
1337 | } | ||
1338 | |||
1339 | emt(mtflags); | ||
1340 | local_irq_restore(flags); | ||
1341 | if (pdb_msg != &id_ho_db_msg[0]) | ||
1342 | printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg); | ||
1343 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ | ||
1344 | |||
1345 | smtc_ipi_replay(); | ||
1346 | } | ||
1347 | |||
1348 | void smtc_soft_dump(void) | ||
1349 | { | ||
1350 | int i; | ||
1351 | |||
1352 | printk("Counter Interrupts taken per CPU (TC)\n"); | ||
1353 | for (i=0; i < NR_CPUS; i++) { | ||
1354 | printk("%d: %ld\n", i, smtc_cpu_stats[i].timerints); | ||
1355 | } | ||
1356 | printk("Self-IPI invocations:\n"); | ||
1357 | for (i=0; i < NR_CPUS; i++) { | ||
1358 | printk("%d: %ld\n", i, smtc_cpu_stats[i].selfipis); | ||
1359 | } | ||
1360 | smtc_ipi_qdump(); | ||
1361 | printk("%d Recoveries of \"stolen\" FPU\n", | ||
1362 | atomic_read(&smtc_fpu_recoveries)); | ||
1363 | } | ||
1364 | |||
1365 | |||
1366 | /* | ||
1367 | * TLB management routines special to SMTC | ||
1368 | */ | ||
1369 | |||
1370 | void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) | ||
1371 | { | ||
1372 | unsigned long flags, mtflags, tcstat, prevhalt, asid; | ||
1373 | int tlb, i; | ||
1374 | |||
1375 | /* | ||
1376 | * It would be nice to be able to use a spinlock here, | ||
1377 | * but this is invoked from within TLB flush routines | ||
1378 | * that protect themselves with DVPE, so if a lock is | ||
1379 | * held by another TC, it'll never be freed. | ||
1380 | * | ||
1381 | * DVPE/DMT must not be done with interrupts enabled, | ||
1382 | * so even so most callers will already have disabled | ||
1383 | * them, let's be really careful... | ||
1384 | */ | ||
1385 | |||
1386 | local_irq_save(flags); | ||
1387 | if (smtc_status & SMTC_TLB_SHARED) { | ||
1388 | mtflags = dvpe(); | ||
1389 | tlb = 0; | ||
1390 | } else { | ||
1391 | mtflags = dmt(); | ||
1392 | tlb = cpu_data[cpu].vpe_id; | ||
1393 | } | ||
1394 | asid = asid_cache(cpu); | ||
1395 | |||
1396 | do { | ||
1397 | if (!((asid += ASID_INC) & ASID_MASK) ) { | ||
1398 | if (cpu_has_vtag_icache) | ||
1399 | flush_icache_all(); | ||
1400 | /* Traverse all online CPUs (hack requires contiguous range) */ | ||
1401 | for_each_online_cpu(i) { | ||
1402 | /* | ||
1403 | * We don't need to worry about our own CPU, nor those of | ||
1404 | * CPUs who don't share our TLB. | ||
1405 | */ | ||
1406 | if ((i != smp_processor_id()) && | ||
1407 | ((smtc_status & SMTC_TLB_SHARED) || | ||
1408 | (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id))) { | ||
1409 | settc(cpu_data[i].tc_id); | ||
1410 | prevhalt = read_tc_c0_tchalt() & TCHALT_H; | ||
1411 | if (!prevhalt) { | ||
1412 | write_tc_c0_tchalt(TCHALT_H); | ||
1413 | mips_ihb(); | ||
1414 | } | ||
1415 | tcstat = read_tc_c0_tcstatus(); | ||
1416 | smtc_live_asid[tlb][(tcstat & ASID_MASK)] |= (asiduse)(0x1 << i); | ||
1417 | if (!prevhalt) | ||
1418 | write_tc_c0_tchalt(0); | ||
1419 | } | ||
1420 | } | ||
1421 | if (!asid) /* fix version if needed */ | ||
1422 | asid = ASID_FIRST_VERSION; | ||
1423 | local_flush_tlb_all(); /* start new asid cycle */ | ||
1424 | } | ||
1425 | } while (smtc_live_asid[tlb][(asid & ASID_MASK)]); | ||
1426 | |||
1427 | /* | ||
1428 | * SMTC shares the TLB within VPEs and possibly across all VPEs. | ||
1429 | */ | ||
1430 | for_each_online_cpu(i) { | ||
1431 | if ((smtc_status & SMTC_TLB_SHARED) || | ||
1432 | (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id)) | ||
1433 | cpu_context(i, mm) = asid_cache(i) = asid; | ||
1434 | } | ||
1435 | |||
1436 | if (smtc_status & SMTC_TLB_SHARED) | ||
1437 | evpe(mtflags); | ||
1438 | else | ||
1439 | emt(mtflags); | ||
1440 | local_irq_restore(flags); | ||
1441 | } | ||
1442 | |||
1443 | /* | ||
1444 | * Invoked from macros defined in mmu_context.h | ||
1445 | * which must already have disabled interrupts | ||
1446 | * and done a DVPE or DMT as appropriate. | ||
1447 | */ | ||
1448 | |||
1449 | void smtc_flush_tlb_asid(unsigned long asid) | ||
1450 | { | ||
1451 | int entry; | ||
1452 | unsigned long ehi; | ||
1453 | |||
1454 | entry = read_c0_wired(); | ||
1455 | |||
1456 | /* Traverse all non-wired entries */ | ||
1457 | while (entry < current_cpu_data.tlbsize) { | ||
1458 | write_c0_index(entry); | ||
1459 | ehb(); | ||
1460 | tlb_read(); | ||
1461 | ehb(); | ||
1462 | ehi = read_c0_entryhi(); | ||
1463 | if ((ehi & ASID_MASK) == asid) { | ||
1464 | /* | ||
1465 | * Invalidate only entries with specified ASID, | ||
1466 | * makiing sure all entries differ. | ||
1467 | */ | ||
1468 | write_c0_entryhi(CKSEG0 + (entry << (PAGE_SHIFT + 1))); | ||
1469 | write_c0_entrylo0(0); | ||
1470 | write_c0_entrylo1(0); | ||
1471 | mtc0_tlbw_hazard(); | ||
1472 | tlb_write_indexed(); | ||
1473 | } | ||
1474 | entry++; | ||
1475 | } | ||
1476 | write_c0_index(PARKED_INDEX); | ||
1477 | tlbw_use_hazard(); | ||
1478 | } | ||
1479 | |||
1480 | /* | ||
1481 | * Support for single-threading cache flush operations. | ||
1482 | */ | ||
1483 | |||
1484 | static int halt_state_save[NR_CPUS]; | ||
1485 | |||
1486 | /* | ||
1487 | * To really, really be sure that nothing is being done | ||
1488 | * by other TCs, halt them all. This code assumes that | ||
1489 | * a DVPE has already been done, so while their Halted | ||
1490 | * state is theoretically architecturally unstable, in | ||
1491 | * practice, it's not going to change while we're looking | ||
1492 | * at it. | ||
1493 | */ | ||
1494 | |||
1495 | void smtc_cflush_lockdown(void) | ||
1496 | { | ||
1497 | int cpu; | ||
1498 | |||
1499 | for_each_online_cpu(cpu) { | ||
1500 | if (cpu != smp_processor_id()) { | ||
1501 | settc(cpu_data[cpu].tc_id); | ||
1502 | halt_state_save[cpu] = read_tc_c0_tchalt(); | ||
1503 | write_tc_c0_tchalt(TCHALT_H); | ||
1504 | } | ||
1505 | } | ||
1506 | mips_ihb(); | ||
1507 | } | ||
1508 | |||
1509 | /* It would be cheating to change the cpu_online states during a flush! */ | ||
1510 | |||
1511 | void smtc_cflush_release(void) | ||
1512 | { | ||
1513 | int cpu; | ||
1514 | |||
1515 | /* | ||
1516 | * Start with a hazard barrier to ensure | ||
1517 | * that all CACHE ops have played through. | ||
1518 | */ | ||
1519 | mips_ihb(); | ||
1520 | |||
1521 | for_each_online_cpu(cpu) { | ||
1522 | if (cpu != smp_processor_id()) { | ||
1523 | settc(cpu_data[cpu].tc_id); | ||
1524 | write_tc_c0_tchalt(halt_state_save[cpu]); | ||
1525 | } | ||
1526 | } | ||
1527 | mips_ihb(); | ||
1528 | } | ||
diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c index c24ad5f4b324..2242bdd4370e 100644 --- a/arch/mips/kernel/sync-r4k.c +++ b/arch/mips/kernel/sync-r4k.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * not have done anything significant (but they may have had interrupts | 6 | * not have done anything significant (but they may have had interrupts |
7 | * enabled briefly - prom_smp_finish() should not be responsible for enabling | 7 | * enabled briefly - prom_smp_finish() should not be responsible for enabling |
8 | * interrupts...) | 8 | * interrupts...) |
9 | * | ||
10 | * FIXME: broken for SMTC | ||
11 | */ | 9 | */ |
12 | 10 | ||
13 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
@@ -33,14 +31,6 @@ void synchronise_count_master(int cpu) | |||
33 | unsigned long flags; | 31 | unsigned long flags; |
34 | unsigned int initcount; | 32 | unsigned int initcount; |
35 | 33 | ||
36 | #ifdef CONFIG_MIPS_MT_SMTC | ||
37 | /* | ||
38 | * SMTC needs to synchronise per VPE, not per CPU | ||
39 | * ignore for now | ||
40 | */ | ||
41 | return; | ||
42 | #endif | ||
43 | |||
44 | printk(KERN_INFO "Synchronize counters for CPU %u: ", cpu); | 34 | printk(KERN_INFO "Synchronize counters for CPU %u: ", cpu); |
45 | 35 | ||
46 | local_irq_save(flags); | 36 | local_irq_save(flags); |
@@ -110,14 +100,6 @@ void synchronise_count_slave(int cpu) | |||
110 | int i; | 100 | int i; |
111 | unsigned int initcount; | 101 | unsigned int initcount; |
112 | 102 | ||
113 | #ifdef CONFIG_MIPS_MT_SMTC | ||
114 | /* | ||
115 | * SMTC needs to synchronise per VPE, not per CPU | ||
116 | * ignore for now | ||
117 | */ | ||
118 | return; | ||
119 | #endif | ||
120 | |||
121 | /* | 103 | /* |
122 | * Not every cpu is online at the time this gets called, | 104 | * Not every cpu is online at the time this gets called, |
123 | * so we first wait for the master to say everyone is ready | 105 | * so we first wait for the master to say everyone is ready |
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index dcb8e5d3bb8a..8d0170969e22 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <asm/cpu-features.h> | 26 | #include <asm/cpu-features.h> |
27 | #include <asm/cpu-type.h> | 27 | #include <asm/cpu-type.h> |
28 | #include <asm/div64.h> | 28 | #include <asm/div64.h> |
29 | #include <asm/smtc_ipi.h> | ||
30 | #include <asm/time.h> | 29 | #include <asm/time.h> |
31 | 30 | ||
32 | /* | 31 | /* |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 8119ac2fdfc9..51706d6dd5b0 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/bug.h> | 15 | #include <linux/bug.h> |
16 | #include <linux/compiler.h> | 16 | #include <linux/compiler.h> |
17 | #include <linux/context_tracking.h> | 17 | #include <linux/context_tracking.h> |
18 | #include <linux/cpu_pm.h> | ||
18 | #include <linux/kexec.h> | 19 | #include <linux/kexec.h> |
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
@@ -370,9 +371,6 @@ void __noreturn die(const char *str, struct pt_regs *regs) | |||
370 | { | 371 | { |
371 | static int die_counter; | 372 | static int die_counter; |
372 | int sig = SIGSEGV; | 373 | int sig = SIGSEGV; |
373 | #ifdef CONFIG_MIPS_MT_SMTC | ||
374 | unsigned long dvpret; | ||
375 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
376 | 374 | ||
377 | oops_enter(); | 375 | oops_enter(); |
378 | 376 | ||
@@ -382,13 +380,7 @@ void __noreturn die(const char *str, struct pt_regs *regs) | |||
382 | 380 | ||
383 | console_verbose(); | 381 | console_verbose(); |
384 | raw_spin_lock_irq(&die_lock); | 382 | raw_spin_lock_irq(&die_lock); |
385 | #ifdef CONFIG_MIPS_MT_SMTC | ||
386 | dvpret = dvpe(); | ||
387 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
388 | bust_spinlocks(1); | 383 | bust_spinlocks(1); |
389 | #ifdef CONFIG_MIPS_MT_SMTC | ||
390 | mips_mt_regdump(dvpret); | ||
391 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
392 | 384 | ||
393 | printk("%s[#%d]:\n", str, ++die_counter); | 385 | printk("%s[#%d]:\n", str, ++die_counter); |
394 | show_registers(regs); | 386 | show_registers(regs); |
@@ -712,10 +704,12 @@ int process_fpemu_return(int sig, void __user *fault_addr) | |||
712 | si.si_addr = fault_addr; | 704 | si.si_addr = fault_addr; |
713 | si.si_signo = sig; | 705 | si.si_signo = sig; |
714 | if (sig == SIGSEGV) { | 706 | if (sig == SIGSEGV) { |
707 | down_read(¤t->mm->mmap_sem); | ||
715 | if (find_vma(current->mm, (unsigned long)fault_addr)) | 708 | if (find_vma(current->mm, (unsigned long)fault_addr)) |
716 | si.si_code = SEGV_ACCERR; | 709 | si.si_code = SEGV_ACCERR; |
717 | else | 710 | else |
718 | si.si_code = SEGV_MAPERR; | 711 | si.si_code = SEGV_MAPERR; |
712 | up_read(¤t->mm->mmap_sem); | ||
719 | } else { | 713 | } else { |
720 | si.si_code = BUS_ADRERR; | 714 | si.si_code = BUS_ADRERR; |
721 | } | 715 | } |
@@ -1759,19 +1753,6 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
1759 | extern char rollback_except_vec_vi; | 1753 | extern char rollback_except_vec_vi; |
1760 | char *vec_start = using_rollback_handler() ? | 1754 | char *vec_start = using_rollback_handler() ? |
1761 | &rollback_except_vec_vi : &except_vec_vi; | 1755 | &rollback_except_vec_vi : &except_vec_vi; |
1762 | #ifdef CONFIG_MIPS_MT_SMTC | ||
1763 | /* | ||
1764 | * We need to provide the SMTC vectored interrupt handler | ||
1765 | * not only with the address of the handler, but with the | ||
1766 | * Status.IM bit to be masked before going there. | ||
1767 | */ | ||
1768 | extern char except_vec_vi_mori; | ||
1769 | #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN) | ||
1770 | const int mori_offset = &except_vec_vi_mori - vec_start + 2; | ||
1771 | #else | ||
1772 | const int mori_offset = &except_vec_vi_mori - vec_start; | ||
1773 | #endif | ||
1774 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
1775 | #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN) | 1756 | #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN) |
1776 | const int lui_offset = &except_vec_vi_lui - vec_start + 2; | 1757 | const int lui_offset = &except_vec_vi_lui - vec_start + 2; |
1777 | const int ori_offset = &except_vec_vi_ori - vec_start + 2; | 1758 | const int ori_offset = &except_vec_vi_ori - vec_start + 2; |
@@ -1795,12 +1776,6 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
1795 | #else | 1776 | #else |
1796 | handler_len); | 1777 | handler_len); |
1797 | #endif | 1778 | #endif |
1798 | #ifdef CONFIG_MIPS_MT_SMTC | ||
1799 | BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ | ||
1800 | |||
1801 | h = (u16 *)(b + mori_offset); | ||
1802 | *h = (0x100 << n); | ||
1803 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
1804 | h = (u16 *)(b + lui_offset); | 1779 | h = (u16 *)(b + lui_offset); |
1805 | *h = (handler >> 16) & 0xffff; | 1780 | *h = (handler >> 16) & 0xffff; |
1806 | h = (u16 *)(b + ori_offset); | 1781 | h = (u16 *)(b + ori_offset); |
@@ -1865,32 +1840,16 @@ static int __init ulri_disable(char *s) | |||
1865 | } | 1840 | } |
1866 | __setup("noulri", ulri_disable); | 1841 | __setup("noulri", ulri_disable); |
1867 | 1842 | ||
1868 | void per_cpu_trap_init(bool is_boot_cpu) | 1843 | /* configure STATUS register */ |
1844 | static void configure_status(void) | ||
1869 | { | 1845 | { |
1870 | unsigned int cpu = smp_processor_id(); | ||
1871 | unsigned int status_set = ST0_CU0; | ||
1872 | unsigned int hwrena = cpu_hwrena_impl_bits; | ||
1873 | #ifdef CONFIG_MIPS_MT_SMTC | ||
1874 | int secondaryTC = 0; | ||
1875 | int bootTC = (cpu == 0); | ||
1876 | |||
1877 | /* | ||
1878 | * Only do per_cpu_trap_init() for first TC of Each VPE. | ||
1879 | * Note that this hack assumes that the SMTC init code | ||
1880 | * assigns TCs consecutively and in ascending order. | ||
1881 | */ | ||
1882 | |||
1883 | if (((read_c0_tcbind() & TCBIND_CURTC) != 0) && | ||
1884 | ((read_c0_tcbind() & TCBIND_CURVPE) == cpu_data[cpu - 1].vpe_id)) | ||
1885 | secondaryTC = 1; | ||
1886 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
1887 | |||
1888 | /* | 1846 | /* |
1889 | * Disable coprocessors and select 32-bit or 64-bit addressing | 1847 | * Disable coprocessors and select 32-bit or 64-bit addressing |
1890 | * and the 16/32 or 32/32 FPR register model. Reset the BEV | 1848 | * and the 16/32 or 32/32 FPR register model. Reset the BEV |
1891 | * flag that some firmware may have left set and the TS bit (for | 1849 | * flag that some firmware may have left set and the TS bit (for |
1892 | * IP27). Set XX for ISA IV code to work. | 1850 | * IP27). Set XX for ISA IV code to work. |
1893 | */ | 1851 | */ |
1852 | unsigned int status_set = ST0_CU0; | ||
1894 | #ifdef CONFIG_64BIT | 1853 | #ifdef CONFIG_64BIT |
1895 | status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX; | 1854 | status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX; |
1896 | #endif | 1855 | #endif |
@@ -1901,6 +1860,12 @@ void per_cpu_trap_init(bool is_boot_cpu) | |||
1901 | 1860 | ||
1902 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, | 1861 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, |
1903 | status_set); | 1862 | status_set); |
1863 | } | ||
1864 | |||
1865 | /* configure HWRENA register */ | ||
1866 | static void configure_hwrena(void) | ||
1867 | { | ||
1868 | unsigned int hwrena = cpu_hwrena_impl_bits; | ||
1904 | 1869 | ||
1905 | if (cpu_has_mips_r2) | 1870 | if (cpu_has_mips_r2) |
1906 | hwrena |= 0x0000000f; | 1871 | hwrena |= 0x0000000f; |
@@ -1910,11 +1875,10 @@ void per_cpu_trap_init(bool is_boot_cpu) | |||
1910 | 1875 | ||
1911 | if (hwrena) | 1876 | if (hwrena) |
1912 | write_c0_hwrena(hwrena); | 1877 | write_c0_hwrena(hwrena); |
1878 | } | ||
1913 | 1879 | ||
1914 | #ifdef CONFIG_MIPS_MT_SMTC | 1880 | static void configure_exception_vector(void) |
1915 | if (!secondaryTC) { | 1881 | { |
1916 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
1917 | |||
1918 | if (cpu_has_veic || cpu_has_vint) { | 1882 | if (cpu_has_veic || cpu_has_vint) { |
1919 | unsigned long sr = set_c0_status(ST0_BEV); | 1883 | unsigned long sr = set_c0_status(ST0_BEV); |
1920 | write_c0_ebase(ebase); | 1884 | write_c0_ebase(ebase); |
@@ -1930,6 +1894,16 @@ void per_cpu_trap_init(bool is_boot_cpu) | |||
1930 | } else | 1894 | } else |
1931 | set_c0_cause(CAUSEF_IV); | 1895 | set_c0_cause(CAUSEF_IV); |
1932 | } | 1896 | } |
1897 | } | ||
1898 | |||
1899 | void per_cpu_trap_init(bool is_boot_cpu) | ||
1900 | { | ||
1901 | unsigned int cpu = smp_processor_id(); | ||
1902 | |||
1903 | configure_status(); | ||
1904 | configure_hwrena(); | ||
1905 | |||
1906 | configure_exception_vector(); | ||
1933 | 1907 | ||
1934 | /* | 1908 | /* |
1935 | * Before R2 both interrupt numbers were fixed to 7, so on R2 only: | 1909 | * Before R2 both interrupt numbers were fixed to 7, so on R2 only: |
@@ -1949,10 +1923,6 @@ void per_cpu_trap_init(bool is_boot_cpu) | |||
1949 | cp0_perfcount_irq = -1; | 1923 | cp0_perfcount_irq = -1; |
1950 | } | 1924 | } |
1951 | 1925 | ||
1952 | #ifdef CONFIG_MIPS_MT_SMTC | ||
1953 | } | ||
1954 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
1955 | |||
1956 | if (!cpu_data[cpu].asid_cache) | 1926 | if (!cpu_data[cpu].asid_cache) |
1957 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; | 1927 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; |
1958 | 1928 | ||
@@ -1961,23 +1931,10 @@ void per_cpu_trap_init(bool is_boot_cpu) | |||
1961 | BUG_ON(current->mm); | 1931 | BUG_ON(current->mm); |
1962 | enter_lazy_tlb(&init_mm, current); | 1932 | enter_lazy_tlb(&init_mm, current); |
1963 | 1933 | ||
1964 | #ifdef CONFIG_MIPS_MT_SMTC | ||
1965 | if (bootTC) { | ||
1966 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
1967 | /* Boot CPU's cache setup in setup_arch(). */ | 1934 | /* Boot CPU's cache setup in setup_arch(). */ |
1968 | if (!is_boot_cpu) | 1935 | if (!is_boot_cpu) |
1969 | cpu_cache_init(); | 1936 | cpu_cache_init(); |
1970 | tlb_init(); | 1937 | tlb_init(); |
1971 | #ifdef CONFIG_MIPS_MT_SMTC | ||
1972 | } else if (!secondaryTC) { | ||
1973 | /* | ||
1974 | * First TC in non-boot VPE must do subset of tlb_init() | ||
1975 | * for MMU countrol registers. | ||
1976 | */ | ||
1977 | write_c0_pagemask(PM_DEFAULT_MASK); | ||
1978 | write_c0_wired(0); | ||
1979 | } | ||
1980 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
1981 | TLBMISS_HANDLER_SETUP(); | 1938 | TLBMISS_HANDLER_SETUP(); |
1982 | } | 1939 | } |
1983 | 1940 | ||
@@ -2185,3 +2142,32 @@ void __init trap_init(void) | |||
2185 | 2142 | ||
2186 | cu2_notifier(default_cu2_call, 0x80000000); /* Run last */ | 2143 | cu2_notifier(default_cu2_call, 0x80000000); /* Run last */ |
2187 | } | 2144 | } |
2145 | |||
2146 | static int trap_pm_notifier(struct notifier_block *self, unsigned long cmd, | ||
2147 | void *v) | ||
2148 | { | ||
2149 | switch (cmd) { | ||
2150 | case CPU_PM_ENTER_FAILED: | ||
2151 | case CPU_PM_EXIT: | ||
2152 | configure_status(); | ||
2153 | configure_hwrena(); | ||
2154 | configure_exception_vector(); | ||
2155 | |||
2156 | /* Restore register with CPU number for TLB handlers */ | ||
2157 | TLBMISS_HANDLER_RESTORE(); | ||
2158 | |||
2159 | break; | ||
2160 | } | ||
2161 | |||
2162 | return NOTIFY_OK; | ||
2163 | } | ||
2164 | |||
2165 | static struct notifier_block trap_pm_notifier_block = { | ||
2166 | .notifier_call = trap_pm_notifier, | ||
2167 | }; | ||
2168 | |||
2169 | static int __init trap_pm_init(void) | ||
2170 | { | ||
2171 | return cpu_pm_register_notifier(&trap_pm_notifier_block); | ||
2172 | } | ||
2173 | arch_initcall(trap_pm_init); | ||
diff --git a/arch/mips/kernel/vpe-mt.c b/arch/mips/kernel/vpe-mt.c index 949ae0e17018..2e003b11a098 100644 --- a/arch/mips/kernel/vpe-mt.c +++ b/arch/mips/kernel/vpe-mt.c | |||
@@ -127,9 +127,8 @@ int vpe_run(struct vpe *v) | |||
127 | clear_c0_mvpcontrol(MVPCONTROL_VPC); | 127 | clear_c0_mvpcontrol(MVPCONTROL_VPC); |
128 | 128 | ||
129 | /* | 129 | /* |
130 | * SMTC/SMVP kernels manage VPE enable independently, | 130 | * SMVP kernels manage VPE enable independently, but uniprocessor |
131 | * but uniprocessor kernels need to turn it on, even | 131 | * kernels need to turn it on, even if that wasn't the pre-dvpe() state. |
132 | * if that wasn't the pre-dvpe() state. | ||
133 | */ | 132 | */ |
134 | #ifdef CONFIG_SMP | 133 | #ifdef CONFIG_SMP |
135 | evpe(vpeflags); | 134 | evpe(vpeflags); |
@@ -454,12 +453,11 @@ int __init vpe_module_init(void) | |||
454 | 453 | ||
455 | settc(tc); | 454 | settc(tc); |
456 | 455 | ||
457 | /* Any TC that is bound to VPE0 gets left as is - in | 456 | /* |
458 | * case we are running SMTC on VPE0. A TC that is bound | 457 | * A TC that is bound to any other VPE gets bound to |
459 | * to any other VPE gets bound to VPE0, ideally I'd like | 458 | * VPE0, ideally I'd like to make it homeless but it |
460 | * to make it homeless but it doesn't appear to let me | 459 | * doesn't appear to let me bind a TC to a non-existent |
461 | * bind a TC to a non-existent VPE. Which is perfectly | 460 | * VPE. Which is perfectly reasonable. |
462 | * reasonable. | ||
463 | * | 461 | * |
464 | * The (un)bound state is visible to an EJTAG probe so | 462 | * The (un)bound state is visible to an EJTAG probe so |
465 | * may notify GDB... | 463 | * may notify GDB... |
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index 85685e1cdb89..030568a70ac4 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c | |||
@@ -61,7 +61,7 @@ | |||
61 | /* we have a cascade of 8 irqs */ | 61 | /* we have a cascade of 8 irqs */ |
62 | #define MIPS_CPU_IRQ_CASCADE 8 | 62 | #define MIPS_CPU_IRQ_CASCADE 8 |
63 | 63 | ||
64 | #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) | 64 | #ifdef CONFIG_MIPS_MT_SMP |
65 | int gic_present; | 65 | int gic_present; |
66 | #endif | 66 | #endif |
67 | 67 | ||
@@ -440,7 +440,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) | |||
440 | arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ, &irq_call); | 440 | arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ, &irq_call); |
441 | #endif | 441 | #endif |
442 | 442 | ||
443 | #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) | 443 | #ifndef CONFIG_MIPS_MT_SMP |
444 | set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | | 444 | set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | |
445 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); | 445 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); |
446 | #else | 446 | #else |
diff --git a/arch/mips/lib/delay.c b/arch/mips/lib/delay.c index 705cfb7c1a74..21d27c6819a2 100644 --- a/arch/mips/lib/delay.c +++ b/arch/mips/lib/delay.c | |||
@@ -11,7 +11,9 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/param.h> | 12 | #include <linux/param.h> |
13 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
14 | #include <linux/stringify.h> | ||
14 | 15 | ||
16 | #include <asm/asm.h> | ||
15 | #include <asm/compiler.h> | 17 | #include <asm/compiler.h> |
16 | #include <asm/war.h> | 18 | #include <asm/war.h> |
17 | 19 | ||
@@ -27,11 +29,7 @@ void __delay(unsigned long loops) | |||
27 | " .set noreorder \n" | 29 | " .set noreorder \n" |
28 | " .align 3 \n" | 30 | " .align 3 \n" |
29 | "1: bnez %0, 1b \n" | 31 | "1: bnez %0, 1b \n" |
30 | #if BITS_PER_LONG == 32 | 32 | " " __stringify(LONG_SUBU) " %0, %1 \n" |
31 | " subu %0, %1 \n" | ||
32 | #else | ||
33 | " dsubu %0, %1 \n" | ||
34 | #endif | ||
35 | " .set reorder \n" | 33 | " .set reorder \n" |
36 | : "=r" (loops) | 34 | : "=r" (loops) |
37 | : GCC_DADDI_IMM_ASM() (1), "0" (loops)); | 35 | : GCC_DADDI_IMM_ASM() (1), "0" (loops)); |
diff --git a/arch/mips/lib/mips-atomic.c b/arch/mips/lib/mips-atomic.c index 6807f7172eaf..57bcdaf1f1c8 100644 --- a/arch/mips/lib/mips-atomic.c +++ b/arch/mips/lib/mips-atomic.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/export.h> | 15 | #include <linux/export.h> |
16 | #include <linux/stringify.h> | 16 | #include <linux/stringify.h> |
17 | 17 | ||
18 | #if !defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT_SMTC) | 18 | #ifndef CONFIG_CPU_MIPSR2 |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * For cli() we have to insert nops to make sure that the new value | 21 | * For cli() we have to insert nops to make sure that the new value |
@@ -42,12 +42,7 @@ notrace void arch_local_irq_disable(void) | |||
42 | __asm__ __volatile__( | 42 | __asm__ __volatile__( |
43 | " .set push \n" | 43 | " .set push \n" |
44 | " .set noat \n" | 44 | " .set noat \n" |
45 | #ifdef CONFIG_MIPS_MT_SMTC | 45 | #if defined(CONFIG_CPU_MIPSR2) |
46 | " mfc0 $1, $2, 1 \n" | ||
47 | " ori $1, 0x400 \n" | ||
48 | " .set noreorder \n" | ||
49 | " mtc0 $1, $2, 1 \n" | ||
50 | #elif defined(CONFIG_CPU_MIPSR2) | ||
51 | /* see irqflags.h for inline function */ | 46 | /* see irqflags.h for inline function */ |
52 | #else | 47 | #else |
53 | " mfc0 $1,$12 \n" | 48 | " mfc0 $1,$12 \n" |
@@ -77,13 +72,7 @@ notrace unsigned long arch_local_irq_save(void) | |||
77 | " .set push \n" | 72 | " .set push \n" |
78 | " .set reorder \n" | 73 | " .set reorder \n" |
79 | " .set noat \n" | 74 | " .set noat \n" |
80 | #ifdef CONFIG_MIPS_MT_SMTC | 75 | #if defined(CONFIG_CPU_MIPSR2) |
81 | " mfc0 %[flags], $2, 1 \n" | ||
82 | " ori $1, %[flags], 0x400 \n" | ||
83 | " .set noreorder \n" | ||
84 | " mtc0 $1, $2, 1 \n" | ||
85 | " andi %[flags], %[flags], 0x400 \n" | ||
86 | #elif defined(CONFIG_CPU_MIPSR2) | ||
87 | /* see irqflags.h for inline function */ | 76 | /* see irqflags.h for inline function */ |
88 | #else | 77 | #else |
89 | " mfc0 %[flags], $12 \n" | 78 | " mfc0 %[flags], $12 \n" |
@@ -108,29 +97,13 @@ notrace void arch_local_irq_restore(unsigned long flags) | |||
108 | { | 97 | { |
109 | unsigned long __tmp1; | 98 | unsigned long __tmp1; |
110 | 99 | ||
111 | #ifdef CONFIG_MIPS_MT_SMTC | ||
112 | /* | ||
113 | * SMTC kernel needs to do a software replay of queued | ||
114 | * IPIs, at the cost of branch and call overhead on each | ||
115 | * local_irq_restore() | ||
116 | */ | ||
117 | if (unlikely(!(flags & 0x0400))) | ||
118 | smtc_ipi_replay(); | ||
119 | #endif | ||
120 | preempt_disable(); | 100 | preempt_disable(); |
121 | 101 | ||
122 | __asm__ __volatile__( | 102 | __asm__ __volatile__( |
123 | " .set push \n" | 103 | " .set push \n" |
124 | " .set noreorder \n" | 104 | " .set noreorder \n" |
125 | " .set noat \n" | 105 | " .set noat \n" |
126 | #ifdef CONFIG_MIPS_MT_SMTC | 106 | #if defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) |
127 | " mfc0 $1, $2, 1 \n" | ||
128 | " andi %[flags], 0x400 \n" | ||
129 | " ori $1, 0x400 \n" | ||
130 | " xori $1, 0x400 \n" | ||
131 | " or %[flags], $1 \n" | ||
132 | " mtc0 %[flags], $2, 1 \n" | ||
133 | #elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) | ||
134 | /* see irqflags.h for inline function */ | 107 | /* see irqflags.h for inline function */ |
135 | #elif defined(CONFIG_CPU_MIPSR2) | 108 | #elif defined(CONFIG_CPU_MIPSR2) |
136 | /* see irqflags.h for inline function */ | 109 | /* see irqflags.h for inline function */ |
@@ -163,14 +136,7 @@ notrace void __arch_local_irq_restore(unsigned long flags) | |||
163 | " .set push \n" | 136 | " .set push \n" |
164 | " .set noreorder \n" | 137 | " .set noreorder \n" |
165 | " .set noat \n" | 138 | " .set noat \n" |
166 | #ifdef CONFIG_MIPS_MT_SMTC | 139 | #if defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) |
167 | " mfc0 $1, $2, 1 \n" | ||
168 | " andi %[flags], 0x400 \n" | ||
169 | " ori $1, 0x400 \n" | ||
170 | " xori $1, 0x400 \n" | ||
171 | " or %[flags], $1 \n" | ||
172 | " mtc0 %[flags], $2, 1 \n" | ||
173 | #elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) | ||
174 | /* see irqflags.h for inline function */ | 140 | /* see irqflags.h for inline function */ |
175 | #elif defined(CONFIG_CPU_MIPSR2) | 141 | #elif defined(CONFIG_CPU_MIPSR2) |
176 | /* see irqflags.h for inline function */ | 142 | /* see irqflags.h for inline function */ |
@@ -192,4 +158,4 @@ notrace void __arch_local_irq_restore(unsigned long flags) | |||
192 | } | 158 | } |
193 | EXPORT_SYMBOL(__arch_local_irq_restore); | 159 | EXPORT_SYMBOL(__arch_local_irq_restore); |
194 | 160 | ||
195 | #endif /* !defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT_SMTC) */ | 161 | #endif /* !CONFIG_CPU_MIPSR2 */ |
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig index 603d79a95f47..e6a86ccc4421 100644 --- a/arch/mips/loongson/Kconfig +++ b/arch/mips/loongson/Kconfig | |||
@@ -95,10 +95,11 @@ config CS5536 | |||
95 | 95 | ||
96 | config CS5536_MFGPT | 96 | config CS5536_MFGPT |
97 | bool "CS5536 MFGPT Timer" | 97 | bool "CS5536 MFGPT Timer" |
98 | depends on CS5536 | 98 | depends on CS5536 && !HIGH_RES_TIMERS |
99 | select MIPS_EXTERNAL_TIMER | 99 | select MIPS_EXTERNAL_TIMER |
100 | help | 100 | help |
101 | This option enables the mfgpt0 timer of AMD CS5536. | 101 | This option enables the mfgpt0 timer of AMD CS5536. With this timer |
102 | switched on you can not use high resolution timers. | ||
102 | 103 | ||
103 | If you want to enable the Loongson2 CPUFreq Driver, Please enable | 104 | If you want to enable the Loongson2 CPUFreq Driver, Please enable |
104 | this option at first, otherwise, You will get wrong system time. | 105 | this option at first, otherwise, You will get wrong system time. |
diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c index c665fe16d4c9..1e8894020ea5 100644 --- a/arch/mips/loongson/loongson-3/smp.c +++ b/arch/mips/loongson/loongson-3/smp.c | |||
@@ -279,13 +279,6 @@ static void loongson3_boot_secondary(int cpu, struct task_struct *idle) | |||
279 | loongson3_ipi_write64(startargs[0], (void *)(ipi_mailbox_buf[cpu]+0x0)); | 279 | loongson3_ipi_write64(startargs[0], (void *)(ipi_mailbox_buf[cpu]+0x0)); |
280 | } | 280 | } |
281 | 281 | ||
282 | /* | ||
283 | * Final cleanup after all secondaries booted | ||
284 | */ | ||
285 | static void __init loongson3_cpus_done(void) | ||
286 | { | ||
287 | } | ||
288 | |||
289 | #ifdef CONFIG_HOTPLUG_CPU | 282 | #ifdef CONFIG_HOTPLUG_CPU |
290 | 283 | ||
291 | static int loongson3_cpu_disable(void) | 284 | static int loongson3_cpu_disable(void) |
@@ -432,7 +425,6 @@ struct plat_smp_ops loongson3_smp_ops = { | |||
432 | .send_ipi_mask = loongson3_send_ipi_mask, | 425 | .send_ipi_mask = loongson3_send_ipi_mask, |
433 | .init_secondary = loongson3_init_secondary, | 426 | .init_secondary = loongson3_init_secondary, |
434 | .smp_finish = loongson3_smp_finish, | 427 | .smp_finish = loongson3_smp_finish, |
435 | .cpus_done = loongson3_cpus_done, | ||
436 | .boot_secondary = loongson3_boot_secondary, | 428 | .boot_secondary = loongson3_boot_secondary, |
437 | .smp_setup = loongson3_smp_setup, | 429 | .smp_setup = loongson3_smp_setup, |
438 | .prepare_cpus = loongson3_prepare_cpus, | 430 | .prepare_cpus = loongson3_prepare_cpus, |
diff --git a/arch/mips/loongson1/Kconfig b/arch/mips/loongson1/Kconfig index fbf75f635798..e23c25d09963 100644 --- a/arch/mips/loongson1/Kconfig +++ b/arch/mips/loongson1/Kconfig | |||
@@ -14,6 +14,7 @@ config LOONGSON1_LS1B | |||
14 | select SYS_SUPPORTS_32BIT_KERNEL | 14 | select SYS_SUPPORTS_32BIT_KERNEL |
15 | select SYS_SUPPORTS_LITTLE_ENDIAN | 15 | select SYS_SUPPORTS_LITTLE_ENDIAN |
16 | select SYS_SUPPORTS_HIGHMEM | 16 | select SYS_SUPPORTS_HIGHMEM |
17 | select SYS_SUPPORTS_MIPS16 | ||
17 | select SYS_HAS_EARLY_PRINTK | 18 | select SYS_HAS_EARLY_PRINTK |
18 | select COMMON_CLK | 19 | select COMMON_CLK |
19 | 20 | ||
diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index 121a848a3594..619cfc1a2442 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile | |||
@@ -2,10 +2,12 @@ | |||
2 | # Makefile for the Linux/MIPS kernel FPU emulation. | 2 | # Makefile for the Linux/MIPS kernel FPU emulation. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \ | 5 | obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o dp_div.o dp_mul.o \ |
6 | ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \ | 6 | dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o dp_tint.o \ |
7 | dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \ | 7 | dp_fint.o dp_tlong.o dp_flong.o sp_div.o sp_mul.o sp_sub.o \ |
8 | dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \ | 8 | sp_add.o sp_fdp.o sp_cmp.o sp_simple.o sp_tint.o sp_fint.o \ |
9 | sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \ | 9 | sp_tlong.o sp_flong.o dsemul.o |
10 | sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \ | 10 | |
11 | dp_sqrt.o sp_sqrt.o kernel_linkage.o dsemul.o | 11 | lib-y += ieee754d.o dp_sqrt.o sp_sqrt.o |
12 | |||
13 | obj-$(CONFIG_DEBUG_FS) += me-debugfs.o | ||
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 7b3c9acae689..736c17a226e9 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator | 2 | * cp1emu.c: a MIPS coprocessor 1 (FPU) instruction emulator |
3 | * | 3 | * |
4 | * MIPS floating point support | 4 | * MIPS floating point support |
5 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 5 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
@@ -18,61 +18,46 @@ | |||
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License along | 19 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 20 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 21 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | 22 | * |
23 | * A complete emulator for MIPS coprocessor 1 instructions. This is | 23 | * A complete emulator for MIPS coprocessor 1 instructions. This is |
24 | * required for #float(switch) or #float(trap), where it catches all | 24 | * required for #float(switch) or #float(trap), where it catches all |
25 | * COP1 instructions via the "CoProcessor Unusable" exception. | 25 | * COP1 instructions via the "CoProcessor Unusable" exception. |
26 | * | 26 | * |
27 | * More surprisingly it is also required for #float(ieee), to help out | 27 | * More surprisingly it is also required for #float(ieee), to help out |
28 | * the hardware fpu at the boundaries of the IEEE-754 representation | 28 | * the hardware FPU at the boundaries of the IEEE-754 representation |
29 | * (denormalised values, infinities, underflow, etc). It is made | 29 | * (denormalised values, infinities, underflow, etc). It is made |
30 | * quite nasty because emulation of some non-COP1 instructions is | 30 | * quite nasty because emulation of some non-COP1 instructions is |
31 | * required, e.g. in branch delay slots. | 31 | * required, e.g. in branch delay slots. |
32 | * | 32 | * |
33 | * Note if you know that you won't have an fpu, then you'll get much | 33 | * Note if you know that you won't have an FPU, then you'll get much |
34 | * better performance by compiling with -msoft-float! | 34 | * better performance by compiling with -msoft-float! |
35 | */ | 35 | */ |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <linux/module.h> | ||
38 | #include <linux/debugfs.h> | 37 | #include <linux/debugfs.h> |
38 | #include <linux/kconfig.h> | ||
39 | #include <linux/percpu-defs.h> | ||
39 | #include <linux/perf_event.h> | 40 | #include <linux/perf_event.h> |
40 | 41 | ||
42 | #include <asm/branch.h> | ||
41 | #include <asm/inst.h> | 43 | #include <asm/inst.h> |
42 | #include <asm/bootinfo.h> | ||
43 | #include <asm/processor.h> | ||
44 | #include <asm/ptrace.h> | 44 | #include <asm/ptrace.h> |
45 | #include <asm/signal.h> | 45 | #include <asm/signal.h> |
46 | #include <asm/mipsregs.h> | 46 | #include <asm/uaccess.h> |
47 | |||
48 | #include <asm/processor.h> | ||
47 | #include <asm/fpu_emulator.h> | 49 | #include <asm/fpu_emulator.h> |
48 | #include <asm/fpu.h> | 50 | #include <asm/fpu.h> |
49 | #include <asm/uaccess.h> | ||
50 | #include <asm/branch.h> | ||
51 | 51 | ||
52 | #include "ieee754.h" | 52 | #include "ieee754.h" |
53 | 53 | ||
54 | /* Strap kernel emulator for full MIPS IV emulation */ | ||
55 | |||
56 | #ifdef __mips | ||
57 | #undef __mips | ||
58 | #endif | ||
59 | #define __mips 4 | ||
60 | |||
61 | /* Function which emulates a floating point instruction. */ | 54 | /* Function which emulates a floating point instruction. */ |
62 | 55 | ||
63 | static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, | 56 | static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, |
64 | mips_instruction); | 57 | mips_instruction); |
65 | 58 | ||
66 | #if __mips >= 4 && __mips != 32 | ||
67 | static int fpux_emu(struct pt_regs *, | 59 | static int fpux_emu(struct pt_regs *, |
68 | struct mips_fpu_struct *, mips_instruction, void *__user *); | 60 | struct mips_fpu_struct *, mips_instruction, void *__user *); |
69 | #endif | ||
70 | |||
71 | /* Further private data for which no space exists in mips_fpu_struct */ | ||
72 | |||
73 | #ifdef CONFIG_DEBUG_FS | ||
74 | DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); | ||
75 | #endif | ||
76 | 61 | ||
77 | /* Control registers */ | 62 | /* Control registers */ |
78 | 63 | ||
@@ -82,27 +67,6 @@ DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); | |||
82 | /* Determine rounding mode from the RM bits of the FCSR */ | 67 | /* Determine rounding mode from the RM bits of the FCSR */ |
83 | #define modeindex(v) ((v) & FPU_CSR_RM) | 68 | #define modeindex(v) ((v) & FPU_CSR_RM) |
84 | 69 | ||
85 | /* microMIPS bitfields */ | ||
86 | #define MM_POOL32A_MINOR_MASK 0x3f | ||
87 | #define MM_POOL32A_MINOR_SHIFT 0x6 | ||
88 | #define MM_MIPS32_COND_FC 0x30 | ||
89 | |||
90 | /* Convert Mips rounding mode (0..3) to IEEE library modes. */ | ||
91 | static const unsigned char ieee_rm[4] = { | ||
92 | [FPU_CSR_RN] = IEEE754_RN, | ||
93 | [FPU_CSR_RZ] = IEEE754_RZ, | ||
94 | [FPU_CSR_RU] = IEEE754_RU, | ||
95 | [FPU_CSR_RD] = IEEE754_RD, | ||
96 | }; | ||
97 | /* Convert IEEE library modes to Mips rounding mode (0..3). */ | ||
98 | static const unsigned char mips_rm[4] = { | ||
99 | [IEEE754_RN] = FPU_CSR_RN, | ||
100 | [IEEE754_RZ] = FPU_CSR_RZ, | ||
101 | [IEEE754_RD] = FPU_CSR_RD, | ||
102 | [IEEE754_RU] = FPU_CSR_RU, | ||
103 | }; | ||
104 | |||
105 | #if __mips >= 4 | ||
106 | /* convert condition code register number to csr bit */ | 70 | /* convert condition code register number to csr bit */ |
107 | static const unsigned int fpucondbit[8] = { | 71 | static const unsigned int fpucondbit[8] = { |
108 | FPU_CSR_COND0, | 72 | FPU_CSR_COND0, |
@@ -114,10 +78,6 @@ static const unsigned int fpucondbit[8] = { | |||
114 | FPU_CSR_COND6, | 78 | FPU_CSR_COND6, |
115 | FPU_CSR_COND7 | 79 | FPU_CSR_COND7 |
116 | }; | 80 | }; |
117 | #endif | ||
118 | |||
119 | /* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */ | ||
120 | static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; | ||
121 | 81 | ||
122 | /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ | 82 | /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ |
123 | static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; | 83 | static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; |
@@ -466,199 +426,6 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) | |||
466 | return 0; | 426 | return 0; |
467 | } | 427 | } |
468 | 428 | ||
469 | int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | ||
470 | unsigned long *contpc) | ||
471 | { | ||
472 | union mips_instruction insn = (union mips_instruction)dec_insn.insn; | ||
473 | int bc_false = 0; | ||
474 | unsigned int fcr31; | ||
475 | unsigned int bit; | ||
476 | |||
477 | if (!cpu_has_mmips) | ||
478 | return 0; | ||
479 | |||
480 | switch (insn.mm_i_format.opcode) { | ||
481 | case mm_pool32a_op: | ||
482 | if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) == | ||
483 | mm_pool32axf_op) { | ||
484 | switch (insn.mm_i_format.simmediate >> | ||
485 | MM_POOL32A_MINOR_SHIFT) { | ||
486 | case mm_jalr_op: | ||
487 | case mm_jalrhb_op: | ||
488 | case mm_jalrs_op: | ||
489 | case mm_jalrshb_op: | ||
490 | if (insn.mm_i_format.rt != 0) /* Not mm_jr */ | ||
491 | regs->regs[insn.mm_i_format.rt] = | ||
492 | regs->cp0_epc + | ||
493 | dec_insn.pc_inc + | ||
494 | dec_insn.next_pc_inc; | ||
495 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
496 | return 1; | ||
497 | } | ||
498 | } | ||
499 | break; | ||
500 | case mm_pool32i_op: | ||
501 | switch (insn.mm_i_format.rt) { | ||
502 | case mm_bltzals_op: | ||
503 | case mm_bltzal_op: | ||
504 | regs->regs[31] = regs->cp0_epc + | ||
505 | dec_insn.pc_inc + | ||
506 | dec_insn.next_pc_inc; | ||
507 | /* Fall through */ | ||
508 | case mm_bltz_op: | ||
509 | if ((long)regs->regs[insn.mm_i_format.rs] < 0) | ||
510 | *contpc = regs->cp0_epc + | ||
511 | dec_insn.pc_inc + | ||
512 | (insn.mm_i_format.simmediate << 1); | ||
513 | else | ||
514 | *contpc = regs->cp0_epc + | ||
515 | dec_insn.pc_inc + | ||
516 | dec_insn.next_pc_inc; | ||
517 | return 1; | ||
518 | case mm_bgezals_op: | ||
519 | case mm_bgezal_op: | ||
520 | regs->regs[31] = regs->cp0_epc + | ||
521 | dec_insn.pc_inc + | ||
522 | dec_insn.next_pc_inc; | ||
523 | /* Fall through */ | ||
524 | case mm_bgez_op: | ||
525 | if ((long)regs->regs[insn.mm_i_format.rs] >= 0) | ||
526 | *contpc = regs->cp0_epc + | ||
527 | dec_insn.pc_inc + | ||
528 | (insn.mm_i_format.simmediate << 1); | ||
529 | else | ||
530 | *contpc = regs->cp0_epc + | ||
531 | dec_insn.pc_inc + | ||
532 | dec_insn.next_pc_inc; | ||
533 | return 1; | ||
534 | case mm_blez_op: | ||
535 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
536 | *contpc = regs->cp0_epc + | ||
537 | dec_insn.pc_inc + | ||
538 | (insn.mm_i_format.simmediate << 1); | ||
539 | else | ||
540 | *contpc = regs->cp0_epc + | ||
541 | dec_insn.pc_inc + | ||
542 | dec_insn.next_pc_inc; | ||
543 | return 1; | ||
544 | case mm_bgtz_op: | ||
545 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
546 | *contpc = regs->cp0_epc + | ||
547 | dec_insn.pc_inc + | ||
548 | (insn.mm_i_format.simmediate << 1); | ||
549 | else | ||
550 | *contpc = regs->cp0_epc + | ||
551 | dec_insn.pc_inc + | ||
552 | dec_insn.next_pc_inc; | ||
553 | return 1; | ||
554 | case mm_bc2f_op: | ||
555 | case mm_bc1f_op: | ||
556 | bc_false = 1; | ||
557 | /* Fall through */ | ||
558 | case mm_bc2t_op: | ||
559 | case mm_bc1t_op: | ||
560 | preempt_disable(); | ||
561 | if (is_fpu_owner()) | ||
562 | asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); | ||
563 | else | ||
564 | fcr31 = current->thread.fpu.fcr31; | ||
565 | preempt_enable(); | ||
566 | |||
567 | if (bc_false) | ||
568 | fcr31 = ~fcr31; | ||
569 | |||
570 | bit = (insn.mm_i_format.rs >> 2); | ||
571 | bit += (bit != 0); | ||
572 | bit += 23; | ||
573 | if (fcr31 & (1 << bit)) | ||
574 | *contpc = regs->cp0_epc + | ||
575 | dec_insn.pc_inc + | ||
576 | (insn.mm_i_format.simmediate << 1); | ||
577 | else | ||
578 | *contpc = regs->cp0_epc + | ||
579 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
580 | return 1; | ||
581 | } | ||
582 | break; | ||
583 | case mm_pool16c_op: | ||
584 | switch (insn.mm_i_format.rt) { | ||
585 | case mm_jalr16_op: | ||
586 | case mm_jalrs16_op: | ||
587 | regs->regs[31] = regs->cp0_epc + | ||
588 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
589 | /* Fall through */ | ||
590 | case mm_jr16_op: | ||
591 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
592 | return 1; | ||
593 | } | ||
594 | break; | ||
595 | case mm_beqz16_op: | ||
596 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0) | ||
597 | *contpc = regs->cp0_epc + | ||
598 | dec_insn.pc_inc + | ||
599 | (insn.mm_b1_format.simmediate << 1); | ||
600 | else | ||
601 | *contpc = regs->cp0_epc + | ||
602 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
603 | return 1; | ||
604 | case mm_bnez16_op: | ||
605 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0) | ||
606 | *contpc = regs->cp0_epc + | ||
607 | dec_insn.pc_inc + | ||
608 | (insn.mm_b1_format.simmediate << 1); | ||
609 | else | ||
610 | *contpc = regs->cp0_epc + | ||
611 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
612 | return 1; | ||
613 | case mm_b16_op: | ||
614 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
615 | (insn.mm_b0_format.simmediate << 1); | ||
616 | return 1; | ||
617 | case mm_beq32_op: | ||
618 | if (regs->regs[insn.mm_i_format.rs] == | ||
619 | regs->regs[insn.mm_i_format.rt]) | ||
620 | *contpc = regs->cp0_epc + | ||
621 | dec_insn.pc_inc + | ||
622 | (insn.mm_i_format.simmediate << 1); | ||
623 | else | ||
624 | *contpc = regs->cp0_epc + | ||
625 | dec_insn.pc_inc + | ||
626 | dec_insn.next_pc_inc; | ||
627 | return 1; | ||
628 | case mm_bne32_op: | ||
629 | if (regs->regs[insn.mm_i_format.rs] != | ||
630 | regs->regs[insn.mm_i_format.rt]) | ||
631 | *contpc = regs->cp0_epc + | ||
632 | dec_insn.pc_inc + | ||
633 | (insn.mm_i_format.simmediate << 1); | ||
634 | else | ||
635 | *contpc = regs->cp0_epc + | ||
636 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
637 | return 1; | ||
638 | case mm_jalx32_op: | ||
639 | regs->regs[31] = regs->cp0_epc + | ||
640 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
641 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
642 | *contpc >>= 28; | ||
643 | *contpc <<= 28; | ||
644 | *contpc |= (insn.j_format.target << 2); | ||
645 | return 1; | ||
646 | case mm_jals32_op: | ||
647 | case mm_jal32_op: | ||
648 | regs->regs[31] = regs->cp0_epc + | ||
649 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
650 | /* Fall through */ | ||
651 | case mm_j32_op: | ||
652 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
653 | *contpc >>= 27; | ||
654 | *contpc <<= 27; | ||
655 | *contpc |= (insn.j_format.target << 1); | ||
656 | set_isa16_mode(*contpc); | ||
657 | return 1; | ||
658 | } | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | /* | 429 | /* |
663 | * Redundant with logic already in kernel/branch.c, | 430 | * Redundant with logic already in kernel/branch.c, |
664 | * embedded in compute_return_epc. At some point, | 431 | * embedded in compute_return_epc. At some point, |
@@ -817,7 +584,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
817 | if (insn.i_format.rs == bc_op) { | 584 | if (insn.i_format.rs == bc_op) { |
818 | preempt_disable(); | 585 | preempt_disable(); |
819 | if (is_fpu_owner()) | 586 | if (is_fpu_owner()) |
820 | asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); | 587 | asm volatile( |
588 | ".set push\n" | ||
589 | "\t.set mips1\n" | ||
590 | "\tcfc1\t%0,$31\n" | ||
591 | "\t.set pop" : "=r" (fcr31)); | ||
821 | else | 592 | else |
822 | fcr31 = current->thread.fpu.fcr31; | 593 | fcr31 = current->thread.fpu.fcr31; |
823 | preempt_enable(); | 594 | preempt_enable(); |
@@ -867,23 +638,25 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
867 | */ | 638 | */ |
868 | static inline int cop1_64bit(struct pt_regs *xcp) | 639 | static inline int cop1_64bit(struct pt_regs *xcp) |
869 | { | 640 | { |
870 | #if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32) | 641 | if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32)) |
871 | return 1; | 642 | return 1; |
872 | #elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT) | 643 | else if (config_enabled(CONFIG_32BIT) && |
873 | return 0; | 644 | !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) |
874 | #else | 645 | return 0; |
646 | |||
875 | return !test_thread_flag(TIF_32BIT_FPREGS); | 647 | return !test_thread_flag(TIF_32BIT_FPREGS); |
876 | #endif | ||
877 | } | 648 | } |
878 | 649 | ||
879 | #define SIFROMREG(si, x) do { \ | 650 | #define SIFROMREG(si, x) \ |
651 | do { \ | ||
880 | if (cop1_64bit(xcp)) \ | 652 | if (cop1_64bit(xcp)) \ |
881 | (si) = get_fpr32(&ctx->fpr[x], 0); \ | 653 | (si) = get_fpr32(&ctx->fpr[x], 0); \ |
882 | else \ | 654 | else \ |
883 | (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ | 655 | (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ |
884 | } while (0) | 656 | } while (0) |
885 | 657 | ||
886 | #define SITOREG(si, x) do { \ | 658 | #define SITOREG(si, x) \ |
659 | do { \ | ||
887 | if (cop1_64bit(xcp)) { \ | 660 | if (cop1_64bit(xcp)) { \ |
888 | unsigned i; \ | 661 | unsigned i; \ |
889 | set_fpr32(&ctx->fpr[x], 0, si); \ | 662 | set_fpr32(&ctx->fpr[x], 0, si); \ |
@@ -896,17 +669,19 @@ static inline int cop1_64bit(struct pt_regs *xcp) | |||
896 | 669 | ||
897 | #define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1)) | 670 | #define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1)) |
898 | 671 | ||
899 | #define SITOHREG(si, x) do { \ | 672 | #define SITOHREG(si, x) \ |
673 | do { \ | ||
900 | unsigned i; \ | 674 | unsigned i; \ |
901 | set_fpr32(&ctx->fpr[x], 1, si); \ | 675 | set_fpr32(&ctx->fpr[x], 1, si); \ |
902 | for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ | 676 | for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ |
903 | set_fpr32(&ctx->fpr[x], i, 0); \ | 677 | set_fpr32(&ctx->fpr[x], i, 0); \ |
904 | } while (0) | 678 | } while (0) |
905 | 679 | ||
906 | #define DIFROMREG(di, x) \ | 680 | #define DIFROMREG(di, x) \ |
907 | ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0)) | 681 | ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0)) |
908 | 682 | ||
909 | #define DITOREG(di, x) do { \ | 683 | #define DITOREG(di, x) \ |
684 | do { \ | ||
910 | unsigned fpr, i; \ | 685 | unsigned fpr, i; \ |
911 | fpr = (x) & ~(cop1_64bit(xcp) == 0); \ | 686 | fpr = (x) & ~(cop1_64bit(xcp) == 0); \ |
912 | set_fpr64(&ctx->fpr[fpr], 0, di); \ | 687 | set_fpr64(&ctx->fpr[fpr], 0, di); \ |
@@ -927,23 +702,36 @@ static inline int cop1_64bit(struct pt_regs *xcp) | |||
927 | static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | 702 | static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, |
928 | struct mm_decoded_insn dec_insn, void *__user *fault_addr) | 703 | struct mm_decoded_insn dec_insn, void *__user *fault_addr) |
929 | { | 704 | { |
930 | mips_instruction ir; | ||
931 | unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; | 705 | unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; |
932 | unsigned int cond; | 706 | unsigned int cond, cbit; |
933 | int pc_inc; | 707 | mips_instruction ir; |
708 | int likely, pc_inc; | ||
709 | u32 __user *wva; | ||
710 | u64 __user *dva; | ||
711 | u32 value; | ||
712 | u32 wval; | ||
713 | u64 dval; | ||
714 | int sig; | ||
715 | |||
716 | /* | ||
717 | * These are giving gcc a gentle hint about what to expect in | ||
718 | * dec_inst in order to do better optimization. | ||
719 | */ | ||
720 | if (!cpu_has_mmips && dec_insn.micro_mips_mode) | ||
721 | unreachable(); | ||
934 | 722 | ||
935 | /* XXX NEC Vr54xx bug workaround */ | 723 | /* XXX NEC Vr54xx bug workaround */ |
936 | if (xcp->cp0_cause & CAUSEF_BD) { | 724 | if (delay_slot(xcp)) { |
937 | if (dec_insn.micro_mips_mode) { | 725 | if (dec_insn.micro_mips_mode) { |
938 | if (!mm_isBranchInstr(xcp, dec_insn, &contpc)) | 726 | if (!mm_isBranchInstr(xcp, dec_insn, &contpc)) |
939 | xcp->cp0_cause &= ~CAUSEF_BD; | 727 | clear_delay_slot(xcp); |
940 | } else { | 728 | } else { |
941 | if (!isBranchInstr(xcp, dec_insn, &contpc)) | 729 | if (!isBranchInstr(xcp, dec_insn, &contpc)) |
942 | xcp->cp0_cause &= ~CAUSEF_BD; | 730 | clear_delay_slot(xcp); |
943 | } | 731 | } |
944 | } | 732 | } |
945 | 733 | ||
946 | if (xcp->cp0_cause & CAUSEF_BD) { | 734 | if (delay_slot(xcp)) { |
947 | /* | 735 | /* |
948 | * The instruction to be emulated is in a branch delay slot | 736 | * The instruction to be emulated is in a branch delay slot |
949 | * which means that we have to emulate the branch instruction | 737 | * which means that we have to emulate the branch instruction |
@@ -985,96 +773,85 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
985 | return SIGILL; | 773 | return SIGILL; |
986 | } | 774 | } |
987 | 775 | ||
988 | emul: | 776 | emul: |
989 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); | 777 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); |
990 | MIPS_FPU_EMU_INC_STATS(emulated); | 778 | MIPS_FPU_EMU_INC_STATS(emulated); |
991 | switch (MIPSInst_OPCODE(ir)) { | 779 | switch (MIPSInst_OPCODE(ir)) { |
992 | case ldc1_op:{ | 780 | case ldc1_op: |
993 | u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + | 781 | dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + |
994 | MIPSInst_SIMM(ir)); | 782 | MIPSInst_SIMM(ir)); |
995 | u64 val; | ||
996 | |||
997 | MIPS_FPU_EMU_INC_STATS(loads); | 783 | MIPS_FPU_EMU_INC_STATS(loads); |
998 | 784 | ||
999 | if (!access_ok(VERIFY_READ, va, sizeof(u64))) { | 785 | if (!access_ok(VERIFY_READ, dva, sizeof(u64))) { |
1000 | MIPS_FPU_EMU_INC_STATS(errors); | 786 | MIPS_FPU_EMU_INC_STATS(errors); |
1001 | *fault_addr = va; | 787 | *fault_addr = dva; |
1002 | return SIGBUS; | 788 | return SIGBUS; |
1003 | } | 789 | } |
1004 | if (__get_user(val, va)) { | 790 | if (__get_user(dval, dva)) { |
1005 | MIPS_FPU_EMU_INC_STATS(errors); | 791 | MIPS_FPU_EMU_INC_STATS(errors); |
1006 | *fault_addr = va; | 792 | *fault_addr = dva; |
1007 | return SIGSEGV; | 793 | return SIGSEGV; |
1008 | } | 794 | } |
1009 | DITOREG(val, MIPSInst_RT(ir)); | 795 | DITOREG(dval, MIPSInst_RT(ir)); |
1010 | break; | 796 | break; |
1011 | } | ||
1012 | |||
1013 | case sdc1_op:{ | ||
1014 | u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
1015 | MIPSInst_SIMM(ir)); | ||
1016 | u64 val; | ||
1017 | 797 | ||
798 | case sdc1_op: | ||
799 | dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
800 | MIPSInst_SIMM(ir)); | ||
1018 | MIPS_FPU_EMU_INC_STATS(stores); | 801 | MIPS_FPU_EMU_INC_STATS(stores); |
1019 | DIFROMREG(val, MIPSInst_RT(ir)); | 802 | DIFROMREG(dval, MIPSInst_RT(ir)); |
1020 | if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { | 803 | if (!access_ok(VERIFY_WRITE, dva, sizeof(u64))) { |
1021 | MIPS_FPU_EMU_INC_STATS(errors); | 804 | MIPS_FPU_EMU_INC_STATS(errors); |
1022 | *fault_addr = va; | 805 | *fault_addr = dva; |
1023 | return SIGBUS; | 806 | return SIGBUS; |
1024 | } | 807 | } |
1025 | if (__put_user(val, va)) { | 808 | if (__put_user(dval, dva)) { |
1026 | MIPS_FPU_EMU_INC_STATS(errors); | 809 | MIPS_FPU_EMU_INC_STATS(errors); |
1027 | *fault_addr = va; | 810 | *fault_addr = dva; |
1028 | return SIGSEGV; | 811 | return SIGSEGV; |
1029 | } | 812 | } |
1030 | break; | 813 | break; |
1031 | } | ||
1032 | |||
1033 | case lwc1_op:{ | ||
1034 | u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
1035 | MIPSInst_SIMM(ir)); | ||
1036 | u32 val; | ||
1037 | 814 | ||
815 | case lwc1_op: | ||
816 | wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
817 | MIPSInst_SIMM(ir)); | ||
1038 | MIPS_FPU_EMU_INC_STATS(loads); | 818 | MIPS_FPU_EMU_INC_STATS(loads); |
1039 | if (!access_ok(VERIFY_READ, va, sizeof(u32))) { | 819 | if (!access_ok(VERIFY_READ, wva, sizeof(u32))) { |
1040 | MIPS_FPU_EMU_INC_STATS(errors); | 820 | MIPS_FPU_EMU_INC_STATS(errors); |
1041 | *fault_addr = va; | 821 | *fault_addr = wva; |
1042 | return SIGBUS; | 822 | return SIGBUS; |
1043 | } | 823 | } |
1044 | if (__get_user(val, va)) { | 824 | if (__get_user(wval, wva)) { |
1045 | MIPS_FPU_EMU_INC_STATS(errors); | 825 | MIPS_FPU_EMU_INC_STATS(errors); |
1046 | *fault_addr = va; | 826 | *fault_addr = wva; |
1047 | return SIGSEGV; | 827 | return SIGSEGV; |
1048 | } | 828 | } |
1049 | SITOREG(val, MIPSInst_RT(ir)); | 829 | SITOREG(wval, MIPSInst_RT(ir)); |
1050 | break; | 830 | break; |
1051 | } | ||
1052 | |||
1053 | case swc1_op:{ | ||
1054 | u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
1055 | MIPSInst_SIMM(ir)); | ||
1056 | u32 val; | ||
1057 | 831 | ||
832 | case swc1_op: | ||
833 | wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
834 | MIPSInst_SIMM(ir)); | ||
1058 | MIPS_FPU_EMU_INC_STATS(stores); | 835 | MIPS_FPU_EMU_INC_STATS(stores); |
1059 | SIFROMREG(val, MIPSInst_RT(ir)); | 836 | SIFROMREG(wval, MIPSInst_RT(ir)); |
1060 | if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { | 837 | if (!access_ok(VERIFY_WRITE, wva, sizeof(u32))) { |
1061 | MIPS_FPU_EMU_INC_STATS(errors); | 838 | MIPS_FPU_EMU_INC_STATS(errors); |
1062 | *fault_addr = va; | 839 | *fault_addr = wva; |
1063 | return SIGBUS; | 840 | return SIGBUS; |
1064 | } | 841 | } |
1065 | if (__put_user(val, va)) { | 842 | if (__put_user(wval, wva)) { |
1066 | MIPS_FPU_EMU_INC_STATS(errors); | 843 | MIPS_FPU_EMU_INC_STATS(errors); |
1067 | *fault_addr = va; | 844 | *fault_addr = wva; |
1068 | return SIGSEGV; | 845 | return SIGSEGV; |
1069 | } | 846 | } |
1070 | break; | 847 | break; |
1071 | } | ||
1072 | 848 | ||
1073 | case cop1_op: | 849 | case cop1_op: |
1074 | switch (MIPSInst_RS(ir)) { | 850 | switch (MIPSInst_RS(ir)) { |
1075 | |||
1076 | #if defined(__mips64) | ||
1077 | case dmfc_op: | 851 | case dmfc_op: |
852 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | ||
853 | return SIGILL; | ||
854 | |||
1078 | /* copregister fs -> gpr[rt] */ | 855 | /* copregister fs -> gpr[rt] */ |
1079 | if (MIPSInst_RT(ir) != 0) { | 856 | if (MIPSInst_RT(ir) != 0) { |
1080 | DIFROMREG(xcp->regs[MIPSInst_RT(ir)], | 857 | DIFROMREG(xcp->regs[MIPSInst_RT(ir)], |
@@ -1083,10 +860,12 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1083 | break; | 860 | break; |
1084 | 861 | ||
1085 | case dmtc_op: | 862 | case dmtc_op: |
863 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | ||
864 | return SIGILL; | ||
865 | |||
1086 | /* copregister fs <- rt */ | 866 | /* copregister fs <- rt */ |
1087 | DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); | 867 | DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); |
1088 | break; | 868 | break; |
1089 | #endif | ||
1090 | 869 | ||
1091 | case mfhc_op: | 870 | case mfhc_op: |
1092 | if (!cpu_has_mips_r2) | 871 | if (!cpu_has_mips_r2) |
@@ -1120,19 +899,14 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1120 | SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); | 899 | SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); |
1121 | break; | 900 | break; |
1122 | 901 | ||
1123 | case cfc_op:{ | 902 | case cfc_op: |
1124 | /* cop control register rd -> gpr[rt] */ | 903 | /* cop control register rd -> gpr[rt] */ |
1125 | u32 value; | ||
1126 | |||
1127 | if (MIPSInst_RD(ir) == FPCREG_CSR) { | 904 | if (MIPSInst_RD(ir) == FPCREG_CSR) { |
1128 | value = ctx->fcr31; | 905 | value = ctx->fcr31; |
1129 | value = (value & ~FPU_CSR_RM) | | 906 | value = (value & ~FPU_CSR_RM) | modeindex(value); |
1130 | mips_rm[modeindex(value)]; | 907 | pr_debug("%p gpr[%d]<-csr=%08x\n", |
1131 | #ifdef CSRTRACE | 908 | (void *) (xcp->cp0_epc), |
1132 | printk("%p gpr[%d]<-csr=%08x\n", | 909 | MIPSInst_RT(ir), value); |
1133 | (void *) (xcp->cp0_epc), | ||
1134 | MIPSInst_RT(ir), value); | ||
1135 | #endif | ||
1136 | } | 910 | } |
1137 | else if (MIPSInst_RD(ir) == FPCREG_RID) | 911 | else if (MIPSInst_RD(ir) == FPCREG_RID) |
1138 | value = 0; | 912 | value = 0; |
@@ -1141,12 +915,9 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1141 | if (MIPSInst_RT(ir)) | 915 | if (MIPSInst_RT(ir)) |
1142 | xcp->regs[MIPSInst_RT(ir)] = value; | 916 | xcp->regs[MIPSInst_RT(ir)] = value; |
1143 | break; | 917 | break; |
1144 | } | ||
1145 | 918 | ||
1146 | case ctc_op:{ | 919 | case ctc_op: |
1147 | /* copregister rd <- rt */ | 920 | /* copregister rd <- rt */ |
1148 | u32 value; | ||
1149 | |||
1150 | if (MIPSInst_RT(ir) == 0) | 921 | if (MIPSInst_RT(ir) == 0) |
1151 | value = 0; | 922 | value = 0; |
1152 | else | 923 | else |
@@ -1155,37 +926,33 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1155 | /* we only have one writable control reg | 926 | /* we only have one writable control reg |
1156 | */ | 927 | */ |
1157 | if (MIPSInst_RD(ir) == FPCREG_CSR) { | 928 | if (MIPSInst_RD(ir) == FPCREG_CSR) { |
1158 | #ifdef CSRTRACE | 929 | pr_debug("%p gpr[%d]->csr=%08x\n", |
1159 | printk("%p gpr[%d]->csr=%08x\n", | 930 | (void *) (xcp->cp0_epc), |
1160 | (void *) (xcp->cp0_epc), | 931 | MIPSInst_RT(ir), value); |
1161 | MIPSInst_RT(ir), value); | ||
1162 | #endif | ||
1163 | 932 | ||
1164 | /* | 933 | /* |
1165 | * Don't write reserved bits, | 934 | * Don't write reserved bits, |
1166 | * and convert to ieee library modes | 935 | * and convert to ieee library modes |
1167 | */ | 936 | */ |
1168 | ctx->fcr31 = (value & | 937 | ctx->fcr31 = (value & ~(FPU_CSR_RSVD | FPU_CSR_RM)) | |
1169 | ~(FPU_CSR_RSVD | FPU_CSR_RM)) | | 938 | modeindex(value); |
1170 | ieee_rm[modeindex(value)]; | ||
1171 | } | 939 | } |
1172 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { | 940 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { |
1173 | return SIGFPE; | 941 | return SIGFPE; |
1174 | } | 942 | } |
1175 | break; | 943 | break; |
1176 | } | ||
1177 | 944 | ||
1178 | case bc_op:{ | 945 | case bc_op: |
1179 | int likely = 0; | 946 | if (delay_slot(xcp)) |
1180 | |||
1181 | if (xcp->cp0_cause & CAUSEF_BD) | ||
1182 | return SIGILL; | 947 | return SIGILL; |
1183 | 948 | ||
1184 | #if __mips >= 4 | 949 | if (cpu_has_mips_4_5_r) |
1185 | cond = ctx->fcr31 & fpucondbit[MIPSInst_RT(ir) >> 2]; | 950 | cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; |
1186 | #else | 951 | else |
1187 | cond = ctx->fcr31 & FPU_CSR_COND; | 952 | cbit = FPU_CSR_COND; |
1188 | #endif | 953 | cond = ctx->fcr31 & cbit; |
954 | |||
955 | likely = 0; | ||
1189 | switch (MIPSInst_RT(ir) & 3) { | 956 | switch (MIPSInst_RT(ir) & 3) { |
1190 | case bcfl_op: | 957 | case bcfl_op: |
1191 | likely = 1; | 958 | likely = 1; |
@@ -1201,10 +968,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1201 | return SIGILL; | 968 | return SIGILL; |
1202 | } | 969 | } |
1203 | 970 | ||
1204 | xcp->cp0_cause |= CAUSEF_BD; | 971 | set_delay_slot(xcp); |
1205 | if (cond) { | 972 | if (cond) { |
1206 | /* branch taken: emulate dslot | 973 | /* |
1207 | * instruction | 974 | * Branch taken: emulate dslot instruction |
1208 | */ | 975 | */ |
1209 | xcp->cp0_epc += dec_insn.pc_inc; | 976 | xcp->cp0_epc += dec_insn.pc_inc; |
1210 | 977 | ||
@@ -1238,23 +1005,37 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1238 | 1005 | ||
1239 | switch (MIPSInst_OPCODE(ir)) { | 1006 | switch (MIPSInst_OPCODE(ir)) { |
1240 | case lwc1_op: | 1007 | case lwc1_op: |
1008 | goto emul; | ||
1009 | |||
1241 | case swc1_op: | 1010 | case swc1_op: |
1242 | #if (__mips >= 2 || defined(__mips64)) | 1011 | goto emul; |
1012 | |||
1243 | case ldc1_op: | 1013 | case ldc1_op: |
1244 | case sdc1_op: | 1014 | case sdc1_op: |
1245 | #endif | 1015 | if (cpu_has_mips_2_3_4_5 || |
1016 | cpu_has_mips64) | ||
1017 | goto emul; | ||
1018 | |||
1019 | return SIGILL; | ||
1020 | goto emul; | ||
1021 | |||
1246 | case cop1_op: | 1022 | case cop1_op: |
1247 | #if __mips >= 4 && __mips != 32 | ||
1248 | case cop1x_op: | ||
1249 | #endif | ||
1250 | /* its one of ours */ | ||
1251 | goto emul; | 1023 | goto emul; |
1252 | #if __mips >= 4 | 1024 | |
1025 | case cop1x_op: | ||
1026 | if (cpu_has_mips_4_5 || cpu_has_mips64) | ||
1027 | /* its one of ours */ | ||
1028 | goto emul; | ||
1029 | |||
1030 | return SIGILL; | ||
1031 | |||
1253 | case spec_op: | 1032 | case spec_op: |
1033 | if (!cpu_has_mips_4_5_r) | ||
1034 | return SIGILL; | ||
1035 | |||
1254 | if (MIPSInst_FUNC(ir) == movc_op) | 1036 | if (MIPSInst_FUNC(ir) == movc_op) |
1255 | goto emul; | 1037 | goto emul; |
1256 | break; | 1038 | break; |
1257 | #endif | ||
1258 | } | 1039 | } |
1259 | 1040 | ||
1260 | /* | 1041 | /* |
@@ -1262,10 +1043,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1262 | * instruction in the dslot | 1043 | * instruction in the dslot |
1263 | */ | 1044 | */ |
1264 | return mips_dsemul(xcp, ir, contpc); | 1045 | return mips_dsemul(xcp, ir, contpc); |
1265 | } | 1046 | } else if (likely) { /* branch not taken */ |
1266 | else { | ||
1267 | /* branch not taken */ | ||
1268 | if (likely) { | ||
1269 | /* | 1047 | /* |
1270 | * branch likely nullifies | 1048 | * branch likely nullifies |
1271 | * dslot if not taken | 1049 | * dslot if not taken |
@@ -1277,34 +1055,31 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1277 | * dslot as normal insn | 1055 | * dslot as normal insn |
1278 | */ | 1056 | */ |
1279 | } | 1057 | } |
1280 | } | ||
1281 | break; | 1058 | break; |
1282 | } | ||
1283 | 1059 | ||
1284 | default: | 1060 | default: |
1285 | if (!(MIPSInst_RS(ir) & 0x10)) | 1061 | if (!(MIPSInst_RS(ir) & 0x10)) |
1286 | return SIGILL; | 1062 | return SIGILL; |
1287 | { | ||
1288 | int sig; | ||
1289 | 1063 | ||
1290 | /* a real fpu computation instruction */ | 1064 | /* a real fpu computation instruction */ |
1291 | if ((sig = fpu_emu(xcp, ctx, ir))) | 1065 | if ((sig = fpu_emu(xcp, ctx, ir))) |
1292 | return sig; | 1066 | return sig; |
1293 | } | ||
1294 | } | 1067 | } |
1295 | break; | 1068 | break; |
1296 | 1069 | ||
1297 | #if __mips >= 4 && __mips != 32 | 1070 | case cop1x_op: |
1298 | case cop1x_op:{ | 1071 | if (!cpu_has_mips_4_5 && !cpu_has_mips64) |
1299 | int sig = fpux_emu(xcp, ctx, ir, fault_addr); | 1072 | return SIGILL; |
1073 | |||
1074 | sig = fpux_emu(xcp, ctx, ir, fault_addr); | ||
1300 | if (sig) | 1075 | if (sig) |
1301 | return sig; | 1076 | return sig; |
1302 | break; | 1077 | break; |
1303 | } | ||
1304 | #endif | ||
1305 | 1078 | ||
1306 | #if __mips >= 4 | ||
1307 | case spec_op: | 1079 | case spec_op: |
1080 | if (!cpu_has_mips_4_5_r) | ||
1081 | return SIGILL; | ||
1082 | |||
1308 | if (MIPSInst_FUNC(ir) != movc_op) | 1083 | if (MIPSInst_FUNC(ir) != movc_op) |
1309 | return SIGILL; | 1084 | return SIGILL; |
1310 | cond = fpucondbit[MIPSInst_RT(ir) >> 2]; | 1085 | cond = fpucondbit[MIPSInst_RT(ir) >> 2]; |
@@ -1312,8 +1087,6 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1312 | xcp->regs[MIPSInst_RD(ir)] = | 1087 | xcp->regs[MIPSInst_RD(ir)] = |
1313 | xcp->regs[MIPSInst_RS(ir)]; | 1088 | xcp->regs[MIPSInst_RS(ir)]; |
1314 | break; | 1089 | break; |
1315 | #endif | ||
1316 | |||
1317 | default: | 1090 | default: |
1318 | sigill: | 1091 | sigill: |
1319 | return SIGILL; | 1092 | return SIGILL; |
@@ -1321,7 +1094,7 @@ sigill: | |||
1321 | 1094 | ||
1322 | /* we did it !! */ | 1095 | /* we did it !! */ |
1323 | xcp->cp0_epc = contpc; | 1096 | xcp->cp0_epc = contpc; |
1324 | xcp->cp0_cause &= ~CAUSEF_BD; | 1097 | clear_delay_slot(xcp); |
1325 | 1098 | ||
1326 | return 0; | 1099 | return 0; |
1327 | } | 1100 | } |
@@ -1342,44 +1115,42 @@ static const unsigned char cmptab[8] = { | |||
1342 | }; | 1115 | }; |
1343 | 1116 | ||
1344 | 1117 | ||
1345 | #if __mips >= 4 && __mips != 32 | ||
1346 | |||
1347 | /* | 1118 | /* |
1348 | * Additional MIPS4 instructions | 1119 | * Additional MIPS4 instructions |
1349 | */ | 1120 | */ |
1350 | 1121 | ||
1351 | #define DEF3OP(name, p, f1, f2, f3) \ | 1122 | #define DEF3OP(name, p, f1, f2, f3) \ |
1352 | static ieee754##p fpemu_##p##_##name(ieee754##p r, ieee754##p s, \ | 1123 | static union ieee754##p fpemu_##p##_##name(union ieee754##p r, \ |
1353 | ieee754##p t) \ | 1124 | union ieee754##p s, union ieee754##p t) \ |
1354 | { \ | 1125 | { \ |
1355 | struct _ieee754_csr ieee754_csr_save; \ | 1126 | struct _ieee754_csr ieee754_csr_save; \ |
1356 | s = f1(s, t); \ | 1127 | s = f1(s, t); \ |
1357 | ieee754_csr_save = ieee754_csr; \ | 1128 | ieee754_csr_save = ieee754_csr; \ |
1358 | s = f2(s, r); \ | 1129 | s = f2(s, r); \ |
1359 | ieee754_csr_save.cx |= ieee754_csr.cx; \ | 1130 | ieee754_csr_save.cx |= ieee754_csr.cx; \ |
1360 | ieee754_csr_save.sx |= ieee754_csr.sx; \ | 1131 | ieee754_csr_save.sx |= ieee754_csr.sx; \ |
1361 | s = f3(s); \ | 1132 | s = f3(s); \ |
1362 | ieee754_csr.cx |= ieee754_csr_save.cx; \ | 1133 | ieee754_csr.cx |= ieee754_csr_save.cx; \ |
1363 | ieee754_csr.sx |= ieee754_csr_save.sx; \ | 1134 | ieee754_csr.sx |= ieee754_csr_save.sx; \ |
1364 | return s; \ | 1135 | return s; \ |
1365 | } | 1136 | } |
1366 | 1137 | ||
1367 | static ieee754dp fpemu_dp_recip(ieee754dp d) | 1138 | static union ieee754dp fpemu_dp_recip(union ieee754dp d) |
1368 | { | 1139 | { |
1369 | return ieee754dp_div(ieee754dp_one(0), d); | 1140 | return ieee754dp_div(ieee754dp_one(0), d); |
1370 | } | 1141 | } |
1371 | 1142 | ||
1372 | static ieee754dp fpemu_dp_rsqrt(ieee754dp d) | 1143 | static union ieee754dp fpemu_dp_rsqrt(union ieee754dp d) |
1373 | { | 1144 | { |
1374 | return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); | 1145 | return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); |
1375 | } | 1146 | } |
1376 | 1147 | ||
1377 | static ieee754sp fpemu_sp_recip(ieee754sp s) | 1148 | static union ieee754sp fpemu_sp_recip(union ieee754sp s) |
1378 | { | 1149 | { |
1379 | return ieee754sp_div(ieee754sp_one(0), s); | 1150 | return ieee754sp_div(ieee754sp_one(0), s); |
1380 | } | 1151 | } |
1381 | 1152 | ||
1382 | static ieee754sp fpemu_sp_rsqrt(ieee754sp s) | 1153 | static union ieee754sp fpemu_sp_rsqrt(union ieee754sp s) |
1383 | { | 1154 | { |
1384 | return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); | 1155 | return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); |
1385 | } | 1156 | } |
@@ -1403,8 +1174,8 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1403 | switch (MIPSInst_FMA_FFMT(ir)) { | 1174 | switch (MIPSInst_FMA_FFMT(ir)) { |
1404 | case s_fmt:{ /* 0 */ | 1175 | case s_fmt:{ /* 0 */ |
1405 | 1176 | ||
1406 | ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp); | 1177 | union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); |
1407 | ieee754sp fd, fr, fs, ft; | 1178 | union ieee754sp fd, fr, fs, ft; |
1408 | u32 __user *va; | 1179 | u32 __user *va; |
1409 | u32 val; | 1180 | u32 val; |
1410 | 1181 | ||
@@ -1467,18 +1238,26 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1467 | SPTOREG(fd, MIPSInst_FD(ir)); | 1238 | SPTOREG(fd, MIPSInst_FD(ir)); |
1468 | 1239 | ||
1469 | copcsr: | 1240 | copcsr: |
1470 | if (ieee754_cxtest(IEEE754_INEXACT)) | 1241 | if (ieee754_cxtest(IEEE754_INEXACT)) { |
1242 | MIPS_FPU_EMU_INC_STATS(ieee754_inexact); | ||
1471 | rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; | 1243 | rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; |
1472 | if (ieee754_cxtest(IEEE754_UNDERFLOW)) | 1244 | } |
1245 | if (ieee754_cxtest(IEEE754_UNDERFLOW)) { | ||
1246 | MIPS_FPU_EMU_INC_STATS(ieee754_underflow); | ||
1473 | rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; | 1247 | rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; |
1474 | if (ieee754_cxtest(IEEE754_OVERFLOW)) | 1248 | } |
1249 | if (ieee754_cxtest(IEEE754_OVERFLOW)) { | ||
1250 | MIPS_FPU_EMU_INC_STATS(ieee754_overflow); | ||
1475 | rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; | 1251 | rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; |
1476 | if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) | 1252 | } |
1253 | if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) { | ||
1254 | MIPS_FPU_EMU_INC_STATS(ieee754_invalidop); | ||
1477 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; | 1255 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; |
1256 | } | ||
1478 | 1257 | ||
1479 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; | 1258 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; |
1480 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { | 1259 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { |
1481 | /*printk ("SIGFPE: fpu csr = %08x\n", | 1260 | /*printk ("SIGFPE: FPU csr = %08x\n", |
1482 | ctx->fcr31); */ | 1261 | ctx->fcr31); */ |
1483 | return SIGFPE; | 1262 | return SIGFPE; |
1484 | } | 1263 | } |
@@ -1492,8 +1271,8 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1492 | } | 1271 | } |
1493 | 1272 | ||
1494 | case d_fmt:{ /* 1 */ | 1273 | case d_fmt:{ /* 1 */ |
1495 | ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp); | 1274 | union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); |
1496 | ieee754dp fd, fr, fs, ft; | 1275 | union ieee754dp fd, fr, fs, ft; |
1497 | u64 __user *va; | 1276 | u64 __user *va; |
1498 | u64 val; | 1277 | u64 val; |
1499 | 1278 | ||
@@ -1574,7 +1353,6 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1574 | 1353 | ||
1575 | return 0; | 1354 | return 0; |
1576 | } | 1355 | } |
1577 | #endif | ||
1578 | 1356 | ||
1579 | 1357 | ||
1580 | 1358 | ||
@@ -1586,23 +1364,25 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1586 | { | 1364 | { |
1587 | int rfmt; /* resulting format */ | 1365 | int rfmt; /* resulting format */ |
1588 | unsigned rcsr = 0; /* resulting csr */ | 1366 | unsigned rcsr = 0; /* resulting csr */ |
1367 | unsigned int oldrm; | ||
1368 | unsigned int cbit; | ||
1589 | unsigned cond; | 1369 | unsigned cond; |
1590 | union { | 1370 | union { |
1591 | ieee754dp d; | 1371 | union ieee754dp d; |
1592 | ieee754sp s; | 1372 | union ieee754sp s; |
1593 | int w; | 1373 | int w; |
1594 | #ifdef __mips64 | ||
1595 | s64 l; | 1374 | s64 l; |
1596 | #endif | ||
1597 | } rv; /* resulting value */ | 1375 | } rv; /* resulting value */ |
1376 | u64 bits; | ||
1598 | 1377 | ||
1599 | MIPS_FPU_EMU_INC_STATS(cp1ops); | 1378 | MIPS_FPU_EMU_INC_STATS(cp1ops); |
1600 | switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { | 1379 | switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { |
1601 | case s_fmt:{ /* 0 */ | 1380 | case s_fmt: { /* 0 */ |
1602 | union { | 1381 | union { |
1603 | ieee754sp(*b) (ieee754sp, ieee754sp); | 1382 | union ieee754sp(*b) (union ieee754sp, union ieee754sp); |
1604 | ieee754sp(*u) (ieee754sp); | 1383 | union ieee754sp(*u) (union ieee754sp); |
1605 | } handler; | 1384 | } handler; |
1385 | union ieee754sp fs, ft; | ||
1606 | 1386 | ||
1607 | switch (MIPSInst_FUNC(ir)) { | 1387 | switch (MIPSInst_FUNC(ir)) { |
1608 | /* binary ops */ | 1388 | /* binary ops */ |
@@ -1620,148 +1400,167 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1620 | goto scopbop; | 1400 | goto scopbop; |
1621 | 1401 | ||
1622 | /* unary ops */ | 1402 | /* unary ops */ |
1623 | #if __mips >= 2 || defined(__mips64) | ||
1624 | case fsqrt_op: | 1403 | case fsqrt_op: |
1404 | if (!cpu_has_mips_4_5_r) | ||
1405 | return SIGILL; | ||
1406 | |||
1625 | handler.u = ieee754sp_sqrt; | 1407 | handler.u = ieee754sp_sqrt; |
1626 | goto scopuop; | 1408 | goto scopuop; |
1627 | #endif | 1409 | |
1628 | #if __mips >= 4 && __mips != 32 | 1410 | /* |
1411 | * Note that on some MIPS IV implementations such as the | ||
1412 | * R5000 and R8000 the FSQRT and FRECIP instructions do not | ||
1413 | * achieve full IEEE-754 accuracy - however this emulator does. | ||
1414 | */ | ||
1629 | case frsqrt_op: | 1415 | case frsqrt_op: |
1416 | if (!cpu_has_mips_4_5_r2) | ||
1417 | return SIGILL; | ||
1418 | |||
1630 | handler.u = fpemu_sp_rsqrt; | 1419 | handler.u = fpemu_sp_rsqrt; |
1631 | goto scopuop; | 1420 | goto scopuop; |
1421 | |||
1632 | case frecip_op: | 1422 | case frecip_op: |
1423 | if (!cpu_has_mips_4_5_r2) | ||
1424 | return SIGILL; | ||
1425 | |||
1633 | handler.u = fpemu_sp_recip; | 1426 | handler.u = fpemu_sp_recip; |
1634 | goto scopuop; | 1427 | goto scopuop; |
1635 | #endif | 1428 | |
1636 | #if __mips >= 4 | ||
1637 | case fmovc_op: | 1429 | case fmovc_op: |
1430 | if (!cpu_has_mips_4_5_r) | ||
1431 | return SIGILL; | ||
1432 | |||
1638 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; | 1433 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; |
1639 | if (((ctx->fcr31 & cond) != 0) != | 1434 | if (((ctx->fcr31 & cond) != 0) != |
1640 | ((MIPSInst_FT(ir) & 1) != 0)) | 1435 | ((MIPSInst_FT(ir) & 1) != 0)) |
1641 | return 0; | 1436 | return 0; |
1642 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | 1437 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
1643 | break; | 1438 | break; |
1439 | |||
1644 | case fmovz_op: | 1440 | case fmovz_op: |
1441 | if (!cpu_has_mips_4_5_r) | ||
1442 | return SIGILL; | ||
1443 | |||
1645 | if (xcp->regs[MIPSInst_FT(ir)] != 0) | 1444 | if (xcp->regs[MIPSInst_FT(ir)] != 0) |
1646 | return 0; | 1445 | return 0; |
1647 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | 1446 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
1648 | break; | 1447 | break; |
1448 | |||
1649 | case fmovn_op: | 1449 | case fmovn_op: |
1450 | if (!cpu_has_mips_4_5_r) | ||
1451 | return SIGILL; | ||
1452 | |||
1650 | if (xcp->regs[MIPSInst_FT(ir)] == 0) | 1453 | if (xcp->regs[MIPSInst_FT(ir)] == 0) |
1651 | return 0; | 1454 | return 0; |
1652 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | 1455 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
1653 | break; | 1456 | break; |
1654 | #endif | 1457 | |
1655 | case fabs_op: | 1458 | case fabs_op: |
1656 | handler.u = ieee754sp_abs; | 1459 | handler.u = ieee754sp_abs; |
1657 | goto scopuop; | 1460 | goto scopuop; |
1461 | |||
1658 | case fneg_op: | 1462 | case fneg_op: |
1659 | handler.u = ieee754sp_neg; | 1463 | handler.u = ieee754sp_neg; |
1660 | goto scopuop; | 1464 | goto scopuop; |
1465 | |||
1661 | case fmov_op: | 1466 | case fmov_op: |
1662 | /* an easy one */ | 1467 | /* an easy one */ |
1663 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | 1468 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
1664 | goto copcsr; | 1469 | goto copcsr; |
1665 | 1470 | ||
1666 | /* binary op on handler */ | 1471 | /* binary op on handler */ |
1667 | scopbop: | 1472 | scopbop: |
1668 | { | 1473 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1669 | ieee754sp fs, ft; | 1474 | SPFROMREG(ft, MIPSInst_FT(ir)); |
1670 | |||
1671 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
1672 | SPFROMREG(ft, MIPSInst_FT(ir)); | ||
1673 | |||
1674 | rv.s = (*handler.b) (fs, ft); | ||
1675 | goto copcsr; | ||
1676 | } | ||
1677 | scopuop: | ||
1678 | { | ||
1679 | ieee754sp fs; | ||
1680 | 1475 | ||
1681 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1476 | rv.s = (*handler.b) (fs, ft); |
1682 | rv.s = (*handler.u) (fs); | 1477 | goto copcsr; |
1683 | goto copcsr; | 1478 | scopuop: |
1684 | } | 1479 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1685 | copcsr: | 1480 | rv.s = (*handler.u) (fs); |
1686 | if (ieee754_cxtest(IEEE754_INEXACT)) | 1481 | goto copcsr; |
1482 | copcsr: | ||
1483 | if (ieee754_cxtest(IEEE754_INEXACT)) { | ||
1484 | MIPS_FPU_EMU_INC_STATS(ieee754_inexact); | ||
1687 | rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; | 1485 | rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; |
1688 | if (ieee754_cxtest(IEEE754_UNDERFLOW)) | 1486 | } |
1487 | if (ieee754_cxtest(IEEE754_UNDERFLOW)) { | ||
1488 | MIPS_FPU_EMU_INC_STATS(ieee754_underflow); | ||
1689 | rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; | 1489 | rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; |
1690 | if (ieee754_cxtest(IEEE754_OVERFLOW)) | 1490 | } |
1491 | if (ieee754_cxtest(IEEE754_OVERFLOW)) { | ||
1492 | MIPS_FPU_EMU_INC_STATS(ieee754_overflow); | ||
1691 | rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; | 1493 | rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; |
1692 | if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) | 1494 | } |
1495 | if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) { | ||
1496 | MIPS_FPU_EMU_INC_STATS(ieee754_zerodiv); | ||
1693 | rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; | 1497 | rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; |
1694 | if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) | 1498 | } |
1499 | if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) { | ||
1500 | MIPS_FPU_EMU_INC_STATS(ieee754_invalidop); | ||
1695 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; | 1501 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; |
1502 | } | ||
1696 | break; | 1503 | break; |
1697 | 1504 | ||
1698 | /* unary conv ops */ | 1505 | /* unary conv ops */ |
1699 | case fcvts_op: | 1506 | case fcvts_op: |
1700 | return SIGILL; /* not defined */ | 1507 | return SIGILL; /* not defined */ |
1701 | case fcvtd_op:{ | ||
1702 | ieee754sp fs; | ||
1703 | 1508 | ||
1509 | case fcvtd_op: | ||
1704 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1510 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1705 | rv.d = ieee754dp_fsp(fs); | 1511 | rv.d = ieee754dp_fsp(fs); |
1706 | rfmt = d_fmt; | 1512 | rfmt = d_fmt; |
1707 | goto copcsr; | 1513 | goto copcsr; |
1708 | } | ||
1709 | case fcvtw_op:{ | ||
1710 | ieee754sp fs; | ||
1711 | 1514 | ||
1515 | case fcvtw_op: | ||
1712 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1516 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1713 | rv.w = ieee754sp_tint(fs); | 1517 | rv.w = ieee754sp_tint(fs); |
1714 | rfmt = w_fmt; | 1518 | rfmt = w_fmt; |
1715 | goto copcsr; | 1519 | goto copcsr; |
1716 | } | ||
1717 | 1520 | ||
1718 | #if __mips >= 2 || defined(__mips64) | ||
1719 | case fround_op: | 1521 | case fround_op: |
1720 | case ftrunc_op: | 1522 | case ftrunc_op: |
1721 | case fceil_op: | 1523 | case fceil_op: |
1722 | case ffloor_op:{ | 1524 | case ffloor_op: |
1723 | unsigned int oldrm = ieee754_csr.rm; | 1525 | if (!cpu_has_mips_2_3_4_5 && !cpu_has_mips64) |
1724 | ieee754sp fs; | 1526 | return SIGILL; |
1725 | 1527 | ||
1528 | oldrm = ieee754_csr.rm; | ||
1726 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1529 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1727 | ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; | 1530 | ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); |
1728 | rv.w = ieee754sp_tint(fs); | 1531 | rv.w = ieee754sp_tint(fs); |
1729 | ieee754_csr.rm = oldrm; | 1532 | ieee754_csr.rm = oldrm; |
1730 | rfmt = w_fmt; | 1533 | rfmt = w_fmt; |
1731 | goto copcsr; | 1534 | goto copcsr; |
1732 | } | ||
1733 | #endif /* __mips >= 2 */ | ||
1734 | 1535 | ||
1735 | #if defined(__mips64) | 1536 | case fcvtl_op: |
1736 | case fcvtl_op:{ | 1537 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1737 | ieee754sp fs; | 1538 | return SIGILL; |
1738 | 1539 | ||
1739 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1540 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1740 | rv.l = ieee754sp_tlong(fs); | 1541 | rv.l = ieee754sp_tlong(fs); |
1741 | rfmt = l_fmt; | 1542 | rfmt = l_fmt; |
1742 | goto copcsr; | 1543 | goto copcsr; |
1743 | } | ||
1744 | 1544 | ||
1745 | case froundl_op: | 1545 | case froundl_op: |
1746 | case ftruncl_op: | 1546 | case ftruncl_op: |
1747 | case fceill_op: | 1547 | case fceill_op: |
1748 | case ffloorl_op:{ | 1548 | case ffloorl_op: |
1749 | unsigned int oldrm = ieee754_csr.rm; | 1549 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1750 | ieee754sp fs; | 1550 | return SIGILL; |
1751 | 1551 | ||
1552 | oldrm = ieee754_csr.rm; | ||
1752 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1553 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1753 | ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; | 1554 | ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); |
1754 | rv.l = ieee754sp_tlong(fs); | 1555 | rv.l = ieee754sp_tlong(fs); |
1755 | ieee754_csr.rm = oldrm; | 1556 | ieee754_csr.rm = oldrm; |
1756 | rfmt = l_fmt; | 1557 | rfmt = l_fmt; |
1757 | goto copcsr; | 1558 | goto copcsr; |
1758 | } | ||
1759 | #endif /* defined(__mips64) */ | ||
1760 | 1559 | ||
1761 | default: | 1560 | default: |
1762 | if (MIPSInst_FUNC(ir) >= fcmp_op) { | 1561 | if (MIPSInst_FUNC(ir) >= fcmp_op) { |
1763 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; | 1562 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
1764 | ieee754sp fs, ft; | 1563 | union ieee754sp fs, ft; |
1765 | 1564 | ||
1766 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1565 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1767 | SPFROMREG(ft, MIPSInst_FT(ir)); | 1566 | SPFROMREG(ft, MIPSInst_FT(ir)); |
@@ -1774,19 +1573,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1774 | else | 1573 | else |
1775 | goto copcsr; | 1574 | goto copcsr; |
1776 | 1575 | ||
1777 | } | 1576 | } else |
1778 | else { | ||
1779 | return SIGILL; | 1577 | return SIGILL; |
1780 | } | ||
1781 | break; | 1578 | break; |
1782 | } | 1579 | } |
1783 | break; | 1580 | break; |
1784 | } | 1581 | } |
1785 | 1582 | ||
1786 | case d_fmt:{ | 1583 | case d_fmt: { |
1584 | union ieee754dp fs, ft; | ||
1787 | union { | 1585 | union { |
1788 | ieee754dp(*b) (ieee754dp, ieee754dp); | 1586 | union ieee754dp(*b) (union ieee754dp, union ieee754dp); |
1789 | ieee754dp(*u) (ieee754dp); | 1587 | union ieee754dp(*u) (union ieee754dp); |
1790 | } handler; | 1588 | } handler; |
1791 | 1589 | ||
1792 | switch (MIPSInst_FUNC(ir)) { | 1590 | switch (MIPSInst_FUNC(ir)) { |
@@ -1805,21 +1603,33 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1805 | goto dcopbop; | 1603 | goto dcopbop; |
1806 | 1604 | ||
1807 | /* unary ops */ | 1605 | /* unary ops */ |
1808 | #if __mips >= 2 || defined(__mips64) | ||
1809 | case fsqrt_op: | 1606 | case fsqrt_op: |
1607 | if (!cpu_has_mips_2_3_4_5_r) | ||
1608 | return SIGILL; | ||
1609 | |||
1810 | handler.u = ieee754dp_sqrt; | 1610 | handler.u = ieee754dp_sqrt; |
1811 | goto dcopuop; | 1611 | goto dcopuop; |
1812 | #endif | 1612 | /* |
1813 | #if __mips >= 4 && __mips != 32 | 1613 | * Note that on some MIPS IV implementations such as the |
1614 | * R5000 and R8000 the FSQRT and FRECIP instructions do not | ||
1615 | * achieve full IEEE-754 accuracy - however this emulator does. | ||
1616 | */ | ||
1814 | case frsqrt_op: | 1617 | case frsqrt_op: |
1618 | if (!cpu_has_mips_4_5_r2) | ||
1619 | return SIGILL; | ||
1620 | |||
1815 | handler.u = fpemu_dp_rsqrt; | 1621 | handler.u = fpemu_dp_rsqrt; |
1816 | goto dcopuop; | 1622 | goto dcopuop; |
1817 | case frecip_op: | 1623 | case frecip_op: |
1624 | if (!cpu_has_mips_4_5_r2) | ||
1625 | return SIGILL; | ||
1626 | |||
1818 | handler.u = fpemu_dp_recip; | 1627 | handler.u = fpemu_dp_recip; |
1819 | goto dcopuop; | 1628 | goto dcopuop; |
1820 | #endif | ||
1821 | #if __mips >= 4 | ||
1822 | case fmovc_op: | 1629 | case fmovc_op: |
1630 | if (!cpu_has_mips_4_5_r) | ||
1631 | return SIGILL; | ||
1632 | |||
1823 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; | 1633 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; |
1824 | if (((ctx->fcr31 & cond) != 0) != | 1634 | if (((ctx->fcr31 & cond) != 0) != |
1825 | ((MIPSInst_FT(ir) & 1) != 0)) | 1635 | ((MIPSInst_FT(ir) & 1) != 0)) |
@@ -1827,16 +1637,21 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1827 | DPFROMREG(rv.d, MIPSInst_FS(ir)); | 1637 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
1828 | break; | 1638 | break; |
1829 | case fmovz_op: | 1639 | case fmovz_op: |
1640 | if (!cpu_has_mips_4_5_r) | ||
1641 | return SIGILL; | ||
1642 | |||
1830 | if (xcp->regs[MIPSInst_FT(ir)] != 0) | 1643 | if (xcp->regs[MIPSInst_FT(ir)] != 0) |
1831 | return 0; | 1644 | return 0; |
1832 | DPFROMREG(rv.d, MIPSInst_FS(ir)); | 1645 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
1833 | break; | 1646 | break; |
1834 | case fmovn_op: | 1647 | case fmovn_op: |
1648 | if (!cpu_has_mips_4_5_r) | ||
1649 | return SIGILL; | ||
1650 | |||
1835 | if (xcp->regs[MIPSInst_FT(ir)] == 0) | 1651 | if (xcp->regs[MIPSInst_FT(ir)] == 0) |
1836 | return 0; | 1652 | return 0; |
1837 | DPFROMREG(rv.d, MIPSInst_FS(ir)); | 1653 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
1838 | break; | 1654 | break; |
1839 | #endif | ||
1840 | case fabs_op: | 1655 | case fabs_op: |
1841 | handler.u = ieee754dp_abs; | 1656 | handler.u = ieee754dp_abs; |
1842 | goto dcopuop; | 1657 | goto dcopuop; |
@@ -1851,91 +1666,78 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1851 | goto copcsr; | 1666 | goto copcsr; |
1852 | 1667 | ||
1853 | /* binary op on handler */ | 1668 | /* binary op on handler */ |
1854 | dcopbop:{ | 1669 | dcopbop: |
1855 | ieee754dp fs, ft; | 1670 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1856 | 1671 | DPFROMREG(ft, MIPSInst_FT(ir)); | |
1857 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
1858 | DPFROMREG(ft, MIPSInst_FT(ir)); | ||
1859 | |||
1860 | rv.d = (*handler.b) (fs, ft); | ||
1861 | goto copcsr; | ||
1862 | } | ||
1863 | dcopuop:{ | ||
1864 | ieee754dp fs; | ||
1865 | |||
1866 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
1867 | rv.d = (*handler.u) (fs); | ||
1868 | goto copcsr; | ||
1869 | } | ||
1870 | 1672 | ||
1871 | /* unary conv ops */ | 1673 | rv.d = (*handler.b) (fs, ft); |
1872 | case fcvts_op:{ | 1674 | goto copcsr; |
1873 | ieee754dp fs; | 1675 | dcopuop: |
1676 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
1677 | rv.d = (*handler.u) (fs); | ||
1678 | goto copcsr; | ||
1874 | 1679 | ||
1680 | /* | ||
1681 | * unary conv ops | ||
1682 | */ | ||
1683 | case fcvts_op: | ||
1875 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1684 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1876 | rv.s = ieee754sp_fdp(fs); | 1685 | rv.s = ieee754sp_fdp(fs); |
1877 | rfmt = s_fmt; | 1686 | rfmt = s_fmt; |
1878 | goto copcsr; | 1687 | goto copcsr; |
1879 | } | 1688 | |
1880 | case fcvtd_op: | 1689 | case fcvtd_op: |
1881 | return SIGILL; /* not defined */ | 1690 | return SIGILL; /* not defined */ |
1882 | 1691 | ||
1883 | case fcvtw_op:{ | 1692 | case fcvtw_op: |
1884 | ieee754dp fs; | ||
1885 | |||
1886 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1693 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1887 | rv.w = ieee754dp_tint(fs); /* wrong */ | 1694 | rv.w = ieee754dp_tint(fs); /* wrong */ |
1888 | rfmt = w_fmt; | 1695 | rfmt = w_fmt; |
1889 | goto copcsr; | 1696 | goto copcsr; |
1890 | } | ||
1891 | 1697 | ||
1892 | #if __mips >= 2 || defined(__mips64) | ||
1893 | case fround_op: | 1698 | case fround_op: |
1894 | case ftrunc_op: | 1699 | case ftrunc_op: |
1895 | case fceil_op: | 1700 | case fceil_op: |
1896 | case ffloor_op:{ | 1701 | case ffloor_op: |
1897 | unsigned int oldrm = ieee754_csr.rm; | 1702 | if (!cpu_has_mips_2_3_4_5_r) |
1898 | ieee754dp fs; | 1703 | return SIGILL; |
1899 | 1704 | ||
1705 | oldrm = ieee754_csr.rm; | ||
1900 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1706 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1901 | ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; | 1707 | ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); |
1902 | rv.w = ieee754dp_tint(fs); | 1708 | rv.w = ieee754dp_tint(fs); |
1903 | ieee754_csr.rm = oldrm; | 1709 | ieee754_csr.rm = oldrm; |
1904 | rfmt = w_fmt; | 1710 | rfmt = w_fmt; |
1905 | goto copcsr; | 1711 | goto copcsr; |
1906 | } | ||
1907 | #endif | ||
1908 | 1712 | ||
1909 | #if defined(__mips64) | 1713 | case fcvtl_op: |
1910 | case fcvtl_op:{ | 1714 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1911 | ieee754dp fs; | 1715 | return SIGILL; |
1912 | 1716 | ||
1913 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1717 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1914 | rv.l = ieee754dp_tlong(fs); | 1718 | rv.l = ieee754dp_tlong(fs); |
1915 | rfmt = l_fmt; | 1719 | rfmt = l_fmt; |
1916 | goto copcsr; | 1720 | goto copcsr; |
1917 | } | ||
1918 | 1721 | ||
1919 | case froundl_op: | 1722 | case froundl_op: |
1920 | case ftruncl_op: | 1723 | case ftruncl_op: |
1921 | case fceill_op: | 1724 | case fceill_op: |
1922 | case ffloorl_op:{ | 1725 | case ffloorl_op: |
1923 | unsigned int oldrm = ieee754_csr.rm; | 1726 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1924 | ieee754dp fs; | 1727 | return SIGILL; |
1925 | 1728 | ||
1729 | oldrm = ieee754_csr.rm; | ||
1926 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1730 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1927 | ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; | 1731 | ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); |
1928 | rv.l = ieee754dp_tlong(fs); | 1732 | rv.l = ieee754dp_tlong(fs); |
1929 | ieee754_csr.rm = oldrm; | 1733 | ieee754_csr.rm = oldrm; |
1930 | rfmt = l_fmt; | 1734 | rfmt = l_fmt; |
1931 | goto copcsr; | 1735 | goto copcsr; |
1932 | } | ||
1933 | #endif /* __mips >= 3 */ | ||
1934 | 1736 | ||
1935 | default: | 1737 | default: |
1936 | if (MIPSInst_FUNC(ir) >= fcmp_op) { | 1738 | if (MIPSInst_FUNC(ir) >= fcmp_op) { |
1937 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; | 1739 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
1938 | ieee754dp fs, ft; | 1740 | union ieee754dp fs, ft; |
1939 | 1741 | ||
1940 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1742 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1941 | DPFROMREG(ft, MIPSInst_FT(ir)); | 1743 | DPFROMREG(ft, MIPSInst_FT(ir)); |
@@ -1957,11 +1759,8 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1957 | break; | 1759 | break; |
1958 | } | 1760 | } |
1959 | break; | 1761 | break; |
1960 | } | ||
1961 | |||
1962 | case w_fmt:{ | ||
1963 | ieee754sp fs; | ||
1964 | 1762 | ||
1763 | case w_fmt: | ||
1965 | switch (MIPSInst_FUNC(ir)) { | 1764 | switch (MIPSInst_FUNC(ir)) { |
1966 | case fcvts_op: | 1765 | case fcvts_op: |
1967 | /* convert word to single precision real */ | 1766 | /* convert word to single precision real */ |
@@ -1981,9 +1780,11 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1981 | break; | 1780 | break; |
1982 | } | 1781 | } |
1983 | 1782 | ||
1984 | #if defined(__mips64) | 1783 | case l_fmt: |
1985 | case l_fmt:{ | 1784 | |
1986 | u64 bits; | 1785 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1786 | return SIGILL; | ||
1787 | |||
1987 | DIFROMREG(bits, MIPSInst_FS(ir)); | 1788 | DIFROMREG(bits, MIPSInst_FS(ir)); |
1988 | 1789 | ||
1989 | switch (MIPSInst_FUNC(ir)) { | 1790 | switch (MIPSInst_FUNC(ir)) { |
@@ -2001,8 +1802,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2001 | return SIGILL; | 1802 | return SIGILL; |
2002 | } | 1803 | } |
2003 | break; | 1804 | break; |
2004 | } | ||
2005 | #endif | ||
2006 | 1805 | ||
2007 | default: | 1806 | default: |
2008 | return SIGILL; | 1807 | return SIGILL; |
@@ -2017,7 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2017 | */ | 1816 | */ |
2018 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; | 1817 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; |
2019 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { | 1818 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { |
2020 | /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ | 1819 | /*printk ("SIGFPE: FPU csr = %08x\n",ctx->fcr31); */ |
2021 | return SIGFPE; | 1820 | return SIGFPE; |
2022 | } | 1821 | } |
2023 | 1822 | ||
@@ -2025,18 +1824,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2025 | * Now we can safely write the result back to the register file. | 1824 | * Now we can safely write the result back to the register file. |
2026 | */ | 1825 | */ |
2027 | switch (rfmt) { | 1826 | switch (rfmt) { |
2028 | case -1:{ | 1827 | case -1: |
2029 | #if __mips >= 4 | 1828 | |
2030 | cond = fpucondbit[MIPSInst_FD(ir) >> 2]; | 1829 | if (cpu_has_mips_4_5_r) |
2031 | #else | 1830 | cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; |
2032 | cond = FPU_CSR_COND; | 1831 | else |
2033 | #endif | 1832 | cbit = FPU_CSR_COND; |
2034 | if (rv.w) | 1833 | if (rv.w) |
2035 | ctx->fcr31 |= cond; | 1834 | ctx->fcr31 |= cbit; |
2036 | else | 1835 | else |
2037 | ctx->fcr31 &= ~cond; | 1836 | ctx->fcr31 &= ~cbit; |
2038 | break; | 1837 | break; |
2039 | } | 1838 | |
2040 | case d_fmt: | 1839 | case d_fmt: |
2041 | DPTOREG(rv.d, MIPSInst_FD(ir)); | 1840 | DPTOREG(rv.d, MIPSInst_FD(ir)); |
2042 | break; | 1841 | break; |
@@ -2046,11 +1845,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2046 | case w_fmt: | 1845 | case w_fmt: |
2047 | SITOREG(rv.w, MIPSInst_FD(ir)); | 1846 | SITOREG(rv.w, MIPSInst_FD(ir)); |
2048 | break; | 1847 | break; |
2049 | #if defined(__mips64) | ||
2050 | case l_fmt: | 1848 | case l_fmt: |
1849 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | ||
1850 | return SIGILL; | ||
1851 | |||
2051 | DITOREG(rv.l, MIPSInst_FD(ir)); | 1852 | DITOREG(rv.l, MIPSInst_FD(ir)); |
2052 | break; | 1853 | break; |
2053 | #endif | ||
2054 | default: | 1854 | default: |
2055 | return SIGILL; | 1855 | return SIGILL; |
2056 | } | 1856 | } |
@@ -2138,11 +1938,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2138 | * ieee754_csr. But ieee754_csr.rm is ieee | 1938 | * ieee754_csr. But ieee754_csr.rm is ieee |
2139 | * library modes. (not mips rounding mode) | 1939 | * library modes. (not mips rounding mode) |
2140 | */ | 1940 | */ |
2141 | /* convert to ieee library modes */ | ||
2142 | ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; | ||
2143 | sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr); | 1941 | sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr); |
2144 | /* revert to mips rounding mode */ | ||
2145 | ieee754_csr.rm = mips_rm[ieee754_csr.rm]; | ||
2146 | } | 1942 | } |
2147 | 1943 | ||
2148 | if (has_fpu) | 1944 | if (has_fpu) |
@@ -2155,58 +1951,8 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2155 | 1951 | ||
2156 | /* SIGILL indicates a non-fpu instruction */ | 1952 | /* SIGILL indicates a non-fpu instruction */ |
2157 | if (sig == SIGILL && xcp->cp0_epc != oldepc) | 1953 | if (sig == SIGILL && xcp->cp0_epc != oldepc) |
2158 | /* but if epc has advanced, then ignore it */ | 1954 | /* but if EPC has advanced, then ignore it */ |
2159 | sig = 0; | 1955 | sig = 0; |
2160 | 1956 | ||
2161 | return sig; | 1957 | return sig; |
2162 | } | 1958 | } |
2163 | |||
2164 | #ifdef CONFIG_DEBUG_FS | ||
2165 | |||
2166 | static int fpuemu_stat_get(void *data, u64 *val) | ||
2167 | { | ||
2168 | int cpu; | ||
2169 | unsigned long sum = 0; | ||
2170 | for_each_online_cpu(cpu) { | ||
2171 | struct mips_fpu_emulator_stats *ps; | ||
2172 | local_t *pv; | ||
2173 | ps = &per_cpu(fpuemustats, cpu); | ||
2174 | pv = (void *)ps + (unsigned long)data; | ||
2175 | sum += local_read(pv); | ||
2176 | } | ||
2177 | *val = sum; | ||
2178 | return 0; | ||
2179 | } | ||
2180 | DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n"); | ||
2181 | |||
2182 | extern struct dentry *mips_debugfs_dir; | ||
2183 | static int __init debugfs_fpuemu(void) | ||
2184 | { | ||
2185 | struct dentry *d, *dir; | ||
2186 | |||
2187 | if (!mips_debugfs_dir) | ||
2188 | return -ENODEV; | ||
2189 | dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir); | ||
2190 | if (!dir) | ||
2191 | return -ENOMEM; | ||
2192 | |||
2193 | #define FPU_STAT_CREATE(M) \ | ||
2194 | do { \ | ||
2195 | d = debugfs_create_file(#M , S_IRUGO, dir, \ | ||
2196 | (void *)offsetof(struct mips_fpu_emulator_stats, M), \ | ||
2197 | &fops_fpuemu_stat); \ | ||
2198 | if (!d) \ | ||
2199 | return -ENOMEM; \ | ||
2200 | } while (0) | ||
2201 | |||
2202 | FPU_STAT_CREATE(emulated); | ||
2203 | FPU_STAT_CREATE(loads); | ||
2204 | FPU_STAT_CREATE(stores); | ||
2205 | FPU_STAT_CREATE(cp1ops); | ||
2206 | FPU_STAT_CREATE(cp1xops); | ||
2207 | FPU_STAT_CREATE(errors); | ||
2208 | |||
2209 | return 0; | ||
2210 | } | ||
2211 | __initcall(debugfs_fpuemu); | ||
2212 | #endif | ||
diff --git a/arch/mips/math-emu/dp_add.c b/arch/mips/math-emu/dp_add.c index c57c8adc42c4..7f64577df984 100644 --- a/arch/mips/math-emu/dp_add.c +++ b/arch/mips/math-emu/dp_add.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,24 +16,22 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | * | ||
25 | */ | 20 | */ |
26 | 21 | ||
27 | |||
28 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
29 | 23 | ||
30 | ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) | 24 | union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y) |
31 | { | 25 | { |
26 | int s; | ||
27 | |||
32 | COMPXDP; | 28 | COMPXDP; |
33 | COMPYDP; | 29 | COMPYDP; |
34 | 30 | ||
35 | EXPLODEXDP; | 31 | EXPLODEXDP; |
36 | EXPLODEYDP; | 32 | EXPLODEYDP; |
37 | 33 | ||
38 | CLEARCX; | 34 | ieee754_clearcx(); |
39 | 35 | ||
40 | FLUSHXDP; | 36 | FLUSHXDP; |
41 | FLUSHYDP; | 37 | FLUSHYDP; |
@@ -52,8 +48,8 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) | |||
52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | 48 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
53 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | 49 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
54 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
55 | SETCX(IEEE754_INVALID_OPERATION); | 51 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
56 | return ieee754dp_nanxcpt(ieee754dp_indef(), "add", x, y); | 52 | return ieee754dp_nanxcpt(ieee754dp_indef()); |
57 | 53 | ||
58 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | 54 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
59 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | 55 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
@@ -69,14 +65,14 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) | |||
69 | return x; | 65 | return x; |
70 | 66 | ||
71 | 67 | ||
72 | /* Infinity handling | 68 | /* |
73 | */ | 69 | * Infinity handling |
74 | 70 | */ | |
75 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | 71 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
76 | if (xs == ys) | 72 | if (xs == ys) |
77 | return x; | 73 | return x; |
78 | SETCX(IEEE754_INVALID_OPERATION); | 74 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
79 | return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y); | 75 | return ieee754dp_indef(); |
80 | 76 | ||
81 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | 77 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
82 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
@@ -88,15 +84,14 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) | |||
88 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
89 | return x; | 85 | return x; |
90 | 86 | ||
91 | /* Zero handling | 87 | /* |
92 | */ | 88 | * Zero handling |
93 | 89 | */ | |
94 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
95 | if (xs == ys) | 91 | if (xs == ys) |
96 | return x; | 92 | return x; |
97 | else | 93 | else |
98 | return ieee754dp_zero(ieee754_csr.rm == | 94 | return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); |
99 | IEEE754_RD); | ||
100 | 95 | ||
101 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | 96 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
102 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | 97 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
@@ -125,20 +120,24 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) | |||
125 | assert(xm & DP_HIDDEN_BIT); | 120 | assert(xm & DP_HIDDEN_BIT); |
126 | assert(ym & DP_HIDDEN_BIT); | 121 | assert(ym & DP_HIDDEN_BIT); |
127 | 122 | ||
128 | /* provide guard,round and stick bit space */ | 123 | /* |
124 | * Provide guard,round and stick bit space. | ||
125 | */ | ||
129 | xm <<= 3; | 126 | xm <<= 3; |
130 | ym <<= 3; | 127 | ym <<= 3; |
131 | 128 | ||
132 | if (xe > ye) { | 129 | if (xe > ye) { |
133 | /* have to shift y fraction right to align | 130 | /* |
131 | * Have to shift y fraction right to align. | ||
134 | */ | 132 | */ |
135 | int s = xe - ye; | 133 | s = xe - ye; |
136 | ym = XDPSRS(ym, s); | 134 | ym = XDPSRS(ym, s); |
137 | ye += s; | 135 | ye += s; |
138 | } else if (ye > xe) { | 136 | } else if (ye > xe) { |
139 | /* have to shift x fraction right to align | 137 | /* |
138 | * Have to shift x fraction right to align. | ||
140 | */ | 139 | */ |
141 | int s = ye - xe; | 140 | s = ye - xe; |
142 | xm = XDPSRS(xm, s); | 141 | xm = XDPSRS(xm, s); |
143 | xe += s; | 142 | xe += s; |
144 | } | 143 | } |
@@ -146,14 +145,15 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) | |||
146 | assert(xe <= DP_EMAX); | 145 | assert(xe <= DP_EMAX); |
147 | 146 | ||
148 | if (xs == ys) { | 147 | if (xs == ys) { |
149 | /* generate 28 bit result of adding two 27 bit numbers | 148 | /* |
150 | * leaving result in xm,xs,xe | 149 | * Generate 28 bit result of adding two 27 bit numbers |
150 | * leaving result in xm, xs and xe. | ||
151 | */ | 151 | */ |
152 | xm = xm + ym; | 152 | xm = xm + ym; |
153 | xe = xe; | 153 | xe = xe; |
154 | xs = xs; | 154 | xs = xs; |
155 | 155 | ||
156 | if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ | 156 | if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */ |
157 | xm = XDPSRS1(xm); | 157 | xm = XDPSRS1(xm); |
158 | xe++; | 158 | xe++; |
159 | } | 159 | } |
@@ -168,15 +168,16 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) | |||
168 | xs = ys; | 168 | xs = ys; |
169 | } | 169 | } |
170 | if (xm == 0) | 170 | if (xm == 0) |
171 | return ieee754dp_zero(ieee754_csr.rm == | 171 | return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); |
172 | IEEE754_RD); | ||
173 | 172 | ||
174 | /* normalize to rounding precision */ | 173 | /* |
175 | while ((xm >> (DP_MBITS + 3)) == 0) { | 174 | * Normalize to rounding precision. |
175 | */ | ||
176 | while ((xm >> (DP_FBITS + 3)) == 0) { | ||
176 | xm <<= 1; | 177 | xm <<= 1; |
177 | xe--; | 178 | xe--; |
178 | } | 179 | } |
179 | |||
180 | } | 180 | } |
181 | DPNORMRET2(xs, xe, xm, "add", x, y); | 181 | |
182 | return ieee754dp_format(xs, xe, xm); | ||
182 | } | 183 | } |
diff --git a/arch/mips/math-emu/dp_cmp.c b/arch/mips/math-emu/dp_cmp.c index 0f32486b0ed9..30f95f6e9ac4 100644 --- a/arch/mips/math-emu/dp_cmp.c +++ b/arch/mips/math-emu/dp_cmp.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,16 +16,16 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
28 | 23 | ||
29 | int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp, int sig) | 24 | int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cmp, int sig) |
30 | { | 25 | { |
26 | s64 vx; | ||
27 | s64 vy; | ||
28 | |||
31 | COMPXDP; | 29 | COMPXDP; |
32 | COMPYDP; | 30 | COMPYDP; |
33 | 31 | ||
@@ -35,21 +33,21 @@ int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp, int sig) | |||
35 | EXPLODEYDP; | 33 | EXPLODEYDP; |
36 | FLUSHXDP; | 34 | FLUSHXDP; |
37 | FLUSHYDP; | 35 | FLUSHYDP; |
38 | CLEARCX; /* Even clear inexact flag here */ | 36 | ieee754_clearcx(); /* Even clear inexact flag here */ |
39 | 37 | ||
40 | if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) { | 38 | if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) { |
41 | if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) | 39 | if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) |
42 | SETCX(IEEE754_INVALID_OPERATION); | 40 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
43 | if (cmp & IEEE754_CUN) | 41 | if (cmp & IEEE754_CUN) |
44 | return 1; | 42 | return 1; |
45 | if (cmp & (IEEE754_CLT | IEEE754_CGT)) { | 43 | if (cmp & (IEEE754_CLT | IEEE754_CGT)) { |
46 | if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION)) | 44 | if (sig && ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) |
47 | return ieee754si_xcpt(0, "fcmpf", x); | 45 | return 0; |
48 | } | 46 | } |
49 | return 0; | 47 | return 0; |
50 | } else { | 48 | } else { |
51 | s64 vx = x.bits; | 49 | vx = x.bits; |
52 | s64 vy = y.bits; | 50 | vy = y.bits; |
53 | 51 | ||
54 | if (vx < 0) | 52 | if (vx < 0) |
55 | vx = -vx ^ DP_SIGN_BIT; | 53 | vx = -vx ^ DP_SIGN_BIT; |
diff --git a/arch/mips/math-emu/dp_div.c b/arch/mips/math-emu/dp_div.c index a1bce1b7c09c..bef0e55e5938 100644 --- a/arch/mips/math-emu/dp_div.c +++ b/arch/mips/math-emu/dp_div.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,23 +16,24 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
28 | 23 | ||
29 | ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) | 24 | union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y) |
30 | { | 25 | { |
26 | u64 rm; | ||
27 | int re; | ||
28 | u64 bm; | ||
29 | |||
31 | COMPXDP; | 30 | COMPXDP; |
32 | COMPYDP; | 31 | COMPYDP; |
33 | 32 | ||
34 | EXPLODEXDP; | 33 | EXPLODEXDP; |
35 | EXPLODEYDP; | 34 | EXPLODEYDP; |
36 | 35 | ||
37 | CLEARCX; | 36 | ieee754_clearcx(); |
38 | 37 | ||
39 | FLUSHXDP; | 38 | FLUSHXDP; |
40 | FLUSHYDP; | 39 | FLUSHYDP; |
@@ -51,8 +50,8 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) | |||
51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | 51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
53 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | 52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
54 | SETCX(IEEE754_INVALID_OPERATION); | 53 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
55 | return ieee754dp_nanxcpt(ieee754dp_indef(), "div", x, y); | 54 | return ieee754dp_nanxcpt(ieee754dp_indef()); |
56 | 55 | ||
57 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | 56 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
58 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | 57 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
@@ -68,12 +67,12 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) | |||
68 | return x; | 67 | return x; |
69 | 68 | ||
70 | 69 | ||
71 | /* Infinity handling | 70 | /* |
72 | */ | 71 | * Infinity handling |
73 | 72 | */ | |
74 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | 73 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
75 | SETCX(IEEE754_INVALID_OPERATION); | 74 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
76 | return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); | 75 | return ieee754dp_indef(); |
77 | 76 | ||
78 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | 77 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
79 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
@@ -85,17 +84,17 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) | |||
85 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
86 | return ieee754dp_inf(xs ^ ys); | 85 | return ieee754dp_inf(xs ^ ys); |
87 | 86 | ||
88 | /* Zero handling | 87 | /* |
89 | */ | 88 | * Zero handling |
90 | 89 | */ | |
91 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
92 | SETCX(IEEE754_INVALID_OPERATION); | 91 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
93 | return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); | 92 | return ieee754dp_indef(); |
94 | 93 | ||
95 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | 94 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
96 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | 95 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
97 | SETCX(IEEE754_ZERO_DIVIDE); | 96 | ieee754_setcx(IEEE754_ZERO_DIVIDE); |
98 | return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y); | 97 | return ieee754dp_inf(xs ^ ys); |
99 | 98 | ||
100 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | 99 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): |
101 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | 100 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): |
@@ -122,35 +121,34 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) | |||
122 | xm <<= 3; | 121 | xm <<= 3; |
123 | ym <<= 3; | 122 | ym <<= 3; |
124 | 123 | ||
125 | { | 124 | /* now the dirty work */ |
126 | /* now the dirty work */ | ||
127 | |||
128 | u64 rm = 0; | ||
129 | int re = xe - ye; | ||
130 | u64 bm; | ||
131 | |||
132 | for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) { | ||
133 | if (xm >= ym) { | ||
134 | xm -= ym; | ||
135 | rm |= bm; | ||
136 | if (xm == 0) | ||
137 | break; | ||
138 | } | ||
139 | xm <<= 1; | ||
140 | } | ||
141 | rm <<= 1; | ||
142 | if (xm) | ||
143 | rm |= 1; /* have remainder, set sticky */ | ||
144 | 125 | ||
145 | assert(rm); | 126 | rm = 0; |
127 | re = xe - ye; | ||
146 | 128 | ||
147 | /* normalise rm to rounding precision ? | 129 | for (bm = DP_MBIT(DP_FBITS + 2); bm; bm >>= 1) { |
148 | */ | 130 | if (xm >= ym) { |
149 | while ((rm >> (DP_MBITS + 3)) == 0) { | 131 | xm -= ym; |
150 | rm <<= 1; | 132 | rm |= bm; |
151 | re--; | 133 | if (xm == 0) |
134 | break; | ||
152 | } | 135 | } |
136 | xm <<= 1; | ||
137 | } | ||
138 | |||
139 | rm <<= 1; | ||
140 | if (xm) | ||
141 | rm |= 1; /* have remainder, set sticky */ | ||
153 | 142 | ||
154 | DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); | 143 | assert(rm); |
144 | |||
145 | /* | ||
146 | * Normalise rm to rounding precision ? | ||
147 | */ | ||
148 | while ((rm >> (DP_FBITS + 3)) == 0) { | ||
149 | rm <<= 1; | ||
150 | re--; | ||
155 | } | 151 | } |
152 | |||
153 | return ieee754dp_format(xs == ys ? 0 : 1, re, rm); | ||
156 | } | 154 | } |
diff --git a/arch/mips/math-emu/dp_fint.c b/arch/mips/math-emu/dp_fint.c index 88571288c9e0..10258f0afd69 100644 --- a/arch/mips/math-emu/dp_fint.c +++ b/arch/mips/math-emu/dp_fint.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,21 +16,18 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
28 | 23 | ||
29 | ieee754dp ieee754dp_fint(int x) | 24 | union ieee754dp ieee754dp_fint(int x) |
30 | { | 25 | { |
31 | u64 xm; | 26 | u64 xm; |
32 | int xe; | 27 | int xe; |
33 | int xs; | 28 | int xs; |
34 | 29 | ||
35 | CLEARCX; | 30 | ieee754_clearcx(); |
36 | 31 | ||
37 | if (x == 0) | 32 | if (x == 0) |
38 | return ieee754dp_zero(0); | 33 | return ieee754dp_zero(0); |
@@ -51,29 +46,11 @@ ieee754dp ieee754dp_fint(int x) | |||
51 | xm = x; | 46 | xm = x; |
52 | } | 47 | } |
53 | 48 | ||
54 | #if 1 | ||
55 | /* normalize - result can never be inexact or overflow */ | 49 | /* normalize - result can never be inexact or overflow */ |
56 | xe = DP_MBITS; | 50 | xe = DP_FBITS; |
57 | while ((xm >> DP_MBITS) == 0) { | 51 | while ((xm >> DP_FBITS) == 0) { |
58 | xm <<= 1; | 52 | xm <<= 1; |
59 | xe--; | 53 | xe--; |
60 | } | 54 | } |
61 | return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); | 55 | return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); |
62 | #else | ||
63 | /* normalize */ | ||
64 | xe = DP_MBITS + 3; | ||
65 | while ((xm >> (DP_MBITS + 3)) == 0) { | ||
66 | xm <<= 1; | ||
67 | xe--; | ||
68 | } | ||
69 | DPNORMRET1(xs, xe, xm, "fint", x); | ||
70 | #endif | ||
71 | } | ||
72 | |||
73 | ieee754dp ieee754dp_funs(unsigned int u) | ||
74 | { | ||
75 | if ((int) u < 0) | ||
76 | return ieee754dp_add(ieee754dp_1e31(), | ||
77 | ieee754dp_fint(u & ~(1 << 31))); | ||
78 | return ieee754dp_fint(u); | ||
79 | } | 56 | } |
diff --git a/arch/mips/math-emu/dp_flong.c b/arch/mips/math-emu/dp_flong.c index 14fc01ec742d..a267c2e39d78 100644 --- a/arch/mips/math-emu/dp_flong.c +++ b/arch/mips/math-emu/dp_flong.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,21 +16,18 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
28 | 23 | ||
29 | ieee754dp ieee754dp_flong(s64 x) | 24 | union ieee754dp ieee754dp_flong(s64 x) |
30 | { | 25 | { |
31 | u64 xm; | 26 | u64 xm; |
32 | int xe; | 27 | int xe; |
33 | int xs; | 28 | int xs; |
34 | 29 | ||
35 | CLEARCX; | 30 | ieee754_clearcx(); |
36 | 31 | ||
37 | if (x == 0) | 32 | if (x == 0) |
38 | return ieee754dp_zero(0); | 33 | return ieee754dp_zero(0); |
@@ -52,26 +47,19 @@ ieee754dp ieee754dp_flong(s64 x) | |||
52 | } | 47 | } |
53 | 48 | ||
54 | /* normalize */ | 49 | /* normalize */ |
55 | xe = DP_MBITS + 3; | 50 | xe = DP_FBITS + 3; |
56 | if (xm >> (DP_MBITS + 1 + 3)) { | 51 | if (xm >> (DP_FBITS + 1 + 3)) { |
57 | /* shunt out overflow bits */ | 52 | /* shunt out overflow bits */ |
58 | while (xm >> (DP_MBITS + 1 + 3)) { | 53 | while (xm >> (DP_FBITS + 1 + 3)) { |
59 | XDPSRSX1(); | 54 | XDPSRSX1(); |
60 | } | 55 | } |
61 | } else { | 56 | } else { |
62 | /* normalize in grs extended double precision */ | 57 | /* normalize in grs extended double precision */ |
63 | while ((xm >> (DP_MBITS + 3)) == 0) { | 58 | while ((xm >> (DP_FBITS + 3)) == 0) { |
64 | xm <<= 1; | 59 | xm <<= 1; |
65 | xe--; | 60 | xe--; |
66 | } | 61 | } |
67 | } | 62 | } |
68 | DPNORMRET1(xs, xe, xm, "dp_flong", x); | ||
69 | } | ||
70 | 63 | ||
71 | ieee754dp ieee754dp_fulong(u64 u) | 64 | return ieee754dp_format(xs, xe, xm); |
72 | { | ||
73 | if ((s64) u < 0) | ||
74 | return ieee754dp_add(ieee754dp_1e63(), | ||
75 | ieee754dp_flong(u & ~(1ULL << 63))); | ||
76 | return ieee754dp_flong(u); | ||
77 | } | 65 | } |
diff --git a/arch/mips/math-emu/dp_frexp.c b/arch/mips/math-emu/dp_frexp.c deleted file mode 100644 index cb15a5eaecbb..000000000000 --- a/arch/mips/math-emu/dp_frexp.c +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | /* IEEE754 floating point arithmetic | ||
2 | * double precision: common utilities | ||
3 | */ | ||
4 | /* | ||
5 | * MIPS floating point support | ||
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
7 | * | ||
8 | * ######################################################################## | ||
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 (Version 2) as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
17 | * for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include "ieee754dp.h" | ||
28 | |||
29 | /* close to ieeep754dp_logb | ||
30 | */ | ||
31 | ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr) | ||
32 | { | ||
33 | COMPXDP; | ||
34 | CLEARCX; | ||
35 | EXPLODEXDP; | ||
36 | |||
37 | switch (xc) { | ||
38 | case IEEE754_CLASS_SNAN: | ||
39 | case IEEE754_CLASS_QNAN: | ||
40 | case IEEE754_CLASS_INF: | ||
41 | case IEEE754_CLASS_ZERO: | ||
42 | *eptr = 0; | ||
43 | return x; | ||
44 | case IEEE754_CLASS_DNORM: | ||
45 | DPDNORMX; | ||
46 | break; | ||
47 | case IEEE754_CLASS_NORM: | ||
48 | break; | ||
49 | } | ||
50 | *eptr = xe + 1; | ||
51 | return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT); | ||
52 | } | ||
diff --git a/arch/mips/math-emu/dp_fsp.c b/arch/mips/math-emu/dp_fsp.c index daed6834dc15..ffb69c5830b0 100644 --- a/arch/mips/math-emu/dp_fsp.c +++ b/arch/mips/math-emu/dp_fsp.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,56 +16,58 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | 22 | #include "ieee754sp.h" | |
27 | #include "ieee754dp.h" | 23 | #include "ieee754dp.h" |
28 | 24 | ||
29 | ieee754dp ieee754dp_fsp(ieee754sp x) | 25 | union ieee754dp ieee754dp_fsp(union ieee754sp x) |
30 | { | 26 | { |
31 | COMPXSP; | 27 | COMPXSP; |
32 | 28 | ||
33 | EXPLODEXSP; | 29 | EXPLODEXSP; |
34 | 30 | ||
35 | CLEARCX; | 31 | ieee754_clearcx(); |
36 | 32 | ||
37 | FLUSHXSP; | 33 | FLUSHXSP; |
38 | 34 | ||
39 | switch (xc) { | 35 | switch (xc) { |
40 | case IEEE754_CLASS_SNAN: | 36 | case IEEE754_CLASS_SNAN: |
41 | SETCX(IEEE754_INVALID_OPERATION); | 37 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
42 | return ieee754dp_nanxcpt(ieee754dp_indef(), "fsp"); | 38 | return ieee754dp_nanxcpt(ieee754dp_indef()); |
39 | |||
43 | case IEEE754_CLASS_QNAN: | 40 | case IEEE754_CLASS_QNAN: |
44 | return ieee754dp_nanxcpt(builddp(xs, | 41 | return ieee754dp_nanxcpt(builddp(xs, |
45 | DP_EMAX + 1 + DP_EBIAS, | 42 | DP_EMAX + 1 + DP_EBIAS, |
46 | ((u64) xm | 43 | ((u64) xm |
47 | << (DP_MBITS - | 44 | << (DP_FBITS - |
48 | SP_MBITS))), "fsp", | 45 | SP_FBITS)))); |
49 | x); | ||
50 | case IEEE754_CLASS_INF: | 46 | case IEEE754_CLASS_INF: |
51 | return ieee754dp_inf(xs); | 47 | return ieee754dp_inf(xs); |
48 | |||
52 | case IEEE754_CLASS_ZERO: | 49 | case IEEE754_CLASS_ZERO: |
53 | return ieee754dp_zero(xs); | 50 | return ieee754dp_zero(xs); |
51 | |||
54 | case IEEE754_CLASS_DNORM: | 52 | case IEEE754_CLASS_DNORM: |
55 | /* normalize */ | 53 | /* normalize */ |
56 | while ((xm >> SP_MBITS) == 0) { | 54 | while ((xm >> SP_FBITS) == 0) { |
57 | xm <<= 1; | 55 | xm <<= 1; |
58 | xe--; | 56 | xe--; |
59 | } | 57 | } |
60 | break; | 58 | break; |
59 | |||
61 | case IEEE754_CLASS_NORM: | 60 | case IEEE754_CLASS_NORM: |
62 | break; | 61 | break; |
63 | } | 62 | } |
64 | 63 | ||
65 | /* CAN'T possibly overflow,underflow, or need rounding | 64 | /* |
65 | * Can't possibly overflow,underflow, or need rounding | ||
66 | */ | 66 | */ |
67 | 67 | ||
68 | /* drop the hidden bit */ | 68 | /* drop the hidden bit */ |
69 | xm &= ~SP_HIDDEN_BIT; | 69 | xm &= ~SP_HIDDEN_BIT; |
70 | 70 | ||
71 | return builddp(xs, xe + DP_EBIAS, | 71 | return builddp(xs, xe + DP_EBIAS, |
72 | (u64) xm << (DP_MBITS - SP_MBITS)); | 72 | (u64) xm << (DP_FBITS - SP_FBITS)); |
73 | } | 73 | } |
diff --git a/arch/mips/math-emu/dp_logb.c b/arch/mips/math-emu/dp_logb.c deleted file mode 100644 index 151127e59f5c..000000000000 --- a/arch/mips/math-emu/dp_logb.c +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | /* IEEE754 floating point arithmetic | ||
2 | * double precision: common utilities | ||
3 | */ | ||
4 | /* | ||
5 | * MIPS floating point support | ||
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
7 | * | ||
8 | * ######################################################################## | ||
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 (Version 2) as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
17 | * for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include "ieee754dp.h" | ||
28 | |||
29 | ieee754dp ieee754dp_logb(ieee754dp x) | ||
30 | { | ||
31 | COMPXDP; | ||
32 | |||
33 | CLEARCX; | ||
34 | |||
35 | EXPLODEXDP; | ||
36 | |||
37 | switch (xc) { | ||
38 | case IEEE754_CLASS_SNAN: | ||
39 | return ieee754dp_nanxcpt(x, "logb", x); | ||
40 | case IEEE754_CLASS_QNAN: | ||
41 | return x; | ||
42 | case IEEE754_CLASS_INF: | ||
43 | return ieee754dp_inf(0); | ||
44 | case IEEE754_CLASS_ZERO: | ||
45 | return ieee754dp_inf(1); | ||
46 | case IEEE754_CLASS_DNORM: | ||
47 | DPDNORMX; | ||
48 | break; | ||
49 | case IEEE754_CLASS_NORM: | ||
50 | break; | ||
51 | } | ||
52 | return ieee754dp_fint(xe); | ||
53 | } | ||
diff --git a/arch/mips/math-emu/dp_modf.c b/arch/mips/math-emu/dp_modf.c deleted file mode 100644 index b01f9cf6d402..000000000000 --- a/arch/mips/math-emu/dp_modf.c +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | /* IEEE754 floating point arithmetic | ||
2 | * double precision: common utilities | ||
3 | */ | ||
4 | /* | ||
5 | * MIPS floating point support | ||
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
7 | * | ||
8 | * ######################################################################## | ||
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 (Version 2) as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
17 | * for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include "ieee754dp.h" | ||
28 | |||
29 | /* modf function is always exact for a finite number | ||
30 | */ | ||
31 | ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp *ip) | ||
32 | { | ||
33 | COMPXDP; | ||
34 | |||
35 | CLEARCX; | ||
36 | |||
37 | EXPLODEXDP; | ||
38 | |||
39 | switch (xc) { | ||
40 | case IEEE754_CLASS_SNAN: | ||
41 | case IEEE754_CLASS_QNAN: | ||
42 | case IEEE754_CLASS_INF: | ||
43 | case IEEE754_CLASS_ZERO: | ||
44 | *ip = x; | ||
45 | return x; | ||
46 | case IEEE754_CLASS_DNORM: | ||
47 | /* far to small */ | ||
48 | *ip = ieee754dp_zero(xs); | ||
49 | return x; | ||
50 | case IEEE754_CLASS_NORM: | ||
51 | break; | ||
52 | } | ||
53 | if (xe < 0) { | ||
54 | *ip = ieee754dp_zero(xs); | ||
55 | return x; | ||
56 | } | ||
57 | if (xe >= DP_MBITS) { | ||
58 | *ip = x; | ||
59 | return ieee754dp_zero(xs); | ||
60 | } | ||
61 | /* generate ipart mantissa by clearing bottom bits | ||
62 | */ | ||
63 | *ip = builddp(xs, xe + DP_EBIAS, | ||
64 | ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) & | ||
65 | ~DP_HIDDEN_BIT); | ||
66 | |||
67 | /* generate fpart mantissa by clearing top bits | ||
68 | * and normalizing (must be able to normalize) | ||
69 | */ | ||
70 | xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe)); | ||
71 | if (xm == 0) | ||
72 | return ieee754dp_zero(xs); | ||
73 | |||
74 | while ((xm >> DP_MBITS) == 0) { | ||
75 | xm <<= 1; | ||
76 | xe--; | ||
77 | } | ||
78 | return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); | ||
79 | } | ||
diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index 09175f461920..d3acdedb5b9d 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,23 +16,32 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
28 | 23 | ||
29 | ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) | 24 | union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) |
30 | { | 25 | { |
26 | int re; | ||
27 | int rs; | ||
28 | u64 rm; | ||
29 | unsigned lxm; | ||
30 | unsigned hxm; | ||
31 | unsigned lym; | ||
32 | unsigned hym; | ||
33 | u64 lrm; | ||
34 | u64 hrm; | ||
35 | u64 t; | ||
36 | u64 at; | ||
37 | |||
31 | COMPXDP; | 38 | COMPXDP; |
32 | COMPYDP; | 39 | COMPYDP; |
33 | 40 | ||
34 | EXPLODEXDP; | 41 | EXPLODEXDP; |
35 | EXPLODEYDP; | 42 | EXPLODEYDP; |
36 | 43 | ||
37 | CLEARCX; | 44 | ieee754_clearcx(); |
38 | 45 | ||
39 | FLUSHXDP; | 46 | FLUSHXDP; |
40 | FLUSHYDP; | 47 | FLUSHYDP; |
@@ -51,8 +58,8 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) | |||
51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | 58 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | 59 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
53 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | 60 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
54 | SETCX(IEEE754_INVALID_OPERATION); | 61 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
55 | return ieee754dp_nanxcpt(ieee754dp_indef(), "mul", x, y); | 62 | return ieee754dp_nanxcpt(ieee754dp_indef()); |
56 | 63 | ||
57 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | 64 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
58 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | 65 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
@@ -68,12 +75,13 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) | |||
68 | return x; | 75 | return x; |
69 | 76 | ||
70 | 77 | ||
71 | /* Infinity handling */ | 78 | /* |
72 | 79 | * Infinity handling | |
80 | */ | ||
73 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | 81 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): |
74 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | 82 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
75 | SETCX(IEEE754_INVALID_OPERATION); | 83 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
76 | return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y); | 84 | return ieee754dp_indef(); |
77 | 85 | ||
78 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | 86 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
79 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | 87 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): |
@@ -107,70 +115,59 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) | |||
107 | /* rm = xm * ym, re = xe+ye basically */ | 115 | /* rm = xm * ym, re = xe+ye basically */ |
108 | assert(xm & DP_HIDDEN_BIT); | 116 | assert(xm & DP_HIDDEN_BIT); |
109 | assert(ym & DP_HIDDEN_BIT); | 117 | assert(ym & DP_HIDDEN_BIT); |
110 | { | ||
111 | int re = xe + ye; | ||
112 | int rs = xs ^ ys; | ||
113 | u64 rm; | ||
114 | 118 | ||
115 | /* shunt to top of word */ | 119 | re = xe + ye; |
116 | xm <<= 64 - (DP_MBITS + 1); | 120 | rs = xs ^ ys; |
117 | ym <<= 64 - (DP_MBITS + 1); | 121 | |
122 | /* shunt to top of word */ | ||
123 | xm <<= 64 - (DP_FBITS + 1); | ||
124 | ym <<= 64 - (DP_FBITS + 1); | ||
118 | 125 | ||
119 | /* multiply 32bits xm,ym to give high 32bits rm with stickness | 126 | /* |
120 | */ | 127 | * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. |
128 | */ | ||
121 | 129 | ||
122 | /* 32 * 32 => 64 */ | 130 | /* 32 * 32 => 64 */ |
123 | #define DPXMULT(x, y) ((u64)(x) * (u64)y) | 131 | #define DPXMULT(x, y) ((u64)(x) * (u64)y) |
124 | 132 | ||
125 | { | 133 | lxm = xm; |
126 | unsigned lxm = xm; | 134 | hxm = xm >> 32; |
127 | unsigned hxm = xm >> 32; | 135 | lym = ym; |
128 | unsigned lym = ym; | 136 | hym = ym >> 32; |
129 | unsigned hym = ym >> 32; | 137 | |
130 | u64 lrm; | 138 | lrm = DPXMULT(lxm, lym); |
131 | u64 hrm; | 139 | hrm = DPXMULT(hxm, hym); |
132 | 140 | ||
133 | lrm = DPXMULT(lxm, lym); | 141 | t = DPXMULT(lxm, hym); |
134 | hrm = DPXMULT(hxm, hym); | 142 | |
135 | 143 | at = lrm + (t << 32); | |
136 | { | 144 | hrm += at < lrm; |
137 | u64 t = DPXMULT(lxm, hym); | 145 | lrm = at; |
138 | { | 146 | |
139 | u64 at = | 147 | hrm = hrm + (t >> 32); |
140 | lrm + (t << 32); | 148 | |
141 | hrm += at < lrm; | 149 | t = DPXMULT(hxm, lym); |
142 | lrm = at; | 150 | |
143 | } | 151 | at = lrm + (t << 32); |
144 | hrm = hrm + (t >> 32); | 152 | hrm += at < lrm; |
145 | } | 153 | lrm = at; |
146 | 154 | ||
147 | { | 155 | hrm = hrm + (t >> 32); |
148 | u64 t = DPXMULT(hxm, lym); | 156 | |
149 | { | 157 | rm = hrm | (lrm != 0); |
150 | u64 at = | 158 | |
151 | lrm + (t << 32); | 159 | /* |
152 | hrm += at < lrm; | 160 | * Sticky shift down to normal rounding precision. |
153 | lrm = at; | 161 | */ |
154 | } | 162 | if ((s64) rm < 0) { |
155 | hrm = hrm + (t >> 32); | 163 | rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | |
156 | } | 164 | ((rm << (DP_FBITS + 1 + 3)) != 0); |
157 | rm = hrm | (lrm != 0); | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * sticky shift down to normal rounding precision | ||
162 | */ | ||
163 | if ((s64) rm < 0) { | ||
164 | rm = | ||
165 | (rm >> (64 - (DP_MBITS + 1 + 3))) | | ||
166 | ((rm << (DP_MBITS + 1 + 3)) != 0); | ||
167 | re++; | 165 | re++; |
168 | } else { | 166 | } else { |
169 | rm = | 167 | rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | |
170 | (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) | | 168 | ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); |
171 | ((rm << (DP_MBITS + 1 + 3 + 1)) != 0); | ||
172 | } | ||
173 | assert(rm & (DP_HIDDEN_BIT << 3)); | ||
174 | DPNORMRET2(rs, re, rm, "mul", x, y); | ||
175 | } | 169 | } |
170 | assert(rm & (DP_HIDDEN_BIT << 3)); | ||
171 | |||
172 | return ieee754dp_format(rs, re, rm); | ||
176 | } | 173 | } |
diff --git a/arch/mips/math-emu/dp_scalb.c b/arch/mips/math-emu/dp_scalb.c deleted file mode 100644 index 6f5df438dda8..000000000000 --- a/arch/mips/math-emu/dp_scalb.c +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | /* IEEE754 floating point arithmetic | ||
2 | * double precision: common utilities | ||
3 | */ | ||
4 | /* | ||
5 | * MIPS floating point support | ||
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
7 | * | ||
8 | * ######################################################################## | ||
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 (Version 2) as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
17 | * for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include "ieee754dp.h" | ||
28 | |||
29 | ieee754dp ieee754dp_scalb(ieee754dp x, int n) | ||
30 | { | ||
31 | COMPXDP; | ||
32 | |||
33 | CLEARCX; | ||
34 | |||
35 | EXPLODEXDP; | ||
36 | |||
37 | switch (xc) { | ||
38 | case IEEE754_CLASS_SNAN: | ||
39 | return ieee754dp_nanxcpt(x, "scalb", x, n); | ||
40 | case IEEE754_CLASS_QNAN: | ||
41 | case IEEE754_CLASS_INF: | ||
42 | case IEEE754_CLASS_ZERO: | ||
43 | return x; | ||
44 | case IEEE754_CLASS_DNORM: | ||
45 | DPDNORMX; | ||
46 | break; | ||
47 | case IEEE754_CLASS_NORM: | ||
48 | break; | ||
49 | } | ||
50 | DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); | ||
51 | } | ||
52 | |||
53 | |||
54 | ieee754dp ieee754dp_ldexp(ieee754dp x, int n) | ||
55 | { | ||
56 | return ieee754dp_scalb(x, n); | ||
57 | } | ||
diff --git a/arch/mips/math-emu/dp_simple.c b/arch/mips/math-emu/dp_simple.c index 79ce2673a714..bccbe90efceb 100644 --- a/arch/mips/math-emu/dp_simple.c +++ b/arch/mips/math-emu/dp_simple.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,33 +16,17 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
28 | 23 | ||
29 | int ieee754dp_finite(ieee754dp x) | 24 | union ieee754dp ieee754dp_neg(union ieee754dp x) |
30 | { | ||
31 | return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS; | ||
32 | } | ||
33 | |||
34 | ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y) | ||
35 | { | ||
36 | CLEARCX; | ||
37 | DPSIGN(x) = DPSIGN(y); | ||
38 | return x; | ||
39 | } | ||
40 | |||
41 | |||
42 | ieee754dp ieee754dp_neg(ieee754dp x) | ||
43 | { | 25 | { |
44 | COMPXDP; | 26 | COMPXDP; |
45 | 27 | ||
46 | EXPLODEXDP; | 28 | EXPLODEXDP; |
47 | CLEARCX; | 29 | ieee754_clearcx(); |
48 | FLUSHXDP; | 30 | FLUSHXDP; |
49 | 31 | ||
50 | /* | 32 | /* |
@@ -55,30 +37,29 @@ ieee754dp ieee754dp_neg(ieee754dp x) | |||
55 | DPSIGN(x) ^= 1; | 37 | DPSIGN(x) ^= 1; |
56 | 38 | ||
57 | if (xc == IEEE754_CLASS_SNAN) { | 39 | if (xc == IEEE754_CLASS_SNAN) { |
58 | ieee754dp y = ieee754dp_indef(); | 40 | union ieee754dp y = ieee754dp_indef(); |
59 | SETCX(IEEE754_INVALID_OPERATION); | 41 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
60 | DPSIGN(y) = DPSIGN(x); | 42 | DPSIGN(y) = DPSIGN(x); |
61 | return ieee754dp_nanxcpt(y, "neg"); | 43 | return ieee754dp_nanxcpt(y); |
62 | } | 44 | } |
63 | 45 | ||
64 | return x; | 46 | return x; |
65 | } | 47 | } |
66 | 48 | ||
67 | 49 | union ieee754dp ieee754dp_abs(union ieee754dp x) | |
68 | ieee754dp ieee754dp_abs(ieee754dp x) | ||
69 | { | 50 | { |
70 | COMPXDP; | 51 | COMPXDP; |
71 | 52 | ||
72 | EXPLODEXDP; | 53 | EXPLODEXDP; |
73 | CLEARCX; | 54 | ieee754_clearcx(); |
74 | FLUSHXDP; | 55 | FLUSHXDP; |
75 | 56 | ||
76 | /* Clear sign ALWAYS, irrespective of NaN */ | 57 | /* Clear sign ALWAYS, irrespective of NaN */ |
77 | DPSIGN(x) = 0; | 58 | DPSIGN(x) = 0; |
78 | 59 | ||
79 | if (xc == IEEE754_CLASS_SNAN) { | 60 | if (xc == IEEE754_CLASS_SNAN) { |
80 | SETCX(IEEE754_INVALID_OPERATION); | 61 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
81 | return ieee754dp_nanxcpt(ieee754dp_indef(), "abs"); | 62 | return ieee754dp_nanxcpt(ieee754dp_indef()); |
82 | } | 63 | } |
83 | 64 | ||
84 | return x; | 65 | return x; |
diff --git a/arch/mips/math-emu/dp_sqrt.c b/arch/mips/math-emu/dp_sqrt.c index b874d60a942b..041bbb6124bb 100644 --- a/arch/mips/math-emu/dp_sqrt.c +++ b/arch/mips/math-emu/dp_sqrt.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,12 +16,9 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
28 | 23 | ||
29 | static const unsigned table[] = { | 24 | static const unsigned table[] = { |
@@ -34,44 +29,49 @@ static const unsigned table[] = { | |||
34 | 1742, 661, 130 | 29 | 1742, 661, 130 |
35 | }; | 30 | }; |
36 | 31 | ||
37 | ieee754dp ieee754dp_sqrt(ieee754dp x) | 32 | union ieee754dp ieee754dp_sqrt(union ieee754dp x) |
38 | { | 33 | { |
39 | struct _ieee754_csr oldcsr; | 34 | struct _ieee754_csr oldcsr; |
40 | ieee754dp y, z, t; | 35 | union ieee754dp y, z, t; |
41 | unsigned scalx, yh; | 36 | unsigned scalx, yh; |
42 | COMPXDP; | 37 | COMPXDP; |
43 | 38 | ||
44 | EXPLODEXDP; | 39 | EXPLODEXDP; |
45 | CLEARCX; | 40 | ieee754_clearcx(); |
46 | FLUSHXDP; | 41 | FLUSHXDP; |
47 | 42 | ||
48 | /* x == INF or NAN? */ | 43 | /* x == INF or NAN? */ |
49 | switch (xc) { | 44 | switch (xc) { |
50 | case IEEE754_CLASS_QNAN: | 45 | case IEEE754_CLASS_QNAN: |
51 | /* sqrt(Nan) = Nan */ | 46 | /* sqrt(Nan) = Nan */ |
52 | return ieee754dp_nanxcpt(x, "sqrt"); | 47 | return ieee754dp_nanxcpt(x); |
48 | |||
53 | case IEEE754_CLASS_SNAN: | 49 | case IEEE754_CLASS_SNAN: |
54 | SETCX(IEEE754_INVALID_OPERATION); | 50 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
55 | return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); | 51 | return ieee754dp_nanxcpt(ieee754dp_indef()); |
52 | |||
56 | case IEEE754_CLASS_ZERO: | 53 | case IEEE754_CLASS_ZERO: |
57 | /* sqrt(0) = 0 */ | 54 | /* sqrt(0) = 0 */ |
58 | return x; | 55 | return x; |
56 | |||
59 | case IEEE754_CLASS_INF: | 57 | case IEEE754_CLASS_INF: |
60 | if (xs) { | 58 | if (xs) { |
61 | /* sqrt(-Inf) = Nan */ | 59 | /* sqrt(-Inf) = Nan */ |
62 | SETCX(IEEE754_INVALID_OPERATION); | 60 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
63 | return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); | 61 | return ieee754dp_nanxcpt(ieee754dp_indef()); |
64 | } | 62 | } |
65 | /* sqrt(+Inf) = Inf */ | 63 | /* sqrt(+Inf) = Inf */ |
66 | return x; | 64 | return x; |
65 | |||
67 | case IEEE754_CLASS_DNORM: | 66 | case IEEE754_CLASS_DNORM: |
68 | DPDNORMX; | 67 | DPDNORMX; |
69 | /* fall through */ | 68 | /* fall through */ |
69 | |||
70 | case IEEE754_CLASS_NORM: | 70 | case IEEE754_CLASS_NORM: |
71 | if (xs) { | 71 | if (xs) { |
72 | /* sqrt(-x) = Nan */ | 72 | /* sqrt(-x) = Nan */ |
73 | SETCX(IEEE754_INVALID_OPERATION); | 73 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
74 | return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); | 74 | return ieee754dp_nanxcpt(ieee754dp_indef()); |
75 | } | 75 | } |
76 | break; | 76 | break; |
77 | } | 77 | } |
@@ -80,7 +80,7 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) | |||
80 | oldcsr = ieee754_csr; | 80 | oldcsr = ieee754_csr; |
81 | ieee754_csr.mx &= ~IEEE754_INEXACT; | 81 | ieee754_csr.mx &= ~IEEE754_INEXACT; |
82 | ieee754_csr.sx &= ~IEEE754_INEXACT; | 82 | ieee754_csr.sx &= ~IEEE754_INEXACT; |
83 | ieee754_csr.rm = IEEE754_RN; | 83 | ieee754_csr.rm = FPU_CSR_RN; |
84 | 84 | ||
85 | /* adjust exponent to prevent overflow */ | 85 | /* adjust exponent to prevent overflow */ |
86 | scalx = 0; | 86 | scalx = 0; |
@@ -110,19 +110,19 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) | |||
110 | /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */ | 110 | /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */ |
111 | /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */ | 111 | /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */ |
112 | z = t = ieee754dp_mul(y, y); | 112 | z = t = ieee754dp_mul(y, y); |
113 | t.parts.bexp += 0x001; | 113 | t.bexp += 0x001; |
114 | t = ieee754dp_add(t, z); | 114 | t = ieee754dp_add(t, z); |
115 | z = ieee754dp_mul(ieee754dp_sub(x, z), y); | 115 | z = ieee754dp_mul(ieee754dp_sub(x, z), y); |
116 | 116 | ||
117 | /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */ | 117 | /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */ |
118 | t = ieee754dp_div(z, ieee754dp_add(t, x)); | 118 | t = ieee754dp_div(z, ieee754dp_add(t, x)); |
119 | t.parts.bexp += 0x001; | 119 | t.bexp += 0x001; |
120 | y = ieee754dp_add(y, t); | 120 | y = ieee754dp_add(y, t); |
121 | 121 | ||
122 | /* twiddle last bit to force y correctly rounded */ | 122 | /* twiddle last bit to force y correctly rounded */ |
123 | 123 | ||
124 | /* set RZ, clear INEX flag */ | 124 | /* set RZ, clear INEX flag */ |
125 | ieee754_csr.rm = IEEE754_RZ; | 125 | ieee754_csr.rm = FPU_CSR_RZ; |
126 | ieee754_csr.sx &= ~IEEE754_INEXACT; | 126 | ieee754_csr.sx &= ~IEEE754_INEXACT; |
127 | 127 | ||
128 | /* t=x/y; ...chopped quotient, possibly inexact */ | 128 | /* t=x/y; ...chopped quotient, possibly inexact */ |
@@ -139,10 +139,10 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) | |||
139 | oldcsr.sx |= IEEE754_INEXACT; | 139 | oldcsr.sx |= IEEE754_INEXACT; |
140 | 140 | ||
141 | switch (oldcsr.rm) { | 141 | switch (oldcsr.rm) { |
142 | case IEEE754_RP: | 142 | case FPU_CSR_RU: |
143 | y.bits += 1; | 143 | y.bits += 1; |
144 | /* drop through */ | 144 | /* drop through */ |
145 | case IEEE754_RN: | 145 | case FPU_CSR_RN: |
146 | t.bits += 1; | 146 | t.bits += 1; |
147 | break; | 147 | break; |
148 | } | 148 | } |
@@ -155,7 +155,7 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) | |||
155 | } | 155 | } |
156 | 156 | ||
157 | /* py[n0]=py[n0]+scalx; ...scale back y */ | 157 | /* py[n0]=py[n0]+scalx; ...scale back y */ |
158 | y.parts.bexp += scalx; | 158 | y.bexp += scalx; |
159 | 159 | ||
160 | /* restore rounding mode, possibly set inexact */ | 160 | /* restore rounding mode, possibly set inexact */ |
161 | ieee754_csr = oldcsr; | 161 | ieee754_csr = oldcsr; |
diff --git a/arch/mips/math-emu/dp_sub.c b/arch/mips/math-emu/dp_sub.c index 91e0a4b5cbc7..7a174029043a 100644 --- a/arch/mips/math-emu/dp_sub.c +++ b/arch/mips/math-emu/dp_sub.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,23 +16,22 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
28 | 23 | ||
29 | ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) | 24 | union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y) |
30 | { | 25 | { |
26 | int s; | ||
27 | |||
31 | COMPXDP; | 28 | COMPXDP; |
32 | COMPYDP; | 29 | COMPYDP; |
33 | 30 | ||
34 | EXPLODEXDP; | 31 | EXPLODEXDP; |
35 | EXPLODEYDP; | 32 | EXPLODEYDP; |
36 | 33 | ||
37 | CLEARCX; | 34 | ieee754_clearcx(); |
38 | 35 | ||
39 | FLUSHXDP; | 36 | FLUSHXDP; |
40 | FLUSHYDP; | 37 | FLUSHYDP; |
@@ -51,8 +48,8 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) | |||
51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | 48 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | 49 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
53 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
54 | SETCX(IEEE754_INVALID_OPERATION); | 51 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
55 | return ieee754dp_nanxcpt(ieee754dp_indef(), "sub", x, y); | 52 | return ieee754dp_nanxcpt(ieee754dp_indef()); |
56 | 53 | ||
57 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | 54 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
58 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | 55 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
@@ -68,14 +65,14 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) | |||
68 | return x; | 65 | return x; |
69 | 66 | ||
70 | 67 | ||
71 | /* Infinity handling | 68 | /* |
72 | */ | 69 | * Infinity handling |
73 | 70 | */ | |
74 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | 71 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
75 | if (xs != ys) | 72 | if (xs != ys) |
76 | return x; | 73 | return x; |
77 | SETCX(IEEE754_INVALID_OPERATION); | 74 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
78 | return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y); | 75 | return ieee754dp_indef(); |
79 | 76 | ||
80 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | 77 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
81 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | 78 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): |
@@ -87,15 +84,14 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) | |||
87 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
88 | return x; | 85 | return x; |
89 | 86 | ||
90 | /* Zero handling | 87 | /* |
91 | */ | 88 | * Zero handling |
92 | 89 | */ | |
93 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
94 | if (xs != ys) | 91 | if (xs != ys) |
95 | return x; | 92 | return x; |
96 | else | 93 | else |
97 | return ieee754dp_zero(ieee754_csr.rm == | 94 | return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); |
98 | IEEE754_RD); | ||
99 | 95 | ||
100 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | 96 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
101 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | 97 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
@@ -136,15 +132,17 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) | |||
136 | ym <<= 3; | 132 | ym <<= 3; |
137 | 133 | ||
138 | if (xe > ye) { | 134 | if (xe > ye) { |
139 | /* have to shift y fraction right to align | 135 | /* |
136 | * Have to shift y fraction right to align | ||
140 | */ | 137 | */ |
141 | int s = xe - ye; | 138 | s = xe - ye; |
142 | ym = XDPSRS(ym, s); | 139 | ym = XDPSRS(ym, s); |
143 | ye += s; | 140 | ye += s; |
144 | } else if (ye > xe) { | 141 | } else if (ye > xe) { |
145 | /* have to shift x fraction right to align | 142 | /* |
143 | * Have to shift x fraction right to align | ||
146 | */ | 144 | */ |
147 | int s = ye - xe; | 145 | s = ye - xe; |
148 | xm = XDPSRS(xm, s); | 146 | xm = XDPSRS(xm, s); |
149 | xe += s; | 147 | xe += s; |
150 | } | 148 | } |
@@ -158,7 +156,7 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) | |||
158 | xe = xe; | 156 | xe = xe; |
159 | xs = xs; | 157 | xs = xs; |
160 | 158 | ||
161 | if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ | 159 | if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */ |
162 | xm = XDPSRS1(xm); /* shift preserving sticky */ | 160 | xm = XDPSRS1(xm); /* shift preserving sticky */ |
163 | xe++; | 161 | xe++; |
164 | } | 162 | } |
@@ -173,7 +171,7 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) | |||
173 | xs = ys; | 171 | xs = ys; |
174 | } | 172 | } |
175 | if (xm == 0) { | 173 | if (xm == 0) { |
176 | if (ieee754_csr.rm == IEEE754_RD) | 174 | if (ieee754_csr.rm == FPU_CSR_RD) |
177 | return ieee754dp_zero(1); /* round negative inf. => sign = -1 */ | 175 | return ieee754dp_zero(1); /* round negative inf. => sign = -1 */ |
178 | else | 176 | else |
179 | return ieee754dp_zero(0); /* other round modes => sign = 1 */ | 177 | return ieee754dp_zero(0); /* other round modes => sign = 1 */ |
@@ -181,10 +179,11 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) | |||
181 | 179 | ||
182 | /* normalize to rounding precision | 180 | /* normalize to rounding precision |
183 | */ | 181 | */ |
184 | while ((xm >> (DP_MBITS + 3)) == 0) { | 182 | while ((xm >> (DP_FBITS + 3)) == 0) { |
185 | xm <<= 1; | 183 | xm <<= 1; |
186 | xe--; | 184 | xe--; |
187 | } | 185 | } |
188 | } | 186 | } |
189 | DPNORMRET2(xs, xe, xm, "sub", x, y); | 187 | |
188 | return ieee754dp_format(xs, xe, xm); | ||
190 | } | 189 | } |
diff --git a/arch/mips/math-emu/dp_tint.c b/arch/mips/math-emu/dp_tint.c index 0ebe8598b94a..6ffc336c530e 100644 --- a/arch/mips/math-emu/dp_tint.c +++ b/arch/mips/math-emu/dp_tint.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,20 +16,21 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
29 | 23 | ||
30 | int ieee754dp_tint(ieee754dp x) | 24 | int ieee754dp_tint(union ieee754dp x) |
31 | { | 25 | { |
26 | u64 residue; | ||
27 | int round; | ||
28 | int sticky; | ||
29 | int odd; | ||
30 | |||
32 | COMPXDP; | 31 | COMPXDP; |
33 | 32 | ||
34 | CLEARCX; | 33 | ieee754_clearcx(); |
35 | 34 | ||
36 | EXPLODEXDP; | 35 | EXPLODEXDP; |
37 | FLUSHXDP; | 36 | FLUSHXDP; |
@@ -40,10 +39,12 @@ int ieee754dp_tint(ieee754dp x) | |||
40 | case IEEE754_CLASS_SNAN: | 39 | case IEEE754_CLASS_SNAN: |
41 | case IEEE754_CLASS_QNAN: | 40 | case IEEE754_CLASS_QNAN: |
42 | case IEEE754_CLASS_INF: | 41 | case IEEE754_CLASS_INF: |
43 | SETCX(IEEE754_INVALID_OPERATION); | 42 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
44 | return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); | 43 | return ieee754si_indef(); |
44 | |||
45 | case IEEE754_CLASS_ZERO: | 45 | case IEEE754_CLASS_ZERO: |
46 | return 0; | 46 | return 0; |
47 | |||
47 | case IEEE754_CLASS_DNORM: | 48 | case IEEE754_CLASS_DNORM: |
48 | case IEEE754_CLASS_NORM: | 49 | case IEEE754_CLASS_NORM: |
49 | break; | 50 | break; |
@@ -51,44 +52,39 @@ int ieee754dp_tint(ieee754dp x) | |||
51 | if (xe > 31) { | 52 | if (xe > 31) { |
52 | /* Set invalid. We will only use overflow for floating | 53 | /* Set invalid. We will only use overflow for floating |
53 | point overflow */ | 54 | point overflow */ |
54 | SETCX(IEEE754_INVALID_OPERATION); | 55 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
55 | return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); | 56 | return ieee754si_indef(); |
56 | } | 57 | } |
57 | /* oh gawd */ | 58 | /* oh gawd */ |
58 | if (xe > DP_MBITS) { | 59 | if (xe > DP_FBITS) { |
59 | xm <<= xe - DP_MBITS; | 60 | xm <<= xe - DP_FBITS; |
60 | } else if (xe < DP_MBITS) { | 61 | } else if (xe < DP_FBITS) { |
61 | u64 residue; | ||
62 | int round; | ||
63 | int sticky; | ||
64 | int odd; | ||
65 | |||
66 | if (xe < -1) { | 62 | if (xe < -1) { |
67 | residue = xm; | 63 | residue = xm; |
68 | round = 0; | 64 | round = 0; |
69 | sticky = residue != 0; | 65 | sticky = residue != 0; |
70 | xm = 0; | 66 | xm = 0; |
71 | } else { | 67 | } else { |
72 | residue = xm << (64 - DP_MBITS + xe); | 68 | residue = xm << (64 - DP_FBITS + xe); |
73 | round = (residue >> 63) != 0; | 69 | round = (residue >> 63) != 0; |
74 | sticky = (residue << 1) != 0; | 70 | sticky = (residue << 1) != 0; |
75 | xm >>= DP_MBITS - xe; | 71 | xm >>= DP_FBITS - xe; |
76 | } | 72 | } |
77 | /* Note: At this point upper 32 bits of xm are guaranteed | 73 | /* Note: At this point upper 32 bits of xm are guaranteed |
78 | to be zero */ | 74 | to be zero */ |
79 | odd = (xm & 0x1) != 0x0; | 75 | odd = (xm & 0x1) != 0x0; |
80 | switch (ieee754_csr.rm) { | 76 | switch (ieee754_csr.rm) { |
81 | case IEEE754_RN: | 77 | case FPU_CSR_RN: |
82 | if (round && (sticky || odd)) | 78 | if (round && (sticky || odd)) |
83 | xm++; | 79 | xm++; |
84 | break; | 80 | break; |
85 | case IEEE754_RZ: | 81 | case FPU_CSR_RZ: |
86 | break; | 82 | break; |
87 | case IEEE754_RU: /* toward +Infinity */ | 83 | case FPU_CSR_RU: /* toward +Infinity */ |
88 | if ((round || sticky) && !xs) | 84 | if ((round || sticky) && !xs) |
89 | xm++; | 85 | xm++; |
90 | break; | 86 | break; |
91 | case IEEE754_RD: /* toward -Infinity */ | 87 | case FPU_CSR_RD: /* toward -Infinity */ |
92 | if ((round || sticky) && xs) | 88 | if ((round || sticky) && xs) |
93 | xm++; | 89 | xm++; |
94 | break; | 90 | break; |
@@ -96,27 +92,14 @@ int ieee754dp_tint(ieee754dp x) | |||
96 | /* look for valid corner case 0x80000000 */ | 92 | /* look for valid corner case 0x80000000 */ |
97 | if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) { | 93 | if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) { |
98 | /* This can happen after rounding */ | 94 | /* This can happen after rounding */ |
99 | SETCX(IEEE754_INVALID_OPERATION); | 95 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
100 | return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); | 96 | return ieee754si_indef(); |
101 | } | 97 | } |
102 | if (round || sticky) | 98 | if (round || sticky) |
103 | SETCX(IEEE754_INEXACT); | 99 | ieee754_setcx(IEEE754_INEXACT); |
104 | } | 100 | } |
105 | if (xs) | 101 | if (xs) |
106 | return -xm; | 102 | return -xm; |
107 | else | 103 | else |
108 | return xm; | 104 | return xm; |
109 | } | 105 | } |
110 | |||
111 | |||
112 | unsigned int ieee754dp_tuns(ieee754dp x) | ||
113 | { | ||
114 | ieee754dp hb = ieee754dp_1e31(); | ||
115 | |||
116 | /* what if x < 0 ?? */ | ||
117 | if (ieee754dp_lt(x, hb)) | ||
118 | return (unsigned) ieee754dp_tint(x); | ||
119 | |||
120 | return (unsigned) ieee754dp_tint(ieee754dp_sub(x, hb)) | | ||
121 | ((unsigned) 1 << 31); | ||
122 | } | ||
diff --git a/arch/mips/math-emu/dp_tlong.c b/arch/mips/math-emu/dp_tlong.c index 133ce2ba0012..9cdc145b75e0 100644 --- a/arch/mips/math-emu/dp_tlong.c +++ b/arch/mips/math-emu/dp_tlong.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,19 +16,21 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754dp.h" | 22 | #include "ieee754dp.h" |
28 | 23 | ||
29 | s64 ieee754dp_tlong(ieee754dp x) | 24 | s64 ieee754dp_tlong(union ieee754dp x) |
30 | { | 25 | { |
26 | u64 residue; | ||
27 | int round; | ||
28 | int sticky; | ||
29 | int odd; | ||
30 | |||
31 | COMPXDP; | 31 | COMPXDP; |
32 | 32 | ||
33 | CLEARCX; | 33 | ieee754_clearcx(); |
34 | 34 | ||
35 | EXPLODEXDP; | 35 | EXPLODEXDP; |
36 | FLUSHXDP; | 36 | FLUSHXDP; |
@@ -39,10 +39,12 @@ s64 ieee754dp_tlong(ieee754dp x) | |||
39 | case IEEE754_CLASS_SNAN: | 39 | case IEEE754_CLASS_SNAN: |
40 | case IEEE754_CLASS_QNAN: | 40 | case IEEE754_CLASS_QNAN: |
41 | case IEEE754_CLASS_INF: | 41 | case IEEE754_CLASS_INF: |
42 | SETCX(IEEE754_INVALID_OPERATION); | 42 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
43 | return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); | 43 | return ieee754di_indef(); |
44 | |||
44 | case IEEE754_CLASS_ZERO: | 45 | case IEEE754_CLASS_ZERO: |
45 | return 0; | 46 | return 0; |
47 | |||
46 | case IEEE754_CLASS_DNORM: | 48 | case IEEE754_CLASS_DNORM: |
47 | case IEEE754_CLASS_NORM: | 49 | case IEEE754_CLASS_NORM: |
48 | break; | 50 | break; |
@@ -53,18 +55,13 @@ s64 ieee754dp_tlong(ieee754dp x) | |||
53 | return -0x8000000000000000LL; | 55 | return -0x8000000000000000LL; |
54 | /* Set invalid. We will only use overflow for floating | 56 | /* Set invalid. We will only use overflow for floating |
55 | point overflow */ | 57 | point overflow */ |
56 | SETCX(IEEE754_INVALID_OPERATION); | 58 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
57 | return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); | 59 | return ieee754di_indef(); |
58 | } | 60 | } |
59 | /* oh gawd */ | 61 | /* oh gawd */ |
60 | if (xe > DP_MBITS) { | 62 | if (xe > DP_FBITS) { |
61 | xm <<= xe - DP_MBITS; | 63 | xm <<= xe - DP_FBITS; |
62 | } else if (xe < DP_MBITS) { | 64 | } else if (xe < DP_FBITS) { |
63 | u64 residue; | ||
64 | int round; | ||
65 | int sticky; | ||
66 | int odd; | ||
67 | |||
68 | if (xe < -1) { | 65 | if (xe < -1) { |
69 | residue = xm; | 66 | residue = xm; |
70 | round = 0; | 67 | round = 0; |
@@ -75,51 +72,38 @@ s64 ieee754dp_tlong(ieee754dp x) | |||
75 | * so we do it in two steps. Be aware that xe | 72 | * so we do it in two steps. Be aware that xe |
76 | * may be -1 */ | 73 | * may be -1 */ |
77 | residue = xm << (xe + 1); | 74 | residue = xm << (xe + 1); |
78 | residue <<= 63 - DP_MBITS; | 75 | residue <<= 63 - DP_FBITS; |
79 | round = (residue >> 63) != 0; | 76 | round = (residue >> 63) != 0; |
80 | sticky = (residue << 1) != 0; | 77 | sticky = (residue << 1) != 0; |
81 | xm >>= DP_MBITS - xe; | 78 | xm >>= DP_FBITS - xe; |
82 | } | 79 | } |
83 | odd = (xm & 0x1) != 0x0; | 80 | odd = (xm & 0x1) != 0x0; |
84 | switch (ieee754_csr.rm) { | 81 | switch (ieee754_csr.rm) { |
85 | case IEEE754_RN: | 82 | case FPU_CSR_RN: |
86 | if (round && (sticky || odd)) | 83 | if (round && (sticky || odd)) |
87 | xm++; | 84 | xm++; |
88 | break; | 85 | break; |
89 | case IEEE754_RZ: | 86 | case FPU_CSR_RZ: |
90 | break; | 87 | break; |
91 | case IEEE754_RU: /* toward +Infinity */ | 88 | case FPU_CSR_RU: /* toward +Infinity */ |
92 | if ((round || sticky) && !xs) | 89 | if ((round || sticky) && !xs) |
93 | xm++; | 90 | xm++; |
94 | break; | 91 | break; |
95 | case IEEE754_RD: /* toward -Infinity */ | 92 | case FPU_CSR_RD: /* toward -Infinity */ |
96 | if ((round || sticky) && xs) | 93 | if ((round || sticky) && xs) |
97 | xm++; | 94 | xm++; |
98 | break; | 95 | break; |
99 | } | 96 | } |
100 | if ((xm >> 63) != 0) { | 97 | if ((xm >> 63) != 0) { |
101 | /* This can happen after rounding */ | 98 | /* This can happen after rounding */ |
102 | SETCX(IEEE754_INVALID_OPERATION); | 99 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
103 | return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); | 100 | return ieee754di_indef(); |
104 | } | 101 | } |
105 | if (round || sticky) | 102 | if (round || sticky) |
106 | SETCX(IEEE754_INEXACT); | 103 | ieee754_setcx(IEEE754_INEXACT); |
107 | } | 104 | } |
108 | if (xs) | 105 | if (xs) |
109 | return -xm; | 106 | return -xm; |
110 | else | 107 | else |
111 | return xm; | 108 | return xm; |
112 | } | 109 | } |
113 | |||
114 | |||
115 | u64 ieee754dp_tulong(ieee754dp x) | ||
116 | { | ||
117 | ieee754dp hb = ieee754dp_1e63(); | ||
118 | |||
119 | /* what if x < 0 ?? */ | ||
120 | if (ieee754dp_lt(x, hb)) | ||
121 | return (u64) ieee754dp_tlong(x); | ||
122 | |||
123 | return (u64) ieee754dp_tlong(ieee754dp_sub(x, hb)) | | ||
124 | (1ULL << 63); | ||
125 | } | ||
diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 7ea622ab8dad..4f514f3724cb 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c | |||
@@ -1,30 +1,12 @@ | |||
1 | #include <linux/compiler.h> | ||
2 | #include <linux/mm.h> | ||
3 | #include <linux/signal.h> | ||
4 | #include <linux/smp.h> | ||
5 | |||
6 | #include <asm/asm.h> | ||
7 | #include <asm/bootinfo.h> | ||
8 | #include <asm/byteorder.h> | ||
9 | #include <asm/cpu.h> | ||
10 | #include <asm/inst.h> | ||
11 | #include <asm/processor.h> | ||
12 | #include <asm/uaccess.h> | ||
13 | #include <asm/branch.h> | 1 | #include <asm/branch.h> |
14 | #include <asm/mipsregs.h> | ||
15 | #include <asm/cacheflush.h> | 2 | #include <asm/cacheflush.h> |
16 | |||
17 | #include <asm/fpu_emulator.h> | 3 | #include <asm/fpu_emulator.h> |
4 | #include <asm/inst.h> | ||
5 | #include <asm/mipsregs.h> | ||
6 | #include <asm/uaccess.h> | ||
18 | 7 | ||
19 | #include "ieee754.h" | 8 | #include "ieee754.h" |
20 | 9 | ||
21 | /* Strap kernel emulator for full MIPS IV emulation */ | ||
22 | |||
23 | #ifdef __mips | ||
24 | #undef __mips | ||
25 | #endif | ||
26 | #define __mips 4 | ||
27 | |||
28 | /* | 10 | /* |
29 | * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when | 11 | * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when |
30 | * we have to emulate the instruction in a COP1 branch delay slot. Do | 12 | * we have to emulate the instruction in a COP1 branch delay slot. Do |
@@ -59,13 +41,11 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) | |||
59 | (ir == 0)) { | 41 | (ir == 0)) { |
60 | /* NOP is easy */ | 42 | /* NOP is easy */ |
61 | regs->cp0_epc = cpc; | 43 | regs->cp0_epc = cpc; |
62 | regs->cp0_cause &= ~CAUSEF_BD; | 44 | clear_delay_slot(regs); |
63 | return 0; | 45 | return 0; |
64 | } | 46 | } |
65 | #ifdef DSEMUL_TRACE | ||
66 | printk("dsemul %lx %lx\n", regs->cp0_epc, cpc); | ||
67 | 47 | ||
68 | #endif | 48 | pr_debug("dsemul %lx %lx\n", regs->cp0_epc, cpc); |
69 | 49 | ||
70 | /* | 50 | /* |
71 | * The strategy is to push the instruction onto the user stack | 51 | * The strategy is to push the instruction onto the user stack |
@@ -167,9 +147,8 @@ int do_dsemulret(struct pt_regs *xcp) | |||
167 | * emulating the branch delay instruction. | 147 | * emulating the branch delay instruction. |
168 | */ | 148 | */ |
169 | 149 | ||
170 | #ifdef DSEMUL_TRACE | 150 | pr_debug("dsemulret\n"); |
171 | printk("dsemulret\n"); | 151 | |
172 | #endif | ||
173 | if (__get_user(epc, &fr->epc)) { /* Saved EPC */ | 152 | if (__get_user(epc, &fr->epc)) { /* Saved EPC */ |
174 | /* This is not a good situation to be in */ | 153 | /* This is not a good situation to be in */ |
175 | force_sig(SIGBUS, current); | 154 | force_sig(SIGBUS, current); |
diff --git a/arch/mips/math-emu/ieee754.c b/arch/mips/math-emu/ieee754.c index 0015cf1989da..53f1d2287084 100644 --- a/arch/mips/math-emu/ieee754.c +++ b/arch/mips/math-emu/ieee754.c | |||
@@ -10,8 +10,6 @@ | |||
10 | * MIPS floating point support | 10 | * MIPS floating point support |
11 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 11 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
12 | * | 12 | * |
13 | * ######################################################################## | ||
14 | * | ||
15 | * This program is free software; you can distribute it and/or modify it | 13 | * This program is free software; you can distribute it and/or modify it |
16 | * under the terms of the GNU General Public License (Version 2) as | 14 | * under the terms of the GNU General Public License (Version 2) as |
17 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
@@ -23,105 +21,69 @@ | |||
23 | * | 21 | * |
24 | * You should have received a copy of the GNU General Public License along | 22 | * You should have received a copy of the GNU General Public License along |
25 | * with this program; if not, write to the Free Software Foundation, Inc., | 23 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 24 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
27 | * | ||
28 | * ######################################################################## | ||
29 | */ | 25 | */ |
30 | 26 | ||
27 | #include <linux/compiler.h> | ||
31 | 28 | ||
32 | #include "ieee754int.h" | 29 | #include "ieee754.h" |
33 | #include "ieee754sp.h" | 30 | #include "ieee754sp.h" |
34 | #include "ieee754dp.h" | 31 | #include "ieee754dp.h" |
35 | 32 | ||
36 | #define DP_EBIAS 1023 | 33 | /* |
37 | #define DP_EMIN (-1022) | 34 | * Special constants |
38 | #define DP_EMAX 1023 | 35 | */ |
39 | |||
40 | #define SP_EBIAS 127 | ||
41 | #define SP_EMIN (-126) | ||
42 | #define SP_EMAX 127 | ||
43 | |||
44 | /* special constants | ||
45 | */ | ||
46 | |||
47 | |||
48 | #if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) | ||
49 | #define SPSTR(s, b, m) {m, b, s} | ||
50 | #define DPSTR(s, b, mh, ml) {ml, mh, b, s} | ||
51 | #endif | ||
52 | |||
53 | #ifdef __MIPSEB__ | ||
54 | #define SPSTR(s, b, m) {s, b, m} | ||
55 | #define DPSTR(s, b, mh, ml) {s, b, mh, ml} | ||
56 | #endif | ||
57 | 36 | ||
58 | const struct ieee754dp_konst __ieee754dp_spcvals[] = { | 37 | #define DPCNST(s, b, m) \ |
59 | DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* + zero */ | 38 | { \ |
60 | DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* - zero */ | 39 | .sign = (s), \ |
61 | DPSTR(0, DP_EBIAS, 0, 0), /* + 1.0 */ | 40 | .bexp = (b) + DP_EBIAS, \ |
62 | DPSTR(1, DP_EBIAS, 0, 0), /* - 1.0 */ | 41 | .mant = (m) \ |
63 | DPSTR(0, 3 + DP_EBIAS, 0x40000, 0), /* + 10.0 */ | 42 | } |
64 | DPSTR(1, 3 + DP_EBIAS, 0x40000, 0), /* - 10.0 */ | ||
65 | DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */ | ||
66 | DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */ | ||
67 | DPSTR(0, DP_EMAX+1+DP_EBIAS, 0x7FFFF, 0xFFFFFFFF), /* + indef quiet Nan */ | ||
68 | DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* + max */ | ||
69 | DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* - max */ | ||
70 | DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0), /* + min normal */ | ||
71 | DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0), /* - min normal */ | ||
72 | DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* + min denormal */ | ||
73 | DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* - min denormal */ | ||
74 | DPSTR(0, 31 + DP_EBIAS, 0, 0), /* + 1.0e31 */ | ||
75 | DPSTR(0, 63 + DP_EBIAS, 0, 0), /* + 1.0e63 */ | ||
76 | }; | ||
77 | 43 | ||
78 | const struct ieee754sp_konst __ieee754sp_spcvals[] = { | 44 | const union ieee754dp __ieee754dp_spcvals[] = { |
79 | SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0), /* + zero */ | 45 | DPCNST(0, DP_EMIN - 1, 0x0000000000000ULL), /* + zero */ |
80 | SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0), /* - zero */ | 46 | DPCNST(1, DP_EMIN - 1, 0x0000000000000ULL), /* - zero */ |
81 | SPSTR(0, SP_EBIAS, 0), /* + 1.0 */ | 47 | DPCNST(0, 0, 0x0000000000000ULL), /* + 1.0 */ |
82 | SPSTR(1, SP_EBIAS, 0), /* - 1.0 */ | 48 | DPCNST(1, 0, 0x0000000000000ULL), /* - 1.0 */ |
83 | SPSTR(0, 3 + SP_EBIAS, 0x200000), /* + 10.0 */ | 49 | DPCNST(0, 3, 0x4000000000000ULL), /* + 10.0 */ |
84 | SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */ | 50 | DPCNST(1, 3, 0x4000000000000ULL), /* - 10.0 */ |
85 | SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */ | 51 | DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL), /* + infinity */ |
86 | SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */ | 52 | DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL), /* - infinity */ |
87 | SPSTR(0, SP_EMAX+1+SP_EBIAS, 0x3FFFFF), /* + indef quiet Nan */ | 53 | DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL), /* + indef quiet Nan */ |
88 | SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */ | 54 | DPCNST(0, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* + max */ |
89 | SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */ | 55 | DPCNST(1, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* - max */ |
90 | SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */ | 56 | DPCNST(0, DP_EMIN, 0x0000000000000ULL), /* + min normal */ |
91 | SPSTR(1, SP_EMIN + SP_EBIAS, 0), /* - min normal */ | 57 | DPCNST(1, DP_EMIN, 0x0000000000000ULL), /* - min normal */ |
92 | SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1), /* + min denormal */ | 58 | DPCNST(0, DP_EMIN - 1, 0x0000000000001ULL), /* + min denormal */ |
93 | SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1), /* - min denormal */ | 59 | DPCNST(1, DP_EMIN - 1, 0x0000000000001ULL), /* - min denormal */ |
94 | SPSTR(0, 31 + SP_EBIAS, 0), /* + 1.0e31 */ | 60 | DPCNST(0, 31, 0x0000000000000ULL), /* + 1.0e31 */ |
95 | SPSTR(0, 63 + SP_EBIAS, 0), /* + 1.0e63 */ | 61 | DPCNST(0, 63, 0x0000000000000ULL), /* + 1.0e63 */ |
96 | }; | 62 | }; |
97 | 63 | ||
98 | 64 | #define SPCNST(s, b, m) \ | |
99 | int ieee754si_xcpt(int r, const char *op, ...) | 65 | { \ |
100 | { | 66 | .sign = (s), \ |
101 | struct ieee754xctx ax; | 67 | .bexp = (b) + SP_EBIAS, \ |
102 | 68 | .mant = (m) \ | |
103 | if (!TSTX()) | ||
104 | return r; | ||
105 | ax.op = op; | ||
106 | ax.rt = IEEE754_RT_SI; | ||
107 | ax.rv.si = r; | ||
108 | va_start(ax.ap, op); | ||
109 | ieee754_xcpt(&ax); | ||
110 | va_end(ax.ap); | ||
111 | return ax.rv.si; | ||
112 | } | 69 | } |
113 | 70 | ||
114 | s64 ieee754di_xcpt(s64 r, const char *op, ...) | 71 | const union ieee754sp __ieee754sp_spcvals[] = { |
115 | { | 72 | SPCNST(0, SP_EMIN - 1, 0x000000), /* + zero */ |
116 | struct ieee754xctx ax; | 73 | SPCNST(1, SP_EMIN - 1, 0x000000), /* - zero */ |
117 | 74 | SPCNST(0, 0, 0x000000), /* + 1.0 */ | |
118 | if (!TSTX()) | 75 | SPCNST(1, 0, 0x000000), /* - 1.0 */ |
119 | return r; | 76 | SPCNST(0, 3, 0x200000), /* + 10.0 */ |
120 | ax.op = op; | 77 | SPCNST(1, 3, 0x200000), /* - 10.0 */ |
121 | ax.rt = IEEE754_RT_DI; | 78 | SPCNST(0, SP_EMAX + 1, 0x000000), /* + infinity */ |
122 | ax.rv.di = r; | 79 | SPCNST(1, SP_EMAX + 1, 0x000000), /* - infinity */ |
123 | va_start(ax.ap, op); | 80 | SPCNST(0, SP_EMAX + 1, 0x3FFFFF), /* + indef quiet Nan */ |
124 | ieee754_xcpt(&ax); | 81 | SPCNST(0, SP_EMAX, 0x7FFFFF), /* + max normal */ |
125 | va_end(ax.ap); | 82 | SPCNST(1, SP_EMAX, 0x7FFFFF), /* - max normal */ |
126 | return ax.rv.di; | 83 | SPCNST(0, SP_EMIN, 0x000000), /* + min normal */ |
127 | } | 84 | SPCNST(1, SP_EMIN, 0x000000), /* - min normal */ |
85 | SPCNST(0, SP_EMIN - 1, 0x000001), /* + min denormal */ | ||
86 | SPCNST(1, SP_EMIN - 1, 0x000001), /* - min denormal */ | ||
87 | SPCNST(0, 31, 0x000000), /* + 1.0e31 */ | ||
88 | SPCNST(0, 63, 0x000000), /* + 1.0e63 */ | ||
89 | }; | ||
diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 22796e012060..43c4fb522ac2 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h | |||
@@ -13,7 +13,7 @@ | |||
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License along | 14 | * You should have received a copy of the GNU General Public License along |
15 | * with this program; if not, write to the Free Software Foundation, Inc., | 15 | * with this program; if not, write to the Free Software Foundation, Inc., |
16 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 16 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
17 | * | 17 | * |
18 | * Nov 7, 2000 | 18 | * Nov 7, 2000 |
19 | * Modification to allow integration with Linux kernel | 19 | * Modification to allow integration with Linux kernel |
@@ -24,186 +24,93 @@ | |||
24 | #ifndef __ARCH_MIPS_MATH_EMU_IEEE754_H | 24 | #ifndef __ARCH_MIPS_MATH_EMU_IEEE754_H |
25 | #define __ARCH_MIPS_MATH_EMU_IEEE754_H | 25 | #define __ARCH_MIPS_MATH_EMU_IEEE754_H |
26 | 26 | ||
27 | #include <linux/compiler.h> | ||
27 | #include <asm/byteorder.h> | 28 | #include <asm/byteorder.h> |
29 | #include <linux/kernel.h> | ||
28 | #include <linux/types.h> | 30 | #include <linux/types.h> |
29 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
32 | #include <asm/bitfield.h> | ||
30 | 33 | ||
31 | /* | 34 | union ieee754dp { |
32 | * Not very pretty, but the Linux kernel's normal va_list definition | ||
33 | * does not allow it to be used as a structure element, as it is here. | ||
34 | */ | ||
35 | #ifndef _STDARG_H | ||
36 | #include <stdarg.h> | ||
37 | #endif | ||
38 | |||
39 | #ifdef __LITTLE_ENDIAN | ||
40 | struct ieee754dp_konst { | ||
41 | unsigned mantlo:32; | ||
42 | unsigned manthi:20; | ||
43 | unsigned bexp:11; | ||
44 | unsigned sign:1; | ||
45 | }; | ||
46 | struct ieee754sp_konst { | ||
47 | unsigned mant:23; | ||
48 | unsigned bexp:8; | ||
49 | unsigned sign:1; | ||
50 | }; | ||
51 | |||
52 | typedef union _ieee754dp { | ||
53 | struct ieee754dp_konst oparts; | ||
54 | struct { | 35 | struct { |
55 | u64 mant:52; | 36 | __BITFIELD_FIELD(unsigned int sign:1, |
56 | unsigned int bexp:11; | 37 | __BITFIELD_FIELD(unsigned int bexp:11, |
57 | unsigned int sign:1; | 38 | __BITFIELD_FIELD(u64 mant:52, |
58 | } parts; | 39 | ;))) |
40 | }; | ||
59 | u64 bits; | 41 | u64 bits; |
60 | double d; | ||
61 | } ieee754dp; | ||
62 | |||
63 | typedef union _ieee754sp { | ||
64 | struct ieee754sp_konst parts; | ||
65 | float f; | ||
66 | u32 bits; | ||
67 | } ieee754sp; | ||
68 | #endif | ||
69 | |||
70 | #ifdef __BIG_ENDIAN | ||
71 | struct ieee754dp_konst { | ||
72 | unsigned sign:1; | ||
73 | unsigned bexp:11; | ||
74 | unsigned manthi:20; | ||
75 | unsigned mantlo:32; | ||
76 | }; | 42 | }; |
77 | 43 | ||
78 | typedef union _ieee754dp { | 44 | union ieee754sp { |
79 | struct ieee754dp_konst oparts; | ||
80 | struct { | 45 | struct { |
81 | unsigned int sign:1; | 46 | __BITFIELD_FIELD(unsigned sign:1, |
82 | unsigned int bexp:11; | 47 | __BITFIELD_FIELD(unsigned bexp:8, |
83 | u64 mant:52; | 48 | __BITFIELD_FIELD(unsigned mant:23, |
84 | } parts; | 49 | ;))) |
85 | double d; | 50 | }; |
86 | u64 bits; | ||
87 | } ieee754dp; | ||
88 | |||
89 | struct ieee754sp_konst { | ||
90 | unsigned sign:1; | ||
91 | unsigned bexp:8; | ||
92 | unsigned mant:23; | ||
93 | }; | ||
94 | |||
95 | typedef union _ieee754sp { | ||
96 | struct ieee754sp_konst parts; | ||
97 | float f; | ||
98 | u32 bits; | 51 | u32 bits; |
99 | } ieee754sp; | 52 | }; |
100 | #endif | ||
101 | 53 | ||
102 | /* | 54 | /* |
103 | * single precision (often aka float) | 55 | * single precision (often aka float) |
104 | */ | 56 | */ |
105 | int ieee754sp_finite(ieee754sp x); | 57 | int ieee754sp_class(union ieee754sp x); |
106 | int ieee754sp_class(ieee754sp x); | ||
107 | |||
108 | ieee754sp ieee754sp_abs(ieee754sp x); | ||
109 | ieee754sp ieee754sp_neg(ieee754sp x); | ||
110 | ieee754sp ieee754sp_scalb(ieee754sp x, int); | ||
111 | ieee754sp ieee754sp_logb(ieee754sp x); | ||
112 | |||
113 | /* x with sign of y */ | ||
114 | ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y); | ||
115 | |||
116 | ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y); | ||
117 | ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y); | ||
118 | ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y); | ||
119 | ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y); | ||
120 | |||
121 | ieee754sp ieee754sp_fint(int x); | ||
122 | ieee754sp ieee754sp_funs(unsigned x); | ||
123 | ieee754sp ieee754sp_flong(s64 x); | ||
124 | ieee754sp ieee754sp_fulong(u64 x); | ||
125 | ieee754sp ieee754sp_fdp(ieee754dp x); | ||
126 | |||
127 | int ieee754sp_tint(ieee754sp x); | ||
128 | unsigned int ieee754sp_tuns(ieee754sp x); | ||
129 | s64 ieee754sp_tlong(ieee754sp x); | ||
130 | u64 ieee754sp_tulong(ieee754sp x); | ||
131 | |||
132 | int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop, int sig); | ||
133 | /* | ||
134 | * basic sp math | ||
135 | */ | ||
136 | ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip); | ||
137 | ieee754sp ieee754sp_frexp(ieee754sp x, int *exp); | ||
138 | ieee754sp ieee754sp_ldexp(ieee754sp x, int exp); | ||
139 | 58 | ||
140 | ieee754sp ieee754sp_ceil(ieee754sp x); | 59 | union ieee754sp ieee754sp_abs(union ieee754sp x); |
141 | ieee754sp ieee754sp_floor(ieee754sp x); | 60 | union ieee754sp ieee754sp_neg(union ieee754sp x); |
142 | ieee754sp ieee754sp_trunc(ieee754sp x); | ||
143 | 61 | ||
144 | ieee754sp ieee754sp_sqrt(ieee754sp x); | 62 | union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y); |
63 | union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y); | ||
64 | union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y); | ||
65 | union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y); | ||
145 | 66 | ||
146 | /* | 67 | union ieee754sp ieee754sp_fint(int x); |
147 | * double precision (often aka double) | 68 | union ieee754sp ieee754sp_flong(s64 x); |
148 | */ | 69 | union ieee754sp ieee754sp_fdp(union ieee754dp x); |
149 | int ieee754dp_finite(ieee754dp x); | ||
150 | int ieee754dp_class(ieee754dp x); | ||
151 | 70 | ||
152 | /* x with sign of y */ | 71 | int ieee754sp_tint(union ieee754sp x); |
153 | ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y); | 72 | s64 ieee754sp_tlong(union ieee754sp x); |
154 | 73 | ||
155 | ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y); | 74 | int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cop, int sig); |
156 | ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y); | ||
157 | ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y); | ||
158 | ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y); | ||
159 | 75 | ||
160 | ieee754dp ieee754dp_abs(ieee754dp x); | 76 | union ieee754sp ieee754sp_sqrt(union ieee754sp x); |
161 | ieee754dp ieee754dp_neg(ieee754dp x); | ||
162 | ieee754dp ieee754dp_scalb(ieee754dp x, int); | ||
163 | 77 | ||
164 | /* return exponent as integer in floating point format | 78 | /* |
165 | */ | 79 | * double precision (often aka double) |
166 | ieee754dp ieee754dp_logb(ieee754dp x); | 80 | */ |
81 | int ieee754dp_class(union ieee754dp x); | ||
167 | 82 | ||
168 | ieee754dp ieee754dp_fint(int x); | 83 | union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y); |
169 | ieee754dp ieee754dp_funs(unsigned x); | 84 | union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y); |
170 | ieee754dp ieee754dp_flong(s64 x); | 85 | union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y); |
171 | ieee754dp ieee754dp_fulong(u64 x); | 86 | union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y); |
172 | ieee754dp ieee754dp_fsp(ieee754sp x); | ||
173 | 87 | ||
174 | ieee754dp ieee754dp_ceil(ieee754dp x); | 88 | union ieee754dp ieee754dp_abs(union ieee754dp x); |
175 | ieee754dp ieee754dp_floor(ieee754dp x); | 89 | union ieee754dp ieee754dp_neg(union ieee754dp x); |
176 | ieee754dp ieee754dp_trunc(ieee754dp x); | ||
177 | 90 | ||
178 | int ieee754dp_tint(ieee754dp x); | 91 | union ieee754dp ieee754dp_fint(int x); |
179 | unsigned int ieee754dp_tuns(ieee754dp x); | 92 | union ieee754dp ieee754dp_flong(s64 x); |
180 | s64 ieee754dp_tlong(ieee754dp x); | 93 | union ieee754dp ieee754dp_fsp(union ieee754sp x); |
181 | u64 ieee754dp_tulong(ieee754dp x); | ||
182 | 94 | ||
183 | int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop, int sig); | 95 | int ieee754dp_tint(union ieee754dp x); |
184 | /* | 96 | s64 ieee754dp_tlong(union ieee754dp x); |
185 | * basic sp math | ||
186 | */ | ||
187 | ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip); | ||
188 | ieee754dp ieee754dp_frexp(ieee754dp x, int *exp); | ||
189 | ieee754dp ieee754dp_ldexp(ieee754dp x, int exp); | ||
190 | 97 | ||
191 | ieee754dp ieee754dp_ceil(ieee754dp x); | 98 | int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cop, int sig); |
192 | ieee754dp ieee754dp_floor(ieee754dp x); | ||
193 | ieee754dp ieee754dp_trunc(ieee754dp x); | ||
194 | 99 | ||
195 | ieee754dp ieee754dp_sqrt(ieee754dp x); | 100 | union ieee754dp ieee754dp_sqrt(union ieee754dp x); |
196 | 101 | ||
197 | 102 | ||
198 | 103 | ||
199 | /* 5 types of floating point number | 104 | /* 5 types of floating point number |
200 | */ | 105 | */ |
201 | #define IEEE754_CLASS_NORM 0x00 | 106 | enum { |
202 | #define IEEE754_CLASS_ZERO 0x01 | 107 | IEEE754_CLASS_NORM = 0x00, |
203 | #define IEEE754_CLASS_DNORM 0x02 | 108 | IEEE754_CLASS_ZERO = 0x01, |
204 | #define IEEE754_CLASS_INF 0x03 | 109 | IEEE754_CLASS_DNORM = 0x02, |
205 | #define IEEE754_CLASS_SNAN 0x04 | 110 | IEEE754_CLASS_INF = 0x03, |
206 | #define IEEE754_CLASS_QNAN 0x05 | 111 | IEEE754_CLASS_SNAN = 0x04, |
112 | IEEE754_CLASS_QNAN = 0x05, | ||
113 | }; | ||
207 | 114 | ||
208 | /* exception numbers */ | 115 | /* exception numbers */ |
209 | #define IEEE754_INEXACT 0x01 | 116 | #define IEEE754_INEXACT 0x01 |
@@ -219,114 +126,84 @@ ieee754dp ieee754dp_sqrt(ieee754dp x); | |||
219 | #define IEEE754_CGT 0x04 | 126 | #define IEEE754_CGT 0x04 |
220 | #define IEEE754_CUN 0x08 | 127 | #define IEEE754_CUN 0x08 |
221 | 128 | ||
222 | /* rounding mode | ||
223 | */ | ||
224 | #define IEEE754_RN 0 /* round to nearest */ | ||
225 | #define IEEE754_RZ 1 /* round toward zero */ | ||
226 | #define IEEE754_RD 2 /* round toward -Infinity */ | ||
227 | #define IEEE754_RU 3 /* round toward +Infinity */ | ||
228 | |||
229 | /* other naming */ | ||
230 | #define IEEE754_RM IEEE754_RD | ||
231 | #define IEEE754_RP IEEE754_RU | ||
232 | |||
233 | /* "normal" comparisons | 129 | /* "normal" comparisons |
234 | */ | 130 | */ |
235 | static inline int ieee754sp_eq(ieee754sp x, ieee754sp y) | 131 | static inline int ieee754sp_eq(union ieee754sp x, union ieee754sp y) |
236 | { | 132 | { |
237 | return ieee754sp_cmp(x, y, IEEE754_CEQ, 0); | 133 | return ieee754sp_cmp(x, y, IEEE754_CEQ, 0); |
238 | } | 134 | } |
239 | 135 | ||
240 | static inline int ieee754sp_ne(ieee754sp x, ieee754sp y) | 136 | static inline int ieee754sp_ne(union ieee754sp x, union ieee754sp y) |
241 | { | 137 | { |
242 | return ieee754sp_cmp(x, y, | 138 | return ieee754sp_cmp(x, y, |
243 | IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); | 139 | IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); |
244 | } | 140 | } |
245 | 141 | ||
246 | static inline int ieee754sp_lt(ieee754sp x, ieee754sp y) | 142 | static inline int ieee754sp_lt(union ieee754sp x, union ieee754sp y) |
247 | { | 143 | { |
248 | return ieee754sp_cmp(x, y, IEEE754_CLT, 0); | 144 | return ieee754sp_cmp(x, y, IEEE754_CLT, 0); |
249 | } | 145 | } |
250 | 146 | ||
251 | static inline int ieee754sp_le(ieee754sp x, ieee754sp y) | 147 | static inline int ieee754sp_le(union ieee754sp x, union ieee754sp y) |
252 | { | 148 | { |
253 | return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); | 149 | return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); |
254 | } | 150 | } |
255 | 151 | ||
256 | static inline int ieee754sp_gt(ieee754sp x, ieee754sp y) | 152 | static inline int ieee754sp_gt(union ieee754sp x, union ieee754sp y) |
257 | { | 153 | { |
258 | return ieee754sp_cmp(x, y, IEEE754_CGT, 0); | 154 | return ieee754sp_cmp(x, y, IEEE754_CGT, 0); |
259 | } | 155 | } |
260 | 156 | ||
261 | 157 | ||
262 | static inline int ieee754sp_ge(ieee754sp x, ieee754sp y) | 158 | static inline int ieee754sp_ge(union ieee754sp x, union ieee754sp y) |
263 | { | 159 | { |
264 | return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); | 160 | return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); |
265 | } | 161 | } |
266 | 162 | ||
267 | static inline int ieee754dp_eq(ieee754dp x, ieee754dp y) | 163 | static inline int ieee754dp_eq(union ieee754dp x, union ieee754dp y) |
268 | { | 164 | { |
269 | return ieee754dp_cmp(x, y, IEEE754_CEQ, 0); | 165 | return ieee754dp_cmp(x, y, IEEE754_CEQ, 0); |
270 | } | 166 | } |
271 | 167 | ||
272 | static inline int ieee754dp_ne(ieee754dp x, ieee754dp y) | 168 | static inline int ieee754dp_ne(union ieee754dp x, union ieee754dp y) |
273 | { | 169 | { |
274 | return ieee754dp_cmp(x, y, | 170 | return ieee754dp_cmp(x, y, |
275 | IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); | 171 | IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); |
276 | } | 172 | } |
277 | 173 | ||
278 | static inline int ieee754dp_lt(ieee754dp x, ieee754dp y) | 174 | static inline int ieee754dp_lt(union ieee754dp x, union ieee754dp y) |
279 | { | 175 | { |
280 | return ieee754dp_cmp(x, y, IEEE754_CLT, 0); | 176 | return ieee754dp_cmp(x, y, IEEE754_CLT, 0); |
281 | } | 177 | } |
282 | 178 | ||
283 | static inline int ieee754dp_le(ieee754dp x, ieee754dp y) | 179 | static inline int ieee754dp_le(union ieee754dp x, union ieee754dp y) |
284 | { | 180 | { |
285 | return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); | 181 | return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); |
286 | } | 182 | } |
287 | 183 | ||
288 | static inline int ieee754dp_gt(ieee754dp x, ieee754dp y) | 184 | static inline int ieee754dp_gt(union ieee754dp x, union ieee754dp y) |
289 | { | 185 | { |
290 | return ieee754dp_cmp(x, y, IEEE754_CGT, 0); | 186 | return ieee754dp_cmp(x, y, IEEE754_CGT, 0); |
291 | } | 187 | } |
292 | 188 | ||
293 | static inline int ieee754dp_ge(ieee754dp x, ieee754dp y) | 189 | static inline int ieee754dp_ge(union ieee754dp x, union ieee754dp y) |
294 | { | 190 | { |
295 | return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); | 191 | return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); |
296 | } | 192 | } |
297 | 193 | ||
298 | |||
299 | /* | ||
300 | * Like strtod | ||
301 | */ | ||
302 | ieee754dp ieee754dp_fstr(const char *s, char **endp); | ||
303 | char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af); | ||
304 | |||
305 | |||
306 | /* | 194 | /* |
307 | * The control status register | 195 | * The control status register |
308 | */ | 196 | */ |
309 | struct _ieee754_csr { | 197 | struct _ieee754_csr { |
310 | #ifdef __BIG_ENDIAN | 198 | __BITFIELD_FIELD(unsigned pad0:7, |
311 | unsigned pad0:7; | 199 | __BITFIELD_FIELD(unsigned nod:1, /* set 1 for no denormalised numbers */ |
312 | unsigned nod:1; /* set 1 for no denormalised numbers */ | 200 | __BITFIELD_FIELD(unsigned c:1, /* condition */ |
313 | unsigned c:1; /* condition */ | 201 | __BITFIELD_FIELD(unsigned pad1:5, |
314 | unsigned pad1:5; | 202 | __BITFIELD_FIELD(unsigned cx:6, /* exceptions this operation */ |
315 | unsigned cx:6; /* exceptions this operation */ | 203 | __BITFIELD_FIELD(unsigned mx:5, /* exception enable mask */ |
316 | unsigned mx:5; /* exception enable mask */ | 204 | __BITFIELD_FIELD(unsigned sx:5, /* exceptions total */ |
317 | unsigned sx:5; /* exceptions total */ | 205 | __BITFIELD_FIELD(unsigned rm:2, /* current rounding mode */ |
318 | unsigned rm:2; /* current rounding mode */ | 206 | ;)))))))) |
319 | #endif | ||
320 | #ifdef __LITTLE_ENDIAN | ||
321 | unsigned rm:2; /* current rounding mode */ | ||
322 | unsigned sx:5; /* exceptions total */ | ||
323 | unsigned mx:5; /* exception enable mask */ | ||
324 | unsigned cx:6; /* exceptions this operation */ | ||
325 | unsigned pad1:5; | ||
326 | unsigned c:1; /* condition */ | ||
327 | unsigned nod:1; /* set 1 for no denormalised numbers */ | ||
328 | unsigned pad0:7; | ||
329 | #endif | ||
330 | }; | 207 | }; |
331 | #define ieee754_csr (*(struct _ieee754_csr *)(¤t->thread.fpu.fcr31)) | 208 | #define ieee754_csr (*(struct _ieee754_csr *)(¤t->thread.fpu.fcr31)) |
332 | 209 | ||
@@ -377,8 +254,8 @@ static inline int ieee754_sxtest(unsigned n) | |||
377 | } | 254 | } |
378 | 255 | ||
379 | /* debugging */ | 256 | /* debugging */ |
380 | ieee754sp ieee754sp_dump(char *s, ieee754sp x); | 257 | union ieee754sp ieee754sp_dump(char *s, union ieee754sp x); |
381 | ieee754dp ieee754dp_dump(char *s, ieee754dp x); | 258 | union ieee754dp ieee754dp_dump(char *s, union ieee754dp x); |
382 | 259 | ||
383 | #define IEEE754_SPCVAL_PZERO 0 | 260 | #define IEEE754_SPCVAL_PZERO 0 |
384 | #define IEEE754_SPCVAL_NZERO 1 | 261 | #define IEEE754_SPCVAL_NZERO 1 |
@@ -398,10 +275,10 @@ ieee754dp ieee754dp_dump(char *s, ieee754dp x); | |||
398 | #define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ | 275 | #define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ |
399 | #define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ | 276 | #define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ |
400 | 277 | ||
401 | extern const struct ieee754dp_konst __ieee754dp_spcvals[]; | 278 | extern const union ieee754dp __ieee754dp_spcvals[]; |
402 | extern const struct ieee754sp_konst __ieee754sp_spcvals[]; | 279 | extern const union ieee754sp __ieee754sp_spcvals[]; |
403 | #define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals) | 280 | #define ieee754dp_spcvals ((const union ieee754dp *)__ieee754dp_spcvals) |
404 | #define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals) | 281 | #define ieee754sp_spcvals ((const union ieee754sp *)__ieee754sp_spcvals) |
405 | 282 | ||
406 | /* | 283 | /* |
407 | * Return infinity with given sign | 284 | * Return infinity with given sign |
@@ -431,28 +308,15 @@ extern const struct ieee754sp_konst __ieee754sp_spcvals[]; | |||
431 | /* | 308 | /* |
432 | * Indefinite integer value | 309 | * Indefinite integer value |
433 | */ | 310 | */ |
434 | #define ieee754si_indef() INT_MAX | 311 | static inline int ieee754si_indef(void) |
435 | #ifdef LONG_LONG_MAX | 312 | { |
436 | #define ieee754di_indef() LONG_LONG_MAX | 313 | return INT_MAX; |
437 | #else | 314 | } |
438 | #define ieee754di_indef() ((s64)(~0ULL>>1)) | 315 | |
439 | #endif | 316 | static inline s64 ieee754di_indef(void) |
440 | 317 | { | |
441 | /* IEEE exception context, passed to handler */ | 318 | return S64_MAX; |
442 | struct ieee754xctx { | 319 | } |
443 | const char *op; /* operation name */ | ||
444 | int rt; /* result type */ | ||
445 | union { | ||
446 | ieee754sp sp; /* single precision */ | ||
447 | ieee754dp dp; /* double precision */ | ||
448 | #ifdef IEEE854_XP | ||
449 | ieee754xp xp; /* extended precision */ | ||
450 | #endif | ||
451 | int si; /* standard signed integer (32bits) */ | ||
452 | s64 di; /* extended signed integer (64bits) */ | ||
453 | } rv; /* default result format implied by op */ | ||
454 | va_list ap; | ||
455 | }; | ||
456 | 320 | ||
457 | /* result types for xctx.rt */ | 321 | /* result types for xctx.rt */ |
458 | #define IEEE754_RT_SP 0 | 322 | #define IEEE754_RT_SP 0 |
@@ -461,8 +325,6 @@ struct ieee754xctx { | |||
461 | #define IEEE754_RT_SI 3 | 325 | #define IEEE754_RT_SI 3 |
462 | #define IEEE754_RT_DI 4 | 326 | #define IEEE754_RT_DI 4 |
463 | 327 | ||
464 | extern void ieee754_xcpt(struct ieee754xctx *xcp); | ||
465 | |||
466 | /* compat */ | 328 | /* compat */ |
467 | #define ieee754dp_fix(x) ieee754dp_tint(x) | 329 | #define ieee754dp_fix(x) ieee754dp_tint(x) |
468 | #define ieee754sp_fix(x) ieee754sp_tint(x) | 330 | #define ieee754sp_fix(x) ieee754sp_tint(x) |
diff --git a/arch/mips/math-emu/ieee754d.c b/arch/mips/math-emu/ieee754d.c index 9599bdd32585..a04e8a7e5ac3 100644 --- a/arch/mips/math-emu/ieee754d.c +++ b/arch/mips/math-emu/ieee754d.c | |||
@@ -16,7 +16,7 @@ | |||
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
18 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
19 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | * | 20 | * |
21 | * Nov 7, 2000 | 21 | * Nov 7, 2000 |
22 | * Modified to build and operate in Linux kernel environment. | 22 | * Modified to build and operate in Linux kernel environment. |
@@ -25,38 +25,13 @@ | |||
25 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. | 25 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/kernel.h> | 28 | #include <linux/types.h> |
29 | #include <linux/printk.h> | ||
29 | #include "ieee754.h" | 30 | #include "ieee754.h" |
31 | #include "ieee754sp.h" | ||
32 | #include "ieee754dp.h" | ||
30 | 33 | ||
31 | #define DP_EBIAS 1023 | 34 | union ieee754dp ieee754dp_dump(char *m, union ieee754dp x) |
32 | #define DP_EMIN (-1022) | ||
33 | #define DP_EMAX 1023 | ||
34 | #define DP_FBITS 52 | ||
35 | |||
36 | #define SP_EBIAS 127 | ||
37 | #define SP_EMIN (-126) | ||
38 | #define SP_EMAX 127 | ||
39 | #define SP_FBITS 23 | ||
40 | |||
41 | #define DP_MBIT(x) ((u64)1 << (x)) | ||
42 | #define DP_HIDDEN_BIT DP_MBIT(DP_FBITS) | ||
43 | #define DP_SIGN_BIT DP_MBIT(63) | ||
44 | |||
45 | |||
46 | #define SP_MBIT(x) ((u32)1 << (x)) | ||
47 | #define SP_HIDDEN_BIT SP_MBIT(SP_FBITS) | ||
48 | #define SP_SIGN_BIT SP_MBIT(31) | ||
49 | |||
50 | |||
51 | #define SPSIGN(sp) (sp.parts.sign) | ||
52 | #define SPBEXP(sp) (sp.parts.bexp) | ||
53 | #define SPMANT(sp) (sp.parts.mant) | ||
54 | |||
55 | #define DPSIGN(dp) (dp.parts.sign) | ||
56 | #define DPBEXP(dp) (dp.parts.bexp) | ||
57 | #define DPMANT(dp) (dp.parts.mant) | ||
58 | |||
59 | ieee754dp ieee754dp_dump(char *m, ieee754dp x) | ||
60 | { | 35 | { |
61 | int i; | 36 | int i; |
62 | 37 | ||
@@ -96,7 +71,7 @@ ieee754dp ieee754dp_dump(char *m, ieee754dp x) | |||
96 | return x; | 71 | return x; |
97 | } | 72 | } |
98 | 73 | ||
99 | ieee754sp ieee754sp_dump(char *m, ieee754sp x) | 74 | union ieee754sp ieee754sp_dump(char *m, union ieee754sp x) |
100 | { | 75 | { |
101 | int i; | 76 | int i; |
102 | 77 | ||
diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c index 068e56be8de9..fd134675fc2e 100644 --- a/arch/mips/math-emu/ieee754dp.c +++ b/arch/mips/math-emu/ieee754dp.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,104 +16,68 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
22 | #include <linux/compiler.h> | ||
26 | 23 | ||
27 | #include "ieee754dp.h" | 24 | #include "ieee754dp.h" |
28 | 25 | ||
29 | int ieee754dp_class(ieee754dp x) | 26 | int ieee754dp_class(union ieee754dp x) |
30 | { | 27 | { |
31 | COMPXDP; | 28 | COMPXDP; |
32 | EXPLODEXDP; | 29 | EXPLODEXDP; |
33 | return xc; | 30 | return xc; |
34 | } | 31 | } |
35 | 32 | ||
36 | int ieee754dp_isnan(ieee754dp x) | 33 | int ieee754dp_isnan(union ieee754dp x) |
37 | { | 34 | { |
38 | return ieee754dp_class(x) >= IEEE754_CLASS_SNAN; | 35 | return ieee754dp_class(x) >= IEEE754_CLASS_SNAN; |
39 | } | 36 | } |
40 | 37 | ||
41 | int ieee754dp_issnan(ieee754dp x) | 38 | static inline int ieee754dp_issnan(union ieee754dp x) |
42 | { | 39 | { |
43 | assert(ieee754dp_isnan(x)); | 40 | assert(ieee754dp_isnan(x)); |
44 | return ((DPMANT(x) & DP_MBIT(DP_MBITS-1)) == DP_MBIT(DP_MBITS-1)); | 41 | return ((DPMANT(x) & DP_MBIT(DP_FBITS-1)) == DP_MBIT(DP_FBITS-1)); |
45 | } | 42 | } |
46 | 43 | ||
47 | 44 | ||
48 | ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...) | 45 | union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r) |
49 | { | ||
50 | struct ieee754xctx ax; | ||
51 | if (!TSTX()) | ||
52 | return r; | ||
53 | |||
54 | ax.op = op; | ||
55 | ax.rt = IEEE754_RT_DP; | ||
56 | ax.rv.dp = r; | ||
57 | va_start(ax.ap, op); | ||
58 | ieee754_xcpt(&ax); | ||
59 | va_end(ax.ap); | ||
60 | return ax.rv.dp; | ||
61 | } | ||
62 | |||
63 | ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...) | ||
64 | { | 46 | { |
65 | struct ieee754xctx ax; | ||
66 | |||
67 | assert(ieee754dp_isnan(r)); | 47 | assert(ieee754dp_isnan(r)); |
68 | 48 | ||
69 | if (!ieee754dp_issnan(r)) /* QNAN does not cause invalid op !! */ | 49 | if (!ieee754dp_issnan(r)) /* QNAN does not cause invalid op !! */ |
70 | return r; | 50 | return r; |
71 | 51 | ||
72 | if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) { | 52 | if (!ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) { |
73 | /* not enabled convert to a quiet NaN */ | 53 | /* not enabled convert to a quiet NaN */ |
74 | DPMANT(r) &= (~DP_MBIT(DP_MBITS-1)); | 54 | DPMANT(r) &= (~DP_MBIT(DP_FBITS-1)); |
75 | if (ieee754dp_isnan(r)) | 55 | if (ieee754dp_isnan(r)) |
76 | return r; | 56 | return r; |
77 | else | 57 | else |
78 | return ieee754dp_indef(); | 58 | return ieee754dp_indef(); |
79 | } | 59 | } |
80 | 60 | ||
81 | ax.op = op; | 61 | return r; |
82 | ax.rt = 0; | ||
83 | ax.rv.dp = r; | ||
84 | va_start(ax.ap, op); | ||
85 | ieee754_xcpt(&ax); | ||
86 | va_end(ax.ap); | ||
87 | return ax.rv.dp; | ||
88 | } | 62 | } |
89 | 63 | ||
90 | ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y) | 64 | static u64 ieee754dp_get_rounding(int sn, u64 xm) |
91 | { | ||
92 | assert(ieee754dp_isnan(x)); | ||
93 | assert(ieee754dp_isnan(y)); | ||
94 | |||
95 | if (DPMANT(x) > DPMANT(y)) | ||
96 | return x; | ||
97 | else | ||
98 | return y; | ||
99 | } | ||
100 | |||
101 | |||
102 | static u64 get_rounding(int sn, u64 xm) | ||
103 | { | 65 | { |
104 | /* inexact must round of 3 bits | 66 | /* inexact must round of 3 bits |
105 | */ | 67 | */ |
106 | if (xm & (DP_MBIT(3) - 1)) { | 68 | if (xm & (DP_MBIT(3) - 1)) { |
107 | switch (ieee754_csr.rm) { | 69 | switch (ieee754_csr.rm) { |
108 | case IEEE754_RZ: | 70 | case FPU_CSR_RZ: |
109 | break; | 71 | break; |
110 | case IEEE754_RN: | 72 | case FPU_CSR_RN: |
111 | xm += 0x3 + ((xm >> 3) & 1); | 73 | xm += 0x3 + ((xm >> 3) & 1); |
112 | /* xm += (xm&0x8)?0x4:0x3 */ | 74 | /* xm += (xm&0x8)?0x4:0x3 */ |
113 | break; | 75 | break; |
114 | case IEEE754_RU: /* toward +Infinity */ | 76 | case FPU_CSR_RU: /* toward +Infinity */ |
115 | if (!sn) /* ?? */ | 77 | if (!sn) /* ?? */ |
116 | xm += 0x8; | 78 | xm += 0x8; |
117 | break; | 79 | break; |
118 | case IEEE754_RD: /* toward -Infinity */ | 80 | case FPU_CSR_RD: /* toward -Infinity */ |
119 | if (sn) /* ?? */ | 81 | if (sn) /* ?? */ |
120 | xm += 0x8; | 82 | xm += 0x8; |
121 | break; | 83 | break; |
@@ -130,11 +92,11 @@ static u64 get_rounding(int sn, u64 xm) | |||
130 | * xe is an unbiased exponent | 92 | * xe is an unbiased exponent |
131 | * xm is 3bit extended precision value. | 93 | * xm is 3bit extended precision value. |
132 | */ | 94 | */ |
133 | ieee754dp ieee754dp_format(int sn, int xe, u64 xm) | 95 | union ieee754dp ieee754dp_format(int sn, int xe, u64 xm) |
134 | { | 96 | { |
135 | assert(xm); /* we don't gen exact zeros (probably should) */ | 97 | assert(xm); /* we don't gen exact zeros (probably should) */ |
136 | 98 | ||
137 | assert((xm >> (DP_MBITS + 1 + 3)) == 0); /* no execess */ | 99 | assert((xm >> (DP_FBITS + 1 + 3)) == 0); /* no execess */ |
138 | assert(xm & (DP_HIDDEN_BIT << 3)); | 100 | assert(xm & (DP_HIDDEN_BIT << 3)); |
139 | 101 | ||
140 | if (xe < DP_EMIN) { | 102 | if (xe < DP_EMIN) { |
@@ -142,32 +104,32 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) | |||
142 | int es = DP_EMIN - xe; | 104 | int es = DP_EMIN - xe; |
143 | 105 | ||
144 | if (ieee754_csr.nod) { | 106 | if (ieee754_csr.nod) { |
145 | SETCX(IEEE754_UNDERFLOW); | 107 | ieee754_setcx(IEEE754_UNDERFLOW); |
146 | SETCX(IEEE754_INEXACT); | 108 | ieee754_setcx(IEEE754_INEXACT); |
147 | 109 | ||
148 | switch(ieee754_csr.rm) { | 110 | switch(ieee754_csr.rm) { |
149 | case IEEE754_RN: | 111 | case FPU_CSR_RN: |
150 | case IEEE754_RZ: | 112 | case FPU_CSR_RZ: |
151 | return ieee754dp_zero(sn); | 113 | return ieee754dp_zero(sn); |
152 | case IEEE754_RU: /* toward +Infinity */ | 114 | case FPU_CSR_RU: /* toward +Infinity */ |
153 | if(sn == 0) | 115 | if (sn == 0) |
154 | return ieee754dp_min(0); | 116 | return ieee754dp_min(0); |
155 | else | 117 | else |
156 | return ieee754dp_zero(1); | 118 | return ieee754dp_zero(1); |
157 | case IEEE754_RD: /* toward -Infinity */ | 119 | case FPU_CSR_RD: /* toward -Infinity */ |
158 | if(sn == 0) | 120 | if (sn == 0) |
159 | return ieee754dp_zero(0); | 121 | return ieee754dp_zero(0); |
160 | else | 122 | else |
161 | return ieee754dp_min(1); | 123 | return ieee754dp_min(1); |
162 | } | 124 | } |
163 | } | 125 | } |
164 | 126 | ||
165 | if (xe == DP_EMIN - 1 | 127 | if (xe == DP_EMIN - 1 && |
166 | && get_rounding(sn, xm) >> (DP_MBITS + 1 + 3)) | 128 | ieee754dp_get_rounding(sn, xm) >> (DP_FBITS + 1 + 3)) |
167 | { | 129 | { |
168 | /* Not tiny after rounding */ | 130 | /* Not tiny after rounding */ |
169 | SETCX(IEEE754_INEXACT); | 131 | ieee754_setcx(IEEE754_INEXACT); |
170 | xm = get_rounding(sn, xm); | 132 | xm = ieee754dp_get_rounding(sn, xm); |
171 | xm >>= 1; | 133 | xm >>= 1; |
172 | /* Clear grs bits */ | 134 | /* Clear grs bits */ |
173 | xm &= ~(DP_MBIT(3) - 1); | 135 | xm &= ~(DP_MBIT(3) - 1); |
@@ -183,17 +145,17 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) | |||
183 | } | 145 | } |
184 | } | 146 | } |
185 | if (xm & (DP_MBIT(3) - 1)) { | 147 | if (xm & (DP_MBIT(3) - 1)) { |
186 | SETCX(IEEE754_INEXACT); | 148 | ieee754_setcx(IEEE754_INEXACT); |
187 | if ((xm & (DP_HIDDEN_BIT << 3)) == 0) { | 149 | if ((xm & (DP_HIDDEN_BIT << 3)) == 0) { |
188 | SETCX(IEEE754_UNDERFLOW); | 150 | ieee754_setcx(IEEE754_UNDERFLOW); |
189 | } | 151 | } |
190 | 152 | ||
191 | /* inexact must round of 3 bits | 153 | /* inexact must round of 3 bits |
192 | */ | 154 | */ |
193 | xm = get_rounding(sn, xm); | 155 | xm = ieee754dp_get_rounding(sn, xm); |
194 | /* adjust exponent for rounding add overflowing | 156 | /* adjust exponent for rounding add overflowing |
195 | */ | 157 | */ |
196 | if (xm >> (DP_MBITS + 3 + 1)) { | 158 | if (xm >> (DP_FBITS + 3 + 1)) { |
197 | /* add causes mantissa overflow */ | 159 | /* add causes mantissa overflow */ |
198 | xm >>= 1; | 160 | xm >>= 1; |
199 | xe++; | 161 | xe++; |
@@ -202,24 +164,24 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) | |||
202 | /* strip grs bits */ | 164 | /* strip grs bits */ |
203 | xm >>= 3; | 165 | xm >>= 3; |
204 | 166 | ||
205 | assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ | 167 | assert((xm >> (DP_FBITS + 1)) == 0); /* no execess */ |
206 | assert(xe >= DP_EMIN); | 168 | assert(xe >= DP_EMIN); |
207 | 169 | ||
208 | if (xe > DP_EMAX) { | 170 | if (xe > DP_EMAX) { |
209 | SETCX(IEEE754_OVERFLOW); | 171 | ieee754_setcx(IEEE754_OVERFLOW); |
210 | SETCX(IEEE754_INEXACT); | 172 | ieee754_setcx(IEEE754_INEXACT); |
211 | /* -O can be table indexed by (rm,sn) */ | 173 | /* -O can be table indexed by (rm,sn) */ |
212 | switch (ieee754_csr.rm) { | 174 | switch (ieee754_csr.rm) { |
213 | case IEEE754_RN: | 175 | case FPU_CSR_RN: |
214 | return ieee754dp_inf(sn); | 176 | return ieee754dp_inf(sn); |
215 | case IEEE754_RZ: | 177 | case FPU_CSR_RZ: |
216 | return ieee754dp_max(sn); | 178 | return ieee754dp_max(sn); |
217 | case IEEE754_RU: /* toward +Infinity */ | 179 | case FPU_CSR_RU: /* toward +Infinity */ |
218 | if (sn == 0) | 180 | if (sn == 0) |
219 | return ieee754dp_inf(0); | 181 | return ieee754dp_inf(0); |
220 | else | 182 | else |
221 | return ieee754dp_max(1); | 183 | return ieee754dp_max(1); |
222 | case IEEE754_RD: /* toward -Infinity */ | 184 | case FPU_CSR_RD: /* toward -Infinity */ |
223 | if (sn == 0) | 185 | if (sn == 0) |
224 | return ieee754dp_max(0); | 186 | return ieee754dp_max(0); |
225 | else | 187 | else |
@@ -232,10 +194,10 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) | |||
232 | /* we underflow (tiny/zero) */ | 194 | /* we underflow (tiny/zero) */ |
233 | assert(xe == DP_EMIN); | 195 | assert(xe == DP_EMIN); |
234 | if (ieee754_csr.mx & IEEE754_UNDERFLOW) | 196 | if (ieee754_csr.mx & IEEE754_UNDERFLOW) |
235 | SETCX(IEEE754_UNDERFLOW); | 197 | ieee754_setcx(IEEE754_UNDERFLOW); |
236 | return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); | 198 | return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); |
237 | } else { | 199 | } else { |
238 | assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ | 200 | assert((xm >> (DP_FBITS + 1)) == 0); /* no execess */ |
239 | assert(xm & DP_HIDDEN_BIT); | 201 | assert(xm & DP_HIDDEN_BIT); |
240 | 202 | ||
241 | return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); | 203 | return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); |
diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h index f139c724c59a..61fd6fd31350 100644 --- a/arch/mips/math-emu/ieee754dp.h +++ b/arch/mips/math-emu/ieee754dp.h | |||
@@ -6,8 +6,6 @@ | |||
6 | * MIPS floating point support | 6 | * MIPS floating point support |
7 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 7 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
8 | * | 8 | * |
9 | * ######################################################################## | ||
10 | * | ||
11 | * This program is free software; you can distribute it and/or modify it | 9 | * This program is free software; you can distribute it and/or modify it |
12 | * under the terms of the GNU General Public License (Version 2) as | 10 | * under the terms of the GNU General Public License (Version 2) as |
13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -19,64 +17,66 @@ | |||
19 | * | 17 | * |
20 | * You should have received a copy of the GNU General Public License along | 18 | * You should have received a copy of the GNU General Public License along |
21 | * with this program; if not, write to the Free Software Foundation, Inc., | 19 | * with this program; if not, write to the Free Software Foundation, Inc., |
22 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 20 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
23 | * | ||
24 | * ######################################################################## | ||
25 | */ | 21 | */ |
26 | 22 | ||
23 | #include <linux/compiler.h> | ||
27 | 24 | ||
28 | #include "ieee754int.h" | 25 | #include "ieee754int.h" |
29 | 26 | ||
30 | #define assert(expr) ((void)0) | 27 | #define assert(expr) ((void)0) |
31 | 28 | ||
29 | #define DP_EBIAS 1023 | ||
30 | #define DP_EMIN (-1022) | ||
31 | #define DP_EMAX 1023 | ||
32 | #define DP_FBITS 52 | ||
33 | #define DP_MBITS 52 | ||
34 | |||
35 | #define DP_MBIT(x) ((u64)1 << (x)) | ||
36 | #define DP_HIDDEN_BIT DP_MBIT(DP_FBITS) | ||
37 | #define DP_SIGN_BIT DP_MBIT(63) | ||
38 | |||
39 | #define DPSIGN(dp) (dp.sign) | ||
40 | #define DPBEXP(dp) (dp.bexp) | ||
41 | #define DPMANT(dp) (dp.mant) | ||
42 | |||
43 | static inline int ieee754dp_finite(union ieee754dp x) | ||
44 | { | ||
45 | return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS; | ||
46 | } | ||
47 | |||
32 | /* 3bit extended double precision sticky right shift */ | 48 | /* 3bit extended double precision sticky right shift */ |
33 | #define XDPSRS(v,rs) \ | 49 | #define XDPSRS(v,rs) \ |
34 | ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0)) | 50 | ((rs > (DP_FBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0)) |
35 | 51 | ||
36 | #define XDPSRSX1() \ | 52 | #define XDPSRSX1() \ |
37 | (xe++, (xm = (xm >> 1) | (xm & 1))) | 53 | (xe++, (xm = (xm >> 1) | (xm & 1))) |
38 | 54 | ||
39 | #define XDPSRS1(v) \ | 55 | #define XDPSRS1(v) \ |
40 | (((v) >> 1) | ((v) & 1)) | 56 | (((v) >> 1) | ((v) & 1)) |
41 | 57 | ||
42 | /* convert denormal to normalized with extended exponent */ | 58 | /* convert denormal to normalized with extended exponent */ |
43 | #define DPDNORMx(m,e) \ | 59 | #define DPDNORMx(m,e) \ |
44 | while( (m >> DP_MBITS) == 0) { m <<= 1; e--; } | 60 | while ((m >> DP_FBITS) == 0) { m <<= 1; e--; } |
45 | #define DPDNORMX DPDNORMx(xm, xe) | 61 | #define DPDNORMX DPDNORMx(xm, xe) |
46 | #define DPDNORMY DPDNORMx(ym, ye) | 62 | #define DPDNORMY DPDNORMx(ym, ye) |
47 | 63 | ||
48 | static inline ieee754dp builddp(int s, int bx, u64 m) | 64 | static inline union ieee754dp builddp(int s, int bx, u64 m) |
49 | { | 65 | { |
50 | ieee754dp r; | 66 | union ieee754dp r; |
51 | 67 | ||
52 | assert((s) == 0 || (s) == 1); | 68 | assert((s) == 0 || (s) == 1); |
53 | assert((bx) >= DP_EMIN - 1 + DP_EBIAS | 69 | assert((bx) >= DP_EMIN - 1 + DP_EBIAS |
54 | && (bx) <= DP_EMAX + 1 + DP_EBIAS); | 70 | && (bx) <= DP_EMAX + 1 + DP_EBIAS); |
55 | assert(((m) >> DP_MBITS) == 0); | 71 | assert(((m) >> DP_FBITS) == 0); |
56 | 72 | ||
57 | r.parts.sign = s; | 73 | r.sign = s; |
58 | r.parts.bexp = bx; | 74 | r.bexp = bx; |
59 | r.parts.mant = m; | 75 | r.mant = m; |
60 | return r; | ||
61 | } | ||
62 | 76 | ||
63 | extern int ieee754dp_isnan(ieee754dp); | 77 | return r; |
64 | extern int ieee754dp_issnan(ieee754dp); | ||
65 | extern int ieee754si_xcpt(int, const char *, ...); | ||
66 | extern s64 ieee754di_xcpt(s64, const char *, ...); | ||
67 | extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...); | ||
68 | extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...); | ||
69 | extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp); | ||
70 | extern ieee754dp ieee754dp_format(int, int, u64); | ||
71 | |||
72 | |||
73 | #define DPNORMRET2(s, e, m, name, a0, a1) \ | ||
74 | { \ | ||
75 | ieee754dp V = ieee754dp_format(s, e, m); \ | ||
76 | if(TSTX()) \ | ||
77 | return ieee754dp_xcpt(V, name, a0, a1); \ | ||
78 | else \ | ||
79 | return V; \ | ||
80 | } | 78 | } |
81 | 79 | ||
82 | #define DPNORMRET1(s, e, m, name, a0) DPNORMRET2(s, e, m, name, a0, a0) | 80 | extern int ieee754dp_isnan(union ieee754dp); |
81 | extern union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp); | ||
82 | extern union ieee754dp ieee754dp_format(int, int, u64); | ||
diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index 4b6c6fb35304..f0365bb86747 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h | |||
@@ -6,8 +6,6 @@ | |||
6 | * MIPS floating point support | 6 | * MIPS floating point support |
7 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 7 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
8 | * | 8 | * |
9 | * ######################################################################## | ||
10 | * | ||
11 | * This program is free software; you can distribute it and/or modify it | 9 | * This program is free software; you can distribute it and/or modify it |
12 | * under the terms of the GNU General Public License (Version 2) as | 10 | * under the terms of the GNU General Public License (Version 2) as |
13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -19,146 +17,125 @@ | |||
19 | * | 17 | * |
20 | * You should have received a copy of the GNU General Public License along | 18 | * You should have received a copy of the GNU General Public License along |
21 | * with this program; if not, write to the Free Software Foundation, Inc., | 19 | * with this program; if not, write to the Free Software Foundation, Inc., |
22 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 20 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
23 | * | ||
24 | * ######################################################################## | ||
25 | */ | 21 | */ |
26 | 22 | #ifndef __IEEE754INT_H | |
23 | #define __IEEE754INT_H | ||
27 | 24 | ||
28 | #include "ieee754.h" | 25 | #include "ieee754.h" |
29 | 26 | ||
30 | #define DP_EBIAS 1023 | ||
31 | #define DP_EMIN (-1022) | ||
32 | #define DP_EMAX 1023 | ||
33 | #define DP_MBITS 52 | ||
34 | |||
35 | #define SP_EBIAS 127 | ||
36 | #define SP_EMIN (-126) | ||
37 | #define SP_EMAX 127 | ||
38 | #define SP_MBITS 23 | ||
39 | |||
40 | #define DP_MBIT(x) ((u64)1 << (x)) | ||
41 | #define DP_HIDDEN_BIT DP_MBIT(DP_MBITS) | ||
42 | #define DP_SIGN_BIT DP_MBIT(63) | ||
43 | |||
44 | #define SP_MBIT(x) ((u32)1 << (x)) | ||
45 | #define SP_HIDDEN_BIT SP_MBIT(SP_MBITS) | ||
46 | #define SP_SIGN_BIT SP_MBIT(31) | ||
47 | |||
48 | |||
49 | #define SPSIGN(sp) (sp.parts.sign) | ||
50 | #define SPBEXP(sp) (sp.parts.bexp) | ||
51 | #define SPMANT(sp) (sp.parts.mant) | ||
52 | |||
53 | #define DPSIGN(dp) (dp.parts.sign) | ||
54 | #define DPBEXP(dp) (dp.parts.bexp) | ||
55 | #define DPMANT(dp) (dp.parts.mant) | ||
56 | |||
57 | #define CLPAIR(x, y) ((x)*6+(y)) | 27 | #define CLPAIR(x, y) ((x)*6+(y)) |
58 | 28 | ||
59 | #define CLEARCX \ | 29 | static inline void ieee754_clearcx(void) |
60 | (ieee754_csr.cx = 0) | 30 | { |
61 | 31 | ieee754_csr.cx = 0; | |
62 | #define SETCX(x) \ | 32 | } |
63 | (ieee754_csr.cx |= (x), ieee754_csr.sx |= (x)) | ||
64 | 33 | ||
65 | #define SETANDTESTCX(x) \ | 34 | static inline void ieee754_setcx(const unsigned int flags) |
66 | (SETCX(x), ieee754_csr.mx & (x)) | 35 | { |
36 | ieee754_csr.cx |= flags; | ||
37 | ieee754_csr.sx |= flags; | ||
38 | } | ||
67 | 39 | ||
68 | #define TSTX() \ | 40 | static inline int ieee754_setandtestcx(const unsigned int x) |
69 | (ieee754_csr.cx & ieee754_csr.mx) | 41 | { |
42 | ieee754_setcx(x); | ||
70 | 43 | ||
44 | return ieee754_csr.mx & x; | ||
45 | } | ||
71 | 46 | ||
72 | #define COMPXSP \ | 47 | #define COMPXSP \ |
73 | unsigned xm; int xe; int xs __maybe_unused; int xc | 48 | unsigned xm; int xe; int xs __maybe_unused; int xc |
74 | 49 | ||
75 | #define COMPYSP \ | 50 | #define COMPYSP \ |
76 | unsigned ym; int ye; int ys; int yc | 51 | unsigned ym; int ye; int ys; int yc |
77 | 52 | ||
78 | #define EXPLODESP(v, vc, vs, ve, vm) \ | 53 | #define EXPLODESP(v, vc, vs, ve, vm) \ |
79 | {\ | 54 | { \ |
80 | vs = SPSIGN(v);\ | 55 | vs = SPSIGN(v); \ |
81 | ve = SPBEXP(v);\ | 56 | ve = SPBEXP(v); \ |
82 | vm = SPMANT(v);\ | 57 | vm = SPMANT(v); \ |
83 | if(ve == SP_EMAX+1+SP_EBIAS){\ | 58 | if (ve == SP_EMAX+1+SP_EBIAS) { \ |
84 | if(vm == 0)\ | 59 | if (vm == 0) \ |
85 | vc = IEEE754_CLASS_INF;\ | 60 | vc = IEEE754_CLASS_INF; \ |
86 | else if(vm & SP_MBIT(SP_MBITS-1)) \ | 61 | else if (vm & SP_MBIT(SP_FBITS-1)) \ |
87 | vc = IEEE754_CLASS_SNAN;\ | 62 | vc = IEEE754_CLASS_SNAN; \ |
88 | else \ | 63 | else \ |
89 | vc = IEEE754_CLASS_QNAN;\ | 64 | vc = IEEE754_CLASS_QNAN; \ |
90 | } else if(ve == SP_EMIN-1+SP_EBIAS) {\ | 65 | } else if (ve == SP_EMIN-1+SP_EBIAS) { \ |
91 | if(vm) {\ | 66 | if (vm) { \ |
92 | ve = SP_EMIN;\ | 67 | ve = SP_EMIN; \ |
93 | vc = IEEE754_CLASS_DNORM;\ | 68 | vc = IEEE754_CLASS_DNORM; \ |
94 | } else\ | 69 | } else \ |
95 | vc = IEEE754_CLASS_ZERO;\ | 70 | vc = IEEE754_CLASS_ZERO; \ |
96 | } else {\ | 71 | } else { \ |
97 | ve -= SP_EBIAS;\ | 72 | ve -= SP_EBIAS; \ |
98 | vm |= SP_HIDDEN_BIT;\ | 73 | vm |= SP_HIDDEN_BIT; \ |
99 | vc = IEEE754_CLASS_NORM;\ | 74 | vc = IEEE754_CLASS_NORM; \ |
100 | }\ | 75 | } \ |
101 | } | 76 | } |
102 | #define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm) | 77 | #define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm) |
103 | #define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym) | 78 | #define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym) |
104 | 79 | ||
105 | 80 | ||
106 | #define COMPXDP \ | 81 | #define COMPXDP \ |
107 | u64 xm; int xe; int xs __maybe_unused; int xc | 82 | u64 xm; int xe; int xs __maybe_unused; int xc |
108 | 83 | ||
109 | #define COMPYDP \ | 84 | #define COMPYDP \ |
110 | u64 ym; int ye; int ys; int yc | 85 | u64 ym; int ye; int ys; int yc |
111 | 86 | ||
112 | #define EXPLODEDP(v, vc, vs, ve, vm) \ | 87 | #define EXPLODEDP(v, vc, vs, ve, vm) \ |
113 | {\ | 88 | { \ |
114 | vm = DPMANT(v);\ | 89 | vm = DPMANT(v); \ |
115 | vs = DPSIGN(v);\ | 90 | vs = DPSIGN(v); \ |
116 | ve = DPBEXP(v);\ | 91 | ve = DPBEXP(v); \ |
117 | if(ve == DP_EMAX+1+DP_EBIAS){\ | 92 | if (ve == DP_EMAX+1+DP_EBIAS) { \ |
118 | if(vm == 0)\ | 93 | if (vm == 0) \ |
119 | vc = IEEE754_CLASS_INF;\ | 94 | vc = IEEE754_CLASS_INF; \ |
120 | else if(vm & DP_MBIT(DP_MBITS-1)) \ | 95 | else if (vm & DP_MBIT(DP_FBITS-1)) \ |
121 | vc = IEEE754_CLASS_SNAN;\ | 96 | vc = IEEE754_CLASS_SNAN; \ |
122 | else \ | 97 | else \ |
123 | vc = IEEE754_CLASS_QNAN;\ | 98 | vc = IEEE754_CLASS_QNAN; \ |
124 | } else if(ve == DP_EMIN-1+DP_EBIAS) {\ | 99 | } else if (ve == DP_EMIN-1+DP_EBIAS) { \ |
125 | if(vm) {\ | 100 | if (vm) { \ |
126 | ve = DP_EMIN;\ | 101 | ve = DP_EMIN; \ |
127 | vc = IEEE754_CLASS_DNORM;\ | 102 | vc = IEEE754_CLASS_DNORM; \ |
128 | } else\ | 103 | } else \ |
129 | vc = IEEE754_CLASS_ZERO;\ | 104 | vc = IEEE754_CLASS_ZERO; \ |
130 | } else {\ | 105 | } else { \ |
131 | ve -= DP_EBIAS;\ | 106 | ve -= DP_EBIAS; \ |
132 | vm |= DP_HIDDEN_BIT;\ | 107 | vm |= DP_HIDDEN_BIT; \ |
133 | vc = IEEE754_CLASS_NORM;\ | 108 | vc = IEEE754_CLASS_NORM; \ |
134 | }\ | 109 | } \ |
135 | } | 110 | } |
136 | #define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm) | 111 | #define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm) |
137 | #define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym) | 112 | #define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym) |
138 | 113 | ||
139 | #define FLUSHDP(v, vc, vs, ve, vm) \ | 114 | #define FLUSHDP(v, vc, vs, ve, vm) \ |
140 | if(vc==IEEE754_CLASS_DNORM) {\ | 115 | if (vc==IEEE754_CLASS_DNORM) { \ |
141 | if(ieee754_csr.nod) {\ | 116 | if (ieee754_csr.nod) { \ |
142 | SETCX(IEEE754_INEXACT);\ | 117 | ieee754_setcx(IEEE754_INEXACT); \ |
143 | vc = IEEE754_CLASS_ZERO;\ | 118 | vc = IEEE754_CLASS_ZERO; \ |
144 | ve = DP_EMIN-1+DP_EBIAS;\ | 119 | ve = DP_EMIN-1+DP_EBIAS; \ |
145 | vm = 0;\ | 120 | vm = 0; \ |
146 | v = ieee754dp_zero(vs);\ | 121 | v = ieee754dp_zero(vs); \ |
147 | }\ | 122 | } \ |
148 | } | 123 | } |
149 | 124 | ||
150 | #define FLUSHSP(v, vc, vs, ve, vm) \ | 125 | #define FLUSHSP(v, vc, vs, ve, vm) \ |
151 | if(vc==IEEE754_CLASS_DNORM) {\ | 126 | if (vc==IEEE754_CLASS_DNORM) { \ |
152 | if(ieee754_csr.nod) {\ | 127 | if (ieee754_csr.nod) { \ |
153 | SETCX(IEEE754_INEXACT);\ | 128 | ieee754_setcx(IEEE754_INEXACT); \ |
154 | vc = IEEE754_CLASS_ZERO;\ | 129 | vc = IEEE754_CLASS_ZERO; \ |
155 | ve = SP_EMIN-1+SP_EBIAS;\ | 130 | ve = SP_EMIN-1+SP_EBIAS; \ |
156 | vm = 0;\ | 131 | vm = 0; \ |
157 | v = ieee754sp_zero(vs);\ | 132 | v = ieee754sp_zero(vs); \ |
158 | }\ | 133 | } \ |
159 | } | 134 | } |
160 | 135 | ||
161 | #define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm) | 136 | #define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm) |
162 | #define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym) | 137 | #define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym) |
163 | #define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm) | 138 | #define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm) |
164 | #define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym) | 139 | #define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym) |
140 | |||
141 | #endif /* __IEEE754INT_H */ | ||
diff --git a/arch/mips/math-emu/ieee754m.c b/arch/mips/math-emu/ieee754m.c deleted file mode 100644 index 24190f3c9dd6..000000000000 --- a/arch/mips/math-emu/ieee754m.c +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | /* | ||
2 | * floor, trunc, ceil | ||
3 | */ | ||
4 | /* | ||
5 | * MIPS floating point support | ||
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
7 | * | ||
8 | * ######################################################################## | ||
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 (Version 2) as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
17 | * for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include "ieee754.h" | ||
28 | |||
29 | ieee754dp ieee754dp_floor(ieee754dp x) | ||
30 | { | ||
31 | ieee754dp i; | ||
32 | |||
33 | if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) | ||
34 | return ieee754dp_sub(i, ieee754dp_one(0)); | ||
35 | else | ||
36 | return i; | ||
37 | } | ||
38 | |||
39 | ieee754dp ieee754dp_ceil(ieee754dp x) | ||
40 | { | ||
41 | ieee754dp i; | ||
42 | |||
43 | if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) | ||
44 | return ieee754dp_add(i, ieee754dp_one(0)); | ||
45 | else | ||
46 | return i; | ||
47 | } | ||
48 | |||
49 | ieee754dp ieee754dp_trunc(ieee754dp x) | ||
50 | { | ||
51 | ieee754dp i; | ||
52 | |||
53 | (void) ieee754dp_modf(x, &i); | ||
54 | return i; | ||
55 | } | ||
diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index 15d1e36cfe64..d348efe91445 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,105 +16,68 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
22 | #include <linux/compiler.h> | ||
26 | 23 | ||
27 | #include "ieee754sp.h" | 24 | #include "ieee754sp.h" |
28 | 25 | ||
29 | int ieee754sp_class(ieee754sp x) | 26 | int ieee754sp_class(union ieee754sp x) |
30 | { | 27 | { |
31 | COMPXSP; | 28 | COMPXSP; |
32 | EXPLODEXSP; | 29 | EXPLODEXSP; |
33 | return xc; | 30 | return xc; |
34 | } | 31 | } |
35 | 32 | ||
36 | int ieee754sp_isnan(ieee754sp x) | 33 | int ieee754sp_isnan(union ieee754sp x) |
37 | { | 34 | { |
38 | return ieee754sp_class(x) >= IEEE754_CLASS_SNAN; | 35 | return ieee754sp_class(x) >= IEEE754_CLASS_SNAN; |
39 | } | 36 | } |
40 | 37 | ||
41 | int ieee754sp_issnan(ieee754sp x) | 38 | static inline int ieee754sp_issnan(union ieee754sp x) |
42 | { | 39 | { |
43 | assert(ieee754sp_isnan(x)); | 40 | assert(ieee754sp_isnan(x)); |
44 | return (SPMANT(x) & SP_MBIT(SP_MBITS-1)); | 41 | return (SPMANT(x) & SP_MBIT(SP_FBITS-1)); |
45 | } | 42 | } |
46 | 43 | ||
47 | 44 | ||
48 | ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...) | 45 | union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r) |
49 | { | ||
50 | struct ieee754xctx ax; | ||
51 | |||
52 | if (!TSTX()) | ||
53 | return r; | ||
54 | |||
55 | ax.op = op; | ||
56 | ax.rt = IEEE754_RT_SP; | ||
57 | ax.rv.sp = r; | ||
58 | va_start(ax.ap, op); | ||
59 | ieee754_xcpt(&ax); | ||
60 | va_end(ax.ap); | ||
61 | return ax.rv.sp; | ||
62 | } | ||
63 | |||
64 | ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...) | ||
65 | { | 46 | { |
66 | struct ieee754xctx ax; | ||
67 | |||
68 | assert(ieee754sp_isnan(r)); | 47 | assert(ieee754sp_isnan(r)); |
69 | 48 | ||
70 | if (!ieee754sp_issnan(r)) /* QNAN does not cause invalid op !! */ | 49 | if (!ieee754sp_issnan(r)) /* QNAN does not cause invalid op !! */ |
71 | return r; | 50 | return r; |
72 | 51 | ||
73 | if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) { | 52 | if (!ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) { |
74 | /* not enabled convert to a quiet NaN */ | 53 | /* not enabled convert to a quiet NaN */ |
75 | SPMANT(r) &= (~SP_MBIT(SP_MBITS-1)); | 54 | SPMANT(r) &= (~SP_MBIT(SP_FBITS-1)); |
76 | if (ieee754sp_isnan(r)) | 55 | if (ieee754sp_isnan(r)) |
77 | return r; | 56 | return r; |
78 | else | 57 | else |
79 | return ieee754sp_indef(); | 58 | return ieee754sp_indef(); |
80 | } | 59 | } |
81 | 60 | ||
82 | ax.op = op; | 61 | return r; |
83 | ax.rt = 0; | ||
84 | ax.rv.sp = r; | ||
85 | va_start(ax.ap, op); | ||
86 | ieee754_xcpt(&ax); | ||
87 | va_end(ax.ap); | ||
88 | return ax.rv.sp; | ||
89 | } | ||
90 | |||
91 | ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y) | ||
92 | { | ||
93 | assert(ieee754sp_isnan(x)); | ||
94 | assert(ieee754sp_isnan(y)); | ||
95 | |||
96 | if (SPMANT(x) > SPMANT(y)) | ||
97 | return x; | ||
98 | else | ||
99 | return y; | ||
100 | } | 62 | } |
101 | 63 | ||
102 | 64 | static unsigned ieee754sp_get_rounding(int sn, unsigned xm) | |
103 | static unsigned get_rounding(int sn, unsigned xm) | ||
104 | { | 65 | { |
105 | /* inexact must round of 3 bits | 66 | /* inexact must round of 3 bits |
106 | */ | 67 | */ |
107 | if (xm & (SP_MBIT(3) - 1)) { | 68 | if (xm & (SP_MBIT(3) - 1)) { |
108 | switch (ieee754_csr.rm) { | 69 | switch (ieee754_csr.rm) { |
109 | case IEEE754_RZ: | 70 | case FPU_CSR_RZ: |
110 | break; | 71 | break; |
111 | case IEEE754_RN: | 72 | case FPU_CSR_RN: |
112 | xm += 0x3 + ((xm >> 3) & 1); | 73 | xm += 0x3 + ((xm >> 3) & 1); |
113 | /* xm += (xm&0x8)?0x4:0x3 */ | 74 | /* xm += (xm&0x8)?0x4:0x3 */ |
114 | break; | 75 | break; |
115 | case IEEE754_RU: /* toward +Infinity */ | 76 | case FPU_CSR_RU: /* toward +Infinity */ |
116 | if (!sn) /* ?? */ | 77 | if (!sn) /* ?? */ |
117 | xm += 0x8; | 78 | xm += 0x8; |
118 | break; | 79 | break; |
119 | case IEEE754_RD: /* toward -Infinity */ | 80 | case FPU_CSR_RD: /* toward -Infinity */ |
120 | if (sn) /* ?? */ | 81 | if (sn) /* ?? */ |
121 | xm += 0x8; | 82 | xm += 0x8; |
122 | break; | 83 | break; |
@@ -131,11 +92,11 @@ static unsigned get_rounding(int sn, unsigned xm) | |||
131 | * xe is an unbiased exponent | 92 | * xe is an unbiased exponent |
132 | * xm is 3bit extended precision value. | 93 | * xm is 3bit extended precision value. |
133 | */ | 94 | */ |
134 | ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) | 95 | union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) |
135 | { | 96 | { |
136 | assert(xm); /* we don't gen exact zeros (probably should) */ | 97 | assert(xm); /* we don't gen exact zeros (probably should) */ |
137 | 98 | ||
138 | assert((xm >> (SP_MBITS + 1 + 3)) == 0); /* no execess */ | 99 | assert((xm >> (SP_FBITS + 1 + 3)) == 0); /* no execess */ |
139 | assert(xm & (SP_HIDDEN_BIT << 3)); | 100 | assert(xm & (SP_HIDDEN_BIT << 3)); |
140 | 101 | ||
141 | if (xe < SP_EMIN) { | 102 | if (xe < SP_EMIN) { |
@@ -143,38 +104,37 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) | |||
143 | int es = SP_EMIN - xe; | 104 | int es = SP_EMIN - xe; |
144 | 105 | ||
145 | if (ieee754_csr.nod) { | 106 | if (ieee754_csr.nod) { |
146 | SETCX(IEEE754_UNDERFLOW); | 107 | ieee754_setcx(IEEE754_UNDERFLOW); |
147 | SETCX(IEEE754_INEXACT); | 108 | ieee754_setcx(IEEE754_INEXACT); |
148 | 109 | ||
149 | switch(ieee754_csr.rm) { | 110 | switch(ieee754_csr.rm) { |
150 | case IEEE754_RN: | 111 | case FPU_CSR_RN: |
151 | case IEEE754_RZ: | 112 | case FPU_CSR_RZ: |
152 | return ieee754sp_zero(sn); | 113 | return ieee754sp_zero(sn); |
153 | case IEEE754_RU: /* toward +Infinity */ | 114 | case FPU_CSR_RU: /* toward +Infinity */ |
154 | if(sn == 0) | 115 | if (sn == 0) |
155 | return ieee754sp_min(0); | 116 | return ieee754sp_min(0); |
156 | else | 117 | else |
157 | return ieee754sp_zero(1); | 118 | return ieee754sp_zero(1); |
158 | case IEEE754_RD: /* toward -Infinity */ | 119 | case FPU_CSR_RD: /* toward -Infinity */ |
159 | if(sn == 0) | 120 | if (sn == 0) |
160 | return ieee754sp_zero(0); | 121 | return ieee754sp_zero(0); |
161 | else | 122 | else |
162 | return ieee754sp_min(1); | 123 | return ieee754sp_min(1); |
163 | } | 124 | } |
164 | } | 125 | } |
165 | 126 | ||
166 | if (xe == SP_EMIN - 1 | 127 | if (xe == SP_EMIN - 1 && |
167 | && get_rounding(sn, xm) >> (SP_MBITS + 1 + 3)) | 128 | ieee754sp_get_rounding(sn, xm) >> (SP_FBITS + 1 + 3)) |
168 | { | 129 | { |
169 | /* Not tiny after rounding */ | 130 | /* Not tiny after rounding */ |
170 | SETCX(IEEE754_INEXACT); | 131 | ieee754_setcx(IEEE754_INEXACT); |
171 | xm = get_rounding(sn, xm); | 132 | xm = ieee754sp_get_rounding(sn, xm); |
172 | xm >>= 1; | 133 | xm >>= 1; |
173 | /* Clear grs bits */ | 134 | /* Clear grs bits */ |
174 | xm &= ~(SP_MBIT(3) - 1); | 135 | xm &= ~(SP_MBIT(3) - 1); |
175 | xe++; | 136 | xe++; |
176 | } | 137 | } else { |
177 | else { | ||
178 | /* sticky right shift es bits | 138 | /* sticky right shift es bits |
179 | */ | 139 | */ |
180 | SPXSRSXn(es); | 140 | SPXSRSXn(es); |
@@ -183,17 +143,17 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) | |||
183 | } | 143 | } |
184 | } | 144 | } |
185 | if (xm & (SP_MBIT(3) - 1)) { | 145 | if (xm & (SP_MBIT(3) - 1)) { |
186 | SETCX(IEEE754_INEXACT); | 146 | ieee754_setcx(IEEE754_INEXACT); |
187 | if ((xm & (SP_HIDDEN_BIT << 3)) == 0) { | 147 | if ((xm & (SP_HIDDEN_BIT << 3)) == 0) { |
188 | SETCX(IEEE754_UNDERFLOW); | 148 | ieee754_setcx(IEEE754_UNDERFLOW); |
189 | } | 149 | } |
190 | 150 | ||
191 | /* inexact must round of 3 bits | 151 | /* inexact must round of 3 bits |
192 | */ | 152 | */ |
193 | xm = get_rounding(sn, xm); | 153 | xm = ieee754sp_get_rounding(sn, xm); |
194 | /* adjust exponent for rounding add overflowing | 154 | /* adjust exponent for rounding add overflowing |
195 | */ | 155 | */ |
196 | if (xm >> (SP_MBITS + 1 + 3)) { | 156 | if (xm >> (SP_FBITS + 1 + 3)) { |
197 | /* add causes mantissa overflow */ | 157 | /* add causes mantissa overflow */ |
198 | xm >>= 1; | 158 | xm >>= 1; |
199 | xe++; | 159 | xe++; |
@@ -202,24 +162,24 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) | |||
202 | /* strip grs bits */ | 162 | /* strip grs bits */ |
203 | xm >>= 3; | 163 | xm >>= 3; |
204 | 164 | ||
205 | assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ | 165 | assert((xm >> (SP_FBITS + 1)) == 0); /* no execess */ |
206 | assert(xe >= SP_EMIN); | 166 | assert(xe >= SP_EMIN); |
207 | 167 | ||
208 | if (xe > SP_EMAX) { | 168 | if (xe > SP_EMAX) { |
209 | SETCX(IEEE754_OVERFLOW); | 169 | ieee754_setcx(IEEE754_OVERFLOW); |
210 | SETCX(IEEE754_INEXACT); | 170 | ieee754_setcx(IEEE754_INEXACT); |
211 | /* -O can be table indexed by (rm,sn) */ | 171 | /* -O can be table indexed by (rm,sn) */ |
212 | switch (ieee754_csr.rm) { | 172 | switch (ieee754_csr.rm) { |
213 | case IEEE754_RN: | 173 | case FPU_CSR_RN: |
214 | return ieee754sp_inf(sn); | 174 | return ieee754sp_inf(sn); |
215 | case IEEE754_RZ: | 175 | case FPU_CSR_RZ: |
216 | return ieee754sp_max(sn); | 176 | return ieee754sp_max(sn); |
217 | case IEEE754_RU: /* toward +Infinity */ | 177 | case FPU_CSR_RU: /* toward +Infinity */ |
218 | if (sn == 0) | 178 | if (sn == 0) |
219 | return ieee754sp_inf(0); | 179 | return ieee754sp_inf(0); |
220 | else | 180 | else |
221 | return ieee754sp_max(1); | 181 | return ieee754sp_max(1); |
222 | case IEEE754_RD: /* toward -Infinity */ | 182 | case FPU_CSR_RD: /* toward -Infinity */ |
223 | if (sn == 0) | 183 | if (sn == 0) |
224 | return ieee754sp_max(0); | 184 | return ieee754sp_max(0); |
225 | else | 185 | else |
@@ -232,10 +192,10 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) | |||
232 | /* we underflow (tiny/zero) */ | 192 | /* we underflow (tiny/zero) */ |
233 | assert(xe == SP_EMIN); | 193 | assert(xe == SP_EMIN); |
234 | if (ieee754_csr.mx & IEEE754_UNDERFLOW) | 194 | if (ieee754_csr.mx & IEEE754_UNDERFLOW) |
235 | SETCX(IEEE754_UNDERFLOW); | 195 | ieee754_setcx(IEEE754_UNDERFLOW); |
236 | return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); | 196 | return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); |
237 | } else { | 197 | } else { |
238 | assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ | 198 | assert((xm >> (SP_FBITS + 1)) == 0); /* no execess */ |
239 | assert(xm & SP_HIDDEN_BIT); | 199 | assert(xm & SP_HIDDEN_BIT); |
240 | 200 | ||
241 | return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); | 201 | return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); |
diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 754fd54649b5..ad268e332318 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h | |||
@@ -6,8 +6,6 @@ | |||
6 | * MIPS floating point support | 6 | * MIPS floating point support |
7 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 7 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
8 | * | 8 | * |
9 | * ######################################################################## | ||
10 | * | ||
11 | * This program is free software; you can distribute it and/or modify it | 9 | * This program is free software; you can distribute it and/or modify it |
12 | * under the terms of the GNU General Public License (Version 2) as | 10 | * under the terms of the GNU General Public License (Version 2) as |
13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -19,70 +17,71 @@ | |||
19 | * | 17 | * |
20 | * You should have received a copy of the GNU General Public License along | 18 | * You should have received a copy of the GNU General Public License along |
21 | * with this program; if not, write to the Free Software Foundation, Inc., | 19 | * with this program; if not, write to the Free Software Foundation, Inc., |
22 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 20 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
23 | * | ||
24 | * ######################################################################## | ||
25 | */ | 21 | */ |
26 | 22 | ||
23 | #include <linux/compiler.h> | ||
27 | 24 | ||
28 | #include "ieee754int.h" | 25 | #include "ieee754int.h" |
29 | 26 | ||
30 | #define assert(expr) ((void)0) | 27 | #define assert(expr) ((void)0) |
31 | 28 | ||
29 | #define SP_EBIAS 127 | ||
30 | #define SP_EMIN (-126) | ||
31 | #define SP_EMAX 127 | ||
32 | #define SP_FBITS 23 | ||
33 | #define SP_MBITS 23 | ||
34 | |||
35 | #define SP_MBIT(x) ((u32)1 << (x)) | ||
36 | #define SP_HIDDEN_BIT SP_MBIT(SP_FBITS) | ||
37 | #define SP_SIGN_BIT SP_MBIT(31) | ||
38 | |||
39 | #define SPSIGN(sp) (sp.sign) | ||
40 | #define SPBEXP(sp) (sp.bexp) | ||
41 | #define SPMANT(sp) (sp.mant) | ||
42 | |||
43 | static inline int ieee754sp_finite(union ieee754sp x) | ||
44 | { | ||
45 | return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; | ||
46 | } | ||
47 | |||
32 | /* 3bit extended single precision sticky right shift */ | 48 | /* 3bit extended single precision sticky right shift */ |
33 | #define SPXSRSXn(rs) \ | 49 | #define SPXSRSXn(rs) \ |
34 | (xe += rs, \ | 50 | (xe += rs, \ |
35 | xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) | 51 | xm = (rs > (SP_FBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) |
36 | 52 | ||
37 | #define SPXSRSX1() \ | 53 | #define SPXSRSX1() \ |
38 | (xe++, (xm = (xm >> 1) | (xm & 1))) | 54 | (xe++, (xm = (xm >> 1) | (xm & 1))) |
39 | 55 | ||
40 | #define SPXSRSYn(rs) \ | 56 | #define SPXSRSYn(rs) \ |
41 | (ye+=rs, \ | 57 | (ye+=rs, \ |
42 | ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) | 58 | ym = (rs > (SP_FBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) |
43 | 59 | ||
44 | #define SPXSRSY1() \ | 60 | #define SPXSRSY1() \ |
45 | (ye++, (ym = (ym >> 1) | (ym & 1))) | 61 | (ye++, (ym = (ym >> 1) | (ym & 1))) |
46 | 62 | ||
47 | /* convert denormal to normalized with extended exponent */ | 63 | /* convert denormal to normalized with extended exponent */ |
48 | #define SPDNORMx(m,e) \ | 64 | #define SPDNORMx(m,e) \ |
49 | while( (m >> SP_MBITS) == 0) { m <<= 1; e--; } | 65 | while ((m >> SP_FBITS) == 0) { m <<= 1; e--; } |
50 | #define SPDNORMX SPDNORMx(xm, xe) | 66 | #define SPDNORMX SPDNORMx(xm, xe) |
51 | #define SPDNORMY SPDNORMx(ym, ye) | 67 | #define SPDNORMY SPDNORMx(ym, ye) |
52 | 68 | ||
53 | static inline ieee754sp buildsp(int s, int bx, unsigned m) | 69 | static inline union ieee754sp buildsp(int s, int bx, unsigned m) |
54 | { | 70 | { |
55 | ieee754sp r; | 71 | union ieee754sp r; |
56 | 72 | ||
57 | assert((s) == 0 || (s) == 1); | 73 | assert((s) == 0 || (s) == 1); |
58 | assert((bx) >= SP_EMIN - 1 + SP_EBIAS | 74 | assert((bx) >= SP_EMIN - 1 + SP_EBIAS |
59 | && (bx) <= SP_EMAX + 1 + SP_EBIAS); | 75 | && (bx) <= SP_EMAX + 1 + SP_EBIAS); |
60 | assert(((m) >> SP_MBITS) == 0); | 76 | assert(((m) >> SP_FBITS) == 0); |
61 | 77 | ||
62 | r.parts.sign = s; | 78 | r.sign = s; |
63 | r.parts.bexp = bx; | 79 | r.bexp = bx; |
64 | r.parts.mant = m; | 80 | r.mant = m; |
65 | 81 | ||
66 | return r; | 82 | return r; |
67 | } | 83 | } |
68 | 84 | ||
69 | extern int ieee754sp_isnan(ieee754sp); | 85 | extern int ieee754sp_isnan(union ieee754sp); |
70 | extern int ieee754sp_issnan(ieee754sp); | 86 | extern union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp); |
71 | extern int ieee754si_xcpt(int, const char *, ...); | 87 | extern union ieee754sp ieee754sp_format(int, int, unsigned); |
72 | extern s64 ieee754di_xcpt(s64, const char *, ...); | ||
73 | extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...); | ||
74 | extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...); | ||
75 | extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp); | ||
76 | extern ieee754sp ieee754sp_format(int, int, unsigned); | ||
77 | |||
78 | |||
79 | #define SPNORMRET2(s, e, m, name, a0, a1) \ | ||
80 | { \ | ||
81 | ieee754sp V = ieee754sp_format(s, e, m); \ | ||
82 | if(TSTX()) \ | ||
83 | return ieee754sp_xcpt(V, name, a0, a1); \ | ||
84 | else \ | ||
85 | return V; \ | ||
86 | } | ||
87 | |||
88 | #define SPNORMRET1(s, e, m, name, a0) SPNORMRET2(s, e, m, name, a0, a0) | ||
diff --git a/arch/mips/math-emu/ieee754xcpt.c b/arch/mips/math-emu/ieee754xcpt.c deleted file mode 100644 index 967167116ae8..000000000000 --- a/arch/mips/math-emu/ieee754xcpt.c +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | /* | ||
2 | * MIPS floating point support | ||
3 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
4 | * | ||
5 | * ######################################################################## | ||
6 | * | ||
7 | * This program is free software; you can distribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License (Version 2) as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
14 | * for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
19 | * | ||
20 | * ######################################################################## | ||
21 | */ | ||
22 | |||
23 | /************************************************************************** | ||
24 | * Nov 7, 2000 | ||
25 | * Added preprocessor hacks to map to Linux kernel diagnostics. | ||
26 | * | ||
27 | * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com | ||
28 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. | ||
29 | *************************************************************************/ | ||
30 | |||
31 | #include <linux/kernel.h> | ||
32 | #include "ieee754.h" | ||
33 | |||
34 | /* | ||
35 | * Very naff exception handler (you can plug in your own and | ||
36 | * override this). | ||
37 | */ | ||
38 | |||
39 | static const char *const rtnames[] = { | ||
40 | "sp", "dp", "xp", "si", "di" | ||
41 | }; | ||
42 | |||
43 | void ieee754_xcpt(struct ieee754xctx *xcp) | ||
44 | { | ||
45 | printk(KERN_DEBUG "floating point exception in \"%s\", type=%s\n", | ||
46 | xcp->op, rtnames[xcp->rt]); | ||
47 | } | ||
diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c deleted file mode 100644 index eb58a85b3157..000000000000 --- a/arch/mips/math-emu/kernel_linkage.c +++ /dev/null | |||
@@ -1,45 +0,0 @@ | |||
1 | /* | ||
2 | * Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com | ||
3 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can distribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License (Version 2) as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
12 | * for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
17 | * | ||
18 | * Routines corresponding to Linux kernel FP context | ||
19 | * manipulation primitives for the Algorithmics MIPS | ||
20 | * FPU Emulator | ||
21 | */ | ||
22 | #include <linux/sched.h> | ||
23 | #include <asm/processor.h> | ||
24 | #include <asm/signal.h> | ||
25 | #include <asm/uaccess.h> | ||
26 | |||
27 | #include <asm/fpu.h> | ||
28 | #include <asm/fpu_emulator.h> | ||
29 | |||
30 | #define SIGNALLING_NAN 0x7ff800007ff80000LL | ||
31 | |||
32 | void fpu_emulator_init_fpu(void) | ||
33 | { | ||
34 | static int first = 1; | ||
35 | int i; | ||
36 | |||
37 | if (first) { | ||
38 | first = 0; | ||
39 | printk("Algorithmics/MIPS FPU Emulator v1.5\n"); | ||
40 | } | ||
41 | |||
42 | current->thread.fpu.fcr31 = 0; | ||
43 | for (i = 0; i < 32; i++) | ||
44 | set_fpr64(¤t->thread.fpu.fpr[i], 0, SIGNALLING_NAN); | ||
45 | } | ||
diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c new file mode 100644 index 000000000000..becdd63e14a9 --- /dev/null +++ b/arch/mips/math-emu/me-debugfs.c | |||
@@ -0,0 +1,67 @@ | |||
1 | #include <linux/cpumask.h> | ||
2 | #include <linux/debugfs.h> | ||
3 | #include <linux/fs.h> | ||
4 | #include <linux/init.h> | ||
5 | #include <linux/percpu.h> | ||
6 | #include <linux/types.h> | ||
7 | #include <asm/fpu_emulator.h> | ||
8 | #include <asm/local.h> | ||
9 | |||
10 | DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); | ||
11 | |||
12 | static int fpuemu_stat_get(void *data, u64 *val) | ||
13 | { | ||
14 | int cpu; | ||
15 | unsigned long sum = 0; | ||
16 | |||
17 | for_each_online_cpu(cpu) { | ||
18 | struct mips_fpu_emulator_stats *ps; | ||
19 | local_t *pv; | ||
20 | |||
21 | ps = &per_cpu(fpuemustats, cpu); | ||
22 | pv = (void *)ps + (unsigned long)data; | ||
23 | sum += local_read(pv); | ||
24 | } | ||
25 | *val = sum; | ||
26 | return 0; | ||
27 | } | ||
28 | DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n"); | ||
29 | |||
30 | extern struct dentry *mips_debugfs_dir; | ||
31 | static int __init debugfs_fpuemu(void) | ||
32 | { | ||
33 | struct dentry *d, *dir; | ||
34 | |||
35 | if (!mips_debugfs_dir) | ||
36 | return -ENODEV; | ||
37 | dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir); | ||
38 | if (!dir) | ||
39 | return -ENOMEM; | ||
40 | |||
41 | #define FPU_EMU_STAT_OFFSET(m) \ | ||
42 | offsetof(struct mips_fpu_emulator_stats, m) | ||
43 | |||
44 | #define FPU_STAT_CREATE(m) \ | ||
45 | do { \ | ||
46 | d = debugfs_create_file(#m , S_IRUGO, dir, \ | ||
47 | (void *)FPU_EMU_STAT_OFFSET(m), \ | ||
48 | &fops_fpuemu_stat); \ | ||
49 | if (!d) \ | ||
50 | return -ENOMEM; \ | ||
51 | } while (0) | ||
52 | |||
53 | FPU_STAT_CREATE(emulated); | ||
54 | FPU_STAT_CREATE(loads); | ||
55 | FPU_STAT_CREATE(stores); | ||
56 | FPU_STAT_CREATE(cp1ops); | ||
57 | FPU_STAT_CREATE(cp1xops); | ||
58 | FPU_STAT_CREATE(errors); | ||
59 | FPU_STAT_CREATE(ieee754_inexact); | ||
60 | FPU_STAT_CREATE(ieee754_underflow); | ||
61 | FPU_STAT_CREATE(ieee754_overflow); | ||
62 | FPU_STAT_CREATE(ieee754_zerodiv); | ||
63 | FPU_STAT_CREATE(ieee754_invalidop); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | __initcall(debugfs_fpuemu); | ||
diff --git a/arch/mips/math-emu/sp_add.c b/arch/mips/math-emu/sp_add.c index c446e64637e2..2d84d460cb67 100644 --- a/arch/mips/math-emu/sp_add.c +++ b/arch/mips/math-emu/sp_add.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,23 +16,22 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
28 | 23 | ||
29 | ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) | 24 | union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y) |
30 | { | 25 | { |
26 | int s; | ||
27 | |||
31 | COMPXSP; | 28 | COMPXSP; |
32 | COMPYSP; | 29 | COMPYSP; |
33 | 30 | ||
34 | EXPLODEXSP; | 31 | EXPLODEXSP; |
35 | EXPLODEYSP; | 32 | EXPLODEYSP; |
36 | 33 | ||
37 | CLEARCX; | 34 | ieee754_clearcx(); |
38 | 35 | ||
39 | FLUSHXSP; | 36 | FLUSHXSP; |
40 | FLUSHYSP; | 37 | FLUSHYSP; |
@@ -51,8 +48,8 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) | |||
51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | 48 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | 49 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
53 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
54 | SETCX(IEEE754_INVALID_OPERATION); | 51 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
55 | return ieee754sp_nanxcpt(ieee754sp_indef(), "add", x, y); | 52 | return ieee754sp_nanxcpt(ieee754sp_indef()); |
56 | 53 | ||
57 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | 54 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
58 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | 55 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
@@ -68,14 +65,14 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) | |||
68 | return x; | 65 | return x; |
69 | 66 | ||
70 | 67 | ||
71 | /* Infinity handling | 68 | /* |
72 | */ | 69 | * Infinity handling |
73 | 70 | */ | |
74 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | 71 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
75 | if (xs == ys) | 72 | if (xs == ys) |
76 | return x; | 73 | return x; |
77 | SETCX(IEEE754_INVALID_OPERATION); | 74 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
78 | return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y); | 75 | return ieee754sp_indef(); |
79 | 76 | ||
80 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | 77 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
81 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
@@ -87,15 +84,14 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) | |||
87 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
88 | return x; | 85 | return x; |
89 | 86 | ||
90 | /* Zero handling | 87 | /* |
91 | */ | 88 | * Zero handling |
92 | 89 | */ | |
93 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
94 | if (xs == ys) | 91 | if (xs == ys) |
95 | return x; | 92 | return x; |
96 | else | 93 | else |
97 | return ieee754sp_zero(ieee754_csr.rm == | 94 | return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); |
98 | IEEE754_RD); | ||
99 | 95 | ||
100 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | 96 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
101 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | 97 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
@@ -108,6 +104,8 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) | |||
108 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | 104 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): |
109 | SPDNORMX; | 105 | SPDNORMX; |
110 | 106 | ||
107 | /* FALL THROUGH */ | ||
108 | |||
111 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): | 109 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): |
112 | SPDNORMY; | 110 | SPDNORMY; |
113 | break; | 111 | break; |
@@ -122,33 +120,38 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) | |||
122 | assert(xm & SP_HIDDEN_BIT); | 120 | assert(xm & SP_HIDDEN_BIT); |
123 | assert(ym & SP_HIDDEN_BIT); | 121 | assert(ym & SP_HIDDEN_BIT); |
124 | 122 | ||
125 | /* provide guard,round and stick bit space */ | 123 | /* |
124 | * Provide guard, round and stick bit space. | ||
125 | */ | ||
126 | xm <<= 3; | 126 | xm <<= 3; |
127 | ym <<= 3; | 127 | ym <<= 3; |
128 | 128 | ||
129 | if (xe > ye) { | 129 | if (xe > ye) { |
130 | /* have to shift y fraction right to align | 130 | /* |
131 | * Have to shift y fraction right to align. | ||
131 | */ | 132 | */ |
132 | int s = xe - ye; | 133 | s = xe - ye; |
133 | SPXSRSYn(s); | 134 | SPXSRSYn(s); |
134 | } else if (ye > xe) { | 135 | } else if (ye > xe) { |
135 | /* have to shift x fraction right to align | 136 | /* |
137 | * Have to shift x fraction right to align. | ||
136 | */ | 138 | */ |
137 | int s = ye - xe; | 139 | s = ye - xe; |
138 | SPXSRSXn(s); | 140 | SPXSRSXn(s); |
139 | } | 141 | } |
140 | assert(xe == ye); | 142 | assert(xe == ye); |
141 | assert(xe <= SP_EMAX); | 143 | assert(xe <= SP_EMAX); |
142 | 144 | ||
143 | if (xs == ys) { | 145 | if (xs == ys) { |
144 | /* generate 28 bit result of adding two 27 bit numbers | 146 | /* |
145 | * leaving result in xm,xs,xe | 147 | * Generate 28 bit result of adding two 27 bit numbers |
148 | * leaving result in xm, xs and xe. | ||
146 | */ | 149 | */ |
147 | xm = xm + ym; | 150 | xm = xm + ym; |
148 | xe = xe; | 151 | xe = xe; |
149 | xs = xs; | 152 | xs = xs; |
150 | 153 | ||
151 | if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ | 154 | if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */ |
152 | SPXSRSX1(); | 155 | SPXSRSX1(); |
153 | } | 156 | } |
154 | } else { | 157 | } else { |
@@ -162,15 +165,16 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) | |||
162 | xs = ys; | 165 | xs = ys; |
163 | } | 166 | } |
164 | if (xm == 0) | 167 | if (xm == 0) |
165 | return ieee754sp_zero(ieee754_csr.rm == | 168 | return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); |
166 | IEEE754_RD); | ||
167 | 169 | ||
168 | /* normalize in extended single precision */ | 170 | /* |
169 | while ((xm >> (SP_MBITS + 3)) == 0) { | 171 | * Normalize in extended single precision |
172 | */ | ||
173 | while ((xm >> (SP_FBITS + 3)) == 0) { | ||
170 | xm <<= 1; | 174 | xm <<= 1; |
171 | xe--; | 175 | xe--; |
172 | } | 176 | } |
173 | |||
174 | } | 177 | } |
175 | SPNORMRET2(xs, xe, xm, "add", x, y); | 178 | |
179 | return ieee754sp_format(xs, xe, xm); | ||
176 | } | 180 | } |
diff --git a/arch/mips/math-emu/sp_cmp.c b/arch/mips/math-emu/sp_cmp.c index 716cf37e2465..addbccb2f556 100644 --- a/arch/mips/math-emu/sp_cmp.c +++ b/arch/mips/math-emu/sp_cmp.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,16 +16,16 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
28 | 23 | ||
29 | int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp, int sig) | 24 | int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cmp, int sig) |
30 | { | 25 | { |
26 | int vx; | ||
27 | int vy; | ||
28 | |||
31 | COMPXSP; | 29 | COMPXSP; |
32 | COMPYSP; | 30 | COMPYSP; |
33 | 31 | ||
@@ -35,21 +33,21 @@ int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp, int sig) | |||
35 | EXPLODEYSP; | 33 | EXPLODEYSP; |
36 | FLUSHXSP; | 34 | FLUSHXSP; |
37 | FLUSHYSP; | 35 | FLUSHYSP; |
38 | CLEARCX; /* Even clear inexact flag here */ | 36 | ieee754_clearcx(); /* Even clear inexact flag here */ |
39 | 37 | ||
40 | if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) { | 38 | if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) { |
41 | if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) | 39 | if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) |
42 | SETCX(IEEE754_INVALID_OPERATION); | 40 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
43 | if (cmp & IEEE754_CUN) | 41 | if (cmp & IEEE754_CUN) |
44 | return 1; | 42 | return 1; |
45 | if (cmp & (IEEE754_CLT | IEEE754_CGT)) { | 43 | if (cmp & (IEEE754_CLT | IEEE754_CGT)) { |
46 | if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION)) | 44 | if (sig && ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) |
47 | return ieee754si_xcpt(0, "fcmpf", x); | 45 | return 0; |
48 | } | 46 | } |
49 | return 0; | 47 | return 0; |
50 | } else { | 48 | } else { |
51 | int vx = x.bits; | 49 | vx = x.bits; |
52 | int vy = y.bits; | 50 | vy = y.bits; |
53 | 51 | ||
54 | if (vx < 0) | 52 | if (vx < 0) |
55 | vx = -vx ^ SP_SIGN_BIT; | 53 | vx = -vx ^ SP_SIGN_BIT; |
diff --git a/arch/mips/math-emu/sp_div.c b/arch/mips/math-emu/sp_div.c index d7747928c954..721f317aa877 100644 --- a/arch/mips/math-emu/sp_div.c +++ b/arch/mips/math-emu/sp_div.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,23 +16,24 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
28 | 23 | ||
29 | ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) | 24 | union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y) |
30 | { | 25 | { |
26 | unsigned rm; | ||
27 | int re; | ||
28 | unsigned bm; | ||
29 | |||
31 | COMPXSP; | 30 | COMPXSP; |
32 | COMPYSP; | 31 | COMPYSP; |
33 | 32 | ||
34 | EXPLODEXSP; | 33 | EXPLODEXSP; |
35 | EXPLODEYSP; | 34 | EXPLODEYSP; |
36 | 35 | ||
37 | CLEARCX; | 36 | ieee754_clearcx(); |
38 | 37 | ||
39 | FLUSHXSP; | 38 | FLUSHXSP; |
40 | FLUSHYSP; | 39 | FLUSHYSP; |
@@ -51,8 +50,8 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) | |||
51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | 51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
53 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | 52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
54 | SETCX(IEEE754_INVALID_OPERATION); | 53 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
55 | return ieee754sp_nanxcpt(ieee754sp_indef(), "div", x, y); | 54 | return ieee754sp_nanxcpt(ieee754sp_indef()); |
56 | 55 | ||
57 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | 56 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
58 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | 57 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
@@ -68,12 +67,12 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) | |||
68 | return x; | 67 | return x; |
69 | 68 | ||
70 | 69 | ||
71 | /* Infinity handling | 70 | /* |
72 | */ | 71 | * Infinity handling |
73 | 72 | */ | |
74 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | 73 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
75 | SETCX(IEEE754_INVALID_OPERATION); | 74 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
76 | return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); | 75 | return ieee754sp_indef(); |
77 | 76 | ||
78 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | 77 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
79 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
@@ -85,17 +84,17 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) | |||
85 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
86 | return ieee754sp_inf(xs ^ ys); | 85 | return ieee754sp_inf(xs ^ ys); |
87 | 86 | ||
88 | /* Zero handling | 87 | /* |
89 | */ | 88 | * Zero handling |
90 | 89 | */ | |
91 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
92 | SETCX(IEEE754_INVALID_OPERATION); | 91 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
93 | return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); | 92 | return ieee754sp_indef(); |
94 | 93 | ||
95 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | 94 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
96 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | 95 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
97 | SETCX(IEEE754_ZERO_DIVIDE); | 96 | ieee754_setcx(IEEE754_ZERO_DIVIDE); |
98 | return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y); | 97 | return ieee754sp_inf(xs ^ ys); |
99 | 98 | ||
100 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | 99 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): |
101 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | 100 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): |
@@ -122,35 +121,33 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) | |||
122 | xm <<= 3; | 121 | xm <<= 3; |
123 | ym <<= 3; | 122 | ym <<= 3; |
124 | 123 | ||
125 | { | 124 | /* now the dirty work */ |
126 | /* now the dirty work */ | ||
127 | |||
128 | unsigned rm = 0; | ||
129 | int re = xe - ye; | ||
130 | unsigned bm; | ||
131 | |||
132 | for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) { | ||
133 | if (xm >= ym) { | ||
134 | xm -= ym; | ||
135 | rm |= bm; | ||
136 | if (xm == 0) | ||
137 | break; | ||
138 | } | ||
139 | xm <<= 1; | ||
140 | } | ||
141 | rm <<= 1; | ||
142 | if (xm) | ||
143 | rm |= 1; /* have remainder, set sticky */ | ||
144 | 125 | ||
145 | assert(rm); | 126 | rm = 0; |
127 | re = xe - ye; | ||
146 | 128 | ||
147 | /* normalise rm to rounding precision ? | 129 | for (bm = SP_MBIT(SP_FBITS + 2); bm; bm >>= 1) { |
148 | */ | 130 | if (xm >= ym) { |
149 | while ((rm >> (SP_MBITS + 3)) == 0) { | 131 | xm -= ym; |
150 | rm <<= 1; | 132 | rm |= bm; |
151 | re--; | 133 | if (xm == 0) |
134 | break; | ||
152 | } | 135 | } |
136 | xm <<= 1; | ||
137 | } | ||
138 | |||
139 | rm <<= 1; | ||
140 | if (xm) | ||
141 | rm |= 1; /* have remainder, set sticky */ | ||
153 | 142 | ||
154 | SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); | 143 | assert(rm); |
144 | |||
145 | /* normalise rm to rounding precision ? | ||
146 | */ | ||
147 | while ((rm >> (SP_FBITS + 3)) == 0) { | ||
148 | rm <<= 1; | ||
149 | re--; | ||
155 | } | 150 | } |
151 | |||
152 | return ieee754sp_format(xs == ys ? 0 : 1, re, rm); | ||
156 | } | 153 | } |
diff --git a/arch/mips/math-emu/sp_fdp.c b/arch/mips/math-emu/sp_fdp.c index e1515aae0166..1b266fb16973 100644 --- a/arch/mips/math-emu/sp_fdp.c +++ b/arch/mips/math-emu/sp_fdp.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,59 +16,61 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
23 | #include "ieee754dp.h" | ||
28 | 24 | ||
29 | ieee754sp ieee754sp_fdp(ieee754dp x) | 25 | union ieee754sp ieee754sp_fdp(union ieee754dp x) |
30 | { | 26 | { |
27 | u32 rm; | ||
28 | |||
31 | COMPXDP; | 29 | COMPXDP; |
32 | ieee754sp nan; | 30 | union ieee754sp nan; |
33 | 31 | ||
34 | EXPLODEXDP; | 32 | EXPLODEXDP; |
35 | 33 | ||
36 | CLEARCX; | 34 | ieee754_clearcx(); |
37 | 35 | ||
38 | FLUSHXDP; | 36 | FLUSHXDP; |
39 | 37 | ||
40 | switch (xc) { | 38 | switch (xc) { |
41 | case IEEE754_CLASS_SNAN: | 39 | case IEEE754_CLASS_SNAN: |
42 | SETCX(IEEE754_INVALID_OPERATION); | 40 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
43 | return ieee754sp_nanxcpt(ieee754sp_indef(), "fdp"); | 41 | return ieee754sp_nanxcpt(ieee754sp_indef()); |
42 | |||
44 | case IEEE754_CLASS_QNAN: | 43 | case IEEE754_CLASS_QNAN: |
45 | nan = buildsp(xs, SP_EMAX + 1 + SP_EBIAS, (u32) | 44 | nan = buildsp(xs, SP_EMAX + 1 + SP_EBIAS, (u32) |
46 | (xm >> (DP_MBITS - SP_MBITS))); | 45 | (xm >> (DP_FBITS - SP_FBITS))); |
47 | if (!ieee754sp_isnan(nan)) | 46 | if (!ieee754sp_isnan(nan)) |
48 | nan = ieee754sp_indef(); | 47 | nan = ieee754sp_indef(); |
49 | return ieee754sp_nanxcpt(nan, "fdp", x); | 48 | return ieee754sp_nanxcpt(nan); |
49 | |||
50 | case IEEE754_CLASS_INF: | 50 | case IEEE754_CLASS_INF: |
51 | return ieee754sp_inf(xs); | 51 | return ieee754sp_inf(xs); |
52 | |||
52 | case IEEE754_CLASS_ZERO: | 53 | case IEEE754_CLASS_ZERO: |
53 | return ieee754sp_zero(xs); | 54 | return ieee754sp_zero(xs); |
55 | |||
54 | case IEEE754_CLASS_DNORM: | 56 | case IEEE754_CLASS_DNORM: |
55 | /* can't possibly be sp representable */ | 57 | /* can't possibly be sp representable */ |
56 | SETCX(IEEE754_UNDERFLOW); | 58 | ieee754_setcx(IEEE754_UNDERFLOW); |
57 | SETCX(IEEE754_INEXACT); | 59 | ieee754_setcx(IEEE754_INEXACT); |
58 | if ((ieee754_csr.rm == IEEE754_RU && !xs) || | 60 | if ((ieee754_csr.rm == FPU_CSR_RU && !xs) || |
59 | (ieee754_csr.rm == IEEE754_RD && xs)) | 61 | (ieee754_csr.rm == FPU_CSR_RD && xs)) |
60 | return ieee754sp_xcpt(ieee754sp_mind(xs), "fdp", x); | 62 | return ieee754sp_mind(xs); |
61 | return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x); | 63 | return ieee754sp_zero(xs); |
64 | |||
62 | case IEEE754_CLASS_NORM: | 65 | case IEEE754_CLASS_NORM: |
63 | break; | 66 | break; |
64 | } | 67 | } |
65 | 68 | ||
66 | { | 69 | /* |
67 | u32 rm; | 70 | * Convert from DP_FBITS to SP_FBITS+3 with sticky right shift. |
68 | 71 | */ | |
69 | /* convert from DP_MBITS to SP_MBITS+3 with sticky right shift | 72 | rm = (xm >> (DP_FBITS - (SP_FBITS + 3))) | |
70 | */ | 73 | ((xm << (64 - (DP_FBITS - (SP_FBITS + 3)))) != 0); |
71 | rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) | | ||
72 | ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0); | ||
73 | 74 | ||
74 | SPNORMRET1(xs, xe, rm, "fdp", x); | 75 | return ieee754sp_format(xs, xe, rm); |
75 | } | ||
76 | } | 76 | } |
diff --git a/arch/mips/math-emu/sp_fint.c b/arch/mips/math-emu/sp_fint.c index 9694d6c016cb..d5d8495b2cc4 100644 --- a/arch/mips/math-emu/sp_fint.c +++ b/arch/mips/math-emu/sp_fint.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,21 +16,18 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
28 | 23 | ||
29 | ieee754sp ieee754sp_fint(int x) | 24 | union ieee754sp ieee754sp_fint(int x) |
30 | { | 25 | { |
31 | unsigned xm; | 26 | unsigned xm; |
32 | int xe; | 27 | int xe; |
33 | int xs; | 28 | int xs; |
34 | 29 | ||
35 | CLEARCX; | 30 | ieee754_clearcx(); |
36 | 31 | ||
37 | if (x == 0) | 32 | if (x == 0) |
38 | return ieee754sp_zero(0); | 33 | return ieee754sp_zero(0); |
@@ -50,30 +45,21 @@ ieee754sp ieee754sp_fint(int x) | |||
50 | } else { | 45 | } else { |
51 | xm = x; | 46 | xm = x; |
52 | } | 47 | } |
53 | xe = SP_MBITS + 3; | 48 | xe = SP_FBITS + 3; |
54 | 49 | ||
55 | if (xm >> (SP_MBITS + 1 + 3)) { | 50 | if (xm >> (SP_FBITS + 1 + 3)) { |
56 | /* shunt out overflow bits | 51 | /* shunt out overflow bits |
57 | */ | 52 | */ |
58 | while (xm >> (SP_MBITS + 1 + 3)) { | 53 | while (xm >> (SP_FBITS + 1 + 3)) { |
59 | SPXSRSX1(); | 54 | SPXSRSX1(); |
60 | } | 55 | } |
61 | } else { | 56 | } else { |
62 | /* normalize in grs extended single precision | 57 | /* normalize in grs extended single precision |
63 | */ | 58 | */ |
64 | while ((xm >> (SP_MBITS + 3)) == 0) { | 59 | while ((xm >> (SP_FBITS + 3)) == 0) { |
65 | xm <<= 1; | 60 | xm <<= 1; |
66 | xe--; | 61 | xe--; |
67 | } | 62 | } |
68 | } | 63 | } |
69 | SPNORMRET1(xs, xe, xm, "fint", x); | 64 | return ieee754sp_format(xs, xe, xm); |
70 | } | ||
71 | |||
72 | |||
73 | ieee754sp ieee754sp_funs(unsigned int u) | ||
74 | { | ||
75 | if ((int) u < 0) | ||
76 | return ieee754sp_add(ieee754sp_1e31(), | ||
77 | ieee754sp_fint(u & ~(1 << 31))); | ||
78 | return ieee754sp_fint(u); | ||
79 | } | 65 | } |
diff --git a/arch/mips/math-emu/sp_flong.c b/arch/mips/math-emu/sp_flong.c index 16a651f29865..012e30ce7589 100644 --- a/arch/mips/math-emu/sp_flong.c +++ b/arch/mips/math-emu/sp_flong.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,21 +16,18 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
28 | 23 | ||
29 | ieee754sp ieee754sp_flong(s64 x) | 24 | union ieee754sp ieee754sp_flong(s64 x) |
30 | { | 25 | { |
31 | u64 xm; /* <--- need 64-bit mantissa temp */ | 26 | u64 xm; /* <--- need 64-bit mantissa temp */ |
32 | int xe; | 27 | int xe; |
33 | int xs; | 28 | int xs; |
34 | 29 | ||
35 | CLEARCX; | 30 | ieee754_clearcx(); |
36 | 31 | ||
37 | if (x == 0) | 32 | if (x == 0) |
38 | return ieee754sp_zero(0); | 33 | return ieee754sp_zero(0); |
@@ -50,29 +45,20 @@ ieee754sp ieee754sp_flong(s64 x) | |||
50 | } else { | 45 | } else { |
51 | xm = x; | 46 | xm = x; |
52 | } | 47 | } |
53 | xe = SP_MBITS + 3; | 48 | xe = SP_FBITS + 3; |
54 | 49 | ||
55 | if (xm >> (SP_MBITS + 1 + 3)) { | 50 | if (xm >> (SP_FBITS + 1 + 3)) { |
56 | /* shunt out overflow bits | 51 | /* shunt out overflow bits |
57 | */ | 52 | */ |
58 | while (xm >> (SP_MBITS + 1 + 3)) { | 53 | while (xm >> (SP_FBITS + 1 + 3)) { |
59 | SPXSRSX1(); | 54 | SPXSRSX1(); |
60 | } | 55 | } |
61 | } else { | 56 | } else { |
62 | /* normalize in grs extended single precision */ | 57 | /* normalize in grs extended single precision */ |
63 | while ((xm >> (SP_MBITS + 3)) == 0) { | 58 | while ((xm >> (SP_FBITS + 3)) == 0) { |
64 | xm <<= 1; | 59 | xm <<= 1; |
65 | xe--; | 60 | xe--; |
66 | } | 61 | } |
67 | } | 62 | } |
68 | SPNORMRET1(xs, xe, xm, "sp_flong", x); | 63 | return ieee754sp_format(xs, xe, xm); |
69 | } | ||
70 | |||
71 | |||
72 | ieee754sp ieee754sp_fulong(u64 u) | ||
73 | { | ||
74 | if ((s64) u < 0) | ||
75 | return ieee754sp_add(ieee754sp_1e63(), | ||
76 | ieee754sp_flong(u & ~(1ULL << 63))); | ||
77 | return ieee754sp_flong(u); | ||
78 | } | 64 | } |
diff --git a/arch/mips/math-emu/sp_frexp.c b/arch/mips/math-emu/sp_frexp.c deleted file mode 100644 index 5bc993c30044..000000000000 --- a/arch/mips/math-emu/sp_frexp.c +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | /* IEEE754 floating point arithmetic | ||
2 | * single precision | ||
3 | */ | ||
4 | /* | ||
5 | * MIPS floating point support | ||
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
7 | * | ||
8 | * ######################################################################## | ||
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 (Version 2) as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
17 | * for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include "ieee754sp.h" | ||
28 | |||
29 | /* close to ieeep754sp_logb | ||
30 | */ | ||
31 | ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr) | ||
32 | { | ||
33 | COMPXSP; | ||
34 | CLEARCX; | ||
35 | EXPLODEXSP; | ||
36 | |||
37 | switch (xc) { | ||
38 | case IEEE754_CLASS_SNAN: | ||
39 | case IEEE754_CLASS_QNAN: | ||
40 | case IEEE754_CLASS_INF: | ||
41 | case IEEE754_CLASS_ZERO: | ||
42 | *eptr = 0; | ||
43 | return x; | ||
44 | case IEEE754_CLASS_DNORM: | ||
45 | SPDNORMX; | ||
46 | break; | ||
47 | case IEEE754_CLASS_NORM: | ||
48 | break; | ||
49 | } | ||
50 | *eptr = xe + 1; | ||
51 | return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT); | ||
52 | } | ||
diff --git a/arch/mips/math-emu/sp_logb.c b/arch/mips/math-emu/sp_logb.c deleted file mode 100644 index 9c14e0c75bd2..000000000000 --- a/arch/mips/math-emu/sp_logb.c +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | /* IEEE754 floating point arithmetic | ||
2 | * single precision | ||
3 | */ | ||
4 | /* | ||
5 | * MIPS floating point support | ||
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
7 | * | ||
8 | * ######################################################################## | ||
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 (Version 2) as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
17 | * for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include "ieee754sp.h" | ||
28 | |||
29 | ieee754sp ieee754sp_logb(ieee754sp x) | ||
30 | { | ||
31 | COMPXSP; | ||
32 | |||
33 | CLEARCX; | ||
34 | |||
35 | EXPLODEXSP; | ||
36 | |||
37 | switch (xc) { | ||
38 | case IEEE754_CLASS_SNAN: | ||
39 | return ieee754sp_nanxcpt(x, "logb", x); | ||
40 | case IEEE754_CLASS_QNAN: | ||
41 | return x; | ||
42 | case IEEE754_CLASS_INF: | ||
43 | return ieee754sp_inf(0); | ||
44 | case IEEE754_CLASS_ZERO: | ||
45 | return ieee754sp_inf(1); | ||
46 | case IEEE754_CLASS_DNORM: | ||
47 | SPDNORMX; | ||
48 | break; | ||
49 | case IEEE754_CLASS_NORM: | ||
50 | break; | ||
51 | } | ||
52 | return ieee754sp_fint(xe); | ||
53 | } | ||
diff --git a/arch/mips/math-emu/sp_modf.c b/arch/mips/math-emu/sp_modf.c deleted file mode 100644 index 25a0fbaa0556..000000000000 --- a/arch/mips/math-emu/sp_modf.c +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | /* IEEE754 floating point arithmetic | ||
2 | * single precision | ||
3 | */ | ||
4 | /* | ||
5 | * MIPS floating point support | ||
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
7 | * | ||
8 | * ######################################################################## | ||
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 (Version 2) as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
17 | * for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include "ieee754sp.h" | ||
28 | |||
29 | /* modf function is always exact for a finite number | ||
30 | */ | ||
31 | ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp *ip) | ||
32 | { | ||
33 | COMPXSP; | ||
34 | |||
35 | CLEARCX; | ||
36 | |||
37 | EXPLODEXSP; | ||
38 | |||
39 | switch (xc) { | ||
40 | case IEEE754_CLASS_SNAN: | ||
41 | case IEEE754_CLASS_QNAN: | ||
42 | case IEEE754_CLASS_INF: | ||
43 | case IEEE754_CLASS_ZERO: | ||
44 | *ip = x; | ||
45 | return x; | ||
46 | case IEEE754_CLASS_DNORM: | ||
47 | /* far to small */ | ||
48 | *ip = ieee754sp_zero(xs); | ||
49 | return x; | ||
50 | case IEEE754_CLASS_NORM: | ||
51 | break; | ||
52 | } | ||
53 | if (xe < 0) { | ||
54 | *ip = ieee754sp_zero(xs); | ||
55 | return x; | ||
56 | } | ||
57 | if (xe >= SP_MBITS) { | ||
58 | *ip = x; | ||
59 | return ieee754sp_zero(xs); | ||
60 | } | ||
61 | /* generate ipart mantissa by clearing bottom bits | ||
62 | */ | ||
63 | *ip = buildsp(xs, xe + SP_EBIAS, | ||
64 | ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) & | ||
65 | ~SP_HIDDEN_BIT); | ||
66 | |||
67 | /* generate fpart mantissa by clearing top bits | ||
68 | * and normalizing (must be able to normalize) | ||
69 | */ | ||
70 | xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe)); | ||
71 | if (xm == 0) | ||
72 | return ieee754sp_zero(xs); | ||
73 | |||
74 | while ((xm >> SP_MBITS) == 0) { | ||
75 | xm <<= 1; | ||
76 | xe--; | ||
77 | } | ||
78 | return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); | ||
79 | } | ||
diff --git a/arch/mips/math-emu/sp_mul.c b/arch/mips/math-emu/sp_mul.c index fa4675cf2aad..890c13a2965e 100644 --- a/arch/mips/math-emu/sp_mul.c +++ b/arch/mips/math-emu/sp_mul.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,23 +16,32 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
28 | 23 | ||
29 | ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) | 24 | union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y) |
30 | { | 25 | { |
26 | int re; | ||
27 | int rs; | ||
28 | unsigned rm; | ||
29 | unsigned short lxm; | ||
30 | unsigned short hxm; | ||
31 | unsigned short lym; | ||
32 | unsigned short hym; | ||
33 | unsigned lrm; | ||
34 | unsigned hrm; | ||
35 | unsigned t; | ||
36 | unsigned at; | ||
37 | |||
31 | COMPXSP; | 38 | COMPXSP; |
32 | COMPYSP; | 39 | COMPYSP; |
33 | 40 | ||
34 | EXPLODEXSP; | 41 | EXPLODEXSP; |
35 | EXPLODEYSP; | 42 | EXPLODEYSP; |
36 | 43 | ||
37 | CLEARCX; | 44 | ieee754_clearcx(); |
38 | 45 | ||
39 | FLUSHXSP; | 46 | FLUSHXSP; |
40 | FLUSHYSP; | 47 | FLUSHYSP; |
@@ -51,8 +58,8 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) | |||
51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | 58 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | 59 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
53 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | 60 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
54 | SETCX(IEEE754_INVALID_OPERATION); | 61 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
55 | return ieee754sp_nanxcpt(ieee754sp_indef(), "mul", x, y); | 62 | return ieee754sp_nanxcpt(ieee754sp_indef()); |
56 | 63 | ||
57 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | 64 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
58 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | 65 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
@@ -68,12 +75,13 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) | |||
68 | return x; | 75 | return x; |
69 | 76 | ||
70 | 77 | ||
71 | /* Infinity handling */ | 78 | /* |
72 | 79 | * Infinity handling | |
80 | */ | ||
73 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): | 81 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): |
74 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | 82 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
75 | SETCX(IEEE754_INVALID_OPERATION); | 83 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
76 | return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y); | 84 | return ieee754sp_indef(); |
77 | 85 | ||
78 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): | 86 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
79 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | 87 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): |
@@ -108,63 +116,50 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) | |||
108 | assert(xm & SP_HIDDEN_BIT); | 116 | assert(xm & SP_HIDDEN_BIT); |
109 | assert(ym & SP_HIDDEN_BIT); | 117 | assert(ym & SP_HIDDEN_BIT); |
110 | 118 | ||
111 | { | 119 | re = xe + ye; |
112 | int re = xe + ye; | 120 | rs = xs ^ ys; |
113 | int rs = xs ^ ys; | 121 | |
114 | unsigned rm; | 122 | /* shunt to top of word */ |
115 | 123 | xm <<= 32 - (SP_FBITS + 1); | |
116 | /* shunt to top of word */ | 124 | ym <<= 32 - (SP_FBITS + 1); |
117 | xm <<= 32 - (SP_MBITS + 1); | 125 | |
118 | ym <<= 32 - (SP_MBITS + 1); | 126 | /* |
119 | 127 | * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. | |
120 | /* multiply 32bits xm,ym to give high 32bits rm with stickness | 128 | */ |
121 | */ | 129 | lxm = xm & 0xffff; |
122 | { | 130 | hxm = xm >> 16; |
123 | unsigned short lxm = xm & 0xffff; | 131 | lym = ym & 0xffff; |
124 | unsigned short hxm = xm >> 16; | 132 | hym = ym >> 16; |
125 | unsigned short lym = ym & 0xffff; | 133 | |
126 | unsigned short hym = ym >> 16; | 134 | lrm = lxm * lym; /* 16 * 16 => 32 */ |
127 | unsigned lrm; | 135 | hrm = hxm * hym; /* 16 * 16 => 32 */ |
128 | unsigned hrm; | 136 | |
129 | 137 | t = lxm * hym; /* 16 * 16 => 32 */ | |
130 | lrm = lxm * lym; /* 16 * 16 => 32 */ | 138 | at = lrm + (t << 16); |
131 | hrm = hxm * hym; /* 16 * 16 => 32 */ | 139 | hrm += at < lrm; |
132 | 140 | lrm = at; | |
133 | { | 141 | hrm = hrm + (t >> 16); |
134 | unsigned t = lxm * hym; /* 16 * 16 => 32 */ | 142 | |
135 | { | 143 | t = hxm * lym; /* 16 * 16 => 32 */ |
136 | unsigned at = lrm + (t << 16); | 144 | at = lrm + (t << 16); |
137 | hrm += at < lrm; | 145 | hrm += at < lrm; |
138 | lrm = at; | 146 | lrm = at; |
139 | } | 147 | hrm = hrm + (t >> 16); |
140 | hrm = hrm + (t >> 16); | 148 | |
141 | } | 149 | rm = hrm | (lrm != 0); |
142 | 150 | ||
143 | { | 151 | /* |
144 | unsigned t = hxm * lym; /* 16 * 16 => 32 */ | 152 | * Sticky shift down to normal rounding precision. |
145 | { | 153 | */ |
146 | unsigned at = lrm + (t << 16); | 154 | if ((int) rm < 0) { |
147 | hrm += at < lrm; | 155 | rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | |
148 | lrm = at; | 156 | ((rm << (SP_FBITS + 1 + 3)) != 0); |
149 | } | 157 | re++; |
150 | hrm = hrm + (t >> 16); | 158 | } else { |
151 | } | 159 | rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | |
152 | rm = hrm | (lrm != 0); | 160 | ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); |
153 | } | ||
154 | |||
155 | /* | ||
156 | * sticky shift down to normal rounding precision | ||
157 | */ | ||
158 | if ((int) rm < 0) { | ||
159 | rm = (rm >> (32 - (SP_MBITS + 1 + 3))) | | ||
160 | ((rm << (SP_MBITS + 1 + 3)) != 0); | ||
161 | re++; | ||
162 | } else { | ||
163 | rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) | | ||
164 | ((rm << (SP_MBITS + 1 + 3 + 1)) != 0); | ||
165 | } | ||
166 | assert(rm & (SP_HIDDEN_BIT << 3)); | ||
167 | |||
168 | SPNORMRET2(rs, re, rm, "mul", x, y); | ||
169 | } | 161 | } |
162 | assert(rm & (SP_HIDDEN_BIT << 3)); | ||
163 | |||
164 | return ieee754sp_format(rs, re, rm); | ||
170 | } | 165 | } |
diff --git a/arch/mips/math-emu/sp_scalb.c b/arch/mips/math-emu/sp_scalb.c deleted file mode 100644 index dd76196984c8..000000000000 --- a/arch/mips/math-emu/sp_scalb.c +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | /* IEEE754 floating point arithmetic | ||
2 | * single precision | ||
3 | */ | ||
4 | /* | ||
5 | * MIPS floating point support | ||
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
7 | * | ||
8 | * ######################################################################## | ||
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 (Version 2) as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
17 | * for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include "ieee754sp.h" | ||
28 | |||
29 | ieee754sp ieee754sp_scalb(ieee754sp x, int n) | ||
30 | { | ||
31 | COMPXSP; | ||
32 | |||
33 | CLEARCX; | ||
34 | |||
35 | EXPLODEXSP; | ||
36 | |||
37 | switch (xc) { | ||
38 | case IEEE754_CLASS_SNAN: | ||
39 | return ieee754sp_nanxcpt(x, "scalb", x, n); | ||
40 | case IEEE754_CLASS_QNAN: | ||
41 | case IEEE754_CLASS_INF: | ||
42 | case IEEE754_CLASS_ZERO: | ||
43 | return x; | ||
44 | case IEEE754_CLASS_DNORM: | ||
45 | SPDNORMX; | ||
46 | break; | ||
47 | case IEEE754_CLASS_NORM: | ||
48 | break; | ||
49 | } | ||
50 | SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); | ||
51 | } | ||
52 | |||
53 | |||
54 | ieee754sp ieee754sp_ldexp(ieee754sp x, int n) | ||
55 | { | ||
56 | return ieee754sp_scalb(x, n); | ||
57 | } | ||
diff --git a/arch/mips/math-emu/sp_simple.c b/arch/mips/math-emu/sp_simple.c index ae4fcfafd853..f1ffaa9a17e0 100644 --- a/arch/mips/math-emu/sp_simple.c +++ b/arch/mips/math-emu/sp_simple.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,33 +16,17 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
28 | 23 | ||
29 | int ieee754sp_finite(ieee754sp x) | 24 | union ieee754sp ieee754sp_neg(union ieee754sp x) |
30 | { | ||
31 | return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; | ||
32 | } | ||
33 | |||
34 | ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y) | ||
35 | { | ||
36 | CLEARCX; | ||
37 | SPSIGN(x) = SPSIGN(y); | ||
38 | return x; | ||
39 | } | ||
40 | |||
41 | |||
42 | ieee754sp ieee754sp_neg(ieee754sp x) | ||
43 | { | 25 | { |
44 | COMPXSP; | 26 | COMPXSP; |
45 | 27 | ||
46 | EXPLODEXSP; | 28 | EXPLODEXSP; |
47 | CLEARCX; | 29 | ieee754_clearcx(); |
48 | FLUSHXSP; | 30 | FLUSHXSP; |
49 | 31 | ||
50 | /* | 32 | /* |
@@ -55,30 +37,29 @@ ieee754sp ieee754sp_neg(ieee754sp x) | |||
55 | SPSIGN(x) ^= 1; | 37 | SPSIGN(x) ^= 1; |
56 | 38 | ||
57 | if (xc == IEEE754_CLASS_SNAN) { | 39 | if (xc == IEEE754_CLASS_SNAN) { |
58 | ieee754sp y = ieee754sp_indef(); | 40 | union ieee754sp y = ieee754sp_indef(); |
59 | SETCX(IEEE754_INVALID_OPERATION); | 41 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
60 | SPSIGN(y) = SPSIGN(x); | 42 | SPSIGN(y) = SPSIGN(x); |
61 | return ieee754sp_nanxcpt(y, "neg"); | 43 | return ieee754sp_nanxcpt(y); |
62 | } | 44 | } |
63 | 45 | ||
64 | return x; | 46 | return x; |
65 | } | 47 | } |
66 | 48 | ||
67 | 49 | union ieee754sp ieee754sp_abs(union ieee754sp x) | |
68 | ieee754sp ieee754sp_abs(ieee754sp x) | ||
69 | { | 50 | { |
70 | COMPXSP; | 51 | COMPXSP; |
71 | 52 | ||
72 | EXPLODEXSP; | 53 | EXPLODEXSP; |
73 | CLEARCX; | 54 | ieee754_clearcx(); |
74 | FLUSHXSP; | 55 | FLUSHXSP; |
75 | 56 | ||
76 | /* Clear sign ALWAYS, irrespective of NaN */ | 57 | /* Clear sign ALWAYS, irrespective of NaN */ |
77 | SPSIGN(x) = 0; | 58 | SPSIGN(x) = 0; |
78 | 59 | ||
79 | if (xc == IEEE754_CLASS_SNAN) { | 60 | if (xc == IEEE754_CLASS_SNAN) { |
80 | SETCX(IEEE754_INVALID_OPERATION); | 61 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
81 | return ieee754sp_nanxcpt(ieee754sp_indef(), "abs"); | 62 | return ieee754sp_nanxcpt(ieee754sp_indef()); |
82 | } | 63 | } |
83 | 64 | ||
84 | return x; | 65 | return x; |
diff --git a/arch/mips/math-emu/sp_sqrt.c b/arch/mips/math-emu/sp_sqrt.c index fed20175f5fb..b7c098a86f95 100644 --- a/arch/mips/math-emu/sp_sqrt.c +++ b/arch/mips/math-emu/sp_sqrt.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,15 +16,12 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
28 | 23 | ||
29 | ieee754sp ieee754sp_sqrt(ieee754sp x) | 24 | union ieee754sp ieee754sp_sqrt(union ieee754sp x) |
30 | { | 25 | { |
31 | int ix, s, q, m, t, i; | 26 | int ix, s, q, m, t, i; |
32 | unsigned int r; | 27 | unsigned int r; |
@@ -35,34 +30,38 @@ ieee754sp ieee754sp_sqrt(ieee754sp x) | |||
35 | /* take care of Inf and NaN */ | 30 | /* take care of Inf and NaN */ |
36 | 31 | ||
37 | EXPLODEXSP; | 32 | EXPLODEXSP; |
38 | CLEARCX; | 33 | ieee754_clearcx(); |
39 | FLUSHXSP; | 34 | FLUSHXSP; |
40 | 35 | ||
41 | /* x == INF or NAN? */ | 36 | /* x == INF or NAN? */ |
42 | switch (xc) { | 37 | switch (xc) { |
43 | case IEEE754_CLASS_QNAN: | 38 | case IEEE754_CLASS_QNAN: |
44 | /* sqrt(Nan) = Nan */ | 39 | /* sqrt(Nan) = Nan */ |
45 | return ieee754sp_nanxcpt(x, "sqrt"); | 40 | return ieee754sp_nanxcpt(x); |
41 | |||
46 | case IEEE754_CLASS_SNAN: | 42 | case IEEE754_CLASS_SNAN: |
47 | SETCX(IEEE754_INVALID_OPERATION); | 43 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
48 | return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); | 44 | return ieee754sp_nanxcpt(ieee754sp_indef()); |
45 | |||
49 | case IEEE754_CLASS_ZERO: | 46 | case IEEE754_CLASS_ZERO: |
50 | /* sqrt(0) = 0 */ | 47 | /* sqrt(0) = 0 */ |
51 | return x; | 48 | return x; |
49 | |||
52 | case IEEE754_CLASS_INF: | 50 | case IEEE754_CLASS_INF: |
53 | if (xs) { | 51 | if (xs) { |
54 | /* sqrt(-Inf) = Nan */ | 52 | /* sqrt(-Inf) = Nan */ |
55 | SETCX(IEEE754_INVALID_OPERATION); | 53 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
56 | return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); | 54 | return ieee754sp_nanxcpt(ieee754sp_indef()); |
57 | } | 55 | } |
58 | /* sqrt(+Inf) = Inf */ | 56 | /* sqrt(+Inf) = Inf */ |
59 | return x; | 57 | return x; |
58 | |||
60 | case IEEE754_CLASS_DNORM: | 59 | case IEEE754_CLASS_DNORM: |
61 | case IEEE754_CLASS_NORM: | 60 | case IEEE754_CLASS_NORM: |
62 | if (xs) { | 61 | if (xs) { |
63 | /* sqrt(-x) = Nan */ | 62 | /* sqrt(-x) = Nan */ |
64 | SETCX(IEEE754_INVALID_OPERATION); | 63 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
65 | return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); | 64 | return ieee754sp_nanxcpt(ieee754sp_indef()); |
66 | } | 65 | } |
67 | break; | 66 | break; |
68 | } | 67 | } |
@@ -99,12 +98,12 @@ ieee754sp ieee754sp_sqrt(ieee754sp x) | |||
99 | } | 98 | } |
100 | 99 | ||
101 | if (ix != 0) { | 100 | if (ix != 0) { |
102 | SETCX(IEEE754_INEXACT); | 101 | ieee754_setcx(IEEE754_INEXACT); |
103 | switch (ieee754_csr.rm) { | 102 | switch (ieee754_csr.rm) { |
104 | case IEEE754_RP: | 103 | case FPU_CSR_RU: |
105 | q += 2; | 104 | q += 2; |
106 | break; | 105 | break; |
107 | case IEEE754_RN: | 106 | case FPU_CSR_RN: |
108 | q += (q & 1); | 107 | q += (q & 1); |
109 | break; | 108 | break; |
110 | } | 109 | } |
diff --git a/arch/mips/math-emu/sp_sub.c b/arch/mips/math-emu/sp_sub.c index e595c6f3d0bb..8592e49032b8 100644 --- a/arch/mips/math-emu/sp_sub.c +++ b/arch/mips/math-emu/sp_sub.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,23 +16,22 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
28 | 23 | ||
29 | ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) | 24 | union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y) |
30 | { | 25 | { |
26 | int s; | ||
27 | |||
31 | COMPXSP; | 28 | COMPXSP; |
32 | COMPYSP; | 29 | COMPYSP; |
33 | 30 | ||
34 | EXPLODEXSP; | 31 | EXPLODEXSP; |
35 | EXPLODEYSP; | 32 | EXPLODEYSP; |
36 | 33 | ||
37 | CLEARCX; | 34 | ieee754_clearcx(); |
38 | 35 | ||
39 | FLUSHXSP; | 36 | FLUSHXSP; |
40 | FLUSHYSP; | 37 | FLUSHYSP; |
@@ -51,8 +48,8 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) | |||
51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): | 48 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): | 49 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
53 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
54 | SETCX(IEEE754_INVALID_OPERATION); | 51 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
55 | return ieee754sp_nanxcpt(ieee754sp_indef(), "sub", x, y); | 52 | return ieee754sp_nanxcpt(ieee754sp_indef()); |
56 | 53 | ||
57 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): | 54 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
58 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): | 55 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
@@ -68,14 +65,14 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) | |||
68 | return x; | 65 | return x; |
69 | 66 | ||
70 | 67 | ||
71 | /* Infinity handling | 68 | /* |
72 | */ | 69 | * Infinity handling |
73 | 70 | */ | |
74 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): | 71 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
75 | if (xs != ys) | 72 | if (xs != ys) |
76 | return x; | 73 | return x; |
77 | SETCX(IEEE754_INVALID_OPERATION); | 74 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
78 | return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y); | 75 | return ieee754sp_indef(); |
79 | 76 | ||
80 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): | 77 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
81 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): | 78 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): |
@@ -87,15 +84,14 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) | |||
87 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
88 | return x; | 85 | return x; |
89 | 86 | ||
90 | /* Zero handling | 87 | /* |
91 | */ | 88 | * Zero handling |
92 | 89 | */ | |
93 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
94 | if (xs != ys) | 91 | if (xs != ys) |
95 | return x; | 92 | return x; |
96 | else | 93 | else |
97 | return ieee754sp_zero(ieee754_csr.rm == | 94 | return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); |
98 | IEEE754_RD); | ||
99 | 95 | ||
100 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): | 96 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
101 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): | 97 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
@@ -104,7 +100,7 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) | |||
104 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): | 100 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): |
105 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): | 101 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): |
106 | /* quick fix up */ | 102 | /* quick fix up */ |
107 | DPSIGN(y) ^= 1; | 103 | SPSIGN(y) ^= 1; |
108 | return y; | 104 | return y; |
109 | 105 | ||
110 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): | 106 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): |
@@ -133,14 +129,16 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) | |||
133 | ym <<= 3; | 129 | ym <<= 3; |
134 | 130 | ||
135 | if (xe > ye) { | 131 | if (xe > ye) { |
136 | /* have to shift y fraction right to align | 132 | /* |
133 | * have to shift y fraction right to align | ||
137 | */ | 134 | */ |
138 | int s = xe - ye; | 135 | s = xe - ye; |
139 | SPXSRSYn(s); | 136 | SPXSRSYn(s); |
140 | } else if (ye > xe) { | 137 | } else if (ye > xe) { |
141 | /* have to shift x fraction right to align | 138 | /* |
139 | * have to shift x fraction right to align | ||
142 | */ | 140 | */ |
143 | int s = ye - xe; | 141 | s = ye - xe; |
144 | SPXSRSXn(s); | 142 | SPXSRSXn(s); |
145 | } | 143 | } |
146 | assert(xe == ye); | 144 | assert(xe == ye); |
@@ -153,7 +151,7 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) | |||
153 | xe = xe; | 151 | xe = xe; |
154 | xs = xs; | 152 | xs = xs; |
155 | 153 | ||
156 | if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ | 154 | if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */ |
157 | SPXSRSX1(); /* shift preserving sticky */ | 155 | SPXSRSX1(); /* shift preserving sticky */ |
158 | } | 156 | } |
159 | } else { | 157 | } else { |
@@ -167,17 +165,18 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) | |||
167 | xs = ys; | 165 | xs = ys; |
168 | } | 166 | } |
169 | if (xm == 0) { | 167 | if (xm == 0) { |
170 | if (ieee754_csr.rm == IEEE754_RD) | 168 | if (ieee754_csr.rm == FPU_CSR_RD) |
171 | return ieee754sp_zero(1); /* round negative inf. => sign = -1 */ | 169 | return ieee754sp_zero(1); /* round negative inf. => sign = -1 */ |
172 | else | 170 | else |
173 | return ieee754sp_zero(0); /* other round modes => sign = 1 */ | 171 | return ieee754sp_zero(0); /* other round modes => sign = 1 */ |
174 | } | 172 | } |
175 | /* normalize to rounding precision | 173 | /* normalize to rounding precision |
176 | */ | 174 | */ |
177 | while ((xm >> (SP_MBITS + 3)) == 0) { | 175 | while ((xm >> (SP_FBITS + 3)) == 0) { |
178 | xm <<= 1; | 176 | xm <<= 1; |
179 | xe--; | 177 | xe--; |
180 | } | 178 | } |
181 | } | 179 | } |
182 | SPNORMRET2(xs, xe, xm, "sub", x, y); | 180 | |
181 | return ieee754sp_format(xs, xe, xm); | ||
183 | } | 182 | } |
diff --git a/arch/mips/math-emu/sp_tint.c b/arch/mips/math-emu/sp_tint.c index 0fe9acc7716e..091299a31798 100644 --- a/arch/mips/math-emu/sp_tint.c +++ b/arch/mips/math-emu/sp_tint.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,20 +16,21 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
29 | 23 | ||
30 | int ieee754sp_tint(ieee754sp x) | 24 | int ieee754sp_tint(union ieee754sp x) |
31 | { | 25 | { |
26 | u32 residue; | ||
27 | int round; | ||
28 | int sticky; | ||
29 | int odd; | ||
30 | |||
32 | COMPXSP; | 31 | COMPXSP; |
33 | 32 | ||
34 | CLEARCX; | 33 | ieee754_clearcx(); |
35 | 34 | ||
36 | EXPLODEXSP; | 35 | EXPLODEXSP; |
37 | FLUSHXSP; | 36 | FLUSHXSP; |
@@ -40,10 +39,12 @@ int ieee754sp_tint(ieee754sp x) | |||
40 | case IEEE754_CLASS_SNAN: | 39 | case IEEE754_CLASS_SNAN: |
41 | case IEEE754_CLASS_QNAN: | 40 | case IEEE754_CLASS_QNAN: |
42 | case IEEE754_CLASS_INF: | 41 | case IEEE754_CLASS_INF: |
43 | SETCX(IEEE754_INVALID_OPERATION); | 42 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
44 | return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); | 43 | return ieee754si_indef(); |
44 | |||
45 | case IEEE754_CLASS_ZERO: | 45 | case IEEE754_CLASS_ZERO: |
46 | return 0; | 46 | return 0; |
47 | |||
47 | case IEEE754_CLASS_DNORM: | 48 | case IEEE754_CLASS_DNORM: |
48 | case IEEE754_CLASS_NORM: | 49 | case IEEE754_CLASS_NORM: |
49 | break; | 50 | break; |
@@ -54,18 +55,13 @@ int ieee754sp_tint(ieee754sp x) | |||
54 | return -0x80000000; | 55 | return -0x80000000; |
55 | /* Set invalid. We will only use overflow for floating | 56 | /* Set invalid. We will only use overflow for floating |
56 | point overflow */ | 57 | point overflow */ |
57 | SETCX(IEEE754_INVALID_OPERATION); | 58 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
58 | return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); | 59 | return ieee754si_indef(); |
59 | } | 60 | } |
60 | /* oh gawd */ | 61 | /* oh gawd */ |
61 | if (xe > SP_MBITS) { | 62 | if (xe > SP_FBITS) { |
62 | xm <<= xe - SP_MBITS; | 63 | xm <<= xe - SP_FBITS; |
63 | } else { | 64 | } else { |
64 | u32 residue; | ||
65 | int round; | ||
66 | int sticky; | ||
67 | int odd; | ||
68 | |||
69 | if (xe < -1) { | 65 | if (xe < -1) { |
70 | residue = xm; | 66 | residue = xm; |
71 | round = 0; | 67 | round = 0; |
@@ -76,51 +72,38 @@ int ieee754sp_tint(ieee754sp x) | |||
76 | * so we do it in two steps. Be aware that xe | 72 | * so we do it in two steps. Be aware that xe |
77 | * may be -1 */ | 73 | * may be -1 */ |
78 | residue = xm << (xe + 1); | 74 | residue = xm << (xe + 1); |
79 | residue <<= 31 - SP_MBITS; | 75 | residue <<= 31 - SP_FBITS; |
80 | round = (residue >> 31) != 0; | 76 | round = (residue >> 31) != 0; |
81 | sticky = (residue << 1) != 0; | 77 | sticky = (residue << 1) != 0; |
82 | xm >>= SP_MBITS - xe; | 78 | xm >>= SP_FBITS - xe; |
83 | } | 79 | } |
84 | odd = (xm & 0x1) != 0x0; | 80 | odd = (xm & 0x1) != 0x0; |
85 | switch (ieee754_csr.rm) { | 81 | switch (ieee754_csr.rm) { |
86 | case IEEE754_RN: | 82 | case FPU_CSR_RN: |
87 | if (round && (sticky || odd)) | 83 | if (round && (sticky || odd)) |
88 | xm++; | 84 | xm++; |
89 | break; | 85 | break; |
90 | case IEEE754_RZ: | 86 | case FPU_CSR_RZ: |
91 | break; | 87 | break; |
92 | case IEEE754_RU: /* toward +Infinity */ | 88 | case FPU_CSR_RU: /* toward +Infinity */ |
93 | if ((round || sticky) && !xs) | 89 | if ((round || sticky) && !xs) |
94 | xm++; | 90 | xm++; |
95 | break; | 91 | break; |
96 | case IEEE754_RD: /* toward -Infinity */ | 92 | case FPU_CSR_RD: /* toward -Infinity */ |
97 | if ((round || sticky) && xs) | 93 | if ((round || sticky) && xs) |
98 | xm++; | 94 | xm++; |
99 | break; | 95 | break; |
100 | } | 96 | } |
101 | if ((xm >> 31) != 0) { | 97 | if ((xm >> 31) != 0) { |
102 | /* This can happen after rounding */ | 98 | /* This can happen after rounding */ |
103 | SETCX(IEEE754_INVALID_OPERATION); | 99 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
104 | return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); | 100 | return ieee754si_indef(); |
105 | } | 101 | } |
106 | if (round || sticky) | 102 | if (round || sticky) |
107 | SETCX(IEEE754_INEXACT); | 103 | ieee754_setcx(IEEE754_INEXACT); |
108 | } | 104 | } |
109 | if (xs) | 105 | if (xs) |
110 | return -xm; | 106 | return -xm; |
111 | else | 107 | else |
112 | return xm; | 108 | return xm; |
113 | } | 109 | } |
114 | |||
115 | |||
116 | unsigned int ieee754sp_tuns(ieee754sp x) | ||
117 | { | ||
118 | ieee754sp hb = ieee754sp_1e31(); | ||
119 | |||
120 | /* what if x < 0 ?? */ | ||
121 | if (ieee754sp_lt(x, hb)) | ||
122 | return (unsigned) ieee754sp_tint(x); | ||
123 | |||
124 | return (unsigned) ieee754sp_tint(ieee754sp_sub(x, hb)) | | ||
125 | ((unsigned) 1 << 31); | ||
126 | } | ||
diff --git a/arch/mips/math-emu/sp_tlong.c b/arch/mips/math-emu/sp_tlong.c index d0ca6e22be29..9f3c742c1cea 100644 --- a/arch/mips/math-emu/sp_tlong.c +++ b/arch/mips/math-emu/sp_tlong.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * MIPS floating point support | 5 | * MIPS floating point support |
6 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
7 | * | 7 | * |
8 | * ######################################################################## | ||
9 | * | ||
10 | * This program is free software; you can distribute it and/or modify it | 8 | * This program is free software; you can distribute it and/or modify it |
11 | * under the terms of the GNU General Public License (Version 2) as | 9 | * under the terms of the GNU General Public License (Version 2) as |
12 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -18,19 +16,22 @@ | |||
18 | * | 16 | * |
19 | * You should have received a copy of the GNU General Public License along | 17 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 18 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 19 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | ||
23 | * ######################################################################## | ||
24 | */ | 20 | */ |
25 | 21 | ||
26 | |||
27 | #include "ieee754sp.h" | 22 | #include "ieee754sp.h" |
23 | #include "ieee754dp.h" | ||
28 | 24 | ||
29 | s64 ieee754sp_tlong(ieee754sp x) | 25 | s64 ieee754sp_tlong(union ieee754sp x) |
30 | { | 26 | { |
27 | u32 residue; | ||
28 | int round; | ||
29 | int sticky; | ||
30 | int odd; | ||
31 | |||
31 | COMPXDP; /* <-- need 64-bit mantissa tmp */ | 32 | COMPXDP; /* <-- need 64-bit mantissa tmp */ |
32 | 33 | ||
33 | CLEARCX; | 34 | ieee754_clearcx(); |
34 | 35 | ||
35 | EXPLODEXSP; | 36 | EXPLODEXSP; |
36 | FLUSHXSP; | 37 | FLUSHXSP; |
@@ -39,10 +40,12 @@ s64 ieee754sp_tlong(ieee754sp x) | |||
39 | case IEEE754_CLASS_SNAN: | 40 | case IEEE754_CLASS_SNAN: |
40 | case IEEE754_CLASS_QNAN: | 41 | case IEEE754_CLASS_QNAN: |
41 | case IEEE754_CLASS_INF: | 42 | case IEEE754_CLASS_INF: |
42 | SETCX(IEEE754_INVALID_OPERATION); | 43 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
43 | return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); | 44 | return ieee754di_indef(); |
45 | |||
44 | case IEEE754_CLASS_ZERO: | 46 | case IEEE754_CLASS_ZERO: |
45 | return 0; | 47 | return 0; |
48 | |||
46 | case IEEE754_CLASS_DNORM: | 49 | case IEEE754_CLASS_DNORM: |
47 | case IEEE754_CLASS_NORM: | 50 | case IEEE754_CLASS_NORM: |
48 | break; | 51 | break; |
@@ -53,69 +56,51 @@ s64 ieee754sp_tlong(ieee754sp x) | |||
53 | return -0x8000000000000000LL; | 56 | return -0x8000000000000000LL; |
54 | /* Set invalid. We will only use overflow for floating | 57 | /* Set invalid. We will only use overflow for floating |
55 | point overflow */ | 58 | point overflow */ |
56 | SETCX(IEEE754_INVALID_OPERATION); | 59 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
57 | return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); | 60 | return ieee754di_indef(); |
58 | } | 61 | } |
59 | /* oh gawd */ | 62 | /* oh gawd */ |
60 | if (xe > SP_MBITS) { | 63 | if (xe > SP_FBITS) { |
61 | xm <<= xe - SP_MBITS; | 64 | xm <<= xe - SP_FBITS; |
62 | } else if (xe < SP_MBITS) { | 65 | } else if (xe < SP_FBITS) { |
63 | u32 residue; | ||
64 | int round; | ||
65 | int sticky; | ||
66 | int odd; | ||
67 | |||
68 | if (xe < -1) { | 66 | if (xe < -1) { |
69 | residue = xm; | 67 | residue = xm; |
70 | round = 0; | 68 | round = 0; |
71 | sticky = residue != 0; | 69 | sticky = residue != 0; |
72 | xm = 0; | 70 | xm = 0; |
73 | } else { | 71 | } else { |
74 | residue = xm << (32 - SP_MBITS + xe); | 72 | residue = xm << (32 - SP_FBITS + xe); |
75 | round = (residue >> 31) != 0; | 73 | round = (residue >> 31) != 0; |
76 | sticky = (residue << 1) != 0; | 74 | sticky = (residue << 1) != 0; |
77 | xm >>= SP_MBITS - xe; | 75 | xm >>= SP_FBITS - xe; |
78 | } | 76 | } |
79 | odd = (xm & 0x1) != 0x0; | 77 | odd = (xm & 0x1) != 0x0; |
80 | switch (ieee754_csr.rm) { | 78 | switch (ieee754_csr.rm) { |
81 | case IEEE754_RN: | 79 | case FPU_CSR_RN: |
82 | if (round && (sticky || odd)) | 80 | if (round && (sticky || odd)) |
83 | xm++; | 81 | xm++; |
84 | break; | 82 | break; |
85 | case IEEE754_RZ: | 83 | case FPU_CSR_RZ: |
86 | break; | 84 | break; |
87 | case IEEE754_RU: /* toward +Infinity */ | 85 | case FPU_CSR_RU: /* toward +Infinity */ |
88 | if ((round || sticky) && !xs) | 86 | if ((round || sticky) && !xs) |
89 | xm++; | 87 | xm++; |
90 | break; | 88 | break; |
91 | case IEEE754_RD: /* toward -Infinity */ | 89 | case FPU_CSR_RD: /* toward -Infinity */ |
92 | if ((round || sticky) && xs) | 90 | if ((round || sticky) && xs) |
93 | xm++; | 91 | xm++; |
94 | break; | 92 | break; |
95 | } | 93 | } |
96 | if ((xm >> 63) != 0) { | 94 | if ((xm >> 63) != 0) { |
97 | /* This can happen after rounding */ | 95 | /* This can happen after rounding */ |
98 | SETCX(IEEE754_INVALID_OPERATION); | 96 | ieee754_setcx(IEEE754_INVALID_OPERATION); |
99 | return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); | 97 | return ieee754di_indef(); |
100 | } | 98 | } |
101 | if (round || sticky) | 99 | if (round || sticky) |
102 | SETCX(IEEE754_INEXACT); | 100 | ieee754_setcx(IEEE754_INEXACT); |
103 | } | 101 | } |
104 | if (xs) | 102 | if (xs) |
105 | return -xm; | 103 | return -xm; |
106 | else | 104 | else |
107 | return xm; | 105 | return xm; |
108 | } | 106 | } |
109 | |||
110 | |||
111 | u64 ieee754sp_tulong(ieee754sp x) | ||
112 | { | ||
113 | ieee754sp hb = ieee754sp_1e63(); | ||
114 | |||
115 | /* what if x < 0 ?? */ | ||
116 | if (ieee754sp_lt(x, hb)) | ||
117 | return (u64) ieee754sp_tlong(x); | ||
118 | |||
119 | return (u64) ieee754sp_tlong(ieee754sp_sub(x, hb)) | | ||
120 | (1ULL << 63); | ||
121 | } | ||
diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c index f41a5c5b0865..05b1d7cf9514 100644 --- a/arch/mips/mm/c-octeon.c +++ b/arch/mips/mm/c-octeon.c | |||
@@ -137,8 +137,10 @@ static void octeon_flush_cache_sigtramp(unsigned long addr) | |||
137 | { | 137 | { |
138 | struct vm_area_struct *vma; | 138 | struct vm_area_struct *vma; |
139 | 139 | ||
140 | down_read(¤t->mm->mmap_sem); | ||
140 | vma = find_vma(current->mm, addr); | 141 | vma = find_vma(current->mm, addr); |
141 | octeon_flush_icache_all_cores(vma); | 142 | octeon_flush_icache_all_cores(vma); |
143 | up_read(¤t->mm->mmap_sem); | ||
142 | } | 144 | } |
143 | 145 | ||
144 | 146 | ||
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 1c74a6ad072a..f2e8302fa70f 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Ralf Baechle (ralf@gnu.org) | 7 | * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Ralf Baechle (ralf@gnu.org) |
8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. | 8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
9 | */ | 9 | */ |
10 | #include <linux/cpu_pm.h> | ||
10 | #include <linux/hardirq.h> | 11 | #include <linux/hardirq.h> |
11 | #include <linux/init.h> | 12 | #include <linux/init.h> |
12 | #include <linux/highmem.h> | 13 | #include <linux/highmem.h> |
@@ -50,7 +51,7 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info) | |||
50 | { | 51 | { |
51 | preempt_disable(); | 52 | preempt_disable(); |
52 | 53 | ||
53 | #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) | 54 | #ifndef CONFIG_MIPS_MT_SMP |
54 | smp_call_function(func, info, 1); | 55 | smp_call_function(func, info, 1); |
55 | #endif | 56 | #endif |
56 | func(info); | 57 | func(info); |
@@ -105,22 +106,37 @@ static inline void r4k_blast_dcache_page_dc32(unsigned long addr) | |||
105 | 106 | ||
106 | static inline void r4k_blast_dcache_page_dc64(unsigned long addr) | 107 | static inline void r4k_blast_dcache_page_dc64(unsigned long addr) |
107 | { | 108 | { |
108 | R4600_HIT_CACHEOP_WAR_IMPL; | ||
109 | blast_dcache64_page(addr); | 109 | blast_dcache64_page(addr); |
110 | } | 110 | } |
111 | 111 | ||
112 | static inline void r4k_blast_dcache_page_dc128(unsigned long addr) | ||
113 | { | ||
114 | blast_dcache128_page(addr); | ||
115 | } | ||
116 | |||
112 | static void r4k_blast_dcache_page_setup(void) | 117 | static void r4k_blast_dcache_page_setup(void) |
113 | { | 118 | { |
114 | unsigned long dc_lsize = cpu_dcache_line_size(); | 119 | unsigned long dc_lsize = cpu_dcache_line_size(); |
115 | 120 | ||
116 | if (dc_lsize == 0) | 121 | switch (dc_lsize) { |
122 | case 0: | ||
117 | r4k_blast_dcache_page = (void *)cache_noop; | 123 | r4k_blast_dcache_page = (void *)cache_noop; |
118 | else if (dc_lsize == 16) | 124 | break; |
125 | case 16: | ||
119 | r4k_blast_dcache_page = blast_dcache16_page; | 126 | r4k_blast_dcache_page = blast_dcache16_page; |
120 | else if (dc_lsize == 32) | 127 | break; |
128 | case 32: | ||
121 | r4k_blast_dcache_page = r4k_blast_dcache_page_dc32; | 129 | r4k_blast_dcache_page = r4k_blast_dcache_page_dc32; |
122 | else if (dc_lsize == 64) | 130 | break; |
131 | case 64: | ||
123 | r4k_blast_dcache_page = r4k_blast_dcache_page_dc64; | 132 | r4k_blast_dcache_page = r4k_blast_dcache_page_dc64; |
133 | break; | ||
134 | case 128: | ||
135 | r4k_blast_dcache_page = r4k_blast_dcache_page_dc128; | ||
136 | break; | ||
137 | default: | ||
138 | break; | ||
139 | } | ||
124 | } | 140 | } |
125 | 141 | ||
126 | #ifndef CONFIG_EVA | 142 | #ifndef CONFIG_EVA |
@@ -159,6 +175,8 @@ static void r4k_blast_dcache_page_indexed_setup(void) | |||
159 | r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed; | 175 | r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed; |
160 | else if (dc_lsize == 64) | 176 | else if (dc_lsize == 64) |
161 | r4k_blast_dcache_page_indexed = blast_dcache64_page_indexed; | 177 | r4k_blast_dcache_page_indexed = blast_dcache64_page_indexed; |
178 | else if (dc_lsize == 128) | ||
179 | r4k_blast_dcache_page_indexed = blast_dcache128_page_indexed; | ||
162 | } | 180 | } |
163 | 181 | ||
164 | void (* r4k_blast_dcache)(void); | 182 | void (* r4k_blast_dcache)(void); |
@@ -176,6 +194,8 @@ static void r4k_blast_dcache_setup(void) | |||
176 | r4k_blast_dcache = blast_dcache32; | 194 | r4k_blast_dcache = blast_dcache32; |
177 | else if (dc_lsize == 64) | 195 | else if (dc_lsize == 64) |
178 | r4k_blast_dcache = blast_dcache64; | 196 | r4k_blast_dcache = blast_dcache64; |
197 | else if (dc_lsize == 128) | ||
198 | r4k_blast_dcache = blast_dcache128; | ||
179 | } | 199 | } |
180 | 200 | ||
181 | /* force code alignment (used for TX49XX_ICACHE_INDEX_INV_WAR) */ | 201 | /* force code alignment (used for TX49XX_ICACHE_INDEX_INV_WAR) */ |
@@ -265,6 +285,8 @@ static void r4k_blast_icache_page_setup(void) | |||
265 | r4k_blast_icache_page = blast_icache32_page; | 285 | r4k_blast_icache_page = blast_icache32_page; |
266 | else if (ic_lsize == 64) | 286 | else if (ic_lsize == 64) |
267 | r4k_blast_icache_page = blast_icache64_page; | 287 | r4k_blast_icache_page = blast_icache64_page; |
288 | else if (ic_lsize == 128) | ||
289 | r4k_blast_icache_page = blast_icache128_page; | ||
268 | } | 290 | } |
269 | 291 | ||
270 | #ifndef CONFIG_EVA | 292 | #ifndef CONFIG_EVA |
@@ -338,6 +360,8 @@ static void r4k_blast_icache_setup(void) | |||
338 | r4k_blast_icache = blast_icache32; | 360 | r4k_blast_icache = blast_icache32; |
339 | } else if (ic_lsize == 64) | 361 | } else if (ic_lsize == 64) |
340 | r4k_blast_icache = blast_icache64; | 362 | r4k_blast_icache = blast_icache64; |
363 | else if (ic_lsize == 128) | ||
364 | r4k_blast_icache = blast_icache128; | ||
341 | } | 365 | } |
342 | 366 | ||
343 | static void (* r4k_blast_scache_page)(unsigned long addr); | 367 | static void (* r4k_blast_scache_page)(unsigned long addr); |
@@ -428,7 +452,7 @@ static void r4k___flush_cache_all(void) | |||
428 | 452 | ||
429 | static inline int has_valid_asid(const struct mm_struct *mm) | 453 | static inline int has_valid_asid(const struct mm_struct *mm) |
430 | { | 454 | { |
431 | #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) | 455 | #ifdef CONFIG_MIPS_MT_SMP |
432 | int i; | 456 | int i; |
433 | 457 | ||
434 | for_each_online_cpu(i) | 458 | for_each_online_cpu(i) |
@@ -1094,6 +1118,21 @@ static void probe_pcache(void) | |||
1094 | c->dcache.waybit = 0; | 1118 | c->dcache.waybit = 0; |
1095 | break; | 1119 | break; |
1096 | 1120 | ||
1121 | case CPU_CAVIUM_OCTEON3: | ||
1122 | /* For now lie about the number of ways. */ | ||
1123 | c->icache.linesz = 128; | ||
1124 | c->icache.sets = 16; | ||
1125 | c->icache.ways = 8; | ||
1126 | c->icache.flags |= MIPS_CACHE_VTAG; | ||
1127 | icache_size = c->icache.sets * c->icache.ways * c->icache.linesz; | ||
1128 | |||
1129 | c->dcache.linesz = 128; | ||
1130 | c->dcache.ways = 8; | ||
1131 | c->dcache.sets = 8; | ||
1132 | dcache_size = c->dcache.sets * c->dcache.ways * c->dcache.linesz; | ||
1133 | c->options |= MIPS_CPU_PREFETCH; | ||
1134 | break; | ||
1135 | |||
1097 | default: | 1136 | default: |
1098 | if (!(config & MIPS_CONF_M)) | 1137 | if (!(config & MIPS_CONF_M)) |
1099 | panic("Don't know how to probe P-caches on this cpu."); | 1138 | panic("Don't know how to probe P-caches on this cpu."); |
@@ -1414,6 +1453,7 @@ static void setup_scache(void) | |||
1414 | loongson3_sc_init(); | 1453 | loongson3_sc_init(); |
1415 | return; | 1454 | return; |
1416 | 1455 | ||
1456 | case CPU_CAVIUM_OCTEON3: | ||
1417 | case CPU_XLP: | 1457 | case CPU_XLP: |
1418 | /* don't need to worry about L2, fully coherent */ | 1458 | /* don't need to worry about L2, fully coherent */ |
1419 | return; | 1459 | return; |
@@ -1644,3 +1684,26 @@ void r4k_cache_init(void) | |||
1644 | coherency_setup(); | 1684 | coherency_setup(); |
1645 | board_cache_error_setup = r4k_cache_error_setup; | 1685 | board_cache_error_setup = r4k_cache_error_setup; |
1646 | } | 1686 | } |
1687 | |||
1688 | static int r4k_cache_pm_notifier(struct notifier_block *self, unsigned long cmd, | ||
1689 | void *v) | ||
1690 | { | ||
1691 | switch (cmd) { | ||
1692 | case CPU_PM_ENTER_FAILED: | ||
1693 | case CPU_PM_EXIT: | ||
1694 | coherency_setup(); | ||
1695 | break; | ||
1696 | } | ||
1697 | |||
1698 | return NOTIFY_OK; | ||
1699 | } | ||
1700 | |||
1701 | static struct notifier_block r4k_cache_pm_notifier_block = { | ||
1702 | .notifier_call = r4k_cache_pm_notifier, | ||
1703 | }; | ||
1704 | |||
1705 | int __init r4k_cache_init_pm(void) | ||
1706 | { | ||
1707 | return cpu_pm_register_notifier(&r4k_cache_pm_notifier_block); | ||
1708 | } | ||
1709 | arch_initcall(r4k_cache_init_pm); | ||
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 4fc74c78265a..6e4413330e36 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c | |||
@@ -44,27 +44,6 @@ | |||
44 | #include <asm/tlb.h> | 44 | #include <asm/tlb.h> |
45 | #include <asm/fixmap.h> | 45 | #include <asm/fixmap.h> |
46 | 46 | ||
47 | /* Atomicity and interruptability */ | ||
48 | #ifdef CONFIG_MIPS_MT_SMTC | ||
49 | |||
50 | #include <asm/mipsmtregs.h> | ||
51 | |||
52 | #define ENTER_CRITICAL(flags) \ | ||
53 | { \ | ||
54 | unsigned int mvpflags; \ | ||
55 | local_irq_save(flags);\ | ||
56 | mvpflags = dvpe() | ||
57 | #define EXIT_CRITICAL(flags) \ | ||
58 | evpe(mvpflags); \ | ||
59 | local_irq_restore(flags); \ | ||
60 | } | ||
61 | #else | ||
62 | |||
63 | #define ENTER_CRITICAL(flags) local_irq_save(flags) | ||
64 | #define EXIT_CRITICAL(flags) local_irq_restore(flags) | ||
65 | |||
66 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
67 | |||
68 | /* | 47 | /* |
69 | * We have up to 8 empty zeroed pages so we can map one of the right colour | 48 | * We have up to 8 empty zeroed pages so we can map one of the right colour |
70 | * when needed. This is necessary only on R4000 / R4400 SC and MC versions | 49 | * when needed. This is necessary only on R4000 / R4400 SC and MC versions |
@@ -100,21 +79,7 @@ void setup_zero_pages(void) | |||
100 | zero_page_mask = ((PAGE_SIZE << order) - 1) & PAGE_MASK; | 79 | zero_page_mask = ((PAGE_SIZE << order) - 1) & PAGE_MASK; |
101 | } | 80 | } |
102 | 81 | ||
103 | #ifdef CONFIG_MIPS_MT_SMTC | 82 | static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot) |
104 | static pte_t *kmap_coherent_pte; | ||
105 | static void __init kmap_coherent_init(void) | ||
106 | { | ||
107 | unsigned long vaddr; | ||
108 | |||
109 | /* cache the first coherent kmap pte */ | ||
110 | vaddr = __fix_to_virt(FIX_CMAP_BEGIN); | ||
111 | kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); | ||
112 | } | ||
113 | #else | ||
114 | static inline void kmap_coherent_init(void) {} | ||
115 | #endif | ||
116 | |||
117 | void *kmap_coherent(struct page *page, unsigned long addr) | ||
118 | { | 83 | { |
119 | enum fixed_addresses idx; | 84 | enum fixed_addresses idx; |
120 | unsigned long vaddr, flags, entrylo; | 85 | unsigned long vaddr, flags, entrylo; |
@@ -126,58 +91,48 @@ void *kmap_coherent(struct page *page, unsigned long addr) | |||
126 | 91 | ||
127 | pagefault_disable(); | 92 | pagefault_disable(); |
128 | idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1); | 93 | idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1); |
129 | #ifdef CONFIG_MIPS_MT_SMTC | ||
130 | idx += FIX_N_COLOURS * smp_processor_id() + | ||
131 | (in_interrupt() ? (FIX_N_COLOURS * NR_CPUS) : 0); | ||
132 | #else | ||
133 | idx += in_interrupt() ? FIX_N_COLOURS : 0; | 94 | idx += in_interrupt() ? FIX_N_COLOURS : 0; |
134 | #endif | ||
135 | vaddr = __fix_to_virt(FIX_CMAP_END - idx); | 95 | vaddr = __fix_to_virt(FIX_CMAP_END - idx); |
136 | pte = mk_pte(page, PAGE_KERNEL); | 96 | pte = mk_pte(page, prot); |
137 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) | 97 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) |
138 | entrylo = pte.pte_high; | 98 | entrylo = pte.pte_high; |
139 | #else | 99 | #else |
140 | entrylo = pte_to_entrylo(pte_val(pte)); | 100 | entrylo = pte_to_entrylo(pte_val(pte)); |
141 | #endif | 101 | #endif |
142 | 102 | ||
143 | ENTER_CRITICAL(flags); | 103 | local_irq_save(flags); |
144 | old_ctx = read_c0_entryhi(); | 104 | old_ctx = read_c0_entryhi(); |
145 | write_c0_entryhi(vaddr & (PAGE_MASK << 1)); | 105 | write_c0_entryhi(vaddr & (PAGE_MASK << 1)); |
146 | write_c0_entrylo0(entrylo); | 106 | write_c0_entrylo0(entrylo); |
147 | write_c0_entrylo1(entrylo); | 107 | write_c0_entrylo1(entrylo); |
148 | #ifdef CONFIG_MIPS_MT_SMTC | ||
149 | set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte); | ||
150 | /* preload TLB instead of local_flush_tlb_one() */ | ||
151 | mtc0_tlbw_hazard(); | ||
152 | tlb_probe(); | ||
153 | tlb_probe_hazard(); | ||
154 | tlbidx = read_c0_index(); | ||
155 | mtc0_tlbw_hazard(); | ||
156 | if (tlbidx < 0) | ||
157 | tlb_write_random(); | ||
158 | else | ||
159 | tlb_write_indexed(); | ||
160 | #else | ||
161 | tlbidx = read_c0_wired(); | 108 | tlbidx = read_c0_wired(); |
162 | write_c0_wired(tlbidx + 1); | 109 | write_c0_wired(tlbidx + 1); |
163 | write_c0_index(tlbidx); | 110 | write_c0_index(tlbidx); |
164 | mtc0_tlbw_hazard(); | 111 | mtc0_tlbw_hazard(); |
165 | tlb_write_indexed(); | 112 | tlb_write_indexed(); |
166 | #endif | ||
167 | tlbw_use_hazard(); | 113 | tlbw_use_hazard(); |
168 | write_c0_entryhi(old_ctx); | 114 | write_c0_entryhi(old_ctx); |
169 | EXIT_CRITICAL(flags); | 115 | local_irq_restore(flags); |
170 | 116 | ||
171 | return (void*) vaddr; | 117 | return (void*) vaddr; |
172 | } | 118 | } |
173 | 119 | ||
120 | void *kmap_coherent(struct page *page, unsigned long addr) | ||
121 | { | ||
122 | return __kmap_pgprot(page, addr, PAGE_KERNEL); | ||
123 | } | ||
124 | |||
125 | void *kmap_noncoherent(struct page *page, unsigned long addr) | ||
126 | { | ||
127 | return __kmap_pgprot(page, addr, PAGE_KERNEL_NC); | ||
128 | } | ||
129 | |||
174 | void kunmap_coherent(void) | 130 | void kunmap_coherent(void) |
175 | { | 131 | { |
176 | #ifndef CONFIG_MIPS_MT_SMTC | ||
177 | unsigned int wired; | 132 | unsigned int wired; |
178 | unsigned long flags, old_ctx; | 133 | unsigned long flags, old_ctx; |
179 | 134 | ||
180 | ENTER_CRITICAL(flags); | 135 | local_irq_save(flags); |
181 | old_ctx = read_c0_entryhi(); | 136 | old_ctx = read_c0_entryhi(); |
182 | wired = read_c0_wired() - 1; | 137 | wired = read_c0_wired() - 1; |
183 | write_c0_wired(wired); | 138 | write_c0_wired(wired); |
@@ -189,8 +144,7 @@ void kunmap_coherent(void) | |||
189 | tlb_write_indexed(); | 144 | tlb_write_indexed(); |
190 | tlbw_use_hazard(); | 145 | tlbw_use_hazard(); |
191 | write_c0_entryhi(old_ctx); | 146 | write_c0_entryhi(old_ctx); |
192 | EXIT_CRITICAL(flags); | 147 | local_irq_restore(flags); |
193 | #endif | ||
194 | pagefault_enable(); | 148 | pagefault_enable(); |
195 | } | 149 | } |
196 | 150 | ||
@@ -256,7 +210,7 @@ EXPORT_SYMBOL_GPL(copy_from_user_page); | |||
256 | void __init fixrange_init(unsigned long start, unsigned long end, | 210 | void __init fixrange_init(unsigned long start, unsigned long end, |
257 | pgd_t *pgd_base) | 211 | pgd_t *pgd_base) |
258 | { | 212 | { |
259 | #if defined(CONFIG_HIGHMEM) || defined(CONFIG_MIPS_MT_SMTC) | 213 | #ifdef CONFIG_HIGHMEM |
260 | pgd_t *pgd; | 214 | pgd_t *pgd; |
261 | pud_t *pud; | 215 | pud_t *pud; |
262 | pmd_t *pmd; | 216 | pmd_t *pmd; |
@@ -327,8 +281,6 @@ void __init paging_init(void) | |||
327 | #ifdef CONFIG_HIGHMEM | 281 | #ifdef CONFIG_HIGHMEM |
328 | kmap_init(); | 282 | kmap_init(); |
329 | #endif | 283 | #endif |
330 | kmap_coherent_init(); | ||
331 | |||
332 | #ifdef CONFIG_ZONE_DMA | 284 | #ifdef CONFIG_ZONE_DMA |
333 | max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; | 285 | max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; |
334 | #endif | 286 | #endif |
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index eeaf50f5df2b..3914e27456f2 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * Carsten Langgaard, carstenl@mips.com | 8 | * Carsten Langgaard, carstenl@mips.com |
9 | * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved. | 9 | * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved. |
10 | */ | 10 | */ |
11 | #include <linux/cpu_pm.h> | ||
11 | #include <linux/init.h> | 12 | #include <linux/init.h> |
12 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
13 | #include <linux/smp.h> | 14 | #include <linux/smp.h> |
@@ -25,28 +26,6 @@ | |||
25 | 26 | ||
26 | extern void build_tlb_refill_handler(void); | 27 | extern void build_tlb_refill_handler(void); |
27 | 28 | ||
28 | /* Atomicity and interruptability */ | ||
29 | #ifdef CONFIG_MIPS_MT_SMTC | ||
30 | |||
31 | #include <asm/smtc.h> | ||
32 | #include <asm/mipsmtregs.h> | ||
33 | |||
34 | #define ENTER_CRITICAL(flags) \ | ||
35 | { \ | ||
36 | unsigned int mvpflags; \ | ||
37 | local_irq_save(flags);\ | ||
38 | mvpflags = dvpe() | ||
39 | #define EXIT_CRITICAL(flags) \ | ||
40 | evpe(mvpflags); \ | ||
41 | local_irq_restore(flags); \ | ||
42 | } | ||
43 | #else | ||
44 | |||
45 | #define ENTER_CRITICAL(flags) local_irq_save(flags) | ||
46 | #define EXIT_CRITICAL(flags) local_irq_restore(flags) | ||
47 | |||
48 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
49 | |||
50 | /* | 29 | /* |
51 | * LOONGSON2/3 has a 4 entry itlb which is a subset of dtlb, | 30 | * LOONGSON2/3 has a 4 entry itlb which is a subset of dtlb, |
52 | * unfortunately, itlb is not totally transparent to software. | 31 | * unfortunately, itlb is not totally transparent to software. |
@@ -75,7 +54,7 @@ void local_flush_tlb_all(void) | |||
75 | unsigned long old_ctx; | 54 | unsigned long old_ctx; |
76 | int entry, ftlbhighset; | 55 | int entry, ftlbhighset; |
77 | 56 | ||
78 | ENTER_CRITICAL(flags); | 57 | local_irq_save(flags); |
79 | /* Save old context and create impossible VPN2 value */ | 58 | /* Save old context and create impossible VPN2 value */ |
80 | old_ctx = read_c0_entryhi(); | 59 | old_ctx = read_c0_entryhi(); |
81 | write_c0_entrylo0(0); | 60 | write_c0_entrylo0(0); |
@@ -112,7 +91,7 @@ void local_flush_tlb_all(void) | |||
112 | tlbw_use_hazard(); | 91 | tlbw_use_hazard(); |
113 | write_c0_entryhi(old_ctx); | 92 | write_c0_entryhi(old_ctx); |
114 | flush_itlb(); | 93 | flush_itlb(); |
115 | EXIT_CRITICAL(flags); | 94 | local_irq_restore(flags); |
116 | } | 95 | } |
117 | EXPORT_SYMBOL(local_flush_tlb_all); | 96 | EXPORT_SYMBOL(local_flush_tlb_all); |
118 | 97 | ||
@@ -142,7 +121,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | |||
142 | if (cpu_context(cpu, mm) != 0) { | 121 | if (cpu_context(cpu, mm) != 0) { |
143 | unsigned long size, flags; | 122 | unsigned long size, flags; |
144 | 123 | ||
145 | ENTER_CRITICAL(flags); | 124 | local_irq_save(flags); |
146 | start = round_down(start, PAGE_SIZE << 1); | 125 | start = round_down(start, PAGE_SIZE << 1); |
147 | end = round_up(end, PAGE_SIZE << 1); | 126 | end = round_up(end, PAGE_SIZE << 1); |
148 | size = (end - start) >> (PAGE_SHIFT + 1); | 127 | size = (end - start) >> (PAGE_SHIFT + 1); |
@@ -176,7 +155,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | |||
176 | drop_mmu_context(mm, cpu); | 155 | drop_mmu_context(mm, cpu); |
177 | } | 156 | } |
178 | flush_itlb(); | 157 | flush_itlb(); |
179 | EXIT_CRITICAL(flags); | 158 | local_irq_restore(flags); |
180 | } | 159 | } |
181 | } | 160 | } |
182 | 161 | ||
@@ -184,7 +163,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) | |||
184 | { | 163 | { |
185 | unsigned long size, flags; | 164 | unsigned long size, flags; |
186 | 165 | ||
187 | ENTER_CRITICAL(flags); | 166 | local_irq_save(flags); |
188 | size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; | 167 | size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; |
189 | size = (size + 1) >> 1; | 168 | size = (size + 1) >> 1; |
190 | if (size <= (current_cpu_data.tlbsizeftlbsets ? | 169 | if (size <= (current_cpu_data.tlbsizeftlbsets ? |
@@ -220,7 +199,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) | |||
220 | local_flush_tlb_all(); | 199 | local_flush_tlb_all(); |
221 | } | 200 | } |
222 | flush_itlb(); | 201 | flush_itlb(); |
223 | EXIT_CRITICAL(flags); | 202 | local_irq_restore(flags); |
224 | } | 203 | } |
225 | 204 | ||
226 | void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | 205 | void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) |
@@ -233,7 +212,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | |||
233 | 212 | ||
234 | newpid = cpu_asid(cpu, vma->vm_mm); | 213 | newpid = cpu_asid(cpu, vma->vm_mm); |
235 | page &= (PAGE_MASK << 1); | 214 | page &= (PAGE_MASK << 1); |
236 | ENTER_CRITICAL(flags); | 215 | local_irq_save(flags); |
237 | oldpid = read_c0_entryhi(); | 216 | oldpid = read_c0_entryhi(); |
238 | write_c0_entryhi(page | newpid); | 217 | write_c0_entryhi(page | newpid); |
239 | mtc0_tlbw_hazard(); | 218 | mtc0_tlbw_hazard(); |
@@ -253,7 +232,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | |||
253 | finish: | 232 | finish: |
254 | write_c0_entryhi(oldpid); | 233 | write_c0_entryhi(oldpid); |
255 | flush_itlb_vm(vma); | 234 | flush_itlb_vm(vma); |
256 | EXIT_CRITICAL(flags); | 235 | local_irq_restore(flags); |
257 | } | 236 | } |
258 | } | 237 | } |
259 | 238 | ||
@@ -266,7 +245,7 @@ void local_flush_tlb_one(unsigned long page) | |||
266 | unsigned long flags; | 245 | unsigned long flags; |
267 | int oldpid, idx; | 246 | int oldpid, idx; |
268 | 247 | ||
269 | ENTER_CRITICAL(flags); | 248 | local_irq_save(flags); |
270 | oldpid = read_c0_entryhi(); | 249 | oldpid = read_c0_entryhi(); |
271 | page &= (PAGE_MASK << 1); | 250 | page &= (PAGE_MASK << 1); |
272 | write_c0_entryhi(page); | 251 | write_c0_entryhi(page); |
@@ -285,7 +264,7 @@ void local_flush_tlb_one(unsigned long page) | |||
285 | } | 264 | } |
286 | write_c0_entryhi(oldpid); | 265 | write_c0_entryhi(oldpid); |
287 | flush_itlb(); | 266 | flush_itlb(); |
288 | EXIT_CRITICAL(flags); | 267 | local_irq_restore(flags); |
289 | } | 268 | } |
290 | 269 | ||
291 | /* | 270 | /* |
@@ -308,7 +287,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) | |||
308 | if (current->active_mm != vma->vm_mm) | 287 | if (current->active_mm != vma->vm_mm) |
309 | return; | 288 | return; |
310 | 289 | ||
311 | ENTER_CRITICAL(flags); | 290 | local_irq_save(flags); |
312 | 291 | ||
313 | pid = read_c0_entryhi() & ASID_MASK; | 292 | pid = read_c0_entryhi() & ASID_MASK; |
314 | address &= (PAGE_MASK << 1); | 293 | address &= (PAGE_MASK << 1); |
@@ -358,7 +337,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) | |||
358 | } | 337 | } |
359 | tlbw_use_hazard(); | 338 | tlbw_use_hazard(); |
360 | flush_itlb_vm(vma); | 339 | flush_itlb_vm(vma); |
361 | EXIT_CRITICAL(flags); | 340 | local_irq_restore(flags); |
362 | } | 341 | } |
363 | 342 | ||
364 | void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, | 343 | void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, |
@@ -369,7 +348,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, | |||
369 | unsigned long old_pagemask; | 348 | unsigned long old_pagemask; |
370 | unsigned long old_ctx; | 349 | unsigned long old_ctx; |
371 | 350 | ||
372 | ENTER_CRITICAL(flags); | 351 | local_irq_save(flags); |
373 | /* Save old context and create impossible VPN2 value */ | 352 | /* Save old context and create impossible VPN2 value */ |
374 | old_ctx = read_c0_entryhi(); | 353 | old_ctx = read_c0_entryhi(); |
375 | old_pagemask = read_c0_pagemask(); | 354 | old_pagemask = read_c0_pagemask(); |
@@ -389,7 +368,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, | |||
389 | tlbw_use_hazard(); /* What is the hazard here? */ | 368 | tlbw_use_hazard(); /* What is the hazard here? */ |
390 | write_c0_pagemask(old_pagemask); | 369 | write_c0_pagemask(old_pagemask); |
391 | local_flush_tlb_all(); | 370 | local_flush_tlb_all(); |
392 | EXIT_CRITICAL(flags); | 371 | local_irq_restore(flags); |
393 | } | 372 | } |
394 | 373 | ||
395 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 374 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
@@ -399,13 +378,13 @@ int __init has_transparent_hugepage(void) | |||
399 | unsigned int mask; | 378 | unsigned int mask; |
400 | unsigned long flags; | 379 | unsigned long flags; |
401 | 380 | ||
402 | ENTER_CRITICAL(flags); | 381 | local_irq_save(flags); |
403 | write_c0_pagemask(PM_HUGE_MASK); | 382 | write_c0_pagemask(PM_HUGE_MASK); |
404 | back_to_back_c0_hazard(); | 383 | back_to_back_c0_hazard(); |
405 | mask = read_c0_pagemask(); | 384 | mask = read_c0_pagemask(); |
406 | write_c0_pagemask(PM_DEFAULT_MASK); | 385 | write_c0_pagemask(PM_DEFAULT_MASK); |
407 | 386 | ||
408 | EXIT_CRITICAL(flags); | 387 | local_irq_restore(flags); |
409 | 388 | ||
410 | return mask == PM_HUGE_MASK; | 389 | return mask == PM_HUGE_MASK; |
411 | } | 390 | } |
@@ -421,7 +400,10 @@ static int __init set_ntlb(char *str) | |||
421 | 400 | ||
422 | __setup("ntlb=", set_ntlb); | 401 | __setup("ntlb=", set_ntlb); |
423 | 402 | ||
424 | void tlb_init(void) | 403 | /* |
404 | * Configure TLB (for init or after a CPU has been powered off). | ||
405 | */ | ||
406 | static void r4k_tlb_configure(void) | ||
425 | { | 407 | { |
426 | /* | 408 | /* |
427 | * You should never change this register: | 409 | * You should never change this register: |
@@ -453,6 +435,11 @@ void tlb_init(void) | |||
453 | local_flush_tlb_all(); | 435 | local_flush_tlb_all(); |
454 | 436 | ||
455 | /* Did I tell you that ARC SUCKS? */ | 437 | /* Did I tell you that ARC SUCKS? */ |
438 | } | ||
439 | |||
440 | void tlb_init(void) | ||
441 | { | ||
442 | r4k_tlb_configure(); | ||
456 | 443 | ||
457 | if (ntlb) { | 444 | if (ntlb) { |
458 | if (ntlb > 1 && ntlb <= current_cpu_data.tlbsize) { | 445 | if (ntlb > 1 && ntlb <= current_cpu_data.tlbsize) { |
@@ -466,3 +453,26 @@ void tlb_init(void) | |||
466 | 453 | ||
467 | build_tlb_refill_handler(); | 454 | build_tlb_refill_handler(); |
468 | } | 455 | } |
456 | |||
457 | static int r4k_tlb_pm_notifier(struct notifier_block *self, unsigned long cmd, | ||
458 | void *v) | ||
459 | { | ||
460 | switch (cmd) { | ||
461 | case CPU_PM_ENTER_FAILED: | ||
462 | case CPU_PM_EXIT: | ||
463 | r4k_tlb_configure(); | ||
464 | break; | ||
465 | } | ||
466 | |||
467 | return NOTIFY_OK; | ||
468 | } | ||
469 | |||
470 | static struct notifier_block r4k_tlb_pm_notifier_block = { | ||
471 | .notifier_call = r4k_tlb_pm_notifier, | ||
472 | }; | ||
473 | |||
474 | static int __init r4k_tlb_init_pm(void) | ||
475 | { | ||
476 | return cpu_pm_register_notifier(&r4k_tlb_pm_notifier_block); | ||
477 | } | ||
478 | arch_initcall(r4k_tlb_init_pm); | ||
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index f99ec587b151..e80e10bafc83 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -1256,7 +1256,7 @@ static void build_r4000_tlb_refill_handler(void) | |||
1256 | memset(relocs, 0, sizeof(relocs)); | 1256 | memset(relocs, 0, sizeof(relocs)); |
1257 | memset(final_handler, 0, sizeof(final_handler)); | 1257 | memset(final_handler, 0, sizeof(final_handler)); |
1258 | 1258 | ||
1259 | if ((scratch_reg >= 0 || scratchpad_available()) && use_bbit_insns()) { | 1259 | if (IS_ENABLED(CONFIG_64BIT) && (scratch_reg >= 0 || scratchpad_available()) && use_bbit_insns()) { |
1260 | htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1, | 1260 | htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1, |
1261 | scratch_reg); | 1261 | scratch_reg); |
1262 | vmalloc_mode = refill_scratch; | 1262 | vmalloc_mode = refill_scratch; |
diff --git a/arch/mips/mm/uasm-micromips.c b/arch/mips/mm/uasm-micromips.c index b8d580ca02e5..775c2800cba2 100644 --- a/arch/mips/mm/uasm-micromips.c +++ b/arch/mips/mm/uasm-micromips.c | |||
@@ -63,6 +63,7 @@ static struct insn insn_table_MM[] = { | |||
63 | { insn_cache, M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM }, | 63 | { insn_cache, M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM }, |
64 | { insn_daddu, 0, 0 }, | 64 | { insn_daddu, 0, 0 }, |
65 | { insn_daddiu, 0, 0 }, | 65 | { insn_daddiu, 0, 0 }, |
66 | { insn_divu, M(mm_pool32a_op, 0, 0, 0, mm_divu_op, mm_pool32axf_op), RT | RS }, | ||
66 | { insn_dmfc0, 0, 0 }, | 67 | { insn_dmfc0, 0, 0 }, |
67 | { insn_dmtc0, 0, 0 }, | 68 | { insn_dmtc0, 0, 0 }, |
68 | { insn_dsll, 0, 0 }, | 69 | { insn_dsll, 0, 0 }, |
@@ -78,14 +79,20 @@ static struct insn insn_table_MM[] = { | |||
78 | { insn_ext, M(mm_pool32a_op, 0, 0, 0, 0, mm_ext_op), RT | RS | RD | RE }, | 79 | { insn_ext, M(mm_pool32a_op, 0, 0, 0, 0, mm_ext_op), RT | RS | RD | RE }, |
79 | { insn_j, M(mm_j32_op, 0, 0, 0, 0, 0), JIMM }, | 80 | { insn_j, M(mm_j32_op, 0, 0, 0, 0, 0), JIMM }, |
80 | { insn_jal, M(mm_jal32_op, 0, 0, 0, 0, 0), JIMM }, | 81 | { insn_jal, M(mm_jal32_op, 0, 0, 0, 0, 0), JIMM }, |
82 | { insn_jalr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RT | RS }, | ||
81 | { insn_jr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS }, | 83 | { insn_jr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS }, |
84 | { insn_lb, M(mm_lb32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, | ||
82 | { insn_ld, 0, 0 }, | 85 | { insn_ld, 0, 0 }, |
86 | { insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RS | RS | SIMM }, | ||
83 | { insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM }, | 87 | { insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM }, |
84 | { insn_lld, 0, 0 }, | 88 | { insn_lld, 0, 0 }, |
85 | { insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM }, | 89 | { insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM }, |
86 | { insn_lw, M(mm_lw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, | 90 | { insn_lw, M(mm_lw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, |
87 | { insn_mfc0, M(mm_pool32a_op, 0, 0, 0, mm_mfc0_op, mm_pool32axf_op), RT | RS | RD }, | 91 | { insn_mfc0, M(mm_pool32a_op, 0, 0, 0, mm_mfc0_op, mm_pool32axf_op), RT | RS | RD }, |
92 | { insn_mfhi, M(mm_pool32a_op, 0, 0, 0, mm_mfhi32_op, mm_pool32axf_op), RS }, | ||
93 | { insn_mflo, M(mm_pool32a_op, 0, 0, 0, mm_mflo32_op, mm_pool32axf_op), RS }, | ||
88 | { insn_mtc0, M(mm_pool32a_op, 0, 0, 0, mm_mtc0_op, mm_pool32axf_op), RT | RS | RD }, | 94 | { insn_mtc0, M(mm_pool32a_op, 0, 0, 0, mm_mtc0_op, mm_pool32axf_op), RT | RS | RD }, |
95 | { insn_mul, M(mm_pool32a_op, 0, 0, 0, 0, mm_mul_op), RT | RS | RD }, | ||
89 | { insn_or, M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD }, | 96 | { insn_or, M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD }, |
90 | { insn_ori, M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM }, | 97 | { insn_ori, M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM }, |
91 | { insn_pref, M(mm_pool32c_op, 0, 0, (mm_pref_func << 1), 0, 0), RT | RS | SIMM }, | 98 | { insn_pref, M(mm_pool32c_op, 0, 0, (mm_pref_func << 1), 0, 0), RT | RS | SIMM }, |
@@ -94,15 +101,22 @@ static struct insn insn_table_MM[] = { | |||
94 | { insn_scd, 0, 0 }, | 101 | { insn_scd, 0, 0 }, |
95 | { insn_sd, 0, 0 }, | 102 | { insn_sd, 0, 0 }, |
96 | { insn_sll, M(mm_pool32a_op, 0, 0, 0, 0, mm_sll32_op), RT | RS | RD }, | 103 | { insn_sll, M(mm_pool32a_op, 0, 0, 0, 0, mm_sll32_op), RT | RS | RD }, |
104 | { insn_sllv, M(mm_pool32a_op, 0, 0, 0, 0, mm_sllv32_op), RT | RS | RD }, | ||
105 | { insn_sltiu, M(mm_sltiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, | ||
106 | { insn_sltu, M(mm_pool32a_op, 0, 0, 0, 0, mm_sltu_op), RT | RS | RD }, | ||
97 | { insn_sra, M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD }, | 107 | { insn_sra, M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD }, |
98 | { insn_srl, M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD }, | 108 | { insn_srl, M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD }, |
109 | { insn_srlv, M(mm_pool32a_op, 0, 0, 0, 0, mm_srlv32_op), RT | RS | RD }, | ||
99 | { insn_rotr, M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD }, | 110 | { insn_rotr, M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD }, |
100 | { insn_subu, M(mm_pool32a_op, 0, 0, 0, 0, mm_subu32_op), RT | RS | RD }, | 111 | { insn_subu, M(mm_pool32a_op, 0, 0, 0, 0, mm_subu32_op), RT | RS | RD }, |
101 | { insn_sw, M(mm_sw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, | 112 | { insn_sw, M(mm_sw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, |
113 | { insn_sync, M(mm_pool32a_op, 0, 0, 0, mm_sync_op, mm_pool32axf_op), RS }, | ||
102 | { insn_tlbp, M(mm_pool32a_op, 0, 0, 0, mm_tlbp_op, mm_pool32axf_op), 0 }, | 114 | { insn_tlbp, M(mm_pool32a_op, 0, 0, 0, mm_tlbp_op, mm_pool32axf_op), 0 }, |
103 | { insn_tlbr, M(mm_pool32a_op, 0, 0, 0, mm_tlbr_op, mm_pool32axf_op), 0 }, | 115 | { insn_tlbr, M(mm_pool32a_op, 0, 0, 0, mm_tlbr_op, mm_pool32axf_op), 0 }, |
104 | { insn_tlbwi, M(mm_pool32a_op, 0, 0, 0, mm_tlbwi_op, mm_pool32axf_op), 0 }, | 116 | { insn_tlbwi, M(mm_pool32a_op, 0, 0, 0, mm_tlbwi_op, mm_pool32axf_op), 0 }, |
105 | { insn_tlbwr, M(mm_pool32a_op, 0, 0, 0, mm_tlbwr_op, mm_pool32axf_op), 0 }, | 117 | { insn_tlbwr, M(mm_pool32a_op, 0, 0, 0, mm_tlbwr_op, mm_pool32axf_op), 0 }, |
118 | { insn_wait, M(mm_pool32a_op, 0, 0, 0, mm_wait_op, mm_pool32axf_op), SCIMM }, | ||
119 | { insn_wsbh, M(mm_pool32a_op, 0, 0, 0, mm_wsbh_op, mm_pool32axf_op), RT | RS }, | ||
106 | { insn_xor, M(mm_pool32a_op, 0, 0, 0, 0, mm_xor32_op), RT | RS | RD }, | 120 | { insn_xor, M(mm_pool32a_op, 0, 0, 0, 0, mm_xor32_op), RT | RS | RD }, |
107 | { insn_xori, M(mm_xori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM }, | 121 | { insn_xori, M(mm_xori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM }, |
108 | { insn_dins, 0, 0 }, | 122 | { insn_dins, 0, 0 }, |
diff --git a/arch/mips/mm/uasm-mips.c b/arch/mips/mm/uasm-mips.c index 3abd609518c9..38792c2364f5 100644 --- a/arch/mips/mm/uasm-mips.c +++ b/arch/mips/mm/uasm-mips.c | |||
@@ -67,6 +67,7 @@ static struct insn insn_table[] = { | |||
67 | { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD }, | 67 | { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD }, |
68 | { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE }, | 68 | { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE }, |
69 | { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE }, | 69 | { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE }, |
70 | { insn_divu, M(spec_op, 0, 0, 0, 0, divu_op), RS | RT }, | ||
70 | { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET}, | 71 | { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET}, |
71 | { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET}, | 72 | { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET}, |
72 | { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE }, | 73 | { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE }, |
@@ -82,17 +83,23 @@ static struct insn insn_table[] = { | |||
82 | { insn_ins, M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE }, | 83 | { insn_ins, M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE }, |
83 | { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, | 84 | { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, |
84 | { insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM }, | 85 | { insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM }, |
86 | { insn_jalr, M(spec_op, 0, 0, 0, 0, jalr_op), RS | RD }, | ||
85 | { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, | 87 | { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, |
86 | { insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS }, | 88 | { insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS }, |
89 | { insn_lb, M(lb_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | ||
87 | { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 90 | { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
88 | { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD }, | 91 | { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD }, |
92 | { insn_lh, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | ||
89 | { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 93 | { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
90 | { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 94 | { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
91 | { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM }, | 95 | { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM }, |
92 | { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 96 | { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
93 | { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD }, | 97 | { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD }, |
94 | { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET}, | 98 | { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET}, |
99 | { insn_mfhi, M(spec_op, 0, 0, 0, 0, mfhi_op), RD }, | ||
100 | { insn_mflo, M(spec_op, 0, 0, 0, 0, mflo_op), RD }, | ||
95 | { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET}, | 101 | { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET}, |
102 | { insn_mul, M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD}, | ||
96 | { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, | 103 | { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, |
97 | { insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD }, | 104 | { insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD }, |
98 | { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 105 | { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
@@ -102,17 +109,25 @@ static struct insn insn_table[] = { | |||
102 | { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 109 | { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
103 | { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 110 | { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
104 | { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE }, | 111 | { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE }, |
112 | { insn_sllv, M(spec_op, 0, 0, 0, 0, sllv_op), RS | RT | RD }, | ||
113 | { insn_sltiu, M(sltiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | ||
114 | { insn_sltu, M(spec_op, 0, 0, 0, 0, sltu_op), RS | RT | RD }, | ||
105 | { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE }, | 115 | { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE }, |
106 | { insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE }, | 116 | { insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE }, |
117 | { insn_srlv, M(spec_op, 0, 0, 0, 0, srlv_op), RS | RT | RD }, | ||
107 | { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD }, | 118 | { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD }, |
108 | { insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 119 | { insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
120 | { insn_sync, M(spec_op, 0, 0, 0, 0, sync_op), RE }, | ||
109 | { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, | 121 | { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, |
110 | { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 }, | 122 | { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 }, |
111 | { insn_tlbr, M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0 }, | 123 | { insn_tlbr, M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0 }, |
112 | { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 }, | 124 | { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 }, |
113 | { insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 }, | 125 | { insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 }, |
126 | { insn_wait, M(cop0_op, cop_op, 0, 0, 0, wait_op), SCIMM }, | ||
127 | { insn_wsbh, M(spec3_op, 0, 0, 0, wsbh_op, bshfl_op), RT | RD }, | ||
114 | { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, | 128 | { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, |
115 | { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, | 129 | { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, |
130 | { insn_yield, M(spec3_op, 0, 0, 0, 0, yield_op), RS | RD }, | ||
116 | { insn_invalid, 0, 0 } | 131 | { insn_invalid, 0, 0 } |
117 | }; | 132 | }; |
118 | 133 | ||
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index b9d14b6c7f58..00515805fe41 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c | |||
@@ -47,14 +47,16 @@ enum opcode { | |||
47 | insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1, | 47 | insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1, |
48 | insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, | 48 | insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, |
49 | insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm, | 49 | insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm, |
50 | insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll, | 50 | insn_divu, insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll, |
51 | insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret, | 51 | insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret, |
52 | insn_ext, insn_ins, insn_j, insn_jal, insn_jr, insn_ld, insn_ldx, | 52 | insn_ext, insn_ins, insn_j, insn_jal, insn_jalr, insn_jr, insn_lb, |
53 | insn_ll, insn_lld, insn_lui, insn_lw, insn_lwx, insn_mfc0, insn_mtc0, | 53 | insn_ld, insn_ldx, insn_lh, insn_ll, insn_lld, insn_lui, insn_lw, |
54 | insn_lwx, insn_mfc0, insn_mfhi, insn_mflo, insn_mtc0, insn_mul, | ||
54 | insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd, | 55 | insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd, |
55 | insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw, | 56 | insn_sd, insn_sll, insn_sllv, insn_sltiu, insn_sltu, insn_sra, |
56 | insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, | 57 | insn_srl, insn_srlv, insn_subu, insn_sw, insn_sync, insn_syscall, |
57 | insn_xori, | 58 | insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait, insn_wsbh, |
59 | insn_xor, insn_xori, insn_yield, | ||
58 | }; | 60 | }; |
59 | 61 | ||
60 | struct insn { | 62 | struct insn { |
@@ -144,6 +146,13 @@ Ip_u2u1u3(op) \ | |||
144 | } \ | 146 | } \ |
145 | UASM_EXPORT_SYMBOL(uasm_i##op); | 147 | UASM_EXPORT_SYMBOL(uasm_i##op); |
146 | 148 | ||
149 | #define I_u3u2u1(op) \ | ||
150 | Ip_u3u2u1(op) \ | ||
151 | { \ | ||
152 | build_insn(buf, insn##op, c, b, a); \ | ||
153 | } \ | ||
154 | UASM_EXPORT_SYMBOL(uasm_i##op); | ||
155 | |||
147 | #define I_u3u1u2(op) \ | 156 | #define I_u3u1u2(op) \ |
148 | Ip_u3u1u2(op) \ | 157 | Ip_u3u1u2(op) \ |
149 | { \ | 158 | { \ |
@@ -200,6 +209,13 @@ Ip_u1u2(op) \ | |||
200 | } \ | 209 | } \ |
201 | UASM_EXPORT_SYMBOL(uasm_i##op); | 210 | UASM_EXPORT_SYMBOL(uasm_i##op); |
202 | 211 | ||
212 | #define I_u2u1(op) \ | ||
213 | Ip_u1u2(op) \ | ||
214 | { \ | ||
215 | build_insn(buf, insn##op, b, a); \ | ||
216 | } \ | ||
217 | UASM_EXPORT_SYMBOL(uasm_i##op); | ||
218 | |||
203 | #define I_u1s2(op) \ | 219 | #define I_u1s2(op) \ |
204 | Ip_u1s2(op) \ | 220 | Ip_u1s2(op) \ |
205 | { \ | 221 | { \ |
@@ -237,6 +253,7 @@ I_u1u2u3(_dmfc0) | |||
237 | I_u1u2u3(_dmtc0) | 253 | I_u1u2u3(_dmtc0) |
238 | I_u2u1s3(_daddiu) | 254 | I_u2u1s3(_daddiu) |
239 | I_u3u1u2(_daddu) | 255 | I_u3u1u2(_daddu) |
256 | I_u1u2(_divu) | ||
240 | I_u2u1u3(_dsll) | 257 | I_u2u1u3(_dsll) |
241 | I_u2u1u3(_dsll32) | 258 | I_u2u1u3(_dsll32) |
242 | I_u2u1u3(_dsra) | 259 | I_u2u1u3(_dsra) |
@@ -250,14 +267,20 @@ I_u2u1msbdu3(_ext) | |||
250 | I_u2u1msbu3(_ins) | 267 | I_u2u1msbu3(_ins) |
251 | I_u1(_j) | 268 | I_u1(_j) |
252 | I_u1(_jal) | 269 | I_u1(_jal) |
270 | I_u2u1(_jalr) | ||
253 | I_u1(_jr) | 271 | I_u1(_jr) |
272 | I_u2s3u1(_lb) | ||
254 | I_u2s3u1(_ld) | 273 | I_u2s3u1(_ld) |
274 | I_u2s3u1(_lh) | ||
255 | I_u2s3u1(_ll) | 275 | I_u2s3u1(_ll) |
256 | I_u2s3u1(_lld) | 276 | I_u2s3u1(_lld) |
257 | I_u1s2(_lui) | 277 | I_u1s2(_lui) |
258 | I_u2s3u1(_lw) | 278 | I_u2s3u1(_lw) |
259 | I_u1u2u3(_mfc0) | 279 | I_u1u2u3(_mfc0) |
280 | I_u1(_mfhi) | ||
281 | I_u1(_mflo) | ||
260 | I_u1u2u3(_mtc0) | 282 | I_u1u2u3(_mtc0) |
283 | I_u3u1u2(_mul) | ||
261 | I_u2u1u3(_ori) | 284 | I_u2u1u3(_ori) |
262 | I_u3u1u2(_or) | 285 | I_u3u1u2(_or) |
263 | I_0(_rfe) | 286 | I_0(_rfe) |
@@ -265,17 +288,25 @@ I_u2s3u1(_sc) | |||
265 | I_u2s3u1(_scd) | 288 | I_u2s3u1(_scd) |
266 | I_u2s3u1(_sd) | 289 | I_u2s3u1(_sd) |
267 | I_u2u1u3(_sll) | 290 | I_u2u1u3(_sll) |
291 | I_u3u2u1(_sllv) | ||
292 | I_u2u1s3(_sltiu) | ||
293 | I_u3u1u2(_sltu) | ||
268 | I_u2u1u3(_sra) | 294 | I_u2u1u3(_sra) |
269 | I_u2u1u3(_srl) | 295 | I_u2u1u3(_srl) |
296 | I_u3u2u1(_srlv) | ||
270 | I_u2u1u3(_rotr) | 297 | I_u2u1u3(_rotr) |
271 | I_u3u1u2(_subu) | 298 | I_u3u1u2(_subu) |
272 | I_u2s3u1(_sw) | 299 | I_u2s3u1(_sw) |
300 | I_u1(_sync) | ||
273 | I_0(_tlbp) | 301 | I_0(_tlbp) |
274 | I_0(_tlbr) | 302 | I_0(_tlbr) |
275 | I_0(_tlbwi) | 303 | I_0(_tlbwi) |
276 | I_0(_tlbwr) | 304 | I_0(_tlbwr) |
305 | I_u1(_wait); | ||
306 | I_u2u1(_wsbh) | ||
277 | I_u3u1u2(_xor) | 307 | I_u3u1u2(_xor) |
278 | I_u2u1u3(_xori) | 308 | I_u2u1u3(_xori) |
309 | I_u2u1(_yield) | ||
279 | I_u2u1msbu3(_dins); | 310 | I_u2u1msbu3(_dins); |
280 | I_u2u1msb32u3(_dinsm); | 311 | I_u2u1msb32u3(_dinsm); |
281 | I_u1(_syscall); | 312 | I_u1(_syscall); |
@@ -469,6 +500,14 @@ void ISAFUNC(uasm_il_b)(u32 **p, struct uasm_reloc **r, int lid) | |||
469 | } | 500 | } |
470 | UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_b)); | 501 | UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_b)); |
471 | 502 | ||
503 | void ISAFUNC(uasm_il_beq)(u32 **p, struct uasm_reloc **r, unsigned int r1, | ||
504 | unsigned int r2, int lid) | ||
505 | { | ||
506 | uasm_r_mips_pc16(r, *p, lid); | ||
507 | ISAFUNC(uasm_i_beq)(p, r1, r2, 0); | ||
508 | } | ||
509 | UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beq)); | ||
510 | |||
472 | void ISAFUNC(uasm_il_beqz)(u32 **p, struct uasm_reloc **r, unsigned int reg, | 511 | void ISAFUNC(uasm_il_beqz)(u32 **p, struct uasm_reloc **r, unsigned int reg, |
473 | int lid) | 512 | int lid) |
474 | { | 513 | { |
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile index eae0ba3876d9..b9510ea8db56 100644 --- a/arch/mips/mti-malta/Makefile +++ b/arch/mips/mti-malta/Makefile | |||
@@ -9,5 +9,4 @@ obj-y := malta-amon.o malta-display.o malta-init.o \ | |||
9 | malta-int.o malta-memory.o malta-platform.o \ | 9 | malta-int.o malta-memory.o malta-platform.o \ |
10 | malta-reset.o malta-setup.o malta-time.o | 10 | malta-reset.o malta-setup.o malta-time.o |
11 | 11 | ||
12 | # FIXME FIXME FIXME | 12 | obj-$(CONFIG_MIPS_MALTA_PM) += malta-pm.o |
13 | obj-$(CONFIG_MIPS_MT_SMTC) += malta-smtc.o | ||
diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index 4f9e44d358b7..0f60256d3784 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c | |||
@@ -116,8 +116,6 @@ phys_t mips_cpc_default_phys_base(void) | |||
116 | return CPC_BASE_ADDR; | 116 | return CPC_BASE_ADDR; |
117 | } | 117 | } |
118 | 118 | ||
119 | extern struct plat_smp_ops msmtc_smp_ops; | ||
120 | |||
121 | void __init prom_init(void) | 119 | void __init prom_init(void) |
122 | { | 120 | { |
123 | mips_display_message("LINUX"); | 121 | mips_display_message("LINUX"); |
@@ -304,8 +302,4 @@ mips_pci_controller: | |||
304 | return; | 302 | return; |
305 | if (!register_vsmp_smp_ops()) | 303 | if (!register_vsmp_smp_ops()) |
306 | return; | 304 | return; |
307 | |||
308 | #ifdef CONFIG_MIPS_MT_SMTC | ||
309 | register_smp_ops(&msmtc_smp_ops); | ||
310 | #endif | ||
311 | } | 305 | } |
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index b71ee809191a..ecc2785f7858 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c | |||
@@ -504,28 +504,9 @@ void __init arch_init_irq(void) | |||
504 | } else if (cpu_has_vint) { | 504 | } else if (cpu_has_vint) { |
505 | set_vi_handler(MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); | 505 | set_vi_handler(MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); |
506 | set_vi_handler(MIPSCPU_INT_COREHI, corehi_irqdispatch); | 506 | set_vi_handler(MIPSCPU_INT_COREHI, corehi_irqdispatch); |
507 | #ifdef CONFIG_MIPS_MT_SMTC | ||
508 | setup_irq_smtc(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq, | ||
509 | (0x100 << MIPSCPU_INT_I8259A)); | ||
510 | setup_irq_smtc(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, | ||
511 | &corehi_irqaction, (0x100 << MIPSCPU_INT_COREHI)); | ||
512 | /* | ||
513 | * Temporary hack to ensure that the subsidiary device | ||
514 | * interrupts coing in via the i8259A, but associated | ||
515 | * with low IRQ numbers, will restore the Status.IM | ||
516 | * value associated with the i8259A. | ||
517 | */ | ||
518 | { | ||
519 | int i; | ||
520 | |||
521 | for (i = 0; i < 16; i++) | ||
522 | irq_hwmask[i] = (0x100 << MIPSCPU_INT_I8259A); | ||
523 | } | ||
524 | #else /* Not SMTC */ | ||
525 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); | 507 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); |
526 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, | 508 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, |
527 | &corehi_irqaction); | 509 | &corehi_irqaction); |
528 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
529 | } else { | 510 | } else { |
530 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); | 511 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); |
531 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, | 512 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, |
diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c index f2364e419682..6d9773096750 100644 --- a/arch/mips/mti-malta/malta-memory.c +++ b/arch/mips/mti-malta/malta-memory.c | |||
@@ -26,8 +26,8 @@ unsigned long physical_memsize = 0L; | |||
26 | 26 | ||
27 | fw_memblock_t * __init fw_getmdesc(int eva) | 27 | fw_memblock_t * __init fw_getmdesc(int eva) |
28 | { | 28 | { |
29 | char *memsize_str, *ememsize_str __maybe_unused = NULL, *ptr; | 29 | char *memsize_str, *ememsize_str = NULL, *ptr; |
30 | unsigned long memsize = 0, ememsize __maybe_unused = 0; | 30 | unsigned long memsize = 0, ememsize = 0; |
31 | static char cmdline[COMMAND_LINE_SIZE] __initdata; | 31 | static char cmdline[COMMAND_LINE_SIZE] __initdata; |
32 | int tmp; | 32 | int tmp; |
33 | 33 | ||
diff --git a/arch/mips/mti-malta/malta-pm.c b/arch/mips/mti-malta/malta-pm.c new file mode 100644 index 000000000000..c1e456c01a44 --- /dev/null +++ b/arch/mips/mti-malta/malta-pm.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Imagination Technologies | ||
3 | * Author: Paul Burton <paul.burton@imgtec.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <linux/delay.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/pci.h> | ||
15 | |||
16 | #include <asm/mach-malta/malta-pm.h> | ||
17 | |||
18 | static struct pci_bus *pm_pci_bus; | ||
19 | static resource_size_t pm_io_offset; | ||
20 | |||
21 | int mips_pm_suspend(unsigned state) | ||
22 | { | ||
23 | int spec_devid; | ||
24 | u16 sts; | ||
25 | |||
26 | if (!pm_pci_bus || !pm_io_offset) | ||
27 | return -ENODEV; | ||
28 | |||
29 | /* Ensure the power button status is clear */ | ||
30 | while (1) { | ||
31 | sts = inw(pm_io_offset + PIIX4_FUNC3IO_PMSTS); | ||
32 | if (!(sts & PIIX4_FUNC3IO_PMSTS_PWRBTN_STS)) | ||
33 | break; | ||
34 | outw(sts, pm_io_offset + PIIX4_FUNC3IO_PMSTS); | ||
35 | } | ||
36 | |||
37 | /* Enable entry to suspend */ | ||
38 | outw(state | PIIX4_FUNC3IO_PMCNTRL_SUS_EN, | ||
39 | pm_io_offset + PIIX4_FUNC3IO_PMCNTRL); | ||
40 | |||
41 | /* If the special cycle occurs too soon this doesn't work... */ | ||
42 | mdelay(10); | ||
43 | |||
44 | /* | ||
45 | * The PIIX4 will enter the suspend state only after seeing a special | ||
46 | * cycle with the correct magic data on the PCI bus. Generate that | ||
47 | * cycle now. | ||
48 | */ | ||
49 | spec_devid = PCI_DEVID(0, PCI_DEVFN(0x1f, 0x7)); | ||
50 | pci_bus_write_config_dword(pm_pci_bus, spec_devid, 0, | ||
51 | PIIX4_SUSPEND_MAGIC); | ||
52 | |||
53 | /* Give the system some time to power down */ | ||
54 | mdelay(1000); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int __init malta_pm_setup(void) | ||
60 | { | ||
61 | struct pci_dev *dev; | ||
62 | int res, io_region = PCI_BRIDGE_RESOURCES; | ||
63 | |||
64 | /* Find a reference to the PCI bus */ | ||
65 | pm_pci_bus = pci_find_next_bus(NULL); | ||
66 | if (!pm_pci_bus) { | ||
67 | pr_warn("malta-pm: failed to find reference to PCI bus\n"); | ||
68 | return -ENODEV; | ||
69 | } | ||
70 | |||
71 | /* Find the PIIX4 PM device */ | ||
72 | dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, | ||
73 | PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, | ||
74 | PCI_ANY_ID, NULL); | ||
75 | if (!dev) { | ||
76 | pr_warn("malta-pm: failed to find PIIX4 PM\n"); | ||
77 | return -ENODEV; | ||
78 | } | ||
79 | |||
80 | /* Request access to the PIIX4 PM IO registers */ | ||
81 | res = pci_request_region(dev, io_region, "PIIX4 PM IO registers"); | ||
82 | if (res) { | ||
83 | pr_warn("malta-pm: failed to request PM IO registers (%d)\n", | ||
84 | res); | ||
85 | pci_dev_put(dev); | ||
86 | return -ENODEV; | ||
87 | } | ||
88 | |||
89 | /* Find the offset to the PIIX4 PM IO registers */ | ||
90 | pm_io_offset = pci_resource_start(dev, io_region); | ||
91 | |||
92 | pci_dev_put(dev); | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | late_initcall(malta_pm_setup); | ||
diff --git a/arch/mips/mti-malta/malta-reset.c b/arch/mips/mti-malta/malta-reset.c index d627d4b2b47f..2fd2cc2c5034 100644 --- a/arch/mips/mti-malta/malta-reset.c +++ b/arch/mips/mti-malta/malta-reset.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/pm.h> | 10 | #include <linux/pm.h> |
11 | 11 | ||
12 | #include <asm/reboot.h> | 12 | #include <asm/reboot.h> |
13 | #include <asm/mach-malta/malta-pm.h> | ||
13 | 14 | ||
14 | #define SOFTRES_REG 0x1f000500 | 15 | #define SOFTRES_REG 0x1f000500 |
15 | #define GORESET 0x42 | 16 | #define GORESET 0x42 |
@@ -24,17 +25,22 @@ static void mips_machine_restart(char *command) | |||
24 | 25 | ||
25 | static void mips_machine_halt(void) | 26 | static void mips_machine_halt(void) |
26 | { | 27 | { |
27 | unsigned int __iomem *softres_reg = | 28 | while (true); |
28 | ioremap(SOFTRES_REG, sizeof(unsigned int)); | 29 | } |
29 | 30 | ||
30 | __raw_writel(GORESET, softres_reg); | 31 | static void mips_machine_power_off(void) |
32 | { | ||
33 | mips_pm_suspend(PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_SOFF); | ||
34 | |||
35 | pr_info("Failed to power down, resetting\n"); | ||
36 | mips_machine_restart(NULL); | ||
31 | } | 37 | } |
32 | 38 | ||
33 | static int __init mips_reboot_setup(void) | 39 | static int __init mips_reboot_setup(void) |
34 | { | 40 | { |
35 | _machine_restart = mips_machine_restart; | 41 | _machine_restart = mips_machine_restart; |
36 | _machine_halt = mips_machine_halt; | 42 | _machine_halt = mips_machine_halt; |
37 | pm_power_off = mips_machine_halt; | 43 | pm_power_off = mips_machine_power_off; |
38 | 44 | ||
39 | return 0; | 45 | return 0; |
40 | } | 46 | } |
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c index bf621516afff..db7c9e5826a6 100644 --- a/arch/mips/mti-malta/malta-setup.c +++ b/arch/mips/mti-malta/malta-setup.c | |||
@@ -77,11 +77,7 @@ const char *get_system_type(void) | |||
77 | return "MIPS Malta"; | 77 | return "MIPS Malta"; |
78 | } | 78 | } |
79 | 79 | ||
80 | #if defined(CONFIG_MIPS_MT_SMTC) | ||
81 | const char display_string[] = " SMTC LINUX ON MALTA "; | ||
82 | #else | ||
83 | const char display_string[] = " LINUX ON MALTA "; | 80 | const char display_string[] = " LINUX ON MALTA "; |
84 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
85 | 81 | ||
86 | #ifdef CONFIG_BLK_DEV_FD | 82 | #ifdef CONFIG_BLK_DEV_FD |
87 | static void __init fd_activate(void) | 83 | static void __init fd_activate(void) |
diff --git a/arch/mips/mti-malta/malta-smtc.c b/arch/mips/mti-malta/malta-smtc.c deleted file mode 100644 index c4849904f013..000000000000 --- a/arch/mips/mti-malta/malta-smtc.c +++ /dev/null | |||
@@ -1,162 +0,0 @@ | |||
1 | /* | ||
2 | * Malta Platform-specific hooks for SMP operation | ||
3 | */ | ||
4 | #include <linux/irq.h> | ||
5 | #include <linux/init.h> | ||
6 | |||
7 | #include <asm/mipsregs.h> | ||
8 | #include <asm/mipsmtregs.h> | ||
9 | #include <asm/smtc.h> | ||
10 | #include <asm/smtc_ipi.h> | ||
11 | |||
12 | /* VPE/SMP Prototype implements platform interfaces directly */ | ||
13 | |||
14 | /* | ||
15 | * Cause the specified action to be performed on a targeted "CPU" | ||
16 | */ | ||
17 | |||
18 | static void msmtc_send_ipi_single(int cpu, unsigned int action) | ||
19 | { | ||
20 | /* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */ | ||
21 | smtc_send_ipi(cpu, LINUX_SMP_IPI, action); | ||
22 | } | ||
23 | |||
24 | static void msmtc_send_ipi_mask(const struct cpumask *mask, unsigned int action) | ||
25 | { | ||
26 | unsigned int i; | ||
27 | |||
28 | for_each_cpu(i, mask) | ||
29 | msmtc_send_ipi_single(i, action); | ||
30 | } | ||
31 | |||
32 | /* | ||
33 | * Post-config but pre-boot cleanup entry point | ||
34 | */ | ||
35 | static void msmtc_init_secondary(void) | ||
36 | { | ||
37 | int myvpe; | ||
38 | |||
39 | /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */ | ||
40 | myvpe = read_c0_tcbind() & TCBIND_CURVPE; | ||
41 | if (myvpe != 0) { | ||
42 | /* Ideally, this should be done only once per VPE, but... */ | ||
43 | clear_c0_status(ST0_IM); | ||
44 | set_c0_status((0x100 << cp0_compare_irq) | ||
45 | | (0x100 << MIPS_CPU_IPI_IRQ)); | ||
46 | if (cp0_perfcount_irq >= 0) | ||
47 | set_c0_status(0x100 << cp0_perfcount_irq); | ||
48 | } | ||
49 | |||
50 | smtc_init_secondary(); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * Platform "CPU" startup hook | ||
55 | */ | ||
56 | static void msmtc_boot_secondary(int cpu, struct task_struct *idle) | ||
57 | { | ||
58 | smtc_boot_secondary(cpu, idle); | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * SMP initialization finalization entry point | ||
63 | */ | ||
64 | static void msmtc_smp_finish(void) | ||
65 | { | ||
66 | smtc_smp_finish(); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Hook for after all CPUs are online | ||
71 | */ | ||
72 | |||
73 | static void msmtc_cpus_done(void) | ||
74 | { | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Platform SMP pre-initialization | ||
79 | * | ||
80 | * As noted above, we can assume a single CPU for now | ||
81 | * but it may be multithreaded. | ||
82 | */ | ||
83 | |||
84 | static void __init msmtc_smp_setup(void) | ||
85 | { | ||
86 | /* | ||
87 | * we won't get the definitive value until | ||
88 | * we've run smtc_prepare_cpus later, but | ||
89 | * we would appear to need an upper bound now. | ||
90 | */ | ||
91 | smp_num_siblings = smtc_build_cpu_map(0); | ||
92 | } | ||
93 | |||
94 | static void __init msmtc_prepare_cpus(unsigned int max_cpus) | ||
95 | { | ||
96 | smtc_prepare_cpus(max_cpus); | ||
97 | } | ||
98 | |||
99 | struct plat_smp_ops msmtc_smp_ops = { | ||
100 | .send_ipi_single = msmtc_send_ipi_single, | ||
101 | .send_ipi_mask = msmtc_send_ipi_mask, | ||
102 | .init_secondary = msmtc_init_secondary, | ||
103 | .smp_finish = msmtc_smp_finish, | ||
104 | .cpus_done = msmtc_cpus_done, | ||
105 | .boot_secondary = msmtc_boot_secondary, | ||
106 | .smp_setup = msmtc_smp_setup, | ||
107 | .prepare_cpus = msmtc_prepare_cpus, | ||
108 | }; | ||
109 | |||
110 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | ||
111 | /* | ||
112 | * IRQ affinity hook | ||
113 | */ | ||
114 | |||
115 | |||
116 | int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, | ||
117 | bool force) | ||
118 | { | ||
119 | cpumask_t tmask; | ||
120 | int cpu = 0; | ||
121 | void smtc_set_irq_affinity(unsigned int irq, cpumask_t aff); | ||
122 | |||
123 | /* | ||
124 | * On the legacy Malta development board, all I/O interrupts | ||
125 | * are routed through the 8259 and combined in a single signal | ||
126 | * to the CPU daughterboard, and on the CoreFPGA2/3 34K models, | ||
127 | * that signal is brought to IP2 of both VPEs. To avoid racing | ||
128 | * concurrent interrupt service events, IP2 is enabled only on | ||
129 | * one VPE, by convention VPE0. So long as no bits are ever | ||
130 | * cleared in the affinity mask, there will never be any | ||
131 | * interrupt forwarding. But as soon as a program or operator | ||
132 | * sets affinity for one of the related IRQs, we need to make | ||
133 | * sure that we don't ever try to forward across the VPE boundary, | ||
134 | * at least not until we engineer a system where the interrupt | ||
135 | * _ack() or _end() function can somehow know that it corresponds | ||
136 | * to an interrupt taken on another VPE, and perform the appropriate | ||
137 | * restoration of Status.IM state using MFTR/MTTR instead of the | ||
138 | * normal local behavior. We also ensure that no attempt will | ||
139 | * be made to forward to an offline "CPU". | ||
140 | */ | ||
141 | |||
142 | cpumask_copy(&tmask, affinity); | ||
143 | for_each_cpu(cpu, affinity) { | ||
144 | if ((cpu_data[cpu].vpe_id != 0) || !cpu_online(cpu)) | ||
145 | cpu_clear(cpu, tmask); | ||
146 | } | ||
147 | cpumask_copy(d->affinity, &tmask); | ||
148 | |||
149 | if (cpus_empty(tmask)) | ||
150 | /* | ||
151 | * We could restore a default mask here, but the | ||
152 | * runtime code can anyway deal with the null set | ||
153 | */ | ||
154 | printk(KERN_WARNING | ||
155 | "IRQ affinity leaves no legal CPU for IRQ %d\n", d->irq); | ||
156 | |||
157 | /* Do any generic SMTC IRQ affinity setup */ | ||
158 | smtc_set_irq_affinity(d->irq, tmask); | ||
159 | |||
160 | return IRQ_SET_MASK_OK_NOCOPY; | ||
161 | } | ||
162 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | ||
diff --git a/arch/mips/mti-sead3/sead3-pic32-i2c-drv.c b/arch/mips/mti-sead3/sead3-pic32-i2c-drv.c index b921e5ec507c..80fe194cfa53 100644 --- a/arch/mips/mti-sead3/sead3-pic32-i2c-drv.c +++ b/arch/mips/mti-sead3/sead3-pic32-i2c-drv.c | |||
@@ -312,16 +312,13 @@ static int i2c_platform_probe(struct platform_device *pdev) | |||
312 | 312 | ||
313 | pr_debug("i2c_platform_probe\n"); | 313 | pr_debug("i2c_platform_probe\n"); |
314 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 314 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
315 | if (!r) { | 315 | if (!r) |
316 | ret = -ENODEV; | 316 | return -ENODEV; |
317 | goto out; | ||
318 | } | ||
319 | 317 | ||
320 | priv = kzalloc(sizeof(struct i2c_platform_data), GFP_KERNEL); | 318 | priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_platform_data), |
321 | if (!priv) { | 319 | GFP_KERNEL); |
322 | ret = -ENOMEM; | 320 | if (!priv) |
323 | goto out; | 321 | return -ENOMEM; |
324 | } | ||
325 | 322 | ||
326 | /* FIXME: need to allocate resource in PIC32 space */ | 323 | /* FIXME: need to allocate resource in PIC32 space */ |
327 | #if 0 | 324 | #if 0 |
@@ -330,10 +327,8 @@ static int i2c_platform_probe(struct platform_device *pdev) | |||
330 | #else | 327 | #else |
331 | priv->base = r->start; | 328 | priv->base = r->start; |
332 | #endif | 329 | #endif |
333 | if (!priv->base) { | 330 | if (!priv->base) |
334 | ret = -EBUSY; | 331 | return -EBUSY; |
335 | goto out_mem; | ||
336 | } | ||
337 | 332 | ||
338 | priv->xfer_timeout = 200; | 333 | priv->xfer_timeout = 200; |
339 | priv->ack_timeout = 200; | 334 | priv->ack_timeout = 200; |
@@ -348,17 +343,13 @@ static int i2c_platform_probe(struct platform_device *pdev) | |||
348 | i2c_platform_setup(priv); | 343 | i2c_platform_setup(priv); |
349 | 344 | ||
350 | ret = i2c_add_numbered_adapter(&priv->adap); | 345 | ret = i2c_add_numbered_adapter(&priv->adap); |
351 | if (ret == 0) { | 346 | if (ret) { |
352 | platform_set_drvdata(pdev, priv); | 347 | i2c_platform_disable(priv); |
353 | return 0; | 348 | return ret; |
354 | } | 349 | } |
355 | 350 | ||
356 | i2c_platform_disable(priv); | 351 | platform_set_drvdata(pdev, priv); |
357 | 352 | return 0; | |
358 | out_mem: | ||
359 | kfree(priv); | ||
360 | out: | ||
361 | return ret; | ||
362 | } | 353 | } |
363 | 354 | ||
364 | static int i2c_platform_remove(struct platform_device *pdev) | 355 | static int i2c_platform_remove(struct platform_device *pdev) |
@@ -369,7 +360,6 @@ static int i2c_platform_remove(struct platform_device *pdev) | |||
369 | platform_set_drvdata(pdev, NULL); | 360 | platform_set_drvdata(pdev, NULL); |
370 | i2c_del_adapter(&priv->adap); | 361 | i2c_del_adapter(&priv->adap); |
371 | i2c_platform_disable(priv); | 362 | i2c_platform_disable(priv); |
372 | kfree(priv); | ||
373 | return 0; | 363 | return 0; |
374 | } | 364 | } |
375 | 365 | ||
diff --git a/arch/mips/net/Makefile b/arch/mips/net/Makefile new file mode 100644 index 000000000000..ae74b3a91f5c --- /dev/null +++ b/arch/mips/net/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | # MIPS networking code | ||
2 | |||
3 | obj-$(CONFIG_BPF_JIT) += bpf_jit.o | ||
diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c new file mode 100644 index 000000000000..a67b9753330b --- /dev/null +++ b/arch/mips/net/bpf_jit.c | |||
@@ -0,0 +1,1399 @@ | |||
1 | /* | ||
2 | * Just-In-Time compiler for BPF filters on MIPS | ||
3 | * | ||
4 | * Copyright (c) 2014 Imagination Technologies Ltd. | ||
5 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
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 as published by the | ||
9 | * Free Software Foundation; version 2 of the License. | ||
10 | */ | ||
11 | |||
12 | #include <linux/bitops.h> | ||
13 | #include <linux/compiler.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/filter.h> | ||
16 | #include <linux/if_vlan.h> | ||
17 | #include <linux/kconfig.h> | ||
18 | #include <linux/moduleloader.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <asm/bitops.h> | ||
24 | #include <asm/cacheflush.h> | ||
25 | #include <asm/cpu-features.h> | ||
26 | #include <asm/uasm.h> | ||
27 | |||
28 | #include "bpf_jit.h" | ||
29 | |||
30 | /* ABI | ||
31 | * | ||
32 | * s0 1st scratch register | ||
33 | * s1 2nd scratch register | ||
34 | * s2 offset register | ||
35 | * s3 BPF register A | ||
36 | * s4 BPF register X | ||
37 | * s5 *skb | ||
38 | * s6 *scratch memory | ||
39 | * | ||
40 | * On entry (*bpf_func)(*skb, *filter) | ||
41 | * a0 = MIPS_R_A0 = skb; | ||
42 | * a1 = MIPS_R_A1 = filter; | ||
43 | * | ||
44 | * Stack | ||
45 | * ... | ||
46 | * M[15] | ||
47 | * M[14] | ||
48 | * M[13] | ||
49 | * ... | ||
50 | * M[0] <-- r_M | ||
51 | * saved reg k-1 | ||
52 | * saved reg k-2 | ||
53 | * ... | ||
54 | * saved reg 0 <-- r_sp | ||
55 | * <no argument area> | ||
56 | * | ||
57 | * Packet layout | ||
58 | * | ||
59 | * <--------------------- len ------------------------> | ||
60 | * <--skb-len(r_skb_hl)-->< ----- skb->data_len ------> | ||
61 | * ---------------------------------------------------- | ||
62 | * | skb->data | | ||
63 | * ---------------------------------------------------- | ||
64 | */ | ||
65 | |||
66 | #define RSIZE (sizeof(unsigned long)) | ||
67 | #define ptr typeof(unsigned long) | ||
68 | |||
69 | /* ABI specific return values */ | ||
70 | #ifdef CONFIG_32BIT /* O32 */ | ||
71 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
72 | #define r_err MIPS_R_V1 | ||
73 | #define r_val MIPS_R_V0 | ||
74 | #else /* CONFIG_CPU_LITTLE_ENDIAN */ | ||
75 | #define r_err MIPS_R_V0 | ||
76 | #define r_val MIPS_R_V1 | ||
77 | #endif | ||
78 | #else /* N64 */ | ||
79 | #define r_err MIPS_R_V0 | ||
80 | #define r_val MIPS_R_V0 | ||
81 | #endif | ||
82 | |||
83 | #define r_ret MIPS_R_V0 | ||
84 | |||
85 | /* | ||
86 | * Use 2 scratch registers to avoid pipeline interlocks. | ||
87 | * There is no overhead during epilogue and prologue since | ||
88 | * any of the $s0-$s6 registers will only be preserved if | ||
89 | * they are going to actually be used. | ||
90 | */ | ||
91 | #define r_s0 MIPS_R_S0 /* scratch reg 1 */ | ||
92 | #define r_s1 MIPS_R_S1 /* scratch reg 2 */ | ||
93 | #define r_off MIPS_R_S2 | ||
94 | #define r_A MIPS_R_S3 | ||
95 | #define r_X MIPS_R_S4 | ||
96 | #define r_skb MIPS_R_S5 | ||
97 | #define r_M MIPS_R_S6 | ||
98 | #define r_tmp_imm MIPS_R_T6 /* No need to preserve this */ | ||
99 | #define r_tmp MIPS_R_T7 /* No need to preserve this */ | ||
100 | #define r_zero MIPS_R_ZERO | ||
101 | #define r_sp MIPS_R_SP | ||
102 | #define r_ra MIPS_R_RA | ||
103 | |||
104 | #define SCRATCH_OFF(k) (4 * (k)) | ||
105 | |||
106 | /* JIT flags */ | ||
107 | #define SEEN_CALL (1 << BPF_MEMWORDS) | ||
108 | #define SEEN_SREG_SFT (BPF_MEMWORDS + 1) | ||
109 | #define SEEN_SREG_BASE (1 << SEEN_SREG_SFT) | ||
110 | #define SEEN_SREG(x) (SEEN_SREG_BASE << (x)) | ||
111 | #define SEEN_S0 SEEN_SREG(0) | ||
112 | #define SEEN_S1 SEEN_SREG(1) | ||
113 | #define SEEN_OFF SEEN_SREG(2) | ||
114 | #define SEEN_A SEEN_SREG(3) | ||
115 | #define SEEN_X SEEN_SREG(4) | ||
116 | #define SEEN_SKB SEEN_SREG(5) | ||
117 | #define SEEN_MEM SEEN_SREG(6) | ||
118 | |||
119 | /* Arguments used by JIT */ | ||
120 | #define ARGS_USED_BY_JIT 2 /* only applicable to 64-bit */ | ||
121 | |||
122 | #define FLAG_NEED_X_RESET (1 << 0) | ||
123 | |||
124 | #define SBIT(x) (1 << (x)) /* Signed version of BIT() */ | ||
125 | |||
126 | /** | ||
127 | * struct jit_ctx - JIT context | ||
128 | * @skf: The sk_filter | ||
129 | * @prologue_bytes: Number of bytes for prologue | ||
130 | * @idx: Instruction index | ||
131 | * @flags: JIT flags | ||
132 | * @offsets: Instruction offsets | ||
133 | * @target: Memory location for the compiled filter | ||
134 | */ | ||
135 | struct jit_ctx { | ||
136 | const struct sk_filter *skf; | ||
137 | unsigned int prologue_bytes; | ||
138 | u32 idx; | ||
139 | u32 flags; | ||
140 | u32 *offsets; | ||
141 | u32 *target; | ||
142 | }; | ||
143 | |||
144 | |||
145 | static inline int optimize_div(u32 *k) | ||
146 | { | ||
147 | /* power of 2 divides can be implemented with right shift */ | ||
148 | if (!(*k & (*k-1))) { | ||
149 | *k = ilog2(*k); | ||
150 | return 1; | ||
151 | } | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /* Simply emit the instruction if the JIT memory space has been allocated */ | ||
157 | #define emit_instr(ctx, func, ...) \ | ||
158 | do { \ | ||
159 | if ((ctx)->target != NULL) { \ | ||
160 | u32 *p = &(ctx)->target[ctx->idx]; \ | ||
161 | uasm_i_##func(&p, ##__VA_ARGS__); \ | ||
162 | } \ | ||
163 | (ctx)->idx++; \ | ||
164 | } while (0) | ||
165 | |||
166 | /* Determine if immediate is within the 16-bit signed range */ | ||
167 | static inline bool is_range16(s32 imm) | ||
168 | { | ||
169 | if (imm >= SBIT(15) || imm < -SBIT(15)) | ||
170 | return true; | ||
171 | return false; | ||
172 | } | ||
173 | |||
174 | static inline void emit_addu(unsigned int dst, unsigned int src1, | ||
175 | unsigned int src2, struct jit_ctx *ctx) | ||
176 | { | ||
177 | emit_instr(ctx, addu, dst, src1, src2); | ||
178 | } | ||
179 | |||
180 | static inline void emit_nop(struct jit_ctx *ctx) | ||
181 | { | ||
182 | emit_instr(ctx, nop); | ||
183 | } | ||
184 | |||
185 | /* Load a u32 immediate to a register */ | ||
186 | static inline void emit_load_imm(unsigned int dst, u32 imm, struct jit_ctx *ctx) | ||
187 | { | ||
188 | if (ctx->target != NULL) { | ||
189 | /* addiu can only handle s16 */ | ||
190 | if (is_range16(imm)) { | ||
191 | u32 *p = &ctx->target[ctx->idx]; | ||
192 | uasm_i_lui(&p, r_tmp_imm, (s32)imm >> 16); | ||
193 | p = &ctx->target[ctx->idx + 1]; | ||
194 | uasm_i_ori(&p, dst, r_tmp_imm, imm & 0xffff); | ||
195 | } else { | ||
196 | u32 *p = &ctx->target[ctx->idx]; | ||
197 | uasm_i_addiu(&p, dst, r_zero, imm); | ||
198 | } | ||
199 | } | ||
200 | ctx->idx++; | ||
201 | |||
202 | if (is_range16(imm)) | ||
203 | ctx->idx++; | ||
204 | } | ||
205 | |||
206 | static inline void emit_or(unsigned int dst, unsigned int src1, | ||
207 | unsigned int src2, struct jit_ctx *ctx) | ||
208 | { | ||
209 | emit_instr(ctx, or, dst, src1, src2); | ||
210 | } | ||
211 | |||
212 | static inline void emit_ori(unsigned int dst, unsigned src, u32 imm, | ||
213 | struct jit_ctx *ctx) | ||
214 | { | ||
215 | if (imm >= BIT(16)) { | ||
216 | emit_load_imm(r_tmp, imm, ctx); | ||
217 | emit_or(dst, src, r_tmp, ctx); | ||
218 | } else { | ||
219 | emit_instr(ctx, ori, dst, src, imm); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | |||
224 | static inline void emit_daddu(unsigned int dst, unsigned int src1, | ||
225 | unsigned int src2, struct jit_ctx *ctx) | ||
226 | { | ||
227 | emit_instr(ctx, daddu, dst, src1, src2); | ||
228 | } | ||
229 | |||
230 | static inline void emit_daddiu(unsigned int dst, unsigned int src, | ||
231 | int imm, struct jit_ctx *ctx) | ||
232 | { | ||
233 | /* | ||
234 | * Only used for stack, so the imm is relatively small | ||
235 | * and it fits in 15-bits | ||
236 | */ | ||
237 | emit_instr(ctx, daddiu, dst, src, imm); | ||
238 | } | ||
239 | |||
240 | static inline void emit_addiu(unsigned int dst, unsigned int src, | ||
241 | u32 imm, struct jit_ctx *ctx) | ||
242 | { | ||
243 | if (is_range16(imm)) { | ||
244 | emit_load_imm(r_tmp, imm, ctx); | ||
245 | emit_addu(dst, r_tmp, src, ctx); | ||
246 | } else { | ||
247 | emit_instr(ctx, addiu, dst, src, imm); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | static inline void emit_and(unsigned int dst, unsigned int src1, | ||
252 | unsigned int src2, struct jit_ctx *ctx) | ||
253 | { | ||
254 | emit_instr(ctx, and, dst, src1, src2); | ||
255 | } | ||
256 | |||
257 | static inline void emit_andi(unsigned int dst, unsigned int src, | ||
258 | u32 imm, struct jit_ctx *ctx) | ||
259 | { | ||
260 | /* If imm does not fit in u16 then load it to register */ | ||
261 | if (imm >= BIT(16)) { | ||
262 | emit_load_imm(r_tmp, imm, ctx); | ||
263 | emit_and(dst, src, r_tmp, ctx); | ||
264 | } else { | ||
265 | emit_instr(ctx, andi, dst, src, imm); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | static inline void emit_xor(unsigned int dst, unsigned int src1, | ||
270 | unsigned int src2, struct jit_ctx *ctx) | ||
271 | { | ||
272 | emit_instr(ctx, xor, dst, src1, src2); | ||
273 | } | ||
274 | |||
275 | static inline void emit_xori(ptr dst, ptr src, u32 imm, struct jit_ctx *ctx) | ||
276 | { | ||
277 | /* If imm does not fit in u16 then load it to register */ | ||
278 | if (imm >= BIT(16)) { | ||
279 | emit_load_imm(r_tmp, imm, ctx); | ||
280 | emit_xor(dst, src, r_tmp, ctx); | ||
281 | } else { | ||
282 | emit_instr(ctx, xori, dst, src, imm); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | static inline void emit_stack_offset(int offset, struct jit_ctx *ctx) | ||
287 | { | ||
288 | if (config_enabled(CONFIG_64BIT)) | ||
289 | emit_instr(ctx, daddiu, r_sp, r_sp, offset); | ||
290 | else | ||
291 | emit_instr(ctx, addiu, r_sp, r_sp, offset); | ||
292 | |||
293 | } | ||
294 | |||
295 | static inline void emit_subu(unsigned int dst, unsigned int src1, | ||
296 | unsigned int src2, struct jit_ctx *ctx) | ||
297 | { | ||
298 | emit_instr(ctx, subu, dst, src1, src2); | ||
299 | } | ||
300 | |||
301 | static inline void emit_neg(unsigned int reg, struct jit_ctx *ctx) | ||
302 | { | ||
303 | emit_subu(reg, r_zero, reg, ctx); | ||
304 | } | ||
305 | |||
306 | static inline void emit_sllv(unsigned int dst, unsigned int src, | ||
307 | unsigned int sa, struct jit_ctx *ctx) | ||
308 | { | ||
309 | emit_instr(ctx, sllv, dst, src, sa); | ||
310 | } | ||
311 | |||
312 | static inline void emit_sll(unsigned int dst, unsigned int src, | ||
313 | unsigned int sa, struct jit_ctx *ctx) | ||
314 | { | ||
315 | /* sa is 5-bits long */ | ||
316 | BUG_ON(sa >= BIT(5)); | ||
317 | emit_instr(ctx, sll, dst, src, sa); | ||
318 | } | ||
319 | |||
320 | static inline void emit_srlv(unsigned int dst, unsigned int src, | ||
321 | unsigned int sa, struct jit_ctx *ctx) | ||
322 | { | ||
323 | emit_instr(ctx, srlv, dst, src, sa); | ||
324 | } | ||
325 | |||
326 | static inline void emit_srl(unsigned int dst, unsigned int src, | ||
327 | unsigned int sa, struct jit_ctx *ctx) | ||
328 | { | ||
329 | /* sa is 5-bits long */ | ||
330 | BUG_ON(sa >= BIT(5)); | ||
331 | emit_instr(ctx, srl, dst, src, sa); | ||
332 | } | ||
333 | |||
334 | static inline void emit_sltu(unsigned int dst, unsigned int src1, | ||
335 | unsigned int src2, struct jit_ctx *ctx) | ||
336 | { | ||
337 | emit_instr(ctx, sltu, dst, src1, src2); | ||
338 | } | ||
339 | |||
340 | static inline void emit_sltiu(unsigned dst, unsigned int src, | ||
341 | unsigned int imm, struct jit_ctx *ctx) | ||
342 | { | ||
343 | /* 16 bit immediate */ | ||
344 | if (is_range16((s32)imm)) { | ||
345 | emit_load_imm(r_tmp, imm, ctx); | ||
346 | emit_sltu(dst, src, r_tmp, ctx); | ||
347 | } else { | ||
348 | emit_instr(ctx, sltiu, dst, src, imm); | ||
349 | } | ||
350 | |||
351 | } | ||
352 | |||
353 | /* Store register on the stack */ | ||
354 | static inline void emit_store_stack_reg(ptr reg, ptr base, | ||
355 | unsigned int offset, | ||
356 | struct jit_ctx *ctx) | ||
357 | { | ||
358 | if (config_enabled(CONFIG_64BIT)) | ||
359 | emit_instr(ctx, sd, reg, offset, base); | ||
360 | else | ||
361 | emit_instr(ctx, sw, reg, offset, base); | ||
362 | } | ||
363 | |||
364 | static inline void emit_store(ptr reg, ptr base, unsigned int offset, | ||
365 | struct jit_ctx *ctx) | ||
366 | { | ||
367 | emit_instr(ctx, sw, reg, offset, base); | ||
368 | } | ||
369 | |||
370 | static inline void emit_load_stack_reg(ptr reg, ptr base, | ||
371 | unsigned int offset, | ||
372 | struct jit_ctx *ctx) | ||
373 | { | ||
374 | if (config_enabled(CONFIG_64BIT)) | ||
375 | emit_instr(ctx, ld, reg, offset, base); | ||
376 | else | ||
377 | emit_instr(ctx, lw, reg, offset, base); | ||
378 | } | ||
379 | |||
380 | static inline void emit_load(unsigned int reg, unsigned int base, | ||
381 | unsigned int offset, struct jit_ctx *ctx) | ||
382 | { | ||
383 | emit_instr(ctx, lw, reg, offset, base); | ||
384 | } | ||
385 | |||
386 | static inline void emit_load_byte(unsigned int reg, unsigned int base, | ||
387 | unsigned int offset, struct jit_ctx *ctx) | ||
388 | { | ||
389 | emit_instr(ctx, lb, reg, offset, base); | ||
390 | } | ||
391 | |||
392 | static inline void emit_half_load(unsigned int reg, unsigned int base, | ||
393 | unsigned int offset, struct jit_ctx *ctx) | ||
394 | { | ||
395 | emit_instr(ctx, lh, reg, offset, base); | ||
396 | } | ||
397 | |||
398 | static inline void emit_mul(unsigned int dst, unsigned int src1, | ||
399 | unsigned int src2, struct jit_ctx *ctx) | ||
400 | { | ||
401 | emit_instr(ctx, mul, dst, src1, src2); | ||
402 | } | ||
403 | |||
404 | static inline void emit_div(unsigned int dst, unsigned int src, | ||
405 | struct jit_ctx *ctx) | ||
406 | { | ||
407 | if (ctx->target != NULL) { | ||
408 | u32 *p = &ctx->target[ctx->idx]; | ||
409 | uasm_i_divu(&p, dst, src); | ||
410 | p = &ctx->target[ctx->idx + 1]; | ||
411 | uasm_i_mfhi(&p, dst); | ||
412 | } | ||
413 | ctx->idx += 2; /* 2 insts */ | ||
414 | } | ||
415 | |||
416 | static inline void emit_mod(unsigned int dst, unsigned int src, | ||
417 | struct jit_ctx *ctx) | ||
418 | { | ||
419 | if (ctx->target != NULL) { | ||
420 | u32 *p = &ctx->target[ctx->idx]; | ||
421 | uasm_i_divu(&p, dst, src); | ||
422 | p = &ctx->target[ctx->idx + 1]; | ||
423 | uasm_i_mflo(&p, dst); | ||
424 | } | ||
425 | ctx->idx += 2; /* 2 insts */ | ||
426 | } | ||
427 | |||
428 | static inline void emit_dsll(unsigned int dst, unsigned int src, | ||
429 | unsigned int sa, struct jit_ctx *ctx) | ||
430 | { | ||
431 | emit_instr(ctx, dsll, dst, src, sa); | ||
432 | } | ||
433 | |||
434 | static inline void emit_dsrl32(unsigned int dst, unsigned int src, | ||
435 | unsigned int sa, struct jit_ctx *ctx) | ||
436 | { | ||
437 | emit_instr(ctx, dsrl32, dst, src, sa); | ||
438 | } | ||
439 | |||
440 | static inline void emit_wsbh(unsigned int dst, unsigned int src, | ||
441 | struct jit_ctx *ctx) | ||
442 | { | ||
443 | emit_instr(ctx, wsbh, dst, src); | ||
444 | } | ||
445 | |||
446 | /* load a function pointer to register */ | ||
447 | static inline void emit_load_func(unsigned int reg, ptr imm, | ||
448 | struct jit_ctx *ctx) | ||
449 | { | ||
450 | if (config_enabled(CONFIG_64BIT)) { | ||
451 | /* At this point imm is always 64-bit */ | ||
452 | emit_load_imm(r_tmp, (u64)imm >> 32, ctx); | ||
453 | emit_dsll(r_tmp_imm, r_tmp, 16, ctx); /* left shift by 16 */ | ||
454 | emit_ori(r_tmp, r_tmp_imm, (imm >> 16) & 0xffff, ctx); | ||
455 | emit_dsll(r_tmp_imm, r_tmp, 16, ctx); /* left shift by 16 */ | ||
456 | emit_ori(reg, r_tmp_imm, imm & 0xffff, ctx); | ||
457 | } else { | ||
458 | emit_load_imm(reg, imm, ctx); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | /* Move to real MIPS register */ | ||
463 | static inline void emit_reg_move(ptr dst, ptr src, struct jit_ctx *ctx) | ||
464 | { | ||
465 | if (config_enabled(CONFIG_64BIT)) | ||
466 | emit_daddu(dst, src, r_zero, ctx); | ||
467 | else | ||
468 | emit_addu(dst, src, r_zero, ctx); | ||
469 | } | ||
470 | |||
471 | /* Move to JIT (32-bit) register */ | ||
472 | static inline void emit_jit_reg_move(ptr dst, ptr src, struct jit_ctx *ctx) | ||
473 | { | ||
474 | emit_addu(dst, src, r_zero, ctx); | ||
475 | } | ||
476 | |||
477 | /* Compute the immediate value for PC-relative branches. */ | ||
478 | static inline u32 b_imm(unsigned int tgt, struct jit_ctx *ctx) | ||
479 | { | ||
480 | if (ctx->target == NULL) | ||
481 | return 0; | ||
482 | |||
483 | /* | ||
484 | * We want a pc-relative branch. We only do forward branches | ||
485 | * so tgt is always after pc. tgt is the instruction offset | ||
486 | * we want to jump to. | ||
487 | |||
488 | * Branch on MIPS: | ||
489 | * I: target_offset <- sign_extend(offset) | ||
490 | * I+1: PC += target_offset (delay slot) | ||
491 | * | ||
492 | * ctx->idx currently points to the branch instruction | ||
493 | * but the offset is added to the delay slot so we need | ||
494 | * to subtract 4. | ||
495 | */ | ||
496 | return ctx->offsets[tgt] - | ||
497 | (ctx->idx * 4 - ctx->prologue_bytes) - 4; | ||
498 | } | ||
499 | |||
500 | static inline void emit_bcond(int cond, unsigned int reg1, unsigned int reg2, | ||
501 | unsigned int imm, struct jit_ctx *ctx) | ||
502 | { | ||
503 | if (ctx->target != NULL) { | ||
504 | u32 *p = &ctx->target[ctx->idx]; | ||
505 | |||
506 | switch (cond) { | ||
507 | case MIPS_COND_EQ: | ||
508 | uasm_i_beq(&p, reg1, reg2, imm); | ||
509 | break; | ||
510 | case MIPS_COND_NE: | ||
511 | uasm_i_bne(&p, reg1, reg2, imm); | ||
512 | break; | ||
513 | case MIPS_COND_ALL: | ||
514 | uasm_i_b(&p, imm); | ||
515 | break; | ||
516 | default: | ||
517 | pr_warn("%s: Unhandled branch conditional: %d\n", | ||
518 | __func__, cond); | ||
519 | } | ||
520 | } | ||
521 | ctx->idx++; | ||
522 | } | ||
523 | |||
524 | static inline void emit_b(unsigned int imm, struct jit_ctx *ctx) | ||
525 | { | ||
526 | emit_bcond(MIPS_COND_ALL, r_zero, r_zero, imm, ctx); | ||
527 | } | ||
528 | |||
529 | static inline void emit_jalr(unsigned int link, unsigned int reg, | ||
530 | struct jit_ctx *ctx) | ||
531 | { | ||
532 | emit_instr(ctx, jalr, link, reg); | ||
533 | } | ||
534 | |||
535 | static inline void emit_jr(unsigned int reg, struct jit_ctx *ctx) | ||
536 | { | ||
537 | emit_instr(ctx, jr, reg); | ||
538 | } | ||
539 | |||
540 | static inline u16 align_sp(unsigned int num) | ||
541 | { | ||
542 | /* Double word alignment for 32-bit, quadword for 64-bit */ | ||
543 | unsigned int align = config_enabled(CONFIG_64BIT) ? 16 : 8; | ||
544 | num = (num + (align - 1)) & -align; | ||
545 | return num; | ||
546 | } | ||
547 | |||
548 | static inline void update_on_xread(struct jit_ctx *ctx) | ||
549 | { | ||
550 | if (!(ctx->flags & SEEN_X)) | ||
551 | ctx->flags |= FLAG_NEED_X_RESET; | ||
552 | |||
553 | ctx->flags |= SEEN_X; | ||
554 | } | ||
555 | |||
556 | static bool is_load_to_a(u16 inst) | ||
557 | { | ||
558 | switch (inst) { | ||
559 | case BPF_S_LD_W_LEN: | ||
560 | case BPF_S_LD_W_ABS: | ||
561 | case BPF_S_LD_H_ABS: | ||
562 | case BPF_S_LD_B_ABS: | ||
563 | case BPF_S_ANC_CPU: | ||
564 | case BPF_S_ANC_IFINDEX: | ||
565 | case BPF_S_ANC_MARK: | ||
566 | case BPF_S_ANC_PROTOCOL: | ||
567 | case BPF_S_ANC_RXHASH: | ||
568 | case BPF_S_ANC_VLAN_TAG: | ||
569 | case BPF_S_ANC_VLAN_TAG_PRESENT: | ||
570 | case BPF_S_ANC_QUEUE: | ||
571 | return true; | ||
572 | default: | ||
573 | return false; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset) | ||
578 | { | ||
579 | int i = 0, real_off = 0; | ||
580 | u32 sflags, tmp_flags; | ||
581 | |||
582 | /* Adjust the stack pointer */ | ||
583 | emit_stack_offset(-align_sp(offset), ctx); | ||
584 | |||
585 | if (ctx->flags & SEEN_CALL) { | ||
586 | /* Argument save area */ | ||
587 | if (config_enabled(CONFIG_64BIT)) | ||
588 | /* Bottom of current frame */ | ||
589 | real_off = align_sp(offset) - RSIZE; | ||
590 | else | ||
591 | /* Top of previous frame */ | ||
592 | real_off = align_sp(offset) + RSIZE; | ||
593 | emit_store_stack_reg(MIPS_R_A0, r_sp, real_off, ctx); | ||
594 | emit_store_stack_reg(MIPS_R_A1, r_sp, real_off + RSIZE, ctx); | ||
595 | |||
596 | real_off = 0; | ||
597 | } | ||
598 | |||
599 | tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT; | ||
600 | /* sflags is essentially a bitmap */ | ||
601 | while (tmp_flags) { | ||
602 | if ((sflags >> i) & 0x1) { | ||
603 | emit_store_stack_reg(MIPS_R_S0 + i, r_sp, real_off, | ||
604 | ctx); | ||
605 | real_off += RSIZE; | ||
606 | } | ||
607 | i++; | ||
608 | tmp_flags >>= 1; | ||
609 | } | ||
610 | |||
611 | /* save return address */ | ||
612 | if (ctx->flags & SEEN_CALL) { | ||
613 | emit_store_stack_reg(r_ra, r_sp, real_off, ctx); | ||
614 | real_off += RSIZE; | ||
615 | } | ||
616 | |||
617 | /* Setup r_M leaving the alignment gap if necessary */ | ||
618 | if (ctx->flags & SEEN_MEM) { | ||
619 | if (real_off % (RSIZE * 2)) | ||
620 | real_off += RSIZE; | ||
621 | emit_addiu(r_M, r_sp, real_off, ctx); | ||
622 | } | ||
623 | } | ||
624 | |||
625 | static void restore_bpf_jit_regs(struct jit_ctx *ctx, | ||
626 | unsigned int offset) | ||
627 | { | ||
628 | int i, real_off = 0; | ||
629 | u32 sflags, tmp_flags; | ||
630 | |||
631 | if (ctx->flags & SEEN_CALL) { | ||
632 | if (config_enabled(CONFIG_64BIT)) | ||
633 | /* Bottom of current frame */ | ||
634 | real_off = align_sp(offset) - RSIZE; | ||
635 | else | ||
636 | /* Top of previous frame */ | ||
637 | real_off = align_sp(offset) + RSIZE; | ||
638 | emit_load_stack_reg(MIPS_R_A0, r_sp, real_off, ctx); | ||
639 | emit_load_stack_reg(MIPS_R_A1, r_sp, real_off + RSIZE, ctx); | ||
640 | |||
641 | real_off = 0; | ||
642 | } | ||
643 | |||
644 | tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT; | ||
645 | /* sflags is a bitmap */ | ||
646 | i = 0; | ||
647 | while (tmp_flags) { | ||
648 | if ((sflags >> i) & 0x1) { | ||
649 | emit_load_stack_reg(MIPS_R_S0 + i, r_sp, real_off, | ||
650 | ctx); | ||
651 | real_off += RSIZE; | ||
652 | } | ||
653 | i++; | ||
654 | tmp_flags >>= 1; | ||
655 | } | ||
656 | |||
657 | /* restore return address */ | ||
658 | if (ctx->flags & SEEN_CALL) | ||
659 | emit_load_stack_reg(r_ra, r_sp, real_off, ctx); | ||
660 | |||
661 | /* Restore the sp and discard the scrach memory */ | ||
662 | emit_stack_offset(align_sp(offset), ctx); | ||
663 | } | ||
664 | |||
665 | static unsigned int get_stack_depth(struct jit_ctx *ctx) | ||
666 | { | ||
667 | int sp_off = 0; | ||
668 | |||
669 | |||
670 | /* How may s* regs do we need to preserved? */ | ||
671 | sp_off += hweight32(ctx->flags >> SEEN_SREG_SFT) * RSIZE; | ||
672 | |||
673 | if (ctx->flags & SEEN_MEM) | ||
674 | sp_off += 4 * BPF_MEMWORDS; /* BPF_MEMWORDS are 32-bit */ | ||
675 | |||
676 | if (ctx->flags & SEEN_CALL) | ||
677 | /* | ||
678 | * The JIT code make calls to external functions using 2 | ||
679 | * arguments. Therefore, for o32 we don't need to allocate | ||
680 | * space because we don't care if the argumetns are lost | ||
681 | * across calls. We do need however to preserve incoming | ||
682 | * arguments but the space is already allocated for us by | ||
683 | * the caller. On the other hand, for n64, we need to allocate | ||
684 | * this space ourselves. We need to preserve $ra as well. | ||
685 | */ | ||
686 | sp_off += config_enabled(CONFIG_64BIT) ? | ||
687 | (ARGS_USED_BY_JIT + 1) * RSIZE : RSIZE; | ||
688 | |||
689 | /* | ||
690 | * Subtract the bytes for the last registers since we only care about | ||
691 | * the location on the stack pointer. | ||
692 | */ | ||
693 | return sp_off - RSIZE; | ||
694 | } | ||
695 | |||
696 | static void build_prologue(struct jit_ctx *ctx) | ||
697 | { | ||
698 | u16 first_inst = ctx->skf->insns[0].code; | ||
699 | int sp_off; | ||
700 | |||
701 | /* Calculate the total offset for the stack pointer */ | ||
702 | sp_off = get_stack_depth(ctx); | ||
703 | save_bpf_jit_regs(ctx, sp_off); | ||
704 | |||
705 | if (ctx->flags & SEEN_SKB) | ||
706 | emit_reg_move(r_skb, MIPS_R_A0, ctx); | ||
707 | |||
708 | if (ctx->flags & FLAG_NEED_X_RESET) | ||
709 | emit_jit_reg_move(r_X, r_zero, ctx); | ||
710 | |||
711 | /* Do not leak kernel data to userspace */ | ||
712 | if ((first_inst != BPF_S_RET_K) && !(is_load_to_a(first_inst))) | ||
713 | emit_jit_reg_move(r_A, r_zero, ctx); | ||
714 | } | ||
715 | |||
716 | static void build_epilogue(struct jit_ctx *ctx) | ||
717 | { | ||
718 | unsigned int sp_off; | ||
719 | |||
720 | /* Calculate the total offset for the stack pointer */ | ||
721 | |||
722 | sp_off = get_stack_depth(ctx); | ||
723 | restore_bpf_jit_regs(ctx, sp_off); | ||
724 | |||
725 | /* Return */ | ||
726 | emit_jr(r_ra, ctx); | ||
727 | emit_nop(ctx); | ||
728 | } | ||
729 | |||
730 | static u64 jit_get_skb_b(struct sk_buff *skb, unsigned offset) | ||
731 | { | ||
732 | u8 ret; | ||
733 | int err; | ||
734 | |||
735 | err = skb_copy_bits(skb, offset, &ret, 1); | ||
736 | |||
737 | return (u64)err << 32 | ret; | ||
738 | } | ||
739 | |||
740 | static u64 jit_get_skb_h(struct sk_buff *skb, unsigned offset) | ||
741 | { | ||
742 | u16 ret; | ||
743 | int err; | ||
744 | |||
745 | err = skb_copy_bits(skb, offset, &ret, 2); | ||
746 | |||
747 | return (u64)err << 32 | ntohs(ret); | ||
748 | } | ||
749 | |||
750 | static u64 jit_get_skb_w(struct sk_buff *skb, unsigned offset) | ||
751 | { | ||
752 | u32 ret; | ||
753 | int err; | ||
754 | |||
755 | err = skb_copy_bits(skb, offset, &ret, 4); | ||
756 | |||
757 | return (u64)err << 32 | ntohl(ret); | ||
758 | } | ||
759 | |||
760 | #define PKT_TYPE_MAX 7 | ||
761 | static int pkt_type_offset(void) | ||
762 | { | ||
763 | struct sk_buff skb_probe = { | ||
764 | .pkt_type = ~0, | ||
765 | }; | ||
766 | char *ct = (char *)&skb_probe; | ||
767 | unsigned int off; | ||
768 | |||
769 | for (off = 0; off < sizeof(struct sk_buff); off++) { | ||
770 | if (ct[off] == PKT_TYPE_MAX) | ||
771 | return off; | ||
772 | } | ||
773 | pr_err_once("Please fix pkt_type_offset(), as pkt_type couldn't be found\n"); | ||
774 | return -1; | ||
775 | } | ||
776 | |||
777 | static int build_body(struct jit_ctx *ctx) | ||
778 | { | ||
779 | void *load_func[] = {jit_get_skb_b, jit_get_skb_h, jit_get_skb_w}; | ||
780 | const struct sk_filter *prog = ctx->skf; | ||
781 | const struct sock_filter *inst; | ||
782 | unsigned int i, off, load_order, condt; | ||
783 | u32 k, b_off __maybe_unused; | ||
784 | |||
785 | for (i = 0; i < prog->len; i++) { | ||
786 | inst = &(prog->insns[i]); | ||
787 | pr_debug("%s: code->0x%02x, jt->0x%x, jf->0x%x, k->0x%x\n", | ||
788 | __func__, inst->code, inst->jt, inst->jf, inst->k); | ||
789 | k = inst->k; | ||
790 | |||
791 | if (ctx->target == NULL) | ||
792 | ctx->offsets[i] = ctx->idx * 4; | ||
793 | |||
794 | switch (inst->code) { | ||
795 | case BPF_S_LD_IMM: | ||
796 | /* A <- k ==> li r_A, k */ | ||
797 | ctx->flags |= SEEN_A; | ||
798 | emit_load_imm(r_A, k, ctx); | ||
799 | break; | ||
800 | case BPF_S_LD_W_LEN: | ||
801 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); | ||
802 | /* A <- len ==> lw r_A, offset(skb) */ | ||
803 | ctx->flags |= SEEN_SKB | SEEN_A; | ||
804 | off = offsetof(struct sk_buff, len); | ||
805 | emit_load(r_A, r_skb, off, ctx); | ||
806 | break; | ||
807 | case BPF_S_LD_MEM: | ||
808 | /* A <- M[k] ==> lw r_A, offset(M) */ | ||
809 | ctx->flags |= SEEN_MEM | SEEN_A; | ||
810 | emit_load(r_A, r_M, SCRATCH_OFF(k), ctx); | ||
811 | break; | ||
812 | case BPF_S_LD_W_ABS: | ||
813 | /* A <- P[k:4] */ | ||
814 | load_order = 2; | ||
815 | goto load; | ||
816 | case BPF_S_LD_H_ABS: | ||
817 | /* A <- P[k:2] */ | ||
818 | load_order = 1; | ||
819 | goto load; | ||
820 | case BPF_S_LD_B_ABS: | ||
821 | /* A <- P[k:1] */ | ||
822 | load_order = 0; | ||
823 | load: | ||
824 | emit_load_imm(r_off, k, ctx); | ||
825 | load_common: | ||
826 | ctx->flags |= SEEN_CALL | SEEN_OFF | SEEN_S0 | | ||
827 | SEEN_SKB | SEEN_A; | ||
828 | |||
829 | emit_load_func(r_s0, (ptr)load_func[load_order], | ||
830 | ctx); | ||
831 | emit_reg_move(MIPS_R_A0, r_skb, ctx); | ||
832 | emit_jalr(MIPS_R_RA, r_s0, ctx); | ||
833 | /* Load second argument to delay slot */ | ||
834 | emit_reg_move(MIPS_R_A1, r_off, ctx); | ||
835 | /* Check the error value */ | ||
836 | if (config_enabled(CONFIG_64BIT)) { | ||
837 | /* Get error code from the top 32-bits */ | ||
838 | emit_dsrl32(r_s0, r_val, 0, ctx); | ||
839 | /* Branch to 3 instructions ahead */ | ||
840 | emit_bcond(MIPS_COND_NE, r_s0, r_zero, 3 << 2, | ||
841 | ctx); | ||
842 | } else { | ||
843 | /* Branch to 3 instructions ahead */ | ||
844 | emit_bcond(MIPS_COND_NE, r_err, r_zero, 3 << 2, | ||
845 | ctx); | ||
846 | } | ||
847 | emit_nop(ctx); | ||
848 | /* We are good */ | ||
849 | emit_b(b_imm(i + 1, ctx), ctx); | ||
850 | emit_jit_reg_move(r_A, r_val, ctx); | ||
851 | /* Return with error */ | ||
852 | emit_b(b_imm(prog->len, ctx), ctx); | ||
853 | emit_reg_move(r_ret, r_zero, ctx); | ||
854 | break; | ||
855 | case BPF_S_LD_W_IND: | ||
856 | /* A <- P[X + k:4] */ | ||
857 | load_order = 2; | ||
858 | goto load_ind; | ||
859 | case BPF_S_LD_H_IND: | ||
860 | /* A <- P[X + k:2] */ | ||
861 | load_order = 1; | ||
862 | goto load_ind; | ||
863 | case BPF_S_LD_B_IND: | ||
864 | /* A <- P[X + k:1] */ | ||
865 | load_order = 0; | ||
866 | load_ind: | ||
867 | update_on_xread(ctx); | ||
868 | ctx->flags |= SEEN_OFF | SEEN_X; | ||
869 | emit_addiu(r_off, r_X, k, ctx); | ||
870 | goto load_common; | ||
871 | case BPF_S_LDX_IMM: | ||
872 | /* X <- k */ | ||
873 | ctx->flags |= SEEN_X; | ||
874 | emit_load_imm(r_X, k, ctx); | ||
875 | break; | ||
876 | case BPF_S_LDX_MEM: | ||
877 | /* X <- M[k] */ | ||
878 | ctx->flags |= SEEN_X | SEEN_MEM; | ||
879 | emit_load(r_X, r_M, SCRATCH_OFF(k), ctx); | ||
880 | break; | ||
881 | case BPF_S_LDX_W_LEN: | ||
882 | /* X <- len */ | ||
883 | ctx->flags |= SEEN_X | SEEN_SKB; | ||
884 | off = offsetof(struct sk_buff, len); | ||
885 | emit_load(r_X, r_skb, off, ctx); | ||
886 | break; | ||
887 | case BPF_S_LDX_B_MSH: | ||
888 | /* X <- 4 * (P[k:1] & 0xf) */ | ||
889 | ctx->flags |= SEEN_X | SEEN_CALL | SEEN_S0 | SEEN_SKB; | ||
890 | /* Load offset to a1 */ | ||
891 | emit_load_func(r_s0, (ptr)jit_get_skb_b, ctx); | ||
892 | /* | ||
893 | * This may emit two instructions so it may not fit | ||
894 | * in the delay slot. So use a0 in the delay slot. | ||
895 | */ | ||
896 | emit_load_imm(MIPS_R_A1, k, ctx); | ||
897 | emit_jalr(MIPS_R_RA, r_s0, ctx); | ||
898 | emit_reg_move(MIPS_R_A0, r_skb, ctx); /* delay slot */ | ||
899 | /* Check the error value */ | ||
900 | if (config_enabled(CONFIG_64BIT)) { | ||
901 | /* Top 32-bits of $v0 on 64-bit */ | ||
902 | emit_dsrl32(r_s0, r_val, 0, ctx); | ||
903 | emit_bcond(MIPS_COND_NE, r_s0, r_zero, | ||
904 | 3 << 2, ctx); | ||
905 | } else { | ||
906 | emit_bcond(MIPS_COND_NE, r_err, r_zero, | ||
907 | 3 << 2, ctx); | ||
908 | } | ||
909 | /* No need for delay slot */ | ||
910 | /* We are good */ | ||
911 | /* X <- P[1:K] & 0xf */ | ||
912 | emit_andi(r_X, r_val, 0xf, ctx); | ||
913 | /* X << 2 */ | ||
914 | emit_b(b_imm(i + 1, ctx), ctx); | ||
915 | emit_sll(r_X, r_X, 2, ctx); /* delay slot */ | ||
916 | /* Return with error */ | ||
917 | emit_b(b_imm(prog->len, ctx), ctx); | ||
918 | emit_load_imm(r_ret, 0, ctx); /* delay slot */ | ||
919 | break; | ||
920 | case BPF_S_ST: | ||
921 | /* M[k] <- A */ | ||
922 | ctx->flags |= SEEN_MEM | SEEN_A; | ||
923 | emit_store(r_A, r_M, SCRATCH_OFF(k), ctx); | ||
924 | break; | ||
925 | case BPF_S_STX: | ||
926 | /* M[k] <- X */ | ||
927 | ctx->flags |= SEEN_MEM | SEEN_X; | ||
928 | emit_store(r_X, r_M, SCRATCH_OFF(k), ctx); | ||
929 | break; | ||
930 | case BPF_S_ALU_ADD_K: | ||
931 | /* A += K */ | ||
932 | ctx->flags |= SEEN_A; | ||
933 | emit_addiu(r_A, r_A, k, ctx); | ||
934 | break; | ||
935 | case BPF_S_ALU_ADD_X: | ||
936 | /* A += X */ | ||
937 | ctx->flags |= SEEN_A | SEEN_X; | ||
938 | emit_addu(r_A, r_A, r_X, ctx); | ||
939 | break; | ||
940 | case BPF_S_ALU_SUB_K: | ||
941 | /* A -= K */ | ||
942 | ctx->flags |= SEEN_A; | ||
943 | emit_addiu(r_A, r_A, -k, ctx); | ||
944 | break; | ||
945 | case BPF_S_ALU_SUB_X: | ||
946 | /* A -= X */ | ||
947 | ctx->flags |= SEEN_A | SEEN_X; | ||
948 | emit_subu(r_A, r_A, r_X, ctx); | ||
949 | break; | ||
950 | case BPF_S_ALU_MUL_K: | ||
951 | /* A *= K */ | ||
952 | /* Load K to scratch register before MUL */ | ||
953 | ctx->flags |= SEEN_A | SEEN_S0; | ||
954 | emit_load_imm(r_s0, k, ctx); | ||
955 | emit_mul(r_A, r_A, r_s0, ctx); | ||
956 | break; | ||
957 | case BPF_S_ALU_MUL_X: | ||
958 | /* A *= X */ | ||
959 | update_on_xread(ctx); | ||
960 | ctx->flags |= SEEN_A | SEEN_X; | ||
961 | emit_mul(r_A, r_A, r_X, ctx); | ||
962 | break; | ||
963 | case BPF_S_ALU_DIV_K: | ||
964 | /* A /= k */ | ||
965 | if (k == 1) | ||
966 | break; | ||
967 | if (optimize_div(&k)) { | ||
968 | ctx->flags |= SEEN_A; | ||
969 | emit_srl(r_A, r_A, k, ctx); | ||
970 | break; | ||
971 | } | ||
972 | ctx->flags |= SEEN_A | SEEN_S0; | ||
973 | emit_load_imm(r_s0, k, ctx); | ||
974 | emit_div(r_A, r_s0, ctx); | ||
975 | break; | ||
976 | case BPF_S_ALU_MOD_K: | ||
977 | /* A %= k */ | ||
978 | if (k == 1 || optimize_div(&k)) { | ||
979 | ctx->flags |= SEEN_A; | ||
980 | emit_jit_reg_move(r_A, r_zero, ctx); | ||
981 | } else { | ||
982 | ctx->flags |= SEEN_A | SEEN_S0; | ||
983 | emit_load_imm(r_s0, k, ctx); | ||
984 | emit_mod(r_A, r_s0, ctx); | ||
985 | } | ||
986 | break; | ||
987 | case BPF_S_ALU_DIV_X: | ||
988 | /* A /= X */ | ||
989 | update_on_xread(ctx); | ||
990 | ctx->flags |= SEEN_X | SEEN_A; | ||
991 | /* Check if r_X is zero */ | ||
992 | emit_bcond(MIPS_COND_EQ, r_X, r_zero, | ||
993 | b_imm(prog->len, ctx), ctx); | ||
994 | emit_load_imm(r_val, 0, ctx); /* delay slot */ | ||
995 | emit_div(r_A, r_X, ctx); | ||
996 | break; | ||
997 | case BPF_S_ALU_MOD_X: | ||
998 | /* A %= X */ | ||
999 | update_on_xread(ctx); | ||
1000 | ctx->flags |= SEEN_X | SEEN_A; | ||
1001 | /* Check if r_X is zero */ | ||
1002 | emit_bcond(MIPS_COND_EQ, r_X, r_zero, | ||
1003 | b_imm(prog->len, ctx), ctx); | ||
1004 | emit_load_imm(r_val, 0, ctx); /* delay slot */ | ||
1005 | emit_mod(r_A, r_X, ctx); | ||
1006 | break; | ||
1007 | case BPF_S_ALU_OR_K: | ||
1008 | /* A |= K */ | ||
1009 | ctx->flags |= SEEN_A; | ||
1010 | emit_ori(r_A, r_A, k, ctx); | ||
1011 | break; | ||
1012 | case BPF_S_ALU_OR_X: | ||
1013 | /* A |= X */ | ||
1014 | update_on_xread(ctx); | ||
1015 | ctx->flags |= SEEN_A; | ||
1016 | emit_ori(r_A, r_A, r_X, ctx); | ||
1017 | break; | ||
1018 | case BPF_S_ALU_XOR_K: | ||
1019 | /* A ^= k */ | ||
1020 | ctx->flags |= SEEN_A; | ||
1021 | emit_xori(r_A, r_A, k, ctx); | ||
1022 | break; | ||
1023 | case BPF_S_ANC_ALU_XOR_X: | ||
1024 | case BPF_S_ALU_XOR_X: | ||
1025 | /* A ^= X */ | ||
1026 | update_on_xread(ctx); | ||
1027 | ctx->flags |= SEEN_A; | ||
1028 | emit_xor(r_A, r_A, r_X, ctx); | ||
1029 | break; | ||
1030 | case BPF_S_ALU_AND_K: | ||
1031 | /* A &= K */ | ||
1032 | ctx->flags |= SEEN_A; | ||
1033 | emit_andi(r_A, r_A, k, ctx); | ||
1034 | break; | ||
1035 | case BPF_S_ALU_AND_X: | ||
1036 | /* A &= X */ | ||
1037 | update_on_xread(ctx); | ||
1038 | ctx->flags |= SEEN_A | SEEN_X; | ||
1039 | emit_and(r_A, r_A, r_X, ctx); | ||
1040 | break; | ||
1041 | case BPF_S_ALU_LSH_K: | ||
1042 | /* A <<= K */ | ||
1043 | ctx->flags |= SEEN_A; | ||
1044 | emit_sll(r_A, r_A, k, ctx); | ||
1045 | break; | ||
1046 | case BPF_S_ALU_LSH_X: | ||
1047 | /* A <<= X */ | ||
1048 | ctx->flags |= SEEN_A | SEEN_X; | ||
1049 | update_on_xread(ctx); | ||
1050 | emit_sllv(r_A, r_A, r_X, ctx); | ||
1051 | break; | ||
1052 | case BPF_S_ALU_RSH_K: | ||
1053 | /* A >>= K */ | ||
1054 | ctx->flags |= SEEN_A; | ||
1055 | emit_srl(r_A, r_A, k, ctx); | ||
1056 | break; | ||
1057 | case BPF_S_ALU_RSH_X: | ||
1058 | ctx->flags |= SEEN_A | SEEN_X; | ||
1059 | update_on_xread(ctx); | ||
1060 | emit_srlv(r_A, r_A, r_X, ctx); | ||
1061 | break; | ||
1062 | case BPF_S_ALU_NEG: | ||
1063 | /* A = -A */ | ||
1064 | ctx->flags |= SEEN_A; | ||
1065 | emit_neg(r_A, ctx); | ||
1066 | break; | ||
1067 | case BPF_S_JMP_JA: | ||
1068 | /* pc += K */ | ||
1069 | emit_b(b_imm(i + k + 1, ctx), ctx); | ||
1070 | emit_nop(ctx); | ||
1071 | break; | ||
1072 | case BPF_S_JMP_JEQ_K: | ||
1073 | /* pc += ( A == K ) ? pc->jt : pc->jf */ | ||
1074 | condt = MIPS_COND_EQ | MIPS_COND_K; | ||
1075 | goto jmp_cmp; | ||
1076 | case BPF_S_JMP_JEQ_X: | ||
1077 | ctx->flags |= SEEN_X; | ||
1078 | /* pc += ( A == X ) ? pc->jt : pc->jf */ | ||
1079 | condt = MIPS_COND_EQ | MIPS_COND_X; | ||
1080 | goto jmp_cmp; | ||
1081 | case BPF_S_JMP_JGE_K: | ||
1082 | /* pc += ( A >= K ) ? pc->jt : pc->jf */ | ||
1083 | condt = MIPS_COND_GE | MIPS_COND_K; | ||
1084 | goto jmp_cmp; | ||
1085 | case BPF_S_JMP_JGE_X: | ||
1086 | ctx->flags |= SEEN_X; | ||
1087 | /* pc += ( A >= X ) ? pc->jt : pc->jf */ | ||
1088 | condt = MIPS_COND_GE | MIPS_COND_X; | ||
1089 | goto jmp_cmp; | ||
1090 | case BPF_S_JMP_JGT_K: | ||
1091 | /* pc += ( A > K ) ? pc->jt : pc->jf */ | ||
1092 | condt = MIPS_COND_GT | MIPS_COND_K; | ||
1093 | goto jmp_cmp; | ||
1094 | case BPF_S_JMP_JGT_X: | ||
1095 | ctx->flags |= SEEN_X; | ||
1096 | /* pc += ( A > X ) ? pc->jt : pc->jf */ | ||
1097 | condt = MIPS_COND_GT | MIPS_COND_X; | ||
1098 | jmp_cmp: | ||
1099 | /* Greater or Equal */ | ||
1100 | if ((condt & MIPS_COND_GE) || | ||
1101 | (condt & MIPS_COND_GT)) { | ||
1102 | if (condt & MIPS_COND_K) { /* K */ | ||
1103 | ctx->flags |= SEEN_S0 | SEEN_A; | ||
1104 | emit_sltiu(r_s0, r_A, k, ctx); | ||
1105 | } else { /* X */ | ||
1106 | ctx->flags |= SEEN_S0 | SEEN_A | | ||
1107 | SEEN_X; | ||
1108 | emit_sltu(r_s0, r_A, r_X, ctx); | ||
1109 | } | ||
1110 | /* A < (K|X) ? r_scrach = 1 */ | ||
1111 | b_off = b_imm(i + inst->jf + 1, ctx); | ||
1112 | emit_bcond(MIPS_COND_GT, r_s0, r_zero, b_off, | ||
1113 | ctx); | ||
1114 | emit_nop(ctx); | ||
1115 | /* A > (K|X) ? scratch = 0 */ | ||
1116 | if (condt & MIPS_COND_GT) { | ||
1117 | /* Checking for equality */ | ||
1118 | ctx->flags |= SEEN_S0 | SEEN_A | SEEN_X; | ||
1119 | if (condt & MIPS_COND_K) | ||
1120 | emit_load_imm(r_s0, k, ctx); | ||
1121 | else | ||
1122 | emit_jit_reg_move(r_s0, r_X, | ||
1123 | ctx); | ||
1124 | b_off = b_imm(i + inst->jf + 1, ctx); | ||
1125 | emit_bcond(MIPS_COND_EQ, r_A, r_s0, | ||
1126 | b_off, ctx); | ||
1127 | emit_nop(ctx); | ||
1128 | /* Finally, A > K|X */ | ||
1129 | b_off = b_imm(i + inst->jt + 1, ctx); | ||
1130 | emit_b(b_off, ctx); | ||
1131 | emit_nop(ctx); | ||
1132 | } else { | ||
1133 | /* A >= (K|X) so jump */ | ||
1134 | b_off = b_imm(i + inst->jt + 1, ctx); | ||
1135 | emit_b(b_off, ctx); | ||
1136 | emit_nop(ctx); | ||
1137 | } | ||
1138 | } else { | ||
1139 | /* A == K|X */ | ||
1140 | if (condt & MIPS_COND_K) { /* K */ | ||
1141 | ctx->flags |= SEEN_S0 | SEEN_A; | ||
1142 | emit_load_imm(r_s0, k, ctx); | ||
1143 | /* jump true */ | ||
1144 | b_off = b_imm(i + inst->jt + 1, ctx); | ||
1145 | emit_bcond(MIPS_COND_EQ, r_A, r_s0, | ||
1146 | b_off, ctx); | ||
1147 | emit_nop(ctx); | ||
1148 | /* jump false */ | ||
1149 | b_off = b_imm(i + inst->jf + 1, | ||
1150 | ctx); | ||
1151 | emit_bcond(MIPS_COND_NE, r_A, r_s0, | ||
1152 | b_off, ctx); | ||
1153 | emit_nop(ctx); | ||
1154 | } else { /* X */ | ||
1155 | /* jump true */ | ||
1156 | ctx->flags |= SEEN_A | SEEN_X; | ||
1157 | b_off = b_imm(i + inst->jt + 1, | ||
1158 | ctx); | ||
1159 | emit_bcond(MIPS_COND_EQ, r_A, r_X, | ||
1160 | b_off, ctx); | ||
1161 | emit_nop(ctx); | ||
1162 | /* jump false */ | ||
1163 | b_off = b_imm(i + inst->jf + 1, ctx); | ||
1164 | emit_bcond(MIPS_COND_NE, r_A, r_X, | ||
1165 | b_off, ctx); | ||
1166 | emit_nop(ctx); | ||
1167 | } | ||
1168 | } | ||
1169 | break; | ||
1170 | case BPF_S_JMP_JSET_K: | ||
1171 | ctx->flags |= SEEN_S0 | SEEN_S1 | SEEN_A; | ||
1172 | /* pc += (A & K) ? pc -> jt : pc -> jf */ | ||
1173 | emit_load_imm(r_s1, k, ctx); | ||
1174 | emit_and(r_s0, r_A, r_s1, ctx); | ||
1175 | /* jump true */ | ||
1176 | b_off = b_imm(i + inst->jt + 1, ctx); | ||
1177 | emit_bcond(MIPS_COND_NE, r_s0, r_zero, b_off, ctx); | ||
1178 | emit_nop(ctx); | ||
1179 | /* jump false */ | ||
1180 | b_off = b_imm(i + inst->jf + 1, ctx); | ||
1181 | emit_b(b_off, ctx); | ||
1182 | emit_nop(ctx); | ||
1183 | break; | ||
1184 | case BPF_S_JMP_JSET_X: | ||
1185 | ctx->flags |= SEEN_S0 | SEEN_X | SEEN_A; | ||
1186 | /* pc += (A & X) ? pc -> jt : pc -> jf */ | ||
1187 | emit_and(r_s0, r_A, r_X, ctx); | ||
1188 | /* jump true */ | ||
1189 | b_off = b_imm(i + inst->jt + 1, ctx); | ||
1190 | emit_bcond(MIPS_COND_NE, r_s0, r_zero, b_off, ctx); | ||
1191 | emit_nop(ctx); | ||
1192 | /* jump false */ | ||
1193 | b_off = b_imm(i + inst->jf + 1, ctx); | ||
1194 | emit_b(b_off, ctx); | ||
1195 | emit_nop(ctx); | ||
1196 | break; | ||
1197 | case BPF_S_RET_A: | ||
1198 | ctx->flags |= SEEN_A; | ||
1199 | if (i != prog->len - 1) | ||
1200 | /* | ||
1201 | * If this is not the last instruction | ||
1202 | * then jump to the epilogue | ||
1203 | */ | ||
1204 | emit_b(b_imm(prog->len, ctx), ctx); | ||
1205 | emit_reg_move(r_ret, r_A, ctx); /* delay slot */ | ||
1206 | break; | ||
1207 | case BPF_S_RET_K: | ||
1208 | /* | ||
1209 | * It can emit two instructions so it does not fit on | ||
1210 | * the delay slot. | ||
1211 | */ | ||
1212 | emit_load_imm(r_ret, k, ctx); | ||
1213 | if (i != prog->len - 1) { | ||
1214 | /* | ||
1215 | * If this is not the last instruction | ||
1216 | * then jump to the epilogue | ||
1217 | */ | ||
1218 | emit_b(b_imm(prog->len, ctx), ctx); | ||
1219 | emit_nop(ctx); | ||
1220 | } | ||
1221 | break; | ||
1222 | case BPF_S_MISC_TAX: | ||
1223 | /* X = A */ | ||
1224 | ctx->flags |= SEEN_X | SEEN_A; | ||
1225 | emit_jit_reg_move(r_X, r_A, ctx); | ||
1226 | break; | ||
1227 | case BPF_S_MISC_TXA: | ||
1228 | /* A = X */ | ||
1229 | ctx->flags |= SEEN_A | SEEN_X; | ||
1230 | update_on_xread(ctx); | ||
1231 | emit_jit_reg_move(r_A, r_X, ctx); | ||
1232 | break; | ||
1233 | /* AUX */ | ||
1234 | case BPF_S_ANC_PROTOCOL: | ||
1235 | /* A = ntohs(skb->protocol */ | ||
1236 | ctx->flags |= SEEN_SKB | SEEN_OFF | SEEN_A; | ||
1237 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, | ||
1238 | protocol) != 2); | ||
1239 | off = offsetof(struct sk_buff, protocol); | ||
1240 | emit_half_load(r_A, r_skb, off, ctx); | ||
1241 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
1242 | /* This needs little endian fixup */ | ||
1243 | if (cpu_has_mips_r2) { | ||
1244 | /* R2 and later have the wsbh instruction */ | ||
1245 | emit_wsbh(r_A, r_A, ctx); | ||
1246 | } else { | ||
1247 | /* Get first byte */ | ||
1248 | emit_andi(r_tmp_imm, r_A, 0xff, ctx); | ||
1249 | /* Shift it */ | ||
1250 | emit_sll(r_tmp, r_tmp_imm, 8, ctx); | ||
1251 | /* Get second byte */ | ||
1252 | emit_srl(r_tmp_imm, r_A, 8, ctx); | ||
1253 | emit_andi(r_tmp_imm, r_tmp_imm, 0xff, ctx); | ||
1254 | /* Put everyting together in r_A */ | ||
1255 | emit_or(r_A, r_tmp, r_tmp_imm, ctx); | ||
1256 | } | ||
1257 | #endif | ||
1258 | break; | ||
1259 | case BPF_S_ANC_CPU: | ||
1260 | ctx->flags |= SEEN_A | SEEN_OFF; | ||
1261 | /* A = current_thread_info()->cpu */ | ||
1262 | BUILD_BUG_ON(FIELD_SIZEOF(struct thread_info, | ||
1263 | cpu) != 4); | ||
1264 | off = offsetof(struct thread_info, cpu); | ||
1265 | /* $28/gp points to the thread_info struct */ | ||
1266 | emit_load(r_A, 28, off, ctx); | ||
1267 | break; | ||
1268 | case BPF_S_ANC_IFINDEX: | ||
1269 | /* A = skb->dev->ifindex */ | ||
1270 | ctx->flags |= SEEN_SKB | SEEN_A | SEEN_S0; | ||
1271 | off = offsetof(struct sk_buff, dev); | ||
1272 | emit_load(r_s0, r_skb, off, ctx); | ||
1273 | /* error (0) in the delay slot */ | ||
1274 | emit_bcond(MIPS_COND_EQ, r_s0, r_zero, | ||
1275 | b_imm(prog->len, ctx), ctx); | ||
1276 | emit_reg_move(r_ret, r_zero, ctx); | ||
1277 | BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, | ||
1278 | ifindex) != 4); | ||
1279 | off = offsetof(struct net_device, ifindex); | ||
1280 | emit_load(r_A, r_s0, off, ctx); | ||
1281 | break; | ||
1282 | case BPF_S_ANC_MARK: | ||
1283 | ctx->flags |= SEEN_SKB | SEEN_A; | ||
1284 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); | ||
1285 | off = offsetof(struct sk_buff, mark); | ||
1286 | emit_load(r_A, r_skb, off, ctx); | ||
1287 | break; | ||
1288 | case BPF_S_ANC_RXHASH: | ||
1289 | ctx->flags |= SEEN_SKB | SEEN_A; | ||
1290 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4); | ||
1291 | off = offsetof(struct sk_buff, hash); | ||
1292 | emit_load(r_A, r_skb, off, ctx); | ||
1293 | break; | ||
1294 | case BPF_S_ANC_VLAN_TAG: | ||
1295 | case BPF_S_ANC_VLAN_TAG_PRESENT: | ||
1296 | ctx->flags |= SEEN_SKB | SEEN_S0 | SEEN_A; | ||
1297 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, | ||
1298 | vlan_tci) != 2); | ||
1299 | off = offsetof(struct sk_buff, vlan_tci); | ||
1300 | emit_half_load(r_s0, r_skb, off, ctx); | ||
1301 | if (inst->code == BPF_S_ANC_VLAN_TAG) | ||
1302 | emit_and(r_A, r_s0, VLAN_VID_MASK, ctx); | ||
1303 | else | ||
1304 | emit_and(r_A, r_s0, VLAN_TAG_PRESENT, ctx); | ||
1305 | break; | ||
1306 | case BPF_S_ANC_PKTTYPE: | ||
1307 | off = pkt_type_offset(); | ||
1308 | |||
1309 | if (off < 0) | ||
1310 | return -1; | ||
1311 | emit_load_byte(r_tmp, r_skb, off, ctx); | ||
1312 | /* Keep only the last 3 bits */ | ||
1313 | emit_andi(r_A, r_tmp, PKT_TYPE_MAX, ctx); | ||
1314 | break; | ||
1315 | case BPF_S_ANC_QUEUE: | ||
1316 | ctx->flags |= SEEN_SKB | SEEN_A; | ||
1317 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, | ||
1318 | queue_mapping) != 2); | ||
1319 | BUILD_BUG_ON(offsetof(struct sk_buff, | ||
1320 | queue_mapping) > 0xff); | ||
1321 | off = offsetof(struct sk_buff, queue_mapping); | ||
1322 | emit_half_load(r_A, r_skb, off, ctx); | ||
1323 | break; | ||
1324 | default: | ||
1325 | pr_warn("%s: Unhandled opcode: 0x%02x\n", __FILE__, | ||
1326 | inst->code); | ||
1327 | return -1; | ||
1328 | } | ||
1329 | } | ||
1330 | |||
1331 | /* compute offsets only during the first pass */ | ||
1332 | if (ctx->target == NULL) | ||
1333 | ctx->offsets[i] = ctx->idx * 4; | ||
1334 | |||
1335 | return 0; | ||
1336 | } | ||
1337 | |||
1338 | int bpf_jit_enable __read_mostly; | ||
1339 | |||
1340 | void bpf_jit_compile(struct sk_filter *fp) | ||
1341 | { | ||
1342 | struct jit_ctx ctx; | ||
1343 | unsigned int alloc_size, tmp_idx; | ||
1344 | |||
1345 | if (!bpf_jit_enable) | ||
1346 | return; | ||
1347 | |||
1348 | memset(&ctx, 0, sizeof(ctx)); | ||
1349 | |||
1350 | ctx.offsets = kcalloc(fp->len, sizeof(*ctx.offsets), GFP_KERNEL); | ||
1351 | if (ctx.offsets == NULL) | ||
1352 | return; | ||
1353 | |||
1354 | ctx.skf = fp; | ||
1355 | |||
1356 | if (build_body(&ctx)) | ||
1357 | goto out; | ||
1358 | |||
1359 | tmp_idx = ctx.idx; | ||
1360 | build_prologue(&ctx); | ||
1361 | ctx.prologue_bytes = (ctx.idx - tmp_idx) * 4; | ||
1362 | /* just to complete the ctx.idx count */ | ||
1363 | build_epilogue(&ctx); | ||
1364 | |||
1365 | alloc_size = 4 * ctx.idx; | ||
1366 | ctx.target = module_alloc(alloc_size); | ||
1367 | if (ctx.target == NULL) | ||
1368 | goto out; | ||
1369 | |||
1370 | /* Clean it */ | ||
1371 | memset(ctx.target, 0, alloc_size); | ||
1372 | |||
1373 | ctx.idx = 0; | ||
1374 | |||
1375 | /* Generate the actual JIT code */ | ||
1376 | build_prologue(&ctx); | ||
1377 | build_body(&ctx); | ||
1378 | build_epilogue(&ctx); | ||
1379 | |||
1380 | /* Update the icache */ | ||
1381 | flush_icache_range((ptr)ctx.target, (ptr)(ctx.target + ctx.idx)); | ||
1382 | |||
1383 | if (bpf_jit_enable > 1) | ||
1384 | /* Dump JIT code */ | ||
1385 | bpf_jit_dump(fp->len, alloc_size, 2, ctx.target); | ||
1386 | |||
1387 | fp->bpf_func = (void *)ctx.target; | ||
1388 | fp->jited = 1; | ||
1389 | |||
1390 | out: | ||
1391 | kfree(ctx.offsets); | ||
1392 | } | ||
1393 | |||
1394 | void bpf_jit_free(struct sk_filter *fp) | ||
1395 | { | ||
1396 | if (fp->jited) | ||
1397 | module_free(NULL, fp->bpf_func); | ||
1398 | kfree(fp); | ||
1399 | } | ||
diff --git a/arch/mips/net/bpf_jit.h b/arch/mips/net/bpf_jit.h new file mode 100644 index 000000000000..3a5751b4335a --- /dev/null +++ b/arch/mips/net/bpf_jit.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Just-In-Time compiler for BPF filters on MIPS | ||
3 | * | ||
4 | * Copyright (c) 2014 Imagination Technologies Ltd. | ||
5 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
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 as published by the | ||
9 | * Free Software Foundation; version 2 of the License. | ||
10 | */ | ||
11 | |||
12 | #ifndef BPF_JIT_MIPS_OP_H | ||
13 | #define BPF_JIT_MIPS_OP_H | ||
14 | |||
15 | /* Registers used by JIT */ | ||
16 | #define MIPS_R_ZERO 0 | ||
17 | #define MIPS_R_V0 2 | ||
18 | #define MIPS_R_V1 3 | ||
19 | #define MIPS_R_A0 4 | ||
20 | #define MIPS_R_A1 5 | ||
21 | #define MIPS_R_T6 14 | ||
22 | #define MIPS_R_T7 15 | ||
23 | #define MIPS_R_S0 16 | ||
24 | #define MIPS_R_S1 17 | ||
25 | #define MIPS_R_S2 18 | ||
26 | #define MIPS_R_S3 19 | ||
27 | #define MIPS_R_S4 20 | ||
28 | #define MIPS_R_S5 21 | ||
29 | #define MIPS_R_S6 22 | ||
30 | #define MIPS_R_S7 23 | ||
31 | #define MIPS_R_SP 29 | ||
32 | #define MIPS_R_RA 31 | ||
33 | |||
34 | /* Conditional codes */ | ||
35 | #define MIPS_COND_EQ 0x1 | ||
36 | #define MIPS_COND_GE (0x1 << 1) | ||
37 | #define MIPS_COND_GT (0x1 << 2) | ||
38 | #define MIPS_COND_NE (0x1 << 3) | ||
39 | #define MIPS_COND_ALL (0x1 << 4) | ||
40 | /* Conditionals on X register or K immediate */ | ||
41 | #define MIPS_COND_X (0x1 << 5) | ||
42 | #define MIPS_COND_K (0x1 << 6) | ||
43 | |||
44 | #endif /* BPF_JIT_MIPS_OP_H */ | ||
diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 5afc4b7fce0f..c100b9afa0ab 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c | |||
@@ -203,6 +203,8 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) | |||
203 | 203 | ||
204 | xirq = nlm_irq_to_xirq(node, irq); | 204 | xirq = nlm_irq_to_xirq(node, irq); |
205 | pic_data = irq_get_handler_data(xirq); | 205 | pic_data = irq_get_handler_data(xirq); |
206 | if (WARN_ON(!pic_data)) | ||
207 | return; | ||
206 | pic_data->extra_ack = xack; | 208 | pic_data->extra_ack = xack; |
207 | } | 209 | } |
208 | 210 | ||
diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S index b231fe1e7a09..701c4bcb9e47 100644 --- a/arch/mips/netlogic/common/reset.S +++ b/arch/mips/netlogic/common/reset.S | |||
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | #include <asm/asm.h> | 36 | #include <asm/asm.h> |
37 | #include <asm/asm-offsets.h> | 37 | #include <asm/asm-offsets.h> |
38 | #include <asm/cpu.h> | ||
38 | #include <asm/cacheops.h> | 39 | #include <asm/cacheops.h> |
39 | #include <asm/regdef.h> | 40 | #include <asm/regdef.h> |
40 | #include <asm/mipsregs.h> | 41 | #include <asm/mipsregs.h> |
@@ -74,13 +75,25 @@ | |||
74 | .endm | 75 | .endm |
75 | 76 | ||
76 | /* | 77 | /* |
78 | * Allow access to physical mem >64G by enabling ELPA in PAGEGRAIN | ||
79 | * register. This is needed before going to C code since the SP can | ||
80 | * in this region. Called from all HW threads. | ||
81 | */ | ||
82 | .macro xlp_early_mmu_init | ||
83 | mfc0 t0, CP0_PAGEMASK, 1 | ||
84 | li t1, (1 << 29) /* ELPA bit */ | ||
85 | or t0, t1 | ||
86 | mtc0 t0, CP0_PAGEMASK, 1 | ||
87 | .endm | ||
88 | |||
89 | /* | ||
77 | * L1D cache has to be flushed before enabling threads in XLP. | 90 | * L1D cache has to be flushed before enabling threads in XLP. |
78 | * On XLP8xx/XLP3xx, we do a low level flush using processor control | 91 | * On XLP8xx/XLP3xx, we do a low level flush using processor control |
79 | * registers. On XLPII CPUs, usual cache instructions work. | 92 | * registers. On XLPII CPUs, usual cache instructions work. |
80 | */ | 93 | */ |
81 | .macro xlp_flush_l1_dcache | 94 | .macro xlp_flush_l1_dcache |
82 | mfc0 t0, CP0_EBASE, 0 | 95 | mfc0 t0, CP0_EBASE, 0 |
83 | andi t0, t0, 0xff00 | 96 | andi t0, t0, PRID_IMP_MASK |
84 | slt t1, t0, 0x1200 | 97 | slt t1, t0, 0x1200 |
85 | beqz t1, 15f | 98 | beqz t1, 15f |
86 | nop | 99 | nop |
@@ -159,11 +172,15 @@ FEXPORT(nlm_reset_entry) | |||
159 | 172 | ||
160 | 1: /* Entry point on core wakeup */ | 173 | 1: /* Entry point on core wakeup */ |
161 | mfc0 t0, CP0_EBASE, 0 /* processor ID */ | 174 | mfc0 t0, CP0_EBASE, 0 /* processor ID */ |
162 | andi t0, 0xff00 | 175 | andi t0, PRID_IMP_MASK |
163 | li t1, 0x1500 /* XLP 9xx */ | 176 | li t1, 0x1500 /* XLP 9xx */ |
164 | beq t0, t1, 2f /* does not need to set coherent */ | 177 | beq t0, t1, 2f /* does not need to set coherent */ |
165 | nop | 178 | nop |
166 | 179 | ||
180 | li t1, 0x1300 /* XLP 5xx */ | ||
181 | beq t0, t1, 2f /* does not need to set coherent */ | ||
182 | nop | ||
183 | |||
167 | /* set bit in SYS coherent register for the core */ | 184 | /* set bit in SYS coherent register for the core */ |
168 | mfc0 t0, CP0_EBASE, 1 | 185 | mfc0 t0, CP0_EBASE, 1 |
169 | mfc0 t1, CP0_EBASE, 1 | 186 | mfc0 t1, CP0_EBASE, 1 |
@@ -197,6 +214,9 @@ FEXPORT(nlm_reset_entry) | |||
197 | EXPORT(nlm_boot_siblings) | 214 | EXPORT(nlm_boot_siblings) |
198 | /* core L1D flush before enable threads */ | 215 | /* core L1D flush before enable threads */ |
199 | xlp_flush_l1_dcache | 216 | xlp_flush_l1_dcache |
217 | /* save ra and sp, will be used later (only for boot cpu) */ | ||
218 | dmtc0 ra, $22, 6 | ||
219 | dmtc0 sp, $22, 7 | ||
200 | /* Enable hw threads by writing to MAP_THREADMODE of the core */ | 220 | /* Enable hw threads by writing to MAP_THREADMODE of the core */ |
201 | li t0, CKSEG1ADDR(RESET_DATA_PHYS) | 221 | li t0, CKSEG1ADDR(RESET_DATA_PHYS) |
202 | lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ | 222 | lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ |
@@ -225,6 +245,8 @@ EXPORT(nlm_boot_siblings) | |||
225 | #endif | 245 | #endif |
226 | mtc0 t1, CP0_STATUS | 246 | mtc0 t1, CP0_STATUS |
227 | 247 | ||
248 | xlp_early_mmu_init | ||
249 | |||
228 | /* mark CPU ready */ | 250 | /* mark CPU ready */ |
229 | li t3, CKSEG1ADDR(RESET_DATA_PHYS) | 251 | li t3, CKSEG1ADDR(RESET_DATA_PHYS) |
230 | ADDIU t1, t3, BOOT_CPU_READY | 252 | ADDIU t1, t3, BOOT_CPU_READY |
@@ -238,14 +260,12 @@ EXPORT(nlm_boot_siblings) | |||
238 | nop | 260 | nop |
239 | 261 | ||
240 | /* | 262 | /* |
241 | * For the boot CPU, we have to restore registers and | 263 | * For the boot CPU, we have to restore ra and sp and return, rest |
242 | * return | 264 | * of the registers will be restored by the caller |
243 | */ | 265 | */ |
244 | 4: dmfc0 t0, $4, 2 /* restore SP from UserLocal */ | 266 | 4: |
245 | li t1, 0xfadebeef | 267 | dmfc0 ra, $22, 6 |
246 | dmtc0 t1, $4, 2 /* restore SP from UserLocal */ | 268 | dmfc0 sp, $22, 7 |
247 | PTR_SUBU sp, t0, PT_SIZE | ||
248 | RESTORE_ALL | ||
249 | jr ra | 269 | jr ra |
250 | nop | 270 | nop |
251 | EXPORT(nlm_reset_entry_end) | 271 | EXPORT(nlm_reset_entry_end) |
@@ -253,6 +273,7 @@ EXPORT(nlm_reset_entry_end) | |||
253 | LEAF(nlm_init_boot_cpu) | 273 | LEAF(nlm_init_boot_cpu) |
254 | #ifdef CONFIG_CPU_XLP | 274 | #ifdef CONFIG_CPU_XLP |
255 | xlp_config_lsu | 275 | xlp_config_lsu |
276 | xlp_early_mmu_init | ||
256 | #endif | 277 | #endif |
257 | jr ra | 278 | jr ra |
258 | nop | 279 | nop |
diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index 6baae15cc7b1..4fde7ac76cc9 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c | |||
@@ -135,10 +135,6 @@ void nlm_smp_finish(void) | |||
135 | local_irq_enable(); | 135 | local_irq_enable(); |
136 | } | 136 | } |
137 | 137 | ||
138 | void nlm_cpus_done(void) | ||
139 | { | ||
140 | } | ||
141 | |||
142 | /* | 138 | /* |
143 | * Boot all other cpus in the system, initialize them, and bring them into | 139 | * Boot all other cpus in the system, initialize them, and bring them into |
144 | * the boot function | 140 | * the boot function |
@@ -198,7 +194,7 @@ void __init nlm_smp_setup(void) | |||
198 | cpumask_scnprintf(buf, ARRAY_SIZE(buf), cpu_possible_mask); | 194 | cpumask_scnprintf(buf, ARRAY_SIZE(buf), cpu_possible_mask); |
199 | pr_info("Possible CPU mask: %s\n", buf); | 195 | pr_info("Possible CPU mask: %s\n", buf); |
200 | 196 | ||
201 | /* check with the cores we have worken up */ | 197 | /* check with the cores we have woken up */ |
202 | for (ncore = 0, i = 0; i < NLM_NR_NODES; i++) | 198 | for (ncore = 0, i = 0; i < NLM_NR_NODES; i++) |
203 | ncore += hweight32(nlm_get_node(i)->coremask); | 199 | ncore += hweight32(nlm_get_node(i)->coremask); |
204 | 200 | ||
@@ -213,6 +209,7 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask) | |||
213 | { | 209 | { |
214 | uint32_t core0_thr_mask, core_thr_mask; | 210 | uint32_t core0_thr_mask, core_thr_mask; |
215 | int threadmode, i, j; | 211 | int threadmode, i, j; |
212 | char buf[64]; | ||
216 | 213 | ||
217 | core0_thr_mask = 0; | 214 | core0_thr_mask = 0; |
218 | for (i = 0; i < NLM_THREADS_PER_CORE; i++) | 215 | for (i = 0; i < NLM_THREADS_PER_CORE; i++) |
@@ -247,8 +244,8 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask) | |||
247 | return threadmode; | 244 | return threadmode; |
248 | 245 | ||
249 | unsupp: | 246 | unsupp: |
250 | panic("Unsupported CPU mask %lx", | 247 | cpumask_scnprintf(buf, ARRAY_SIZE(buf), wakeup_mask); |
251 | (unsigned long)cpumask_bits(wakeup_mask)[0]); | 248 | panic("Unsupported CPU mask %s", buf); |
252 | return 0; | 249 | return 0; |
253 | } | 250 | } |
254 | 251 | ||
@@ -277,7 +274,6 @@ struct plat_smp_ops nlm_smp_ops = { | |||
277 | .send_ipi_mask = nlm_send_ipi_mask, | 274 | .send_ipi_mask = nlm_send_ipi_mask, |
278 | .init_secondary = nlm_init_secondary, | 275 | .init_secondary = nlm_init_secondary, |
279 | .smp_finish = nlm_smp_finish, | 276 | .smp_finish = nlm_smp_finish, |
280 | .cpus_done = nlm_cpus_done, | ||
281 | .boot_secondary = nlm_boot_secondary, | 277 | .boot_secondary = nlm_boot_secondary, |
282 | .smp_setup = nlm_smp_setup, | 278 | .smp_setup = nlm_smp_setup, |
283 | .prepare_cpus = nlm_prepare_cpus, | 279 | .prepare_cpus = nlm_prepare_cpus, |
diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index 8597657c27fc..805355b0bd05 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S | |||
@@ -54,8 +54,9 @@ | |||
54 | .set noat | 54 | .set noat |
55 | .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ | 55 | .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ |
56 | 56 | ||
57 | FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ | 57 | /* Called by the boot cpu to wake up its sibling threads */ |
58 | dmtc0 sp, $4, 2 /* SP saved in UserLocal */ | 58 | NESTED(xlp_boot_core0_siblings, PT_SIZE, sp) |
59 | /* CPU register contents lost when enabling threads, save them first */ | ||
59 | SAVE_ALL | 60 | SAVE_ALL |
60 | sync | 61 | sync |
61 | /* find the location to which nlm_boot_siblings was relocated */ | 62 | /* find the location to which nlm_boot_siblings was relocated */ |
@@ -65,9 +66,12 @@ FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ | |||
65 | dsubu t2, t1 | 66 | dsubu t2, t1 |
66 | daddu t2, t0 | 67 | daddu t2, t0 |
67 | /* call it */ | 68 | /* call it */ |
68 | jr t2 | 69 | jalr t2 |
69 | nop | 70 | nop |
70 | /* not reached */ | 71 | RESTORE_ALL |
72 | jr ra | ||
73 | nop | ||
74 | END(xlp_boot_core0_siblings) | ||
71 | 75 | ||
72 | NESTED(nlm_boot_secondary_cpus, 16, sp) | 76 | NESTED(nlm_boot_secondary_cpus, 16, sp) |
73 | /* Initialize CP0 Status */ | 77 | /* Initialize CP0 Status */ |
diff --git a/arch/mips/netlogic/common/time.c b/arch/mips/netlogic/common/time.c index 13391b8a6031..0c0a1a606f73 100644 --- a/arch/mips/netlogic/common/time.c +++ b/arch/mips/netlogic/common/time.c | |||
@@ -82,6 +82,7 @@ static struct clocksource csrc_pic = { | |||
82 | static void nlm_init_pic_timer(void) | 82 | static void nlm_init_pic_timer(void) |
83 | { | 83 | { |
84 | uint64_t picbase = nlm_get_node(0)->picbase; | 84 | uint64_t picbase = nlm_get_node(0)->picbase; |
85 | u32 picfreq; | ||
85 | 86 | ||
86 | nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0); | 87 | nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0); |
87 | if (current_cpu_data.cputype == CPU_XLR) { | 88 | if (current_cpu_data.cputype == CPU_XLR) { |
@@ -92,7 +93,9 @@ static void nlm_init_pic_timer(void) | |||
92 | csrc_pic.read = nlm_get_pic_timer; | 93 | csrc_pic.read = nlm_get_pic_timer; |
93 | } | 94 | } |
94 | csrc_pic.rating = 1000; | 95 | csrc_pic.rating = 1000; |
95 | clocksource_register_hz(&csrc_pic, pic_timer_freq()); | 96 | picfreq = pic_timer_freq(); |
97 | clocksource_register_hz(&csrc_pic, picfreq); | ||
98 | pr_info("PIC clock source added, frequency %d\n", picfreq); | ||
96 | } | 99 | } |
97 | 100 | ||
98 | void __init plat_time_init(void) | 101 | void __init plat_time_init(void) |
diff --git a/arch/mips/netlogic/dts/xlp_gvp.dts b/arch/mips/netlogic/dts/xlp_gvp.dts index 047d27f54487..bb4ecd1d47fc 100644 --- a/arch/mips/netlogic/dts/xlp_gvp.dts +++ b/arch/mips/netlogic/dts/xlp_gvp.dts | |||
@@ -26,11 +26,12 @@ | |||
26 | interrupt-parent = <&pic>; | 26 | interrupt-parent = <&pic>; |
27 | interrupts = <17>; | 27 | interrupts = <17>; |
28 | }; | 28 | }; |
29 | pic: pic@4000 { | 29 | pic: pic@110000 { |
30 | interrupt-controller; | 30 | compatible = "netlogic,xlp-pic"; |
31 | #address-cells = <0>; | 31 | #address-cells = <0>; |
32 | #interrupt-cells = <1>; | 32 | #interrupt-cells = <1>; |
33 | reg = <0 0x110000 0x200>; | 33 | reg = <0 0x110000 0x200>; |
34 | interrupt-controller; | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | nor_flash@1,0 { | 37 | nor_flash@1,0 { |
diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile index ed9a93c04650..be358a8050c5 100644 --- a/arch/mips/netlogic/xlp/Makefile +++ b/arch/mips/netlogic/xlp/Makefile | |||
@@ -2,3 +2,5 @@ obj-y += setup.o nlm_hal.o cop2-ex.o dt.o | |||
2 | obj-$(CONFIG_SMP) += wakeup.o | 2 | obj-$(CONFIG_SMP) += wakeup.o |
3 | obj-$(CONFIG_USB) += usb-init.o | 3 | obj-$(CONFIG_USB) += usb-init.o |
4 | obj-$(CONFIG_USB) += usb-init-xlp2.o | 4 | obj-$(CONFIG_USB) += usb-init-xlp2.o |
5 | obj-$(CONFIG_SATA_AHCI) += ahci-init.o | ||
6 | obj-$(CONFIG_SATA_AHCI) += ahci-init-xlp2.o | ||
diff --git a/arch/mips/netlogic/xlp/ahci-init-xlp2.c b/arch/mips/netlogic/xlp/ahci-init-xlp2.c new file mode 100644 index 000000000000..c83dbf3689e2 --- /dev/null +++ b/arch/mips/netlogic/xlp/ahci-init-xlp2.c | |||
@@ -0,0 +1,377 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2014 Broadcom Corporation | ||
3 | * All Rights Reserved | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/dma-mapping.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/pci.h> | ||
40 | #include <linux/irq.h> | ||
41 | #include <linux/bitops.h> | ||
42 | #include <linux/pci_ids.h> | ||
43 | #include <linux/nodemask.h> | ||
44 | |||
45 | #include <asm/cpu.h> | ||
46 | #include <asm/mipsregs.h> | ||
47 | |||
48 | #include <asm/netlogic/common.h> | ||
49 | #include <asm/netlogic/haldefs.h> | ||
50 | #include <asm/netlogic/mips-extns.h> | ||
51 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
52 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
53 | |||
54 | #define SATA_CTL 0x0 | ||
55 | #define SATA_STATUS 0x1 /* Status Reg */ | ||
56 | #define SATA_INT 0x2 /* Interrupt Reg */ | ||
57 | #define SATA_INT_MASK 0x3 /* Interrupt Mask Reg */ | ||
58 | #define SATA_BIU_TIMEOUT 0x4 | ||
59 | #define AXIWRSPERRLOG 0x5 | ||
60 | #define AXIRDSPERRLOG 0x6 | ||
61 | #define BiuTimeoutLow 0x7 | ||
62 | #define BiuTimeoutHi 0x8 | ||
63 | #define BiuSlvErLow 0x9 | ||
64 | #define BiuSlvErHi 0xa | ||
65 | #define IO_CONFIG_SWAP_DIS 0xb | ||
66 | #define CR_REG_TIMER 0xc | ||
67 | #define CORE_ID 0xd | ||
68 | #define AXI_SLAVE_OPT1 0xe | ||
69 | #define PHY_MEM_ACCESS 0xf | ||
70 | #define PHY0_CNTRL 0x10 | ||
71 | #define PHY0_STAT 0x11 | ||
72 | #define PHY0_RX_ALIGN 0x12 | ||
73 | #define PHY0_RX_EQ_LO 0x13 | ||
74 | #define PHY0_RX_EQ_HI 0x14 | ||
75 | #define PHY0_BIST_LOOP 0x15 | ||
76 | #define PHY1_CNTRL 0x16 | ||
77 | #define PHY1_STAT 0x17 | ||
78 | #define PHY1_RX_ALIGN 0x18 | ||
79 | #define PHY1_RX_EQ_LO 0x19 | ||
80 | #define PHY1_RX_EQ_HI 0x1a | ||
81 | #define PHY1_BIST_LOOP 0x1b | ||
82 | #define RdExBase 0x1c | ||
83 | #define RdExLimit 0x1d | ||
84 | #define CacheAllocBase 0x1e | ||
85 | #define CacheAllocLimit 0x1f | ||
86 | #define BiuSlaveCmdGstNum 0x20 | ||
87 | |||
88 | /*SATA_CTL Bits */ | ||
89 | #define SATA_RST_N BIT(0) /* Active low reset sata_core phy */ | ||
90 | #define SataCtlReserve0 BIT(1) | ||
91 | #define M_CSYSREQ BIT(2) /* AXI master low power, not used */ | ||
92 | #define S_CSYSREQ BIT(3) /* AXI slave low power, not used */ | ||
93 | #define P0_CP_DET BIT(8) /* Reserved, bring in from pad */ | ||
94 | #define P0_MP_SW BIT(9) /* Mech Switch */ | ||
95 | #define P0_DISABLE BIT(10) /* disable p0 */ | ||
96 | #define P0_ACT_LED_EN BIT(11) /* Active LED enable */ | ||
97 | #define P0_IRST_HARD_SYNTH BIT(12) /* PHY hard synth reset */ | ||
98 | #define P0_IRST_HARD_TXRX BIT(13) /* PHY lane hard reset */ | ||
99 | #define P0_IRST_POR BIT(14) /* PHY power on reset*/ | ||
100 | #define P0_IPDTXL BIT(15) /* PHY Tx lane dis/power down */ | ||
101 | #define P0_IPDRXL BIT(16) /* PHY Rx lane dis/power down */ | ||
102 | #define P0_IPDIPDMSYNTH BIT(17) /* PHY synthesizer dis/porwer down */ | ||
103 | #define P0_CP_POD_EN BIT(18) /* CP_POD enable */ | ||
104 | #define P0_AT_BYPASS BIT(19) /* P0 address translation by pass */ | ||
105 | #define P1_CP_DET BIT(20) /* Reserved,Cold Detect */ | ||
106 | #define P1_MP_SW BIT(21) /* Mech Switch */ | ||
107 | #define P1_DISABLE BIT(22) /* disable p1 */ | ||
108 | #define P1_ACT_LED_EN BIT(23) /* Active LED enable */ | ||
109 | #define P1_IRST_HARD_SYNTH BIT(24) /* PHY hard synth reset */ | ||
110 | #define P1_IRST_HARD_TXRX BIT(25) /* PHY lane hard reset */ | ||
111 | #define P1_IRST_POR BIT(26) /* PHY power on reset*/ | ||
112 | #define P1_IPDTXL BIT(27) /* PHY Tx lane dis/porwer down */ | ||
113 | #define P1_IPDRXL BIT(28) /* PHY Rx lane dis/porwer down */ | ||
114 | #define P1_IPDIPDMSYNTH BIT(29) /* PHY synthesizer dis/porwer down */ | ||
115 | #define P1_CP_POD_EN BIT(30) | ||
116 | #define P1_AT_BYPASS BIT(31) /* P1 address translation by pass */ | ||
117 | |||
118 | /* Status register */ | ||
119 | #define M_CACTIVE BIT(0) /* m_cactive, not used */ | ||
120 | #define S_CACTIVE BIT(1) /* s_cactive, not used */ | ||
121 | #define P0_PHY_READY BIT(8) /* phy is ready */ | ||
122 | #define P0_CP_POD BIT(9) /* Cold PowerOn */ | ||
123 | #define P0_SLUMBER BIT(10) /* power mode slumber */ | ||
124 | #define P0_PATIAL BIT(11) /* power mode patial */ | ||
125 | #define P0_PHY_SIG_DET BIT(12) /* phy dignal detect */ | ||
126 | #define P0_PHY_CALI BIT(13) /* phy calibration done */ | ||
127 | #define P1_PHY_READY BIT(16) /* phy is ready */ | ||
128 | #define P1_CP_POD BIT(17) /* Cold PowerOn */ | ||
129 | #define P1_SLUMBER BIT(18) /* power mode slumber */ | ||
130 | #define P1_PATIAL BIT(19) /* power mode patial */ | ||
131 | #define P1_PHY_SIG_DET BIT(20) /* phy dignal detect */ | ||
132 | #define P1_PHY_CALI BIT(21) /* phy calibration done */ | ||
133 | |||
134 | /* SATA CR_REG_TIMER bits */ | ||
135 | #define CR_TIME_SCALE (0x1000 << 0) | ||
136 | |||
137 | /* SATA PHY specific registers start and end address */ | ||
138 | #define RXCDRCALFOSC0 0x0065 | ||
139 | #define CALDUTY 0x006e | ||
140 | #define RXDPIF 0x8065 | ||
141 | #define PPMDRIFTMAX_HI 0x80A4 | ||
142 | |||
143 | #define nlm_read_sata_reg(b, r) nlm_read_reg(b, r) | ||
144 | #define nlm_write_sata_reg(b, r, v) nlm_write_reg(b, r, v) | ||
145 | #define nlm_get_sata_pcibase(node) \ | ||
146 | nlm_pcicfg_base(XLP9XX_IO_SATA_OFFSET(node)) | ||
147 | #define nlm_get_sata_regbase(node) \ | ||
148 | (nlm_get_sata_pcibase(node) + 0x100) | ||
149 | |||
150 | /* SATA PHY config for register block 1 0x0065 .. 0x006e */ | ||
151 | static const u8 sata_phy_config1[] = { | ||
152 | 0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x01, 0x01, 0x22, 0x00 | ||
153 | }; | ||
154 | |||
155 | /* SATA PHY config for register block 2 0x0x8065 .. 0x0x80A4 */ | ||
156 | static const u8 sata_phy_config2[] = { | ||
157 | 0xAA, 0x00, 0x4C, 0xC9, 0xC9, 0x07, 0x07, 0x18, | ||
158 | 0x18, 0x05, 0x0C, 0x10, 0x00, 0x10, 0x00, 0xFF, | ||
159 | 0xCF, 0xF7, 0xE1, 0xF5, 0xFD, 0xFD, 0xFF, 0xFF, | ||
160 | 0xFF, 0xFF, 0xE3, 0xE7, 0xDB, 0xF5, 0xFD, 0xFD, | ||
161 | 0xF5, 0xF5, 0xFF, 0xFF, 0xE3, 0xE7, 0xDB, 0xF5, | ||
162 | 0xFD, 0xFD, 0xF5, 0xF5, 0xFF, 0xFF, 0xFF, 0xF5, | ||
163 | 0x3F, 0x00, 0x32, 0x00, 0x03, 0x01, 0x05, 0x05, | ||
164 | 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x04, | ||
165 | }; | ||
166 | |||
167 | const int sata_phy_debug = 0; /* set to verify PHY writes */ | ||
168 | |||
169 | static void sata_clear_glue_reg(u64 regbase, u32 off, u32 bit) | ||
170 | { | ||
171 | u32 reg_val; | ||
172 | |||
173 | reg_val = nlm_read_sata_reg(regbase, off); | ||
174 | nlm_write_sata_reg(regbase, off, (reg_val & ~bit)); | ||
175 | } | ||
176 | |||
177 | static void sata_set_glue_reg(u64 regbase, u32 off, u32 bit) | ||
178 | { | ||
179 | u32 reg_val; | ||
180 | |||
181 | reg_val = nlm_read_sata_reg(regbase, off); | ||
182 | nlm_write_sata_reg(regbase, off, (reg_val | bit)); | ||
183 | } | ||
184 | |||
185 | static void write_phy_reg(u64 regbase, u32 addr, u32 physel, u8 data) | ||
186 | { | ||
187 | nlm_write_sata_reg(regbase, PHY_MEM_ACCESS, | ||
188 | (1u << 31) | (physel << 24) | (data << 16) | addr); | ||
189 | udelay(850); | ||
190 | } | ||
191 | |||
192 | static u8 read_phy_reg(u64 regbase, u32 addr, u32 physel) | ||
193 | { | ||
194 | u32 val; | ||
195 | |||
196 | nlm_write_sata_reg(regbase, PHY_MEM_ACCESS, | ||
197 | (0 << 31) | (physel << 24) | (0 << 16) | addr); | ||
198 | udelay(850); | ||
199 | val = nlm_read_sata_reg(regbase, PHY_MEM_ACCESS); | ||
200 | return (val >> 16) & 0xff; | ||
201 | } | ||
202 | |||
203 | static void config_sata_phy(u64 regbase) | ||
204 | { | ||
205 | u32 port, i, reg; | ||
206 | |||
207 | for (port = 0; port < 2; port++) { | ||
208 | for (i = 0, reg = RXCDRCALFOSC0; reg <= CALDUTY; reg++, i++) | ||
209 | write_phy_reg(regbase, reg, port, sata_phy_config1[i]); | ||
210 | |||
211 | for (i = 0, reg = RXDPIF; reg <= PPMDRIFTMAX_HI; reg++, i++) | ||
212 | write_phy_reg(regbase, reg, port, sata_phy_config2[i]); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static void check_phy_register(u64 regbase, u32 addr, u32 physel, u8 xdata) | ||
217 | { | ||
218 | u8 data; | ||
219 | |||
220 | data = read_phy_reg(regbase, addr, physel); | ||
221 | pr_info("PHY read addr = 0x%x physel = %d data = 0x%x %s\n", | ||
222 | addr, physel, data, data == xdata ? "TRUE" : "FALSE"); | ||
223 | } | ||
224 | |||
225 | static void verify_sata_phy_config(u64 regbase) | ||
226 | { | ||
227 | u32 port, i, reg; | ||
228 | |||
229 | for (port = 0; port < 2; port++) { | ||
230 | for (i = 0, reg = RXCDRCALFOSC0; reg <= CALDUTY; reg++, i++) | ||
231 | check_phy_register(regbase, reg, port, | ||
232 | sata_phy_config1[i]); | ||
233 | |||
234 | for (i = 0, reg = RXDPIF; reg <= PPMDRIFTMAX_HI; reg++, i++) | ||
235 | check_phy_register(regbase, reg, port, | ||
236 | sata_phy_config2[i]); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static void nlm_sata_firmware_init(int node) | ||
241 | { | ||
242 | u32 reg_val; | ||
243 | u64 regbase; | ||
244 | int n; | ||
245 | |||
246 | pr_info("Initializing XLP9XX On-chip AHCI...\n"); | ||
247 | regbase = nlm_get_sata_regbase(node); | ||
248 | |||
249 | /* Reset port0 */ | ||
250 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_POR); | ||
251 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_TXRX); | ||
252 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_SYNTH); | ||
253 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDTXL); | ||
254 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDRXL); | ||
255 | sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDIPDMSYNTH); | ||
256 | |||
257 | /* port1 */ | ||
258 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_POR); | ||
259 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_TXRX); | ||
260 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_SYNTH); | ||
261 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDTXL); | ||
262 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDRXL); | ||
263 | sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDIPDMSYNTH); | ||
264 | udelay(300); | ||
265 | |||
266 | /* Set PHY */ | ||
267 | sata_set_glue_reg(regbase, SATA_CTL, P0_IPDTXL); | ||
268 | sata_set_glue_reg(regbase, SATA_CTL, P0_IPDRXL); | ||
269 | sata_set_glue_reg(regbase, SATA_CTL, P0_IPDIPDMSYNTH); | ||
270 | sata_set_glue_reg(regbase, SATA_CTL, P1_IPDTXL); | ||
271 | sata_set_glue_reg(regbase, SATA_CTL, P1_IPDRXL); | ||
272 | sata_set_glue_reg(regbase, SATA_CTL, P1_IPDIPDMSYNTH); | ||
273 | |||
274 | udelay(1000); | ||
275 | sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_POR); | ||
276 | udelay(1000); | ||
277 | sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_POR); | ||
278 | udelay(1000); | ||
279 | |||
280 | /* setup PHY */ | ||
281 | config_sata_phy(regbase); | ||
282 | if (sata_phy_debug) | ||
283 | verify_sata_phy_config(regbase); | ||
284 | |||
285 | udelay(1000); | ||
286 | sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_TXRX); | ||
287 | sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_SYNTH); | ||
288 | sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_TXRX); | ||
289 | sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_SYNTH); | ||
290 | udelay(300); | ||
291 | |||
292 | /* Override reset in serial PHY mode */ | ||
293 | sata_set_glue_reg(regbase, CR_REG_TIMER, CR_TIME_SCALE); | ||
294 | /* Set reset SATA */ | ||
295 | sata_set_glue_reg(regbase, SATA_CTL, SATA_RST_N); | ||
296 | sata_set_glue_reg(regbase, SATA_CTL, M_CSYSREQ); | ||
297 | sata_set_glue_reg(regbase, SATA_CTL, S_CSYSREQ); | ||
298 | |||
299 | pr_debug("Waiting for PHYs to come up.\n"); | ||
300 | n = 10000; | ||
301 | do { | ||
302 | reg_val = nlm_read_sata_reg(regbase, SATA_STATUS); | ||
303 | if ((reg_val & P1_PHY_READY) && (reg_val & P0_PHY_READY)) | ||
304 | break; | ||
305 | udelay(10); | ||
306 | } while (--n > 0); | ||
307 | |||
308 | if (reg_val & P0_PHY_READY) | ||
309 | pr_info("PHY0 is up.\n"); | ||
310 | else | ||
311 | pr_info("PHY0 is down.\n"); | ||
312 | if (reg_val & P1_PHY_READY) | ||
313 | pr_info("PHY1 is up.\n"); | ||
314 | else | ||
315 | pr_info("PHY1 is down.\n"); | ||
316 | |||
317 | pr_info("XLP AHCI Init Done.\n"); | ||
318 | } | ||
319 | |||
320 | static int __init nlm_ahci_init(void) | ||
321 | { | ||
322 | int node; | ||
323 | |||
324 | if (!cpu_is_xlp9xx()) | ||
325 | return 0; | ||
326 | for (node = 0; node < NLM_NR_NODES; node++) | ||
327 | if (nlm_node_present(node)) | ||
328 | nlm_sata_firmware_init(node); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static void nlm_sata_intr_ack(struct irq_data *data) | ||
333 | { | ||
334 | u64 regbase; | ||
335 | u32 val; | ||
336 | int node; | ||
337 | |||
338 | node = data->irq / NLM_IRQS_PER_NODE; | ||
339 | regbase = nlm_get_sata_regbase(node); | ||
340 | val = nlm_read_sata_reg(regbase, SATA_INT); | ||
341 | sata_set_glue_reg(regbase, SATA_INT, val); | ||
342 | } | ||
343 | |||
344 | static void nlm_sata_fixup_bar(struct pci_dev *dev) | ||
345 | { | ||
346 | dev->resource[5] = dev->resource[0]; | ||
347 | memset(&dev->resource[0], 0, sizeof(dev->resource[0])); | ||
348 | } | ||
349 | |||
350 | static void nlm_sata_fixup_final(struct pci_dev *dev) | ||
351 | { | ||
352 | u32 val; | ||
353 | u64 regbase; | ||
354 | int node; | ||
355 | |||
356 | /* Find end bridge function to find node */ | ||
357 | node = xlp_socdev_to_node(dev); | ||
358 | regbase = nlm_get_sata_regbase(node); | ||
359 | |||
360 | /* clear pending interrupts and then enable them */ | ||
361 | val = nlm_read_sata_reg(regbase, SATA_INT); | ||
362 | sata_set_glue_reg(regbase, SATA_INT, val); | ||
363 | |||
364 | /* Enable only the core interrupt */ | ||
365 | sata_set_glue_reg(regbase, SATA_INT_MASK, 0x1); | ||
366 | |||
367 | dev->irq = nlm_irq_to_xirq(node, PIC_SATA_IRQ); | ||
368 | nlm_set_pic_extra_ack(node, PIC_SATA_IRQ, nlm_sata_intr_ack); | ||
369 | } | ||
370 | |||
371 | arch_initcall(nlm_ahci_init); | ||
372 | |||
373 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_SATA, | ||
374 | nlm_sata_fixup_bar); | ||
375 | |||
376 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_SATA, | ||
377 | nlm_sata_fixup_final); | ||
diff --git a/arch/mips/netlogic/xlp/ahci-init.c b/arch/mips/netlogic/xlp/ahci-init.c new file mode 100644 index 000000000000..a9d0fae02103 --- /dev/null +++ b/arch/mips/netlogic/xlp/ahci-init.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2014 Broadcom Corporation | ||
3 | * All Rights Reserved | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/dma-mapping.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/pci.h> | ||
40 | #include <linux/irq.h> | ||
41 | #include <linux/bitops.h> | ||
42 | |||
43 | #include <asm/cpu.h> | ||
44 | #include <asm/mipsregs.h> | ||
45 | |||
46 | #include <asm/netlogic/haldefs.h> | ||
47 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
48 | #include <asm/netlogic/common.h> | ||
49 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
50 | #include <asm/netlogic/mips-extns.h> | ||
51 | |||
52 | #define SATA_CTL 0x0 | ||
53 | #define SATA_STATUS 0x1 /* Status Reg */ | ||
54 | #define SATA_INT 0x2 /* Interrupt Reg */ | ||
55 | #define SATA_INT_MASK 0x3 /* Interrupt Mask Reg */ | ||
56 | #define SATA_CR_REG_TIMER 0x4 /* PHY Conrol Timer Reg */ | ||
57 | #define SATA_CORE_ID 0x5 /* Core ID Reg */ | ||
58 | #define SATA_AXI_SLAVE_OPT1 0x6 /* AXI Slave Options Reg */ | ||
59 | #define SATA_PHY_LOS_LEV 0x7 /* PHY LOS Level Reg */ | ||
60 | #define SATA_PHY_MULTI 0x8 /* PHY Multiplier Reg */ | ||
61 | #define SATA_PHY_CLK_SEL 0x9 /* Clock Select Reg */ | ||
62 | #define SATA_PHY_AMP1_GEN1 0xa /* PHY Transmit Amplitude Reg 1 */ | ||
63 | #define SATA_PHY_AMP1_GEN2 0xb /* PHY Transmit Amplitude Reg 2 */ | ||
64 | #define SATA_PHY_AMP1_GEN3 0xc /* PHY Transmit Amplitude Reg 3 */ | ||
65 | #define SATA_PHY_PRE1 0xd /* PHY Transmit Preemphasis Reg 1 */ | ||
66 | #define SATA_PHY_PRE2 0xe /* PHY Transmit Preemphasis Reg 2 */ | ||
67 | #define SATA_PHY_PRE3 0xf /* PHY Transmit Preemphasis Reg 3 */ | ||
68 | #define SATA_SPDMODE 0x10 /* Speed Mode Reg */ | ||
69 | #define SATA_REFCLK 0x11 /* Reference Clock Control Reg */ | ||
70 | #define SATA_BYTE_SWAP_DIS 0x12 /* byte swap disable */ | ||
71 | |||
72 | /*SATA_CTL Bits */ | ||
73 | #define SATA_RST_N BIT(0) | ||
74 | #define PHY0_RESET_N BIT(16) | ||
75 | #define PHY1_RESET_N BIT(17) | ||
76 | #define PHY2_RESET_N BIT(18) | ||
77 | #define PHY3_RESET_N BIT(19) | ||
78 | #define M_CSYSREQ BIT(2) | ||
79 | #define S_CSYSREQ BIT(3) | ||
80 | |||
81 | /*SATA_STATUS Bits */ | ||
82 | #define P0_PHY_READY BIT(4) | ||
83 | #define P1_PHY_READY BIT(5) | ||
84 | #define P2_PHY_READY BIT(6) | ||
85 | #define P3_PHY_READY BIT(7) | ||
86 | |||
87 | #define nlm_read_sata_reg(b, r) nlm_read_reg(b, r) | ||
88 | #define nlm_write_sata_reg(b, r, v) nlm_write_reg(b, r, v) | ||
89 | #define nlm_get_sata_pcibase(node) \ | ||
90 | nlm_pcicfg_base(XLP_IO_SATA_OFFSET(node)) | ||
91 | /* SATA device specific configuration registers are starts at 0x900 offset */ | ||
92 | #define nlm_get_sata_regbase(node) \ | ||
93 | (nlm_get_sata_pcibase(node) + 0x900) | ||
94 | |||
95 | static void sata_clear_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) | ||
96 | { | ||
97 | uint32_t reg_val; | ||
98 | |||
99 | reg_val = nlm_read_sata_reg(regbase, off); | ||
100 | nlm_write_sata_reg(regbase, off, (reg_val & ~bit)); | ||
101 | } | ||
102 | |||
103 | static void sata_set_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) | ||
104 | { | ||
105 | uint32_t reg_val; | ||
106 | |||
107 | reg_val = nlm_read_sata_reg(regbase, off); | ||
108 | nlm_write_sata_reg(regbase, off, (reg_val | bit)); | ||
109 | } | ||
110 | |||
111 | static void nlm_sata_firmware_init(int node) | ||
112 | { | ||
113 | uint32_t reg_val; | ||
114 | uint64_t regbase; | ||
115 | int i; | ||
116 | |||
117 | pr_info("XLP AHCI Initialization started.\n"); | ||
118 | regbase = nlm_get_sata_regbase(node); | ||
119 | |||
120 | /* Reset SATA */ | ||
121 | sata_clear_glue_reg(regbase, SATA_CTL, SATA_RST_N); | ||
122 | /* Reset PHY */ | ||
123 | sata_clear_glue_reg(regbase, SATA_CTL, | ||
124 | (PHY3_RESET_N | PHY2_RESET_N | ||
125 | | PHY1_RESET_N | PHY0_RESET_N)); | ||
126 | |||
127 | /* Set SATA */ | ||
128 | sata_set_glue_reg(regbase, SATA_CTL, SATA_RST_N); | ||
129 | /* Set PHY */ | ||
130 | sata_set_glue_reg(regbase, SATA_CTL, | ||
131 | (PHY3_RESET_N | PHY2_RESET_N | ||
132 | | PHY1_RESET_N | PHY0_RESET_N)); | ||
133 | |||
134 | pr_debug("Waiting for PHYs to come up.\n"); | ||
135 | i = 0; | ||
136 | do { | ||
137 | reg_val = nlm_read_sata_reg(regbase, SATA_STATUS); | ||
138 | i++; | ||
139 | } while (((reg_val & 0xF0) != 0xF0) && (i < 10000)); | ||
140 | |||
141 | for (i = 0; i < 4; i++) { | ||
142 | if (reg_val & (P0_PHY_READY << i)) | ||
143 | pr_info("PHY%d is up.\n", i); | ||
144 | else | ||
145 | pr_info("PHY%d is down.\n", i); | ||
146 | } | ||
147 | |||
148 | pr_info("XLP AHCI init done.\n"); | ||
149 | } | ||
150 | |||
151 | static int __init nlm_ahci_init(void) | ||
152 | { | ||
153 | int node = 0; | ||
154 | int chip = read_c0_prid() & PRID_REV_MASK; | ||
155 | |||
156 | if (chip == PRID_IMP_NETLOGIC_XLP3XX) | ||
157 | nlm_sata_firmware_init(node); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void nlm_sata_intr_ack(struct irq_data *data) | ||
162 | { | ||
163 | uint32_t val = 0; | ||
164 | uint64_t regbase; | ||
165 | |||
166 | regbase = nlm_get_sata_regbase(nlm_nodeid()); | ||
167 | val = nlm_read_sata_reg(regbase, SATA_INT); | ||
168 | sata_set_glue_reg(regbase, SATA_INT, val); | ||
169 | } | ||
170 | |||
171 | static void nlm_sata_fixup_bar(struct pci_dev *dev) | ||
172 | { | ||
173 | /* | ||
174 | * The AHCI resource is in BAR 0, move it to | ||
175 | * BAR 5, where it is expected | ||
176 | */ | ||
177 | dev->resource[5] = dev->resource[0]; | ||
178 | memset(&dev->resource[0], 0, sizeof(dev->resource[0])); | ||
179 | } | ||
180 | |||
181 | static void nlm_sata_fixup_final(struct pci_dev *dev) | ||
182 | { | ||
183 | uint32_t val; | ||
184 | uint64_t regbase; | ||
185 | int node = 0; /* XLP3XX does not support multi-node */ | ||
186 | |||
187 | regbase = nlm_get_sata_regbase(node); | ||
188 | |||
189 | /* clear pending interrupts and then enable them */ | ||
190 | val = nlm_read_sata_reg(regbase, SATA_INT); | ||
191 | sata_set_glue_reg(regbase, SATA_INT, val); | ||
192 | |||
193 | /* Mask the core interrupt. If all the interrupts | ||
194 | * are enabled there are spurious interrupt flow | ||
195 | * happening, to avoid only enable core interrupt | ||
196 | * mask. | ||
197 | */ | ||
198 | sata_set_glue_reg(regbase, SATA_INT_MASK, 0x1); | ||
199 | |||
200 | dev->irq = PIC_SATA_IRQ; | ||
201 | nlm_set_pic_extra_ack(node, PIC_SATA_IRQ, nlm_sata_intr_ack); | ||
202 | } | ||
203 | |||
204 | arch_initcall(nlm_ahci_init); | ||
205 | |||
206 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, | ||
207 | nlm_sata_fixup_bar); | ||
208 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, | ||
209 | nlm_sata_fixup_final); | ||
diff --git a/arch/mips/netlogic/xlp/dt.c b/arch/mips/netlogic/xlp/dt.c index bdde33147bce..7cc46032b28e 100644 --- a/arch/mips/netlogic/xlp/dt.c +++ b/arch/mips/netlogic/xlp/dt.c | |||
@@ -48,9 +48,10 @@ static void *xlp_fdt_blob; | |||
48 | void __init *xlp_dt_init(void *fdtp) | 48 | void __init *xlp_dt_init(void *fdtp) |
49 | { | 49 | { |
50 | if (!fdtp) { | 50 | if (!fdtp) { |
51 | switch (current_cpu_data.processor_id & 0xff00) { | 51 | switch (current_cpu_data.processor_id & PRID_IMP_MASK) { |
52 | #ifdef CONFIG_DT_XLP_GVP | 52 | #ifdef CONFIG_DT_XLP_GVP |
53 | case PRID_IMP_NETLOGIC_XLP9XX: | 53 | case PRID_IMP_NETLOGIC_XLP9XX: |
54 | case PRID_IMP_NETLOGIC_XLP5XX: | ||
54 | fdtp = __dtb_xlp_gvp_begin; | 55 | fdtp = __dtb_xlp_gvp_begin; |
55 | break; | 56 | break; |
56 | #endif | 57 | #endif |
diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index 997cd9ee10de..bc24beb3a426 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c | |||
@@ -54,6 +54,8 @@ void nlm_node_init(int node) | |||
54 | struct nlm_soc_info *nodep; | 54 | struct nlm_soc_info *nodep; |
55 | 55 | ||
56 | nodep = nlm_get_node(node); | 56 | nodep = nlm_get_node(node); |
57 | if (node == 0) | ||
58 | nodep->coremask = 1; /* node 0, boot cpu */ | ||
57 | nodep->sysbase = nlm_get_sys_regbase(node); | 59 | nodep->sysbase = nlm_get_sys_regbase(node); |
58 | nodep->picbase = nlm_get_pic_regbase(node); | 60 | nodep->picbase = nlm_get_pic_regbase(node); |
59 | nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); | 61 | nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); |
@@ -64,31 +66,39 @@ void nlm_node_init(int node) | |||
64 | spin_lock_init(&nodep->piclock); | 66 | spin_lock_init(&nodep->piclock); |
65 | } | 67 | } |
66 | 68 | ||
67 | int nlm_irq_to_irt(int irq) | 69 | static int xlp9xx_irq_to_irt(int irq) |
70 | { | ||
71 | switch (irq) { | ||
72 | case PIC_GPIO_IRQ: | ||
73 | return 12; | ||
74 | case PIC_9XX_XHCI_0_IRQ: | ||
75 | return 114; | ||
76 | case PIC_9XX_XHCI_1_IRQ: | ||
77 | return 115; | ||
78 | case PIC_UART_0_IRQ: | ||
79 | return 133; | ||
80 | case PIC_UART_1_IRQ: | ||
81 | return 134; | ||
82 | case PIC_SATA_IRQ: | ||
83 | return 143; | ||
84 | case PIC_SPI_IRQ: | ||
85 | return 152; | ||
86 | case PIC_MMC_IRQ: | ||
87 | return 153; | ||
88 | case PIC_PCIE_LINK_LEGACY_IRQ(0): | ||
89 | case PIC_PCIE_LINK_LEGACY_IRQ(1): | ||
90 | case PIC_PCIE_LINK_LEGACY_IRQ(2): | ||
91 | case PIC_PCIE_LINK_LEGACY_IRQ(3): | ||
92 | return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE; | ||
93 | } | ||
94 | return -1; | ||
95 | } | ||
96 | |||
97 | static int xlp_irq_to_irt(int irq) | ||
68 | { | 98 | { |
69 | uint64_t pcibase; | 99 | uint64_t pcibase; |
70 | int devoff, irt; | 100 | int devoff, irt; |
71 | 101 | ||
72 | /* bypass for 9xx */ | ||
73 | if (cpu_is_xlp9xx()) { | ||
74 | switch (irq) { | ||
75 | case PIC_9XX_XHCI_0_IRQ: | ||
76 | return 114; | ||
77 | case PIC_9XX_XHCI_1_IRQ: | ||
78 | return 115; | ||
79 | case PIC_UART_0_IRQ: | ||
80 | return 133; | ||
81 | case PIC_UART_1_IRQ: | ||
82 | return 134; | ||
83 | case PIC_PCIE_LINK_LEGACY_IRQ(0): | ||
84 | case PIC_PCIE_LINK_LEGACY_IRQ(1): | ||
85 | case PIC_PCIE_LINK_LEGACY_IRQ(2): | ||
86 | case PIC_PCIE_LINK_LEGACY_IRQ(3): | ||
87 | return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE; | ||
88 | } | ||
89 | return -1; | ||
90 | } | ||
91 | |||
92 | devoff = 0; | 102 | devoff = 0; |
93 | switch (irq) { | 103 | switch (irq) { |
94 | case PIC_UART_0_IRQ: | 104 | case PIC_UART_0_IRQ: |
@@ -98,7 +108,7 @@ int nlm_irq_to_irt(int irq) | |||
98 | devoff = XLP_IO_UART1_OFFSET(0); | 108 | devoff = XLP_IO_UART1_OFFSET(0); |
99 | break; | 109 | break; |
100 | case PIC_MMC_IRQ: | 110 | case PIC_MMC_IRQ: |
101 | devoff = XLP_IO_SD_OFFSET(0); | 111 | devoff = XLP_IO_MMC_OFFSET(0); |
102 | break; | 112 | break; |
103 | case PIC_I2C_0_IRQ: /* I2C will be fixed up */ | 113 | case PIC_I2C_0_IRQ: /* I2C will be fixed up */ |
104 | case PIC_I2C_1_IRQ: | 114 | case PIC_I2C_1_IRQ: |
@@ -109,6 +119,18 @@ int nlm_irq_to_irt(int irq) | |||
109 | else | 119 | else |
110 | devoff = XLP_IO_I2C0_OFFSET(0); | 120 | devoff = XLP_IO_I2C0_OFFSET(0); |
111 | break; | 121 | break; |
122 | case PIC_SATA_IRQ: | ||
123 | devoff = XLP_IO_SATA_OFFSET(0); | ||
124 | break; | ||
125 | case PIC_GPIO_IRQ: | ||
126 | devoff = XLP_IO_GPIO_OFFSET(0); | ||
127 | break; | ||
128 | case PIC_NAND_IRQ: | ||
129 | devoff = XLP_IO_NAND_OFFSET(0); | ||
130 | break; | ||
131 | case PIC_SPI_IRQ: | ||
132 | devoff = XLP_IO_SPI_OFFSET(0); | ||
133 | break; | ||
112 | default: | 134 | default: |
113 | if (cpu_is_xlpii()) { | 135 | if (cpu_is_xlpii()) { |
114 | switch (irq) { | 136 | switch (irq) { |
@@ -164,61 +186,123 @@ int nlm_irq_to_irt(int irq) | |||
164 | /* HW bug, PCI IRT entries are bad on early silicon, fix */ | 186 | /* HW bug, PCI IRT entries are bad on early silicon, fix */ |
165 | irt = PIC_IRT_PCIE_LINK_INDEX(irq - | 187 | irt = PIC_IRT_PCIE_LINK_INDEX(irq - |
166 | PIC_PCIE_LINK_LEGACY_IRQ_BASE); | 188 | PIC_PCIE_LINK_LEGACY_IRQ_BASE); |
167 | } else if (irq >= PIC_PCIE_LINK_MSI_IRQ(0) && | ||
168 | irq <= PIC_PCIE_LINK_MSI_IRQ(3)) { | ||
169 | irt = -2; | ||
170 | } else if (irq >= PIC_PCIE_MSIX_IRQ(0) && | ||
171 | irq <= PIC_PCIE_MSIX_IRQ(3)) { | ||
172 | irt = -2; | ||
173 | } else { | 189 | } else { |
174 | irt = -1; | 190 | irt = -1; |
175 | } | 191 | } |
176 | return irt; | 192 | return irt; |
177 | } | 193 | } |
178 | 194 | ||
179 | unsigned int nlm_get_core_frequency(int node, int core) | 195 | int nlm_irq_to_irt(int irq) |
180 | { | 196 | { |
181 | unsigned int pll_divf, pll_divr, dfs_div, ext_div; | 197 | /* return -2 for irqs without 1-1 mapping */ |
182 | unsigned int rstval, dfsval, denom; | 198 | if (irq >= PIC_PCIE_LINK_MSI_IRQ(0) && irq <= PIC_PCIE_LINK_MSI_IRQ(3)) |
183 | uint64_t num, sysbase; | 199 | return -2; |
200 | if (irq >= PIC_PCIE_MSIX_IRQ(0) && irq <= PIC_PCIE_MSIX_IRQ(3)) | ||
201 | return -2; | ||
184 | 202 | ||
185 | sysbase = nlm_get_node(node)->sysbase; | ||
186 | if (cpu_is_xlp9xx()) | 203 | if (cpu_is_xlp9xx()) |
187 | rstval = nlm_read_sys_reg(sysbase, SYS_9XX_POWER_ON_RESET_CFG); | 204 | return xlp9xx_irq_to_irt(irq); |
188 | else | 205 | else |
189 | rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); | 206 | return xlp_irq_to_irt(irq); |
190 | if (cpu_is_xlpii()) { | 207 | } |
191 | num = 1000000ULL * (400 * 3 + 100 * (rstval >> 26)); | 208 | |
192 | denom = 3; | 209 | static unsigned int nlm_xlp2_get_core_frequency(int node, int core) |
210 | { | ||
211 | unsigned int pll_post_div, ctrl_val0, ctrl_val1, denom; | ||
212 | uint64_t num, sysbase, clockbase; | ||
213 | |||
214 | if (cpu_is_xlp9xx()) { | ||
215 | clockbase = nlm_get_clock_regbase(node); | ||
216 | ctrl_val0 = nlm_read_sys_reg(clockbase, | ||
217 | SYS_9XX_CPU_PLL_CTRL0(core)); | ||
218 | ctrl_val1 = nlm_read_sys_reg(clockbase, | ||
219 | SYS_9XX_CPU_PLL_CTRL1(core)); | ||
193 | } else { | 220 | } else { |
194 | dfsval = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIV_VALUE); | 221 | sysbase = nlm_get_node(node)->sysbase; |
195 | pll_divf = ((rstval >> 10) & 0x7f) + 1; | 222 | ctrl_val0 = nlm_read_sys_reg(sysbase, |
196 | pll_divr = ((rstval >> 8) & 0x3) + 1; | 223 | SYS_CPU_PLL_CTRL0(core)); |
197 | ext_div = ((rstval >> 30) & 0x3) + 1; | 224 | ctrl_val1 = nlm_read_sys_reg(sysbase, |
198 | dfs_div = ((dfsval >> (core * 4)) & 0xf) + 1; | 225 | SYS_CPU_PLL_CTRL1(core)); |
199 | 226 | } | |
200 | num = 800000000ULL * pll_divf; | 227 | |
201 | denom = 3 * pll_divr * ext_div * dfs_div; | 228 | /* Find PLL post divider value */ |
229 | switch ((ctrl_val0 >> 24) & 0x7) { | ||
230 | case 1: | ||
231 | pll_post_div = 2; | ||
232 | break; | ||
233 | case 3: | ||
234 | pll_post_div = 4; | ||
235 | break; | ||
236 | case 7: | ||
237 | pll_post_div = 8; | ||
238 | break; | ||
239 | case 6: | ||
240 | pll_post_div = 16; | ||
241 | break; | ||
242 | case 0: | ||
243 | default: | ||
244 | pll_post_div = 1; | ||
245 | break; | ||
202 | } | 246 | } |
247 | |||
248 | num = 1000000ULL * (400 * 3 + 100 * (ctrl_val1 & 0x3f)); | ||
249 | denom = 3 * pll_post_div; | ||
203 | do_div(num, denom); | 250 | do_div(num, denom); |
251 | |||
204 | return (unsigned int)num; | 252 | return (unsigned int)num; |
205 | } | 253 | } |
206 | 254 | ||
207 | /* Calculate Frequency to the PIC from PLL. | 255 | static unsigned int nlm_xlp_get_core_frequency(int node, int core) |
208 | * freq_out = ( ref_freq/2 * (6 + ctrl2[7:0]) + ctrl2[20:8]/2^13 ) / | 256 | { |
209 | * ((2^ctrl0[7:5]) * Table(ctrl0[26:24])) | 257 | unsigned int pll_divf, pll_divr, dfs_div, ext_div; |
258 | unsigned int rstval, dfsval, denom; | ||
259 | uint64_t num, sysbase; | ||
260 | |||
261 | sysbase = nlm_get_node(node)->sysbase; | ||
262 | rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); | ||
263 | dfsval = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIV_VALUE); | ||
264 | pll_divf = ((rstval >> 10) & 0x7f) + 1; | ||
265 | pll_divr = ((rstval >> 8) & 0x3) + 1; | ||
266 | ext_div = ((rstval >> 30) & 0x3) + 1; | ||
267 | dfs_div = ((dfsval >> (core * 4)) & 0xf) + 1; | ||
268 | |||
269 | num = 800000000ULL * pll_divf; | ||
270 | denom = 3 * pll_divr * ext_div * dfs_div; | ||
271 | do_div(num, denom); | ||
272 | |||
273 | return (unsigned int)num; | ||
274 | } | ||
275 | |||
276 | unsigned int nlm_get_core_frequency(int node, int core) | ||
277 | { | ||
278 | if (cpu_is_xlpii()) | ||
279 | return nlm_xlp2_get_core_frequency(node, core); | ||
280 | else | ||
281 | return nlm_xlp_get_core_frequency(node, core); | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Calculate PIC frequency from PLL registers. | ||
286 | * freq_out = (ref_freq/2 * (6 + ctrl2[7:0]) + ctrl2[20:8]/2^13) / | ||
287 | * ((2^ctrl0[7:5]) * Table(ctrl0[26:24])) | ||
210 | */ | 288 | */ |
211 | static unsigned int nlm_2xx_get_pic_frequency(int node) | 289 | static unsigned int nlm_xlp2_get_pic_frequency(int node) |
212 | { | 290 | { |
213 | u32 ctrl_val0, ctrl_val2, vco_post_div, pll_post_div; | 291 | u32 ctrl_val0, ctrl_val2, vco_post_div, pll_post_div, cpu_xlp9xx; |
214 | u32 mdiv, fdiv, pll_out_freq_den, reg_select, ref_div, pic_div; | 292 | u32 mdiv, fdiv, pll_out_freq_den, reg_select, ref_div, pic_div; |
215 | u64 ref_clk, sysbase, pll_out_freq_num, ref_clk_select; | 293 | u64 sysbase, pll_out_freq_num, ref_clk_select, clockbase, ref_clk; |
216 | 294 | ||
217 | sysbase = nlm_get_node(node)->sysbase; | 295 | sysbase = nlm_get_node(node)->sysbase; |
296 | clockbase = nlm_get_clock_regbase(node); | ||
297 | cpu_xlp9xx = cpu_is_xlp9xx(); | ||
218 | 298 | ||
219 | /* Find ref_clk_base */ | 299 | /* Find ref_clk_base */ |
220 | ref_clk_select = | 300 | if (cpu_xlp9xx) |
221 | (nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG) >> 18) & 0x3; | 301 | ref_clk_select = (nlm_read_sys_reg(sysbase, |
302 | SYS_9XX_POWER_ON_RESET_CFG) >> 18) & 0x3; | ||
303 | else | ||
304 | ref_clk_select = (nlm_read_sys_reg(sysbase, | ||
305 | SYS_POWER_ON_RESET_CFG) >> 18) & 0x3; | ||
222 | switch (ref_clk_select) { | 306 | switch (ref_clk_select) { |
223 | case 0: | 307 | case 0: |
224 | ref_clk = 200000000ULL; | 308 | ref_clk = 200000000ULL; |
@@ -239,30 +323,70 @@ static unsigned int nlm_2xx_get_pic_frequency(int node) | |||
239 | } | 323 | } |
240 | 324 | ||
241 | /* Find the clock source PLL device for PIC */ | 325 | /* Find the clock source PLL device for PIC */ |
242 | reg_select = (nlm_read_sys_reg(sysbase, SYS_CLK_DEV_SEL) >> 22) & 0x3; | 326 | if (cpu_xlp9xx) { |
243 | switch (reg_select) { | 327 | reg_select = nlm_read_sys_reg(clockbase, |
244 | case 0: | 328 | SYS_9XX_CLK_DEV_SEL) & 0x3; |
245 | ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0); | 329 | switch (reg_select) { |
246 | ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2); | 330 | case 0: |
247 | break; | 331 | ctrl_val0 = nlm_read_sys_reg(clockbase, |
248 | case 1: | 332 | SYS_9XX_PLL_CTRL0); |
249 | ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(0)); | 333 | ctrl_val2 = nlm_read_sys_reg(clockbase, |
250 | ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(0)); | 334 | SYS_9XX_PLL_CTRL2); |
251 | break; | 335 | break; |
252 | case 2: | 336 | case 1: |
253 | ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(1)); | 337 | ctrl_val0 = nlm_read_sys_reg(clockbase, |
254 | ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(1)); | 338 | SYS_9XX_PLL_CTRL0_DEVX(0)); |
255 | break; | 339 | ctrl_val2 = nlm_read_sys_reg(clockbase, |
256 | case 3: | 340 | SYS_9XX_PLL_CTRL2_DEVX(0)); |
257 | ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(2)); | 341 | break; |
258 | ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(2)); | 342 | case 2: |
259 | break; | 343 | ctrl_val0 = nlm_read_sys_reg(clockbase, |
344 | SYS_9XX_PLL_CTRL0_DEVX(1)); | ||
345 | ctrl_val2 = nlm_read_sys_reg(clockbase, | ||
346 | SYS_9XX_PLL_CTRL2_DEVX(1)); | ||
347 | break; | ||
348 | case 3: | ||
349 | ctrl_val0 = nlm_read_sys_reg(clockbase, | ||
350 | SYS_9XX_PLL_CTRL0_DEVX(2)); | ||
351 | ctrl_val2 = nlm_read_sys_reg(clockbase, | ||
352 | SYS_9XX_PLL_CTRL2_DEVX(2)); | ||
353 | break; | ||
354 | } | ||
355 | } else { | ||
356 | reg_select = (nlm_read_sys_reg(sysbase, | ||
357 | SYS_CLK_DEV_SEL) >> 22) & 0x3; | ||
358 | switch (reg_select) { | ||
359 | case 0: | ||
360 | ctrl_val0 = nlm_read_sys_reg(sysbase, | ||
361 | SYS_PLL_CTRL0); | ||
362 | ctrl_val2 = nlm_read_sys_reg(sysbase, | ||
363 | SYS_PLL_CTRL2); | ||
364 | break; | ||
365 | case 1: | ||
366 | ctrl_val0 = nlm_read_sys_reg(sysbase, | ||
367 | SYS_PLL_CTRL0_DEVX(0)); | ||
368 | ctrl_val2 = nlm_read_sys_reg(sysbase, | ||
369 | SYS_PLL_CTRL2_DEVX(0)); | ||
370 | break; | ||
371 | case 2: | ||
372 | ctrl_val0 = nlm_read_sys_reg(sysbase, | ||
373 | SYS_PLL_CTRL0_DEVX(1)); | ||
374 | ctrl_val2 = nlm_read_sys_reg(sysbase, | ||
375 | SYS_PLL_CTRL2_DEVX(1)); | ||
376 | break; | ||
377 | case 3: | ||
378 | ctrl_val0 = nlm_read_sys_reg(sysbase, | ||
379 | SYS_PLL_CTRL0_DEVX(2)); | ||
380 | ctrl_val2 = nlm_read_sys_reg(sysbase, | ||
381 | SYS_PLL_CTRL2_DEVX(2)); | ||
382 | break; | ||
383 | } | ||
260 | } | 384 | } |
261 | 385 | ||
262 | vco_post_div = (ctrl_val0 >> 5) & 0x7; | 386 | vco_post_div = (ctrl_val0 >> 5) & 0x7; |
263 | pll_post_div = (ctrl_val0 >> 24) & 0x7; | 387 | pll_post_div = (ctrl_val0 >> 24) & 0x7; |
264 | mdiv = ctrl_val2 & 0xff; | 388 | mdiv = ctrl_val2 & 0xff; |
265 | fdiv = (ctrl_val2 >> 8) & 0xfff; | 389 | fdiv = (ctrl_val2 >> 8) & 0x1fff; |
266 | 390 | ||
267 | /* Find PLL post divider value */ | 391 | /* Find PLL post divider value */ |
268 | switch (pll_post_div) { | 392 | switch (pll_post_div) { |
@@ -292,7 +416,12 @@ static unsigned int nlm_2xx_get_pic_frequency(int node) | |||
292 | do_div(pll_out_freq_num, pll_out_freq_den); | 416 | do_div(pll_out_freq_num, pll_out_freq_den); |
293 | 417 | ||
294 | /* PIC post divider, which happens after PLL */ | 418 | /* PIC post divider, which happens after PLL */ |
295 | pic_div = (nlm_read_sys_reg(sysbase, SYS_CLK_DEV_DIV) >> 22) & 0x3; | 419 | if (cpu_xlp9xx) |
420 | pic_div = nlm_read_sys_reg(clockbase, | ||
421 | SYS_9XX_CLK_DEV_DIV) & 0x3; | ||
422 | else | ||
423 | pic_div = (nlm_read_sys_reg(sysbase, | ||
424 | SYS_CLK_DEV_DIV) >> 22) & 0x3; | ||
296 | do_div(pll_out_freq_num, 1 << pic_div); | 425 | do_div(pll_out_freq_num, 1 << pic_div); |
297 | 426 | ||
298 | return pll_out_freq_num; | 427 | return pll_out_freq_num; |
@@ -300,12 +429,8 @@ static unsigned int nlm_2xx_get_pic_frequency(int node) | |||
300 | 429 | ||
301 | unsigned int nlm_get_pic_frequency(int node) | 430 | unsigned int nlm_get_pic_frequency(int node) |
302 | { | 431 | { |
303 | /* TODO Has to calculate freq as like 2xx */ | ||
304 | if (cpu_is_xlp9xx()) | ||
305 | return 250000000; | ||
306 | |||
307 | if (cpu_is_xlpii()) | 432 | if (cpu_is_xlpii()) |
308 | return nlm_2xx_get_pic_frequency(node); | 433 | return nlm_xlp2_get_pic_frequency(node); |
309 | else | 434 | else |
310 | return 133333333; | 435 | return 133333333; |
311 | } | 436 | } |
diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c index 8c60a2dd9ef6..4fdd9fd29d1d 100644 --- a/arch/mips/netlogic/xlp/setup.c +++ b/arch/mips/netlogic/xlp/setup.c | |||
@@ -121,8 +121,9 @@ void __init plat_mem_setup(void) | |||
121 | 121 | ||
122 | const char *get_system_type(void) | 122 | const char *get_system_type(void) |
123 | { | 123 | { |
124 | switch (read_c0_prid() & 0xff00) { | 124 | switch (read_c0_prid() & PRID_IMP_MASK) { |
125 | case PRID_IMP_NETLOGIC_XLP9XX: | 125 | case PRID_IMP_NETLOGIC_XLP9XX: |
126 | case PRID_IMP_NETLOGIC_XLP5XX: | ||
126 | case PRID_IMP_NETLOGIC_XLP2XX: | 127 | case PRID_IMP_NETLOGIC_XLP2XX: |
127 | return "Broadcom XLPII Series"; | 128 | return "Broadcom XLPII Series"; |
128 | default: | 129 | default: |
diff --git a/arch/mips/netlogic/xlp/wakeup.c b/arch/mips/netlogic/xlp/wakeup.c index 9a92617a2af5..e5f44d2605a8 100644 --- a/arch/mips/netlogic/xlp/wakeup.c +++ b/arch/mips/netlogic/xlp/wakeup.c | |||
@@ -135,11 +135,19 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) | |||
135 | if (cpu_is_xlp9xx()) { | 135 | if (cpu_is_xlp9xx()) { |
136 | fusebase = nlm_get_fuse_regbase(n); | 136 | fusebase = nlm_get_fuse_regbase(n); |
137 | fusemask = nlm_read_reg(fusebase, FUSE_9XX_DEVCFG6); | 137 | fusemask = nlm_read_reg(fusebase, FUSE_9XX_DEVCFG6); |
138 | mask = 0xfffff; | 138 | switch (read_c0_prid() & PRID_IMP_MASK) { |
139 | case PRID_IMP_NETLOGIC_XLP5XX: | ||
140 | mask = 0xff; | ||
141 | break; | ||
142 | case PRID_IMP_NETLOGIC_XLP9XX: | ||
143 | default: | ||
144 | mask = 0xfffff; | ||
145 | break; | ||
146 | } | ||
139 | } else { | 147 | } else { |
140 | fusemask = nlm_read_sys_reg(nodep->sysbase, | 148 | fusemask = nlm_read_sys_reg(nodep->sysbase, |
141 | SYS_EFUSE_DEVICE_CFG_STATUS0); | 149 | SYS_EFUSE_DEVICE_CFG_STATUS0); |
142 | switch (read_c0_prid() & 0xff00) { | 150 | switch (read_c0_prid() & PRID_IMP_MASK) { |
143 | case PRID_IMP_NETLOGIC_XLP3XX: | 151 | case PRID_IMP_NETLOGIC_XLP3XX: |
144 | mask = 0xf; | 152 | mask = 0xf; |
145 | break; | 153 | break; |
@@ -159,10 +167,6 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) | |||
159 | */ | 167 | */ |
160 | syscoremask = (1 << hweight32(~fusemask & mask)) - 1; | 168 | syscoremask = (1 << hweight32(~fusemask & mask)) - 1; |
161 | 169 | ||
162 | /* The boot cpu */ | ||
163 | if (n == 0) | ||
164 | nodep->coremask = 1; | ||
165 | |||
166 | pr_info("Node %d - SYS/FUSE coremask %x\n", n, syscoremask); | 170 | pr_info("Node %d - SYS/FUSE coremask %x\n", n, syscoremask); |
167 | for (core = 0; core < nlm_cores_per_node(); core++) { | 171 | for (core = 0; core < nlm_cores_per_node(); core++) { |
168 | /* we will be on node 0 core 0 */ | 172 | /* we will be on node 0 core 0 */ |
diff --git a/arch/mips/paravirt/Kconfig b/arch/mips/paravirt/Kconfig new file mode 100644 index 000000000000..ecae5861b601 --- /dev/null +++ b/arch/mips/paravirt/Kconfig | |||
@@ -0,0 +1,6 @@ | |||
1 | if MIPS_PARAVIRT | ||
2 | |||
3 | config MIPS_PCI_VIRTIO | ||
4 | def_bool y | ||
5 | |||
6 | endif # MIPS_PARAVIRT | ||
diff --git a/arch/mips/paravirt/Makefile b/arch/mips/paravirt/Makefile new file mode 100644 index 000000000000..5023af733a35 --- /dev/null +++ b/arch/mips/paravirt/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | # | ||
2 | # Makefile for MIPS para-virtualized specific kernel interface routines | ||
3 | # under Linux. | ||
4 | # | ||
5 | # This file is subject to the terms and conditions of the GNU General Public | ||
6 | # License. See the file "COPYING" in the main directory of this archive | ||
7 | # for more details. | ||
8 | # | ||
9 | # Copyright (C) 2013 Cavium, Inc. | ||
10 | # | ||
11 | |||
12 | obj-y := setup.o serial.o paravirt-irq.o | ||
13 | |||
14 | obj-$(CONFIG_SMP) += paravirt-smp.o | ||
diff --git a/arch/mips/paravirt/Platform b/arch/mips/paravirt/Platform new file mode 100644 index 000000000000..7e76ef25ea17 --- /dev/null +++ b/arch/mips/paravirt/Platform | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Generic para-virtualized guest. | ||
3 | # | ||
4 | platform-$(CONFIG_MIPS_PARAVIRT) += paravirt/ | ||
5 | cflags-$(CONFIG_MIPS_PARAVIRT) += \ | ||
6 | -I$(srctree)/arch/mips/include/asm/mach-paravirt | ||
7 | |||
8 | load-$(CONFIG_MIPS_PARAVIRT) = 0xffffffff80010000 | ||
diff --git a/arch/mips/paravirt/paravirt-irq.c b/arch/mips/paravirt/paravirt-irq.c new file mode 100644 index 000000000000..8987b06c9de9 --- /dev/null +++ b/arch/mips/paravirt/paravirt-irq.c | |||
@@ -0,0 +1,368 @@ | |||
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 | * Copyright (C) 2013 Cavium, Inc. | ||
7 | */ | ||
8 | |||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/cpumask.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/mutex.h> | ||
13 | |||
14 | #include <asm/io.h> | ||
15 | |||
16 | #define MBOX_BITS_PER_CPU 2 | ||
17 | |||
18 | static int cpunum_for_cpu(int cpu) | ||
19 | { | ||
20 | #ifdef CONFIG_SMP | ||
21 | return cpu_logical_map(cpu); | ||
22 | #else | ||
23 | return get_ebase_cpunum(); | ||
24 | #endif | ||
25 | } | ||
26 | |||
27 | struct core_chip_data { | ||
28 | struct mutex core_irq_mutex; | ||
29 | bool current_en; | ||
30 | bool desired_en; | ||
31 | u8 bit; | ||
32 | }; | ||
33 | |||
34 | static struct core_chip_data irq_core_chip_data[8]; | ||
35 | |||
36 | static void irq_core_ack(struct irq_data *data) | ||
37 | { | ||
38 | struct core_chip_data *cd = irq_data_get_irq_chip_data(data); | ||
39 | unsigned int bit = cd->bit; | ||
40 | |||
41 | /* | ||
42 | * We don't need to disable IRQs to make these atomic since | ||
43 | * they are already disabled earlier in the low level | ||
44 | * interrupt code. | ||
45 | */ | ||
46 | clear_c0_status(0x100 << bit); | ||
47 | /* The two user interrupts must be cleared manually. */ | ||
48 | if (bit < 2) | ||
49 | clear_c0_cause(0x100 << bit); | ||
50 | } | ||
51 | |||
52 | static void irq_core_eoi(struct irq_data *data) | ||
53 | { | ||
54 | struct core_chip_data *cd = irq_data_get_irq_chip_data(data); | ||
55 | |||
56 | /* | ||
57 | * We don't need to disable IRQs to make these atomic since | ||
58 | * they are already disabled earlier in the low level | ||
59 | * interrupt code. | ||
60 | */ | ||
61 | set_c0_status(0x100 << cd->bit); | ||
62 | } | ||
63 | |||
64 | static void irq_core_set_enable_local(void *arg) | ||
65 | { | ||
66 | struct irq_data *data = arg; | ||
67 | struct core_chip_data *cd = irq_data_get_irq_chip_data(data); | ||
68 | unsigned int mask = 0x100 << cd->bit; | ||
69 | |||
70 | /* | ||
71 | * Interrupts are already disabled, so these are atomic. | ||
72 | */ | ||
73 | if (cd->desired_en) | ||
74 | set_c0_status(mask); | ||
75 | else | ||
76 | clear_c0_status(mask); | ||
77 | |||
78 | } | ||
79 | |||
80 | static void irq_core_disable(struct irq_data *data) | ||
81 | { | ||
82 | struct core_chip_data *cd = irq_data_get_irq_chip_data(data); | ||
83 | cd->desired_en = false; | ||
84 | } | ||
85 | |||
86 | static void irq_core_enable(struct irq_data *data) | ||
87 | { | ||
88 | struct core_chip_data *cd = irq_data_get_irq_chip_data(data); | ||
89 | cd->desired_en = true; | ||
90 | } | ||
91 | |||
92 | static void irq_core_bus_lock(struct irq_data *data) | ||
93 | { | ||
94 | struct core_chip_data *cd = irq_data_get_irq_chip_data(data); | ||
95 | |||
96 | mutex_lock(&cd->core_irq_mutex); | ||
97 | } | ||
98 | |||
99 | static void irq_core_bus_sync_unlock(struct irq_data *data) | ||
100 | { | ||
101 | struct core_chip_data *cd = irq_data_get_irq_chip_data(data); | ||
102 | |||
103 | if (cd->desired_en != cd->current_en) { | ||
104 | on_each_cpu(irq_core_set_enable_local, data, 1); | ||
105 | cd->current_en = cd->desired_en; | ||
106 | } | ||
107 | |||
108 | mutex_unlock(&cd->core_irq_mutex); | ||
109 | } | ||
110 | |||
111 | static struct irq_chip irq_chip_core = { | ||
112 | .name = "Core", | ||
113 | .irq_enable = irq_core_enable, | ||
114 | .irq_disable = irq_core_disable, | ||
115 | .irq_ack = irq_core_ack, | ||
116 | .irq_eoi = irq_core_eoi, | ||
117 | .irq_bus_lock = irq_core_bus_lock, | ||
118 | .irq_bus_sync_unlock = irq_core_bus_sync_unlock, | ||
119 | |||
120 | .irq_cpu_online = irq_core_eoi, | ||
121 | .irq_cpu_offline = irq_core_ack, | ||
122 | .flags = IRQCHIP_ONOFFLINE_ENABLED, | ||
123 | }; | ||
124 | |||
125 | static void __init irq_init_core(void) | ||
126 | { | ||
127 | int i; | ||
128 | int irq; | ||
129 | struct core_chip_data *cd; | ||
130 | |||
131 | /* Start with a clean slate */ | ||
132 | clear_c0_status(ST0_IM); | ||
133 | clear_c0_cause(CAUSEF_IP0 | CAUSEF_IP1); | ||
134 | |||
135 | for (i = 0; i < ARRAY_SIZE(irq_core_chip_data); i++) { | ||
136 | cd = irq_core_chip_data + i; | ||
137 | cd->current_en = false; | ||
138 | cd->desired_en = false; | ||
139 | cd->bit = i; | ||
140 | mutex_init(&cd->core_irq_mutex); | ||
141 | |||
142 | irq = MIPS_CPU_IRQ_BASE + i; | ||
143 | |||
144 | switch (i) { | ||
145 | case 0: /* SW0 */ | ||
146 | case 1: /* SW1 */ | ||
147 | case 5: /* IP5 */ | ||
148 | case 6: /* IP6 */ | ||
149 | case 7: /* IP7 */ | ||
150 | irq_set_chip_data(irq, cd); | ||
151 | irq_set_chip_and_handler(irq, &irq_chip_core, | ||
152 | handle_percpu_irq); | ||
153 | break; | ||
154 | default: | ||
155 | break; | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static void __iomem *mips_irq_chip; | ||
161 | #define MIPS_IRQ_CHIP_NUM_BITS 0 | ||
162 | #define MIPS_IRQ_CHIP_REGS 8 | ||
163 | |||
164 | static int mips_irq_cpu_stride; | ||
165 | static int mips_irq_chip_reg_raw; | ||
166 | static int mips_irq_chip_reg_src; | ||
167 | static int mips_irq_chip_reg_en; | ||
168 | static int mips_irq_chip_reg_raw_w1s; | ||
169 | static int mips_irq_chip_reg_raw_w1c; | ||
170 | static int mips_irq_chip_reg_en_w1s; | ||
171 | static int mips_irq_chip_reg_en_w1c; | ||
172 | |||
173 | static void irq_pci_enable(struct irq_data *data) | ||
174 | { | ||
175 | u32 mask = 1u << data->irq; | ||
176 | |||
177 | __raw_writel(mask, mips_irq_chip + mips_irq_chip_reg_en_w1s); | ||
178 | } | ||
179 | |||
180 | static void irq_pci_disable(struct irq_data *data) | ||
181 | { | ||
182 | u32 mask = 1u << data->irq; | ||
183 | |||
184 | __raw_writel(mask, mips_irq_chip + mips_irq_chip_reg_en_w1c); | ||
185 | } | ||
186 | |||
187 | static void irq_pci_ack(struct irq_data *data) | ||
188 | { | ||
189 | } | ||
190 | |||
191 | static void irq_pci_mask(struct irq_data *data) | ||
192 | { | ||
193 | u32 mask = 1u << data->irq; | ||
194 | |||
195 | __raw_writel(mask, mips_irq_chip + mips_irq_chip_reg_en_w1c); | ||
196 | } | ||
197 | |||
198 | static void irq_pci_unmask(struct irq_data *data) | ||
199 | { | ||
200 | u32 mask = 1u << data->irq; | ||
201 | |||
202 | __raw_writel(mask, mips_irq_chip + mips_irq_chip_reg_en_w1s); | ||
203 | } | ||
204 | |||
205 | static struct irq_chip irq_chip_pci = { | ||
206 | .name = "PCI", | ||
207 | .irq_enable = irq_pci_enable, | ||
208 | .irq_disable = irq_pci_disable, | ||
209 | .irq_ack = irq_pci_ack, | ||
210 | .irq_mask = irq_pci_mask, | ||
211 | .irq_unmask = irq_pci_unmask, | ||
212 | }; | ||
213 | |||
214 | static void irq_mbox_all(struct irq_data *data, void __iomem *base) | ||
215 | { | ||
216 | int cpu; | ||
217 | unsigned int mbox = data->irq - MIPS_IRQ_MBOX0; | ||
218 | u32 mask; | ||
219 | |||
220 | WARN_ON(mbox >= MBOX_BITS_PER_CPU); | ||
221 | |||
222 | for_each_online_cpu(cpu) { | ||
223 | unsigned int cpuid = cpunum_for_cpu(cpu); | ||
224 | mask = 1 << (cpuid * MBOX_BITS_PER_CPU + mbox); | ||
225 | __raw_writel(mask, base + (cpuid * mips_irq_cpu_stride)); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static void irq_mbox_enable(struct irq_data *data) | ||
230 | { | ||
231 | irq_mbox_all(data, mips_irq_chip + mips_irq_chip_reg_en_w1s + sizeof(u32)); | ||
232 | } | ||
233 | |||
234 | static void irq_mbox_disable(struct irq_data *data) | ||
235 | { | ||
236 | irq_mbox_all(data, mips_irq_chip + mips_irq_chip_reg_en_w1c + sizeof(u32)); | ||
237 | } | ||
238 | |||
239 | static void irq_mbox_ack(struct irq_data *data) | ||
240 | { | ||
241 | u32 mask; | ||
242 | unsigned int mbox = data->irq - MIPS_IRQ_MBOX0; | ||
243 | |||
244 | WARN_ON(mbox >= MBOX_BITS_PER_CPU); | ||
245 | |||
246 | mask = 1 << (get_ebase_cpunum() * MBOX_BITS_PER_CPU + mbox); | ||
247 | __raw_writel(mask, mips_irq_chip + mips_irq_chip_reg_raw_w1c + sizeof(u32)); | ||
248 | } | ||
249 | |||
250 | void irq_mbox_ipi(int cpu, unsigned int actions) | ||
251 | { | ||
252 | unsigned int cpuid = cpunum_for_cpu(cpu); | ||
253 | u32 mask; | ||
254 | |||
255 | WARN_ON(actions >= (1 << MBOX_BITS_PER_CPU)); | ||
256 | |||
257 | mask = actions << (cpuid * MBOX_BITS_PER_CPU); | ||
258 | __raw_writel(mask, mips_irq_chip + mips_irq_chip_reg_raw_w1s + sizeof(u32)); | ||
259 | } | ||
260 | |||
261 | static void irq_mbox_cpu_onoffline(struct irq_data *data, void __iomem *base) | ||
262 | { | ||
263 | unsigned int mbox = data->irq - MIPS_IRQ_MBOX0; | ||
264 | unsigned int cpuid = get_ebase_cpunum(); | ||
265 | u32 mask; | ||
266 | |||
267 | WARN_ON(mbox >= MBOX_BITS_PER_CPU); | ||
268 | |||
269 | mask = 1 << (cpuid * MBOX_BITS_PER_CPU + mbox); | ||
270 | __raw_writel(mask, base + (cpuid * mips_irq_cpu_stride)); | ||
271 | |||
272 | } | ||
273 | |||
274 | static void irq_mbox_cpu_online(struct irq_data *data) | ||
275 | { | ||
276 | irq_mbox_cpu_onoffline(data, mips_irq_chip + mips_irq_chip_reg_en_w1s + sizeof(u32)); | ||
277 | } | ||
278 | |||
279 | static void irq_mbox_cpu_offline(struct irq_data *data) | ||
280 | { | ||
281 | irq_mbox_cpu_onoffline(data, mips_irq_chip + mips_irq_chip_reg_en_w1c + sizeof(u32)); | ||
282 | } | ||
283 | |||
284 | static struct irq_chip irq_chip_mbox = { | ||
285 | .name = "MBOX", | ||
286 | .irq_enable = irq_mbox_enable, | ||
287 | .irq_disable = irq_mbox_disable, | ||
288 | .irq_ack = irq_mbox_ack, | ||
289 | .irq_cpu_online = irq_mbox_cpu_online, | ||
290 | .irq_cpu_offline = irq_mbox_cpu_offline, | ||
291 | .flags = IRQCHIP_ONOFFLINE_ENABLED, | ||
292 | }; | ||
293 | |||
294 | static void __init irq_pci_init(void) | ||
295 | { | ||
296 | int i, stride; | ||
297 | u32 num_bits; | ||
298 | |||
299 | mips_irq_chip = ioremap(0x1e010000, 4096); | ||
300 | |||
301 | num_bits = __raw_readl(mips_irq_chip + MIPS_IRQ_CHIP_NUM_BITS); | ||
302 | stride = 8 * (1 + ((num_bits - 1) / 64)); | ||
303 | |||
304 | |||
305 | pr_notice("mips_irq_chip: %u bits, reg stride: %d\n", num_bits, stride); | ||
306 | mips_irq_chip_reg_raw = MIPS_IRQ_CHIP_REGS + 0 * stride; | ||
307 | mips_irq_chip_reg_raw_w1s = MIPS_IRQ_CHIP_REGS + 1 * stride; | ||
308 | mips_irq_chip_reg_raw_w1c = MIPS_IRQ_CHIP_REGS + 2 * stride; | ||
309 | mips_irq_chip_reg_src = MIPS_IRQ_CHIP_REGS + 3 * stride; | ||
310 | mips_irq_chip_reg_en = MIPS_IRQ_CHIP_REGS + 4 * stride; | ||
311 | mips_irq_chip_reg_en_w1s = MIPS_IRQ_CHIP_REGS + 5 * stride; | ||
312 | mips_irq_chip_reg_en_w1c = MIPS_IRQ_CHIP_REGS + 6 * stride; | ||
313 | mips_irq_cpu_stride = stride * 4; | ||
314 | |||
315 | for (i = 0; i < 4; i++) | ||
316 | irq_set_chip_and_handler(i + MIPS_IRQ_PCIA, &irq_chip_pci, handle_level_irq); | ||
317 | |||
318 | for (i = 0; i < 2; i++) | ||
319 | irq_set_chip_and_handler(i + MIPS_IRQ_MBOX0, &irq_chip_mbox, handle_percpu_irq); | ||
320 | |||
321 | |||
322 | set_c0_status(STATUSF_IP2); | ||
323 | } | ||
324 | |||
325 | static void irq_pci_dispatch(void) | ||
326 | { | ||
327 | unsigned int cpuid = get_ebase_cpunum(); | ||
328 | u32 en; | ||
329 | |||
330 | en = __raw_readl(mips_irq_chip + mips_irq_chip_reg_src + | ||
331 | (cpuid * mips_irq_cpu_stride)); | ||
332 | |||
333 | if (!en) { | ||
334 | en = __raw_readl(mips_irq_chip + mips_irq_chip_reg_src + (cpuid * mips_irq_cpu_stride) + sizeof(u32)); | ||
335 | en = (en >> (2 * cpuid)) & 3; | ||
336 | |||
337 | if (!en) | ||
338 | spurious_interrupt(); | ||
339 | else | ||
340 | do_IRQ(__ffs(en) + MIPS_IRQ_MBOX0); /* MBOX type */ | ||
341 | } else { | ||
342 | do_IRQ(__ffs(en)); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | |||
347 | void __init arch_init_irq(void) | ||
348 | { | ||
349 | irq_init_core(); | ||
350 | irq_pci_init(); | ||
351 | } | ||
352 | |||
353 | asmlinkage void plat_irq_dispatch(void) | ||
354 | { | ||
355 | unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; | ||
356 | int ip; | ||
357 | |||
358 | if (unlikely(!pending)) { | ||
359 | spurious_interrupt(); | ||
360 | return; | ||
361 | } | ||
362 | |||
363 | ip = ffs(pending) - 1 - STATUSB_IP0; | ||
364 | if (ip == 2) | ||
365 | irq_pci_dispatch(); | ||
366 | else | ||
367 | do_IRQ(MIPS_CPU_IRQ_BASE + ip); | ||
368 | } | ||
diff --git a/arch/mips/paravirt/paravirt-smp.c b/arch/mips/paravirt/paravirt-smp.c new file mode 100644 index 000000000000..0164b0c48352 --- /dev/null +++ b/arch/mips/paravirt/paravirt-smp.c | |||
@@ -0,0 +1,143 @@ | |||
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 | * Copyright (C) 2013 Cavium, Inc. | ||
7 | */ | ||
8 | |||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/cpumask.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/sched.h> | ||
13 | |||
14 | #include <asm/mipsregs.h> | ||
15 | #include <asm/setup.h> | ||
16 | #include <asm/time.h> | ||
17 | #include <asm/smp.h> | ||
18 | |||
19 | /* | ||
20 | * Writing the sp releases the CPU, so writes must be ordered, gp | ||
21 | * first, then sp. | ||
22 | */ | ||
23 | unsigned long paravirt_smp_sp[NR_CPUS]; | ||
24 | unsigned long paravirt_smp_gp[NR_CPUS]; | ||
25 | |||
26 | static int numcpus = 1; | ||
27 | |||
28 | static int __init set_numcpus(char *str) | ||
29 | { | ||
30 | int newval; | ||
31 | |||
32 | if (get_option(&str, &newval)) { | ||
33 | if (newval < 1 || newval >= NR_CPUS) | ||
34 | goto bad; | ||
35 | numcpus = newval; | ||
36 | return 0; | ||
37 | } | ||
38 | bad: | ||
39 | return -EINVAL; | ||
40 | } | ||
41 | early_param("numcpus", set_numcpus); | ||
42 | |||
43 | |||
44 | static void paravirt_smp_setup(void) | ||
45 | { | ||
46 | int id; | ||
47 | unsigned int cpunum = get_ebase_cpunum(); | ||
48 | |||
49 | if (WARN_ON(cpunum >= NR_CPUS)) | ||
50 | return; | ||
51 | |||
52 | /* The present CPUs are initially just the boot cpu (CPU 0). */ | ||
53 | for (id = 0; id < NR_CPUS; id++) { | ||
54 | set_cpu_possible(id, id == 0); | ||
55 | set_cpu_present(id, id == 0); | ||
56 | } | ||
57 | __cpu_number_map[cpunum] = 0; | ||
58 | __cpu_logical_map[0] = cpunum; | ||
59 | |||
60 | for (id = 0; id < numcpus; id++) { | ||
61 | set_cpu_possible(id, true); | ||
62 | set_cpu_present(id, true); | ||
63 | __cpu_number_map[id] = id; | ||
64 | __cpu_logical_map[id] = id; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | void irq_mbox_ipi(int cpu, unsigned int actions); | ||
69 | static void paravirt_send_ipi_single(int cpu, unsigned int action) | ||
70 | { | ||
71 | irq_mbox_ipi(cpu, action); | ||
72 | } | ||
73 | |||
74 | static void paravirt_send_ipi_mask(const struct cpumask *mask, unsigned int action) | ||
75 | { | ||
76 | unsigned int cpu; | ||
77 | |||
78 | for_each_cpu_mask(cpu, *mask) | ||
79 | paravirt_send_ipi_single(cpu, action); | ||
80 | } | ||
81 | |||
82 | static void paravirt_init_secondary(void) | ||
83 | { | ||
84 | unsigned int sr; | ||
85 | |||
86 | sr = set_c0_status(ST0_BEV); | ||
87 | write_c0_ebase((u32)ebase); | ||
88 | |||
89 | sr |= STATUSF_IP2; /* Interrupt controller on IP2 */ | ||
90 | write_c0_status(sr); | ||
91 | |||
92 | irq_cpu_online(); | ||
93 | } | ||
94 | |||
95 | static void paravirt_smp_finish(void) | ||
96 | { | ||
97 | /* to generate the first CPU timer interrupt */ | ||
98 | write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); | ||
99 | local_irq_enable(); | ||
100 | } | ||
101 | |||
102 | static void paravirt_boot_secondary(int cpu, struct task_struct *idle) | ||
103 | { | ||
104 | paravirt_smp_gp[cpu] = (unsigned long)task_thread_info(idle); | ||
105 | smp_wmb(); | ||
106 | paravirt_smp_sp[cpu] = __KSTK_TOS(idle); | ||
107 | } | ||
108 | |||
109 | static irqreturn_t paravirt_reched_interrupt(int irq, void *dev_id) | ||
110 | { | ||
111 | scheduler_ipi(); | ||
112 | return IRQ_HANDLED; | ||
113 | } | ||
114 | |||
115 | static irqreturn_t paravirt_function_interrupt(int irq, void *dev_id) | ||
116 | { | ||
117 | smp_call_function_interrupt(); | ||
118 | return IRQ_HANDLED; | ||
119 | } | ||
120 | |||
121 | static void paravirt_prepare_cpus(unsigned int max_cpus) | ||
122 | { | ||
123 | if (request_irq(MIPS_IRQ_MBOX0, paravirt_reched_interrupt, | ||
124 | IRQF_PERCPU | IRQF_NO_THREAD, "Scheduler", | ||
125 | paravirt_reched_interrupt)) { | ||
126 | panic("Cannot request_irq for SchedulerIPI"); | ||
127 | } | ||
128 | if (request_irq(MIPS_IRQ_MBOX1, paravirt_function_interrupt, | ||
129 | IRQF_PERCPU | IRQF_NO_THREAD, "SMP-Call", | ||
130 | paravirt_function_interrupt)) { | ||
131 | panic("Cannot request_irq for SMP-Call"); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | struct plat_smp_ops paravirt_smp_ops = { | ||
136 | .send_ipi_single = paravirt_send_ipi_single, | ||
137 | .send_ipi_mask = paravirt_send_ipi_mask, | ||
138 | .init_secondary = paravirt_init_secondary, | ||
139 | .smp_finish = paravirt_smp_finish, | ||
140 | .boot_secondary = paravirt_boot_secondary, | ||
141 | .smp_setup = paravirt_smp_setup, | ||
142 | .prepare_cpus = paravirt_prepare_cpus, | ||
143 | }; | ||
diff --git a/arch/mips/paravirt/serial.c b/arch/mips/paravirt/serial.c new file mode 100644 index 000000000000..02b665c02272 --- /dev/null +++ b/arch/mips/paravirt/serial.c | |||
@@ -0,0 +1,40 @@ | |||
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 | * Copyright (C) 2013 Cavium, Inc. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/virtio_console.h> | ||
11 | #include <linux/kvm_para.h> | ||
12 | |||
13 | /* | ||
14 | * Emit one character to the boot console. | ||
15 | */ | ||
16 | int prom_putchar(char c) | ||
17 | { | ||
18 | kvm_hypercall3(KVM_HC_MIPS_CONSOLE_OUTPUT, 0 /* port 0 */, | ||
19 | (unsigned long)&c, 1 /* len == 1 */); | ||
20 | |||
21 | return 1; | ||
22 | } | ||
23 | |||
24 | #ifdef CONFIG_VIRTIO_CONSOLE | ||
25 | static int paravirt_put_chars(u32 vtermno, const char *buf, int count) | ||
26 | { | ||
27 | kvm_hypercall3(KVM_HC_MIPS_CONSOLE_OUTPUT, vtermno, | ||
28 | (unsigned long)buf, count); | ||
29 | |||
30 | return count; | ||
31 | } | ||
32 | |||
33 | static int __init paravirt_cons_init(void) | ||
34 | { | ||
35 | virtio_cons_early_init(paravirt_put_chars); | ||
36 | return 0; | ||
37 | } | ||
38 | core_initcall(paravirt_cons_init); | ||
39 | |||
40 | #endif | ||
diff --git a/arch/mips/paravirt/setup.c b/arch/mips/paravirt/setup.c new file mode 100644 index 000000000000..cb8448b373a7 --- /dev/null +++ b/arch/mips/paravirt/setup.c | |||
@@ -0,0 +1,67 @@ | |||
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 | * Copyright (C) 2013 Cavium, Inc. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/kvm_para.h> | ||
11 | |||
12 | #include <asm/reboot.h> | ||
13 | #include <asm/bootinfo.h> | ||
14 | #include <asm/smp-ops.h> | ||
15 | #include <asm/time.h> | ||
16 | |||
17 | extern struct plat_smp_ops paravirt_smp_ops; | ||
18 | |||
19 | const char *get_system_type(void) | ||
20 | { | ||
21 | return "MIPS Para-Virtualized Guest"; | ||
22 | } | ||
23 | |||
24 | void __init plat_time_init(void) | ||
25 | { | ||
26 | mips_hpt_frequency = kvm_hypercall0(KVM_HC_MIPS_GET_CLOCK_FREQ); | ||
27 | |||
28 | preset_lpj = mips_hpt_frequency / (2 * HZ); | ||
29 | } | ||
30 | |||
31 | static void pv_machine_halt(void) | ||
32 | { | ||
33 | kvm_hypercall0(KVM_HC_MIPS_EXIT_VM); | ||
34 | } | ||
35 | |||
36 | /* | ||
37 | * Early entry point for arch setup | ||
38 | */ | ||
39 | void __init prom_init(void) | ||
40 | { | ||
41 | int i; | ||
42 | int argc = fw_arg0; | ||
43 | char **argv = (char **)fw_arg1; | ||
44 | |||
45 | #ifdef CONFIG_32BIT | ||
46 | set_io_port_base(KSEG1ADDR(0x1e000000)); | ||
47 | #else /* CONFIG_64BIT */ | ||
48 | set_io_port_base(PHYS_TO_XKSEG_UNCACHED(0x1e000000)); | ||
49 | #endif | ||
50 | |||
51 | for (i = 0; i < argc; i++) { | ||
52 | strlcat(arcs_cmdline, argv[i], COMMAND_LINE_SIZE); | ||
53 | if (i < argc - 1) | ||
54 | strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE); | ||
55 | } | ||
56 | _machine_halt = pv_machine_halt; | ||
57 | register_smp_ops(¶virt_smp_ops); | ||
58 | } | ||
59 | |||
60 | void __init plat_mem_setup(void) | ||
61 | { | ||
62 | /* Do nothing, the "mem=???" parser handles our memory. */ | ||
63 | } | ||
64 | |||
65 | void __init prom_free_prom_memory(void) | ||
66 | { | ||
67 | } | ||
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index d61138a177cc..ff8a5539b363 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile | |||
@@ -21,7 +21,7 @@ obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ | |||
21 | obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o | 21 | obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o |
22 | obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o | 22 | obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o |
23 | obj-$(CONFIG_PCI_AR724X) += pci-ar724x.o | 23 | obj-$(CONFIG_PCI_AR724X) += pci-ar724x.o |
24 | 24 | obj-$(CONFIG_MIPS_PCI_VIRTIO) += pci-virtio-guest.o | |
25 | # | 25 | # |
26 | # These are still pretty much in the old state, watch, go blind. | 26 | # These are still pretty much in the old state, watch, go blind. |
27 | # | 27 | # |
diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c index 2f9e52a1a750..40e920c653cc 100644 --- a/arch/mips/pci/fixup-malta.c +++ b/arch/mips/pci/fixup-malta.c | |||
@@ -68,6 +68,7 @@ static void malta_piix_func0_fixup(struct pci_dev *pdev) | |||
68 | { | 68 | { |
69 | unsigned char reg_val; | 69 | unsigned char reg_val; |
70 | u32 reg_val32; | 70 | u32 reg_val32; |
71 | u16 reg_val16; | ||
71 | /* PIIX PIRQC[A:D] irq mappings */ | 72 | /* PIIX PIRQC[A:D] irq mappings */ |
72 | static int piixirqmap[PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX] = { | 73 | static int piixirqmap[PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX] = { |
73 | 0, 0, 0, 3, | 74 | 0, 0, 0, 3, |
@@ -107,6 +108,11 @@ static void malta_piix_func0_fixup(struct pci_dev *pdev) | |||
107 | pci_read_config_byte(pdev, PIIX4_FUNC0_SERIRQC, ®_val); | 108 | pci_read_config_byte(pdev, PIIX4_FUNC0_SERIRQC, ®_val); |
108 | reg_val |= PIIX4_FUNC0_SERIRQC_EN | PIIX4_FUNC0_SERIRQC_CONT; | 109 | reg_val |= PIIX4_FUNC0_SERIRQC_EN | PIIX4_FUNC0_SERIRQC_CONT; |
109 | pci_write_config_byte(pdev, PIIX4_FUNC0_SERIRQC, reg_val); | 110 | pci_write_config_byte(pdev, PIIX4_FUNC0_SERIRQC, reg_val); |
111 | |||
112 | /* Enable response to special cycles */ | ||
113 | pci_read_config_word(pdev, PCI_COMMAND, ®_val16); | ||
114 | pci_write_config_word(pdev, PCI_COMMAND, | ||
115 | reg_val16 | PCI_COMMAND_SPECIAL); | ||
110 | } | 116 | } |
111 | 117 | ||
112 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, | 118 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, |
diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index 2b91b0e61566..ab0c5d14c6f7 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <asm/octeon/cvmx-npi-defs.h> | 15 | #include <asm/octeon/cvmx-npi-defs.h> |
16 | #include <asm/octeon/cvmx-pci-defs.h> | 16 | #include <asm/octeon/cvmx-pci-defs.h> |
17 | #include <asm/octeon/cvmx-npei-defs.h> | 17 | #include <asm/octeon/cvmx-npei-defs.h> |
18 | #include <asm/octeon/cvmx-sli-defs.h> | ||
18 | #include <asm/octeon/cvmx-pexp-defs.h> | 19 | #include <asm/octeon/cvmx-pexp-defs.h> |
19 | #include <asm/octeon/pci-octeon.h> | 20 | #include <asm/octeon/pci-octeon.h> |
20 | 21 | ||
@@ -162,6 +163,11 @@ msi_irq_allocated: | |||
162 | msg.address_lo = (0 + CVMX_NPEI_PCIE_MSI_RCV) & 0xffffffff; | 163 | msg.address_lo = (0 + CVMX_NPEI_PCIE_MSI_RCV) & 0xffffffff; |
163 | msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32; | 164 | msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32; |
164 | break; | 165 | break; |
166 | case OCTEON_DMA_BAR_TYPE_PCIE2: | ||
167 | /* When using PCIe2, Bar 0 is based at 0 */ | ||
168 | msg.address_lo = (0 + CVMX_SLI_PCIE_MSI_RCV) & 0xffffffff; | ||
169 | msg.address_hi = (0 + CVMX_SLI_PCIE_MSI_RCV) >> 32; | ||
170 | break; | ||
165 | default: | 171 | default: |
166 | panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type"); | 172 | panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type"); |
167 | } | 173 | } |
diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c index 3249685e03ad..fa374fe3746b 100644 --- a/arch/mips/pci/msi-xlp.c +++ b/arch/mips/pci/msi-xlp.c | |||
@@ -56,8 +56,8 @@ | |||
56 | #include <asm/netlogic/xlp-hal/bridge.h> | 56 | #include <asm/netlogic/xlp-hal/bridge.h> |
57 | 57 | ||
58 | #define XLP_MSIVEC_PER_LINK 32 | 58 | #define XLP_MSIVEC_PER_LINK 32 |
59 | #define XLP_MSIXVEC_TOTAL 32 | 59 | #define XLP_MSIXVEC_TOTAL (cpu_is_xlp9xx() ? 128 : 32) |
60 | #define XLP_MSIXVEC_PER_LINK 8 | 60 | #define XLP_MSIXVEC_PER_LINK (cpu_is_xlp9xx() ? 32 : 8) |
61 | 61 | ||
62 | /* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */ | 62 | /* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */ |
63 | static inline int nlm_link_msiirq(int link, int msivec) | 63 | static inline int nlm_link_msiirq(int link, int msivec) |
@@ -65,35 +65,44 @@ static inline int nlm_link_msiirq(int link, int msivec) | |||
65 | return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec; | 65 | return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec; |
66 | } | 66 | } |
67 | 67 | ||
68 | /* get the link MSI vector from irq number */ | ||
68 | static inline int nlm_irq_msivec(int irq) | 69 | static inline int nlm_irq_msivec(int irq) |
69 | { | 70 | { |
70 | return irq % XLP_MSIVEC_PER_LINK; | 71 | return (irq - NLM_MSI_VEC_BASE) % XLP_MSIVEC_PER_LINK; |
71 | } | 72 | } |
72 | 73 | ||
74 | /* get the link from the irq number */ | ||
73 | static inline int nlm_irq_msilink(int irq) | 75 | static inline int nlm_irq_msilink(int irq) |
74 | { | 76 | { |
75 | return (irq % (XLP_MSIVEC_PER_LINK * PCIE_NLINKS)) / | 77 | int total_msivec = XLP_MSIVEC_PER_LINK * PCIE_NLINKS; |
76 | XLP_MSIVEC_PER_LINK; | 78 | |
79 | return ((irq - NLM_MSI_VEC_BASE) % total_msivec) / | ||
80 | XLP_MSIVEC_PER_LINK; | ||
77 | } | 81 | } |
78 | 82 | ||
79 | /* | 83 | /* |
80 | * Only 32 MSI-X vectors are possible because there are only 32 PIC | 84 | * For XLP 8xx/4xx/3xx/2xx, only 32 MSI-X vectors are possible because |
81 | * interrupts for MSI. We split them statically and use 8 MSI-X vectors | 85 | * there are only 32 PIC interrupts for MSI. We split them statically |
82 | * per link - this keeps the allocation and lookup simple. | 86 | * and use 8 MSI-X vectors per link - this keeps the allocation and |
87 | * lookup simple. | ||
88 | * On XLP 9xx, there are 32 vectors per link, and the interrupts are | ||
89 | * not routed thru PIC, so we can use all 128 MSI-X vectors. | ||
83 | */ | 90 | */ |
84 | static inline int nlm_link_msixirq(int link, int bit) | 91 | static inline int nlm_link_msixirq(int link, int bit) |
85 | { | 92 | { |
86 | return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit; | 93 | return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit; |
87 | } | 94 | } |
88 | 95 | ||
96 | /* get the link MSI vector from irq number */ | ||
89 | static inline int nlm_irq_msixvec(int irq) | 97 | static inline int nlm_irq_msixvec(int irq) |
90 | { | 98 | { |
91 | return irq % XLP_MSIXVEC_TOTAL; /* works when given xirq */ | 99 | return (irq - NLM_MSIX_VEC_BASE) % XLP_MSIXVEC_TOTAL; |
92 | } | 100 | } |
93 | 101 | ||
94 | static inline int nlm_irq_msixlink(int irq) | 102 | /* get the link from MSIX vec */ |
103 | static inline int nlm_irq_msixlink(int msixvec) | ||
95 | { | 104 | { |
96 | return nlm_irq_msixvec(irq) / XLP_MSIXVEC_PER_LINK; | 105 | return msixvec / XLP_MSIXVEC_PER_LINK; |
97 | } | 106 | } |
98 | 107 | ||
99 | /* | 108 | /* |
@@ -129,7 +138,11 @@ static void xlp_msi_enable(struct irq_data *d) | |||
129 | vec = nlm_irq_msivec(d->irq); | 138 | vec = nlm_irq_msivec(d->irq); |
130 | spin_lock_irqsave(&md->msi_lock, flags); | 139 | spin_lock_irqsave(&md->msi_lock, flags); |
131 | md->msi_enabled_mask |= 1u << vec; | 140 | md->msi_enabled_mask |= 1u << vec; |
132 | nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); | 141 | if (cpu_is_xlp9xx()) |
142 | nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_EN, | ||
143 | md->msi_enabled_mask); | ||
144 | else | ||
145 | nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); | ||
133 | spin_unlock_irqrestore(&md->msi_lock, flags); | 146 | spin_unlock_irqrestore(&md->msi_lock, flags); |
134 | } | 147 | } |
135 | 148 | ||
@@ -142,7 +155,11 @@ static void xlp_msi_disable(struct irq_data *d) | |||
142 | vec = nlm_irq_msivec(d->irq); | 155 | vec = nlm_irq_msivec(d->irq); |
143 | spin_lock_irqsave(&md->msi_lock, flags); | 156 | spin_lock_irqsave(&md->msi_lock, flags); |
144 | md->msi_enabled_mask &= ~(1u << vec); | 157 | md->msi_enabled_mask &= ~(1u << vec); |
145 | nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); | 158 | if (cpu_is_xlp9xx()) |
159 | nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_EN, | ||
160 | md->msi_enabled_mask); | ||
161 | else | ||
162 | nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); | ||
146 | spin_unlock_irqrestore(&md->msi_lock, flags); | 163 | spin_unlock_irqrestore(&md->msi_lock, flags); |
147 | } | 164 | } |
148 | 165 | ||
@@ -156,11 +173,18 @@ static void xlp_msi_mask_ack(struct irq_data *d) | |||
156 | xlp_msi_disable(d); | 173 | xlp_msi_disable(d); |
157 | 174 | ||
158 | /* Ack MSI on bridge */ | 175 | /* Ack MSI on bridge */ |
159 | nlm_write_reg(md->lnkbase, PCIE_MSI_STATUS, 1u << vec); | 176 | if (cpu_is_xlp9xx()) |
177 | nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_STATUS, 1u << vec); | ||
178 | else | ||
179 | nlm_write_reg(md->lnkbase, PCIE_MSI_STATUS, 1u << vec); | ||
160 | 180 | ||
161 | /* Ack at eirr and PIC */ | 181 | /* Ack at eirr and PIC */ |
162 | ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link)); | 182 | ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link)); |
163 | nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link)); | 183 | if (cpu_is_xlp9xx()) |
184 | nlm_pic_ack(md->node->picbase, | ||
185 | PIC_9XX_IRT_PCIE_LINK_INDEX(link)); | ||
186 | else | ||
187 | nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link)); | ||
164 | } | 188 | } |
165 | 189 | ||
166 | static struct irq_chip xlp_msi_chip = { | 190 | static struct irq_chip xlp_msi_chip = { |
@@ -172,30 +196,45 @@ static struct irq_chip xlp_msi_chip = { | |||
172 | }; | 196 | }; |
173 | 197 | ||
174 | /* | 198 | /* |
175 | * The MSI-X interrupt handling is different from MSI, there are 32 | 199 | * XLP8XX/4XX/3XX/2XX: |
176 | * MSI-X interrupts generated by the PIC and each of these correspond | 200 | * The MSI-X interrupt handling is different from MSI, there are 32 MSI-X |
177 | * to a MSI-X vector (0-31) that can be assigned. | 201 | * interrupts generated by the PIC and each of these correspond to a MSI-X |
202 | * vector (0-31) that can be assigned. | ||
178 | * | 203 | * |
179 | * We divide the MSI-X vectors to 8 per link and do a per-link | 204 | * We divide the MSI-X vectors to 8 per link and do a per-link allocation |
180 | * allocation | 205 | * |
206 | * XLP9XX: | ||
207 | * 32 MSI-X vectors are available per link, and the interrupts are not routed | ||
208 | * thru the PIC. PIC ack not needed. | ||
181 | * | 209 | * |
182 | * Enable and disable done using standard MSI functions. | 210 | * Enable and disable done using standard MSI functions. |
183 | */ | 211 | */ |
184 | static void xlp_msix_mask_ack(struct irq_data *d) | 212 | static void xlp_msix_mask_ack(struct irq_data *d) |
185 | { | 213 | { |
186 | struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); | 214 | struct xlp_msi_data *md; |
187 | int link, msixvec; | 215 | int link, msixvec; |
216 | uint32_t status_reg, bit; | ||
188 | 217 | ||
189 | msixvec = nlm_irq_msixvec(d->irq); | 218 | msixvec = nlm_irq_msixvec(d->irq); |
190 | link = nlm_irq_msixlink(d->irq); | 219 | link = nlm_irq_msixlink(msixvec); |
191 | mask_msi_irq(d); | 220 | mask_msi_irq(d); |
221 | md = irq_data_get_irq_handler_data(d); | ||
192 | 222 | ||
193 | /* Ack MSI on bridge */ | 223 | /* Ack MSI on bridge */ |
194 | nlm_write_reg(md->lnkbase, PCIE_MSIX_STATUS, 1u << msixvec); | 224 | if (cpu_is_xlp9xx()) { |
225 | status_reg = PCIE_9XX_MSIX_STATUSX(link); | ||
226 | bit = msixvec % XLP_MSIXVEC_PER_LINK; | ||
227 | } else { | ||
228 | status_reg = PCIE_MSIX_STATUS; | ||
229 | bit = msixvec; | ||
230 | } | ||
231 | nlm_write_reg(md->lnkbase, status_reg, 1u << bit); | ||
195 | 232 | ||
196 | /* Ack at eirr and PIC */ | 233 | /* Ack at eirr and PIC */ |
197 | ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link)); | 234 | ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link)); |
198 | nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_MSIX_INDEX(msixvec)); | 235 | if (!cpu_is_xlp9xx()) |
236 | nlm_pic_ack(md->node->picbase, | ||
237 | PIC_IRT_PCIE_MSIX_INDEX(msixvec)); | ||
199 | } | 238 | } |
200 | 239 | ||
201 | static struct irq_chip xlp_msix_chip = { | 240 | static struct irq_chip xlp_msix_chip = { |
@@ -219,10 +258,18 @@ static void xlp_config_link_msi(uint64_t lnkbase, int lirq, uint64_t msiaddr) | |||
219 | { | 258 | { |
220 | u32 val; | 259 | u32 val; |
221 | 260 | ||
222 | val = nlm_read_reg(lnkbase, PCIE_INT_EN0); | 261 | if (cpu_is_xlp9xx()) { |
223 | if ((val & 0x200) == 0) { | 262 | val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0); |
224 | val |= 0x200; /* MSI Interrupt enable */ | 263 | if ((val & 0x200) == 0) { |
225 | nlm_write_reg(lnkbase, PCIE_INT_EN0, val); | 264 | val |= 0x200; /* MSI Interrupt enable */ |
265 | nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val); | ||
266 | } | ||
267 | } else { | ||
268 | val = nlm_read_reg(lnkbase, PCIE_INT_EN0); | ||
269 | if ((val & 0x200) == 0) { | ||
270 | val |= 0x200; | ||
271 | nlm_write_reg(lnkbase, PCIE_INT_EN0, val); | ||
272 | } | ||
226 | } | 273 | } |
227 | 274 | ||
228 | val = nlm_read_reg(lnkbase, 0x1); /* CMD */ | 275 | val = nlm_read_reg(lnkbase, 0x1); /* CMD */ |
@@ -269,9 +316,12 @@ static int xlp_setup_msi(uint64_t lnkbase, int node, int link, | |||
269 | 316 | ||
270 | spin_lock_irqsave(&md->msi_lock, flags); | 317 | spin_lock_irqsave(&md->msi_lock, flags); |
271 | if (md->msi_alloc_mask == 0) { | 318 | if (md->msi_alloc_mask == 0) { |
272 | /* switch the link IRQ to MSI range */ | ||
273 | xlp_config_link_msi(lnkbase, lirq, msiaddr); | 319 | xlp_config_link_msi(lnkbase, lirq, msiaddr); |
274 | irt = PIC_IRT_PCIE_LINK_INDEX(link); | 320 | /* switch the link IRQ to MSI range */ |
321 | if (cpu_is_xlp9xx()) | ||
322 | irt = PIC_9XX_IRT_PCIE_LINK_INDEX(link); | ||
323 | else | ||
324 | irt = PIC_IRT_PCIE_LINK_INDEX(link); | ||
275 | nlm_setup_pic_irq(node, lirq, lirq, irt); | 325 | nlm_setup_pic_irq(node, lirq, lirq, irt); |
276 | nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq, | 326 | nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq, |
277 | node * nlm_threads_per_node(), 1 /*en */); | 327 | node * nlm_threads_per_node(), 1 /*en */); |
@@ -311,10 +361,19 @@ static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr) | |||
311 | val |= 0x80000000U; | 361 | val |= 0x80000000U; |
312 | nlm_write_reg(lnkbase, 0x2C, val); | 362 | nlm_write_reg(lnkbase, 0x2C, val); |
313 | } | 363 | } |
314 | val = nlm_read_reg(lnkbase, PCIE_INT_EN0); | 364 | |
315 | if ((val & 0x200) == 0) { | 365 | if (cpu_is_xlp9xx()) { |
316 | val |= 0x200; /* MSI Interrupt enable */ | 366 | val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0); |
317 | nlm_write_reg(lnkbase, PCIE_INT_EN0, val); | 367 | if ((val & 0x200) == 0) { |
368 | val |= 0x200; /* MSI Interrupt enable */ | ||
369 | nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val); | ||
370 | } | ||
371 | } else { | ||
372 | val = nlm_read_reg(lnkbase, PCIE_INT_EN0); | ||
373 | if ((val & 0x200) == 0) { | ||
374 | val |= 0x200; /* MSI Interrupt enable */ | ||
375 | nlm_write_reg(lnkbase, PCIE_INT_EN0, val); | ||
376 | } | ||
318 | } | 377 | } |
319 | 378 | ||
320 | val = nlm_read_reg(lnkbase, 0x1); /* CMD */ | 379 | val = nlm_read_reg(lnkbase, 0x1); /* CMD */ |
@@ -329,10 +388,19 @@ static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr) | |||
329 | val |= (1 << 8) | lirq; | 388 | val |= (1 << 8) | lirq; |
330 | nlm_write_pci_reg(lnkbase, 0xf, val); | 389 | nlm_write_pci_reg(lnkbase, 0xf, val); |
331 | 390 | ||
332 | /* MSI-X addresses */ | 391 | if (cpu_is_xlp9xx()) { |
333 | nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_BASE, msixaddr >> 8); | 392 | /* MSI-X addresses */ |
334 | nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_LIMIT, | 393 | nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_BASE, |
335 | (msixaddr + MSI_ADDR_SZ) >> 8); | 394 | msixaddr >> 8); |
395 | nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_LIMIT, | ||
396 | (msixaddr + MSI_ADDR_SZ) >> 8); | ||
397 | } else { | ||
398 | /* MSI-X addresses */ | ||
399 | nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_BASE, | ||
400 | msixaddr >> 8); | ||
401 | nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_LIMIT, | ||
402 | (msixaddr + MSI_ADDR_SZ) >> 8); | ||
403 | } | ||
336 | } | 404 | } |
337 | 405 | ||
338 | /* | 406 | /* |
@@ -369,6 +437,7 @@ static int xlp_setup_msix(uint64_t lnkbase, int node, int link, | |||
369 | 437 | ||
370 | xirq += t; | 438 | xirq += t; |
371 | msixvec = nlm_irq_msixvec(xirq); | 439 | msixvec = nlm_irq_msixvec(xirq); |
440 | |||
372 | msg.address_hi = msixaddr >> 32; | 441 | msg.address_hi = msixaddr >> 32; |
373 | msg.address_lo = msixaddr & 0xffffffff; | 442 | msg.address_lo = msixaddr & 0xffffffff; |
374 | msg.data = 0xc00 | msixvec; | 443 | msg.data = 0xc00 | msixvec; |
@@ -409,7 +478,7 @@ void __init xlp_init_node_msi_irqs(int node, int link) | |||
409 | { | 478 | { |
410 | struct nlm_soc_info *nodep; | 479 | struct nlm_soc_info *nodep; |
411 | struct xlp_msi_data *md; | 480 | struct xlp_msi_data *md; |
412 | int irq, i, irt, msixvec; | 481 | int irq, i, irt, msixvec, val; |
413 | 482 | ||
414 | pr_info("[%d %d] Init node PCI IRT\n", node, link); | 483 | pr_info("[%d %d] Init node PCI IRT\n", node, link); |
415 | nodep = nlm_get_node(node); | 484 | nodep = nlm_get_node(node); |
@@ -430,19 +499,28 @@ void __init xlp_init_node_msi_irqs(int node, int link) | |||
430 | irq_set_handler_data(i, md); | 499 | irq_set_handler_data(i, md); |
431 | } | 500 | } |
432 | 501 | ||
433 | for (i = 0; i < XLP_MSIXVEC_PER_LINK; i++) { | 502 | for (i = 0; i < XLP_MSIXVEC_PER_LINK ; i++) { |
434 | /* Initialize MSI-X irts to generate one interrupt per link */ | 503 | if (cpu_is_xlp9xx()) { |
435 | msixvec = link * XLP_MSIXVEC_PER_LINK + i; | 504 | val = ((node * nlm_threads_per_node()) << 7 | |
436 | irt = PIC_IRT_PCIE_MSIX_INDEX(msixvec); | 505 | PIC_PCIE_MSIX_IRQ(link) << 1 | 0 << 0); |
437 | nlm_pic_init_irt(nodep->picbase, irt, PIC_PCIE_MSIX_IRQ(link), | 506 | nlm_write_pcie_reg(md->lnkbase, PCIE_9XX_MSIX_VECX(i + |
438 | node * nlm_threads_per_node(), 1 /* enable */); | 507 | (link * XLP_MSIXVEC_PER_LINK)), val); |
508 | } else { | ||
509 | /* Initialize MSI-X irts to generate one interrupt | ||
510 | * per link | ||
511 | */ | ||
512 | msixvec = link * XLP_MSIXVEC_PER_LINK + i; | ||
513 | irt = PIC_IRT_PCIE_MSIX_INDEX(msixvec); | ||
514 | nlm_pic_init_irt(nodep->picbase, irt, | ||
515 | PIC_PCIE_MSIX_IRQ(link), | ||
516 | node * nlm_threads_per_node(), 1); | ||
517 | } | ||
439 | 518 | ||
440 | /* Initialize MSI-X extended irq space for the link */ | 519 | /* Initialize MSI-X extended irq space for the link */ |
441 | irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); | 520 | irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); |
442 | irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); | 521 | irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); |
443 | irq_set_handler_data(irq, md); | 522 | irq_set_handler_data(irq, md); |
444 | } | 523 | } |
445 | |||
446 | } | 524 | } |
447 | 525 | ||
448 | void nlm_dispatch_msi(int node, int lirq) | 526 | void nlm_dispatch_msi(int node, int lirq) |
@@ -454,7 +532,11 @@ void nlm_dispatch_msi(int node, int lirq) | |||
454 | link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; | 532 | link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; |
455 | irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); | 533 | irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); |
456 | md = irq_get_handler_data(irqbase); | 534 | md = irq_get_handler_data(irqbase); |
457 | status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) & | 535 | if (cpu_is_xlp9xx()) |
536 | status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) & | ||
537 | md->msi_enabled_mask; | ||
538 | else | ||
539 | status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) & | ||
458 | md->msi_enabled_mask; | 540 | md->msi_enabled_mask; |
459 | while (status) { | 541 | while (status) { |
460 | i = __ffs(status); | 542 | i = __ffs(status); |
@@ -472,10 +554,14 @@ void nlm_dispatch_msix(int node, int lirq) | |||
472 | link = lirq - PIC_PCIE_MSIX_IRQ_BASE; | 554 | link = lirq - PIC_PCIE_MSIX_IRQ_BASE; |
473 | irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); | 555 | irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); |
474 | md = irq_get_handler_data(irqbase); | 556 | md = irq_get_handler_data(irqbase); |
475 | status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS); | 557 | if (cpu_is_xlp9xx()) |
558 | status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link)); | ||
559 | else | ||
560 | status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS); | ||
476 | 561 | ||
477 | /* narrow it down to the MSI-x vectors for our link */ | 562 | /* narrow it down to the MSI-x vectors for our link */ |
478 | status = (status >> (link * XLP_MSIXVEC_PER_LINK)) & | 563 | if (!cpu_is_xlp9xx()) |
564 | status = (status >> (link * XLP_MSIXVEC_PER_LINK)) & | ||
479 | ((1 << XLP_MSIXVEC_PER_LINK) - 1); | 565 | ((1 << XLP_MSIXVEC_PER_LINK) - 1); |
480 | 566 | ||
481 | while (status) { | 567 | while (status) { |
diff --git a/arch/mips/pci/ops-pmcmsp.c b/arch/mips/pci/ops-pmcmsp.c index 3d27800edba2..50034f985be1 100644 --- a/arch/mips/pci/ops-pmcmsp.c +++ b/arch/mips/pci/ops-pmcmsp.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | 7 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net |
8 | * | 8 | * |
9 | * Much of the code is derived from the original DDB5074 port by | 9 | * Much of the code is derived from the original DDB5074 port by |
10 | * Geert Uytterhoeven <geert@sonycom.com> | 10 | * Geert Uytterhoeven <geert@linux-m68k.org> |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify it | 12 | * This program is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
diff --git a/arch/mips/pci/ops-tx3927.c b/arch/mips/pci/ops-tx3927.c index 02d64f77e967..d35dc9c9ab9d 100644 --- a/arch/mips/pci/ops-tx3927.c +++ b/arch/mips/pci/ops-tx3927.c | |||
@@ -11,7 +11,7 @@ | |||
11 | * Define the pci_ops for TX3927. | 11 | * Define the pci_ops for TX3927. |
12 | * | 12 | * |
13 | * Much of the code is derived from the original DDB5074 port by | 13 | * Much of the code is derived from the original DDB5074 port by |
14 | * Geert Uytterhoeven <geert@sonycom.com> | 14 | * Geert Uytterhoeven <geert@linux-m68k.org> |
15 | * | 15 | * |
16 | * This program is free software; you can redistribute it and/or modify it | 16 | * This program is free software; you can redistribute it and/or modify it |
17 | * under the terms of the GNU General Public License as published by the | 17 | * under the terms of the GNU General Public License as published by the |
diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c index 3d5df514d024..0e046d82e4e3 100644 --- a/arch/mips/pci/ops-tx4927.c +++ b/arch/mips/pci/ops-tx4927.c | |||
@@ -202,17 +202,20 @@ char *tx4927_pcibios_setup(char *str) | |||
202 | unsigned long val; | 202 | unsigned long val; |
203 | 203 | ||
204 | if (!strncmp(str, "trdyto=", 7)) { | 204 | if (!strncmp(str, "trdyto=", 7)) { |
205 | if (strict_strtoul(str + 7, 0, &val) == 0) | 205 | u8 val = 0; |
206 | if (kstrtou8(str + 7, 0, &val) == 0) | ||
206 | tx4927_pci_opts.trdyto = val; | 207 | tx4927_pci_opts.trdyto = val; |
207 | return NULL; | 208 | return NULL; |
208 | } | 209 | } |
209 | if (!strncmp(str, "retryto=", 8)) { | 210 | if (!strncmp(str, "retryto=", 8)) { |
210 | if (strict_strtoul(str + 8, 0, &val) == 0) | 211 | u8 val = 0; |
212 | if (kstrtou8(str + 8, 0, &val) == 0) | ||
211 | tx4927_pci_opts.retryto = val; | 213 | tx4927_pci_opts.retryto = val; |
212 | return NULL; | 214 | return NULL; |
213 | } | 215 | } |
214 | if (!strncmp(str, "gbwc=", 5)) { | 216 | if (!strncmp(str, "gbwc=", 5)) { |
215 | if (strict_strtoul(str + 5, 0, &val) == 0) | 217 | u16 val; |
218 | if (kstrtou16(str + 5, 0, &val) == 0) | ||
216 | tx4927_pci_opts.gbwc = val; | 219 | tx4927_pci_opts.gbwc = val; |
217 | return NULL; | 220 | return NULL; |
218 | } | 221 | } |
diff --git a/arch/mips/pci/pci-virtio-guest.c b/arch/mips/pci/pci-virtio-guest.c new file mode 100644 index 000000000000..40a078bc4617 --- /dev/null +++ b/arch/mips/pci/pci-virtio-guest.c | |||
@@ -0,0 +1,131 @@ | |||
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 | * Copyright (C) 2013 Cavium, Inc. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/pci.h> | ||
13 | |||
14 | #include <uapi/asm/bitfield.h> | ||
15 | #include <asm/byteorder.h> | ||
16 | #include <asm/io.h> | ||
17 | |||
18 | #define PCI_CONFIG_ADDRESS 0xcf8 | ||
19 | #define PCI_CONFIG_DATA 0xcfc | ||
20 | |||
21 | union pci_config_address { | ||
22 | struct { | ||
23 | __BITFIELD_FIELD(unsigned enable_bit : 1, /* 31 */ | ||
24 | __BITFIELD_FIELD(unsigned reserved : 7, /* 30 .. 24 */ | ||
25 | __BITFIELD_FIELD(unsigned bus_number : 8, /* 23 .. 16 */ | ||
26 | __BITFIELD_FIELD(unsigned devfn_number : 8, /* 15 .. 8 */ | ||
27 | __BITFIELD_FIELD(unsigned register_number : 8, /* 7 .. 0 */ | ||
28 | ))))); | ||
29 | }; | ||
30 | u32 w; | ||
31 | }; | ||
32 | |||
33 | int pcibios_plat_dev_init(struct pci_dev *dev) | ||
34 | { | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
39 | { | ||
40 | return ((pin + slot) % 4)+ MIPS_IRQ_PCIA; | ||
41 | } | ||
42 | |||
43 | static void pci_virtio_guest_write_config_addr(struct pci_bus *bus, | ||
44 | unsigned int devfn, int reg) | ||
45 | { | ||
46 | union pci_config_address pca = { .w = 0 }; | ||
47 | |||
48 | pca.register_number = reg; | ||
49 | pca.devfn_number = devfn; | ||
50 | pca.bus_number = bus->number; | ||
51 | pca.enable_bit = 1; | ||
52 | |||
53 | outl(pca.w, PCI_CONFIG_ADDRESS); | ||
54 | } | ||
55 | |||
56 | static int pci_virtio_guest_write_config(struct pci_bus *bus, | ||
57 | unsigned int devfn, int reg, int size, u32 val) | ||
58 | { | ||
59 | pci_virtio_guest_write_config_addr(bus, devfn, reg); | ||
60 | |||
61 | switch (size) { | ||
62 | case 1: | ||
63 | outb(val, PCI_CONFIG_DATA + (reg & 3)); | ||
64 | break; | ||
65 | case 2: | ||
66 | outw(val, PCI_CONFIG_DATA + (reg & 2)); | ||
67 | break; | ||
68 | case 4: | ||
69 | outl(val, PCI_CONFIG_DATA); | ||
70 | break; | ||
71 | } | ||
72 | |||
73 | return PCIBIOS_SUCCESSFUL; | ||
74 | } | ||
75 | |||
76 | static int pci_virtio_guest_read_config(struct pci_bus *bus, unsigned int devfn, | ||
77 | int reg, int size, u32 *val) | ||
78 | { | ||
79 | pci_virtio_guest_write_config_addr(bus, devfn, reg); | ||
80 | |||
81 | switch (size) { | ||
82 | case 1: | ||
83 | *val = inb(PCI_CONFIG_DATA + (reg & 3)); | ||
84 | break; | ||
85 | case 2: | ||
86 | *val = inw(PCI_CONFIG_DATA + (reg & 2)); | ||
87 | break; | ||
88 | case 4: | ||
89 | *val = inl(PCI_CONFIG_DATA); | ||
90 | break; | ||
91 | } | ||
92 | return PCIBIOS_SUCCESSFUL; | ||
93 | } | ||
94 | |||
95 | static struct pci_ops pci_virtio_guest_ops = { | ||
96 | .read = pci_virtio_guest_read_config, | ||
97 | .write = pci_virtio_guest_write_config, | ||
98 | }; | ||
99 | |||
100 | static struct resource pci_virtio_guest_mem_resource = { | ||
101 | .name = "Virtio MEM", | ||
102 | .flags = IORESOURCE_MEM, | ||
103 | .start = 0x10000000, | ||
104 | .end = 0x1dffffff | ||
105 | }; | ||
106 | |||
107 | static struct resource pci_virtio_guest_io_resource = { | ||
108 | .name = "Virtio IO", | ||
109 | .flags = IORESOURCE_IO, | ||
110 | .start = 0, | ||
111 | .end = 0xffff | ||
112 | }; | ||
113 | |||
114 | static struct pci_controller pci_virtio_guest_controller = { | ||
115 | .pci_ops = &pci_virtio_guest_ops, | ||
116 | .mem_resource = &pci_virtio_guest_mem_resource, | ||
117 | .io_resource = &pci_virtio_guest_io_resource, | ||
118 | }; | ||
119 | |||
120 | static int __init pci_virtio_guest_setup(void) | ||
121 | { | ||
122 | pr_err("pci_virtio_guest_setup\n"); | ||
123 | |||
124 | /* Virtio comes pre-assigned */ | ||
125 | pci_set_flags(PCI_PROBE_ONLY); | ||
126 | |||
127 | pci_virtio_guest_controller.io_map_base = mips_io_port_base; | ||
128 | register_pci_controller(&pci_virtio_guest_controller); | ||
129 | return 0; | ||
130 | } | ||
131 | arch_initcall(pci_virtio_guest_setup); | ||
diff --git a/arch/mips/pmcs-msp71xx/Makefile b/arch/mips/pmcs-msp71xx/Makefile index 9201c8b3858d..d4f7220f2485 100644 --- a/arch/mips/pmcs-msp71xx/Makefile +++ b/arch/mips/pmcs-msp71xx/Makefile | |||
@@ -10,4 +10,3 @@ obj-$(CONFIG_PCI) += msp_pci.o | |||
10 | obj-$(CONFIG_MSP_HAS_MAC) += msp_eth.o | 10 | obj-$(CONFIG_MSP_HAS_MAC) += msp_eth.o |
11 | obj-$(CONFIG_MSP_HAS_USB) += msp_usb.o | 11 | obj-$(CONFIG_MSP_HAS_USB) += msp_usb.o |
12 | obj-$(CONFIG_MIPS_MT_SMP) += msp_smp.o | 12 | obj-$(CONFIG_MIPS_MT_SMP) += msp_smp.o |
13 | obj-$(CONFIG_MIPS_MT_SMTC) += msp_smtc.o | ||
diff --git a/arch/mips/pmcs-msp71xx/msp_eth.c b/arch/mips/pmcs-msp71xx/msp_eth.c index c584df393de2..15679b427f44 100644 --- a/arch/mips/pmcs-msp71xx/msp_eth.c +++ b/arch/mips/pmcs-msp71xx/msp_eth.c | |||
@@ -38,73 +38,6 @@ | |||
38 | #define MSP_ETHERNET_GPIO1 15 | 38 | #define MSP_ETHERNET_GPIO1 15 |
39 | #define MSP_ETHERNET_GPIO2 16 | 39 | #define MSP_ETHERNET_GPIO2 16 |
40 | 40 | ||
41 | #ifdef CONFIG_MSP_HAS_TSMAC | ||
42 | #define MSP_TSMAC_SIZE 0x10020 | ||
43 | #define MSP_TSMAC_ID "pmc_tsmac" | ||
44 | |||
45 | static struct resource msp_tsmac0_resources[] = { | ||
46 | [0] = { | ||
47 | .start = MSP_MAC0_BASE, | ||
48 | .end = MSP_MAC0_BASE + MSP_TSMAC_SIZE - 1, | ||
49 | .flags = IORESOURCE_MEM, | ||
50 | }, | ||
51 | [1] = { | ||
52 | .start = MSP_INT_MAC0, | ||
53 | .end = MSP_INT_MAC0, | ||
54 | .flags = IORESOURCE_IRQ, | ||
55 | }, | ||
56 | }; | ||
57 | |||
58 | static struct resource msp_tsmac1_resources[] = { | ||
59 | [0] = { | ||
60 | .start = MSP_MAC1_BASE, | ||
61 | .end = MSP_MAC1_BASE + MSP_TSMAC_SIZE - 1, | ||
62 | .flags = IORESOURCE_MEM, | ||
63 | }, | ||
64 | [1] = { | ||
65 | .start = MSP_INT_MAC1, | ||
66 | .end = MSP_INT_MAC1, | ||
67 | .flags = IORESOURCE_IRQ, | ||
68 | }, | ||
69 | }; | ||
70 | static struct resource msp_tsmac2_resources[] = { | ||
71 | [0] = { | ||
72 | .start = MSP_MAC2_BASE, | ||
73 | .end = MSP_MAC2_BASE + MSP_TSMAC_SIZE - 1, | ||
74 | .flags = IORESOURCE_MEM, | ||
75 | }, | ||
76 | [1] = { | ||
77 | .start = MSP_INT_SAR, | ||
78 | .end = MSP_INT_SAR, | ||
79 | .flags = IORESOURCE_IRQ, | ||
80 | }, | ||
81 | }; | ||
82 | |||
83 | |||
84 | static struct platform_device tsmac_device[] = { | ||
85 | [0] = { | ||
86 | .name = MSP_TSMAC_ID, | ||
87 | .id = 0, | ||
88 | .num_resources = ARRAY_SIZE(msp_tsmac0_resources), | ||
89 | .resource = msp_tsmac0_resources, | ||
90 | }, | ||
91 | [1] = { | ||
92 | .name = MSP_TSMAC_ID, | ||
93 | .id = 1, | ||
94 | .num_resources = ARRAY_SIZE(msp_tsmac1_resources), | ||
95 | .resource = msp_tsmac1_resources, | ||
96 | }, | ||
97 | [2] = { | ||
98 | .name = MSP_TSMAC_ID, | ||
99 | .id = 2, | ||
100 | .num_resources = ARRAY_SIZE(msp_tsmac2_resources), | ||
101 | .resource = msp_tsmac2_resources, | ||
102 | }, | ||
103 | }; | ||
104 | #define msp_eth_devs tsmac_device | ||
105 | |||
106 | #else | ||
107 | /* If it is not TSMAC assume MSP_ETH (100Mbps) */ | ||
108 | #define MSP_ETH_ID "pmc_mspeth" | 41 | #define MSP_ETH_ID "pmc_mspeth" |
109 | #define MSP_ETH_SIZE 0xE0 | 42 | #define MSP_ETH_SIZE 0xE0 |
110 | static struct resource msp_eth0_resources[] = { | 43 | static struct resource msp_eth0_resources[] = { |
@@ -152,7 +85,6 @@ static struct platform_device mspeth_device[] = { | |||
152 | }; | 85 | }; |
153 | #define msp_eth_devs mspeth_device | 86 | #define msp_eth_devs mspeth_device |
154 | 87 | ||
155 | #endif | ||
156 | int __init msp_eth_setup(void) | 88 | int __init msp_eth_setup(void) |
157 | { | 89 | { |
158 | int i, ret = 0; | 90 | int i, ret = 0; |
@@ -161,14 +93,6 @@ int __init msp_eth_setup(void) | |||
161 | msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO0); | 93 | msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO0); |
162 | msp_gpio_pin_hi(MSP_ETHERNET_GPIO0); | 94 | msp_gpio_pin_hi(MSP_ETHERNET_GPIO0); |
163 | 95 | ||
164 | #ifdef CONFIG_MSP_HAS_TSMAC | ||
165 | /* 3 phys on boards with TSMAC */ | ||
166 | msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO1); | ||
167 | msp_gpio_pin_hi(MSP_ETHERNET_GPIO1); | ||
168 | |||
169 | msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO2); | ||
170 | msp_gpio_pin_hi(MSP_ETHERNET_GPIO2); | ||
171 | #endif | ||
172 | for (i = 0; i < ARRAY_SIZE(msp_eth_devs); i++) { | 96 | for (i = 0; i < ARRAY_SIZE(msp_eth_devs); i++) { |
173 | ret = platform_device_register(&msp_eth_devs[i]); | 97 | ret = platform_device_register(&msp_eth_devs[i]); |
174 | printk(KERN_INFO "device: %d, return value = %d\n", i, ret); | 98 | printk(KERN_INFO "device: %d, return value = %d\n", i, ret); |
diff --git a/arch/mips/pmcs-msp71xx/msp_irq.c b/arch/mips/pmcs-msp71xx/msp_irq.c index 9da5619c00a5..941744aabb51 100644 --- a/arch/mips/pmcs-msp71xx/msp_irq.c +++ b/arch/mips/pmcs-msp71xx/msp_irq.c | |||
@@ -32,7 +32,7 @@ extern void msp_vsmp_int_init(void); | |||
32 | 32 | ||
33 | /* vectored interrupt implementation */ | 33 | /* vectored interrupt implementation */ |
34 | 34 | ||
35 | /* SW0/1 interrupts are used for SMP/SMTC */ | 35 | /* SW0/1 interrupts are used for SMP */ |
36 | static inline void mac0_int_dispatch(void) { do_IRQ(MSP_INT_MAC0); } | 36 | static inline void mac0_int_dispatch(void) { do_IRQ(MSP_INT_MAC0); } |
37 | static inline void mac1_int_dispatch(void) { do_IRQ(MSP_INT_MAC1); } | 37 | static inline void mac1_int_dispatch(void) { do_IRQ(MSP_INT_MAC1); } |
38 | static inline void mac2_int_dispatch(void) { do_IRQ(MSP_INT_SAR); } | 38 | static inline void mac2_int_dispatch(void) { do_IRQ(MSP_INT_SAR); } |
@@ -138,14 +138,6 @@ void __init arch_init_irq(void) | |||
138 | set_vi_handler(MSP_INT_SEC, sec_int_dispatch); | 138 | set_vi_handler(MSP_INT_SEC, sec_int_dispatch); |
139 | #ifdef CONFIG_MIPS_MT_SMP | 139 | #ifdef CONFIG_MIPS_MT_SMP |
140 | msp_vsmp_int_init(); | 140 | msp_vsmp_int_init(); |
141 | #elif defined CONFIG_MIPS_MT_SMTC | ||
142 | /*Set hwmask for all platform devices */ | ||
143 | irq_hwmask[MSP_INT_MAC0] = C_IRQ0; | ||
144 | irq_hwmask[MSP_INT_MAC1] = C_IRQ1; | ||
145 | irq_hwmask[MSP_INT_USB] = C_IRQ2; | ||
146 | irq_hwmask[MSP_INT_SAR] = C_IRQ3; | ||
147 | irq_hwmask[MSP_INT_SEC] = C_IRQ5; | ||
148 | |||
149 | #endif /* CONFIG_MIPS_MT_SMP */ | 141 | #endif /* CONFIG_MIPS_MT_SMP */ |
150 | #endif /* CONFIG_MIPS_MT */ | 142 | #endif /* CONFIG_MIPS_MT */ |
151 | /* setup the cascaded interrupts */ | 143 | /* setup the cascaded interrupts */ |
@@ -153,8 +145,10 @@ void __init arch_init_irq(void) | |||
153 | setup_irq(MSP_INT_PER, &per_cascade_msp); | 145 | setup_irq(MSP_INT_PER, &per_cascade_msp); |
154 | 146 | ||
155 | #else | 147 | #else |
156 | /* setup the 2nd-level SLP register based interrupt controller */ | 148 | /* |
157 | /* VSMP /SMTC support support is not enabled for SLP */ | 149 | * Setup the 2nd-level SLP register based interrupt controller. |
150 | * VSMP support support is not enabled for SLP. | ||
151 | */ | ||
158 | msp_slp_irq_init(); | 152 | msp_slp_irq_init(); |
159 | 153 | ||
160 | /* setup the cascaded SLP/PER interrupts */ | 154 | /* setup the cascaded SLP/PER interrupts */ |
diff --git a/arch/mips/pmcs-msp71xx/msp_irq_cic.c b/arch/mips/pmcs-msp71xx/msp_irq_cic.c index e49b499f66db..b8df2f7b3328 100644 --- a/arch/mips/pmcs-msp71xx/msp_irq_cic.c +++ b/arch/mips/pmcs-msp71xx/msp_irq_cic.c | |||
@@ -120,10 +120,9 @@ static void msp_cic_irq_ack(struct irq_data *d) | |||
120 | * hurt for the others | 120 | * hurt for the others |
121 | */ | 121 | */ |
122 | *CIC_STS_REG = (1 << (d->irq - MSP_CIC_INTBASE)); | 122 | *CIC_STS_REG = (1 << (d->irq - MSP_CIC_INTBASE)); |
123 | smtc_im_ack_irq(d->irq); | ||
124 | } | 123 | } |
125 | 124 | ||
126 | /*Note: Limiting to VSMP . Not tested in SMTC */ | 125 | /* Note: Limiting to VSMP. */ |
127 | 126 | ||
128 | #ifdef CONFIG_MIPS_MT_SMP | 127 | #ifdef CONFIG_MIPS_MT_SMP |
129 | static int msp_cic_irq_set_affinity(struct irq_data *d, | 128 | static int msp_cic_irq_set_affinity(struct irq_data *d, |
@@ -183,10 +182,6 @@ void __init msp_cic_irq_init(void) | |||
183 | for (i = MSP_CIC_INTBASE ; i < MSP_CIC_INTBASE + 32 ; i++) { | 182 | for (i = MSP_CIC_INTBASE ; i < MSP_CIC_INTBASE + 32 ; i++) { |
184 | irq_set_chip_and_handler(i, &msp_cic_irq_controller, | 183 | irq_set_chip_and_handler(i, &msp_cic_irq_controller, |
185 | handle_level_irq); | 184 | handle_level_irq); |
186 | #ifdef CONFIG_MIPS_MT_SMTC | ||
187 | /* Mask of CIC interrupt */ | ||
188 | irq_hwmask[i] = C_IRQ4; | ||
189 | #endif | ||
190 | } | 185 | } |
191 | 186 | ||
192 | /* Initialize the PER interrupt sub-system */ | 187 | /* Initialize the PER interrupt sub-system */ |
diff --git a/arch/mips/pmcs-msp71xx/msp_irq_per.c b/arch/mips/pmcs-msp71xx/msp_irq_per.c index d1fd530479d4..a111836bcec2 100644 --- a/arch/mips/pmcs-msp71xx/msp_irq_per.c +++ b/arch/mips/pmcs-msp71xx/msp_irq_per.c | |||
@@ -113,9 +113,6 @@ void __init msp_per_irq_init(void) | |||
113 | /* initialize all the IRQ descriptors */ | 113 | /* initialize all the IRQ descriptors */ |
114 | for (i = MSP_PER_INTBASE; i < MSP_PER_INTBASE + 32; i++) { | 114 | for (i = MSP_PER_INTBASE; i < MSP_PER_INTBASE + 32; i++) { |
115 | irq_set_chip(i, &msp_per_irq_controller); | 115 | irq_set_chip(i, &msp_per_irq_controller); |
116 | #ifdef CONFIG_MIPS_MT_SMTC | ||
117 | irq_hwmask[i] = C_IRQ4; | ||
118 | #endif | ||
119 | } | 116 | } |
120 | } | 117 | } |
121 | 118 | ||
diff --git a/arch/mips/pmcs-msp71xx/msp_setup.c b/arch/mips/pmcs-msp71xx/msp_setup.c index 7e980767679c..4f925e06c414 100644 --- a/arch/mips/pmcs-msp71xx/msp_setup.c +++ b/arch/mips/pmcs-msp71xx/msp_setup.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | extern void msp_serial_setup(void); | 29 | extern void msp_serial_setup(void); |
30 | extern void pmctwiled_setup(void); | ||
31 | 30 | ||
32 | #if defined(CONFIG_PMC_MSP7120_EVAL) || \ | 31 | #if defined(CONFIG_PMC_MSP7120_EVAL) || \ |
33 | defined(CONFIG_PMC_MSP7120_GW) || \ | 32 | defined(CONFIG_PMC_MSP7120_GW) || \ |
@@ -148,8 +147,6 @@ void __init plat_mem_setup(void) | |||
148 | pm_power_off = msp_power_off; | 147 | pm_power_off = msp_power_off; |
149 | } | 148 | } |
150 | 149 | ||
151 | extern struct plat_smp_ops msp_smtc_smp_ops; | ||
152 | |||
153 | void __init prom_init(void) | 150 | void __init prom_init(void) |
154 | { | 151 | { |
155 | unsigned long family; | 152 | unsigned long family; |
@@ -230,17 +227,5 @@ void __init prom_init(void) | |||
230 | */ | 227 | */ |
231 | msp_serial_setup(); | 228 | msp_serial_setup(); |
232 | 229 | ||
233 | if (register_vsmp_smp_ops()) { | 230 | register_vsmp_smp_ops(); |
234 | #ifdef CONFIG_MIPS_MT_SMTC | ||
235 | register_smp_ops(&msp_smtc_smp_ops); | ||
236 | #endif | ||
237 | } | ||
238 | |||
239 | #ifdef CONFIG_PMCTWILED | ||
240 | /* | ||
241 | * Setup LED states before the subsys_initcall loads other | ||
242 | * dependent drivers/modules. | ||
243 | */ | ||
244 | pmctwiled_setup(); | ||
245 | #endif | ||
246 | } | 231 | } |
diff --git a/arch/mips/pmcs-msp71xx/msp_smtc.c b/arch/mips/pmcs-msp71xx/msp_smtc.c deleted file mode 100644 index 6b5607fce279..000000000000 --- a/arch/mips/pmcs-msp71xx/msp_smtc.c +++ /dev/null | |||
@@ -1,104 +0,0 @@ | |||
1 | /* | ||
2 | * MSP71xx Platform-specific hooks for SMP operation | ||
3 | */ | ||
4 | #include <linux/irq.h> | ||
5 | #include <linux/init.h> | ||
6 | |||
7 | #include <asm/mipsmtregs.h> | ||
8 | #include <asm/mipsregs.h> | ||
9 | #include <asm/smtc.h> | ||
10 | #include <asm/smtc_ipi.h> | ||
11 | |||
12 | /* VPE/SMP Prototype implements platform interfaces directly */ | ||
13 | |||
14 | /* | ||
15 | * Cause the specified action to be performed on a targeted "CPU" | ||
16 | */ | ||
17 | |||
18 | static void msp_smtc_send_ipi_single(int cpu, unsigned int action) | ||
19 | { | ||
20 | /* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */ | ||
21 | smtc_send_ipi(cpu, LINUX_SMP_IPI, action); | ||
22 | } | ||
23 | |||
24 | static void msp_smtc_send_ipi_mask(const struct cpumask *mask, | ||
25 | unsigned int action) | ||
26 | { | ||
27 | unsigned int i; | ||
28 | |||
29 | for_each_cpu(i, mask) | ||
30 | msp_smtc_send_ipi_single(i, action); | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Post-config but pre-boot cleanup entry point | ||
35 | */ | ||
36 | static void msp_smtc_init_secondary(void) | ||
37 | { | ||
38 | int myvpe; | ||
39 | |||
40 | /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */ | ||
41 | myvpe = read_c0_tcbind() & TCBIND_CURVPE; | ||
42 | if (myvpe > 0) | ||
43 | change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 | | ||
44 | STATUSF_IP6 | STATUSF_IP7); | ||
45 | smtc_init_secondary(); | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Platform "CPU" startup hook | ||
50 | */ | ||
51 | static void msp_smtc_boot_secondary(int cpu, struct task_struct *idle) | ||
52 | { | ||
53 | smtc_boot_secondary(cpu, idle); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * SMP initialization finalization entry point | ||
58 | */ | ||
59 | static void msp_smtc_smp_finish(void) | ||
60 | { | ||
61 | smtc_smp_finish(); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * Hook for after all CPUs are online | ||
66 | */ | ||
67 | |||
68 | static void msp_smtc_cpus_done(void) | ||
69 | { | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * Platform SMP pre-initialization | ||
74 | * | ||
75 | * As noted above, we can assume a single CPU for now | ||
76 | * but it may be multithreaded. | ||
77 | */ | ||
78 | |||
79 | static void __init msp_smtc_smp_setup(void) | ||
80 | { | ||
81 | /* | ||
82 | * we won't get the definitive value until | ||
83 | * we've run smtc_prepare_cpus later, but | ||
84 | */ | ||
85 | |||
86 | if (read_c0_config3() & (1 << 2)) | ||
87 | smp_num_siblings = smtc_build_cpu_map(0); | ||
88 | } | ||
89 | |||
90 | static void __init msp_smtc_prepare_cpus(unsigned int max_cpus) | ||
91 | { | ||
92 | smtc_prepare_cpus(max_cpus); | ||
93 | } | ||
94 | |||
95 | struct plat_smp_ops msp_smtc_smp_ops = { | ||
96 | .send_ipi_single = msp_smtc_send_ipi_single, | ||
97 | .send_ipi_mask = msp_smtc_send_ipi_mask, | ||
98 | .init_secondary = msp_smtc_init_secondary, | ||
99 | .smp_finish = msp_smtc_smp_finish, | ||
100 | .cpus_done = msp_smtc_cpus_done, | ||
101 | .boot_secondary = msp_smtc_boot_secondary, | ||
102 | .smp_setup = msp_smtc_smp_setup, | ||
103 | .prepare_cpus = msp_smtc_prepare_cpus, | ||
104 | }; | ||
diff --git a/arch/mips/pmcs-msp71xx/msp_usb.c b/arch/mips/pmcs-msp71xx/msp_usb.c index 4dab915696e7..c87c5f810cd1 100644 --- a/arch/mips/pmcs-msp71xx/msp_usb.c +++ b/arch/mips/pmcs-msp71xx/msp_usb.c | |||
@@ -75,47 +75,6 @@ static struct mspusb_device msp_usbhost0_device = { | |||
75 | .resource = msp_usbhost0_resources, | 75 | .resource = msp_usbhost0_resources, |
76 | }, | 76 | }, |
77 | }; | 77 | }; |
78 | |||
79 | /* MSP7140/MSP82XX has two USB2 hosts. */ | ||
80 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
81 | static u64 msp_usbhost1_dma_mask = 0xffffffffUL; | ||
82 | |||
83 | static struct resource msp_usbhost1_resources[] = { | ||
84 | [0] = { /* EHCI-HS operational and capabilities registers */ | ||
85 | .start = MSP_USB1_HS_START, | ||
86 | .end = MSP_USB1_HS_END, | ||
87 | .flags = IORESOURCE_MEM, | ||
88 | }, | ||
89 | [1] = { | ||
90 | .start = MSP_INT_USB, | ||
91 | .end = MSP_INT_USB, | ||
92 | .flags = IORESOURCE_IRQ, | ||
93 | }, | ||
94 | [2] = { /* MSBus-to-AMBA bridge register space */ | ||
95 | .start = MSP_USB1_MAB_START, | ||
96 | .end = MSP_USB1_MAB_END, | ||
97 | .flags = IORESOURCE_MEM, | ||
98 | }, | ||
99 | [3] = { /* Identification and general hardware parameters */ | ||
100 | .start = MSP_USB1_ID_START, | ||
101 | .end = MSP_USB1_ID_END, | ||
102 | .flags = IORESOURCE_MEM, | ||
103 | }, | ||
104 | }; | ||
105 | |||
106 | static struct mspusb_device msp_usbhost1_device = { | ||
107 | .dev = { | ||
108 | .name = "pmcmsp-ehci", | ||
109 | .id = 1, | ||
110 | .dev = { | ||
111 | .dma_mask = &msp_usbhost1_dma_mask, | ||
112 | .coherent_dma_mask = 0xffffffffUL, | ||
113 | }, | ||
114 | .num_resources = ARRAY_SIZE(msp_usbhost1_resources), | ||
115 | .resource = msp_usbhost1_resources, | ||
116 | }, | ||
117 | }; | ||
118 | #endif /* CONFIG_MSP_HAS_DUAL_USB */ | ||
119 | #endif /* CONFIG_USB_EHCI_HCD */ | 78 | #endif /* CONFIG_USB_EHCI_HCD */ |
120 | 79 | ||
121 | #if defined(CONFIG_USB_GADGET) | 80 | #if defined(CONFIG_USB_GADGET) |
@@ -157,46 +116,6 @@ static struct mspusb_device msp_usbdev0_device = { | |||
157 | .resource = msp_usbdev0_resources, | 116 | .resource = msp_usbdev0_resources, |
158 | }, | 117 | }, |
159 | }; | 118 | }; |
160 | |||
161 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
162 | static struct resource msp_usbdev1_resources[] = { | ||
163 | [0] = { /* EHCI-HS operational and capabilities registers */ | ||
164 | .start = MSP_USB1_HS_START, | ||
165 | .end = MSP_USB1_HS_END, | ||
166 | .flags = IORESOURCE_MEM, | ||
167 | }, | ||
168 | [1] = { | ||
169 | .start = MSP_INT_USB, | ||
170 | .end = MSP_INT_USB, | ||
171 | .flags = IORESOURCE_IRQ, | ||
172 | }, | ||
173 | [2] = { /* MSBus-to-AMBA bridge register space */ | ||
174 | .start = MSP_USB1_MAB_START, | ||
175 | .end = MSP_USB1_MAB_END, | ||
176 | .flags = IORESOURCE_MEM, | ||
177 | }, | ||
178 | [3] = { /* Identification and general hardware parameters */ | ||
179 | .start = MSP_USB1_ID_START, | ||
180 | .end = MSP_USB1_ID_END, | ||
181 | .flags = IORESOURCE_MEM, | ||
182 | }, | ||
183 | }; | ||
184 | |||
185 | /* This may need to be converted to a mspusb_device, too. */ | ||
186 | static struct mspusb_device msp_usbdev1_device = { | ||
187 | .dev = { | ||
188 | .name = "msp71xx_udc", | ||
189 | .id = 0, | ||
190 | .dev = { | ||
191 | .dma_mask = &msp_usbdev_dma_mask, | ||
192 | .coherent_dma_mask = 0xffffffffUL, | ||
193 | }, | ||
194 | .num_resources = ARRAY_SIZE(msp_usbdev1_resources), | ||
195 | .resource = msp_usbdev1_resources, | ||
196 | }, | ||
197 | }; | ||
198 | |||
199 | #endif /* CONFIG_MSP_HAS_DUAL_USB */ | ||
200 | #endif /* CONFIG_USB_GADGET */ | 119 | #endif /* CONFIG_USB_GADGET */ |
201 | 120 | ||
202 | static int __init msp_usb_setup(void) | 121 | static int __init msp_usb_setup(void) |
@@ -231,10 +150,6 @@ static int __init msp_usb_setup(void) | |||
231 | #if defined(CONFIG_USB_EHCI_HCD) | 150 | #if defined(CONFIG_USB_EHCI_HCD) |
232 | msp_devs[0] = &msp_usbhost0_device.dev; | 151 | msp_devs[0] = &msp_usbhost0_device.dev; |
233 | ppfinit("platform add USB HOST done %s.\n", msp_devs[0]->name); | 152 | ppfinit("platform add USB HOST done %s.\n", msp_devs[0]->name); |
234 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
235 | msp_devs[1] = &msp_usbhost1_device.dev; | ||
236 | ppfinit("platform add USB HOST done %s.\n", msp_devs[1]->name); | ||
237 | #endif | ||
238 | #else | 153 | #else |
239 | ppfinit("%s: echi_hcd not supported\n", __FILE__); | 154 | ppfinit("%s: echi_hcd not supported\n", __FILE__); |
240 | #endif /* CONFIG_USB_EHCI_HCD */ | 155 | #endif /* CONFIG_USB_EHCI_HCD */ |
@@ -244,11 +159,6 @@ static int __init msp_usb_setup(void) | |||
244 | msp_devs[0] = &msp_usbdev0_device.dev; | 159 | msp_devs[0] = &msp_usbdev0_device.dev; |
245 | ppfinit("platform add USB DEVICE done %s.\n" | 160 | ppfinit("platform add USB DEVICE done %s.\n" |
246 | , msp_devs[0]->name); | 161 | , msp_devs[0]->name); |
247 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
248 | msp_devs[1] = &msp_usbdev1_device.dev; | ||
249 | ppfinit("platform add USB DEVICE done %s.\n" | ||
250 | , msp_devs[1]->name); | ||
251 | #endif | ||
252 | #else | 162 | #else |
253 | ppfinit("%s: usb_gadget not supported\n", __FILE__); | 163 | ppfinit("%s: usb_gadget not supported\n", __FILE__); |
254 | #endif /* CONFIG_USB_GADGET */ | 164 | #endif /* CONFIG_USB_GADGET */ |
diff --git a/arch/mips/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c index 2b7e837dc2e2..b4b774bc3178 100644 --- a/arch/mips/pnx833x/common/platform.c +++ b/arch/mips/pnx833x/common/platform.c | |||
@@ -33,11 +33,6 @@ | |||
33 | #include <linux/mtd/nand.h> | 33 | #include <linux/mtd/nand.h> |
34 | #include <linux/mtd/partitions.h> | 34 | #include <linux/mtd/partitions.h> |
35 | 35 | ||
36 | #ifdef CONFIG_I2C_PNX0105 | ||
37 | /* Until i2c driver available in kernel.*/ | ||
38 | #include <linux/i2c-pnx0105.h> | ||
39 | #endif | ||
40 | |||
41 | #include <irq.h> | 36 | #include <irq.h> |
42 | #include <irq-mapping.h> | 37 | #include <irq-mapping.h> |
43 | #include <pnx833x.h> | 38 | #include <pnx833x.h> |
@@ -134,70 +129,6 @@ static struct platform_device pnx833x_usb_ehci_device = { | |||
134 | .resource = pnx833x_usb_ehci_resources, | 129 | .resource = pnx833x_usb_ehci_resources, |
135 | }; | 130 | }; |
136 | 131 | ||
137 | #ifdef CONFIG_I2C_PNX0105 | ||
138 | static struct resource pnx833x_i2c0_resources[] = { | ||
139 | { | ||
140 | .start = PNX833X_I2C0_PORTS_START, | ||
141 | .end = PNX833X_I2C0_PORTS_END, | ||
142 | .flags = IORESOURCE_MEM, | ||
143 | }, | ||
144 | { | ||
145 | .start = PNX833X_PIC_I2C0_INT, | ||
146 | .end = PNX833X_PIC_I2C0_INT, | ||
147 | .flags = IORESOURCE_IRQ, | ||
148 | }, | ||
149 | }; | ||
150 | |||
151 | static struct resource pnx833x_i2c1_resources[] = { | ||
152 | { | ||
153 | .start = PNX833X_I2C1_PORTS_START, | ||
154 | .end = PNX833X_I2C1_PORTS_END, | ||
155 | .flags = IORESOURCE_MEM, | ||
156 | }, | ||
157 | { | ||
158 | .start = PNX833X_PIC_I2C1_INT, | ||
159 | .end = PNX833X_PIC_I2C1_INT, | ||
160 | .flags = IORESOURCE_IRQ, | ||
161 | }, | ||
162 | }; | ||
163 | |||
164 | static struct i2c_pnx0105_dev pnx833x_i2c_dev[] = { | ||
165 | { | ||
166 | .base = PNX833X_I2C0_PORTS_START, | ||
167 | .irq = -1, /* should be PNX833X_PIC_I2C0_INT but polling is faster */ | ||
168 | .clock = 6, /* 0 == 400 kHz, 4 == 100 kHz(Maximum HDMI), 6 = 50kHz(Preferred HDCP) */ | ||
169 | .bus_addr = 0, /* no slave support */ | ||
170 | }, | ||
171 | { | ||
172 | .base = PNX833X_I2C1_PORTS_START, | ||
173 | .irq = -1, /* on high freq, polling is faster */ | ||
174 | /*.irq = PNX833X_PIC_I2C1_INT,*/ | ||
175 | .clock = 4, /* 0 == 400 kHz, 4 == 100 kHz. 100 kHz seems a safe default for now */ | ||
176 | .bus_addr = 0, /* no slave support */ | ||
177 | }, | ||
178 | }; | ||
179 | |||
180 | static struct platform_device pnx833x_i2c0_device = { | ||
181 | .name = "i2c-pnx0105", | ||
182 | .id = 0, | ||
183 | .dev = { | ||
184 | .platform_data = &pnx833x_i2c_dev[0], | ||
185 | }, | ||
186 | .num_resources = ARRAY_SIZE(pnx833x_i2c0_resources), | ||
187 | .resource = pnx833x_i2c0_resources, | ||
188 | }; | ||
189 | |||
190 | static struct platform_device pnx833x_i2c1_device = { | ||
191 | .name = "i2c-pnx0105", | ||
192 | .id = 1, | ||
193 | .dev = { | ||
194 | .platform_data = &pnx833x_i2c_dev[1], | ||
195 | }, | ||
196 | .num_resources = ARRAY_SIZE(pnx833x_i2c1_resources), | ||
197 | .resource = pnx833x_i2c1_resources, | ||
198 | }; | ||
199 | #endif | ||
200 | |||
201 | static u64 ethernet_dmamask = DMA_BIT_MASK(32); | 132 | static u64 ethernet_dmamask = DMA_BIT_MASK(32); |
202 | 133 | ||
203 | static struct resource pnx833x_ethernet_resources[] = { | 134 | static struct resource pnx833x_ethernet_resources[] = { |
@@ -294,10 +225,6 @@ static struct platform_device pnx833x_flash_nand = { | |||
294 | static struct platform_device *pnx833x_platform_devices[] __initdata = { | 225 | static struct platform_device *pnx833x_platform_devices[] __initdata = { |
295 | &pnx833x_uart_device, | 226 | &pnx833x_uart_device, |
296 | &pnx833x_usb_ehci_device, | 227 | &pnx833x_usb_ehci_device, |
297 | #ifdef CONFIG_I2C_PNX0105 | ||
298 | &pnx833x_i2c0_device, | ||
299 | &pnx833x_i2c1_device, | ||
300 | #endif | ||
301 | &pnx833x_ethernet_device, | 228 | &pnx833x_ethernet_device, |
302 | &pnx833x_sata_device, | 229 | &pnx833x_sata_device, |
303 | &pnx833x_flash_nand, | 230 | &pnx833x_flash_nand, |
diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c index ab0e379dc7e0..8e52446286ca 100644 --- a/arch/mips/sgi-ip22/ip22-gio.c +++ b/arch/mips/sgi-ip22/ip22-gio.c | |||
@@ -19,6 +19,9 @@ static struct { | |||
19 | } gio_name_table[] = { | 19 | } gio_name_table[] = { |
20 | { .name = "SGI Impact", .id = 0x10 }, | 20 | { .name = "SGI Impact", .id = 0x10 }, |
21 | { .name = "Phobos G160", .id = 0x35 }, | 21 | { .name = "Phobos G160", .id = 0x35 }, |
22 | { .name = "Phobos G130", .id = 0x36 }, | ||
23 | { .name = "Phobos G100", .id = 0x37 }, | ||
24 | { .name = "Set Engineering GFE", .id = 0x38 }, | ||
22 | /* fake IDs */ | 25 | /* fake IDs */ |
23 | { .name = "SGI Newport", .id = 0x7e }, | 26 | { .name = "SGI Newport", .id = 0x7e }, |
24 | { .name = "SGI GR2/GR3", .id = 0x7f }, | 27 | { .name = "SGI GR2/GR3", .id = 0x7f }, |
@@ -293,7 +296,16 @@ static int ip22_gio_id(unsigned long addr, u32 *res) | |||
293 | * data matches | 296 | * data matches |
294 | */ | 297 | */ |
295 | ptr8 = (void *)CKSEG1ADDR(addr + 3); | 298 | ptr8 = (void *)CKSEG1ADDR(addr + 3); |
296 | get_dbe(tmp8, ptr8); | 299 | if (get_dbe(tmp8, ptr8)) { |
300 | /* | ||
301 | * 32bit access worked, but 8bit doesn't | ||
302 | * so we don't see phantom reads on | ||
303 | * a pipelined bus, but a real card which | ||
304 | * doesn't support 8 bit reads | ||
305 | */ | ||
306 | *res = tmp32; | ||
307 | return 1; | ||
308 | } | ||
297 | ptr16 = (void *)CKSEG1ADDR(addr + 2); | 309 | ptr16 = (void *)CKSEG1ADDR(addr + 2); |
298 | get_dbe(tmp16, ptr16); | 310 | get_dbe(tmp16, ptr16); |
299 | if (tmp8 == (tmp16 & 0xff) && | 311 | if (tmp8 == (tmp16 & 0xff) && |
@@ -324,7 +336,7 @@ static int ip22_is_gr2(unsigned long addr) | |||
324 | } | 336 | } |
325 | 337 | ||
326 | 338 | ||
327 | static void ip22_check_gio(int slotno, unsigned long addr) | 339 | static void ip22_check_gio(int slotno, unsigned long addr, int irq) |
328 | { | 340 | { |
329 | const char *name = "Unknown"; | 341 | const char *name = "Unknown"; |
330 | struct gio_device *gio_dev; | 342 | struct gio_device *gio_dev; |
@@ -338,9 +350,9 @@ static void ip22_check_gio(int slotno, unsigned long addr) | |||
338 | else { | 350 | else { |
339 | if (!ip22_gio_id(addr, &tmp)) { | 351 | if (!ip22_gio_id(addr, &tmp)) { |
340 | /* | 352 | /* |
341 | * no GIO signature at start address of slot, but | 353 | * no GIO signature at start address of slot |
342 | * Newport doesn't have one, so let's check usea | 354 | * since Newport doesn't have one, we check if |
343 | * status register | 355 | * user status register is readable |
344 | */ | 356 | */ |
345 | if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp)) | 357 | if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp)) |
346 | tmp = 0x7e; | 358 | tmp = 0x7e; |
@@ -369,6 +381,7 @@ static void ip22_check_gio(int slotno, unsigned long addr) | |||
369 | gio_dev->resource.start = addr; | 381 | gio_dev->resource.start = addr; |
370 | gio_dev->resource.end = addr + 0x3fffff; | 382 | gio_dev->resource.end = addr + 0x3fffff; |
371 | gio_dev->resource.flags = IORESOURCE_MEM; | 383 | gio_dev->resource.flags = IORESOURCE_MEM; |
384 | gio_dev->irq = irq; | ||
372 | dev_set_name(&gio_dev->dev, "%d", slotno); | 385 | dev_set_name(&gio_dev->dev, "%d", slotno); |
373 | gio_device_register(gio_dev); | 386 | gio_device_register(gio_dev); |
374 | } else | 387 | } else |
@@ -408,16 +421,17 @@ int __init ip22_gio_init(void) | |||
408 | request_resource(&iomem_resource, &gio_bus_resource); | 421 | request_resource(&iomem_resource, &gio_bus_resource); |
409 | printk(KERN_INFO "GIO: Probing bus...\n"); | 422 | printk(KERN_INFO "GIO: Probing bus...\n"); |
410 | 423 | ||
411 | if (ip22_is_fullhouse() || | 424 | if (ip22_is_fullhouse()) { |
412 | !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) { | 425 | /* Indigo2 */ |
413 | /* Indigo2 and ChallengeS */ | 426 | ip22_check_gio(0, GIO_SLOT_GFX_BASE, SGI_GIO_1_IRQ); |
414 | ip22_check_gio(0, GIO_SLOT_GFX_BASE); | 427 | ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIO_1_IRQ); |
415 | ip22_check_gio(1, GIO_SLOT_EXP0_BASE); | ||
416 | } else { | 428 | } else { |
417 | /* Indy */ | 429 | /* Indy/Challenge S */ |
418 | ip22_check_gio(0, GIO_SLOT_GFX_BASE); | 430 | if (get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) |
419 | ip22_check_gio(1, GIO_SLOT_EXP0_BASE); | 431 | ip22_check_gio(0, GIO_SLOT_GFX_BASE, |
420 | ip22_check_gio(2, GIO_SLOT_EXP1_BASE); | 432 | SGI_GIO_0_IRQ); |
433 | ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIOEXP0_IRQ); | ||
434 | ip22_check_gio(2, GIO_SLOT_EXP1_BASE, SGI_GIOEXP1_IRQ); | ||
421 | } | 435 | } |
422 | } else | 436 | } else |
423 | device_unregister(&gio_bus); | 437 | device_unregister(&gio_bus); |
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index 58b40ae59335..c66889fc4913 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c | |||
@@ -119,9 +119,14 @@ static void indy_local0_irqdispatch(void) | |||
119 | } else | 119 | } else |
120 | irq = lc0msk_to_irqnr[mask]; | 120 | irq = lc0msk_to_irqnr[mask]; |
121 | 121 | ||
122 | /* if irq == 0, then the interrupt has already been cleared */ | 122 | /* |
123 | * workaround for INT2 bug; if irq == 0, INT2 has seen a fifo full | ||
124 | * irq, but failed to latch it into status register | ||
125 | */ | ||
123 | if (irq) | 126 | if (irq) |
124 | do_IRQ(irq); | 127 | do_IRQ(irq); |
128 | else | ||
129 | do_IRQ(SGINT_LOCAL0 + 0); | ||
125 | } | 130 | } |
126 | 131 | ||
127 | static void indy_local1_irqdispatch(void) | 132 | static void indy_local1_irqdispatch(void) |
diff --git a/arch/mips/sgi-ip27/ip27-smp.c b/arch/mips/sgi-ip27/ip27-smp.c index f4ea8aa79ba2..f9ae6a8fa7c7 100644 --- a/arch/mips/sgi-ip27/ip27-smp.c +++ b/arch/mips/sgi-ip27/ip27-smp.c | |||
@@ -186,10 +186,6 @@ static void ip27_smp_finish(void) | |||
186 | local_irq_enable(); | 186 | local_irq_enable(); |
187 | } | 187 | } |
188 | 188 | ||
189 | static void __init ip27_cpus_done(void) | ||
190 | { | ||
191 | } | ||
192 | |||
193 | /* | 189 | /* |
194 | * Launch a slave into smp_bootstrap(). It doesn't take an argument, and we | 190 | * Launch a slave into smp_bootstrap(). It doesn't take an argument, and we |
195 | * set sp to the kernel stack of the newly created idle process, gp to the proc | 191 | * set sp to the kernel stack of the newly created idle process, gp to the proc |
@@ -236,7 +232,6 @@ struct plat_smp_ops ip27_smp_ops = { | |||
236 | .send_ipi_mask = ip27_send_ipi_mask, | 232 | .send_ipi_mask = ip27_send_ipi_mask, |
237 | .init_secondary = ip27_init_secondary, | 233 | .init_secondary = ip27_init_secondary, |
238 | .smp_finish = ip27_smp_finish, | 234 | .smp_finish = ip27_smp_finish, |
239 | .cpus_done = ip27_cpus_done, | ||
240 | .boot_secondary = ip27_boot_secondary, | 235 | .boot_secondary = ip27_boot_secondary, |
241 | .smp_setup = ip27_smp_setup, | 236 | .smp_setup = ip27_smp_setup, |
242 | .prepare_cpus = ip27_prepare_cpus, | 237 | .prepare_cpus = ip27_prepare_cpus, |
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index 59cfe2659771..373fbbc8425c 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c | |||
@@ -347,19 +347,8 @@ asmlinkage void plat_irq_dispatch(void) | |||
347 | unsigned int cpu = smp_processor_id(); | 347 | unsigned int cpu = smp_processor_id(); |
348 | unsigned int pending; | 348 | unsigned int pending; |
349 | 349 | ||
350 | #ifdef CONFIG_SIBYTE_BCM1480_PROF | ||
351 | /* Set compare to count to silence count/compare timer interrupts */ | ||
352 | write_c0_compare(read_c0_count()); | ||
353 | #endif | ||
354 | |||
355 | pending = read_c0_cause() & read_c0_status(); | 350 | pending = read_c0_cause() & read_c0_status(); |
356 | 351 | ||
357 | #ifdef CONFIG_SIBYTE_BCM1480_PROF | ||
358 | if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */ | ||
359 | sbprof_cpu_intr(); | ||
360 | else | ||
361 | #endif | ||
362 | |||
363 | if (pending & CAUSEF_IP4) | 352 | if (pending & CAUSEF_IP4) |
364 | do_IRQ(K_BCM1480_INT_TIMER_0 + cpu); | 353 | do_IRQ(K_BCM1480_INT_TIMER_0 + cpu); |
365 | #ifdef CONFIG_SMP | 354 | #ifdef CONFIG_SMP |
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c index 70d9182b26f1..af7d44edd9a8 100644 --- a/arch/mips/sibyte/bcm1480/smp.c +++ b/arch/mips/sibyte/bcm1480/smp.c | |||
@@ -115,13 +115,6 @@ static void bcm1480_smp_finish(void) | |||
115 | } | 115 | } |
116 | 116 | ||
117 | /* | 117 | /* |
118 | * Final cleanup after all secondaries booted | ||
119 | */ | ||
120 | static void bcm1480_cpus_done(void) | ||
121 | { | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * Setup the PC, SP, and GP of a secondary processor and start it | 118 | * Setup the PC, SP, and GP of a secondary processor and start it |
126 | * running! | 119 | * running! |
127 | */ | 120 | */ |
@@ -170,7 +163,6 @@ struct plat_smp_ops bcm1480_smp_ops = { | |||
170 | .send_ipi_mask = bcm1480_send_ipi_mask, | 163 | .send_ipi_mask = bcm1480_send_ipi_mask, |
171 | .init_secondary = bcm1480_init_secondary, | 164 | .init_secondary = bcm1480_init_secondary, |
172 | .smp_finish = bcm1480_smp_finish, | 165 | .smp_finish = bcm1480_smp_finish, |
173 | .cpus_done = bcm1480_cpus_done, | ||
174 | .boot_secondary = bcm1480_boot_secondary, | 166 | .boot_secondary = bcm1480_boot_secondary, |
175 | .smp_setup = bcm1480_smp_setup, | 167 | .smp_setup = bcm1480_smp_setup, |
176 | .prepare_cpus = bcm1480_prepare_cpus, | 168 | .prepare_cpus = bcm1480_prepare_cpus, |
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c index db976117dd4d..c0c4b3f88a08 100644 --- a/arch/mips/sibyte/sb1250/smp.c +++ b/arch/mips/sibyte/sb1250/smp.c | |||
@@ -103,13 +103,6 @@ static void sb1250_smp_finish(void) | |||
103 | } | 103 | } |
104 | 104 | ||
105 | /* | 105 | /* |
106 | * Final cleanup after all secondaries booted | ||
107 | */ | ||
108 | static void sb1250_cpus_done(void) | ||
109 | { | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Setup the PC, SP, and GP of a secondary processor and start it | 106 | * Setup the PC, SP, and GP of a secondary processor and start it |
114 | * running! | 107 | * running! |
115 | */ | 108 | */ |
@@ -158,7 +151,6 @@ struct plat_smp_ops sb_smp_ops = { | |||
158 | .send_ipi_mask = sb1250_send_ipi_mask, | 151 | .send_ipi_mask = sb1250_send_ipi_mask, |
159 | .init_secondary = sb1250_init_secondary, | 152 | .init_secondary = sb1250_init_secondary, |
160 | .smp_finish = sb1250_smp_finish, | 153 | .smp_finish = sb1250_smp_finish, |
161 | .cpus_done = sb1250_cpus_done, | ||
162 | .boot_secondary = sb1250_boot_secondary, | 154 | .boot_secondary = sb1250_boot_secondary, |
163 | .smp_setup = sb1250_smp_setup, | 155 | .smp_setup = sb1250_smp_setup, |
164 | .prepare_cpus = sb1250_prepare_cpus, | 156 | .prepare_cpus = sb1250_prepare_cpus, |
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 2b0b83c171e0..dd2cf25b5ae5 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c | |||
@@ -309,8 +309,8 @@ static void __init preprocess_cmdline(void) | |||
309 | txx9_board_vec = find_board_byname(str + 6); | 309 | txx9_board_vec = find_board_byname(str + 6); |
310 | continue; | 310 | continue; |
311 | } else if (strncmp(str, "masterclk=", 10) == 0) { | 311 | } else if (strncmp(str, "masterclk=", 10) == 0) { |
312 | unsigned long val; | 312 | unsigned int val; |
313 | if (strict_strtoul(str + 10, 10, &val) == 0) | 313 | if (kstrtouint(str + 10, 10, &val) == 0) |
314 | txx9_master_clock = val; | 314 | txx9_master_clock = val; |
315 | continue; | 315 | continue; |
316 | } else if (strcmp(str, "icdisable") == 0) { | 316 | } else if (strcmp(str, "icdisable") == 0) { |