diff options
256 files changed, 8562 insertions, 7905 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 454c054b1790..77556fc91cdd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -2700,6 +2700,15 @@ S: Orphan | |||
| 2700 | F: Documentation/networking/decnet.txt | 2700 | F: Documentation/networking/decnet.txt |
| 2701 | F: net/decnet/ | 2701 | F: net/decnet/ |
| 2702 | 2702 | ||
| 2703 | DECSTATION PLATFORM SUPPORT | ||
| 2704 | M: "Maciej W. Rozycki" <macro@linux-mips.org> | ||
| 2705 | L: linux-mips@linux-mips.org | ||
| 2706 | W: http://www.linux-mips.org/wiki/DECstation | ||
| 2707 | S: Maintained | ||
| 2708 | F: arch/mips/dec/ | ||
| 2709 | F: arch/mips/include/asm/dec/ | ||
| 2710 | F: arch/mips/include/asm/mach-dec/ | ||
| 2711 | |||
| 2703 | DEFXX FDDI NETWORK DRIVER | 2712 | DEFXX FDDI NETWORK DRIVER |
| 2704 | M: "Maciej W. Rozycki" <macro@linux-mips.org> | 2713 | M: "Maciej W. Rozycki" <macro@linux-mips.org> |
| 2705 | S: Maintained | 2714 | S: Maintained |
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) { |
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index f04e25f6c98d..1b96fb91d32c 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig | |||
| @@ -35,6 +35,11 @@ depends on ARM | |||
| 35 | source "drivers/cpuidle/Kconfig.arm" | 35 | source "drivers/cpuidle/Kconfig.arm" |
| 36 | endmenu | 36 | endmenu |
| 37 | 37 | ||
| 38 | menu "MIPS CPU Idle Drivers" | ||
| 39 | depends on MIPS | ||
| 40 | source "drivers/cpuidle/Kconfig.mips" | ||
| 41 | endmenu | ||
| 42 | |||
| 38 | menu "POWERPC CPU Idle Drivers" | 43 | menu "POWERPC CPU Idle Drivers" |
| 39 | depends on PPC | 44 | depends on PPC |
| 40 | source "drivers/cpuidle/Kconfig.powerpc" | 45 | source "drivers/cpuidle/Kconfig.powerpc" |
diff --git a/drivers/cpuidle/Kconfig.mips b/drivers/cpuidle/Kconfig.mips new file mode 100644 index 000000000000..0e70ee28a5ca --- /dev/null +++ b/drivers/cpuidle/Kconfig.mips | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | # | ||
| 2 | # MIPS CPU Idle Drivers | ||
| 3 | # | ||
| 4 | config MIPS_CPS_CPUIDLE | ||
| 5 | bool "CPU Idle driver for MIPS CPS platforms" | ||
| 6 | depends on CPU_IDLE | ||
| 7 | depends on SYS_SUPPORTS_MIPS_CPS | ||
| 8 | select ARCH_NEEDS_CPU_IDLE_COUPLED if MIPS_MT | ||
| 9 | select GENERIC_CLOCKEVENTS_BROADCAST if SMP | ||
| 10 | select MIPS_CPS_PM | ||
| 11 | default y | ||
| 12 | help | ||
| 13 | Select this option to enable processor idle state management | ||
| 14 | through cpuidle for systems built around the MIPS Coherent | ||
| 15 | Processing System (CPS) architecture. In order to make use of | ||
| 16 | the deepest idle states you will need to ensure that you are | ||
| 17 | also using the CONFIG_MIPS_CPS SMP implementation. | ||
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 9b5b2b560d70..d8bb1ff72561 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile | |||
| @@ -18,6 +18,10 @@ obj-$(CONFIG_ARM_AT91_CPUIDLE) += cpuidle-at91.o | |||
| 18 | obj-$(CONFIG_ARM_EXYNOS_CPUIDLE) += cpuidle-exynos.o | 18 | obj-$(CONFIG_ARM_EXYNOS_CPUIDLE) += cpuidle-exynos.o |
| 19 | 19 | ||
| 20 | ############################################################################### | 20 | ############################################################################### |
| 21 | # MIPS drivers | ||
| 22 | obj-$(CONFIG_MIPS_CPS_CPUIDLE) += cpuidle-cps.o | ||
| 23 | |||
| 24 | ############################################################################### | ||
| 21 | # POWERPC drivers | 25 | # POWERPC drivers |
| 22 | obj-$(CONFIG_PSERIES_CPUIDLE) += cpuidle-pseries.o | 26 | obj-$(CONFIG_PSERIES_CPUIDLE) += cpuidle-pseries.o |
| 23 | obj-$(CONFIG_POWERNV_CPUIDLE) += cpuidle-powernv.o | 27 | obj-$(CONFIG_POWERNV_CPUIDLE) += cpuidle-powernv.o |
diff --git a/drivers/cpuidle/cpuidle-cps.c b/drivers/cpuidle/cpuidle-cps.c new file mode 100644 index 000000000000..fc7b62720deb --- /dev/null +++ b/drivers/cpuidle/cpuidle-cps.c | |||
| @@ -0,0 +1,186 @@ | |||
| 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/cpu_pm.h> | ||
| 12 | #include <linux/cpuidle.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | |||
| 15 | #include <asm/idle.h> | ||
| 16 | #include <asm/pm-cps.h> | ||
| 17 | |||
| 18 | /* Enumeration of the various idle states this driver may enter */ | ||
| 19 | enum cps_idle_state { | ||
| 20 | STATE_WAIT = 0, /* MIPS wait instruction, coherent */ | ||
| 21 | STATE_NC_WAIT, /* MIPS wait instruction, non-coherent */ | ||
| 22 | STATE_CLOCK_GATED, /* Core clock gated */ | ||
| 23 | STATE_POWER_GATED, /* Core power gated */ | ||
| 24 | STATE_COUNT | ||
| 25 | }; | ||
| 26 | |||
| 27 | static int cps_nc_enter(struct cpuidle_device *dev, | ||
| 28 | struct cpuidle_driver *drv, int index) | ||
| 29 | { | ||
| 30 | enum cps_pm_state pm_state; | ||
| 31 | int err; | ||
| 32 | |||
| 33 | /* | ||
| 34 | * At least one core must remain powered up & clocked in order for the | ||
| 35 | * system to have any hope of functioning. | ||
| 36 | * | ||
| 37 | * TODO: don't treat core 0 specially, just prevent the final core | ||
| 38 | * TODO: remap interrupt affinity temporarily | ||
| 39 | */ | ||
| 40 | if (!cpu_data[dev->cpu].core && (index > STATE_NC_WAIT)) | ||
| 41 | index = STATE_NC_WAIT; | ||
| 42 | |||
| 43 | /* Select the appropriate cps_pm_state */ | ||
| 44 | switch (index) { | ||
| 45 | case STATE_NC_WAIT: | ||
| 46 | pm_state = CPS_PM_NC_WAIT; | ||
| 47 | break; | ||
| 48 | case STATE_CLOCK_GATED: | ||
| 49 | pm_state = CPS_PM_CLOCK_GATED; | ||
| 50 | break; | ||
| 51 | case STATE_POWER_GATED: | ||
| 52 | pm_state = CPS_PM_POWER_GATED; | ||
| 53 | break; | ||
| 54 | default: | ||
| 55 | BUG(); | ||
| 56 | return -EINVAL; | ||
| 57 | } | ||
| 58 | |||
| 59 | /* Notify listeners the CPU is about to power down */ | ||
| 60 | if ((pm_state == CPS_PM_POWER_GATED) && cpu_pm_enter()) | ||
| 61 | return -EINTR; | ||
| 62 | |||
| 63 | /* Enter that state */ | ||
| 64 | err = cps_pm_enter_state(pm_state); | ||
| 65 | |||
| 66 | /* Notify listeners the CPU is back up */ | ||
| 67 | if (pm_state == CPS_PM_POWER_GATED) | ||
| 68 | cpu_pm_exit(); | ||
| 69 | |||
| 70 | return err ?: index; | ||
| 71 | } | ||
| 72 | |||
| 73 | static struct cpuidle_driver cps_driver = { | ||
| 74 | .name = "cpc_cpuidle", | ||
| 75 | .owner = THIS_MODULE, | ||
| 76 | .states = { | ||
| 77 | [STATE_WAIT] = MIPS_CPUIDLE_WAIT_STATE, | ||
| 78 | [STATE_NC_WAIT] = { | ||
| 79 | .enter = cps_nc_enter, | ||
| 80 | .exit_latency = 200, | ||
| 81 | .target_residency = 450, | ||
| 82 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
| 83 | .name = "nc-wait", | ||
| 84 | .desc = "non-coherent MIPS wait", | ||
| 85 | }, | ||
| 86 | [STATE_CLOCK_GATED] = { | ||
| 87 | .enter = cps_nc_enter, | ||
| 88 | .exit_latency = 300, | ||
| 89 | .target_residency = 700, | ||
| 90 | .flags = CPUIDLE_FLAG_TIME_VALID | | ||
| 91 | CPUIDLE_FLAG_TIMER_STOP, | ||
| 92 | .name = "clock-gated", | ||
| 93 | .desc = "core clock gated", | ||
| 94 | }, | ||
| 95 | [STATE_POWER_GATED] = { | ||
| 96 | .enter = cps_nc_enter, | ||
| 97 | .exit_latency = 600, | ||
| 98 | .target_residency = 1000, | ||
| 99 | .flags = CPUIDLE_FLAG_TIME_VALID | | ||
| 100 | CPUIDLE_FLAG_TIMER_STOP, | ||
| 101 | .name = "power-gated", | ||
| 102 | .desc = "core power gated", | ||
| 103 | }, | ||
| 104 | }, | ||
| 105 | .state_count = STATE_COUNT, | ||
| 106 | .safe_state_index = 0, | ||
| 107 | }; | ||
| 108 | |||
| 109 | static void __init cps_cpuidle_unregister(void) | ||
| 110 | { | ||
| 111 | int cpu; | ||
| 112 | struct cpuidle_device *device; | ||
| 113 | |||
| 114 | for_each_possible_cpu(cpu) { | ||
| 115 | device = &per_cpu(cpuidle_dev, cpu); | ||
| 116 | cpuidle_unregister_device(device); | ||
| 117 | } | ||
| 118 | |||
| 119 | cpuidle_unregister_driver(&cps_driver); | ||
| 120 | } | ||
| 121 | |||
| 122 | static int __init cps_cpuidle_init(void) | ||
| 123 | { | ||
| 124 | int err, cpu, core, i; | ||
| 125 | struct cpuidle_device *device; | ||
| 126 | |||
| 127 | /* Detect supported states */ | ||
| 128 | if (!cps_pm_support_state(CPS_PM_POWER_GATED)) | ||
| 129 | cps_driver.state_count = STATE_CLOCK_GATED + 1; | ||
| 130 | if (!cps_pm_support_state(CPS_PM_CLOCK_GATED)) | ||
| 131 | cps_driver.state_count = STATE_NC_WAIT + 1; | ||
| 132 | if (!cps_pm_support_state(CPS_PM_NC_WAIT)) | ||
| 133 | cps_driver.state_count = STATE_WAIT + 1; | ||
| 134 | |||
| 135 | /* Inform the user if some states are unavailable */ | ||
| 136 | if (cps_driver.state_count < STATE_COUNT) { | ||
| 137 | pr_info("cpuidle-cps: limited to "); | ||
| 138 | switch (cps_driver.state_count - 1) { | ||
| 139 | case STATE_WAIT: | ||
| 140 | pr_cont("coherent wait\n"); | ||
| 141 | break; | ||
| 142 | case STATE_NC_WAIT: | ||
| 143 | pr_cont("non-coherent wait\n"); | ||
| 144 | break; | ||
| 145 | case STATE_CLOCK_GATED: | ||
| 146 | pr_cont("clock gating\n"); | ||
| 147 | break; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | /* | ||
| 152 | * Set the coupled flag on the appropriate states if this system | ||
| 153 | * requires it. | ||
| 154 | */ | ||
| 155 | if (coupled_coherence) | ||
| 156 | for (i = STATE_NC_WAIT; i < cps_driver.state_count; i++) | ||
| 157 | cps_driver.states[i].flags |= CPUIDLE_FLAG_COUPLED; | ||
| 158 | |||
| 159 | err = cpuidle_register_driver(&cps_driver); | ||
| 160 | if (err) { | ||
| 161 | pr_err("Failed to register CPS cpuidle driver\n"); | ||
| 162 | return err; | ||
| 163 | } | ||
| 164 | |||
| 165 | for_each_possible_cpu(cpu) { | ||
| 166 | core = cpu_data[cpu].core; | ||
| 167 | device = &per_cpu(cpuidle_dev, cpu); | ||
| 168 | device->cpu = cpu; | ||
| 169 | #ifdef CONFIG_MIPS_MT | ||
| 170 | cpumask_copy(&device->coupled_cpus, &cpu_sibling_map[cpu]); | ||
| 171 | #endif | ||
| 172 | |||
| 173 | err = cpuidle_register_device(device); | ||
| 174 | if (err) { | ||
| 175 | pr_err("Failed to register CPU%d cpuidle device\n", | ||
| 176 | cpu); | ||
| 177 | goto err_out; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | err_out: | ||
| 183 | cps_cpuidle_unregister(); | ||
| 184 | return err; | ||
| 185 | } | ||
| 186 | device_initcall(cps_cpuidle_init); | ||
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c index af3974a5e7c2..7d75465d97c7 100644 --- a/drivers/usb/host/ehci-pmcmsp.c +++ b/drivers/usb/host/ehci-pmcmsp.c | |||
| @@ -68,9 +68,6 @@ static void usb_hcd_tdi_set_mode(struct ehci_hcd *ehci) | |||
| 68 | 68 | ||
| 69 | /* set TWI GPIO USB_HOST_DEV pin high */ | 69 | /* set TWI GPIO USB_HOST_DEV pin high */ |
| 70 | gpio_direction_output(MSP_PIN_USB0_HOST_DEV, 1); | 70 | gpio_direction_output(MSP_PIN_USB0_HOST_DEV, 1); |
| 71 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
| 72 | gpio_direction_output(MSP_PIN_USB1_HOST_DEV, 1); | ||
| 73 | #endif | ||
| 74 | } | 71 | } |
| 75 | 72 | ||
| 76 | /* called during probe() after chip reset completes */ | 73 | /* called during probe() after chip reset completes */ |
| @@ -248,33 +245,6 @@ void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev) | |||
| 248 | usb_put_hcd(hcd); | 245 | usb_put_hcd(hcd); |
| 249 | } | 246 | } |
| 250 | 247 | ||
| 251 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
| 252 | /* | ||
| 253 | * Wrapper around the main ehci_irq. Since both USB host controllers are | ||
| 254 | * sharing the same IRQ, need to first determine whether we're the intended | ||
| 255 | * recipient of this interrupt. | ||
| 256 | */ | ||
| 257 | static irqreturn_t ehci_msp_irq(struct usb_hcd *hcd) | ||
| 258 | { | ||
| 259 | u32 int_src; | ||
| 260 | struct device *dev = hcd->self.controller; | ||
| 261 | struct platform_device *pdev; | ||
| 262 | struct mspusb_device *mdev; | ||
| 263 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
| 264 | /* need to reverse-map a couple of containers to get our device */ | ||
| 265 | pdev = to_platform_device(dev); | ||
| 266 | mdev = to_mspusb_device(pdev); | ||
| 267 | |||
| 268 | /* Check to see if this interrupt is for this host controller */ | ||
| 269 | int_src = ehci_readl(ehci, &mdev->mab_regs->int_stat); | ||
| 270 | if (int_src & (1 << pdev->id)) | ||
| 271 | return ehci_irq(hcd); | ||
| 272 | |||
| 273 | /* Not for this device */ | ||
| 274 | return IRQ_NONE; | ||
| 275 | } | ||
| 276 | #endif /* DUAL_USB */ | ||
| 277 | |||
| 278 | static const struct hc_driver ehci_msp_hc_driver = { | 248 | static const struct hc_driver ehci_msp_hc_driver = { |
| 279 | .description = hcd_name, | 249 | .description = hcd_name, |
| 280 | .product_desc = "PMC MSP EHCI", | 250 | .product_desc = "PMC MSP EHCI", |
| @@ -283,11 +253,7 @@ static const struct hc_driver ehci_msp_hc_driver = { | |||
| 283 | /* | 253 | /* |
| 284 | * generic hardware linkage | 254 | * generic hardware linkage |
| 285 | */ | 255 | */ |
| 286 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
| 287 | .irq = ehci_msp_irq, | ||
| 288 | #else | ||
| 289 | .irq = ehci_irq, | 256 | .irq = ehci_irq, |
| 290 | #endif | ||
| 291 | .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, | 257 | .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, |
| 292 | 258 | ||
| 293 | /* | 259 | /* |
| @@ -334,9 +300,6 @@ static int ehci_hcd_msp_drv_probe(struct platform_device *pdev) | |||
| 334 | return -ENODEV; | 300 | return -ENODEV; |
| 335 | 301 | ||
| 336 | gpio_request(MSP_PIN_USB0_HOST_DEV, "USB0_HOST_DEV_GPIO"); | 302 | gpio_request(MSP_PIN_USB0_HOST_DEV, "USB0_HOST_DEV_GPIO"); |
| 337 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
| 338 | gpio_request(MSP_PIN_USB1_HOST_DEV, "USB1_HOST_DEV_GPIO"); | ||
| 339 | #endif | ||
| 340 | 303 | ||
| 341 | ret = usb_hcd_msp_probe(&ehci_msp_hc_driver, pdev); | 304 | ret = usb_hcd_msp_probe(&ehci_msp_hc_driver, pdev); |
| 342 | 305 | ||
| @@ -351,9 +314,6 @@ static int ehci_hcd_msp_drv_remove(struct platform_device *pdev) | |||
| 351 | 314 | ||
| 352 | /* free TWI GPIO USB_HOST_DEV pin */ | 315 | /* free TWI GPIO USB_HOST_DEV pin */ |
| 353 | gpio_free(MSP_PIN_USB0_HOST_DEV); | 316 | gpio_free(MSP_PIN_USB0_HOST_DEV); |
| 354 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
| 355 | gpio_free(MSP_PIN_USB1_HOST_DEV); | ||
| 356 | #endif | ||
| 357 | 317 | ||
| 358 | return 0; | 318 | return 0; |
| 359 | } | 319 | } |
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index c51a436135c4..25e0df6155a4 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h | |||
| @@ -84,6 +84,7 @@ struct cpuidle_device { | |||
| 84 | }; | 84 | }; |
| 85 | 85 | ||
| 86 | DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); | 86 | DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); |
| 87 | DECLARE_PER_CPU(struct cpuidle_device, cpuidle_dev); | ||
| 87 | 88 | ||
| 88 | /** | 89 | /** |
| 89 | * cpuidle_get_last_residency - retrieves the last state's residency time | 90 | * cpuidle_get_last_residency - retrieves the last state's residency time |
diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h index 2841f86eae0b..bf6cd7d5cac2 100644 --- a/include/uapi/linux/kvm_para.h +++ b/include/uapi/linux/kvm_para.h | |||
| @@ -20,6 +20,9 @@ | |||
| 20 | #define KVM_HC_FEATURES 3 | 20 | #define KVM_HC_FEATURES 3 |
| 21 | #define KVM_HC_PPC_MAP_MAGIC_PAGE 4 | 21 | #define KVM_HC_PPC_MAP_MAGIC_PAGE 4 |
| 22 | #define KVM_HC_KICK_CPU 5 | 22 | #define KVM_HC_KICK_CPU 5 |
| 23 | #define KVM_HC_MIPS_GET_CLOCK_FREQ 6 | ||
| 24 | #define KVM_HC_MIPS_EXIT_VM 7 | ||
| 25 | #define KVM_HC_MIPS_CONSOLE_OUTPUT 8 | ||
| 23 | 26 | ||
| 24 | /* | 27 | /* |
| 25 | * hypercalls use architecture specific | 28 | * hypercalls use architecture specific |
