Pull MIPS updates from Ralf Baechle: - three fixes for 3.15 that didn't make it in time - limited Octeon 3 support. - paravirtualization support - improvment to platform support for Netlogix SOCs. - add support for powering down the Malta eval board in software - add many instructions to the in-kernel microassembler. - add support for the BPF JIT. - minor cleanups of the BCM47xx code. - large cleanup of math emu code resulting in significant code size reduction, better readability of the code and more accurate emulation. - improvments to the MIPS CPS code. - support C3 power status for the R4k count/compare clock device. - improvments to the GIO support for older SGI workstations. - increase number of supported CPUs to 256; this can be reached on certain embedded multithreaded ccNUMA configurations. - various small cleanups, updates and fixes * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (173 commits) MIPS: IP22/IP28: Improve GIO support MIPS: Octeon: Add twsi interrupt initialization for OCTEON 3XXX, 5XXX, 63XX DEC: Document the R4k MB ASIC mini interrupt controller DEC: Add self as the maintainer MIPS: Add microMIPS MSA support. MIPS: Replace calls to obsolete strict_strto call with kstrto* equivalents. MIPS: Replace obsolete strict_strto call with kstrto MIPS: BFP: Simplify code slightly. MIPS: Call find_vma with the mmap_sem held MIPS: Fix 'write_msa_##' inline macro. MIPS: Fix MSA toolchain support detection. mips: Update the email address of Geert Uytterhoeven MIPS: Add minimal defconfig for mips_paravirt MIPS: Enable build for new system 'paravirt' MIPS: paravirt: Add pci controller for virtio MIPS: Add code for new system 'paravirt' MIPS: Add functions for hypervisor call MIPS: OCTEON: Add OCTEON3 to __get_cpu_type MIPS: Add function get_ebase_cpunum MIPS: Add minimal support for OCTEON3 to c-r4k.c ...
Unified · Split
| @@ -2700,6 +2700,15 @@ S: Orphan · 2699 unmodified lines | ||
| 2700 | 2700 | F: Documentation/networking/decnet.txt |
| 2701 | 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 | 2712 | DEFXX FDDI NETWORK DRIVER |
| 2704 | 2713 | M: "Maciej W. Rozycki" <macro@linux-mips.org> |
| 2705 | 2714 | S: Maintained |
| @@ -16,7 +16,7 @@ obj- := $(platform-) · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | obj-y += kernel/ |
| 18 | 18 | obj-y += mm/ |
| 19 | −obj-y += math-emu/ | |
| 19 | +obj-y += net/ | |
| 20 | 20 | |
| 21 | 21 | ifdef CONFIG_KVM |
| 22 | 22 | obj-y += kvm/ |
| @@ -18,6 +18,7 @@ platforms += loongson1 · 17 unmodified lines | ||
| 18 | 18 | platforms += mti-malta |
| 19 | 19 | platforms += mti-sead3 |
| 20 | 20 | platforms += netlogic |
| 21 | +platforms += paravirt | |
| 21 | 22 | platforms += pmcs-msp71xx |
| 22 | 23 | platforms += pnx833x |
| 23 | 24 | platforms += ralink |
| @@ -12,6 +12,7 @@ config MIPS · 11 unmodified lines | ||
| 12 | 12 | select HAVE_ARCH_KGDB |
| 13 | 13 | select HAVE_ARCH_SECCOMP_FILTER |
| 14 | 14 | select HAVE_ARCH_TRACEHOOK |
| 15 | + select HAVE_BPF_JIT if !CPU_MICROMIPS | |
| 15 | 16 | select ARCH_HAVE_CUSTOM_GPIO_H |
| 16 | 17 | select HAVE_FUNCTION_TRACER |
| 17 | 18 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST |
| @@ -50,6 +51,8 @@ config MIPS · 32 unmodified lines | ||
| 50 | 51 | select CLONE_BACKWARDS |
| 51 | 52 | select HAVE_DEBUG_STACKOVERFLOW |
| 52 | 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 | 57 | menu "Machine selection" |
| 55 | 58 | |
| @@ -83,6 +86,7 @@ config AR7 · 27 unmodified lines | ||
| 83 | 86 | select SYS_HAS_EARLY_PRINTK |
| 84 | 87 | select SYS_SUPPORTS_32BIT_KERNEL |
| 85 | 88 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 89 | + select SYS_SUPPORTS_MIPS16 | |
| 86 | 90 | select SYS_SUPPORTS_ZBOOT_UART16550 |
| 87 | 91 | select ARCH_REQUIRE_GPIOLIB |
| 88 | 92 | select VLYNQ |
| @@ -106,6 +110,7 @@ config ATH79 · 17 unmodified lines | ||
| 106 | 110 | select SYS_HAS_EARLY_PRINTK |
| 107 | 111 | select SYS_SUPPORTS_32BIT_KERNEL |
| 108 | 112 | select SYS_SUPPORTS_BIG_ENDIAN |
| 113 | + select SYS_SUPPORTS_MIPS16 | |
| 109 | 114 | help |
| 110 | 115 | Support for the Atheros AR71XX/AR724X/AR913X SoCs. |
| 111 | 116 | |
| @@ -122,6 +127,7 @@ config BCM47XX · 10 unmodified lines | ||
| 122 | 127 | select NO_EXCEPT_FILL |
| 123 | 128 | select SYS_SUPPORTS_32BIT_KERNEL |
| 124 | 129 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 130 | + select SYS_SUPPORTS_MIPS16 | |
| 125 | 131 | select SYS_HAS_EARLY_PRINTK |
| 126 | 132 | select USE_GENERIC_EARLY_PRINTK_8250 |
| 127 | 133 | help |
| @@ -168,9 +174,9 @@ config MACH_DECSTATION · 40 unmodified lines | ||
| 168 | 174 | bool "DECstations" |
| 169 | 175 | select BOOT_ELF32 |
| 170 | 176 | select CEVT_DS1287 |
| 171 | − select CEVT_R4K | |
| 177 | + select CEVT_R4K if CPU_R4X00 | |
| 172 | 178 | select CSRC_IOASIC |
| 173 | − select CSRC_R4K | |
| 179 | + select CSRC_R4K if CPU_R4X00 | |
| 174 | 180 | select CPU_DADDI_WORKAROUNDS if 64BIT |
| 175 | 181 | select CPU_R4000_WORKAROUNDS if 64BIT |
| 176 | 182 | select CPU_R4400_WORKAROUNDS if 64BIT |
| @@ -248,6 +254,7 @@ config LANTIQ · 71 unmodified lines | ||
| 248 | 254 | select SYS_HAS_CPU_MIPS32_R2 |
| 249 | 255 | select SYS_SUPPORTS_BIG_ENDIAN |
| 250 | 256 | select SYS_SUPPORTS_32BIT_KERNEL |
| 257 | + select SYS_SUPPORTS_MIPS16 | |
| 251 | 258 | select SYS_SUPPORTS_MULTITHREADING |
| 252 | 259 | select SYS_HAS_EARLY_PRINTK |
| 253 | 260 | select ARCH_REQUIRE_GPIOLIB |
| @@ -330,6 +337,7 @@ config MIPS_MALTA · 76 unmodified lines | ||
| 330 | 337 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 331 | 338 | select SYS_SUPPORTS_MIPS_CMP |
| 332 | 339 | select SYS_SUPPORTS_MIPS_CPS |
| 340 | + select SYS_SUPPORTS_MIPS16 | |
| 333 | 341 | select SYS_SUPPORTS_MULTITHREADING |
| 334 | 342 | select SYS_SUPPORTS_SMARTMIPS |
| 335 | 343 | select SYS_SUPPORTS_ZBOOT |
| @@ -361,6 +369,7 @@ config MIPS_SEAD3 · 25 unmodified lines | ||
| 361 | 369 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 362 | 370 | select SYS_SUPPORTS_SMARTMIPS |
| 363 | 371 | select SYS_SUPPORTS_MICROMIPS |
| 372 | + select SYS_SUPPORTS_MIPS16 | |
| 364 | 373 | select USB_EHCI_BIG_ENDIAN_DESC |
| 365 | 374 | select USB_EHCI_BIG_ENDIAN_MMIO |
| 366 | 375 | select USE_OF |
| @@ -380,6 +389,7 @@ config MACH_VR41XX · 13 unmodified lines | ||
| 380 | 389 | select CEVT_R4K |
| 381 | 390 | select CSRC_R4K |
| 382 | 391 | select SYS_HAS_CPU_VR41XX |
| 392 | + select SYS_SUPPORTS_MIPS16 | |
| 383 | 393 | select ARCH_REQUIRE_GPIOLIB |
| 384 | 394 | |
| 385 | 395 | config NXP_STB220 |
| @@ -407,6 +417,7 @@ config PMC_MSP · 21 unmodified lines | ||
| 407 | 417 | select SYS_HAS_CPU_MIPS32_R2 |
| 408 | 418 | select SYS_SUPPORTS_32BIT_KERNEL |
| 409 | 419 | select SYS_SUPPORTS_BIG_ENDIAN |
| 420 | + select SYS_SUPPORTS_MIPS16 | |
| 410 | 421 | select IRQ_CPU |
| 411 | 422 | select SERIAL_8250 |
| 412 | 423 | select SERIAL_8250_CONSOLE |
| @@ -430,6 +441,7 @@ config RALINK · 17 unmodified lines | ||
| 430 | 441 | select SYS_HAS_CPU_MIPS32_R2 |
| 431 | 442 | select SYS_SUPPORTS_32BIT_KERNEL |
| 432 | 443 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 444 | + select SYS_SUPPORTS_MIPS16 | |
| 433 | 445 | select SYS_HAS_EARLY_PRINTK |
| 434 | 446 | select HAVE_MACH_CLKDEV |
| 435 | 447 | select CLKDEV_LOOKUP |
| @@ -674,7 +686,6 @@ config SNI_RM · 238 unmodified lines | ||
| 674 | 686 | select SYS_SUPPORTS_BIG_ENDIAN |
| 675 | 687 | select SYS_SUPPORTS_HIGHMEM |
| 676 | 688 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 677 | − select USE_GENERIC_EARLY_PRINTK_8250 | |
| 678 | 689 | help |
| 679 | 690 | The SNI RM200/300/400 are MIPS-based machines manufactured by |
| 680 | 691 | Siemens Nixdorf Informationssysteme (SNI), parent company of Pyramid |
| @@ -721,6 +732,11 @@ config CAVIUM_OCTEON_SOC · 40 unmodified lines | ||
| 721 | 732 | select ZONE_DMA32 |
| 722 | 733 | select HOLES_IN_ZONE |
| 723 | 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 | 740 | help |
| 725 | 741 | This option supports all of the Octeon reference boards from Cavium |
| 726 | 742 | Networks. It builds a kernel that dynamically determines the Octeon |
| @@ -789,6 +805,25 @@ config NLM_XLP_BOARD · 62 unmodified lines | ||
| 789 | 805 | This board is based on Netlogic XLP Processor. |
| 790 | 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 | 827 | endchoice |
| 793 | 828 | |
| 794 | 829 | source "arch/mips/alchemy/Kconfig" |
| @@ -809,6 +844,7 @@ source "arch/mips/cavium-octeon/Kconfig" · 14 unmodified lines | ||
| 809 | 844 | source "arch/mips/loongson/Kconfig" |
| 810 | 845 | source "arch/mips/loongson1/Kconfig" |
| 811 | 846 | source "arch/mips/netlogic/Kconfig" |
| 847 | +source "arch/mips/paravirt/Kconfig" | |
| 812 | 848 | |
| 813 | 849 | endmenu |
| 814 | 850 | |
| @@ -1059,6 +1095,7 @@ config SOC_PNX833X · 244 unmodified lines | ||
| 1059 | 1095 | select SYS_SUPPORTS_32BIT_KERNEL |
| 1060 | 1096 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 1061 | 1097 | select SYS_SUPPORTS_BIG_ENDIAN |
| 1098 | + select SYS_SUPPORTS_MIPS16 | |
| 1062 | 1099 | select CPU_MIPSR2_IRQ_VI |
| 1063 | 1100 | |
| 1064 | 1101 | config SOC_PNX8335 |
| @@ -1398,16 +1435,11 @@ config CPU_SB1 · 333 unmodified lines | ||
| 1398 | 1435 | config CPU_CAVIUM_OCTEON |
| 1399 | 1436 | bool "Cavium Octeon processor" |
| 1400 | 1437 | depends on SYS_HAS_CPU_CAVIUM_OCTEON |
| 1401 | − select ARCH_SPARSEMEM_ENABLE | |
| 1402 | 1438 | select CPU_HAS_PREFETCH |
| 1403 | 1439 | select CPU_SUPPORTS_64BIT_KERNEL |
| 1404 | − select SYS_SUPPORTS_SMP | |
| 1405 | − select NR_CPUS_DEFAULT_16 | |
| 1406 | 1440 | select WEAK_ORDERING |
| 1407 | 1441 | select CPU_SUPPORTS_HIGHMEM |
| 1408 | 1442 | select CPU_SUPPORTS_HUGEPAGES |
| 1409 | − select LIBFDT | |
| 1410 | − select USE_OF | |
| 1411 | 1443 | select USB_EHCI_BIG_ENDIAN_MMIO |
| 1412 | 1444 | select MIPS_L1_CACHE_SHIFT_7 |
| 1413 | 1445 | help |
| @@ -1659,6 +1691,12 @@ config SYS_HAS_CPU_XLR · 245 unmodified lines | ||
| 1659 | 1691 | config SYS_HAS_CPU_XLP |
| 1660 | 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 | 1701 | # CPU may reorder R->R, R->W, W->R, W->W |
| 1664 | 1702 | # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC |
| @@ -1842,7 +1880,7 @@ config FORCE_MAX_ZONEORDER · 177 unmodified lines | ||
| 1842 | 1880 | |
| 1843 | 1881 | config CEVT_GIC |
| 1844 | 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 | 1884 | help |
| 1847 | 1885 | Use the GIC global counter for the clock events. The R4K clock |
| 1848 | 1886 | event driver is always present, so if the platform ends up not |
| @@ -1895,19 +1933,8 @@ config CPU_R4K_CACHE_TLB · 46 unmodified lines | ||
| 1895 | 1933 | bool |
| 1896 | 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 | 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 | 1938 | depends on SYS_SUPPORTS_MULTITHREADING |
| 1912 | 1939 | select CPU_MIPSR2_IRQ_VI |
| 1913 | 1940 | select CPU_MIPSR2_IRQ_EI |
| @@ -1926,26 +1953,6 @@ config MIPS_MT_SMP · 12 unmodified lines | ||
| 1926 | 1953 | Intel Hyperthreading feature. For further information go to |
| 1927 | 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 | 1956 | config MIPS_MT |
| 1950 | 1957 | bool |
| 1951 | 1958 | |
| @@ -1967,7 +1974,7 @@ config SYS_SUPPORTS_MULTITHREADING · 15 unmodified lines | ||
| 1967 | 1974 | config MIPS_MT_FPAFF |
| 1968 | 1975 | bool "Dynamic FPU affinity for FP-intensive threads" |
| 1969 | 1976 | default y |
| 1970 | − depends on MIPS_MT_SMP || MIPS_MT_SMTC | |
| 1977 | + depends on MIPS_MT_SMP | |
| 1971 | 1978 | |
| 1972 | 1979 | config MIPS_VPE_LOADER |
| 1973 | 1980 | bool "VPE loader support." |
| @@ -1989,29 +1996,6 @@ config MIPS_VPE_LOADER_MT · 15 unmodified lines | ||
| 1989 | 1996 | default "y" |
| 1990 | 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 | 1999 | config MIPS_VPE_LOADER_TOM |
| 2016 | 2000 | bool "Load VPE program into memory hidden from linux" |
| 2017 | 2001 | depends on MIPS_VPE_LOADER |
| @@ -2039,7 +2023,7 @@ config MIPS_VPE_APSP_API_MT · 21 unmodified lines | ||
| 2039 | 2023 | |
| 2040 | 2024 | config MIPS_CMP |
| 2041 | 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 | 2027 | select MIPS_GIC_IPI |
| 2044 | 2028 | select SYNC_R4K |
| 2045 | 2029 | select WEAK_ORDERING |
| @@ -2057,9 +2041,11 @@ config MIPS_CPS · 11 unmodified lines | ||
| 2057 | 2041 | depends on SYS_SUPPORTS_MIPS_CPS |
| 2058 | 2042 | select MIPS_CM |
| 2059 | 2043 | select MIPS_CPC |
| 2044 | + select MIPS_CPS_PM if HOTPLUG_CPU | |
| 2060 | 2045 | select MIPS_GIC_IPI |
| 2061 | 2046 | select SMP |
| 2062 | 2047 | select SYNC_R4K if (CEVT_R4K || CSRC_R4K) |
| 2048 | + select SYS_SUPPORTS_HOTPLUG_CPU | |
| 2063 | 2049 | select SYS_SUPPORTS_SMP |
| 2064 | 2050 | select WEAK_ORDERING |
| 2065 | 2051 | help |
| @@ -2069,6 +2055,9 @@ config MIPS_CPS · 3 unmodified lines | ||
| 2069 | 2055 | no external assistance. It is safe to enable this when hardware |
| 2070 | 2056 | support is unavailable. |
| 2071 | 2057 | |
| 2058 | +config MIPS_CPS_PM | |
| 2059 | + bool | |
| 2060 | + | |
| 2072 | 2061 | config MIPS_GIC_IPI |
| 2073 | 2062 | bool |
| 2074 | 2063 | |
| @@ -2199,6 +2188,13 @@ config SYS_SUPPORTS_SMARTMIPS · 124 unmodified lines | ||
| 2199 | 2188 | config SYS_SUPPORTS_MICROMIPS |
| 2200 | 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 | 2198 | config CPU_SUPPORTS_MSA |
| 2203 | 2199 | bool |
| 2204 | 2200 | |
| @@ -2239,7 +2235,7 @@ config NODES_SHIFT · 34 unmodified lines | ||
| 2239 | 2235 | |
| 2240 | 2236 | config HW_PERF_EVENTS |
| 2241 | 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 | 2239 | default y |
| 2244 | 2240 | help |
| 2245 | 2241 | Enable hardware performance counter support for perf events. If |
| @@ -2297,8 +2293,8 @@ config NR_CPUS_DEFAULT_64 · 51 unmodified lines | ||
| 2297 | 2293 | bool |
| 2298 | 2294 | |
| 2299 | 2295 | config NR_CPUS |
| 2300 | − int "Maximum number of CPUs (2-64)" | |
| 2301 | − range 2 64 | |
| 2296 | + int "Maximum number of CPUs (2-256)" | |
| 2297 | + range 2 256 | |
| 2302 | 2298 | depends on SMP |
| 2303 | 2299 | default "4" if NR_CPUS_DEFAULT_4 |
| 2304 | 2300 | default "8" if NR_CPUS_DEFAULT_8 |
| @@ -2671,12 +2667,16 @@ endmenu · 366 unmodified lines | ||
| 2671 | 2667 | config MIPS_EXTERNAL_TIMER |
| 2672 | 2668 | bool |
| 2673 | 2669 | |
| 2674 | −if CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER | |
| 2675 | 2670 | menu "CPU Power Management" |
| 2671 | + | |
| 2672 | +if CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER | |
| 2676 | 2673 | source "drivers/cpufreq/Kconfig" |
| 2677 | −endmenu | |
| 2678 | 2674 | endif |
| 2679 | 2675 | |
| 2676 | +source "drivers/cpuidle/Kconfig" | |
| 2677 | + | |
| 2678 | +endmenu | |
| 2679 | + | |
| 2680 | 2680 | source "net/Kconfig" |
| 2681 | 2681 | |
| 2682 | 2682 | source "drivers/Kconfig" |
| @@ -79,15 +79,6 @@ config CMDLINE_OVERRIDE · 78 unmodified lines | ||
| 79 | 79 | |
| 80 | 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 | 82 | config SB1XXX_CORELIS |
| 92 | 83 | bool "Corelis Debugger" |
| 93 | 84 | depends on SIBYTE_SB1xxx_SOC |
| @@ -120,7 +120,7 @@ cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \ · 119 unmodified lines | ||
| 120 | 120 | -fno-omit-frame-pointer |
| 121 | 121 | |
| 122 | 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 | 124 | cflags-$(toolchain-msa) += -DTOOLCHAIN_SUPPORTS_MSA |
| 125 | 125 | endif |
| 126 | 126 | |
| @@ -251,6 +251,7 @@ OBJCOPYFLAGS += --remove-section=.reginfo · 124 unmodified lines | ||
| 251 | 251 | head-y := arch/mips/kernel/head.o |
| 252 | 252 | |
| 253 | 253 | libs-y += arch/mips/lib/ |
| 254 | +libs-y += arch/mips/math-emu/ | |
| 254 | 255 | |
| 255 | 256 | # See arch/mips/Kbuild for content of core part of the kernel |
| 256 | 257 | core-y += arch/mips/ |
| @@ -49,7 +49,7 @@ void __init prom_init(void) · 48 unmodified lines | ||
| 49 | 49 | prom_init_cmdline(); |
| 50 | 50 | |
| 51 | 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 | 53 | memsize = 0x04000000; |
| 54 | 54 | |
| 55 | 55 | add_memory_region(0, memsize, BOOT_MEM_RAM); |
| @@ -67,6 +67,12 @@ void __init plat_mem_setup(void) · 66 unmodified lines | ||
| 67 | 67 | case ALCHEMY_CPU_AU1500: |
| 68 | 68 | case ALCHEMY_CPU_AU1100: |
| 69 | 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 | 78 | board_setup(); /* board specific setup */ |
| @@ -355,47 +355,25 @@ static inline void __au1200_udc_control(void __iomem *base, int enable) · 354 unmodified lines | ||
| 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 | 358 | static inline int au1200_usb_control(int block, int enable) |
| 373 | 359 | { |
| 374 | 360 | void __iomem *base = |
| 375 | 361 | (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); |
| 376 | − int ret = 0; | |
| 377 | 362 | |
| 378 | 363 | switch (block) { |
| 379 | 364 | case ALCHEMY_USB_OHCI0: |
| 380 | − ret = au1200_coherency_bug(); | |
| 381 | − if (ret && enable) | |
| 382 | − goto out; | |
| 383 | 365 | __au1200_ohci_control(base, enable); |
| 384 | 366 | break; |
| 385 | 367 | case ALCHEMY_USB_UDC0: |
| 386 | 368 | __au1200_udc_control(base, enable); |
| 387 | 369 | break; |
| 388 | 370 | case ALCHEMY_USB_EHCI0: |
| 389 | − ret = au1200_coherency_bug(); | |
| 390 | − if (ret && enable) | |
| 391 | − goto out; | |
| 392 | 371 | __au1200_ehci_control(base, enable); |
| 393 | 372 | break; |
| 394 | 373 | default: |
| 395 | − ret = -ENODEV; | |
| 374 | + return -ENODEV; | |
| 396 | 375 | } |
| 397 | −out: | |
| 398 | − return ret; | |
| 376 | + return 0; | |
| 399 | 377 | } |
| 400 | 378 | |
| 401 | 379 | |
| @@ -158,7 +158,7 @@ static ssize_t db1x_pmattr_store(struct kobject *kobj, · 157 unmodified lines | ||
| 158 | 158 | int tmp; |
| 159 | 159 | |
| 160 | 160 | if (ATTRCMP(timer_timeout)) { |
| 161 | − tmp = strict_strtoul(instr, 0, &l); | |
| 161 | + tmp = kstrtoul(instr, 0, &l); | |
| 162 | 162 | if (tmp) |
| 163 | 163 | return tmp; |
| 164 | 164 | |
| @@ -181,7 +181,7 @@ static ssize_t db1x_pmattr_store(struct kobject *kobj, · 16 unmodified lines | ||
| 181 | 181 | } |
| 182 | 182 | |
| 183 | 183 | } else if (ATTRCMP(wakemsk)) { |
| 184 | − tmp = strict_strtoul(instr, 0, &l); | |
| 184 | + tmp = kstrtoul(instr, 0, &l); | |
| 185 | 185 | if (tmp) |
| 186 | 186 | return tmp; |
| 187 | 187 | |
| @@ -69,15 +69,18 @@ static __init void prom_init_mem(void) · 68 unmodified lines | ||
| 69 | 69 | * BCM47XX uses 128MB for addressing the ram, if the system contains |
| 70 | 70 | * less that that amount of ram it remaps the ram more often into the |
| 71 | 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; | |
| 77 | − max = off | ((128 << 20) - 1); | |
| 78 | − for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { | |
| 79 | − if ((off + mem) > max) { | |
| 80 | − mem = (128 << 20); | |
| 73 | + | |
| 74 | + /* Physical address, without mapping to any kernel segment */ | |
| 75 | + off = CPHYSADDR((unsigned long)prom_init); | |
| 76 | + | |
| 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 | 84 | printk(KERN_DEBUG "assume 128MB RAM\n"); |
| 82 | 85 | break; |
| 83 | 86 | } |
| @@ -10,6 +10,17 @@ config CAVIUM_CN63XXP1 · 9 unmodified lines | ||
| 10 | 10 | non-CN63XXP1 hardware, so it is recommended to select "n" |
| 11 | 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 | 24 | endif # CPU_CAVIUM_OCTEON |
| 14 | 25 | |
| 15 | 26 | if CAVIUM_OCTEON_SOC |
| @@ -23,17 +34,6 @@ config CAVIUM_OCTEON_2ND_KERNEL · 7 unmodified lines | ||
| 23 | 34 | with this option to be run at the same time as one built without this |
| 24 | 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 | 37 | config CAVIUM_OCTEON_LOCK_L2 |
| 38 | 38 | bool "Lock often used kernel code in the L2" |
| 39 | 39 | default "y" |
| @@ -86,7 +86,6 @@ config SWIOTLB · 46 unmodified lines | ||
| 86 | 86 | select IOMMU_HELPER |
| 87 | 87 | select NEED_SG_DMA_LENGTH |
| 88 | 88 | |
| 89 | − | |
| 90 | 89 | config OCTEON_ILM |
| 91 | 90 | tristate "Module to measure interrupt latency using Octeon CIU Timer" |
| 92 | 91 | help |
| @@ -105,6 +105,158 @@ int cvmx_helper_ports_on_interface(int interface) · 104 unmodified lines | ||
| 105 | 105 | } |
| 106 | 106 | EXPORT_SYMBOL_GPL(cvmx_helper_ports_on_interface); |
| 107 | 107 | |
| 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 | + | |
| 108 | 260 | /** |
| 109 | 261 | * Get the operating mode of an interface. Depending on the Octeon |
| 110 | 262 | * chip and configuration, this function returns an enumeration |
| @@ -118,6 +270,20 @@ EXPORT_SYMBOL_GPL(cvmx_helper_ports_on_interface); · 7 unmodified lines | ||
| 118 | 270 | cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface) |
| 119 | 271 | { |
| 120 | 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 | 287 | if (interface == 2) |
| 122 | 288 | return CVMX_HELPER_INTERFACE_MODE_NPI; |
| 123 | 289 | |
| @@ -1260,11 +1260,13 @@ static void __init octeon_irq_init_ciu(void) · 1259 unmodified lines | ||
| 1260 | 1260 | for (i = 0; i < 4; i++) |
| 1261 | 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 | 1264 | octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_RML, 0, 46); |
| 1264 | 1265 | for (i = 0; i < 4; i++) |
| 1265 | 1266 | octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_TIMER0, 0, i + 52); |
| 1266 | 1267 | |
| 1267 | 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 | 1271 | /* CIU_1 */ |
| 1270 | 1272 | for (i = 0; i < 16; i++) |
| @@ -729,17 +729,6 @@ void __init prom_init(void) · 728 unmodified lines | ||
| 729 | 729 | octeon_write_lcd("Linux"); |
| 730 | 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 | 732 | octeon_setup_delays(); |
| 744 | 733 | |
| 745 | 734 | /* |
| @@ -779,12 +768,6 @@ void __init prom_init(void) · 33 unmodified lines | ||
| 779 | 768 | MAX_MEMORY = 32ull << 30; |
| 780 | 769 | if (*p == '@') |
| 781 | 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 | 771 | #ifdef CONFIG_KEXEC |
| 789 | 772 | } else if (strncmp(arg, "crashkernel=", 12) == 0) { |
| 790 | 773 | crashk_size = memparse(arg+12, &p); |
| @@ -218,15 +218,6 @@ void octeon_prepare_cpus(unsigned int max_cpus) · 217 unmodified lines | ||
| 218 | 218 | */ |
| 219 | 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 | 221 | octeon_user_io_init(); |
| 231 | 222 | |
| 232 | 223 | /* to generate the first CPU timer interrupt */ |
| @@ -234,21 +225,6 @@ static void octeon_smp_finish(void) · 1 unmodified line | ||
| 234 | 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 | 228 | #ifdef CONFIG_HOTPLUG_CPU |
| 253 | 229 | |
| 254 | 230 | /* State of each CPU. */ |
| @@ -405,7 +381,6 @@ struct plat_smp_ops octeon_smp_ops = { · 150 unmodified lines | ||
| 405 | 381 | .send_ipi_mask = octeon_send_ipi_mask, |
| 406 | 382 | .init_secondary = octeon_init_secondary, |
| 407 | 383 | .smp_finish = octeon_smp_finish, |
| 408 | − .cpus_done = octeon_cpus_done, | |
| 409 | 384 | .boot_secondary = octeon_boot_secondary, |
| 410 | 385 | .smp_setup = octeon_smp_setup, |
| 411 | 386 | .prepare_cpus = octeon_prepare_cpus, |
| @@ -46,7 +46,6 @@ CONFIG_MTD=y · 45 unmodified lines | ||
| 46 | 46 | CONFIG_MTD_REDBOOT_PARTS=y |
| 47 | 47 | CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2 |
| 48 | 48 | CONFIG_MTD_CMDLINE_PARTS=y |
| 49 | −CONFIG_MTD_CHAR=y | |
| 50 | 49 | CONFIG_MTD_BLOCK=y |
| 51 | 50 | CONFIG_MTD_CFI=y |
| 52 | 51 | CONFIG_MTD_JEDECPROBE=y |
| @@ -54,7 +53,7 @@ CONFIG_MTD_CFI_AMDSTD=y · 1 unmodified line | ||
| 54 | 53 | CONFIG_MTD_COMPLEX_MAPPINGS=y |
| 55 | 54 | CONFIG_MTD_PHYSMAP=y |
| 56 | 55 | CONFIG_MTD_M25P80=y |
| 57 | −# CONFIG_M25PXX_USE_FAST_READ is not set | |
| 56 | +CONFIG_MTD_SPI_NOR=y | |
| 58 | 57 | CONFIG_NETDEVICES=y |
| 59 | 58 | # CONFIG_NET_PACKET_ENGINE is not set |
| 60 | 59 | CONFIG_ATH_COMMON=m |
| @@ -113,6 +113,7 @@ CONFIG_MTD_NAND=y · 112 unmodified lines | ||
| 113 | 113 | CONFIG_MTD_NAND_ECC_BCH=y |
| 114 | 114 | CONFIG_MTD_NAND_AU1550=y |
| 115 | 115 | CONFIG_MTD_NAND_PLATFORM=y |
| 116 | +CONFIG_MTD_SPI_NOR=y | |
| 116 | 117 | CONFIG_EEPROM_AT24=y |
| 117 | 118 | CONFIG_EEPROM_AT25=y |
| 118 | 119 | CONFIG_SCSI_TGT=y |
| @@ -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 | |
| @@ -4,10 +4,9 @@ CONFIG_CPU_MIPS32_R2=y · 3 unmodified lines | ||
| 4 | 4 | CONFIG_PAGE_SIZE_16KB=y |
| 5 | 5 | CONFIG_MIPS_MT_SMP=y |
| 6 | 6 | CONFIG_SCHED_SMT=y |
| 7 | −CONFIG_MIPS_CMP=y | |
| 7 | +CONFIG_MIPS_CPS=y | |
| 8 | 8 | CONFIG_NR_CPUS=8 |
| 9 | 9 | CONFIG_HZ_100=y |
| 10 | −CONFIG_LOCALVERSION="cmp" | |
| 11 | 10 | CONFIG_SYSVIPC=y |
| 12 | 11 | CONFIG_POSIX_MQUEUE=y |
| 13 | 12 | CONFIG_AUDIT=y |
| @@ -5,10 +5,9 @@ CONFIG_CPU_MIPS32_3_5_FEATURES=y · 4 unmodified lines | ||
| 5 | 5 | CONFIG_PAGE_SIZE_16KB=y |
| 6 | 6 | CONFIG_MIPS_MT_SMP=y |
| 7 | 7 | CONFIG_SCHED_SMT=y |
| 8 | −CONFIG_MIPS_CMP=y | |
| 8 | +CONFIG_MIPS_CPS=y | |
| 9 | 9 | CONFIG_NR_CPUS=8 |
| 10 | 10 | CONFIG_HZ_100=y |
| 11 | −CONFIG_LOCALVERSION="cmp" | |
| 12 | 11 | CONFIG_SYSVIPC=y |
| 13 | 12 | CONFIG_POSIX_MQUEUE=y |
| 14 | 13 | CONFIG_AUDIT=y |
| @@ -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 | |
| @@ -81,7 +81,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" · 80 unmodified lines | ||
| 81 | 81 | # CONFIG_FIRMWARE_IN_KERNEL is not set |
| 82 | 82 | CONFIG_MTD=y |
| 83 | 83 | CONFIG_MTD_CMDLINE_PARTS=y |
| 84 | −CONFIG_MTD_CHAR=y | |
| 85 | 84 | CONFIG_MTD_BLOCK=y |
| 86 | 85 | CONFIG_MTD_CFI=y |
| 87 | 86 | CONFIG_MTD_CFI_AMDSTD=y |
| @@ -89,6 +88,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y · 1 unmodified line | ||
| 89 | 88 | CONFIG_MTD_PHYSMAP=y |
| 90 | 89 | CONFIG_MTD_PHYSMAP_OF=y |
| 91 | 90 | CONFIG_MTD_M25P80=y |
| 91 | +CONFIG_MTD_SPI_NOR=y | |
| 92 | 92 | CONFIG_EEPROM_93CX6=m |
| 93 | 93 | CONFIG_SCSI=y |
| 94 | 94 | CONFIG_BLK_DEV_SD=y |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <asm/bootinfo.h> |
| 24 | 24 | #include <asm/cpu.h> |
| 25 | 25 | #include <asm/cpu-features.h> |
| 26 | +#include <asm/cpu-type.h> | |
| 26 | 27 | #include <asm/irq.h> |
| 27 | 28 | #include <asm/irq_cpu.h> |
| 28 | 29 | #include <asm/mipsregs.h> |
| @@ -748,6 +749,10 @@ void __init arch_init_irq(void) · 719 unmodified lines | ||
| 748 | 749 | cpu_fpu_mask = 0; |
| 749 | 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 | 757 | /* Register board interrupts: FPU and cascade. */ |
| 753 | 758 | if (dec_interrupt[DEC_IRQ_FPU] >= 0) |
| @@ -17,26 +17,8 @@ · 16 unmodified lines | ||
| 17 | 17 | #ifdef CONFIG_64BIT |
| 18 | 18 | #include <asm/asmmacro-64.h> |
| 19 | 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 | |
| 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) | |
| 21 | +#ifdef CONFIG_CPU_MIPSR2 | |
| 40 | 22 | .macro local_irq_enable reg=t0 |
| 41 | 23 | ei |
| 42 | 24 | irq_enable_hazard |
| @@ -71,7 +53,7 @@ · 28 unmodified lines | ||
| 71 | 53 | sw \reg, TI_PRE_COUNT($28) |
| 72 | 54 | #endif |
| 73 | 55 | .endm |
| 74 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 56 | +#endif /* CONFIG_CPU_MIPSR2 */ | |
| 75 | 57 | |
| 76 | 58 | .macro fpu_save_16even thread tmp=t0 |
| 77 | 59 | cfc1 \tmp, fcr31 |
| @@ -267,13 +249,35 @@ · 189 unmodified lines | ||
| 267 | 249 | .set pop |
| 268 | 250 | .endm |
| 269 | 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 | 274 | * Temporary until all toolchains in use include MSA support. |
| 272 | 275 | */ |
| 273 | 276 | .macro cfcmsa rd, cs |
| 274 | 277 | .set push |
| 275 | 278 | .set noat |
| 276 | − .word 0x787e0059 | (\cs << 11) | |
| 279 | + .insn | |
| 280 | + .word CFC_MSA_INSN | (\cs << 11) | |
| 277 | 281 | move \rd, $1 |
| 278 | 282 | .set pop |
| 279 | 283 | .endm |
| @@ -282,7 +286,7 @@ · 2 unmodified lines | ||
| 282 | 286 | .set push |
| 283 | 287 | .set noat |
| 284 | 288 | move $1, \rs |
| 285 | − .word 0x783e0819 | (\cd << 6) | |
| 289 | + .word CTC_MSA_INSN | (\cd << 6) | |
| 286 | 290 | .set pop |
| 287 | 291 | .endm |
| 288 | 292 | |
| @@ -290,7 +294,7 @@ · 1 unmodified line | ||
| 290 | 294 | .set push |
| 291 | 295 | .set noat |
| 292 | 296 | add $1, \base, \off |
| 293 | − .word 0x78000823 | (\wd << 6) | |
| 297 | + .word LDD_MSA_INSN | (\wd << 6) | |
| 294 | 298 | .set pop |
| 295 | 299 | .endm |
| 296 | 300 | |
| @@ -298,14 +302,15 @@ · 1 unmodified line | ||
| 298 | 302 | .set push |
| 299 | 303 | .set noat |
| 300 | 304 | add $1, \base, \off |
| 301 | − .word 0x78000827 | (\wd << 6) | |
| 305 | + .word STD_MSA_INSN | (\wd << 6) | |
| 302 | 306 | .set pop |
| 303 | 307 | .endm |
| 304 | 308 | |
| 305 | 309 | .macro copy_u_w rd, ws, n |
| 306 | 310 | .set push |
| 307 | 311 | .set noat |
| 308 | − .word 0x78f00059 | (\n << 16) | (\ws << 11) | |
| 312 | + .insn | |
| 313 | + .word COPY_UW_MSA_INSN | (\n << 16) | (\ws << 11) | |
| 309 | 314 | /* move triggers an assembler bug... */ |
| 310 | 315 | or \rd, $1, zero |
| 311 | 316 | .set pop |
| @@ -314,7 +319,8 @@ · 2 unmodified lines | ||
| 314 | 319 | .macro copy_u_d rd, ws, n |
| 315 | 320 | .set push |
| 316 | 321 | .set noat |
| 317 | − .word 0x78f80059 | (\n << 16) | (\ws << 11) | |
| 322 | + .insn | |
| 323 | + .word COPY_UD_MSA_INSN | (\n << 16) | (\ws << 11) | |
| 318 | 324 | /* move triggers an assembler bug... */ |
| 319 | 325 | or \rd, $1, zero |
| 320 | 326 | .set pop |
| @@ -325,7 +331,7 @@ · 4 unmodified lines | ||
| 325 | 331 | .set noat |
| 326 | 332 | /* move triggers an assembler bug... */ |
| 327 | 333 | or $1, \rs, zero |
| 328 | − .word 0x79300819 | (\n << 16) | (\wd << 6) | |
| 334 | + .word INSERT_W_MSA_INSN | (\n << 16) | (\wd << 6) | |
| 329 | 335 | .set pop |
| 330 | 336 | .endm |
| 331 | 337 | |
| @@ -334,7 +340,7 @@ · 2 unmodified lines | ||
| 334 | 340 | .set noat |
| 335 | 341 | /* move triggers an assembler bug... */ |
| 336 | 342 | or $1, \rs, zero |
| 337 | − .word 0x79380819 | (\n << 16) | (\wd << 6) | |
| 343 | + .word INSERT_D_MSA_INSN | (\n << 16) | (\wd << 6) | |
| 338 | 344 | .set pop |
| 339 | 345 | .endm |
| 340 | 346 | #endif |
| @@ -8,6 +8,8 @@ · 7 unmodified lines | ||
| 8 | 8 | #ifndef _ASM_BRANCH_H |
| 9 | 9 | #define _ASM_BRANCH_H |
| 10 | 10 | |
| 11 | +#include <asm/cpu-features.h> | |
| 12 | +#include <asm/mipsregs.h> | |
| 11 | 13 | #include <asm/ptrace.h> |
| 12 | 14 | #include <asm/inst.h> |
| 13 | 15 | |
| @@ -18,12 +20,40 @@ extern int __compute_return_epc_for_insn(struct pt_regs *regs, · 4 unmodified lines | ||
| 18 | 20 | extern int __microMIPS_compute_return_epc(struct pt_regs *regs); |
| 19 | 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 | 42 | static inline int delay_slot(struct pt_regs *regs) |
| 23 | 43 | { |
| 24 | 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 | 57 | static inline unsigned long exception_epc(struct pt_regs *regs) |
| 28 | 58 | { |
| 29 | 59 | if (likely(!delay_slot(regs))) |
| @@ -113,6 +113,12 @@ unsigned long run_uncached(void *func); · 112 unmodified lines | ||
| 113 | 113 | |
| 114 | 114 | extern void *kmap_coherent(struct page *page, unsigned long addr); |
| 115 | 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 | 123 | #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE |
| 118 | 124 | static inline void flush_kernel_dcache_page(struct page *page) |
| @@ -10,7 +10,6 @@ extern void cmp_smp_setup(void); · 9 unmodified lines | ||
| 10 | 10 | extern void cmp_smp_finish(void); |
| 11 | 11 | extern void cmp_boot_secondary(int cpu, struct task_struct *t); |
| 12 | 12 | extern void cmp_init_secondary(void); |
| 13 | −extern void cmp_cpus_done(void); | |
| 14 | 13 | extern void cmp_prepare_cpus(unsigned int max_cpus); |
| 15 | 14 | |
| 16 | 15 | /* This is platform specific */ |
| @@ -110,9 +110,15 @@ · 109 unmodified lines | ||
| 110 | 110 | #ifndef cpu_has_smartmips |
| 111 | 111 | #define cpu_has_smartmips (cpu_data[0].ases & MIPS_ASE_SMARTMIPS) |
| 112 | 112 | #endif |
| 113 | + | |
| 113 | 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 | 120 | #endif |
| 121 | + | |
| 116 | 122 | #ifndef cpu_has_mmips |
| 117 | 123 | # ifdef CONFIG_SYS_SUPPORTS_MICROMIPS |
| 118 | 124 | # define cpu_has_mmips (cpu_data[0].options & MIPS_CPU_MICROMIPS) |
| @@ -120,6 +126,7 @@ · 1 unmodified line | ||
| 120 | 126 | # define cpu_has_mmips 0 |
| 121 | 127 | # endif |
| 122 | 128 | #endif |
| 129 | + | |
| 123 | 130 | #ifndef cpu_has_vtag_icache |
| 124 | 131 | #define cpu_has_vtag_icache (cpu_data[0].icache.flags & MIPS_CACHE_VTAG) |
| 125 | 132 | #endif |
| @@ -183,6 +190,17 @@ · 57 unmodified lines | ||
| 183 | 190 | /* |
| 184 | 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 | 204 | #define cpu_has_mips32 (cpu_has_mips32r1 | cpu_has_mips32r2) |
| 187 | 205 | #define cpu_has_mips64 (cpu_has_mips64r1 | cpu_has_mips64r2) |
| 188 | 206 | #define cpu_has_mips_r1 (cpu_has_mips32r1 | cpu_has_mips64r1) |
| @@ -65,17 +65,12 @@ struct cpuinfo_mips { · 64 unmodified lines | ||
| 65 | 65 | #ifdef CONFIG_64BIT |
| 66 | 66 | int vmbits; /* Virtual memory size in bits */ |
| 67 | 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 | |
| 71 | − * to be a "CPU" for the purposes of scheduling, but | |
| 72 | − * exception resources, ASID spaces, etc, are common | |
| 73 | − * to all TCs within the same VPE. | |
| 70 | + * There is not necessarily a 1:1 mapping of VPE num to CPU number | |
| 71 | + * in particular on multi-core systems. | |
| 74 | 72 | */ |
| 75 | 73 | int vpe_id; /* Virtual Processor number */ |
| 76 | −#endif | |
| 77 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 78 | − int tc_id; /* Thread Context number */ | |
| 79 | 74 | #endif |
| 80 | 75 | void *data; /* Additional data */ |
| 81 | 76 | unsigned int watch_reg_count; /* Number that exist */ |
| @@ -117,7 +112,7 @@ struct proc_cpuinfo_notifier_args { · 35 unmodified lines | ||
| 117 | 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 | 116 | # define cpu_vpe_id(cpuinfo) ((cpuinfo)->vpe_id) |
| 122 | 117 | #else |
| 123 | 118 | # define cpu_vpe_id(cpuinfo) 0 |
| @@ -155,9 +155,6 @@ static inline int __pure __get_cpu_type(const int cpu_type) · 154 unmodified lines | ||
| 155 | 155 | case CPU_RM7000: |
| 156 | 156 | case CPU_SR71000: |
| 157 | 157 | #endif |
| 158 | −#ifdef CONFIG_SYS_HAS_CPU_RM9000 | |
| 159 | − case CPU_RM9000: | |
| 160 | −#endif | |
| 161 | 158 | #ifdef CONFIG_SYS_HAS_CPU_SB1 |
| 162 | 159 | case CPU_SB1: |
| 163 | 160 | case CPU_SB1A: |
| @@ -166,6 +163,7 @@ static inline int __pure __get_cpu_type(const int cpu_type) · 2 unmodified lines | ||
| 166 | 163 | case CPU_CAVIUM_OCTEON: |
| 167 | 164 | case CPU_CAVIUM_OCTEON_PLUS: |
| 168 | 165 | case CPU_CAVIUM_OCTEON2: |
| 166 | + case CPU_CAVIUM_OCTEON3: | |
| 169 | 167 | #endif |
| 170 | 168 | |
| 171 | 169 | #if defined(CONFIG_SYS_HAS_CPU_BMIPS32_3300) || \ |
| @@ -201,6 +201,7 @@ · 200 unmodified lines | ||
| 201 | 201 | #define PRID_IMP_NETLOGIC_XLP3XX 0x1100 |
| 202 | 202 | #define PRID_IMP_NETLOGIC_XLP2XX 0x1200 |
| 203 | 203 | #define PRID_IMP_NETLOGIC_XLP9XX 0x1500 |
| 204 | +#define PRID_IMP_NETLOGIC_XLP5XX 0x1300 | |
| 204 | 205 | |
| 205 | 206 | /* |
| 206 | 207 | * Particular Revision values for bits 7:0 of the PRId register. |
| @@ -281,7 +282,7 @@ enum cpu_type_enum { · 74 unmodified lines | ||
| 281 | 282 | CPU_R4700, CPU_R5000, CPU_R5500, CPU_NEVADA, CPU_R5432, CPU_R10000, |
| 282 | 283 | CPU_R12000, CPU_R14000, CPU_VR41XX, CPU_VR4111, CPU_VR4121, CPU_VR4122, |
| 283 | 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 | 288 | * R8000 class processors |
| @@ -48,13 +48,21 @@ · 47 unmodified lines | ||
| 48 | 48 | #define KN4K_RES_14 (14*IOASIC_SLOT_SIZE) /* unused? */ |
| 49 | 49 | #define KN4K_RES_15 (15*IOASIC_SLOT_SIZE) /* unused? */ |
| 50 | 50 | |
| 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 | + | |
| 51 | 60 | /* |
| 52 | 61 | * Bits for the MB interrupt register. |
| 53 | 62 | * The register appears read-only. |
| 54 | 63 | */ |
| 55 | −#define KN4K_MB_INT_TC (1<<0) /* TURBOchannel? */ | |
| 56 | −#define KN4K_MB_INT_RTC (1<<1) /* RTC? */ | |
| 57 | −#define KN4K_MB_INT_MT (1<<3) /* I/O ASIC cascade */ | |
| 64 | +#define KN4K_MB_INT_IRQ (0x1f<<0) /* CPU Int[4:0] status. */ | |
| 65 | +#define KN4K_MB_INT_IRQ_N(n) (1<<(n)) /* Individual status bits. */ | |
| 58 | 66 | |
| 59 | 67 | /* |
| 60 | 68 | * Bits for the MB control & status register. |
| @@ -70,6 +78,7 @@ · 9 unmodified lines | ||
| 70 | 78 | #define KN4K_MB_CSR_NC (1<<14) /* ??? */ |
| 71 | 79 | #define KN4K_MB_CSR_EE (1<<15) /* (bus) Exception Enable? */ |
| 72 | 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 | 82 | #define KN4K_MB_CSR_FW (1<<21) /* ??? */ |
| 74 | 83 | #define KN4K_MB_CSR_W (1<<31) /* ??? */ |
| 75 | 84 | |
| @@ -48,11 +48,7 @@ · 47 unmodified lines | ||
| 48 | 48 | enum fixed_addresses { |
| 49 | 49 | #define FIX_N_COLOURS 8 |
| 50 | 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 | 51 | FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * 2), |
| 55 | −#endif | |
| 56 | 52 | #ifdef CONFIG_HIGHMEM |
| 57 | 53 | /* reserved pte's for temporary kernel mappings */ |
| 58 | 54 | FIX_KMAP_BEGIN = FIX_CMAP_END + 1, |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <asm/mipsregs.h> |
| 18 | 18 | #include <asm/cpu.h> |
| 19 | 19 | #include <asm/cpu-features.h> |
| 20 | +#include <asm/fpu_emulator.h> | |
| 20 | 21 | #include <asm/hazards.h> |
| 21 | 22 | #include <asm/processor.h> |
| 22 | 23 | #include <asm/current.h> |
| @@ -28,7 +29,6 @@ · 5 unmodified lines | ||
| 28 | 29 | struct sigcontext; |
| 29 | 30 | struct sigcontext32; |
| 30 | 31 | |
| 31 | −extern void fpu_emulator_init_fpu(void); | |
| 32 | 32 | extern void _init_fpu(void); |
| 33 | 33 | extern void _save_fp(struct task_struct *); |
| 34 | 34 | extern void _restore_fp(struct task_struct *); |
| @@ -156,15 +156,16 @@ static inline int init_fpu(void) · 121 unmodified lines | ||
| 156 | 156 | int ret = 0; |
| 157 | 157 | |
| 158 | 158 | preempt_disable(); |
| 159 | + | |
| 159 | 160 | if (cpu_has_fpu) { |
| 160 | 161 | ret = __own_fpu(); |
| 161 | 162 | if (!ret) |
| 162 | 163 | _init_fpu(); |
| 163 | − } else { | |
| 164 | + } else | |
| 164 | 165 | fpu_emulator_init_fpu(); |
| 165 | − } | |
| 166 | 166 | |
| 167 | 167 | preempt_enable(); |
| 168 | + | |
| 168 | 169 | return ret; |
| 169 | 170 | } |
| 170 | 171 | |
| @@ -23,9 +23,12 @@ · 22 unmodified lines | ||
| 23 | 23 | #ifndef _ASM_FPU_EMULATOR_H |
| 24 | 24 | #define _ASM_FPU_EMULATOR_H |
| 25 | 25 | |
| 26 | +#include <linux/sched.h> | |
| 26 | 27 | #include <asm/break.h> |
| 28 | +#include <asm/thread_info.h> | |
| 27 | 29 | #include <asm/inst.h> |
| 28 | 30 | #include <asm/local.h> |
| 31 | +#include <asm/processor.h> | |
| 29 | 32 | |
| 30 | 33 | #ifdef CONFIG_DEBUG_FS |
| 31 | 34 | |
| @@ -36,6 +39,11 @@ struct mips_fpu_emulator_stats { · 4 unmodified lines | ||
| 36 | 39 | local_t cp1ops; |
| 37 | 40 | local_t cp1xops; |
| 38 | 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 | 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, · 29 unmodified lines | ||
| 71 | 79 | */ |
| 72 | 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 | 95 | #endif /* _ASM_FPU_EMULATOR_H */ |
| @@ -380,6 +380,7 @@ extern unsigned int gic_compare_int (void); · 379 unmodified lines | ||
| 380 | 380 | extern cycle_t gic_read_count(void); |
| 381 | 381 | extern cycle_t gic_read_compare(void); |
| 382 | 382 | extern void gic_write_compare(cycle_t cnt); |
| 383 | +extern void gic_write_cpu_compare(cycle_t cnt, int cpu); | |
| 383 | 384 | extern void gic_send_ipi(unsigned int intr); |
| 384 | 385 | extern unsigned int plat_ipi_call_int_xlate(unsigned int); |
| 385 | 386 | extern unsigned int plat_ipi_resched_int_xlate(unsigned int); |
| @@ -50,7 +50,7 @@ static inline void gio_device_free(struct gio_device *dev) · 49 unmodified lines | ||
| 50 | 50 | extern int gio_register_driver(struct gio_driver *); |
| 51 | 51 | extern void gio_unregister_driver(struct gio_driver *); |
| 52 | 52 | |
| 53 | −#define gio_get_drvdata(_dev) drv_get_drvdata(&(_dev)->dev) | |
| 54 | −#define gio_set_drvdata(_dev, data) drv_set_drvdata(&(_dev)->dev, (data)) | |
| 53 | +#define gio_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev) | |
| 54 | +#define gio_set_drvdata(_dev, data) dev_set_drvdata(&(_dev)->dev, (data)) | |
| 55 | 55 | |
| 56 | 56 | extern void gio_set_master(struct gio_device *); |
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | #ifndef __ASM_IDLE_H |
| 2 | 2 | #define __ASM_IDLE_H |
| 3 | 3 | |
| 4 | +#include <linux/cpuidle.h> | |
| 4 | 5 | #include <linux/linkage.h> |
| 5 | 6 | |
| 6 | 7 | extern void (*cpu_wait)(void); |
| @@ -20,4 +21,17 @@ static inline int address_is_in_r4k_wait_irqoff(unsigned long addr) · 13 unmodified lines | ||
| 20 | 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 | 37 | #endif /* __ASM_IDLE_H */ |
| @@ -26,104 +26,8 @@ static inline int irq_canonicalize(int irq) · 25 unmodified lines | ||
| 26 | 26 | #define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */ |
| 27 | 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 | 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 | 31 | extern void arch_init_irq(void); |
| 128 | 32 | extern void spurious_interrupt(void); |
| 129 | 33 | |
| @@ -17,7 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/stringify.h> |
| 18 | 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 | 22 | static inline void arch_local_irq_disable(void) |
| 23 | 23 | { |
| @@ -118,30 +118,15 @@ void arch_local_irq_disable(void); · 94 unmodified lines | ||
| 118 | 118 | unsigned long arch_local_irq_save(void); |
| 119 | 119 | void arch_local_irq_restore(unsigned long flags); |
| 120 | 120 | void __arch_local_irq_restore(unsigned long flags); |
| 121 | −#endif /* if defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_MIPS_MT_SMTC) */ | |
| 122 | − | |
| 123 | − | |
| 124 | −extern void smtc_ipi_replay(void); | |
| 121 | +#endif /* CONFIG_CPU_MIPSR2 */ | |
| 125 | 122 | |
| 126 | 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 | 125 | __asm__ __volatile__( |
| 136 | 126 | " .set push \n" |
| 137 | 127 | " .set reorder \n" |
| 138 | 128 | " .set noat \n" |
| 139 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 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) | |
| 129 | +#if defined(CONFIG_CPU_MIPSR2) | |
| 145 | 130 | " ei \n" |
| 146 | 131 | #else |
| 147 | 132 | " mfc0 $1,$12 \n" |
| @@ -163,11 +148,7 @@ static inline unsigned long arch_local_save_flags(void) · 15 unmodified lines | ||
| 163 | 148 | asm __volatile__( |
| 164 | 149 | " .set push \n" |
| 165 | 150 | " .set reorder \n" |
| 166 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 167 | − " mfc0 %[flags], $2, 1 \n" | |
| 168 | −#else | |
| 169 | 151 | " mfc0 %[flags], $12 \n" |
| 170 | −#endif | |
| 171 | 152 | " .set pop \n" |
| 172 | 153 | : [flags] "=r" (flags)); |
| 173 | 154 | |
| @@ -177,14 +158,7 @@ static inline unsigned long arch_local_save_flags(void) · 3 unmodified lines | ||
| 177 | 158 | |
| 178 | 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 | 161 | return !(flags & 1); |
| 187 | −#endif | |
| 188 | 162 | } |
| 189 | 163 | |
| 190 | 164 | #endif /* #ifndef __ASSEMBLY__ */ |
| @@ -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 */ | |
| @@ -22,7 +22,6 @@ · 21 unmodified lines | ||
| 22 | 22 | #define cpu_has_3k_cache 0 |
| 23 | 23 | #define cpu_has_4k_cache 0 |
| 24 | 24 | #define cpu_has_tx39_cache 0 |
| 25 | −#define cpu_has_fpu 0 | |
| 26 | 25 | #define cpu_has_counter 1 |
| 27 | 26 | #define cpu_has_watch 1 |
| 28 | 27 | #define cpu_has_divec 1 |
| @@ -35,6 +35,8 @@ enum octeon_irq { · 34 unmodified lines | ||
| 35 | 35 | OCTEON_IRQ_PCI_MSI2, |
| 36 | 36 | OCTEON_IRQ_PCI_MSI3, |
| 37 | 37 | |
| 38 | + OCTEON_IRQ_TWSI, | |
| 39 | + OCTEON_IRQ_TWSI2, | |
| 38 | 40 | OCTEON_IRQ_RML, |
| 39 | 41 | OCTEON_IRQ_TIMER0, |
| 40 | 42 | OCTEON_IRQ_TIMER1, |
| @@ -39,6 +39,10 @@ · 38 unmodified lines | ||
| 39 | 39 | #define cpu_has_nofpuex 0 |
| 40 | 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 | 46 | #define cpu_has_mips32r1 0 |
| 43 | 47 | #define cpu_has_mips32r2 0 |
| 44 | 48 | #define cpu_has_mips64r1 0 |
| @@ -80,36 +80,6 @@ · 79 unmodified lines | ||
| 80 | 80 | .endm |
| 81 | 81 | |
| 82 | 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 | 84 | #ifdef CONFIG_EVA |
| 115 | 85 | sync |
| @@ -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__ */ | |
| @@ -10,10 +10,12 @@ · 9 unmodified lines | ||
| 10 | 10 | |
| 11 | 11 | #include <asm/mach-netlogic/multi-node.h> |
| 12 | 12 | |
| 13 | +#ifdef CONFIG_SMP | |
| 13 | 14 | #define topology_physical_package_id(cpu) cpu_to_node(cpu) |
| 14 | 15 | #define topology_core_id(cpu) (cpu_logical_map(cpu) / NLM_THREADS_PER_CORE) |
| 15 | 16 | #define topology_thread_cpumask(cpu) (&cpu_sibling_map[cpu]) |
| 16 | 17 | #define topology_core_cpumask(cpu) cpumask_of_node(cpu_to_node(cpu)) |
| 18 | +#endif | |
| 17 | 19 | |
| 18 | 20 | #include <asm-generic/topology.h> |
| 19 | 21 | |
| @@ -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 */ | |
| @@ -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__ */ | |
| @@ -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 */ | |
| @@ -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 */ | |
| @@ -25,11 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #ifndef MSP_USB_H_ |
| 26 | 26 | #define MSP_USB_H_ |
| 27 | 27 | |
| 28 | −#ifdef CONFIG_MSP_HAS_DUAL_USB | |
| 29 | −#define NUM_USB_DEVS 2 | |
| 30 | −#else | |
| 31 | 28 | #define NUM_USB_DEVS 1 |
| 32 | −#endif | |
| 33 | 29 | |
| 34 | 30 | /* Register spaces for USB host 0 */ |
| 35 | 31 | #define MSP_USB0_MAB_START (MSP_USB0_BASE + 0x0) |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | #define MIPS4K_ICACHE_REFILL_WAR 0 |
| 18 | 18 | #define MIPS_CACHE_SYNC_WAR 0 |
| 19 | 19 | #define TX49XX_ICACHE_INDEX_INV_WAR 0 |
| 20 | −#define RM9000_CDEX_SMP_WAR 0 | |
| 21 | 20 | #define ICACHE_REFILLS_WORKAROUND_WAR 0 |
| 22 | 21 | #define R10000_LLSC_WAR 0 |
| 23 | 22 | #define MIPS34K_MISSED_ITLB_WAR 0 |
| @@ -10,37 +10,6 @@ · 9 unmodified lines | ||
| 10 | 10 | #define __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H |
| 11 | 11 | |
| 12 | 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 | 13 | .endm |
| 45 | 14 | |
| 46 | 15 | /* |
| @@ -55,4 +55,16 @@ · 54 unmodified lines | ||
| 55 | 55 | #define PIIX4_FUNC3_PMREGMISC 0x80 |
| 56 | 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 | 70 | #endif /* __ASM_MIPS_BOARDS_PIIX4_H */ |
| @@ -72,7 +72,12 @@ static inline bool mips_cpc_present(void) · 71 unmodified lines | ||
| 72 | 72 | #define MIPS_CPC_COCB_OFS 0x4000 |
| 73 | 73 | |
| 74 | 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 | 81 | static inline u32 read_cpc_##name(void) \ |
| 77 | 82 | { \ |
| 78 | 83 | return __raw_readl(mips_cpc_base + (off)); \ |
| @@ -147,4 +152,31 @@ BUILD_CPC_Cx_RW(other, 0x10) · 68 unmodified lines | ||
| 147 | 152 | #define CPC_Cx_OTHER_CORENUM_SHF 16 |
| 148 | 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 | 182 | #endif /* __MIPS_ASM_MIPS_CPC_H__ */ |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | /* |
| 2 | − * Definitions and decalrations for MIPS MT support | |
| 3 | − * that are common between SMTC, VSMP, and/or AP/SP | |
| 4 | − * kernel models. | |
| 2 | + * Definitions and decalrations for MIPS MT support that are common between | |
| 3 | + * the VSMP, and AP/SP kernel models. | |
| 5 | 4 | */ |
| 6 | 5 | #ifndef __ASM_MIPS_MT_H |
| 7 | 6 | #define __ASM_MIPS_MT_H |
| @@ -36,6 +36,8 @@ · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 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 | 41 | #define read_c0_tccontext() __read_32bit_c0_register($2, 5) |
| 40 | 42 | #define write_c0_tccontext(val) __write_32bit_c0_register($2, 5, val) |
| 41 | 43 | |
| @@ -709,11 +709,18 @@ · 708 unmodified lines | ||
| 709 | 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 | 716 | #define get_isa16_mode(x) ((x) & 0x1) |
| 715 | 717 | #define msk_isa16_mode(x) ((x) & ~0x1) |
| 716 | 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 | 726 | * microMIPS instructions can be 16-bit or 32-bit in length. This |
| @@ -1007,19 +1014,8 @@ do { \ · 287 unmodified lines | ||
| 1007 | 1014 | #define write_c0_compare3(val) __write_32bit_c0_register($11, 7, val) |
| 1008 | 1015 | |
| 1009 | 1016 | #define read_c0_status() __read_32bit_c0_register($12, 0) |
| 1010 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 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 | − */ | |
| 1017 | + | |
| 1021 | 1018 | #define write_c0_status(val) __write_32bit_c0_register($12, 0, val) |
| 1022 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 1023 | 1019 | |
| 1024 | 1020 | #define read_c0_cause() __read_32bit_c0_register($13, 0) |
| 1025 | 1021 | #define write_c0_cause(val) __write_32bit_c0_register($13, 0, val) |
| @@ -1743,11 +1739,6 @@ static inline void tlb_write_random(void) · 717 unmodified lines | ||
| 1743 | 1739 | /* |
| 1744 | 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 | 1742 | #define __BUILD_SET_C0(name) \ |
| 1752 | 1743 | static inline unsigned int \ |
| 1753 | 1744 | set_c0_##name(unsigned int set) \ |
| @@ -1786,121 +1777,6 @@ change_c0_##name(unsigned int change, unsigned int val) \ · 32 unmodified lines | ||
| 1786 | 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 | 1780 | __BUILD_SET_C0(status) |
| 1905 | 1781 | __BUILD_SET_C0(cause) |
| 1906 | 1782 | __BUILD_SET_C0(config) |
| @@ -1916,6 +1792,15 @@ __BUILD_SET_C0(brcm_cmt_ctrl) · 9 unmodified lines | ||
| 1916 | 1792 | __BUILD_SET_C0(brcm_config) |
| 1917 | 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 | 1804 | #endif /* !__ASSEMBLY__ */ |
| 1920 | 1805 | |
| 1921 | 1806 | #endif /* _ASM_MIPSREGS_H */ |
| @@ -18,10 +18,6 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <asm/cacheflush.h> |
| 19 | 19 | #include <asm/hazards.h> |
| 20 | 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 | 21 | #include <asm-generic/mm_hooks.h> |
| 26 | 22 | |
| 27 | 23 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ |
| @@ -31,11 +27,15 @@ do { \ · 3 unmodified lines | ||
| 31 | 27 | } while (0) |
| 32 | 28 | |
| 33 | 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 | 35 | #define TLBMISS_HANDLER_SETUP() \ |
| 35 | 36 | do { \ |
| 36 | 37 | TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir); \ |
| 37 | − write_c0_xcontext((unsigned long) smp_processor_id() << \ | |
| 38 | − SMP_CPUID_REGSHIFT); \ | |
| 38 | + TLBMISS_HANDLER_RESTORE(); \ | |
| 39 | 39 | } while (0) |
| 40 | 40 | |
| 41 | 41 | #else /* !CONFIG_MIPS_PGD_C0_CONTEXT: using pgd_current*/ |
| @@ -47,9 +47,12 @@ do { \ · 5 unmodified lines | ||
| 47 | 47 | */ |
| 48 | 48 | extern unsigned long pgd_current[]; |
| 49 | 49 | |
| 50 | −#define TLBMISS_HANDLER_SETUP() \ | |
| 50 | +#define TLBMISS_HANDLER_RESTORE() \ | |
| 51 | 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 | 56 | back_to_back_c0_hazard(); \ |
| 54 | 57 | TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) |
| 55 | 58 | #endif /* CONFIG_MIPS_PGD_C0_CONTEXT*/ |
| @@ -63,13 +66,6 @@ extern unsigned long pgd_current[]; · 7 unmodified lines | ||
| 63 | 66 | #define ASID_INC 0x10 |
| 64 | 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 | 69 | #else /* FIXME: not correct for R6000 */ |
| 74 | 70 | |
| 75 | 71 | #define ASID_INC 0x1 |
| @@ -92,7 +88,6 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) · 16 unmodified lines | ||
| 92 | 88 | #define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1))) |
| 93 | 89 | #define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1) |
| 94 | 90 | |
| 95 | −#ifndef CONFIG_MIPS_MT_SMTC | |
| 96 | 91 | /* Normal, classic MIPS get_new_mmu_context */ |
| 97 | 92 | static inline void |
| 98 | 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) · 16 unmodified lines | ||
| 115 | 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 | 114 | * Initialize the context related info for a new mm_struct |
| 126 | 115 | * instance. |
| @@ -141,46 +130,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, · 14 unmodified lines | ||
| 141 | 130 | { |
| 142 | 131 | unsigned int cpu = smp_processor_id(); |
| 143 | 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 | 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 | 135 | /* Check if our ASID is of an older version and thus invalid */ |
| 155 | 136 | if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK) |
| 156 | 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 | 138 | write_c0_entryhi(cpu_asid(cpu, next)); |
| 183 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 184 | 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) · 26 unmodified lines | ||
| 213 | 168 | unsigned long flags; |
| 214 | 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 | 171 | local_irq_save(flags); |
| 223 | 172 | |
| 224 | 173 | /* Unconditionally get a new ASID. */ |
| 225 | 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 | 176 | write_c0_entryhi(cpu_asid(cpu, next)); |
| 243 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 244 | 177 | TLBMISS_HANDLER_SETUP_PGD(next->pgd); |
| 245 | 178 | |
| 246 | 179 | /* mark mmu ownership change */ |
| @@ -258,48 +191,15 @@ static inline void · 11 unmodified lines | ||
| 258 | 191 | drop_mmu_context(struct mm_struct *mm, unsigned cpu) |
| 259 | 192 | { |
| 260 | 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 | 195 | local_irq_save(flags); |
| 269 | 196 | |
| 270 | 197 | if (cpumask_test_cpu(cpu, mm_cpumask(mm))) { |
| 271 | 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 | 199 | write_c0_entryhi(cpu_asid(cpu, mm)); |
| 288 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 289 | 200 | } else { |
| 290 | 201 | /* will get a new context next time */ |
| 291 | −#ifndef CONFIG_MIPS_MT_SMTC | |
| 292 | 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 | 204 | local_irq_restore(flags); |
| 305 | 205 | } |
| @@ -144,13 +144,7 @@ search_module_dbetables(unsigned long addr) · 143 unmodified lines | ||
| 144 | 144 | #define MODULE_KERNEL_TYPE "64BIT " |
| 145 | 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 | 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 | 150 | #endif /* _ASM_MODULE_H */ |
| @@ -84,7 +84,7 @@ static inline void write_msa_##name(unsigned int val) \ · 83 unmodified lines | ||
| 84 | 84 | __asm__ __volatile__( \ |
| 85 | 85 | " .set push\n" \ |
| 86 | 86 | " .set msa\n" \ |
| 87 | − " cfcmsa $" #cs ", %0\n" \ | |
| 87 | + " ctcmsa $" #cs ", %0\n" \ | |
| 88 | 88 | " .set pop\n" \ |
| 89 | 89 | : : "r"(val)); \ |
| 90 | 90 | } |
| @@ -96,6 +96,13 @@ static inline void write_msa_##name(unsigned int val) \ · 5 unmodified lines | ||
| 96 | 96 | * allow compilation with toolchains that do not support MSA. Once all |
| 97 | 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 | 107 | #define __BUILD_MSA_CTL_REG(name, cs) \ |
| 101 | 108 | static inline unsigned int read_msa_##name(void) \ |
| @@ -104,7 +111,8 @@ static inline unsigned int read_msa_##name(void) \ · 2 unmodified lines | ||
| 104 | 111 | __asm__ __volatile__( \ |
| 105 | 112 | " .set push\n" \ |
| 106 | 113 | " .set noat\n" \ |
| 107 | − " .word 0x787e0059 | (" #cs " << 11)\n" \ | |
| 114 | + " .insn\n" \ | |
| 115 | + " .word #CFC_MSA_INSN | (" #cs " << 11)\n" \ | |
| 108 | 116 | " move %0, $1\n" \ |
| 109 | 117 | " .set pop\n" \ |
| 110 | 118 | : "=r"(reg)); \ |
| @@ -117,7 +125,8 @@ static inline void write_msa_##name(unsigned int val) \ · 6 unmodified lines | ||
| 117 | 125 | " .set push\n" \ |
| 118 | 126 | " .set noat\n" \ |
| 119 | 127 | " move $1, %0\n" \ |
| 120 | − " .word 0x783e0819 | (" #cs " << 6)\n" \ | |
| 128 | + " .insn\n" \ | |
| 129 | + " .word #CTC_MSA_INSN | (" #cs " << 6)\n" \ | |
| 121 | 130 | " .set pop\n" \ |
| 122 | 131 | : : "r"(val)); \ |
| 123 | 132 | } |
| @@ -146,9 +146,10 @@ static inline int hard_smp_processor_id(void) · 145 unmodified lines | ||
| 146 | 146 | |
| 147 | 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 | 153 | return (__read_32bit_c0_register($15, 1) >> 7) & 0x7; |
| 153 | 154 | else |
| 154 | 155 | return (__read_32bit_c0_register($15, 1) >> 5) & 0x3; |
| @@ -74,6 +74,8 @@ · 73 unmodified lines | ||
| 74 | 74 | #define XLP_IO_USB_OHCI2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 4) |
| 75 | 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 | 79 | /* XLP2xx has an updated USB block */ |
| 78 | 80 | #define XLP2XX_IO_USB_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 4, i) |
| 79 | 81 | #define XLP2XX_IO_USB_XHCI0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 4, 1) |
| @@ -103,13 +105,11 @@ · 23 unmodified lines | ||
| 103 | 105 | #define XLP_IO_SYS_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 5) |
| 104 | 106 | #define XLP_IO_JTAG_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 6) |
| 105 | 107 | |
| 108 | +/* Flash */ | |
| 106 | 109 | #define XLP_IO_NOR_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 0) |
| 107 | 110 | #define XLP_IO_NAND_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 1) |
| 108 | 111 | #define XLP_IO_SPI_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 2) |
| 109 | −/* SD flash */ | |
| 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) | |
| 112 | +#define XLP_IO_MMC_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 3) | |
| 113 | 113 | |
| 114 | 114 | /* Things have changed drastically in XLP 9XX */ |
| 115 | 115 | #define XLP9XX_HDR_OFFSET(n, d, f) \ |
| @@ -120,6 +120,8 @@ · 4 unmodified lines | ||
| 120 | 120 | #define XLP9XX_IO_UART_OFFSET(node) XLP9XX_HDR_OFFSET(node, 2, 2) |
| 121 | 121 | #define XLP9XX_IO_SYS_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 0) |
| 122 | 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 | 125 | #define XLP9XX_IO_JTAG_OFFSET(node) XLP9XX_HDR_OFFSET(node, 6, 4) |
| 124 | 126 | |
| 125 | 127 | #define XLP9XX_IO_PCIE_OFFSET(node, i) XLP9XX_HDR_OFFSET(node, 1, i) |
| @@ -135,11 +137,11 @@ · 9 unmodified lines | ||
| 135 | 137 | /* XLP9XX on-chip SATA controller */ |
| 136 | 138 | #define XLP9XX_IO_SATA_OFFSET(node) XLP9XX_HDR_OFFSET(node, 3, 2) |
| 137 | 139 | |
| 140 | +/* Flash */ | |
| 138 | 141 | #define XLP9XX_IO_NOR_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 0) |
| 139 | 142 | #define XLP9XX_IO_NAND_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 1) |
| 140 | 143 | #define XLP9XX_IO_SPI_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 2) |
| 141 | −/* SD flash */ | |
| 142 | −#define XLP9XX_IO_MMCSD_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 3) | |
| 144 | +#define XLP9XX_IO_MMC_OFFSET(node) XLP9XX_HDR_OFFSET(node, 7, 3) | |
| 143 | 145 | |
| 144 | 146 | /* PCI config header register id's */ |
| 145 | 147 | #define XLP_PCI_CFGREG0 0x00 |
| @@ -186,8 +188,10 @@ · 40 unmodified lines | ||
| 186 | 188 | #define PCI_DEVICE_ID_NLM_NOR 0x1015 |
| 187 | 189 | #define PCI_DEVICE_ID_NLM_NAND 0x1016 |
| 188 | 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 | 195 | #define PCI_DEVICE_ID_XLP9XX_SATA 0x901A |
| 192 | 196 | #define PCI_DEVICE_ID_XLP9XX_XHCI 0x901D |
| 193 | 197 | |
| @@ -69,6 +69,20 @@ · 68 unmodified lines | ||
| 69 | 69 | #define PCIE_9XX_BYTE_SWAP_IO_BASE 0x25e |
| 70 | 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 | 86 | /* other */ |
| 73 | 87 | #define PCIE_NLINKS 4 |
| 74 | 88 | |
| @@ -199,6 +199,10 @@ · 198 unmodified lines | ||
| 199 | 199 | #define PIC_IRT_PCIE_LINK_3_INDEX 81 |
| 200 | 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 | 206 | #define PIC_CLOCK_TIMER 7 |
| 203 | 207 | |
| 204 | 208 | #if !defined(LOCORE) && !defined(__ASSEMBLY__) |
| @@ -118,6 +118,10 @@ · 117 unmodified lines | ||
| 118 | 118 | #define SYS_SCRTCH3 0x4c |
| 119 | 119 | |
| 120 | 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 | 125 | #define SYS_PLL_CTRL0 0x240 |
| 122 | 126 | #define SYS_PLL_CTRL1 0x241 |
| 123 | 127 | #define SYS_PLL_CTRL2 0x242 |
| @@ -147,6 +151,32 @@ · 23 unmodified lines | ||
| 147 | 151 | #define SYS_SYS_PLL_MEM_REQ 0x2a3 |
| 148 | 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 | 180 | /* Registers changed on 9XX */ |
| 151 | 181 | #define SYS_9XX_POWER_ON_RESET_CFG 0x00 |
| 152 | 182 | #define SYS_9XX_CHIP_RESET 0x01 |
| @@ -170,6 +200,11 @@ · 17 unmodified lines | ||
| 170 | 200 | #define nlm_get_fuse_regbase(node) \ |
| 171 | 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 | 208 | unsigned int nlm_get_pic_frequency(int node); |
| 174 | 209 | #endif |
| 175 | 210 | #endif |
| @@ -58,6 +58,10 @@ · 57 unmodified lines | ||
| 58 | 58 | #define PIC_I2C_1_IRQ 31 |
| 59 | 59 | #define PIC_I2C_2_IRQ 32 |
| 60 | 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 | 66 | #define PIC_PCIE_LINK_MSI_IRQ_BASE 44 /* 44 - 47 MSI IRQ */ |
| 63 | 67 | #define PIC_PCIE_LINK_MSI_IRQ(i) (44 + (i)) |
| @@ -66,8 +70,9 @@ · 2 unmodified lines | ||
| 66 | 70 | #define PIC_PCIE_MSIX_IRQ_BASE 48 /* 48 - 51 MSI-X IRQ */ |
| 67 | 71 | #define PIC_PCIE_MSIX_IRQ(i) (48 + (i)) |
| 68 | 72 | |
| 69 | −#define NLM_MSIX_VEC_BASE 96 /* 96 - 127 - MSIX mapped */ | |
| 70 | −#define NLM_MSI_VEC_BASE 128 /* 128 -255 - MSI mapped */ | |
| 73 | +/* XLP9xx and XLP8xx has 128 and 32 MSIX vectors respectively */ | |
| 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 | 77 | #define NLM_PIC_INDIRECT_VEC_BASE 512 |
| 73 | 78 | #define NLM_GPIO_VEC_BASE 768 |
| @@ -95,17 +100,19 @@ void *xlp_dt_init(void *fdtp); · 21 unmodified lines | ||
| 95 | 100 | |
| 96 | 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 | 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 | 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 | 117 | #endif /* !__ASSEMBLY__ */ |
| 111 | 118 | #endif /* _ASM_NLM_XLP_H */ |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | /* |
| 2 | 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 | 5 | * Sony Software Development Center Europe (SDCE), Brussels |
| 6 | 6 | * |
| 7 | 7 | * This file is based on the following documentation: |
| @@ -211,7 +211,6 @@ union octeon_cvmemctl { · 210 unmodified lines | ||
| 211 | 211 | |
| 212 | 212 | extern void octeon_write_lcd(const char *s); |
| 213 | 213 | extern void octeon_check_cpu_bist(void); |
| 214 | −extern int octeon_get_boot_debug_flag(void); | |
| 215 | 214 | extern int octeon_get_boot_uart(void); |
| 216 | 215 | |
| 217 | 216 | struct uart_port; |
| @@ -32,6 +32,8 @@ struct vm_area_struct; · 31 unmodified lines | ||
| 32 | 32 | _page_cachable_default) |
| 33 | 33 | #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ |
| 34 | 34 | _PAGE_GLOBAL | _page_cachable_default) |
| 35 | +#define PAGE_KERNEL_NC __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ | |
| 36 | + _PAGE_GLOBAL | _CACHE_CACHABLE_NONCOHERENT) | |
| 35 | 37 | #define PAGE_USERIO __pgprot(_PAGE_PRESENT | (cpu_has_rixi ? 0 : _PAGE_READ) | _PAGE_WRITE | \ |
| 36 | 38 | _page_cachable_default) |
| 37 | 39 | #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | \ |
| @@ -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__ */ | |
| @@ -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 */ | |
| @@ -39,9 +39,6 @@ struct pt_regs { · 38 unmodified lines | ||
| 39 | 39 | unsigned long cp0_badvaddr; |
| 40 | 40 | unsigned long cp0_cause; |
| 41 | 41 | unsigned long cp0_epc; |
| 42 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 43 | − unsigned long cp0_tcstatus; | |
| 44 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 45 | 42 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
| 46 | 43 | unsigned long long mpl[3]; /* MTM{0,1,2} */ |
| 47 | 44 | unsigned long long mtp[3]; /* MTP{0,1,2} */ |
| @@ -43,11 +43,10 @@ · 42 unmodified lines | ||
| 43 | 43 | : "i" (op), "R" (*(unsigned char *)(addr))) |
| 44 | 44 | |
| 45 | 45 | #ifdef CONFIG_MIPS_MT |
| 46 | + | |
| 46 | 47 | /* |
| 47 | − * Temporary hacks for SMTC debug. Optionally force single-threaded | |
| 48 | − * execution during I-cache flushes. | |
| 48 | + * Optionally force single-threaded execution during I-cache flushes. | |
| 49 | 49 | */ |
| 50 | − | |
| 51 | 50 | #define PROTECT_CACHE_FLUSHES 1 |
| 52 | 51 | |
| 53 | 52 | #ifdef PROTECT_CACHE_FLUSHES |
| @@ -524,6 +523,8 @@ __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32, · 470 unmodified lines | ||
| 524 | 523 | __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64, ) |
| 525 | 524 | __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, ) |
| 526 | 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 | 528 | __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, ) |
| 528 | 529 | |
| 529 | 530 | __BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16, ) |
| @@ -69,6 +69,8 @@ · 68 unmodified lines | ||
| 69 | 69 | #define SGI_EISA_IRQ SGINT_LOCAL2 + 3 /* EISA interrupts */ |
| 70 | 70 | #define SGI_KEYBD_IRQ SGINT_LOCAL2 + 4 /* keyboard */ |
| 71 | 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 | 75 | #define ip22_is_fullhouse() (sgioc->sysid & SGIOC_SYSID_FULLHOUSE) |
| 74 | 76 | |
| @@ -13,17 +13,28 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | #ifndef __ASSEMBLY__ |
| 15 | 15 | |
| 16 | −struct boot_config { | |
| 17 | − unsigned int core; | |
| 18 | − unsigned int vpe; | |
| 16 | +struct vpe_boot_config { | |
| 19 | 17 | unsigned long pc; |
| 20 | 18 | unsigned long sp; |
| 21 | 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 | 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 | 39 | #else /* __ASSEMBLY__ */ |
| 29 | 40 | |
| @@ -26,7 +26,6 @@ struct plat_smp_ops { · 25 unmodified lines | ||
| 26 | 26 | void (*send_ipi_mask)(const struct cpumask *mask, unsigned int action); |
| 27 | 27 | void (*init_secondary)(void); |
| 28 | 28 | void (*smp_finish)(void); |
| 29 | − void (*cpus_done)(void); | |
| 30 | 29 | void (*boot_secondary)(int cpu, struct task_struct *idle); |
| 31 | 30 | void (*smp_setup)(void); |
| 32 | 31 | void (*prepare_cpus)(unsigned int max_cpus); |
| @@ -46,6 +46,9 @@ extern int __cpu_logical_map[NR_CPUS]; · 45 unmodified lines | ||
| 46 | 46 | |
| 47 | 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 | 52 | extern void asmlinkage smp_bootstrap(void); |
| 50 | 53 | |
| 51 | 54 | /* |
| @@ -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 */ | |
| @@ -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 */ | |
| @@ -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 */ | |
| @@ -19,22 +19,12 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <asm/asm-offsets.h> |
| 20 | 20 | #include <asm/thread_info.h> |
| 21 | 21 | |
| 22 | −/* | |
| 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) | |
| 22 | +#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) | |
| 29 | 23 | #define STATMASK 0x3f |
| 30 | 24 | #else |
| 31 | 25 | #define STATMASK 0x1f |
| 32 | 26 | #endif |
| 33 | 27 | |
| 34 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 35 | −#include <asm/mipsmtregs.h> | |
| 36 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 37 | − | |
| 38 | 28 | .macro SAVE_AT |
| 39 | 29 | .set push |
| 40 | 30 | .set noat |
| @@ -186,16 +176,6 @@ · 145 unmodified lines | ||
| 186 | 176 | mfc0 v1, CP0_STATUS |
| 187 | 177 | LONG_S $2, PT_R2(sp) |
| 188 | 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 | 179 | LONG_S $4, PT_R4(sp) |
| 200 | 180 | mfc0 v1, CP0_CAUSE |
| 201 | 181 | LONG_S $5, PT_R5(sp) |
| @@ -321,36 +301,6 @@ · 119 unmodified lines | ||
| 321 | 301 | .set push |
| 322 | 302 | .set reorder |
| 323 | 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 | 304 | mfc0 a0, CP0_STATUS |
| 355 | 305 | ori a0, STATMASK |
| 356 | 306 | xori a0, STATMASK |
| @@ -362,59 +312,6 @@ · 5 unmodified lines | ||
| 362 | 312 | and v0, v1 |
| 363 | 313 | or v0, a0 |
| 364 | 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 | 315 | LONG_L v1, PT_EPC(sp) |
| 419 | 316 | MTC0 v1, CP0_EPC |
| 420 | 317 | LONG_L $31, PT_R31(sp) |
| @@ -467,33 +364,11 @@ · 46 unmodified lines | ||
| 467 | 364 | * Set cp0 enable bit as sign that we're running on the kernel stack |
| 468 | 365 | */ |
| 469 | 366 | .macro CLI |
| 470 | −#if !defined(CONFIG_MIPS_MT_SMTC) | |
| 471 | 367 | mfc0 t0, CP0_STATUS |
| 472 | 368 | li t1, ST0_CU0 | STATMASK |
| 473 | 369 | or t0, t1 |
| 474 | 370 | xori t0, STATMASK |
| 475 | 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 | 372 | irq_disable_hazard |
| 498 | 373 | .endm |
| 499 | 374 | |
| @@ -502,35 +377,11 @@ · 2 unmodified lines | ||
| 502 | 377 | * Set cp0 enable bit as sign that we're running on the kernel stack |
| 503 | 378 | */ |
| 504 | 379 | .macro STI |
| 505 | −#if !defined(CONFIG_MIPS_MT_SMTC) | |
| 506 | 380 | mfc0 t0, CP0_STATUS |
| 507 | 381 | li t1, ST0_CU0 | STATMASK |
| 508 | 382 | or t0, t1 |
| 509 | 383 | xori t0, STATMASK & ~1 |
| 510 | 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 | 385 | irq_enable_hazard |
| 535 | 386 | .endm |
| 536 | 387 | |
| @@ -540,32 +391,6 @@ · 3 unmodified lines | ||
| 540 | 391 | * Set cp0 enable bit as sign that we're running on the kernel stack |
| 541 | 392 | */ |
| 542 | 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 | 394 | mfc0 t0, CP0_STATUS |
| 570 | 395 | li t1, ST0_CU0 | (STATMASK & ~1) |
| 571 | 396 | #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) |
| @@ -576,25 +401,6 @@ · 4 unmodified lines | ||
| 576 | 401 | or t0, t1 |
| 577 | 402 | xori t0, STATMASK & ~1 |
| 578 | 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 | 404 | irq_disable_hazard |
| 599 | 405 | .endm |
| 600 | 406 | |
| @@ -159,11 +159,7 @@ static inline struct thread_info *current_thread_info(void) · 158 unmodified lines | ||
| 159 | 159 | * We stash processor id into a COP0 register to retrieve it fast |
| 160 | 160 | * at kernel exception entry. |
| 161 | 161 | */ |
| 162 | −#if defined(CONFIG_MIPS_MT_SMTC) | |
| 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) | |
| 162 | +#if defined(CONFIG_MIPS_PGD_C0_CONTEXT) | |
| 167 | 163 | #define SMP_CPUID_REG 20, 0 /* XCONTEXT */ |
| 168 | 164 | #define ASM_SMP_CPUID_REG $20 |
| 169 | 165 | #define SMP_CPUID_PTRSHIFT 48 |
| @@ -179,13 +175,8 @@ static inline struct thread_info *current_thread_info(void) · 9 unmodified lines | ||
| 179 | 175 | #define SMP_CPUID_REGSHIFT (SMP_CPUID_PTRSHIFT + 2) |
| 180 | 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 | 178 | #define ASM_CPUID_MFC0 MFC0 |
| 187 | 179 | #define UASM_i_CPUID_MFC0 UASM_i_MFC0 |
| 188 | −#endif | |
| 189 | 180 | |
| 190 | 181 | #endif /* __KERNEL__ */ |
| 191 | 182 | #endif /* _ASM_THREAD_INFO_H */ |
| @@ -52,14 +52,11 @@ extern int (*perf_irq)(void); · 51 unmodified lines | ||
| 52 | 52 | */ |
| 53 | 53 | extern unsigned int __weak get_c0_compare_int(void); |
| 54 | 54 | extern int r4k_clockevent_init(void); |
| 55 | −extern int smtc_clockevent_init(void); | |
| 56 | 55 | extern int gic_clockevent_init(void); |
| 57 | 56 | |
| 58 | 57 | static inline int mips_clockevent_init(void) |
| 59 | 58 | { |
| 60 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 61 | − return smtc_clockevent_init(); | |
| 62 | −#elif defined(CONFIG_CEVT_GIC) | |
| 59 | +#if defined(CONFIG_CEVT_GIC) | |
| 63 | 60 | return (gic_clockevent_init() | r4k_clockevent_init()); |
| 64 | 61 | #elif defined(CONFIG_CEVT_R4K) |
| 65 | 62 | return r4k_clockevent_init(); |
| @@ -4,12 +4,16 @@ · 3 unmodified lines | ||
| 4 | 4 | * for more details. |
| 5 | 5 | * |
| 6 | 6 | * Copyright (C) 1998, 1999, 2003 by Ralf Baechle |
| 7 | + * Copyright (C) 2014 by Maciej W. Rozycki | |
| 7 | 8 | */ |
| 8 | 9 | #ifndef _ASM_TIMEX_H |
| 9 | 10 | #define _ASM_TIMEX_H |
| 10 | 11 | |
| 11 | 12 | #ifdef __KERNEL__ |
| 12 | 13 | |
| 14 | +#include <linux/compiler.h> | |
| 15 | + | |
| 16 | +#include <asm/cpu.h> | |
| 13 | 17 | #include <asm/cpu-features.h> |
| 14 | 18 | #include <asm/mipsregs.h> |
| 15 | 19 | #include <asm/cpu-type.h> |
| @@ -45,29 +49,54 @@ typedef unsigned int cycles_t; · 29 unmodified lines | ||
| 45 | 49 | * However for now the implementaton of this function doesn't get these |
| 46 | 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()) { | |
| 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; | |
| 54 | + int comp = (prid & PRID_COMP_MASK) != PRID_COMP_LEGACY; | |
| 57 | 55 | |
| 58 | − case CPU_R4000PC: | |
| 59 | − case CPU_R4000SC: | |
| 60 | − case CPU_R4000MC: | |
| 61 | − break; | |
| 56 | + if (__builtin_constant_p(cpu_has_counter) && !cpu_has_counter) | |
| 57 | + return 0; | |
| 58 | + else if (__builtin_constant_p(cpu_has_mips_r) && cpu_has_mips_r) | |
| 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: | |
| 64 | − if (cpu_has_counter) | |
| 65 | − return read_c0_count(); | |
| 66 | − break; | |
| 67 | − } | |
| 72 | +static inline cycles_t get_cycles(void) | |
| 73 | +{ | |
| 74 | + if (can_use_mips_counter(read_c0_prid())) | |
| 75 | + return read_c0_count(); | |
| 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 | 101 | #endif /* __KERNEL__ */ |
| 73 | 102 | |
| @@ -55,6 +55,9 @@ void ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c) · 54 unmodified lines | ||
| 55 | 55 | #define Ip_u2u1u3(op) \ |
| 56 | 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 | 61 | #define Ip_u3u1u2(op) \ |
| 59 | 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, \ · 13 unmodified lines | ||
| 74 | 77 | #define Ip_u1u2(op) \ |
| 75 | 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 | 83 | #define Ip_u1s2(op) \ |
| 78 | 84 | void ISAOPC(op)(u32 **buf, unsigned int a, signed int b) |
| 79 | 85 | |
| @@ -99,6 +105,7 @@ Ip_u2u1s3(_daddiu); · 19 unmodified lines | ||
| 99 | 105 | Ip_u3u1u2(_daddu); |
| 100 | 106 | Ip_u2u1msbu3(_dins); |
| 101 | 107 | Ip_u2u1msbu3(_dinsm); |
| 108 | +Ip_u1u2(_divu); | |
| 102 | 109 | Ip_u1u2u3(_dmfc0); |
| 103 | 110 | Ip_u1u2u3(_dmtc0); |
| 104 | 111 | Ip_u2u1u3(_drotr); |
| @@ -114,16 +121,22 @@ Ip_u2u1msbu3(_ext); · 9 unmodified lines | ||
| 114 | 121 | Ip_u2u1msbu3(_ins); |
| 115 | 122 | Ip_u1(_j); |
| 116 | 123 | Ip_u1(_jal); |
| 124 | +Ip_u2u1(_jalr); | |
| 117 | 125 | Ip_u1(_jr); |
| 126 | +Ip_u2s3u1(_lb); | |
| 118 | 127 | Ip_u2s3u1(_ld); |
| 119 | 128 | Ip_u3u1u2(_ldx); |
| 129 | +Ip_u2s3u1(_lh); | |
| 120 | 130 | Ip_u2s3u1(_ll); |
| 121 | 131 | Ip_u2s3u1(_lld); |
| 122 | 132 | Ip_u1s2(_lui); |
| 123 | 133 | Ip_u2s3u1(_lw); |
| 124 | 134 | Ip_u3u1u2(_lwx); |
| 125 | 135 | Ip_u1u2u3(_mfc0); |
| 136 | +Ip_u1(_mfhi); | |
| 137 | +Ip_u1(_mflo); | |
| 126 | 138 | Ip_u1u2u3(_mtc0); |
| 139 | +Ip_u3u1u2(_mul); | |
| 127 | 140 | Ip_u3u1u2(_or); |
| 128 | 141 | Ip_u2u1u3(_ori); |
| 129 | 142 | Ip_u2s3u1(_pref); |
| @@ -133,17 +146,25 @@ Ip_u2s3u1(_sc); · 3 unmodified lines | ||
| 133 | 146 | Ip_u2s3u1(_scd); |
| 134 | 147 | Ip_u2s3u1(_sd); |
| 135 | 148 | Ip_u2u1u3(_sll); |
| 149 | +Ip_u3u2u1(_sllv); | |
| 150 | +Ip_u2u1s3(_sltiu); | |
| 151 | +Ip_u3u1u2(_sltu); | |
| 136 | 152 | Ip_u2u1u3(_sra); |
| 137 | 153 | Ip_u2u1u3(_srl); |
| 154 | +Ip_u3u2u1(_srlv); | |
| 138 | 155 | Ip_u3u1u2(_subu); |
| 139 | 156 | Ip_u2s3u1(_sw); |
| 157 | +Ip_u1(_sync); | |
| 140 | 158 | Ip_u1(_syscall); |
| 141 | 159 | Ip_0(_tlbp); |
| 142 | 160 | Ip_0(_tlbr); |
| 143 | 161 | Ip_0(_tlbwi); |
| 144 | 162 | Ip_0(_tlbwr); |
| 163 | +Ip_u1(_wait); | |
| 164 | +Ip_u2u1(_wsbh); | |
| 145 | 165 | Ip_u3u1u2(_xor); |
| 146 | 166 | Ip_u2u1u3(_xori); |
| 167 | +Ip_u2u1(_yield); | |
| 147 | 168 | |
| 148 | 169 | |
| 149 | 170 | /* Handle labels. */ |
| @@ -264,6 +285,8 @@ void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg, · 114 unmodified lines | ||
| 264 | 285 | unsigned int bit, int lid); |
| 265 | 286 | void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg, |
| 266 | 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 | 290 | void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
| 268 | 291 | void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
| 269 | 292 | void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
| @@ -4,6 +4,7 @@ include include/uapi/asm-generic/Kbuild.asm · 3 unmodified lines | ||
| 4 | 4 | generic-y += auxvec.h |
| 5 | 5 | generic-y += ipcbuf.h |
| 6 | 6 | |
| 7 | +header-y += bitfield.h | |
| 7 | 8 | header-y += bitsperlong.h |
| 8 | 9 | header-y += break.h |
| 9 | 10 | header-y += byteorder.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 */ | |
| @@ -13,6 +13,8 @@ · 12 unmodified lines | ||
| 13 | 13 | #ifndef _UAPI_ASM_INST_H |
| 14 | 14 | #define _UAPI_ASM_INST_H |
| 15 | 15 | |
| 16 | +#include <asm/bitfield.h> | |
| 17 | + | |
| 16 | 18 | /* |
| 17 | 19 | * Major opcodes; before MIPS IV cop1x was called cop3. |
| 18 | 20 | */ |
| @@ -74,16 +76,17 @@ enum spec2_op { · 55 unmodified lines | ||
| 74 | 76 | enum spec3_op { |
| 75 | 77 | ext_op, dextm_op, dextu_op, dext_op, |
| 76 | 78 | ins_op, dinsm_op, dinsu_op, dins_op, |
| 77 | − lx_op = 0x0a, lwle_op = 0x19, | |
| 78 | − lwre_op = 0x1a, cachee_op = 0x1b, | |
| 79 | − sbe_op = 0x1c, she_op = 0x1d, | |
| 80 | − sce_op = 0x1e, swe_op = 0x1f, | |
| 81 | − bshfl_op = 0x20, swle_op = 0x21, | |
| 82 | − swre_op = 0x22, prefe_op = 0x23, | |
| 83 | − dbshfl_op = 0x24, lbue_op = 0x28, | |
| 84 | − lhue_op = 0x29, lbe_op = 0x2c, | |
| 85 | − lhe_op = 0x2d, lle_op = 0x2e, | |
| 86 | − lwe_op = 0x2f, rdhwr_op = 0x3b | |
| 79 | + yield_op = 0x09, lx_op = 0x0a, | |
| 80 | + lwle_op = 0x19, lwre_op = 0x1a, | |
| 81 | + cachee_op = 0x1b, sbe_op = 0x1c, | |
| 82 | + she_op = 0x1d, sce_op = 0x1e, | |
| 83 | + swe_op = 0x1f, bshfl_op = 0x20, | |
| 84 | + swle_op = 0x21, swre_op = 0x22, | |
| 85 | + prefe_op = 0x23, dbshfl_op = 0x24, | |
| 86 | + lbue_op = 0x28, lhue_op = 0x29, | |
| 87 | + lbe_op = 0x2c, lhe_op = 0x2d, | |
| 88 | + lle_op = 0x2e, lwe_op = 0x2f, | |
| 89 | + rdhwr_op = 0x3b | |
| 87 | 90 | }; |
| 88 | 91 | |
| 89 | 92 | /* |
| @@ -125,7 +128,8 @@ enum bcop_op { · 35 unmodified lines | ||
| 125 | 128 | enum cop0_coi_func { |
| 126 | 129 | tlbr_op = 0x01, tlbwi_op = 0x02, |
| 127 | 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 | /* |
| @@ -201,6 +205,16 @@ enum lx_func { · 69 unmodified lines | ||
| 201 | 205 | lbx_op = 0x16, |
| 202 | 206 | }; |
| 203 | 207 | |
| 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 | + | |
| 204 | 218 | /* |
| 205 | 219 | * (microMIPS) Major opcodes. |
| 206 | 220 | */ |
| @@ -244,17 +258,22 @@ enum mm_32i_minor_op { · 37 unmodified lines | ||
| 244 | 258 | enum mm_32a_minor_op { |
| 245 | 259 | mm_sll32_op = 0x000, |
| 246 | 260 | mm_ins_op = 0x00c, |
| 261 | + mm_sllv32_op = 0x010, | |
| 247 | 262 | mm_ext_op = 0x02c, |
| 248 | 263 | mm_pool32axf_op = 0x03c, |
| 249 | 264 | mm_srl32_op = 0x040, |
| 250 | 265 | mm_sra_op = 0x080, |
| 266 | + mm_srlv32_op = 0x090, | |
| 251 | 267 | mm_rotr_op = 0x0c0, |
| 252 | 268 | mm_lwxs_op = 0x118, |
| 253 | 269 | mm_addu32_op = 0x150, |
| 254 | 270 | mm_subu32_op = 0x1d0, |
| 271 | + mm_wsbh_op = 0x1ec, | |
| 272 | + mm_mul_op = 0x210, | |
| 255 | 273 | mm_and_op = 0x250, |
| 256 | 274 | mm_or32_op = 0x290, |
| 257 | 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 { · 33 unmodified lines | ||
| 294 | 313 | mm_mfc0_op = 0x003, |
| 295 | 314 | mm_mtc0_op = 0x00b, |
| 296 | 315 | mm_tlbp_op = 0x00d, |
| 316 | + mm_mfhi32_op = 0x035, | |
| 297 | 317 | mm_jalr_op = 0x03c, |
| 298 | 318 | mm_tlbr_op = 0x04d, |
| 319 | + mm_mflo32_op = 0x075, | |
| 299 | 320 | mm_jalrhb_op = 0x07c, |
| 300 | 321 | mm_tlbwi_op = 0x08d, |
| 301 | 322 | mm_tlbwr_op = 0x0cd, |
| 302 | 323 | mm_jalrs_op = 0x13c, |
| 303 | 324 | mm_jalrshb_op = 0x17c, |
| 325 | + mm_sync_op = 0x1ad, | |
| 304 | 326 | mm_syscall_op = 0x22d, |
| 327 | + mm_wait_op = 0x24d, | |
| 305 | 328 | mm_eret_op = 0x3cd, |
| 329 | + mm_divu_op = 0x5dc, | |
| 306 | 330 | }; |
| 307 | 331 | |
| 308 | 332 | /* |
| @@ -480,24 +504,6 @@ enum MIPS6e_i8_func { · 171 unmodified lines | ||
| 480 | 504 | */ |
| 481 | 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 | 507 | struct j_format { |
| 502 | 508 | __BITFIELD_FIELD(unsigned int opcode : 6, /* Jump format */ |
| 503 | 509 | __BITFIELD_FIELD(unsigned int target : 26, |
| @@ -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 */ | |
| @@ -14,9 +14,12 @@ · 13 unmodified lines | ||
| 14 | 14 | /* |
| 15 | 15 | * We don't use int-l64.h for the kernel anymore but still use it for |
| 16 | 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 | 21 | #ifndef __KERNEL__ |
| 19 | −# if _MIPS_SZLONG == 64 | |
| 22 | +# if _MIPS_SZLONG == 64 && !defined(__SANE_USERSPACE_TYPES__) | |
| 20 | 23 | # include <asm-generic/int-l64.h> |
| 21 | 24 | # else |
| 22 | 25 | # include <asm-generic/int-ll64.h> |
| @@ -17,7 +17,6 @@ endif · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o |
| 19 | 19 | obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o |
| 20 | −obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o | |
| 21 | 20 | obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o |
| 22 | 21 | obj-$(CONFIG_CEVT_GIC) += cevt-gic.o |
| 23 | 22 | obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o |
| @@ -42,7 +41,7 @@ obj-$(CONFIG_CPU_R4K_FPU) += r4k_fpu.o r4k_switch.o · 18 unmodified lines | ||
| 42 | 41 | obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o |
| 43 | 42 | obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o |
| 44 | 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 | 46 | obj-$(CONFIG_SMP) += smp.o |
| 48 | 47 | obj-$(CONFIG_SMP_UP) += smp-up.o |
| @@ -50,7 +49,6 @@ obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o · 1 unmodified line | ||
| 50 | 49 | |
| 51 | 50 | obj-$(CONFIG_MIPS_MT) += mips-mt.o |
| 52 | 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 | 52 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o |
| 55 | 53 | obj-$(CONFIG_MIPS_CMP) += smp-cmp.o |
| 56 | 54 | obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o |
| @@ -107,6 +105,9 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o · 50 unmodified lines | ||
| 107 | 105 | obj-$(CONFIG_MIPS_CM) += mips-cm.o |
| 108 | 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 | 112 | # DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not |
| 112 | 113 | # safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/mm.h> |
| 15 | 15 | #include <linux/kbuild.h> |
| 16 | 16 | #include <linux/suspend.h> |
| 17 | +#include <asm/pm.h> | |
| 17 | 18 | #include <asm/ptrace.h> |
| 18 | 19 | #include <asm/processor.h> |
| 19 | 20 | #include <asm/smp-cps.h> |
| @@ -64,9 +65,6 @@ void output_ptreg_defines(void) · 44 unmodified lines | ||
| 64 | 65 | OFFSET(PT_BVADDR, pt_regs, cp0_badvaddr); |
| 65 | 66 | OFFSET(PT_STATUS, pt_regs, cp0_status); |
| 66 | 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 | 68 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
| 71 | 69 | OFFSET(PT_MPL, pt_regs, mpl); |
| 72 | 70 | OFFSET(PT_MTP, pt_regs, mtp); |
| @@ -404,6 +402,20 @@ void output_pbe_defines(void) · 331 unmodified lines | ||
| 404 | 402 | } |
| 405 | 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 | 419 | void output_kvm_defines(void) |
| 408 | 420 | { |
| 409 | 421 | COMMENT(" KVM/MIPS Specfic offsets. "); |
| @@ -472,10 +484,14 @@ void output_kvm_defines(void) · 62 unmodified lines | ||
| 472 | 484 | void output_cps_defines(void) |
| 473 | 485 | { |
| 474 | 486 | COMMENT(" MIPS CPS offsets. "); |
| 475 | − OFFSET(BOOTCFG_CORE, boot_config, core); | |
| 476 | − OFFSET(BOOTCFG_VPE, boot_config, vpe); | |
| 477 | − OFFSET(BOOTCFG_PC, boot_config, pc); | |
| 478 | − OFFSET(BOOTCFG_SP, boot_config, sp); | |
| 479 | − OFFSET(BOOTCFG_GP, boot_config, gp); | |
| 487 | + | |
| 488 | + OFFSET(COREBOOTCFG_VPEMASK, core_boot_config, vpe_mask); | |
| 489 | + OFFSET(COREBOOTCFG_VPECONFIG, core_boot_config, vpe_config); | |
| 490 | + DEFINE(COREBOOTCFG_SIZE, sizeof(struct core_boot_config)); | |
| 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 | 497 | #endif |
| @@ -48,6 +48,202 @@ int __isa_exception_epc(struct pt_regs *regs) · 47 unmodified lines | ||
| 48 | 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 | 248 | * Compute return address and emulate branch in microMIPS mode after an |
| 53 | 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, · 312 unmodified lines | ||
| 366 | 562 | case cop1_op: |
| 367 | 563 | preempt_disable(); |
| 368 | 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 | 570 | else |
| 371 | 571 | fcr31 = current->thread.fpu.fcr31; |
| 372 | 572 | preempt_enable(); |
| @@ -26,7 +26,7 @@ static int gic_next_event(unsigned long delta, struct clock_event_device *evt) · 25 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | cnt = gic_read_count(); |
| 28 | 28 | cnt += (u64)delta; |
| 29 | − gic_write_compare(cnt); | |
| 29 | + gic_write_cpu_compare(cnt, cpumask_first(evt->cpumask)); | |
| 30 | 30 | res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0; |
| 31 | 31 | return res; |
| 32 | 32 | } |
| @@ -73,7 +73,8 @@ int gic_clockevent_init(void) · 40 unmodified lines | ||
| 73 | 73 | cd = &per_cpu(gic_clockevent_device, cpu); |
| 74 | 74 | |
| 75 | 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 | 79 | clockevent_set_clock(cd, gic_frequency); |
| 79 | 80 | |
| @@ -12,17 +12,10 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/smp.h> |
| 13 | 13 | #include <linux/irq.h> |
| 14 | 14 | |
| 15 | −#include <asm/smtc_ipi.h> | |
| 16 | 15 | #include <asm/time.h> |
| 17 | 16 | #include <asm/cevt-r4k.h> |
| 18 | 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 | 19 | static int mips_next_event(unsigned long delta, |
| 27 | 20 | struct clock_event_device *evt) |
| 28 | 21 | { |
| @@ -36,8 +29,6 @@ static int mips_next_event(unsigned long delta, · 7 unmodified lines | ||
| 36 | 29 | return res; |
| 37 | 30 | } |
| 38 | 31 | |
| 39 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 40 | − | |
| 41 | 32 | void mips_set_clock_mode(enum clock_event_mode mode, |
| 42 | 33 | struct clock_event_device *evt) |
| 43 | 34 | { |
| @@ -47,7 +38,6 @@ void mips_set_clock_mode(enum clock_event_mode mode, · 3 unmodified lines | ||
| 47 | 38 | DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); |
| 48 | 39 | int cp0_timer_irq_installed; |
| 49 | 40 | |
| 50 | −#ifndef CONFIG_MIPS_MT_SMTC | |
| 51 | 41 | irqreturn_t c0_compare_interrupt(int irq, void *dev_id) |
| 52 | 42 | { |
| 53 | 43 | const int r2 = cpu_has_mips_r2; |
| @@ -72,9 +62,6 @@ irqreturn_t c0_compare_interrupt(int irq, void *dev_id) · 18 unmodified lines | ||
| 72 | 62 | /* Clear Count/Compare Interrupt */ |
| 73 | 63 | write_c0_compare(read_c0_compare()); |
| 74 | 64 | cd = &per_cpu(mips_clockevent_device, cpu); |
| 75 | −#ifdef CONFIG_CEVT_GIC | |
| 76 | − if (!gic_present) | |
| 77 | −#endif | |
| 78 | 65 | cd->event_handler(cd); |
| 79 | 66 | } |
| 80 | 67 | |
| @@ -82,8 +69,6 @@ out: · 1 unmodified line | ||
| 82 | 69 | return IRQ_HANDLED; |
| 83 | 70 | } |
| 84 | 71 | |
| 85 | −#endif /* Not CONFIG_MIPS_MT_SMTC */ | |
| 86 | − | |
| 87 | 72 | struct irqaction c0_compare_irqaction = { |
| 88 | 73 | .handler = c0_compare_interrupt, |
| 89 | 74 | .flags = IRQF_PERCPU | IRQF_TIMER, |
| @@ -170,7 +155,6 @@ int c0_compare_int_usable(void) · 80 unmodified lines | ||
| 170 | 155 | return 1; |
| 171 | 156 | } |
| 172 | 157 | |
| 173 | −#ifndef CONFIG_MIPS_MT_SMTC | |
| 174 | 158 | int r4k_clockevent_init(void) |
| 175 | 159 | { |
| 176 | 160 | unsigned int cpu = smp_processor_id(); |
| @@ -195,7 +179,9 @@ int r4k_clockevent_init(void) · 18 unmodified lines | ||
| 195 | 179 | cd = &per_cpu(mips_clockevent_device, cpu); |
| 196 | 180 | |
| 197 | 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 | 186 | clockevent_set_clock(cd, mips_hpt_frequency); |
| 201 | 187 | |
| @@ -210,9 +196,6 @@ int r4k_clockevent_init(void) · 8 unmodified lines | ||
| 210 | 196 | cd->set_mode = mips_set_clock_mode; |
| 211 | 197 | cd->event_handler = mips_event_handler; |
| 212 | 198 | |
| 213 | −#ifdef CONFIG_CEVT_GIC | |
| 214 | − if (!gic_present) | |
| 215 | −#endif | |
| 216 | 199 | clockevents_register_device(cd); |
| 217 | 200 | |
| 218 | 201 | if (cp0_timer_irq_installed) |
| @@ -225,4 +208,3 @@ int r4k_clockevent_init(void) · 6 unmodified lines | ||
| 225 | 208 | return 0; |
| 226 | 209 | } |
| 227 | 210 | |
| 228 | −#endif /* Not CONFIG_MIPS_MT_SMTC */ | |
| @@ -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 | −} | |
| @@ -14,19 +14,43 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <asm/asmmacro.h> |
| 15 | 15 | #include <asm/cacheops.h> |
| 16 | 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 | 43 | .section .text.cps-vec |
| 21 | 44 | .balign 0x1000 |
| 22 | −.set noreorder | |
| 23 | 45 | |
| 24 | 46 | LEAF(mips_cps_core_entry) |
| 25 | 47 | /* |
| 26 | − * These first 8 bytes will be patched by cps_smp_setup to load the | |
| 27 | − * base address of the CM GCRs into register v1. | |
| 48 | + * These first 12 bytes will be patched by cps_smp_setup to load the | |
| 49 | + * base address of the CM GCRs into register v1 and the CCA to use into | |
| 50 | + * register s0. | |
| 28 | 51 | */ |
| 29 | 52 | .quad 0 |
| 53 | + .word 0 | |
| 30 | 54 | |
| 31 | 55 | /* Check whether we're here due to an NMI */ |
| 32 | 56 | mfc0 k0, CP0_STATUS |
| @@ -117,10 +141,11 @@ icache_done: · 84 unmodified lines | ||
| 117 | 141 | add a0, a0, t0 |
| 118 | 142 | dcache_done: |
| 119 | 143 | |
| 120 | − /* Set Kseg0 cacheable, coherent, write-back, write-allocate */ | |
| 144 | + /* Set Kseg0 CCA to that in s0 */ | |
| 121 | 145 | mfc0 t0, CP0_CONFIG |
| 122 | 146 | ori t0, 0x7 |
| 123 | − xori t0, 0x2 | |
| 147 | + xori t0, 0x7 | |
| 148 | + or t0, t0, s0 | |
| 124 | 149 | mtc0 t0, CP0_CONFIG |
| 125 | 150 | ehb |
| 126 | 151 | |
| @@ -134,21 +159,24 @@ dcache_done: · 7 unmodified lines | ||
| 134 | 159 | jr t0 |
| 135 | 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 | |
| 141 | − * if non-zero we should start that VPE and stop this one. For | |
| 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. | |
| 170 | + * Boot any other VPEs within this core that should be online, and | |
| 171 | + * deactivate this VPE if it should be offline. | |
| 145 | 172 | */ |
| 173 | + jal mips_cps_boot_vpes | |
| 174 | + nop | |
| 146 | 175 | |
| 147 | 176 | /* Off we go! */ |
| 148 | − la t0, mips_cps_bootcfg | |
| 149 | − lw t1, BOOTCFG_PC(t0) | |
| 150 | − lw gp, BOOTCFG_GP(t0) | |
| 151 | − lw sp, BOOTCFG_SP(t0) | |
| 177 | + lw t1, VPEBOOTCFG_PC(v0) | |
| 178 | + lw gp, VPEBOOTCFG_GP(v0) | |
| 179 | + lw sp, VPEBOOTCFG_SP(v0) | |
| 152 | 180 | jr t1 |
| 153 | 181 | nop |
| 154 | 182 | END(mips_cps_core_entry) |
| @@ -189,3 +217,271 @@ LEAF(excep_ejtag) · 34 unmodified lines | ||
| 189 | 217 | jr k0 |
| 190 | 218 | nop |
| 191 | 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 */ | |
| @@ -62,7 +62,7 @@ static inline void check_errata(void) · 61 unmodified lines | ||
| 62 | 62 | case CPU_34K: |
| 63 | 63 | /* |
| 64 | 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 | 66 | * making use of VPE1 will be responsable for that VPE. |
| 67 | 67 | */ |
| 68 | 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) · 354 unmodified lines | ||
| 423 | 423 | |
| 424 | 424 | #ifndef CONFIG_MIPS_CPS |
| 425 | 425 | if (cpu_has_mips_r2) { |
| 426 | − c->core = read_c0_ebase() & 0x3ff; | |
| 426 | + c->core = get_ebase_cpunum(); | |
| 427 | 427 | if (cpu_has_mipsmt) |
| 428 | 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) · 254 unmodified lines | ||
| 684 | 684 | */ |
| 685 | 685 | c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48; |
| 686 | 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 | 687 | case PRID_IMP_R8000: |
| 703 | 688 | c->cputype = CPU_R8000; |
| 704 | 689 | __cpu_name[cpu] = "RM8000"; |
| @@ -1041,6 +1026,7 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) · 336 unmodified lines | ||
| 1041 | 1026 | decode_configs(c); |
| 1042 | 1027 | /* JZRISC does not implement the CP0 counter. */ |
| 1043 | 1028 | c->options &= ~MIPS_CPU_COUNTER; |
| 1029 | + BUG_ON(!__builtin_constant_p(cpu_has_counter) || cpu_has_counter); | |
| 1044 | 1030 | switch (c->processor_id & PRID_IMP_MASK) { |
| 1045 | 1031 | case PRID_IMP_JZRISC: |
| 1046 | 1032 | c->cputype = CPU_JZRISC; |
| @@ -1074,6 +1060,7 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) · 27 unmodified lines | ||
| 1074 | 1060 | switch (c->processor_id & PRID_IMP_MASK) { |
| 1075 | 1061 | case PRID_IMP_NETLOGIC_XLP2XX: |
| 1076 | 1062 | case PRID_IMP_NETLOGIC_XLP9XX: |
| 1063 | + case PRID_IMP_NETLOGIC_XLP5XX: | |
| 1077 | 1064 | c->cputype = CPU_XLP; |
| 1078 | 1065 | __cpu_name[cpu] = "Broadcom XLPII"; |
| 1079 | 1066 | break; |
| @@ -16,9 +16,6 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <asm/isadep.h> |
| 17 | 17 | #include <asm/thread_info.h> |
| 18 | 18 | #include <asm/war.h> |
| 19 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 20 | −#include <asm/mipsmtregs.h> | |
| 21 | −#endif | |
| 22 | 19 | |
| 23 | 20 | #ifndef CONFIG_PREEMPT |
| 24 | 21 | #define resume_kernel restore_all |
| @@ -89,41 +86,6 @@ FEXPORT(syscall_exit) · 64 unmodified lines | ||
| 89 | 86 | bnez t0, syscall_exit_work |
| 90 | 87 | |
| 91 | 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 | 89 | .set noat |
| 128 | 90 | RESTORE_TEMP |
| 129 | 91 | RESTORE_AT |
| @@ -21,20 +21,6 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <asm/war.h> |
| 22 | 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 | 24 | __INIT |
| 39 | 25 | |
| 40 | 26 | /* |
| @@ -251,15 +237,6 @@ NESTED(except_vec_vi, 0, sp) · 210 unmodified lines | ||
| 251 | 237 | SAVE_AT |
| 252 | 238 | .set push |
| 253 | 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 | 240 | PTR_LA v1, except_vec_vi_handler |
| 264 | 241 | FEXPORT(except_vec_vi_lui) |
| 265 | 242 | lui v0, 0 /* Patched */ |
| @@ -277,37 +254,10 @@ EXPORT(except_vec_vi_end) · 11 unmodified lines | ||
| 277 | 254 | NESTED(except_vec_vi_handler, 0, sp) |
| 278 | 255 | SAVE_TEMP |
| 279 | 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 | 257 | CLI |
| 302 | 258 | #ifdef CONFIG_TRACE_IRQFLAGS |
| 303 | 259 | move s0, v0 |
| 304 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 305 | − move s1, a0 | |
| 306 | −#endif | |
| 307 | 260 | TRACE_IRQS_OFF |
| 308 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 309 | − move a0, s1 | |
| 310 | −#endif | |
| 311 | 261 | move v0, s0 |
| 312 | 262 | #endif |
| 313 | 263 | |
| @@ -496,9 +446,6 @@ NESTED(nmi_handler, PT_SIZE, sp) · 182 unmodified lines | ||
| 496 | 446 | |
| 497 | 447 | .align 5 |
| 498 | 448 | LEAF(handle_ri_rdhwr_vivt) |
| 499 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 500 | − PANIC_PIC("handle_ri_rdhwr_vivt called") | |
| 501 | −#else | |
| 502 | 449 | .set push |
| 503 | 450 | .set noat |
| 504 | 451 | .set noreorder |
| @@ -517,7 +464,6 @@ NESTED(nmi_handler, PT_SIZE, sp) · 12 unmodified lines | ||
| 517 | 464 | .set pop |
| 518 | 465 | bltz k1, handle_ri /* slow path */ |
| 519 | 466 | /* fall thru */ |
| 520 | −#endif | |
| 521 | 467 | END(handle_ri_rdhwr_vivt) |
| 522 | 468 | |
| 523 | 469 | LEAF(handle_ri_rdhwr) |
| @@ -35,33 +35,12 @@ · 34 unmodified lines | ||
| 35 | 35 | */ |
| 36 | 36 | .macro setup_c0_status set clr |
| 37 | 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 | 38 | mfc0 t0, CP0_STATUS |
| 59 | 39 | or t0, ST0_CU0|\set|0x1f|\clr |
| 60 | 40 | xor t0, 0x1f|\clr |
| 61 | 41 | mtc0 t0, CP0_STATUS |
| 62 | 42 | .set noreorder |
| 63 | 43 | sll zero,3 # ehb |
| 64 | −#endif | |
| 65 | 44 | .set pop |
| 66 | 45 | .endm |
| 67 | 46 | |
| @@ -115,24 +94,6 @@ NESTED(kernel_entry, 16, sp) # kernel entry point · 47 unmodified lines | ||
| 115 | 94 | jr t0 |
| 116 | 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 | 97 | PTR_LA t0, __bss_start # clear .bss |
| 137 | 98 | LONG_S zero, (t0) |
| 138 | 99 | PTR_LA t1, __bss_stop - LONGSIZE |
| @@ -164,25 +125,8 @@ NESTED(kernel_entry, 16, sp) # kernel entry point · 25 unmodified lines | ||
| 164 | 125 | * function after setting up the stack and gp registers. |
| 165 | 126 | */ |
| 166 | 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 | 128 | smp_slave_setup |
| 179 | 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 | 130 | j start_secondary |
| 187 | 131 | END(smp_bootstrap) |
| 188 | 132 | #endif /* CONFIG_SMP */ |
| @@ -42,9 +42,6 @@ static struct irq_chip i8259A_chip = { · 41 unmodified lines | ||
| 42 | 42 | .irq_disable = disable_8259A_irq, |
| 43 | 43 | .irq_unmask = enable_8259A_irq, |
| 44 | 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: · 129 unmodified lines | ||
| 180 | 177 | outb(cached_master_mask, PIC_MASTER_IMR); |
| 181 | 178 | outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ |
| 182 | 179 | } |
| 183 | − smtc_im_ack_irq(irq); | |
| 184 | 180 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
| 185 | 181 | return; |
| 186 | 182 | |
| @@ -224,29 +224,26 @@ void __init check_wait(void) · 223 unmodified lines | ||
| 224 | 224 | cpu_wait = r4k_wait; |
| 225 | 225 | */ |
| 226 | 226 | break; |
| 227 | − case CPU_RM9000: | |
| 228 | − if ((c->processor_id & 0x00ff) >= 0x40) | |
| 229 | − cpu_wait = r4k_wait; | |
| 230 | − break; | |
| 231 | 227 | default: |
| 232 | 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 | 232 | void arch_cpu_idle(void) |
| 246 | 233 | { |
| 247 | − smtc_idle_hook(); | |
| 248 | 234 | if (cpu_wait) |
| 249 | 235 | cpu_wait(); |
| 250 | 236 | else |
| 251 | 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 | |
| @@ -54,6 +54,21 @@ void gic_write_compare(cycle_t cnt) · 53 unmodified lines | ||
| 54 | 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 | 72 | cycle_t gic_read_compare(void) |
| 58 | 73 | { |
| 59 | 74 | unsigned int hi, lo; |
| @@ -53,13 +53,9 @@ static inline void unmask_msc_irq(struct irq_data *d) · 52 unmodified lines | ||
| 53 | 53 | */ |
| 54 | 54 | static void level_mask_and_ack_msc_irq(struct irq_data *d) |
| 55 | 55 | { |
| 56 | − unsigned int irq = d->irq; | |
| 57 | − | |
| 58 | 56 | mask_msc_irq(d); |
| 59 | 57 | if (!cpu_has_veic) |
| 60 | 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) · 12 unmodified lines | ||
| 78 | 74 | MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); |
| 79 | 75 | MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); |
| 80 | 76 | } |
| 81 | − smtc_im_ack_irq(irq); | |
| 82 | 77 | } |
| 83 | 78 | |
| 84 | 79 | /* |
| @@ -73,7 +73,6 @@ void free_irqno(unsigned int irq) · 72 unmodified lines | ||
| 73 | 73 | */ |
| 74 | 74 | void ack_bad_irq(unsigned int irq) |
| 75 | 75 | { |
| 76 | − smtc_im_ack_irq(irq); | |
| 77 | 76 | printk("unexpected IRQ # %d\n", irq); |
| 78 | 77 | } |
| 79 | 78 | |
| @@ -142,23 +141,7 @@ void __irq_entry do_IRQ(unsigned int irq) · 62 unmodified lines | ||
| 142 | 141 | { |
| 143 | 142 | irq_enter(); |
| 144 | 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 | 144 | generic_handle_irq(irq); |
| 161 | 145 | irq_exit(); |
| 162 | 146 | } |
| 163 | 147 | |
| 164 | −#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | |
| @@ -9,12 +9,18 @@ · 8 unmodified lines | ||
| 9 | 9 | */ |
| 10 | 10 | |
| 11 | 11 | #include <linux/errno.h> |
| 12 | +#include <linux/percpu.h> | |
| 13 | +#include <linux/spinlock.h> | |
| 12 | 14 | |
| 13 | 15 | #include <asm/mips-cm.h> |
| 14 | 16 | #include <asm/mips-cpc.h> |
| 15 | 17 | |
| 16 | 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 | 24 | phys_t __weak mips_cpc_phys_base(void) |
| 19 | 25 | { |
| 20 | 26 | u32 cpc_base; |
| @@ -39,6 +45,10 @@ phys_t __weak mips_cpc_phys_base(void) · 18 unmodified lines | ||
| 39 | 45 | int mips_cpc_probe(void) |
| 40 | 46 | { |
| 41 | 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 | 53 | addr = mips_cpc_phys_base(); |
| 44 | 54 | if (!addr) |
| @@ -50,3 +60,21 @@ int mips_cpc_probe(void) · 5 unmodified lines | ||
| 50 | 60 | |
| 51 | 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 | +} | |
| @@ -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 | 3 | * Copyright (C) 2005 Mips Technologies, Inc |
| 4 | 4 | */ |
| 5 | 5 | #include <linux/cpu.h> |
| @@ -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 | 3 | * Copyright (C) 2005 Mips Technologies, Inc |
| 4 | 4 | */ |
| 5 | 5 | |
| @@ -57,9 +57,6 @@ void mips_mt_regdump(unsigned long mvpctl) · 51 unmodified lines | ||
| 57 | 57 | int tc; |
| 58 | 58 | unsigned long haltval; |
| 59 | 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 | 61 | local_irq_save(flags); |
| 65 | 62 | vpflags = dvpe(); |
| @@ -116,9 +113,6 @@ void mips_mt_regdump(unsigned long mvpctl) · 50 unmodified lines | ||
| 116 | 113 | if (!haltval) |
| 117 | 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 | 116 | printk("===========================\n"); |
| 123 | 117 | evpe(vpflags); |
| 124 | 118 | local_irq_restore(flags); |
| @@ -295,21 +289,11 @@ void mips_mt_set_cpuoptions(void) · 170 unmodified lines | ||
| 295 | 289 | |
| 296 | 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 | 292 | /* FILL IN VSMP and AP/SP VERSIONS HERE */ |
| 304 | 293 | } |
| 305 | 294 | |
| 306 | 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 | 297 | /* FILL IN VSMP and AP/SP VERSIONS HERE */ |
| 314 | 298 | } |
| 315 | 299 | |
| @@ -10,24 +10,12 @@ · 9 unmodified lines | ||
| 10 | 10 | * Copyright (C) 2000 MIPS Technologies, Inc. |
| 11 | 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 | 20 | * task_struct *resume(task_struct *prev, task_struct *next, |
| 33 | 21 | * struct thread_info *next_ti, int usedfpu) |
| @@ -40,6 +28,61 @@ · 6 unmodified lines | ||
| 40 | 28 | cpu_save_nonscratch a0 |
| 41 | 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 | 86 | #if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 |
| 44 | 87 | /* Check if we need to store CVMSEG state */ |
| 45 | 88 | mfc0 t0, $11,7 /* CvmMemCtl */ |
| @@ -85,12 +128,7 @@ · 39 unmodified lines | ||
| 85 | 128 | move $28, a2 |
| 86 | 129 | cpu_restore_nonscratch a1 |
| 87 | 130 | |
| 88 | −#if (_THREAD_SIZE - 32) < 0x8000 | |
| 89 | − PTR_ADDIU t0, $28, _THREAD_SIZE - 32 | |
| 90 | −#else | |
| 91 | − PTR_LI t0, _THREAD_SIZE - 32 | |
| 92 | − PTR_ADDU t0, $28 | |
| 93 | −#endif | |
| 131 | + PTR_ADDU t0, $28, _THREAD_SIZE - 32 | |
| 94 | 132 | set_saved_sp t0, t1, t2 |
| 95 | 133 | |
| 96 | 134 | mfc0 t1, CP0_STATUS /* Do we really need this? */ |
| @@ -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); | |
| @@ -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); | |
| @@ -140,13 +140,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, · 139 unmodified lines | ||
| 140 | 140 | */ |
| 141 | 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 | 143 | clear_tsk_thread_flag(p, TIF_USEDFPU); |
| 151 | 144 | |
| 152 | 145 | #ifdef CONFIG_MIPS_MT_FPAFF |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | */ |
| 29 | 29 | #define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS) |
| 30 | 30 | |
| 31 | +#ifndef USE_ALTERNATE_RESUME_IMPL | |
| 31 | 32 | /* |
| 32 | 33 | * task_struct *resume(task_struct *prev, task_struct *next, |
| 33 | 34 | * struct thread_info *next_ti, s32 fp_save) |
| @@ -87,18 +88,6 @@ · 53 unmodified lines | ||
| 87 | 88 | |
| 88 | 89 | PTR_ADDU t0, $28, _THREAD_SIZE - 32 |
| 89 | 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 | 91 | mfc0 t1, CP0_STATUS /* Do we really need this? */ |
| 103 | 92 | li a3, 0xff01 |
| 104 | 93 | and t1, a3 |
| @@ -107,22 +96,12 @@ · 2 unmodified lines | ||
| 107 | 96 | and a2, a3 |
| 108 | 97 | or a2, t1 |
| 109 | 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 | 99 | move v0, a0 |
| 123 | 100 | jr ra |
| 124 | 101 | END(resume) |
| 125 | 102 | |
| 103 | +#endif /* USE_ALTERNATE_RESUME_IMPL */ | |
| 104 | + | |
| 126 | 105 | /* |
| 127 | 106 | * Save a thread's fp context. |
| 128 | 107 | */ |
| @@ -176,19 +155,10 @@ LEAF(_restore_msa) · 47 unmodified lines | ||
| 176 | 155 | #define FPU_DEFAULT 0x00000000 |
| 177 | 156 | |
| 178 | 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 | 158 | mfc0 t0, CP0_STATUS |
| 188 | 159 | li t1, ST0_CU1 |
| 189 | 160 | or t0, t1 |
| 190 | 161 | mtc0 t0, CP0_STATUS |
| 191 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 192 | 162 | enable_fpu_hazard |
| 193 | 163 | |
| 194 | 164 | li t1, FPU_DEFAULT |
| @@ -36,7 +36,6 @@ static irqreturn_t rtlx_interrupt(int irq, void *dev_id) · 35 unmodified lines | ||
| 36 | 36 | unsigned long flags; |
| 37 | 37 | int i; |
| 38 | 38 | |
| 39 | − /* Ought not to be strictly necessary for SMTC builds */ | |
| 40 | 39 | local_irq_save(flags); |
| 41 | 40 | vpeflags = dvpe(); |
| 42 | 41 | set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ); |
| @@ -280,13 +280,6 @@ static void bmips_smp_finish(void) · 279 unmodified lines | ||
| 280 | 280 | irq_enable_hazard(); |
| 281 | 281 | } |
| 282 | 282 | |
| 283 | −/* | |
| 284 | − * Runs on CPU0 after all CPUs have been booted | |
| 285 | − */ | |
| 286 | −static void bmips_cpus_done(void) | |
| 287 | −{ | |
| 288 | −} | |
| 289 | − | |
| 290 | 283 | /* |
| 291 | 284 | * BMIPS5000 raceless IPIs |
| 292 | 285 | * |
| @@ -434,7 +427,6 @@ struct plat_smp_ops bmips43xx_smp_ops = { · 141 unmodified lines | ||
| 434 | 427 | .boot_secondary = bmips_boot_secondary, |
| 435 | 428 | .smp_finish = bmips_smp_finish, |
| 436 | 429 | .init_secondary = bmips_init_secondary, |
| 437 | − .cpus_done = bmips_cpus_done, | |
| 438 | 430 | .send_ipi_single = bmips43xx_send_ipi_single, |
| 439 | 431 | .send_ipi_mask = bmips43xx_send_ipi_mask, |
| 440 | 432 | #ifdef CONFIG_HOTPLUG_CPU |
| @@ -449,7 +441,6 @@ struct plat_smp_ops bmips5000_smp_ops = { · 8 unmodified lines | ||
| 449 | 441 | .boot_secondary = bmips_boot_secondary, |
| 450 | 442 | .smp_finish = bmips_smp_finish, |
| 451 | 443 | .init_secondary = bmips_init_secondary, |
| 452 | − .cpus_done = bmips_cpus_done, | |
| 453 | 444 | .send_ipi_single = bmips5000_send_ipi_single, |
| 454 | 445 | .send_ipi_mask = bmips5000_send_ipi_mask, |
| 455 | 446 | #ifdef CONFIG_HOTPLUG_CPU |
| @@ -49,14 +49,11 @@ static void cmp_init_secondary(void) · 48 unmodified lines | ||
| 49 | 49 | |
| 50 | 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 | 53 | if (cpu_has_mipsmt) |
| 54 | 54 | c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & |
| 55 | 55 | TCBIND_CURVPE; |
| 56 | 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 | 59 | static void cmp_smp_finish(void) |
| @@ -75,11 +72,6 @@ static void cmp_smp_finish(void) · 12 unmodified lines | ||
| 75 | 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 | 76 | * Setup the PC, SP, and GP of a secondary processor and start it running |
| 85 | 77 | * smp_bootstrap is the place to resume from |
| @@ -135,10 +127,6 @@ void __init cmp_smp_setup(void) · 49 unmodified lines | ||
| 135 | 127 | unsigned int mvpconf0 = read_c0_mvpconf0(); |
| 136 | 128 | |
| 137 | 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 | 130 | #endif |
| 143 | 131 | smp_num_siblings = nvpe; |
| 144 | 132 | } |
| @@ -165,7 +153,6 @@ struct plat_smp_ops cmp_smp_ops = { · 20 unmodified lines | ||
| 165 | 153 | .send_ipi_mask = gic_send_ipi_mask, |
| 166 | 154 | .init_secondary = cmp_init_secondary, |
| 167 | 155 | .smp_finish = cmp_smp_finish, |
| 168 | − .cpus_done = cmp_cpus_done, | |
| 169 | 156 | .boot_secondary = cmp_boot_secondary, |
| 170 | 157 | .smp_setup = cmp_smp_setup, |
| 171 | 158 | .prepare_cpus = cmp_prepare_cpus, |
| @@ -20,104 +20,43 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <asm/mips-cpc.h> |
| 21 | 21 | #include <asm/mips_mt.h> |
| 22 | 22 | #include <asm/mipsregs.h> |
| 23 | +#include <asm/pm-cps.h> | |
| 23 | 24 | #include <asm/smp-cps.h> |
| 24 | 25 | #include <asm/time.h> |
| 25 | 26 | #include <asm/uasm.h> |
| 26 | 27 | |
| 27 | 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 | − u32 mvpconf0, vpeconf0, vpecontrol, tcstatus, tcbind, status; | |
| 34 | + unsigned cfg; | |
| 35 | 35 | |
| 36 | − if (!cpu_has_mipsmt) | |
| 37 | − return; | |
| 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 | − } | |
| 36 | + if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) | |
| 37 | + return 1; | |
| 95 | 38 | |
| 96 | − /* Leave VPE configuration state */ | |
| 97 | − clear_c0_mvpcontrol(MVPCONTROL_VPC); | |
| 39 | + write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF); | |
| 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 | 44 | static void __init cps_smp_setup(void) |
| 101 | 45 | { |
| 102 | 46 | unsigned int ncores, nvpes, core_vpes; |
| 103 | 47 | int c, v; |
| 104 | − u32 core_cfg, *entry_code; | |
| 105 | 48 | |
| 106 | 49 | /* Detect & record VPE topology */ |
| 107 | 50 | ncores = mips_cm_numcores(); |
| 108 | 51 | pr_info("VPE topology "); |
| 109 | 52 | for (c = nvpes = 0; c < ncores; c++) { |
| 110 | − if (cpu_has_mipsmt && config_enabled(CONFIG_MIPS_MT_SMP)) { | |
| 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 | − | |
| 53 | + core_vpes = core_vpe_count(c); | |
| 119 | 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 | 60 | for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) { |
| 122 | 61 | cpu_data[nvpes + v].core = c; |
| 123 | 62 | #ifdef CONFIG_MIPS_MT_SMP |
| @@ -137,19 +76,14 @@ static void __init cps_smp_setup(void) · 13 unmodified lines | ||
| 137 | 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 | 82 | /* Core 0 is powered up (we're running on it) */ |
| 141 | 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 | 85 | /* Initialise core 0 */ |
| 148 | − init_core(); | |
| 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); | |
| 86 | + mips_cps_core_init(); | |
| 153 | 87 | |
| 154 | 88 | /* Make core 0 coherent with everything */ |
| 155 | 89 | write_gcr_cl_coherence(0xff); |
| @@ -157,15 +91,99 @@ static void __init cps_smp_setup(void) · 1 unmodified line | ||
| 157 | 91 | |
| 158 | 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 | 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 | 183 | u32 access; |
| 166 | 184 | |
| 167 | 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 | 188 | /* Set its reset vector */ |
| 171 | 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) · 3 unmodified lines | ||
| 175 | 193 | |
| 176 | 194 | /* Ensure the core can access the GCRs */ |
| 177 | 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 | 197 | write_gcr_access(access); |
| 180 | 198 | |
| 181 | − /* Copy cfg */ | |
| 182 | − mips_cps_bootcfg = *cfg; | |
| 183 | − | |
| 184 | 199 | if (mips_cpc_present()) { |
| 185 | − /* Select the appropriate core */ | |
| 186 | − write_cpc_cl_other(cfg->core << CPC_Cx_OTHER_CORENUM_SHF); | |
| 187 | − | |
| 188 | 200 | /* Reset the core */ |
| 201 | + mips_cpc_lock_other(core); | |
| 189 | 202 | write_cpc_co_cmd(CPC_Cx_CMD_RESET); |
| 203 | + mips_cpc_unlock_other(); | |
| 190 | 204 | } else { |
| 191 | 205 | /* Take the core out of reset */ |
| 192 | 206 | write_gcr_co_reset_release(0); |
| 193 | 207 | } |
| 194 | 208 | |
| 195 | 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; | |
| 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); | |
| 215 | + mips_cps_boot_vpes(); | |
| 236 | 216 | } |
| 237 | 217 | |
| 238 | 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 | 224 | unsigned int remote; |
| 242 | 225 | int err; |
| 243 | 226 | |
| 244 | − cfg.core = cpu_data[cpu].core; | |
| 245 | − cfg.vpe = cpu_vpe_id(&cpu_data[cpu]); | |
| 246 | − cfg.pc = (unsigned long)&smp_bootstrap; | |
| 247 | − cfg.sp = __KSTK_TOS(idle); | |
| 248 | − cfg.gp = (unsigned long)task_thread_info(idle); | |
| 227 | + vpe_cfg->pc = (unsigned long)&smp_bootstrap; | |
| 228 | + vpe_cfg->sp = __KSTK_TOS(idle); | |
| 229 | + vpe_cfg->gp = (unsigned long)task_thread_info(idle); | |
| 230 | + | |
| 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 | 236 | /* Boot a VPE on a powered down core */ |
| 252 | − boot_core(&cfg); | |
| 253 | − return; | |
| 237 | + boot_core(core); | |
| 238 | + goto out; | |
| 254 | 239 | } |
| 255 | 240 | |
| 256 | − if (cfg.core != current_cpu_data.core) { | |
| 241 | + if (core != current_cpu_data.core) { | |
| 257 | 242 | /* Boot a VPE on another powered up core */ |
| 258 | 243 | for (remote = 0; remote < NR_CPUS; remote++) { |
| 259 | − if (cpu_data[remote].core != cfg.core) | |
| 244 | + if (cpu_data[remote].core != core) | |
| 260 | 245 | continue; |
| 261 | 246 | if (cpu_online(remote)) |
| 262 | 247 | break; |
| 263 | 248 | } |
| 264 | 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 | 253 | if (err) |
| 268 | 254 | panic("Failed to call remote CPU\n"); |
| 269 | − return; | |
| 255 | + goto out; | |
| 270 | 256 | } |
| 271 | 257 | |
| 272 | 258 | BUG_ON(!cpu_has_mipsmt); |
| 273 | 259 | |
| 274 | 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 | 266 | static void cps_init_secondary(void) |
| @@ -281,10 +269,6 @@ static void cps_init_secondary(void) · 2 unmodified lines | ||
| 281 | 269 | if (cpu_has_mipsmt) |
| 282 | 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 | 272 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | |
| 289 | 273 | STATUSF_IP6 | STATUSF_IP7); |
| 290 | 274 | } |
| @@ -302,10 +286,148 @@ static void cps_smp_finish(void) · 11 unmodified lines | ||
| 302 | 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 | 431 | static struct plat_smp_ops cps_smp_ops = { |
| 310 | 432 | .smp_setup = cps_smp_setup, |
| 311 | 433 | .prepare_cpus = cps_prepare_cpus, |
| @@ -314,9 +436,18 @@ static struct plat_smp_ops cps_smp_ops = { · 2 unmodified lines | ||
| 314 | 436 | .smp_finish = cps_smp_finish, |
| 315 | 437 | .send_ipi_single = gic_send_ipi_single, |
| 316 | 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 | 451 | int register_cps_smp_ops(void) |
| 321 | 452 | { |
| 322 | 453 | if (!mips_cm_present()) { |
| @@ -15,12 +15,14 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <linux/printk.h> |
| 16 | 16 | |
| 17 | 17 | #include <asm/gic.h> |
| 18 | +#include <asm/mips-cpc.h> | |
| 18 | 19 | #include <asm/smp-ops.h> |
| 19 | 20 | |
| 20 | 21 | void gic_send_ipi_single(int cpu, unsigned int action) |
| 21 | 22 | { |
| 22 | 23 | unsigned long flags; |
| 23 | 24 | unsigned int intr; |
| 25 | + unsigned int core = cpu_data[cpu].core; | |
| 24 | 26 | |
| 25 | 27 | pr_debug("CPU%d: %s cpu %d action %u status %08x\n", |
| 26 | 28 | smp_processor_id(), __func__, cpu, action, read_c0_status()); |
| @@ -41,6 +43,15 @@ void gic_send_ipi_single(int cpu, unsigned int action) · 14 unmodified lines | ||
| 41 | 43 | } |
| 42 | 44 | |
| 43 | 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 | 55 | local_irq_restore(flags); |
| 45 | 56 | } |
| 46 | 57 | |
| @@ -183,10 +183,6 @@ static void vsmp_smp_finish(void) · 182 unmodified lines | ||
| 183 | 183 | local_irq_enable(); |
| 184 | 184 | } |
| 185 | 185 | |
| 186 | −static void vsmp_cpus_done(void) | |
| 187 | −{ | |
| 188 | −} | |
| 189 | − | |
| 190 | 186 | /* |
| 191 | 187 | * Setup the PC, SP, and GP of a secondary processor and start it |
| 192 | 188 | * running! |
| @@ -287,7 +283,6 @@ struct plat_smp_ops vsmp_smp_ops = { · 94 unmodified lines | ||
| 287 | 283 | .send_ipi_mask = vsmp_send_ipi_mask, |
| 288 | 284 | .init_secondary = vsmp_init_secondary, |
| 289 | 285 | .smp_finish = vsmp_smp_finish, |
| 290 | − .cpus_done = vsmp_cpus_done, | |
| 291 | 286 | .boot_secondary = vsmp_boot_secondary, |
| 292 | 287 | .smp_setup = vsmp_smp_setup, |
| 293 | 288 | .prepare_cpus = vsmp_prepare_cpus, |
| @@ -36,11 +36,6 @@ static void up_smp_finish(void) · 35 unmodified lines | ||
| 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 | 40 | * Firmware CPU startup hook |
| 46 | 41 | */ |
| @@ -73,7 +68,6 @@ struct plat_smp_ops up_smp_ops = { · 26 unmodified lines | ||
| 73 | 68 | .send_ipi_mask = up_send_ipi_mask, |
| 74 | 69 | .init_secondary = up_init_secondary, |
| 75 | 70 | .smp_finish = up_smp_finish, |
| 76 | − .cpus_done = up_cpus_done, | |
| 77 | 71 | .boot_secondary = up_boot_secondary, |
| 78 | 72 | .smp_setup = up_smp_setup, |
| 79 | 73 | .prepare_cpus = up_prepare_cpus, |
| @@ -43,10 +43,6 @@ · 42 unmodified lines | ||
| 43 | 43 | #include <asm/time.h> |
| 44 | 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 | 46 | volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ |
| 51 | 47 | |
| 52 | 48 | int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ |
| @@ -66,6 +62,8 @@ EXPORT_SYMBOL(cpu_sibling_map); · 13 unmodified lines | ||
| 66 | 62 | /* representing cpus for which sibling maps can be computed */ |
| 67 | 63 | static cpumask_t cpu_sibling_setup_map; |
| 68 | 64 | |
| 65 | +cpumask_t cpu_coherent_mask; | |
| 66 | + | |
| 69 | 67 | static inline void set_cpu_sibling_map(int cpu) |
| 70 | 68 | { |
| 71 | 69 | int i; |
| @@ -102,12 +100,6 @@ asmlinkage void start_secondary(void) · 30 unmodified lines | ||
| 102 | 100 | { |
| 103 | 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 | 103 | cpu_probe(); |
| 112 | 104 | cpu_report(); |
| 113 | 105 | per_cpu_trap_init(false); |
| @@ -124,6 +116,7 @@ asmlinkage void start_secondary(void) · 10 unmodified lines | ||
| 124 | 116 | cpu = smp_processor_id(); |
| 125 | 117 | cpu_data[cpu].udelay_val = loops_per_jiffy; |
| 126 | 118 | |
| 119 | + cpu_set(cpu, cpu_coherent_mask); | |
| 127 | 120 | notify_cpu_starting(cpu); |
| 128 | 121 | |
| 129 | 122 | set_cpu_online(cpu, true); |
| @@ -173,7 +166,6 @@ void smp_send_stop(void) · 43 unmodified lines | ||
| 173 | 166 | |
| 174 | 167 | void __init smp_cpus_done(unsigned int max_cpus) |
| 175 | 168 | { |
| 176 | − mp_ops->cpus_done(); | |
| 177 | 169 | } |
| 178 | 170 | |
| 179 | 171 | /* called from main before smp_init() */ |
| @@ -186,6 +178,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) · 6 unmodified lines | ||
| 186 | 178 | #ifndef CONFIG_HOTPLUG_CPU |
| 187 | 179 | init_cpu_present(cpu_possible_mask); |
| 188 | 180 | #endif |
| 181 | + cpumask_copy(&cpu_coherent_mask, cpu_possible_mask); | |
| 189 | 182 | } |
| 190 | 183 | |
| 191 | 184 | /* preload SMP state for boot cpu */ |
| @@ -238,13 +231,10 @@ static void flush_tlb_mm_ipi(void *mm) · 46 unmodified lines | ||
| 238 | 231 | * o collapses to normal function call on UP kernels |
| 239 | 232 | * o collapses to normal function call on systems with a single shared |
| 240 | 233 | * primary cache. |
| 241 | − * o CONFIG_MIPS_MT_SMTC currently implies there is only one physical core. | |
| 242 | 234 | */ |
| 243 | 235 | static inline void smp_on_other_tlbs(void (*func) (void *info), void *info) |
| 244 | 236 | { |
| 245 | −#ifndef CONFIG_MIPS_MT_SMTC | |
| 246 | 237 | smp_call_function(func, info, 1); |
| 247 | −#endif | |
| 248 | 238 | } |
| 249 | 239 | |
| 250 | 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 *)) · 153 unmodified lines | ||
| 404 | 394 | } |
| 405 | 395 | EXPORT_SYMBOL(dump_send_ipi); |
| 406 | 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 */ | |
| @@ -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) | |
| @@ -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); | |
| @@ -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 | −} | |
| @@ -6,8 +6,6 @@ · 5 unmodified lines | ||
| 6 | 6 | * not have done anything significant (but they may have had interrupts |
| 7 | 7 | * enabled briefly - prom_smp_finish() should not be responsible for enabling |
| 8 | 8 | * interrupts...) |
| 9 | − * | |
| 10 | − * FIXME: broken for SMTC | |
| 11 | 9 | */ |
| 12 | 10 | |
| 13 | 11 | #include <linux/kernel.h> |
| @@ -33,14 +31,6 @@ void synchronise_count_master(int cpu) · 19 unmodified lines | ||
| 33 | 31 | unsigned long flags; |
| 34 | 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 | 34 | printk(KERN_INFO "Synchronize counters for CPU %u: ", cpu); |
| 45 | 35 | |
| 46 | 36 | local_irq_save(flags); |
| @@ -110,14 +100,6 @@ void synchronise_count_slave(int cpu) · 63 unmodified lines | ||
| 110 | 100 | int i; |
| 111 | 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 | 104 | * Not every cpu is online at the time this gets called, |
| 123 | 105 | * so we first wait for the master to say everyone is ready |
| @@ -26,7 +26,6 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <asm/cpu-features.h> |
| 27 | 27 | #include <asm/cpu-type.h> |
| 28 | 28 | #include <asm/div64.h> |
| 29 | −#include <asm/smtc_ipi.h> | |
| 30 | 29 | #include <asm/time.h> |
| 31 | 30 | |
| 32 | 31 | /* |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <linux/bug.h> |
| 16 | 16 | #include <linux/compiler.h> |
| 17 | 17 | #include <linux/context_tracking.h> |
| 18 | +#include <linux/cpu_pm.h> | |
| 18 | 19 | #include <linux/kexec.h> |
| 19 | 20 | #include <linux/init.h> |
| 20 | 21 | #include <linux/kernel.h> |
| @@ -370,9 +371,6 @@ void __noreturn die(const char *str, struct pt_regs *regs) · 349 unmodified lines | ||
| 370 | 371 | { |
| 371 | 372 | static int die_counter; |
| 372 | 373 | int sig = SIGSEGV; |
| 373 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 374 | − unsigned long dvpret; | |
| 375 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 376 | 374 | |
| 377 | 375 | oops_enter(); |
| 378 | 376 | |
| @@ -382,13 +380,7 @@ void __noreturn die(const char *str, struct pt_regs *regs) · 3 unmodified lines | ||
| 382 | 380 | |
| 383 | 381 | console_verbose(); |
| 384 | 382 | raw_spin_lock_irq(&die_lock); |
| 385 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 386 | − dvpret = dvpe(); | |
| 387 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 388 | 383 | bust_spinlocks(1); |
| 389 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 390 | − mips_mt_regdump(dvpret); | |
| 391 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 392 | 384 | |
| 393 | 385 | printk("%s[#%d]:\n", str, ++die_counter); |
| 394 | 386 | show_registers(regs); |
| @@ -712,10 +704,12 @@ int process_fpemu_return(int sig, void __user *fault_addr) · 317 unmodified lines | ||
| 712 | 704 | si.si_addr = fault_addr; |
| 713 | 705 | si.si_signo = sig; |
| 714 | 706 | if (sig == SIGSEGV) { |
| 707 | + down_read(¤t->mm->mmap_sem); | |
| 715 | 708 | if (find_vma(current->mm, (unsigned long)fault_addr)) |
| 716 | 709 | si.si_code = SEGV_ACCERR; |
| 717 | 710 | else |
| 718 | 711 | si.si_code = SEGV_MAPERR; |
| 712 | + up_read(¤t->mm->mmap_sem); | |
| 719 | 713 | } else { |
| 720 | 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) · 1037 unmodified lines | ||
| 1759 | 1753 | extern char rollback_except_vec_vi; |
| 1760 | 1754 | char *vec_start = using_rollback_handler() ? |
| 1761 | 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 | 1756 | #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN) |
| 1776 | 1757 | const int lui_offset = &except_vec_vi_lui - vec_start + 2; |
| 1777 | 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) · 17 unmodified lines | ||
| 1795 | 1776 | #else |
| 1796 | 1777 | handler_len); |
| 1797 | 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 | 1779 | h = (u16 *)(b + lui_offset); |
| 1805 | 1780 | *h = (handler >> 16) & 0xffff; |
| 1806 | 1781 | h = (u16 *)(b + ori_offset); |
| @@ -1865,32 +1840,16 @@ static int __init ulri_disable(char *s) · 58 unmodified lines | ||
| 1865 | 1840 | } |
| 1866 | 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 | 1847 | * Disable coprocessors and select 32-bit or 64-bit addressing |
| 1890 | 1848 | * and the 16/32 or 32/32 FPR register model. Reset the BEV |
| 1891 | 1849 | * flag that some firmware may have left set and the TS bit (for |
| 1892 | 1850 | * IP27). Set XX for ISA IV code to work. |
| 1893 | 1851 | */ |
| 1852 | + unsigned int status_set = ST0_CU0; | |
| 1894 | 1853 | #ifdef CONFIG_64BIT |
| 1895 | 1854 | status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX; |
| 1896 | 1855 | #endif |
| @@ -1901,6 +1860,12 @@ void per_cpu_trap_init(bool is_boot_cpu) · 4 unmodified lines | ||
| 1901 | 1860 | |
| 1902 | 1861 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, |
| 1903 | 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 | 1870 | if (cpu_has_mips_r2) |
| 1906 | 1871 | hwrena |= 0x0000000f; |
| @@ -1910,11 +1875,10 @@ void per_cpu_trap_init(bool is_boot_cpu) · 3 unmodified lines | ||
| 1910 | 1875 | |
| 1911 | 1876 | if (hwrena) |
| 1912 | 1877 | write_c0_hwrena(hwrena); |
| 1878 | +} | |
| 1913 | 1879 | |
| 1914 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 1915 | − if (!secondaryTC) { | |
| 1916 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 1917 | − | |
| 1880 | +static void configure_exception_vector(void) | |
| 1881 | +{ | |
| 1918 | 1882 | if (cpu_has_veic || cpu_has_vint) { |
| 1919 | 1883 | unsigned long sr = set_c0_status(ST0_BEV); |
| 1920 | 1884 | write_c0_ebase(ebase); |
| @@ -1930,6 +1894,16 @@ void per_cpu_trap_init(bool is_boot_cpu) · 9 unmodified lines | ||
| 1930 | 1894 | } else |
| 1931 | 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 | 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) · 13 unmodified lines | ||
| 1949 | 1923 | cp0_perfcount_irq = -1; |
| 1950 | 1924 | } |
| 1951 | 1925 | |
| 1952 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 1953 | − } | |
| 1954 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 1955 | − | |
| 1956 | 1926 | if (!cpu_data[cpu].asid_cache) |
| 1957 | 1927 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; |
| 1958 | 1928 | |
| @@ -1961,23 +1931,10 @@ void per_cpu_trap_init(bool is_boot_cpu) · 2 unmodified lines | ||
| 1961 | 1931 | BUG_ON(current->mm); |
| 1962 | 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 | 1934 | /* Boot CPU's cache setup in setup_arch(). */ |
| 1968 | 1935 | if (!is_boot_cpu) |
| 1969 | 1936 | cpu_cache_init(); |
| 1970 | 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 | 1938 | TLBMISS_HANDLER_SETUP(); |
| 1982 | 1939 | } |
| 1983 | 1940 | |
| @@ -2185,3 +2142,32 @@ void __init trap_init(void) · 201 unmodified lines | ||
| 2185 | 2142 | |
| 2186 | 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); | |
| @@ -127,9 +127,8 @@ int vpe_run(struct vpe *v) · 126 unmodified lines | ||
| 127 | 127 | clear_c0_mvpcontrol(MVPCONTROL_VPC); |
| 128 | 128 | |
| 129 | 129 | /* |
| 130 | − * SMTC/SMVP kernels manage VPE enable independently, | |
| 131 | − * but uniprocessor kernels need to turn it on, even | |
| 132 | − * if that wasn't the pre-dvpe() state. | |
| 130 | + * SMVP kernels manage VPE enable independently, but uniprocessor | |
| 131 | + * kernels need to turn it on, even if that wasn't the pre-dvpe() state. | |
| 133 | 132 | */ |
| 134 | 133 | #ifdef CONFIG_SMP |
| 135 | 134 | evpe(vpeflags); |
| @@ -454,12 +453,11 @@ int __init vpe_module_init(void) · 318 unmodified lines | ||
| 454 | 453 | |
| 455 | 454 | settc(tc); |
| 456 | 455 | |
| 457 | − /* Any TC that is bound to VPE0 gets left as is - in | |
| 458 | − * case we are running SMTC on VPE0. A TC that is bound | |
| 459 | − * to any other VPE gets bound to VPE0, ideally I'd like | |
| 460 | − * to make it homeless but it doesn't appear to let me | |
| 461 | − * bind a TC to a non-existent VPE. Which is perfectly | |
| 462 | − * reasonable. | |
| 456 | + /* | |
| 457 | + * A TC that is bound to any other VPE gets bound to | |
| 458 | + * VPE0, ideally I'd like to make it homeless but it | |
| 459 | + * doesn't appear to let me bind a TC to a non-existent | |
| 460 | + * VPE. Which is perfectly reasonable. | |
| 463 | 461 | * |
| 464 | 462 | * The (un)bound state is visible to an EJTAG probe so |
| 465 | 463 | * may notify GDB... |
| @@ -61,7 +61,7 @@ · 60 unmodified lines | ||
| 61 | 61 | /* we have a cascade of 8 irqs */ |
| 62 | 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 | 65 | int gic_present; |
| 66 | 66 | #endif |
| 67 | 67 | |
| @@ -440,7 +440,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) · 372 unmodified lines | ||
| 440 | 440 | arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ, &irq_call); |
| 441 | 441 | #endif |
| 442 | 442 | |
| 443 | −#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) | |
| 443 | +#ifndef CONFIG_MIPS_MT_SMP | |
| 444 | 444 | set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | |
| 445 | 445 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); |
| 446 | 446 | #else |
| @@ -11,7 +11,9 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <linux/module.h> |
| 12 | 12 | #include <linux/param.h> |
| 13 | 13 | #include <linux/smp.h> |
| 14 | +#include <linux/stringify.h> | |
| 14 | 15 | |
| 16 | +#include <asm/asm.h> | |
| 15 | 17 | #include <asm/compiler.h> |
| 16 | 18 | #include <asm/war.h> |
| 17 | 19 | |
| @@ -27,11 +29,7 @@ void __delay(unsigned long loops) · 9 unmodified lines | ||
| 27 | 29 | " .set noreorder \n" |
| 28 | 30 | " .align 3 \n" |
| 29 | 31 | "1: bnez %0, 1b \n" |
| 30 | −#if BITS_PER_LONG == 32 | |
| 31 | − " subu %0, %1 \n" | |
| 32 | −#else | |
| 33 | − " dsubu %0, %1 \n" | |
| 34 | −#endif | |
| 32 | + " " __stringify(LONG_SUBU) " %0, %1 \n" | |
| 35 | 33 | " .set reorder \n" |
| 36 | 34 | : "=r" (loops) |
| 37 | 35 | : GCC_DADDI_IMM_ASM() (1), "0" (loops)); |
| @@ -15,7 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <linux/export.h> |
| 16 | 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 | 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) · 20 unmodified lines | ||
| 42 | 42 | __asm__ __volatile__( |
| 43 | 43 | " .set push \n" |
| 44 | 44 | " .set noat \n" |
| 45 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 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) | |
| 45 | +#if defined(CONFIG_CPU_MIPSR2) | |
| 51 | 46 | /* see irqflags.h for inline function */ |
| 52 | 47 | #else |
| 53 | 48 | " mfc0 $1,$12 \n" |
| @@ -77,13 +72,7 @@ notrace unsigned long arch_local_irq_save(void) · 23 unmodified lines | ||
| 77 | 72 | " .set push \n" |
| 78 | 73 | " .set reorder \n" |
| 79 | 74 | " .set noat \n" |
| 80 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 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) | |
| 75 | +#if defined(CONFIG_CPU_MIPSR2) | |
| 87 | 76 | /* see irqflags.h for inline function */ |
| 88 | 77 | #else |
| 89 | 78 | " mfc0 %[flags], $12 \n" |
| @@ -108,29 +97,13 @@ notrace void arch_local_irq_restore(unsigned long flags) · 18 unmodified lines | ||
| 108 | 97 | { |
| 109 | 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 | 100 | preempt_disable(); |
| 121 | 101 | |
| 122 | 102 | __asm__ __volatile__( |
| 123 | 103 | " .set push \n" |
| 124 | 104 | " .set noreorder \n" |
| 125 | 105 | " .set noat \n" |
| 126 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 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) | |
| 106 | +#if defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) | |
| 134 | 107 | /* see irqflags.h for inline function */ |
| 135 | 108 | #elif defined(CONFIG_CPU_MIPSR2) |
| 136 | 109 | /* see irqflags.h for inline function */ |
| @@ -163,14 +136,7 @@ notrace void __arch_local_irq_restore(unsigned long flags) · 26 unmodified lines | ||
| 163 | 136 | " .set push \n" |
| 164 | 137 | " .set noreorder \n" |
| 165 | 138 | " .set noat \n" |
| 166 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 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) | |
| 139 | +#if defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) | |
| 174 | 140 | /* see irqflags.h for inline function */ |
| 175 | 141 | #elif defined(CONFIG_CPU_MIPSR2) |
| 176 | 142 | /* see irqflags.h for inline function */ |
| @@ -192,4 +158,4 @@ notrace void __arch_local_irq_restore(unsigned long flags) · 15 unmodified lines | ||
| 192 | 158 | } |
| 193 | 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 */ | |
| @@ -95,10 +95,11 @@ config CS5536 · 94 unmodified lines | ||
| 95 | 95 | |
| 96 | 96 | config CS5536_MFGPT |
| 97 | 97 | bool "CS5536 MFGPT Timer" |
| 98 | − depends on CS5536 | |
| 98 | + depends on CS5536 && !HIGH_RES_TIMERS | |
| 99 | 99 | select MIPS_EXTERNAL_TIMER |
| 100 | 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 | 104 | If you want to enable the Loongson2 CPUFreq Driver, Please enable |
| 104 | 105 | this option at first, otherwise, You will get wrong system time. |
| @@ -279,13 +279,6 @@ static void loongson3_boot_secondary(int cpu, struct task_struct *idle) · 278 unmodified lines | ||
| 279 | 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 | 282 | #ifdef CONFIG_HOTPLUG_CPU |
| 290 | 283 | |
| 291 | 284 | static int loongson3_cpu_disable(void) |
| @@ -432,7 +425,6 @@ struct plat_smp_ops loongson3_smp_ops = { · 140 unmodified lines | ||
| 432 | 425 | .send_ipi_mask = loongson3_send_ipi_mask, |
| 433 | 426 | .init_secondary = loongson3_init_secondary, |
| 434 | 427 | .smp_finish = loongson3_smp_finish, |
| 435 | − .cpus_done = loongson3_cpus_done, | |
| 436 | 428 | .boot_secondary = loongson3_boot_secondary, |
| 437 | 429 | .smp_setup = loongson3_smp_setup, |
| 438 | 430 | .prepare_cpus = loongson3_prepare_cpus, |
| @@ -14,6 +14,7 @@ config LOONGSON1_LS1B · 13 unmodified lines | ||
| 14 | 14 | select SYS_SUPPORTS_32BIT_KERNEL |
| 15 | 15 | select SYS_SUPPORTS_LITTLE_ENDIAN |
| 16 | 16 | select SYS_SUPPORTS_HIGHMEM |
| 17 | + select SYS_SUPPORTS_MIPS16 | |
| 17 | 18 | select SYS_HAS_EARLY_PRINTK |
| 18 | 19 | select COMMON_CLK |
| 19 | 20 | |
| @@ -2,10 +2,12 @@ · 1 unmodified line | ||
| 2 | 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 \ | |
| 6 | − ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \ | |
| 7 | − dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \ | |
| 8 | − dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \ | |
| 9 | − sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \ | |
| 10 | − sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \ | |
| 11 | − dp_sqrt.o sp_sqrt.o kernel_linkage.o dsemul.o | |
| 5 | +obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o dp_div.o dp_mul.o \ | |
| 6 | + dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o dp_tint.o \ | |
| 7 | + dp_fint.o dp_tlong.o dp_flong.o sp_div.o sp_mul.o sp_sub.o \ | |
| 8 | + sp_add.o sp_fdp.o sp_cmp.o sp_simple.o sp_tint.o sp_fint.o \ | |
| 9 | + sp_tlong.o sp_flong.o dsemul.o | |
| 10 | + | |
| 11 | +lib-y += ieee754d.o dp_sqrt.o sp_sqrt.o | |
| 12 | + | |
| 13 | +obj-$(CONFIG_DEBUG_FS) += me-debugfs.o | |
| @@ -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 | 4 | * MIPS floating point support |
| 5 | 5 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| @@ -18,61 +18,46 @@ · 12 unmodified lines | ||
| 18 | 18 | * |
| 19 | 19 | * You should have received a copy of the GNU General Public License along |
| 20 | 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 | 23 | * A complete emulator for MIPS coprocessor 1 instructions. This is |
| 24 | 24 | * required for #float(switch) or #float(trap), where it catches all |
| 25 | 25 | * COP1 instructions via the "CoProcessor Unusable" exception. |
| 26 | 26 | * |
| 27 | 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 | 29 | * (denormalised values, infinities, underflow, etc). It is made |
| 30 | 30 | * quite nasty because emulation of some non-COP1 instructions is |
| 31 | 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 | 34 | * better performance by compiling with -msoft-float! |
| 35 | 35 | */ |
| 36 | 36 | #include <linux/sched.h> |
| 37 | −#include <linux/module.h> | |
| 38 | 37 | #include <linux/debugfs.h> |
| 38 | +#include <linux/kconfig.h> | |
| 39 | +#include <linux/percpu-defs.h> | |
| 39 | 40 | #include <linux/perf_event.h> |
| 40 | 41 | |
| 42 | +#include <asm/branch.h> | |
| 41 | 43 | #include <asm/inst.h> |
| 42 | −#include <asm/bootinfo.h> | |
| 43 | −#include <asm/processor.h> | |
| 44 | 44 | #include <asm/ptrace.h> |
| 45 | 45 | #include <asm/signal.h> |
| 46 | −#include <asm/mipsregs.h> | |
| 46 | +#include <asm/uaccess.h> | |
| 47 | + | |
| 48 | +#include <asm/processor.h> | |
| 47 | 49 | #include <asm/fpu_emulator.h> |
| 48 | 50 | #include <asm/fpu.h> |
| 49 | −#include <asm/uaccess.h> | |
| 50 | −#include <asm/branch.h> | |
| 51 | 51 | |
| 52 | 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 | 54 | /* Function which emulates a floating point instruction. */ |
| 62 | 55 | |
| 63 | 56 | static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, |
| 64 | 57 | mips_instruction); |
| 65 | 58 | |
| 66 | −#if __mips >= 4 && __mips != 32 | |
| 67 | 59 | static int fpux_emu(struct pt_regs *, |
| 68 | 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 | 62 | /* Control registers */ |
| 78 | 63 | |
| @@ -82,27 +67,6 @@ DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); · 3 unmodified lines | ||
| 82 | 67 | /* Determine rounding mode from the RM bits of the FCSR */ |
| 83 | 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 | 70 | /* convert condition code register number to csr bit */ |
| 107 | 71 | static const unsigned int fpucondbit[8] = { |
| 108 | 72 | FPU_CSR_COND0, |
| @@ -114,10 +78,6 @@ static const unsigned int fpucondbit[8] = { · 5 unmodified lines | ||
| 114 | 78 | FPU_CSR_COND6, |
| 115 | 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 | 82 | /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ |
| 123 | 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) · 342 unmodified lines | ||
| 466 | 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 | 430 | * Redundant with logic already in kernel/branch.c, |
| 664 | 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, · 152 unmodified lines | ||
| 817 | 584 | if (insn.i_format.rs == bc_op) { |
| 818 | 585 | preempt_disable(); |
| 819 | 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 | 592 | else |
| 822 | 593 | fcr31 = current->thread.fpu.fcr31; |
| 823 | 594 | preempt_enable(); |
| @@ -867,23 +638,25 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, · 43 unmodified lines | ||
| 867 | 638 | */ |
| 868 | 639 | static inline int cop1_64bit(struct pt_regs *xcp) |
| 869 | 640 | { |
| 870 | −#if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32) | |
| 871 | − return 1; | |
| 872 | −#elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT) | |
| 873 | − return 0; | |
| 874 | −#else | |
| 641 | + if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32)) | |
| 642 | + return 1; | |
| 643 | + else if (config_enabled(CONFIG_32BIT) && | |
| 644 | + !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) | |
| 645 | + return 0; | |
| 646 | + | |
| 875 | 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 | 652 | if (cop1_64bit(xcp)) \ |
| 881 | 653 | (si) = get_fpr32(&ctx->fpr[x], 0); \ |
| 882 | 654 | else \ |
| 883 | 655 | (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ |
| 884 | 656 | } while (0) |
| 885 | 657 | |
| 886 | −#define SITOREG(si, x) do { \ | |
| 658 | +#define SITOREG(si, x) \ | |
| 659 | +do { \ | |
| 887 | 660 | if (cop1_64bit(xcp)) { \ |
| 888 | 661 | unsigned i; \ |
| 889 | 662 | set_fpr32(&ctx->fpr[x], 0, si); \ |
| @@ -896,17 +669,19 @@ static inline int cop1_64bit(struct pt_regs *xcp) · 6 unmodified lines | ||
| 896 | 669 | |
| 897 | 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 | 674 | unsigned i; \ |
| 901 | 675 | set_fpr32(&ctx->fpr[x], 1, si); \ |
| 902 | 676 | for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ |
| 903 | 677 | set_fpr32(&ctx->fpr[x], i, 0); \ |
| 904 | 678 | } while (0) |
| 905 | 679 | |
| 906 | −#define DIFROMREG(di, x) \ | |
| 680 | +#define DIFROMREG(di, x) \ | |
| 907 | 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 | 685 | unsigned fpr, i; \ |
| 911 | 686 | fpr = (x) & ~(cop1_64bit(xcp) == 0); \ |
| 912 | 687 | set_fpr64(&ctx->fpr[fpr], 0, di); \ |
| @@ -927,23 +702,36 @@ static inline int cop1_64bit(struct pt_regs *xcp) · 14 unmodified lines | ||
| 927 | 702 | static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, |
| 928 | 703 | struct mm_decoded_insn dec_insn, void *__user *fault_addr) |
| 929 | 704 | { |
| 930 | − mips_instruction ir; | |
| 931 | 705 | unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; |
| 932 | − unsigned int cond; | |
| 933 | − int pc_inc; | |
| 706 | + unsigned int cond, cbit; | |
| 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 | 723 | /* XXX NEC Vr54xx bug workaround */ |
| 936 | − if (xcp->cp0_cause & CAUSEF_BD) { | |
| 724 | + if (delay_slot(xcp)) { | |
| 937 | 725 | if (dec_insn.micro_mips_mode) { |
| 938 | 726 | if (!mm_isBranchInstr(xcp, dec_insn, &contpc)) |
| 939 | − xcp->cp0_cause &= ~CAUSEF_BD; | |
| 727 | + clear_delay_slot(xcp); | |
| 940 | 728 | } else { |
| 941 | 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 | 736 | * The instruction to be emulated is in a branch delay slot |
| 949 | 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, · 35 unmodified lines | ||
| 985 | 773 | return SIGILL; |
| 986 | 774 | } |
| 987 | 775 | |
| 988 | − emul: | |
| 776 | +emul: | |
| 989 | 777 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); |
| 990 | 778 | MIPS_FPU_EMU_INC_STATS(emulated); |
| 991 | 779 | switch (MIPSInst_OPCODE(ir)) { |
| 992 | − case ldc1_op:{ | |
| 993 | − u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + | |
| 994 | − MIPSInst_SIMM(ir)); | |
| 995 | − u64 val; | |
| 996 | − | |
| 780 | + case ldc1_op: | |
| 781 | + dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + | |
| 782 | + MIPSInst_SIMM(ir)); | |
| 997 | 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 | 786 | MIPS_FPU_EMU_INC_STATS(errors); |
| 1001 | − *fault_addr = va; | |
| 787 | + *fault_addr = dva; | |
| 1002 | 788 | return SIGBUS; |
| 1003 | 789 | } |
| 1004 | − if (__get_user(val, va)) { | |
| 790 | + if (__get_user(dval, dva)) { | |
| 1005 | 791 | MIPS_FPU_EMU_INC_STATS(errors); |
| 1006 | − *fault_addr = va; | |
| 792 | + *fault_addr = dva; | |
| 1007 | 793 | return SIGSEGV; |
| 1008 | 794 | } |
| 1009 | − DITOREG(val, MIPSInst_RT(ir)); | |
| 795 | + DITOREG(dval, MIPSInst_RT(ir)); | |
| 1010 | 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 | 801 | MIPS_FPU_EMU_INC_STATS(stores); |
| 1019 | − DIFROMREG(val, MIPSInst_RT(ir)); | |
| 1020 | − if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { | |
| 802 | + DIFROMREG(dval, MIPSInst_RT(ir)); | |
| 803 | + if (!access_ok(VERIFY_WRITE, dva, sizeof(u64))) { | |
| 1021 | 804 | MIPS_FPU_EMU_INC_STATS(errors); |
| 1022 | − *fault_addr = va; | |
| 805 | + *fault_addr = dva; | |
| 1023 | 806 | return SIGBUS; |
| 1024 | 807 | } |
| 1025 | − if (__put_user(val, va)) { | |
| 808 | + if (__put_user(dval, dva)) { | |
| 1026 | 809 | MIPS_FPU_EMU_INC_STATS(errors); |
| 1027 | − *fault_addr = va; | |
| 810 | + *fault_addr = dva; | |
| 1028 | 811 | return SIGSEGV; |
| 1029 | 812 | } |
| 1030 | 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 | 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 | 820 | MIPS_FPU_EMU_INC_STATS(errors); |
| 1041 | − *fault_addr = va; | |
| 821 | + *fault_addr = wva; | |
| 1042 | 822 | return SIGBUS; |
| 1043 | 823 | } |
| 1044 | − if (__get_user(val, va)) { | |
| 824 | + if (__get_user(wval, wva)) { | |
| 1045 | 825 | MIPS_FPU_EMU_INC_STATS(errors); |
| 1046 | − *fault_addr = va; | |
| 826 | + *fault_addr = wva; | |
| 1047 | 827 | return SIGSEGV; |
| 1048 | 828 | } |
| 1049 | − SITOREG(val, MIPSInst_RT(ir)); | |
| 829 | + SITOREG(wval, MIPSInst_RT(ir)); | |
| 1050 | 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 | 835 | MIPS_FPU_EMU_INC_STATS(stores); |
| 1059 | − SIFROMREG(val, MIPSInst_RT(ir)); | |
| 1060 | − if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { | |
| 836 | + SIFROMREG(wval, MIPSInst_RT(ir)); | |
| 837 | + if (!access_ok(VERIFY_WRITE, wva, sizeof(u32))) { | |
| 1061 | 838 | MIPS_FPU_EMU_INC_STATS(errors); |
| 1062 | − *fault_addr = va; | |
| 839 | + *fault_addr = wva; | |
| 1063 | 840 | return SIGBUS; |
| 1064 | 841 | } |
| 1065 | − if (__put_user(val, va)) { | |
| 842 | + if (__put_user(wval, wva)) { | |
| 1066 | 843 | MIPS_FPU_EMU_INC_STATS(errors); |
| 1067 | − *fault_addr = va; | |
| 844 | + *fault_addr = wva; | |
| 1068 | 845 | return SIGSEGV; |
| 1069 | 846 | } |
| 1070 | 847 | break; |
| 1071 | − } | |
| 1072 | 848 | |
| 1073 | 849 | case cop1_op: |
| 1074 | 850 | switch (MIPSInst_RS(ir)) { |
| 1075 | − | |
| 1076 | −#if defined(__mips64) | |
| 1077 | 851 | case dmfc_op: |
| 852 | + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | |
| 853 | + return SIGILL; | |
| 854 | + | |
| 1078 | 855 | /* copregister fs -> gpr[rt] */ |
| 1079 | 856 | if (MIPSInst_RT(ir) != 0) { |
| 1080 | 857 | DIFROMREG(xcp->regs[MIPSInst_RT(ir)], |
| @@ -1083,10 +860,12 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 2 unmodified lines | ||
| 1083 | 860 | break; |
| 1084 | 861 | |
| 1085 | 862 | case dmtc_op: |
| 863 | + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | |
| 864 | + return SIGILL; | |
| 865 | + | |
| 1086 | 866 | /* copregister fs <- rt */ |
| 1087 | 867 | DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); |
| 1088 | 868 | break; |
| 1089 | −#endif | |
| 1090 | 869 | |
| 1091 | 870 | case mfhc_op: |
| 1092 | 871 | if (!cpu_has_mips_r2) |
| @@ -1120,19 +899,14 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 27 unmodified lines | ||
| 1120 | 899 | SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); |
| 1121 | 900 | break; |
| 1122 | 901 | |
| 1123 | − case cfc_op:{ | |
| 902 | + case cfc_op: | |
| 1124 | 903 | /* cop control register rd -> gpr[rt] */ |
| 1125 | − u32 value; | |
| 1126 | − | |
| 1127 | 904 | if (MIPSInst_RD(ir) == FPCREG_CSR) { |
| 1128 | 905 | value = ctx->fcr31; |
| 1129 | − value = (value & ~FPU_CSR_RM) | | |
| 1130 | − mips_rm[modeindex(value)]; | |
| 1131 | −#ifdef CSRTRACE | |
| 1132 | − printk("%p gpr[%d]<-csr=%08x\n", | |
| 1133 | − (void *) (xcp->cp0_epc), | |
| 1134 | − MIPSInst_RT(ir), value); | |
| 1135 | −#endif | |
| 906 | + value = (value & ~FPU_CSR_RM) | modeindex(value); | |
| 907 | + pr_debug("%p gpr[%d]<-csr=%08x\n", | |
| 908 | + (void *) (xcp->cp0_epc), | |
| 909 | + MIPSInst_RT(ir), value); | |
| 1136 | 910 | } |
| 1137 | 911 | else if (MIPSInst_RD(ir) == FPCREG_RID) |
| 1138 | 912 | value = 0; |
| @@ -1141,12 +915,9 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 2 unmodified lines | ||
| 1141 | 915 | if (MIPSInst_RT(ir)) |
| 1142 | 916 | xcp->regs[MIPSInst_RT(ir)] = value; |
| 1143 | 917 | break; |
| 1144 | − } | |
| 1145 | 918 | |
| 1146 | − case ctc_op:{ | |
| 919 | + case ctc_op: | |
| 1147 | 920 | /* copregister rd <- rt */ |
| 1148 | − u32 value; | |
| 1149 | − | |
| 1150 | 921 | if (MIPSInst_RT(ir) == 0) |
| 1151 | 922 | value = 0; |
| 1152 | 923 | else |
| @@ -1155,37 +926,33 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 2 unmodified lines | ||
| 1155 | 926 | /* we only have one writable control reg |
| 1156 | 927 | */ |
| 1157 | 928 | if (MIPSInst_RD(ir) == FPCREG_CSR) { |
| 1158 | −#ifdef CSRTRACE | |
| 1159 | − printk("%p gpr[%d]->csr=%08x\n", | |
| 1160 | − (void *) (xcp->cp0_epc), | |
| 1161 | − MIPSInst_RT(ir), value); | |
| 1162 | −#endif | |
| 929 | + pr_debug("%p gpr[%d]->csr=%08x\n", | |
| 930 | + (void *) (xcp->cp0_epc), | |
| 931 | + MIPSInst_RT(ir), value); | |
| 1163 | 932 | |
| 1164 | 933 | /* |
| 1165 | 934 | * Don't write reserved bits, |
| 1166 | 935 | * and convert to ieee library modes |
| 1167 | 936 | */ |
| 1168 | − ctx->fcr31 = (value & | |
| 1169 | − ~(FPU_CSR_RSVD | FPU_CSR_RM)) | | |
| 1170 | − ieee_rm[modeindex(value)]; | |
| 937 | + ctx->fcr31 = (value & ~(FPU_CSR_RSVD | FPU_CSR_RM)) | | |
| 938 | + modeindex(value); | |
| 1171 | 939 | } |
| 1172 | 940 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { |
| 1173 | 941 | return SIGFPE; |
| 1174 | 942 | } |
| 1175 | 943 | break; |
| 1176 | − } | |
| 1177 | 944 | |
| 1178 | − case bc_op:{ | |
| 1179 | − int likely = 0; | |
| 1180 | − | |
| 1181 | − if (xcp->cp0_cause & CAUSEF_BD) | |
| 945 | + case bc_op: | |
| 946 | + if (delay_slot(xcp)) | |
| 1182 | 947 | return SIGILL; |
| 1183 | 948 | |
| 1184 | −#if __mips >= 4 | |
| 1185 | − cond = ctx->fcr31 & fpucondbit[MIPSInst_RT(ir) >> 2]; | |
| 1186 | −#else | |
| 1187 | − cond = ctx->fcr31 & FPU_CSR_COND; | |
| 1188 | −#endif | |
| 949 | + if (cpu_has_mips_4_5_r) | |
| 950 | + cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; | |
| 951 | + else | |
| 952 | + cbit = FPU_CSR_COND; | |
| 953 | + cond = ctx->fcr31 & cbit; | |
| 954 | + | |
| 955 | + likely = 0; | |
| 1189 | 956 | switch (MIPSInst_RT(ir) & 3) { |
| 1190 | 957 | case bcfl_op: |
| 1191 | 958 | likely = 1; |
| @@ -1201,10 +968,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 9 unmodified lines | ||
| 1201 | 968 | return SIGILL; |
| 1202 | 969 | } |
| 1203 | 970 | |
| 1204 | − xcp->cp0_cause |= CAUSEF_BD; | |
| 971 | + set_delay_slot(xcp); | |
| 1205 | 972 | if (cond) { |
| 1206 | − /* branch taken: emulate dslot | |
| 1207 | − * instruction | |
| 973 | + /* | |
| 974 | + * Branch taken: emulate dslot instruction | |
| 1208 | 975 | */ |
| 1209 | 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, · 27 unmodified lines | ||
| 1238 | 1005 | |
| 1239 | 1006 | switch (MIPSInst_OPCODE(ir)) { |
| 1240 | 1007 | case lwc1_op: |
| 1008 | + goto emul; | |
| 1009 | + | |
| 1241 | 1010 | case swc1_op: |
| 1242 | −#if (__mips >= 2 || defined(__mips64)) | |
| 1011 | + goto emul; | |
| 1012 | + | |
| 1243 | 1013 | case ldc1_op: |
| 1244 | 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 | 1022 | case cop1_op: |
| 1247 | −#if __mips >= 4 && __mips != 32 | |
| 1248 | − case cop1x_op: | |
| 1249 | −#endif | |
| 1250 | − /* its one of ours */ | |
| 1251 | 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 | 1032 | case spec_op: |
| 1033 | + if (!cpu_has_mips_4_5_r) | |
| 1034 | + return SIGILL; | |
| 1035 | + | |
| 1254 | 1036 | if (MIPSInst_FUNC(ir) == movc_op) |
| 1255 | 1037 | goto emul; |
| 1256 | 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, · 1 unmodified line | ||
| 1262 | 1043 | * instruction in the dslot |
| 1263 | 1044 | */ |
| 1264 | 1045 | return mips_dsemul(xcp, ir, contpc); |
| 1265 | − } | |
| 1266 | − else { | |
| 1267 | − /* branch not taken */ | |
| 1268 | − if (likely) { | |
| 1046 | + } else if (likely) { /* branch not taken */ | |
| 1269 | 1047 | /* |
| 1270 | 1048 | * branch likely nullifies |
| 1271 | 1049 | * dslot if not taken |
| @@ -1277,34 +1055,31 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 5 unmodified lines | ||
| 1277 | 1055 | * dslot as normal insn |
| 1278 | 1056 | */ |
| 1279 | 1057 | } |
| 1280 | − } | |
| 1281 | 1058 | break; |
| 1282 | − } | |
| 1283 | 1059 | |
| 1284 | 1060 | default: |
| 1285 | 1061 | if (!(MIPSInst_RS(ir) & 0x10)) |
| 1286 | 1062 | return SIGILL; |
| 1287 | − { | |
| 1288 | − int sig; | |
| 1289 | 1063 | |
| 1290 | − /* a real fpu computation instruction */ | |
| 1291 | − if ((sig = fpu_emu(xcp, ctx, ir))) | |
| 1292 | − return sig; | |
| 1293 | − } | |
| 1064 | + /* a real fpu computation instruction */ | |
| 1065 | + if ((sig = fpu_emu(xcp, ctx, ir))) | |
| 1066 | + return sig; | |
| 1294 | 1067 | } |
| 1295 | 1068 | break; |
| 1296 | 1069 | |
| 1297 | −#if __mips >= 4 && __mips != 32 | |
| 1298 | − case cop1x_op:{ | |
| 1299 | − int sig = fpux_emu(xcp, ctx, ir, fault_addr); | |
| 1070 | + case cop1x_op: | |
| 1071 | + if (!cpu_has_mips_4_5 && !cpu_has_mips64) | |
| 1072 | + return SIGILL; | |
| 1073 | + | |
| 1074 | + sig = fpux_emu(xcp, ctx, ir, fault_addr); | |
| 1300 | 1075 | if (sig) |
| 1301 | 1076 | return sig; |
| 1302 | 1077 | break; |
| 1303 | − } | |
| 1304 | −#endif | |
| 1305 | 1078 | |
| 1306 | −#if __mips >= 4 | |
| 1307 | 1079 | case spec_op: |
| 1080 | + if (!cpu_has_mips_4_5_r) | |
| 1081 | + return SIGILL; | |
| 1082 | + | |
| 1308 | 1083 | if (MIPSInst_FUNC(ir) != movc_op) |
| 1309 | 1084 | return SIGILL; |
| 1310 | 1085 | cond = fpucondbit[MIPSInst_RT(ir) >> 2]; |
| @@ -1312,8 +1087,6 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 1 unmodified line | ||
| 1312 | 1087 | xcp->regs[MIPSInst_RD(ir)] = |
| 1313 | 1088 | xcp->regs[MIPSInst_RS(ir)]; |
| 1314 | 1089 | break; |
| 1315 | −#endif | |
| 1316 | − | |
| 1317 | 1090 | default: |
| 1318 | 1091 | sigill: |
| 1319 | 1092 | return SIGILL; |
| @@ -1321,7 +1094,7 @@ sigill: · 1 unmodified line | ||
| 1321 | 1094 | |
| 1322 | 1095 | /* we did it !! */ |
| 1323 | 1096 | xcp->cp0_epc = contpc; |
| 1324 | − xcp->cp0_cause &= ~CAUSEF_BD; | |
| 1097 | + clear_delay_slot(xcp); | |
| 1325 | 1098 | |
| 1326 | 1099 | return 0; |
| 1327 | 1100 | } |
| @@ -1342,44 +1115,42 @@ static const unsigned char cmptab[8] = { · 14 unmodified lines | ||
| 1342 | 1115 | }; |
| 1343 | 1116 | |
| 1344 | 1117 | |
| 1345 | −#if __mips >= 4 && __mips != 32 | |
| 1346 | − | |
| 1347 | 1118 | /* |
| 1348 | 1119 | * Additional MIPS4 instructions |
| 1349 | 1120 | */ |
| 1350 | 1121 | |
| 1351 | −#define DEF3OP(name, p, f1, f2, f3) \ | |
| 1352 | −static ieee754##p fpemu_##p##_##name(ieee754##p r, ieee754##p s, \ | |
| 1353 | − ieee754##p t) \ | |
| 1354 | −{ \ | |
| 1355 | − struct _ieee754_csr ieee754_csr_save; \ | |
| 1356 | − s = f1(s, t); \ | |
| 1357 | − ieee754_csr_save = ieee754_csr; \ | |
| 1358 | − s = f2(s, r); \ | |
| 1359 | − ieee754_csr_save.cx |= ieee754_csr.cx; \ | |
| 1360 | − ieee754_csr_save.sx |= ieee754_csr.sx; \ | |
| 1361 | − s = f3(s); \ | |
| 1362 | − ieee754_csr.cx |= ieee754_csr_save.cx; \ | |
| 1363 | − ieee754_csr.sx |= ieee754_csr_save.sx; \ | |
| 1364 | − return s; \ | |
| 1122 | +#define DEF3OP(name, p, f1, f2, f3) \ | |
| 1123 | +static union ieee754##p fpemu_##p##_##name(union ieee754##p r, \ | |
| 1124 | + union ieee754##p s, union ieee754##p t) \ | |
| 1125 | +{ \ | |
| 1126 | + struct _ieee754_csr ieee754_csr_save; \ | |
| 1127 | + s = f1(s, t); \ | |
| 1128 | + ieee754_csr_save = ieee754_csr; \ | |
| 1129 | + s = f2(s, r); \ | |
| 1130 | + ieee754_csr_save.cx |= ieee754_csr.cx; \ | |
| 1131 | + ieee754_csr_save.sx |= ieee754_csr.sx; \ | |
| 1132 | + s = f3(s); \ | |
| 1133 | + ieee754_csr.cx |= ieee754_csr_save.cx; \ | |
| 1134 | + ieee754_csr.sx |= ieee754_csr_save.sx; \ | |
| 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 | 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 | 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 | 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 | 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, · 17 unmodified lines | ||
| 1403 | 1174 | switch (MIPSInst_FMA_FFMT(ir)) { |
| 1404 | 1175 | case s_fmt:{ /* 0 */ |
| 1405 | 1176 | |
| 1406 | − ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp); | |
| 1407 | − ieee754sp fd, fr, fs, ft; | |
| 1177 | + union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); | |
| 1178 | + union ieee754sp fd, fr, fs, ft; | |
| 1408 | 1179 | u32 __user *va; |
| 1409 | 1180 | u32 val; |
| 1410 | 1181 | |
| @@ -1467,18 +1238,26 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 56 unmodified lines | ||
| 1467 | 1238 | SPTOREG(fd, MIPSInst_FD(ir)); |
| 1468 | 1239 | |
| 1469 | 1240 | copcsr: |
| 1470 | − if (ieee754_cxtest(IEEE754_INEXACT)) | |
| 1241 | + if (ieee754_cxtest(IEEE754_INEXACT)) { | |
| 1242 | + MIPS_FPU_EMU_INC_STATS(ieee754_inexact); | |
| 1471 | 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 | 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 | 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 | 1255 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; |
| 1256 | + } | |
| 1478 | 1257 | |
| 1479 | 1258 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; |
| 1480 | 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 | 1261 | ctx->fcr31); */ |
| 1483 | 1262 | return SIGFPE; |
| 1484 | 1263 | } |
| @@ -1492,8 +1271,8 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 7 unmodified lines | ||
| 1492 | 1271 | } |
| 1493 | 1272 | |
| 1494 | 1273 | case d_fmt:{ /* 1 */ |
| 1495 | − ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp); | |
| 1496 | − ieee754dp fd, fr, fs, ft; | |
| 1274 | + union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); | |
| 1275 | + union ieee754dp fd, fr, fs, ft; | |
| 1497 | 1276 | u64 __user *va; |
| 1498 | 1277 | u64 val; |
| 1499 | 1278 | |
| @@ -1574,7 +1353,6 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 74 unmodified lines | ||
| 1574 | 1353 | |
| 1575 | 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, · 5 unmodified lines | ||
| 1586 | 1364 | { |
| 1587 | 1365 | int rfmt; /* resulting format */ |
| 1588 | 1366 | unsigned rcsr = 0; /* resulting csr */ |
| 1367 | + unsigned int oldrm; | |
| 1368 | + unsigned int cbit; | |
| 1589 | 1369 | unsigned cond; |
| 1590 | 1370 | union { |
| 1591 | − ieee754dp d; | |
| 1592 | − ieee754sp s; | |
| 1371 | + union ieee754dp d; | |
| 1372 | + union ieee754sp s; | |
| 1593 | 1373 | int w; |
| 1594 | −#ifdef __mips64 | |
| 1595 | 1374 | s64 l; |
| 1596 | −#endif | |
| 1597 | 1375 | } rv; /* resulting value */ |
| 1376 | + u64 bits; | |
| 1598 | 1377 | |
| 1599 | 1378 | MIPS_FPU_EMU_INC_STATS(cp1ops); |
| 1600 | 1379 | switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { |
| 1601 | − case s_fmt:{ /* 0 */ | |
| 1380 | + case s_fmt: { /* 0 */ | |
| 1602 | 1381 | union { |
| 1603 | − ieee754sp(*b) (ieee754sp, ieee754sp); | |
| 1604 | − ieee754sp(*u) (ieee754sp); | |
| 1382 | + union ieee754sp(*b) (union ieee754sp, union ieee754sp); | |
| 1383 | + union ieee754sp(*u) (union ieee754sp); | |
| 1605 | 1384 | } handler; |
| 1385 | + union ieee754sp fs, ft; | |
| 1606 | 1386 | |
| 1607 | 1387 | switch (MIPSInst_FUNC(ir)) { |
| 1608 | 1388 | /* binary ops */ |
| @@ -1620,148 +1400,167 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 11 unmodified lines | ||
| 1620 | 1400 | goto scopbop; |
| 1621 | 1401 | |
| 1622 | 1402 | /* unary ops */ |
| 1623 | −#if __mips >= 2 || defined(__mips64) | |
| 1624 | 1403 | case fsqrt_op: |
| 1404 | + if (!cpu_has_mips_4_5_r) | |
| 1405 | + return SIGILL; | |
| 1406 | + | |
| 1625 | 1407 | handler.u = ieee754sp_sqrt; |
| 1626 | 1408 | goto scopuop; |
| 1627 | −#endif | |
| 1628 | −#if __mips >= 4 && __mips != 32 | |
| 1409 | + | |
| 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 | 1415 | case frsqrt_op: |
| 1416 | + if (!cpu_has_mips_4_5_r2) | |
| 1417 | + return SIGILL; | |
| 1418 | + | |
| 1630 | 1419 | handler.u = fpemu_sp_rsqrt; |
| 1631 | 1420 | goto scopuop; |
| 1421 | + | |
| 1632 | 1422 | case frecip_op: |
| 1423 | + if (!cpu_has_mips_4_5_r2) | |
| 1424 | + return SIGILL; | |
| 1425 | + | |
| 1633 | 1426 | handler.u = fpemu_sp_recip; |
| 1634 | 1427 | goto scopuop; |
| 1635 | −#endif | |
| 1636 | −#if __mips >= 4 | |
| 1428 | + | |
| 1637 | 1429 | case fmovc_op: |
| 1430 | + if (!cpu_has_mips_4_5_r) | |
| 1431 | + return SIGILL; | |
| 1432 | + | |
| 1638 | 1433 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; |
| 1639 | 1434 | if (((ctx->fcr31 & cond) != 0) != |
| 1640 | 1435 | ((MIPSInst_FT(ir) & 1) != 0)) |
| 1641 | 1436 | return 0; |
| 1642 | 1437 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
| 1643 | 1438 | break; |
| 1439 | + | |
| 1644 | 1440 | case fmovz_op: |
| 1441 | + if (!cpu_has_mips_4_5_r) | |
| 1442 | + return SIGILL; | |
| 1443 | + | |
| 1645 | 1444 | if (xcp->regs[MIPSInst_FT(ir)] != 0) |
| 1646 | 1445 | return 0; |
| 1647 | 1446 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
| 1648 | 1447 | break; |
| 1448 | + | |
| 1649 | 1449 | case fmovn_op: |
| 1450 | + if (!cpu_has_mips_4_5_r) | |
| 1451 | + return SIGILL; | |
| 1452 | + | |
| 1650 | 1453 | if (xcp->regs[MIPSInst_FT(ir)] == 0) |
| 1651 | 1454 | return 0; |
| 1652 | 1455 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
| 1653 | 1456 | break; |
| 1654 | −#endif | |
| 1457 | + | |
| 1655 | 1458 | case fabs_op: |
| 1656 | 1459 | handler.u = ieee754sp_abs; |
| 1657 | 1460 | goto scopuop; |
| 1461 | + | |
| 1658 | 1462 | case fneg_op: |
| 1659 | 1463 | handler.u = ieee754sp_neg; |
| 1660 | 1464 | goto scopuop; |
| 1465 | + | |
| 1661 | 1466 | case fmov_op: |
| 1662 | 1467 | /* an easy one */ |
| 1663 | 1468 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
| 1664 | 1469 | goto copcsr; |
| 1665 | 1470 | |
| 1666 | 1471 | /* binary op on handler */ |
| 1667 | − scopbop: | |
| 1668 | − { | |
| 1669 | − ieee754sp fs, ft; | |
| 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; | |
| 1472 | +scopbop: | |
| 1473 | + SPFROMREG(fs, MIPSInst_FS(ir)); | |
| 1474 | + SPFROMREG(ft, MIPSInst_FT(ir)); | |
| 1680 | 1475 | |
| 1681 | − SPFROMREG(fs, MIPSInst_FS(ir)); | |
| 1682 | − rv.s = (*handler.u) (fs); | |
| 1683 | − goto copcsr; | |
| 1684 | − } | |
| 1685 | − copcsr: | |
| 1686 | − if (ieee754_cxtest(IEEE754_INEXACT)) | |
| 1476 | + rv.s = (*handler.b) (fs, ft); | |
| 1477 | + goto copcsr; | |
| 1478 | +scopuop: | |
| 1479 | + SPFROMREG(fs, MIPSInst_FS(ir)); | |
| 1480 | + rv.s = (*handler.u) (fs); | |
| 1481 | + goto copcsr; | |
| 1482 | +copcsr: | |
| 1483 | + if (ieee754_cxtest(IEEE754_INEXACT)) { | |
| 1484 | + MIPS_FPU_EMU_INC_STATS(ieee754_inexact); | |
| 1687 | 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 | 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 | 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 | 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 | 1501 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; |
| 1502 | + } | |
| 1696 | 1503 | break; |
| 1697 | 1504 | |
| 1698 | 1505 | /* unary conv ops */ |
| 1699 | 1506 | case fcvts_op: |
| 1700 | 1507 | return SIGILL; /* not defined */ |
| 1701 | − case fcvtd_op:{ | |
| 1702 | − ieee754sp fs; | |
| 1703 | 1508 | |
| 1509 | + case fcvtd_op: | |
| 1704 | 1510 | SPFROMREG(fs, MIPSInst_FS(ir)); |
| 1705 | 1511 | rv.d = ieee754dp_fsp(fs); |
| 1706 | 1512 | rfmt = d_fmt; |
| 1707 | 1513 | goto copcsr; |
| 1708 | − } | |
| 1709 | − case fcvtw_op:{ | |
| 1710 | − ieee754sp fs; | |
| 1711 | 1514 | |
| 1515 | + case fcvtw_op: | |
| 1712 | 1516 | SPFROMREG(fs, MIPSInst_FS(ir)); |
| 1713 | 1517 | rv.w = ieee754sp_tint(fs); |
| 1714 | 1518 | rfmt = w_fmt; |
| 1715 | 1519 | goto copcsr; |
| 1716 | − } | |
| 1717 | 1520 | |
| 1718 | −#if __mips >= 2 || defined(__mips64) | |
| 1719 | 1521 | case fround_op: |
| 1720 | 1522 | case ftrunc_op: |
| 1721 | 1523 | case fceil_op: |
| 1722 | − case ffloor_op:{ | |
| 1723 | − unsigned int oldrm = ieee754_csr.rm; | |
| 1724 | − ieee754sp fs; | |
| 1524 | + case ffloor_op: | |
| 1525 | + if (!cpu_has_mips_2_3_4_5 && !cpu_has_mips64) | |
| 1526 | + return SIGILL; | |
| 1725 | 1527 | |
| 1528 | + oldrm = ieee754_csr.rm; | |
| 1726 | 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 | 1531 | rv.w = ieee754sp_tint(fs); |
| 1729 | 1532 | ieee754_csr.rm = oldrm; |
| 1730 | 1533 | rfmt = w_fmt; |
| 1731 | 1534 | goto copcsr; |
| 1732 | − } | |
| 1733 | −#endif /* __mips >= 2 */ | |
| 1734 | 1535 | |
| 1735 | −#if defined(__mips64) | |
| 1736 | − case fcvtl_op:{ | |
| 1737 | − ieee754sp fs; | |
| 1536 | + case fcvtl_op: | |
| 1537 | + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | |
| 1538 | + return SIGILL; | |
| 1738 | 1539 | |
| 1739 | 1540 | SPFROMREG(fs, MIPSInst_FS(ir)); |
| 1740 | 1541 | rv.l = ieee754sp_tlong(fs); |
| 1741 | 1542 | rfmt = l_fmt; |
| 1742 | 1543 | goto copcsr; |
| 1743 | − } | |
| 1744 | 1544 | |
| 1745 | 1545 | case froundl_op: |
| 1746 | 1546 | case ftruncl_op: |
| 1747 | 1547 | case fceill_op: |
| 1748 | − case ffloorl_op:{ | |
| 1749 | − unsigned int oldrm = ieee754_csr.rm; | |
| 1750 | − ieee754sp fs; | |
| 1548 | + case ffloorl_op: | |
| 1549 | + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | |
| 1550 | + return SIGILL; | |
| 1751 | 1551 | |
| 1552 | + oldrm = ieee754_csr.rm; | |
| 1752 | 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 | 1555 | rv.l = ieee754sp_tlong(fs); |
| 1755 | 1556 | ieee754_csr.rm = oldrm; |
| 1756 | 1557 | rfmt = l_fmt; |
| 1757 | 1558 | goto copcsr; |
| 1758 | − } | |
| 1759 | −#endif /* defined(__mips64) */ | |
| 1760 | 1559 | |
| 1761 | 1560 | default: |
| 1762 | 1561 | if (MIPSInst_FUNC(ir) >= fcmp_op) { |
| 1763 | 1562 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
| 1764 | − ieee754sp fs, ft; | |
| 1563 | + union ieee754sp fs, ft; | |
| 1765 | 1564 | |
| 1766 | 1565 | SPFROMREG(fs, MIPSInst_FS(ir)); |
| 1767 | 1566 | SPFROMREG(ft, MIPSInst_FT(ir)); |
| @@ -1774,19 +1573,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 6 unmodified lines | ||
| 1774 | 1573 | else |
| 1775 | 1574 | goto copcsr; |
| 1776 | 1575 | |
| 1777 | − } | |
| 1778 | − else { | |
| 1576 | + } else | |
| 1779 | 1577 | return SIGILL; |
| 1780 | − } | |
| 1781 | 1578 | break; |
| 1782 | 1579 | } |
| 1783 | 1580 | break; |
| 1784 | 1581 | } |
| 1785 | 1582 | |
| 1786 | − case d_fmt:{ | |
| 1583 | + case d_fmt: { | |
| 1584 | + union ieee754dp fs, ft; | |
| 1787 | 1585 | union { |
| 1788 | − ieee754dp(*b) (ieee754dp, ieee754dp); | |
| 1789 | − ieee754dp(*u) (ieee754dp); | |
| 1586 | + union ieee754dp(*b) (union ieee754dp, union ieee754dp); | |
| 1587 | + union ieee754dp(*u) (union ieee754dp); | |
| 1790 | 1588 | } handler; |
| 1791 | 1589 | |
| 1792 | 1590 | switch (MIPSInst_FUNC(ir)) { |
| @@ -1805,21 +1603,33 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 12 unmodified lines | ||
| 1805 | 1603 | goto dcopbop; |
| 1806 | 1604 | |
| 1807 | 1605 | /* unary ops */ |
| 1808 | −#if __mips >= 2 || defined(__mips64) | |
| 1809 | 1606 | case fsqrt_op: |
| 1607 | + if (!cpu_has_mips_2_3_4_5_r) | |
| 1608 | + return SIGILL; | |
| 1609 | + | |
| 1810 | 1610 | handler.u = ieee754dp_sqrt; |
| 1811 | 1611 | goto dcopuop; |
| 1812 | −#endif | |
| 1813 | −#if __mips >= 4 && __mips != 32 | |
| 1612 | + /* | |
| 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 | 1617 | case frsqrt_op: |
| 1618 | + if (!cpu_has_mips_4_5_r2) | |
| 1619 | + return SIGILL; | |
| 1620 | + | |
| 1815 | 1621 | handler.u = fpemu_dp_rsqrt; |
| 1816 | 1622 | goto dcopuop; |
| 1817 | 1623 | case frecip_op: |
| 1624 | + if (!cpu_has_mips_4_5_r2) | |
| 1625 | + return SIGILL; | |
| 1626 | + | |
| 1818 | 1627 | handler.u = fpemu_dp_recip; |
| 1819 | 1628 | goto dcopuop; |
| 1820 | −#endif | |
| 1821 | −#if __mips >= 4 | |
| 1822 | 1629 | case fmovc_op: |
| 1630 | + if (!cpu_has_mips_4_5_r) | |
| 1631 | + return SIGILL; | |
| 1632 | + | |
| 1823 | 1633 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; |
| 1824 | 1634 | if (((ctx->fcr31 & cond) != 0) != |
| 1825 | 1635 | ((MIPSInst_FT(ir) & 1) != 0)) |
| @@ -1827,16 +1637,21 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 1 unmodified line | ||
| 1827 | 1637 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
| 1828 | 1638 | break; |
| 1829 | 1639 | case fmovz_op: |
| 1640 | + if (!cpu_has_mips_4_5_r) | |
| 1641 | + return SIGILL; | |
| 1642 | + | |
| 1830 | 1643 | if (xcp->regs[MIPSInst_FT(ir)] != 0) |
| 1831 | 1644 | return 0; |
| 1832 | 1645 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
| 1833 | 1646 | break; |
| 1834 | 1647 | case fmovn_op: |
| 1648 | + if (!cpu_has_mips_4_5_r) | |
| 1649 | + return SIGILL; | |
| 1650 | + | |
| 1835 | 1651 | if (xcp->regs[MIPSInst_FT(ir)] == 0) |
| 1836 | 1652 | return 0; |
| 1837 | 1653 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
| 1838 | 1654 | break; |
| 1839 | −#endif | |
| 1840 | 1655 | case fabs_op: |
| 1841 | 1656 | handler.u = ieee754dp_abs; |
| 1842 | 1657 | goto dcopuop; |
| @@ -1851,91 +1666,78 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 8 unmodified lines | ||
| 1851 | 1666 | goto copcsr; |
| 1852 | 1667 | |
| 1853 | 1668 | /* binary op on handler */ |
| 1854 | − dcopbop:{ | |
| 1855 | − ieee754dp fs, ft; | |
| 1856 | − | |
| 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 | − } | |
| 1669 | +dcopbop: | |
| 1670 | + DPFROMREG(fs, MIPSInst_FS(ir)); | |
| 1671 | + DPFROMREG(ft, MIPSInst_FT(ir)); | |
| 1870 | 1672 | |
| 1871 | − /* unary conv ops */ | |
| 1872 | − case fcvts_op:{ | |
| 1873 | − ieee754dp fs; | |
| 1673 | + rv.d = (*handler.b) (fs, ft); | |
| 1674 | + goto copcsr; | |
| 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 | 1684 | DPFROMREG(fs, MIPSInst_FS(ir)); |
| 1876 | 1685 | rv.s = ieee754sp_fdp(fs); |
| 1877 | 1686 | rfmt = s_fmt; |
| 1878 | 1687 | goto copcsr; |
| 1879 | − } | |
| 1688 | + | |
| 1880 | 1689 | case fcvtd_op: |
| 1881 | 1690 | return SIGILL; /* not defined */ |
| 1882 | 1691 | |
| 1883 | − case fcvtw_op:{ | |
| 1884 | − ieee754dp fs; | |
| 1885 | − | |
| 1692 | + case fcvtw_op: | |
| 1886 | 1693 | DPFROMREG(fs, MIPSInst_FS(ir)); |
| 1887 | 1694 | rv.w = ieee754dp_tint(fs); /* wrong */ |
| 1888 | 1695 | rfmt = w_fmt; |
| 1889 | 1696 | goto copcsr; |
| 1890 | − } | |
| 1891 | 1697 | |
| 1892 | −#if __mips >= 2 || defined(__mips64) | |
| 1893 | 1698 | case fround_op: |
| 1894 | 1699 | case ftrunc_op: |
| 1895 | 1700 | case fceil_op: |
| 1896 | − case ffloor_op:{ | |
| 1897 | − unsigned int oldrm = ieee754_csr.rm; | |
| 1898 | − ieee754dp fs; | |
| 1701 | + case ffloor_op: | |
| 1702 | + if (!cpu_has_mips_2_3_4_5_r) | |
| 1703 | + return SIGILL; | |
| 1899 | 1704 | |
| 1705 | + oldrm = ieee754_csr.rm; | |
| 1900 | 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 | 1708 | rv.w = ieee754dp_tint(fs); |
| 1903 | 1709 | ieee754_csr.rm = oldrm; |
| 1904 | 1710 | rfmt = w_fmt; |
| 1905 | 1711 | goto copcsr; |
| 1906 | − } | |
| 1907 | −#endif | |
| 1908 | 1712 | |
| 1909 | −#if defined(__mips64) | |
| 1910 | − case fcvtl_op:{ | |
| 1911 | − ieee754dp fs; | |
| 1713 | + case fcvtl_op: | |
| 1714 | + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | |
| 1715 | + return SIGILL; | |
| 1912 | 1716 | |
| 1913 | 1717 | DPFROMREG(fs, MIPSInst_FS(ir)); |
| 1914 | 1718 | rv.l = ieee754dp_tlong(fs); |
| 1915 | 1719 | rfmt = l_fmt; |
| 1916 | 1720 | goto copcsr; |
| 1917 | − } | |
| 1918 | 1721 | |
| 1919 | 1722 | case froundl_op: |
| 1920 | 1723 | case ftruncl_op: |
| 1921 | 1724 | case fceill_op: |
| 1922 | − case ffloorl_op:{ | |
| 1923 | − unsigned int oldrm = ieee754_csr.rm; | |
| 1924 | − ieee754dp fs; | |
| 1725 | + case ffloorl_op: | |
| 1726 | + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | |
| 1727 | + return SIGILL; | |
| 1925 | 1728 | |
| 1729 | + oldrm = ieee754_csr.rm; | |
| 1926 | 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 | 1732 | rv.l = ieee754dp_tlong(fs); |
| 1929 | 1733 | ieee754_csr.rm = oldrm; |
| 1930 | 1734 | rfmt = l_fmt; |
| 1931 | 1735 | goto copcsr; |
| 1932 | − } | |
| 1933 | −#endif /* __mips >= 3 */ | |
| 1934 | 1736 | |
| 1935 | 1737 | default: |
| 1936 | 1738 | if (MIPSInst_FUNC(ir) >= fcmp_op) { |
| 1937 | 1739 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
| 1938 | − ieee754dp fs, ft; | |
| 1740 | + union ieee754dp fs, ft; | |
| 1939 | 1741 | |
| 1940 | 1742 | DPFROMREG(fs, MIPSInst_FS(ir)); |
| 1941 | 1743 | DPFROMREG(ft, MIPSInst_FT(ir)); |
| @@ -1957,11 +1759,8 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 15 unmodified lines | ||
| 1957 | 1759 | break; |
| 1958 | 1760 | } |
| 1959 | 1761 | break; |
| 1960 | − } | |
| 1961 | − | |
| 1962 | − case w_fmt:{ | |
| 1963 | − ieee754sp fs; | |
| 1964 | 1762 | |
| 1763 | + case w_fmt: | |
| 1965 | 1764 | switch (MIPSInst_FUNC(ir)) { |
| 1966 | 1765 | case fcvts_op: |
| 1967 | 1766 | /* convert word to single precision real */ |
| @@ -1981,9 +1780,11 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 13 unmodified lines | ||
| 1981 | 1780 | break; |
| 1982 | 1781 | } |
| 1983 | 1782 | |
| 1984 | −#if defined(__mips64) | |
| 1985 | − case l_fmt:{ | |
| 1986 | − u64 bits; | |
| 1783 | + case l_fmt: | |
| 1784 | + | |
| 1785 | + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | |
| 1786 | + return SIGILL; | |
| 1787 | + | |
| 1987 | 1788 | DIFROMREG(bits, MIPSInst_FS(ir)); |
| 1988 | 1789 | |
| 1989 | 1790 | switch (MIPSInst_FUNC(ir)) { |
| @@ -2001,8 +1802,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 11 unmodified lines | ||
| 2001 | 1802 | return SIGILL; |
| 2002 | 1803 | } |
| 2003 | 1804 | break; |
| 2004 | − } | |
| 2005 | −#endif | |
| 2006 | 1805 | |
| 2007 | 1806 | default: |
| 2008 | 1807 | return SIGILL; |
| @@ -2017,7 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 8 unmodified lines | ||
| 2017 | 1816 | */ |
| 2018 | 1817 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; |
| 2019 | 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 | 1820 | return SIGFPE; |
| 2022 | 1821 | } |
| 2023 | 1822 | |
| @@ -2025,18 +1824,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 1 unmodified line | ||
| 2025 | 1824 | * Now we can safely write the result back to the register file. |
| 2026 | 1825 | */ |
| 2027 | 1826 | switch (rfmt) { |
| 2028 | − case -1:{ | |
| 2029 | −#if __mips >= 4 | |
| 2030 | − cond = fpucondbit[MIPSInst_FD(ir) >> 2]; | |
| 2031 | −#else | |
| 2032 | − cond = FPU_CSR_COND; | |
| 2033 | −#endif | |
| 1827 | + case -1: | |
| 1828 | + | |
| 1829 | + if (cpu_has_mips_4_5_r) | |
| 1830 | + cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; | |
| 1831 | + else | |
| 1832 | + cbit = FPU_CSR_COND; | |
| 2034 | 1833 | if (rv.w) |
| 2035 | − ctx->fcr31 |= cond; | |
| 1834 | + ctx->fcr31 |= cbit; | |
| 2036 | 1835 | else |
| 2037 | − ctx->fcr31 &= ~cond; | |
| 1836 | + ctx->fcr31 &= ~cbit; | |
| 2038 | 1837 | break; |
| 2039 | − } | |
| 1838 | + | |
| 2040 | 1839 | case d_fmt: |
| 2041 | 1840 | DPTOREG(rv.d, MIPSInst_FD(ir)); |
| 2042 | 1841 | break; |
| @@ -2046,11 +1845,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 3 unmodified lines | ||
| 2046 | 1845 | case w_fmt: |
| 2047 | 1846 | SITOREG(rv.w, MIPSInst_FD(ir)); |
| 2048 | 1847 | break; |
| 2049 | −#if defined(__mips64) | |
| 2050 | 1848 | case l_fmt: |
| 1849 | + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | |
| 1850 | + return SIGILL; | |
| 1851 | + | |
| 2051 | 1852 | DITOREG(rv.l, MIPSInst_FD(ir)); |
| 2052 | 1853 | break; |
| 2053 | −#endif | |
| 2054 | 1854 | default: |
| 2055 | 1855 | return SIGILL; |
| 2056 | 1856 | } |
| @@ -2138,11 +1938,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 81 unmodified lines | ||
| 2138 | 1938 | * ieee754_csr. But ieee754_csr.rm is ieee |
| 2139 | 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 | 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 | 1944 | if (has_fpu) |
| @@ -2155,58 +1951,8 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, · 6 unmodified lines | ||
| 2155 | 1951 | |
| 2156 | 1952 | /* SIGILL indicates a non-fpu instruction */ |
| 2157 | 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 | 1955 | sig = 0; |
| 2160 | 1956 | |
| 2161 | 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 | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,24 +16,22 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 25 | 20 | */ |
| 26 | 21 | |
| 27 | − | |
| 28 | 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 | 28 | COMPXDP; |
| 33 | 29 | COMPYDP; |
| 34 | 30 | |
| 35 | 31 | EXPLODEXDP; |
| 36 | 32 | EXPLODEYDP; |
| 37 | 33 | |
| 38 | − CLEARCX; | |
| 34 | + ieee754_clearcx(); | |
| 39 | 35 | |
| 40 | 36 | FLUSHXDP; |
| 41 | 37 | FLUSHYDP; |
| @@ -52,8 +48,8 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) · 10 unmodified lines | ||
| 52 | 48 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
| 53 | 49 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
| 54 | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
| 55 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 56 | − return ieee754dp_nanxcpt(ieee754dp_indef(), "add", x, y); | |
| 51 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 52 | + return ieee754dp_nanxcpt(ieee754dp_indef()); | |
| 57 | 53 | |
| 58 | 54 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
| 59 | 55 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
| @@ -69,14 +65,14 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) · 9 unmodified lines | ||
| 69 | 65 | return x; |
| 70 | 66 | |
| 71 | 67 | |
| 72 | − /* Infinity handling | |
| 73 | − */ | |
| 74 | − | |
| 68 | + /* | |
| 69 | + * Infinity handling | |
| 70 | + */ | |
| 75 | 71 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
| 76 | 72 | if (xs == ys) |
| 77 | 73 | return x; |
| 78 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 79 | − return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y); | |
| 74 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 75 | + return ieee754dp_indef(); | |
| 80 | 76 | |
| 81 | 77 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
| 82 | 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
| @@ -88,15 +84,14 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) · 5 unmodified lines | ||
| 88 | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
| 89 | 85 | return x; |
| 90 | 86 | |
| 91 | − /* Zero handling | |
| 92 | − */ | |
| 93 | − | |
| 87 | + /* | |
| 88 | + * Zero handling | |
| 89 | + */ | |
| 94 | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
| 95 | 91 | if (xs == ys) |
| 96 | 92 | return x; |
| 97 | 93 | else |
| 98 | − return ieee754dp_zero(ieee754_csr.rm == | |
| 99 | − IEEE754_RD); | |
| 94 | + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); | |
| 100 | 95 | |
| 101 | 96 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
| 102 | 97 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
| @@ -125,20 +120,24 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) · 22 unmodified lines | ||
| 125 | 120 | assert(xm & DP_HIDDEN_BIT); |
| 126 | 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 | 126 | xm <<= 3; |
| 130 | 127 | ym <<= 3; |
| 131 | 128 | |
| 132 | 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 | 134 | ym = XDPSRS(ym, s); |
| 137 | 135 | ye += s; |
| 138 | 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 | 141 | xm = XDPSRS(xm, s); |
| 143 | 142 | xe += s; |
| 144 | 143 | } |
| @@ -146,14 +145,15 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) · 1 unmodified line | ||
| 146 | 145 | assert(xe <= DP_EMAX); |
| 147 | 146 | |
| 148 | 147 | if (xs == ys) { |
| 149 | − /* generate 28 bit result of adding two 27 bit numbers | |
| 150 | − * leaving result in xm,xs,xe | |
| 148 | + /* | |
| 149 | + * Generate 28 bit result of adding two 27 bit numbers | |
| 150 | + * leaving result in xm, xs and xe. | |
| 151 | 151 | */ |
| 152 | 152 | xm = xm + ym; |
| 153 | 153 | xe = xe; |
| 154 | 154 | xs = xs; |
| 155 | 155 | |
| 156 | − if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ | |
| 156 | + if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */ | |
| 157 | 157 | xm = XDPSRS1(xm); |
| 158 | 158 | xe++; |
| 159 | 159 | } |
| @@ -168,15 +168,16 @@ ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) · 8 unmodified lines | ||
| 168 | 168 | xs = ys; |
| 169 | 169 | } |
| 170 | 170 | if (xm == 0) |
| 171 | − return ieee754dp_zero(ieee754_csr.rm == | |
| 172 | − IEEE754_RD); | |
| 171 | + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); | |
| 173 | 172 | |
| 174 | − /* normalize to rounding precision */ | |
| 175 | − while ((xm >> (DP_MBITS + 3)) == 0) { | |
| 173 | + /* | |
| 174 | + * Normalize to rounding precision. | |
| 175 | + */ | |
| 176 | + while ((xm >> (DP_FBITS + 3)) == 0) { | |
| 176 | 177 | xm <<= 1; |
| 177 | 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 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,16 +16,16 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 29 | COMPXDP; |
| 32 | 30 | COMPYDP; |
| 33 | 31 | |
| @@ -35,21 +33,21 @@ int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp, int sig) · 1 unmodified line | ||
| 35 | 33 | EXPLODEYDP; |
| 36 | 34 | FLUSHXDP; |
| 37 | 35 | FLUSHYDP; |
| 38 | − CLEARCX; /* Even clear inexact flag here */ | |
| 36 | + ieee754_clearcx(); /* Even clear inexact flag here */ | |
| 39 | 37 | |
| 40 | 38 | if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) { |
| 41 | 39 | if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) |
| 42 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 40 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 43 | 41 | if (cmp & IEEE754_CUN) |
| 44 | 42 | return 1; |
| 45 | 43 | if (cmp & (IEEE754_CLT | IEEE754_CGT)) { |
| 46 | − if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION)) | |
| 47 | − return ieee754si_xcpt(0, "fcmpf", x); | |
| 44 | + if (sig && ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) | |
| 45 | + return 0; | |
| 48 | 46 | } |
| 49 | 47 | return 0; |
| 50 | 48 | } else { |
| 51 | − s64 vx = x.bits; | |
| 52 | − s64 vy = y.bits; | |
| 49 | + vx = x.bits; | |
| 50 | + vy = y.bits; | |
| 53 | 51 | |
| 54 | 52 | if (vx < 0) |
| 55 | 53 | vx = -vx ^ DP_SIGN_BIT; |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,23 +16,24 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 30 | COMPXDP; |
| 32 | 31 | COMPYDP; |
| 33 | 32 | |
| 34 | 33 | EXPLODEXDP; |
| 35 | 34 | EXPLODEYDP; |
| 36 | 35 | |
| 37 | − CLEARCX; | |
| 36 | + ieee754_clearcx(); | |
| 38 | 37 | |
| 39 | 38 | FLUSHXDP; |
| 40 | 39 | FLUSHYDP; |
| @@ -51,8 +50,8 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) · 10 unmodified lines | ||
| 51 | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
| 52 | 51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
| 53 | 52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
| 54 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 55 | − return ieee754dp_nanxcpt(ieee754dp_indef(), "div", x, y); | |
| 53 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 54 | + return ieee754dp_nanxcpt(ieee754dp_indef()); | |
| 56 | 55 | |
| 57 | 56 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
| 58 | 57 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
| @@ -68,12 +67,12 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) · 9 unmodified lines | ||
| 68 | 67 | return x; |
| 69 | 68 | |
| 70 | 69 | |
| 71 | − /* Infinity handling | |
| 72 | − */ | |
| 73 | − | |
| 70 | + /* | |
| 71 | + * Infinity handling | |
| 72 | + */ | |
| 74 | 73 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
| 75 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 76 | − return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); | |
| 74 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 75 | + return ieee754dp_indef(); | |
| 77 | 76 | |
| 78 | 77 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
| 79 | 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
| @@ -85,17 +84,17 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) · 5 unmodified lines | ||
| 85 | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
| 86 | 85 | return ieee754dp_inf(xs ^ ys); |
| 87 | 86 | |
| 88 | − /* Zero handling | |
| 89 | − */ | |
| 90 | − | |
| 87 | + /* | |
| 88 | + * Zero handling | |
| 89 | + */ | |
| 91 | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
| 92 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 93 | − return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); | |
| 91 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 92 | + return ieee754dp_indef(); | |
| 94 | 93 | |
| 95 | 94 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
| 96 | 95 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
| 97 | − SETCX(IEEE754_ZERO_DIVIDE); | |
| 98 | − return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y); | |
| 96 | + ieee754_setcx(IEEE754_ZERO_DIVIDE); | |
| 97 | + return ieee754dp_inf(xs ^ ys); | |
| 99 | 98 | |
| 100 | 99 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): |
| 101 | 100 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): |
| @@ -122,35 +121,34 @@ ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) · 20 unmodified lines | ||
| 122 | 121 | xm <<= 3; |
| 123 | 122 | ym <<= 3; |
| 124 | 123 | |
| 125 | − { | |
| 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 */ | |
| 124 | + /* now the dirty work */ | |
| 144 | 125 | |
| 145 | − assert(rm); | |
| 126 | + rm = 0; | |
| 127 | + re = xe - ye; | |
| 146 | 128 | |
| 147 | − /* normalise rm to rounding precision ? | |
| 148 | − */ | |
| 149 | − while ((rm >> (DP_MBITS + 3)) == 0) { | |
| 150 | − rm <<= 1; | |
| 151 | − re--; | |
| 129 | + for (bm = DP_MBIT(DP_FBITS + 2); bm; bm >>= 1) { | |
| 130 | + if (xm >= ym) { | |
| 131 | + xm -= ym; | |
| 132 | + rm |= bm; | |
| 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 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,21 +16,18 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 22 | #include "ieee754dp.h" |
| 28 | 23 | |
| 29 | −ieee754dp ieee754dp_fint(int x) | |
| 24 | +union ieee754dp ieee754dp_fint(int x) | |
| 30 | 25 | { |
| 31 | 26 | u64 xm; |
| 32 | 27 | int xe; |
| 33 | 28 | int xs; |
| 34 | 29 | |
| 35 | − CLEARCX; | |
| 30 | + ieee754_clearcx(); | |
| 36 | 31 | |
| 37 | 32 | if (x == 0) |
| 38 | 33 | return ieee754dp_zero(0); |
| @@ -51,29 +46,11 @@ ieee754dp ieee754dp_fint(int x) · 12 unmodified lines | ||
| 51 | 46 | xm = x; |
| 52 | 47 | } |
| 53 | 48 | |
| 54 | −#if 1 | |
| 55 | 49 | /* normalize - result can never be inexact or overflow */ |
| 56 | − xe = DP_MBITS; | |
| 57 | − while ((xm >> DP_MBITS) == 0) { | |
| 50 | + xe = DP_FBITS; | |
| 51 | + while ((xm >> DP_FBITS) == 0) { | |
| 58 | 52 | xm <<= 1; |
| 59 | 53 | xe--; |
| 60 | 54 | } |
| 61 | 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 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,21 +16,18 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 22 | #include "ieee754dp.h" |
| 28 | 23 | |
| 29 | −ieee754dp ieee754dp_flong(s64 x) | |
| 24 | +union ieee754dp ieee754dp_flong(s64 x) | |
| 30 | 25 | { |
| 31 | 26 | u64 xm; |
| 32 | 27 | int xe; |
| 33 | 28 | int xs; |
| 34 | 29 | |
| 35 | − CLEARCX; | |
| 30 | + ieee754_clearcx(); | |
| 36 | 31 | |
| 37 | 32 | if (x == 0) |
| 38 | 33 | return ieee754dp_zero(0); |
| @@ -52,26 +47,19 @@ ieee754dp ieee754dp_flong(s64 x) · 13 unmodified lines | ||
| 52 | 47 | } |
| 53 | 48 | |
| 54 | 49 | /* normalize */ |
| 55 | − xe = DP_MBITS + 3; | |
| 56 | − if (xm >> (DP_MBITS + 1 + 3)) { | |
| 50 | + xe = DP_FBITS + 3; | |
| 51 | + if (xm >> (DP_FBITS + 1 + 3)) { | |
| 57 | 52 | /* shunt out overflow bits */ |
| 58 | − while (xm >> (DP_MBITS + 1 + 3)) { | |
| 53 | + while (xm >> (DP_FBITS + 1 + 3)) { | |
| 59 | 54 | XDPSRSX1(); |
| 60 | 55 | } |
| 61 | 56 | } else { |
| 62 | 57 | /* normalize in grs extended double precision */ |
| 63 | − while ((xm >> (DP_MBITS + 3)) == 0) { | |
| 58 | + while ((xm >> (DP_FBITS + 3)) == 0) { | |
| 64 | 59 | xm <<= 1; |
| 65 | 60 | xe--; |
| 66 | 61 | } |
| 67 | 62 | } |
| 68 | − DPNORMRET1(xs, xe, xm, "dp_flong", x); | |
| 69 | −} | |
| 70 | 63 | |
| 71 | −ieee754dp ieee754dp_fulong(u64 u) | |
| 72 | −{ | |
| 73 | − if ((s64) u < 0) | |
| 74 | − return ieee754dp_add(ieee754dp_1e63(), | |
| 75 | − ieee754dp_flong(u & ~(1ULL << 63))); | |
| 76 | − return ieee754dp_flong(u); | |
| 64 | + return ieee754dp_format(xs, xe, xm); | |
| 77 | 65 | } |
| @@ -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 | −} | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,56 +16,58 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 22 | +#include "ieee754sp.h" | |
| 27 | 23 | #include "ieee754dp.h" |
| 28 | 24 | |
| 29 | −ieee754dp ieee754dp_fsp(ieee754sp x) | |
| 25 | +union ieee754dp ieee754dp_fsp(union ieee754sp x) | |
| 30 | 26 | { |
| 31 | 27 | COMPXSP; |
| 32 | 28 | |
| 33 | 29 | EXPLODEXSP; |
| 34 | 30 | |
| 35 | − CLEARCX; | |
| 31 | + ieee754_clearcx(); | |
| 36 | 32 | |
| 37 | 33 | FLUSHXSP; |
| 38 | 34 | |
| 39 | 35 | switch (xc) { |
| 40 | 36 | case IEEE754_CLASS_SNAN: |
| 41 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 42 | − return ieee754dp_nanxcpt(ieee754dp_indef(), "fsp"); | |
| 37 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 38 | + return ieee754dp_nanxcpt(ieee754dp_indef()); | |
| 39 | + | |
| 43 | 40 | case IEEE754_CLASS_QNAN: |
| 44 | 41 | return ieee754dp_nanxcpt(builddp(xs, |
| 45 | 42 | DP_EMAX + 1 + DP_EBIAS, |
| 46 | 43 | ((u64) xm |
| 47 | − << (DP_MBITS - | |
| 48 | − SP_MBITS))), "fsp", | |
| 49 | − x); | |
| 44 | + << (DP_FBITS - | |
| 45 | + SP_FBITS)))); | |
| 50 | 46 | case IEEE754_CLASS_INF: |
| 51 | 47 | return ieee754dp_inf(xs); |
| 48 | + | |
| 52 | 49 | case IEEE754_CLASS_ZERO: |
| 53 | 50 | return ieee754dp_zero(xs); |
| 51 | + | |
| 54 | 52 | case IEEE754_CLASS_DNORM: |
| 55 | 53 | /* normalize */ |
| 56 | − while ((xm >> SP_MBITS) == 0) { | |
| 54 | + while ((xm >> SP_FBITS) == 0) { | |
| 57 | 55 | xm <<= 1; |
| 58 | 56 | xe--; |
| 59 | 57 | } |
| 60 | 58 | break; |
| 59 | + | |
| 61 | 60 | case IEEE754_CLASS_NORM: |
| 62 | 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 | 68 | /* drop the hidden bit */ |
| 69 | 69 | xm &= ~SP_HIDDEN_BIT; |
| 70 | 70 | |
| 71 | 71 | return builddp(xs, xe + DP_EBIAS, |
| 72 | − (u64) xm << (DP_MBITS - SP_MBITS)); | |
| 72 | + (u64) xm << (DP_FBITS - SP_FBITS)); | |
| 73 | 73 | } |
| @@ -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 | −} | |
| @@ -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 | −} | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,23 +16,32 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 38 | COMPXDP; |
| 32 | 39 | COMPYDP; |
| 33 | 40 | |
| 34 | 41 | EXPLODEXDP; |
| 35 | 42 | EXPLODEYDP; |
| 36 | 43 | |
| 37 | − CLEARCX; | |
| 44 | + ieee754_clearcx(); | |
| 38 | 45 | |
| 39 | 46 | FLUSHXDP; |
| 40 | 47 | FLUSHYDP; |
| @@ -51,8 +58,8 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) · 10 unmodified lines | ||
| 51 | 58 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
| 52 | 59 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
| 53 | 60 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
| 54 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 55 | − return ieee754dp_nanxcpt(ieee754dp_indef(), "mul", x, y); | |
| 61 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 62 | + return ieee754dp_nanxcpt(ieee754dp_indef()); | |
| 56 | 63 | |
| 57 | 64 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
| 58 | 65 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
| @@ -68,12 +75,13 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) · 9 unmodified lines | ||
| 68 | 75 | return x; |
| 69 | 76 | |
| 70 | 77 | |
| 71 | − /* Infinity handling */ | |
| 72 | − | |
| 78 | + /* | |
| 79 | + * Infinity handling | |
| 80 | + */ | |
| 73 | 81 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): |
| 74 | 82 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
| 75 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 76 | − return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y); | |
| 83 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 84 | + return ieee754dp_indef(); | |
| 77 | 85 | |
| 78 | 86 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
| 79 | 87 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): |
| @@ -107,70 +115,59 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) · 27 unmodified lines | ||
| 107 | 115 | /* rm = xm * ym, re = xe+ye basically */ |
| 108 | 116 | assert(xm & DP_HIDDEN_BIT); |
| 109 | 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 */ | |
| 116 | − xm <<= 64 - (DP_MBITS + 1); | |
| 117 | − ym <<= 64 - (DP_MBITS + 1); | |
| 119 | + re = xe + ye; | |
| 120 | + rs = xs ^ ys; | |
| 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 | |
| 120 | − */ | |
| 126 | + /* | |
| 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 | 131 | #define DPXMULT(x, y) ((u64)(x) * (u64)y) |
| 124 | 132 | |
| 125 | − { | |
| 126 | − unsigned lxm = xm; | |
| 127 | − unsigned hxm = xm >> 32; | |
| 128 | − unsigned lym = ym; | |
| 129 | − unsigned hym = ym >> 32; | |
| 130 | − u64 lrm; | |
| 131 | − u64 hrm; | |
| 132 | − | |
| 133 | − lrm = DPXMULT(lxm, lym); | |
| 134 | − hrm = DPXMULT(hxm, hym); | |
| 135 | − | |
| 136 | − { | |
| 137 | − u64 t = DPXMULT(lxm, hym); | |
| 138 | − { | |
| 139 | − u64 at = | |
| 140 | − lrm + (t << 32); | |
| 141 | − hrm += at < lrm; | |
| 142 | − lrm = at; | |
| 143 | − } | |
| 144 | − hrm = hrm + (t >> 32); | |
| 145 | − } | |
| 146 | − | |
| 147 | − { | |
| 148 | − u64 t = DPXMULT(hxm, lym); | |
| 149 | − { | |
| 150 | − u64 at = | |
| 151 | − lrm + (t << 32); | |
| 152 | − hrm += at < lrm; | |
| 153 | − lrm = at; | |
| 154 | − } | |
| 155 | − hrm = hrm + (t >> 32); | |
| 156 | − } | |
| 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); | |
| 133 | + lxm = xm; | |
| 134 | + hxm = xm >> 32; | |
| 135 | + lym = ym; | |
| 136 | + hym = ym >> 32; | |
| 137 | + | |
| 138 | + lrm = DPXMULT(lxm, lym); | |
| 139 | + hrm = DPXMULT(hxm, hym); | |
| 140 | + | |
| 141 | + t = DPXMULT(lxm, hym); | |
| 142 | + | |
| 143 | + at = lrm + (t << 32); | |
| 144 | + hrm += at < lrm; | |
| 145 | + lrm = at; | |
| 146 | + | |
| 147 | + hrm = hrm + (t >> 32); | |
| 148 | + | |
| 149 | + t = DPXMULT(hxm, lym); | |
| 150 | + | |
| 151 | + at = lrm + (t << 32); | |
| 152 | + hrm += at < lrm; | |
| 153 | + lrm = at; | |
| 154 | + | |
| 155 | + hrm = hrm + (t >> 32); | |
| 156 | + | |
| 157 | + rm = hrm | (lrm != 0); | |
| 158 | + | |
| 159 | + /* | |
| 160 | + * Sticky shift down to normal rounding precision. | |
| 161 | + */ | |
| 162 | + if ((s64) rm < 0) { | |
| 163 | + rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | | |
| 164 | + ((rm << (DP_FBITS + 1 + 3)) != 0); | |
| 167 | 165 | re++; |
| 168 | − } else { | |
| 169 | − rm = | |
| 170 | − (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) | | |
| 171 | − ((rm << (DP_MBITS + 1 + 3 + 1)) != 0); | |
| 172 | − } | |
| 173 | − assert(rm & (DP_HIDDEN_BIT << 3)); | |
| 174 | − DPNORMRET2(rs, re, rm, "mul", x, y); | |
| 166 | + } else { | |
| 167 | + rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | | |
| 168 | + ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); | |
| 175 | 169 | } |
| 170 | + assert(rm & (DP_HIDDEN_BIT << 3)); | |
| 171 | + | |
| 172 | + return ieee754dp_format(rs, re, rm); | |
| 176 | 173 | } |
| @@ -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 | −} | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,33 +16,17 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 22 | #include "ieee754dp.h" |
| 28 | 23 | |
| 29 | −int ieee754dp_finite(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) | |
| 24 | +union ieee754dp ieee754dp_neg(union ieee754dp x) | |
| 43 | 25 | { |
| 44 | 26 | COMPXDP; |
| 45 | 27 | |
| 46 | 28 | EXPLODEXDP; |
| 47 | − CLEARCX; | |
| 29 | + ieee754_clearcx(); | |
| 48 | 30 | FLUSHXDP; |
| 49 | 31 | |
| 50 | 32 | /* |
| @@ -55,30 +37,29 @@ ieee754dp ieee754dp_neg(ieee754dp x) · 4 unmodified lines | ||
| 55 | 37 | DPSIGN(x) ^= 1; |
| 56 | 38 | |
| 57 | 39 | if (xc == IEEE754_CLASS_SNAN) { |
| 58 | − ieee754dp y = ieee754dp_indef(); | |
| 59 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 40 | + union ieee754dp y = ieee754dp_indef(); | |
| 41 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 60 | 42 | DPSIGN(y) = DPSIGN(x); |
| 61 | − return ieee754dp_nanxcpt(y, "neg"); | |
| 43 | + return ieee754dp_nanxcpt(y); | |
| 62 | 44 | } |
| 63 | 45 | |
| 64 | 46 | return x; |
| 65 | 47 | } |
| 66 | 48 | |
| 67 | − | |
| 68 | −ieee754dp ieee754dp_abs(ieee754dp x) | |
| 49 | +union ieee754dp ieee754dp_abs(union ieee754dp x) | |
| 69 | 50 | { |
| 70 | 51 | COMPXDP; |
| 71 | 52 | |
| 72 | 53 | EXPLODEXDP; |
| 73 | − CLEARCX; | |
| 54 | + ieee754_clearcx(); | |
| 74 | 55 | FLUSHXDP; |
| 75 | 56 | |
| 76 | 57 | /* Clear sign ALWAYS, irrespective of NaN */ |
| 77 | 58 | DPSIGN(x) = 0; |
| 78 | 59 | |
| 79 | 60 | if (xc == IEEE754_CLASS_SNAN) { |
| 80 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 81 | − return ieee754dp_nanxcpt(ieee754dp_indef(), "abs"); | |
| 61 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 62 | + return ieee754dp_nanxcpt(ieee754dp_indef()); | |
| 82 | 63 | } |
| 83 | 64 | |
| 84 | 65 | return x; |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,12 +16,9 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 22 | #include "ieee754dp.h" |
| 28 | 23 | |
| 29 | 24 | static const unsigned table[] = { |
| @@ -34,44 +29,49 @@ static const unsigned table[] = { · 4 unmodified lines | ||
| 34 | 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 | 34 | struct _ieee754_csr oldcsr; |
| 40 | − ieee754dp y, z, t; | |
| 35 | + union ieee754dp y, z, t; | |
| 41 | 36 | unsigned scalx, yh; |
| 42 | 37 | COMPXDP; |
| 43 | 38 | |
| 44 | 39 | EXPLODEXDP; |
| 45 | − CLEARCX; | |
| 40 | + ieee754_clearcx(); | |
| 46 | 41 | FLUSHXDP; |
| 47 | 42 | |
| 48 | 43 | /* x == INF or NAN? */ |
| 49 | 44 | switch (xc) { |
| 50 | 45 | case IEEE754_CLASS_QNAN: |
| 51 | 46 | /* sqrt(Nan) = Nan */ |
| 52 | − return ieee754dp_nanxcpt(x, "sqrt"); | |
| 47 | + return ieee754dp_nanxcpt(x); | |
| 48 | + | |
| 53 | 49 | case IEEE754_CLASS_SNAN: |
| 54 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 55 | − return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); | |
| 50 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 51 | + return ieee754dp_nanxcpt(ieee754dp_indef()); | |
| 52 | + | |
| 56 | 53 | case IEEE754_CLASS_ZERO: |
| 57 | 54 | /* sqrt(0) = 0 */ |
| 58 | 55 | return x; |
| 56 | + | |
| 59 | 57 | case IEEE754_CLASS_INF: |
| 60 | 58 | if (xs) { |
| 61 | 59 | /* sqrt(-Inf) = Nan */ |
| 62 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 63 | − return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); | |
| 60 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 61 | + return ieee754dp_nanxcpt(ieee754dp_indef()); | |
| 64 | 62 | } |
| 65 | 63 | /* sqrt(+Inf) = Inf */ |
| 66 | 64 | return x; |
| 65 | + | |
| 67 | 66 | case IEEE754_CLASS_DNORM: |
| 68 | 67 | DPDNORMX; |
| 69 | 68 | /* fall through */ |
| 69 | + | |
| 70 | 70 | case IEEE754_CLASS_NORM: |
| 71 | 71 | if (xs) { |
| 72 | 72 | /* sqrt(-x) = Nan */ |
| 73 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 74 | − return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); | |
| 73 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 74 | + return ieee754dp_nanxcpt(ieee754dp_indef()); | |
| 75 | 75 | } |
| 76 | 76 | break; |
| 77 | 77 | } |
| @@ -80,7 +80,7 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) · 2 unmodified lines | ||
| 80 | 80 | oldcsr = ieee754_csr; |
| 81 | 81 | ieee754_csr.mx &= ~IEEE754_INEXACT; |
| 82 | 82 | ieee754_csr.sx &= ~IEEE754_INEXACT; |
| 83 | − ieee754_csr.rm = IEEE754_RN; | |
| 83 | + ieee754_csr.rm = FPU_CSR_RN; | |
| 84 | 84 | |
| 85 | 85 | /* adjust exponent to prevent overflow */ |
| 86 | 86 | scalx = 0; |
| @@ -110,19 +110,19 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) · 23 unmodified lines | ||
| 110 | 110 | /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */ |
| 111 | 111 | /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */ |
| 112 | 112 | z = t = ieee754dp_mul(y, y); |
| 113 | − t.parts.bexp += 0x001; | |
| 113 | + t.bexp += 0x001; | |
| 114 | 114 | t = ieee754dp_add(t, z); |
| 115 | 115 | z = ieee754dp_mul(ieee754dp_sub(x, z), y); |
| 116 | 116 | |
| 117 | 117 | /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */ |
| 118 | 118 | t = ieee754dp_div(z, ieee754dp_add(t, x)); |
| 119 | − t.parts.bexp += 0x001; | |
| 119 | + t.bexp += 0x001; | |
| 120 | 120 | y = ieee754dp_add(y, t); |
| 121 | 121 | |
| 122 | 122 | /* twiddle last bit to force y correctly rounded */ |
| 123 | 123 | |
| 124 | 124 | /* set RZ, clear INEX flag */ |
| 125 | − ieee754_csr.rm = IEEE754_RZ; | |
| 125 | + ieee754_csr.rm = FPU_CSR_RZ; | |
| 126 | 126 | ieee754_csr.sx &= ~IEEE754_INEXACT; |
| 127 | 127 | |
| 128 | 128 | /* t=x/y; ...chopped quotient, possibly inexact */ |
| @@ -139,10 +139,10 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) · 10 unmodified lines | ||
| 139 | 139 | oldcsr.sx |= IEEE754_INEXACT; |
| 140 | 140 | |
| 141 | 141 | switch (oldcsr.rm) { |
| 142 | − case IEEE754_RP: | |
| 142 | + case FPU_CSR_RU: | |
| 143 | 143 | y.bits += 1; |
| 144 | 144 | /* drop through */ |
| 145 | − case IEEE754_RN: | |
| 145 | + case FPU_CSR_RN: | |
| 146 | 146 | t.bits += 1; |
| 147 | 147 | break; |
| 148 | 148 | } |
| @@ -155,7 +155,7 @@ ieee754dp ieee754dp_sqrt(ieee754dp x) · 6 unmodified lines | ||
| 155 | 155 | } |
| 156 | 156 | |
| 157 | 157 | /* py[n0]=py[n0]+scalx; ...scale back y */ |
| 158 | − y.parts.bexp += scalx; | |
| 158 | + y.bexp += scalx; | |
| 159 | 159 | |
| 160 | 160 | /* restore rounding mode, possibly set inexact */ |
| 161 | 161 | ieee754_csr = oldcsr; |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,23 +16,22 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 28 | COMPXDP; |
| 32 | 29 | COMPYDP; |
| 33 | 30 | |
| 34 | 31 | EXPLODEXDP; |
| 35 | 32 | EXPLODEYDP; |
| 36 | 33 | |
| 37 | − CLEARCX; | |
| 34 | + ieee754_clearcx(); | |
| 38 | 35 | |
| 39 | 36 | FLUSHXDP; |
| 40 | 37 | FLUSHYDP; |
| @@ -51,8 +48,8 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) · 10 unmodified lines | ||
| 51 | 48 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
| 52 | 49 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
| 53 | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
| 54 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 55 | − return ieee754dp_nanxcpt(ieee754dp_indef(), "sub", x, y); | |
| 51 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 52 | + return ieee754dp_nanxcpt(ieee754dp_indef()); | |
| 56 | 53 | |
| 57 | 54 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
| 58 | 55 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
| @@ -68,14 +65,14 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) · 9 unmodified lines | ||
| 68 | 65 | return x; |
| 69 | 66 | |
| 70 | 67 | |
| 71 | − /* Infinity handling | |
| 72 | − */ | |
| 73 | − | |
| 68 | + /* | |
| 69 | + * Infinity handling | |
| 70 | + */ | |
| 74 | 71 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
| 75 | 72 | if (xs != ys) |
| 76 | 73 | return x; |
| 77 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 78 | − return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y); | |
| 74 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 75 | + return ieee754dp_indef(); | |
| 79 | 76 | |
| 80 | 77 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
| 81 | 78 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): |
| @@ -87,15 +84,14 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) · 5 unmodified lines | ||
| 87 | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
| 88 | 85 | return x; |
| 89 | 86 | |
| 90 | − /* Zero handling | |
| 91 | − */ | |
| 92 | − | |
| 87 | + /* | |
| 88 | + * Zero handling | |
| 89 | + */ | |
| 93 | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
| 94 | 91 | if (xs != ys) |
| 95 | 92 | return x; |
| 96 | 93 | else |
| 97 | − return ieee754dp_zero(ieee754_csr.rm == | |
| 98 | − IEEE754_RD); | |
| 94 | + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); | |
| 99 | 95 | |
| 100 | 96 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
| 101 | 97 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
| @@ -136,15 +132,17 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) · 34 unmodified lines | ||
| 136 | 132 | ym <<= 3; |
| 137 | 133 | |
| 138 | 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 | 139 | ym = XDPSRS(ym, s); |
| 143 | 140 | ye += s; |
| 144 | 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 | 146 | xm = XDPSRS(xm, s); |
| 149 | 147 | xe += s; |
| 150 | 148 | } |
| @@ -158,7 +156,7 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) · 7 unmodified lines | ||
| 158 | 156 | xe = xe; |
| 159 | 157 | xs = xs; |
| 160 | 158 | |
| 161 | − if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ | |
| 159 | + if (xm >> (DP_FBITS + 1 + 3)) { /* carry out */ | |
| 162 | 160 | xm = XDPSRS1(xm); /* shift preserving sticky */ |
| 163 | 161 | xe++; |
| 164 | 162 | } |
| @@ -173,7 +171,7 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) · 8 unmodified lines | ||
| 173 | 171 | xs = ys; |
| 174 | 172 | } |
| 175 | 173 | if (xm == 0) { |
| 176 | − if (ieee754_csr.rm == IEEE754_RD) | |
| 174 | + if (ieee754_csr.rm == FPU_CSR_RD) | |
| 177 | 175 | return ieee754dp_zero(1); /* round negative inf. => sign = -1 */ |
| 178 | 176 | else |
| 179 | 177 | return ieee754dp_zero(0); /* other round modes => sign = 1 */ |
| @@ -181,10 +179,11 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) · 1 unmodified line | ||
| 181 | 179 | |
| 182 | 180 | /* normalize to rounding precision |
| 183 | 181 | */ |
| 184 | − while ((xm >> (DP_MBITS + 3)) == 0) { | |
| 182 | + while ((xm >> (DP_FBITS + 3)) == 0) { | |
| 185 | 183 | xm <<= 1; |
| 186 | 184 | xe--; |
| 187 | 185 | } |
| 188 | 186 | } |
| 189 | − DPNORMRET2(xs, xe, xm, "sub", x, y); | |
| 187 | + | |
| 188 | + return ieee754dp_format(xs, xe, xm); | |
| 190 | 189 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,20 +16,21 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | −#include <linux/kernel.h> | |
| 28 | 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 | 31 | COMPXDP; |
| 33 | 32 | |
| 34 | − CLEARCX; | |
| 33 | + ieee754_clearcx(); | |
| 35 | 34 | |
| 36 | 35 | EXPLODEXDP; |
| 37 | 36 | FLUSHXDP; |
| @@ -40,10 +39,12 @@ int ieee754dp_tint(ieee754dp x) · 2 unmodified lines | ||
| 40 | 39 | case IEEE754_CLASS_SNAN: |
| 41 | 40 | case IEEE754_CLASS_QNAN: |
| 42 | 41 | case IEEE754_CLASS_INF: |
| 43 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 44 | − return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); | |
| 42 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 43 | + return ieee754si_indef(); | |
| 44 | + | |
| 45 | 45 | case IEEE754_CLASS_ZERO: |
| 46 | 46 | return 0; |
| 47 | + | |
| 47 | 48 | case IEEE754_CLASS_DNORM: |
| 48 | 49 | case IEEE754_CLASS_NORM: |
| 49 | 50 | break; |
| @@ -51,44 +52,39 @@ int ieee754dp_tint(ieee754dp x) · 1 unmodified line | ||
| 51 | 52 | if (xe > 31) { |
| 52 | 53 | /* Set invalid. We will only use overflow for floating |
| 53 | 54 | point overflow */ |
| 54 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 55 | − return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); | |
| 55 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 56 | + return ieee754si_indef(); | |
| 56 | 57 | } |
| 57 | 58 | /* oh gawd */ |
| 58 | − if (xe > DP_MBITS) { | |
| 59 | − xm <<= xe - DP_MBITS; | |
| 60 | − } else if (xe < DP_MBITS) { | |
| 61 | − u64 residue; | |
| 62 | − int round; | |
| 63 | − int sticky; | |
| 64 | − int odd; | |
| 65 | − | |
| 59 | + if (xe > DP_FBITS) { | |
| 60 | + xm <<= xe - DP_FBITS; | |
| 61 | + } else if (xe < DP_FBITS) { | |
| 66 | 62 | if (xe < -1) { |
| 67 | 63 | residue = xm; |
| 68 | 64 | round = 0; |
| 69 | 65 | sticky = residue != 0; |
| 70 | 66 | xm = 0; |
| 71 | 67 | } else { |
| 72 | − residue = xm << (64 - DP_MBITS + xe); | |
| 68 | + residue = xm << (64 - DP_FBITS + xe); | |
| 73 | 69 | round = (residue >> 63) != 0; |
| 74 | 70 | sticky = (residue << 1) != 0; |
| 75 | − xm >>= DP_MBITS - xe; | |
| 71 | + xm >>= DP_FBITS - xe; | |
| 76 | 72 | } |
| 77 | 73 | /* Note: At this point upper 32 bits of xm are guaranteed |
| 78 | 74 | to be zero */ |
| 79 | 75 | odd = (xm & 0x1) != 0x0; |
| 80 | 76 | switch (ieee754_csr.rm) { |
| 81 | − case IEEE754_RN: | |
| 77 | + case FPU_CSR_RN: | |
| 82 | 78 | if (round && (sticky || odd)) |
| 83 | 79 | xm++; |
| 84 | 80 | break; |
| 85 | − case IEEE754_RZ: | |
| 81 | + case FPU_CSR_RZ: | |
| 86 | 82 | break; |
| 87 | − case IEEE754_RU: /* toward +Infinity */ | |
| 83 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 88 | 84 | if ((round || sticky) && !xs) |
| 89 | 85 | xm++; |
| 90 | 86 | break; |
| 91 | − case IEEE754_RD: /* toward -Infinity */ | |
| 87 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 92 | 88 | if ((round || sticky) && xs) |
| 93 | 89 | xm++; |
| 94 | 90 | break; |
| @@ -96,27 +92,14 @@ int ieee754dp_tint(ieee754dp x) · 1 unmodified line | ||
| 96 | 92 | /* look for valid corner case 0x80000000 */ |
| 97 | 93 | if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) { |
| 98 | 94 | /* This can happen after rounding */ |
| 99 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 100 | − return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); | |
| 95 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 96 | + return ieee754si_indef(); | |
| 101 | 97 | } |
| 102 | 98 | if (round || sticky) |
| 103 | − SETCX(IEEE754_INEXACT); | |
| 99 | + ieee754_setcx(IEEE754_INEXACT); | |
| 104 | 100 | } |
| 105 | 101 | if (xs) |
| 106 | 102 | return -xm; |
| 107 | 103 | else |
| 108 | 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 | −} | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,19 +16,21 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 31 | COMPXDP; |
| 32 | 32 | |
| 33 | − CLEARCX; | |
| 33 | + ieee754_clearcx(); | |
| 34 | 34 | |
| 35 | 35 | EXPLODEXDP; |
| 36 | 36 | FLUSHXDP; |
| @@ -39,10 +39,12 @@ s64 ieee754dp_tlong(ieee754dp x) · 2 unmodified lines | ||
| 39 | 39 | case IEEE754_CLASS_SNAN: |
| 40 | 40 | case IEEE754_CLASS_QNAN: |
| 41 | 41 | case IEEE754_CLASS_INF: |
| 42 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 43 | − return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); | |
| 42 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 43 | + return ieee754di_indef(); | |
| 44 | + | |
| 44 | 45 | case IEEE754_CLASS_ZERO: |
| 45 | 46 | return 0; |
| 47 | + | |
| 46 | 48 | case IEEE754_CLASS_DNORM: |
| 47 | 49 | case IEEE754_CLASS_NORM: |
| 48 | 50 | break; |
| @@ -53,18 +55,13 @@ s64 ieee754dp_tlong(ieee754dp x) · 4 unmodified lines | ||
| 53 | 55 | return -0x8000000000000000LL; |
| 54 | 56 | /* Set invalid. We will only use overflow for floating |
| 55 | 57 | point overflow */ |
| 56 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 57 | − return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); | |
| 58 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 59 | + return ieee754di_indef(); | |
| 58 | 60 | } |
| 59 | 61 | /* oh gawd */ |
| 60 | − if (xe > DP_MBITS) { | |
| 61 | − xm <<= xe - DP_MBITS; | |
| 62 | − } else if (xe < DP_MBITS) { | |
| 63 | − u64 residue; | |
| 64 | − int round; | |
| 65 | − int sticky; | |
| 66 | − int odd; | |
| 67 | − | |
| 62 | + if (xe > DP_FBITS) { | |
| 63 | + xm <<= xe - DP_FBITS; | |
| 64 | + } else if (xe < DP_FBITS) { | |
| 68 | 65 | if (xe < -1) { |
| 69 | 66 | residue = xm; |
| 70 | 67 | round = 0; |
| @@ -75,51 +72,38 @@ s64 ieee754dp_tlong(ieee754dp x) · 4 unmodified lines | ||
| 75 | 72 | * so we do it in two steps. Be aware that xe |
| 76 | 73 | * may be -1 */ |
| 77 | 74 | residue = xm << (xe + 1); |
| 78 | − residue <<= 63 - DP_MBITS; | |
| 75 | + residue <<= 63 - DP_FBITS; | |
| 79 | 76 | round = (residue >> 63) != 0; |
| 80 | 77 | sticky = (residue << 1) != 0; |
| 81 | − xm >>= DP_MBITS - xe; | |
| 78 | + xm >>= DP_FBITS - xe; | |
| 82 | 79 | } |
| 83 | 80 | odd = (xm & 0x1) != 0x0; |
| 84 | 81 | switch (ieee754_csr.rm) { |
| 85 | − case IEEE754_RN: | |
| 82 | + case FPU_CSR_RN: | |
| 86 | 83 | if (round && (sticky || odd)) |
| 87 | 84 | xm++; |
| 88 | 85 | break; |
| 89 | − case IEEE754_RZ: | |
| 86 | + case FPU_CSR_RZ: | |
| 90 | 87 | break; |
| 91 | − case IEEE754_RU: /* toward +Infinity */ | |
| 88 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 92 | 89 | if ((round || sticky) && !xs) |
| 93 | 90 | xm++; |
| 94 | 91 | break; |
| 95 | − case IEEE754_RD: /* toward -Infinity */ | |
| 92 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 96 | 93 | if ((round || sticky) && xs) |
| 97 | 94 | xm++; |
| 98 | 95 | break; |
| 99 | 96 | } |
| 100 | 97 | if ((xm >> 63) != 0) { |
| 101 | 98 | /* This can happen after rounding */ |
| 102 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 103 | − return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); | |
| 99 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 100 | + return ieee754di_indef(); | |
| 104 | 101 | } |
| 105 | 102 | if (round || sticky) |
| 106 | − SETCX(IEEE754_INEXACT); | |
| 103 | + ieee754_setcx(IEEE754_INEXACT); | |
| 107 | 104 | } |
| 108 | 105 | if (xs) |
| 109 | 106 | return -xm; |
| 110 | 107 | else |
| 111 | 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 | −} | |
| @@ -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 | 1 | #include <asm/branch.h> |
| 14 | −#include <asm/mipsregs.h> | |
| 15 | 2 | #include <asm/cacheflush.h> |
| 16 | − | |
| 17 | 3 | #include <asm/fpu_emulator.h> |
| 4 | +#include <asm/inst.h> | |
| 5 | +#include <asm/mipsregs.h> | |
| 6 | +#include <asm/uaccess.h> | |
| 18 | 7 | |
| 19 | 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 | 11 | * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when |
| 30 | 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) · 28 unmodified lines | ||
| 59 | 41 | (ir == 0)) { |
| 60 | 42 | /* NOP is easy */ |
| 61 | 43 | regs->cp0_epc = cpc; |
| 62 | − regs->cp0_cause &= ~CAUSEF_BD; | |
| 44 | + clear_delay_slot(regs); | |
| 63 | 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 | 51 | * The strategy is to push the instruction onto the user stack |
| @@ -167,9 +147,8 @@ int do_dsemulret(struct pt_regs *xcp) · 95 unmodified lines | ||
| 167 | 147 | * emulating the branch delay instruction. |
| 168 | 148 | */ |
| 169 | 149 | |
| 170 | −#ifdef DSEMUL_TRACE | |
| 171 | − printk("dsemulret\n"); | |
| 172 | −#endif | |
| 150 | + pr_debug("dsemulret\n"); | |
| 151 | + | |
| 173 | 152 | if (__get_user(epc, &fr->epc)) { /* Saved EPC */ |
| 174 | 153 | /* This is not a good situation to be in */ |
| 175 | 154 | force_sig(SIGBUS, current); |
| @@ -10,8 +10,6 @@ · 9 unmodified lines | ||
| 10 | 10 | * MIPS floating point support |
| 11 | 11 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 12 | 12 | * |
| 13 | − * ######################################################################## | |
| 14 | − * | |
| 15 | 13 | * This program is free software; you can distribute it and/or modify it |
| 16 | 14 | * under the terms of the GNU General Public License (Version 2) as |
| 17 | 15 | * published by the Free Software Foundation. |
| @@ -23,105 +21,69 @@ · 5 unmodified lines | ||
| 23 | 21 | * |
| 24 | 22 | * You should have received a copy of the GNU General Public License along |
| 25 | 23 | * with this program; if not, write to the Free Software Foundation, Inc., |
| 26 | − * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
| 27 | − * | |
| 28 | − * ######################################################################## | |
| 24 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 29 | 25 | */ |
| 30 | 26 | |
| 27 | +#include <linux/compiler.h> | |
| 31 | 28 | |
| 32 | −#include "ieee754int.h" | |
| 29 | +#include "ieee754.h" | |
| 33 | 30 | #include "ieee754sp.h" |
| 34 | 31 | #include "ieee754dp.h" |
| 35 | 32 | |
| 36 | −#define DP_EBIAS 1023 | |
| 37 | −#define DP_EMIN (-1022) | |
| 38 | −#define DP_EMAX 1023 | |
| 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 | |
| 33 | +/* | |
| 34 | + * Special constants | |
| 35 | + */ | |
| 57 | 36 | |
| 58 | −const struct ieee754dp_konst __ieee754dp_spcvals[] = { | |
| 59 | − DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* + zero */ | |
| 60 | − DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* - zero */ | |
| 61 | − DPSTR(0, DP_EBIAS, 0, 0), /* + 1.0 */ | |
| 62 | − DPSTR(1, DP_EBIAS, 0, 0), /* - 1.0 */ | |
| 63 | − DPSTR(0, 3 + DP_EBIAS, 0x40000, 0), /* + 10.0 */ | |
| 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 | −}; | |
| 37 | +#define DPCNST(s, b, m) \ | |
| 38 | +{ \ | |
| 39 | + .sign = (s), \ | |
| 40 | + .bexp = (b) + DP_EBIAS, \ | |
| 41 | + .mant = (m) \ | |
| 42 | +} | |
| 77 | 43 | |
| 78 | −const struct ieee754sp_konst __ieee754sp_spcvals[] = { | |
| 79 | − SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0), /* + zero */ | |
| 80 | − SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0), /* - zero */ | |
| 81 | − SPSTR(0, SP_EBIAS, 0), /* + 1.0 */ | |
| 82 | − SPSTR(1, SP_EBIAS, 0), /* - 1.0 */ | |
| 83 | − SPSTR(0, 3 + SP_EBIAS, 0x200000), /* + 10.0 */ | |
| 84 | − SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */ | |
| 85 | − SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */ | |
| 86 | − SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */ | |
| 87 | − SPSTR(0, SP_EMAX+1+SP_EBIAS, 0x3FFFFF), /* + indef quiet Nan */ | |
| 88 | − SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */ | |
| 89 | − SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */ | |
| 90 | − SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */ | |
| 91 | − SPSTR(1, SP_EMIN + SP_EBIAS, 0), /* - min normal */ | |
| 92 | − SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1), /* + min denormal */ | |
| 93 | − SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1), /* - min denormal */ | |
| 94 | − SPSTR(0, 31 + SP_EBIAS, 0), /* + 1.0e31 */ | |
| 95 | − SPSTR(0, 63 + SP_EBIAS, 0), /* + 1.0e63 */ | |
| 44 | +const union ieee754dp __ieee754dp_spcvals[] = { | |
| 45 | + DPCNST(0, DP_EMIN - 1, 0x0000000000000ULL), /* + zero */ | |
| 46 | + DPCNST(1, DP_EMIN - 1, 0x0000000000000ULL), /* - zero */ | |
| 47 | + DPCNST(0, 0, 0x0000000000000ULL), /* + 1.0 */ | |
| 48 | + DPCNST(1, 0, 0x0000000000000ULL), /* - 1.0 */ | |
| 49 | + DPCNST(0, 3, 0x4000000000000ULL), /* + 10.0 */ | |
| 50 | + DPCNST(1, 3, 0x4000000000000ULL), /* - 10.0 */ | |
| 51 | + DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL), /* + infinity */ | |
| 52 | + DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL), /* - infinity */ | |
| 53 | + DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL), /* + indef quiet Nan */ | |
| 54 | + DPCNST(0, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* + max */ | |
| 55 | + DPCNST(1, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* - max */ | |
| 56 | + DPCNST(0, DP_EMIN, 0x0000000000000ULL), /* + min normal */ | |
| 57 | + DPCNST(1, DP_EMIN, 0x0000000000000ULL), /* - min normal */ | |
| 58 | + DPCNST(0, DP_EMIN - 1, 0x0000000000001ULL), /* + min denormal */ | |
| 59 | + DPCNST(1, DP_EMIN - 1, 0x0000000000001ULL), /* - min denormal */ | |
| 60 | + DPCNST(0, 31, 0x0000000000000ULL), /* + 1.0e31 */ | |
| 61 | + DPCNST(0, 63, 0x0000000000000ULL), /* + 1.0e63 */ | |
| 96 | 62 | }; |
| 97 | 63 | |
| 98 | − | |
| 99 | −int ieee754si_xcpt(int r, const char *op, ...) | |
| 100 | −{ | |
| 101 | − struct ieee754xctx ax; | |
| 102 | − | |
| 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; | |
| 64 | +#define SPCNST(s, b, m) \ | |
| 65 | +{ \ | |
| 66 | + .sign = (s), \ | |
| 67 | + .bexp = (b) + SP_EBIAS, \ | |
| 68 | + .mant = (m) \ | |
| 112 | 69 | } |
| 113 | 70 | |
| 114 | −s64 ieee754di_xcpt(s64 r, const char *op, ...) | |
| 115 | −{ | |
| 116 | − struct ieee754xctx ax; | |
| 117 | − | |
| 118 | − if (!TSTX()) | |
| 119 | − return r; | |
| 120 | − ax.op = op; | |
| 121 | − ax.rt = IEEE754_RT_DI; | |
| 122 | − ax.rv.di = r; | |
| 123 | − va_start(ax.ap, op); | |
| 124 | − ieee754_xcpt(&ax); | |
| 125 | − va_end(ax.ap); | |
| 126 | − return ax.rv.di; | |
| 127 | −} | |
| 71 | +const union ieee754sp __ieee754sp_spcvals[] = { | |
| 72 | + SPCNST(0, SP_EMIN - 1, 0x000000), /* + zero */ | |
| 73 | + SPCNST(1, SP_EMIN - 1, 0x000000), /* - zero */ | |
| 74 | + SPCNST(0, 0, 0x000000), /* + 1.0 */ | |
| 75 | + SPCNST(1, 0, 0x000000), /* - 1.0 */ | |
| 76 | + SPCNST(0, 3, 0x200000), /* + 10.0 */ | |
| 77 | + SPCNST(1, 3, 0x200000), /* - 10.0 */ | |
| 78 | + SPCNST(0, SP_EMAX + 1, 0x000000), /* + infinity */ | |
| 79 | + SPCNST(1, SP_EMAX + 1, 0x000000), /* - infinity */ | |
| 80 | + SPCNST(0, SP_EMAX + 1, 0x3FFFFF), /* + indef quiet Nan */ | |
| 81 | + SPCNST(0, SP_EMAX, 0x7FFFFF), /* + max normal */ | |
| 82 | + SPCNST(1, SP_EMAX, 0x7FFFFF), /* - max normal */ | |
| 83 | + SPCNST(0, SP_EMIN, 0x000000), /* + min normal */ | |
| 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 | +}; | |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | * |
| 14 | 14 | * You should have received a copy of the GNU General Public License along |
| 15 | 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 | 18 | * Nov 7, 2000 |
| 19 | 19 | * Modification to allow integration with Linux kernel |
| @@ -24,186 +24,93 @@ · 4 unmodified lines | ||
| 24 | 24 | #ifndef __ARCH_MIPS_MATH_EMU_IEEE754_H |
| 25 | 25 | #define __ARCH_MIPS_MATH_EMU_IEEE754_H |
| 26 | 26 | |
| 27 | +#include <linux/compiler.h> | |
| 27 | 28 | #include <asm/byteorder.h> |
| 29 | +#include <linux/kernel.h> | |
| 28 | 30 | #include <linux/types.h> |
| 29 | 31 | #include <linux/sched.h> |
| 32 | +#include <asm/bitfield.h> | |
| 30 | 33 | |
| 31 | −/* | |
| 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; | |
| 34 | +union ieee754dp { | |
| 54 | 35 | struct { |
| 55 | − u64 mant:52; | |
| 56 | − unsigned int bexp:11; | |
| 57 | − unsigned int sign:1; | |
| 58 | − } parts; | |
| 36 | + __BITFIELD_FIELD(unsigned int sign:1, | |
| 37 | + __BITFIELD_FIELD(unsigned int bexp:11, | |
| 38 | + __BITFIELD_FIELD(u64 mant:52, | |
| 39 | + ;))) | |
| 40 | + }; | |
| 59 | 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 { | |
| 79 | − struct ieee754dp_konst oparts; | |
| 44 | +union ieee754sp { | |
| 80 | 45 | struct { |
| 81 | − unsigned int sign:1; | |
| 82 | − unsigned int bexp:11; | |
| 83 | − u64 mant:52; | |
| 84 | − } parts; | |
| 85 | − double d; | |
| 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; | |
| 46 | + __BITFIELD_FIELD(unsigned sign:1, | |
| 47 | + __BITFIELD_FIELD(unsigned bexp:8, | |
| 48 | + __BITFIELD_FIELD(unsigned mant:23, | |
| 49 | + ;))) | |
| 50 | + }; | |
| 98 | 51 | u32 bits; |
| 99 | −} ieee754sp; | |
| 100 | −#endif | |
| 52 | +}; | |
| 101 | 53 | |
| 102 | 54 | /* |
| 103 | 55 | * single precision (often aka float) |
| 104 | 56 | */ |
| 105 | −int ieee754sp_finite(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); | |
| 57 | +int ieee754sp_class(union ieee754sp x); | |
| 139 | 58 | |
| 140 | −ieee754sp ieee754sp_ceil(ieee754sp x); | |
| 141 | −ieee754sp ieee754sp_floor(ieee754sp x); | |
| 142 | −ieee754sp ieee754sp_trunc(ieee754sp x); | |
| 59 | +union ieee754sp ieee754sp_abs(union ieee754sp x); | |
| 60 | +union ieee754sp ieee754sp_neg(union 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 | −/* | |
| 147 | − * double precision (often aka double) | |
| 148 | −*/ | |
| 149 | −int ieee754dp_finite(ieee754dp x); | |
| 150 | −int ieee754dp_class(ieee754dp x); | |
| 67 | +union ieee754sp ieee754sp_fint(int x); | |
| 68 | +union ieee754sp ieee754sp_flong(s64 x); | |
| 69 | +union ieee754sp ieee754sp_fdp(union ieee754dp x); | |
| 151 | 70 | |
| 152 | −/* x with sign of y */ | |
| 153 | −ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y); | |
| 71 | +int ieee754sp_tint(union ieee754sp x); | |
| 72 | +s64 ieee754sp_tlong(union ieee754sp x); | |
| 154 | 73 | |
| 155 | −ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y); | |
| 156 | −ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y); | |
| 157 | −ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y); | |
| 158 | −ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y); | |
| 74 | +int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cop, int sig); | |
| 159 | 75 | |
| 160 | −ieee754dp ieee754dp_abs(ieee754dp x); | |
| 161 | −ieee754dp ieee754dp_neg(ieee754dp x); | |
| 162 | −ieee754dp ieee754dp_scalb(ieee754dp x, int); | |
| 76 | +union ieee754sp ieee754sp_sqrt(union ieee754sp x); | |
| 163 | 77 | |
| 164 | −/* return exponent as integer in floating point format | |
| 165 | − */ | |
| 166 | −ieee754dp ieee754dp_logb(ieee754dp x); | |
| 78 | +/* | |
| 79 | + * double precision (often aka double) | |
| 80 | +*/ | |
| 81 | +int ieee754dp_class(union ieee754dp x); | |
| 167 | 82 | |
| 168 | −ieee754dp ieee754dp_fint(int x); | |
| 169 | −ieee754dp ieee754dp_funs(unsigned x); | |
| 170 | −ieee754dp ieee754dp_flong(s64 x); | |
| 171 | −ieee754dp ieee754dp_fulong(u64 x); | |
| 172 | −ieee754dp ieee754dp_fsp(ieee754sp x); | |
| 83 | +union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y); | |
| 84 | +union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y); | |
| 85 | +union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y); | |
| 86 | +union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y); | |
| 173 | 87 | |
| 174 | −ieee754dp ieee754dp_ceil(ieee754dp x); | |
| 175 | −ieee754dp ieee754dp_floor(ieee754dp x); | |
| 176 | −ieee754dp ieee754dp_trunc(ieee754dp x); | |
| 88 | +union ieee754dp ieee754dp_abs(union ieee754dp x); | |
| 89 | +union ieee754dp ieee754dp_neg(union ieee754dp x); | |
| 177 | 90 | |
| 178 | −int ieee754dp_tint(ieee754dp x); | |
| 179 | −unsigned int ieee754dp_tuns(ieee754dp x); | |
| 180 | −s64 ieee754dp_tlong(ieee754dp x); | |
| 181 | −u64 ieee754dp_tulong(ieee754dp x); | |
| 91 | +union ieee754dp ieee754dp_fint(int x); | |
| 92 | +union ieee754dp ieee754dp_flong(s64 x); | |
| 93 | +union ieee754dp ieee754dp_fsp(union ieee754sp x); | |
| 182 | 94 | |
| 183 | −int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop, int sig); | |
| 184 | −/* | |
| 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); | |
| 95 | +int ieee754dp_tint(union ieee754dp x); | |
| 96 | +s64 ieee754dp_tlong(union ieee754dp x); | |
| 190 | 97 | |
| 191 | −ieee754dp ieee754dp_ceil(ieee754dp x); | |
| 192 | −ieee754dp ieee754dp_floor(ieee754dp x); | |
| 193 | −ieee754dp ieee754dp_trunc(ieee754dp x); | |
| 98 | +int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cop, int sig); | |
| 194 | 99 | |
| 195 | −ieee754dp ieee754dp_sqrt(ieee754dp x); | |
| 100 | +union ieee754dp ieee754dp_sqrt(union ieee754dp x); | |
| 196 | 101 | |
| 197 | 102 | |
| 198 | 103 | |
| 199 | 104 | /* 5 types of floating point number |
| 200 | 105 | */ |
| 201 | −#define IEEE754_CLASS_NORM 0x00 | |
| 202 | −#define IEEE754_CLASS_ZERO 0x01 | |
| 203 | −#define IEEE754_CLASS_DNORM 0x02 | |
| 204 | −#define IEEE754_CLASS_INF 0x03 | |
| 205 | −#define IEEE754_CLASS_SNAN 0x04 | |
| 206 | −#define IEEE754_CLASS_QNAN 0x05 | |
| 106 | +enum { | |
| 107 | + IEEE754_CLASS_NORM = 0x00, | |
| 108 | + IEEE754_CLASS_ZERO = 0x01, | |
| 109 | + IEEE754_CLASS_DNORM = 0x02, | |
| 110 | + IEEE754_CLASS_INF = 0x03, | |
| 111 | + IEEE754_CLASS_SNAN = 0x04, | |
| 112 | + IEEE754_CLASS_QNAN = 0x05, | |
| 113 | +}; | |
| 207 | 114 | |
| 208 | 115 | /* exception numbers */ |
| 209 | 116 | #define IEEE754_INEXACT 0x01 |
| @@ -219,114 +126,84 @@ ieee754dp ieee754dp_sqrt(ieee754dp x); · 9 unmodified lines | ||
| 219 | 126 | #define IEEE754_CGT 0x04 |
| 220 | 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 | 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 | 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 | 138 | return ieee754sp_cmp(x, y, |
| 243 | 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 | 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 | 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 | 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 | 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 | 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 | 170 | return ieee754dp_cmp(x, y, |
| 275 | 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 | 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 | 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 | 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 | 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 | 195 | * The control status register |
| 308 | 196 | */ |
| 309 | 197 | struct _ieee754_csr { |
| 310 | −#ifdef __BIG_ENDIAN | |
| 311 | − unsigned pad0:7; | |
| 312 | − unsigned nod:1; /* set 1 for no denormalised numbers */ | |
| 313 | − unsigned c:1; /* condition */ | |
| 314 | − unsigned pad1:5; | |
| 315 | − unsigned cx:6; /* exceptions this operation */ | |
| 316 | − unsigned mx:5; /* exception enable mask */ | |
| 317 | − unsigned sx:5; /* exceptions total */ | |
| 318 | − unsigned rm:2; /* current rounding mode */ | |
| 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 | |
| 198 | + __BITFIELD_FIELD(unsigned pad0:7, | |
| 199 | + __BITFIELD_FIELD(unsigned nod:1, /* set 1 for no denormalised numbers */ | |
| 200 | + __BITFIELD_FIELD(unsigned c:1, /* condition */ | |
| 201 | + __BITFIELD_FIELD(unsigned pad1:5, | |
| 202 | + __BITFIELD_FIELD(unsigned cx:6, /* exceptions this operation */ | |
| 203 | + __BITFIELD_FIELD(unsigned mx:5, /* exception enable mask */ | |
| 204 | + __BITFIELD_FIELD(unsigned sx:5, /* exceptions total */ | |
| 205 | + __BITFIELD_FIELD(unsigned rm:2, /* current rounding mode */ | |
| 206 | + ;)))))))) | |
| 330 | 207 | }; |
| 331 | 208 | #define ieee754_csr (*(struct _ieee754_csr *)(¤t->thread.fpu.fcr31)) |
| 332 | 209 | |
| @@ -377,8 +254,8 @@ static inline int ieee754_sxtest(unsigned n) · 44 unmodified lines | ||
| 377 | 254 | } |
| 378 | 255 | |
| 379 | 256 | /* debugging */ |
| 380 | −ieee754sp ieee754sp_dump(char *s, ieee754sp x); | |
| 381 | −ieee754dp ieee754dp_dump(char *s, ieee754dp x); | |
| 257 | +union ieee754sp ieee754sp_dump(char *s, union ieee754sp x); | |
| 258 | +union ieee754dp ieee754dp_dump(char *s, union ieee754dp x); | |
| 382 | 259 | |
| 383 | 260 | #define IEEE754_SPCVAL_PZERO 0 |
| 384 | 261 | #define IEEE754_SPCVAL_NZERO 1 |
| @@ -398,10 +275,10 @@ ieee754dp ieee754dp_dump(char *s, ieee754dp x); · 13 unmodified lines | ||
| 398 | 275 | #define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ |
| 399 | 276 | #define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ |
| 400 | 277 | |
| 401 | −extern const struct ieee754dp_konst __ieee754dp_spcvals[]; | |
| 402 | −extern const struct ieee754sp_konst __ieee754sp_spcvals[]; | |
| 403 | −#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals) | |
| 404 | −#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals) | |
| 278 | +extern const union ieee754dp __ieee754dp_spcvals[]; | |
| 279 | +extern const union ieee754sp __ieee754sp_spcvals[]; | |
| 280 | +#define ieee754dp_spcvals ((const union ieee754dp *)__ieee754dp_spcvals) | |
| 281 | +#define ieee754sp_spcvals ((const union ieee754sp *)__ieee754sp_spcvals) | |
| 405 | 282 | |
| 406 | 283 | /* |
| 407 | 284 | * Return infinity with given sign |
| @@ -431,28 +308,15 @@ extern const struct ieee754sp_konst __ieee754sp_spcvals[]; · 23 unmodified lines | ||
| 431 | 308 | /* |
| 432 | 309 | * Indefinite integer value |
| 433 | 310 | */ |
| 434 | −#define ieee754si_indef() INT_MAX | |
| 435 | −#ifdef LONG_LONG_MAX | |
| 436 | −#define ieee754di_indef() LONG_LONG_MAX | |
| 437 | −#else | |
| 438 | −#define ieee754di_indef() ((s64)(~0ULL>>1)) | |
| 439 | −#endif | |
| 440 | − | |
| 441 | −/* IEEE exception context, passed to handler */ | |
| 442 | −struct ieee754xctx { | |
| 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 | −}; | |
| 311 | +static inline int ieee754si_indef(void) | |
| 312 | +{ | |
| 313 | + return INT_MAX; | |
| 314 | +} | |
| 315 | + | |
| 316 | +static inline s64 ieee754di_indef(void) | |
| 317 | +{ | |
| 318 | + return S64_MAX; | |
| 319 | +} | |
| 456 | 320 | |
| 457 | 321 | /* result types for xctx.rt */ |
| 458 | 322 | #define IEEE754_RT_SP 0 |
| @@ -461,8 +325,6 @@ struct ieee754xctx { · 2 unmodified lines | ||
| 461 | 325 | #define IEEE754_RT_SI 3 |
| 462 | 326 | #define IEEE754_RT_DI 4 |
| 463 | 327 | |
| 464 | −extern void ieee754_xcpt(struct ieee754xctx *xcp); | |
| 465 | − | |
| 466 | 328 | /* compat */ |
| 467 | 329 | #define ieee754dp_fix(x) ieee754dp_tint(x) |
| 468 | 330 | #define ieee754sp_fix(x) ieee754sp_tint(x) |
| @@ -16,7 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | * |
| 17 | 17 | * You should have received a copy of the GNU General Public License along |
| 18 | 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 | 21 | * Nov 7, 2000 |
| 22 | 22 | * Modified to build and operate in Linux kernel environment. |
| @@ -25,38 +25,13 @@ · 2 unmodified lines | ||
| 25 | 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 | 30 | #include "ieee754.h" |
| 31 | +#include "ieee754sp.h" | |
| 32 | +#include "ieee754dp.h" | |
| 30 | 33 | |
| 31 | −#define DP_EBIAS 1023 | |
| 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) | |
| 34 | +union ieee754dp ieee754dp_dump(char *m, union ieee754dp x) | |
| 60 | 35 | { |
| 61 | 36 | int i; |
| 62 | 37 | |
| @@ -96,7 +71,7 @@ ieee754dp ieee754dp_dump(char *m, ieee754dp x) · 33 unmodified lines | ||
| 96 | 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 | 76 | int i; |
| 102 | 77 | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,104 +16,68 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 22 | +#include <linux/compiler.h> | |
| 26 | 23 | |
| 27 | 24 | #include "ieee754dp.h" |
| 28 | 25 | |
| 29 | −int ieee754dp_class(ieee754dp x) | |
| 26 | +int ieee754dp_class(union ieee754dp x) | |
| 30 | 27 | { |
| 31 | 28 | COMPXDP; |
| 32 | 29 | EXPLODEXDP; |
| 33 | 30 | return xc; |
| 34 | 31 | } |
| 35 | 32 | |
| 36 | −int ieee754dp_isnan(ieee754dp x) | |
| 33 | +int ieee754dp_isnan(union ieee754dp x) | |
| 37 | 34 | { |
| 38 | 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 | 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, ...) | |
| 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, ...) | |
| 45 | +union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r) | |
| 64 | 46 | { |
| 65 | − struct ieee754xctx ax; | |
| 66 | − | |
| 67 | 47 | assert(ieee754dp_isnan(r)); |
| 68 | 48 | |
| 69 | 49 | if (!ieee754dp_issnan(r)) /* QNAN does not cause invalid op !! */ |
| 70 | 50 | return r; |
| 71 | 51 | |
| 72 | − if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) { | |
| 52 | + if (!ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) { | |
| 73 | 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 | 55 | if (ieee754dp_isnan(r)) |
| 76 | 56 | return r; |
| 77 | 57 | else |
| 78 | 58 | return ieee754dp_indef(); |
| 79 | 59 | } |
| 80 | 60 | |
| 81 | − ax.op = op; | |
| 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; | |
| 61 | + return r; | |
| 88 | 62 | } |
| 89 | 63 | |
| 90 | −ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y) | |
| 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) | |
| 64 | +static u64 ieee754dp_get_rounding(int sn, u64 xm) | |
| 103 | 65 | { |
| 104 | 66 | /* inexact must round of 3 bits |
| 105 | 67 | */ |
| 106 | 68 | if (xm & (DP_MBIT(3) - 1)) { |
| 107 | 69 | switch (ieee754_csr.rm) { |
| 108 | − case IEEE754_RZ: | |
| 70 | + case FPU_CSR_RZ: | |
| 109 | 71 | break; |
| 110 | − case IEEE754_RN: | |
| 72 | + case FPU_CSR_RN: | |
| 111 | 73 | xm += 0x3 + ((xm >> 3) & 1); |
| 112 | 74 | /* xm += (xm&0x8)?0x4:0x3 */ |
| 113 | 75 | break; |
| 114 | − case IEEE754_RU: /* toward +Infinity */ | |
| 76 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 115 | 77 | if (!sn) /* ?? */ |
| 116 | 78 | xm += 0x8; |
| 117 | 79 | break; |
| 118 | − case IEEE754_RD: /* toward -Infinity */ | |
| 80 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 119 | 81 | if (sn) /* ?? */ |
| 120 | 82 | xm += 0x8; |
| 121 | 83 | break; |
| @@ -130,11 +92,11 @@ static u64 get_rounding(int sn, u64 xm) · 8 unmodified lines | ||
| 130 | 92 | * xe is an unbiased exponent |
| 131 | 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 | 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 | 100 | assert(xm & (DP_HIDDEN_BIT << 3)); |
| 139 | 101 | |
| 140 | 102 | if (xe < DP_EMIN) { |
| @@ -142,32 +104,32 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) · 1 unmodified line | ||
| 142 | 104 | int es = DP_EMIN - xe; |
| 143 | 105 | |
| 144 | 106 | if (ieee754_csr.nod) { |
| 145 | − SETCX(IEEE754_UNDERFLOW); | |
| 146 | − SETCX(IEEE754_INEXACT); | |
| 107 | + ieee754_setcx(IEEE754_UNDERFLOW); | |
| 108 | + ieee754_setcx(IEEE754_INEXACT); | |
| 147 | 109 | |
| 148 | 110 | switch(ieee754_csr.rm) { |
| 149 | − case IEEE754_RN: | |
| 150 | − case IEEE754_RZ: | |
| 111 | + case FPU_CSR_RN: | |
| 112 | + case FPU_CSR_RZ: | |
| 151 | 113 | return ieee754dp_zero(sn); |
| 152 | − case IEEE754_RU: /* toward +Infinity */ | |
| 153 | − if(sn == 0) | |
| 114 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 115 | + if (sn == 0) | |
| 154 | 116 | return ieee754dp_min(0); |
| 155 | 117 | else |
| 156 | 118 | return ieee754dp_zero(1); |
| 157 | − case IEEE754_RD: /* toward -Infinity */ | |
| 158 | − if(sn == 0) | |
| 119 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 120 | + if (sn == 0) | |
| 159 | 121 | return ieee754dp_zero(0); |
| 160 | 122 | else |
| 161 | 123 | return ieee754dp_min(1); |
| 162 | 124 | } |
| 163 | 125 | } |
| 164 | 126 | |
| 165 | − if (xe == DP_EMIN - 1 | |
| 166 | − && get_rounding(sn, xm) >> (DP_MBITS + 1 + 3)) | |
| 127 | + if (xe == DP_EMIN - 1 && | |
| 128 | + ieee754dp_get_rounding(sn, xm) >> (DP_FBITS + 1 + 3)) | |
| 167 | 129 | { |
| 168 | 130 | /* Not tiny after rounding */ |
| 169 | − SETCX(IEEE754_INEXACT); | |
| 170 | − xm = get_rounding(sn, xm); | |
| 131 | + ieee754_setcx(IEEE754_INEXACT); | |
| 132 | + xm = ieee754dp_get_rounding(sn, xm); | |
| 171 | 133 | xm >>= 1; |
| 172 | 134 | /* Clear grs bits */ |
| 173 | 135 | xm &= ~(DP_MBIT(3) - 1); |
| @@ -183,17 +145,17 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) · 9 unmodified lines | ||
| 183 | 145 | } |
| 184 | 146 | } |
| 185 | 147 | if (xm & (DP_MBIT(3) - 1)) { |
| 186 | − SETCX(IEEE754_INEXACT); | |
| 148 | + ieee754_setcx(IEEE754_INEXACT); | |
| 187 | 149 | if ((xm & (DP_HIDDEN_BIT << 3)) == 0) { |
| 188 | − SETCX(IEEE754_UNDERFLOW); | |
| 150 | + ieee754_setcx(IEEE754_UNDERFLOW); | |
| 189 | 151 | } |
| 190 | 152 | |
| 191 | 153 | /* inexact must round of 3 bits |
| 192 | 154 | */ |
| 193 | − xm = get_rounding(sn, xm); | |
| 155 | + xm = ieee754dp_get_rounding(sn, xm); | |
| 194 | 156 | /* adjust exponent for rounding add overflowing |
| 195 | 157 | */ |
| 196 | − if (xm >> (DP_MBITS + 3 + 1)) { | |
| 158 | + if (xm >> (DP_FBITS + 3 + 1)) { | |
| 197 | 159 | /* add causes mantissa overflow */ |
| 198 | 160 | xm >>= 1; |
| 199 | 161 | xe++; |
| @@ -202,24 +164,24 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) · 2 unmodified lines | ||
| 202 | 164 | /* strip grs bits */ |
| 203 | 165 | xm >>= 3; |
| 204 | 166 | |
| 205 | − assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ | |
| 167 | + assert((xm >> (DP_FBITS + 1)) == 0); /* no execess */ | |
| 206 | 168 | assert(xe >= DP_EMIN); |
| 207 | 169 | |
| 208 | 170 | if (xe > DP_EMAX) { |
| 209 | − SETCX(IEEE754_OVERFLOW); | |
| 210 | − SETCX(IEEE754_INEXACT); | |
| 171 | + ieee754_setcx(IEEE754_OVERFLOW); | |
| 172 | + ieee754_setcx(IEEE754_INEXACT); | |
| 211 | 173 | /* -O can be table indexed by (rm,sn) */ |
| 212 | 174 | switch (ieee754_csr.rm) { |
| 213 | − case IEEE754_RN: | |
| 175 | + case FPU_CSR_RN: | |
| 214 | 176 | return ieee754dp_inf(sn); |
| 215 | − case IEEE754_RZ: | |
| 177 | + case FPU_CSR_RZ: | |
| 216 | 178 | return ieee754dp_max(sn); |
| 217 | − case IEEE754_RU: /* toward +Infinity */ | |
| 179 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 218 | 180 | if (sn == 0) |
| 219 | 181 | return ieee754dp_inf(0); |
| 220 | 182 | else |
| 221 | 183 | return ieee754dp_max(1); |
| 222 | − case IEEE754_RD: /* toward -Infinity */ | |
| 184 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 223 | 185 | if (sn == 0) |
| 224 | 186 | return ieee754dp_max(0); |
| 225 | 187 | else |
| @@ -232,10 +194,10 @@ ieee754dp ieee754dp_format(int sn, int xe, u64 xm) · 6 unmodified lines | ||
| 232 | 194 | /* we underflow (tiny/zero) */ |
| 233 | 195 | assert(xe == DP_EMIN); |
| 234 | 196 | if (ieee754_csr.mx & IEEE754_UNDERFLOW) |
| 235 | − SETCX(IEEE754_UNDERFLOW); | |
| 197 | + ieee754_setcx(IEEE754_UNDERFLOW); | |
| 236 | 198 | return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); |
| 237 | 199 | } else { |
| 238 | − assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ | |
| 200 | + assert((xm >> (DP_FBITS + 1)) == 0); /* no execess */ | |
| 239 | 201 | assert(xm & DP_HIDDEN_BIT); |
| 240 | 202 | |
| 241 | 203 | return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); |
| @@ -6,8 +6,6 @@ · 5 unmodified lines | ||
| 6 | 6 | * MIPS floating point support |
| 7 | 7 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 8 | 8 | * |
| 9 | − * ######################################################################## | |
| 10 | − * | |
| 11 | 9 | * This program is free software; you can distribute it and/or modify it |
| 12 | 10 | * under the terms of the GNU General Public License (Version 2) as |
| 13 | 11 | * published by the Free Software Foundation. |
| @@ -19,64 +17,66 @@ · 5 unmodified lines | ||
| 19 | 17 | * |
| 20 | 18 | * You should have received a copy of the GNU General Public License along |
| 21 | 19 | * with this program; if not, write to the Free Software Foundation, Inc., |
| 22 | − * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
| 23 | − * | |
| 24 | − * ######################################################################## | |
| 20 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 25 | 21 | */ |
| 26 | 22 | |
| 23 | +#include <linux/compiler.h> | |
| 27 | 24 | |
| 28 | 25 | #include "ieee754int.h" |
| 29 | 26 | |
| 30 | 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 | 48 | /* 3bit extended double precision sticky right shift */ |
| 33 | 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 | 52 | #define XDPSRSX1() \ |
| 37 | − (xe++, (xm = (xm >> 1) | (xm & 1))) | |
| 53 | + (xe++, (xm = (xm >> 1) | (xm & 1))) | |
| 38 | 54 | |
| 39 | 55 | #define XDPSRS1(v) \ |
| 40 | − (((v) >> 1) | ((v) & 1)) | |
| 56 | + (((v) >> 1) | ((v) & 1)) | |
| 41 | 57 | |
| 42 | 58 | /* convert denormal to normalized with extended exponent */ |
| 43 | 59 | #define DPDNORMx(m,e) \ |
| 44 | − while( (m >> DP_MBITS) == 0) { m <<= 1; e--; } | |
| 60 | + while ((m >> DP_FBITS) == 0) { m <<= 1; e--; } | |
| 45 | 61 | #define DPDNORMX DPDNORMx(xm, xe) |
| 46 | 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 | 68 | assert((s) == 0 || (s) == 1); |
| 53 | 69 | assert((bx) >= DP_EMIN - 1 + DP_EBIAS |
| 54 | 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; | |
| 58 | − r.parts.bexp = bx; | |
| 59 | − r.parts.mant = m; | |
| 60 | − return r; | |
| 61 | −} | |
| 73 | + r.sign = s; | |
| 74 | + r.bexp = bx; | |
| 75 | + r.mant = m; | |
| 62 | 76 | |
| 63 | −extern int ieee754dp_isnan(ieee754dp); | |
| 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; \ | |
| 77 | + return r; | |
| 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); | |
| @@ -6,8 +6,6 @@ · 5 unmodified lines | ||
| 6 | 6 | * MIPS floating point support |
| 7 | 7 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 8 | 8 | * |
| 9 | − * ######################################################################## | |
| 10 | − * | |
| 11 | 9 | * This program is free software; you can distribute it and/or modify it |
| 12 | 10 | * under the terms of the GNU General Public License (Version 2) as |
| 13 | 11 | * published by the Free Software Foundation. |
| @@ -19,146 +17,125 @@ · 5 unmodified lines | ||
| 19 | 17 | * |
| 20 | 18 | * You should have received a copy of the GNU General Public License along |
| 21 | 19 | * with this program; if not, write to the Free Software Foundation, Inc., |
| 22 | − * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
| 23 | − * | |
| 24 | − * ######################################################################## | |
| 20 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 25 | 21 | */ |
| 26 | − | |
| 22 | +#ifndef __IEEE754INT_H | |
| 23 | +#define __IEEE754INT_H | |
| 27 | 24 | |
| 28 | 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 | 27 | #define CLPAIR(x, y) ((x)*6+(y)) |
| 58 | 28 | |
| 59 | −#define CLEARCX \ | |
| 60 | − (ieee754_csr.cx = 0) | |
| 61 | − | |
| 62 | −#define SETCX(x) \ | |
| 63 | − (ieee754_csr.cx |= (x), ieee754_csr.sx |= (x)) | |
| 29 | +static inline void ieee754_clearcx(void) | |
| 30 | +{ | |
| 31 | + ieee754_csr.cx = 0; | |
| 32 | +} | |
| 64 | 33 | |
| 65 | −#define SETANDTESTCX(x) \ | |
| 66 | − (SETCX(x), ieee754_csr.mx & (x)) | |
| 34 | +static inline void ieee754_setcx(const unsigned int flags) | |
| 35 | +{ | |
| 36 | + ieee754_csr.cx |= flags; | |
| 37 | + ieee754_csr.sx |= flags; | |
| 38 | +} | |
| 67 | 39 | |
| 68 | −#define TSTX() \ | |
| 69 | − (ieee754_csr.cx & ieee754_csr.mx) | |
| 40 | +static inline int ieee754_setandtestcx(const unsigned int x) | |
| 41 | +{ | |
| 42 | + ieee754_setcx(x); | |
| 70 | 43 | |
| 44 | + return ieee754_csr.mx & x; | |
| 45 | +} | |
| 71 | 46 | |
| 72 | 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 | 50 | #define COMPYSP \ |
| 76 | − unsigned ym; int ye; int ys; int yc | |
| 77 | − | |
| 78 | −#define EXPLODESP(v, vc, vs, ve, vm) \ | |
| 79 | −{\ | |
| 80 | − vs = SPSIGN(v);\ | |
| 81 | − ve = SPBEXP(v);\ | |
| 82 | − vm = SPMANT(v);\ | |
| 83 | − if(ve == SP_EMAX+1+SP_EBIAS){\ | |
| 84 | − if(vm == 0)\ | |
| 85 | − vc = IEEE754_CLASS_INF;\ | |
| 86 | − else if(vm & SP_MBIT(SP_MBITS-1)) \ | |
| 87 | − vc = IEEE754_CLASS_SNAN;\ | |
| 88 | − else \ | |
| 89 | − vc = IEEE754_CLASS_QNAN;\ | |
| 90 | − } else if(ve == SP_EMIN-1+SP_EBIAS) {\ | |
| 91 | − if(vm) {\ | |
| 92 | − ve = SP_EMIN;\ | |
| 93 | − vc = IEEE754_CLASS_DNORM;\ | |
| 94 | − } else\ | |
| 95 | − vc = IEEE754_CLASS_ZERO;\ | |
| 96 | − } else {\ | |
| 97 | − ve -= SP_EBIAS;\ | |
| 98 | − vm |= SP_HIDDEN_BIT;\ | |
| 99 | − vc = IEEE754_CLASS_NORM;\ | |
| 100 | − }\ | |
| 51 | + unsigned ym; int ye; int ys; int yc | |
| 52 | + | |
| 53 | +#define EXPLODESP(v, vc, vs, ve, vm) \ | |
| 54 | +{ \ | |
| 55 | + vs = SPSIGN(v); \ | |
| 56 | + ve = SPBEXP(v); \ | |
| 57 | + vm = SPMANT(v); \ | |
| 58 | + if (ve == SP_EMAX+1+SP_EBIAS) { \ | |
| 59 | + if (vm == 0) \ | |
| 60 | + vc = IEEE754_CLASS_INF; \ | |
| 61 | + else if (vm & SP_MBIT(SP_FBITS-1)) \ | |
| 62 | + vc = IEEE754_CLASS_SNAN; \ | |
| 63 | + else \ | |
| 64 | + vc = IEEE754_CLASS_QNAN; \ | |
| 65 | + } else if (ve == SP_EMIN-1+SP_EBIAS) { \ | |
| 66 | + if (vm) { \ | |
| 67 | + ve = SP_EMIN; \ | |
| 68 | + vc = IEEE754_CLASS_DNORM; \ | |
| 69 | + } else \ | |
| 70 | + vc = IEEE754_CLASS_ZERO; \ | |
| 71 | + } else { \ | |
| 72 | + ve -= SP_EBIAS; \ | |
| 73 | + vm |= SP_HIDDEN_BIT; \ | |
| 74 | + vc = IEEE754_CLASS_NORM; \ | |
| 75 | + } \ | |
| 101 | 76 | } |
| 102 | 77 | #define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm) |
| 103 | 78 | #define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym) |
| 104 | 79 | |
| 105 | 80 | |
| 106 | 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 | 84 | #define COMPYDP \ |
| 110 | −u64 ym; int ye; int ys; int yc | |
| 111 | − | |
| 112 | −#define EXPLODEDP(v, vc, vs, ve, vm) \ | |
| 113 | −{\ | |
| 114 | − vm = DPMANT(v);\ | |
| 115 | − vs = DPSIGN(v);\ | |
| 116 | − ve = DPBEXP(v);\ | |
| 117 | − if(ve == DP_EMAX+1+DP_EBIAS){\ | |
| 118 | − if(vm == 0)\ | |
| 119 | − vc = IEEE754_CLASS_INF;\ | |
| 120 | − else if(vm & DP_MBIT(DP_MBITS-1)) \ | |
| 121 | − vc = IEEE754_CLASS_SNAN;\ | |
| 122 | − else \ | |
| 123 | − vc = IEEE754_CLASS_QNAN;\ | |
| 124 | − } else if(ve == DP_EMIN-1+DP_EBIAS) {\ | |
| 125 | − if(vm) {\ | |
| 126 | − ve = DP_EMIN;\ | |
| 127 | − vc = IEEE754_CLASS_DNORM;\ | |
| 128 | − } else\ | |
| 129 | − vc = IEEE754_CLASS_ZERO;\ | |
| 130 | − } else {\ | |
| 131 | − ve -= DP_EBIAS;\ | |
| 132 | − vm |= DP_HIDDEN_BIT;\ | |
| 133 | − vc = IEEE754_CLASS_NORM;\ | |
| 134 | − }\ | |
| 85 | + u64 ym; int ye; int ys; int yc | |
| 86 | + | |
| 87 | +#define EXPLODEDP(v, vc, vs, ve, vm) \ | |
| 88 | +{ \ | |
| 89 | + vm = DPMANT(v); \ | |
| 90 | + vs = DPSIGN(v); \ | |
| 91 | + ve = DPBEXP(v); \ | |
| 92 | + if (ve == DP_EMAX+1+DP_EBIAS) { \ | |
| 93 | + if (vm == 0) \ | |
| 94 | + vc = IEEE754_CLASS_INF; \ | |
| 95 | + else if (vm & DP_MBIT(DP_FBITS-1)) \ | |
| 96 | + vc = IEEE754_CLASS_SNAN; \ | |
| 97 | + else \ | |
| 98 | + vc = IEEE754_CLASS_QNAN; \ | |
| 99 | + } else if (ve == DP_EMIN-1+DP_EBIAS) { \ | |
| 100 | + if (vm) { \ | |
| 101 | + ve = DP_EMIN; \ | |
| 102 | + vc = IEEE754_CLASS_DNORM; \ | |
| 103 | + } else \ | |
| 104 | + vc = IEEE754_CLASS_ZERO; \ | |
| 105 | + } else { \ | |
| 106 | + ve -= DP_EBIAS; \ | |
| 107 | + vm |= DP_HIDDEN_BIT; \ | |
| 108 | + vc = IEEE754_CLASS_NORM; \ | |
| 109 | + } \ | |
| 135 | 110 | } |
| 136 | 111 | #define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm) |
| 137 | 112 | #define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym) |
| 138 | 113 | |
| 139 | −#define FLUSHDP(v, vc, vs, ve, vm) \ | |
| 140 | − if(vc==IEEE754_CLASS_DNORM) {\ | |
| 141 | − if(ieee754_csr.nod) {\ | |
| 142 | − SETCX(IEEE754_INEXACT);\ | |
| 143 | − vc = IEEE754_CLASS_ZERO;\ | |
| 144 | − ve = DP_EMIN-1+DP_EBIAS;\ | |
| 145 | − vm = 0;\ | |
| 146 | − v = ieee754dp_zero(vs);\ | |
| 147 | − }\ | |
| 114 | +#define FLUSHDP(v, vc, vs, ve, vm) \ | |
| 115 | + if (vc==IEEE754_CLASS_DNORM) { \ | |
| 116 | + if (ieee754_csr.nod) { \ | |
| 117 | + ieee754_setcx(IEEE754_INEXACT); \ | |
| 118 | + vc = IEEE754_CLASS_ZERO; \ | |
| 119 | + ve = DP_EMIN-1+DP_EBIAS; \ | |
| 120 | + vm = 0; \ | |
| 121 | + v = ieee754dp_zero(vs); \ | |
| 122 | + } \ | |
| 148 | 123 | } |
| 149 | 124 | |
| 150 | −#define FLUSHSP(v, vc, vs, ve, vm) \ | |
| 151 | − if(vc==IEEE754_CLASS_DNORM) {\ | |
| 152 | − if(ieee754_csr.nod) {\ | |
| 153 | − SETCX(IEEE754_INEXACT);\ | |
| 154 | − vc = IEEE754_CLASS_ZERO;\ | |
| 155 | − ve = SP_EMIN-1+SP_EBIAS;\ | |
| 156 | − vm = 0;\ | |
| 157 | − v = ieee754sp_zero(vs);\ | |
| 158 | − }\ | |
| 125 | +#define FLUSHSP(v, vc, vs, ve, vm) \ | |
| 126 | + if (vc==IEEE754_CLASS_DNORM) { \ | |
| 127 | + if (ieee754_csr.nod) { \ | |
| 128 | + ieee754_setcx(IEEE754_INEXACT); \ | |
| 129 | + vc = IEEE754_CLASS_ZERO; \ | |
| 130 | + ve = SP_EMIN-1+SP_EBIAS; \ | |
| 131 | + vm = 0; \ | |
| 132 | + v = ieee754sp_zero(vs); \ | |
| 133 | + } \ | |
| 159 | 134 | } |
| 160 | 135 | |
| 161 | 136 | #define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm) |
| 162 | 137 | #define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym) |
| 163 | 138 | #define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm) |
| 164 | 139 | #define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym) |
| 140 | + | |
| 141 | +#endif /* __IEEE754INT_H */ | |
| @@ -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 | −} | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,105 +16,68 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 22 | +#include <linux/compiler.h> | |
| 26 | 23 | |
| 27 | 24 | #include "ieee754sp.h" |
| 28 | 25 | |
| 29 | −int ieee754sp_class(ieee754sp x) | |
| 26 | +int ieee754sp_class(union ieee754sp x) | |
| 30 | 27 | { |
| 31 | 28 | COMPXSP; |
| 32 | 29 | EXPLODEXSP; |
| 33 | 30 | return xc; |
| 34 | 31 | } |
| 35 | 32 | |
| 36 | −int ieee754sp_isnan(ieee754sp x) | |
| 33 | +int ieee754sp_isnan(union ieee754sp x) | |
| 37 | 34 | { |
| 38 | 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 | 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, ...) | |
| 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, ...) | |
| 45 | +union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r) | |
| 65 | 46 | { |
| 66 | − struct ieee754xctx ax; | |
| 67 | − | |
| 68 | 47 | assert(ieee754sp_isnan(r)); |
| 69 | 48 | |
| 70 | 49 | if (!ieee754sp_issnan(r)) /* QNAN does not cause invalid op !! */ |
| 71 | 50 | return r; |
| 72 | 51 | |
| 73 | − if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) { | |
| 52 | + if (!ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) { | |
| 74 | 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 | 55 | if (ieee754sp_isnan(r)) |
| 77 | 56 | return r; |
| 78 | 57 | else |
| 79 | 58 | return ieee754sp_indef(); |
| 80 | 59 | } |
| 81 | 60 | |
| 82 | − ax.op = op; | |
| 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; | |
| 61 | + return r; | |
| 100 | 62 | } |
| 101 | 63 | |
| 102 | − | |
| 103 | −static unsigned get_rounding(int sn, unsigned xm) | |
| 64 | +static unsigned ieee754sp_get_rounding(int sn, unsigned xm) | |
| 104 | 65 | { |
| 105 | 66 | /* inexact must round of 3 bits |
| 106 | 67 | */ |
| 107 | 68 | if (xm & (SP_MBIT(3) - 1)) { |
| 108 | 69 | switch (ieee754_csr.rm) { |
| 109 | − case IEEE754_RZ: | |
| 70 | + case FPU_CSR_RZ: | |
| 110 | 71 | break; |
| 111 | − case IEEE754_RN: | |
| 72 | + case FPU_CSR_RN: | |
| 112 | 73 | xm += 0x3 + ((xm >> 3) & 1); |
| 113 | 74 | /* xm += (xm&0x8)?0x4:0x3 */ |
| 114 | 75 | break; |
| 115 | − case IEEE754_RU: /* toward +Infinity */ | |
| 76 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 116 | 77 | if (!sn) /* ?? */ |
| 117 | 78 | xm += 0x8; |
| 118 | 79 | break; |
| 119 | − case IEEE754_RD: /* toward -Infinity */ | |
| 80 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 120 | 81 | if (sn) /* ?? */ |
| 121 | 82 | xm += 0x8; |
| 122 | 83 | break; |
| @@ -131,11 +92,11 @@ static unsigned get_rounding(int sn, unsigned xm) · 8 unmodified lines | ||
| 131 | 92 | * xe is an unbiased exponent |
| 132 | 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 | 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 | 100 | assert(xm & (SP_HIDDEN_BIT << 3)); |
| 140 | 101 | |
| 141 | 102 | if (xe < SP_EMIN) { |
| @@ -143,38 +104,37 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) · 1 unmodified line | ||
| 143 | 104 | int es = SP_EMIN - xe; |
| 144 | 105 | |
| 145 | 106 | if (ieee754_csr.nod) { |
| 146 | − SETCX(IEEE754_UNDERFLOW); | |
| 147 | − SETCX(IEEE754_INEXACT); | |
| 107 | + ieee754_setcx(IEEE754_UNDERFLOW); | |
| 108 | + ieee754_setcx(IEEE754_INEXACT); | |
| 148 | 109 | |
| 149 | 110 | switch(ieee754_csr.rm) { |
| 150 | − case IEEE754_RN: | |
| 151 | − case IEEE754_RZ: | |
| 111 | + case FPU_CSR_RN: | |
| 112 | + case FPU_CSR_RZ: | |
| 152 | 113 | return ieee754sp_zero(sn); |
| 153 | − case IEEE754_RU: /* toward +Infinity */ | |
| 154 | − if(sn == 0) | |
| 114 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 115 | + if (sn == 0) | |
| 155 | 116 | return ieee754sp_min(0); |
| 156 | 117 | else |
| 157 | 118 | return ieee754sp_zero(1); |
| 158 | − case IEEE754_RD: /* toward -Infinity */ | |
| 159 | − if(sn == 0) | |
| 119 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 120 | + if (sn == 0) | |
| 160 | 121 | return ieee754sp_zero(0); |
| 161 | 122 | else |
| 162 | 123 | return ieee754sp_min(1); |
| 163 | 124 | } |
| 164 | 125 | } |
| 165 | 126 | |
| 166 | − if (xe == SP_EMIN - 1 | |
| 167 | − && get_rounding(sn, xm) >> (SP_MBITS + 1 + 3)) | |
| 127 | + if (xe == SP_EMIN - 1 && | |
| 128 | + ieee754sp_get_rounding(sn, xm) >> (SP_FBITS + 1 + 3)) | |
| 168 | 129 | { |
| 169 | 130 | /* Not tiny after rounding */ |
| 170 | − SETCX(IEEE754_INEXACT); | |
| 171 | − xm = get_rounding(sn, xm); | |
| 131 | + ieee754_setcx(IEEE754_INEXACT); | |
| 132 | + xm = ieee754sp_get_rounding(sn, xm); | |
| 172 | 133 | xm >>= 1; |
| 173 | 134 | /* Clear grs bits */ |
| 174 | 135 | xm &= ~(SP_MBIT(3) - 1); |
| 175 | 136 | xe++; |
| 176 | − } | |
| 177 | − else { | |
| 137 | + } else { | |
| 178 | 138 | /* sticky right shift es bits |
| 179 | 139 | */ |
| 180 | 140 | SPXSRSXn(es); |
| @@ -183,17 +143,17 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) · 2 unmodified lines | ||
| 183 | 143 | } |
| 184 | 144 | } |
| 185 | 145 | if (xm & (SP_MBIT(3) - 1)) { |
| 186 | − SETCX(IEEE754_INEXACT); | |
| 146 | + ieee754_setcx(IEEE754_INEXACT); | |
| 187 | 147 | if ((xm & (SP_HIDDEN_BIT << 3)) == 0) { |
| 188 | − SETCX(IEEE754_UNDERFLOW); | |
| 148 | + ieee754_setcx(IEEE754_UNDERFLOW); | |
| 189 | 149 | } |
| 190 | 150 | |
| 191 | 151 | /* inexact must round of 3 bits |
| 192 | 152 | */ |
| 193 | − xm = get_rounding(sn, xm); | |
| 153 | + xm = ieee754sp_get_rounding(sn, xm); | |
| 194 | 154 | /* adjust exponent for rounding add overflowing |
| 195 | 155 | */ |
| 196 | − if (xm >> (SP_MBITS + 1 + 3)) { | |
| 156 | + if (xm >> (SP_FBITS + 1 + 3)) { | |
| 197 | 157 | /* add causes mantissa overflow */ |
| 198 | 158 | xm >>= 1; |
| 199 | 159 | xe++; |
| @@ -202,24 +162,24 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) · 2 unmodified lines | ||
| 202 | 162 | /* strip grs bits */ |
| 203 | 163 | xm >>= 3; |
| 204 | 164 | |
| 205 | − assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ | |
| 165 | + assert((xm >> (SP_FBITS + 1)) == 0); /* no execess */ | |
| 206 | 166 | assert(xe >= SP_EMIN); |
| 207 | 167 | |
| 208 | 168 | if (xe > SP_EMAX) { |
| 209 | − SETCX(IEEE754_OVERFLOW); | |
| 210 | − SETCX(IEEE754_INEXACT); | |
| 169 | + ieee754_setcx(IEEE754_OVERFLOW); | |
| 170 | + ieee754_setcx(IEEE754_INEXACT); | |
| 211 | 171 | /* -O can be table indexed by (rm,sn) */ |
| 212 | 172 | switch (ieee754_csr.rm) { |
| 213 | − case IEEE754_RN: | |
| 173 | + case FPU_CSR_RN: | |
| 214 | 174 | return ieee754sp_inf(sn); |
| 215 | − case IEEE754_RZ: | |
| 175 | + case FPU_CSR_RZ: | |
| 216 | 176 | return ieee754sp_max(sn); |
| 217 | − case IEEE754_RU: /* toward +Infinity */ | |
| 177 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 218 | 178 | if (sn == 0) |
| 219 | 179 | return ieee754sp_inf(0); |
| 220 | 180 | else |
| 221 | 181 | return ieee754sp_max(1); |
| 222 | − case IEEE754_RD: /* toward -Infinity */ | |
| 182 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 223 | 183 | if (sn == 0) |
| 224 | 184 | return ieee754sp_max(0); |
| 225 | 185 | else |
| @@ -232,10 +192,10 @@ ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) · 6 unmodified lines | ||
| 232 | 192 | /* we underflow (tiny/zero) */ |
| 233 | 193 | assert(xe == SP_EMIN); |
| 234 | 194 | if (ieee754_csr.mx & IEEE754_UNDERFLOW) |
| 235 | − SETCX(IEEE754_UNDERFLOW); | |
| 195 | + ieee754_setcx(IEEE754_UNDERFLOW); | |
| 236 | 196 | return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); |
| 237 | 197 | } else { |
| 238 | − assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ | |
| 198 | + assert((xm >> (SP_FBITS + 1)) == 0); /* no execess */ | |
| 239 | 199 | assert(xm & SP_HIDDEN_BIT); |
| 240 | 200 | |
| 241 | 201 | return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); |
| @@ -6,8 +6,6 @@ · 5 unmodified lines | ||
| 6 | 6 | * MIPS floating point support |
| 7 | 7 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 8 | 8 | * |
| 9 | − * ######################################################################## | |
| 10 | − * | |
| 11 | 9 | * This program is free software; you can distribute it and/or modify it |
| 12 | 10 | * under the terms of the GNU General Public License (Version 2) as |
| 13 | 11 | * published by the Free Software Foundation. |
| @@ -19,70 +17,71 @@ · 5 unmodified lines | ||
| 19 | 17 | * |
| 20 | 18 | * You should have received a copy of the GNU General Public License along |
| 21 | 19 | * with this program; if not, write to the Free Software Foundation, Inc., |
| 22 | − * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
| 23 | − * | |
| 24 | − * ######################################################################## | |
| 20 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 25 | 21 | */ |
| 26 | 22 | |
| 23 | +#include <linux/compiler.h> | |
| 27 | 24 | |
| 28 | 25 | #include "ieee754int.h" |
| 29 | 26 | |
| 30 | 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 | 48 | /* 3bit extended single precision sticky right shift */ |
| 33 | −#define SPXSRSXn(rs) \ | |
| 34 | − (xe += rs, \ | |
| 35 | − xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) | |
| 49 | +#define SPXSRSXn(rs) \ | |
| 50 | + (xe += rs, \ | |
| 51 | + xm = (rs > (SP_FBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) | |
| 36 | 52 | |
| 37 | 53 | #define SPXSRSX1() \ |
| 38 | − (xe++, (xm = (xm >> 1) | (xm & 1))) | |
| 54 | + (xe++, (xm = (xm >> 1) | (xm & 1))) | |
| 39 | 55 | |
| 40 | −#define SPXSRSYn(rs) \ | |
| 41 | − (ye+=rs, \ | |
| 42 | − ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) | |
| 56 | +#define SPXSRSYn(rs) \ | |
| 57 | + (ye+=rs, \ | |
| 58 | + ym = (rs > (SP_FBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) | |
| 43 | 59 | |
| 44 | 60 | #define SPXSRSY1() \ |
| 45 | − (ye++, (ym = (ym >> 1) | (ym & 1))) | |
| 61 | + (ye++, (ym = (ym >> 1) | (ym & 1))) | |
| 46 | 62 | |
| 47 | 63 | /* convert denormal to normalized with extended exponent */ |
| 48 | 64 | #define SPDNORMx(m,e) \ |
| 49 | − while( (m >> SP_MBITS) == 0) { m <<= 1; e--; } | |
| 65 | + while ((m >> SP_FBITS) == 0) { m <<= 1; e--; } | |
| 50 | 66 | #define SPDNORMX SPDNORMx(xm, xe) |
| 51 | 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 | 73 | assert((s) == 0 || (s) == 1); |
| 58 | 74 | assert((bx) >= SP_EMIN - 1 + SP_EBIAS |
| 59 | 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; | |
| 63 | − r.parts.bexp = bx; | |
| 64 | − r.parts.mant = m; | |
| 78 | + r.sign = s; | |
| 79 | + r.bexp = bx; | |
| 80 | + r.mant = m; | |
| 65 | 81 | |
| 66 | 82 | return r; |
| 67 | 83 | } |
| 68 | 84 | |
| 69 | −extern int ieee754sp_isnan(ieee754sp); | |
| 70 | −extern int ieee754sp_issnan(ieee754sp); | |
| 71 | −extern int ieee754si_xcpt(int, const char *, ...); | |
| 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) | |
| 85 | +extern int ieee754sp_isnan(union ieee754sp); | |
| 86 | +extern union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp); | |
| 87 | +extern union ieee754sp ieee754sp_format(int, int, unsigned); | |
| @@ -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 | −} | |
| @@ -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 | −} | |
| @@ -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); | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,23 +16,22 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 28 | COMPXSP; |
| 32 | 29 | COMPYSP; |
| 33 | 30 | |
| 34 | 31 | EXPLODEXSP; |
| 35 | 32 | EXPLODEYSP; |
| 36 | 33 | |
| 37 | − CLEARCX; | |
| 34 | + ieee754_clearcx(); | |
| 38 | 35 | |
| 39 | 36 | FLUSHXSP; |
| 40 | 37 | FLUSHYSP; |
| @@ -51,8 +48,8 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) · 10 unmodified lines | ||
| 51 | 48 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
| 52 | 49 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
| 53 | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
| 54 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 55 | − return ieee754sp_nanxcpt(ieee754sp_indef(), "add", x, y); | |
| 51 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 52 | + return ieee754sp_nanxcpt(ieee754sp_indef()); | |
| 56 | 53 | |
| 57 | 54 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
| 58 | 55 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
| @@ -68,14 +65,14 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) · 9 unmodified lines | ||
| 68 | 65 | return x; |
| 69 | 66 | |
| 70 | 67 | |
| 71 | − /* Infinity handling | |
| 72 | − */ | |
| 73 | − | |
| 68 | + /* | |
| 69 | + * Infinity handling | |
| 70 | + */ | |
| 74 | 71 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
| 75 | 72 | if (xs == ys) |
| 76 | 73 | return x; |
| 77 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 78 | − return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y); | |
| 74 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 75 | + return ieee754sp_indef(); | |
| 79 | 76 | |
| 80 | 77 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
| 81 | 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
| @@ -87,15 +84,14 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) · 5 unmodified lines | ||
| 87 | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
| 88 | 85 | return x; |
| 89 | 86 | |
| 90 | − /* Zero handling | |
| 91 | − */ | |
| 92 | − | |
| 87 | + /* | |
| 88 | + * Zero handling | |
| 89 | + */ | |
| 93 | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
| 94 | 91 | if (xs == ys) |
| 95 | 92 | return x; |
| 96 | 93 | else |
| 97 | − return ieee754sp_zero(ieee754_csr.rm == | |
| 98 | − IEEE754_RD); | |
| 94 | + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); | |
| 99 | 95 | |
| 100 | 96 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
| 101 | 97 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
| @@ -108,6 +104,8 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) · 6 unmodified lines | ||
| 108 | 104 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): |
| 109 | 105 | SPDNORMX; |
| 110 | 106 | |
| 107 | + /* FALL THROUGH */ | |
| 108 | + | |
| 111 | 109 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): |
| 112 | 110 | SPDNORMY; |
| 113 | 111 | break; |
| @@ -122,33 +120,38 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) · 8 unmodified lines | ||
| 122 | 120 | assert(xm & SP_HIDDEN_BIT); |
| 123 | 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 | 126 | xm <<= 3; |
| 127 | 127 | ym <<= 3; |
| 128 | 128 | |
| 129 | 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 | 134 | SPXSRSYn(s); |
| 134 | 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 | 140 | SPXSRSXn(s); |
| 139 | 141 | } |
| 140 | 142 | assert(xe == ye); |
| 141 | 143 | assert(xe <= SP_EMAX); |
| 142 | 144 | |
| 143 | 145 | if (xs == ys) { |
| 144 | − /* generate 28 bit result of adding two 27 bit numbers | |
| 145 | − * leaving result in xm,xs,xe | |
| 146 | + /* | |
| 147 | + * Generate 28 bit result of adding two 27 bit numbers | |
| 148 | + * leaving result in xm, xs and xe. | |
| 146 | 149 | */ |
| 147 | 150 | xm = xm + ym; |
| 148 | 151 | xe = xe; |
| 149 | 152 | xs = xs; |
| 150 | 153 | |
| 151 | − if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ | |
| 154 | + if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */ | |
| 152 | 155 | SPXSRSX1(); |
| 153 | 156 | } |
| 154 | 157 | } else { |
| @@ -162,15 +165,16 @@ ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) · 7 unmodified lines | ||
| 162 | 165 | xs = ys; |
| 163 | 166 | } |
| 164 | 167 | if (xm == 0) |
| 165 | − return ieee754sp_zero(ieee754_csr.rm == | |
| 166 | − IEEE754_RD); | |
| 168 | + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); | |
| 167 | 169 | |
| 168 | − /* normalize in extended single precision */ | |
| 169 | − while ((xm >> (SP_MBITS + 3)) == 0) { | |
| 170 | + /* | |
| 171 | + * Normalize in extended single precision | |
| 172 | + */ | |
| 173 | + while ((xm >> (SP_FBITS + 3)) == 0) { | |
| 170 | 174 | xm <<= 1; |
| 171 | 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 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,16 +16,16 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 29 | COMPXSP; |
| 32 | 30 | COMPYSP; |
| 33 | 31 | |
| @@ -35,21 +33,21 @@ int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp, int sig) · 1 unmodified line | ||
| 35 | 33 | EXPLODEYSP; |
| 36 | 34 | FLUSHXSP; |
| 37 | 35 | FLUSHYSP; |
| 38 | − CLEARCX; /* Even clear inexact flag here */ | |
| 36 | + ieee754_clearcx(); /* Even clear inexact flag here */ | |
| 39 | 37 | |
| 40 | 38 | if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) { |
| 41 | 39 | if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) |
| 42 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 40 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 43 | 41 | if (cmp & IEEE754_CUN) |
| 44 | 42 | return 1; |
| 45 | 43 | if (cmp & (IEEE754_CLT | IEEE754_CGT)) { |
| 46 | − if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION)) | |
| 47 | − return ieee754si_xcpt(0, "fcmpf", x); | |
| 44 | + if (sig && ieee754_setandtestcx(IEEE754_INVALID_OPERATION)) | |
| 45 | + return 0; | |
| 48 | 46 | } |
| 49 | 47 | return 0; |
| 50 | 48 | } else { |
| 51 | − int vx = x.bits; | |
| 52 | − int vy = y.bits; | |
| 49 | + vx = x.bits; | |
| 50 | + vy = y.bits; | |
| 53 | 51 | |
| 54 | 52 | if (vx < 0) |
| 55 | 53 | vx = -vx ^ SP_SIGN_BIT; |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,23 +16,24 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 30 | COMPXSP; |
| 32 | 31 | COMPYSP; |
| 33 | 32 | |
| 34 | 33 | EXPLODEXSP; |
| 35 | 34 | EXPLODEYSP; |
| 36 | 35 | |
| 37 | − CLEARCX; | |
| 36 | + ieee754_clearcx(); | |
| 38 | 37 | |
| 39 | 38 | FLUSHXSP; |
| 40 | 39 | FLUSHYSP; |
| @@ -51,8 +50,8 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) · 10 unmodified lines | ||
| 51 | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
| 52 | 51 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
| 53 | 52 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
| 54 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 55 | − return ieee754sp_nanxcpt(ieee754sp_indef(), "div", x, y); | |
| 53 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 54 | + return ieee754sp_nanxcpt(ieee754sp_indef()); | |
| 56 | 55 | |
| 57 | 56 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
| 58 | 57 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
| @@ -68,12 +67,12 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) · 9 unmodified lines | ||
| 68 | 67 | return x; |
| 69 | 68 | |
| 70 | 69 | |
| 71 | − /* Infinity handling | |
| 72 | − */ | |
| 73 | − | |
| 70 | + /* | |
| 71 | + * Infinity handling | |
| 72 | + */ | |
| 74 | 73 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
| 75 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 76 | − return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); | |
| 74 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 75 | + return ieee754sp_indef(); | |
| 77 | 76 | |
| 78 | 77 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
| 79 | 78 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
| @@ -85,17 +84,17 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) · 5 unmodified lines | ||
| 85 | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
| 86 | 85 | return ieee754sp_inf(xs ^ ys); |
| 87 | 86 | |
| 88 | − /* Zero handling | |
| 89 | − */ | |
| 90 | − | |
| 87 | + /* | |
| 88 | + * Zero handling | |
| 89 | + */ | |
| 91 | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
| 92 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 93 | − return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); | |
| 91 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 92 | + return ieee754sp_indef(); | |
| 94 | 93 | |
| 95 | 94 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
| 96 | 95 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
| 97 | − SETCX(IEEE754_ZERO_DIVIDE); | |
| 98 | − return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y); | |
| 96 | + ieee754_setcx(IEEE754_ZERO_DIVIDE); | |
| 97 | + return ieee754sp_inf(xs ^ ys); | |
| 99 | 98 | |
| 100 | 99 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): |
| 101 | 100 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): |
| @@ -122,35 +121,33 @@ ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) · 20 unmodified lines | ||
| 122 | 121 | xm <<= 3; |
| 123 | 122 | ym <<= 3; |
| 124 | 123 | |
| 125 | − { | |
| 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 */ | |
| 124 | + /* now the dirty work */ | |
| 144 | 125 | |
| 145 | − assert(rm); | |
| 126 | + rm = 0; | |
| 127 | + re = xe - ye; | |
| 146 | 128 | |
| 147 | − /* normalise rm to rounding precision ? | |
| 148 | − */ | |
| 149 | − while ((rm >> (SP_MBITS + 3)) == 0) { | |
| 150 | − rm <<= 1; | |
| 151 | − re--; | |
| 129 | + for (bm = SP_MBIT(SP_FBITS + 2); bm; bm >>= 1) { | |
| 130 | + if (xm >= ym) { | |
| 131 | + xm -= ym; | |
| 132 | + rm |= bm; | |
| 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 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,59 +16,61 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 29 | COMPXDP; |
| 32 | − ieee754sp nan; | |
| 30 | + union ieee754sp nan; | |
| 33 | 31 | |
| 34 | 32 | EXPLODEXDP; |
| 35 | 33 | |
| 36 | − CLEARCX; | |
| 34 | + ieee754_clearcx(); | |
| 37 | 35 | |
| 38 | 36 | FLUSHXDP; |
| 39 | 37 | |
| 40 | 38 | switch (xc) { |
| 41 | 39 | case IEEE754_CLASS_SNAN: |
| 42 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 43 | − return ieee754sp_nanxcpt(ieee754sp_indef(), "fdp"); | |
| 40 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 41 | + return ieee754sp_nanxcpt(ieee754sp_indef()); | |
| 42 | + | |
| 44 | 43 | case IEEE754_CLASS_QNAN: |
| 45 | 44 | nan = buildsp(xs, SP_EMAX + 1 + SP_EBIAS, (u32) |
| 46 | − (xm >> (DP_MBITS - SP_MBITS))); | |
| 45 | + (xm >> (DP_FBITS - SP_FBITS))); | |
| 47 | 46 | if (!ieee754sp_isnan(nan)) |
| 48 | 47 | nan = ieee754sp_indef(); |
| 49 | − return ieee754sp_nanxcpt(nan, "fdp", x); | |
| 48 | + return ieee754sp_nanxcpt(nan); | |
| 49 | + | |
| 50 | 50 | case IEEE754_CLASS_INF: |
| 51 | 51 | return ieee754sp_inf(xs); |
| 52 | + | |
| 52 | 53 | case IEEE754_CLASS_ZERO: |
| 53 | 54 | return ieee754sp_zero(xs); |
| 55 | + | |
| 54 | 56 | case IEEE754_CLASS_DNORM: |
| 55 | 57 | /* can't possibly be sp representable */ |
| 56 | − SETCX(IEEE754_UNDERFLOW); | |
| 57 | − SETCX(IEEE754_INEXACT); | |
| 58 | − if ((ieee754_csr.rm == IEEE754_RU && !xs) || | |
| 59 | − (ieee754_csr.rm == IEEE754_RD && xs)) | |
| 60 | − return ieee754sp_xcpt(ieee754sp_mind(xs), "fdp", x); | |
| 61 | − return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x); | |
| 58 | + ieee754_setcx(IEEE754_UNDERFLOW); | |
| 59 | + ieee754_setcx(IEEE754_INEXACT); | |
| 60 | + if ((ieee754_csr.rm == FPU_CSR_RU && !xs) || | |
| 61 | + (ieee754_csr.rm == FPU_CSR_RD && xs)) | |
| 62 | + return ieee754sp_mind(xs); | |
| 63 | + return ieee754sp_zero(xs); | |
| 64 | + | |
| 62 | 65 | case IEEE754_CLASS_NORM: |
| 63 | 66 | break; |
| 64 | 67 | } |
| 65 | 68 | |
| 66 | − { | |
| 67 | − u32 rm; | |
| 68 | − | |
| 69 | − /* convert from DP_MBITS to SP_MBITS+3 with sticky right shift | |
| 70 | − */ | |
| 71 | − rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) | | |
| 72 | − ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0); | |
| 69 | + /* | |
| 70 | + * Convert from DP_FBITS to SP_FBITS+3 with sticky right shift. | |
| 71 | + */ | |
| 72 | + rm = (xm >> (DP_FBITS - (SP_FBITS + 3))) | | |
| 73 | + ((xm << (64 - (DP_FBITS - (SP_FBITS + 3)))) != 0); | |
| 73 | 74 | |
| 74 | − SPNORMRET1(xs, xe, rm, "fdp", x); | |
| 75 | − } | |
| 75 | + return ieee754sp_format(xs, xe, rm); | |
| 76 | 76 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,21 +16,18 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 22 | #include "ieee754sp.h" |
| 28 | 23 | |
| 29 | −ieee754sp ieee754sp_fint(int x) | |
| 24 | +union ieee754sp ieee754sp_fint(int x) | |
| 30 | 25 | { |
| 31 | 26 | unsigned xm; |
| 32 | 27 | int xe; |
| 33 | 28 | int xs; |
| 34 | 29 | |
| 35 | − CLEARCX; | |
| 30 | + ieee754_clearcx(); | |
| 36 | 31 | |
| 37 | 32 | if (x == 0) |
| 38 | 33 | return ieee754sp_zero(0); |
| @@ -50,30 +45,21 @@ ieee754sp ieee754sp_fint(int x) · 11 unmodified lines | ||
| 50 | 45 | } else { |
| 51 | 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 | 51 | /* shunt out overflow bits |
| 57 | 52 | */ |
| 58 | − while (xm >> (SP_MBITS + 1 + 3)) { | |
| 53 | + while (xm >> (SP_FBITS + 1 + 3)) { | |
| 59 | 54 | SPXSRSX1(); |
| 60 | 55 | } |
| 61 | 56 | } else { |
| 62 | 57 | /* normalize in grs extended single precision |
| 63 | 58 | */ |
| 64 | − while ((xm >> (SP_MBITS + 3)) == 0) { | |
| 59 | + while ((xm >> (SP_FBITS + 3)) == 0) { | |
| 65 | 60 | xm <<= 1; |
| 66 | 61 | xe--; |
| 67 | 62 | } |
| 68 | 63 | } |
| 69 | − SPNORMRET1(xs, xe, xm, "fint", x); | |
| 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); | |
| 64 | + return ieee754sp_format(xs, xe, xm); | |
| 79 | 65 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,21 +16,18 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 22 | #include "ieee754sp.h" |
| 28 | 23 | |
| 29 | −ieee754sp ieee754sp_flong(s64 x) | |
| 24 | +union ieee754sp ieee754sp_flong(s64 x) | |
| 30 | 25 | { |
| 31 | 26 | u64 xm; /* <--- need 64-bit mantissa temp */ |
| 32 | 27 | int xe; |
| 33 | 28 | int xs; |
| 34 | 29 | |
| 35 | − CLEARCX; | |
| 30 | + ieee754_clearcx(); | |
| 36 | 31 | |
| 37 | 32 | if (x == 0) |
| 38 | 33 | return ieee754sp_zero(0); |
| @@ -50,29 +45,20 @@ ieee754sp ieee754sp_flong(s64 x) · 11 unmodified lines | ||
| 50 | 45 | } else { |
| 51 | 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 | 51 | /* shunt out overflow bits |
| 57 | 52 | */ |
| 58 | − while (xm >> (SP_MBITS + 1 + 3)) { | |
| 53 | + while (xm >> (SP_FBITS + 1 + 3)) { | |
| 59 | 54 | SPXSRSX1(); |
| 60 | 55 | } |
| 61 | 56 | } else { |
| 62 | 57 | /* normalize in grs extended single precision */ |
| 63 | − while ((xm >> (SP_MBITS + 3)) == 0) { | |
| 58 | + while ((xm >> (SP_FBITS + 3)) == 0) { | |
| 64 | 59 | xm <<= 1; |
| 65 | 60 | xe--; |
| 66 | 61 | } |
| 67 | 62 | } |
| 68 | − SPNORMRET1(xs, xe, xm, "sp_flong", x); | |
| 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); | |
| 63 | + return ieee754sp_format(xs, xe, xm); | |
| 78 | 64 | } |
| @@ -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 | −} | |
| @@ -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 | −} | |
| @@ -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 | −} | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,23 +16,32 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 38 | COMPXSP; |
| 32 | 39 | COMPYSP; |
| 33 | 40 | |
| 34 | 41 | EXPLODEXSP; |
| 35 | 42 | EXPLODEYSP; |
| 36 | 43 | |
| 37 | − CLEARCX; | |
| 44 | + ieee754_clearcx(); | |
| 38 | 45 | |
| 39 | 46 | FLUSHXSP; |
| 40 | 47 | FLUSHYSP; |
| @@ -51,8 +58,8 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) · 10 unmodified lines | ||
| 51 | 58 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
| 52 | 59 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
| 53 | 60 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
| 54 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 55 | − return ieee754sp_nanxcpt(ieee754sp_indef(), "mul", x, y); | |
| 61 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 62 | + return ieee754sp_nanxcpt(ieee754sp_indef()); | |
| 56 | 63 | |
| 57 | 64 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
| 58 | 65 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
| @@ -68,12 +75,13 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) · 9 unmodified lines | ||
| 68 | 75 | return x; |
| 69 | 76 | |
| 70 | 77 | |
| 71 | − /* Infinity handling */ | |
| 72 | − | |
| 78 | + /* | |
| 79 | + * Infinity handling | |
| 80 | + */ | |
| 73 | 81 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): |
| 74 | 82 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
| 75 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 76 | − return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y); | |
| 83 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 84 | + return ieee754sp_indef(); | |
| 77 | 85 | |
| 78 | 86 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): |
| 79 | 87 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): |
| @@ -108,63 +116,50 @@ ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) · 28 unmodified lines | ||
| 108 | 116 | assert(xm & SP_HIDDEN_BIT); |
| 109 | 117 | assert(ym & SP_HIDDEN_BIT); |
| 110 | 118 | |
| 111 | − { | |
| 112 | − int re = xe + ye; | |
| 113 | − int rs = xs ^ ys; | |
| 114 | − unsigned rm; | |
| 115 | − | |
| 116 | − /* shunt to top of word */ | |
| 117 | − xm <<= 32 - (SP_MBITS + 1); | |
| 118 | − ym <<= 32 - (SP_MBITS + 1); | |
| 119 | − | |
| 120 | − /* multiply 32bits xm,ym to give high 32bits rm with stickness | |
| 121 | − */ | |
| 122 | − { | |
| 123 | − unsigned short lxm = xm & 0xffff; | |
| 124 | − unsigned short hxm = xm >> 16; | |
| 125 | − unsigned short lym = ym & 0xffff; | |
| 126 | − unsigned short hym = ym >> 16; | |
| 127 | − unsigned lrm; | |
| 128 | − unsigned hrm; | |
| 129 | − | |
| 130 | − lrm = lxm * lym; /* 16 * 16 => 32 */ | |
| 131 | − hrm = hxm * hym; /* 16 * 16 => 32 */ | |
| 132 | − | |
| 133 | − { | |
| 134 | − unsigned t = lxm * hym; /* 16 * 16 => 32 */ | |
| 135 | − { | |
| 136 | − unsigned at = lrm + (t << 16); | |
| 137 | − hrm += at < lrm; | |
| 138 | − lrm = at; | |
| 139 | − } | |
| 140 | − hrm = hrm + (t >> 16); | |
| 141 | − } | |
| 142 | − | |
| 143 | − { | |
| 144 | − unsigned t = hxm * lym; /* 16 * 16 => 32 */ | |
| 145 | − { | |
| 146 | − unsigned at = lrm + (t << 16); | |
| 147 | − hrm += at < lrm; | |
| 148 | − lrm = at; | |
| 149 | − } | |
| 150 | − hrm = hrm + (t >> 16); | |
| 151 | − } | |
| 152 | − rm = hrm | (lrm != 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); | |
| 119 | + re = xe + ye; | |
| 120 | + rs = xs ^ ys; | |
| 121 | + | |
| 122 | + /* shunt to top of word */ | |
| 123 | + xm <<= 32 - (SP_FBITS + 1); | |
| 124 | + ym <<= 32 - (SP_FBITS + 1); | |
| 125 | + | |
| 126 | + /* | |
| 127 | + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. | |
| 128 | + */ | |
| 129 | + lxm = xm & 0xffff; | |
| 130 | + hxm = xm >> 16; | |
| 131 | + lym = ym & 0xffff; | |
| 132 | + hym = ym >> 16; | |
| 133 | + | |
| 134 | + lrm = lxm * lym; /* 16 * 16 => 32 */ | |
| 135 | + hrm = hxm * hym; /* 16 * 16 => 32 */ | |
| 136 | + | |
| 137 | + t = lxm * hym; /* 16 * 16 => 32 */ | |
| 138 | + at = lrm + (t << 16); | |
| 139 | + hrm += at < lrm; | |
| 140 | + lrm = at; | |
| 141 | + hrm = hrm + (t >> 16); | |
| 142 | + | |
| 143 | + t = hxm * lym; /* 16 * 16 => 32 */ | |
| 144 | + at = lrm + (t << 16); | |
| 145 | + hrm += at < lrm; | |
| 146 | + lrm = at; | |
| 147 | + hrm = hrm + (t >> 16); | |
| 148 | + | |
| 149 | + rm = hrm | (lrm != 0); | |
| 150 | + | |
| 151 | + /* | |
| 152 | + * Sticky shift down to normal rounding precision. | |
| 153 | + */ | |
| 154 | + if ((int) rm < 0) { | |
| 155 | + rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | | |
| 156 | + ((rm << (SP_FBITS + 1 + 3)) != 0); | |
| 157 | + re++; | |
| 158 | + } else { | |
| 159 | + rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | | |
| 160 | + ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); | |
| 169 | 161 | } |
| 162 | + assert(rm & (SP_HIDDEN_BIT << 3)); | |
| 163 | + | |
| 164 | + return ieee754sp_format(rs, re, rm); | |
| 170 | 165 | } |
| @@ -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 | −} | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,33 +16,17 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 22 | #include "ieee754sp.h" |
| 28 | 23 | |
| 29 | −int ieee754sp_finite(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) | |
| 24 | +union ieee754sp ieee754sp_neg(union ieee754sp x) | |
| 43 | 25 | { |
| 44 | 26 | COMPXSP; |
| 45 | 27 | |
| 46 | 28 | EXPLODEXSP; |
| 47 | − CLEARCX; | |
| 29 | + ieee754_clearcx(); | |
| 48 | 30 | FLUSHXSP; |
| 49 | 31 | |
| 50 | 32 | /* |
| @@ -55,30 +37,29 @@ ieee754sp ieee754sp_neg(ieee754sp x) · 4 unmodified lines | ||
| 55 | 37 | SPSIGN(x) ^= 1; |
| 56 | 38 | |
| 57 | 39 | if (xc == IEEE754_CLASS_SNAN) { |
| 58 | − ieee754sp y = ieee754sp_indef(); | |
| 59 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 40 | + union ieee754sp y = ieee754sp_indef(); | |
| 41 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 60 | 42 | SPSIGN(y) = SPSIGN(x); |
| 61 | − return ieee754sp_nanxcpt(y, "neg"); | |
| 43 | + return ieee754sp_nanxcpt(y); | |
| 62 | 44 | } |
| 63 | 45 | |
| 64 | 46 | return x; |
| 65 | 47 | } |
| 66 | 48 | |
| 67 | − | |
| 68 | −ieee754sp ieee754sp_abs(ieee754sp x) | |
| 49 | +union ieee754sp ieee754sp_abs(union ieee754sp x) | |
| 69 | 50 | { |
| 70 | 51 | COMPXSP; |
| 71 | 52 | |
| 72 | 53 | EXPLODEXSP; |
| 73 | − CLEARCX; | |
| 54 | + ieee754_clearcx(); | |
| 74 | 55 | FLUSHXSP; |
| 75 | 56 | |
| 76 | 57 | /* Clear sign ALWAYS, irrespective of NaN */ |
| 77 | 58 | SPSIGN(x) = 0; |
| 78 | 59 | |
| 79 | 60 | if (xc == IEEE754_CLASS_SNAN) { |
| 80 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 81 | − return ieee754sp_nanxcpt(ieee754sp_indef(), "abs"); | |
| 61 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 62 | + return ieee754sp_nanxcpt(ieee754sp_indef()); | |
| 82 | 63 | } |
| 83 | 64 | |
| 84 | 65 | return x; |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,15 +16,12 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 22 | #include "ieee754sp.h" |
| 28 | 23 | |
| 29 | −ieee754sp ieee754sp_sqrt(ieee754sp x) | |
| 24 | +union ieee754sp ieee754sp_sqrt(union ieee754sp x) | |
| 30 | 25 | { |
| 31 | 26 | int ix, s, q, m, t, i; |
| 32 | 27 | unsigned int r; |
| @@ -35,34 +30,38 @@ ieee754sp ieee754sp_sqrt(ieee754sp x) · 2 unmodified lines | ||
| 35 | 30 | /* take care of Inf and NaN */ |
| 36 | 31 | |
| 37 | 32 | EXPLODEXSP; |
| 38 | − CLEARCX; | |
| 33 | + ieee754_clearcx(); | |
| 39 | 34 | FLUSHXSP; |
| 40 | 35 | |
| 41 | 36 | /* x == INF or NAN? */ |
| 42 | 37 | switch (xc) { |
| 43 | 38 | case IEEE754_CLASS_QNAN: |
| 44 | 39 | /* sqrt(Nan) = Nan */ |
| 45 | − return ieee754sp_nanxcpt(x, "sqrt"); | |
| 40 | + return ieee754sp_nanxcpt(x); | |
| 41 | + | |
| 46 | 42 | case IEEE754_CLASS_SNAN: |
| 47 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 48 | − return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); | |
| 43 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 44 | + return ieee754sp_nanxcpt(ieee754sp_indef()); | |
| 45 | + | |
| 49 | 46 | case IEEE754_CLASS_ZERO: |
| 50 | 47 | /* sqrt(0) = 0 */ |
| 51 | 48 | return x; |
| 49 | + | |
| 52 | 50 | case IEEE754_CLASS_INF: |
| 53 | 51 | if (xs) { |
| 54 | 52 | /* sqrt(-Inf) = Nan */ |
| 55 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 56 | − return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); | |
| 53 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 54 | + return ieee754sp_nanxcpt(ieee754sp_indef()); | |
| 57 | 55 | } |
| 58 | 56 | /* sqrt(+Inf) = Inf */ |
| 59 | 57 | return x; |
| 58 | + | |
| 60 | 59 | case IEEE754_CLASS_DNORM: |
| 61 | 60 | case IEEE754_CLASS_NORM: |
| 62 | 61 | if (xs) { |
| 63 | 62 | /* sqrt(-x) = Nan */ |
| 64 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 65 | − return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); | |
| 63 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 64 | + return ieee754sp_nanxcpt(ieee754sp_indef()); | |
| 66 | 65 | } |
| 67 | 66 | break; |
| 68 | 67 | } |
| @@ -99,12 +98,12 @@ ieee754sp ieee754sp_sqrt(ieee754sp x) · 30 unmodified lines | ||
| 99 | 98 | } |
| 100 | 99 | |
| 101 | 100 | if (ix != 0) { |
| 102 | − SETCX(IEEE754_INEXACT); | |
| 101 | + ieee754_setcx(IEEE754_INEXACT); | |
| 103 | 102 | switch (ieee754_csr.rm) { |
| 104 | − case IEEE754_RP: | |
| 103 | + case FPU_CSR_RU: | |
| 105 | 104 | q += 2; |
| 106 | 105 | break; |
| 107 | − case IEEE754_RN: | |
| 106 | + case FPU_CSR_RN: | |
| 108 | 107 | q += (q & 1); |
| 109 | 108 | break; |
| 110 | 109 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,23 +16,22 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 28 | COMPXSP; |
| 32 | 29 | COMPYSP; |
| 33 | 30 | |
| 34 | 31 | EXPLODEXSP; |
| 35 | 32 | EXPLODEYSP; |
| 36 | 33 | |
| 37 | − CLEARCX; | |
| 34 | + ieee754_clearcx(); | |
| 38 | 35 | |
| 39 | 36 | FLUSHXSP; |
| 40 | 37 | FLUSHYSP; |
| @@ -51,8 +48,8 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) · 10 unmodified lines | ||
| 51 | 48 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): |
| 52 | 49 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): |
| 53 | 50 | case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): |
| 54 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 55 | − return ieee754sp_nanxcpt(ieee754sp_indef(), "sub", x, y); | |
| 51 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 52 | + return ieee754sp_nanxcpt(ieee754sp_indef()); | |
| 56 | 53 | |
| 57 | 54 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): |
| 58 | 55 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): |
| @@ -68,14 +65,14 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) · 9 unmodified lines | ||
| 68 | 65 | return x; |
| 69 | 66 | |
| 70 | 67 | |
| 71 | − /* Infinity handling | |
| 72 | − */ | |
| 73 | − | |
| 68 | + /* | |
| 69 | + * Infinity handling | |
| 70 | + */ | |
| 74 | 71 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): |
| 75 | 72 | if (xs != ys) |
| 76 | 73 | return x; |
| 77 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 78 | − return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y); | |
| 74 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 75 | + return ieee754sp_indef(); | |
| 79 | 76 | |
| 80 | 77 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): |
| 81 | 78 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): |
| @@ -87,15 +84,14 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) · 5 unmodified lines | ||
| 87 | 84 | case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): |
| 88 | 85 | return x; |
| 89 | 86 | |
| 90 | − /* Zero handling | |
| 91 | − */ | |
| 92 | − | |
| 87 | + /* | |
| 88 | + * Zero handling | |
| 89 | + */ | |
| 93 | 90 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): |
| 94 | 91 | if (xs != ys) |
| 95 | 92 | return x; |
| 96 | 93 | else |
| 97 | − return ieee754sp_zero(ieee754_csr.rm == | |
| 98 | − IEEE754_RD); | |
| 94 | + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); | |
| 99 | 95 | |
| 100 | 96 | case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): |
| 101 | 97 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): |
| @@ -104,7 +100,7 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) · 2 unmodified lines | ||
| 104 | 100 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): |
| 105 | 101 | case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): |
| 106 | 102 | /* quick fix up */ |
| 107 | − DPSIGN(y) ^= 1; | |
| 103 | + SPSIGN(y) ^= 1; | |
| 108 | 104 | return y; |
| 109 | 105 | |
| 110 | 106 | case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): |
| @@ -133,14 +129,16 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) · 22 unmodified lines | ||
| 133 | 129 | ym <<= 3; |
| 134 | 130 | |
| 135 | 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 | 136 | SPXSRSYn(s); |
| 140 | 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 | 142 | SPXSRSXn(s); |
| 145 | 143 | } |
| 146 | 144 | assert(xe == ye); |
| @@ -153,7 +151,7 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) · 6 unmodified lines | ||
| 153 | 151 | xe = xe; |
| 154 | 152 | xs = xs; |
| 155 | 153 | |
| 156 | − if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ | |
| 154 | + if (xm >> (SP_FBITS + 1 + 3)) { /* carry out */ | |
| 157 | 155 | SPXSRSX1(); /* shift preserving sticky */ |
| 158 | 156 | } |
| 159 | 157 | } else { |
| @@ -167,17 +165,18 @@ ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) · 7 unmodified lines | ||
| 167 | 165 | xs = ys; |
| 168 | 166 | } |
| 169 | 167 | if (xm == 0) { |
| 170 | − if (ieee754_csr.rm == IEEE754_RD) | |
| 168 | + if (ieee754_csr.rm == FPU_CSR_RD) | |
| 171 | 169 | return ieee754sp_zero(1); /* round negative inf. => sign = -1 */ |
| 172 | 170 | else |
| 173 | 171 | return ieee754sp_zero(0); /* other round modes => sign = 1 */ |
| 174 | 172 | } |
| 175 | 173 | /* normalize to rounding precision |
| 176 | 174 | */ |
| 177 | − while ((xm >> (SP_MBITS + 3)) == 0) { | |
| 175 | + while ((xm >> (SP_FBITS + 3)) == 0) { | |
| 178 | 176 | xm <<= 1; |
| 179 | 177 | xe--; |
| 180 | 178 | } |
| 181 | 179 | } |
| 182 | − SPNORMRET2(xs, xe, xm, "sub", x, y); | |
| 180 | + | |
| 181 | + return ieee754sp_format(xs, xe, xm); | |
| 183 | 182 | } |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,20 +16,21 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | −#include <linux/kernel.h> | |
| 28 | 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 | 31 | COMPXSP; |
| 33 | 32 | |
| 34 | − CLEARCX; | |
| 33 | + ieee754_clearcx(); | |
| 35 | 34 | |
| 36 | 35 | EXPLODEXSP; |
| 37 | 36 | FLUSHXSP; |
| @@ -40,10 +39,12 @@ int ieee754sp_tint(ieee754sp x) · 2 unmodified lines | ||
| 40 | 39 | case IEEE754_CLASS_SNAN: |
| 41 | 40 | case IEEE754_CLASS_QNAN: |
| 42 | 41 | case IEEE754_CLASS_INF: |
| 43 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 44 | − return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); | |
| 42 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 43 | + return ieee754si_indef(); | |
| 44 | + | |
| 45 | 45 | case IEEE754_CLASS_ZERO: |
| 46 | 46 | return 0; |
| 47 | + | |
| 47 | 48 | case IEEE754_CLASS_DNORM: |
| 48 | 49 | case IEEE754_CLASS_NORM: |
| 49 | 50 | break; |
| @@ -54,18 +55,13 @@ int ieee754sp_tint(ieee754sp x) · 4 unmodified lines | ||
| 54 | 55 | return -0x80000000; |
| 55 | 56 | /* Set invalid. We will only use overflow for floating |
| 56 | 57 | point overflow */ |
| 57 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 58 | − return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); | |
| 58 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 59 | + return ieee754si_indef(); | |
| 59 | 60 | } |
| 60 | 61 | /* oh gawd */ |
| 61 | − if (xe > SP_MBITS) { | |
| 62 | − xm <<= xe - SP_MBITS; | |
| 62 | + if (xe > SP_FBITS) { | |
| 63 | + xm <<= xe - SP_FBITS; | |
| 63 | 64 | } else { |
| 64 | − u32 residue; | |
| 65 | − int round; | |
| 66 | − int sticky; | |
| 67 | − int odd; | |
| 68 | − | |
| 69 | 65 | if (xe < -1) { |
| 70 | 66 | residue = xm; |
| 71 | 67 | round = 0; |
| @@ -76,51 +72,38 @@ int ieee754sp_tint(ieee754sp x) · 4 unmodified lines | ||
| 76 | 72 | * so we do it in two steps. Be aware that xe |
| 77 | 73 | * may be -1 */ |
| 78 | 74 | residue = xm << (xe + 1); |
| 79 | − residue <<= 31 - SP_MBITS; | |
| 75 | + residue <<= 31 - SP_FBITS; | |
| 80 | 76 | round = (residue >> 31) != 0; |
| 81 | 77 | sticky = (residue << 1) != 0; |
| 82 | − xm >>= SP_MBITS - xe; | |
| 78 | + xm >>= SP_FBITS - xe; | |
| 83 | 79 | } |
| 84 | 80 | odd = (xm & 0x1) != 0x0; |
| 85 | 81 | switch (ieee754_csr.rm) { |
| 86 | − case IEEE754_RN: | |
| 82 | + case FPU_CSR_RN: | |
| 87 | 83 | if (round && (sticky || odd)) |
| 88 | 84 | xm++; |
| 89 | 85 | break; |
| 90 | − case IEEE754_RZ: | |
| 86 | + case FPU_CSR_RZ: | |
| 91 | 87 | break; |
| 92 | − case IEEE754_RU: /* toward +Infinity */ | |
| 88 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 93 | 89 | if ((round || sticky) && !xs) |
| 94 | 90 | xm++; |
| 95 | 91 | break; |
| 96 | − case IEEE754_RD: /* toward -Infinity */ | |
| 92 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 97 | 93 | if ((round || sticky) && xs) |
| 98 | 94 | xm++; |
| 99 | 95 | break; |
| 100 | 96 | } |
| 101 | 97 | if ((xm >> 31) != 0) { |
| 102 | 98 | /* This can happen after rounding */ |
| 103 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 104 | − return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); | |
| 99 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 100 | + return ieee754si_indef(); | |
| 105 | 101 | } |
| 106 | 102 | if (round || sticky) |
| 107 | − SETCX(IEEE754_INEXACT); | |
| 103 | + ieee754_setcx(IEEE754_INEXACT); | |
| 108 | 104 | } |
| 109 | 105 | if (xs) |
| 110 | 106 | return -xm; |
| 111 | 107 | else |
| 112 | 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 | −} | |
| @@ -5,8 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | * MIPS floating point support |
| 6 | 6 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
| 7 | 7 | * |
| 8 | − * ######################################################################## | |
| 9 | − * | |
| 10 | 8 | * This program is free software; you can distribute it and/or modify it |
| 11 | 9 | * under the terms of the GNU General Public License (Version 2) as |
| 12 | 10 | * published by the Free Software Foundation. |
| @@ -18,19 +16,22 @@ · 5 unmodified lines | ||
| 18 | 16 | * |
| 19 | 17 | * You should have received a copy of the GNU General Public License along |
| 20 | 18 | * 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 | − * ######################################################################## | |
| 19 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 24 | 20 | */ |
| 25 | 21 | |
| 26 | − | |
| 27 | 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 | 32 | COMPXDP; /* <-- need 64-bit mantissa tmp */ |
| 32 | 33 | |
| 33 | − CLEARCX; | |
| 34 | + ieee754_clearcx(); | |
| 34 | 35 | |
| 35 | 36 | EXPLODEXSP; |
| 36 | 37 | FLUSHXSP; |
| @@ -39,10 +40,12 @@ s64 ieee754sp_tlong(ieee754sp x) · 2 unmodified lines | ||
| 39 | 40 | case IEEE754_CLASS_SNAN: |
| 40 | 41 | case IEEE754_CLASS_QNAN: |
| 41 | 42 | case IEEE754_CLASS_INF: |
| 42 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 43 | − return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); | |
| 43 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 44 | + return ieee754di_indef(); | |
| 45 | + | |
| 44 | 46 | case IEEE754_CLASS_ZERO: |
| 45 | 47 | return 0; |
| 48 | + | |
| 46 | 49 | case IEEE754_CLASS_DNORM: |
| 47 | 50 | case IEEE754_CLASS_NORM: |
| 48 | 51 | break; |
| @@ -53,69 +56,51 @@ s64 ieee754sp_tlong(ieee754sp x) · 4 unmodified lines | ||
| 53 | 56 | return -0x8000000000000000LL; |
| 54 | 57 | /* Set invalid. We will only use overflow for floating |
| 55 | 58 | point overflow */ |
| 56 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 57 | − return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); | |
| 59 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 60 | + return ieee754di_indef(); | |
| 58 | 61 | } |
| 59 | 62 | /* oh gawd */ |
| 60 | − if (xe > SP_MBITS) { | |
| 61 | − xm <<= xe - SP_MBITS; | |
| 62 | − } else if (xe < SP_MBITS) { | |
| 63 | − u32 residue; | |
| 64 | − int round; | |
| 65 | − int sticky; | |
| 66 | − int odd; | |
| 67 | − | |
| 63 | + if (xe > SP_FBITS) { | |
| 64 | + xm <<= xe - SP_FBITS; | |
| 65 | + } else if (xe < SP_FBITS) { | |
| 68 | 66 | if (xe < -1) { |
| 69 | 67 | residue = xm; |
| 70 | 68 | round = 0; |
| 71 | 69 | sticky = residue != 0; |
| 72 | 70 | xm = 0; |
| 73 | 71 | } else { |
| 74 | − residue = xm << (32 - SP_MBITS + xe); | |
| 72 | + residue = xm << (32 - SP_FBITS + xe); | |
| 75 | 73 | round = (residue >> 31) != 0; |
| 76 | 74 | sticky = (residue << 1) != 0; |
| 77 | − xm >>= SP_MBITS - xe; | |
| 75 | + xm >>= SP_FBITS - xe; | |
| 78 | 76 | } |
| 79 | 77 | odd = (xm & 0x1) != 0x0; |
| 80 | 78 | switch (ieee754_csr.rm) { |
| 81 | − case IEEE754_RN: | |
| 79 | + case FPU_CSR_RN: | |
| 82 | 80 | if (round && (sticky || odd)) |
| 83 | 81 | xm++; |
| 84 | 82 | break; |
| 85 | − case IEEE754_RZ: | |
| 83 | + case FPU_CSR_RZ: | |
| 86 | 84 | break; |
| 87 | − case IEEE754_RU: /* toward +Infinity */ | |
| 85 | + case FPU_CSR_RU: /* toward +Infinity */ | |
| 88 | 86 | if ((round || sticky) && !xs) |
| 89 | 87 | xm++; |
| 90 | 88 | break; |
| 91 | − case IEEE754_RD: /* toward -Infinity */ | |
| 89 | + case FPU_CSR_RD: /* toward -Infinity */ | |
| 92 | 90 | if ((round || sticky) && xs) |
| 93 | 91 | xm++; |
| 94 | 92 | break; |
| 95 | 93 | } |
| 96 | 94 | if ((xm >> 63) != 0) { |
| 97 | 95 | /* This can happen after rounding */ |
| 98 | − SETCX(IEEE754_INVALID_OPERATION); | |
| 99 | − return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); | |
| 96 | + ieee754_setcx(IEEE754_INVALID_OPERATION); | |
| 97 | + return ieee754di_indef(); | |
| 100 | 98 | } |
| 101 | 99 | if (round || sticky) |
| 102 | − SETCX(IEEE754_INEXACT); | |
| 100 | + ieee754_setcx(IEEE754_INEXACT); | |
| 103 | 101 | } |
| 104 | 102 | if (xs) |
| 105 | 103 | return -xm; |
| 106 | 104 | else |
| 107 | 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 | −} | |
| @@ -137,8 +137,10 @@ static void octeon_flush_cache_sigtramp(unsigned long addr) · 136 unmodified lines | ||
| 137 | 137 | { |
| 138 | 138 | struct vm_area_struct *vma; |
| 139 | 139 | |
| 140 | + down_read(¤t->mm->mmap_sem); | |
| 140 | 141 | vma = find_vma(current->mm, addr); |
| 141 | 142 | octeon_flush_icache_all_cores(vma); |
| 143 | + up_read(¤t->mm->mmap_sem); | |
| 142 | 144 | } |
| 143 | 145 | |
| 144 | 146 | |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Ralf Baechle (ralf@gnu.org) |
| 8 | 8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
| 9 | 9 | */ |
| 10 | +#include <linux/cpu_pm.h> | |
| 10 | 11 | #include <linux/hardirq.h> |
| 11 | 12 | #include <linux/init.h> |
| 12 | 13 | #include <linux/highmem.h> |
| @@ -50,7 +51,7 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info) · 37 unmodified lines | ||
| 50 | 51 | { |
| 51 | 52 | preempt_disable(); |
| 52 | 53 | |
| 53 | −#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) | |
| 54 | +#ifndef CONFIG_MIPS_MT_SMP | |
| 54 | 55 | smp_call_function(func, info, 1); |
| 55 | 56 | #endif |
| 56 | 57 | func(info); |
| @@ -105,22 +106,37 @@ static inline void r4k_blast_dcache_page_dc32(unsigned long addr) · 48 unmodified lines | ||
| 105 | 106 | |
| 106 | 107 | static inline void r4k_blast_dcache_page_dc64(unsigned long addr) |
| 107 | 108 | { |
| 108 | − R4600_HIT_CACHEOP_WAR_IMPL; | |
| 109 | 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 | 117 | static void r4k_blast_dcache_page_setup(void) |
| 113 | 118 | { |
| 114 | 119 | unsigned long dc_lsize = cpu_dcache_line_size(); |
| 115 | 120 | |
| 116 | − if (dc_lsize == 0) | |
| 121 | + switch (dc_lsize) { | |
| 122 | + case 0: | |
| 117 | 123 | r4k_blast_dcache_page = (void *)cache_noop; |
| 118 | − else if (dc_lsize == 16) | |
| 124 | + break; | |
| 125 | + case 16: | |
| 119 | 126 | r4k_blast_dcache_page = blast_dcache16_page; |
| 120 | − else if (dc_lsize == 32) | |
| 127 | + break; | |
| 128 | + case 32: | |
| 121 | 129 | r4k_blast_dcache_page = r4k_blast_dcache_page_dc32; |
| 122 | − else if (dc_lsize == 64) | |
| 130 | + break; | |
| 131 | + case 64: | |
| 123 | 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 | 142 | #ifndef CONFIG_EVA |
| @@ -159,6 +175,8 @@ static void r4k_blast_dcache_page_indexed_setup(void) · 32 unmodified lines | ||
| 159 | 175 | r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed; |
| 160 | 176 | else if (dc_lsize == 64) |
| 161 | 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 | 182 | void (* r4k_blast_dcache)(void); |
| @@ -176,6 +194,8 @@ static void r4k_blast_dcache_setup(void) · 11 unmodified lines | ||
| 176 | 194 | r4k_blast_dcache = blast_dcache32; |
| 177 | 195 | else if (dc_lsize == 64) |
| 178 | 196 | r4k_blast_dcache = blast_dcache64; |
| 197 | + else if (dc_lsize == 128) | |
| 198 | + r4k_blast_dcache = blast_dcache128; | |
| 179 | 199 | } |
| 180 | 200 | |
| 181 | 201 | /* force code alignment (used for TX49XX_ICACHE_INDEX_INV_WAR) */ |
| @@ -265,6 +285,8 @@ static void r4k_blast_icache_page_setup(void) · 83 unmodified lines | ||
| 265 | 285 | r4k_blast_icache_page = blast_icache32_page; |
| 266 | 286 | else if (ic_lsize == 64) |
| 267 | 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 | 292 | #ifndef CONFIG_EVA |
| @@ -338,6 +360,8 @@ static void r4k_blast_icache_setup(void) · 67 unmodified lines | ||
| 338 | 360 | r4k_blast_icache = blast_icache32; |
| 339 | 361 | } else if (ic_lsize == 64) |
| 340 | 362 | r4k_blast_icache = blast_icache64; |
| 363 | + else if (ic_lsize == 128) | |
| 364 | + r4k_blast_icache = blast_icache128; | |
| 341 | 365 | } |
| 342 | 366 | |
| 343 | 367 | static void (* r4k_blast_scache_page)(unsigned long addr); |
| @@ -428,7 +452,7 @@ static void r4k___flush_cache_all(void) · 84 unmodified lines | ||
| 428 | 452 | |
| 429 | 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 | 456 | int i; |
| 433 | 457 | |
| 434 | 458 | for_each_online_cpu(i) |
| @@ -1094,6 +1118,21 @@ static void probe_pcache(void) · 659 unmodified lines | ||
| 1094 | 1118 | c->dcache.waybit = 0; |
| 1095 | 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 | 1136 | default: |
| 1098 | 1137 | if (!(config & MIPS_CONF_M)) |
| 1099 | 1138 | panic("Don't know how to probe P-caches on this cpu."); |
| @@ -1414,6 +1453,7 @@ static void setup_scache(void) · 314 unmodified lines | ||
| 1414 | 1453 | loongson3_sc_init(); |
| 1415 | 1454 | return; |
| 1416 | 1455 | |
| 1456 | + case CPU_CAVIUM_OCTEON3: | |
| 1417 | 1457 | case CPU_XLP: |
| 1418 | 1458 | /* don't need to worry about L2, fully coherent */ |
| 1419 | 1459 | return; |
| @@ -1644,3 +1684,26 @@ void r4k_cache_init(void) · 224 unmodified lines | ||
| 1644 | 1684 | coherency_setup(); |
| 1645 | 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); | |
| @@ -44,27 +44,6 @@ · 43 unmodified lines | ||
| 44 | 44 | #include <asm/tlb.h> |
| 45 | 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 | 48 | * We have up to 8 empty zeroed pages so we can map one of the right colour |
| 70 | 49 | * when needed. This is necessary only on R4000 / R4400 SC and MC versions |
| @@ -100,21 +79,7 @@ void setup_zero_pages(void) · 29 unmodified lines | ||
| 100 | 79 | zero_page_mask = ((PAGE_SIZE << order) - 1) & PAGE_MASK; |
| 101 | 80 | } |
| 102 | 81 | |
| 103 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 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) | |
| 82 | +static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot) | |
| 118 | 83 | { |
| 119 | 84 | enum fixed_addresses idx; |
| 120 | 85 | unsigned long vaddr, flags, entrylo; |
| @@ -126,58 +91,48 @@ void *kmap_coherent(struct page *page, unsigned long addr) · 5 unmodified lines | ||
| 126 | 91 | |
| 127 | 92 | pagefault_disable(); |
| 128 | 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 | 94 | idx += in_interrupt() ? FIX_N_COLOURS : 0; |
| 134 | −#endif | |
| 135 | 95 | vaddr = __fix_to_virt(FIX_CMAP_END - idx); |
| 136 | − pte = mk_pte(page, PAGE_KERNEL); | |
| 96 | + pte = mk_pte(page, prot); | |
| 137 | 97 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) |
| 138 | 98 | entrylo = pte.pte_high; |
| 139 | 99 | #else |
| 140 | 100 | entrylo = pte_to_entrylo(pte_val(pte)); |
| 141 | 101 | #endif |
| 142 | 102 | |
| 143 | − ENTER_CRITICAL(flags); | |
| 103 | + local_irq_save(flags); | |
| 144 | 104 | old_ctx = read_c0_entryhi(); |
| 145 | 105 | write_c0_entryhi(vaddr & (PAGE_MASK << 1)); |
| 146 | 106 | write_c0_entrylo0(entrylo); |
| 147 | 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 | 108 | tlbidx = read_c0_wired(); |
| 162 | 109 | write_c0_wired(tlbidx + 1); |
| 163 | 110 | write_c0_index(tlbidx); |
| 164 | 111 | mtc0_tlbw_hazard(); |
| 165 | 112 | tlb_write_indexed(); |
| 166 | −#endif | |
| 167 | 113 | tlbw_use_hazard(); |
| 168 | 114 | write_c0_entryhi(old_ctx); |
| 169 | − EXIT_CRITICAL(flags); | |
| 115 | + local_irq_restore(flags); | |
| 170 | 116 | |
| 171 | 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 | 130 | void kunmap_coherent(void) |
| 175 | 131 | { |
| 176 | −#ifndef CONFIG_MIPS_MT_SMTC | |
| 177 | 132 | unsigned int wired; |
| 178 | 133 | unsigned long flags, old_ctx; |
| 179 | 134 | |
| 180 | − ENTER_CRITICAL(flags); | |
| 135 | + local_irq_save(flags); | |
| 181 | 136 | old_ctx = read_c0_entryhi(); |
| 182 | 137 | wired = read_c0_wired() - 1; |
| 183 | 138 | write_c0_wired(wired); |
| @@ -189,8 +144,7 @@ void kunmap_coherent(void) · 5 unmodified lines | ||
| 189 | 144 | tlb_write_indexed(); |
| 190 | 145 | tlbw_use_hazard(); |
| 191 | 146 | write_c0_entryhi(old_ctx); |
| 192 | − EXIT_CRITICAL(flags); | |
| 193 | −#endif | |
| 147 | + local_irq_restore(flags); | |
| 194 | 148 | pagefault_enable(); |
| 195 | 149 | } |
| 196 | 150 | |
| @@ -256,7 +210,7 @@ EXPORT_SYMBOL_GPL(copy_from_user_page); · 59 unmodified lines | ||
| 256 | 210 | void __init fixrange_init(unsigned long start, unsigned long end, |
| 257 | 211 | pgd_t *pgd_base) |
| 258 | 212 | { |
| 259 | −#if defined(CONFIG_HIGHMEM) || defined(CONFIG_MIPS_MT_SMTC) | |
| 213 | +#ifdef CONFIG_HIGHMEM | |
| 260 | 214 | pgd_t *pgd; |
| 261 | 215 | pud_t *pud; |
| 262 | 216 | pmd_t *pmd; |
| @@ -327,8 +281,6 @@ void __init paging_init(void) · 64 unmodified lines | ||
| 327 | 281 | #ifdef CONFIG_HIGHMEM |
| 328 | 282 | kmap_init(); |
| 329 | 283 | #endif |
| 330 | − kmap_coherent_init(); | |
| 331 | − | |
| 332 | 284 | #ifdef CONFIG_ZONE_DMA |
| 333 | 285 | max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; |
| 334 | 286 | #endif |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | * Carsten Langgaard, carstenl@mips.com |
| 9 | 9 | * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved. |
| 10 | 10 | */ |
| 11 | +#include <linux/cpu_pm.h> | |
| 11 | 12 | #include <linux/init.h> |
| 12 | 13 | #include <linux/sched.h> |
| 13 | 14 | #include <linux/smp.h> |
| @@ -25,28 +26,6 @@ · 11 unmodified lines | ||
| 25 | 26 | |
| 26 | 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 | 30 | * LOONGSON2/3 has a 4 entry itlb which is a subset of dtlb, |
| 52 | 31 | * unfortunately, itlb is not totally transparent to software. |
| @@ -75,7 +54,7 @@ void local_flush_tlb_all(void) · 22 unmodified lines | ||
| 75 | 54 | unsigned long old_ctx; |
| 76 | 55 | int entry, ftlbhighset; |
| 77 | 56 | |
| 78 | − ENTER_CRITICAL(flags); | |
| 57 | + local_irq_save(flags); | |
| 79 | 58 | /* Save old context and create impossible VPN2 value */ |
| 80 | 59 | old_ctx = read_c0_entryhi(); |
| 81 | 60 | write_c0_entrylo0(0); |
| @@ -112,7 +91,7 @@ void local_flush_tlb_all(void) · 30 unmodified lines | ||
| 112 | 91 | tlbw_use_hazard(); |
| 113 | 92 | write_c0_entryhi(old_ctx); |
| 114 | 93 | flush_itlb(); |
| 115 | − EXIT_CRITICAL(flags); | |
| 94 | + local_irq_restore(flags); | |
| 116 | 95 | } |
| 117 | 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, · 23 unmodified lines | ||
| 142 | 121 | if (cpu_context(cpu, mm) != 0) { |
| 143 | 122 | unsigned long size, flags; |
| 144 | 123 | |
| 145 | − ENTER_CRITICAL(flags); | |
| 124 | + local_irq_save(flags); | |
| 146 | 125 | start = round_down(start, PAGE_SIZE << 1); |
| 147 | 126 | end = round_up(end, PAGE_SIZE << 1); |
| 148 | 127 | size = (end - start) >> (PAGE_SHIFT + 1); |
| @@ -176,7 +155,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, · 27 unmodified lines | ||
| 176 | 155 | drop_mmu_context(mm, cpu); |
| 177 | 156 | } |
| 178 | 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) · 1 unmodified line | ||
| 184 | 163 | { |
| 185 | 164 | unsigned long size, flags; |
| 186 | 165 | |
| 187 | − ENTER_CRITICAL(flags); | |
| 166 | + local_irq_save(flags); | |
| 188 | 167 | size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; |
| 189 | 168 | size = (size + 1) >> 1; |
| 190 | 169 | if (size <= (current_cpu_data.tlbsizeftlbsets ? |
| @@ -220,7 +199,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) · 29 unmodified lines | ||
| 220 | 199 | local_flush_tlb_all(); |
| 221 | 200 | } |
| 222 | 201 | flush_itlb(); |
| 223 | − EXIT_CRITICAL(flags); | |
| 202 | + local_irq_restore(flags); | |
| 224 | 203 | } |
| 225 | 204 | |
| 226 | 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) · 6 unmodified lines | ||
| 233 | 212 | |
| 234 | 213 | newpid = cpu_asid(cpu, vma->vm_mm); |
| 235 | 214 | page &= (PAGE_MASK << 1); |
| 236 | − ENTER_CRITICAL(flags); | |
| 215 | + local_irq_save(flags); | |
| 237 | 216 | oldpid = read_c0_entryhi(); |
| 238 | 217 | write_c0_entryhi(page | newpid); |
| 239 | 218 | mtc0_tlbw_hazard(); |
| @@ -253,7 +232,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) · 13 unmodified lines | ||
| 253 | 232 | finish: |
| 254 | 233 | write_c0_entryhi(oldpid); |
| 255 | 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) · 6 unmodified lines | ||
| 266 | 245 | unsigned long flags; |
| 267 | 246 | int oldpid, idx; |
| 268 | 247 | |
| 269 | − ENTER_CRITICAL(flags); | |
| 248 | + local_irq_save(flags); | |
| 270 | 249 | oldpid = read_c0_entryhi(); |
| 271 | 250 | page &= (PAGE_MASK << 1); |
| 272 | 251 | write_c0_entryhi(page); |
| @@ -285,7 +264,7 @@ void local_flush_tlb_one(unsigned long page) · 12 unmodified lines | ||
| 285 | 264 | } |
| 286 | 265 | write_c0_entryhi(oldpid); |
| 287 | 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) · 16 unmodified lines | ||
| 308 | 287 | if (current->active_mm != vma->vm_mm) |
| 309 | 288 | return; |
| 310 | 289 | |
| 311 | − ENTER_CRITICAL(flags); | |
| 290 | + local_irq_save(flags); | |
| 312 | 291 | |
| 313 | 292 | pid = read_c0_entryhi() & ASID_MASK; |
| 314 | 293 | address &= (PAGE_MASK << 1); |
| @@ -358,7 +337,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) · 43 unmodified lines | ||
| 358 | 337 | } |
| 359 | 338 | tlbw_use_hazard(); |
| 360 | 339 | flush_itlb_vm(vma); |
| 361 | − EXIT_CRITICAL(flags); | |
| 340 | + local_irq_restore(flags); | |
| 362 | 341 | } |
| 363 | 342 | |
| 364 | 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, · 4 unmodified lines | ||
| 369 | 348 | unsigned long old_pagemask; |
| 370 | 349 | unsigned long old_ctx; |
| 371 | 350 | |
| 372 | − ENTER_CRITICAL(flags); | |
| 351 | + local_irq_save(flags); | |
| 373 | 352 | /* Save old context and create impossible VPN2 value */ |
| 374 | 353 | old_ctx = read_c0_entryhi(); |
| 375 | 354 | old_pagemask = read_c0_pagemask(); |
| @@ -389,7 +368,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, · 13 unmodified lines | ||
| 389 | 368 | tlbw_use_hazard(); /* What is the hazard here? */ |
| 390 | 369 | write_c0_pagemask(old_pagemask); |
| 391 | 370 | local_flush_tlb_all(); |
| 392 | − EXIT_CRITICAL(flags); | |
| 371 | + local_irq_restore(flags); | |
| 393 | 372 | } |
| 394 | 373 | |
| 395 | 374 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
| @@ -399,13 +378,13 @@ int __init has_transparent_hugepage(void) · 3 unmodified lines | ||
| 399 | 378 | unsigned int mask; |
| 400 | 379 | unsigned long flags; |
| 401 | 380 | |
| 402 | − ENTER_CRITICAL(flags); | |
| 381 | + local_irq_save(flags); | |
| 403 | 382 | write_c0_pagemask(PM_HUGE_MASK); |
| 404 | 383 | back_to_back_c0_hazard(); |
| 405 | 384 | mask = read_c0_pagemask(); |
| 406 | 385 | write_c0_pagemask(PM_DEFAULT_MASK); |
| 407 | 386 | |
| 408 | − EXIT_CRITICAL(flags); | |
| 387 | + local_irq_restore(flags); | |
| 409 | 388 | |
| 410 | 389 | return mask == PM_HUGE_MASK; |
| 411 | 390 | } |
| @@ -421,7 +400,10 @@ static int __init set_ntlb(char *str) · 9 unmodified lines | ||
| 421 | 400 | |
| 422 | 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 | 409 | * You should never change this register: |
| @@ -453,6 +435,11 @@ void tlb_init(void) · 25 unmodified lines | ||
| 453 | 435 | local_flush_tlb_all(); |
| 454 | 436 | |
| 455 | 437 | /* Did I tell you that ARC SUCKS? */ |
| 438 | +} | |
| 439 | + | |
| 440 | +void tlb_init(void) | |
| 441 | +{ | |
| 442 | + r4k_tlb_configure(); | |
| 456 | 443 | |
| 457 | 444 | if (ntlb) { |
| 458 | 445 | if (ntlb > 1 && ntlb <= current_cpu_data.tlbsize) { |
| @@ -466,3 +453,26 @@ void tlb_init(void) · 7 unmodified lines | ||
| 466 | 453 | |
| 467 | 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); | |
| @@ -1256,7 +1256,7 @@ static void build_r4000_tlb_refill_handler(void) · 1255 unmodified lines | ||
| 1256 | 1256 | memset(relocs, 0, sizeof(relocs)); |
| 1257 | 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 | 1260 | htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1, |
| 1261 | 1261 | scratch_reg); |
| 1262 | 1262 | vmalloc_mode = refill_scratch; |
| @@ -63,6 +63,7 @@ static struct insn insn_table_MM[] = { · 62 unmodified lines | ||
| 63 | 63 | { insn_cache, M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM }, |
| 64 | 64 | { insn_daddu, 0, 0 }, |
| 65 | 65 | { insn_daddiu, 0, 0 }, |
| 66 | + { insn_divu, M(mm_pool32a_op, 0, 0, 0, mm_divu_op, mm_pool32axf_op), RT | RS }, | |
| 66 | 67 | { insn_dmfc0, 0, 0 }, |
| 67 | 68 | { insn_dmtc0, 0, 0 }, |
| 68 | 69 | { insn_dsll, 0, 0 }, |
| @@ -78,14 +79,20 @@ static struct insn insn_table_MM[] = { · 9 unmodified lines | ||
| 78 | 79 | { insn_ext, M(mm_pool32a_op, 0, 0, 0, 0, mm_ext_op), RT | RS | RD | RE }, |
| 79 | 80 | { insn_j, M(mm_j32_op, 0, 0, 0, 0, 0), JIMM }, |
| 80 | 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 | 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 | 85 | { insn_ld, 0, 0 }, |
| 86 | + { insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RS | RS | SIMM }, | |
| 83 | 87 | { insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM }, |
| 84 | 88 | { insn_lld, 0, 0 }, |
| 85 | 89 | { insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM }, |
| 86 | 90 | { insn_lw, M(mm_lw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, |
| 87 | 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 | 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 | 96 | { insn_or, M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD }, |
| 90 | 97 | { insn_ori, M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM }, |
| 91 | 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[] = { · 2 unmodified lines | ||
| 94 | 101 | { insn_scd, 0, 0 }, |
| 95 | 102 | { insn_sd, 0, 0 }, |
| 96 | 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 | 107 | { insn_sra, M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD }, |
| 98 | 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 | 110 | { insn_rotr, M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD }, |
| 100 | 111 | { insn_subu, M(mm_pool32a_op, 0, 0, 0, 0, mm_subu32_op), RT | RS | RD }, |
| 101 | 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 | 114 | { insn_tlbp, M(mm_pool32a_op, 0, 0, 0, mm_tlbp_op, mm_pool32axf_op), 0 }, |
| 103 | 115 | { insn_tlbr, M(mm_pool32a_op, 0, 0, 0, mm_tlbr_op, mm_pool32axf_op), 0 }, |
| 104 | 116 | { insn_tlbwi, M(mm_pool32a_op, 0, 0, 0, mm_tlbwi_op, mm_pool32axf_op), 0 }, |
| 105 | 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 | 120 | { insn_xor, M(mm_pool32a_op, 0, 0, 0, 0, mm_xor32_op), RT | RS | RD }, |
| 107 | 121 | { insn_xori, M(mm_xori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM }, |
| 108 | 122 | { insn_dins, 0, 0 }, |
| @@ -67,6 +67,7 @@ static struct insn insn_table[] = { · 66 unmodified lines | ||
| 67 | 67 | { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD }, |
| 68 | 68 | { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE }, |
| 69 | 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 | 71 | { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET}, |
| 71 | 72 | { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET}, |
| 72 | 73 | { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE }, |
| @@ -82,17 +83,23 @@ static struct insn insn_table[] = { · 9 unmodified lines | ||
| 82 | 83 | { insn_ins, M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE }, |
| 83 | 84 | { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, |
| 84 | 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 | 87 | { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, |
| 86 | 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 | 90 | { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
| 88 | 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 | 93 | { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
| 90 | 94 | { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
| 91 | 95 | { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM }, |
| 92 | 96 | { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
| 93 | 97 | { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD }, |
| 94 | 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 | 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 | 103 | { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, |
| 97 | 104 | { insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD }, |
| 98 | 105 | { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
| @@ -102,17 +109,25 @@ static struct insn insn_table[] = { · 3 unmodified lines | ||
| 102 | 109 | { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
| 103 | 110 | { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
| 104 | 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 | 115 | { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE }, |
| 106 | 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 | 118 | { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD }, |
| 108 | 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 | 121 | { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, |
| 110 | 122 | { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 }, |
| 111 | 123 | { insn_tlbr, M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0 }, |
| 112 | 124 | { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 }, |
| 113 | 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 | 128 | { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, |
| 115 | 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 | 131 | { insn_invalid, 0, 0 } |
| 117 | 132 | }; |
| 118 | 133 | |
| @@ -47,14 +47,16 @@ enum opcode { · 46 unmodified lines | ||
| 47 | 47 | insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1, |
| 48 | 48 | insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, |
| 49 | 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 | 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, | |
| 53 | − insn_ll, insn_lld, insn_lui, insn_lw, insn_lwx, insn_mfc0, insn_mtc0, | |
| 52 | + insn_ext, insn_ins, insn_j, insn_jal, insn_jalr, insn_jr, insn_lb, | |
| 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 | 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_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, | |
| 57 | − insn_xori, | |
| 56 | + insn_sd, insn_sll, insn_sllv, insn_sltiu, insn_sltu, insn_sra, | |
| 57 | + insn_srl, insn_srlv, insn_subu, insn_sw, insn_sync, insn_syscall, | |
| 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 | 62 | struct insn { |
| @@ -144,6 +146,13 @@ Ip_u2u1u3(op) \ · 83 unmodified lines | ||
| 144 | 146 | } \ |
| 145 | 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 | 156 | #define I_u3u1u2(op) \ |
| 148 | 157 | Ip_u3u1u2(op) \ |
| 149 | 158 | { \ |
| @@ -200,6 +209,13 @@ Ip_u1u2(op) \ · 50 unmodified lines | ||
| 200 | 209 | } \ |
| 201 | 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 | 219 | #define I_u1s2(op) \ |
| 204 | 220 | Ip_u1s2(op) \ |
| 205 | 221 | { \ |
| @@ -237,6 +253,7 @@ I_u1u2u3(_dmfc0) · 31 unmodified lines | ||
| 237 | 253 | I_u1u2u3(_dmtc0) |
| 238 | 254 | I_u2u1s3(_daddiu) |
| 239 | 255 | I_u3u1u2(_daddu) |
| 256 | +I_u1u2(_divu) | |
| 240 | 257 | I_u2u1u3(_dsll) |
| 241 | 258 | I_u2u1u3(_dsll32) |
| 242 | 259 | I_u2u1u3(_dsra) |
| @@ -250,14 +267,20 @@ I_u2u1msbdu3(_ext) · 7 unmodified lines | ||
| 250 | 267 | I_u2u1msbu3(_ins) |
| 251 | 268 | I_u1(_j) |
| 252 | 269 | I_u1(_jal) |
| 270 | +I_u2u1(_jalr) | |
| 253 | 271 | I_u1(_jr) |
| 272 | +I_u2s3u1(_lb) | |
| 254 | 273 | I_u2s3u1(_ld) |
| 274 | +I_u2s3u1(_lh) | |
| 255 | 275 | I_u2s3u1(_ll) |
| 256 | 276 | I_u2s3u1(_lld) |
| 257 | 277 | I_u1s2(_lui) |
| 258 | 278 | I_u2s3u1(_lw) |
| 259 | 279 | I_u1u2u3(_mfc0) |
| 280 | +I_u1(_mfhi) | |
| 281 | +I_u1(_mflo) | |
| 260 | 282 | I_u1u2u3(_mtc0) |
| 283 | +I_u3u1u2(_mul) | |
| 261 | 284 | I_u2u1u3(_ori) |
| 262 | 285 | I_u3u1u2(_or) |
| 263 | 286 | I_0(_rfe) |
| @@ -265,17 +288,25 @@ I_u2s3u1(_sc) · 1 unmodified line | ||
| 265 | 288 | I_u2s3u1(_scd) |
| 266 | 289 | I_u2s3u1(_sd) |
| 267 | 290 | I_u2u1u3(_sll) |
| 291 | +I_u3u2u1(_sllv) | |
| 292 | +I_u2u1s3(_sltiu) | |
| 293 | +I_u3u1u2(_sltu) | |
| 268 | 294 | I_u2u1u3(_sra) |
| 269 | 295 | I_u2u1u3(_srl) |
| 296 | +I_u3u2u1(_srlv) | |
| 270 | 297 | I_u2u1u3(_rotr) |
| 271 | 298 | I_u3u1u2(_subu) |
| 272 | 299 | I_u2s3u1(_sw) |
| 300 | +I_u1(_sync) | |
| 273 | 301 | I_0(_tlbp) |
| 274 | 302 | I_0(_tlbr) |
| 275 | 303 | I_0(_tlbwi) |
| 276 | 304 | I_0(_tlbwr) |
| 305 | +I_u1(_wait); | |
| 306 | +I_u2u1(_wsbh) | |
| 277 | 307 | I_u3u1u2(_xor) |
| 278 | 308 | I_u2u1u3(_xori) |
| 309 | +I_u2u1(_yield) | |
| 279 | 310 | I_u2u1msbu3(_dins); |
| 280 | 311 | I_u2u1msb32u3(_dinsm); |
| 281 | 312 | I_u1(_syscall); |
| @@ -469,6 +500,14 @@ void ISAFUNC(uasm_il_b)(u32 **p, struct uasm_reloc **r, int lid) · 187 unmodified lines | ||
| 469 | 500 | } |
| 470 | 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 | 511 | void ISAFUNC(uasm_il_beqz)(u32 **p, struct uasm_reloc **r, unsigned int reg, |
| 473 | 512 | int lid) |
| 474 | 513 | { |
| @@ -9,5 +9,4 @@ obj-y := malta-amon.o malta-display.o malta-init.o \ · 8 unmodified lines | ||
| 9 | 9 | malta-int.o malta-memory.o malta-platform.o \ |
| 10 | 10 | malta-reset.o malta-setup.o malta-time.o |
| 11 | 11 | |
| 12 | −# FIXME FIXME FIXME | |
| 13 | −obj-$(CONFIG_MIPS_MT_SMTC) += malta-smtc.o | |
| 12 | +obj-$(CONFIG_MIPS_MALTA_PM) += malta-pm.o | |
| @@ -116,8 +116,6 @@ phys_t mips_cpc_default_phys_base(void) · 115 unmodified lines | ||
| 116 | 116 | return CPC_BASE_ADDR; |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | −extern struct plat_smp_ops msmtc_smp_ops; | |
| 120 | − | |
| 121 | 119 | void __init prom_init(void) |
| 122 | 120 | { |
| 123 | 121 | mips_display_message("LINUX"); |
| @@ -304,8 +302,4 @@ mips_pci_controller: · 180 unmodified lines | ||
| 304 | 302 | return; |
| 305 | 303 | if (!register_vsmp_smp_ops()) |
| 306 | 304 | return; |
| 307 | − | |
| 308 | −#ifdef CONFIG_MIPS_MT_SMTC | |
| 309 | − register_smp_ops(&msmtc_smp_ops); | |
| 310 | −#endif | |
| 311 | 305 | } |
| @@ -504,28 +504,9 @@ void __init arch_init_irq(void) · 503 unmodified lines | ||
| 504 | 504 | } else if (cpu_has_vint) { |
| 505 | 505 | set_vi_handler(MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); |
| 506 | 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 | 507 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); |
| 526 | 508 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, |
| 527 | 509 | &corehi_irqaction); |
| 528 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 529 | 510 | } else { |
| 530 | 511 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); |
| 531 | 512 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, |
| @@ -26,8 +26,8 @@ unsigned long physical_memsize = 0L; · 25 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | fw_memblock_t * __init fw_getmdesc(int eva) |
| 28 | 28 | { |
| 29 | − char *memsize_str, *ememsize_str __maybe_unused = NULL, *ptr; | |
| 30 | − unsigned long memsize = 0, ememsize __maybe_unused = 0; | |
| 29 | + char *memsize_str, *ememsize_str = NULL, *ptr; | |
| 30 | + unsigned long memsize = 0, ememsize = 0; | |
| 31 | 31 | static char cmdline[COMMAND_LINE_SIZE] __initdata; |
| 32 | 32 | int tmp; |
| 33 | 33 | |
| @@ -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); | |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/pm.h> |
| 11 | 11 | |
| 12 | 12 | #include <asm/reboot.h> |
| 13 | +#include <asm/mach-malta/malta-pm.h> | |
| 13 | 14 | |
| 14 | 15 | #define SOFTRES_REG 0x1f000500 |
| 15 | 16 | #define GORESET 0x42 |
| @@ -24,17 +25,22 @@ static void mips_machine_restart(char *command) · 8 unmodified lines | ||
| 24 | 25 | |
| 25 | 26 | static void mips_machine_halt(void) |
| 26 | 27 | { |
| 27 | − unsigned int __iomem *softres_reg = | |
| 28 | − ioremap(SOFTRES_REG, sizeof(unsigned int)); | |
| 28 | + while (true); | |
| 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 | 39 | static int __init mips_reboot_setup(void) |
| 34 | 40 | { |
| 35 | 41 | _machine_restart = mips_machine_restart; |
| 36 | 42 | _machine_halt = mips_machine_halt; |
| 37 | − pm_power_off = mips_machine_halt; | |
| 43 | + pm_power_off = mips_machine_power_off; | |
| 38 | 44 | |
| 39 | 45 | return 0; |
| 40 | 46 | } |
| @@ -77,11 +77,7 @@ const char *get_system_type(void) · 76 unmodified lines | ||
| 77 | 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 | 80 | const char display_string[] = " LINUX ON MALTA "; |
| 84 | −#endif /* CONFIG_MIPS_MT_SMTC */ | |
| 85 | 81 | |
| 86 | 82 | #ifdef CONFIG_BLK_DEV_FD |
| 87 | 83 | static void __init fd_activate(void) |
| @@ -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 */ | |
| @@ -312,16 +312,13 @@ static int i2c_platform_probe(struct platform_device *pdev) · 311 unmodified lines | ||
| 312 | 312 | |
| 313 | 313 | pr_debug("i2c_platform_probe\n"); |
| 314 | 314 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 315 | − if (!r) { | |
| 316 | − ret = -ENODEV; | |
| 317 | − goto out; | |
| 318 | − } | |
| 315 | + if (!r) | |
| 316 | + return -ENODEV; | |
| 319 | 317 | |
| 320 | − priv = kzalloc(sizeof(struct i2c_platform_data), GFP_KERNEL); | |
| 321 | − if (!priv) { | |
| 322 | − ret = -ENOMEM; | |
| 323 | − goto out; | |
| 324 | − } | |
| 318 | + priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_platform_data), | |
| 319 | + GFP_KERNEL); | |
| 320 | + if (!priv) | |
| 321 | + return -ENOMEM; | |
| 325 | 322 | |
| 326 | 323 | /* FIXME: need to allocate resource in PIC32 space */ |
| 327 | 324 | #if 0 |
| @@ -330,10 +327,8 @@ static int i2c_platform_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 330 | 327 | #else |
| 331 | 328 | priv->base = r->start; |
| 332 | 329 | #endif |
| 333 | − if (!priv->base) { | |
| 334 | − ret = -EBUSY; | |
| 335 | − goto out_mem; | |
| 336 | − } | |
| 330 | + if (!priv->base) | |
| 331 | + return -EBUSY; | |
| 337 | 332 | |
| 338 | 333 | priv->xfer_timeout = 200; |
| 339 | 334 | priv->ack_timeout = 200; |
| @@ -348,17 +343,13 @@ static int i2c_platform_probe(struct platform_device *pdev) · 8 unmodified lines | ||
| 348 | 343 | i2c_platform_setup(priv); |
| 349 | 344 | |
| 350 | 345 | ret = i2c_add_numbered_adapter(&priv->adap); |
| 351 | − if (ret == 0) { | |
| 352 | − platform_set_drvdata(pdev, priv); | |
| 353 | − return 0; | |
| 346 | + if (ret) { | |
| 347 | + i2c_platform_disable(priv); | |
| 348 | + return ret; | |
| 354 | 349 | } |
| 355 | 350 | |
| 356 | − i2c_platform_disable(priv); | |
| 357 | − | |
| 358 | −out_mem: | |
| 359 | − kfree(priv); | |
| 360 | −out: | |
| 361 | − return ret; | |
| 351 | + platform_set_drvdata(pdev, priv); | |
| 352 | + return 0; | |
| 362 | 353 | } |
| 363 | 354 | |
| 364 | 355 | static int i2c_platform_remove(struct platform_device *pdev) |
| @@ -369,7 +360,6 @@ static int i2c_platform_remove(struct platform_device *pdev) · 4 unmodified lines | ||
| 369 | 360 | platform_set_drvdata(pdev, NULL); |
| 370 | 361 | i2c_del_adapter(&priv->adap); |
| 371 | 362 | i2c_platform_disable(priv); |
| 372 | − kfree(priv); | |
| 373 | 363 | return 0; |
| 374 | 364 | } |
| 375 | 365 | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# MIPS networking code | |
| 2 | + | |
| 3 | +obj-$(CONFIG_BPF_JIT) += bpf_jit.o | |
| @@ -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 | +} | |
| @@ -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 */ | |
| @@ -203,6 +203,8 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) · 202 unmodified lines | ||
| 203 | 203 | |
| 204 | 204 | xirq = nlm_irq_to_xirq(node, irq); |
| 205 | 205 | pic_data = irq_get_handler_data(xirq); |
| 206 | + if (WARN_ON(!pic_data)) | |
| 207 | + return; | |
| 206 | 208 | pic_data->extra_ack = xack; |
| 207 | 209 | } |
| 208 | 210 | |
| @@ -35,6 +35,7 @@ · 34 unmodified lines | ||
| 35 | 35 | |
| 36 | 36 | #include <asm/asm.h> |
| 37 | 37 | #include <asm/asm-offsets.h> |
| 38 | +#include <asm/cpu.h> | |
| 38 | 39 | #include <asm/cacheops.h> |
| 39 | 40 | #include <asm/regdef.h> |
| 40 | 41 | #include <asm/mipsregs.h> |
| @@ -73,6 +74,18 @@ · 32 unmodified lines | ||
| 73 | 74 | mtcr t1, t0 |
| 74 | 75 | .endm |
| 75 | 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 | + | |
| 76 | 89 | /* |
| 77 | 90 | * L1D cache has to be flushed before enabling threads in XLP. |
| 78 | 91 | * On XLP8xx/XLP3xx, we do a low level flush using processor control |
| @@ -80,7 +93,7 @@ · 1 unmodified line | ||
| 80 | 93 | */ |
| 81 | 94 | .macro xlp_flush_l1_dcache |
| 82 | 95 | mfc0 t0, CP0_EBASE, 0 |
| 83 | − andi t0, t0, 0xff00 | |
| 96 | + andi t0, t0, PRID_IMP_MASK | |
| 84 | 97 | slt t1, t0, 0x1200 |
| 85 | 98 | beqz t1, 15f |
| 86 | 99 | nop |
| @@ -159,11 +172,15 @@ FEXPORT(nlm_reset_entry) · 72 unmodified lines | ||
| 159 | 172 | |
| 160 | 173 | 1: /* Entry point on core wakeup */ |
| 161 | 174 | mfc0 t0, CP0_EBASE, 0 /* processor ID */ |
| 162 | − andi t0, 0xff00 | |
| 175 | + andi t0, PRID_IMP_MASK | |
| 163 | 176 | li t1, 0x1500 /* XLP 9xx */ |
| 164 | 177 | beq t0, t1, 2f /* does not need to set coherent */ |
| 165 | 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 | 184 | /* set bit in SYS coherent register for the core */ |
| 168 | 185 | mfc0 t0, CP0_EBASE, 1 |
| 169 | 186 | mfc0 t1, CP0_EBASE, 1 |
| @@ -197,6 +214,9 @@ FEXPORT(nlm_reset_entry) · 27 unmodified lines | ||
| 197 | 214 | EXPORT(nlm_boot_siblings) |
| 198 | 215 | /* core L1D flush before enable threads */ |
| 199 | 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 | 220 | /* Enable hw threads by writing to MAP_THREADMODE of the core */ |
| 201 | 221 | li t0, CKSEG1ADDR(RESET_DATA_PHYS) |
| 202 | 222 | lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ |
| @@ -225,6 +245,8 @@ EXPORT(nlm_boot_siblings) · 22 unmodified lines | ||
| 225 | 245 | #endif |
| 226 | 246 | mtc0 t1, CP0_STATUS |
| 227 | 247 | |
| 248 | + xlp_early_mmu_init | |
| 249 | + | |
| 228 | 250 | /* mark CPU ready */ |
| 229 | 251 | li t3, CKSEG1ADDR(RESET_DATA_PHYS) |
| 230 | 252 | ADDIU t1, t3, BOOT_CPU_READY |
| @@ -238,14 +260,12 @@ EXPORT(nlm_boot_siblings) · 7 unmodified lines | ||
| 238 | 260 | nop |
| 239 | 261 | |
| 240 | 262 | /* |
| 241 | − * For the boot CPU, we have to restore registers and | |
| 242 | − * return | |
| 263 | + * For the boot CPU, we have to restore ra and sp and return, rest | |
| 264 | + * of the registers will be restored by the caller | |
| 243 | 265 | */ |
| 244 | −4: dmfc0 t0, $4, 2 /* restore SP from UserLocal */ | |
| 245 | − li t1, 0xfadebeef | |
| 246 | − dmtc0 t1, $4, 2 /* restore SP from UserLocal */ | |
| 247 | − PTR_SUBU sp, t0, PT_SIZE | |
| 248 | − RESTORE_ALL | |
| 266 | +4: | |
| 267 | + dmfc0 ra, $22, 6 | |
| 268 | + dmfc0 sp, $22, 7 | |
| 249 | 269 | jr ra |
| 250 | 270 | nop |
| 251 | 271 | EXPORT(nlm_reset_entry_end) |
| @@ -253,6 +273,7 @@ EXPORT(nlm_reset_entry_end) · 1 unmodified line | ||
| 253 | 273 | LEAF(nlm_init_boot_cpu) |
| 254 | 274 | #ifdef CONFIG_CPU_XLP |
| 255 | 275 | xlp_config_lsu |
| 276 | + xlp_early_mmu_init | |
| 256 | 277 | #endif |
| 257 | 278 | jr ra |
| 258 | 279 | nop |
| @@ -135,10 +135,6 @@ void nlm_smp_finish(void) · 134 unmodified lines | ||
| 135 | 135 | local_irq_enable(); |
| 136 | 136 | } |
| 137 | 137 | |
| 138 | −void nlm_cpus_done(void) | |
| 139 | −{ | |
| 140 | −} | |
| 141 | − | |
| 142 | 138 | /* |
| 143 | 139 | * Boot all other cpus in the system, initialize them, and bring them into |
| 144 | 140 | * the boot function |
| @@ -198,7 +194,7 @@ void __init nlm_smp_setup(void) · 53 unmodified lines | ||
| 198 | 194 | cpumask_scnprintf(buf, ARRAY_SIZE(buf), cpu_possible_mask); |
| 199 | 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 | 198 | for (ncore = 0, i = 0; i < NLM_NR_NODES; i++) |
| 203 | 199 | ncore += hweight32(nlm_get_node(i)->coremask); |
| 204 | 200 | |
| @@ -213,6 +209,7 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask) · 8 unmodified lines | ||
| 213 | 209 | { |
| 214 | 210 | uint32_t core0_thr_mask, core_thr_mask; |
| 215 | 211 | int threadmode, i, j; |
| 212 | + char buf[64]; | |
| 216 | 213 | |
| 217 | 214 | core0_thr_mask = 0; |
| 218 | 215 | for (i = 0; i < NLM_THREADS_PER_CORE; i++) |
| @@ -247,8 +244,8 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask) · 28 unmodified lines | ||
| 247 | 244 | return threadmode; |
| 248 | 245 | |
| 249 | 246 | unsupp: |
| 250 | − panic("Unsupported CPU mask %lx", | |
| 251 | − (unsigned long)cpumask_bits(wakeup_mask)[0]); | |
| 247 | + cpumask_scnprintf(buf, ARRAY_SIZE(buf), wakeup_mask); | |
| 248 | + panic("Unsupported CPU mask %s", buf); | |
| 252 | 249 | return 0; |
| 253 | 250 | } |
| 254 | 251 | |
| @@ -277,7 +274,6 @@ struct plat_smp_ops nlm_smp_ops = { · 22 unmodified lines | ||
| 277 | 274 | .send_ipi_mask = nlm_send_ipi_mask, |
| 278 | 275 | .init_secondary = nlm_init_secondary, |
| 279 | 276 | .smp_finish = nlm_smp_finish, |
| 280 | − .cpus_done = nlm_cpus_done, | |
| 281 | 277 | .boot_secondary = nlm_boot_secondary, |
| 282 | 278 | .smp_setup = nlm_smp_setup, |
| 283 | 279 | .prepare_cpus = nlm_prepare_cpus, |
| @@ -54,8 +54,9 @@ · 53 unmodified lines | ||
| 54 | 54 | .set noat |
| 55 | 55 | .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ |
| 56 | 56 | |
| 57 | −FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ | |
| 58 | − dmtc0 sp, $4, 2 /* SP saved in UserLocal */ | |
| 57 | +/* Called by the boot cpu to wake up its sibling threads */ | |
| 58 | +NESTED(xlp_boot_core0_siblings, PT_SIZE, sp) | |
| 59 | + /* CPU register contents lost when enabling threads, save them first */ | |
| 59 | 60 | SAVE_ALL |
| 60 | 61 | sync |
| 61 | 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 */ · 3 unmodified lines | ||
| 65 | 66 | dsubu t2, t1 |
| 66 | 67 | daddu t2, t0 |
| 67 | 68 | /* call it */ |
| 68 | − jr t2 | |
| 69 | + jalr t2 | |
| 69 | 70 | nop |
| 70 | − /* not reached */ | |
| 71 | + RESTORE_ALL | |
| 72 | + jr ra | |
| 73 | + nop | |
| 74 | +END(xlp_boot_core0_siblings) | |
| 71 | 75 | |
| 72 | 76 | NESTED(nlm_boot_secondary_cpus, 16, sp) |
| 73 | 77 | /* Initialize CP0 Status */ |
| @@ -82,6 +82,7 @@ static struct clocksource csrc_pic = { · 81 unmodified lines | ||
| 82 | 82 | static void nlm_init_pic_timer(void) |
| 83 | 83 | { |
| 84 | 84 | uint64_t picbase = nlm_get_node(0)->picbase; |
| 85 | + u32 picfreq; | |
| 85 | 86 | |
| 86 | 87 | nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0); |
| 87 | 88 | if (current_cpu_data.cputype == CPU_XLR) { |
| @@ -92,7 +93,9 @@ static void nlm_init_pic_timer(void) · 4 unmodified lines | ||
| 92 | 93 | csrc_pic.read = nlm_get_pic_timer; |
| 93 | 94 | } |
| 94 | 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 | 101 | void __init plat_time_init(void) |
| @@ -26,11 +26,12 @@ · 25 unmodified lines | ||
| 26 | 26 | interrupt-parent = <&pic>; |
| 27 | 27 | interrupts = <17>; |
| 28 | 28 | }; |
| 29 | − pic: pic@4000 { | |
| 30 | − interrupt-controller; | |
| 29 | + pic: pic@110000 { | |
| 30 | + compatible = "netlogic,xlp-pic"; | |
| 31 | 31 | #address-cells = <0>; |
| 32 | 32 | #interrupt-cells = <1>; |
| 33 | 33 | reg = <0 0x110000 0x200>; |
| 34 | + interrupt-controller; | |
| 34 | 35 | }; |
| 35 | 36 | |
| 36 | 37 | nor_flash@1,0 { |
| @@ -2,3 +2,5 @@ obj-y += setup.o nlm_hal.o cop2-ex.o dt.o · 1 unmodified line | ||
| 2 | 2 | obj-$(CONFIG_SMP) += wakeup.o |
| 3 | 3 | obj-$(CONFIG_USB) += usb-init.o |
| 4 | 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 | |
| @@ -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 | +} | |
187 more lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 372 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 369 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 336 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 132 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 187 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.