Commit c5951e7c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mips_5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux

Pull MIPS changes from Paul Burton:
 "Nothing too big or scary in here:

   - Support mremap() for the VDSO, primarily to allow CRIU to restore
     the VDSO to its checkpointed location.

   - Restore the MIPS32 cBPF JIT, after having reverted the enablement
     of the eBPF JIT for MIPS32 systems in the 5.5 cycle.

   - Improve cop0 counter synchronization behaviour whilst onlining CPUs
     by running with interrupts disabled.

   - Better match FPU behaviour when emulating multiply-accumulate
     instructions on pre-r6 systems that implement IEEE754-2008 style
     MACs.

   - Loongson64 kernels now build using the MIPS64r2 ISA, allowing them
     to take advantage of instructions introduced by r2.

   - Support for the Ingenic X1000 SoC & the really nice little CU Neo
     development board that's using it.

   - Support for WMAC on GARDENA Smart Gateway devices.

   - Lots of cleanup & refactoring of SGI IP27 (Origin 2*) support in
     preparation for introducing IP35 (Origin 3*) support.

   - Various Kconfig & Makefile cleanups"

* tag 'mips_5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux: (60 commits)
  MIPS: PCI: Add detection of IOC3 on IO7, IO8, IO9 and Fuel
  MIPS: Loongson64: Disable exec hazard
  MIPS: Loongson64: Bump ISA level to MIPSR2
  MIPS: Make DIEI support as a config option
  MIPS: OCTEON: octeon-irq: fix spelling mistake "to" -> "too"
  MIPS: asm: local: add barriers for Loongson
  MIPS: Loongson64: Select mac2008 only feature
  MIPS: Add MAC2008 Support
  Revert "MIPS: Add custom serial.h with BASE_BAUD override for generic kernel"
  MIPS: sort MIPS and MIPS_GENERIC Kconfig selects alphabetically (again)
  MIPS: make CPU_HAS_LOAD_STORE_LR opt-out
  MIPS: generic: don't unconditionally select PINCTRL
  MIPS: don't explicitly select LIBFDT in Kconfig
  MIPS: sync-r4k: do slave counter synchronization with disabled HW interrupts
  MIPS: SGI-IP30: Check for valid pointer before using it
  MIPS: syscalls: fix indentation of the 'SYSNR' message
  MIPS: boot: fix typo in 'vmlinux.lzma.its' target
  MIPS: fix indentation of the 'RELOCS' message
  dt-bindings: Document loongson vendor-prefix
  MIPS: CU1000-Neo: Refresh defconfig to support HWMON and WiFi.
  ...
parents b7e573bb 2c428871
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mips/ingenic/devices.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ingenic XBurst based Platforms Device Tree Bindings
maintainers:
- 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
description: |
Devices with a Ingenic XBurst CPU shall have the following properties.
properties:
$nodename:
const: '/'
compatible:
oneOf:
- description: Qi Hardware Ben NanoNote
items:
- const: qi,lb60
- description: Game Consoles Worldwide GCW Zero
items:
- const: gcw,zero
- description: MIPS Creator CI20
items:
- const: img,ci20
- description: YSH & ATIL General Board CU Neo
items:
- const: yna,cu1000-neo
...
......@@ -555,6 +555,8 @@ patternProperties:
description: Logic PD, Inc.
"^longcheer,.*":
description: Longcheer Technology (Shanghai) Co., Ltd.
"^loongson,.*":
description: Loongson Technology Corporation Limited
"^lsi,.*":
description: LSI Corp. (LSI Logic)
"^lwn,.*":
......@@ -1084,6 +1086,8 @@ patternProperties:
description: Shenzhen Xunlong Software CO.,Limited
"^xylon,.*":
description: Xylon
"^yna,.*":
description: YSH & ATIL
"^yones-toptech,.*":
description: Yones Toptech Co., Ltd.
"^ysoft,.*":
......
......@@ -11116,7 +11116,6 @@ F: drivers/usb/image/microtek.*
MIPS
M: Ralf Baechle <ralf@linux-mips.org>
M: Paul Burton <paulburton@kernel.org>
M: James Hogan <jhogan@kernel.org>
L: linux-mips@vger.kernel.org
W: http://www.linux-mips.org/
T: git git://git.linux-mips.org/pub/scm/ralf/linux.git
......
......@@ -5,9 +5,11 @@ config MIPS
select ARCH_32BIT_OFF_T if !64BIT
select ARCH_BINFMT_ELF_STATE if MIPS_FP_SUPPORT
select ARCH_CLOCKSOURCE_DATA
select ARCH_HAS_FORTIFY_SOURCE
select ARCH_HAS_KCOV
select ARCH_HAS_PTE_SPECIAL if !(32BIT && CPU_HAS_RIXI)
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_HAS_UBSAN_SANITIZE_ALL
select ARCH_HAS_FORTIFY_SOURCE
select ARCH_SUPPORTS_UPROBES
select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_CMPXCHG_LOCKREF if 64BIT
......@@ -47,7 +49,7 @@ config MIPS
select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES
select HAVE_ASM_MODVERSIONS
select HAVE_EBPF_JIT if 64BIT && !CPU_MICROMIPS && TARGET_ISA_REV >= 2
select HAVE_CBPF_JIT if !64BIT && !CPU_MICROMIPS
select HAVE_CONTEXT_TRACKING
select HAVE_COPY_THREAD_TLS
select HAVE_C_RECORDMCOUNT
......@@ -55,11 +57,14 @@ config MIPS
select HAVE_DEBUG_STACKOVERFLOW
select HAVE_DMA_CONTIGUOUS
select HAVE_DYNAMIC_FTRACE
select HAVE_EBPF_JIT if 64BIT && !CPU_MICROMIPS && TARGET_ISA_REV >= 2
select HAVE_EXIT_THREAD
select HAVE_FAST_GUP
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACER
select HAVE_GCC_PLUGINS
select HAVE_GENERIC_VDSO
select HAVE_IDE
select HAVE_IOREMAP_PROT
select HAVE_IRQ_EXIT_ON_IRQ_STACK
......@@ -78,18 +83,14 @@ config MIPS
select HAVE_STACKPROTECTOR
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_VIRT_CPU_ACCOUNTING_GEN if 64BIT || !SMP
select HAVE_GENERIC_VDSO
select IRQ_FORCED_THREADING
select ISA if EISA
select MODULES_USE_ELF_RELA if MODULES && 64BIT
select MODULES_USE_ELF_REL if MODULES
select MODULES_USE_ELF_RELA if MODULES && 64BIT
select PERF_USE_VMALLOC
select RTC_LIB
select SYSCTL_EXCEPTION_TRACE
select VIRT_TO_BUS
select ARCH_HAS_PTE_SPECIAL if !(32BIT && CPU_HAS_RIXI)
select ARCH_HAS_KCOV
select HAVE_GCC_PLUGINS
menu "Machine selection"
......@@ -104,20 +105,18 @@ config MIPS_GENERIC
select CEVT_R4K
select CLKSRC_MIPS_GIC
select COMMON_CLK
select CPU_MIPSR2_IRQ_VI
select CPU_MIPSR2_IRQ_EI
select CPU_MIPSR2_IRQ_VI
select CSRC_R4K
select DMA_PERDEV_COHERENT
select HAVE_PCI
select IRQ_MIPS_CPU
select LIBFDT
select MIPS_AUTO_PFN_OFFSET
select MIPS_CPU_SCACHE
select MIPS_GIC
select MIPS_L1_CACHE_SHIFT_7
select NO_EXCEPT_FILL
select PCI_DRIVERS_GENERIC
select PINCTRL
select SMP_UP if SMP
select SWAP_IO_SPACE
select SYS_HAS_CPU_MIPS32_R1
......@@ -132,11 +131,12 @@ config MIPS_GENERIC
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_MICROMIPS
select SYS_SUPPORTS_MIPS_CPS
select SYS_SUPPORTS_MIPS16
select SYS_SUPPORTS_MIPS_CPS
select SYS_SUPPORTS_MULTITHREADING
select SYS_SUPPORTS_RELOCATABLE
select SYS_SUPPORTS_SMARTMIPS
select UHI_BOOT
select USB_EHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
select USB_OHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
......@@ -144,7 +144,6 @@ config MIPS_GENERIC
select USB_UHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
select USB_UHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
select USE_OF
select UHI_BOOT
help
Select this to build a kernel which aims to support multiple boards,
generally using a flattened device tree passed from the bootloader
......@@ -403,7 +402,6 @@ config MACH_INGENIC
select GENERIC_IRQ_CHIP
select BUILTIN_DTB if MIPS_NO_APPENDED_DTB
select USE_OF
select LIBFDT
config LANTIQ
bool "Lantiq based platforms"
......@@ -510,7 +508,6 @@ config MACH_PISTACHIO
select DMA_NONCOHERENT
select GPIOLIB
select IRQ_MIPS_CPU
select LIBFDT
select MFD_SYSCON
select MIPS_CPU_SCACHE
select MIPS_GIC
......@@ -548,7 +545,6 @@ config MIPS_MALTA
select I8253
select I8259
select IRQ_MIPS_CPU
select LIBFDT
select MIPS_BONITO64
select MIPS_CPU_SCACHE
select MIPS_GIC
......@@ -980,7 +976,6 @@ config CAVIUM_OCTEON_SOC
select ZONE_DMA32
select HOLES_IN_ZONE
select GPIOLIB
select LIBFDT
select USE_OF
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_SMP
......@@ -1223,8 +1218,7 @@ config NO_IOPORT_MAP
def_bool n
config GENERIC_CSUM
bool
default y if !CPU_HAS_LOAD_STORE_LR
def_bool CPU_NO_LOAD_STORE_LR
config GENERIC_ISA_DMA
bool
......@@ -1442,11 +1436,14 @@ config CPU_LOONGSON64
bool "Loongson 64-bit CPU"
depends on SYS_HAS_CPU_LOONGSON64
select ARCH_HAS_PHYS_TO_DMA
select CPU_MIPSR2
select CPU_HAS_PREFETCH
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_HUGEPAGES
select CPU_SUPPORTS_MSA
select CPU_HAS_LOAD_STORE_LR
select CPU_DIEI_BROKEN if !LOONGSON3_ENHANCEMENT
select CPU_MIPSR2_IRQ_VI
select WEAK_ORDERING
select WEAK_REORDERING_BEYOND_LLSC
select MIPS_ASID_BITS_VARIABLE
......@@ -1464,8 +1461,6 @@ config CPU_LOONGSON64
config LOONGSON3_ENHANCEMENT
bool "New Loongson-3 CPU Enhancements"
default n
select CPU_MIPSR2
select CPU_HAS_PREFETCH
depends on CPU_LOONGSON64
help
New Loongson-3 cores (since Loongson-3A R2, as opposed to Loongson-3A
......@@ -1542,7 +1537,6 @@ config CPU_MIPS32_R1
bool "MIPS32 Release 1"
depends on SYS_HAS_CPU_MIPS32_R1
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
help
......@@ -1560,7 +1554,6 @@ config CPU_MIPS32_R2
bool "MIPS32 Release 2"
depends on SYS_HAS_CPU_MIPS32_R2
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_MSA
......@@ -1576,6 +1569,7 @@ config CPU_MIPS32_R6
bool "MIPS32 Release 6"
depends on SYS_HAS_CPU_MIPS32_R6
select CPU_HAS_PREFETCH
select CPU_NO_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_MSA
......@@ -1591,7 +1585,6 @@ config CPU_MIPS64_R1
bool "MIPS64 Release 1"
depends on SYS_HAS_CPU_MIPS64_R1
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
......@@ -1611,7 +1604,6 @@ config CPU_MIPS64_R2
bool "MIPS64 Release 2"
depends on SYS_HAS_CPU_MIPS64_R2
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
......@@ -1629,6 +1621,7 @@ config CPU_MIPS64_R6
bool "MIPS64 Release 6"
depends on SYS_HAS_CPU_MIPS64_R6
select CPU_HAS_PREFETCH
select CPU_NO_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
......@@ -1646,7 +1639,6 @@ config CPU_R3000
bool "R3000"
depends on SYS_HAS_CPU_R3000
select CPU_HAS_WB
select CPU_HAS_LOAD_STORE_LR
select CPU_R3K_TLB
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
......@@ -1662,7 +1654,6 @@ config CPU_TX39XX
bool "R39XX"
depends on SYS_HAS_CPU_TX39XX
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_HAS_LOAD_STORE_LR
select CPU_R3K_TLB
config CPU_VR41XX
......@@ -1670,7 +1661,6 @@ config CPU_VR41XX
depends on SYS_HAS_CPU_VR41XX
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_HAS_LOAD_STORE_LR
help
The options selects support for the NEC VR4100 series of processors.
Only choose this option if you have one of these processors as a
......@@ -1683,7 +1673,6 @@ config CPU_R4X00
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HUGEPAGES
select CPU_HAS_LOAD_STORE_LR
help
MIPS Technologies R4000-series processors other than 4300, including
the R4000, R4400, R4600, and 4700.
......@@ -1692,7 +1681,6 @@ config CPU_TX49XX
bool "R49XX"
depends on SYS_HAS_CPU_TX49XX
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HUGEPAGES
......@@ -1703,7 +1691,6 @@ config CPU_R5000
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HUGEPAGES
select CPU_HAS_LOAD_STORE_LR
help
MIPS Technologies R5000-series processors other than the Nevada.
......@@ -1713,7 +1700,6 @@ config CPU_R5500
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HUGEPAGES
select CPU_HAS_LOAD_STORE_LR
help
NEC VR5500 and VR5500A series processors implement 64-bit MIPS IV
instruction set.
......@@ -1724,7 +1710,6 @@ config CPU_NEVADA
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HUGEPAGES
select CPU_HAS_LOAD_STORE_LR
help
QED / PMC-Sierra RM52xx-series ("Nevada") processors.
......@@ -1732,7 +1717,6 @@ config CPU_R10000
bool "R10000"
depends on SYS_HAS_CPU_R10000
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
......@@ -1744,7 +1728,6 @@ config CPU_RM7000
bool "RM7000"
depends on SYS_HAS_CPU_RM7000
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
......@@ -1753,7 +1736,6 @@ config CPU_RM7000
config CPU_SB1
bool "SB1"
depends on SYS_HAS_CPU_SB1
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
......@@ -1764,7 +1746,6 @@ config CPU_CAVIUM_OCTEON
bool "Cavium Octeon processor"
depends on SYS_HAS_CPU_CAVIUM_OCTEON
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_64BIT_KERNEL
select WEAK_ORDERING
select CPU_SUPPORTS_HIGHMEM
......@@ -1794,7 +1775,6 @@ config CPU_BMIPS
select WEAK_ORDERING
select CPU_SUPPORTS_HIGHMEM
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_CPUFREQ
select MIPS_EXTERNAL_TIMER
help
......@@ -1803,7 +1783,6 @@ config CPU_BMIPS
config CPU_XLR
bool "Netlogic XLR SoC"
depends on SYS_HAS_CPU_XLR
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
......@@ -1822,7 +1801,6 @@ config CPU_XLP
select WEAK_ORDERING
select WEAK_REORDERING_BEYOND_LLSC
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_MIPSR2
select CPU_SUPPORTS_HUGEPAGES
select MIPS_ASID_BITS_VARIABLE
......@@ -1928,14 +1906,12 @@ config CPU_LOONGSON2EF
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_HUGEPAGES
select ARCH_HAS_PHYS_TO_DMA
select CPU_HAS_LOAD_STORE_LR
config CPU_LOONGSON32
bool
select CPU_MIPS32
select CPU_MIPSR2
select CPU_HAS_PREFETCH
select CPU_HAS_LOAD_STORE_LR
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_CPUFREQ
......@@ -2110,12 +2086,14 @@ config CPU_MIPSR2
bool
default y if CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_CAVIUM_OCTEON
select CPU_HAS_RIXI
select CPU_HAS_DIEI if !CPU_DIEI_BROKEN
select MIPS_SPRAM
config CPU_MIPSR6
bool
default y if CPU_MIPS32_R6 || CPU_MIPS64_R6
select CPU_HAS_RIXI
select CPU_HAS_DIEI if !CPU_DIEI_BROKEN
select HAVE_ARCH_BITREVERSE
select MIPS_ASID_BITS_VARIABLE
select MIPS_CRC_SUPPORT
......@@ -2575,15 +2553,23 @@ config CPU_HAS_WB
config XKS01
bool
config CPU_HAS_DIEI
depends on !CPU_DIEI_BROKEN
bool
config CPU_DIEI_BROKEN
bool
config CPU_HAS_RIXI
bool
config CPU_HAS_LOAD_STORE_LR
config CPU_NO_LOAD_STORE_LR
bool
help
CPU has support for unaligned load and store instructions:
CPU lacks support for unaligned load and store instructions:
LWL, LWR, SWL, SWR (Load/store word left/right).
LDL, LDR, SDL, SDR (Load/store doubleword left/right, for 64bit systems).
LDL, LDR, SDL, SDR (Load/store doubleword left/right, for 64bit
systems).
#
# Vectored interrupt mode is an R2 feature
......@@ -2696,6 +2682,14 @@ config NUMA
config SYS_SUPPORTS_NUMA
bool
config HAVE_SETUP_PER_CPU_AREA
def_bool y
depends on NUMA
config NEED_PER_CPU_EMBED_FIRST_CHUNK
def_bool y
depends on NUMA
config RELOCATABLE
bool "Relocatable kernel"
depends on SYS_SUPPORTS_RELOCATABLE && (CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_MIPS32_R6 || CPU_MIPS64_R6 || CAVIUM_OCTEON_SOC)
......
......@@ -123,7 +123,7 @@ $(obj)/vmlinux.its.S: $(addprefix $(srctree)/arch/mips/$(PLATFORM)/,$(ITS_INPUTS
targets += vmlinux.its
targets += vmlinux.gz.its
targets += vmlinux.bz2.its
targets += vmlinux.lzmo.its
targets += vmlinux.lzma.its
targets += vmlinux.lzo.its
quiet_cmd_cpp_its_S = ITS $@
......
......@@ -2,5 +2,6 @@
dtb-$(CONFIG_JZ4740_QI_LB60) += qi_lb60.dtb
dtb-$(CONFIG_JZ4770_GCW0) += gcw0.dtb
dtb-$(CONFIG_JZ4780_CI20) += ci20.dtb
dtb-$(CONFIG_X1000_CU1000_NEO) += cu1000-neo.dtb
obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y))
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "x1000.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/clock/ingenic,tcu.h>
#include <dt-bindings/interrupt-controller/irq.h>
/ {
compatible = "yna,cu1000-neo", "ingenic,x1000";
model = "YSH & ATIL General Board CU Neo";
aliases {
serial2 = &uart2;
};
chosen {
stdout-path = "serial2:115200n8";
};
memory {
device_type = "memory";
reg = <0x0 0x04000000>;
};
wlan_pwrseq: msc1-pwrseq {
compatible = "mmc-pwrseq-simple";
clocks = <&lpoclk>;
clock-names = "ext_clock";
reset-gpios = <&gpc 17 GPIO_ACTIVE_LOW>;
post-power-on-delay-ms = <200>;
lpoclk: ap6212a {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
};
};
};
&exclk {
clock-frequency = <24000000>;
};
&tcu {
/* 1500 kHz for the system timer and clocksource */
assigned-clocks = <&tcu TCU_CLK_TIMER0>, <&tcu TCU_CLK_TIMER2>;
assigned-clock-rates = <1500000>, <1500000>;
/* Use channel #0 for the system timer channel #2 for the clocksource */
ingenic,pwm-channels-mask = <0xfa>;
};
&i2c0 {
status = "okay";
clock-frequency = <400000>;
pinctrl-names = "default";
pinctrl-0 = <&pins_i2c0>;
ads7830@48 {
compatible = "ti,ads7830";
reg = <0x48>;
};
};
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&pins_uart2>;
status = "okay";
};
&mac {
phy-mode = "rmii";
phy-handle = <&lan8720a>;
pinctrl-names = "default";
pinctrl-0 = <&pins_mac>;
snps,reset-gpio = <&gpc 23 GPIO_ACTIVE_LOW>; /* PC23 */
snps,reset-active-low;
snps,reset-delays-us = <0 10000 30000>;
status = "okay";
};
&mdio {
status = "okay";
lan8720a: ethernet-phy@0 {
compatible = "ethernet-phy-id0007.c0f0", "ethernet-phy-ieee802.3-c22";
reg = <0>;
};
};
&msc0 {
bus-width = <8>;
max-frequency = <50000000>;
pinctrl-names = "default";
pinctrl-0 = <&pins_msc0>;
non-removable;
status = "okay";
};
&msc1 {
bus-width = <4>;
max-frequency = <50000000>;
pinctrl-names = "default";
pinctrl-0 = <&pins_msc1>;
#address-cells = <1>;
#size-cells = <0>;
non-removable;
mmc-pwrseq = <&wlan_pwrseq>;
status = "okay";
ap6212a: wifi@1 {
compatible = "brcm,bcm4329-fmac";
reg = <1>;
interrupt-parent = <&gpc>;
interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
interrupt-names = "host-wake";
brcm,drive-strength = <10>;
};
};
&pinctrl {
pins_i2c0: i2c0 {
function = "i2c0";
groups = "i2c0-data";
bias-disable;
};
pins_uart2: uart2 {
function = "uart2";
groups = "uart2-data-d";
bias-disable;
};
pins_mac: mac {
function = "mac";
groups = "mac";
bias-disable;
};
pins_msc0: msc0 {
function = "mmc0";
groups = "mmc0-1bit", "mmc0-4bit", "mmc0-8bit";
bias-disable;
};
pins_msc1: msc1 {
function = "mmc1";
groups = "mmc1-1bit", "mmc1-4bit";
bias-disable;
};
};
// SPDX-License-Identifier: GPL-2.0
#include <dt-bindings/clock/x1000-cgu.h>
#include <dt-bindings/dma/x1000-dma.h>
/ {
#address-cells = <1>;
#size-cells = <1>;
compatible = "ingenic,x1000", "ingenic,x1000e";
cpuintc: interrupt-controller {
#address-cells = <0>;
#interrupt-cells = <1>;
interrupt-controller;
compatible = "mti,cpu-interrupt-controller";
};
intc: interrupt-controller@10001000 {
compatible = "ingenic,x1000-intc", "ingenic,jz4780-intc";
reg = <0x10001000 0x50>;
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&cpuintc>;
interrupts = <2>;
};
exclk: ext {
compatible = "fixed-clock";
#clock-cells = <0>;
};
rtclk: rtc {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
};
cgu: x1000-cgu@10000000 {
compatible = "ingenic,x1000-cgu";
reg = <0x10000000 0x100>;
#clock-cells = <1>;
clocks = <&exclk>, <&rtclk>;
clock-names = "ext", "rtc";
};
tcu: timer@10002000 {
compatible = "ingenic,x1000-tcu",
"ingenic,jz4770-tcu",
"simple-mfd";
reg = <0x10002000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x10002000 0x1000>;
#clock-cells = <1>;
clocks = <&cgu X1000_CLK_RTCLK
&cgu X1000_CLK_EXCLK
&cgu X1000_CLK_PCLK>;
clock-names = "rtc", "ext", "pclk";
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&intc>;
interrupts = <27 26 25>;
wdt: watchdog@0 {
compatible = "ingenic,x1000-watchdog", "ingenic,jz4780-watchdog";
reg = <0x0 0x10>;
clocks = <&cgu X1000_CLK_RTCLK>;
clock-names = "wdt";
};
};
rtc: rtc@10003000 {
compatible = "ingenic,x1000-rtc", "ingenic,jz4780-rtc";
reg = <0x10003000 0x4c>;
interrupt-parent = <&intc>;
interrupts = <32>;
clocks = <&cgu X1000_CLK_RTCLK>;
clock-names = "rtc";
};
pinctrl: pin-controller@10010000 {
compatible = "ingenic,x1000-pinctrl";
reg = <0x10010000 0x800>;
#address-cells = <1>;
#size-cells = <0>;
gpa: gpio@0 {
compatible = "ingenic,x1000-gpio";
reg = <0>;
gpio-controller;
gpio-ranges = <&pinctrl 0 0 32>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <17>;
};
gpb: gpio@1 {
compatible = "ingenic,x1000-gpio";
reg = <1>;
gpio-controller;
gpio-ranges = <&pinctrl 0 32 32>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <16>;
};
gpc: gpio@2 {
compatible = "ingenic,x1000-gpio";
reg = <2>;
gpio-controller;
gpio-ranges = <&pinctrl 0 64 32>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <15>;
};
gpd: gpio@3 {
compatible = "ingenic,x1000-gpio";
reg = <3>;
gpio-controller;
gpio-ranges = <&pinctrl 0 96 32>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <14>;
};
};
i2c0: i2c-controller@10050000 {
compatible = "ingenic,x1000-i2c";
reg = <0x10050000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&intc>;
interrupts = <60>;
clocks = <&cgu X1000_CLK_I2C0>;
status = "disabled";
};
i2c1: i2c-controller@10051000 {
compatible = "ingenic,x1000-i2c";
reg = <0x10051000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&intc>;
interrupts = <59>;
clocks = <&cgu X1000_CLK_I2C1>;
status = "disabled";
};
i2c2: i2c-controller@10052000 {
compatible = "ingenic,x1000-i2c";
reg = <0x10052000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&intc>;
interrupts = <58>;
clocks = <&cgu X1000_CLK_I2C2>;
status = "disabled";
};
uart0: serial@10030000 {
compatible = "ingenic,x1000-uart";
reg = <0x10030000 0x100>;
interrupt-parent = <&intc>;
interrupts = <51>;
clocks = <&exclk>, <&cgu X1000_CLK_UART0>;
clock-names = "baud", "module";
status = "disabled";
};
uart1: serial@10031000 {
compatible = "ingenic,x1000-uart";
reg = <0x10031000 0x100>;
interrupt-parent = <&intc>;
interrupts = <50>;
clocks = <&exclk>, <&cgu X1000_CLK_UART1>;
clock-names = "baud", "module";
status = "disabled";
};
uart2: serial@10032000 {
compatible = "ingenic,x1000-uart";
reg = <0x10032000 0x100>;
interrupt-parent = <&intc>;
interrupts = <49>;
clocks = <&exclk>, <&cgu X1000_CLK_UART2>;
clock-names = "baud", "module";
status = "disabled";
};
pdma: dma-controller@13420000 {
compatible = "ingenic,x1000-dma";
reg = <0x13420000 0x400
0x13421000 0x40>;
#dma-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <10>;
clocks = <&cgu X1000_CLK_PDMA>;
};
mac: ethernet@134b0000 {
compatible = "ingenic,x1000-mac", "snps,dwmac";
reg = <0x134b0000 0x2000>;
interrupt-parent = <&intc>;
interrupts = <55>;
interrupt-names = "macirq";
clocks = <&cgu X1000_CLK_MAC>;
clock-names = "stmmaceth";
status = "disabled";
mdio: mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
};
msc0: mmc@13450000 {
compatible = "ingenic,x1000-mmc";
reg = <0x13450000 0x1000>;
interrupt-parent = <&intc>;
interrupts = <37>;
clocks = <&cgu X1000_CLK_MSC0>;
clock-names = "mmc";
cap-sd-highspeed;
cap-mmc-highspeed;
cap-sdio-irq;
dmas = <&pdma X1000_DMA_MSC0_RX 0xffffffff>,
<&pdma X1000_DMA_MSC0_TX 0xffffffff>;
dma-names = "rx", "tx";
status = "disabled";
};
msc1: mmc@13460000 {
compatible = "ingenic,x1000-mmc";
reg = <0x13460000 0x1000>;
interrupt-parent = <&intc>;
interrupts = <36>;
clocks = <&cgu X1000_CLK_MSC1>;
clock-names = "mmc";
cap-sd-highspeed;
cap-mmc-highspeed;
cap-sdio-irq;
dmas = <&pdma X1000_DMA_MSC1_RX 0xffffffff>,
<&pdma X1000_DMA_MSC1_TX 0xffffffff>;
dma-names = "rx", "tx";
status = "disabled";
};
};
......@@ -177,6 +177,9 @@ &uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinmux_i2s_gpio>; /* GPIO0..3 */
fifo-size = <8>;
tx-threshold = <8>;
rts-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
cts-gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
};
......@@ -195,3 +198,8 @@ &uart2 {
&watchdog {
status = "okay";
};
&wmac {
status = "okay";
mediatek,mtd-eeprom = <&factory 0x0000>;
};
......@@ -285,4 +285,14 @@ ehci@101c0000 {
interrupt-parent = <&intc>;
interrupts = <18>;
};
wmac: wmac@10300000 {
compatible = "mediatek,mt7628-wmac";
reg = <0x10300000 0x100000>;
interrupt-parent = <&cpuintc>;
interrupts = <6>;
status = "disabled";
};
};
......@@ -2193,7 +2193,7 @@ static int octeon_irq_cib_map(struct irq_domain *d,
struct octeon_irq_cib_chip_data *cd;
if (hw >= host_data->max_bits) {
pr_err("ERROR: %s mapping %u is to big!\n",
pr_err("ERROR: %s mapping %u is too big!\n",
irq_domain_get_of_node(d)->name, (unsigned)hw);
return -EINVAL;
}
......
CONFIG_LOCALVERSION_AUTO=y
CONFIG_KERNEL_GZIP=y
CONFIG_SYSVIPC=y
CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_CGROUPS=y
CONFIG_MEMCG=y
CONFIG_MEMCG_KMEM=y
CONFIG_CGROUP_SCHED=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_NAMESPACES=y
CONFIG_USER_NS=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
CONFIG_MACH_INGENIC=y
CONFIG_X1000_CU1000_NEO=y
CONFIG_HIGHMEM=y
CONFIG_HZ_100=y
# CONFIG_SECCOMP is not set
# CONFIG_SUSPEND is not set
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_COMPACTION is not set
CONFIG_CMA=y
CONFIG_CMA_AREAS=7
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_CFG80211=y
CONFIG_UEVENT_HELPER=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
# CONFIG_FW_LOADER is not set
# CONFIG_ALLOW_DEV_COREDUMP is not set
CONFIG_NETDEVICES=y
CONFIG_STMMAC_ETH=y
CONFIG_SMSC_PHY=y
CONFIG_BRCMFMAC=y
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_LEGACY_PTY_COUNT=2
CONFIG_SERIAL_EARLYCON=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=3
CONFIG_SERIAL_8250_RUNTIME_UARTS=3
CONFIG_SERIAL_8250_INGENIC=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_JZ4780=y
CONFIG_GPIO_SYSFS=y
CONFIG_SENSORS_ADS7828=y
CONFIG_WATCHDOG=y
CONFIG_JZ4740_WDT=y
# CONFIG_LCD_CLASS_DEVICE is not set
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
# CONFIG_VGA_CONSOLE is not set
# CONFIG_HID is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_MMC=y
CONFIG_MMC_JZ4740=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_JZ4740=y
CONFIG_DMADEVICES=y
CONFIG_DMA_JZ4780=y
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_NVMEM=y
CONFIG_NVMEM_SYSFS=y
CONFIG_EXT4_FS=y
# CONFIG_DNOTIFY is not set
CONFIG_AUTOFS_FS=y
CONFIG_PROC_KCORE=y
# CONFIG_PROC_PAGE_MONITOR is not set
CONFIG_TMPFS=y
CONFIG_CONFIGFS_FS=y
CONFIG_NFS_FS=y
CONFIG_NLS=y
CONFIG_NLS_CODEPAGE_936=y
CONFIG_NLS_CODEPAGE_950=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
CONFIG_CRYPTO_ECHAINIV=y
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_LZO=y
CONFIG_PRINTK_TIME=y
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
CONFIG_CONSOLE_LOGLEVEL_QUIET=15
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7
CONFIG_DEBUG_INFO=y
CONFIG_STRIP_ASM_SYMS=y
CONFIG_DEBUG_FS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_TIMEOUT=10
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_STACKTRACE=y
# CONFIG_FTRACE is not set
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE="earlycon clk_ignore_unused"
......@@ -41,6 +41,7 @@ CONFIG_SPI_DESIGNWARE=y
CONFIG_SPI_DW_MMIO=y
CONFIG_SPI_SPIDEV=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_OCELOT=y
CONFIG_GPIO_SYSFS=y
......
......@@ -19,6 +19,7 @@ generic-y += preempt.h
generic-y += qrwlock.h
generic-y += qspinlock.h
generic-y += sections.h
generic-y += serial.h
generic-y += trace_clock.h
generic-y += unaligned.h
generic-y += user.h
......
......@@ -81,6 +81,7 @@ enum loongson2ef_machine_type {
#define MACH_INGENIC_JZ4770 2 /* JZ4770 SOC */
#define MACH_INGENIC_JZ4780 3 /* JZ4780 SOC */
#define MACH_INGENIC_X1000 4 /* X1000 SOC */
#define MACH_INGENIC_X1830 5 /* X1830 SOC */
extern char *system_type;
const char *get_system_type(void);
......
......@@ -555,6 +555,10 @@
# define cpu_has_perf __opt(MIPS_CPU_PERF)
#endif
#ifndef cpu_has_mac2008_only
# define cpu_has_mac2008_only __opt(MIPS_CPU_MAC_2008_ONLY)
#endif
#ifdef CONFIG_SMP
/*
* Some systems share FTLB RAMs between threads within a core (siblings in
......
......@@ -46,7 +46,7 @@
#define PRID_COMP_NETLOGIC 0x0c0000
#define PRID_COMP_CAVIUM 0x0d0000
#define PRID_COMP_LOONGSON 0x140000
#define PRID_COMP_INGENIC_D0 0xd00000 /* JZ4740, JZ4750 */
#define PRID_COMP_INGENIC_D0 0xd00000 /* JZ4740, JZ4750, X1830 */
#define PRID_COMP_INGENIC_D1 0xd10000 /* JZ4770, JZ4775, X1000 */
#define PRID_COMP_INGENIC_E1 0xe10000 /* JZ4780 */
......@@ -185,7 +185,8 @@
* These are the PRID's for when 23:16 == PRID_COMP_INGENIC_*
*/
#define PRID_IMP_XBURST 0x0200
#define PRID_IMP_XBURST_REV1 0x0200 /* XBurst with MXU SIMD ISA */
#define PRID_IMP_XBURST_REV2 0x0100 /* XBurst with MXU2 SIMD ISA */
/*
* These are the PRID's for when 23:16 == PRID_COMP_NETLOGIC
......@@ -415,6 +416,7 @@ enum cpu_type_enum {
#define MIPS_CPU_MT_PER_TC_PERF_COUNTERS \
BIT_ULL(56) /* CPU has perf counters implemented per TC (MIPSMT ASE) */
#define MIPS_CPU_MMID BIT_ULL(57) /* CPU supports MemoryMapIDs */
#define MIPS_CPU_MAC_2008_ONLY BIT_ULL(58) /* CPU Only support MAC2008 Fused multiply-add instruction */
/*
* CPU ASE encodings
......
......@@ -32,8 +32,6 @@ struct gio_driver {
};
#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver)
extern const struct gio_device_id *gio_match_device(const struct gio_device_id *,
const struct gio_device *);
extern struct gio_device *gio_dev_get(struct gio_device *);
extern void gio_dev_put(struct gio_device *);
......
......@@ -23,7 +23,7 @@
* TLB hazards
*/
#if (defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)) && \
!defined(CONFIG_CPU_CAVIUM_OCTEON) && !defined(CONFIG_LOONGSON3_ENHANCEMENT)
!defined(CONFIG_CPU_CAVIUM_OCTEON) && !defined(CONFIG_CPU_LOONGSON64)
/*
* MIPSR2 defines ehb for hazard avoidance
......@@ -158,7 +158,7 @@ do { \
} while (0)
#elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \
defined(CONFIG_CPU_LOONGSON2EF) || defined(CONFIG_LOONGSON3_ENHANCEMENT) || \
defined(CONFIG_CPU_LOONGSON2EF) || defined(CONFIG_CPU_LOONGSON64) || \
defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_R5500) || defined(CONFIG_CPU_XLR)
/*
......
......@@ -18,7 +18,7 @@
#include <asm/compiler.h>
#include <asm/hazards.h>
#if defined(CONFIG_CPU_MIPSR2) || defined (CONFIG_CPU_MIPSR6)
#if defined(CONFIG_CPU_HAS_DIEI)
static inline void arch_local_irq_disable(void)
{
......@@ -94,7 +94,7 @@ static inline void arch_local_irq_restore(unsigned long flags)
void arch_local_irq_disable(void);
unsigned long arch_local_irq_save(void);
void arch_local_irq_restore(unsigned long flags);
#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */
#endif /* CONFIG_CPU_HAS_DIEI */
static inline void arch_local_irq_enable(void)
{
......@@ -102,7 +102,7 @@ static inline void arch_local_irq_enable(void)
" .set push \n"
" .set reorder \n"
" .set noat \n"
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
#if defined(CONFIG_CPU_HAS_DIEI)
" ei \n"
#else
" mfc0 $1,$12 \n"
......
......@@ -37,6 +37,7 @@ static __inline__ long local_add_return(long i, local_t * l)
__asm__ __volatile__(
" .set push \n"
" .set arch=r4000 \n"
__SYNC(full, loongson3_war) " \n"
"1:" __LL "%1, %2 # local_add_return \n"
" addu %0, %1, %3 \n"
__SC "%0, %2 \n"
......@@ -52,6 +53,7 @@ static __inline__ long local_add_return(long i, local_t * l)
__asm__ __volatile__(
" .set push \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
__SYNC(full, loongson3_war) " \n"
"1:" __LL "%1, %2 # local_add_return \n"
" addu %0, %1, %3 \n"
__SC "%0, %2 \n"
......@@ -84,6 +86,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
__asm__ __volatile__(
" .set push \n"
" .set arch=r4000 \n"
__SYNC(full, loongson3_war) " \n"
"1:" __LL "%1, %2 # local_sub_return \n"
" subu %0, %1, %3 \n"
__SC "%0, %2 \n"
......@@ -99,6 +102,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
__asm__ __volatile__(
" .set push \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
__SYNC(full, loongson3_war) " \n"
"1:" __LL "%1, %2 # local_sub_return \n"
" subu %0, %1, %3 \n"
__SC "%0, %2 \n"
......
......@@ -10,19 +10,9 @@
#define __ASM_MACH_IP27_KERNEL_ENTRY_H
#include <asm/sn/addrs.h>
#include <asm/sn/sn0/hubni.h>
#include <asm/sn/agent.h>
#include <asm/sn/klkernvars.h>
/*
* Returns the local nasid into res.
*/
.macro GET_NASID_ASM res
dli \res, LOCAL_HUB_ADDR(NI_STATUS_REV_ID)
ld \res, (\res)
and \res, NSRI_NODEID_MASK
dsrl \res, NSRI_NODEID_SHFT
.endm
/*
* TLB bits
*/
......
......@@ -8,7 +8,7 @@
#ifndef __ASM_MACH_IP27_MANGLE_PORT_H
#define __ASM_MACH_IP27_MANGLE_PORT_H
#define __swizzle_addr_b(port) (port)
#define __swizzle_addr_b(port) ((port) ^ 3)
#define __swizzle_addr_w(port) ((port) ^ 2)
#define __swizzle_addr_l(port) (port)
#define __swizzle_addr_q(port) (port)
......@@ -20,6 +20,6 @@
# define ioswabl(a, x) (x)
# define __mem_ioswabl(a, x) cpu_to_le32(x)
# define ioswabq(a, x) (x)
# define __mem_ioswabq(a, x) cpu_to_le32(x)
# define __mem_ioswabq(a, x) cpu_to_le64(x)
#endif /* __ASM_MACH_IP27_MANGLE_PORT_H */
......@@ -4,7 +4,8 @@
#include <asm/sn/addrs.h>
#include <asm/sn/arch.h>
#include <asm/sn/hub.h>
#include <asm/sn/agent.h>
#include <asm/sn/klkernvars.h>
#define pa_to_nid(addr) NASID_GET(addr)
......@@ -12,7 +13,6 @@ struct hub_data {
kern_vars_t kern_vars;
DECLARE_BITMAP(h_bigwin_used, HUB_NUM_BIG_WINDOW);
cpumask_t h_cpus;
unsigned long slice_map;
};
struct node_data {
......
......@@ -2,12 +2,12 @@
#ifndef _ASM_MACH_TOPOLOGY_H
#define _ASM_MACH_TOPOLOGY_H 1
#include <asm/sn/hub.h>
#include <asm/sn/types.h>
#include <asm/mmzone.h>
struct cpuinfo_ip27 {
nasid_t p_nasid; /* my node ID in numa-as-id-space */
unsigned short p_speed; /* cpu speed in MHz */
unsigned char p_slice; /* Physical position on node board */
};
......
......@@ -46,5 +46,7 @@
#define cpu_has_wsbh 1
#define cpu_has_ic_fills_f_dc 1
#define cpu_hwrena_impl_bits 0xc0000000
#define cpu_has_mac2008_only 1
#define cpu_has_mips_r2_exec_hazard 0
#endif /* __ASM_MACH_LOONGSON64_CPU_FEATURE_OVERRIDES_H */
......@@ -1101,9 +1101,12 @@
/*
* Bits 22:20 of the FPU Status Register will be read as 0,
* and should be written as zero.
* MAC2008 was removed in Release 5 so we still treat it as
* reserved.
*/
#define FPU_CSR_RSVD (_ULCAST_(7) << 20)
#define FPU_CSR_MAC2008 (_ULCAST_(1) << 20)
#define FPU_CSR_ABS2008 (_ULCAST_(1) << 19)
#define FPU_CSR_NAN2008 (_ULCAST_(1) << 18)
......
......@@ -806,7 +806,8 @@ struct bridge_controller {
unsigned long baddr;
unsigned long intr_addr;
struct irq_domain *domain;
unsigned int pci_int[8];
unsigned int pci_int[8][2];
unsigned int int_mapping[8][2];
u32 ioc3_sid[8];
nasid_t nasid;
};
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2017 MIPS Tech, LLC
*/
#ifndef __ASM__SERIAL_H
#define __ASM__SERIAL_H
#ifdef CONFIG_MIPS_GENERIC
/*
* Generic kernels cannot know a correct value for all platforms at
* compile time. Set it to 0 to prevent 8250_early using it
*/
#define BASE_BAUD 0
#else
#include <asm-generic/serial.h>
#endif
#endif /* __ASM__SERIAL_H */
......@@ -25,7 +25,4 @@
#define INVALID_MODULE (moduleid_t)-1
#define INVALID_PARTID (partid_t)-1
extern nasid_t get_nasid(void);
extern int get_cpu_slice(cpuid_t);
#endif /* _ASM_SN_ARCH_H */
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_SN_HUB_H
#define __ASM_SN_HUB_H
#include <linux/types.h>
#include <linux/cpumask.h>
#include <asm/sn/types.h>
#include <asm/sn/io.h>
#include <asm/sn/klkernvars.h>
#include <asm/xtalk/xtalk.h>
/* ip27-hubio.c */
extern unsigned long hub_pio_map(nasid_t nasid, xwidgetnum_t widget,
unsigned long xtalk_addr, size_t size);
extern void hub_pio_init(nasid_t nasid);
#endif /* __ASM_SN_HUB_H */
......@@ -8,15 +8,6 @@
#ifndef __ASM_SN_INTR_H
#define __ASM_SN_INTR_H
/* Number of interrupt levels associated with each interrupt register. */
#define N_INTPEND_BITS 64
#define INT_PEND0_BASELVL 0
#define INT_PEND1_BASELVL 64
#define N_INTPENDJUNK_BITS 8
#define INTPENDJUNK_CLRBIT 0x80
/*
* Macros to manipulate the interrupt register on the calling hub chip.
*/
......@@ -84,14 +75,6 @@ do { \
#define CPU_RESCHED_B_IRQ 8
#define CPU_CALL_A_IRQ 9
#define CPU_CALL_B_IRQ 10
#define MSC_MESG_INTR 11
#define BASE_PCI_IRQ 12
/*
* INT_PEND0 again, bits determined by hardware / hardcoded:
*/
#define SDISK_INTR 63 /* SABLE name */
#define IP_PEND0_6_63 63 /* What is this bit? */
/*
* INT_PEND1 hard-coded bits:
......
......@@ -21,50 +21,50 @@ struct ioc3_serialregs {
/* SUPERIO uart register map */
struct ioc3_uartregs {
u8 iu_lcr;
union {
u8 iu_rbr; /* read only, DLAB == 0 */
u8 iu_thr; /* write only, DLAB == 0 */
u8 iu_dll; /* DLAB == 1 */
u8 iu_iir; /* read only */
u8 iu_fcr; /* write only */
};
union {
u8 iu_ier; /* DLAB == 0 */
u8 iu_dlm; /* DLAB == 1 */
};
union {
u8 iu_iir; /* read only */
u8 iu_fcr; /* write only */
u8 iu_rbr; /* read only, DLAB == 0 */
u8 iu_thr; /* write only, DLAB == 0 */
u8 iu_dll; /* DLAB == 1 */
};
u8 iu_lcr;
u8 iu_mcr;
u8 iu_lsr;
u8 iu_msr;
u8 iu_scr;
u8 iu_msr;
u8 iu_lsr;
u8 iu_mcr;
};
struct ioc3_sioregs {
u8 fill[0x141]; /* starts at 0x141 */
u8 uartc;
u8 kbdcg;
u8 uartc;
u8 fill0[0x150 - 0x142 - 1];
u8 fill0[0x151 - 0x142 - 1];
u8 pp_data;
u8 pp_dsr;
u8 pp_dcr;
u8 pp_dsr;
u8 pp_data;
u8 fill1[0x158 - 0x152 - 1];
u8 fill1[0x159 - 0x153 - 1];
u8 pp_fifa;
u8 pp_cfgb;
u8 pp_ecr;
u8 pp_cfgb;
u8 pp_fifa;
u8 fill2[0x168 - 0x15a - 1];
u8 fill2[0x16a - 0x15b - 1];
u8 rtcad;
u8 rtcdat;
u8 rtcad;
u8 fill3[0x170 - 0x169 - 1];
u8 fill3[0x170 - 0x16b - 1];
struct ioc3_uartregs uartb; /* 0x20170 */
struct ioc3_uartregs uarta; /* 0x20178 */
......@@ -598,5 +598,9 @@ struct ioc3_etxd {
#define IOC3_SUBSYS_IP30_SYSBOARD 0xc304
#define IOC3_SUBSYS_MENET 0xc305
#define IOC3_SUBSYS_MENET4 0xc306
#define IOC3_SUBSYS_IO7 0xc307
#define IOC3_SUBSYS_IO8 0xc308
#define IOC3_SUBSYS_IO9 0xc309
#define IOC3_SUBSYS_IP34_SYSBOARD 0xc30A
#endif /* MIPS_SN_IOC3_H */
......@@ -889,10 +889,6 @@ typedef union {
extern lboard_t *find_lboard(lboard_t *start, unsigned char type);
extern klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char type);
extern klinfo_t *find_first_component(lboard_t *brd, unsigned char type);
extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int);
extern lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_class);
extern klcpu_t *sn_get_cpuinfo(cpuid_t cpu);
#endif /* _ASM_SN_KLCONFIG_H */
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Derived from IRIX <sys/SN/kldir.h>, revision 1.21.
*
* Copyright (C) 1992 - 1997, 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 1999, 2000 by Ralf Baechle
*/
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SN_KLDIR_H
#define _ASM_SN_KLDIR_H
/*
* The kldir memory area resides at a fixed place in each node's memory and
* provides pointers to most other IP27 memory areas. This allows us to
* resize and/or relocate memory areas at a later time without breaking all
* firmware and kernels that use them. Indices in the array are
* permanently dedicated to areas listed below. Some memory areas (marked
* below) reside at a permanently fixed location, but are included in the
* directory for completeness.
*/
#define KLDIR_MAGIC 0x434d5f53505f5357
/*
* The upper portion of the memory map applies during boot
* only and is overwritten by IRIX/SYMMON.
*
* MEMORY MAP PER NODE
*
* 0x2000000 (32M) +-----------------------------------------+
* | IO6 BUFFERS FOR FLASH ENET IOC3 |
* 0x1F80000 (31.5M) +-----------------------------------------+
* | IO6 TEXT/DATA/BSS/stack |
* 0x1C00000 (30M) +-----------------------------------------+
* | IO6 PROM DEBUG TEXT/DATA/BSS/stack |
* 0x0800000 (28M) +-----------------------------------------+
* | IP27 PROM TEXT/DATA/BSS/stack |
* 0x1B00000 (27M) +-----------------------------------------+
* | IP27 CFG |
* 0x1A00000 (26M) +-----------------------------------------+
* | Graphics PROM |
* 0x1800000 (24M) +-----------------------------------------+
* | 3rd Party PROM drivers |
* 0x1600000 (22M) +-----------------------------------------+
* | |
* | Free |
* | |
* +-----------------------------------------+
* | UNIX DEBUG Version |
* 0x190000 (2M--) +-----------------------------------------+
* | SYMMON |
* | (For UNIX Debug only) |
* 0x34000 (208K) +-----------------------------------------+
* | SYMMON STACK [NUM_CPU_PER_NODE] |
* | (For UNIX Debug only) |
* 0x25000 (148K) +-----------------------------------------+
* | KLCONFIG - II (temp) |
* | |
* | ---------------------------- |
* | |
* | UNIX NON-DEBUG Version |
* 0x19000 (100K) +-----------------------------------------+
*
*
* The lower portion of the memory map contains information that is
* permanent and is used by the IP27PROM, IO6PROM and IRIX.
*
* 0x19000 (100K) +-----------------------------------------+
* | |
* | PI Error Spools (32K) |
* | |
* 0x12000 (72K) +-----------------------------------------+
* | Unused |
* 0x11c00 (71K) +-----------------------------------------+
* | CPU 1 NMI Eframe area |
* 0x11a00 (70.5K) +-----------------------------------------+
* | CPU 0 NMI Eframe area |
* 0x11800 (70K) +-----------------------------------------+
* | CPU 1 NMI Register save area |
* 0x11600 (69.5K) +-----------------------------------------+
* | CPU 0 NMI Register save area |
* 0x11400 (69K) +-----------------------------------------+
* | GDA (1k) |
* 0x11000 (68K) +-----------------------------------------+
* | Early cache Exception stack |
* | and/or |
* | kernel/io6prom nmi registers |
* 0x10800 (66k) +-----------------------------------------+
* | cache error eframe |
* 0x10400 (65K) +-----------------------------------------+
* | Exception Handlers (UALIAS copy) |
* 0x10000 (64K) +-----------------------------------------+
* | |
* | |
* | KLCONFIG - I (permanent) (48K) |
* | |
* | |
* | |
* 0x4000 (16K) +-----------------------------------------+
* | NMI Handler (Protected Page) |
* 0x3000 (12K) +-----------------------------------------+
* | ARCS PVECTORS (master node only) |
* 0x2c00 (11K) +-----------------------------------------+
* | ARCS TVECTORS (master node only) |
* 0x2800 (10K) +-----------------------------------------+
* | LAUNCH [NUM_CPU] |
* 0x2400 (9K) +-----------------------------------------+
* | Low memory directory (KLDIR) |
* 0x2000 (8K) +-----------------------------------------+
* | ARCS SPB (1K) |
* 0x1000 (4K) +-----------------------------------------+
* | Early cache Exception stack |
* | and/or |
* | kernel/io6prom nmi registers |
* 0x800 (2k) +-----------------------------------------+
* | cache error eframe |
* 0x400 (1K) +-----------------------------------------+
* | Exception Handlers |
* 0x0 (0K) +-----------------------------------------+
*/
#ifdef __ASSEMBLY__
#define KLDIR_OFF_MAGIC 0x00
#define KLDIR_OFF_OFFSET 0x08
#define KLDIR_OFF_POINTER 0x10
#define KLDIR_OFF_SIZE 0x18
#define KLDIR_OFF_COUNT 0x20
#define KLDIR_OFF_STRIDE 0x28
#endif /* __ASSEMBLY__ */
/*
* This is defined here because IP27_SYMMON_STK_SIZE must be at least what
* we define here. Since it's set up in the prom. We can't redefine it later
* and expect more space to be allocated. The way to find out the true size
* of the symmon stacks is to divide SYMMON_STK_SIZE by SYMMON_STK_STRIDE
* for a particular node.
*/
#define SYMMON_STACK_SIZE 0x8000
#if defined(PROM)
/*
* These defines are prom version dependent. No code other than the IP27
* prom should attempt to use these values.
*/
#define IP27_LAUNCH_OFFSET 0x2400
#define IP27_LAUNCH_SIZE 0x400
#define IP27_LAUNCH_COUNT 2
#define IP27_LAUNCH_STRIDE 0x200
#define IP27_KLCONFIG_OFFSET 0x4000
#define IP27_KLCONFIG_SIZE 0xc000
#define IP27_KLCONFIG_COUNT 1
#define IP27_KLCONFIG_STRIDE 0
#define IP27_NMI_OFFSET 0x3000
#define IP27_NMI_SIZE 0x40
#define IP27_NMI_COUNT 2
#define IP27_NMI_STRIDE 0x40
#define IP27_PI_ERROR_OFFSET 0x12000
#define IP27_PI_ERROR_SIZE 0x4000
#define IP27_PI_ERROR_COUNT 1
#define IP27_PI_ERROR_STRIDE 0
#define IP27_SYMMON_STK_OFFSET 0x25000
#define IP27_SYMMON_STK_SIZE 0xe000
#define IP27_SYMMON_STK_COUNT 2
/* IP27_SYMMON_STK_STRIDE must be >= SYMMON_STACK_SIZE */
#define IP27_SYMMON_STK_STRIDE 0x7000
#define IP27_FREEMEM_OFFSET 0x19000
#define IP27_FREEMEM_SIZE -1
#define IP27_FREEMEM_COUNT 1
#define IP27_FREEMEM_STRIDE 0
#endif /* PROM */
/*
* There will be only one of these in a partition so the IO6 must set it up.
*/
#define IO6_GDA_OFFSET 0x11000
#define IO6_GDA_SIZE 0x400
#define IO6_GDA_COUNT 1
#define IO6_GDA_STRIDE 0
/*
* save area of kernel nmi regs in the prom format
*/
#define IP27_NMI_KREGS_OFFSET 0x11400
#define IP27_NMI_KREGS_CPU_SIZE 0x200
/*
* save area of kernel nmi regs in eframe format
*/
#define IP27_NMI_EFRAME_OFFSET 0x11800
#define IP27_NMI_EFRAME_SIZE 0x200
#define KLDIR_ENT_SIZE 0x40
#define KLDIR_MAX_ENTRIES (0x400 / 0x40)
......@@ -214,4 +29,8 @@ typedef struct kldir_ent_s {
} kldir_ent_t;
#endif /* !__ASSEMBLY__ */
#ifdef CONFIG_SGI_IP27
#include <asm/sn/sn0/kldir.h>
#endif
#endif /* _ASM_SN_KLDIR_H */
......@@ -37,4 +37,26 @@
#define UATTR_MSPEC 2
#define UATTR_UNCAC 3
#ifdef __ASSEMBLY__
/*
* Returns the local nasid into res.
*/
.macro GET_NASID_ASM res
dli \res, LOCAL_HUB_ADDR(NI_STATUS_REV_ID)
ld \res, (\res)
and \res, NSRI_NODEID_MASK
dsrl \res, NSRI_NODEID_SHFT
.endm
#else
/*
* get_nasid() returns the physical node id number of the caller.
*/
static inline nasid_t get_nasid(void)
{
return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK)
>> NSRI_NODEID_SHFT);
}
#endif
#endif /* _ASM_SN_SN0_HUB_H */
......@@ -250,6 +250,14 @@ typedef union hubni_port_error_u {
#define NI_LLP_CB_MAX 0xff
#define NI_LLP_SN_MAX 0xff
static inline int get_region_shift(void)
{
if (LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK)
return NASID_TO_FINEREG_SHFT;
return NASID_TO_COARSEREG_SHFT;
}
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_SGI_SN0_HUBNI_H */
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Derived from IRIX <sys/SN/SN0/IP27.h>.
*
* Copyright (C) 1992 - 1997, 1999 Silicon Graphics, Inc.
* Copyright (C) 1999, 2006 by Ralf Baechle
*/
#ifndef _ASM_SN_SN0_IP27_H
#define _ASM_SN_SN0_IP27_H
#include <asm/mipsregs.h>
/*
* Simple definitions for the masks which remove SW bits from pte.
*/
#define TLBLO_HWBITSHIFT 0 /* Shift value, for masking */
#ifndef __ASSEMBLY__
#define CAUSE_BERRINTR IE_IRQ5
#define ECCF_CACHE_ERR 0
#define ECCF_TAGLO 1
#define ECCF_ECC 2
#define ECCF_ERROREPC 3
#define ECCF_PADDR 4
#define ECCF_SIZE (5 * sizeof(long))
#endif /* !__ASSEMBLY__ */
#ifdef __ASSEMBLY__
/*
* KL_GET_CPUNUM (similar to EV_GET_SPNUM for EVEREST platform) reads
* the processor number of the calling processor. The proc parameters
* must be a register.
*/
#define KL_GET_CPUNUM(proc) \
dli proc, LOCAL_HUB(0); \
ld proc, PI_CPU_NUM(proc)
#endif /* __ASSEMBLY__ */
/*
* R10000 status register interrupt bit mask usage for IP27.
*/
#define SRB_SWTIMO IE_SW0 /* 0x0100 */
#define SRB_NET IE_SW1 /* 0x0200 */
#define SRB_DEV0 IE_IRQ0 /* 0x0400 */
#define SRB_DEV1 IE_IRQ1 /* 0x0800 */
#define SRB_TIMOCLK IE_IRQ2 /* 0x1000 */
#define SRB_PROFCLK IE_IRQ3 /* 0x2000 */
#define SRB_ERR IE_IRQ4 /* 0x4000 */
#define SRB_SCHEDCLK IE_IRQ5 /* 0x8000 */
#define SR_IBIT_HI SRB_DEV0
#define SR_IBIT_PROF SRB_PROFCLK
#define SRB_SWTIMO_IDX 0
#define SRB_NET_IDX 1
#define SRB_DEV0_IDX 2
#define SRB_DEV1_IDX 3
#define SRB_TIMOCLK_IDX 4
#define SRB_PROFCLK_IDX 5
#define SRB_ERR_IDX 6
#define SRB_SCHEDCLK_IDX 7
#define NUM_CAUSE_INTRS 8
#define SCACHE_LINESIZE 128
#define SCACHE_LINEMASK (SCACHE_LINESIZE - 1)
#include <asm/sn/addrs.h>
#define LED_CYCLE_MASK 0x0f
#define LED_CYCLE_SHFT 4
#define SEND_NMI(_nasid, _slice) \
REMOTE_HUB_S((_nasid), (PI_NMI_A + ((_slice) * PI_NMI_OFFSET)), 1)
#endif /* _ASM_SN_SN0_IP27_H */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Derived from IRIX <sys/SN/kldir.h>, revision 1.21.
*
* Copyright (C) 1992 - 1997, 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 1999, 2000 by Ralf Baechle
*/
#ifndef _ASM_SN_SN0_KLDIR_H
#define _ASM_SN_SN0_KLDIR_H
/*
* The kldir memory area resides at a fixed place in each node's memory and
* provides pointers to most other IP27 memory areas. This allows us to
* resize and/or relocate memory areas at a later time without breaking all
* firmware and kernels that use them. Indices in the array are
* permanently dedicated to areas listed below. Some memory areas (marked
* below) reside at a permanently fixed location, but are included in the
* directory for completeness.
*/
/*
* The upper portion of the memory map applies during boot
* only and is overwritten by IRIX/SYMMON.
*
* MEMORY MAP PER NODE
*
* 0x2000000 (32M) +-----------------------------------------+
* | IO6 BUFFERS FOR FLASH ENET IOC3 |
* 0x1F80000 (31.5M) +-----------------------------------------+
* | IO6 TEXT/DATA/BSS/stack |
* 0x1C00000 (30M) +-----------------------------------------+
* | IO6 PROM DEBUG TEXT/DATA/BSS/stack |
* 0x0800000 (28M) +-----------------------------------------+
* | IP27 PROM TEXT/DATA/BSS/stack |
* 0x1B00000 (27M) +-----------------------------------------+
* | IP27 CFG |
* 0x1A00000 (26M) +-----------------------------------------+
* | Graphics PROM |
* 0x1800000 (24M) +-----------------------------------------+
* | 3rd Party PROM drivers |
* 0x1600000 (22M) +-----------------------------------------+
* | |
* | Free |
* | |
* +-----------------------------------------+
* | UNIX DEBUG Version |
* 0x190000 (2M--) +-----------------------------------------+
* | SYMMON |
* | (For UNIX Debug only) |
* 0x34000 (208K) +-----------------------------------------+
* | SYMMON STACK [NUM_CPU_PER_NODE] |
* | (For UNIX Debug only) |
* 0x25000 (148K) +-----------------------------------------+
* | KLCONFIG - II (temp) |
* | |
* | ---------------------------- |
* | |
* | UNIX NON-DEBUG Version |
* 0x19000 (100K) +-----------------------------------------+
*
*
* The lower portion of the memory map contains information that is
* permanent and is used by the IP27PROM, IO6PROM and IRIX.
*
* 0x19000 (100K) +-----------------------------------------+
* | |
* | PI Error Spools (32K) |
* | |
* 0x12000 (72K) +-----------------------------------------+
* | Unused |
* 0x11c00 (71K) +-----------------------------------------+
* | CPU 1 NMI Eframe area |
* 0x11a00 (70.5K) +-----------------------------------------+
* | CPU 0 NMI Eframe area |
* 0x11800 (70K) +-----------------------------------------+
* | CPU 1 NMI Register save area |
* 0x11600 (69.5K) +-----------------------------------------+
* | CPU 0 NMI Register save area |
* 0x11400 (69K) +-----------------------------------------+
* | GDA (1k) |
* 0x11000 (68K) +-----------------------------------------+
* | Early cache Exception stack |
* | and/or |
* | kernel/io6prom nmi registers |
* 0x10800 (66k) +-----------------------------------------+
* | cache error eframe |
* 0x10400 (65K) +-----------------------------------------+
* | Exception Handlers (UALIAS copy) |
* 0x10000 (64K) +-----------------------------------------+
* | |
* | |
* | KLCONFIG - I (permanent) (48K) |
* | |
* | |
* | |
* 0x4000 (16K) +-----------------------------------------+
* | NMI Handler (Protected Page) |
* 0x3000 (12K) +-----------------------------------------+
* | ARCS PVECTORS (master node only) |
* 0x2c00 (11K) +-----------------------------------------+
* | ARCS TVECTORS (master node only) |
* 0x2800 (10K) +-----------------------------------------+
* | LAUNCH [NUM_CPU] |
* 0x2400 (9K) +-----------------------------------------+
* | Low memory directory (KLDIR) |
* 0x2000 (8K) +-----------------------------------------+
* | ARCS SPB (1K) |
* 0x1000 (4K) +-----------------------------------------+
* | Early cache Exception stack |
* | and/or |
* | kernel/io6prom nmi registers |
* 0x800 (2k) +-----------------------------------------+
* | cache error eframe |
* 0x400 (1K) +-----------------------------------------+
* | Exception Handlers |
* 0x0 (0K) +-----------------------------------------+
*/
/*
* This is defined here because IP27_SYMMON_STK_SIZE must be at least what
* we define here. Since it's set up in the prom. We can't redefine it later
* and expect more space to be allocated. The way to find out the true size
* of the symmon stacks is to divide SYMMON_STK_SIZE by SYMMON_STK_STRIDE
* for a particular node.
*/
#define SYMMON_STACK_SIZE 0x8000
#if defined(PROM)
/*
* These defines are prom version dependent. No code other than the IP27
* prom should attempt to use these values.
*/
#define IP27_LAUNCH_OFFSET 0x2400
#define IP27_LAUNCH_SIZE 0x400
#define IP27_LAUNCH_COUNT 2
#define IP27_LAUNCH_STRIDE 0x200
#define IP27_KLCONFIG_OFFSET 0x4000
#define IP27_KLCONFIG_SIZE 0xc000
#define IP27_KLCONFIG_COUNT 1
#define IP27_KLCONFIG_STRIDE 0
#define IP27_NMI_OFFSET 0x3000
#define IP27_NMI_SIZE 0x40
#define IP27_NMI_COUNT 2
#define IP27_NMI_STRIDE 0x40
#define IP27_PI_ERROR_OFFSET 0x12000
#define IP27_PI_ERROR_SIZE 0x4000
#define IP27_PI_ERROR_COUNT 1
#define IP27_PI_ERROR_STRIDE 0
#define IP27_SYMMON_STK_OFFSET 0x25000
#define IP27_SYMMON_STK_SIZE 0xe000
#define IP27_SYMMON_STK_COUNT 2
/* IP27_SYMMON_STK_STRIDE must be >= SYMMON_STACK_SIZE */
#define IP27_SYMMON_STK_STRIDE 0x7000
#define IP27_FREEMEM_OFFSET 0x19000
#define IP27_FREEMEM_SIZE -1
#define IP27_FREEMEM_COUNT 1
#define IP27_FREEMEM_STRIDE 0
#endif /* PROM */
/*
* There will be only one of these in a partition so the IO6 must set it up.
*/
#define IO6_GDA_OFFSET 0x11000
#define IO6_GDA_SIZE 0x400
#define IO6_GDA_COUNT 1
#define IO6_GDA_STRIDE 0
/*
* save area of kernel nmi regs in the prom format
*/
#define IP27_NMI_KREGS_OFFSET 0x11400
#define IP27_NMI_KREGS_CPU_SIZE 0x200
/*
* save area of kernel nmi regs in eframe format
*/
#define IP27_NMI_EFRAME_OFFSET 0x11800
#define IP27_NMI_EFRAME_SIZE 0x200
#endif /* _ASM_SN_SN0_KLDIR_H */
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_SN_SN_PRIVATE_H
#define __ASM_SN_SN_PRIVATE_H
#include <asm/sn/types.h>
extern nasid_t master_nasid;
extern void cpu_node_probe(void);
extern void hub_rtc_init(nasid_t nasid);
extern void cpu_time_init(void);
extern void per_cpu_init(void);
extern void install_cpu_nmi_handler(int slice);
extern void install_ipi(void);
extern void setup_replication_mask(void);
extern void replicate_kernel_text(void);
extern unsigned long node_getfirstfree(nasid_t nasid);
#endif /* __ASM_SN_SN_PRIVATE_H */
......@@ -11,6 +11,8 @@
#include <linux/types.h>
#ifndef __ASSEMBLY__
typedef unsigned long cpuid_t;
typedef signed short nasid_t; /* node id in numa-as-id space */
typedef signed char partid_t; /* partition ID type */
......@@ -18,4 +20,6 @@ typedef signed short moduleid_t; /* user-visible module number type */
typedef dev_t vertex_hdl_t; /* hardware graph vertex handle */
#endif
#endif /* _ASM_SN_TYPES_H */
......@@ -16,6 +16,10 @@ config JZ4780_CI20
bool "MIPS Creator CI20"
select MACH_JZ4780
config X1000_CU1000_NEO
bool "YSH & ATIL CU1000 Module with Neo backplane"
select MACH_X1000
endchoice
config MACH_JZ4740
......@@ -33,3 +37,9 @@ config MACH_JZ4780
select MIPS_CPU_SCACHE
select SYS_HAS_CPU_MIPS32_R2
select SYS_SUPPORTS_HIGHMEM
config MACH_X1000
bool
select MIPS_CPU_SCACHE
select SYS_HAS_CPU_MIPS32_R2
select SYS_SUPPORTS_HIGHMEM
......@@ -44,6 +44,8 @@ static void __init jz4740_detect_mem(void)
static unsigned long __init get_board_mach_type(const void *fdt)
{
if (!fdt_node_check_compatible(fdt, 0, "ingenic,x1830"))
return MACH_INGENIC_X1830;
if (!fdt_node_check_compatible(fdt, 0, "ingenic,x1000"))
return MACH_INGENIC_X1000;
if (!fdt_node_check_compatible(fdt, 0, "ingenic,jz4780"))
......@@ -86,6 +88,8 @@ void __init device_tree_init(void)
const char *get_system_type(void)
{
switch (mips_machtype) {
case MACH_INGENIC_X1830:
return "X1830";
case MACH_INGENIC_X1000:
return "X1000";
case MACH_INGENIC_JZ4780:
......
......@@ -102,7 +102,12 @@ static void cpu_set_fpu_2008(struct cpuinfo_mips *c)
if (fir & MIPS_FPIR_HAS2008) {
fcsr = read_32bit_cp1_register(CP1_STATUS);
fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
/*
* MAC2008 toolchain never landed in real world, so we're only
* testing wether it can be disabled and don't try to enabled
* it.
*/
fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008 | FPU_CSR_MAC2008);
write_32bit_cp1_register(CP1_STATUS, fcsr0);
fcsr0 = read_32bit_cp1_register(CP1_STATUS);
......@@ -112,6 +117,15 @@ static void cpu_set_fpu_2008(struct cpuinfo_mips *c)
write_32bit_cp1_register(CP1_STATUS, fcsr);
if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2)) {
/*
* The bit for MAC2008 might be reused by R6 in future,
* so we only test for R2-R5.
*/
if (fcsr0 & FPU_CSR_MAC2008)
c->options |= MIPS_CPU_MAC_2008_ONLY;
}
if (!(fcsr0 & FPU_CSR_NAN2008))
c->options |= MIPS_CPU_NAN_LEGACY;
if (fcsr1 & FPU_CSR_NAN2008)
......@@ -1960,10 +1974,8 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
BUG_ON(!__builtin_constant_p(cpu_has_counter) || cpu_has_counter);
switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_XBURST:
c->cputype = CPU_XBURST;
c->writecombine = _CACHE_UNCACHED_ACCELERATED;
__cpu_name[cpu] = "Ingenic JZRISC";
case PRID_IMP_XBURST_REV1:
/*
* The XBurst core by default attempts to avoid branch target
* buffer lookups by detecting & special casing loops. This
......@@ -1971,13 +1983,18 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
* Set cp0 config7 bit 4 to disable this feature.
*/
set_c0_config7(MIPS_CONF7_BTB_LOOP_EN);
break;
default:
panic("Unknown Ingenic Processor ID!");
break;
}
switch (c->processor_id & PRID_COMP_MASK) {
/*
* The config0 register in the XBurst CPUs with a processor ID of
* PRID_COMP_INGENIC_D0 report themselves as MIPS32r2 compatible,
* but they don't actually support this ISA.
*/
case PRID_COMP_INGENIC_D0:
c->isa_level &= ~MIPS_CPU_ISA_M32R2;
break;
/*
* The config0 register in the XBurst CPUs with a processor ID of
* PRID_COMP_INGENIC_D1 has an abandoned huge page tlb mode, this
......@@ -1990,15 +2007,19 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
case PRID_COMP_INGENIC_D1:
write_c0_page_ctrl(XBURST_PAGECTRL_HPTLB_DIS);
break;
/*
* The config0 register in the XBurst CPUs with a processor ID of
* PRID_COMP_INGENIC_D0 report themselves as MIPS32r2 compatible,
* but they don't actually support this ISA.
*/
case PRID_COMP_INGENIC_D0:
c->isa_level &= ~MIPS_CPU_ISA_M32R2;
default:
break;
}
/* fall-through */
case PRID_IMP_XBURST_REV2:
c->cputype = CPU_XBURST;
c->writecombine = _CACHE_UNCACHED_ACCELERATED;
__cpu_name[cpu] = "Ingenic XBurst";
break;
default:
panic("Unknown Ingenic Processor ID!");
break;
}
}
......
......@@ -515,8 +515,7 @@ static void __init request_crashkernel(struct resource *res)
ret = request_resource(res, &crashk_res);
if (!ret)
pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
(unsigned long)((crashk_res.end -
crashk_res.start + 1) >> 20),
(unsigned long)(resource_size(&crashk_res) >> 20),
(unsigned long)(crashk_res.start >> 20));
}
#else /* !defined(CONFIG_KEXEC) */
......@@ -698,8 +697,7 @@ static void __init arch_mem_init(char **cmdline_p)
mips_parse_crashkernel();
#ifdef CONFIG_KEXEC
if (crashk_res.start != crashk_res.end)
memblock_reserve(crashk_res.start,
crashk_res.end - crashk_res.start + 1);
memblock_reserve(crashk_res.start, resource_size(&crashk_res));
#endif
device_tree_init();
sparse_init();
......
......@@ -90,6 +90,9 @@ void synchronise_count_master(int cpu)
void synchronise_count_slave(int cpu)
{
int i;
unsigned long flags;
local_irq_save(flags);
/*
* Not every cpu is online at the time this gets called,
......@@ -113,5 +116,7 @@ void synchronise_count_slave(int cpu)
}
/* Arrange for an interrupt in a short while */
write_c0_compare(read_c0_count() + COUNTON);
local_irq_restore(flags);
}
#undef NR_LOOPS
......@@ -131,7 +131,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
#define _LoadW(addr, value, res, type) \
do { \
__asm__ __volatile__ ( \
......@@ -152,7 +152,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
/* For CPUs without lwl instruction */
#define _LoadW(addr, value, res, type) \
do { \
......@@ -187,7 +187,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
#define _LoadHWU(addr, value, res, type) \
do { \
......@@ -213,7 +213,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
#define _LoadWU(addr, value, res, type) \
do { \
__asm__ __volatile__ ( \
......@@ -256,7 +256,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
/* For CPUs without lwl and ldl instructions */
#define _LoadWU(addr, value, res, type) \
do { \
......@@ -340,7 +340,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
#define _StoreHW(addr, value, res, type) \
......@@ -366,7 +366,7 @@ do { \
: "r" (value), "r" (addr), "i" (-EFAULT));\
} while(0)
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
#define _StoreW(addr, value, res, type) \
do { \
__asm__ __volatile__ ( \
......@@ -407,7 +407,7 @@ do { \
: "r" (value), "r" (addr), "i" (-EFAULT)); \
} while(0)
#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
#define _StoreW(addr, value, res, type) \
do { \
__asm__ __volatile__ ( \
......@@ -483,7 +483,7 @@ do { \
: "memory"); \
} while(0)
#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
#else /* __BIG_ENDIAN */
......@@ -509,7 +509,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
#define _LoadW(addr, value, res, type) \
do { \
__asm__ __volatile__ ( \
......@@ -530,7 +530,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
/* For CPUs without lwl instruction */
#define _LoadW(addr, value, res, type) \
do { \
......@@ -565,7 +565,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
#define _LoadHWU(addr, value, res, type) \
......@@ -592,7 +592,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
#define _LoadWU(addr, value, res, type) \
do { \
__asm__ __volatile__ ( \
......@@ -635,7 +635,7 @@ do { \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
/* For CPUs without lwl and ldl instructions */
#define _LoadWU(addr, value, res, type) \
do { \
......@@ -718,7 +718,7 @@ do { \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT)); \
} while(0)
#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
#define _StoreHW(addr, value, res, type) \
do { \
......@@ -743,7 +743,7 @@ do { \
: "r" (value), "r" (addr), "i" (-EFAULT));\
} while(0)
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
#define _StoreW(addr, value, res, type) \
do { \
__asm__ __volatile__ ( \
......@@ -784,7 +784,7 @@ do { \
: "r" (value), "r" (addr), "i" (-EFAULT)); \
} while(0)
#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
/* For CPUs without swl and sdl instructions */
#define _StoreW(addr, value, res, type) \
do { \
......@@ -861,7 +861,7 @@ do { \
: "memory"); \
} while(0)
#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
#endif
#define LoadHWU(addr, value, res) _LoadHWU(addr, value, res, kernel)
......
......@@ -301,14 +301,14 @@
and t0, src, ADDRMASK
PREFS( 0, 2*32(src) )
PREFD( 1, 2*32(dst) )
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
bnez t1, .Ldst_unaligned\@
nop
bnez t0, .Lsrc_unaligned_dst_aligned\@
#else
#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
or t0, t0, t1
bnez t0, .Lcopy_unaligned_bytes\@
#endif
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
/*
* use delay slot for fall-through
* src and dst are aligned; need to compute rem
......@@ -389,7 +389,7 @@
bne rem, len, 1b
.set noreorder
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
/*
* src and dst are aligned, need to copy rem bytes (rem < NBYTES)
* A loop would do only a byte at a time with possible branch
......@@ -491,7 +491,7 @@
bne len, rem, 1b
.set noreorder
#endif /* CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* !CONFIG_CPU_NO_LOAD_STORE_LR */
.Lcopy_bytes_checklen\@:
beqz len, .Ldone\@
nop
......@@ -520,7 +520,7 @@
jr ra
nop
#ifndef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifdef CONFIG_CPU_NO_LOAD_STORE_LR
.Lcopy_unaligned_bytes\@:
1:
COPY_BYTE(0)
......@@ -534,7 +534,7 @@
ADD src, src, 8
b 1b
ADD dst, dst, 8
#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
.if __memcpy == 1
END(memcpy)
.set __memcpy, 0
......
......@@ -115,7 +115,7 @@
#endif
.set reorder
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
R10KCBARRIER(0(ra))
#ifdef __MIPSEB__
EX(LONG_S_L, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */
......@@ -125,7 +125,7 @@
PTR_SUBU a0, t0 /* long align ptr */
PTR_ADDU a2, t0 /* correct size */
#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
#define STORE_BYTE(N) \
EX(sb, a1, N(a0), .Lbyte_fixup\@); \
.set noreorder; \
......@@ -150,7 +150,7 @@
ori a0, STORMASK
xori a0, STORMASK
PTR_ADDIU a0, STORSIZE
#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
1: ori t1, a2, 0x3f /* # of full blocks */
xori t1, 0x3f
andi t0, a2, 0x40-STORSIZE
......@@ -185,7 +185,7 @@
.set noreorder
beqz a2, 1f
#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
PTR_ADDU a0, a2 /* What's left */
.set reorder
R10KCBARRIER(0(ra))
......@@ -194,7 +194,7 @@
#else
EX(LONG_S_L, a1, -1(a0), .Llast_fixup\@)
#endif
#else
#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
PTR_SUBU t0, $0, a2
.set reorder
move a2, zero /* No remaining longs */
......@@ -211,7 +211,7 @@
EX(sb, a1, 6(a0), .Lbyte_fixup\@)
#endif
0:
#endif
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
1: move a2, zero
jr ra
......@@ -234,7 +234,7 @@
.hidden __memset
.endif
#ifndef CONFIG_CPU_HAS_LOAD_STORE_LR
#ifdef CONFIG_CPU_NO_LOAD_STORE_LR
.Lbyte_fixup\@:
/*
* unset_bytes = (#bytes - (#unaligned bytes)) - (-#unaligned bytes remaining + 1) + 1
......@@ -243,7 +243,7 @@
PTR_SUBU a2, t0
PTR_ADDIU a2, 1
jr ra
#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */
#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
.Lfirst_fixup\@:
/* unset_bytes already in a2 */
......
......@@ -15,7 +15,7 @@
#include <linux/export.h>
#include <linux/stringify.h>
#if !defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_CPU_MIPSR6)
#if !defined(CONFIG_CPU_HAS_DIEI)
/*
* For cli() we have to insert nops to make sure that the new value
......@@ -110,4 +110,4 @@ notrace void arch_local_irq_restore(unsigned long flags)
}
EXPORT_SYMBOL(arch_local_irq_restore);
#endif /* !CONFIG_CPU_MIPSR2 && !CONFIG_CPU_MIPSR6 */
#endif /* !CONFIG_CPU_HAS_DIEI */
......@@ -91,7 +91,7 @@ static inline void stop_perf_counters(void)
static void loongson_suspend_enter(void)
{
static unsigned int cached_cpu_freq;
unsigned int cached_cpu_freq;
/* setup wakeup events via enabling the IRQs */
setup_wakeup_events();
......
......@@ -75,7 +75,7 @@ static int __init compute_node_distance(int row, int col)
loongson_sysconf.cores_per_package;
if (col == row)
return 0;
return LOCAL_DISTANCE;
else if (package_row == package_col)
return 40;
else
......
......@@ -27,6 +27,9 @@ static int __init loongson3_platform_init(void)
continue;
pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
if (!pdev)
return -ENOMEM;
pdev->name = loongson_sysconf.sensors[i].name;
pdev->id = loongson_sysconf.sensors[i].id;
pdev->dev.platform_data = &loongson_sysconf.sensors[i];
......
......@@ -1514,15 +1514,27 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
break;
case madd_s_op:
if (cpu_has_mac2008_only)
handler = ieee754sp_madd;
else
handler = fpemu_sp_madd;
goto scoptop;
case msub_s_op:
if (cpu_has_mac2008_only)
handler = ieee754sp_msub;
else
handler = fpemu_sp_msub;
goto scoptop;
case nmadd_s_op:
if (cpu_has_mac2008_only)
handler = ieee754sp_nmadd;
else
handler = fpemu_sp_nmadd;
goto scoptop;
case nmsub_s_op:
if (cpu_has_mac2008_only)
handler = ieee754sp_nmsub;
else
handler = fpemu_sp_nmsub;
goto scoptop;
......@@ -1610,15 +1622,27 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
break;
case madd_d_op:
if (cpu_has_mac2008_only)
handler = ieee754dp_madd;
else
handler = fpemu_dp_madd;
goto dcoptop;
case msub_d_op:
if (cpu_has_mac2008_only)
handler = ieee754dp_msub;
else
handler = fpemu_dp_msub;
goto dcoptop;
case nmadd_d_op:
if (cpu_has_mac2008_only)
handler = ieee754dp_nmadd;
else
handler = fpemu_dp_nmadd;
goto dcoptop;
case nmsub_d_op:
if (cpu_has_mac2008_only)
handler = ieee754dp_nmsub;
else
handler = fpemu_dp_nmsub;
goto dcoptop;
......
......@@ -68,6 +68,12 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
ieee754_clearcx();
rs = xs ^ ys;
if (flags & MADDF_NEGATE_PRODUCT)
rs ^= 1;
if (flags & MADDF_NEGATE_ADDITION)
zs ^= 1;
/*
* Handle the cases when at least one of x, y or z is a NaN.
* Order of precedence is sNaN, qNaN and z, x, y.
......@@ -104,9 +110,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
if ((zc == IEEE754_CLASS_INF) &&
((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) ||
((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) {
if ((zc == IEEE754_CLASS_INF) && (zs != rs)) {
/*
* Cases of addition of infinities with opposite signs
* or subtraction of infinities with same signs.
......@@ -116,15 +120,10 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
}
/*
* z is here either not an infinity, or an infinity having the
* same sign as product (x*y) (in case of MADDF.D instruction)
* or product -(x*y) (in MSUBF.D case). The result must be an
* infinity, and its sign is determined only by the value of
* (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y.
* same sign as product (x*y). The result must be an infinity,
* and its sign is determined only by the sign of product (x*y).
*/
if (flags & MADDF_NEGATE_PRODUCT)
return ieee754dp_inf(1 ^ (xs ^ ys));
else
return ieee754dp_inf(xs ^ ys);
return ieee754dp_inf(rs);
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
......@@ -135,10 +134,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
return ieee754dp_inf(zs);
if (zc == IEEE754_CLASS_ZERO) {
/* Handle cases +0 + (-0) and similar ones. */
if ((!(flags & MADDF_NEGATE_PRODUCT)
&& (zs == (xs ^ ys))) ||
((flags & MADDF_NEGATE_PRODUCT)
&& (zs != (xs ^ ys))))
if (zs == rs)
/*
* Cases of addition of zeros of equal signs
* or subtraction of zeroes of opposite signs.
......@@ -187,9 +183,6 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
assert(ym & DP_HIDDEN_BIT);
re = xe + ye;
rs = xs ^ ys;
if (flags & MADDF_NEGATE_PRODUCT)
rs ^= 1;
/* shunt to top of word */
xm <<= 64 - (DP_FBITS + 1);
......@@ -340,3 +333,27 @@ union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x,
{
return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
}
union ieee754dp ieee754dp_madd(union ieee754dp z, union ieee754dp x,
union ieee754dp y)
{
return _dp_maddf(z, x, y, 0);
}
union ieee754dp ieee754dp_msub(union ieee754dp z, union ieee754dp x,
union ieee754dp y)
{
return _dp_maddf(z, x, y, MADDF_NEGATE_ADDITION);
}
union ieee754dp ieee754dp_nmadd(union ieee754dp z, union ieee754dp x,
union ieee754dp y)
{
return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT|MADDF_NEGATE_ADDITION);
}
union ieee754dp ieee754dp_nmsub(union ieee754dp z, union ieee754dp x,
union ieee754dp y)
{
return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
}
......@@ -68,6 +68,14 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
union ieee754sp y);
union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
union ieee754sp y);
union ieee754sp ieee754sp_madd(union ieee754sp z, union ieee754sp x,
union ieee754sp y);
union ieee754sp ieee754sp_msub(union ieee754sp z, union ieee754sp x,
union ieee754sp y);
union ieee754sp ieee754sp_nmadd(union ieee754sp z, union ieee754sp x,
union ieee754sp y);
union ieee754sp ieee754sp_nmsub(union ieee754sp z, union ieee754sp x,
union ieee754sp y);
int ieee754sp_2008class(union ieee754sp x);
union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y);
union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y);
......@@ -103,6 +111,14 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
union ieee754dp y);
union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x,
union ieee754dp y);
union ieee754dp ieee754dp_madd(union ieee754dp z, union ieee754dp x,
union ieee754dp y);
union ieee754dp ieee754dp_msub(union ieee754dp z, union ieee754dp x,
union ieee754dp y);
union ieee754dp ieee754dp_nmadd(union ieee754dp z, union ieee754dp x,
union ieee754dp y);
union ieee754dp ieee754dp_nmsub(union ieee754dp z, union ieee754dp x,
union ieee754dp y);
int ieee754dp_2008class(union ieee754dp x);
union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y);
union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y);
......
......@@ -16,6 +16,7 @@
enum maddf_flags {
MADDF_NEGATE_PRODUCT = 1 << 0,
MADDF_NEGATE_ADDITION = 1 << 1,
};
static inline void ieee754_clearcx(void)
......
......@@ -36,6 +36,12 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
ieee754_clearcx();
rs = xs ^ ys;
if (flags & MADDF_NEGATE_PRODUCT)
rs ^= 1;
if (flags & MADDF_NEGATE_ADDITION)
zs ^= 1;
/*
* Handle the cases when at least one of x, y or z is a NaN.
* Order of precedence is sNaN, qNaN and z, x, y.
......@@ -73,9 +79,7 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
if ((zc == IEEE754_CLASS_INF) &&
((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) ||
((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) {
if ((zc == IEEE754_CLASS_INF) && (zs != rs)) {
/*
* Cases of addition of infinities with opposite signs
* or subtraction of infinities with same signs.
......@@ -85,15 +89,10 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
}
/*
* z is here either not an infinity, or an infinity having the
* same sign as product (x*y) (in case of MADDF.D instruction)
* or product -(x*y) (in MSUBF.D case). The result must be an
* infinity, and its sign is determined only by the value of
* (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y.
* same sign as product (x*y). The result must be an infinity,
* and its sign is determined only by the sign of product (x*y).
*/
if (flags & MADDF_NEGATE_PRODUCT)
return ieee754sp_inf(1 ^ (xs ^ ys));
else
return ieee754sp_inf(xs ^ ys);
return ieee754sp_inf(rs);
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
......@@ -104,10 +103,7 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
return ieee754sp_inf(zs);
if (zc == IEEE754_CLASS_ZERO) {
/* Handle cases +0 + (-0) and similar ones. */
if ((!(flags & MADDF_NEGATE_PRODUCT)
&& (zs == (xs ^ ys))) ||
((flags & MADDF_NEGATE_PRODUCT)
&& (zs != (xs ^ ys))))
if (zs == rs)
/*
* Cases of addition of zeros of equal signs
* or subtraction of zeroes of opposite signs.
......@@ -158,9 +154,6 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
assert(ym & SP_HIDDEN_BIT);
re = xe + ye;
rs = xs ^ ys;
if (flags & MADDF_NEGATE_PRODUCT)
rs ^= 1;
/* Multiple 24 bit xm and ym to give 48 bit results */
rm64 = (uint64_t)xm * ym;
......@@ -260,3 +253,27 @@ union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
{
return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
}
union ieee754sp ieee754sp_madd(union ieee754sp z, union ieee754sp x,
union ieee754sp y)
{
return _sp_maddf(z, x, y, 0);
}
union ieee754sp ieee754sp_msub(union ieee754sp z, union ieee754sp x,
union ieee754sp y)
{
return _sp_maddf(z, x, y, MADDF_NEGATE_ADDITION);
}
union ieee754sp ieee754sp_nmadd(union ieee754sp z, union ieee754sp x,
union ieee754sp y)
{
return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT|MADDF_NEGATE_ADDITION);
}
union ieee754sp ieee754sp_nmsub(union ieee754sp z, union ieee754sp x,
union ieee754sp y)
{
return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
}
......@@ -508,6 +508,51 @@ void __ref free_initmem(void)
free_initmem_default(POISON_FREE_INITMEM);
}
#ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA
unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(__per_cpu_offset);
static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
{
return node_distance(cpu_to_node(from), cpu_to_node(to));
}
static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size,
size_t align)
{
return memblock_alloc_try_nid(size, align, __pa(MAX_DMA_ADDRESS),
MEMBLOCK_ALLOC_ACCESSIBLE,
cpu_to_node(cpu));
}
static void __init pcpu_fc_free(void *ptr, size_t size)
{
memblock_free_early(__pa(ptr), size);
}
void __init setup_per_cpu_areas(void)
{
unsigned long delta;
unsigned int cpu;
int rc;
/*
* Always reserve area for module percpu variables. That's
* what the legacy allocator did.
*/
rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE,
PERCPU_DYNAMIC_RESERVE, PAGE_SIZE,
pcpu_cpu_distance,
pcpu_fc_alloc, pcpu_fc_free);
if (rc < 0)
panic("Failed to initialize percpu areas.");
delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
for_each_possible_cpu(cpu)
__per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
}
#endif
#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
unsigned long pgd_current[NR_CPUS];
#endif
......
# SPDX-License-Identifier: GPL-2.0-only
# MIPS networking code
obj-$(CONFIG_MIPS_CBPF_JIT) += bpf_jit.o bpf_jit_asm.o
obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o
/*
* Just-In-Time compiler for BPF filters on MIPS
*
* Copyright (c) 2014 Imagination Technologies Ltd.
* Author: Markos Chandras <markos.chandras@imgtec.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License.
*/
#include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/filter.h>
#include <linux/if_vlan.h>
#include <linux/moduleloader.h>
#include <linux/netdevice.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <asm/asm.h>
#include <asm/bitops.h>
#include <asm/cacheflush.h>
#include <asm/cpu-features.h>
#include <asm/uasm.h>
#include "bpf_jit.h"
/* ABI
* r_skb_hl SKB header length
* r_data SKB data pointer
* r_off Offset
* r_A BPF register A
* r_X BPF register X
* r_skb *skb
* r_M *scratch memory
* r_skb_len SKB length
*
* On entry (*bpf_func)(*skb, *filter)
* a0 = MIPS_R_A0 = skb;
* a1 = MIPS_R_A1 = filter;
*
* Stack
* ...
* M[15]
* M[14]
* M[13]
* ...
* M[0] <-- r_M
* saved reg k-1
* saved reg k-2
* ...
* saved reg 0 <-- r_sp
* <no argument area>
*
* Packet layout
*
* <--------------------- len ------------------------>
* <--skb-len(r_skb_hl)-->< ----- skb->data_len ------>
* ----------------------------------------------------
* | skb->data |
* ----------------------------------------------------
*/
#define ptr typeof(unsigned long)
#define SCRATCH_OFF(k) (4 * (k))
/* JIT flags */
#define SEEN_CALL (1 << BPF_MEMWORDS)
#define SEEN_SREG_SFT (BPF_MEMWORDS + 1)
#define SEEN_SREG_BASE (1 << SEEN_SREG_SFT)
#define SEEN_SREG(x) (SEEN_SREG_BASE << (x))
#define SEEN_OFF SEEN_SREG(2)
#define SEEN_A SEEN_SREG(3)
#define SEEN_X SEEN_SREG(4)
#define SEEN_SKB SEEN_SREG(5)
#define SEEN_MEM SEEN_SREG(6)
/* SEEN_SK_DATA also implies skb_hl an skb_len */
#define SEEN_SKB_DATA (SEEN_SREG(7) | SEEN_SREG(1) | SEEN_SREG(0))
/* Arguments used by JIT */
#define ARGS_USED_BY_JIT 2 /* only applicable to 64-bit */
#define SBIT(x) (1 << (x)) /* Signed version of BIT() */
/**
* struct jit_ctx - JIT context
* @skf: The sk_filter
* @prologue_bytes: Number of bytes for prologue
* @idx: Instruction index
* @flags: JIT flags
* @offsets: Instruction offsets
* @target: Memory location for the compiled filter
*/
struct jit_ctx {
const struct bpf_prog *skf;
unsigned int prologue_bytes;
u32 idx;
u32 flags;
u32 *offsets;
u32 *target;
};
static inline int optimize_div(u32 *k)
{
/* power of 2 divides can be implemented with right shift */
if (!(*k & (*k-1))) {
*k = ilog2(*k);
return 1;
}
return 0;
}
static inline void emit_jit_reg_move(ptr dst, ptr src, struct jit_ctx *ctx);
/* Simply emit the instruction if the JIT memory space has been allocated */
#define emit_instr(ctx, func, ...) \
do { \
if ((ctx)->target != NULL) { \
u32 *p = &(ctx)->target[ctx->idx]; \
uasm_i_##func(&p, ##__VA_ARGS__); \
} \
(ctx)->idx++; \
} while (0)
/*
* Similar to emit_instr but it must be used when we need to emit
* 32-bit or 64-bit instructions
*/
#define emit_long_instr(ctx, func, ...) \
do { \
if ((ctx)->target != NULL) { \
u32 *p = &(ctx)->target[ctx->idx]; \
UASM_i_##func(&p, ##__VA_ARGS__); \
} \
(ctx)->idx++; \
} while (0)
/* Determine if immediate is within the 16-bit signed range */
static inline bool is_range16(s32 imm)
{
return !(imm >= SBIT(15) || imm < -SBIT(15));
}
static inline void emit_addu(unsigned int dst, unsigned int src1,
unsigned int src2, struct jit_ctx *ctx)
{
emit_instr(ctx, addu, dst, src1, src2);
}
static inline void emit_nop(struct jit_ctx *ctx)
{
emit_instr(ctx, nop);
}
/* Load a u32 immediate to a register */
static inline void emit_load_imm(unsigned int dst, u32 imm, struct jit_ctx *ctx)
{
if (ctx->target != NULL) {
/* addiu can only handle s16 */
if (!is_range16(imm)) {
u32 *p = &ctx->target[ctx->idx];
uasm_i_lui(&p, r_tmp_imm, (s32)imm >> 16);
p = &ctx->target[ctx->idx + 1];
uasm_i_ori(&p, dst, r_tmp_imm, imm & 0xffff);
} else {
u32 *p = &ctx->target[ctx->idx];
uasm_i_addiu(&p, dst, r_zero, imm);
}
}
ctx->idx++;
if (!is_range16(imm))
ctx->idx++;
}
static inline void emit_or(unsigned int dst, unsigned int src1,
unsigned int src2, struct jit_ctx *ctx)
{
emit_instr(ctx, or, dst, src1, src2);
}
static inline void emit_ori(unsigned int dst, unsigned src, u32 imm,
struct jit_ctx *ctx)
{
if (imm >= BIT(16)) {
emit_load_imm(r_tmp, imm, ctx);
emit_or(dst, src, r_tmp, ctx);
} else {
emit_instr(ctx, ori, dst, src, imm);
}
}
static inline void emit_daddiu(unsigned int dst, unsigned int src,
int imm, struct jit_ctx *ctx)
{
/*
* Only used for stack, so the imm is relatively small
* and it fits in 15-bits
*/
emit_instr(ctx, daddiu, dst, src, imm);
}
static inline void emit_addiu(unsigned int dst, unsigned int src,
u32 imm, struct jit_ctx *ctx)
{
if (!is_range16(imm)) {
emit_load_imm(r_tmp, imm, ctx);
emit_addu(dst, r_tmp, src, ctx);
} else {
emit_instr(ctx, addiu, dst, src, imm);
}
}
static inline void emit_and(unsigned int dst, unsigned int src1,
unsigned int src2, struct jit_ctx *ctx)
{
emit_instr(ctx, and, dst, src1, src2);
}
static inline void emit_andi(unsigned int dst, unsigned int src,
u32 imm, struct jit_ctx *ctx)
{
/* If imm does not fit in u16 then load it to register */
if (imm >= BIT(16)) {
emit_load_imm(r_tmp, imm, ctx);
emit_and(dst, src, r_tmp, ctx);
} else {
emit_instr(ctx, andi, dst, src, imm);
}
}
static inline void emit_xor(unsigned int dst, unsigned int src1,
unsigned int src2, struct jit_ctx *ctx)
{
emit_instr(ctx, xor, dst, src1, src2);
}
static inline void emit_xori(ptr dst, ptr src, u32 imm, struct jit_ctx *ctx)
{
/* If imm does not fit in u16 then load it to register */
if (imm >= BIT(16)) {
emit_load_imm(r_tmp, imm, ctx);
emit_xor(dst, src, r_tmp, ctx);
} else {
emit_instr(ctx, xori, dst, src, imm);
}
}
static inline void emit_stack_offset(int offset, struct jit_ctx *ctx)
{
emit_long_instr(ctx, ADDIU, r_sp, r_sp, offset);
}
static inline void emit_subu(unsigned int dst, unsigned int src1,
unsigned int src2, struct jit_ctx *ctx)
{
emit_instr(ctx, subu, dst, src1, src2);
}
static inline void emit_neg(unsigned int reg, struct jit_ctx *ctx)
{
emit_subu(reg, r_zero, reg, ctx);
}
static inline void emit_sllv(unsigned int dst, unsigned int src,
unsigned int sa, struct jit_ctx *ctx)
{
emit_instr(ctx, sllv, dst, src, sa);
}
static inline void emit_sll(unsigned int dst, unsigned int src,
unsigned int sa, struct jit_ctx *ctx)
{
/* sa is 5-bits long */
if (sa >= BIT(5))
/* Shifting >= 32 results in zero */
emit_jit_reg_move(dst, r_zero, ctx);
else
emit_instr(ctx, sll, dst, src, sa);
}
static inline void emit_srlv(unsigned int dst, unsigned int src,
unsigned int sa, struct jit_ctx *ctx)
{
emit_instr(ctx, srlv, dst, src, sa);
}
static inline void emit_srl(unsigned int dst, unsigned int src,
unsigned int sa, struct jit_ctx *ctx)
{
/* sa is 5-bits long */
if (sa >= BIT(5))
/* Shifting >= 32 results in zero */
emit_jit_reg_move(dst, r_zero, ctx);
else
emit_instr(ctx, srl, dst, src, sa);
}
static inline void emit_slt(unsigned int dst, unsigned int src1,
unsigned int src2, struct jit_ctx *ctx)
{
emit_instr(ctx, slt, dst, src1, src2);
}
static inline void emit_sltu(unsigned int dst, unsigned int src1,
unsigned int src2, struct jit_ctx *ctx)
{
emit_instr(ctx, sltu, dst, src1, src2);
}
static inline void emit_sltiu(unsigned dst, unsigned int src,
unsigned int imm, struct jit_ctx *ctx)
{
/* 16 bit immediate */
if (!is_range16((s32)imm)) {
emit_load_imm(r_tmp, imm, ctx);
emit_sltu(dst, src, r_tmp, ctx);
} else {
emit_instr(ctx, sltiu, dst, src, imm);
}
}
/* Store register on the stack */
static inline void emit_store_stack_reg(ptr reg, ptr base,
unsigned int offset,
struct jit_ctx *ctx)
{
emit_long_instr(ctx, SW, reg, offset, base);
}
static inline void emit_store(ptr reg, ptr base, unsigned int offset,
struct jit_ctx *ctx)
{
emit_instr(ctx, sw, reg, offset, base);
}
static inline void emit_load_stack_reg(ptr reg, ptr base,
unsigned int offset,
struct jit_ctx *ctx)
{
emit_long_instr(ctx, LW, reg, offset, base);
}
static inline void emit_load(unsigned int reg, unsigned int base,
unsigned int offset, struct jit_ctx *ctx)
{
emit_instr(ctx, lw, reg, offset, base);
}
static inline void emit_load_byte(unsigned int reg, unsigned int base,
unsigned int offset, struct jit_ctx *ctx)
{
emit_instr(ctx, lb, reg, offset, base);
}
static inline void emit_half_load(unsigned int reg, unsigned int base,
unsigned int offset, struct jit_ctx *ctx)
{
emit_instr(ctx, lh, reg, offset, base);
}
static inline void emit_half_load_unsigned(unsigned int reg, unsigned int base,
unsigned int offset, struct jit_ctx *ctx)
{
emit_instr(ctx, lhu, reg, offset, base);
}
static inline void emit_mul(unsigned int dst, unsigned int src1,
unsigned int src2, struct jit_ctx *ctx)
{
emit_instr(ctx, mul, dst, src1, src2);
}
static inline void emit_div(unsigned int dst, unsigned int src,
struct jit_ctx *ctx)
{
if (ctx->target != NULL) {
u32 *p = &ctx->target[ctx->idx];
uasm_i_divu(&p, dst, src);
p = &ctx->target[ctx->idx + 1];
uasm_i_mflo(&p, dst);
}
ctx->idx += 2; /* 2 insts */
}
static inline void emit_mod(unsigned int dst, unsigned int src,
struct jit_ctx *ctx)
{
if (ctx->target != NULL) {
u32 *p = &ctx->target[ctx->idx];
uasm_i_divu(&p, dst, src);
p = &ctx->target[ctx->idx + 1];
uasm_i_mfhi(&p, dst);
}
ctx->idx += 2; /* 2 insts */
}
static inline void emit_dsll(unsigned int dst, unsigned int src,
unsigned int sa, struct jit_ctx *ctx)
{
emit_instr(ctx, dsll, dst, src, sa);
}
static inline void emit_dsrl32(unsigned int dst, unsigned int src,
unsigned int sa, struct jit_ctx *ctx)
{
emit_instr(ctx, dsrl32, dst, src, sa);
}
static inline void emit_wsbh(unsigned int dst, unsigned int src,
struct jit_ctx *ctx)
{
emit_instr(ctx, wsbh, dst, src);
}
/* load pointer to register */
static inline void emit_load_ptr(unsigned int dst, unsigned int src,
int imm, struct jit_ctx *ctx)
{
/* src contains the base addr of the 32/64-pointer */
emit_long_instr(ctx, LW, dst, imm, src);
}
/* load a function pointer to register */
static inline void emit_load_func(unsigned int reg, ptr imm,
struct jit_ctx *ctx)
{
if (IS_ENABLED(CONFIG_64BIT)) {
/* At this point imm is always 64-bit */
emit_load_imm(r_tmp, (u64)imm >> 32, ctx);
emit_dsll(r_tmp_imm, r_tmp, 16, ctx); /* left shift by 16 */
emit_ori(r_tmp, r_tmp_imm, (imm >> 16) & 0xffff, ctx);
emit_dsll(r_tmp_imm, r_tmp, 16, ctx); /* left shift by 16 */
emit_ori(reg, r_tmp_imm, imm & 0xffff, ctx);
} else {
emit_load_imm(reg, imm, ctx);
}
}
/* Move to real MIPS register */
static inline void emit_reg_move(ptr dst, ptr src, struct jit_ctx *ctx)
{
emit_long_instr(ctx, ADDU, dst, src, r_zero);
}
/* Move to JIT (32-bit) register */
static inline void emit_jit_reg_move(ptr dst, ptr src, struct jit_ctx *ctx)
{
emit_addu(dst, src, r_zero, ctx);
}
/* Compute the immediate value for PC-relative branches. */
static inline u32 b_imm(unsigned int tgt, struct jit_ctx *ctx)
{
if (ctx->target == NULL)
return 0;
/*
* We want a pc-relative branch. We only do forward branches
* so tgt is always after pc. tgt is the instruction offset
* we want to jump to.
* Branch on MIPS:
* I: target_offset <- sign_extend(offset)
* I+1: PC += target_offset (delay slot)
*
* ctx->idx currently points to the branch instruction
* but the offset is added to the delay slot so we need
* to subtract 4.
*/
return ctx->offsets[tgt] -
(ctx->idx * 4 - ctx->prologue_bytes) - 4;
}
static inline void emit_bcond(int cond, unsigned int reg1, unsigned int reg2,
unsigned int imm, struct jit_ctx *ctx)
{
if (ctx->target != NULL) {
u32 *p = &ctx->target[ctx->idx];
switch (cond) {
case MIPS_COND_EQ:
uasm_i_beq(&p, reg1, reg2, imm);
break;
case MIPS_COND_NE:
uasm_i_bne(&p, reg1, reg2, imm);
break;
case MIPS_COND_ALL:
uasm_i_b(&p, imm);
break;
default:
pr_warn("%s: Unhandled branch conditional: %d\n",
__func__, cond);
}
}
ctx->idx++;
}
static inline void emit_b(unsigned int imm, struct jit_ctx *ctx)
{
emit_bcond(MIPS_COND_ALL, r_zero, r_zero, imm, ctx);
}
static inline void emit_jalr(unsigned int link, unsigned int reg,
struct jit_ctx *ctx)
{
emit_instr(ctx, jalr, link, reg);
}
static inline void emit_jr(unsigned int reg, struct jit_ctx *ctx)
{
emit_instr(ctx, jr, reg);
}
static inline u16 align_sp(unsigned int num)
{
/* Double word alignment for 32-bit, quadword for 64-bit */
unsigned int align = IS_ENABLED(CONFIG_64BIT) ? 16 : 8;
num = (num + (align - 1)) & -align;
return num;
}
static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset)
{
int i = 0, real_off = 0;
u32 sflags, tmp_flags;
/* Adjust the stack pointer */
if (offset)
emit_stack_offset(-align_sp(offset), ctx);
tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT;
/* sflags is essentially a bitmap */
while (tmp_flags) {
if ((sflags >> i) & 0x1) {
emit_store_stack_reg(MIPS_R_S0 + i, r_sp, real_off,
ctx);
real_off += SZREG;
}
i++;
tmp_flags >>= 1;
}
/* save return address */
if (ctx->flags & SEEN_CALL) {
emit_store_stack_reg(r_ra, r_sp, real_off, ctx);
real_off += SZREG;
}
/* Setup r_M leaving the alignment gap if necessary */
if (ctx->flags & SEEN_MEM) {
if (real_off % (SZREG * 2))
real_off += SZREG;
emit_long_instr(ctx, ADDIU, r_M, r_sp, real_off);
}
}
static void restore_bpf_jit_regs(struct jit_ctx *ctx,
unsigned int offset)
{
int i, real_off = 0;
u32 sflags, tmp_flags;
tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT;
/* sflags is a bitmap */
i = 0;
while (tmp_flags) {
if ((sflags >> i) & 0x1) {
emit_load_stack_reg(MIPS_R_S0 + i, r_sp, real_off,
ctx);
real_off += SZREG;
}
i++;
tmp_flags >>= 1;
}
/* restore return address */
if (ctx->flags & SEEN_CALL)
emit_load_stack_reg(r_ra, r_sp, real_off, ctx);
/* Restore the sp and discard the scrach memory */
if (offset)
emit_stack_offset(align_sp(offset), ctx);
}
static unsigned int get_stack_depth(struct jit_ctx *ctx)
{
int sp_off = 0;
/* How may s* regs do we need to preserved? */
sp_off += hweight32(ctx->flags >> SEEN_SREG_SFT) * SZREG;
if (ctx->flags & SEEN_MEM)
sp_off += 4 * BPF_MEMWORDS; /* BPF_MEMWORDS are 32-bit */
if (ctx->flags & SEEN_CALL)
sp_off += SZREG; /* Space for our ra register */
return sp_off;
}
static void build_prologue(struct jit_ctx *ctx)
{
int sp_off;
/* Calculate the total offset for the stack pointer */
sp_off = get_stack_depth(ctx);
save_bpf_jit_regs(ctx, sp_off);
if (ctx->flags & SEEN_SKB)
emit_reg_move(r_skb, MIPS_R_A0, ctx);
if (ctx->flags & SEEN_SKB_DATA) {
/* Load packet length */
emit_load(r_skb_len, r_skb, offsetof(struct sk_buff, len),
ctx);
emit_load(r_tmp, r_skb, offsetof(struct sk_buff, data_len),
ctx);
/* Load the data pointer */
emit_load_ptr(r_skb_data, r_skb,
offsetof(struct sk_buff, data), ctx);
/* Load the header length */
emit_subu(r_skb_hl, r_skb_len, r_tmp, ctx);
}
if (ctx->flags & SEEN_X)
emit_jit_reg_move(r_X, r_zero, ctx);
/*
* Do not leak kernel data to userspace, we only need to clear
* r_A if it is ever used. In fact if it is never used, we
* will not save/restore it, so clearing it in this case would
* corrupt the state of the caller.
*/
if (bpf_needs_clear_a(&ctx->skf->insns[0]) &&
(ctx->flags & SEEN_A))
emit_jit_reg_move(r_A, r_zero, ctx);
}
static void build_epilogue(struct jit_ctx *ctx)
{
unsigned int sp_off;
/* Calculate the total offset for the stack pointer */
sp_off = get_stack_depth(ctx);
restore_bpf_jit_regs(ctx, sp_off);
/* Return */
emit_jr(r_ra, ctx);
emit_nop(ctx);
}
#define CHOOSE_LOAD_FUNC(K, func) \
((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative : func) : \
func##_positive)
static int build_body(struct jit_ctx *ctx)
{
const struct bpf_prog *prog = ctx->skf;
const struct sock_filter *inst;
unsigned int i, off, condt;
u32 k, b_off __maybe_unused;
u8 (*sk_load_func)(unsigned long *skb, int offset);
for (i = 0; i < prog->len; i++) {
u16 code;
inst = &(prog->insns[i]);
pr_debug("%s: code->0x%02x, jt->0x%x, jf->0x%x, k->0x%x\n",
__func__, inst->code, inst->jt, inst->jf, inst->k);
k = inst->k;
code = bpf_anc_helper(inst);
if (ctx->target == NULL)
ctx->offsets[i] = ctx->idx * 4;
switch (code) {
case BPF_LD | BPF_IMM:
/* A <- k ==> li r_A, k */
ctx->flags |= SEEN_A;
emit_load_imm(r_A, k, ctx);
break;
case BPF_LD | BPF_W | BPF_LEN:
BUILD_BUG_ON(sizeof_field(struct sk_buff, len) != 4);
/* A <- len ==> lw r_A, offset(skb) */
ctx->flags |= SEEN_SKB | SEEN_A;
off = offsetof(struct sk_buff, len);
emit_load(r_A, r_skb, off, ctx);
break;
case BPF_LD | BPF_MEM:
/* A <- M[k] ==> lw r_A, offset(M) */
ctx->flags |= SEEN_MEM | SEEN_A;
emit_load(r_A, r_M, SCRATCH_OFF(k), ctx);
break;
case BPF_LD | BPF_W | BPF_ABS:
/* A <- P[k:4] */
sk_load_func = CHOOSE_LOAD_FUNC(k, sk_load_word);
goto load;
case BPF_LD | BPF_H | BPF_ABS:
/* A <- P[k:2] */
sk_load_func = CHOOSE_LOAD_FUNC(k, sk_load_half);
goto load;
case BPF_LD | BPF_B | BPF_ABS:
/* A <- P[k:1] */
sk_load_func = CHOOSE_LOAD_FUNC(k, sk_load_byte);
load:
emit_load_imm(r_off, k, ctx);
load_common:
ctx->flags |= SEEN_CALL | SEEN_OFF |
SEEN_SKB | SEEN_A | SEEN_SKB_DATA;
emit_load_func(r_s0, (ptr)sk_load_func, ctx);
emit_reg_move(MIPS_R_A0, r_skb, ctx);
emit_jalr(MIPS_R_RA, r_s0, ctx);
/* Load second argument to delay slot */
emit_reg_move(MIPS_R_A1, r_off, ctx);
/* Check the error value */
emit_bcond(MIPS_COND_EQ, r_ret, 0, b_imm(i + 1, ctx),
ctx);
/* Load return register on DS for failures */
emit_reg_move(r_ret, r_zero, ctx);
/* Return with error */
emit_b(b_imm(prog->len, ctx), ctx);
emit_nop(ctx);
break;
case BPF_LD | BPF_W | BPF_IND:
/* A <- P[X + k:4] */
sk_load_func = sk_load_word;
goto load_ind;
case BPF_LD | BPF_H | BPF_IND:
/* A <- P[X + k:2] */
sk_load_func = sk_load_half;
goto load_ind;
case BPF_LD | BPF_B | BPF_IND:
/* A <- P[X + k:1] */
sk_load_func = sk_load_byte;
load_ind:
ctx->flags |= SEEN_OFF | SEEN_X;
emit_addiu(r_off, r_X, k, ctx);
goto load_common;
case BPF_LDX | BPF_IMM:
/* X <- k */
ctx->flags |= SEEN_X;
emit_load_imm(r_X, k, ctx);
break;
case BPF_LDX | BPF_MEM:
/* X <- M[k] */
ctx->flags |= SEEN_X | SEEN_MEM;
emit_load(r_X, r_M, SCRATCH_OFF(k), ctx);
break;
case BPF_LDX | BPF_W | BPF_LEN:
/* X <- len */
ctx->flags |= SEEN_X | SEEN_SKB;
off = offsetof(struct sk_buff, len);
emit_load(r_X, r_skb, off, ctx);
break;
case BPF_LDX | BPF_B | BPF_MSH:
/* X <- 4 * (P[k:1] & 0xf) */
ctx->flags |= SEEN_X | SEEN_CALL | SEEN_SKB;
/* Load offset to a1 */
emit_load_func(r_s0, (ptr)sk_load_byte, ctx);
/*
* This may emit two instructions so it may not fit
* in the delay slot. So use a0 in the delay slot.
*/
emit_load_imm(MIPS_R_A1, k, ctx);
emit_jalr(MIPS_R_RA, r_s0, ctx);
emit_reg_move(MIPS_R_A0, r_skb, ctx); /* delay slot */
/* Check the error value */
emit_bcond(MIPS_COND_NE, r_ret, 0,
b_imm(prog->len, ctx), ctx);
emit_reg_move(r_ret, r_zero, ctx);
/* We are good */
/* X <- P[1:K] & 0xf */
emit_andi(r_X, r_A, 0xf, ctx);
/* X << 2 */
emit_b(b_imm(i + 1, ctx), ctx);
emit_sll(r_X, r_X, 2, ctx); /* delay slot */
break;
case BPF_ST:
/* M[k] <- A */
ctx->flags |= SEEN_MEM | SEEN_A;
emit_store(r_A, r_M, SCRATCH_OFF(k), ctx);
break;
case BPF_STX:
/* M[k] <- X */
ctx->flags |= SEEN_MEM | SEEN_X;
emit_store(r_X, r_M, SCRATCH_OFF(k), ctx);
break;
case BPF_ALU | BPF_ADD | BPF_K:
/* A += K */
ctx->flags |= SEEN_A;
emit_addiu(r_A, r_A, k, ctx);
break;
case BPF_ALU | BPF_ADD | BPF_X:
/* A += X */
ctx->flags |= SEEN_A | SEEN_X;
emit_addu(r_A, r_A, r_X, ctx);
break;
case BPF_ALU | BPF_SUB | BPF_K:
/* A -= K */
ctx->flags |= SEEN_A;
emit_addiu(r_A, r_A, -k, ctx);
break;
case BPF_ALU | BPF_SUB | BPF_X:
/* A -= X */
ctx->flags |= SEEN_A | SEEN_X;
emit_subu(r_A, r_A, r_X, ctx);
break;
case BPF_ALU | BPF_MUL | BPF_K:
/* A *= K */
/* Load K to scratch register before MUL */
ctx->flags |= SEEN_A;
emit_load_imm(r_s0, k, ctx);
emit_mul(r_A, r_A, r_s0, ctx);
break;
case BPF_ALU | BPF_MUL | BPF_X:
/* A *= X */
ctx->flags |= SEEN_A | SEEN_X;
emit_mul(r_A, r_A, r_X, ctx);
break;
case BPF_ALU | BPF_DIV | BPF_K:
/* A /= k */
if (k == 1)
break;
if (optimize_div(&k)) {
ctx->flags |= SEEN_A;
emit_srl(r_A, r_A, k, ctx);
break;
}
ctx->flags |= SEEN_A;
emit_load_imm(r_s0, k, ctx);
emit_div(r_A, r_s0, ctx);
break;
case BPF_ALU | BPF_MOD | BPF_K:
/* A %= k */
if (k == 1) {
ctx->flags |= SEEN_A;
emit_jit_reg_move(r_A, r_zero, ctx);
} else {
ctx->flags |= SEEN_A;
emit_load_imm(r_s0, k, ctx);
emit_mod(r_A, r_s0, ctx);
}
break;
case BPF_ALU | BPF_DIV | BPF_X:
/* A /= X */
ctx->flags |= SEEN_X | SEEN_A;
/* Check if r_X is zero */
emit_bcond(MIPS_COND_EQ, r_X, r_zero,
b_imm(prog->len, ctx), ctx);
emit_load_imm(r_ret, 0, ctx); /* delay slot */
emit_div(r_A, r_X, ctx);
break;
case BPF_ALU | BPF_MOD | BPF_X:
/* A %= X */
ctx->flags |= SEEN_X | SEEN_A;
/* Check if r_X is zero */
emit_bcond(MIPS_COND_EQ, r_X, r_zero,
b_imm(prog->len, ctx), ctx);
emit_load_imm(r_ret, 0, ctx); /* delay slot */
emit_mod(r_A, r_X, ctx);
break;
case BPF_ALU | BPF_OR | BPF_K:
/* A |= K */
ctx->flags |= SEEN_A;
emit_ori(r_A, r_A, k, ctx);
break;
case BPF_ALU | BPF_OR | BPF_X:
/* A |= X */
ctx->flags |= SEEN_A;
emit_ori(r_A, r_A, r_X, ctx);
break;
case BPF_ALU | BPF_XOR | BPF_K:
/* A ^= k */
ctx->flags |= SEEN_A;
emit_xori(r_A, r_A, k, ctx);
break;
case BPF_ANC | SKF_AD_ALU_XOR_X:
case BPF_ALU | BPF_XOR | BPF_X:
/* A ^= X */
ctx->flags |= SEEN_A;
emit_xor(r_A, r_A, r_X, ctx);
break;
case BPF_ALU | BPF_AND | BPF_K:
/* A &= K */
ctx->flags |= SEEN_A;
emit_andi(r_A, r_A, k, ctx);
break;
case BPF_ALU | BPF_AND | BPF_X:
/* A &= X */
ctx->flags |= SEEN_A | SEEN_X;
emit_and(r_A, r_A, r_X, ctx);
break;
case BPF_ALU | BPF_LSH | BPF_K:
/* A <<= K */
ctx->flags |= SEEN_A;
emit_sll(r_A, r_A, k, ctx);
break;
case BPF_ALU | BPF_LSH | BPF_X:
/* A <<= X */
ctx->flags |= SEEN_A | SEEN_X;
emit_sllv(r_A, r_A, r_X, ctx);
break;
case BPF_ALU | BPF_RSH | BPF_K:
/* A >>= K */
ctx->flags |= SEEN_A;
emit_srl(r_A, r_A, k, ctx);
break;
case BPF_ALU | BPF_RSH | BPF_X:
ctx->flags |= SEEN_A | SEEN_X;
emit_srlv(r_A, r_A, r_X, ctx);
break;
case BPF_ALU | BPF_NEG:
/* A = -A */
ctx->flags |= SEEN_A;
emit_neg(r_A, ctx);
break;
case BPF_JMP | BPF_JA:
/* pc += K */
emit_b(b_imm(i + k + 1, ctx), ctx);
emit_nop(ctx);
break;
case BPF_JMP | BPF_JEQ | BPF_K:
/* pc += ( A == K ) ? pc->jt : pc->jf */
condt = MIPS_COND_EQ | MIPS_COND_K;
goto jmp_cmp;
case BPF_JMP | BPF_JEQ | BPF_X:
ctx->flags |= SEEN_X;
/* pc += ( A == X ) ? pc->jt : pc->jf */
condt = MIPS_COND_EQ | MIPS_COND_X;
goto jmp_cmp;
case BPF_JMP | BPF_JGE | BPF_K:
/* pc += ( A >= K ) ? pc->jt : pc->jf */
condt = MIPS_COND_GE | MIPS_COND_K;
goto jmp_cmp;
case BPF_JMP | BPF_JGE | BPF_X:
ctx->flags |= SEEN_X;
/* pc += ( A >= X ) ? pc->jt : pc->jf */
condt = MIPS_COND_GE | MIPS_COND_X;
goto jmp_cmp;
case BPF_JMP | BPF_JGT | BPF_K:
/* pc += ( A > K ) ? pc->jt : pc->jf */
condt = MIPS_COND_GT | MIPS_COND_K;
goto jmp_cmp;
case BPF_JMP | BPF_JGT | BPF_X:
ctx->flags |= SEEN_X;
/* pc += ( A > X ) ? pc->jt : pc->jf */
condt = MIPS_COND_GT | MIPS_COND_X;
jmp_cmp:
/* Greater or Equal */
if ((condt & MIPS_COND_GE) ||
(condt & MIPS_COND_GT)) {
if (condt & MIPS_COND_K) { /* K */
ctx->flags |= SEEN_A;
emit_sltiu(r_s0, r_A, k, ctx);
} else { /* X */
ctx->flags |= SEEN_A |
SEEN_X;
emit_sltu(r_s0, r_A, r_X, ctx);
}
/* A < (K|X) ? r_scrach = 1 */
b_off = b_imm(i + inst->jf + 1, ctx);
emit_bcond(MIPS_COND_NE, r_s0, r_zero, b_off,
ctx);
emit_nop(ctx);
/* A > (K|X) ? scratch = 0 */
if (condt & MIPS_COND_GT) {
/* Checking for equality */
ctx->flags |= SEEN_A | SEEN_X;
if (condt & MIPS_COND_K)
emit_load_imm(r_s0, k, ctx);
else
emit_jit_reg_move(r_s0, r_X,
ctx);
b_off = b_imm(i + inst->jf + 1, ctx);
emit_bcond(MIPS_COND_EQ, r_A, r_s0,
b_off, ctx);
emit_nop(ctx);
/* Finally, A > K|X */
b_off = b_imm(i + inst->jt + 1, ctx);
emit_b(b_off, ctx);
emit_nop(ctx);
} else {
/* A >= (K|X) so jump */
b_off = b_imm(i + inst->jt + 1, ctx);
emit_b(b_off, ctx);
emit_nop(ctx);
}
} else {
/* A == K|X */
if (condt & MIPS_COND_K) { /* K */
ctx->flags |= SEEN_A;
emit_load_imm(r_s0, k, ctx);
/* jump true */
b_off = b_imm(i + inst->jt + 1, ctx);
emit_bcond(MIPS_COND_EQ, r_A, r_s0,
b_off, ctx);
emit_nop(ctx);
/* jump false */
b_off = b_imm(i + inst->jf + 1,
ctx);
emit_bcond(MIPS_COND_NE, r_A, r_s0,
b_off, ctx);
emit_nop(ctx);
} else { /* X */
/* jump true */
ctx->flags |= SEEN_A | SEEN_X;
b_off = b_imm(i + inst->jt + 1,
ctx);
emit_bcond(MIPS_COND_EQ, r_A, r_X,
b_off, ctx);
emit_nop(ctx);
/* jump false */
b_off = b_imm(i + inst->jf + 1, ctx);
emit_bcond(MIPS_COND_NE, r_A, r_X,
b_off, ctx);
emit_nop(ctx);
}
}
break;
case BPF_JMP | BPF_JSET | BPF_K:
ctx->flags |= SEEN_A;
/* pc += (A & K) ? pc -> jt : pc -> jf */
emit_load_imm(r_s1, k, ctx);
emit_and(r_s0, r_A, r_s1, ctx);
/* jump true */
b_off = b_imm(i + inst->jt + 1, ctx);
emit_bcond(MIPS_COND_NE, r_s0, r_zero, b_off, ctx);
emit_nop(ctx);
/* jump false */
b_off = b_imm(i + inst->jf + 1, ctx);
emit_b(b_off, ctx);
emit_nop(ctx);
break;
case BPF_JMP | BPF_JSET | BPF_X:
ctx->flags |= SEEN_X | SEEN_A;
/* pc += (A & X) ? pc -> jt : pc -> jf */
emit_and(r_s0, r_A, r_X, ctx);
/* jump true */
b_off = b_imm(i + inst->jt + 1, ctx);
emit_bcond(MIPS_COND_NE, r_s0, r_zero, b_off, ctx);
emit_nop(ctx);
/* jump false */
b_off = b_imm(i + inst->jf + 1, ctx);
emit_b(b_off, ctx);
emit_nop(ctx);
break;
case BPF_RET | BPF_A:
ctx->flags |= SEEN_A;
if (i != prog->len - 1)
/*
* If this is not the last instruction
* then jump to the epilogue
*/
emit_b(b_imm(prog->len, ctx), ctx);
emit_reg_move(r_ret, r_A, ctx); /* delay slot */
break;
case BPF_RET | BPF_K:
/*
* It can emit two instructions so it does not fit on
* the delay slot.
*/
emit_load_imm(r_ret, k, ctx);
if (i != prog->len - 1) {
/*
* If this is not the last instruction
* then jump to the epilogue
*/
emit_b(b_imm(prog->len, ctx), ctx);
emit_nop(ctx);
}
break;
case BPF_MISC | BPF_TAX:
/* X = A */
ctx->flags |= SEEN_X | SEEN_A;
emit_jit_reg_move(r_X, r_A, ctx);
break;
case BPF_MISC | BPF_TXA:
/* A = X */
ctx->flags |= SEEN_A | SEEN_X;
emit_jit_reg_move(r_A, r_X, ctx);
break;
/* AUX */
case BPF_ANC | SKF_AD_PROTOCOL:
/* A = ntohs(skb->protocol */
ctx->flags |= SEEN_SKB | SEEN_OFF | SEEN_A;
BUILD_BUG_ON(sizeof_field(struct sk_buff,
protocol) != 2);
off = offsetof(struct sk_buff, protocol);
emit_half_load(r_A, r_skb, off, ctx);
#ifdef CONFIG_CPU_LITTLE_ENDIAN
/* This needs little endian fixup */
if (cpu_has_wsbh) {
/* R2 and later have the wsbh instruction */
emit_wsbh(r_A, r_A, ctx);
} else {
/* Get first byte */
emit_andi(r_tmp_imm, r_A, 0xff, ctx);
/* Shift it */
emit_sll(r_tmp, r_tmp_imm, 8, ctx);
/* Get second byte */
emit_srl(r_tmp_imm, r_A, 8, ctx);
emit_andi(r_tmp_imm, r_tmp_imm, 0xff, ctx);
/* Put everyting together in r_A */
emit_or(r_A, r_tmp, r_tmp_imm, ctx);
}
#endif
break;
case BPF_ANC | SKF_AD_CPU:
ctx->flags |= SEEN_A | SEEN_OFF;
/* A = current_thread_info()->cpu */
BUILD_BUG_ON(sizeof_field(struct thread_info,
cpu) != 4);
off = offsetof(struct thread_info, cpu);
/* $28/gp points to the thread_info struct */
emit_load(r_A, 28, off, ctx);
break;
case BPF_ANC | SKF_AD_IFINDEX:
/* A = skb->dev->ifindex */
case BPF_ANC | SKF_AD_HATYPE:
/* A = skb->dev->type */
ctx->flags |= SEEN_SKB | SEEN_A;
off = offsetof(struct sk_buff, dev);
/* Load *dev pointer */
emit_load_ptr(r_s0, r_skb, off, ctx);
/* error (0) in the delay slot */
emit_bcond(MIPS_COND_EQ, r_s0, r_zero,
b_imm(prog->len, ctx), ctx);
emit_reg_move(r_ret, r_zero, ctx);
if (code == (BPF_ANC | SKF_AD_IFINDEX)) {
BUILD_BUG_ON(sizeof_field(struct net_device, ifindex) != 4);
off = offsetof(struct net_device, ifindex);
emit_load(r_A, r_s0, off, ctx);
} else { /* (code == (BPF_ANC | SKF_AD_HATYPE) */
BUILD_BUG_ON(sizeof_field(struct net_device, type) != 2);
off = offsetof(struct net_device, type);
emit_half_load_unsigned(r_A, r_s0, off, ctx);
}
break;
case BPF_ANC | SKF_AD_MARK:
ctx->flags |= SEEN_SKB | SEEN_A;
BUILD_BUG_ON(sizeof_field(struct sk_buff, mark) != 4);
off = offsetof(struct sk_buff, mark);
emit_load(r_A, r_skb, off, ctx);
break;
case BPF_ANC | SKF_AD_RXHASH:
ctx->flags |= SEEN_SKB | SEEN_A;
BUILD_BUG_ON(sizeof_field(struct sk_buff, hash) != 4);
off = offsetof(struct sk_buff, hash);
emit_load(r_A, r_skb, off, ctx);
break;
case BPF_ANC | SKF_AD_VLAN_TAG:
ctx->flags |= SEEN_SKB | SEEN_A;
BUILD_BUG_ON(sizeof_field(struct sk_buff,
vlan_tci) != 2);
off = offsetof(struct sk_buff, vlan_tci);
emit_half_load_unsigned(r_A, r_skb, off, ctx);
break;
case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT:
ctx->flags |= SEEN_SKB | SEEN_A;
emit_load_byte(r_A, r_skb, PKT_VLAN_PRESENT_OFFSET(), ctx);
if (PKT_VLAN_PRESENT_BIT)
emit_srl(r_A, r_A, PKT_VLAN_PRESENT_BIT, ctx);
if (PKT_VLAN_PRESENT_BIT < 7)
emit_andi(r_A, r_A, 1, ctx);
break;
case BPF_ANC | SKF_AD_PKTTYPE:
ctx->flags |= SEEN_SKB;
emit_load_byte(r_tmp, r_skb, PKT_TYPE_OFFSET(), ctx);
/* Keep only the last 3 bits */
emit_andi(r_A, r_tmp, PKT_TYPE_MAX, ctx);
#ifdef __BIG_ENDIAN_BITFIELD
/* Get the actual packet type to the lower 3 bits */
emit_srl(r_A, r_A, 5, ctx);
#endif
break;
case BPF_ANC | SKF_AD_QUEUE:
ctx->flags |= SEEN_SKB | SEEN_A;
BUILD_BUG_ON(sizeof_field(struct sk_buff,
queue_mapping) != 2);
BUILD_BUG_ON(offsetof(struct sk_buff,
queue_mapping) > 0xff);
off = offsetof(struct sk_buff, queue_mapping);
emit_half_load_unsigned(r_A, r_skb, off, ctx);
break;
default:
pr_debug("%s: Unhandled opcode: 0x%02x\n", __FILE__,
inst->code);
return -1;
}
}
/* compute offsets only during the first pass */
if (ctx->target == NULL)
ctx->offsets[i] = ctx->idx * 4;
return 0;
}
void bpf_jit_compile(struct bpf_prog *fp)
{
struct jit_ctx ctx;
unsigned int alloc_size, tmp_idx;
if (!bpf_jit_enable)
return;
memset(&ctx, 0, sizeof(ctx));
ctx.offsets = kcalloc(fp->len + 1, sizeof(*ctx.offsets), GFP_KERNEL);
if (ctx.offsets == NULL)
return;
ctx.skf = fp;
if (build_body(&ctx))
goto out;
tmp_idx = ctx.idx;
build_prologue(&ctx);
ctx.prologue_bytes = (ctx.idx - tmp_idx) * 4;
/* just to complete the ctx.idx count */
build_epilogue(&ctx);
alloc_size = 4 * ctx.idx;
ctx.target = module_alloc(alloc_size);
if (ctx.target == NULL)
goto out;
/* Clean it */
memset(ctx.target, 0, alloc_size);
ctx.idx = 0;
/* Generate the actual JIT code */
build_prologue(&ctx);
build_body(&ctx);
build_epilogue(&ctx);
/* Update the icache */
flush_icache_range((ptr)ctx.target, (ptr)(ctx.target + ctx.idx));
if (bpf_jit_enable > 1)
/* Dump JIT code */
bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
fp->bpf_func = (void *)ctx.target;
fp->jited = 1;
out:
kfree(ctx.offsets);
}
void bpf_jit_free(struct bpf_prog *fp)
{
if (fp->jited)
module_memfree(fp->bpf_func);
bpf_prog_unlock_free(fp);
}
/*
* bpf_jib_asm.S: Packet/header access helper functions for MIPS/MIPS64 BPF
* compiler.
*
* Copyright (C) 2015 Imagination Technologies Ltd.
* Author: Markos Chandras <markos.chandras@imgtec.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License.
*/
#include <asm/asm.h>
#include <asm/isa-rev.h>
#include <asm/regdef.h>
#include "bpf_jit.h"
/* ABI
*
* r_skb_hl skb header length
* r_skb_data skb data
* r_off(a1) offset register
* r_A BPF register A
* r_X PF register X
* r_skb(a0) *skb
* r_M *scratch memory
* r_skb_le skb length
* r_s0 Scratch register 0
* r_s1 Scratch register 1
*
* On entry:
* a0: *skb
* a1: offset (imm or imm + X)
*
* All non-BPF-ABI registers are free for use. On return, we only
* care about r_ret. The BPF-ABI registers are assumed to remain
* unmodified during the entire filter operation.
*/
#define skb a0
#define offset a1
#define SKF_LL_OFF (-0x200000) /* Can't include linux/filter.h in assembly */
/* We know better :) so prevent assembler reordering etc */
.set noreorder
#define is_offset_negative(TYPE) \
/* If offset is negative we have more work to do */ \
slti t0, offset, 0; \
bgtz t0, bpf_slow_path_##TYPE##_neg; \
/* Be careful what follows in DS. */
#define is_offset_in_header(SIZE, TYPE) \
/* Reading from header? */ \
addiu $r_s0, $r_skb_hl, -SIZE; \
slt t0, $r_s0, offset; \
bgtz t0, bpf_slow_path_##TYPE; \
LEAF(sk_load_word)
is_offset_negative(word)
FEXPORT(sk_load_word_positive)
is_offset_in_header(4, word)
/* Offset within header boundaries */
PTR_ADDU t1, $r_skb_data, offset
.set reorder
lw $r_A, 0(t1)
.set noreorder
#ifdef CONFIG_CPU_LITTLE_ENDIAN
# if MIPS_ISA_REV >= 2
wsbh t0, $r_A
rotr $r_A, t0, 16
# else
sll t0, $r_A, 24
srl t1, $r_A, 24
srl t2, $r_A, 8
or t0, t0, t1
andi t2, t2, 0xff00
andi t1, $r_A, 0xff00
or t0, t0, t2
sll t1, t1, 8
or $r_A, t0, t1
# endif
#endif
jr $r_ra
move $r_ret, zero
END(sk_load_word)
LEAF(sk_load_half)
is_offset_negative(half)
FEXPORT(sk_load_half_positive)
is_offset_in_header(2, half)
/* Offset within header boundaries */
PTR_ADDU t1, $r_skb_data, offset
lhu $r_A, 0(t1)
#ifdef CONFIG_CPU_LITTLE_ENDIAN
# if MIPS_ISA_REV >= 2
wsbh $r_A, $r_A
# else
sll t0, $r_A, 8
srl t1, $r_A, 8
andi t0, t0, 0xff00
or $r_A, t0, t1
# endif
#endif
jr $r_ra
move $r_ret, zero
END(sk_load_half)
LEAF(sk_load_byte)
is_offset_negative(byte)
FEXPORT(sk_load_byte_positive)
is_offset_in_header(1, byte)
/* Offset within header boundaries */
PTR_ADDU t1, $r_skb_data, offset
lbu $r_A, 0(t1)
jr $r_ra
move $r_ret, zero
END(sk_load_byte)
/*
* call skb_copy_bits:
* (prototype in linux/skbuff.h)
*
* int skb_copy_bits(sk_buff *skb, int offset, void *to, int len)
*
* o32 mandates we leave 4 spaces for argument registers in case
* the callee needs to use them. Even though we don't care about
* the argument registers ourselves, we need to allocate that space
* to remain ABI compliant since the callee may want to use that space.
* We also allocate 2 more spaces for $r_ra and our return register (*to).
*
* n64 is a bit different. The *caller* will allocate the space to preserve
* the arguments. So in 64-bit kernels, we allocate the 4-arg space for no
* good reason but it does not matter that much really.
*
* (void *to) is returned in r_s0
*
*/
#ifdef CONFIG_CPU_LITTLE_ENDIAN
#define DS_OFFSET(SIZE) (4 * SZREG)
#else
#define DS_OFFSET(SIZE) ((4 * SZREG) + (4 - SIZE))
#endif
#define bpf_slow_path_common(SIZE) \
/* Quick check. Are we within reasonable boundaries? */ \
LONG_ADDIU $r_s1, $r_skb_len, -SIZE; \
sltu $r_s0, offset, $r_s1; \
beqz $r_s0, fault; \
/* Load 4th argument in DS */ \
LONG_ADDIU a3, zero, SIZE; \
PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \
PTR_LA t0, skb_copy_bits; \
PTR_S $r_ra, (5 * SZREG)($r_sp); \
/* Assign low slot to a2 */ \
PTR_ADDIU a2, $r_sp, DS_OFFSET(SIZE); \
jalr t0; \
/* Reset our destination slot (DS but it's ok) */ \
INT_S zero, (4 * SZREG)($r_sp); \
/* \
* skb_copy_bits returns 0 on success and -EFAULT \
* on error. Our data live in a2. Do not bother with \
* our data if an error has been returned. \
*/ \
/* Restore our frame */ \
PTR_L $r_ra, (5 * SZREG)($r_sp); \
INT_L $r_s0, (4 * SZREG)($r_sp); \
bltz v0, fault; \
PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \
move $r_ret, zero; \
NESTED(bpf_slow_path_word, (6 * SZREG), $r_sp)
bpf_slow_path_common(4)
#ifdef CONFIG_CPU_LITTLE_ENDIAN
# if MIPS_ISA_REV >= 2
wsbh t0, $r_s0
jr $r_ra
rotr $r_A, t0, 16
# else
sll t0, $r_s0, 24
srl t1, $r_s0, 24
srl t2, $r_s0, 8
or t0, t0, t1
andi t2, t2, 0xff00
andi t1, $r_s0, 0xff00
or t0, t0, t2
sll t1, t1, 8
jr $r_ra
or $r_A, t0, t1
# endif
#else
jr $r_ra
move $r_A, $r_s0
#endif
END(bpf_slow_path_word)
NESTED(bpf_slow_path_half, (6 * SZREG), $r_sp)
bpf_slow_path_common(2)
#ifdef CONFIG_CPU_LITTLE_ENDIAN
# if MIPS_ISA_REV >= 2
jr $r_ra
wsbh $r_A, $r_s0
# else
sll t0, $r_s0, 8
andi t1, $r_s0, 0xff00
andi t0, t0, 0xff00
srl t1, t1, 8
jr $r_ra
or $r_A, t0, t1
# endif
#else
jr $r_ra
move $r_A, $r_s0
#endif
END(bpf_slow_path_half)
NESTED(bpf_slow_path_byte, (6 * SZREG), $r_sp)
bpf_slow_path_common(1)
jr $r_ra
move $r_A, $r_s0
END(bpf_slow_path_byte)
/*
* Negative entry points
*/
.macro bpf_is_end_of_data
li t0, SKF_LL_OFF
/* Reading link layer data? */
slt t1, offset, t0
bgtz t1, fault
/* Be careful what follows in DS. */
.endm
/*
* call skb_copy_bits:
* (prototype in linux/filter.h)
*
* void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb,
* int k, unsigned int size)
*
* see above (bpf_slow_path_common) for ABI restrictions
*/
#define bpf_negative_common(SIZE) \
PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \
PTR_LA t0, bpf_internal_load_pointer_neg_helper; \
PTR_S $r_ra, (5 * SZREG)($r_sp); \
jalr t0; \
li a2, SIZE; \
PTR_L $r_ra, (5 * SZREG)($r_sp); \
/* Check return pointer */ \
beqz v0, fault; \
PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \
/* Preserve our pointer */ \
move $r_s0, v0; \
/* Set return value */ \
move $r_ret, zero; \
bpf_slow_path_word_neg:
bpf_is_end_of_data
NESTED(sk_load_word_negative, (6 * SZREG), $r_sp)
bpf_negative_common(4)
jr $r_ra
lw $r_A, 0($r_s0)
END(sk_load_word_negative)
bpf_slow_path_half_neg:
bpf_is_end_of_data
NESTED(sk_load_half_negative, (6 * SZREG), $r_sp)
bpf_negative_common(2)
jr $r_ra
lhu $r_A, 0($r_s0)
END(sk_load_half_negative)
bpf_slow_path_byte_neg:
bpf_is_end_of_data
NESTED(sk_load_byte_negative, (6 * SZREG), $r_sp)
bpf_negative_common(1)
jr $r_ra
lbu $r_A, 0($r_s0)
END(sk_load_byte_negative)
fault:
jr $r_ra
addiu $r_ret, zero, 1
......@@ -10,7 +10,7 @@
#include <asm/sn/addrs.h>
#include <asm/sn/types.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/hub.h>
#include <asm/sn/agent.h>
#include <asm/sn/ioc3.h>
#include <asm/pci/bridge.h>
......
......@@ -437,17 +437,28 @@ static int bridge_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
struct irq_alloc_info info;
int irq;
irq = bc->pci_int[slot];
switch (pin) {
case PCI_INTERRUPT_UNKNOWN:
case PCI_INTERRUPT_INTA:
case PCI_INTERRUPT_INTC:
pin = 0;
break;
case PCI_INTERRUPT_INTB:
case PCI_INTERRUPT_INTD:
pin = 1;
}
irq = bc->pci_int[slot][pin];
if (irq == -1) {
info.ctrl = bc;
info.nasid = bc->nasid;
info.pin = slot;
info.pin = bc->int_mapping[slot][pin];
irq = irq_domain_alloc_irqs(bc->domain, 1, bc->nasid, &info);
if (irq < 0)
return irq;
bc->pci_int[slot] = irq;
bc->pci_int[slot][pin] = irq;
}
return irq;
}
......@@ -458,21 +469,26 @@ static void bridge_setup_ip27_baseio6g(struct bridge_controller *bc)
{
bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP27_BASEIO6G);
bc->ioc3_sid[6] = IOC3_SID(IOC3_SUBSYS_IP27_MIO);
bc->int_mapping[2][1] = 4;
bc->int_mapping[6][1] = 6;
}
static void bridge_setup_ip27_baseio(struct bridge_controller *bc)
{
bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP27_BASEIO);
bc->int_mapping[2][1] = 4;
}
static void bridge_setup_ip29_baseio(struct bridge_controller *bc)
{
bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP29_SYSBOARD);
bc->int_mapping[2][1] = 3;
}
static void bridge_setup_ip30_sysboard(struct bridge_controller *bc)
{
bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP30_SYSBOARD);
bc->int_mapping[2][1] = 4;
}
static void bridge_setup_menet(struct bridge_controller *bc)
......@@ -483,6 +499,26 @@ static void bridge_setup_menet(struct bridge_controller *bc)
bc->ioc3_sid[3] = IOC3_SID(IOC3_SUBSYS_MENET4);
}
static void bridge_setup_io7(struct bridge_controller *bc)
{
bc->ioc3_sid[4] = IOC3_SID(IOC3_SUBSYS_IO7);
}
static void bridge_setup_io8(struct bridge_controller *bc)
{
bc->ioc3_sid[4] = IOC3_SID(IOC3_SUBSYS_IO8);
}
static void bridge_setup_io9(struct bridge_controller *bc)
{
bc->ioc3_sid[1] = IOC3_SID(IOC3_SUBSYS_IO9);
}
static void bridge_setup_ip34_fuel_sysboard(struct bridge_controller *bc)
{
bc->ioc3_sid[4] = IOC3_SID(IOC3_SUBSYS_IP34_SYSBOARD);
}
#define BRIDGE_BOARD_SETUP(_partno, _setup) \
{ .match = _partno, .setup = _setup }
......@@ -500,6 +536,10 @@ static const struct {
BRIDGE_BOARD_SETUP("030-0887-", bridge_setup_ip30_sysboard),
BRIDGE_BOARD_SETUP("030-1467-", bridge_setup_ip30_sysboard),
BRIDGE_BOARD_SETUP("030-0873-", bridge_setup_menet),
BRIDGE_BOARD_SETUP("030-1557-", bridge_setup_io7),
BRIDGE_BOARD_SETUP("030-1673-", bridge_setup_io8),
BRIDGE_BOARD_SETUP("030-1771-", bridge_setup_io9),
BRIDGE_BOARD_SETUP("030-1707-", bridge_setup_ip34_fuel_sysboard),
};
static void bridge_setup_board(struct bridge_controller *bc, char *partnum)
......@@ -655,7 +695,11 @@ static int bridge_probe(struct platform_device *pdev)
for (slot = 0; slot < 8; slot++) {
bridge_set(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
bc->pci_int[slot] = -1;
bc->pci_int[slot][0] = -1;
bc->pci_int[slot][1] = -1;
/* default interrupt pin mapping */
bc->int_mapping[slot][0] = slot;
bc->int_mapping[slot][1] = slot ^ 4;
}
bridge_read(bc, b_wid_tflush); /* wait until Bridge PIO complete */
......
......@@ -67,11 +67,13 @@ static int __init ill_acc_of_setup(void)
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
dev_err(&pdev->dev, "failed to get irq\n");
put_device(&pdev->dev);
return -EINVAL;
}
if (request_irq(irq, ill_acc_irq_handler, 0, "ill_acc", &pdev->dev)) {
dev_err(&pdev->dev, "failed to request irq\n");
put_device(&pdev->dev);
return -EINVAL;
}
......
......@@ -47,7 +47,8 @@ static struct device gio_bus = {
* Used by a driver to check whether an of_device present in the
* system is in its list of supported devices.
*/
const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
static const struct gio_device_id *
gio_match_device(const struct gio_device_id *match,
const struct gio_device *dev)
{
const struct gio_device_id *ids;
......@@ -58,7 +59,6 @@ const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
return NULL;
}
EXPORT_SYMBOL_GPL(gio_match_device);
struct gio_device *gio_dev_get(struct gio_device *dev)
{
......
......@@ -16,8 +16,8 @@
#include <asm/ptrace.h>
#include <asm/sn/addrs.h>
#include <asm/sn/agent.h>
#include <asm/sn/arch.h>
#include <asm/sn/sn0/hub.h>
#include <asm/tlbdebug.h>
#include <asm/traps.h>
#include <linux/uaccess.h>
......@@ -30,29 +30,31 @@ static void dump_hub_information(unsigned long errst0, unsigned long errst1)
{ "WERR", "Uncached Partial Write", "PWERR", "Write Timeout",
NULL, NULL, NULL, NULL }
};
int wrb = errst1 & PI_ERR_ST1_WRBRRB_MASK;
union pi_err_stat0 st0;
union pi_err_stat1 st1;
if (!(errst0 & PI_ERR_ST0_VALID_MASK)) {
printk("Hub does not contain valid error information\n");
st0.pi_stat0_word = errst0;
st1.pi_stat1_word = errst1;
if (!st0.pi_stat0_fmt.s0_valid) {
pr_info("Hub does not contain valid error information\n");
return;
}
printk("Hub has valid error information:\n");
if (errst0 & PI_ERR_ST0_OVERRUN_MASK)
printk("Overrun is set. Error stack may contain additional "
pr_info("Hub has valid error information:\n");
if (st0.pi_stat0_fmt.s0_ovr_run)
pr_info("Overrun is set. Error stack may contain additional "
"information.\n");
printk("Hub error address is %08lx\n",
(errst0 & PI_ERR_ST0_ADDR_MASK) >> (PI_ERR_ST0_ADDR_SHFT - 3));
printk("Incoming message command 0x%lx\n",
(errst0 & PI_ERR_ST0_CMD_MASK) >> PI_ERR_ST0_CMD_SHFT);
printk("Supplemental field of incoming message is 0x%lx\n",
(errst0 & PI_ERR_ST0_SUPPL_MASK) >> PI_ERR_ST0_SUPPL_SHFT);
printk("T5 Rn (for RRB only) is 0x%lx\n",
(errst0 & PI_ERR_ST0_REQNUM_MASK) >> PI_ERR_ST0_REQNUM_SHFT);
printk("Error type is %s\n", err_type[wrb]
[(errst0 & PI_ERR_ST0_TYPE_MASK) >> PI_ERR_ST0_TYPE_SHFT]
? : "invalid");
pr_info("Hub error address is %08lx\n",
(unsigned long)st0.pi_stat0_fmt.s0_addr);
pr_info("Incoming message command 0x%lx\n",
(unsigned long)st0.pi_stat0_fmt.s0_cmd);
pr_info("Supplemental field of incoming message is 0x%lx\n",
(unsigned long)st0.pi_stat0_fmt.s0_supl);
pr_info("T5 Rn (for RRB only) is 0x%lx\n",
(unsigned long)st0.pi_stat0_fmt.s0_t5_req);
pr_info("Error type is %s\n", err_type[st1.pi_stat1_fmt.s1_rw_rb]
[st0.pi_stat0_fmt.s0_err_type] ? : "invalid");
}
int ip27_be_handler(struct pt_regs *regs, int is_fixup)
......
......@@ -3,8 +3,18 @@
#ifndef __IP27_COMMON_H
#define __IP27_COMMON_H
extern void ip27_reboot_setup(void);
extern nasid_t master_nasid;
extern void cpu_node_probe(void);
extern void hub_rt_clock_event_init(void);
extern void hub_rtc_init(nasid_t nasid);
extern void install_cpu_nmi_handler(int slice);
extern void install_ipi(void);
extern void ip27_reboot_setup(void);
extern const struct plat_smp_ops ip27_smp_ops;
extern unsigned long node_getfirstfree(nasid_t nasid);
extern void per_cpu_init(void);
extern void replicate_kernel_text(void);
extern void setup_replication_mask(void);
#endif /* __IP27_COMMON_H */
......@@ -9,14 +9,15 @@
#include <asm/page.h>
#include <asm/setup.h>
#include <asm/sn/addrs.h>
#include <asm/sn/sn0/hub.h>
#include <asm/sn/agent.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/ioc3.h>
#include <asm/sn/sn_private.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include "ip27-common.h"
#define IOC3_CLK (22000000 / 3)
#define IOC3_FLAGS (0)
......
......@@ -11,7 +11,9 @@
#include <linux/mmzone.h>
#include <asm/sn/addrs.h>
#include <asm/sn/arch.h>
#include <asm/sn/hub.h>
#include <asm/sn/agent.h>
#include <asm/sn/io.h>
#include <asm/xtalk/xtalk.h>
static int force_fire_and_forget = 1;
......@@ -82,7 +84,7 @@ unsigned long hub_pio_map(nasid_t nasid, xwidgetnum_t widget,
*/
static void hub_setup_prb(nasid_t nasid, int prbnum, int credits)
{
iprb_t prb;
union iprb_u prb;
int prb_offset;
/*
......@@ -135,7 +137,7 @@ static void hub_setup_prb(nasid_t nasid, int prbnum, int credits)
static void hub_set_piomode(nasid_t nasid)
{
u64 ii_iowa;
hubii_wcr_t ii_wcr;
union hubii_wcr_u ii_wcr;
unsigned i;
ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS);
......
......@@ -19,23 +19,18 @@
#include <asm/pgtable.h>
#include <asm/sgialib.h>
#include <asm/time.h>
#include <asm/sn/agent.h>
#include <asm/sn/types.h>
#include <asm/sn/sn0/addrs.h>
#include <asm/sn/sn0/hubni.h>
#include <asm/sn/sn0/hubio.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/ioc3.h>
#include <asm/mipsregs.h>
#include <asm/sn/gda.h>
#include <asm/sn/hub.h>
#include <asm/sn/intr.h>
#include <asm/current.h>
#include <asm/processor.h>
#include <asm/mmu_context.h>
#include <asm/thread_info.h>
#include <asm/sn/launch.h>
#include <asm/sn/sn_private.h>
#include <asm/sn/sn0/ip27.h>
#include <asm/sn/mapped_kernel.h>
#include "ip27-common.h"
......@@ -77,18 +72,14 @@ static void per_hub_init(nasid_t nasid)
void per_cpu_init(void)
{
int cpu = smp_processor_id();
int slice = LOCAL_HUB_L(PI_CPU_NUM);
nasid_t nasid = get_nasid();
struct hub_data *hub = hub_data(nasid);
if (test_and_set_bit(slice, &hub->slice_map))
return;
clear_c0_status(ST0_IM);
per_hub_init(nasid);
cpu_time_init();
pr_info("CPU %d clock is %dMHz.\n", cpu, sn_cpu_info[cpu].p_speed);
install_ipi();
/* Install our NMI handler if symmon hasn't installed one. */
......@@ -98,16 +89,6 @@ void per_cpu_init(void)
enable_percpu_irq(IP27_HUB_PEND1_IRQ, IRQ_TYPE_NONE);
}
/*
* get_nasid() returns the physical node id number of the caller.
*/
nasid_t
get_nasid(void)
{
return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK)
>> NSRI_NODEID_SHFT);
}
void __init plat_mem_setup(void)
{
u64 p, e, n_mode;
......
......@@ -19,7 +19,6 @@
#include <asm/sn/addrs.h>
#include <asm/sn/agent.h>
#include <asm/sn/arch.h>
#include <asm/sn/hub.h>
#include <asm/sn/intr.h>
#include <asm/sn/irq_alloc.h>
......@@ -288,11 +287,9 @@ void __init arch_init_irq(void)
* Mark these as reserved right away so they won't be used accidentally
* later.
*/
for (i = 0; i <= BASE_PCI_IRQ; i++)
for (i = 0; i <= CPU_CALL_B_IRQ; i++)
set_bit(i, hub_irq_map);
set_bit(IP_PEND0_6_63, hub_irq_map);
for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++)
set_bit(i, hub_irq_map);
......
......@@ -72,54 +72,3 @@ lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_type)
/* Didn't find it. */
return (lboard_t *)NULL;
}
klcpu_t *nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
{
lboard_t *brd;
klcpu_t *acpu;
if (!(brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27)))
return (klcpu_t *)NULL;
if (!(acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU)))
return (klcpu_t *)NULL;
do {
if ((acpu->cpu_info.physid) == slice)
return acpu;
} while ((acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu,
KLSTRUCT_CPU)));
return (klcpu_t *)NULL;
}
klcpu_t *sn_get_cpuinfo(cpuid_t cpu)
{
nasid_t nasid;
int slice;
klcpu_t *acpu;
if (!(cpu < MAXCPUS)) {
printk("sn_get_cpuinfo: illegal cpuid 0x%lx\n", cpu);
return NULL;
}
nasid = cputonasid(cpu);
if (nasid == INVALID_NASID)
return NULL;
for (slice = 0; slice < CPUS_PER_NODE; slice++) {
acpu = nasid_slice_to_cpuinfo(nasid, slice);
if (acpu && acpu->cpu_info.virtid == cpu)
return acpu;
}
return NULL;
}
int get_cpu_slice(cpuid_t cpu)
{
klcpu_t *acpu;
if ((acpu = sn_get_cpuinfo(cpu)) == NULL)
return -1;
return acpu->cpu_info.physid;
}
......@@ -16,11 +16,11 @@
#include <asm/sn/types.h>
#include <asm/sn/arch.h>
#include <asm/sn/gda.h>
#include <asm/sn/hub.h>
#include <asm/sn/mapped_kernel.h>
#include <asm/sn/sn_private.h>
static cpumask_t ktext_repmask;
#include "ip27-common.h"
static nodemask_t ktext_repmask;
/*
* XXX - This needs to be much smarter about where it puts copies of the
......@@ -30,8 +30,8 @@ static cpumask_t ktext_repmask;
void __init setup_replication_mask(void)
{
/* Set only the master cnode's bit. The master cnode is always 0. */
cpumask_clear(&ktext_repmask);
cpumask_set_cpu(0, &ktext_repmask);
nodes_clear(ktext_repmask);
node_set(0, ktext_repmask);
#ifdef CONFIG_REPLICATE_KTEXT
#ifndef CONFIG_MAPPED_KERNEL
......@@ -44,7 +44,7 @@ void __init setup_replication_mask(void)
if (nasid == 0)
continue;
/* Advertise that we have a copy of the kernel */
cpumask_set_cpu(nasid, &ktext_repmask);
node_set(nasid, ktext_repmask);
}
}
#endif
......@@ -98,7 +98,7 @@ void __init replicate_kernel_text(void)
continue;
/* Check if this node should get a copy of the kernel */
if (cpumask_test_cpu(client_nasid, &ktext_repmask)) {
if (node_isset(client_nasid, ktext_repmask)) {
server_nasid = client_nasid;
copy_kernel(server_nasid);
}
......@@ -122,7 +122,7 @@ unsigned long node_getfirstfree(nasid_t nasid)
loadbase += 16777216;
#endif
offset = PAGE_ALIGN((unsigned long)(&_end)) - loadbase;
if ((nasid == 0) || (cpumask_test_cpu(nasid, &ktext_repmask)))
if ((nasid == 0) || (node_isset(nasid, ktext_repmask)))
return TO_NODE(nasid, offset) >> PAGE_SHIFT;
else
return KDM_TO_PHYS(PAGE_ALIGN(SYMMON_STK_ADDR(nasid, 0))) >> PAGE_SHIFT;
......
......@@ -25,10 +25,10 @@
#include <asm/sections.h>
#include <asm/sn/arch.h>
#include <asm/sn/hub.h>
#include <asm/sn/agent.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/sn_private.h>
#include "ip27-common.h"
#define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT)
#define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT)
......@@ -37,31 +37,18 @@ struct node_data *__node_data[MAX_NUMNODES];
EXPORT_SYMBOL(__node_data);
static int fine_mode;
static int is_fine_dirmode(void)
{
return ((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE;
}
static u64 get_region(nasid_t nasid)
{
if (fine_mode)
return nasid >> NASID_TO_FINEREG_SHFT;
else
return nasid >> NASID_TO_COARSEREG_SHFT;
}
static u64 region_mask;
static void gen_region_mask(u64 *region_mask)
static u64 gen_region_mask(void)
{
int region_shift;
u64 region_mask;
nasid_t nasid;
(*region_mask) = 0;
for_each_online_node(nasid) {
(*region_mask) |= 1ULL << get_region(nasid);
}
region_shift = get_region_shift();
region_mask = 0;
for_each_online_node(nasid)
region_mask |= BIT_ULL(nasid >> region_shift);
return region_mask;
}
#define rou_rflag rou_flags
......@@ -148,25 +135,25 @@ static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
} while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
}
if (nasid_a == nasid_b)
return LOCAL_DISTANCE;
if (router_a == router_b)
return LOCAL_DISTANCE + 1;
if (router_a == NULL) {
pr_info("node_distance: router_a NULL\n");
return -1;
return 255;
}
if (router_b == NULL) {
pr_info("node_distance: router_b NULL\n");
return -1;
return 255;
}
if (nasid_a == nasid_b)
return 0;
if (router_a == router_b)
return 1;
router_distance = 100;
router_recurse(router_a, router_b, 2);
return router_distance;
return LOCAL_DISTANCE + router_distance;
}
static void __init init_topology_matrix(void)
......@@ -281,10 +268,10 @@ static unsigned long __init slot_psize_compute(nasid_t nasid, int slot)
static void __init mlreset(void)
{
u64 region_mask;
nasid_t nasid;
master_nasid = get_nasid();
fine_mode = is_fine_dirmode();
/*
* Probe for all CPUs - this creates the cpumask and sets up the
......@@ -297,7 +284,7 @@ static void __init mlreset(void)
init_topology_matrix();
dump_topology();
gen_region_mask(&region_mask);
region_mask = gen_region_mask();
setup_replication_mask();
......
......@@ -9,7 +9,7 @@
#include <asm/sn/addrs.h>
#include <asm/sn/nmi.h>
#include <asm/sn/arch.h>
#include <asm/sn/sn0/hub.h>
#include <asm/sn/agent.h>
#if 0
#define NODE_NUM_CPUS(n) CNODE_NUM_CPUS(n)
......@@ -17,6 +17,9 @@
#define NODE_NUM_CPUS(n) CPUS_PER_NODE
#endif
#define SEND_NMI(_nasid, _slice) \
REMOTE_HUB_S((_nasid), (PI_NMI_A + ((_slice) * PI_NMI_OFFSET)), 1)
typedef unsigned long machreg_t;
static arch_spinlock_t nmi_lock = __ARCH_SPIN_LOCK_UNLOCKED;
......
......@@ -22,9 +22,9 @@
#include <asm/reboot.h>
#include <asm/sgialib.h>
#include <asm/sn/addrs.h>
#include <asm/sn/agent.h>
#include <asm/sn/arch.h>
#include <asm/sn/gda.h>
#include <asm/sn/sn0/hub.h>
#include "ip27-common.h"
......
......@@ -15,36 +15,22 @@
#include <asm/page.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/sn/agent.h>
#include <asm/sn/arch.h>
#include <asm/sn/gda.h>
#include <asm/sn/intr.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/launch.h>
#include <asm/sn/mapped_kernel.h>
#include <asm/sn/sn_private.h>
#include <asm/sn/types.h>
#include <asm/sn/sn0/hubpi.h>
#include <asm/sn/sn0/hubio.h>
#include <asm/sn/sn0/ip27.h>
#include "ip27-common.h"
/*
* Takes as first input the PROM assigned cpu id, and the kernel
* assigned cpu id as the second.
*/
static void alloc_cpupda(nasid_t nasid, cpuid_t cpu, int cpunum)
{
cputonasid(cpunum) = nasid;
cputoslice(cpunum) = get_cpu_slice(cpu);
}
static int do_cpumask(nasid_t nasid, int highest)
static int node_scan_cpus(nasid_t nasid, int highest)
{
static int tot_cpus_found = 0;
static int cpus_found;
lboard_t *brd;
klcpu_t *acpu;
int cpus_found = 0;
cpuid_t cpuid;
brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
......@@ -55,13 +41,15 @@ static int do_cpumask(nasid_t nasid, int highest)
cpuid = acpu->cpu_info.virtid;
/* Only let it join in if it's marked enabled */
if ((acpu->cpu_info.flags & KLINFO_ENABLE) &&
(tot_cpus_found != NR_CPUS)) {
(cpus_found != NR_CPUS)) {
if (cpuid > highest)
highest = cpuid;
set_cpu_possible(cpuid, true);
alloc_cpupda(nasid, cpuid, tot_cpus_found);
cputonasid(cpus_found) = nasid;
cputoslice(cpus_found) = acpu->cpu_info.physid;
sn_cpu_info[cpus_found].p_speed =
acpu->cpu_speed;
cpus_found++;
tot_cpus_found++;
}
acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu,
KLSTRUCT_CPU);
......@@ -87,7 +75,7 @@ void cpu_node_probe(void)
if (nasid == INVALID_NASID)
break;
node_set_online(nasid);
highest = do_cpumask(nasid, highest);
highest = node_scan_cpus(nasid, highest);
}
printk("Discovered %d cpus on %d nodes\n", highest + 1, num_online_nodes());
......@@ -180,7 +168,8 @@ static void __init ip27_smp_setup(void)
/*
* PROM sets up system, that boot cpu is always first CPU on nasid 0
*/
alloc_cpupda(0, 0, 0);
cputonasid(0) = 0;
cputoslice(0) = LOCAL_HUB_L(PI_CPU_NUM);
}
static void __init ip27_prepare_cpus(unsigned int max_cpus)
......
......@@ -25,17 +25,14 @@
#include <asm/sn/klconfig.h>
#include <asm/sn/arch.h>
#include <asm/sn/addrs.h>
#include <asm/sn/sn_private.h>
#include <asm/sn/sn0/ip27.h>
#include <asm/sn/sn0/hub.h>
#include <asm/sn/agent.h>
#include "ip27-common.h"
#define TICK_SIZE (tick_nsec / 1000)
/* Includes for ioc3_init(). */
#include <asm/sn/types.h>
#include <asm/sn/sn0/addrs.h>
#include <asm/sn/sn0/hubni.h>
#include <asm/sn/sn0/hubio.h>
#include <asm/pci/bridge.h>
#include "ip27-common.h"
......@@ -153,25 +150,6 @@ void __init plat_time_init(void)
hub_rt_clock_event_init();
}
void cpu_time_init(void)
{
lboard_t *board;
klcpu_t *cpu;
int cpuid;
/* Don't use ARCS. ARCS is fragile. Klconfig is simple and sane. */
board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27);
if (!board)
panic("Can't find board info for myself.");
cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX;
cpu = (klcpu_t *) KLCF_COMP(board, cpuid);
if (!cpu)
panic("No information about myself?");
printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
}
void hub_rtc_init(nasid_t nasid)
{
......@@ -190,23 +168,3 @@ void hub_rtc_init(nasid_t nasid)
LOCAL_HUB_S(PI_RT_PEND_B, 0);
}
}
static int __init sgi_ip27_rtc_devinit(void)
{
struct resource res;
memset(&res, 0, sizeof(res));
res.start = XPHYSADDR(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base +
IOC3_BYTEBUS_DEV0);
res.end = res.start + 32767;
res.flags = IORESOURCE_MEM;
return IS_ERR(platform_device_register_simple("rtc-m48t35", -1,
&res, 1));
}
/*
* kludge make this a device_initcall after ioc3 resource conflicts
* are resolved
*/
late_initcall(sgi_ip27_rtc_devinit);
......@@ -15,7 +15,6 @@
#include <asm/sn/addrs.h>
#include <asm/sn/types.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/hub.h>
#include <asm/pci/bridge.h>
#include <asm/xtalk/xtalk.h>
......
......@@ -232,9 +232,10 @@ static void heart_domain_free(struct irq_domain *domain,
return;
irqd = irq_domain_get_irq_data(domain, virq);
if (irqd) {
clear_bit(irqd->hwirq, heart_irq_map);
if (irqd && irqd->chip_data)
kfree(irqd->chip_data);
}
}
static const struct irq_domain_ops heart_domain_ops = {
......
......@@ -251,6 +251,18 @@ int main(int argc, char **argv)
fprintf(out_file, "#include <linux/linkage.h>\n");
fprintf(out_file, "#include <linux/mm.h>\n");
fprintf(out_file, "#include <asm/vdso.h>\n");
fprintf(out_file, "static int vdso_mremap(\n");
fprintf(out_file, " const struct vm_special_mapping *sm,\n");
fprintf(out_file, " struct vm_area_struct *new_vma)\n");
fprintf(out_file, "{\n");
fprintf(out_file, " unsigned long new_size =\n");
fprintf(out_file, " new_vma->vm_end - new_vma->vm_start;\n");
fprintf(out_file, " if (vdso_image.size != new_size)\n");
fprintf(out_file, " return -EINVAL;\n");
fprintf(out_file, " current->mm->context.vdso =\n");
fprintf(out_file, " (void __user *)(new_vma->vm_start);\n");
fprintf(out_file, " return 0;\n");
fprintf(out_file, "}\n");
/* Write out the stripped VDSO data. */
fprintf(out_file,
......@@ -275,6 +287,7 @@ int main(int argc, char **argv)
fprintf(out_file, "\t.mapping = {\n");
fprintf(out_file, "\t\t.name = \"[vdso]\",\n");
fprintf(out_file, "\t\t.pages = vdso_pages,\n");
fprintf(out_file, "\t\t.mremap = vdso_mremap,\n");
fprintf(out_file, "\t},\n");
/* Calculate and write symbol offsets to <output file> */
......
......@@ -2004,5 +2004,18 @@ config RAVE_SP_CORE
Select this to get support for the Supervisory Processor
device found on several devices in RAVE line of hardware.
config SGI_MFD_IOC3
tristate "SGI IOC3 core driver"
depends on PCI && MIPS && 64BIT
select MFD_CORE
help
This option enables basic support for the SGI IOC3-based
controller cards. This option does not enable any specific
functions on such a card, but provides necessary infrastructure
for other drivers to utilize.
If you have an SGI Origin, Octane, or a PCI IOC3 card,
then say Y. Otherwise say N.
endmenu
endif
......@@ -255,3 +255,4 @@ obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
// SPDX-License-Identifier: GPL-2.0
/*
* SGI IOC3 multifunction device driver
*
* Copyright (C) 2018, 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
*
* Based on work by:
* Stanislaw Skowronek <skylark@unaligned.org>
* Joshua Kinard <kumba@gentoo.org>
* Brent Casavant <bcasavan@sgi.com> - IOC4 master driver
* Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer
*/
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/platform_data/sgi-w1.h>
#include <linux/rtc/ds1685.h>
#include <asm/pci/bridge.h>
#include <asm/sn/ioc3.h>
#define IOC3_IRQ_SERIAL_A 6
#define IOC3_IRQ_SERIAL_B 15
#define IOC3_IRQ_KBD 22
/* Bitmask for selecting which IRQs are level triggered */
#define IOC3_LVL_MASK (BIT(IOC3_IRQ_SERIAL_A) | BIT(IOC3_IRQ_SERIAL_B))
#define M48T35_REG_SIZE 32768 /* size of m48t35 registers */
/* 1.2 us latency timer (40 cycles at 33 MHz) */
#define IOC3_LATENCY 40
struct ioc3_priv_data {
struct irq_domain *domain;
struct ioc3 __iomem *regs;
struct pci_dev *pdev;
int domain_irq;
};
static void ioc3_irq_ack(struct irq_data *d)
{
struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
unsigned int hwirq = irqd_to_hwirq(d);
writel(BIT(hwirq), &ipd->regs->sio_ir);
}
static void ioc3_irq_mask(struct irq_data *d)
{
struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
unsigned int hwirq = irqd_to_hwirq(d);
writel(BIT(hwirq), &ipd->regs->sio_iec);
}
static void ioc3_irq_unmask(struct irq_data *d)
{
struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
unsigned int hwirq = irqd_to_hwirq(d);
writel(BIT(hwirq), &ipd->regs->sio_ies);
}
static struct irq_chip ioc3_irq_chip = {
.name = "IOC3",
.irq_ack = ioc3_irq_ack,
.irq_mask = ioc3_irq_mask,
.irq_unmask = ioc3_irq_unmask,
};
static int ioc3_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq)
{
/* Set level IRQs for every interrupt contained in IOC3_LVL_MASK */
if (BIT(hwirq) & IOC3_LVL_MASK)
irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_level_irq);
else
irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_edge_irq);
irq_set_chip_data(irq, d->host_data);
return 0;
}
static void ioc3_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
{
irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(irq, NULL);
}
static const struct irq_domain_ops ioc3_irq_domain_ops = {
.map = ioc3_irq_domain_map,
.unmap = ioc3_irq_domain_unmap,
};
static void ioc3_irq_handler(struct irq_desc *desc)
{
struct irq_domain *domain = irq_desc_get_handler_data(desc);
struct ioc3_priv_data *ipd = domain->host_data;
struct ioc3 __iomem *regs = ipd->regs;
u32 pending, mask;
unsigned int irq;
pending = readl(&regs->sio_ir);
mask = readl(&regs->sio_ies);
pending &= mask; /* Mask off not enabled interrupts */
if (pending) {
irq = irq_find_mapping(domain, __ffs(pending));
if (irq)
generic_handle_irq(irq);
} else {
spurious_interrupt();
}
}
/*
* System boards/BaseIOs use more interrupt pins of the bridge ASIC
* to which the IOC3 is connected. Since the IOC3 MFD driver
* knows wiring of these extra pins, we use the map_irq function
* to get interrupts activated
*/
static int ioc3_map_irq(struct pci_dev *pdev, int slot, int pin)
{
struct pci_host_bridge *hbrg = pci_find_host_bridge(pdev->bus);
return hbrg->map_irq(pdev, slot, pin);
}
static int ioc3_irq_domain_setup(struct ioc3_priv_data *ipd, int irq)
{
struct irq_domain *domain;
struct fwnode_handle *fn;
fn = irq_domain_alloc_named_fwnode("IOC3");
if (!fn)
goto err;
domain = irq_domain_create_linear(fn, 24, &ioc3_irq_domain_ops, ipd);
if (!domain)
goto err;
irq_domain_free_fwnode(fn);
ipd->domain = domain;
irq_set_chained_handler_and_data(irq, ioc3_irq_handler, domain);
ipd->domain_irq = irq;
return 0;
err:
dev_err(&ipd->pdev->dev, "irq domain setup failed\n");
return -ENOMEM;
}
static struct resource ioc3_uarta_resources[] = {
DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uarta),
sizeof_field(struct ioc3, sregs.uarta)),
DEFINE_RES_IRQ(IOC3_IRQ_SERIAL_A)
};
static struct resource ioc3_uartb_resources[] = {
DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uartb),
sizeof_field(struct ioc3, sregs.uartb)),
DEFINE_RES_IRQ(IOC3_IRQ_SERIAL_B)
};
static struct mfd_cell ioc3_serial_cells[] = {
{
.name = "ioc3-serial8250",
.resources = ioc3_uarta_resources,
.num_resources = ARRAY_SIZE(ioc3_uarta_resources),
},
{
.name = "ioc3-serial8250",
.resources = ioc3_uartb_resources,
.num_resources = ARRAY_SIZE(ioc3_uartb_resources),
}
};
static int ioc3_serial_setup(struct ioc3_priv_data *ipd)
{
int ret;
/* Set gpio pins for RS232/RS422 mode selection */
writel(GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL,
&ipd->regs->gpcr_s);
/* Select RS232 mode for uart a */
writel(0, &ipd->regs->gppr[6]);
/* Select RS232 mode for uart b */
writel(0, &ipd->regs->gppr[7]);
/* Switch both ports to 16650 mode */
writel(readl(&ipd->regs->port_a.sscr) & ~SSCR_DMA_EN,
&ipd->regs->port_a.sscr);
writel(readl(&ipd->regs->port_b.sscr) & ~SSCR_DMA_EN,
&ipd->regs->port_b.sscr);
udelay(1000); /* Wait until mode switch is done */
ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO,
ioc3_serial_cells, ARRAY_SIZE(ioc3_serial_cells),
&ipd->pdev->resource[0], 0, ipd->domain);
if (ret) {
dev_err(&ipd->pdev->dev, "Failed to add 16550 subdevs\n");
return ret;
}
return 0;
}
static struct resource ioc3_kbd_resources[] = {
DEFINE_RES_MEM(offsetof(struct ioc3, serio),
sizeof_field(struct ioc3, serio)),
DEFINE_RES_IRQ(IOC3_IRQ_KBD)
};
static struct mfd_cell ioc3_kbd_cells[] = {
{
.name = "ioc3-kbd",
.resources = ioc3_kbd_resources,
.num_resources = ARRAY_SIZE(ioc3_kbd_resources),
}
};
static int ioc3_kbd_setup(struct ioc3_priv_data *ipd)
{
int ret;
ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO,
ioc3_kbd_cells, ARRAY_SIZE(ioc3_kbd_cells),
&ipd->pdev->resource[0], 0, ipd->domain);
if (ret) {
dev_err(&ipd->pdev->dev, "Failed to add 16550 subdevs\n");
return ret;
}
return 0;
}
static struct resource ioc3_eth_resources[] = {
DEFINE_RES_MEM(offsetof(struct ioc3, eth),
sizeof_field(struct ioc3, eth)),
DEFINE_RES_MEM(offsetof(struct ioc3, ssram),
sizeof_field(struct ioc3, ssram)),
DEFINE_RES_IRQ(0)
};
static struct resource ioc3_w1_resources[] = {
DEFINE_RES_MEM(offsetof(struct ioc3, mcr),
sizeof_field(struct ioc3, mcr)),
};
static struct sgi_w1_platform_data ioc3_w1_platform_data;
static struct mfd_cell ioc3_eth_cells[] = {
{
.name = "ioc3-eth",
.resources = ioc3_eth_resources,
.num_resources = ARRAY_SIZE(ioc3_eth_resources),
},
{
.name = "sgi_w1",
.resources = ioc3_w1_resources,
.num_resources = ARRAY_SIZE(ioc3_w1_resources),
.platform_data = &ioc3_w1_platform_data,
.pdata_size = sizeof(ioc3_w1_platform_data),
}
};
static int ioc3_eth_setup(struct ioc3_priv_data *ipd)
{
int ret;
/* Enable One-Wire bus */
writel(GPCR_MLAN_EN, &ipd->regs->gpcr_s);
/* Generate unique identifier */
snprintf(ioc3_w1_platform_data.dev_id,
sizeof(ioc3_w1_platform_data.dev_id), "ioc3-%012llx",
ipd->pdev->resource->start);
ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO,
ioc3_eth_cells, ARRAY_SIZE(ioc3_eth_cells),
&ipd->pdev->resource[0], ipd->pdev->irq, NULL);
if (ret) {
dev_err(&ipd->pdev->dev, "Failed to add ETH/W1 subdev\n");
return ret;
}
return 0;
}
static struct resource ioc3_m48t35_resources[] = {
DEFINE_RES_MEM(IOC3_BYTEBUS_DEV0, M48T35_REG_SIZE)
};
static struct mfd_cell ioc3_m48t35_cells[] = {
{
.name = "rtc-m48t35",
.resources = ioc3_m48t35_resources,
.num_resources = ARRAY_SIZE(ioc3_m48t35_resources),
}
};
static int ioc3_m48t35_setup(struct ioc3_priv_data *ipd)
{
int ret;
ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO,
ioc3_m48t35_cells, ARRAY_SIZE(ioc3_m48t35_cells),
&ipd->pdev->resource[0], 0, ipd->domain);
if (ret)
dev_err(&ipd->pdev->dev, "Failed to add M48T35 subdev\n");
return ret;
}
static struct ds1685_rtc_platform_data ip30_rtc_platform_data = {
.bcd_mode = false,
.no_irq = false,
.uie_unsupported = true,
.access_type = ds1685_reg_indirect,
};
static struct resource ioc3_rtc_ds1685_resources[] = {
DEFINE_RES_MEM(IOC3_BYTEBUS_DEV1, 1),
DEFINE_RES_MEM(IOC3_BYTEBUS_DEV2, 1),
DEFINE_RES_IRQ(0)
};
static struct mfd_cell ioc3_ds1685_cells[] = {
{
.name = "rtc-ds1685",
.resources = ioc3_rtc_ds1685_resources,
.num_resources = ARRAY_SIZE(ioc3_rtc_ds1685_resources),
.platform_data = &ip30_rtc_platform_data,
.pdata_size = sizeof(ip30_rtc_platform_data),
.id = PLATFORM_DEVID_NONE,
}
};
static int ioc3_ds1685_setup(struct ioc3_priv_data *ipd)
{
int ret, irq;
irq = ioc3_map_irq(ipd->pdev, 6, 0);
ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_ds1685_cells,
ARRAY_SIZE(ioc3_ds1685_cells),
&ipd->pdev->resource[0], irq, NULL);
if (ret)
dev_err(&ipd->pdev->dev, "Failed to add DS1685 subdev\n");
return ret;
};
static struct resource ioc3_leds_resources[] = {
DEFINE_RES_MEM(offsetof(struct ioc3, gppr[0]),
sizeof_field(struct ioc3, gppr[0])),
DEFINE_RES_MEM(offsetof(struct ioc3, gppr[1]),
sizeof_field(struct ioc3, gppr[1])),
};
static struct mfd_cell ioc3_led_cells[] = {
{
.name = "ip30-leds",
.resources = ioc3_leds_resources,
.num_resources = ARRAY_SIZE(ioc3_leds_resources),
.id = PLATFORM_DEVID_NONE,
}
};
static int ioc3_led_setup(struct ioc3_priv_data *ipd)
{
int ret;
ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_led_cells,
ARRAY_SIZE(ioc3_led_cells),
&ipd->pdev->resource[0], 0, ipd->domain);
if (ret)
dev_err(&ipd->pdev->dev, "Failed to add LED subdev\n");
return ret;
}
static int ip27_baseio_setup(struct ioc3_priv_data *ipd)
{
int ret, io_irq;
io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
PCI_INTERRUPT_INTB);
ret = ioc3_irq_domain_setup(ipd, io_irq);
if (ret)
return ret;
ret = ioc3_eth_setup(ipd);
if (ret)
return ret;
ret = ioc3_serial_setup(ipd);
if (ret)
return ret;
return ioc3_m48t35_setup(ipd);
}
static int ip27_baseio6g_setup(struct ioc3_priv_data *ipd)
{
int ret, io_irq;
io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
PCI_INTERRUPT_INTB);
ret = ioc3_irq_domain_setup(ipd, io_irq);
if (ret)
return ret;
ret = ioc3_eth_setup(ipd);
if (ret)
return ret;
ret = ioc3_serial_setup(ipd);
if (ret)
return ret;
ret = ioc3_m48t35_setup(ipd);
if (ret)
return ret;
return ioc3_kbd_setup(ipd);
}
static int ip27_mio_setup(struct ioc3_priv_data *ipd)
{
int ret;
ret = ioc3_irq_domain_setup(ipd, ipd->pdev->irq);
if (ret)
return ret;
ret = ioc3_serial_setup(ipd);
if (ret)
return ret;
return ioc3_kbd_setup(ipd);
}
static int ip30_sysboard_setup(struct ioc3_priv_data *ipd)
{
int ret, io_irq;
io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
PCI_INTERRUPT_INTB);
ret = ioc3_irq_domain_setup(ipd, io_irq);
if (ret)
return ret;
ret = ioc3_eth_setup(ipd);
if (ret)
return ret;
ret = ioc3_serial_setup(ipd);
if (ret)
return ret;
ret = ioc3_kbd_setup(ipd);
if (ret)
return ret;
ret = ioc3_ds1685_setup(ipd);
if (ret)
return ret;
return ioc3_led_setup(ipd);
}
static int ioc3_menet_setup(struct ioc3_priv_data *ipd)
{
int ret, io_irq;
io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
PCI_INTERRUPT_INTB);
ret = ioc3_irq_domain_setup(ipd, io_irq);
if (ret)
return ret;
ret = ioc3_eth_setup(ipd);
if (ret)
return ret;
return ioc3_serial_setup(ipd);
}
static int ioc3_menet4_setup(struct ioc3_priv_data *ipd)
{
return ioc3_eth_setup(ipd);
}
static int ioc3_cad_duo_setup(struct ioc3_priv_data *ipd)
{
int ret, io_irq;
io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
PCI_INTERRUPT_INTB);
ret = ioc3_irq_domain_setup(ipd, io_irq);
if (ret)
return ret;
ret = ioc3_eth_setup(ipd);
if (ret)
return ret;
return ioc3_kbd_setup(ipd);
}
/* Helper macro for filling ioc3_info array */
#define IOC3_SID(_name, _sid, _setup) \
{ \
.name = _name, \
.sid = PCI_VENDOR_ID_SGI | (IOC3_SUBSYS_ ## _sid << 16), \
.setup = _setup, \
}
static struct {
const char *name;
u32 sid;
int (*setup)(struct ioc3_priv_data *ipd);
} ioc3_infos[] = {
IOC3_SID("IP27 BaseIO6G", IP27_BASEIO6G, &ip27_baseio6g_setup),
IOC3_SID("IP27 MIO", IP27_MIO, &ip27_mio_setup),
IOC3_SID("IP27 BaseIO", IP27_BASEIO, &ip27_baseio_setup),
IOC3_SID("IP29 System Board", IP29_SYSBOARD, &ip27_baseio6g_setup),
IOC3_SID("IP30 System Board", IP30_SYSBOARD, &ip30_sysboard_setup),
IOC3_SID("MENET", MENET, &ioc3_menet_setup),
IOC3_SID("MENET4", MENET4, &ioc3_menet4_setup)
};
#undef IOC3_SID
static int ioc3_setup(struct ioc3_priv_data *ipd)
{
u32 sid;
int i;
/* Clear IRQs */
writel(~0, &ipd->regs->sio_iec);
writel(~0, &ipd->regs->sio_ir);
writel(0, &ipd->regs->eth.eier);
writel(~0, &ipd->regs->eth.eisr);
/* Read subsystem vendor id and subsystem id */
pci_read_config_dword(ipd->pdev, PCI_SUBSYSTEM_VENDOR_ID, &sid);
for (i = 0; i < ARRAY_SIZE(ioc3_infos); i++)
if (sid == ioc3_infos[i].sid) {
pr_info("ioc3: %s\n", ioc3_infos[i].name);
return ioc3_infos[i].setup(ipd);
}
/* Treat everything not identified by PCI subid as CAD DUO */
pr_info("ioc3: CAD DUO\n");
return ioc3_cad_duo_setup(ipd);
}
static int ioc3_mfd_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
struct ioc3_priv_data *ipd;
struct ioc3 __iomem *regs;
int ret;
ret = pci_enable_device(pdev);
if (ret)
return ret;
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, IOC3_LATENCY);
pci_set_master(pdev);
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (ret) {
pr_err("%s: No usable DMA configuration, aborting.\n",
pci_name(pdev));
goto out_disable_device;
}
/* Set up per-IOC3 data */
ipd = devm_kzalloc(&pdev->dev, sizeof(struct ioc3_priv_data),
GFP_KERNEL);
if (!ipd) {
ret = -ENOMEM;
goto out_disable_device;
}
ipd->pdev = pdev;
/*
* Map all IOC3 registers. These are shared between subdevices
* so the main IOC3 module manages them.
*/
regs = pci_ioremap_bar(pdev, 0);
if (!regs) {
dev_warn(&pdev->dev, "ioc3: Unable to remap PCI BAR for %s.\n",
pci_name(pdev));
ret = -ENOMEM;
goto out_disable_device;
}
ipd->regs = regs;
/* Track PCI-device specific data */
pci_set_drvdata(pdev, ipd);
ret = ioc3_setup(ipd);
if (ret) {
/* Remove all already added MFD devices */
mfd_remove_devices(&ipd->pdev->dev);
if (ipd->domain) {
irq_domain_remove(ipd->domain);
free_irq(ipd->domain_irq, (void *)ipd);
}
pci_iounmap(pdev, regs);
goto out_disable_device;
}
return 0;
out_disable_device:
pci_disable_device(pdev);
return ret;
}
static void ioc3_mfd_remove(struct pci_dev *pdev)
{
struct ioc3_priv_data *ipd;
ipd = pci_get_drvdata(pdev);
/* Clear and disable all IRQs */
writel(~0, &ipd->regs->sio_iec);
writel(~0, &ipd->regs->sio_ir);
/* Release resources */
mfd_remove_devices(&ipd->pdev->dev);
if (ipd->domain) {
irq_domain_remove(ipd->domain);
free_irq(ipd->domain_irq, (void *)ipd);
}
pci_iounmap(pdev, ipd->regs);
pci_disable_device(pdev);
}
static struct pci_device_id ioc3_mfd_id_table[] = {
{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, ioc3_mfd_id_table);
static struct pci_driver ioc3_mfd_driver = {
.name = "IOC3",
.id_table = ioc3_mfd_id_table,
.probe = ioc3_mfd_probe,
.remove = ioc3_mfd_remove,
};
module_pci_driver(ioc3_mfd_driver);
MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
MODULE_DESCRIPTION("SGI IOC3 MFD driver");
MODULE_LICENSE("GPL v2");
......@@ -6,7 +6,7 @@
config NET_VENDOR_SGI
bool "SGI devices"
default y
depends on (PCI && SGI_IP27) || SGI_IP32
depends on (PCI && SGI_MFD_IOC3) || SGI_IP32
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
......@@ -19,7 +19,8 @@ if NET_VENDOR_SGI
config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
depends on PCI && SGI_IP27
depends on PCI && SGI_MFD_IOC3
select CRC16
select CRC32
select MII
---help---
......
......@@ -14,7 +14,6 @@
* o Use prefetching for large packets. What is a good lower limit for
* prefetching?
* o Use hardware checksums.
* o Convert to using a IOC3 meta driver.
* o Which PHYs might possibly be attached to the IOC3 in real live,
* which workarounds are required for them? Do we ever have Lucent's?
* o For the 2.5 branch kill the mii-tool ioctls.
......@@ -28,7 +27,8 @@
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/crc16.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/in.h>
......@@ -37,28 +37,22 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/gfp.h>
#ifdef CONFIG_SERIAL_8250
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
#endif
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/nvmem-consumer.h>
#include <net/ip.h>
#include <asm/byteorder.h>
#include <asm/pgtable.h>
#include <linux/uaccess.h>
#include <asm/sn/types.h>
#include <asm/sn/ioc3.h>
#include <asm/pci/bridge.h>
#define CRC16_INIT 0
#define CRC16_VALID 0xb001
/* Number of RX buffers. This is tunable in the range of 16 <= x < 512.
* The value must be a power of two.
*/
......@@ -85,7 +79,6 @@
/* Private per NIC data of the driver. */
struct ioc3_private {
struct ioc3_ethregs *regs;
struct ioc3 *all_regs;
struct device *dma_dev;
u32 *ssram;
unsigned long *rxr; /* pointer to receiver ring */
......@@ -104,9 +97,6 @@ struct ioc3_private {
spinlock_t ioc3_lock;
struct mii_if_info mii;
struct net_device *dev;
struct pci_dev *pdev;
/* Members used by autonegotiation */
struct timer_list ioc3_timer;
};
......@@ -123,10 +113,8 @@ static int ioc3_alloc_rx_bufs(struct net_device *dev);
static void ioc3_free_rx_bufs(struct ioc3_private *ip);
static inline void ioc3_clean_tx_ring(struct ioc3_private *ip);
static const char ioc3_str[] = "IOC3 Ethernet";
static const struct ethtool_ops ioc3_ethtool_ops;
static inline unsigned long aligned_rx_skb_addr(unsigned long addr)
{
return (~addr + 1) & (IOC3_DMA_XFER_LEN - 1UL);
......@@ -179,225 +167,61 @@ static inline unsigned long ioc3_map(dma_addr_t addr, unsigned long attr)
#define ERBAR_VAL 0
#endif
#define IOC3_SIZE 0x100000
static inline u32 mcr_pack(u32 pulse, u32 sample)
{
return (pulse << 10) | (sample << 2);
}
static int nic_wait(u32 __iomem *mcr)
{
u32 m;
do {
m = readl(mcr);
} while (!(m & 2));
return m & 1;
}
static int nic_reset(u32 __iomem *mcr)
{
int presence;
writel(mcr_pack(500, 65), mcr);
presence = nic_wait(mcr);
writel(mcr_pack(0, 500), mcr);
nic_wait(mcr);
return presence;
}
static inline int nic_read_bit(u32 __iomem *mcr)
{
int result;
writel(mcr_pack(6, 13), mcr);
result = nic_wait(mcr);
writel(mcr_pack(0, 100), mcr);
nic_wait(mcr);
return result;
}
static inline void nic_write_bit(u32 __iomem *mcr, int bit)
{
if (bit)
writel(mcr_pack(6, 110), mcr);
else
writel(mcr_pack(80, 30), mcr);
nic_wait(mcr);
}
/* Read a byte from an iButton device
*/
static u32 nic_read_byte(u32 __iomem *mcr)
{
u32 result = 0;
int i;
for (i = 0; i < 8; i++)
result = (result >> 1) | (nic_read_bit(mcr) << 7);
return result;
}
/* Write a byte to an iButton device
*/
static void nic_write_byte(u32 __iomem *mcr, int byte)
{
int i, bit;
for (i = 8; i; i--) {
bit = byte & 1;
byte >>= 1;
nic_write_bit(mcr, bit);
}
}
static u64 nic_find(u32 __iomem *mcr, int *last)
static int ioc3eth_nvmem_match(struct device *dev, const void *data)
{
int a, b, index, disc;
u64 address = 0;
nic_reset(mcr);
/* Search ROM. */
nic_write_byte(mcr, 0xf0);
const char *name = dev_name(dev);
const char *prefix = data;
int prefix_len;
/* Algorithm from ``Book of iButton Standards''. */
for (index = 0, disc = 0; index < 64; index++) {
a = nic_read_bit(mcr);
b = nic_read_bit(mcr);
if (a && b) {
pr_warn("NIC search failed (not fatal).\n");
*last = 0;
prefix_len = strlen(prefix);
if (strlen(name) < (prefix_len + 3))
return 0;
}
if (!a && !b) {
if (index == *last) {
address |= 1UL << index;
} else if (index > *last) {
address &= ~(1UL << index);
disc = index;
} else if ((address & (1UL << index)) == 0) {
disc = index;
}
nic_write_bit(mcr, address & (1UL << index));
continue;
} else {
if (a)
address |= 1UL << index;
else
address &= ~(1UL << index);
nic_write_bit(mcr, a);
continue;
}
}
*last = disc;
return address;
}
static int nic_init(u32 __iomem *mcr)
{
const char *unknown = "unknown";
const char *type = unknown;
u8 crc;
u8 serial[6];
int save = 0, i;
while (1) {
u64 reg;
reg = nic_find(mcr, &save);
switch (reg & 0xff) {
case 0x91:
type = "DS1981U";
break;
default:
if (save == 0) {
/* Let the caller try again. */
return -1;
}
continue;
}
nic_reset(mcr);
/* Match ROM. */
nic_write_byte(mcr, 0x55);
for (i = 0; i < 8; i++)
nic_write_byte(mcr, (reg >> (i << 3)) & 0xff);
reg >>= 8; /* Shift out type. */
for (i = 0; i < 6; i++) {
serial[i] = reg & 0xff;
reg >>= 8;
}
crc = reg & 0xff;
break;
}
if (memcmp(prefix, name, prefix_len) != 0)
return 0;
pr_info("Found %s NIC", type);
if (type != unknown)
pr_cont(" registration number %pM, CRC %02x", serial, crc);
pr_cont(".\n");
/* found nvmem device which is attached to our ioc3
* now check for one wire family code 09, 89 and 91
*/
if (memcmp(name + prefix_len, "09-", 3) == 0)
return 1;
if (memcmp(name + prefix_len, "89-", 3) == 0)
return 1;
if (memcmp(name + prefix_len, "91-", 3) == 0)
return 1;
return 0;
}
/* Read the NIC (Number-In-a-Can) device used to store the MAC address on
* SN0 / SN00 nodeboards and PCI cards.
*/
static void ioc3_get_eaddr_nic(struct ioc3_private *ip)
static int ioc3eth_get_mac_addr(struct resource *res, u8 mac_addr[6])
{
u32 __iomem *mcr = &ip->all_regs->mcr;
int tries = 2; /* There may be some problem with the battery? */
u8 nic[14];
struct nvmem_device *nvmem;
char prefix[24];
u8 prom[16];
int ret;
int i;
writel(1 << 21, &ip->all_regs->gpcr_s);
snprintf(prefix, sizeof(prefix), "ioc3-%012llx-",
res->start & ~0xffff);
while (tries--) {
if (!nic_init(mcr))
break;
udelay(500);
}
if (tries < 0) {
pr_err("Failed to read MAC address\n");
return;
}
/* Read Memory. */
nic_write_byte(mcr, 0xf0);
nic_write_byte(mcr, 0x00);
nic_write_byte(mcr, 0x00);
nvmem = nvmem_device_find(prefix, ioc3eth_nvmem_match);
if (IS_ERR(nvmem))
return PTR_ERR(nvmem);
for (i = 13; i >= 0; i--)
nic[i] = nic_read_byte(mcr);
ret = nvmem_device_read(nvmem, 0, 16, prom);
nvmem_device_put(nvmem);
if (ret < 0)
return ret;
for (i = 2; i < 8; i++)
ip->dev->dev_addr[i - 2] = nic[i];
}
/* check, if content is valid */
if (prom[0] != 0x0a ||
crc16(CRC16_INIT, prom, 13) != CRC16_VALID)
return -EINVAL;
/* Ok, this is hosed by design. It's necessary to know what machine the
* NIC is in in order to know how to read the NIC address. We also have
* to know if it's a PCI card or a NIC in on the node board ...
*/
static void ioc3_get_eaddr(struct ioc3_private *ip)
{
ioc3_get_eaddr_nic(ip);
for (i = 0; i < 6; i++)
mac_addr[i] = prom[10 - i];
pr_info("Ethernet address is %pM.\n", ip->dev->dev_addr);
return 0;
}
static void __ioc3_set_mac_address(struct net_device *dev)
......@@ -770,7 +594,7 @@ static int ioc3_mii_init(struct ioc3_private *ip)
u16 word;
for (i = 0; i < 32; i++) {
word = ioc3_mdio_read(ip->dev, i, MII_PHYSID1);
word = ioc3_mdio_read(ip->mii.dev, i, MII_PHYSID1);
if (word != 0xffff && word != 0x0000) {
found = 1;
......@@ -975,12 +799,6 @@ static int ioc3_open(struct net_device *dev)
{
struct ioc3_private *ip = netdev_priv(dev);
if (request_irq(dev->irq, ioc3_interrupt, IRQF_SHARED, ioc3_str, dev)) {
netdev_err(dev, "Can't get irq %d\n", dev->irq);
return -EAGAIN;
}
ip->ehar_h = 0;
ip->ehar_l = 0;
......@@ -1013,147 +831,6 @@ static int ioc3_close(struct net_device *dev)
return 0;
}
/* MENET cards have four IOC3 chips, which are attached to two sets of
* PCI slot resources each: the primary connections are on slots
* 0..3 and the secondaries are on 4..7
*
* All four ethernets are brought out to connectors; six serial ports
* (a pair from each of the first three IOC3s) are brought out to
* MiniDINs; all other subdevices are left swinging in the wind, leave
* them disabled.
*/
static int ioc3_adjacent_is_ioc3(struct pci_dev *pdev, int slot)
{
struct pci_dev *dev = pci_get_slot(pdev->bus, PCI_DEVFN(slot, 0));
int ret = 0;
if (dev) {
if (dev->vendor == PCI_VENDOR_ID_SGI &&
dev->device == PCI_DEVICE_ID_SGI_IOC3)
ret = 1;
pci_dev_put(dev);
}
return ret;
}
static int ioc3_is_menet(struct pci_dev *pdev)
{
return !pdev->bus->parent &&
ioc3_adjacent_is_ioc3(pdev, 0) &&
ioc3_adjacent_is_ioc3(pdev, 1) &&
ioc3_adjacent_is_ioc3(pdev, 2);
}
#ifdef CONFIG_SERIAL_8250
/* Note about serial ports and consoles:
* For console output, everyone uses the IOC3 UARTA (offset 0x178)
* connected to the master node (look in ip27_setup_console() and
* ip27prom_console_write()).
*
* For serial (/dev/ttyS0 etc), we can not have hardcoded serial port
* addresses on a partitioned machine. Since we currently use the ioc3
* serial ports, we use dynamic serial port discovery that the serial.c
* driver uses for pci/pnp ports (there is an entry for the SGI ioc3
* boards in pci_boards[]). Unfortunately, UARTA's pio address is greater
* than UARTB's, although UARTA on o200s has traditionally been known as
* port 0. So, we just use one serial port from each ioc3 (since the
* serial driver adds addresses to get to higher ports).
*
* The first one to do a register_console becomes the preferred console
* (if there is no kernel command line console= directive). /dev/console
* (ie 5, 1) is then "aliased" into the device number returned by the
* "device" routine referred to in this console structure
* (ip27prom_console_dev).
*
* Also look in ip27-pci.c:pci_fixup_ioc3() for some comments on working
* around ioc3 oddities in this respect.
*
* The IOC3 serials use a 22MHz clock rate with an additional divider which
* can be programmed in the SCR register if the DLAB bit is set.
*
* Register to interrupt zero because we share the interrupt with
* the serial driver which we don't properly support yet.
*
* Can't use UPF_IOREMAP as the whole of IOC3 resources have already been
* registered.
*/
static void ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
{
#define COSMISC_CONSTANT 6
struct uart_8250_port port = {
.port = {
.irq = 0,
.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
.iotype = UPIO_MEM,
.regshift = 0,
.uartclk = (22000000 << 1) / COSMISC_CONSTANT,
.membase = (unsigned char __iomem *)uart,
.mapbase = (unsigned long)uart,
}
};
unsigned char lcr;
lcr = readb(&uart->iu_lcr);
writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr);
writeb(COSMISC_CONSTANT, &uart->iu_scr);
writeb(lcr, &uart->iu_lcr);
readb(&uart->iu_lcr);
serial8250_register_8250_port(&port);
}
static void ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
{
u32 sio_iec;
/* We need to recognice and treat the fourth MENET serial as it
* does not have an SuperIO chip attached to it, therefore attempting
* to access it will result in bus errors. We call something an
* MENET if PCI slot 0, 1, 2 and 3 of a master PCI bus all have an IOC3
* in it. This is paranoid but we want to avoid blowing up on a
* showhorn PCI box that happens to have 4 IOC3 cards in it so it's
* not paranoid enough ...
*/
if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3)
return;
/* Switch IOC3 to PIO mode. It probably already was but let's be
* paranoid
*/
writel(GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL, &ioc3->gpcr_s);
readl(&ioc3->gpcr_s);
writel(0, &ioc3->gppr[6]);
readl(&ioc3->gppr[6]);
writel(0, &ioc3->gppr[7]);
readl(&ioc3->gppr[7]);
writel(readl(&ioc3->port_a.sscr) & ~SSCR_DMA_EN, &ioc3->port_a.sscr);
readl(&ioc3->port_a.sscr);
writel(readl(&ioc3->port_b.sscr) & ~SSCR_DMA_EN, &ioc3->port_b.sscr);
readl(&ioc3->port_b.sscr);
/* Disable all SA/B interrupts except for SA/B_INT in SIO_IEC. */
sio_iec = readl(&ioc3->sio_iec);
sio_iec &= ~(SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL |
SIO_IR_SA_RX_HIGH | SIO_IR_SA_RX_TIMER |
SIO_IR_SA_DELTA_DCD | SIO_IR_SA_DELTA_CTS |
SIO_IR_SA_TX_EXPLICIT | SIO_IR_SA_MEMERR);
sio_iec |= SIO_IR_SA_INT;
sio_iec &= ~(SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL |
SIO_IR_SB_RX_HIGH | SIO_IR_SB_RX_TIMER |
SIO_IR_SB_DELTA_DCD | SIO_IR_SB_DELTA_CTS |
SIO_IR_SB_TX_EXPLICIT | SIO_IR_SB_MEMERR);
sio_iec |= SIO_IR_SB_INT;
writel(sio_iec, &ioc3->sio_iec);
writel(0, &ioc3->port_a.sscr);
writel(0, &ioc3->port_b.sscr);
ioc3_8250_register(&ioc3->sregs.uarta);
ioc3_8250_register(&ioc3->sregs.uartb);
}
#endif
static const struct net_device_ops ioc3_netdev_ops = {
.ndo_open = ioc3_open,
.ndo_stop = ioc3_close,
......@@ -1166,61 +843,52 @@ static const struct net_device_ops ioc3_netdev_ops = {
.ndo_set_mac_address = ioc3_set_mac_address,
};
static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
static int ioc3eth_probe(struct platform_device *pdev)
{
unsigned int sw_physid1, sw_physid2;
struct net_device *dev = NULL;
u32 sw_physid1, sw_physid2, vendor, model, rev;
struct ioc3_private *ip;
struct ioc3 *ioc3;
unsigned long ioc3_base, ioc3_size;
u32 vendor, model, rev;
struct net_device *dev;
struct resource *regs;
u8 mac_addr[6];
int err;
/* Configure DMA attributes. */
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (err) {
pr_err("%s: No usable DMA configuration, aborting.\n",
pci_name(pdev));
goto out;
}
if (pci_enable_device(pdev))
return -ENODEV;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/* get mac addr from one wire prom */
if (ioc3eth_get_mac_addr(regs, mac_addr))
return -EPROBE_DEFER; /* not available yet */
dev = alloc_etherdev(sizeof(struct ioc3_private));
if (!dev) {
err = -ENOMEM;
goto out_disable;
}
err = pci_request_regions(pdev, "ioc3");
if (err)
goto out_free;
if (!dev)
return -ENOMEM;
SET_NETDEV_DEV(dev, &pdev->dev);
ip = netdev_priv(dev);
ip->dev = dev;
ip->dma_dev = &pdev->dev;
dev->irq = pdev->irq;
ip->dma_dev = pdev->dev.parent;
ip->regs = devm_platform_ioremap_resource(pdev, 0);
if (!ip->regs) {
err = -ENOMEM;
goto out_free;
}
ioc3_base = pci_resource_start(pdev, 0);
ioc3_size = pci_resource_len(pdev, 0);
ioc3 = (struct ioc3 *)ioremap(ioc3_base, ioc3_size);
if (!ioc3) {
pr_err("ioc3eth(%s): ioremap failed, goodbye.\n",
pci_name(pdev));
ip->ssram = devm_platform_ioremap_resource(pdev, 1);
if (!ip->ssram) {
err = -ENOMEM;
goto out_res;
goto out_free;
}
ip->regs = &ioc3->eth;
ip->ssram = ioc3->ssram;
ip->all_regs = ioc3;
#ifdef CONFIG_SERIAL_8250
ioc3_serial_probe(pdev, ioc3);
#endif
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq < 0) {
err = dev->irq;
goto out_free;
}
if (devm_request_irq(&pdev->dev, dev->irq, ioc3_interrupt,
IRQF_SHARED, "ioc3-eth", dev)) {
dev_err(&pdev->dev, "Can't get irq %d\n", dev->irq);
err = -ENODEV;
goto out_free;
}
spin_lock_init(&ip->ioc3_lock);
timer_setup(&ip->ioc3_timer, ioc3_timer, 0);
......@@ -1250,8 +918,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ioc3_init(dev);
ip->pdev = pdev;
ip->mii.phy_id_mask = 0x1f;
ip->mii.reg_num_mask = 0x1f;
ip->mii.dev = dev;
......@@ -1261,15 +927,14 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ioc3_mii_init(ip);
if (ip->mii.phy_id == -1) {
pr_err("ioc3-eth(%s): Didn't find a PHY, goodbye.\n",
pci_name(pdev));
netdev_err(dev, "Didn't find a PHY, goodbye.\n");
err = -ENODEV;
goto out_stop;
}
ioc3_mii_start(ip);
ioc3_ssram_disc(ip);
ioc3_get_eaddr(ip);
memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
/* The IOC3-specific entries in the device structure. */
dev->watchdog_timeo = 5 * HZ;
......@@ -1306,21 +971,14 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ip->tx_ring)
dma_free_coherent(ip->dma_dev, TX_RING_SIZE, ip->tx_ring,
ip->txr_dma);
out_res:
pci_release_regions(pdev);
out_free:
free_netdev(dev);
out_disable:
/* We should call pci_disable_device(pdev); here if the IOC3 wasn't
* such a weird device ...
*/
out:
return err;
}
static void ioc3_remove_one(struct pci_dev *pdev)
static int ioc3eth_remove(struct platform_device *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct net_device *dev = platform_get_drvdata(pdev);
struct ioc3_private *ip = netdev_priv(dev);
dma_free_coherent(ip->dma_dev, RX_RING_SIZE, ip->rxr, ip->rxr_dma);
......@@ -1328,27 +986,11 @@ static void ioc3_remove_one(struct pci_dev *pdev)
unregister_netdev(dev);
del_timer_sync(&ip->ioc3_timer);
iounmap(ip->all_regs);
pci_release_regions(pdev);
free_netdev(dev);
/* We should call pci_disable_device(pdev); here if the IOC3 wasn't
* such a weird device ...
*/
}
static const struct pci_device_id ioc3_pci_tbl[] = {
{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ioc3_pci_tbl);
return 0;
}
static struct pci_driver ioc3_driver = {
.name = "ioc3-eth",
.id_table = ioc3_pci_tbl,
.probe = ioc3_probe,
.remove = ioc3_remove_one,
};
static netdev_tx_t ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
......@@ -1530,11 +1172,10 @@ static inline unsigned int ioc3_hash(const unsigned char *addr)
static void ioc3_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct ioc3_private *ip = netdev_priv(dev);
strlcpy(info->driver, IOC3_NAME, sizeof(info->driver));
strlcpy(info->version, IOC3_VERSION, sizeof(info->version));
strlcpy(info->bus_info, pci_name(ip->pdev), sizeof(info->bus_info));
strlcpy(info->bus_info, pci_name(to_pci_dev(dev->dev.parent)),
sizeof(info->bus_info));
}
static int ioc3_get_link_ksettings(struct net_device *dev,
......@@ -1646,7 +1287,16 @@ static void ioc3_set_multicast_list(struct net_device *dev)
spin_unlock_irq(&ip->ioc3_lock);
}
module_pci_driver(ioc3_driver);
static struct platform_driver ioc3eth_driver = {
.probe = ioc3eth_probe,
.remove = ioc3eth_remove,
.driver = {
.name = "ioc3-eth",
}
};
module_platform_driver(ioc3eth_driver);
MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
MODULE_DESCRIPTION("SGI IOC3 Ethernet driver");
MODULE_LICENSE("GPL");
......@@ -20,6 +20,16 @@
struct m48t35_rtc {
u8 pad[0x7ff8]; /* starts at 0x7ff8 */
#ifdef CONFIG_SGI_IP27
u8 hour;
u8 min;
u8 sec;
u8 control;
u8 year;
u8 month;
u8 date;
u8 day;
#else
u8 control;
u8 sec;
u8 min;
......@@ -28,6 +38,7 @@ struct m48t35_rtc {
u8 date;
u8 month;
u8 year;
#endif
};
#define M48T35_RTC_SET 0x80
......
......@@ -28,14 +28,12 @@ static int ltq_fpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct resource *res_xbar;
struct regmap *rcu_regmap;
void __iomem *xbar_membase;
u32 rcu_ahb_endianness_reg_offset;
int ret;
res_xbar = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xbar_membase = devm_ioremap_resource(dev, res_xbar);
xbar_membase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(xbar_membase))
return PTR_ERR(xbar_membase);
......
......@@ -56,7 +56,7 @@ EXPORT_SYMBOL(tc_unregister_driver);
* system is in its list of supported devices. Returns the matching
* tc_device_id structure or %NULL if there is no match.
*/
const struct tc_device_id *tc_match_device(struct tc_driver *tdrv,
static const struct tc_device_id *tc_match_device(struct tc_driver *tdrv,
struct tc_dev *tdev)
{
const struct tc_device_id *id = tdrv->id_table;
......@@ -71,7 +71,6 @@ const struct tc_device_id *tc_match_device(struct tc_driver *tdrv,
}
return NULL;
}
EXPORT_SYMBOL(tc_match_device);
/**
* tc_bus_match - Tell if a device structure has a matching
......
// SPDX-License-Identifier: GPL-2.0
/*
* SGI IOC3 8250 UART driver
*
* Copyright (C) 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
*
* based on code Copyright (C) 2005 Stanislaw Skowronek <skylark@unaligned.org>
* Copyright (C) 2014 Joshua Kinard <kumba@gentoo.org>
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include "8250.h"
#define IOC3_UARTCLK (22000000 / 3)
struct ioc3_8250_data {
int line;
};
static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
{
return readb(p->membase + (offset ^ 3));
}
static void ioc3_serial_out(struct uart_port *p, int offset, int value)
{
writeb(value, p->membase + (offset ^ 3));
}
static int serial8250_ioc3_probe(struct platform_device *pdev)
{
struct ioc3_8250_data *data;
struct uart_8250_port up;
struct resource *r;
void __iomem *membase;
int irq, line;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r)
return -ENODEV;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
membase = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r));
if (!membase)
return -ENOMEM;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
irq = 0; /* no interrupt -> use polling */
/* Register serial ports with 8250.c */
memset(&up, 0, sizeof(struct uart_8250_port));
up.port.iotype = UPIO_MEM;
up.port.uartclk = IOC3_UARTCLK;
up.port.type = PORT_16550A;
up.port.irq = irq;
up.port.flags = (UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ);
up.port.dev = &pdev->dev;
up.port.membase = membase;
up.port.mapbase = r->start;
up.port.serial_in = ioc3_serial_in;
up.port.serial_out = ioc3_serial_out;
line = serial8250_register_8250_port(&up);
if (line < 0)
return line;
platform_set_drvdata(pdev, data);
return 0;
}
static int serial8250_ioc3_remove(struct platform_device *pdev)
{
struct ioc3_8250_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
return 0;
}
static struct platform_driver serial8250_ioc3_driver = {
.probe = serial8250_ioc3_probe,
.remove = serial8250_ioc3_remove,
.driver = {
.name = "ioc3-serial8250",
}
};
module_platform_driver(serial8250_ioc3_driver);
MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
MODULE_DESCRIPTION("SGI IOC3 8250 UART driver");
MODULE_LICENSE("GPL");
......@@ -381,6 +381,17 @@ config SERIAL_8250_EM
port hardware found on the Emma Mobile line of processors.
If unsure, say N.
config SERIAL_8250_IOC3
tristate "SGI IOC3 8250 UART support"
depends on SGI_MFD_IOC3 && SERIAL_8250
select SERIAL_8250_EXTENDED
select SERIAL_8250_SHARE_IRQ
help
Enable this if you have a SGI Origin or Octane machine. This module
provides basic serial support by directly driving the UART chip
behind the IOC3 device on those systems. Maximum baud speed is
38400bps using this driver.
config SERIAL_8250_RT288X
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
depends on SERIAL_8250
......
......@@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment