diff --git a/Documentation/driver-api/eisa.rst b/Documentation/driver-api/eisa.rst
index 3563e5f7e98d..fa2f281d39d3 100644
--- a/Documentation/driver-api/eisa.rst
+++ b/Documentation/driver-api/eisa.rst
@@ -196,8 +196,8 @@ eisa_bus.disable_dev
virtual_root.force_probe
Force the probing code to probe EISA slots even when it cannot find an
EISA compliant mainboard (nothing appears on slot 0). Defaults to 0
- (don't force), and set to 1 (force probing) when
- CONFIG_EISA_VLB_PRIMING is set.
+ (don't force), and set to 1 (force probing) when either
+ CONFIG_ALPHA_JENSEN or CONFIG_EISA_VLB_PRIMING are set.
Random notes
============
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 6c7dbf0adad6..1b1383ae3c9f 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -11,7 +11,8 @@ config ALPHA
select ARCH_NO_PREEMPT
select ARCH_NO_SG_CHAIN
select ARCH_USE_CMPXCHG_LOCKREF
- select FORCE_PCI
+ select DMA_OPS if PCI
+ select FORCE_PCI if !ALPHA_JENSEN
select PCI_DOMAINS if PCI
select PCI_SYSCALL if PCI
select HAVE_ASM_MODVERSIONS
@@ -92,11 +93,22 @@ choice
. In summary:
Alcor/Alpha-XLT AS 600, AS 500, XL-300, XL-366
+ Alpha-XL XL-233, XL-266
+ AlphaBook1 Alpha laptop
+ Avanti AS 200, AS 205, AS 250, AS 255, AS 300, AS 400
+ Cabriolet AlphaPC64, AlphaPCI64
DP264 DP264 / DS20 / ES40 / DS10 / DS10L
+ EB164 EB164 21164 evaluation board
+ EB64+ EB64+ 21064 evaluation board
+ EB66 EB66 21066 evaluation board
+ EB66+ EB66+ 21066 evaluation board
+ Jensen DECpc 150, DEC 2000 models 300, 500
LX164 AlphaPC164-LX
+ Lynx AS 2100A
Miata Personal Workstation 433/500/600 a/au
Marvel AlphaServer ES47 / ES80 / GS1280
Mikasa AS 1000
+ Noname AXPpci33, UDB (Multia)
Noritake AS 1000A, AS 600A, AS 800
PC164 AlphaPC164
Rawhide AS 1200, AS 4000, AS 4100
@@ -128,6 +140,27 @@ config ALPHA_ALCOR
all the work required to support an external Bcache and to maintain
memory coherence when a PCI device DMAs into (or out of) memory.
+config ALPHA_XL
+ bool "Alpha-XL"
+ help
+ XL-233 and XL-266-based Alpha systems.
+
+config ALPHA_BOOK1
+ bool "AlphaBook1"
+ help
+ Dec AlphaBook1/Burns Alpha-based laptops.
+
+config ALPHA_AVANTI_CH
+ bool "Avanti"
+
+config ALPHA_CABRIOLET
+ bool "Cabriolet"
+ help
+ Cabriolet AlphaPC64, AlphaPCI64 systems. Derived from EB64+ but now
+ baby-AT with Flash boot ROM, no on-board SCSI or Ethernet. 3 ISA
+ slots, 4 PCI slots (one pair are on a shared slot), uses plug-in
+ Bcache SIMMs. Requires power supply with 3.3V output.
+
config ALPHA_DP264
bool "DP264"
help
@@ -135,18 +168,62 @@ config ALPHA_DP264
API Networks: 264DP, UP2000(+), CS20;
Compaq: DS10(E,L), XP900, XP1000, DS20(E), ES40.
+config ALPHA_EB164
+ bool "EB164"
+ help
+ EB164 21164 evaluation board from DEC. Uses 21164 and ALCOR. Has
+ ISA and PCI expansion (3 ISA slots, 2 64-bit PCI slots (one is
+ shared with an ISA slot) and 2 32-bit PCI slots. Uses plus-in
+ Bcache SIMMs. I/O sub-system provides SuperI/O (2S, 1P, FD), KBD,
+ MOUSE (PS2 style), RTC/NVRAM. Boot ROM is Flash. PC-AT-sized
+ motherboard. Requires power supply with 3.3V output.
+
+config ALPHA_EB64P_CH
+ bool "EB64+"
+
+config ALPHA_EB66
+ bool "EB66"
+ help
+ A Digital DS group board. Uses 21066 or 21066A. I/O sub-system is
+ identical to EB64+. Baby PC-AT size. Runs from standard PC power
+ supply. The EB66 schematic was published as a marketing poster
+ advertising the 21066 as "the first microprocessor in the world with
+ embedded PCI".
+
+config ALPHA_EB66P
+ bool "EB66+"
+ help
+ Later variant of the EB66 board.
+
config ALPHA_EIGER
bool "Eiger"
help
Apparently an obscure OEM single-board computer based on the
Typhoon/Tsunami chipset family. Information on it is scanty.
+config ALPHA_JENSEN
+ bool "Jensen"
+ select HAVE_EISA
+ help
+ DEC PC 150 AXP (aka Jensen): This is a very old Digital system - one
+ of the first-generation Alpha systems. A number of these systems
+ seem to be available on the second- hand market. The Jensen is a
+ floor-standing tower system which originally used a 150MHz 21064 It
+ used programmable logic to interface a 486 EISA I/O bridge to the
+ CPU.
+
config ALPHA_LX164
bool "LX164"
help
A technical overview of this board is available at
.
+config ALPHA_LYNX
+ bool "Lynx"
+ select HAVE_EISA
+ help
+ AlphaServer 2100A-based systems.
+
config ALPHA_MARVEL
bool "Marvel"
help
@@ -169,6 +246,9 @@ config ALPHA_NAUTILUS
help
Alpha systems based on the AMD 751 & ALI 1543C chipsets.
+config ALPHA_NONAME_CH
+ bool "Noname"
+
config ALPHA_NORITAKE
bool "Noritake"
select HAVE_EISA
@@ -179,6 +259,9 @@ config ALPHA_NORITAKE
config ALPHA_PC164
bool "PC164"
+config ALPHA_P2K
+ bool "Platform2000"
+
config ALPHA_RAWHIDE
bool "Rawhide"
select HAVE_EISA
@@ -242,18 +325,84 @@ config ISA_DMA_API
bool
default y
+config ALPHA_NONAME
+ bool
+ depends on ALPHA_BOOK1 || ALPHA_NONAME_CH
+ default y
+ help
+ The AXPpci33 (aka NoName), is based on the EB66 (includes the Multia
+ UDB). This design was produced by Digital's Technical OEM (TOEM)
+ group. It uses the 21066 processor running at 166MHz or 233MHz. It
+ is a baby-AT size, and runs from a standard PC power supply. It has
+ 5 ISA slots and 3 PCI slots (one pair are a shared slot). There are
+ 2 versions, with either PS/2 or large DIN connectors for the
+ keyboard.
+
+config ALPHA_EV4
+ bool
+ depends on ALPHA_JENSEN || (ALPHA_SABLE && !ALPHA_GAMMA) || ALPHA_LYNX || ALPHA_NORITAKE && !ALPHA_PRIMO || ALPHA_MIKASA && !ALPHA_PRIMO || ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P_CH || ALPHA_XL || ALPHA_NONAME || ALPHA_EB66 || ALPHA_EB66P || ALPHA_P2K
+ default y if !ALPHA_LYNX
+ default y if !ALPHA_EV5
+
+config ALPHA_LCA
+ bool
+ depends on ALPHA_NONAME || ALPHA_EB66 || ALPHA_EB66P || ALPHA_P2K
+ default y
+
+config ALPHA_APECS
+ bool
+ depends on !ALPHA_PRIMO && (ALPHA_NORITAKE || ALPHA_MIKASA) || ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P_CH || ALPHA_XL
+ default y
+
+config ALPHA_EB64P
+ bool
+ depends on ALPHA_CABRIOLET || ALPHA_EB64P_CH
+ default y
+ help
+ Uses 21064 or 21064A and APECs. Has ISA and PCI expansion (3 ISA,
+ 2 PCI, one pair are on a shared slot). Supports 36-bit DRAM SIMs.
+ ISA bus generated by Intel SaturnI/O PCI-ISA bridge. On-board SCSI
+ (NCR 810 on PCI) Ethernet (Digital 21040), KBD, MOUSE (PS2 style),
+ SuperI/O (2S, 1P, FD), RTC/NVRAM. Boot ROM is EPROM. PC-AT size.
+ Runs from standard PC power supply.
+
+config ALPHA_EV5
+ bool "EV5 CPU(s) (model 5/xxx)?" if ALPHA_LYNX
+ default y if ALPHA_RX164 || ALPHA_RAWHIDE || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN || ALPHA_SABLE && ALPHA_GAMMA || ALPHA_NORITAKE && ALPHA_PRIMO || ALPHA_MIKASA && ALPHA_PRIMO || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR
+
config ALPHA_CIA
bool
- depends on ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN || ALPHA_NORITAKE || ALPHA_MIKASA || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_ALCOR
+ depends on ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN || ALPHA_NORITAKE && ALPHA_PRIMO || ALPHA_MIKASA && ALPHA_PRIMO || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR
default y
config ALPHA_EV56
- bool
- default y if ALPHA_ALCOR || ALPHA_RX164 || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_NORITAKE || ALPHA_MIKASA || ALPHA_RAWHIDE || ALPHA_SABLE
+ bool "EV56 CPU (speed >= 366MHz)?" if ALPHA_ALCOR
+ default y if ALPHA_RX164 || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN || ALPHA_PC164 || ALPHA_TAKARA
+
+config ALPHA_EV56
+ prompt "EV56 CPU (speed >= 333MHz)?"
+ depends on ALPHA_NORITAKE || ALPHA_PRIMO
+
+config ALPHA_EV56
+ prompt "EV56 CPU (speed >= 400MHz)?"
+ depends on ALPHA_RAWHIDE
+
+config ALPHA_PRIMO
+ bool "EV5 CPU daughtercard (model 5/xxx)?"
+ depends on ALPHA_NORITAKE || ALPHA_MIKASA
+ help
+ Say Y if you have an AS 1000 5/xxx or an AS 1000A 5/xxx.
+
+config ALPHA_GAMMA
+ bool "EV5 CPU(s) (model 5/xxx)?" if ALPHA_SABLE
+ depends on ALPHA_SABLE || ALPHA_LYNX
+ default ALPHA_LYNX
+ help
+ Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx.
config ALPHA_T2
bool
- depends on ALPHA_SABLE
+ depends on ALPHA_SABLE || ALPHA_LYNX
default y
config ALPHA_PYXIS
@@ -297,6 +446,15 @@ config GENERIC_HWEIGHT
bool
default y if !ALPHA_EV67
+config ALPHA_AVANTI
+ bool
+ depends on ALPHA_XL || ALPHA_AVANTI_CH
+ default y
+ help
+ Avanti AS 200, AS 205, AS 250, AS 255, AS 300, and AS 400-based
+ Alphas. Info at
+ .
+
config ALPHA_BROKEN_IRQ_MASK
bool
depends on ALPHA_GENERIC || ALPHA_PC164
@@ -326,9 +484,9 @@ config ALPHA_QEMU
config ALPHA_SRM
- bool "Use SRM as bootloader" if ALPHA_PC164 || ALPHA_TAKARA || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS
+ bool "Use SRM as bootloader" if ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS || ALPHA_NONAME
depends on TTY
- default y if ALPHA_MIKASA || ALPHA_SABLE || ALPHA_NORITAKE || ALPHA_DP264 || ALPHA_RAWHIDE || ALPHA_EIGER || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL
+ default y if ALPHA_JENSEN || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_DP264 || ALPHA_RAWHIDE || ALPHA_EIGER || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL
help
There are two different types of booting firmware on Alphas: SRM,
which is command line driven, and ARC, which uses menus and arrow
@@ -354,7 +512,7 @@ config ARCH_MAY_HAVE_PC_FDC
config SMP
bool "Symmetric multi-processing support"
- depends on ALPHA_SABLE || ALPHA_RAWHIDE || ALPHA_DP264 || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_GENERIC || ALPHA_SHARK || ALPHA_MARVEL
+ depends on ALPHA_SABLE || ALPHA_LYNX || ALPHA_RAWHIDE || ALPHA_DP264 || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_GENERIC || ALPHA_SHARK || ALPHA_MARVEL
help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, say N. If you have a system with more
@@ -390,7 +548,7 @@ config ARCH_SPARSEMEM_ENABLE
config ALPHA_WTINT
bool "Use WTINT" if ALPHA_SRM || ALPHA_GENERIC
default y if ALPHA_QEMU
- default n if ALPHA_EV56
+ default n if ALPHA_EV5 || ALPHA_EV56 || (ALPHA_EV4 && !ALPHA_LCA)
default n if !ALPHA_SRM && !ALPHA_GENERIC
default y if SMP
help
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile
index 35445ff2e489..45158024085e 100644
--- a/arch/alpha/Makefile
+++ b/arch/alpha/Makefile
@@ -15,14 +15,18 @@ CHECKFLAGS += -D__alpha__
cflags-y := -pipe -mno-fp-regs -ffixed-8
cflags-y += $(call cc-option, -fno-jump-tables)
+cpuflags-$(CONFIG_ALPHA_EV4) := -mcpu=ev4
+cpuflags-$(CONFIG_ALPHA_EV5) := -mcpu=ev5
cpuflags-$(CONFIG_ALPHA_EV56) := -mcpu=ev56
cpuflags-$(CONFIG_ALPHA_POLARIS) := -mcpu=pca56
cpuflags-$(CONFIG_ALPHA_SX164) := -mcpu=pca56
cpuflags-$(CONFIG_ALPHA_EV6) := -mcpu=ev6
cpuflags-$(CONFIG_ALPHA_EV67) := -mcpu=ev67
# If GENERIC, make sure to turn off any instruction set extensions that
-# the host compiler might have on by default.
-cpuflags-$(CONFIG_ALPHA_GENERIC) := -mcpu=ev56 -mtune=ev6
+# the host compiler might have on by default. Given that EV4 and EV5
+# have the same instruction set, prefer EV5 because an EV5 schedule is
+# more likely to keep an EV4 processor busy than vice-versa.
+cpuflags-$(CONFIG_ALPHA_GENERIC) := -mcpu=ev5
cflags-y += $(cpuflags-y)
diff --git a/arch/alpha/include/asm/core_apecs.h b/arch/alpha/include/asm/core_apecs.h
new file mode 100644
index 000000000000..69a2fc62c9c3
--- /dev/null
+++ b/arch/alpha/include/asm/core_apecs.h
@@ -0,0 +1,534 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ALPHA_APECS__H__
+#define __ALPHA_APECS__H__
+
+#include
+#include
+
+/*
+ * APECS is the internal name for the 2107x chipset which provides
+ * memory controller and PCI access for the 21064 chip based systems.
+ *
+ * This file is based on:
+ *
+ * DECchip 21071-AA and DECchip 21072-AA Core Logic Chipsets
+ * Data Sheet
+ *
+ * EC-N0648-72
+ *
+ *
+ * david.rusling@reo.mts.dec.com Initial Version.
+ *
+ */
+
+/*
+ An AVANTI *might* be an XL, and an XL has only 27 bits of ISA address
+ that get passed through the PCI<->ISA bridge chip. So we've gotta use
+ both windows to max out the physical memory we can DMA to. Sigh...
+
+ If we try a window at 0 for 1GB as a work-around, we run into conflicts
+ with ISA/PCI bus memory which can't be relocated, like VGA aperture and
+ BIOS ROMs. So we must put the windows high enough to avoid these areas.
+
+ We put window 1 at BUS 64Mb for 64Mb, mapping physical 0 to 64Mb-1,
+ and window 2 at BUS 1Gb for 1Gb, mapping physical 0 to 1Gb-1.
+ Yes, this does map 0 to 64Mb-1 twice, but only window 1 will actually
+ be used for that range (via virt_to_bus()).
+
+ Note that we actually fudge the window 1 maximum as 48Mb instead of 64Mb,
+ to keep virt_to_bus() from returning an address in the first window, for
+ a data area that goes beyond the 64Mb first DMA window. Sigh...
+ The fudge factor MUST match with MAX_DMA_ADDRESS, but
+ we can't just use that here, because of header file looping... :-(
+
+ Window 1 will be used for all DMA from the ISA bus; yes, that does
+ limit what memory an ISA floppy or sound card or Ethernet can touch, but
+ it's also a known limitation on other platforms as well. We use the
+ same technique that is used on INTEL platforms with similar limitation:
+ set MAX_DMA_ADDRESS and clear some pages' DMAable flags during mem_init().
+ We trust that any ISA bus device drivers will *always* ask for DMAable
+ memory explicitly via kmalloc()/get_free_pages() flags arguments.
+
+ Note that most PCI bus devices' drivers do *not* explicitly ask for
+ DMAable memory; they count on being able to DMA to any memory they
+ get from kmalloc()/get_free_pages(). They will also use window 1 for
+ any physical memory accesses below 64Mb; the rest will be handled by
+ window 2, maxing out at 1Gb of memory. I trust this is enough... :-)
+
+ We hope that the area before the first window is large enough so that
+ there will be no overlap at the top end (64Mb). We *must* locate the
+ PCI cards' memory just below window 1, so that there's still the
+ possibility of being able to access it via SPARSE space. This is
+ important for cards such as the Matrox Millennium, whose Xserver
+ wants to access memory-mapped registers in byte and short lengths.
+
+ Note that the XL is treated differently from the AVANTI, even though
+ for most other things they are identical. It didn't seem reasonable to
+ make the AVANTI support pay for the limitations of the XL. It is true,
+ however, that an XL kernel will run on an AVANTI without problems.
+
+ %%% All of this should be obviated by the ability to route
+ everything through the iommu.
+*/
+
+/*
+ * 21071-DA Control and Status registers.
+ * These are used for PCI memory access.
+ */
+#define APECS_IOC_DCSR (IDENT_ADDR + 0x1A0000000UL)
+#define APECS_IOC_PEAR (IDENT_ADDR + 0x1A0000020UL)
+#define APECS_IOC_SEAR (IDENT_ADDR + 0x1A0000040UL)
+#define APECS_IOC_DR1 (IDENT_ADDR + 0x1A0000060UL)
+#define APECS_IOC_DR2 (IDENT_ADDR + 0x1A0000080UL)
+#define APECS_IOC_DR3 (IDENT_ADDR + 0x1A00000A0UL)
+
+#define APECS_IOC_TB1R (IDENT_ADDR + 0x1A00000C0UL)
+#define APECS_IOC_TB2R (IDENT_ADDR + 0x1A00000E0UL)
+
+#define APECS_IOC_PB1R (IDENT_ADDR + 0x1A0000100UL)
+#define APECS_IOC_PB2R (IDENT_ADDR + 0x1A0000120UL)
+
+#define APECS_IOC_PM1R (IDENT_ADDR + 0x1A0000140UL)
+#define APECS_IOC_PM2R (IDENT_ADDR + 0x1A0000160UL)
+
+#define APECS_IOC_HAXR0 (IDENT_ADDR + 0x1A0000180UL)
+#define APECS_IOC_HAXR1 (IDENT_ADDR + 0x1A00001A0UL)
+#define APECS_IOC_HAXR2 (IDENT_ADDR + 0x1A00001C0UL)
+
+#define APECS_IOC_PMLT (IDENT_ADDR + 0x1A00001E0UL)
+
+#define APECS_IOC_TLBTAG0 (IDENT_ADDR + 0x1A0000200UL)
+#define APECS_IOC_TLBTAG1 (IDENT_ADDR + 0x1A0000220UL)
+#define APECS_IOC_TLBTAG2 (IDENT_ADDR + 0x1A0000240UL)
+#define APECS_IOC_TLBTAG3 (IDENT_ADDR + 0x1A0000260UL)
+#define APECS_IOC_TLBTAG4 (IDENT_ADDR + 0x1A0000280UL)
+#define APECS_IOC_TLBTAG5 (IDENT_ADDR + 0x1A00002A0UL)
+#define APECS_IOC_TLBTAG6 (IDENT_ADDR + 0x1A00002C0UL)
+#define APECS_IOC_TLBTAG7 (IDENT_ADDR + 0x1A00002E0UL)
+
+#define APECS_IOC_TLBDATA0 (IDENT_ADDR + 0x1A0000300UL)
+#define APECS_IOC_TLBDATA1 (IDENT_ADDR + 0x1A0000320UL)
+#define APECS_IOC_TLBDATA2 (IDENT_ADDR + 0x1A0000340UL)
+#define APECS_IOC_TLBDATA3 (IDENT_ADDR + 0x1A0000360UL)
+#define APECS_IOC_TLBDATA4 (IDENT_ADDR + 0x1A0000380UL)
+#define APECS_IOC_TLBDATA5 (IDENT_ADDR + 0x1A00003A0UL)
+#define APECS_IOC_TLBDATA6 (IDENT_ADDR + 0x1A00003C0UL)
+#define APECS_IOC_TLBDATA7 (IDENT_ADDR + 0x1A00003E0UL)
+
+#define APECS_IOC_TBIA (IDENT_ADDR + 0x1A0000400UL)
+
+
+/*
+ * 21071-CA Control and Status registers.
+ * These are used to program memory timing,
+ * configure memory and initialise the B-Cache.
+ */
+#define APECS_MEM_GCR (IDENT_ADDR + 0x180000000UL)
+#define APECS_MEM_EDSR (IDENT_ADDR + 0x180000040UL)
+#define APECS_MEM_TAR (IDENT_ADDR + 0x180000060UL)
+#define APECS_MEM_ELAR (IDENT_ADDR + 0x180000080UL)
+#define APECS_MEM_EHAR (IDENT_ADDR + 0x1800000a0UL)
+#define APECS_MEM_SFT_RST (IDENT_ADDR + 0x1800000c0UL)
+#define APECS_MEM_LDxLAR (IDENT_ADDR + 0x1800000e0UL)
+#define APECS_MEM_LDxHAR (IDENT_ADDR + 0x180000100UL)
+#define APECS_MEM_GTR (IDENT_ADDR + 0x180000200UL)
+#define APECS_MEM_RTR (IDENT_ADDR + 0x180000220UL)
+#define APECS_MEM_VFPR (IDENT_ADDR + 0x180000240UL)
+#define APECS_MEM_PDLDR (IDENT_ADDR + 0x180000260UL)
+#define APECS_MEM_PDhDR (IDENT_ADDR + 0x180000280UL)
+
+/* Bank x Base Address Register */
+#define APECS_MEM_B0BAR (IDENT_ADDR + 0x180000800UL)
+#define APECS_MEM_B1BAR (IDENT_ADDR + 0x180000820UL)
+#define APECS_MEM_B2BAR (IDENT_ADDR + 0x180000840UL)
+#define APECS_MEM_B3BAR (IDENT_ADDR + 0x180000860UL)
+#define APECS_MEM_B4BAR (IDENT_ADDR + 0x180000880UL)
+#define APECS_MEM_B5BAR (IDENT_ADDR + 0x1800008A0UL)
+#define APECS_MEM_B6BAR (IDENT_ADDR + 0x1800008C0UL)
+#define APECS_MEM_B7BAR (IDENT_ADDR + 0x1800008E0UL)
+#define APECS_MEM_B8BAR (IDENT_ADDR + 0x180000900UL)
+
+/* Bank x Configuration Register */
+#define APECS_MEM_B0BCR (IDENT_ADDR + 0x180000A00UL)
+#define APECS_MEM_B1BCR (IDENT_ADDR + 0x180000A20UL)
+#define APECS_MEM_B2BCR (IDENT_ADDR + 0x180000A40UL)
+#define APECS_MEM_B3BCR (IDENT_ADDR + 0x180000A60UL)
+#define APECS_MEM_B4BCR (IDENT_ADDR + 0x180000A80UL)
+#define APECS_MEM_B5BCR (IDENT_ADDR + 0x180000AA0UL)
+#define APECS_MEM_B6BCR (IDENT_ADDR + 0x180000AC0UL)
+#define APECS_MEM_B7BCR (IDENT_ADDR + 0x180000AE0UL)
+#define APECS_MEM_B8BCR (IDENT_ADDR + 0x180000B00UL)
+
+/* Bank x Timing Register A */
+#define APECS_MEM_B0TRA (IDENT_ADDR + 0x180000C00UL)
+#define APECS_MEM_B1TRA (IDENT_ADDR + 0x180000C20UL)
+#define APECS_MEM_B2TRA (IDENT_ADDR + 0x180000C40UL)
+#define APECS_MEM_B3TRA (IDENT_ADDR + 0x180000C60UL)
+#define APECS_MEM_B4TRA (IDENT_ADDR + 0x180000C80UL)
+#define APECS_MEM_B5TRA (IDENT_ADDR + 0x180000CA0UL)
+#define APECS_MEM_B6TRA (IDENT_ADDR + 0x180000CC0UL)
+#define APECS_MEM_B7TRA (IDENT_ADDR + 0x180000CE0UL)
+#define APECS_MEM_B8TRA (IDENT_ADDR + 0x180000D00UL)
+
+/* Bank x Timing Register B */
+#define APECS_MEM_B0TRB (IDENT_ADDR + 0x180000E00UL)
+#define APECS_MEM_B1TRB (IDENT_ADDR + 0x180000E20UL)
+#define APECS_MEM_B2TRB (IDENT_ADDR + 0x180000E40UL)
+#define APECS_MEM_B3TRB (IDENT_ADDR + 0x180000E60UL)
+#define APECS_MEM_B4TRB (IDENT_ADDR + 0x180000E80UL)
+#define APECS_MEM_B5TRB (IDENT_ADDR + 0x180000EA0UL)
+#define APECS_MEM_B6TRB (IDENT_ADDR + 0x180000EC0UL)
+#define APECS_MEM_B7TRB (IDENT_ADDR + 0x180000EE0UL)
+#define APECS_MEM_B8TRB (IDENT_ADDR + 0x180000F00UL)
+
+
+/*
+ * Memory spaces:
+ */
+#define APECS_IACK_SC (IDENT_ADDR + 0x1b0000000UL)
+#define APECS_CONF (IDENT_ADDR + 0x1e0000000UL)
+#define APECS_IO (IDENT_ADDR + 0x1c0000000UL)
+#define APECS_SPARSE_MEM (IDENT_ADDR + 0x200000000UL)
+#define APECS_DENSE_MEM (IDENT_ADDR + 0x300000000UL)
+
+
+/*
+ * Bit definitions for I/O Controller status register 0:
+ */
+#define APECS_IOC_STAT0_CMD 0xf
+#define APECS_IOC_STAT0_ERR (1<<4)
+#define APECS_IOC_STAT0_LOST (1<<5)
+#define APECS_IOC_STAT0_THIT (1<<6)
+#define APECS_IOC_STAT0_TREF (1<<7)
+#define APECS_IOC_STAT0_CODE_SHIFT 8
+#define APECS_IOC_STAT0_CODE_MASK 0x7
+#define APECS_IOC_STAT0_P_NBR_SHIFT 13
+#define APECS_IOC_STAT0_P_NBR_MASK 0x7ffff
+
+#define APECS_HAE_ADDRESS APECS_IOC_HAXR1
+
+
+/*
+ * Data structure for handling APECS machine checks:
+ */
+
+struct el_apecs_mikasa_sysdata_mcheck
+{
+ unsigned long coma_gcr;
+ unsigned long coma_edsr;
+ unsigned long coma_ter;
+ unsigned long coma_elar;
+ unsigned long coma_ehar;
+ unsigned long coma_ldlr;
+ unsigned long coma_ldhr;
+ unsigned long coma_base0;
+ unsigned long coma_base1;
+ unsigned long coma_base2;
+ unsigned long coma_base3;
+ unsigned long coma_cnfg0;
+ unsigned long coma_cnfg1;
+ unsigned long coma_cnfg2;
+ unsigned long coma_cnfg3;
+ unsigned long epic_dcsr;
+ unsigned long epic_pear;
+ unsigned long epic_sear;
+ unsigned long epic_tbr1;
+ unsigned long epic_tbr2;
+ unsigned long epic_pbr1;
+ unsigned long epic_pbr2;
+ unsigned long epic_pmr1;
+ unsigned long epic_pmr2;
+ unsigned long epic_harx1;
+ unsigned long epic_harx2;
+ unsigned long epic_pmlt;
+ unsigned long epic_tag0;
+ unsigned long epic_tag1;
+ unsigned long epic_tag2;
+ unsigned long epic_tag3;
+ unsigned long epic_tag4;
+ unsigned long epic_tag5;
+ unsigned long epic_tag6;
+ unsigned long epic_tag7;
+ unsigned long epic_data0;
+ unsigned long epic_data1;
+ unsigned long epic_data2;
+ unsigned long epic_data3;
+ unsigned long epic_data4;
+ unsigned long epic_data5;
+ unsigned long epic_data6;
+ unsigned long epic_data7;
+
+ unsigned long pceb_vid;
+ unsigned long pceb_did;
+ unsigned long pceb_revision;
+ unsigned long pceb_command;
+ unsigned long pceb_status;
+ unsigned long pceb_latency;
+ unsigned long pceb_control;
+ unsigned long pceb_arbcon;
+ unsigned long pceb_arbpri;
+
+ unsigned long esc_id;
+ unsigned long esc_revision;
+ unsigned long esc_int0;
+ unsigned long esc_int1;
+ unsigned long esc_elcr0;
+ unsigned long esc_elcr1;
+ unsigned long esc_last_eisa;
+ unsigned long esc_nmi_stat;
+
+ unsigned long pci_ir;
+ unsigned long pci_imr;
+ unsigned long svr_mgr;
+};
+
+/* This for the normal APECS machines. */
+struct el_apecs_sysdata_mcheck
+{
+ unsigned long coma_gcr;
+ unsigned long coma_edsr;
+ unsigned long coma_ter;
+ unsigned long coma_elar;
+ unsigned long coma_ehar;
+ unsigned long coma_ldlr;
+ unsigned long coma_ldhr;
+ unsigned long coma_base0;
+ unsigned long coma_base1;
+ unsigned long coma_base2;
+ unsigned long coma_cnfg0;
+ unsigned long coma_cnfg1;
+ unsigned long coma_cnfg2;
+ unsigned long epic_dcsr;
+ unsigned long epic_pear;
+ unsigned long epic_sear;
+ unsigned long epic_tbr1;
+ unsigned long epic_tbr2;
+ unsigned long epic_pbr1;
+ unsigned long epic_pbr2;
+ unsigned long epic_pmr1;
+ unsigned long epic_pmr2;
+ unsigned long epic_harx1;
+ unsigned long epic_harx2;
+ unsigned long epic_pmlt;
+ unsigned long epic_tag0;
+ unsigned long epic_tag1;
+ unsigned long epic_tag2;
+ unsigned long epic_tag3;
+ unsigned long epic_tag4;
+ unsigned long epic_tag5;
+ unsigned long epic_tag6;
+ unsigned long epic_tag7;
+ unsigned long epic_data0;
+ unsigned long epic_data1;
+ unsigned long epic_data2;
+ unsigned long epic_data3;
+ unsigned long epic_data4;
+ unsigned long epic_data5;
+ unsigned long epic_data6;
+ unsigned long epic_data7;
+};
+
+struct el_apecs_procdata
+{
+ unsigned long paltemp[32]; /* PAL TEMP REGS. */
+ /* EV4-specific fields */
+ unsigned long exc_addr; /* Address of excepting instruction. */
+ unsigned long exc_sum; /* Summary of arithmetic traps. */
+ unsigned long exc_mask; /* Exception mask (from exc_sum). */
+ unsigned long iccsr; /* IBox hardware enables. */
+ unsigned long pal_base; /* Base address for PALcode. */
+ unsigned long hier; /* Hardware Interrupt Enable. */
+ unsigned long hirr; /* Hardware Interrupt Request. */
+ unsigned long csr; /* D-stream fault info. */
+ unsigned long dc_stat; /* D-cache status (ECC/Parity Err). */
+ unsigned long dc_addr; /* EV3 Phys Addr for ECC/DPERR. */
+ unsigned long abox_ctl; /* ABox Control Register. */
+ unsigned long biu_stat; /* BIU Status. */
+ unsigned long biu_addr; /* BUI Address. */
+ unsigned long biu_ctl; /* BIU Control. */
+ unsigned long fill_syndrome;/* For correcting ECC errors. */
+ unsigned long fill_addr; /* Cache block which was being read */
+ unsigned long va; /* Effective VA of fault or miss. */
+ unsigned long bc_tag; /* Backup Cache Tag Probe Results.*/
+};
+
+
+#ifdef __KERNEL__
+
+#ifndef __EXTERN_INLINE
+#define __EXTERN_INLINE extern inline
+#define __IO_EXTERN_INLINE
+#endif
+
+/*
+ * I/O functions:
+ *
+ * Unlike Jensen, the APECS machines have no concept of local
+ * I/O---everything goes over the PCI bus.
+ *
+ * There is plenty room for optimization here. In particular,
+ * the Alpha's insb/insw/extb/extw should be useful in moving
+ * data to/from the right byte-lanes.
+ */
+
+#define vip volatile int __force *
+#define vuip volatile unsigned int __force *
+#define vulp volatile unsigned long __force *
+
+#define APECS_SET_HAE \
+ do { \
+ if (addr >= (1UL << 24)) { \
+ unsigned long msb = addr & 0xf8000000; \
+ addr -= msb; \
+ set_hae(msb); \
+ } \
+ } while (0)
+
+__EXTERN_INLINE u8 apecs_ioread8(const void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ unsigned long result, base_and_type;
+
+ if (addr >= APECS_DENSE_MEM) {
+ addr -= APECS_DENSE_MEM;
+ APECS_SET_HAE;
+ base_and_type = APECS_SPARSE_MEM + 0x00;
+ } else {
+ addr -= APECS_IO;
+ base_and_type = APECS_IO + 0x00;
+ }
+
+ result = *(vip) ((addr << 5) + base_and_type);
+ return __kernel_extbl(result, addr & 3);
+}
+
+__EXTERN_INLINE void apecs_iowrite8(u8 b, void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ unsigned long w, base_and_type;
+
+ if (addr >= APECS_DENSE_MEM) {
+ addr -= APECS_DENSE_MEM;
+ APECS_SET_HAE;
+ base_and_type = APECS_SPARSE_MEM + 0x00;
+ } else {
+ addr -= APECS_IO;
+ base_and_type = APECS_IO + 0x00;
+ }
+
+ w = __kernel_insbl(b, addr & 3);
+ *(vuip) ((addr << 5) + base_and_type) = w;
+}
+
+__EXTERN_INLINE u16 apecs_ioread16(const void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ unsigned long result, base_and_type;
+
+ if (addr >= APECS_DENSE_MEM) {
+ addr -= APECS_DENSE_MEM;
+ APECS_SET_HAE;
+ base_and_type = APECS_SPARSE_MEM + 0x08;
+ } else {
+ addr -= APECS_IO;
+ base_and_type = APECS_IO + 0x08;
+ }
+
+ result = *(vip) ((addr << 5) + base_and_type);
+ return __kernel_extwl(result, addr & 3);
+}
+
+__EXTERN_INLINE void apecs_iowrite16(u16 b, void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ unsigned long w, base_and_type;
+
+ if (addr >= APECS_DENSE_MEM) {
+ addr -= APECS_DENSE_MEM;
+ APECS_SET_HAE;
+ base_and_type = APECS_SPARSE_MEM + 0x08;
+ } else {
+ addr -= APECS_IO;
+ base_and_type = APECS_IO + 0x08;
+ }
+
+ w = __kernel_inswl(b, addr & 3);
+ *(vuip) ((addr << 5) + base_and_type) = w;
+}
+
+__EXTERN_INLINE u32 apecs_ioread32(const void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr < APECS_DENSE_MEM)
+ addr = ((addr - APECS_IO) << 5) + APECS_IO + 0x18;
+ return *(vuip)addr;
+}
+
+__EXTERN_INLINE void apecs_iowrite32(u32 b, void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr < APECS_DENSE_MEM)
+ addr = ((addr - APECS_IO) << 5) + APECS_IO + 0x18;
+ *(vuip)addr = b;
+}
+
+__EXTERN_INLINE u64 apecs_ioread64(const void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr < APECS_DENSE_MEM)
+ addr = ((addr - APECS_IO) << 5) + APECS_IO + 0x18;
+ return *(vulp)addr;
+}
+
+__EXTERN_INLINE void apecs_iowrite64(u64 b, void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr < APECS_DENSE_MEM)
+ addr = ((addr - APECS_IO) << 5) + APECS_IO + 0x18;
+ *(vulp)addr = b;
+}
+
+__EXTERN_INLINE void __iomem *apecs_ioportmap(unsigned long addr)
+{
+ return (void __iomem *)(addr + APECS_IO);
+}
+
+__EXTERN_INLINE void __iomem *apecs_ioremap(unsigned long addr,
+ unsigned long size)
+{
+ return (void __iomem *)(addr + APECS_DENSE_MEM);
+}
+
+__EXTERN_INLINE int apecs_is_ioaddr(unsigned long addr)
+{
+ return addr >= IDENT_ADDR + 0x180000000UL;
+}
+
+__EXTERN_INLINE int apecs_is_mmio(const volatile void __iomem *addr)
+{
+ return (unsigned long)addr >= APECS_DENSE_MEM;
+}
+
+#undef APECS_SET_HAE
+
+#undef vip
+#undef vuip
+#undef vulp
+
+#undef __IO_PREFIX
+#define __IO_PREFIX apecs
+#define apecs_trivial_io_bw 0
+#define apecs_trivial_io_lq 0
+#define apecs_trivial_rw_bw 2
+#define apecs_trivial_rw_lq 1
+#define apecs_trivial_iounmap 1
+#include
+
+#ifdef __IO_EXTERN_INLINE
+#undef __EXTERN_INLINE
+#undef __IO_EXTERN_INLINE
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* __ALPHA_APECS__H__ */
diff --git a/arch/alpha/include/asm/core_lca.h b/arch/alpha/include/asm/core_lca.h
new file mode 100644
index 000000000000..d8c3e72ef8f6
--- /dev/null
+++ b/arch/alpha/include/asm/core_lca.h
@@ -0,0 +1,378 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ALPHA_LCA__H__
+#define __ALPHA_LCA__H__
+
+#include
+#include
+
+/*
+ * Low Cost Alpha (LCA) definitions (these apply to 21066 and 21068,
+ * for example).
+ *
+ * This file is based on:
+ *
+ * DECchip 21066 and DECchip 21068 Alpha AXP Microprocessors
+ * Hardware Reference Manual; Digital Equipment Corp.; May 1994;
+ * Maynard, MA; Order Number: EC-N2681-71.
+ */
+
+/*
+ * NOTE: The LCA uses a Host Address Extension (HAE) register to access
+ * PCI addresses that are beyond the first 27 bits of address
+ * space. Updating the HAE requires an external cycle (and
+ * a memory barrier), which tends to be slow. Instead of updating
+ * it on each sparse memory access, we keep the current HAE value
+ * cached in variable cache_hae. Only if the cached HAE differs
+ * from the desired HAE value do we actually updated HAE register.
+ * The HAE register is preserved by the interrupt handler entry/exit
+ * code, so this scheme works even in the presence of interrupts.
+ *
+ * Dense memory space doesn't require the HAE, but is restricted to
+ * aligned 32 and 64 bit accesses. Special Cycle and Interrupt
+ * Acknowledge cycles may also require the use of the HAE. The LCA
+ * limits I/O address space to the bottom 24 bits of address space,
+ * but this easily covers the 16 bit ISA I/O address space.
+ */
+
+/*
+ * NOTE 2! The memory operations do not set any memory barriers, as
+ * it's not needed for cases like a frame buffer that is essentially
+ * memory-like. You need to do them by hand if the operations depend
+ * on ordering.
+ *
+ * Similarly, the port I/O operations do a "mb" only after a write
+ * operation: if an mb is needed before (as in the case of doing
+ * memory mapped I/O first, and then a port I/O operation to the same
+ * device), it needs to be done by hand.
+ *
+ * After the above has bitten me 100 times, I'll give up and just do
+ * the mb all the time, but right now I'm hoping this will work out.
+ * Avoiding mb's may potentially be a noticeable speed improvement,
+ * but I can't honestly say I've tested it.
+ *
+ * Handling interrupts that need to do mb's to synchronize to
+ * non-interrupts is another fun race area. Don't do it (because if
+ * you do, I'll have to do *everything* with interrupts disabled,
+ * ugh).
+ */
+
+/*
+ * Memory Controller registers:
+ */
+#define LCA_MEM_BCR0 (IDENT_ADDR + 0x120000000UL)
+#define LCA_MEM_BCR1 (IDENT_ADDR + 0x120000008UL)
+#define LCA_MEM_BCR2 (IDENT_ADDR + 0x120000010UL)
+#define LCA_MEM_BCR3 (IDENT_ADDR + 0x120000018UL)
+#define LCA_MEM_BMR0 (IDENT_ADDR + 0x120000020UL)
+#define LCA_MEM_BMR1 (IDENT_ADDR + 0x120000028UL)
+#define LCA_MEM_BMR2 (IDENT_ADDR + 0x120000030UL)
+#define LCA_MEM_BMR3 (IDENT_ADDR + 0x120000038UL)
+#define LCA_MEM_BTR0 (IDENT_ADDR + 0x120000040UL)
+#define LCA_MEM_BTR1 (IDENT_ADDR + 0x120000048UL)
+#define LCA_MEM_BTR2 (IDENT_ADDR + 0x120000050UL)
+#define LCA_MEM_BTR3 (IDENT_ADDR + 0x120000058UL)
+#define LCA_MEM_GTR (IDENT_ADDR + 0x120000060UL)
+#define LCA_MEM_ESR (IDENT_ADDR + 0x120000068UL)
+#define LCA_MEM_EAR (IDENT_ADDR + 0x120000070UL)
+#define LCA_MEM_CAR (IDENT_ADDR + 0x120000078UL)
+#define LCA_MEM_VGR (IDENT_ADDR + 0x120000080UL)
+#define LCA_MEM_PLM (IDENT_ADDR + 0x120000088UL)
+#define LCA_MEM_FOR (IDENT_ADDR + 0x120000090UL)
+
+/*
+ * I/O Controller registers:
+ */
+#define LCA_IOC_HAE (IDENT_ADDR + 0x180000000UL)
+#define LCA_IOC_CONF (IDENT_ADDR + 0x180000020UL)
+#define LCA_IOC_STAT0 (IDENT_ADDR + 0x180000040UL)
+#define LCA_IOC_STAT1 (IDENT_ADDR + 0x180000060UL)
+#define LCA_IOC_TBIA (IDENT_ADDR + 0x180000080UL)
+#define LCA_IOC_TB_ENA (IDENT_ADDR + 0x1800000a0UL)
+#define LCA_IOC_SFT_RST (IDENT_ADDR + 0x1800000c0UL)
+#define LCA_IOC_PAR_DIS (IDENT_ADDR + 0x1800000e0UL)
+#define LCA_IOC_W_BASE0 (IDENT_ADDR + 0x180000100UL)
+#define LCA_IOC_W_BASE1 (IDENT_ADDR + 0x180000120UL)
+#define LCA_IOC_W_MASK0 (IDENT_ADDR + 0x180000140UL)
+#define LCA_IOC_W_MASK1 (IDENT_ADDR + 0x180000160UL)
+#define LCA_IOC_T_BASE0 (IDENT_ADDR + 0x180000180UL)
+#define LCA_IOC_T_BASE1 (IDENT_ADDR + 0x1800001a0UL)
+#define LCA_IOC_TB_TAG0 (IDENT_ADDR + 0x188000000UL)
+#define LCA_IOC_TB_TAG1 (IDENT_ADDR + 0x188000020UL)
+#define LCA_IOC_TB_TAG2 (IDENT_ADDR + 0x188000040UL)
+#define LCA_IOC_TB_TAG3 (IDENT_ADDR + 0x188000060UL)
+#define LCA_IOC_TB_TAG4 (IDENT_ADDR + 0x188000070UL)
+#define LCA_IOC_TB_TAG5 (IDENT_ADDR + 0x1880000a0UL)
+#define LCA_IOC_TB_TAG6 (IDENT_ADDR + 0x1880000c0UL)
+#define LCA_IOC_TB_TAG7 (IDENT_ADDR + 0x1880000e0UL)
+
+/*
+ * Memory spaces:
+ */
+#define LCA_IACK_SC (IDENT_ADDR + 0x1a0000000UL)
+#define LCA_CONF (IDENT_ADDR + 0x1e0000000UL)
+#define LCA_IO (IDENT_ADDR + 0x1c0000000UL)
+#define LCA_SPARSE_MEM (IDENT_ADDR + 0x200000000UL)
+#define LCA_DENSE_MEM (IDENT_ADDR + 0x300000000UL)
+
+/*
+ * Bit definitions for I/O Controller status register 0:
+ */
+#define LCA_IOC_STAT0_CMD 0xf
+#define LCA_IOC_STAT0_ERR (1<<4)
+#define LCA_IOC_STAT0_LOST (1<<5)
+#define LCA_IOC_STAT0_THIT (1<<6)
+#define LCA_IOC_STAT0_TREF (1<<7)
+#define LCA_IOC_STAT0_CODE_SHIFT 8
+#define LCA_IOC_STAT0_CODE_MASK 0x7
+#define LCA_IOC_STAT0_P_NBR_SHIFT 13
+#define LCA_IOC_STAT0_P_NBR_MASK 0x7ffff
+
+#define LCA_HAE_ADDRESS LCA_IOC_HAE
+
+/* LCA PMR Power Management register defines */
+#define LCA_PMR_ADDR (IDENT_ADDR + 0x120000098UL)
+#define LCA_PMR_PDIV 0x7 /* Primary clock divisor */
+#define LCA_PMR_ODIV 0x38 /* Override clock divisor */
+#define LCA_PMR_INTO 0x40 /* Interrupt override */
+#define LCA_PMR_DMAO 0x80 /* DMA override */
+#define LCA_PMR_OCCEB 0xffff0000L /* Override cycle counter - even bits */
+#define LCA_PMR_OCCOB 0xffff000000000000L /* Override cycle counter - even bits */
+#define LCA_PMR_PRIMARY_MASK 0xfffffffffffffff8L
+
+/* LCA PMR Macros */
+
+#define LCA_READ_PMR (*(volatile unsigned long *)LCA_PMR_ADDR)
+#define LCA_WRITE_PMR(d) (*((volatile unsigned long *)LCA_PMR_ADDR) = (d))
+
+#define LCA_GET_PRIMARY(r) ((r) & LCA_PMR_PDIV)
+#define LCA_GET_OVERRIDE(r) (((r) >> 3) & LCA_PMR_PDIV)
+#define LCA_SET_PRIMARY_CLOCK(r, c) ((r) = (((r) & LCA_PMR_PRIMARY_MASK)|(c)))
+
+/* LCA PMR Divisor values */
+#define LCA_PMR_DIV_1 0x0
+#define LCA_PMR_DIV_1_5 0x1
+#define LCA_PMR_DIV_2 0x2
+#define LCA_PMR_DIV_4 0x3
+#define LCA_PMR_DIV_8 0x4
+#define LCA_PMR_DIV_16 0x5
+#define LCA_PMR_DIV_MIN DIV_1
+#define LCA_PMR_DIV_MAX DIV_16
+
+
+/*
+ * Data structure for handling LCA machine checks. Correctable errors
+ * result in a short logout frame, uncorrectable ones in a long one.
+ */
+struct el_lca_mcheck_short {
+ struct el_common h; /* common logout header */
+ unsigned long esr; /* error-status register */
+ unsigned long ear; /* error-address register */
+ unsigned long dc_stat; /* dcache status register */
+ unsigned long ioc_stat0; /* I/O controller status register 0 */
+ unsigned long ioc_stat1; /* I/O controller status register 1 */
+};
+
+struct el_lca_mcheck_long {
+ struct el_common h; /* common logout header */
+ unsigned long pt[31]; /* PAL temps */
+ unsigned long exc_addr; /* exception address */
+ unsigned long pad1[3];
+ unsigned long pal_base; /* PALcode base address */
+ unsigned long hier; /* hw interrupt enable */
+ unsigned long hirr; /* hw interrupt request */
+ unsigned long mm_csr; /* MMU control & status */
+ unsigned long dc_stat; /* data cache status */
+ unsigned long dc_addr; /* data cache addr register */
+ unsigned long abox_ctl; /* address box control register */
+ unsigned long esr; /* error status register */
+ unsigned long ear; /* error address register */
+ unsigned long car; /* cache control register */
+ unsigned long ioc_stat0; /* I/O controller status register 0 */
+ unsigned long ioc_stat1; /* I/O controller status register 1 */
+ unsigned long va; /* virtual address register */
+};
+
+union el_lca {
+ struct el_common * c;
+ struct el_lca_mcheck_long * l;
+ struct el_lca_mcheck_short * s;
+};
+
+#ifdef __KERNEL__
+
+#ifndef __EXTERN_INLINE
+#define __EXTERN_INLINE extern inline
+#define __IO_EXTERN_INLINE
+#endif
+
+/*
+ * I/O functions:
+ *
+ * Unlike Jensen, the Noname machines have no concept of local
+ * I/O---everything goes over the PCI bus.
+ *
+ * There is plenty room for optimization here. In particular,
+ * the Alpha's insb/insw/extb/extw should be useful in moving
+ * data to/from the right byte-lanes.
+ */
+
+#define vip volatile int __force *
+#define vuip volatile unsigned int __force *
+#define vulp volatile unsigned long __force *
+
+#define LCA_SET_HAE \
+ do { \
+ if (addr >= (1UL << 24)) { \
+ unsigned long msb = addr & 0xf8000000; \
+ addr -= msb; \
+ set_hae(msb); \
+ } \
+ } while (0)
+
+
+__EXTERN_INLINE u8 lca_ioread8(const void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ unsigned long result, base_and_type;
+
+ if (addr >= LCA_DENSE_MEM) {
+ addr -= LCA_DENSE_MEM;
+ LCA_SET_HAE;
+ base_and_type = LCA_SPARSE_MEM + 0x00;
+ } else {
+ addr -= LCA_IO;
+ base_and_type = LCA_IO + 0x00;
+ }
+
+ result = *(vip) ((addr << 5) + base_and_type);
+ return __kernel_extbl(result, addr & 3);
+}
+
+__EXTERN_INLINE void lca_iowrite8(u8 b, void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ unsigned long w, base_and_type;
+
+ if (addr >= LCA_DENSE_MEM) {
+ addr -= LCA_DENSE_MEM;
+ LCA_SET_HAE;
+ base_and_type = LCA_SPARSE_MEM + 0x00;
+ } else {
+ addr -= LCA_IO;
+ base_and_type = LCA_IO + 0x00;
+ }
+
+ w = __kernel_insbl(b, addr & 3);
+ *(vuip) ((addr << 5) + base_and_type) = w;
+}
+
+__EXTERN_INLINE u16 lca_ioread16(const void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ unsigned long result, base_and_type;
+
+ if (addr >= LCA_DENSE_MEM) {
+ addr -= LCA_DENSE_MEM;
+ LCA_SET_HAE;
+ base_and_type = LCA_SPARSE_MEM + 0x08;
+ } else {
+ addr -= LCA_IO;
+ base_and_type = LCA_IO + 0x08;
+ }
+
+ result = *(vip) ((addr << 5) + base_and_type);
+ return __kernel_extwl(result, addr & 3);
+}
+
+__EXTERN_INLINE void lca_iowrite16(u16 b, void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ unsigned long w, base_and_type;
+
+ if (addr >= LCA_DENSE_MEM) {
+ addr -= LCA_DENSE_MEM;
+ LCA_SET_HAE;
+ base_and_type = LCA_SPARSE_MEM + 0x08;
+ } else {
+ addr -= LCA_IO;
+ base_and_type = LCA_IO + 0x08;
+ }
+
+ w = __kernel_inswl(b, addr & 3);
+ *(vuip) ((addr << 5) + base_and_type) = w;
+}
+
+__EXTERN_INLINE u32 lca_ioread32(const void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr < LCA_DENSE_MEM)
+ addr = ((addr - LCA_IO) << 5) + LCA_IO + 0x18;
+ return *(vuip)addr;
+}
+
+__EXTERN_INLINE void lca_iowrite32(u32 b, void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr < LCA_DENSE_MEM)
+ addr = ((addr - LCA_IO) << 5) + LCA_IO + 0x18;
+ *(vuip)addr = b;
+}
+
+__EXTERN_INLINE u64 lca_ioread64(const void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr < LCA_DENSE_MEM)
+ addr = ((addr - LCA_IO) << 5) + LCA_IO + 0x18;
+ return *(vulp)addr;
+}
+
+__EXTERN_INLINE void lca_iowrite64(u64 b, void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr < LCA_DENSE_MEM)
+ addr = ((addr - LCA_IO) << 5) + LCA_IO + 0x18;
+ *(vulp)addr = b;
+}
+
+__EXTERN_INLINE void __iomem *lca_ioportmap(unsigned long addr)
+{
+ return (void __iomem *)(addr + LCA_IO);
+}
+
+__EXTERN_INLINE void __iomem *lca_ioremap(unsigned long addr,
+ unsigned long size)
+{
+ return (void __iomem *)(addr + LCA_DENSE_MEM);
+}
+
+__EXTERN_INLINE int lca_is_ioaddr(unsigned long addr)
+{
+ return addr >= IDENT_ADDR + 0x120000000UL;
+}
+
+__EXTERN_INLINE int lca_is_mmio(const volatile void __iomem *addr)
+{
+ return (unsigned long)addr >= LCA_DENSE_MEM;
+}
+
+#undef vip
+#undef vuip
+#undef vulp
+
+#undef __IO_PREFIX
+#define __IO_PREFIX lca
+#define lca_trivial_rw_bw 2
+#define lca_trivial_rw_lq 1
+#define lca_trivial_io_bw 0
+#define lca_trivial_io_lq 0
+#define lca_trivial_iounmap 1
+#include
+
+#ifdef __IO_EXTERN_INLINE
+#undef __EXTERN_INLINE
+#undef __IO_EXTERN_INLINE
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* __ALPHA_LCA__H__ */
diff --git a/arch/alpha/include/asm/core_t2.h b/arch/alpha/include/asm/core_t2.h
index ca9b091d9c5f..ab956b1625b5 100644
--- a/arch/alpha/include/asm/core_t2.h
+++ b/arch/alpha/include/asm/core_t2.h
@@ -25,8 +25,16 @@
#define T2_MEM_R1_MASK 0x07ffffff /* Mem sparse region 1 mask is 27 bits */
/* GAMMA-SABLE is a SABLE with EV5-based CPUs */
+/* All LYNX machines, EV4 or EV5, use the GAMMA bias also */
#define _GAMMA_BIAS 0x8000000000UL
+
+#if defined(CONFIG_ALPHA_GENERIC)
+#define GAMMA_BIAS alpha_mv.sys.t2.gamma_bias
+#elif defined(CONFIG_ALPHA_GAMMA)
#define GAMMA_BIAS _GAMMA_BIAS
+#else
+#define GAMMA_BIAS 0
+#endif
/*
* Memory spaces:
diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h
index ad5a59b035cb..6ce7e2041685 100644
--- a/arch/alpha/include/asm/dma-mapping.h
+++ b/arch/alpha/include/asm/dma-mapping.h
@@ -6,7 +6,11 @@ extern const struct dma_map_ops alpha_pci_ops;
static inline const struct dma_map_ops *get_arch_dma_ops(void)
{
+#ifdef CONFIG_ALPHA_JENSEN
+ return NULL;
+#else
return &alpha_pci_ops;
+#endif
}
#endif /* _ALPHA_DMA_MAPPING_H */
diff --git a/arch/alpha/include/asm/dma.h b/arch/alpha/include/asm/dma.h
index 3a88812b7165..a04d76b96089 100644
--- a/arch/alpha/include/asm/dma.h
+++ b/arch/alpha/include/asm/dma.h
@@ -82,6 +82,11 @@
just a wiring limit.
*/
+/* The maximum address for ISA DMA transfer on Alpha XL, due to an
+ hardware SIO limitation, is 64MB.
+*/
+#define ALPHA_XL_MAX_ISA_DMA_ADDRESS 0x04000000UL
+
/* The maximum address for ISA DMA transfer on RUFFIAN,
due to an hardware SIO limitation, is 16MB.
*/
@@ -102,7 +107,9 @@
#ifdef CONFIG_ALPHA_GENERIC
# define MAX_ISA_DMA_ADDRESS (alpha_mv.max_isa_dma_address)
#else
-# if defined(CONFIG_ALPHA_RUFFIAN)
+# if defined(CONFIG_ALPHA_XL)
+# define MAX_ISA_DMA_ADDRESS ALPHA_XL_MAX_ISA_DMA_ADDRESS
+# elif defined(CONFIG_ALPHA_RUFFIAN)
# define MAX_ISA_DMA_ADDRESS ALPHA_RUFFIAN_MAX_ISA_DMA_ADDRESS
# elif defined(CONFIG_ALPHA_SABLE)
# define MAX_ISA_DMA_ADDRESS ALPHA_SABLE_MAX_ISA_DMA_ADDRESS
diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h
index 50c82187e60e..adc87404ef87 100644
--- a/arch/alpha/include/asm/elf.h
+++ b/arch/alpha/include/asm/elf.h
@@ -133,7 +133,9 @@ extern int dump_elf_task(elf_greg_t *dest, struct task_struct *task);
#define ELF_PLATFORM \
({ \
enum implver_enum i_ = implver(); \
- ( i_ == IMPLVER_EV5 ? "ev56" \
+ ( i_ == IMPLVER_EV4 ? "ev4" \
+ : i_ == IMPLVER_EV5 \
+ ? (amask(AMASK_BWX) ? "ev5" : "ev56") \
: amask (AMASK_CIX) ? "ev6" : "ev67"); \
})
diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h
index fa3e4c246cda..0bfd1585b216 100644
--- a/arch/alpha/include/asm/io.h
+++ b/arch/alpha/include/asm/io.h
@@ -198,10 +198,16 @@ static inline int generic_is_mmio(const volatile void __iomem *a)
#else
-#if defined(CONFIG_ALPHA_CIA)
+#if defined(CONFIG_ALPHA_APECS)
+# include
+#elif defined(CONFIG_ALPHA_CIA)
# include
#elif defined(CONFIG_ALPHA_IRONGATE)
# include
+#elif defined(CONFIG_ALPHA_JENSEN)
+# include
+#elif defined(CONFIG_ALPHA_LCA)
+# include
#elif defined(CONFIG_ALPHA_MARVEL)
# include
#elif defined(CONFIG_ALPHA_MCPCIA)
@@ -633,7 +639,23 @@ extern void outsl (unsigned long port, const void *src, unsigned long count);
#define outsw outsw
#define outsl outsl
-#define RTC_PORT(x) (0x70 + (x))
+/*
+ * The Alpha Jensen hardware for some rather strange reason puts
+ * the RTC clock at 0x170 instead of 0x70. Probably due to some
+ * misguided idea about using 0x70 for NMI stuff.
+ *
+ * These defines will override the defaults when doing RTC queries
+ */
+
+#ifdef CONFIG_ALPHA_GENERIC
+# define RTC_PORT(x) ((x) + alpha_mv.rtc_port)
+#else
+# ifdef CONFIG_ALPHA_JENSEN
+# define RTC_PORT(x) (0x170+(x))
+# else
+# define RTC_PORT(x) (0x70 + (x))
+# endif
+#endif
#define RTC_ALWAYS_BCD 0
#define ioread64 ioread64
diff --git a/arch/alpha/include/asm/irq.h b/arch/alpha/include/asm/irq.h
index d83b26b6660f..432402c8e47f 100644
--- a/arch/alpha/include/asm/irq.h
+++ b/arch/alpha/include/asm/irq.h
@@ -31,11 +31,16 @@
# define NR_IRQS (32768 + 16) /* marvel - 32 pids */
# endif
-#elif defined(CONFIG_ALPHA_PC164) || \
+#elif defined(CONFIG_ALPHA_CABRIOLET) || \
+ defined(CONFIG_ALPHA_EB66P) || \
+ defined(CONFIG_ALPHA_EB164) || \
+ defined(CONFIG_ALPHA_PC164) || \
defined(CONFIG_ALPHA_LX164)
# define NR_IRQS 35
-#elif defined(CONFIG_ALPHA_MIKASA)
+#elif defined(CONFIG_ALPHA_EB66) || \
+ defined(CONFIG_ALPHA_EB64P) || \
+ defined(CONFIG_ALPHA_MIKASA)
# define NR_IRQS 32
#elif defined(CONFIG_ALPHA_ALCOR) || \
@@ -50,6 +55,7 @@
# define NR_IRQS 40
#elif defined(CONFIG_ALPHA_DP264) || \
+ defined(CONFIG_ALPHA_LYNX) || \
defined(CONFIG_ALPHA_SHARK)
# define NR_IRQS 64
diff --git a/arch/alpha/include/asm/jensen.h b/arch/alpha/include/asm/jensen.h
new file mode 100644
index 000000000000..66eb049eb421
--- /dev/null
+++ b/arch/alpha/include/asm/jensen.h
@@ -0,0 +1,363 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ALPHA_JENSEN_H
+#define __ALPHA_JENSEN_H
+
+#include
+
+/*
+ * Defines for the AlphaPC EISA IO and memory address space.
+ */
+
+/*
+ * NOTE! The memory operations do not set any memory barriers, as it's
+ * not needed for cases like a frame buffer that is essentially memory-like.
+ * You need to do them by hand if the operations depend on ordering.
+ *
+ * Similarly, the port IO operations do a "mb" only after a write operation:
+ * if an mb is needed before (as in the case of doing memory mapped IO
+ * first, and then a port IO operation to the same device), it needs to be
+ * done by hand.
+ *
+ * After the above has bitten me 100 times, I'll give up and just do the
+ * mb all the time, but right now I'm hoping this will work out. Avoiding
+ * mb's may potentially be a noticeable speed improvement, but I can't
+ * honestly say I've tested it.
+ *
+ * Handling interrupts that need to do mb's to synchronize to non-interrupts
+ * is another fun race area. Don't do it (because if you do, I'll have to
+ * do *everything* with interrupts disabled, ugh).
+ */
+
+/*
+ * EISA Interrupt Acknowledge address
+ */
+#define EISA_INTA (IDENT_ADDR + 0x100000000UL)
+
+/*
+ * FEPROM addresses
+ */
+#define EISA_FEPROM0 (IDENT_ADDR + 0x180000000UL)
+#define EISA_FEPROM1 (IDENT_ADDR + 0x1A0000000UL)
+
+/*
+ * VL82C106 base address
+ */
+#define EISA_VL82C106 (IDENT_ADDR + 0x1C0000000UL)
+
+/*
+ * EISA "Host Address Extension" address (bits 25-31 of the EISA address)
+ */
+#define EISA_HAE (IDENT_ADDR + 0x1D0000000UL)
+
+/*
+ * "SYSCTL" register address
+ */
+#define EISA_SYSCTL (IDENT_ADDR + 0x1E0000000UL)
+
+/*
+ * "spare" register address
+ */
+#define EISA_SPARE (IDENT_ADDR + 0x1F0000000UL)
+
+/*
+ * EISA memory address offset
+ */
+#define EISA_MEM (IDENT_ADDR + 0x200000000UL)
+
+/*
+ * EISA IO address offset
+ */
+#define EISA_IO (IDENT_ADDR + 0x300000000UL)
+
+
+#ifdef __KERNEL__
+
+#ifndef __EXTERN_INLINE
+#define __EXTERN_INLINE extern inline
+#define __IO_EXTERN_INLINE
+#endif
+
+/*
+ * Handle the "host address register". This needs to be set
+ * to the high 7 bits of the EISA address. This is also needed
+ * for EISA IO addresses, which are only 16 bits wide (the
+ * hae needs to be set to 0).
+ *
+ * HAE isn't needed for the local IO operations, though.
+ */
+
+#define JENSEN_HAE_ADDRESS EISA_HAE
+#define JENSEN_HAE_MASK 0x1ffffff
+
+__EXTERN_INLINE void jensen_set_hae(unsigned long addr)
+{
+ /* hae on the Jensen is bits 31:25 shifted right */
+ addr >>= 25;
+ if (addr != alpha_mv.hae_cache)
+ set_hae(addr);
+}
+
+#define vuip volatile unsigned int *
+#define vulp volatile unsigned long *
+
+/*
+ * IO functions
+ *
+ * The "local" functions are those that don't go out to the EISA bus,
+ * but instead act on the VL82C106 chip directly.. This is mainly the
+ * keyboard, RTC, printer and first two serial lines..
+ *
+ * The local stuff makes for some complications, but it seems to be
+ * gone in the PCI version. I hope I can get DEC suckered^H^H^H^H^H^H^H^H
+ * convinced that I need one of the newer machines.
+ */
+
+__EXTERN_INLINE unsigned int jensen_local_inb(unsigned long addr)
+{
+ return 0xff & *(vuip)((addr << 9) + EISA_VL82C106);
+}
+
+__EXTERN_INLINE void jensen_local_outb(u8 b, unsigned long addr)
+{
+ *(vuip)((addr << 9) + EISA_VL82C106) = b;
+ mb();
+}
+
+__EXTERN_INLINE unsigned int jensen_bus_inb(unsigned long addr)
+{
+ long result;
+
+ jensen_set_hae(0);
+ result = *(volatile int *)((addr << 7) + EISA_IO + 0x00);
+ return __kernel_extbl(result, addr & 3);
+}
+
+__EXTERN_INLINE void jensen_bus_outb(u8 b, unsigned long addr)
+{
+ jensen_set_hae(0);
+ *(vuip)((addr << 7) + EISA_IO + 0x00) = b * 0x01010101;
+ mb();
+}
+
+/*
+ * It seems gcc is not very good at optimizing away logical
+ * operations that result in operations across inline functions.
+ * Which is why this is a macro.
+ */
+
+#define jensen_is_local(addr) ( \
+/* keyboard */ (addr == 0x60 || addr == 0x64) || \
+/* RTC */ (addr == 0x170 || addr == 0x171) || \
+/* mb COM2 */ (addr >= 0x2f8 && addr <= 0x2ff) || \
+/* mb LPT1 */ (addr >= 0x3bc && addr <= 0x3be) || \
+/* mb COM2 */ (addr >= 0x3f8 && addr <= 0x3ff))
+
+__EXTERN_INLINE u8 jensen_inb(unsigned long addr)
+{
+ if (jensen_is_local(addr))
+ return jensen_local_inb(addr);
+ else
+ return jensen_bus_inb(addr);
+}
+
+__EXTERN_INLINE void jensen_outb(u8 b, unsigned long addr)
+{
+ if (jensen_is_local(addr))
+ jensen_local_outb(b, addr);
+ else
+ jensen_bus_outb(b, addr);
+}
+
+__EXTERN_INLINE u16 jensen_inw(unsigned long addr)
+{
+ long result;
+
+ jensen_set_hae(0);
+ result = *(volatile int *) ((addr << 7) + EISA_IO + 0x20);
+ result >>= (addr & 3) * 8;
+ return 0xffffUL & result;
+}
+
+__EXTERN_INLINE u32 jensen_inl(unsigned long addr)
+{
+ jensen_set_hae(0);
+ return *(vuip) ((addr << 7) + EISA_IO + 0x60);
+}
+
+__EXTERN_INLINE u64 jensen_inq(unsigned long addr)
+{
+ jensen_set_hae(0);
+ return *(vulp) ((addr << 7) + EISA_IO + 0x60);
+}
+
+__EXTERN_INLINE void jensen_outw(u16 b, unsigned long addr)
+{
+ jensen_set_hae(0);
+ *(vuip) ((addr << 7) + EISA_IO + 0x20) = b * 0x00010001;
+ mb();
+}
+
+__EXTERN_INLINE void jensen_outl(u32 b, unsigned long addr)
+{
+ jensen_set_hae(0);
+ *(vuip) ((addr << 7) + EISA_IO + 0x60) = b;
+ mb();
+}
+
+__EXTERN_INLINE void jensen_outq(u64 b, unsigned long addr)
+{
+ jensen_set_hae(0);
+ *(vulp) ((addr << 7) + EISA_IO + 0x60) = b;
+ mb();
+}
+
+/*
+ * Memory functions.
+ */
+
+__EXTERN_INLINE u8 jensen_readb(const volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ long result;
+
+ jensen_set_hae(addr);
+ addr &= JENSEN_HAE_MASK;
+ result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x00);
+ result >>= (addr & 3) * 8;
+ return 0xffUL & result;
+}
+
+__EXTERN_INLINE u16 jensen_readw(const volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ long result;
+
+ jensen_set_hae(addr);
+ addr &= JENSEN_HAE_MASK;
+ result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x20);
+ result >>= (addr & 3) * 8;
+ return 0xffffUL & result;
+}
+
+__EXTERN_INLINE u32 jensen_readl(const volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ jensen_set_hae(addr);
+ addr &= JENSEN_HAE_MASK;
+ return *(vuip) ((addr << 7) + EISA_MEM + 0x60);
+}
+
+__EXTERN_INLINE u64 jensen_readq(const volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ unsigned long r0, r1;
+
+ jensen_set_hae(addr);
+ addr &= JENSEN_HAE_MASK;
+ addr = (addr << 7) + EISA_MEM + 0x60;
+ r0 = *(vuip) (addr);
+ r1 = *(vuip) (addr + (4 << 7));
+ return r1 << 32 | r0;
+}
+
+__EXTERN_INLINE void jensen_writeb(u8 b, volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ jensen_set_hae(addr);
+ addr &= JENSEN_HAE_MASK;
+ *(vuip) ((addr << 7) + EISA_MEM + 0x00) = b * 0x01010101;
+}
+
+__EXTERN_INLINE void jensen_writew(u16 b, volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ jensen_set_hae(addr);
+ addr &= JENSEN_HAE_MASK;
+ *(vuip) ((addr << 7) + EISA_MEM + 0x20) = b * 0x00010001;
+}
+
+__EXTERN_INLINE void jensen_writel(u32 b, volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ jensen_set_hae(addr);
+ addr &= JENSEN_HAE_MASK;
+ *(vuip) ((addr << 7) + EISA_MEM + 0x60) = b;
+}
+
+__EXTERN_INLINE void jensen_writeq(u64 b, volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ jensen_set_hae(addr);
+ addr &= JENSEN_HAE_MASK;
+ addr = (addr << 7) + EISA_MEM + 0x60;
+ *(vuip) (addr) = b;
+ *(vuip) (addr + (4 << 7)) = b >> 32;
+}
+
+__EXTERN_INLINE void __iomem *jensen_ioportmap(unsigned long addr)
+{
+ return (void __iomem *)addr;
+}
+
+__EXTERN_INLINE void __iomem *jensen_ioremap(unsigned long addr,
+ unsigned long size)
+{
+ return (void __iomem *)(addr + 0x100000000ul);
+}
+
+__EXTERN_INLINE int jensen_is_ioaddr(unsigned long addr)
+{
+ return (long)addr >= 0;
+}
+
+__EXTERN_INLINE int jensen_is_mmio(const volatile void __iomem *addr)
+{
+ return (unsigned long)addr >= 0x100000000ul;
+}
+
+/* New-style ioread interface. All the routines are so ugly for Jensen
+ that it doesn't make sense to merge them. */
+
+#define IOPORT(OS, NS) \
+__EXTERN_INLINE u##NS jensen_ioread##NS(const void __iomem *xaddr) \
+{ \
+ if (jensen_is_mmio(xaddr)) \
+ return jensen_read##OS(xaddr - 0x100000000ul); \
+ else \
+ return jensen_in##OS((unsigned long)xaddr); \
+} \
+__EXTERN_INLINE void jensen_iowrite##NS(u##NS b, void __iomem *xaddr) \
+{ \
+ if (jensen_is_mmio(xaddr)) \
+ jensen_write##OS(b, xaddr - 0x100000000ul); \
+ else \
+ jensen_out##OS(b, (unsigned long)xaddr); \
+}
+
+IOPORT(b, 8)
+IOPORT(w, 16)
+IOPORT(l, 32)
+IOPORT(q, 64)
+
+#undef IOPORT
+
+#undef vuip
+#undef vulp
+
+#undef __IO_PREFIX
+#define __IO_PREFIX jensen
+#define jensen_trivial_rw_bw 0
+#define jensen_trivial_rw_lq 0
+#define jensen_trivial_io_bw 0
+#define jensen_trivial_io_lq 0
+#define jensen_trivial_iounmap 1
+#include
+
+#ifdef __IO_EXTERN_INLINE
+#undef __EXTERN_INLINE
+#undef __IO_EXTERN_INLINE
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* __ALPHA_JENSEN_H */
diff --git a/arch/alpha/include/asm/machvec.h b/arch/alpha/include/asm/machvec.h
index 490fc880bb3f..8623f995d34c 100644
--- a/arch/alpha/include/asm/machvec.h
+++ b/arch/alpha/include/asm/machvec.h
@@ -72,6 +72,15 @@ struct alpha_machine_vector
int (*mv_is_ioaddr)(unsigned long);
int (*mv_is_mmio)(const volatile void __iomem *);
+ void (*mv_switch_mm)(struct mm_struct *, struct mm_struct *,
+ struct task_struct *);
+ void (*mv_activate_mm)(struct mm_struct *, struct mm_struct *);
+
+ void (*mv_flush_tlb_current)(struct mm_struct *);
+ void (*mv_flush_tlb_current_page)(struct mm_struct * mm,
+ struct vm_area_struct *vma,
+ unsigned long addr);
+
void (*update_irq_hw)(unsigned long, unsigned long, int);
void (*ack_irq)(unsigned long);
void (*device_interrupt)(unsigned long vector);
diff --git a/arch/alpha/include/asm/mmu_context.h b/arch/alpha/include/asm/mmu_context.h
index eee8fe836a59..29a3e3a1f02b 100644
--- a/arch/alpha/include/asm/mmu_context.h
+++ b/arch/alpha/include/asm/mmu_context.h
@@ -71,7 +71,9 @@ __reload_thread(struct pcb_struct *pcb)
#ifdef CONFIG_ALPHA_GENERIC
# define MAX_ASN (alpha_mv.max_asn)
#else
-# if defined(CONFIG_ALPHA_EV56)
+# ifdef CONFIG_ALPHA_EV4
+# define MAX_ASN EV4_MAX_ASN
+# elif defined(CONFIG_ALPHA_EV5)
# define MAX_ASN EV5_MAX_ASN
# else
# define MAX_ASN EV6_MAX_ASN
@@ -160,6 +162,26 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
task_thread_info(next)->pcb.asn = mmc & HARDWARE_ASN_MASK;
}
+__EXTERN_INLINE void
+ev4_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
+ struct task_struct *next)
+{
+ /* As described, ASN's are broken for TLB usage. But we can
+ optimize for switching between threads -- if the mm is
+ unchanged from current we needn't flush. */
+ /* ??? May not be needed because EV4 PALcode recognizes that
+ ASN's are broken and does a tbiap itself on swpctx, under
+ the "Must set ASN or flush" rule. At least this is true
+ for a 1992 SRM, reports Joseph Martin (jmartin@hlo.dec.com).
+ I'm going to leave this here anyway, just to Be Sure. -- r~ */
+ if (prev_mm != next_mm)
+ tbiap();
+
+ /* Do continue to allocate ASNs, because we can still use them
+ to avoid flushing the icache. */
+ ev5_switch_mm(prev_mm, next_mm, next);
+}
+
extern void __load_new_mm_context(struct mm_struct *);
asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr,
long cause, struct pt_regs *regs);
@@ -187,8 +209,25 @@ ev5_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
__load_new_mm_context(next_mm);
}
-#define switch_mm(a,b,c) ev5_switch_mm((a),(b),(c))
-#define activate_mm(x,y) ev5_activate_mm((x),(y))
+__EXTERN_INLINE void
+ev4_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
+{
+ __load_new_mm_context(next_mm);
+ tbiap();
+}
+
+#ifdef CONFIG_ALPHA_GENERIC
+# define switch_mm(a,b,c) alpha_mv.mv_switch_mm((a),(b),(c))
+# define activate_mm(x,y) alpha_mv.mv_activate_mm((x),(y))
+#else
+# ifdef CONFIG_ALPHA_EV4
+# define switch_mm(a,b,c) ev4_switch_mm((a),(b),(c))
+# define activate_mm(x,y) ev4_activate_mm((x),(y))
+# else
+# define switch_mm(a,b,c) ev5_switch_mm((a),(b),(c))
+# define activate_mm(x,y) ev5_activate_mm((x),(y))
+# endif
+#endif
#define init_new_context init_new_context
static inline int
diff --git a/arch/alpha/include/asm/special_insns.h b/arch/alpha/include/asm/special_insns.h
index 798d0bdb11f9..ca2c5c30b22e 100644
--- a/arch/alpha/include/asm/special_insns.h
+++ b/arch/alpha/include/asm/special_insns.h
@@ -15,7 +15,10 @@ enum implver_enum {
(enum implver_enum) __implver; })
#else
/* Try to eliminate some dead code. */
-#ifdef CONFIG_ALPHA_EV56
+#ifdef CONFIG_ALPHA_EV4
+#define implver() IMPLVER_EV4
+#endif
+#ifdef CONFIG_ALPHA_EV5
#define implver() IMPLVER_EV5
#endif
#if defined(CONFIG_ALPHA_EV6)
diff --git a/arch/alpha/include/asm/tlbflush.h b/arch/alpha/include/asm/tlbflush.h
index 0c8529997f54..e78de2456ffa 100644
--- a/arch/alpha/include/asm/tlbflush.h
+++ b/arch/alpha/include/asm/tlbflush.h
@@ -14,6 +14,16 @@
extern void __load_new_mm_context(struct mm_struct *);
+/* Use a few helper functions to hide the ugly broken ASN
+ numbers on early Alphas (ev4 and ev45). */
+
+__EXTERN_INLINE void
+ev4_flush_tlb_current(struct mm_struct *mm)
+{
+ __load_new_mm_context(mm);
+ tbiap();
+}
+
__EXTERN_INLINE void
ev5_flush_tlb_current(struct mm_struct *mm)
{
@@ -24,6 +34,19 @@ ev5_flush_tlb_current(struct mm_struct *mm)
careful about the icache here, there is no way to invalidate a
specific icache page. */
+__EXTERN_INLINE void
+ev4_flush_tlb_current_page(struct mm_struct * mm,
+ struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ int tbi_flag = 2;
+ if (vma->vm_flags & VM_EXEC) {
+ __load_new_mm_context(mm);
+ tbi_flag = 3;
+ }
+ tbi(tbi_flag, addr);
+}
+
__EXTERN_INLINE void
ev5_flush_tlb_current_page(struct mm_struct * mm,
struct vm_area_struct *vma,
@@ -36,8 +59,18 @@ ev5_flush_tlb_current_page(struct mm_struct * mm,
}
-#define flush_tlb_current ev5_flush_tlb_current
-#define flush_tlb_current_page ev5_flush_tlb_current_page
+#ifdef CONFIG_ALPHA_GENERIC
+# define flush_tlb_current alpha_mv.mv_flush_tlb_current
+# define flush_tlb_current_page alpha_mv.mv_flush_tlb_current_page
+#else
+# ifdef CONFIG_ALPHA_EV4
+# define flush_tlb_current ev4_flush_tlb_current
+# define flush_tlb_current_page ev4_flush_tlb_current_page
+# else
+# define flush_tlb_current ev5_flush_tlb_current
+# define flush_tlb_current_page ev5_flush_tlb_current_page
+# endif
+#endif
#ifdef __MMU_EXTERN_INLINE
#undef __EXTERN_INLINE
diff --git a/arch/alpha/include/asm/uaccess.h b/arch/alpha/include/asm/uaccess.h
index ef295cbb797c..c32c2584c0b7 100644
--- a/arch/alpha/include/asm/uaccess.h
+++ b/arch/alpha/include/asm/uaccess.h
@@ -96,6 +96,9 @@ struct __large_struct { unsigned long buf[100]; };
: "=r"(__gu_val), "=r"(__gu_err) \
: "m"(__m(addr)), "1"(__gu_err))
+#ifdef __alpha_bwx__
+/* Those lucky bastards with ev56 and later CPUs can do byte/word moves. */
+
#define __get_user_16(addr) \
__asm__("1: ldwu %0,%2\n" \
"2:\n" \
@@ -109,6 +112,33 @@ struct __large_struct { unsigned long buf[100]; };
EXC(1b,2b,%0,%1) \
: "=r"(__gu_val), "=r"(__gu_err) \
: "m"(__m(addr)), "1"(__gu_err))
+#else
+/* Unfortunately, we can't get an unaligned access trap for the sub-word
+ load, so we have to do a general unaligned operation. */
+
+#define __get_user_16(addr) \
+{ \
+ long __gu_tmp; \
+ __asm__("1: ldq_u %0,0(%3)\n" \
+ "2: ldq_u %1,1(%3)\n" \
+ " extwl %0,%3,%0\n" \
+ " extwh %1,%3,%1\n" \
+ " or %0,%1,%0\n" \
+ "3:\n" \
+ EXC(1b,3b,%0,%2) \
+ EXC(2b,3b,%0,%2) \
+ : "=&r"(__gu_val), "=&r"(__gu_tmp), "=r"(__gu_err) \
+ : "r"(addr), "2"(__gu_err)); \
+}
+
+#define __get_user_8(addr) \
+ __asm__("1: ldq_u %0,0(%2)\n" \
+ " extbl %0,%2,%0\n" \
+ "2:\n" \
+ EXC(1b,2b,%0,%1) \
+ : "=&r"(__gu_val), "=r"(__gu_err) \
+ : "r"(addr), "1"(__gu_err))
+#endif
extern void __put_user_unknown(void);
@@ -162,6 +192,9 @@ __asm__ __volatile__("1: stl %r2,%1\n" \
: "=r"(__pu_err) \
: "m"(__m(addr)), "rJ"(x), "0"(__pu_err))
+#ifdef __alpha_bwx__
+/* Those lucky bastards with ev56 and later CPUs can do byte/word moves. */
+
#define __put_user_16(x, addr) \
__asm__ __volatile__("1: stw %r2,%1\n" \
"2:\n" \
@@ -175,6 +208,53 @@ __asm__ __volatile__("1: stb %r2,%1\n" \
EXC(1b,2b,$31,%0) \
: "=r"(__pu_err) \
: "m"(__m(addr)), "rJ"(x), "0"(__pu_err))
+#else
+/* Unfortunately, we can't get an unaligned access trap for the sub-word
+ write, so we have to do a general unaligned operation. */
+
+#define __put_user_16(x, addr) \
+{ \
+ long __pu_tmp1, __pu_tmp2, __pu_tmp3, __pu_tmp4; \
+ __asm__ __volatile__( \
+ "1: ldq_u %2,1(%5)\n" \
+ "2: ldq_u %1,0(%5)\n" \
+ " inswh %6,%5,%4\n" \
+ " inswl %6,%5,%3\n" \
+ " mskwh %2,%5,%2\n" \
+ " mskwl %1,%5,%1\n" \
+ " or %2,%4,%2\n" \
+ " or %1,%3,%1\n" \
+ "3: stq_u %2,1(%5)\n" \
+ "4: stq_u %1,0(%5)\n" \
+ "5:\n" \
+ EXC(1b,5b,$31,%0) \
+ EXC(2b,5b,$31,%0) \
+ EXC(3b,5b,$31,%0) \
+ EXC(4b,5b,$31,%0) \
+ : "=r"(__pu_err), "=&r"(__pu_tmp1), \
+ "=&r"(__pu_tmp2), "=&r"(__pu_tmp3), \
+ "=&r"(__pu_tmp4) \
+ : "r"(addr), "r"((unsigned long)(x)), "0"(__pu_err)); \
+}
+
+#define __put_user_8(x, addr) \
+{ \
+ long __pu_tmp1, __pu_tmp2; \
+ __asm__ __volatile__( \
+ "1: ldq_u %1,0(%4)\n" \
+ " insbl %3,%4,%2\n" \
+ " mskbl %1,%4,%1\n" \
+ " or %1,%2,%1\n" \
+ "2: stq_u %1,0(%4)\n" \
+ "3:\n" \
+ EXC(1b,3b,$31,%0) \
+ EXC(2b,3b,$31,%0) \
+ : "=r"(__pu_err), \
+ "=&r"(__pu_tmp1), "=&r"(__pu_tmp2) \
+ : "r"((unsigned long)(x)), "r"(addr), "0"(__pu_err)); \
+}
+#endif
+
/*
* Complex access routines
diff --git a/arch/alpha/include/uapi/asm/compiler.h b/arch/alpha/include/uapi/asm/compiler.h
index 8c03740966b4..0e00c0e13374 100644
--- a/arch/alpha/include/uapi/asm/compiler.h
+++ b/arch/alpha/include/uapi/asm/compiler.h
@@ -95,6 +95,24 @@
#define __kernel_ldwu(mem) (mem)
#define __kernel_stb(val,mem) ((mem) = (val))
#define __kernel_stw(val,mem) ((mem) = (val))
+#else
+#define __kernel_ldbu(mem) \
+ ({ unsigned char __kir; \
+ __asm__(".arch ev56; \
+ ldbu %0,%1" : "=r"(__kir) : "m"(mem)); \
+ __kir; })
+#define __kernel_ldwu(mem) \
+ ({ unsigned short __kir; \
+ __asm__(".arch ev56; \
+ ldwu %0,%1" : "=r"(__kir) : "m"(mem)); \
+ __kir; })
+#define __kernel_stb(val,mem) \
+ __asm__(".arch ev56; \
+ stb %1,%0" : "=m"(mem) : "r"(val))
+#define __kernel_stw(val,mem) \
+ __asm__(".arch ev56; \
+ stw %1,%0" : "=m"(mem) : "r"(val))
#endif
+
#endif /* _UAPI__ALPHA_COMPILER_H */
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 187cd8df2faf..8676c0d01690 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -22,14 +22,14 @@ obj-$(CONFIG_AUDIT) += audit.o
ifdef CONFIG_ALPHA_GENERIC
-obj-y += core_cia.o core_irongate.o \
+obj-y += core_apecs.o core_cia.o core_irongate.o core_lca.o \
core_mcpcia.o core_polaris.o core_t2.o \
core_tsunami.o
-obj-y += sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eiger.o \
- sys_miata.o sys_mikasa.o sys_nautilus.o \
+obj-y += sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \
+ sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o \
sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \
- sys_sable.o sys_sx164.o sys_takara.o
+ sys_sable.o sys_sio.o sys_sx164.o sys_takara.o
ifndef CONFIG_ALPHA_LEGACY_START_ADDRESS
obj-y += core_marvel.o core_titan.o core_wildfire.o
@@ -48,8 +48,10 @@ else
obj-$(CONFIG_ALPHA_SRM) += srmcons.o
# Core logic support
+obj-$(CONFIG_ALPHA_APECS) += core_apecs.o
obj-$(CONFIG_ALPHA_CIA) += core_cia.o
obj-$(CONFIG_ALPHA_IRONGATE) += core_irongate.o
+obj-$(CONFIG_ALPHA_LCA) += core_lca.o
obj-$(CONFIG_ALPHA_MARVEL) += core_marvel.o gct.o
obj-$(CONFIG_ALPHA_MCPCIA) += core_mcpcia.o
obj-$(CONFIG_ALPHA_POLARIS) += core_polaris.o
@@ -60,6 +62,12 @@ obj-$(CONFIG_ALPHA_WILDFIRE) += core_wildfire.o
# Board support
obj-$(CONFIG_ALPHA_ALCOR) += sys_alcor.o irq_i8259.o irq_srm.o
+obj-$(CONFIG_ALPHA_CABRIOLET) += sys_cabriolet.o irq_i8259.o irq_srm.o \
+ pc873xx.o
+obj-$(CONFIG_ALPHA_EB164) += sys_cabriolet.o irq_i8259.o irq_srm.o \
+ pc873xx.o
+obj-$(CONFIG_ALPHA_EB66P) += sys_cabriolet.o irq_i8259.o irq_srm.o \
+ pc873xx.o
obj-$(CONFIG_ALPHA_LX164) += sys_cabriolet.o irq_i8259.o irq_srm.o \
smc37c93x.o
obj-$(CONFIG_ALPHA_PC164) += sys_cabriolet.o irq_i8259.o irq_srm.o \
@@ -67,7 +75,10 @@ obj-$(CONFIG_ALPHA_PC164) += sys_cabriolet.o irq_i8259.o irq_srm.o \
obj-$(CONFIG_ALPHA_DP264) += sys_dp264.o irq_i8259.o es1888.o smc37c669.o
obj-$(CONFIG_ALPHA_SHARK) += sys_dp264.o irq_i8259.o es1888.o smc37c669.o
obj-$(CONFIG_ALPHA_TITAN) += sys_titan.o irq_i8259.o smc37c669.o
+obj-$(CONFIG_ALPHA_EB64P) += sys_eb64p.o irq_i8259.o
+obj-$(CONFIG_ALPHA_EB66) += sys_eb64p.o irq_i8259.o
obj-$(CONFIG_ALPHA_EIGER) += sys_eiger.o irq_i8259.o
+obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o pci-noop.o irq_i8259.o
obj-$(CONFIG_ALPHA_MARVEL) += sys_marvel.o
obj-$(CONFIG_ALPHA_MIATA) += sys_miata.o irq_pyxis.o irq_i8259.o \
es1888.o smc37c669.o
@@ -78,6 +89,12 @@ obj-$(CONFIG_ALPHA_RAWHIDE) += sys_rawhide.o irq_i8259.o
obj-$(CONFIG_ALPHA_RUFFIAN) += sys_ruffian.o irq_pyxis.o irq_i8259.o
obj-$(CONFIG_ALPHA_RX164) += sys_rx164.o irq_i8259.o
obj-$(CONFIG_ALPHA_SABLE) += sys_sable.o
+obj-$(CONFIG_ALPHA_LYNX) += sys_sable.o
+obj-$(CONFIG_ALPHA_BOOK1) += sys_sio.o irq_i8259.o irq_srm.o pc873xx.o
+obj-$(CONFIG_ALPHA_AVANTI) += sys_sio.o irq_i8259.o irq_srm.o pc873xx.o
+obj-$(CONFIG_ALPHA_NONAME) += sys_sio.o irq_i8259.o irq_srm.o pc873xx.o
+obj-$(CONFIG_ALPHA_P2K) += sys_sio.o irq_i8259.o irq_srm.o pc873xx.o
+obj-$(CONFIG_ALPHA_XL) += sys_sio.o irq_i8259.o irq_srm.o pc873xx.o
obj-$(CONFIG_ALPHA_SX164) += sys_sx164.o irq_pyxis.o irq_i8259.o \
irq_srm.o smc37c669.o
obj-$(CONFIG_ALPHA_TAKARA) += sys_takara.o irq_i8259.o pc873xx.o
diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c
new file mode 100644
index 000000000000..6df765ff2b10
--- /dev/null
+++ b/arch/alpha/kernel/core_apecs.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/alpha/kernel/core_apecs.c
+ *
+ * Rewritten for Apecs from the lca.c from:
+ *
+ * Written by David Mosberger (davidm@cs.arizona.edu) with some code
+ * taken from Dave Rusling's (david.rusling@reo.mts.dec.com) 32-bit
+ * bios code.
+ *
+ * Code common to all APECS core logic chips.
+ */
+
+#define __EXTERN_INLINE inline
+#include
+#include
+#undef __EXTERN_INLINE
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "proto.h"
+#include "pci_impl.h"
+
+/*
+ * NOTE: Herein lie back-to-back mb instructions. They are magic.
+ * One plausible explanation is that the i/o controller does not properly
+ * handle the system transaction. Another involves timing. Ho hum.
+ */
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBGC(args) printk args
+#else
+# define DBGC(args)
+#endif
+
+#define vuip volatile unsigned int *
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the APECS_HAXR2 register
+ * accordingly. It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | | | | | | | | | | | | | | |F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:11 Device select bit.
+ * 10:8 Function number
+ * 7:2 Register number
+ *
+ * Type 1:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:24 reserved
+ * 23:16 bus number (8 bits = 128 possible buses)
+ * 15:11 Device number (5 bits)
+ * 10:8 function number
+ * 7:2 register number
+ *
+ * Notes:
+ * The function number selects which function of a multi-function device
+ * (e.g., SCSI and Ethernet).
+ *
+ * The register selects a DWORD (32 bit) register offset. Hence it
+ * doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ * bits.
+ */
+
+static int
+mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where,
+ unsigned long *pci_addr, unsigned char *type1)
+{
+ unsigned long addr;
+ u8 bus = pbus->number;
+
+ DBGC(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
+ " pci_addr=0x%p, type1=0x%p)\n",
+ bus, device_fn, where, pci_addr, type1));
+
+ if (bus == 0) {
+ int device = device_fn >> 3;
+
+ /* type 0 configuration cycle: */
+
+ if (device > 20) {
+ DBGC(("mk_conf_addr: device (%d) > 20, returning -1\n",
+ device));
+ return -1;
+ }
+
+ *type1 = 0;
+ addr = (device_fn << 8) | (where);
+ } else {
+ /* type 1 configuration cycle: */
+ *type1 = 1;
+ addr = (bus << 16) | (device_fn << 8) | (where);
+ }
+ *pci_addr = addr;
+ DBGC(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return 0;
+}
+
+static unsigned int
+conf_read(unsigned long addr, unsigned char type1)
+{
+ unsigned long flags;
+ unsigned int stat0, value;
+ unsigned int haxr2 = 0;
+
+ local_irq_save(flags); /* avoid getting hit by machine check */
+
+ DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+
+ /* Reset status register to avoid losing errors. */
+ stat0 = *(vuip)APECS_IOC_DCSR;
+ *(vuip)APECS_IOC_DCSR = stat0;
+ mb();
+ DBGC(("conf_read: APECS DCSR was 0x%x\n", stat0));
+
+ /* If Type1 access, must set HAE #2. */
+ if (type1) {
+ haxr2 = *(vuip)APECS_IOC_HAXR2;
+ mb();
+ *(vuip)APECS_IOC_HAXR2 = haxr2 | 1;
+ DBGC(("conf_read: TYPE1 access\n"));
+ }
+
+ draina();
+ mcheck_expected(0) = 1;
+ mcheck_taken(0) = 0;
+ mb();
+
+ /* Access configuration space. */
+
+ /* Some SRMs step on these registers during a machine check. */
+ asm volatile("ldl %0,%1; mb; mb" : "=r"(value) : "m"(*(vuip)addr)
+ : "$9", "$10", "$11", "$12", "$13", "$14", "memory");
+
+ if (mcheck_taken(0)) {
+ mcheck_taken(0) = 0;
+ value = 0xffffffffU;
+ mb();
+ }
+ mcheck_expected(0) = 0;
+ mb();
+
+#if 1
+ /*
+ * david.rusling@reo.mts.dec.com. This code is needed for the
+ * EB64+ as it does not generate a machine check (why I don't
+ * know). When we build kernels for one particular platform
+ * then we can make this conditional on the type.
+ */
+ draina();
+
+ /* Now look for any errors. */
+ stat0 = *(vuip)APECS_IOC_DCSR;
+ DBGC(("conf_read: APECS DCSR after read 0x%x\n", stat0));
+
+ /* Is any error bit set? */
+ if (stat0 & 0xffe0U) {
+ /* If not NDEV, print status. */
+ if (!(stat0 & 0x0800)) {
+ printk("apecs.c:conf_read: got stat0=%x\n", stat0);
+ }
+
+ /* Reset error status. */
+ *(vuip)APECS_IOC_DCSR = stat0;
+ mb();
+ wrmces(0x7); /* reset machine check */
+ value = 0xffffffff;
+ }
+#endif
+
+ /* If Type1 access, must reset HAE #2 so normal IO space ops work. */
+ if (type1) {
+ *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1;
+ mb();
+ }
+ local_irq_restore(flags);
+
+ return value;
+}
+
+static void
+conf_write(unsigned long addr, unsigned int value, unsigned char type1)
+{
+ unsigned long flags;
+ unsigned int stat0;
+ unsigned int haxr2 = 0;
+
+ local_irq_save(flags); /* avoid getting hit by machine check */
+
+ /* Reset status register to avoid losing errors. */
+ stat0 = *(vuip)APECS_IOC_DCSR;
+ *(vuip)APECS_IOC_DCSR = stat0;
+ mb();
+
+ /* If Type1 access, must set HAE #2. */
+ if (type1) {
+ haxr2 = *(vuip)APECS_IOC_HAXR2;
+ mb();
+ *(vuip)APECS_IOC_HAXR2 = haxr2 | 1;
+ }
+
+ draina();
+ mcheck_expected(0) = 1;
+ mb();
+
+ /* Access configuration space. */
+ *(vuip)addr = value;
+ mb();
+ mb(); /* magic */
+ mcheck_expected(0) = 0;
+ mb();
+
+#if 1
+ /*
+ * david.rusling@reo.mts.dec.com. This code is needed for the
+ * EB64+ as it does not generate a machine check (why I don't
+ * know). When we build kernels for one particular platform
+ * then we can make this conditional on the type.
+ */
+ draina();
+
+ /* Now look for any errors. */
+ stat0 = *(vuip)APECS_IOC_DCSR;
+
+ /* Is any error bit set? */
+ if (stat0 & 0xffe0U) {
+ /* If not NDEV, print status. */
+ if (!(stat0 & 0x0800)) {
+ printk("apecs.c:conf_write: got stat0=%x\n", stat0);
+ }
+
+ /* Reset error status. */
+ *(vuip)APECS_IOC_DCSR = stat0;
+ mb();
+ wrmces(0x7); /* reset machine check */
+ }
+#endif
+
+ /* If Type1 access, must reset HAE #2 so normal IO space ops work. */
+ if (type1) {
+ *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1;
+ mb();
+ }
+ local_irq_restore(flags);
+}
+
+static int
+apecs_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr, pci_addr;
+ unsigned char type1;
+ long mask;
+ int shift;
+
+ if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ mask = (size - 1) * 8;
+ shift = (where & 3) * 8;
+ addr = (pci_addr << 5) + mask + APECS_CONF;
+ *value = conf_read(addr, type1) >> (shift);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+apecs_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ unsigned long addr, pci_addr;
+ unsigned char type1;
+ long mask;
+
+ if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ mask = (size - 1) * 8;
+ addr = (pci_addr << 5) + mask + APECS_CONF;
+ conf_write(addr, value << ((where & 3) * 8), type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops apecs_pci_ops =
+{
+ .read = apecs_read_config,
+ .write = apecs_write_config,
+};
+
+void
+apecs_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+ wmb();
+ *(vip)APECS_IOC_TBIA = 0;
+ mb();
+}
+
+void __init
+apecs_init_arch(void)
+{
+ struct pci_controller *hose;
+
+ /*
+ * Create our single hose.
+ */
+
+ pci_isa_hose = hose = alloc_pci_controller();
+ hose->io_space = &ioport_resource;
+ hose->mem_space = &iomem_resource;
+ hose->index = 0;
+
+ hose->sparse_mem_base = APECS_SPARSE_MEM - IDENT_ADDR;
+ hose->dense_mem_base = APECS_DENSE_MEM - IDENT_ADDR;
+ hose->sparse_io_base = APECS_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+
+ /*
+ * Set up the PCI to main memory translation windows.
+ *
+ * Window 1 is direct access 1GB at 1GB
+ * Window 2 is scatter-gather 8MB at 8MB (for isa)
+ */
+ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000,
+ SMP_CACHE_BYTES);
+ hose->sg_pci = NULL;
+ __direct_map_base = 0x40000000;
+ __direct_map_size = 0x40000000;
+
+ *(vuip)APECS_IOC_PB1R = __direct_map_base | 0x00080000;
+ *(vuip)APECS_IOC_PM1R = (__direct_map_size - 1) & 0xfff00000U;
+ *(vuip)APECS_IOC_TB1R = 0;
+
+ *(vuip)APECS_IOC_PB2R = hose->sg_isa->dma_base | 0x000c0000;
+ *(vuip)APECS_IOC_PM2R = (hose->sg_isa->size - 1) & 0xfff00000;
+ *(vuip)APECS_IOC_TB2R = virt_to_phys(hose->sg_isa->ptes) >> 1;
+
+ apecs_pci_tbi(hose, 0, -1);
+
+ /*
+ * Finally, clear the HAXR2 register, which gets used
+ * for PCI Config Space accesses. That is the way
+ * we want to use it, and we do not want to depend on
+ * what ARC or SRM might have left behind...
+ */
+ *(vuip)APECS_IOC_HAXR2 = 0;
+ mb();
+}
+
+void
+apecs_pci_clr_err(void)
+{
+ unsigned int jd;
+
+ jd = *(vuip)APECS_IOC_DCSR;
+ if (jd & 0xffe0L) {
+ *(vuip)APECS_IOC_SEAR;
+ *(vuip)APECS_IOC_DCSR = jd | 0xffe1L;
+ mb();
+ *(vuip)APECS_IOC_DCSR;
+ }
+ *(vuip)APECS_IOC_TBIA = (unsigned int)APECS_IOC_TBIA;
+ mb();
+ *(vuip)APECS_IOC_TBIA;
+}
+
+void
+apecs_machine_check(unsigned long vector, unsigned long la_ptr)
+{
+ struct el_common *mchk_header;
+ struct el_apecs_procdata *mchk_procdata;
+ struct el_apecs_sysdata_mcheck *mchk_sysdata;
+
+ mchk_header = (struct el_common *)la_ptr;
+
+ mchk_procdata = (struct el_apecs_procdata *)
+ (la_ptr + mchk_header->proc_offset
+ - sizeof(mchk_procdata->paltemp));
+
+ mchk_sysdata = (struct el_apecs_sysdata_mcheck *)
+ (la_ptr + mchk_header->sys_offset);
+
+
+ /* Clear the error before any reporting. */
+ mb();
+ mb(); /* magic */
+ draina();
+ apecs_pci_clr_err();
+ wrmces(0x7); /* reset machine check pending flag */
+ mb();
+
+ process_mcheck_info(vector, la_ptr, "APECS",
+ (mcheck_expected(0)
+ && (mchk_sysdata->epic_dcsr & 0x0c00UL)));
+}
diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c
new file mode 100644
index 000000000000..4616b11643d5
--- /dev/null
+++ b/arch/alpha/kernel/core_lca.c
@@ -0,0 +1,473 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/alpha/kernel/core_lca.c
+ *
+ * Written by David Mosberger (davidm@cs.arizona.edu) with some code
+ * taken from Dave Rusling's (david.rusling@reo.mts.dec.com) 32-bit
+ * bios code.
+ *
+ * Code common to all LCA core logic chips.
+ */
+
+#define __EXTERN_INLINE inline
+#include
+#include
+#undef __EXTERN_INLINE
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "proto.h"
+#include "pci_impl.h"
+
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+/*
+ * Machine check reasons. Defined according to PALcode sources
+ * (osf.h and platform.h).
+ */
+#define MCHK_K_TPERR 0x0080
+#define MCHK_K_TCPERR 0x0082
+#define MCHK_K_HERR 0x0084
+#define MCHK_K_ECC_C 0x0086
+#define MCHK_K_ECC_NC 0x0088
+#define MCHK_K_UNKNOWN 0x008A
+#define MCHK_K_CACKSOFT 0x008C
+#define MCHK_K_BUGCHECK 0x008E
+#define MCHK_K_OS_BUGCHECK 0x0090
+#define MCHK_K_DCPERR 0x0092
+#define MCHK_K_ICPERR 0x0094
+
+
+/*
+ * Platform-specific machine-check reasons:
+ */
+#define MCHK_K_SIO_SERR 0x204 /* all platforms so far */
+#define MCHK_K_SIO_IOCHK 0x206 /* all platforms so far */
+#define MCHK_K_DCSR 0x208 /* all but Noname */
+
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the LCA_IOC_CONF register
+ * accordingly. It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | | | | | | | | | | | | | | |F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:11 Device select bit.
+ * 10:8 Function number
+ * 7:2 Register number
+ *
+ * Type 1:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:24 reserved
+ * 23:16 bus number (8 bits = 128 possible buses)
+ * 15:11 Device number (5 bits)
+ * 10:8 function number
+ * 7:2 register number
+ *
+ * Notes:
+ * The function number selects which function of a multi-function device
+ * (e.g., SCSI and Ethernet).
+ *
+ * The register selects a DWORD (32 bit) register offset. Hence it
+ * doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ * bits.
+ */
+
+static int
+mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where,
+ unsigned long *pci_addr)
+{
+ unsigned long addr;
+ u8 bus = pbus->number;
+
+ if (bus == 0) {
+ int device = device_fn >> 3;
+ int func = device_fn & 0x7;
+
+ /* Type 0 configuration cycle. */
+
+ if (device > 12) {
+ return -1;
+ }
+
+ *(vulp)LCA_IOC_CONF = 0;
+ addr = (1 << (11 + device)) | (func << 8) | where;
+ } else {
+ /* Type 1 configuration cycle. */
+ *(vulp)LCA_IOC_CONF = 1;
+ addr = (bus << 16) | (device_fn << 8) | where;
+ }
+ *pci_addr = addr;
+ return 0;
+}
+
+static unsigned int
+conf_read(unsigned long addr)
+{
+ unsigned long flags, code, stat0;
+ unsigned int value;
+
+ local_irq_save(flags);
+
+ /* Reset status register to avoid losing errors. */
+ stat0 = *(vulp)LCA_IOC_STAT0;
+ *(vulp)LCA_IOC_STAT0 = stat0;
+ mb();
+
+ /* Access configuration space. */
+ value = *(vuip)addr;
+ draina();
+
+ stat0 = *(vulp)LCA_IOC_STAT0;
+ if (stat0 & LCA_IOC_STAT0_ERR) {
+ code = ((stat0 >> LCA_IOC_STAT0_CODE_SHIFT)
+ & LCA_IOC_STAT0_CODE_MASK);
+ if (code != 1) {
+ printk("lca.c:conf_read: got stat0=%lx\n", stat0);
+ }
+
+ /* Reset error status. */
+ *(vulp)LCA_IOC_STAT0 = stat0;
+ mb();
+
+ /* Reset machine check. */
+ wrmces(0x7);
+
+ value = 0xffffffff;
+ }
+ local_irq_restore(flags);
+ return value;
+}
+
+static void
+conf_write(unsigned long addr, unsigned int value)
+{
+ unsigned long flags, code, stat0;
+
+ local_irq_save(flags); /* avoid getting hit by machine check */
+
+ /* Reset status register to avoid losing errors. */
+ stat0 = *(vulp)LCA_IOC_STAT0;
+ *(vulp)LCA_IOC_STAT0 = stat0;
+ mb();
+
+ /* Access configuration space. */
+ *(vuip)addr = value;
+ draina();
+
+ stat0 = *(vulp)LCA_IOC_STAT0;
+ if (stat0 & LCA_IOC_STAT0_ERR) {
+ code = ((stat0 >> LCA_IOC_STAT0_CODE_SHIFT)
+ & LCA_IOC_STAT0_CODE_MASK);
+ if (code != 1) {
+ printk("lca.c:conf_write: got stat0=%lx\n", stat0);
+ }
+
+ /* Reset error status. */
+ *(vulp)LCA_IOC_STAT0 = stat0;
+ mb();
+
+ /* Reset machine check. */
+ wrmces(0x7);
+ }
+ local_irq_restore(flags);
+}
+
+static int
+lca_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr, pci_addr;
+ long mask;
+ int shift;
+
+ if (mk_conf_addr(bus, devfn, where, &pci_addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ shift = (where & 3) * 8;
+ mask = (size - 1) * 8;
+ addr = (pci_addr << 5) + mask + LCA_CONF;
+ *value = conf_read(addr) >> (shift);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+lca_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size,
+ u32 value)
+{
+ unsigned long addr, pci_addr;
+ long mask;
+
+ if (mk_conf_addr(bus, devfn, where, &pci_addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ mask = (size - 1) * 8;
+ addr = (pci_addr << 5) + mask + LCA_CONF;
+ conf_write(addr, value << ((where & 3) * 8));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops lca_pci_ops =
+{
+ .read = lca_read_config,
+ .write = lca_write_config,
+};
+
+void
+lca_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+ wmb();
+ *(vulp)LCA_IOC_TBIA = 0;
+ mb();
+}
+
+void __init
+lca_init_arch(void)
+{
+ struct pci_controller *hose;
+
+ /*
+ * Create our single hose.
+ */
+
+ pci_isa_hose = hose = alloc_pci_controller();
+ hose->io_space = &ioport_resource;
+ hose->mem_space = &iomem_resource;
+ hose->index = 0;
+
+ hose->sparse_mem_base = LCA_SPARSE_MEM - IDENT_ADDR;
+ hose->dense_mem_base = LCA_DENSE_MEM - IDENT_ADDR;
+ hose->sparse_io_base = LCA_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+
+ /*
+ * Set up the PCI to main memory translation windows.
+ *
+ * Mimic the SRM settings for the direct-map window.
+ * Window 0 is scatter-gather 8MB at 8MB (for isa).
+ * Window 1 is direct access 1GB at 1GB.
+ *
+ * Note that we do not try to save any of the DMA window CSRs
+ * before setting them, since we cannot read those CSRs on LCA.
+ */
+ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000,
+ SMP_CACHE_BYTES);
+ hose->sg_pci = NULL;
+ __direct_map_base = 0x40000000;
+ __direct_map_size = 0x40000000;
+
+ *(vulp)LCA_IOC_W_BASE0 = hose->sg_isa->dma_base | (3UL << 32);
+ *(vulp)LCA_IOC_W_MASK0 = (hose->sg_isa->size - 1) & 0xfff00000;
+ *(vulp)LCA_IOC_T_BASE0 = virt_to_phys(hose->sg_isa->ptes);
+
+ *(vulp)LCA_IOC_W_BASE1 = __direct_map_base | (2UL << 32);
+ *(vulp)LCA_IOC_W_MASK1 = (__direct_map_size - 1) & 0xfff00000;
+ *(vulp)LCA_IOC_T_BASE1 = 0;
+
+ *(vulp)LCA_IOC_TB_ENA = 0x80;
+
+ lca_pci_tbi(hose, 0, -1);
+
+ /*
+ * Disable PCI parity for now. The NCR53c810 chip has
+ * troubles meeting the PCI spec which results in
+ * data parity errors.
+ */
+ *(vulp)LCA_IOC_PAR_DIS = 1UL<<5;
+
+ /*
+ * Finally, set up for restoring the correct HAE if using SRM.
+ * Again, since we cannot read many of the CSRs on the LCA,
+ * one of which happens to be the HAE, we save the value that
+ * the SRM will expect...
+ */
+ if (alpha_using_srm)
+ srm_hae = 0x80000000UL;
+}
+
+/*
+ * Constants used during machine-check handling. I suppose these
+ * could be moved into lca.h but I don't see much reason why anybody
+ * else would want to use them.
+ */
+
+#define ESR_EAV (1UL<< 0) /* error address valid */
+#define ESR_CEE (1UL<< 1) /* correctable error */
+#define ESR_UEE (1UL<< 2) /* uncorrectable error */
+#define ESR_WRE (1UL<< 3) /* write-error */
+#define ESR_SOR (1UL<< 4) /* error source */
+#define ESR_CTE (1UL<< 7) /* cache-tag error */
+#define ESR_MSE (1UL<< 9) /* multiple soft errors */
+#define ESR_MHE (1UL<<10) /* multiple hard errors */
+#define ESR_NXM (1UL<<12) /* non-existent memory */
+
+#define IOC_ERR ( 1<<4) /* ioc logs an error */
+#define IOC_CMD_SHIFT 0
+#define IOC_CMD (0xf<> IOC_CODE_SHIFT;
+ unsigned cmd = (stat0 & IOC_CMD) >> IOC_CMD_SHIFT;
+
+ printk(" %s initiated PCI %s cycle to address %x"
+ " failed due to %s.\n",
+ code > 3 ? "PCI" : "CPU", pci_cmd[cmd], stat1, err_name[code]);
+
+ if (code == 5 || code == 6) {
+ printk(" (Error occurred at PCI memory address %x.)\n",
+ (stat0 & ~IOC_P_NBR));
+ }
+ if (stat0 & IOC_LOST) {
+ printk(" Other PCI errors occurred simultaneously.\n");
+ }
+}
+
+void
+lca_machine_check(unsigned long vector, unsigned long la_ptr)
+{
+ const char * reason;
+ union el_lca el;
+
+ el.c = (struct el_common *) la_ptr;
+
+ wrmces(rdmces()); /* reset machine check pending flag */
+
+ printk(KERN_CRIT "LCA machine check: vector=%#lx pc=%#lx code=%#x\n",
+ vector, get_irq_regs()->pc, (unsigned int) el.c->code);
+
+ /*
+ * The first quadword after the common header always seems to
+ * be the machine check reason---don't know why this isn't
+ * part of the common header instead. In the case of a long
+ * logout frame, the upper 32 bits is the machine check
+ * revision level, which we ignore for now.
+ */
+ switch ((unsigned int) el.c->code) {
+ case MCHK_K_TPERR: reason = "tag parity error"; break;
+ case MCHK_K_TCPERR: reason = "tag control parity error"; break;
+ case MCHK_K_HERR: reason = "access to non-existent memory"; break;
+ case MCHK_K_ECC_C: reason = "correctable ECC error"; break;
+ case MCHK_K_ECC_NC: reason = "non-correctable ECC error"; break;
+ case MCHK_K_CACKSOFT: reason = "MCHK_K_CACKSOFT"; break;
+ case MCHK_K_BUGCHECK: reason = "illegal exception in PAL mode"; break;
+ case MCHK_K_OS_BUGCHECK: reason = "callsys in kernel mode"; break;
+ case MCHK_K_DCPERR: reason = "d-cache parity error"; break;
+ case MCHK_K_ICPERR: reason = "i-cache parity error"; break;
+ case MCHK_K_SIO_SERR: reason = "SIO SERR occurred on PCI bus"; break;
+ case MCHK_K_SIO_IOCHK: reason = "SIO IOCHK occurred on ISA bus"; break;
+ case MCHK_K_DCSR: reason = "MCHK_K_DCSR"; break;
+ case MCHK_K_UNKNOWN:
+ default: reason = "unknown"; break;
+ }
+
+ switch (el.c->size) {
+ case sizeof(struct el_lca_mcheck_short):
+ printk(KERN_CRIT
+ " Reason: %s (short frame%s, dc_stat=%#lx):\n",
+ reason, el.c->retry ? ", retryable" : "",
+ el.s->dc_stat);
+ if (el.s->esr & ESR_EAV) {
+ mem_error(el.s->esr, el.s->ear);
+ }
+ if (el.s->ioc_stat0 & IOC_ERR) {
+ ioc_error(el.s->ioc_stat0, el.s->ioc_stat1);
+ }
+ break;
+
+ case sizeof(struct el_lca_mcheck_long):
+ printk(KERN_CRIT " Reason: %s (long frame%s):\n",
+ reason, el.c->retry ? ", retryable" : "");
+ printk(KERN_CRIT
+ " reason: %#lx exc_addr: %#lx dc_stat: %#lx\n",
+ el.l->pt[0], el.l->exc_addr, el.l->dc_stat);
+ printk(KERN_CRIT " car: %#lx\n", el.l->car);
+ if (el.l->esr & ESR_EAV) {
+ mem_error(el.l->esr, el.l->ear);
+ }
+ if (el.l->ioc_stat0 & IOC_ERR) {
+ ioc_error(el.l->ioc_stat0, el.l->ioc_stat1);
+ }
+ break;
+
+ default:
+ printk(KERN_CRIT " Unknown errorlog size %d\n", el.c->size);
+ }
+
+ /* Dump the logout area to give all info. */
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (alpha_verbose_mcheck > 1) {
+ unsigned long * ptr = (unsigned long *) la_ptr;
+ long i;
+ for (i = 0; i < el.c->size / sizeof(long); i += 2) {
+ printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+ i*sizeof(long), ptr[i], ptr[i+1]);
+ }
+ }
+#endif /* CONFIG_VERBOSE_MCHECK */
+}
diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c
index 29c6c477ac35..1dcf0d9038fd 100644
--- a/arch/alpha/kernel/irq_i8259.c
+++ b/arch/alpha/kernel/irq_i8259.c
@@ -98,6 +98,10 @@ init_i8259a_irqs(void)
#if defined(CONFIG_ALPHA_GENERIC)
# define IACK_SC alpha_mv.iack_sc
+#elif defined(CONFIG_ALPHA_APECS)
+# define IACK_SC APECS_IACK_SC
+#elif defined(CONFIG_ALPHA_LCA)
+# define IACK_SC LCA_IACK_SC
#elif defined(CONFIG_ALPHA_CIA)
# define IACK_SC CIA_IACK_SC
#elif defined(CONFIG_ALPHA_PYXIS)
diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h
index 129ae36b8e6d..c2ebcb39e589 100644
--- a/arch/alpha/kernel/machvec_impl.h
+++ b/arch/alpha/kernel/machvec_impl.h
@@ -44,14 +44,33 @@
#define DO_DEFAULT_RTC .rtc_port = 0x70
+#define DO_EV4_MMU \
+ .max_asn = EV4_MAX_ASN, \
+ .mv_switch_mm = ev4_switch_mm, \
+ .mv_activate_mm = ev4_activate_mm, \
+ .mv_flush_tlb_current = ev4_flush_tlb_current, \
+ .mv_flush_tlb_current_page = ev4_flush_tlb_current_page
+
#define DO_EV5_MMU \
- .max_asn = EV5_MAX_ASN \
+ .max_asn = EV5_MAX_ASN, \
+ .mv_switch_mm = ev5_switch_mm, \
+ .mv_activate_mm = ev5_activate_mm, \
+ .mv_flush_tlb_current = ev5_flush_tlb_current, \
+ .mv_flush_tlb_current_page = ev5_flush_tlb_current_page
#define DO_EV6_MMU \
- .max_asn = EV6_MAX_ASN \
+ .max_asn = EV6_MAX_ASN, \
+ .mv_switch_mm = ev5_switch_mm, \
+ .mv_activate_mm = ev5_activate_mm, \
+ .mv_flush_tlb_current = ev5_flush_tlb_current, \
+ .mv_flush_tlb_current_page = ev5_flush_tlb_current_page
#define DO_EV7_MMU \
- .max_asn = EV6_MAX_ASN \
+ .max_asn = EV6_MAX_ASN, \
+ .mv_switch_mm = ev5_switch_mm, \
+ .mv_activate_mm = ev5_activate_mm, \
+ .mv_flush_tlb_current = ev5_flush_tlb_current, \
+ .mv_flush_tlb_current_page = ev5_flush_tlb_current_page
#define IO_LITE(UP,low) \
.hae_register = (unsigned long *) CAT(UP,_HAE_ADDRESS), \
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
new file mode 100644
index 000000000000..32ca59a5a704
--- /dev/null
+++ b/arch/alpha/kernel/pci-noop.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/alpha/kernel/pci-noop.c
+ *
+ * Stub PCI interfaces for Jensen-specific kernels.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "pci_impl.h"
+#include "proto.h"
+
+
+/*
+ * The PCI controller list.
+ */
+
+struct pci_controller *hose_head, **hose_tail = &hose_head;
+struct pci_controller *pci_isa_hose;
+
+
+struct pci_controller * __init
+alloc_pci_controller(void)
+{
+ struct pci_controller *hose;
+
+ hose = memblock_alloc(sizeof(*hose), SMP_CACHE_BYTES);
+ if (!hose)
+ panic("%s: Failed to allocate %zu bytes\n", __func__,
+ sizeof(*hose));
+
+ *hose_tail = hose;
+ hose_tail = &hose->next;
+
+ return hose;
+}
+
+struct resource * __init
+alloc_resource(void)
+{
+ void *ptr = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
+
+ if (!ptr)
+ panic("%s: Failed to allocate %zu bytes\n", __func__,
+ sizeof(struct resource));
+
+ return ptr;
+}
+
+SYSCALL_DEFINE3(pciconfig_iobase, long, which, unsigned long, bus,
+ unsigned long, dfn)
+{
+ struct pci_controller *hose;
+
+ /* from hose or from bus.devfn */
+ if (which & IOBASE_FROM_HOSE) {
+ for (hose = hose_head; hose; hose = hose->next)
+ if (hose->index == bus)
+ break;
+ if (!hose)
+ return -ENODEV;
+ } else {
+ /* Special hook for ISA access. */
+ if (bus == 0 && dfn == 0)
+ hose = pci_isa_hose;
+ else
+ return -ENODEV;
+ }
+
+ switch (which & ~IOBASE_FROM_HOSE) {
+ case IOBASE_HOSE:
+ return hose->index;
+ case IOBASE_SPARSE_MEM:
+ return hose->sparse_mem_base;
+ case IOBASE_DENSE_MEM:
+ return hose->dense_mem_base;
+ case IOBASE_SPARSE_IO:
+ return hose->sparse_io_base;
+ case IOBASE_DENSE_IO:
+ return hose->dense_io_base;
+ case IOBASE_ROOT_BUS:
+ return hose->bus->number;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
+ unsigned long, off, unsigned long, len, void __user *, buf)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ else
+ return -ENODEV;
+}
+
+SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
+ unsigned long, off, unsigned long, len, void __user *, buf)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ else
+ return -ENODEV;
+}
diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h
index a16325ce21c4..18043af45e2b 100644
--- a/arch/alpha/kernel/pci_impl.h
+++ b/arch/alpha/kernel/pci_impl.h
@@ -143,7 +143,9 @@ struct pci_iommu_arena
unsigned int align_entry;
};
-#if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_CIA)
+#if defined(CONFIG_ALPHA_SRM) && \
+ (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
+ defined(CONFIG_ALPHA_AVANTI))
# define NEED_SRM_SAVE_RESTORE
#else
# undef NEED_SRM_SAVE_RESTORE
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index a8bc3ead776b..5b1d0d71d479 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -17,6 +17,13 @@ struct pci_dev;
struct pci_controller;
struct pci_bus;
+/* core_apecs.c */
+extern struct pci_ops apecs_pci_ops;
+extern void apecs_init_arch(void);
+extern void apecs_pci_clr_err(void);
+extern void apecs_machine_check(unsigned long vector, unsigned long la_ptr);
+extern void apecs_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+
/* core_cia.c */
extern struct pci_ops cia_pci_ops;
extern void cia_init_pci(void);
@@ -32,6 +39,12 @@ extern int irongate_pci_clr_err(void);
extern void irongate_init_arch(void);
#define irongate_pci_tbi ((void *)0)
+/* core_lca.c */
+extern struct pci_ops lca_pci_ops;
+extern void lca_init_arch(void);
+extern void lca_machine_check(unsigned long vector, unsigned long la_ptr);
+extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+
/* core_marvel.c */
extern struct pci_ops marvel_pci_ops;
extern void marvel_init_arch(void);
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index f0af444a69a4..b669d78f896b 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -171,22 +171,35 @@ EXPORT_SYMBOL(__direct_map_size);
asm(".weak "#X)
WEAK(alcor_mv);
+WEAK(alphabook1_mv);
+WEAK(avanti_mv);
+WEAK(cabriolet_mv);
WEAK(clipper_mv);
WEAK(dp264_mv);
WEAK(eb164_mv);
+WEAK(eb64p_mv);
+WEAK(eb66_mv);
+WEAK(eb66p_mv);
WEAK(eiger_mv);
+WEAK(jensen_mv);
WEAK(lx164_mv);
+WEAK(lynx_mv);
WEAK(marvel_ev7_mv);
WEAK(miata_mv);
+WEAK(mikasa_mv);
WEAK(mikasa_primo_mv);
WEAK(monet_mv);
WEAK(nautilus_mv);
+WEAK(noname_mv);
+WEAK(noritake_mv);
WEAK(noritake_primo_mv);
+WEAK(p2k_mv);
WEAK(pc164_mv);
WEAK(privateer_mv);
WEAK(rawhide_mv);
WEAK(ruffian_mv);
WEAK(rx164_mv);
+WEAK(sable_mv);
WEAK(sable_gamma_mv);
WEAK(shark_mv);
WEAK(sx164_mv);
@@ -194,6 +207,7 @@ WEAK(takara_mv);
WEAK(titan_mv);
WEAK(webbrick_mv);
WEAK(wildfire_mv);
+WEAK(xl_mv);
WEAK(xlt_mv);
#undef WEAK
@@ -210,7 +224,7 @@ static void __init
reserve_std_resources(void)
{
static struct resource standard_io_resources[] = {
- { .name = "rtc", .start = 0x70, .end = 0x7f},
+ { .name = "rtc", .start = -1, .end = -1 },
{ .name = "dma1", .start = 0x00, .end = 0x1f },
{ .name = "pic1", .start = 0x20, .end = 0x3f },
{ .name = "timer", .start = 0x40, .end = 0x5f },
@@ -232,6 +246,10 @@ reserve_std_resources(void)
}
}
+ /* Fix up for the Jensen's queer RTC placement. */
+ standard_io_resources[0].start = RTC_PORT(0);
+ standard_io_resources[0].end = RTC_PORT(0) + 0x0f;
+
for (i = 0; i < ARRAY_SIZE(standard_io_resources); ++i)
request_resource(io, standard_io_resources+i);
}
@@ -468,7 +486,14 @@ setup_arch(char **cmdline_p)
/*
* Locate the command line.
*/
- strscpy(command_line, COMMAND_LINE, sizeof(command_line));
+ /* Hack for Jensen... since we're restricted to 8 or 16 chars for
+ boot flags depending on the boot mode, we need some shorthand.
+ This should do for installation. */
+ if (strcmp(COMMAND_LINE, "INSTALL") == 0) {
+ strscpy(command_line, "root=/dev/fd0 load_ramdisk=1", sizeof(command_line));
+ } else {
+ strscpy(command_line, COMMAND_LINE, sizeof(command_line));
+ }
strcpy(boot_command_line, command_line);
*cmdline_p = command_line;
@@ -680,6 +705,12 @@ static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,4};
static char alcor_names[][16] = {"Alcor", "Maverick", "Bret"};
static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2};
+static char eb64p_names[][16] = {"EB64+", "Cabriolet", "AlphaPCI64"};
+static int eb64p_indices[] = {0,0,1,2};
+
+static char eb66_names[][8] = {"EB66", "EB66+"};
+static int eb66_indices[] = {0,0,1};
+
static char marvel_names[][16] = {
"Marvel/EV7"
};
@@ -713,26 +744,26 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu)
NULL, /* Ruby */
NULL, /* Flamingo */
NULL, /* Mannequin */
- NULL, /* Jensens */
+ &jensen_mv,
NULL, /* Pelican */
NULL, /* Morgan */
NULL, /* Sable -- see below. */
NULL, /* Medulla */
- NULL, /* Noname */
+ &noname_mv,
NULL, /* Turbolaser */
- NULL, /* Avanti */
+ &avanti_mv,
NULL, /* Mustang */
NULL, /* Alcor, Bret, Maverick. HWRPB inaccurate? */
NULL, /* Tradewind */
NULL, /* Mikasa -- see below. */
NULL, /* EB64 */
- NULL, /* EB66 */
- NULL, /* EB64+ */
- NULL, /* Alphabook1 */
+ NULL, /* EB66 -- see variation. */
+ NULL, /* EB64+ -- see variation. */
+ &alphabook1_mv,
&rawhide_mv,
NULL, /* K2 */
- NULL, /* Lynx */
- NULL, /* XL */
+ &lynx_mv, /* Lynx */
+ &xl_mv,
NULL, /* EB164 -- see variation. */
NULL, /* Noritake -- see below. */
NULL, /* Cortex */
@@ -771,6 +802,19 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu)
&eb164_mv, &pc164_mv, &lx164_mv, &sx164_mv, &rx164_mv
};
+ static struct alpha_machine_vector *eb64p_vecs[] __initdata =
+ {
+ &eb64p_mv,
+ &cabriolet_mv,
+ &cabriolet_mv /* AlphaPCI64 */
+ };
+
+ static struct alpha_machine_vector *eb66_vecs[] __initdata =
+ {
+ &eb66_mv,
+ &eb66p_mv
+ };
+
static struct alpha_machine_vector *marvel_vecs[] __initdata =
{
&marvel_ev7_mv,
@@ -838,6 +882,14 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu)
if (vec == &eb164_mv && cpu == EV56_CPU)
vec = &pc164_mv;
break;
+ case ST_DEC_EB64P:
+ if (member < ARRAY_SIZE(eb64p_indices))
+ vec = eb64p_vecs[eb64p_indices[member]];
+ break;
+ case ST_DEC_EB66:
+ if (member < ARRAY_SIZE(eb66_indices))
+ vec = eb66_vecs[eb66_indices[member]];
+ break;
case ST_DEC_MARVEL:
if (member < ARRAY_SIZE(marvel_indices))
vec = marvel_vecs[marvel_indices[member]];
@@ -852,13 +904,22 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu)
vec = tsunami_vecs[tsunami_indices[member]];
break;
case ST_DEC_1000:
- vec = &mikasa_primo_mv;
+ if (cpu == EV5_CPU || cpu == EV56_CPU)
+ vec = &mikasa_primo_mv;
+ else
+ vec = &mikasa_mv;
break;
case ST_DEC_NORITAKE:
- vec = &noritake_primo_mv;
+ if (cpu == EV5_CPU || cpu == EV56_CPU)
+ vec = &noritake_primo_mv;
+ else
+ vec = &noritake_mv;
break;
case ST_DEC_2100_A500:
- vec = &sable_gamma_mv;
+ if (cpu == EV5_CPU || cpu == EV56_CPU)
+ vec = &sable_gamma_mv;
+ else
+ vec = &sable_mv;
break;
}
}
@@ -871,27 +932,41 @@ get_sysvec_byname(const char *name)
static struct alpha_machine_vector *all_vecs[] __initdata =
{
&alcor_mv,
+ &alphabook1_mv,
+ &avanti_mv,
+ &cabriolet_mv,
&clipper_mv,
&dp264_mv,
&eb164_mv,
+ &eb64p_mv,
+ &eb66_mv,
+ &eb66p_mv,
&eiger_mv,
+ &jensen_mv,
&lx164_mv,
+ &lynx_mv,
&miata_mv,
+ &mikasa_mv,
&mikasa_primo_mv,
&monet_mv,
&nautilus_mv,
+ &noname_mv,
+ &noritake_mv,
&noritake_primo_mv,
+ &p2k_mv,
&pc164_mv,
&privateer_mv,
&rawhide_mv,
&ruffian_mv,
&rx164_mv,
+ &sable_mv,
&sable_gamma_mv,
&shark_mv,
&sx164_mv,
&takara_mv,
&webbrick_mv,
&wildfire_mv,
+ &xl_mv,
&xlt_mv
};
@@ -953,6 +1028,14 @@ get_sysnames(unsigned long type, unsigned long variation, unsigned long cpu,
if (member < ARRAY_SIZE(alcor_indices))
*variation_name = alcor_names[alcor_indices[member]];
break;
+ case ST_DEC_EB64P:
+ if (member < ARRAY_SIZE(eb64p_indices))
+ *variation_name = eb64p_names[eb64p_indices[member]];
+ break;
+ case ST_DEC_EB66:
+ if (member < ARRAY_SIZE(eb66_indices))
+ *variation_name = eb66_names[eb66_indices[member]];
+ break;
case ST_DEC_MARVEL:
if (member < ARRAY_SIZE(marvel_indices))
*variation_name = marvel_names[marvel_indices[member]];
diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c
index 54e75d4fdbe3..47459b73cdb7 100644
--- a/arch/alpha/kernel/sys_cabriolet.c
+++ b/arch/alpha/kernel/sys_cabriolet.c
@@ -6,7 +6,8 @@
* Copyright (C) 1996 Jay A Estabrook
* Copyright (C) 1998, 1999, 2000 Richard Henderson
*
- * Code supporting the PC164 and LX164.
+ * Code supporting the Cabriolet (AlphaPC64), EB66+, and EB164,
+ * PC164 and LX164.
*/
#include
@@ -22,7 +23,9 @@
#include
#include
#include
+#include
#include
+#include
#include
#include "proto.h"
@@ -229,6 +232,13 @@ cabriolet_enable_ide(void)
}
}
+static inline void __init
+cabriolet_init_pci(void)
+{
+ common_init_pci();
+ cabriolet_enable_ide();
+}
+
static inline void __init
cia_cab_init_pci(void)
{
@@ -307,6 +317,81 @@ alphapc164_init_pci(void)
* The System Vector
*/
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET)
+struct alpha_machine_vector cabriolet_mv __initmv = {
+ .vector_name = "Cabriolet",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_APECS_IO,
+ .machine_check = apecs_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 35,
+ .device_interrupt = cabriolet_device_interrupt,
+
+ .init_arch = apecs_init_arch,
+ .init_irq = cabriolet_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = cabriolet_init_pci,
+ .pci_map_irq = cabriolet_map_irq,
+ .pci_swizzle = common_swizzle,
+};
+#ifndef CONFIG_ALPHA_EB64P
+ALIAS_MV(cabriolet)
+#endif
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB164)
+struct alpha_machine_vector eb164_mv __initmv = {
+ .vector_name = "EB164",
+ DO_EV5_MMU,
+ DO_DEFAULT_RTC,
+ DO_CIA_IO,
+ .machine_check = cia_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = CIA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 35,
+ .device_interrupt = cabriolet_device_interrupt,
+
+ .init_arch = cia_init_arch,
+ .init_irq = cabriolet_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = cia_cab_init_pci,
+ .kill_arch = cia_kill_arch,
+ .pci_map_irq = cabriolet_map_irq,
+ .pci_swizzle = common_swizzle,
+};
+ALIAS_MV(eb164)
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66P)
+struct alpha_machine_vector eb66p_mv __initmv = {
+ .vector_name = "EB66+",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_LCA_IO,
+ .machine_check = lca_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 35,
+ .device_interrupt = cabriolet_device_interrupt,
+
+ .init_arch = lca_init_arch,
+ .init_irq = cabriolet_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = cabriolet_init_pci,
+ .pci_map_irq = eb66p_map_irq,
+ .pci_swizzle = common_swizzle,
+};
+ALIAS_MV(eb66p)
+#endif
+
#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LX164)
struct alpha_machine_vector lx164_mv __initmv = {
.vector_name = "LX164",
diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c
new file mode 100644
index 000000000000..3c43fd347526
--- /dev/null
+++ b/arch/alpha/kernel/sys_eb64p.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/alpha/kernel/sys_eb64p.c
+ *
+ * Copyright (C) 1995 David A Rusling
+ * Copyright (C) 1996 Jay A Estabrook
+ * Copyright (C) 1998, 1999 Richard Henderson
+ *
+ * Code supporting the EB64+ and EB66.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "proto.h"
+#include "irq_impl.h"
+#include "pci_impl.h"
+#include "machvec_impl.h"
+
+
+/* Note mask bit is true for DISABLED irqs. */
+static unsigned int cached_irq_mask = -1;
+
+static inline void
+eb64p_update_irq_hw(unsigned int irq, unsigned long mask)
+{
+ outb(mask >> (irq >= 24 ? 24 : 16), (irq >= 24 ? 0x27 : 0x26));
+}
+
+static inline void
+eb64p_enable_irq(struct irq_data *d)
+{
+ eb64p_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << d->irq));
+}
+
+static void
+eb64p_disable_irq(struct irq_data *d)
+{
+ eb64p_update_irq_hw(d->irq, cached_irq_mask |= 1 << d->irq);
+}
+
+static struct irq_chip eb64p_irq_type = {
+ .name = "EB64P",
+ .irq_unmask = eb64p_enable_irq,
+ .irq_mask = eb64p_disable_irq,
+ .irq_mask_ack = eb64p_disable_irq,
+};
+
+static void
+eb64p_device_interrupt(unsigned long vector)
+{
+ unsigned long pld;
+ unsigned int i;
+
+ /* Read the interrupt summary registers */
+ pld = inb(0x26) | (inb(0x27) << 8);
+
+ /*
+ * Now, for every possible bit set, work through
+ * them and call the appropriate interrupt handler.
+ */
+ while (pld) {
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+
+ if (i == 5) {
+ isa_device_interrupt(vector);
+ } else {
+ handle_irq(16 + i);
+ }
+ }
+}
+
+static void __init
+eb64p_init_irq(void)
+{
+ long i;
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET)
+ /*
+ * CABRIO SRM may not set variation correctly, so here we test
+ * the high word of the interrupt summary register for the RAZ
+ * bits, and hope that a true EB64+ would read all ones...
+ */
+ if (inw(0x806) != 0xffff) {
+ extern struct alpha_machine_vector cabriolet_mv;
+
+ printk("Detected Cabriolet: correcting HWRPB.\n");
+
+ hwrpb->sys_variation |= 2L << 10;
+ hwrpb_update_checksum(hwrpb);
+
+ alpha_mv = cabriolet_mv;
+ alpha_mv.init_irq();
+ return;
+ }
+#endif /* GENERIC */
+
+ outb(0xff, 0x26);
+ outb(0xff, 0x27);
+
+ init_i8259a_irqs();
+
+ for (i = 16; i < 32; ++i) {
+ irq_set_chip_and_handler(i, &eb64p_irq_type, handle_level_irq);
+ irq_set_status_flags(i, IRQ_LEVEL);
+ }
+
+ common_init_isa_dma();
+ if (request_irq(16 + 5, no_action, 0, "isa-cascade", NULL))
+ pr_err("Failed to register isa-cascade interrupt\n");
+}
+
+/*
+ * PCI Fixup configuration.
+ *
+ * There are two 8 bit external summary registers as follows:
+ *
+ * Summary @ 0x26:
+ * Bit Meaning
+ * 0 Interrupt Line A from slot 0
+ * 1 Interrupt Line A from slot 1
+ * 2 Interrupt Line B from slot 0
+ * 3 Interrupt Line B from slot 1
+ * 4 Interrupt Line C from slot 0
+ * 5 Interrupt line from the two ISA PICs
+ * 6 Tulip
+ * 7 NCR SCSI
+ *
+ * Summary @ 0x27
+ * Bit Meaning
+ * 0 Interrupt Line C from slot 1
+ * 1 Interrupt Line D from slot 0
+ * 2 Interrupt Line D from slot 1
+ * 3 RAZ
+ * 4 RAZ
+ * 5 RAZ
+ * 6 RAZ
+ * 7 RAZ
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot Device
+ * 5 NCR SCSI controller
+ * 6 PCI on board slot 0
+ * 7 PCI on board slot 1
+ * 8 Intel SIO PCI-ISA bridge chip
+ * 9 Tulip - DECchip 21040 Ethernet controller
+ *
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and
+ * above for PCI interrupts. The IRQ relates to which bit the interrupt
+ * comes in on. This makes interrupt processing much easier.
+ */
+
+static int
+eb64p_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ static char irq_tab[5][5] = {
+ /*INT INTA INTB INTC INTD */
+ {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */
+ {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */
+ {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */
+ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
+ {16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 9, TULIP */
+ };
+ const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5;
+ return COMMON_TABLE_LOOKUP;
+}
+
+
+/*
+ * The System Vector
+ */
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB64P)
+struct alpha_machine_vector eb64p_mv __initmv = {
+ .vector_name = "EB64+",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_APECS_IO,
+ .machine_check = apecs_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 32,
+ .device_interrupt = eb64p_device_interrupt,
+
+ .init_arch = apecs_init_arch,
+ .init_irq = eb64p_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = common_init_pci,
+ .kill_arch = NULL,
+ .pci_map_irq = eb64p_map_irq,
+ .pci_swizzle = common_swizzle,
+};
+ALIAS_MV(eb64p)
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66)
+struct alpha_machine_vector eb66_mv __initmv = {
+ .vector_name = "EB66",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_LCA_IO,
+ .machine_check = lca_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 32,
+ .device_interrupt = eb64p_device_interrupt,
+
+ .init_arch = lca_init_arch,
+ .init_irq = eb64p_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = common_init_pci,
+ .pci_map_irq = eb64p_map_irq,
+ .pci_swizzle = common_swizzle,
+};
+ALIAS_MV(eb66)
+#endif
diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
new file mode 100644
index 000000000000..a1bb1c4a7e93
--- /dev/null
+++ b/arch/alpha/kernel/sys_jensen.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/alpha/kernel/sys_jensen.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright (C) 1998, 1999 Richard Henderson
+ *
+ * Code supporting the Jensen.
+ */
+#define __EXTERN_INLINE inline
+#include
+#include
+#undef __EXTERN_INLINE
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "proto.h"
+#include "irq_impl.h"
+#include "pci_impl.h"
+#include "machvec_impl.h"
+
+
+/*
+ * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and
+ * 0x9X0 for the local motherboard interrupts.
+ *
+ * Note especially that those local interrupts CANNOT be masked,
+ * which causes much of the pain below...
+ *
+ * 0x660 - NMI
+ *
+ * 0x800 - IRQ0 interval timer (not used, as we use the RTC timer)
+ * 0x810 - IRQ1 line printer (duh..)
+ * 0x860 - IRQ6 floppy disk
+ *
+ * 0x900 - COM1
+ * 0x920 - COM2
+ * 0x980 - keyboard
+ * 0x990 - mouse
+ *
+ * PCI-based systems are more sane: they don't have the local
+ * interrupts at all, and have only normal PCI interrupts from
+ * devices. Happily it's easy enough to do a sane mapping from the
+ * Jensen.
+ *
+ * Note that this means that we may have to do a hardware
+ * "local_op" to a different interrupt than we report to the rest of the
+ * world.
+ */
+
+static void
+jensen_local_enable(struct irq_data *d)
+{
+ /* the parport is really hw IRQ 1, silly Jensen. */
+ if (d->irq == 7)
+ i8259a_enable_irq(d);
+}
+
+static void
+jensen_local_disable(struct irq_data *d)
+{
+ /* the parport is really hw IRQ 1, silly Jensen. */
+ if (d->irq == 7)
+ i8259a_disable_irq(d);
+}
+
+static void
+jensen_local_mask_ack(struct irq_data *d)
+{
+ /* the parport is really hw IRQ 1, silly Jensen. */
+ if (d->irq == 7)
+ i8259a_mask_and_ack_irq(d);
+}
+
+static struct irq_chip jensen_local_irq_type = {
+ .name = "LOCAL",
+ .irq_unmask = jensen_local_enable,
+ .irq_mask = jensen_local_disable,
+ .irq_mask_ack = jensen_local_mask_ack,
+};
+
+static void
+jensen_device_interrupt(unsigned long vector)
+{
+ int irq;
+
+ switch (vector) {
+ case 0x660:
+ printk("Whee.. NMI received. Probable hardware error\n");
+ printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
+ return;
+
+ /* local device interrupts: */
+ case 0x900: irq = 4; break; /* com1 -> irq 4 */
+ case 0x920: irq = 3; break; /* com2 -> irq 3 */
+ case 0x980: irq = 1; break; /* kbd -> irq 1 */
+ case 0x990: irq = 9; break; /* mouse -> irq 9 */
+
+ default:
+ if (vector > 0x900) {
+ printk("Unknown local interrupt %lx\n", vector);
+ return;
+ }
+
+ irq = (vector - 0x800) >> 4;
+ if (irq == 1)
+ irq = 7;
+ break;
+ }
+
+ /* If there is no handler yet... */
+ if (!irq_has_action(irq)) {
+ /* If it is a local interrupt that cannot be masked... */
+ if (vector >= 0x900)
+ {
+ /* Clear keyboard/mouse state */
+ inb(0x64);
+ inb(0x60);
+ /* Reset serial ports */
+ inb(0x3fa);
+ inb(0x2fa);
+ outb(0x0c, 0x3fc);
+ outb(0x0c, 0x2fc);
+ /* Clear NMI */
+ outb(0,0x61);
+ outb(0,0x461);
+ }
+ }
+
+#if 0
+ /* A useful bit of code to find out if an interrupt is going wild. */
+ {
+ static unsigned int last_msg = 0, last_cc = 0;
+ static int last_irq = -1, count = 0;
+ unsigned int cc;
+
+ __asm __volatile("rpcc %0" : "=r"(cc));
+ ++count;
+#define JENSEN_CYCLES_PER_SEC (150000000)
+ if (cc - last_msg > ((JENSEN_CYCLES_PER_SEC) * 3) ||
+ irq != last_irq) {
+ printk(KERN_CRIT " irq %d count %d cc %u @ %lx\n",
+ irq, count, cc-last_cc, get_irq_regs()->pc);
+ count = 0;
+ last_msg = cc;
+ last_irq = irq;
+ }
+ last_cc = cc;
+ }
+#endif
+
+ handle_irq(irq);
+}
+
+static void __init
+jensen_init_irq(void)
+{
+ init_i8259a_irqs();
+
+ irq_set_chip_and_handler(1, &jensen_local_irq_type, handle_level_irq);
+ irq_set_chip_and_handler(4, &jensen_local_irq_type, handle_level_irq);
+ irq_set_chip_and_handler(3, &jensen_local_irq_type, handle_level_irq);
+ irq_set_chip_and_handler(7, &jensen_local_irq_type, handle_level_irq);
+ irq_set_chip_and_handler(9, &jensen_local_irq_type, handle_level_irq);
+
+ common_init_isa_dma();
+}
+
+static void __init
+jensen_init_arch(void)
+{
+ struct pci_controller *hose;
+#ifdef CONFIG_PCI
+ static struct pci_dev fake_isa_bridge = { .dma_mask = 0xffffffffUL, };
+
+ isa_bridge = &fake_isa_bridge;
+#endif
+
+ /* Create a hose so that we can report i/o base addresses to
+ userland. */
+
+ pci_isa_hose = hose = alloc_pci_controller();
+ hose->io_space = &ioport_resource;
+ hose->mem_space = &iomem_resource;
+ hose->index = 0;
+
+ hose->sparse_mem_base = EISA_MEM - IDENT_ADDR;
+ hose->dense_mem_base = 0;
+ hose->sparse_io_base = EISA_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+
+ hose->sg_isa = hose->sg_pci = NULL;
+ __direct_map_base = 0;
+ __direct_map_size = 0xffffffff;
+}
+
+static void
+jensen_machine_check(unsigned long vector, unsigned long la)
+{
+ printk(KERN_CRIT "Machine check\n");
+}
+
+/*
+ * The System Vector
+ */
+
+struct alpha_machine_vector jensen_mv __initmv = {
+ .vector_name = "Jensen",
+ DO_EV4_MMU,
+ IO_LITE(JENSEN,jensen),
+ .machine_check = jensen_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .rtc_port = 0x170,
+
+ .nr_irqs = 16,
+ .device_interrupt = jensen_device_interrupt,
+
+ .init_arch = jensen_init_arch,
+ .init_irq = jensen_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = NULL,
+ .kill_arch = NULL,
+};
+ALIAS_MV(jensen)
diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c
index 557802398231..7690dfd57cb6 100644
--- a/arch/alpha/kernel/sys_mikasa.c
+++ b/arch/alpha/kernel/sys_mikasa.c
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
@@ -163,9 +164,64 @@ mikasa_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
}
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
+static void
+mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr)
+{
+#define MCHK_NO_DEVSEL 0x205U
+#define MCHK_NO_TABT 0x204U
+
+ struct el_common *mchk_header;
+ unsigned int code;
+
+ mchk_header = (struct el_common *)la_ptr;
+
+ /* Clear the error before any reporting. */
+ mb();
+ mb(); /* magic */
+ draina();
+ apecs_pci_clr_err();
+ wrmces(0x7);
+ mb();
+
+ code = mchk_header->code;
+ process_mcheck_info(vector, la_ptr, "MIKASA APECS",
+ (mcheck_expected(0)
+ && (code == MCHK_NO_DEVSEL
+ || code == MCHK_NO_TABT)));
+}
+#endif
+
+
/*
* The System Vector
*/
+
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
+struct alpha_machine_vector mikasa_mv __initmv = {
+ .vector_name = "Mikasa",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_APECS_IO,
+ .machine_check = mikasa_apecs_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 32,
+ .device_interrupt = mikasa_device_interrupt,
+
+ .init_arch = apecs_init_arch,
+ .init_irq = mikasa_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = common_init_pci,
+ .pci_map_irq = mikasa_map_irq,
+ .pci_swizzle = common_swizzle,
+};
+ALIAS_MV(mikasa)
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PRIMO)
struct alpha_machine_vector mikasa_primo_mv __initmv = {
.vector_name = "Mikasa-Primo",
DO_EV5_MMU,
@@ -188,3 +244,4 @@ struct alpha_machine_vector mikasa_primo_mv __initmv = {
.pci_swizzle = common_swizzle,
};
ALIAS_MV(mikasa_primo)
+#endif
diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c
index eed3f16561c0..47f3ce4f719a 100644
--- a/arch/alpha/kernel/sys_noritake.c
+++ b/arch/alpha/kernel/sys_noritake.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
@@ -252,6 +253,64 @@ noritake_swizzle(struct pci_dev *dev, u8 *pinp)
return slot;
}
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
+static void
+noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr)
+{
+#define MCHK_NO_DEVSEL 0x205U
+#define MCHK_NO_TABT 0x204U
+
+ struct el_common *mchk_header;
+ unsigned int code;
+
+ mchk_header = (struct el_common *)la_ptr;
+
+ /* Clear the error before any reporting. */
+ mb();
+ mb(); /* magic */
+ draina();
+ apecs_pci_clr_err();
+ wrmces(0x7);
+ mb();
+
+ code = mchk_header->code;
+ process_mcheck_info(vector, la_ptr, "NORITAKE APECS",
+ (mcheck_expected(0)
+ && (code == MCHK_NO_DEVSEL
+ || code == MCHK_NO_TABT)));
+}
+#endif
+
+
+/*
+ * The System Vectors
+ */
+
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
+struct alpha_machine_vector noritake_mv __initmv = {
+ .vector_name = "Noritake",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_APECS_IO,
+ .machine_check = noritake_apecs_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = EISA_DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 48,
+ .device_interrupt = noritake_device_interrupt,
+
+ .init_arch = apecs_init_arch,
+ .init_irq = noritake_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = common_init_pci,
+ .pci_map_irq = noritake_map_irq,
+ .pci_swizzle = noritake_swizzle,
+};
+ALIAS_MV(noritake)
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PRIMO)
struct alpha_machine_vector noritake_primo_mv __initmv = {
.vector_name = "Noritake-Primo",
DO_EV5_MMU,
@@ -274,3 +333,4 @@ struct alpha_machine_vector noritake_primo_mv __initmv = {
.pci_swizzle = noritake_swizzle,
};
ALIAS_MV(noritake_primo)
+#endif
diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c
index 49f5c75134ec..930005b2f630 100644
--- a/arch/alpha/kernel/sys_sable.c
+++ b/arch/alpha/kernel/sys_sable.c
@@ -212,6 +212,232 @@ sable_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
}
#endif /* defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SABLE) */
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LYNX)
+
+/***********************************************************************/
+/* LYNX hardware specifics
+ */
+/*
+ * For LYNX, which is also baroque, we manage 64 IRQs, via a custom IC.
+ *
+ * Bit Meaning Kernel IRQ
+ *------------------------------------------
+ * 0
+ * 1
+ * 2
+ * 3 mouse 12
+ * 4
+ * 5
+ * 6 keyboard 1
+ * 7 floppy 6
+ * 8 COM2 3
+ * 9 parallel port 7
+ *10 EISA irq 3 -
+ *11 EISA irq 4 -
+ *12 EISA irq 5 5
+ *13 EISA irq 6 -
+ *14 EISA irq 7 -
+ *15 COM1 4
+ *16 EISA irq 9 9
+ *17 EISA irq 10 10
+ *18 EISA irq 11 11
+ *19 EISA irq 12 -
+ *20
+ *21 EISA irq 14 14
+ *22 EISA irq 15 15
+ *23 IIC -
+ *24 VGA (builtin) -
+ *25
+ *26
+ *27
+ *28 NCR810 (builtin) 28
+ *29
+ *30
+ *31
+ *32 PCI 0 slot 4 A primary bus 32
+ *33 PCI 0 slot 4 B primary bus 33
+ *34 PCI 0 slot 4 C primary bus 34
+ *35 PCI 0 slot 4 D primary bus
+ *36 PCI 0 slot 5 A primary bus
+ *37 PCI 0 slot 5 B primary bus
+ *38 PCI 0 slot 5 C primary bus
+ *39 PCI 0 slot 5 D primary bus
+ *40 PCI 0 slot 6 A primary bus
+ *41 PCI 0 slot 6 B primary bus
+ *42 PCI 0 slot 6 C primary bus
+ *43 PCI 0 slot 6 D primary bus
+ *44 PCI 0 slot 7 A primary bus
+ *45 PCI 0 slot 7 B primary bus
+ *46 PCI 0 slot 7 C primary bus
+ *47 PCI 0 slot 7 D primary bus
+ *48 PCI 0 slot 0 A secondary bus
+ *49 PCI 0 slot 0 B secondary bus
+ *50 PCI 0 slot 0 C secondary bus
+ *51 PCI 0 slot 0 D secondary bus
+ *52 PCI 0 slot 1 A secondary bus
+ *53 PCI 0 slot 1 B secondary bus
+ *54 PCI 0 slot 1 C secondary bus
+ *55 PCI 0 slot 1 D secondary bus
+ *56 PCI 0 slot 2 A secondary bus
+ *57 PCI 0 slot 2 B secondary bus
+ *58 PCI 0 slot 2 C secondary bus
+ *59 PCI 0 slot 2 D secondary bus
+ *60 PCI 0 slot 3 A secondary bus
+ *61 PCI 0 slot 3 B secondary bus
+ *62 PCI 0 slot 3 C secondary bus
+ *63 PCI 0 slot 3 D secondary bus
+ */
+
+static void
+lynx_update_irq_hw(unsigned long bit, unsigned long mask)
+{
+ /*
+ * Write the AIR register on the T3/T4 with the
+ * address of the IC mask register (offset 0x40)
+ */
+ *(vulp)T2_AIR = 0x40;
+ mb();
+ *(vulp)T2_AIR; /* re-read to force write */
+ mb();
+ *(vulp)T2_DIR = mask;
+ mb();
+ mb();
+}
+
+static void
+lynx_ack_irq_hw(unsigned long bit)
+{
+ *(vulp)T2_VAR = (u_long) bit;
+ mb();
+ mb();
+}
+
+static irq_swizzle_t lynx_irq_swizzle = {
+ { /* irq_to_mask */
+ -1, 6, -1, 8, 15, 12, 7, 9, /* pseudo PIC 0-7 */
+ -1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo */
+ -1, -1, -1, -1, 28, -1, -1, -1, /* pseudo */
+ 32, 33, 34, 35, 36, 37, 38, 39, /* mask 32-39 */
+ 40, 41, 42, 43, 44, 45, 46, 47, /* mask 40-47 */
+ 48, 49, 50, 51, 52, 53, 54, 55, /* mask 48-55 */
+ 56, 57, 58, 59, 60, 61, 62, 63 /* mask 56-63 */
+ },
+ { /* mask_to_irq */
+ -1, -1, -1, 12, -1, -1, 1, 6, /* mask 0-7 */
+ 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */
+ 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */
+ -1, -1, -1, -1, 28, -1, -1, -1, /* mask 24-31 */
+ 32, 33, 34, 35, 36, 37, 38, 39, /* mask 32-39 */
+ 40, 41, 42, 43, 44, 45, 46, 47, /* mask 40-47 */
+ 48, 49, 50, 51, 52, 53, 54, 55, /* mask 48-55 */
+ 56, 57, 58, 59, 60, 61, 62, 63 /* mask 56-63 */
+ },
+ -1,
+ lynx_update_irq_hw,
+ lynx_ack_irq_hw
+};
+
+static void __init
+lynx_init_irq(void)
+{
+ sable_lynx_irq_swizzle = &lynx_irq_swizzle;
+ sable_lynx_init_irq(64);
+}
+
+/*
+ * PCI Fixup configuration for ALPHA LYNX (2100A)
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot Device
+ * 0 none
+ * 1 none
+ * 2 PCI-EISA bridge
+ * 3 PCI-PCI bridge
+ * 4 NCR 810 (Demi-Lynx only)
+ * 5 none
+ * 6 PCI on board slot 4
+ * 7 PCI on board slot 5
+ * 8 PCI on board slot 6
+ * 9 PCI on board slot 7
+ *
+ * And behind the PPB we have:
+ *
+ * 11 PCI on board slot 0
+ * 12 PCI on board slot 1
+ * 13 PCI on board slot 2
+ * 14 PCI on board slot 3
+ */
+/*
+ * NOTE: the IRQ assignments below are arbitrary, but need to be consistent
+ * with the values in the irq swizzling tables above.
+ */
+
+static int
+lynx_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ static char irq_tab[19][5] = {
+ /*INT INTA INTB INTC INTD */
+ { -1, -1, -1, -1, -1}, /* IdSel 13, PCEB */
+ { -1, -1, -1, -1, -1}, /* IdSel 14, PPB */
+ { 28, 28, 28, 28, 28}, /* IdSel 15, NCR demi */
+ { -1, -1, -1, -1, -1}, /* IdSel 16, none */
+ { 32, 32, 33, 34, 35}, /* IdSel 17, slot 4 */
+ { 36, 36, 37, 38, 39}, /* IdSel 18, slot 5 */
+ { 40, 40, 41, 42, 43}, /* IdSel 19, slot 6 */
+ { 44, 44, 45, 46, 47}, /* IdSel 20, slot 7 */
+ { -1, -1, -1, -1, -1}, /* IdSel 22, none */
+ /* The following are actually behind the PPB. */
+ { -1, -1, -1, -1, -1}, /* IdSel 16 none */
+ { 28, 28, 28, 28, 28}, /* IdSel 17 NCR lynx */
+ { -1, -1, -1, -1, -1}, /* IdSel 18 none */
+ { -1, -1, -1, -1, -1}, /* IdSel 19 none */
+ { -1, -1, -1, -1, -1}, /* IdSel 20 none */
+ { -1, -1, -1, -1, -1}, /* IdSel 21 none */
+ { 48, 48, 49, 50, 51}, /* IdSel 22 slot 0 */
+ { 52, 52, 53, 54, 55}, /* IdSel 23 slot 1 */
+ { 56, 56, 57, 58, 59}, /* IdSel 24 slot 2 */
+ { 60, 60, 61, 62, 63} /* IdSel 25 slot 3 */
+ };
+ const long min_idsel = 2, max_idsel = 20, irqs_per_slot = 5;
+ return COMMON_TABLE_LOOKUP;
+}
+
+static u8
+lynx_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+ int slot, pin = *pinp;
+
+ if (dev->bus->number == 0) {
+ slot = PCI_SLOT(dev->devfn);
+ }
+ /* Check for the built-in bridge */
+ else if (PCI_SLOT(dev->bus->self->devfn) == 3) {
+ slot = PCI_SLOT(dev->devfn) + 11;
+ }
+ else
+ {
+ /* Must be a card-based bridge. */
+ do {
+ if (PCI_SLOT(dev->bus->self->devfn) == 3) {
+ slot = PCI_SLOT(dev->devfn) + 11;
+ break;
+ }
+ pin = pci_swizzle_interrupt_pin(dev, pin);
+
+ /* Move up the chain of bridges. */
+ dev = dev->bus->self;
+ /* Slot of the next bridge. */
+ slot = PCI_SLOT(dev->devfn);
+ } while (dev->bus->self);
+ }
+ *pinp = pin;
+ return slot;
+}
+
+#endif /* defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LYNX) */
+
/***********************************************************************/
/* GENERIC irq routines */
@@ -313,7 +539,40 @@ sable_lynx_init_pci(void)
* these games with GAMMA_BIAS.
*/
-#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SABLE)
+#if defined(CONFIG_ALPHA_GENERIC) || \
+ (defined(CONFIG_ALPHA_SABLE) && !defined(CONFIG_ALPHA_GAMMA))
+#undef GAMMA_BIAS
+#define GAMMA_BIAS 0
+struct alpha_machine_vector sable_mv __initmv = {
+ .vector_name = "Sable",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_T2_IO,
+ .machine_check = t2_machine_check,
+ .max_isa_dma_address = ALPHA_SABLE_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = EISA_DEFAULT_IO_BASE,
+ .min_mem_address = T2_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 40,
+ .device_interrupt = sable_lynx_srm_device_interrupt,
+
+ .init_arch = t2_init_arch,
+ .init_irq = sable_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = sable_lynx_init_pci,
+ .kill_arch = t2_kill_arch,
+ .pci_map_irq = sable_map_irq,
+ .pci_swizzle = common_swizzle,
+
+ .sys = { .t2 = {
+ .gamma_bias = 0
+ } }
+};
+ALIAS_MV(sable)
+#endif /* GENERIC || (SABLE && !GAMMA) */
+
+#if defined(CONFIG_ALPHA_GENERIC) || \
+ (defined(CONFIG_ALPHA_SABLE) && defined(CONFIG_ALPHA_GAMMA))
#undef GAMMA_BIAS
#define GAMMA_BIAS _GAMMA_BIAS
struct alpha_machine_vector sable_gamma_mv __initmv = {
@@ -342,4 +601,35 @@ struct alpha_machine_vector sable_gamma_mv __initmv = {
} }
};
ALIAS_MV(sable_gamma)
-#endif /* GENERIC || SABLE */
+#endif /* GENERIC || (SABLE && GAMMA) */
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LYNX)
+#undef GAMMA_BIAS
+#define GAMMA_BIAS _GAMMA_BIAS
+struct alpha_machine_vector lynx_mv __initmv = {
+ .vector_name = "Lynx",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_T2_IO,
+ .machine_check = t2_machine_check,
+ .max_isa_dma_address = ALPHA_SABLE_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = EISA_DEFAULT_IO_BASE,
+ .min_mem_address = T2_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 64,
+ .device_interrupt = sable_lynx_srm_device_interrupt,
+
+ .init_arch = t2_init_arch,
+ .init_irq = lynx_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = sable_lynx_init_pci,
+ .kill_arch = t2_kill_arch,
+ .pci_map_irq = lynx_map_irq,
+ .pci_swizzle = lynx_swizzle,
+
+ .sys = { .t2 = {
+ .gamma_bias = _GAMMA_BIAS
+ } }
+};
+ALIAS_MV(lynx)
+#endif /* GENERIC || LYNX */
diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c
new file mode 100644
index 000000000000..c28a6ae1d989
--- /dev/null
+++ b/arch/alpha/kernel/sys_sio.c
@@ -0,0 +1,486 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/alpha/kernel/sys_sio.c
+ *
+ * Copyright (C) 1995 David A Rusling
+ * Copyright (C) 1996 Jay A Estabrook
+ * Copyright (C) 1998, 1999 Richard Henderson
+ *
+ * Code for all boards that route the PCI interrupts through the SIO
+ * PCI/ISA bridge. This includes Noname (AXPpci33), Multia (UDB),
+ * Kenetics's Platform 2000, Avanti (AlphaStation), XL, and AlphaBook1.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "proto.h"
+#include "irq_impl.h"
+#include "pci_impl.h"
+#include "machvec_impl.h"
+#include "pc873xx.h"
+
+#if defined(ALPHA_RESTORE_SRM_SETUP)
+/* Save LCA configuration data as the console had it set up. */
+struct
+{
+ unsigned int orig_route_tab; /* for SAVE/RESTORE */
+} saved_config __attribute((common));
+#endif
+
+
+static void __init
+sio_init_irq(void)
+{
+ if (alpha_using_srm)
+ alpha_mv.device_interrupt = srm_device_interrupt;
+
+ init_i8259a_irqs();
+ common_init_isa_dma();
+}
+
+static inline void __init
+alphabook1_init_arch(void)
+{
+#ifdef CONFIG_VGA_CONSOLE
+ /* The AlphaBook1 has LCD video fixed at 800x600,
+ 37 rows and 100 cols. */
+ vgacon_screen_info.orig_y = 37;
+ vgacon_screen_info.orig_video_cols = 100;
+ vgacon_screen_info.orig_video_lines = 37;
+#endif
+
+ lca_init_arch();
+}
+
+
+/*
+ * sio_route_tab selects irq routing in PCI/ISA bridge so that:
+ * PIRQ0 -> irq 15
+ * PIRQ1 -> irq 9
+ * PIRQ2 -> irq 10
+ * PIRQ3 -> irq 11
+ *
+ * This probably ought to be configurable via MILO. For
+ * example, sound boards seem to like using IRQ 9.
+ *
+ * This is NOT how we should do it. PIRQ0-X should have
+ * their own IRQs, the way intel uses the IO-APIC IRQs.
+ */
+
+static void __init
+sio_pci_route(void)
+{
+ unsigned int orig_route_tab;
+
+ /* First, ALWAYS read and print the original setting. */
+ pci_bus_read_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60,
+ &orig_route_tab);
+ printk("%s: PIRQ original 0x%x new 0x%x\n", __func__,
+ orig_route_tab, alpha_mv.sys.sio.route_tab);
+
+#if defined(ALPHA_RESTORE_SRM_SETUP)
+ saved_config.orig_route_tab = orig_route_tab;
+#endif
+
+ /* Now override with desired setting. */
+ pci_bus_write_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60,
+ alpha_mv.sys.sio.route_tab);
+}
+
+static bool sio_pci_dev_irq_needs_level(const struct pci_dev *dev)
+{
+ if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
+ (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
+ return false;
+
+ return true;
+}
+
+static unsigned int __init
+sio_collect_irq_levels(void)
+{
+ unsigned int level_bits = 0;
+ struct pci_dev *dev = NULL;
+
+ /* Iterate through the devices, collecting IRQ levels. */
+ for_each_pci_dev(dev) {
+ if (!sio_pci_dev_irq_needs_level(dev))
+ continue;
+
+ if (dev->irq)
+ level_bits |= (1 << dev->irq);
+ }
+ return level_bits;
+}
+
+static void __sio_fixup_irq_levels(unsigned int level_bits, bool reset)
+{
+ unsigned int old_level_bits;
+
+ /*
+ * Now, make all PCI interrupts level sensitive. Notice:
+ * these registers must be accessed byte-wise. inw()/outw()
+ * don't work.
+ *
+ * Make sure to turn off any level bits set for IRQs 9,10,11,15,
+ * so that the only bits getting set are for devices actually found.
+ * Note that we do preserve the remainder of the bits, which we hope
+ * will be set correctly by ARC/SRM.
+ *
+ * Note: we at least preserve any level-set bits on AlphaBook1
+ */
+ old_level_bits = inb(0x4d0) | (inb(0x4d1) << 8);
+
+ if (reset)
+ old_level_bits &= 0x71ff;
+
+ level_bits |= old_level_bits;
+
+ outb((level_bits >> 0) & 0xff, 0x4d0);
+ outb((level_bits >> 8) & 0xff, 0x4d1);
+}
+
+static inline void
+sio_fixup_irq_levels(unsigned int level_bits)
+{
+ __sio_fixup_irq_levels(level_bits, true);
+}
+
+static inline int
+noname_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ /*
+ * The Noname board has 5 PCI slots with each of the 4
+ * interrupt pins routed to different pins on the PCI/ISA
+ * bridge (PIRQ0-PIRQ3). The table below is based on
+ * information available at:
+ *
+ * http://ftp.digital.com/pub/DEC/axppci/ref_interrupts.txt
+ *
+ * I have no information on the Avanti interrupt routing, but
+ * the routing seems to be identical to the Noname except
+ * that the Avanti has an additional slot whose routing I'm
+ * unsure of.
+ *
+ * pirq_tab[0] is a fake entry to deal with old PCI boards
+ * that have the interrupt pin number hardwired to 0 (meaning
+ * that they use the default INTA line, if they are interrupt
+ * driven at all).
+ */
+ static char irq_tab[][5] = {
+ /*INT A B C D */
+ { 3, 3, 3, 3, 3}, /* idsel 6 (53c810) */
+ {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */
+ { 2, 2, -1, -1, -1}, /* idsel 8 (Hack: slot closest ISA) */
+ {-1, -1, -1, -1, -1}, /* idsel 9 (unused) */
+ {-1, -1, -1, -1, -1}, /* idsel 10 (unused) */
+ { 0, 0, 2, 1, 0}, /* idsel 11 KN25_PCI_SLOT0 */
+ { 1, 1, 0, 2, 1}, /* idsel 12 KN25_PCI_SLOT1 */
+ { 2, 2, 1, 0, 2}, /* idsel 13 KN25_PCI_SLOT2 */
+ { 0, 0, 0, 0, 0}, /* idsel 14 AS255 TULIP */
+ };
+ const long min_idsel = 6, max_idsel = 14, irqs_per_slot = 5;
+ int irq = COMMON_TABLE_LOOKUP, tmp;
+ tmp = __kernel_extbl(alpha_mv.sys.sio.route_tab, irq);
+
+ irq = irq >= 0 ? tmp : -1;
+
+ /* Fixup IRQ level if an actual IRQ mapping is detected */
+ if (sio_pci_dev_irq_needs_level(dev) && irq >= 0)
+ __sio_fixup_irq_levels(1 << irq, false);
+
+ return irq;
+}
+
+static inline int
+p2k_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ static char irq_tab[][5] = {
+ /*INT A B C D */
+ { 0, 0, -1, -1, -1}, /* idsel 6 (53c810) */
+ {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */
+ { 1, 1, 2, 3, 0}, /* idsel 8 (slot A) */
+ { 2, 2, 3, 0, 1}, /* idsel 9 (slot B) */
+ {-1, -1, -1, -1, -1}, /* idsel 10 (unused) */
+ {-1, -1, -1, -1, -1}, /* idsel 11 (unused) */
+ { 3, 3, -1, -1, -1}, /* idsel 12 (CMD0646) */
+ };
+ const long min_idsel = 6, max_idsel = 12, irqs_per_slot = 5;
+ int irq = COMMON_TABLE_LOOKUP, tmp;
+ tmp = __kernel_extbl(alpha_mv.sys.sio.route_tab, irq);
+ return irq >= 0 ? tmp : -1;
+}
+
+static inline void __init
+noname_init_pci(void)
+{
+ common_init_pci();
+ sio_pci_route();
+ sio_fixup_irq_levels(sio_collect_irq_levels());
+
+ if (pc873xx_probe() == -1) {
+ printk(KERN_ERR "Probing for PC873xx Super IO chip failed.\n");
+ } else {
+ printk(KERN_INFO "Found %s Super IO chip at 0x%x\n",
+ pc873xx_get_model(), pc873xx_get_base());
+
+ /* Enabling things in the Super IO chip doesn't actually
+ * configure and enable things, the legacy drivers still
+ * need to do the actual configuration and enabling.
+ * This only unblocks them.
+ */
+
+#if !defined(CONFIG_ALPHA_AVANTI)
+ /* Don't bother on the Avanti family.
+ * None of them had on-board IDE.
+ */
+ pc873xx_enable_ide();
+#endif
+ pc873xx_enable_epp19();
+ }
+}
+
+static inline void __init
+alphabook1_init_pci(void)
+{
+ struct pci_dev *dev;
+ unsigned char orig, config;
+
+ common_init_pci();
+ sio_pci_route();
+
+ /*
+ * On the AlphaBook1, the PCMCIA chip (Cirrus 6729)
+ * is sensitive to PCI bus bursts, so we must DISABLE
+ * burst mode for the NCR 8xx SCSI... :-(
+ *
+ * Note that the NCR810 SCSI driver must preserve the
+ * setting of the bit in order for this to work. At the
+ * moment (2.0.29), ncr53c8xx.c does NOT do this, but
+ * 53c7,8xx.c DOES.
+ */
+
+ dev = NULL;
+ while ((dev = pci_get_device(PCI_VENDOR_ID_NCR, PCI_ANY_ID, dev))) {
+ if (dev->device == PCI_DEVICE_ID_NCR_53C810
+ || dev->device == PCI_DEVICE_ID_NCR_53C815
+ || dev->device == PCI_DEVICE_ID_NCR_53C820
+ || dev->device == PCI_DEVICE_ID_NCR_53C825) {
+ unsigned long io_port;
+ unsigned char ctest4;
+
+ io_port = dev->resource[0].start;
+ ctest4 = inb(io_port+0x21);
+ if (!(ctest4 & 0x80)) {
+ printk("AlphaBook1 NCR init: setting"
+ " burst disable\n");
+ outb(ctest4 | 0x80, io_port+0x21);
+ }
+ }
+ }
+
+ /* Do not set *ANY* level triggers for AlphaBook1. */
+ sio_fixup_irq_levels(0);
+
+ /* Make sure that register PR1 indicates 1Mb mem */
+ outb(0x0f, 0x3ce); orig = inb(0x3cf); /* read PR5 */
+ outb(0x0f, 0x3ce); outb(0x05, 0x3cf); /* unlock PR0-4 */
+ outb(0x0b, 0x3ce); config = inb(0x3cf); /* read PR1 */
+ if ((config & 0xc0) != 0xc0) {
+ printk("AlphaBook1 VGA init: setting 1Mb memory\n");
+ config |= 0xc0;
+ outb(0x0b, 0x3ce); outb(config, 0x3cf); /* write PR1 */
+ }
+ outb(0x0f, 0x3ce); outb(orig, 0x3cf); /* (re)lock PR0-4 */
+}
+
+static void
+sio_kill_arch(int mode)
+{
+#if defined(ALPHA_RESTORE_SRM_SETUP)
+ /* Since we cannot read the PCI DMA Window CSRs, we
+ * cannot restore them here.
+ *
+ * However, we CAN read the PIRQ route register, so restore it
+ * now...
+ */
+ pci_bus_write_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60,
+ saved_config.orig_route_tab);
+#endif
+}
+
+
+/*
+ * The System Vectors
+ */
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_BOOK1)
+struct alpha_machine_vector alphabook1_mv __initmv = {
+ .vector_name = "AlphaBook1",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_LCA_IO,
+ .machine_check = lca_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 16,
+ .device_interrupt = isa_device_interrupt,
+
+ .init_arch = alphabook1_init_arch,
+ .init_irq = sio_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = alphabook1_init_pci,
+ .kill_arch = sio_kill_arch,
+ .pci_map_irq = noname_map_irq,
+ .pci_swizzle = common_swizzle,
+
+ .sys = { .sio = {
+ /* NCR810 SCSI is 14, PCMCIA controller is 15. */
+ .route_tab = 0x0e0f0a0a,
+ }}
+};
+ALIAS_MV(alphabook1)
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_AVANTI_CH)
+struct alpha_machine_vector avanti_mv __initmv = {
+ .vector_name = "Avanti",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_APECS_IO,
+ .machine_check = apecs_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 16,
+ .device_interrupt = isa_device_interrupt,
+
+ .init_arch = apecs_init_arch,
+ .init_irq = sio_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = noname_init_pci,
+ .kill_arch = sio_kill_arch,
+ .pci_map_irq = noname_map_irq,
+ .pci_swizzle = common_swizzle,
+
+ .sys = { .sio = {
+ .route_tab = 0x0b0a050f, /* leave 14 for IDE, 9 for SND */
+ }}
+};
+ALIAS_MV(avanti)
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_NONAME_CH)
+struct alpha_machine_vector noname_mv __initmv = {
+ .vector_name = "Noname",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_LCA_IO,
+ .machine_check = lca_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 16,
+ .device_interrupt = srm_device_interrupt,
+
+ .init_arch = lca_init_arch,
+ .init_irq = sio_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = noname_init_pci,
+ .kill_arch = sio_kill_arch,
+ .pci_map_irq = noname_map_irq,
+ .pci_swizzle = common_swizzle,
+
+ .sys = { .sio = {
+ /* For UDB, the only available PCI slot must not map to IRQ 9,
+ since that's the builtin MSS sound chip. That PCI slot
+ will map to PIRQ1 (for INTA at least), so we give it IRQ 15
+ instead.
+
+ Unfortunately we have to do this for NONAME as well, since
+ they are co-indicated when the platform type "Noname" is
+ selected... :-( */
+
+ .route_tab = 0x0b0a0f0d,
+ }}
+};
+ALIAS_MV(noname)
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_P2K)
+struct alpha_machine_vector p2k_mv __initmv = {
+ .vector_name = "Platform2000",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_LCA_IO,
+ .machine_check = lca_machine_check,
+ .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 16,
+ .device_interrupt = srm_device_interrupt,
+
+ .init_arch = lca_init_arch,
+ .init_irq = sio_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = noname_init_pci,
+ .kill_arch = sio_kill_arch,
+ .pci_map_irq = p2k_map_irq,
+ .pci_swizzle = common_swizzle,
+
+ .sys = { .sio = {
+ .route_tab = 0x0b0a090f,
+ }}
+};
+ALIAS_MV(p2k)
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_XL)
+struct alpha_machine_vector xl_mv __initmv = {
+ .vector_name = "XL",
+ DO_EV4_MMU,
+ DO_DEFAULT_RTC,
+ DO_APECS_IO,
+ .machine_check = apecs_machine_check,
+ .max_isa_dma_address = ALPHA_XL_MAX_ISA_DMA_ADDRESS,
+ .min_io_address = DEFAULT_IO_BASE,
+ .min_mem_address = XL_DEFAULT_MEM_BASE,
+
+ .nr_irqs = 16,
+ .device_interrupt = isa_device_interrupt,
+
+ .init_arch = apecs_init_arch,
+ .init_irq = sio_init_irq,
+ .init_rtc = common_init_rtc,
+ .init_pci = noname_init_pci,
+ .kill_arch = sio_kill_arch,
+ .pci_map_irq = noname_map_irq,
+ .pci_swizzle = common_swizzle,
+
+ .sys = { .sio = {
+ .route_tab = 0x0b0a090f,
+ }}
+};
+ALIAS_MV(xl)
+#endif
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 7004397937cf..c0101b41dcd5 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -30,6 +30,39 @@
#include "proto.h"
+/* Work-around for some SRMs which mishandle opDEC faults. */
+
+static int opDEC_fix;
+
+static void
+opDEC_check(void)
+{
+ __asm__ __volatile__ (
+ /* Load the address of... */
+ " br $16, 1f\n"
+ /* A stub instruction fault handler. Just add 4 to the
+ pc and continue. */
+ " ldq $16, 8($sp)\n"
+ " addq $16, 4, $16\n"
+ " stq $16, 8($sp)\n"
+ " call_pal %[rti]\n"
+ /* Install the instruction fault handler. */
+ "1: lda $17, 3\n"
+ " call_pal %[wrent]\n"
+ /* With that in place, the fault from the round-to-minf fp
+ insn will arrive either at the "lda 4" insn (bad) or one
+ past that (good). This places the correct fixup in %0. */
+ " lda %[fix], 0\n"
+ " cvttq/svm $f31,$f31\n"
+ " lda %[fix], 4"
+ : [fix] "=r" (opDEC_fix)
+ : [rti] "n" (PAL_rti), [wrent] "n" (PAL_wrent)
+ : "$0", "$1", "$16", "$17", "$22", "$23", "$24", "$25");
+
+ if (opDEC_fix)
+ printk("opDEC fixup enabled.\n");
+}
+
void
dik_show_regs(struct pt_regs *regs, unsigned long *r9_15)
{
@@ -320,6 +353,32 @@ do_entIF(unsigned long type, struct pt_regs *regs)
return;
case 4: /* opDEC */
+ if (implver() == IMPLVER_EV4) {
+ long si_code;
+
+ /* The some versions of SRM do not handle
+ the opDEC properly - they return the PC of the
+ opDEC fault, not the instruction after as the
+ Alpha architecture requires. Here we fix it up.
+ We do this by intentionally causing an opDEC
+ fault during the boot sequence and testing if
+ we get the correct PC. If not, we set a flag
+ to correct it every time through. */
+ regs->pc += opDEC_fix;
+
+ /* EV4 does not implement anything except normal
+ rounding. Everything else will come here as
+ an illegal instruction. Emulate them. */
+ si_code = alpha_fp_emul(regs->pc - 4);
+ if (si_code == 0)
+ return;
+ if (si_code > 0) {
+ send_sig_fault_trapno(SIGFPE, si_code,
+ (void __user *) regs->pc,
+ 0, current);
+ return;
+ }
+ }
break;
case 5: /* illoc */
@@ -920,6 +979,11 @@ trap_init(void)
register unsigned long gptr __asm__("$29");
wrkgp(gptr);
+ /* Hack for Multia (UDB) and JENSEN: some of their SRMs have
+ a bug in the handling of the opDEC fault. Fix it up if so. */
+ if (implver() == IMPLVER_EV4)
+ opDEC_check();
+
wrent(entArith, 1);
wrent(entMM, 2);
wrent(entIF, 3);
diff --git a/drivers/eisa/Kconfig b/drivers/eisa/Kconfig
index a66b3be502a9..c8bbf90209f5 100644
--- a/drivers/eisa/Kconfig
+++ b/drivers/eisa/Kconfig
@@ -44,16 +44,17 @@ config EISA_PCI_EISA
When in doubt, say Y.
-# Using EISA_VIRTUAL_ROOT on something other than an X86 may lead
-# to crashes...
+# Using EISA_VIRTUAL_ROOT on something other than an Alpha or
+# an X86 may lead to crashes...
config EISA_VIRTUAL_ROOT
bool "EISA virtual root device"
- depends on EISA && X86
+ depends on EISA && (ALPHA || X86)
default y
help
Activate this option if your system only have EISA bus
- (no PCI slots).
+ (no PCI slots). The Alpha Jensen is an example of such
+ a system.
When in doubt, say Y.
diff --git a/drivers/eisa/virtual_root.c b/drivers/eisa/virtual_root.c
index cd9515d9d8f0..37e6dd219c37 100644
--- a/drivers/eisa/virtual_root.c
+++ b/drivers/eisa/virtual_root.c
@@ -13,7 +13,7 @@
#include
#include
-#if defined(CONFIG_EISA_VLB_PRIMING)
+#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_EISA_VLB_PRIMING)
#define EISA_FORCE_PROBE_DEFAULT 1
#else
#define EISA_FORCE_PROBE_DEFAULT 0
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index a8f4b2d70e59..64590b86eb37 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -15,7 +15,10 @@
* IRQs.
*/
-#if defined(__arm__)
+#ifdef __alpha__
+# define I8042_KBD_IRQ 1
+# define I8042_AUX_IRQ (RTC_PORT(0) == 0x170 ? 9 : 12) /* Jensen is special */
+#elif defined(__arm__)
/* defined in include/asm-arm/arch-xxx/irqs.h */
#include
#elif defined(CONFIG_PPC)
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 8caecfc85d93..fdd5f43bf4ae 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -304,6 +304,9 @@ static inline int serial8250_in_MCR(struct uart_8250_port *up)
return mctrl;
}
+bool alpha_jensen(void);
+void alpha_jensen_set_mctrl(struct uart_port *port, unsigned int mctrl);
+
#ifdef CONFIG_SERIAL_8250_PNP
int serial8250_pnp_init(void);
void serial8250_pnp_exit(void);
diff --git a/drivers/tty/serial/8250/8250_alpha.c b/drivers/tty/serial/8250/8250_alpha.c
new file mode 100644
index 000000000000..58e70328aa4d
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_alpha.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include
+#include "8250.h"
+
+bool alpha_jensen(void)
+{
+ return !strcmp(alpha_mv.vector_name, "Jensen");
+}
+
+void alpha_jensen_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /*
+ * Digital did something really horribly wrong with the OUT1 and OUT2
+ * lines on Alpha Jensen. The failure mode is that if either is
+ * cleared, the machine locks up with endless interrupts.
+ */
+ mctrl |= TIOCM_OUT1 | TIOCM_OUT2;
+
+ serial8250_do_set_mctrl(port, mctrl);
+}
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 0e81f78c6063..74f309fef1dc 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -360,6 +360,10 @@ struct uart_8250_port *serial8250_setup_port(int index)
up->ops = &univ8250_driver_ops;
+ if (IS_ENABLED(CONFIG_ALPHA_JENSEN) ||
+ (IS_ENABLED(CONFIG_ALPHA_GENERIC) && alpha_jensen()))
+ up->port.set_mctrl = alpha_jensen_set_mctrl;
+
serial8250_set_defaults(up);
return up;
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 6d21402b4435..b94eacd52612 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -6,6 +6,8 @@
obj-$(CONFIG_SERIAL_8250) += 8250.o
8250-y := 8250_core.o
8250-y += 8250_platform.o
+8250-$(CONFIG_ALPHA_GENERIC) += 8250_alpha.o
+8250-$(CONFIG_ALPHA_JENSEN) += 8250_alpha.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
obj-$(CONFIG_SERIAL_8250) += 8250_base.o
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index d59553324a84..aca5251d1f9a 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -92,9 +92,15 @@ struct block_device {
/*
* Block error status values. See block/blk-core:blk_errors for the details.
+ * Alpha cannot write a byte atomically, so we need to use 32-bit value.
*/
+#if defined(CONFIG_ALPHA) && !defined(__alpha_bwx__)
+typedef u32 __bitwise blk_status_t;
+typedef u32 blk_short_t;
+#else
typedef u8 __bitwise blk_status_t;
typedef u16 blk_short_t;
+#endif
#define BLK_STS_OK 0
#define BLK_STS_NOTSUPP ((__force blk_status_t)1)
#define BLK_STS_TIMEOUT ((__force blk_status_t)2)
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 0a46e4054dec..6c1daeb0acc9 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -145,12 +145,15 @@ struct tty_operations;
* @count: count of open processes, reaching zero cancels all the work for
* this tty and drops a @kref too (but does not free this tty)
* @winsize: size of the terminal "window" (cf. @winsize_mutex)
- * @flow: flow settings grouped together
+ * @flow: flow settings grouped together, see also @flow.unused
* @flow.lock: lock for @flow members
* @flow.stopped: tty stopped/started by stop_tty()/start_tty()
* @flow.tco_stopped: tty stopped/started by %TCOOFF/%TCOON ioctls (it has
* precedence over @flow.stopped)
- * @ctrl: control settings grouped together
+ * @flow.unused: alignment for Alpha, so that no members other than @flow.* are
+ * modified by the same 64b word store. The @flow's __aligned is
+ * there for the very same reason.
+ * @ctrl: control settings grouped together, see also @ctrl.unused
* @ctrl.lock: lock for @ctrl members
* @ctrl.pgrp: process group of this tty (setpgrp(2))
* @ctrl.session: session of this tty (setsid(2)). Writes are protected by both
@@ -158,6 +161,7 @@ struct tty_operations;
* them.
* @ctrl.pktstatus: packet mode status (bitwise OR of %TIOCPKT_ constants)
* @ctrl.packet: packet mode enabled
+ * @ctrl.unused: alignment for Alpha, see @flow.unused for explanation
* @hw_stopped: not controlled by the tty layer, under @driver's control for CTS
* handling
* @receive_room: bytes permitted to feed to @ldisc without any being lost
@@ -212,7 +216,8 @@ struct tty_struct {
spinlock_t lock;
bool stopped;
bool tco_stopped;
- } flow;
+ unsigned long unused[0];
+ } __aligned(sizeof(unsigned long)) flow;
struct {
struct pid *pgrp;
@@ -220,7 +225,8 @@ struct tty_struct {
spinlock_t lock;
unsigned char pktstatus;
bool packet;
- } ctrl;
+ unsigned long unused[0];
+ } __aligned(sizeof(unsigned long)) ctrl;
bool hw_stopped;
bool closing;