summaryrefslogtreecommitdiff
path: root/arch/alpha
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/alpha
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/alpha')
-rw-r--r--arch/alpha/Kconfig606
-rw-r--r--arch/alpha/Kconfig.debug59
-rw-r--r--arch/alpha/Makefile130
-rw-r--r--arch/alpha/boot/Makefile116
-rw-r--r--arch/alpha/boot/bootloader.lds24
-rw-r--r--arch/alpha/boot/bootp.c214
-rw-r--r--arch/alpha/boot/bootpz.c469
-rw-r--r--arch/alpha/boot/head.S123
-rw-r--r--arch/alpha/boot/main.c191
-rw-r--r--arch/alpha/boot/misc.c207
-rw-r--r--arch/alpha/boot/tools/mkbb.c151
-rw-r--r--arch/alpha/boot/tools/objstrip.c281
-rw-r--r--arch/alpha/defconfig927
-rw-r--r--arch/alpha/kernel/Makefile104
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c235
-rw-r--r--arch/alpha/kernel/asm-offsets.c43
-rw-r--r--arch/alpha/kernel/console.c66
-rw-r--r--arch/alpha/kernel/core_apecs.c418
-rw-r--r--arch/alpha/kernel/core_cia.c1212
-rw-r--r--arch/alpha/kernel/core_irongate.c416
-rw-r--r--arch/alpha/kernel/core_lca.c515
-rw-r--r--arch/alpha/kernel/core_marvel.c1154
-rw-r--r--arch/alpha/kernel/core_mcpcia.c618
-rw-r--r--arch/alpha/kernel/core_polaris.c203
-rw-r--r--arch/alpha/kernel/core_t2.c622
-rw-r--r--arch/alpha/kernel/core_titan.c806
-rw-r--r--arch/alpha/kernel/core_tsunami.c459
-rw-r--r--arch/alpha/kernel/core_wildfire.c658
-rw-r--r--arch/alpha/kernel/entry.S957
-rw-r--r--arch/alpha/kernel/err_common.c321
-rw-r--r--arch/alpha/kernel/err_ev6.c274
-rw-r--r--arch/alpha/kernel/err_ev7.c289
-rw-r--r--arch/alpha/kernel/err_impl.h85
-rw-r--r--arch/alpha/kernel/err_marvel.c1159
-rw-r--r--arch/alpha/kernel/err_titan.c756
-rw-r--r--arch/alpha/kernel/es1888.c49
-rw-r--r--arch/alpha/kernel/gct.c48
-rw-r--r--arch/alpha/kernel/head.S99
-rw-r--r--arch/alpha/kernel/init_task.c23
-rw-r--r--arch/alpha/kernel/io.c630
-rw-r--r--arch/alpha/kernel/irq.c774
-rw-r--r--arch/alpha/kernel/irq_alpha.c252
-rw-r--r--arch/alpha/kernel/irq_i8259.c183
-rw-r--r--arch/alpha/kernel/irq_impl.h42
-rw-r--r--arch/alpha/kernel/irq_pyxis.c127
-rw-r--r--arch/alpha/kernel/irq_srm.c79
-rw-r--r--arch/alpha/kernel/machvec_impl.h150
-rw-r--r--arch/alpha/kernel/module.c311
-rw-r--r--arch/alpha/kernel/ns87312.c38
-rw-r--r--arch/alpha/kernel/osf_sys.c1345
-rw-r--r--arch/alpha/kernel/pci-noop.c214
-rw-r--r--arch/alpha/kernel/pci.c561
-rw-r--r--arch/alpha/kernel/pci_impl.h209
-rw-r--r--arch/alpha/kernel/pci_iommu.c971
-rw-r--r--arch/alpha/kernel/process.c528
-rw-r--r--arch/alpha/kernel/proto.h210
-rw-r--r--arch/alpha/kernel/ptrace.c415
-rw-r--r--arch/alpha/kernel/semaphore.c224
-rw-r--r--arch/alpha/kernel/setup.c1486
-rw-r--r--arch/alpha/kernel/signal.c672
-rw-r--r--arch/alpha/kernel/smc37c669.c2554
-rw-r--r--arch/alpha/kernel/smc37c93x.c277
-rw-r--r--arch/alpha/kernel/smp.c1163
-rw-r--r--arch/alpha/kernel/srm_env.c335
-rw-r--r--arch/alpha/kernel/srmcons.c326
-rw-r--r--arch/alpha/kernel/sys_alcor.c326
-rw-r--r--arch/alpha/kernel/sys_cabriolet.c448
-rw-r--r--arch/alpha/kernel/sys_dp264.c689
-rw-r--r--arch/alpha/kernel/sys_eb64p.c256
-rw-r--r--arch/alpha/kernel/sys_eiger.c242
-rw-r--r--arch/alpha/kernel/sys_jensen.c274
-rw-r--r--arch/alpha/kernel/sys_marvel.c499
-rw-r--r--arch/alpha/kernel/sys_miata.c289
-rw-r--r--arch/alpha/kernel/sys_mikasa.c265
-rw-r--r--arch/alpha/kernel/sys_nautilus.c269
-rw-r--r--arch/alpha/kernel/sys_noritake.c347
-rw-r--r--arch/alpha/kernel/sys_rawhide.c270
-rw-r--r--arch/alpha/kernel/sys_ruffian.c240
-rw-r--r--arch/alpha/kernel/sys_rx164.c220
-rw-r--r--arch/alpha/kernel/sys_sable.c653
-rw-r--r--arch/alpha/kernel/sys_sio.c438
-rw-r--r--arch/alpha/kernel/sys_sx164.c178
-rw-r--r--arch/alpha/kernel/sys_takara.c296
-rw-r--r--arch/alpha/kernel/sys_titan.c420
-rw-r--r--arch/alpha/kernel/sys_wildfire.c361
-rw-r--r--arch/alpha/kernel/systbls.S468
-rw-r--r--arch/alpha/kernel/time.c591
-rw-r--r--arch/alpha/kernel/traps.c1092
-rw-r--r--arch/alpha/kernel/vmlinux.lds.S149
-rw-r--r--arch/alpha/lib/Makefile58
-rw-r--r--arch/alpha/lib/callback_srm.S104
-rw-r--r--arch/alpha/lib/checksum.c186
-rw-r--r--arch/alpha/lib/clear_page.S39
-rw-r--r--arch/alpha/lib/clear_user.S113
-rw-r--r--arch/alpha/lib/copy_page.S49
-rw-r--r--arch/alpha/lib/copy_user.S145
-rw-r--r--arch/alpha/lib/csum_ipv6_magic.S92
-rw-r--r--arch/alpha/lib/csum_partial_copy.c391
-rw-r--r--arch/alpha/lib/dbg_current.S29
-rw-r--r--arch/alpha/lib/dbg_stackcheck.S27
-rw-r--r--arch/alpha/lib/dbg_stackkill.S35
-rw-r--r--arch/alpha/lib/dec_and_lock.c42
-rw-r--r--arch/alpha/lib/divide.S195
-rw-r--r--arch/alpha/lib/ev6-clear_page.S54
-rw-r--r--arch/alpha/lib/ev6-clear_user.S225
-rw-r--r--arch/alpha/lib/ev6-copy_page.S203
-rw-r--r--arch/alpha/lib/ev6-copy_user.S259
-rw-r--r--arch/alpha/lib/ev6-csum_ipv6_magic.S126
-rw-r--r--arch/alpha/lib/ev6-divide.S259
-rw-r--r--arch/alpha/lib/ev6-memchr.S191
-rw-r--r--arch/alpha/lib/ev6-memcpy.S248
-rw-r--r--arch/alpha/lib/ev6-memset.S597
-rw-r--r--arch/alpha/lib/ev6-strncpy_from_user.S424
-rw-r--r--arch/alpha/lib/ev6-stxcpy.S321
-rw-r--r--arch/alpha/lib/ev6-stxncpy.S397
-rw-r--r--arch/alpha/lib/ev67-strcat.S54
-rw-r--r--arch/alpha/lib/ev67-strchr.S88
-rw-r--r--arch/alpha/lib/ev67-strlen.S49
-rw-r--r--arch/alpha/lib/ev67-strlen_user.S107
-rw-r--r--arch/alpha/lib/ev67-strncat.S94
-rw-r--r--arch/alpha/lib/ev67-strrchr.S109
-rw-r--r--arch/alpha/lib/fpreg.c193
-rw-r--r--arch/alpha/lib/memchr.S164
-rw-r--r--arch/alpha/lib/memcpy.c163
-rw-r--r--arch/alpha/lib/memmove.S181
-rw-r--r--arch/alpha/lib/memset.S124
-rw-r--r--arch/alpha/lib/srm_printk.c41
-rw-r--r--arch/alpha/lib/srm_puts.c23
-rw-r--r--arch/alpha/lib/stacktrace.c103
-rw-r--r--arch/alpha/lib/strcasecmp.c26
-rw-r--r--arch/alpha/lib/strcat.S52
-rw-r--r--arch/alpha/lib/strchr.S70
-rw-r--r--arch/alpha/lib/strcpy.S23
-rw-r--r--arch/alpha/lib/strlen.S57
-rw-r--r--arch/alpha/lib/strlen_user.S91
-rw-r--r--arch/alpha/lib/strncat.S84
-rw-r--r--arch/alpha/lib/strncpy.S81
-rw-r--r--arch/alpha/lib/strncpy_from_user.S339
-rw-r--r--arch/alpha/lib/strrchr.S87
-rw-r--r--arch/alpha/lib/stxcpy.S289
-rw-r--r--arch/alpha/lib/stxncpy.S345
-rw-r--r--arch/alpha/lib/udelay.c55
-rw-r--r--arch/alpha/math-emu/Makefile9
-rw-r--r--arch/alpha/math-emu/math.c400
-rw-r--r--arch/alpha/math-emu/qrnnd.S163
-rw-r--r--arch/alpha/math-emu/sfp-util.h35
-rw-r--r--arch/alpha/mm/Makefile9
-rw-r--r--arch/alpha/mm/extable.c34
-rw-r--r--arch/alpha/mm/fault.c247
-rw-r--r--arch/alpha/mm/init.c382
-rw-r--r--arch/alpha/mm/numa.c395
-rw-r--r--arch/alpha/mm/remap.c90
-rw-r--r--arch/alpha/oprofile/Kconfig23
-rw-r--r--arch/alpha/oprofile/Makefile19
-rw-r--r--arch/alpha/oprofile/common.c189
-rw-r--r--arch/alpha/oprofile/op_impl.h55
-rw-r--r--arch/alpha/oprofile/op_model_ev4.c116
-rw-r--r--arch/alpha/oprofile/op_model_ev5.c211
-rw-r--r--arch/alpha/oprofile/op_model_ev6.c103
-rw-r--r--arch/alpha/oprofile/op_model_ev67.c263
160 files changed, 49087 insertions, 0 deletions
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
new file mode 100644
index 000000000000..0c79b9d95f74
--- /dev/null
+++ b/arch/alpha/Kconfig
@@ -0,0 +1,606 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+config ALPHA
+ bool
+ default y
+ help
+ The Alpha is a 64-bit general-purpose processor designed and
+ marketed by the Digital Equipment Corporation of blessed memory,
+ now Hewlett-Packard. The Alpha Linux project has a home page at
+ <http://www.alphalinux.org/>.
+
+config 64BIT
+ def_bool y
+
+config MMU
+ bool
+ default y
+
+config UID16
+ bool
+
+config RWSEM_GENERIC_SPINLOCK
+ bool
+
+config RWSEM_XCHGADD_ALGORITHM
+ bool
+ default y
+
+config GENERIC_CALIBRATE_DELAY
+ bool
+ default y
+
+config GENERIC_ISA_DMA
+ bool
+ default y
+
+config GENERIC_IOMAP
+ bool
+ default n
+
+source "init/Kconfig"
+
+
+menu "System setup"
+
+choice
+ prompt "Alpha system type"
+ default ALPHA_GENERIC
+ ---help---
+ This is the system type of your hardware. A "generic" kernel will
+ run on any supported Alpha system. However, if you configure a
+ kernel for your specific system, it will be faster and smaller.
+
+ To find out what type of Alpha system you have, you may want to
+ check out the Linux/Alpha FAQ, accessible on the WWW from
+ <http://www.alphalinux.org/>. In summary:
+
+ Alcor/Alpha-XLT AS 600
+ 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
+ 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 model 300,
+ DEC 2000 model 500
+ LX164 AlphaPC164-LX
+ Lynx AS 2100A
+ Miata Personal Workstation 433a, 433au, 500a,
+ 500au, 600a, or 600au
+ 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
+ Ruffian RPX164-2, AlphaPC164-UX, AlphaPC164-BX
+ SX164 AlphaPC164-SX
+ Sable AS 2000, AS 2100
+ Shark DS 20L
+ Takara Takara
+ Titan AlphaServer ES45 / DS25
+ Wildfire AlphaServer GS 40/80/160/320
+
+ If you don't know what to do, choose "generic".
+
+config ALPHA_GENERIC
+ bool "Generic"
+ help
+ A generic kernel will run on all supported Alpha hardware.
+
+config ALPHA_ALCOR
+ bool "Alcor/Alpha-XLT"
+ help
+ For systems using the Digital ALCOR chipset: 5 chips (4, 64-bit data
+ slices (Data Switch, DSW) - 208-pin PQFP and 1 control (Control, I/O
+ Address, CIA) - a 383 pin plastic PGA). It provides a DRAM
+ controller (256-bit memory bus) and a PCI interface. It also does
+ 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
+ Various 21264 systems with the tsunami core logic chipset.
+ 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"
+ 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
+ <http://www.unix-ag.org/Linux-Alpha/Architectures/LX164.html>.
+
+config ALPHA_LYNX
+ bool "Lynx"
+ help
+ AlphaServer 2100A-based systems.
+
+config ALPHA_MARVEL
+ bool "Marvel"
+ help
+ AlphaServer ES47 / ES80 / GS1280 based on EV7.
+
+config ALPHA_MIATA
+ bool "Miata"
+ help
+ The Digital PersonalWorkStation (PWS 433a, 433au, 500a, 500au, 600a,
+ or 600au). There is an Installation HOWTO for this hardware at
+ <http://eijk.homelinux.org/~stefan/miata.html>.
+
+config ALPHA_MIKASA
+ bool "Mikasa"
+ help
+ AlphaServer 1000-based Alpha systems.
+
+config ALPHA_NAUTILUS
+ bool "Nautilus"
+ help
+ Alpha systems based on the AMD 751 & ALI 1543C chipsets.
+
+config ALPHA_NONAME_CH
+ bool "Noname"
+
+config ALPHA_NORITAKE
+ bool "Noritake"
+ help
+ AlphaServer 1000A, AlphaServer 600A, and AlphaServer 800-based
+ systems.
+
+config ALPHA_PC164
+ bool "PC164"
+
+config ALPHA_P2K
+ bool "Platform2000"
+
+config ALPHA_RAWHIDE
+ bool "Rawhide"
+ help
+ AlphaServer 1200, AlphaServer 4000 and AlphaServer 4100 machines.
+ See HOWTO at
+ <http://www.alphalinux.org/docs/rawhide/4100_install.shtml>.
+
+config ALPHA_RUFFIAN
+ bool "Ruffian"
+ help
+ Samsung APC164UX. There is a page on known problems and workarounds
+ at <http://www.alphalinux.org/faq/FAQ-11.html>.
+
+config ALPHA_RX164
+ bool "RX164"
+
+config ALPHA_SX164
+ bool "SX164"
+
+config ALPHA_SABLE
+ bool "Sable"
+ help
+ Digital AlphaServer 2000 and 2100-based systems.
+
+config ALPHA_SHARK
+ bool "Shark"
+
+config ALPHA_TAKARA
+ bool "Takara"
+ help
+ Alpha 11164-based OEM single-board computer.
+
+config ALPHA_TITAN
+ bool "Titan"
+ help
+ AlphaServer ES45/DS25 SMP based on EV68 and Titan chipset.
+
+config ALPHA_WILDFIRE
+ bool "Wildfire"
+ help
+ AlphaServer GS 40/80/160/320 SMP based on the EV67 core.
+
+endchoice
+
+# clear all implied options (don't want default values for those):
+# Most of these machines have ISA slots; not exactly sure which don't,
+# and this doesn't activate hordes of code, so do it always.
+config ISA
+ bool
+ default y
+ help
+ Find out whether you have ISA slots on your motherboard. ISA is the
+ name of a bus system, i.e. the way the CPU talks to the other stuff
+ inside your box. Other bus systems are PCI, EISA, MicroChannel
+ (MCA) or VESA. ISA is an older system, now being displaced by PCI;
+ newer boards don't support it. If you have ISA, say Y, otherwise N.
+
+config PCI
+ bool
+ depends on !ALPHA_JENSEN
+ default y
+ help
+ Find out whether you have a PCI motherboard. PCI is the name of a
+ bus system, i.e. the way the CPU talks to the other stuff inside
+ your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+ VESA. If you have PCI, say Y, otherwise N.
+
+ The PCI-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>, contains valuable
+ information about which PCI hardware does work under Linux and which
+ doesn't.
+
+config PCI_DOMAINS
+ bool
+ default y
+
+config ALPHA_CORE_AGP
+ bool
+ depends on ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL
+ 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
+
+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_EV4
+ bool
+ default y if ALPHA_LYNX && !ALPHA_EV5
+
+config ALPHA_CIA
+ bool
+ 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 "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)?"
+ depends on ALPHA_SABLE
+ help
+ Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx.
+
+config ALPHA_GAMMA
+ bool
+ depends on ALPHA_LYNX
+ default y
+
+config ALPHA_T2
+ bool
+ depends on ALPHA_SABLE || ALPHA_LYNX
+ default y
+
+config ALPHA_PYXIS
+ bool
+ depends on ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN
+ default y
+
+config ALPHA_EV6
+ bool
+ depends on ALPHA_NAUTILUS || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_DP264 || ALPHA_EIGER || ALPHA_MARVEL
+ default y
+
+config ALPHA_TSUNAMI
+ bool
+ depends on ALPHA_SHARK || ALPHA_DP264 || ALPHA_EIGER
+ default y
+
+config ALPHA_EV67
+ bool "EV67 (or later) CPU (speed > 600MHz)?" if ALPHA_DP264 || ALPHA_EIGER
+ default y if ALPHA_NAUTILUS || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL
+ help
+ Is this a machine based on the EV67 core? If in doubt, select N here
+ and the machine will be treated as an EV6.
+
+config ALPHA_EV7
+ bool
+ depends on ALPHA_MARVEL
+ default y
+
+config ALPHA_MCPCIA
+ bool
+ depends on ALPHA_RAWHIDE
+ default y
+
+config ALPHA_POLARIS
+ bool
+ depends on ALPHA_RX164
+ default y
+
+config ALPHA_IRONGATE
+ bool
+ depends on ALPHA_NAUTILUS
+ default y
+
+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
+ <http://www.unix-ag.org/Linux-Alpha/Architectures/Avanti.html>.
+
+config ALPHA_BROKEN_IRQ_MASK
+ bool
+ depends on ALPHA_GENERIC || ALPHA_PC164
+ default y
+
+config ALPHA_SRM
+ 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
+ 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
+ keys. Details about the Linux/Alpha booting process are contained in
+ the Linux/Alpha FAQ, accessible on the WWW from
+ <http://www.alphalinux.org/>.
+
+ The usual way to load Linux on an Alpha machine is to use MILO
+ (a bootloader that lets you pass command line parameters to the
+ kernel just like lilo does for the x86 architecture) which can be
+ loaded either from ARC or can be installed directly as a permanent
+ firmware replacement from floppy (which requires changing a certain
+ jumper on the motherboard). If you want to do either of these, say N
+ here. If MILO doesn't work on your system (true for Jensen
+ motherboards), you can bypass it altogether and boot Linux directly
+ from an SRM console; say Y here in order to do that. Note that you
+ won't be able to boot from an IDE disk using SRM.
+
+ If unsure, say N.
+
+config EISA
+ bool
+ depends on ALPHA_GENERIC || ALPHA_JENSEN || ALPHA_ALCOR || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_RAWHIDE
+ default y
+
+config SMP
+ bool "Symmetric multi-processing support"
+ 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, like most personal computers, say N. If
+ you have a system with more than one CPU, say Y.
+
+ If you say N here, the kernel will run on single and multiprocessor
+ machines, but will use only one CPU of a multiprocessor machine. If
+ you say Y here, the kernel will run on many, but not all,
+ singleprocessor machines. On a singleprocessor machine, the kernel
+ will run faster if you say N here.
+
+ See also the <file:Documentation/smp.txt>, and the SMP-HOWTO
+ available at <http://www.tldp.org/docs.html#howto>.
+
+ If you don't know what to do here, say N.
+
+config HAVE_DEC_LOCK
+ bool
+ depends on SMP
+ default y
+
+config NR_CPUS
+ int "Maximum number of CPUs (2-64)"
+ range 2 64
+ depends on SMP
+ default "64"
+
+config DISCONTIGMEM
+ bool "Discontiguous Memory Support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ Say Y to upport efficient handling of discontiguous physical memory,
+ for architectures which are either NUMA (Non-Uniform Memory Access)
+ or have huge holes in the physical address space for other reasons.
+ See <file:Documentation/vm/numa> for more.
+
+config NUMA
+ bool "NUMA Support (EXPERIMENTAL)"
+ depends on DISCONTIGMEM
+ help
+ Say Y to compile the kernel to support NUMA (Non-Uniform Memory
+ Access). This option is for configuring high-end multiprocessor
+ server machines. If in doubt, say N.
+
+# LARGE_VMALLOC is racy, if you *really* need it then fix it first
+config ALPHA_LARGE_VMALLOC
+ bool
+ ---help---
+ Process creation and other aspects of virtual memory management can
+ be streamlined if we restrict the kernel to one PGD for all vmalloc
+ allocations. This equates to about 8GB.
+
+ Under normal circumstances, this is so far and above what is needed
+ as to be laughable. However, there are certain applications (such
+ as benchmark-grade in-kernel web serving) that can make use of as
+ much vmalloc space as is available.
+
+ Say N unless you know you need gobs and gobs of vmalloc space.
+
+config VERBOSE_MCHECK
+ bool "Verbose Machine Checks"
+
+config VERBOSE_MCHECK_ON
+ int "Verbose Printing Mode (0=off, 1=on, 2=all)"
+ depends on VERBOSE_MCHECK
+ default 1
+ ---help---
+ This option allows the default printing mode to be set, and then
+ possibly overridden by a boot command argument.
+
+ For example, if one wanted the option of printing verbose
+ machine checks, but wanted the default to be as if verbose
+ machine check printing was turned off, then one would choose
+ the printing mode to be 0. Then, upon reboot, one could add
+ the boot command line "verbose_mcheck=1" to get the normal
+ verbose machine check printing, or "verbose_mcheck=2" to get
+ the maximum information available.
+
+ Take the default (1) unless you want more control or more info.
+
+source "drivers/pci/Kconfig"
+source "drivers/eisa/Kconfig"
+
+source "drivers/pcmcia/Kconfig"
+
+config SRM_ENV
+ tristate "SRM environment through procfs"
+ depends on PROC_FS
+ ---help---
+ If you enable this option, a subdirectory inside /proc called
+ /proc/srm_environment will give you access to the all important
+ SRM environment variables (those which have a name) and also
+ to all others (by their internal number).
+
+ SRM is something like a BIOS for Alpha machines. There are some
+ other such BIOSes, like AlphaBIOS, which this driver cannot
+ support (hey, that's not SRM!).
+
+ Despite the fact that this driver doesn't work on all Alphas (but
+ only on those which have SRM as their firmware), it's save to
+ build it even if your particular machine doesn't know about SRM
+ (or if you intend to compile a generic kernel). It will simply
+ not create those subdirectory in /proc (and give you some warning,
+ of course).
+
+ This driver is also available as a module and will be called
+ srm_env then.
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/alpha/oprofile/Kconfig"
+
+source "arch/alpha/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
diff --git a/arch/alpha/Kconfig.debug b/arch/alpha/Kconfig.debug
new file mode 100644
index 000000000000..36d0106c32eb
--- /dev/null
+++ b/arch/alpha/Kconfig.debug
@@ -0,0 +1,59 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config EARLY_PRINTK
+ bool
+ depends on ALPHA_GENERIC || ALPHA_SRM
+ default y
+
+config DEBUG_RWLOCK
+ bool "Read-write spinlock debugging"
+ depends on DEBUG_KERNEL
+ help
+ If you say Y here then read-write lock processing will count how many
+ times it has tried to get the lock and issue an error message after
+ too many attempts. If you suspect a rwlock problem or a kernel
+ hacker asks for this option then say Y. Otherwise say N.
+
+config DEBUG_SEMAPHORE
+ bool "Semaphore debugging"
+ depends on DEBUG_KERNEL
+ help
+ If you say Y here then semaphore processing will issue lots of
+ verbose debugging messages. If you suspect a semaphore problem or a
+ kernel hacker asks for this option then say Y. Otherwise say N.
+
+config ALPHA_LEGACY_START_ADDRESS
+ bool "Legacy kernel start address"
+ depends on ALPHA_GENERIC
+ default n
+ ---help---
+ The 2.4 kernel changed the kernel start address from 0x310000
+ to 0x810000 to make room for the Wildfire's larger SRM console.
+ Recent consoles on Titan and Marvel machines also require the
+ extra room.
+
+ If you're using aboot 0.7 or later, the bootloader will examine the
+ ELF headers to determine where to transfer control. Unfortunately,
+ most older bootloaders -- APB or MILO -- hardcoded the kernel start
+ address rather than examining the ELF headers, and the result is a
+ hard lockup.
+
+ Say Y if you have a broken bootloader. Say N if you do not, or if
+ you wish to run on Wildfire, Titan, or Marvel.
+
+config ALPHA_LEGACY_START_ADDRESS
+ bool
+ depends on !ALPHA_GENERIC && !ALPHA_TITAN && !ALPHA_MARVEL && !ALPHA_WILDFIRE
+ default y
+
+config MATHEMU
+ tristate "Kernel FP software completion" if DEBUG_KERNEL && !SMP
+ default y if !DEBUG_KERNEL || SMP
+ help
+ This option is required for IEEE compliant floating point arithmetic
+ on the Alpha. The only time you would ever not say Y is to say M in
+ order to debug the code. Say Y unless you know what you are doing.
+
+endmenu
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile
new file mode 100644
index 000000000000..22ebfb2be0e4
--- /dev/null
+++ b/arch/alpha/Makefile
@@ -0,0 +1,130 @@
+#
+# alpha/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+
+NM := $(NM) -B
+
+LDFLAGS_vmlinux := -static -N #-relax
+CHECKFLAGS += -D__alpha__ -m64
+cflags-y := -pipe -mno-fp-regs -ffixed-8
+
+# Determine if we can use the BWX instructions with GAS.
+old_gas := $(shell if $(AS) --version 2>&1 | grep 'version 2.7' > /dev/null; then echo y; else echo n; fi)
+
+ifeq ($(old_gas),y)
+$(error The assembler '$(AS)' does not support the BWX instruction)
+endif
+
+# Determine if GCC understands the -mcpu= option.
+have_mcpu := $(call cc-option-yn, -mcpu=ev5)
+have_mcpu_pca56 := $(call cc-option-yn, -mcpu=pca56)
+have_mcpu_ev6 := $(call cc-option-yn, -mcpu=ev6)
+have_mcpu_ev67 := $(call cc-option-yn, -mcpu=ev67)
+have_msmall_data := $(call cc-option-yn, -msmall-data)
+
+cflags-$(have_msmall_data) += -msmall-data
+
+# Turn on the proper cpu optimizations.
+ifeq ($(have_mcpu),y)
+ mcpu_done := n
+ # If GENERIC, make sure to turn off any instruction set extensions that
+ # 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.
+ ifeq ($(CONFIG_ALPHA_GENERIC),y)
+ mcpu := ev5
+ mcpu_done := y
+ endif
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_SX164)$(have_mcpu_pca56),nyy)
+ mcpu := pca56
+ mcpu_done := y
+ endif
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_POLARIS)$(have_mcpu_pca56),nyy)
+ mcpu := pca56
+ mcpu_done := y
+ endif
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV4),ny)
+ mcpu := ev4
+ mcpu_done := y
+ endif
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV56),ny)
+ mcpu := ev56
+ mcpu_done := y
+ endif
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV5),ny)
+ mcpu := ev5
+ mcpu_done := y
+ endif
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV67)$(have_mcpu_ev67),nyy)
+ mcpu := ev67
+ mcpu_done := y
+ endif
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV6),ny)
+ ifeq ($(have_mcpu_ev6),y)
+ mcpu := ev6
+ else
+ ifeq ($(have_mcpu_pca56),y)
+ mcpu := pca56
+ else
+ mcpu=ev56
+ endif
+ endif
+ mcpu_done := y
+ endif
+ cflags-$(mcpu_done) += -mcpu=$(mcpu)
+endif
+
+
+# For TSUNAMI, we must have the assembler not emulate our instructions.
+# The same is true for IRONGATE, POLARIS, PYXIS.
+# BWX is most important, but we don't really want any emulation ever.
+CFLAGS += $(cflags-y) -Wa,-mev6
+
+head-y := arch/alpha/kernel/head.o
+
+core-y += arch/alpha/kernel/ arch/alpha/mm/
+core-$(CONFIG_MATHEMU) += arch/alpha/math-emu/
+drivers-$(CONFIG_OPROFILE) += arch/alpha/oprofile/
+libs-y += arch/alpha/lib/
+
+# export what is needed by arch/alpha/boot/Makefile
+LIBS_Y := $(patsubst %/, %/lib.a, $(libs-y))
+export LIBS_Y
+
+boot := arch/alpha/boot
+
+#Default target when executing make with no arguments
+all boot: $(boot)/vmlinux.gz
+
+$(boot)/vmlinux.gz: vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $@
+
+bootimage bootpfile bootpzfile: vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+
+prepare: include/asm-$(ARCH)/asm_offsets.h
+
+arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
+ include/config/MARKER
+
+include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s
+ $(call filechk,gen-asm-offsets)
+
+archclean:
+ $(Q)$(MAKE) $(clean)=$(boot)
+
+CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h
+
+define archhelp
+ echo '* boot - Compressed kernel image (arch/alpha/boot/vmlinux.gz)'
+ echo ' bootimage - SRM bootable image (arch/alpha/boot/bootimage)'
+ echo ' bootpfile - BOOTP bootable image (arch/alpha/boot/bootpfile)'
+ echo ' bootpzfile - compressed kernel BOOTP image (arch/alpha/boot/bootpzfile)'
+endef
diff --git a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile
new file mode 100644
index 000000000000..e1ae14cd2b4e
--- /dev/null
+++ b/arch/alpha/boot/Makefile
@@ -0,0 +1,116 @@
+#
+# arch/alpha/boot/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+
+hostprogs-y := tools/mkbb tools/objstrip
+targets := vmlinux.gz vmlinux \
+ vmlinux.nh tools/lxboot tools/bootlx tools/bootph \
+ tools/bootpzh bootloader bootpheader bootpzheader
+OBJSTRIP := $(obj)/tools/objstrip
+
+# SRM bootable image. Copy to offset 512 of a partition.
+$(obj)/bootimage: $(addprefix $(obj)/tools/,mkbb lxboot bootlx) $(obj)/vmlinux.nh
+ ( cat $(obj)/tools/lxboot $(obj)/tools/bootlx $(obj)/vmlinux.nh ) > $@
+ $(obj)/tools/mkbb $@ $(obj)/tools/lxboot
+ @echo ' Bootimage $@ is ready'
+
+# BOOTP bootable image. Define INITRD during make to append initrd image.
+$(obj)/bootpfile: $(obj)/tools/bootph $(obj)/vmlinux.nh
+ cat $(obj)/tools/bootph $(obj)/vmlinux.nh > $@
+ifdef INITRD
+ cat $(INITRD) >> $@
+endif
+
+# Compressed kernel BOOTP bootable image.
+# Define INITRD during make to append initrd image.
+$(obj)/bootpzfile: $(obj)/tools/bootpzh $(obj)/vmlinux.nh.gz
+ cat $(obj)/tools/bootpzh $(obj)/vmlinux.nh.gz > $@
+ifdef INITRD
+ cat $(INITRD) >> $@
+endif
+
+# Compressed kernel image
+$(obj)/vmlinux.gz: $(obj)/vmlinux FORCE
+ $(call if_changed,gzip)
+ @echo ' Kernel $@ is ready'
+
+$(obj)/main.o: $(obj)/ksize.h
+$(obj)/bootp.o: $(obj)/ksize.h
+$(obj)/bootpz.o: $(obj)/kzsize.h
+
+$(obj)/ksize.h: $(obj)/vmlinux.nh FORCE
+ echo "#define KERNEL_SIZE `ls -l $(obj)/vmlinux.nh | awk '{print $$5}'`" > $@T
+ifdef INITRD
+ [ -f $(INITRD) ] || exit 1
+ echo "#define INITRD_IMAGE_SIZE `ls -l $(INITRD) | awk '{print $$5}'`" >> $@T
+endif
+ cmp -s $@T $@ || mv -f $@T $@
+ rm -f $@T
+
+$(obj)/kzsize.h: $(obj)/vmlinux.nh.gz FORCE
+ echo "#define KERNEL_SIZE `ls -l $(obj)/vmlinux.nh | awk '{print $$5}'`" > $@T
+ echo "#define KERNEL_Z_SIZE `ls -l $(obj)/vmlinux.nh.gz | awk '{print $$5}'`" >> $@T
+ifdef INITRD
+ [ -f $(INITRD) ] || exit 1
+ echo "#define INITRD_IMAGE_SIZE `ls -l $(INITRD) | awk '{print $$5}'`" >> $@T
+endif
+ cmp -s $@T $@ || mv -f $@T $@
+ rm -f $@T
+
+quiet_cmd_strip = STRIP $@
+ cmd_strip = $(STRIP) -o $@ $<
+
+$(obj)/vmlinux: vmlinux FORCE
+ $(call if_changed,strip)
+
+quiet_cmd_objstrip = OBJSTRIP $@
+ cmd_objstrip = $(OBJSTRIP) $(OSFLAGS_$(@F)) $< $@
+
+OSFLAGS_vmlinux.nh := -v
+OSFLAGS_lxboot := -p
+OSFLAGS_bootlx := -vb
+OSFLAGS_bootph := -vb
+OSFLAGS_bootpzh := -vb
+
+$(obj)/vmlinux.nh: vmlinux $(OBJSTRIP) FORCE
+ $(call if_changed,objstrip)
+
+$(obj)/vmlinux.nh.gz: $(obj)/vmlinux.nh FORCE
+ $(call if_changed,gzip)
+
+$(obj)/tools/lxboot: $(obj)/bootloader $(OBJSTRIP) FORCE
+ $(call if_changed,objstrip)
+
+$(obj)/tools/bootlx: $(obj)/bootloader $(OBJSTRIP) FORCE
+ $(call if_changed,objstrip)
+
+$(obj)/tools/bootph: $(obj)/bootpheader $(OBJSTRIP) FORCE
+ $(call if_changed,objstrip)
+
+$(obj)/tools/bootpzh: $(obj)/bootpzheader $(OBJSTRIP) FORCE
+ $(call if_changed,objstrip)
+
+LDFLAGS_bootloader := -static -uvsprintf -T #-N -relax
+LDFLAGS_bootpheader := -static -uvsprintf -T #-N -relax
+LDFLAGS_bootpzheader := -static -uvsprintf -T #-N -relax
+
+OBJ_bootlx := $(obj)/head.o $(obj)/main.o
+OBJ_bootph := $(obj)/head.o $(obj)/bootp.o
+OBJ_bootpzh := $(obj)/head.o $(obj)/bootpz.o $(obj)/misc.o
+
+$(obj)/bootloader: $(obj)/bootloader.lds $(OBJ_bootlx) FORCE
+ $(call if_changed,ld)
+
+$(obj)/bootpheader: $(obj)/bootloader.lds $(OBJ_bootph) $(LIBS_Y) FORCE
+ $(call if_changed,ld)
+
+$(obj)/bootpzheader: $(obj)/bootloader.lds $(OBJ_bootpzh) $(LIBS_Y) FORCE
+ $(call if_changed,ld)
+
+$(obj)/misc.o: lib/inflate.c
diff --git a/arch/alpha/boot/bootloader.lds b/arch/alpha/boot/bootloader.lds
new file mode 100644
index 000000000000..31c081ce1d50
--- /dev/null
+++ b/arch/alpha/boot/bootloader.lds
@@ -0,0 +1,24 @@
+OUTPUT_FORMAT("elf64-alpha")
+ENTRY(__start)
+printk = srm_printk;
+SECTIONS
+{
+ . = 0x20000000;
+ .text : { *(.text) }
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata) *(.rodata.*) }
+ .data : { *(.data) CONSTRUCTORS }
+ .got : { *(.got) }
+ .sdata : { *(.sdata) }
+ _edata = .;
+ PROVIDE (edata = .);
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss : { *(.bss) *(COMMON) }
+ _end = . ;
+ PROVIDE (end = .);
+
+ .mdebug 0 : { *(.mdebug) }
+ .note 0 : { *(.note) }
+ .comment 0 : { *(.comment) }
+}
diff --git a/arch/alpha/boot/bootp.c b/arch/alpha/boot/bootp.c
new file mode 100644
index 000000000000..ec53c28e33de
--- /dev/null
+++ b/arch/alpha/boot/bootp.c
@@ -0,0 +1,214 @@
+/*
+ * arch/alpha/boot/bootp.c
+ *
+ * Copyright (C) 1997 Jay Estabrook
+ *
+ * This file is used for creating a bootp file for the Linux/AXP kernel
+ *
+ * based significantly on the arch/alpha/boot/main.c of Linus Torvalds
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/console.h>
+#include <asm/hwrpb.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include <stdarg.h>
+
+#include "ksize.h"
+
+extern unsigned long switch_to_osf_pal(unsigned long nr,
+ struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
+ unsigned long *vptb);
+
+extern void move_stack(unsigned long new_stack);
+
+struct hwrpb_struct *hwrpb = INIT_HWRPB;
+static struct pcb_struct pcb_va[1];
+
+/*
+ * Find a physical address of a virtual object..
+ *
+ * This is easy using the virtual page table address.
+ */
+
+static inline void *
+find_pa(unsigned long *vptb, void *ptr)
+{
+ unsigned long address = (unsigned long) ptr;
+ unsigned long result;
+
+ result = vptb[address >> 13];
+ result >>= 32;
+ result <<= 13;
+ result |= address & 0x1fff;
+ return (void *) result;
+}
+
+/*
+ * This function moves into OSF/1 pal-code, and has a temporary
+ * PCB for that. The kernel proper should replace this PCB with
+ * the real one as soon as possible.
+ *
+ * The page table muckery in here depends on the fact that the boot
+ * code has the L1 page table identity-map itself in the second PTE
+ * in the L1 page table. Thus the L1-page is virtually addressable
+ * itself (through three levels) at virtual address 0x200802000.
+ */
+
+#define VPTB ((unsigned long *) 0x200000000)
+#define L1 ((unsigned long *) 0x200802000)
+
+void
+pal_init(void)
+{
+ unsigned long i, rev;
+ struct percpu_struct * percpu;
+ struct pcb_struct * pcb_pa;
+
+ /* Create the dummy PCB. */
+ pcb_va->ksp = 0;
+ pcb_va->usp = 0;
+ pcb_va->ptbr = L1[1] >> 32;
+ pcb_va->asn = 0;
+ pcb_va->pcc = 0;
+ pcb_va->unique = 0;
+ pcb_va->flags = 1;
+ pcb_va->res1 = 0;
+ pcb_va->res2 = 0;
+ pcb_pa = find_pa(VPTB, pcb_va);
+
+ /*
+ * a0 = 2 (OSF)
+ * a1 = return address, but we give the asm the vaddr of the PCB
+ * a2 = physical addr of PCB
+ * a3 = new virtual page table pointer
+ * a4 = KSP (but the asm sets it)
+ */
+ srm_printk("Switching to OSF PAL-code .. ");
+
+ i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
+ if (i) {
+ srm_printk("failed, code %ld\n", i);
+ __halt();
+ }
+
+ percpu = (struct percpu_struct *)
+ (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
+ rev = percpu->pal_revision = percpu->palcode_avail[2];
+
+ srm_printk("Ok (rev %lx)\n", rev);
+
+ tbia(); /* do it directly in case we are SMP */
+}
+
+static inline void
+load(unsigned long dst, unsigned long src, unsigned long count)
+{
+ memcpy((void *)dst, (void *)src, count);
+}
+
+/*
+ * Start the kernel.
+ */
+static inline void
+runkernel(void)
+{
+ __asm__ __volatile__(
+ "bis %0,%0,$27\n\t"
+ "jmp ($27)"
+ : /* no outputs: it doesn't even return */
+ : "r" (START_ADDR));
+}
+
+extern char _end;
+#define KERNEL_ORIGIN \
+ ((((unsigned long)&_end) + 511) & ~511)
+
+void
+start_kernel(void)
+{
+ /*
+ * Note that this crufty stuff with static and envval
+ * and envbuf is because:
+ *
+ * 1. Frequently, the stack is short, and we don't want to overrun;
+ * 2. Frequently the stack is where we are going to copy the kernel to;
+ * 3. A certain SRM console required the GET_ENV output to stack.
+ * ??? A comment in the aboot sources indicates that the GET_ENV
+ * destination must be quadword aligned. Might this explain the
+ * behaviour, rather than requiring output to the stack, which
+ * seems rather far-fetched.
+ */
+ static long nbytes;
+ static char envval[256] __attribute__((aligned(8)));
+ static unsigned long initrd_start;
+
+ srm_printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n");
+ if (INIT_HWRPB->pagesize != 8192) {
+ srm_printk("Expected 8kB pages, got %ldkB\n",
+ INIT_HWRPB->pagesize >> 10);
+ return;
+ }
+ if (INIT_HWRPB->vptb != (unsigned long) VPTB) {
+ srm_printk("Expected vptb at %p, got %p\n",
+ VPTB, (void *)INIT_HWRPB->vptb);
+ return;
+ }
+ pal_init();
+
+ /* The initrd must be page-aligned. See below for the
+ cause of the magic number 5. */
+ initrd_start = ((START_ADDR + 5*KERNEL_SIZE + PAGE_SIZE) |
+ (PAGE_SIZE-1)) + 1;
+#ifdef INITRD_IMAGE_SIZE
+ srm_printk("Initrd positioned at %#lx\n", initrd_start);
+#endif
+
+ /*
+ * Move the stack to a safe place to ensure it won't be
+ * overwritten by kernel image.
+ */
+ move_stack(initrd_start - PAGE_SIZE);
+
+ nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
+ if (nbytes < 0 || nbytes >= sizeof(envval)) {
+ nbytes = 0;
+ }
+ envval[nbytes] = '\0';
+ srm_printk("Loading the kernel...'%s'\n", envval);
+
+ /* NOTE: *no* callbacks or printouts from here on out!!! */
+
+ /* This is a hack, as some consoles seem to get virtual 20000000 (ie
+ * where the SRM console puts the kernel bootp image) memory
+ * overlapping physical memory where the kernel wants to be put,
+ * which causes real problems when attempting to copy the former to
+ * the latter... :-(
+ *
+ * So, we first move the kernel virtual-to-physical way above where
+ * we physically want the kernel to end up, then copy it from there
+ * to its final resting place... ;-}
+ *
+ * Sigh... */
+
+#ifdef INITRD_IMAGE_SIZE
+ load(initrd_start, KERNEL_ORIGIN+KERNEL_SIZE, INITRD_IMAGE_SIZE);
+#endif
+ load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE);
+ load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE);
+
+ memset((char*)ZERO_PGE, 0, PAGE_SIZE);
+ strcpy((char*)ZERO_PGE, envval);
+#ifdef INITRD_IMAGE_SIZE
+ ((long *)(ZERO_PGE+256))[0] = initrd_start;
+ ((long *)(ZERO_PGE+256))[1] = INITRD_IMAGE_SIZE;
+#endif
+
+ runkernel();
+}
diff --git a/arch/alpha/boot/bootpz.c b/arch/alpha/boot/bootpz.c
new file mode 100644
index 000000000000..a6657f2cf9bd
--- /dev/null
+++ b/arch/alpha/boot/bootpz.c
@@ -0,0 +1,469 @@
+/*
+ * arch/alpha/boot/bootpz.c
+ *
+ * Copyright (C) 1997 Jay Estabrook
+ *
+ * This file is used for creating a compressed BOOTP file for the
+ * Linux/AXP kernel
+ *
+ * based significantly on the arch/alpha/boot/main.c of Linus Torvalds
+ * and the decompression code from MILO.
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/console.h>
+#include <asm/hwrpb.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include <stdarg.h>
+
+#include "kzsize.h"
+
+/* FIXME FIXME FIXME */
+#define MALLOC_AREA_SIZE 0x200000 /* 2MB for now */
+/* FIXME FIXME FIXME */
+
+
+/*
+ WARNING NOTE
+
+ It is very possible that turning on additional messages may cause
+ kernel image corruption due to stack usage to do the printing.
+
+*/
+
+#undef DEBUG_CHECK_RANGE
+#undef DEBUG_ADDRESSES
+#undef DEBUG_LAST_STEPS
+
+extern unsigned long switch_to_osf_pal(unsigned long nr,
+ struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
+ unsigned long *vptb);
+
+extern int decompress_kernel(void* destination, void *source,
+ size_t ksize, size_t kzsize);
+
+extern void move_stack(unsigned long new_stack);
+
+struct hwrpb_struct *hwrpb = INIT_HWRPB;
+static struct pcb_struct pcb_va[1];
+
+/*
+ * Find a physical address of a virtual object..
+ *
+ * This is easy using the virtual page table address.
+ */
+#define VPTB ((unsigned long *) 0x200000000)
+
+static inline unsigned long
+find_pa(unsigned long address)
+{
+ unsigned long result;
+
+ result = VPTB[address >> 13];
+ result >>= 32;
+ result <<= 13;
+ result |= address & 0x1fff;
+ return result;
+}
+
+int
+check_range(unsigned long vstart, unsigned long vend,
+ unsigned long kstart, unsigned long kend)
+{
+ unsigned long vaddr, kaddr;
+
+#ifdef DEBUG_CHECK_RANGE
+ srm_printk("check_range: V[0x%lx:0x%lx] K[0x%lx:0x%lx]\n",
+ vstart, vend, kstart, kend);
+#endif
+ /* do some range checking for detecting an overlap... */
+ for (vaddr = vstart; vaddr <= vend; vaddr += PAGE_SIZE)
+ {
+ kaddr = (find_pa(vaddr) | PAGE_OFFSET);
+ if (kaddr >= kstart && kaddr <= kend)
+ {
+#ifdef DEBUG_CHECK_RANGE
+ srm_printk("OVERLAP: vaddr 0x%lx kaddr 0x%lx"
+ " [0x%lx:0x%lx]\n",
+ vaddr, kaddr, kstart, kend);
+#endif
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * This function moves into OSF/1 pal-code, and has a temporary
+ * PCB for that. The kernel proper should replace this PCB with
+ * the real one as soon as possible.
+ *
+ * The page table muckery in here depends on the fact that the boot
+ * code has the L1 page table identity-map itself in the second PTE
+ * in the L1 page table. Thus the L1-page is virtually addressable
+ * itself (through three levels) at virtual address 0x200802000.
+ */
+
+#define L1 ((unsigned long *) 0x200802000)
+
+void
+pal_init(void)
+{
+ unsigned long i, rev;
+ struct percpu_struct * percpu;
+ struct pcb_struct * pcb_pa;
+
+ /* Create the dummy PCB. */
+ pcb_va->ksp = 0;
+ pcb_va->usp = 0;
+ pcb_va->ptbr = L1[1] >> 32;
+ pcb_va->asn = 0;
+ pcb_va->pcc = 0;
+ pcb_va->unique = 0;
+ pcb_va->flags = 1;
+ pcb_va->res1 = 0;
+ pcb_va->res2 = 0;
+ pcb_pa = (struct pcb_struct *)find_pa((unsigned long)pcb_va);
+
+ /*
+ * a0 = 2 (OSF)
+ * a1 = return address, but we give the asm the vaddr of the PCB
+ * a2 = physical addr of PCB
+ * a3 = new virtual page table pointer
+ * a4 = KSP (but the asm sets it)
+ */
+ srm_printk("Switching to OSF PAL-code... ");
+
+ i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
+ if (i) {
+ srm_printk("failed, code %ld\n", i);
+ __halt();
+ }
+
+ percpu = (struct percpu_struct *)
+ (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
+ rev = percpu->pal_revision = percpu->palcode_avail[2];
+
+ srm_printk("OK (rev %lx)\n", rev);
+
+ tbia(); /* do it directly in case we are SMP */
+}
+
+/*
+ * Start the kernel.
+ */
+static inline void
+runkernel(void)
+{
+ __asm__ __volatile__(
+ "bis %0,%0,$27\n\t"
+ "jmp ($27)"
+ : /* no outputs: it doesn't even return */
+ : "r" (START_ADDR));
+}
+
+/* Must record the SP (it is virtual) on entry, so we can make sure
+ not to overwrite it during movement or decompression. */
+unsigned long SP_on_entry;
+
+/* Calculate the kernel image address based on the end of the BOOTP
+ bootstrapper (ie this program).
+*/
+extern char _end;
+#define KERNEL_ORIGIN \
+ ((((unsigned long)&_end) + 511) & ~511)
+
+/* Round address to next higher page boundary. */
+#define NEXT_PAGE(a) (((a) | (PAGE_SIZE - 1)) + 1)
+
+#ifdef INITRD_IMAGE_SIZE
+# define REAL_INITRD_SIZE INITRD_IMAGE_SIZE
+#else
+# define REAL_INITRD_SIZE 0
+#endif
+
+/* Defines from include/asm-alpha/system.h
+
+ BOOT_ADDR Virtual address at which the consoles loads
+ the BOOTP image.
+
+ KERNEL_START KSEG address at which the kernel is built to run,
+ which includes some initial data pages before the
+ code.
+
+ START_ADDR KSEG address of the entry point of kernel code.
+
+ ZERO_PGE KSEG address of page full of zeroes, but
+ upon entry to kerne cvan be expected
+ to hold the parameter list and possible
+ INTRD information.
+
+ These are used in the local defines below.
+*/
+
+
+/* Virtual addresses for the BOOTP image. Note that this includes the
+ bootstrapper code as well as the compressed kernel image, and
+ possibly the INITRD image.
+
+ Oh, and do NOT forget the STACK, which appears to be placed virtually
+ beyond the end of the loaded image.
+*/
+#define V_BOOT_IMAGE_START BOOT_ADDR
+#define V_BOOT_IMAGE_END SP_on_entry
+
+/* Virtual addresses for just the bootstrapper part of the BOOTP image. */
+#define V_BOOTSTRAPPER_START BOOT_ADDR
+#define V_BOOTSTRAPPER_END KERNEL_ORIGIN
+
+/* Virtual addresses for just the data part of the BOOTP
+ image. This may also include the INITRD image, but always
+ includes the STACK.
+*/
+#define V_DATA_START KERNEL_ORIGIN
+#define V_INITRD_START (KERNEL_ORIGIN + KERNEL_Z_SIZE)
+#define V_INTRD_END (V_INITRD_START + REAL_INITRD_SIZE)
+#define V_DATA_END V_BOOT_IMAGE_END
+
+/* KSEG addresses for the uncompressed kernel.
+
+ Note that the end address includes workspace for the decompression.
+ Note also that the DATA_START address is ZERO_PGE, to which we write
+ just before jumping to the kernel image at START_ADDR.
+ */
+#define K_KERNEL_DATA_START ZERO_PGE
+#define K_KERNEL_IMAGE_START START_ADDR
+#define K_KERNEL_IMAGE_END (START_ADDR + KERNEL_SIZE)
+
+/* Define to where we may have to decompress the kernel image, before
+ we move it to the final position, in case of overlap. This will be
+ above the final position of the kernel.
+
+ Regardless of overlap, we move the INITRD image to the end of this
+ copy area, because there needs to be a buffer area after the kernel
+ for "bootmem" anyway.
+*/
+#define K_COPY_IMAGE_START NEXT_PAGE(K_KERNEL_IMAGE_END)
+/* Reserve one page below INITRD for the new stack. */
+#define K_INITRD_START \
+ NEXT_PAGE(K_COPY_IMAGE_START + KERNEL_SIZE + PAGE_SIZE)
+#define K_COPY_IMAGE_END \
+ (K_INITRD_START + REAL_INITRD_SIZE + MALLOC_AREA_SIZE)
+#define K_COPY_IMAGE_SIZE \
+ NEXT_PAGE(K_COPY_IMAGE_END - K_COPY_IMAGE_START)
+
+void
+start_kernel(void)
+{
+ int must_move = 0;
+
+ /* Initialize these for the decompression-in-place situation,
+ which is the smallest amount of work and most likely to
+ occur when using the normal START_ADDR of the kernel
+ (currently set to 16MB, to clear all console code.
+ */
+ unsigned long uncompressed_image_start = K_KERNEL_IMAGE_START;
+ unsigned long uncompressed_image_end = K_KERNEL_IMAGE_END;
+
+ unsigned long initrd_image_start = K_INITRD_START;
+
+ /*
+ * Note that this crufty stuff with static and envval
+ * and envbuf is because:
+ *
+ * 1. Frequently, the stack is short, and we don't want to overrun;
+ * 2. Frequently the stack is where we are going to copy the kernel to;
+ * 3. A certain SRM console required the GET_ENV output to stack.
+ * ??? A comment in the aboot sources indicates that the GET_ENV
+ * destination must be quadword aligned. Might this explain the
+ * behaviour, rather than requiring output to the stack, which
+ * seems rather far-fetched.
+ */
+ static long nbytes;
+ static char envval[256] __attribute__((aligned(8)));
+ register unsigned long asm_sp asm("30");
+
+ SP_on_entry = asm_sp;
+
+ srm_printk("Linux/Alpha BOOTPZ Loader for Linux " UTS_RELEASE "\n");
+
+ /* Validity check the HWRPB. */
+ if (INIT_HWRPB->pagesize != 8192) {
+ srm_printk("Expected 8kB pages, got %ldkB\n",
+ INIT_HWRPB->pagesize >> 10);
+ return;
+ }
+ if (INIT_HWRPB->vptb != (unsigned long) VPTB) {
+ srm_printk("Expected vptb at %p, got %p\n",
+ VPTB, (void *)INIT_HWRPB->vptb);
+ return;
+ }
+
+ /* PALcode (re)initialization. */
+ pal_init();
+
+ /* Get the parameter list from the console environment variable. */
+ nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
+ if (nbytes < 0 || nbytes >= sizeof(envval)) {
+ nbytes = 0;
+ }
+ envval[nbytes] = '\0';
+
+#ifdef DEBUG_ADDRESSES
+ srm_printk("START_ADDR 0x%lx\n", START_ADDR);
+ srm_printk("KERNEL_ORIGIN 0x%lx\n", KERNEL_ORIGIN);
+ srm_printk("KERNEL_SIZE 0x%x\n", KERNEL_SIZE);
+ srm_printk("KERNEL_Z_SIZE 0x%x\n", KERNEL_Z_SIZE);
+#endif
+
+ /* Since all the SRM consoles load the BOOTP image at virtual
+ * 0x20000000, we have to ensure that the physical memory
+ * pages occupied by that image do NOT overlap the physical
+ * address range where the kernel wants to be run. This
+ * causes real problems when attempting to cdecompress the
+ * former into the latter... :-(
+ *
+ * So, we may have to decompress/move the kernel/INITRD image
+ * virtual-to-physical someplace else first before moving
+ * kernel /INITRD to their final resting places... ;-}
+ *
+ * Sigh...
+ */
+
+ /* First, check to see if the range of addresses occupied by
+ the bootstrapper part of the BOOTP image include any of the
+ physical pages into which the kernel will be placed for
+ execution.
+
+ We only need check on the final kernel image range, since we
+ will put the INITRD someplace that we can be sure is not
+ in conflict.
+ */
+ if (check_range(V_BOOTSTRAPPER_START, V_BOOTSTRAPPER_END,
+ K_KERNEL_DATA_START, K_KERNEL_IMAGE_END))
+ {
+ srm_printk("FATAL ERROR: overlap of bootstrapper code\n");
+ __halt();
+ }
+
+ /* Next, check to see if the range of addresses occupied by
+ the compressed kernel/INITRD/stack portion of the BOOTP
+ image include any of the physical pages into which the
+ decompressed kernel or the INITRD will be placed for
+ execution.
+ */
+ if (check_range(V_DATA_START, V_DATA_END,
+ K_KERNEL_IMAGE_START, K_COPY_IMAGE_END))
+ {
+#ifdef DEBUG_ADDRESSES
+ srm_printk("OVERLAP: cannot decompress in place\n");
+#endif
+ uncompressed_image_start = K_COPY_IMAGE_START;
+ uncompressed_image_end = K_COPY_IMAGE_END;
+ must_move = 1;
+
+ /* Finally, check to see if the range of addresses
+ occupied by the compressed kernel/INITRD part of
+ the BOOTP image include any of the physical pages
+ into which that part is to be copied for
+ decompression.
+ */
+ while (check_range(V_DATA_START, V_DATA_END,
+ uncompressed_image_start,
+ uncompressed_image_end))
+ {
+#if 0
+ uncompressed_image_start += K_COPY_IMAGE_SIZE;
+ uncompressed_image_end += K_COPY_IMAGE_SIZE;
+ initrd_image_start += K_COPY_IMAGE_SIZE;
+#else
+ /* Keep as close as possible to end of BOOTP image. */
+ uncompressed_image_start += PAGE_SIZE;
+ uncompressed_image_end += PAGE_SIZE;
+ initrd_image_start += PAGE_SIZE;
+#endif
+ }
+ }
+
+ srm_printk("Starting to load the kernel with args '%s'\n", envval);
+
+#ifdef DEBUG_ADDRESSES
+ srm_printk("Decompressing the kernel...\n"
+ "...from 0x%lx to 0x%lx size 0x%x\n",
+ V_DATA_START,
+ uncompressed_image_start,
+ KERNEL_SIZE);
+#endif
+ decompress_kernel((void *)uncompressed_image_start,
+ (void *)V_DATA_START,
+ KERNEL_SIZE, KERNEL_Z_SIZE);
+
+ /*
+ * Now, move things to their final positions, if/as required.
+ */
+
+#ifdef INITRD_IMAGE_SIZE
+
+ /* First, we always move the INITRD image, if present. */
+#ifdef DEBUG_ADDRESSES
+ srm_printk("Moving the INITRD image...\n"
+ " from 0x%lx to 0x%lx size 0x%x\n",
+ V_INITRD_START,
+ initrd_image_start,
+ INITRD_IMAGE_SIZE);
+#endif
+ memcpy((void *)initrd_image_start, (void *)V_INITRD_START,
+ INITRD_IMAGE_SIZE);
+
+#endif /* INITRD_IMAGE_SIZE */
+
+ /* Next, we may have to move the uncompressed kernel to the
+ final destination.
+ */
+ if (must_move) {
+#ifdef DEBUG_ADDRESSES
+ srm_printk("Moving the uncompressed kernel...\n"
+ "...from 0x%lx to 0x%lx size 0x%x\n",
+ uncompressed_image_start,
+ K_KERNEL_IMAGE_START,
+ (unsigned)KERNEL_SIZE);
+#endif
+ /*
+ * Move the stack to a safe place to ensure it won't be
+ * overwritten by kernel image.
+ */
+ move_stack(initrd_image_start - PAGE_SIZE);
+
+ memcpy((void *)K_KERNEL_IMAGE_START,
+ (void *)uncompressed_image_start, KERNEL_SIZE);
+ }
+
+ /* Clear the zero page, then move the argument list in. */
+#ifdef DEBUG_LAST_STEPS
+ srm_printk("Preparing ZERO_PGE...\n");
+#endif
+ memset((char*)ZERO_PGE, 0, PAGE_SIZE);
+ strcpy((char*)ZERO_PGE, envval);
+
+#ifdef INITRD_IMAGE_SIZE
+
+#ifdef DEBUG_LAST_STEPS
+ srm_printk("Preparing INITRD info...\n");
+#endif
+ /* Finally, set the INITRD paramenters for the kernel. */
+ ((long *)(ZERO_PGE+256))[0] = initrd_image_start;
+ ((long *)(ZERO_PGE+256))[1] = INITRD_IMAGE_SIZE;
+
+#endif /* INITRD_IMAGE_SIZE */
+
+#ifdef DEBUG_LAST_STEPS
+ srm_printk("Doing 'runkernel()'...\n");
+#endif
+ runkernel();
+}
diff --git a/arch/alpha/boot/head.S b/arch/alpha/boot/head.S
new file mode 100644
index 000000000000..f3d98089b3dc
--- /dev/null
+++ b/arch/alpha/boot/head.S
@@ -0,0 +1,123 @@
+/*
+ * arch/alpha/boot/head.S
+ *
+ * initial bootloader stuff..
+ */
+
+#include <asm/system.h>
+
+ .set noreorder
+ .globl __start
+ .ent __start
+__start:
+ br $29,2f
+2: ldgp $29,0($29)
+ jsr $26,start_kernel
+ call_pal PAL_halt
+ .end __start
+
+ .align 5
+ .globl wrent
+ .ent wrent
+wrent:
+ .prologue 0
+ call_pal PAL_wrent
+ ret ($26)
+ .end wrent
+
+ .align 5
+ .globl wrkgp
+ .ent wrkgp
+wrkgp:
+ .prologue 0
+ call_pal PAL_wrkgp
+ ret ($26)
+ .end wrkgp
+
+ .align 5
+ .globl switch_to_osf_pal
+ .ent switch_to_osf_pal
+switch_to_osf_pal:
+ subq $30,128,$30
+ .frame $30,128,$26
+ stq $26,0($30)
+ stq $1,8($30)
+ stq $2,16($30)
+ stq $3,24($30)
+ stq $4,32($30)
+ stq $5,40($30)
+ stq $6,48($30)
+ stq $7,56($30)
+ stq $8,64($30)
+ stq $9,72($30)
+ stq $10,80($30)
+ stq $11,88($30)
+ stq $12,96($30)
+ stq $13,104($30)
+ stq $14,112($30)
+ stq $15,120($30)
+ .prologue 0
+
+ stq $30,0($17) /* save KSP in PCB */
+
+ bis $30,$30,$20 /* a4 = KSP */
+ br $17,1f
+
+ ldq $26,0($30)
+ ldq $1,8($30)
+ ldq $2,16($30)
+ ldq $3,24($30)
+ ldq $4,32($30)
+ ldq $5,40($30)
+ ldq $6,48($30)
+ ldq $7,56($30)
+ ldq $8,64($30)
+ ldq $9,72($30)
+ ldq $10,80($30)
+ ldq $11,88($30)
+ ldq $12,96($30)
+ ldq $13,104($30)
+ ldq $14,112($30)
+ ldq $15,120($30)
+ addq $30,128,$30
+ ret ($26)
+1: call_pal PAL_swppal
+ .end switch_to_osf_pal
+
+ .align 3
+ .globl tbi
+ .ent tbi
+tbi:
+ .prologue 0
+ call_pal PAL_tbi
+ ret ($26)
+ .end tbi
+
+ .align 3
+ .globl halt
+ .ent halt
+halt:
+ .prologue 0
+ call_pal PAL_halt
+ .end halt
+
+/* $16 - new stack page */
+ .align 3
+ .globl move_stack
+ .ent move_stack
+move_stack:
+ .prologue 0
+ lda $0, 0x1fff($31)
+ and $0, $30, $1 /* Stack offset */
+ or $1, $16, $16 /* New stack pointer */
+ mov $30, $1
+ mov $16, $2
+1: ldq $3, 0($1) /* Move the stack */
+ addq $1, 8, $1
+ stq $3, 0($2)
+ and $0, $1, $4
+ addq $2, 8, $2
+ bne $4, 1b
+ mov $16, $30
+ ret ($26)
+ .end move_stack
diff --git a/arch/alpha/boot/main.c b/arch/alpha/boot/main.c
new file mode 100644
index 000000000000..78c9b0b6eea7
--- /dev/null
+++ b/arch/alpha/boot/main.c
@@ -0,0 +1,191 @@
+/*
+ * arch/alpha/boot/main.c
+ *
+ * Copyright (C) 1994, 1995 Linus Torvalds
+ *
+ * This file is the bootloader for the Linux/AXP kernel
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/console.h>
+#include <asm/hwrpb.h>
+#include <asm/pgtable.h>
+
+#include <stdarg.h>
+
+#include "ksize.h"
+
+extern int vsprintf(char *, const char *, va_list);
+extern unsigned long switch_to_osf_pal(unsigned long nr,
+ struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
+ unsigned long *vptb);
+struct hwrpb_struct *hwrpb = INIT_HWRPB;
+static struct pcb_struct pcb_va[1];
+
+/*
+ * Find a physical address of a virtual object..
+ *
+ * This is easy using the virtual page table address.
+ */
+
+static inline void *
+find_pa(unsigned long *vptb, void *ptr)
+{
+ unsigned long address = (unsigned long) ptr;
+ unsigned long result;
+
+ result = vptb[address >> 13];
+ result >>= 32;
+ result <<= 13;
+ result |= address & 0x1fff;
+ return (void *) result;
+}
+
+/*
+ * This function moves into OSF/1 pal-code, and has a temporary
+ * PCB for that. The kernel proper should replace this PCB with
+ * the real one as soon as possible.
+ *
+ * The page table muckery in here depends on the fact that the boot
+ * code has the L1 page table identity-map itself in the second PTE
+ * in the L1 page table. Thus the L1-page is virtually addressable
+ * itself (through three levels) at virtual address 0x200802000.
+ */
+
+#define VPTB ((unsigned long *) 0x200000000)
+#define L1 ((unsigned long *) 0x200802000)
+
+void
+pal_init(void)
+{
+ unsigned long i, rev;
+ struct percpu_struct * percpu;
+ struct pcb_struct * pcb_pa;
+
+ /* Create the dummy PCB. */
+ pcb_va->ksp = 0;
+ pcb_va->usp = 0;
+ pcb_va->ptbr = L1[1] >> 32;
+ pcb_va->asn = 0;
+ pcb_va->pcc = 0;
+ pcb_va->unique = 0;
+ pcb_va->flags = 1;
+ pcb_va->res1 = 0;
+ pcb_va->res2 = 0;
+ pcb_pa = find_pa(VPTB, pcb_va);
+
+ /*
+ * a0 = 2 (OSF)
+ * a1 = return address, but we give the asm the vaddr of the PCB
+ * a2 = physical addr of PCB
+ * a3 = new virtual page table pointer
+ * a4 = KSP (but the asm sets it)
+ */
+ srm_printk("Switching to OSF PAL-code .. ");
+
+ i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
+ if (i) {
+ srm_printk("failed, code %ld\n", i);
+ __halt();
+ }
+
+ percpu = (struct percpu_struct *)
+ (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
+ rev = percpu->pal_revision = percpu->palcode_avail[2];
+
+ srm_printk("Ok (rev %lx)\n", rev);
+
+ tbia(); /* do it directly in case we are SMP */
+}
+
+static inline long openboot(void)
+{
+ char bootdev[256];
+ long result;
+
+ result = callback_getenv(ENV_BOOTED_DEV, bootdev, 255);
+ if (result < 0)
+ return result;
+ return callback_open(bootdev, result & 255);
+}
+
+static inline long close(long dev)
+{
+ return callback_close(dev);
+}
+
+static inline long load(long dev, unsigned long addr, unsigned long count)
+{
+ char bootfile[256];
+ extern char _end;
+ long result, boot_size = &_end - (char *) BOOT_ADDR;
+
+ result = callback_getenv(ENV_BOOTED_FILE, bootfile, 255);
+ if (result < 0)
+ return result;
+ result &= 255;
+ bootfile[result] = '\0';
+ if (result)
+ srm_printk("Boot file specification (%s) not implemented\n",
+ bootfile);
+ return callback_read(dev, count, addr, boot_size/512 + 1);
+}
+
+/*
+ * Start the kernel.
+ */
+static void runkernel(void)
+{
+ __asm__ __volatile__(
+ "bis %1,%1,$30\n\t"
+ "bis %0,%0,$26\n\t"
+ "ret ($26)"
+ : /* no outputs: it doesn't even return */
+ : "r" (START_ADDR),
+ "r" (PAGE_SIZE + INIT_STACK));
+}
+
+void start_kernel(void)
+{
+ long i;
+ long dev;
+ int nbytes;
+ char envval[256];
+
+ srm_printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n");
+ if (INIT_HWRPB->pagesize != 8192) {
+ srm_printk("Expected 8kB pages, got %ldkB\n", INIT_HWRPB->pagesize >> 10);
+ return;
+ }
+ pal_init();
+ dev = openboot();
+ if (dev < 0) {
+ srm_printk("Unable to open boot device: %016lx\n", dev);
+ return;
+ }
+ dev &= 0xffffffff;
+ srm_printk("Loading vmlinux ...");
+ i = load(dev, START_ADDR, KERNEL_SIZE);
+ close(dev);
+ if (i != KERNEL_SIZE) {
+ srm_printk("Failed (%lx)\n", i);
+ return;
+ }
+
+ nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval));
+ if (nbytes < 0) {
+ nbytes = 0;
+ }
+ envval[nbytes] = '\0';
+ strcpy((char*)ZERO_PGE, envval);
+
+ srm_printk(" Ok\nNow booting the kernel\n");
+ runkernel();
+ for (i = 0 ; i < 0x100000000 ; i++)
+ /* nothing */;
+ __halt();
+}
diff --git a/arch/alpha/boot/misc.c b/arch/alpha/boot/misc.c
new file mode 100644
index 000000000000..1d65adf5691e
--- /dev/null
+++ b/arch/alpha/boot/misc.c
@@ -0,0 +1,207 @@
+/*
+ * misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Modified for ARM Linux by Russell King
+ *
+ * Nicolas Pitre <nico@visuaide.com> 1999/04/14 :
+ * For this code to run directly from Flash, all constant variables must
+ * be marked with 'const' and all other variables initialized at run-time
+ * only. This way all non constant variables will end up in the bss segment,
+ * which should point to addresses in RAM and cleared to 0 on start.
+ * This allows for a much quicker boot time.
+ *
+ * Modified for Alpha, from the ARM version, by Jay Estabrook 2003.
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/uaccess.h>
+
+#define memzero(s,n) memset ((s),0,(n))
+#define puts srm_printk
+extern long srm_printk(const char *, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+/*
+ * gzip delarations
+ */
+#define OF(args) args
+#define STATIC static
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define WSIZE 0x8000 /* Window size must be at least 32k, */
+ /* and a power of two */
+
+static uch *inbuf; /* input buffer */
+static uch *window; /* Sliding window buffer */
+
+static unsigned insize; /* valid bytes in inbuf */
+static unsigned inptr; /* index of next byte to be processed in inbuf */
+static unsigned outcnt; /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+static char *input_data;
+static int input_data_size;
+
+static uch *output_data;
+static ulg output_ptr;
+static ulg bytes_out;
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern int end;
+static ulg free_mem_ptr;
+static ulg free_mem_ptr_end;
+
+#define HEAP_SIZE 0x2000
+
+#include "../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+ void *p;
+
+ if (size <0) error("Malloc error");
+ if (free_mem_ptr <= 0) error("Memory error");
+
+ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+ p = (void *)free_mem_ptr;
+ free_mem_ptr += size;
+
+ if (free_mem_ptr >= free_mem_ptr_end)
+ error("Out of memory");
+ return p;
+}
+
+static void free(void *where)
+{ /* gzip_mark & gzip_release do the free */
+}
+
+static void gzip_mark(void **ptr)
+{
+ *ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+ free_mem_ptr = (long) *ptr;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+int fill_inbuf(void)
+{
+ if (insize != 0)
+ error("ran out of input data");
+
+ inbuf = input_data;
+ insize = input_data_size;
+
+ inptr = 1;
+ return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+void flush_window(void)
+{
+ ulg c = crc;
+ unsigned n;
+ uch *in, *out, ch;
+
+ in = window;
+ out = &output_data[output_ptr];
+ for (n = 0; n < outcnt; n++) {
+ ch = *out++ = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+ bytes_out += (ulg)outcnt;
+ output_ptr += (ulg)outcnt;
+ outcnt = 0;
+/* puts("."); */
+}
+
+static void error(char *x)
+{
+ puts("\n\n");
+ puts(x);
+ puts("\n\n -- System halted");
+
+ while(1); /* Halt */
+}
+
+unsigned int
+decompress_kernel(void *output_start,
+ void *input_start,
+ size_t ksize,
+ size_t kzsize)
+{
+ output_data = (uch *)output_start;
+ input_data = (uch *)input_start;
+ input_data_size = kzsize; /* use compressed size */
+
+ /* FIXME FIXME FIXME */
+ free_mem_ptr = (ulg)output_start + ksize;
+ free_mem_ptr_end = (ulg)output_start + ksize + 0x200000;
+ /* FIXME FIXME FIXME */
+
+ /* put in temp area to reduce initial footprint */
+ window = malloc(WSIZE);
+
+ makecrc();
+/* puts("Uncompressing Linux..."); */
+ gunzip();
+/* puts(" done, booting the kernel.\n"); */
+ return output_ptr;
+}
diff --git a/arch/alpha/boot/tools/mkbb.c b/arch/alpha/boot/tools/mkbb.c
new file mode 100644
index 000000000000..23c7190b047c
--- /dev/null
+++ b/arch/alpha/boot/tools/mkbb.c
@@ -0,0 +1,151 @@
+/* This utility makes a bootblock suitable for the SRM console/miniloader */
+
+/* Usage:
+ * mkbb <device> <lxboot>
+ *
+ * Where <device> is the name of the device to install the bootblock on,
+ * and <lxboot> is the name of a bootblock to merge in. This bootblock
+ * contains the offset and size of the bootloader. It must be exactly
+ * 512 bytes long.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+/* Minimal definition of disklabel, so we don't have to include
+ * asm/disklabel.h (confuses make)
+ */
+#ifndef MAXPARTITIONS
+#define MAXPARTITIONS 8 /* max. # of partitions */
+#endif
+
+#ifndef u8
+#define u8 unsigned char
+#endif
+
+#ifndef u16
+#define u16 unsigned short
+#endif
+
+#ifndef u32
+#define u32 unsigned int
+#endif
+
+struct disklabel {
+ u32 d_magic; /* must be DISKLABELMAGIC */
+ u16 d_type, d_subtype;
+ u8 d_typename[16];
+ u8 d_packname[16];
+ u32 d_secsize;
+ u32 d_nsectors;
+ u32 d_ntracks;
+ u32 d_ncylinders;
+ u32 d_secpercyl;
+ u32 d_secprtunit;
+ u16 d_sparespertrack;
+ u16 d_sparespercyl;
+ u32 d_acylinders;
+ u16 d_rpm, d_interleave, d_trackskew, d_cylskew;
+ u32 d_headswitch, d_trkseek, d_flags;
+ u32 d_drivedata[5];
+ u32 d_spare[5];
+ u32 d_magic2; /* must be DISKLABELMAGIC */
+ u16 d_checksum;
+ u16 d_npartitions;
+ u32 d_bbsize, d_sbsize;
+ struct d_partition {
+ u32 p_size;
+ u32 p_offset;
+ u32 p_fsize;
+ u8 p_fstype;
+ u8 p_frag;
+ u16 p_cpg;
+ } d_partitions[MAXPARTITIONS];
+};
+
+
+typedef union __bootblock {
+ struct {
+ char __pad1[64];
+ struct disklabel __label;
+ } __u1;
+ struct {
+ unsigned long __pad2[63];
+ unsigned long __checksum;
+ } __u2;
+ char bootblock_bytes[512];
+ unsigned long bootblock_quadwords[64];
+} bootblock;
+
+#define bootblock_label __u1.__label
+#define bootblock_checksum __u2.__checksum
+
+main(int argc, char ** argv)
+{
+ bootblock bootblock_from_disk;
+ bootblock bootloader_image;
+ int dev, fd;
+ int i;
+ int nread;
+
+ /* Make sure of the arg count */
+ if(argc != 3) {
+ fprintf(stderr, "Usage: %s device lxboot\n", argv[0]);
+ exit(0);
+ }
+
+ /* First, open the device and make sure it's accessible */
+ dev = open(argv[1], O_RDWR);
+ if(dev < 0) {
+ perror(argv[1]);
+ exit(0);
+ }
+
+ /* Now open the lxboot and make sure it's reasonable */
+ fd = open(argv[2], O_RDONLY);
+ if(fd < 0) {
+ perror(argv[2]);
+ close(dev);
+ exit(0);
+ }
+
+ /* Read in the lxboot */
+ nread = read(fd, &bootloader_image, sizeof(bootblock));
+ if(nread != sizeof(bootblock)) {
+ perror("lxboot read");
+ fprintf(stderr, "expected %d, got %d\n", sizeof(bootblock), nread);
+ exit(0);
+ }
+
+ /* Read in the bootblock from disk. */
+ nread = read(dev, &bootblock_from_disk, sizeof(bootblock));
+ if(nread != sizeof(bootblock)) {
+ perror("bootblock read");
+ fprintf(stderr, "expected %d, got %d\n", sizeof(bootblock), nread);
+ exit(0);
+ }
+
+ /* Swap the bootblock's disklabel into the bootloader */
+ bootloader_image.bootblock_label = bootblock_from_disk.bootblock_label;
+
+ /* Calculate the bootblock checksum */
+ bootloader_image.bootblock_checksum = 0;
+ for(i = 0; i < 63; i++) {
+ bootloader_image.bootblock_checksum +=
+ bootloader_image.bootblock_quadwords[i];
+ }
+
+ /* Write the whole thing out! */
+ lseek(dev, 0L, SEEK_SET);
+ if(write(dev, &bootloader_image, sizeof(bootblock)) != sizeof(bootblock)) {
+ perror("bootblock write");
+ exit(0);
+ }
+
+ close(fd);
+ close(dev);
+ exit(0);
+}
+
+
diff --git a/arch/alpha/boot/tools/objstrip.c b/arch/alpha/boot/tools/objstrip.c
new file mode 100644
index 000000000000..67beb1b45e4f
--- /dev/null
+++ b/arch/alpha/boot/tools/objstrip.c
@@ -0,0 +1,281 @@
+/*
+ * arch/alpha/boot/tools/objstrip.c
+ *
+ * Strip the object file headers/trailers from an executable (ELF or ECOFF).
+ *
+ * Copyright (C) 1996 David Mosberger-Tang.
+ */
+/*
+ * Converts an ECOFF or ELF object file into a bootable file. The
+ * object file must be a OMAGIC file (i.e., data and bss follow immediately
+ * behind the text). See DEC "Assembly Language Programmer's Guide"
+ * documentation for details. The SRM boot process is documented in
+ * the Alpha AXP Architecture Reference Manual, Second Edition by
+ * Richard L. Sites and Richard T. Witek.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/a.out.h>
+#include <linux/coff.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#ifdef __ELF__
+# include <linux/elf.h>
+#endif
+
+/* bootfile size must be multiple of BLOCK_SIZE: */
+#define BLOCK_SIZE 512
+
+const char * prog_name;
+
+
+void
+usage (void)
+{
+ fprintf(stderr,
+ "usage: %s [-v] -p file primary\n"
+ " %s [-vb] file [secondary]\n", prog_name, prog_name);
+ exit(1);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ size_t nwritten, tocopy, n, mem_size, fil_size, pad = 0;
+ int fd, ofd, i, j, verbose = 0, primary = 0;
+ char buf[8192], *inname;
+ struct exec * aout; /* includes file & aout header */
+ long offset;
+#ifdef __ELF__
+ struct elfhdr *elf;
+ struct elf_phdr *elf_phdr; /* program header */
+ unsigned long long e_entry;
+#endif
+
+ prog_name = argv[0];
+
+ for (i = 1; i < argc && argv[i][0] == '-'; ++i) {
+ for (j = 1; argv[i][j]; ++j) {
+ switch (argv[i][j]) {
+ case 'v':
+ verbose = ~verbose;
+ break;
+
+ case 'b':
+ pad = BLOCK_SIZE;
+ break;
+
+ case 'p':
+ primary = 1; /* make primary bootblock */
+ break;
+ }
+ }
+ }
+
+ if (i >= argc) {
+ usage();
+ }
+ inname = argv[i++];
+
+ fd = open(inname, O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ exit(1);
+ }
+
+ ofd = 1;
+ if (i < argc) {
+ ofd = open(argv[i++], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd == -1) {
+ perror("open");
+ exit(1);
+ }
+ }
+
+ if (primary) {
+ /* generate bootblock for primary loader */
+
+ unsigned long bb[64], sum = 0;
+ struct stat st;
+ off_t size;
+ int i;
+
+ if (ofd == 1) {
+ usage();
+ }
+
+ if (fstat(fd, &st) == -1) {
+ perror("fstat");
+ exit(1);
+ }
+
+ size = (st.st_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1);
+ memset(bb, 0, sizeof(bb));
+ strcpy((char *) bb, "Linux SRM bootblock");
+ bb[60] = size / BLOCK_SIZE; /* count */
+ bb[61] = 1; /* starting sector # */
+ bb[62] = 0; /* flags---must be 0 */
+ for (i = 0; i < 63; ++i) {
+ sum += bb[i];
+ }
+ bb[63] = sum;
+ if (write(ofd, bb, sizeof(bb)) != sizeof(bb)) {
+ perror("boot-block write");
+ exit(1);
+ }
+ printf("%lu\n", size);
+ return 0;
+ }
+
+ /* read and inspect exec header: */
+
+ if (read(fd, buf, sizeof(buf)) < 0) {
+ perror("read");
+ exit(1);
+ }
+
+#ifdef __ELF__
+ elf = (struct elfhdr *) buf;
+
+ if (elf->e_ident[0] == 0x7f && strncmp(elf->e_ident + 1, "ELF", 3) == 0) {
+ if (elf->e_type != ET_EXEC) {
+ fprintf(stderr, "%s: %s is not an ELF executable\n",
+ prog_name, inname);
+ exit(1);
+ }
+ if (!elf_check_arch(elf)) {
+ fprintf(stderr, "%s: is not for this processor (e_machine=%d)\n",
+ prog_name, elf->e_machine);
+ exit(1);
+ }
+ if (elf->e_phnum != 1) {
+ fprintf(stderr,
+ "%s: %d program headers (forgot to link with -N?)\n",
+ prog_name, elf->e_phnum);
+ }
+
+ e_entry = elf->e_entry;
+
+ lseek(fd, elf->e_phoff, SEEK_SET);
+ if (read(fd, buf, sizeof(*elf_phdr)) != sizeof(*elf_phdr)) {
+ perror("read");
+ exit(1);
+ }
+
+ elf_phdr = (struct elf_phdr *) buf;
+ offset = elf_phdr->p_offset;
+ mem_size = elf_phdr->p_memsz;
+ fil_size = elf_phdr->p_filesz;
+
+ /* work around ELF bug: */
+ if (elf_phdr->p_vaddr < e_entry) {
+ unsigned long delta = e_entry - elf_phdr->p_vaddr;
+ offset += delta;
+ mem_size -= delta;
+ fil_size -= delta;
+ elf_phdr->p_vaddr += delta;
+ }
+
+ if (verbose) {
+ fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n",
+ prog_name, (long) elf_phdr->p_vaddr,
+ elf_phdr->p_vaddr + fil_size, offset);
+ }
+ } else
+#endif
+ {
+ aout = (struct exec *) buf;
+
+ if (!(aout->fh.f_flags & COFF_F_EXEC)) {
+ fprintf(stderr, "%s: %s is not in executable format\n",
+ prog_name, inname);
+ exit(1);
+ }
+
+ if (aout->fh.f_opthdr != sizeof(aout->ah)) {
+ fprintf(stderr, "%s: %s has unexpected optional header size\n",
+ prog_name, inname);
+ exit(1);
+ }
+
+ if (N_MAGIC(*aout) != OMAGIC) {
+ fprintf(stderr, "%s: %s is not an OMAGIC file\n",
+ prog_name, inname);
+ exit(1);
+ }
+ offset = N_TXTOFF(*aout);
+ fil_size = aout->ah.tsize + aout->ah.dsize;
+ mem_size = fil_size + aout->ah.bsize;
+
+ if (verbose) {
+ fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n",
+ prog_name, aout->ah.text_start,
+ aout->ah.text_start + fil_size, offset);
+ }
+ }
+
+ if (lseek(fd, offset, SEEK_SET) != offset) {
+ perror("lseek");
+ exit(1);
+ }
+
+ if (verbose) {
+ fprintf(stderr, "%s: copying %lu byte from %s\n",
+ prog_name, (unsigned long) fil_size, inname);
+ }
+
+ tocopy = fil_size;
+ while (tocopy > 0) {
+ n = tocopy;
+ if (n > sizeof(buf)) {
+ n = sizeof(buf);
+ }
+ tocopy -= n;
+ if ((size_t) read(fd, buf, n) != n) {
+ perror("read");
+ exit(1);
+ }
+ do {
+ nwritten = write(ofd, buf, n);
+ if ((ssize_t) nwritten == -1) {
+ perror("write");
+ exit(1);
+ }
+ n -= nwritten;
+ } while (n > 0);
+ }
+
+ if (pad) {
+ mem_size = ((mem_size + pad - 1) / pad) * pad;
+ }
+
+ tocopy = mem_size - fil_size;
+ if (tocopy > 0) {
+ fprintf(stderr,
+ "%s: zero-filling bss and aligning to %lu with %lu bytes\n",
+ prog_name, pad, (unsigned long) tocopy);
+
+ memset(buf, 0x00, sizeof(buf));
+ do {
+ n = tocopy;
+ if (n > sizeof(buf)) {
+ n = sizeof(buf);
+ }
+ nwritten = write(ofd, buf, n);
+ if ((ssize_t) nwritten == -1) {
+ perror("write");
+ exit(1);
+ }
+ tocopy -= nwritten;
+ } while (tocopy > 0);
+ }
+ return 0;
+}
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
new file mode 100644
index 000000000000..5e39b7a7c8f4
--- /dev/null
+++ b/arch/alpha/defconfig
@@ -0,0 +1,927 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc2
+# Sat Sep 25 15:38:35 2004
+#
+CONFIG_ALPHA=y
+CONFIG_64BIT=y
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_GENERIC_IOMAP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System setup
+#
+CONFIG_ALPHA_GENERIC=y
+# CONFIG_ALPHA_ALCOR is not set
+# CONFIG_ALPHA_XL is not set
+# CONFIG_ALPHA_BOOK1 is not set
+# CONFIG_ALPHA_AVANTI_CH is not set
+# CONFIG_ALPHA_CABRIOLET is not set
+# CONFIG_ALPHA_DP264 is not set
+# CONFIG_ALPHA_EB164 is not set
+# CONFIG_ALPHA_EB64P_CH is not set
+# CONFIG_ALPHA_EB66 is not set
+# CONFIG_ALPHA_EB66P is not set
+# CONFIG_ALPHA_EIGER is not set
+# CONFIG_ALPHA_JENSEN is not set
+# CONFIG_ALPHA_LX164 is not set
+# CONFIG_ALPHA_LYNX is not set
+# CONFIG_ALPHA_MARVEL is not set
+# CONFIG_ALPHA_MIATA is not set
+# CONFIG_ALPHA_MIKASA is not set
+# CONFIG_ALPHA_NAUTILUS is not set
+# CONFIG_ALPHA_NONAME_CH is not set
+# CONFIG_ALPHA_NORITAKE is not set
+# CONFIG_ALPHA_PC164 is not set
+# CONFIG_ALPHA_P2K is not set
+# CONFIG_ALPHA_RAWHIDE is not set
+# CONFIG_ALPHA_RUFFIAN is not set
+# CONFIG_ALPHA_RX164 is not set
+# CONFIG_ALPHA_SX164 is not set
+# CONFIG_ALPHA_SABLE is not set
+# CONFIG_ALPHA_SHARK is not set
+# CONFIG_ALPHA_TAKARA is not set
+# CONFIG_ALPHA_TITAN is not set
+# CONFIG_ALPHA_WILDFIRE is not set
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_ALPHA_CORE_AGP=y
+CONFIG_ALPHA_BROKEN_IRQ_MASK=y
+CONFIG_EISA=y
+# CONFIG_SMP is not set
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_VERBOSE_MCHECK=y
+CONFIG_VERBOSE_MCHECK_ON=1
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+CONFIG_EISA_PCI_EISA=y
+CONFIG_EISA_VIRTUAL_ROOT=y
+CONFIG_EISA_NAMES=y
+CONFIG_SRM_ENV=m
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_EM86 is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+CONFIG_ISAPNP=y
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+CONFIG_BLK_DEV_ALI15X3=y
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_TRIFLEX is not set
+CONFIG_BLK_DEV_CY82C693=y
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=5000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA6322 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+# CONFIG_IP_NF_MATCH_MAC is not set
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+# CONFIG_IP_NF_MATCH_MARK is not set
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+# CONFIG_IP_NF_MATCH_STATE is not set
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_EL3 is not set
+# CONFIG_3C515 is not set
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+CONFIG_TULIP_MMIO=y
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+CONFIG_YELLOWFIN=y
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=m
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_OSF_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_DEBUG_RWLOCK is not set
+# CONFIG_DEBUG_SEMAPHORE is not set
+CONFIG_ALPHA_LEGACY_START_ADDRESS=y
+CONFIG_MATHEMU=y
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WHIRLPOOL is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
new file mode 100644
index 000000000000..ab6fa54b3860
--- /dev/null
+++ b/arch/alpha/kernel/Makefile
@@ -0,0 +1,104 @@
+#
+# Makefile for the linux kernel.
+#
+
+extra-y := head.o vmlinux.lds
+EXTRA_AFLAGS := $(CFLAGS)
+EXTRA_CFLAGS := -Werror -Wno-sign-compare
+
+obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o \
+ irq_alpha.o signal.o setup.o ptrace.o time.o semaphore.o \
+ alpha_ksyms.o systbls.o err_common.o io.o
+
+obj-$(CONFIG_VGA_HOSE) += console.o
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_PCI) += pci.o pci_iommu.o
+obj-$(CONFIG_SRM_ENV) += srm_env.o
+obj-$(CONFIG_MODULES) += module.o
+
+ifdef CONFIG_ALPHA_GENERIC
+
+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_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_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
+obj-y += sys_marvel.o sys_titan.o sys_wildfire.o
+obj-y += err_ev7.o err_titan.o err_marvel.o
+endif
+
+obj-y += irq_pyxis.o irq_i8259.o irq_srm.o
+obj-y += err_ev6.o
+obj-y += es1888.o smc37c669.o smc37c93x.o ns87312.o gct.o
+obj-y += srmcons.o
+
+else
+
+# Misc support
+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
+obj-$(CONFIG_ALPHA_T2) += core_t2.o
+obj-$(CONFIG_ALPHA_TSUNAMI) += core_tsunami.o
+obj-$(CONFIG_ALPHA_TITAN) += core_titan.o
+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 \
+ ns87312.o
+obj-$(CONFIG_ALPHA_EB164) += sys_cabriolet.o irq_i8259.o irq_srm.o \
+ ns87312.o
+obj-$(CONFIG_ALPHA_EB66P) += sys_cabriolet.o irq_i8259.o irq_srm.o \
+ ns87312.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 \
+ smc37c93x.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
+obj-$(CONFIG_ALPHA_MIKASA) += sys_mikasa.o irq_i8259.o irq_srm.o
+obj-$(CONFIG_ALPHA_NAUTILUS) += sys_nautilus.o irq_i8259.o irq_srm.o
+obj-$(CONFIG_ALPHA_NORITAKE) += sys_noritake.o irq_i8259.o
+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 ns87312.o
+obj-$(CONFIG_ALPHA_AVANTI) += sys_sio.o irq_i8259.o irq_srm.o ns87312.o
+obj-$(CONFIG_ALPHA_NONAME) += sys_sio.o irq_i8259.o irq_srm.o ns87312.o
+obj-$(CONFIG_ALPHA_P2K) += sys_sio.o irq_i8259.o irq_srm.o ns87312.o
+obj-$(CONFIG_ALPHA_XL) += sys_sio.o irq_i8259.o irq_srm.o ns87312.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 ns87312.o
+obj-$(CONFIG_ALPHA_WILDFIRE) += sys_wildfire.o irq_i8259.o
+
+# Error support
+obj-$(CONFIG_ALPHA_MARVEL) += err_ev7.o err_marvel.o
+obj-$(CONFIG_ALPHA_NAUTILUS) += err_ev6.o
+obj-$(CONFIG_ALPHA_TITAN) += err_ev6.o err_titan.o
+
+endif # GENERIC
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
new file mode 100644
index 000000000000..fc5ef90c4fc9
--- /dev/null
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -0,0 +1,235 @@
+/*
+ * linux/arch/alpha/kernel/ksyms.c
+ *
+ * Export the alpha-specific functions that are needed for loadable
+ * modules.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+#include <linux/socket.h>
+#include <linux/syscalls.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/pci.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/console.h>
+#include <asm/hwrpb.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/checksum.h>
+#include <linux/interrupt.h>
+#include <asm/fpu.h>
+#include <asm/irq.h>
+#include <asm/machvec.h>
+#include <asm/pgalloc.h>
+#include <asm/semaphore.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/vga.h>
+
+#define __KERNEL_SYSCALLS__
+#include <asm/unistd.h>
+
+extern struct hwrpb_struct *hwrpb;
+extern void dump_thread(struct pt_regs *, struct user *);
+extern spinlock_t rtc_lock;
+
+/* these are C runtime functions with special calling conventions: */
+extern void __divl (void);
+extern void __reml (void);
+extern void __divq (void);
+extern void __remq (void);
+extern void __divlu (void);
+extern void __remlu (void);
+extern void __divqu (void);
+extern void __remqu (void);
+
+EXPORT_SYMBOL(alpha_mv);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
+EXPORT_SYMBOL(probe_irq_mask);
+EXPORT_SYMBOL(screen_info);
+EXPORT_SYMBOL(perf_irq);
+EXPORT_SYMBOL(callback_getenv);
+EXPORT_SYMBOL(callback_setenv);
+EXPORT_SYMBOL(callback_save_env);
+#ifdef CONFIG_ALPHA_GENERIC
+EXPORT_SYMBOL(alpha_using_srm);
+#endif /* CONFIG_ALPHA_GENERIC */
+
+/* platform dependent support */
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(__memcpy);
+EXPORT_SYMBOL(__memset);
+EXPORT_SYMBOL(__memsetw);
+EXPORT_SYMBOL(__constant_c_memset);
+EXPORT_SYMBOL(copy_page);
+EXPORT_SYMBOL(clear_page);
+
+EXPORT_SYMBOL(__direct_map_base);
+EXPORT_SYMBOL(__direct_map_size);
+
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_map_page);
+EXPORT_SYMBOL(pci_unmap_single);
+EXPORT_SYMBOL(pci_unmap_page);
+EXPORT_SYMBOL(pci_map_sg);
+EXPORT_SYMBOL(pci_unmap_sg);
+EXPORT_SYMBOL(pci_dma_supported);
+EXPORT_SYMBOL(pci_dac_dma_supported);
+EXPORT_SYMBOL(pci_dac_page_to_dma);
+EXPORT_SYMBOL(pci_dac_dma_to_page);
+EXPORT_SYMBOL(pci_dac_dma_to_offset);
+EXPORT_SYMBOL(alpha_gendev_to_pci);
+#endif
+EXPORT_SYMBOL(dma_set_mask);
+
+EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(dump_elf_thread);
+EXPORT_SYMBOL(dump_elf_task);
+EXPORT_SYMBOL(dump_elf_task_fp);
+EXPORT_SYMBOL(hwrpb);
+EXPORT_SYMBOL(start_thread);
+EXPORT_SYMBOL(alpha_read_fp_reg);
+EXPORT_SYMBOL(alpha_read_fp_reg_s);
+EXPORT_SYMBOL(alpha_write_fp_reg);
+EXPORT_SYMBOL(alpha_write_fp_reg_s);
+
+/* In-kernel system calls. */
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_dup);
+EXPORT_SYMBOL(sys_exit);
+EXPORT_SYMBOL(sys_write);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(execve);
+EXPORT_SYMBOL(sys_setsid);
+EXPORT_SYMBOL(sys_wait4);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_tcpudp_magic);
+EXPORT_SYMBOL(ip_compute_csum);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+EXPORT_SYMBOL(csum_ipv6_magic);
+
+#ifdef CONFIG_MATHEMU_MODULE
+extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
+extern long (*alpha_fp_emul) (unsigned long pc);
+EXPORT_SYMBOL(alpha_fp_emul_imprecise);
+EXPORT_SYMBOL(alpha_fp_emul);
+#endif
+
+#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+EXPORT_SYMBOL(__min_ipl);
+#endif
+
+/*
+ * The following are specially called from the uaccess assembly stubs.
+ */
+EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(__do_clear_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(__strnlen_user);
+
+/* Semaphore helper functions. */
+EXPORT_SYMBOL(__down_failed);
+EXPORT_SYMBOL(__down_failed_interruptible);
+EXPORT_SYMBOL(__up_wakeup);
+EXPORT_SYMBOL(down);
+EXPORT_SYMBOL(down_interruptible);
+EXPORT_SYMBOL(down_trylock);
+EXPORT_SYMBOL(up);
+
+/*
+ * SMP-specific symbols.
+ */
+
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(flush_tlb_mm);
+EXPORT_SYMBOL(flush_tlb_range);
+EXPORT_SYMBOL(flush_tlb_page);
+EXPORT_SYMBOL(smp_imb);
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(smp_call_function);
+EXPORT_SYMBOL(smp_call_function_on_cpu);
+EXPORT_SYMBOL(_atomic_dec_and_lock);
+#ifdef CONFIG_DEBUG_SPINLOCK
+EXPORT_SYMBOL(_raw_spin_unlock);
+EXPORT_SYMBOL(debug_spin_lock);
+EXPORT_SYMBOL(debug_spin_trylock);
+#endif
+#ifdef CONFIG_DEBUG_RWLOCK
+EXPORT_SYMBOL(_raw_write_lock);
+EXPORT_SYMBOL(_raw_read_lock);
+#endif
+EXPORT_SYMBOL(cpu_present_mask);
+#endif /* CONFIG_SMP */
+
+/*
+ * NUMA specific symbols
+ */
+#ifdef CONFIG_DISCONTIGMEM
+EXPORT_SYMBOL(node_data);
+#endif /* CONFIG_DISCONTIGMEM */
+
+EXPORT_SYMBOL(rtc_lock);
+
+/*
+ * The following are special because they're not called
+ * explicitly (the C compiler or assembler generates them in
+ * response to division operations). Fortunately, their
+ * interface isn't gonna change any time soon now, so it's OK
+ * to leave it out of version control.
+ */
+# undef memcpy
+# undef memset
+EXPORT_SYMBOL(__divl);
+EXPORT_SYMBOL(__divlu);
+EXPORT_SYMBOL(__divq);
+EXPORT_SYMBOL(__divqu);
+EXPORT_SYMBOL(__reml);
+EXPORT_SYMBOL(__remlu);
+EXPORT_SYMBOL(__remq);
+EXPORT_SYMBOL(__remqu);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memchr);
+
+EXPORT_SYMBOL(get_wchan);
+
+#ifdef CONFIG_ALPHA_IRONGATE
+EXPORT_SYMBOL(irongate_ioremap);
+EXPORT_SYMBOL(irongate_iounmap);
+#endif
diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
new file mode 100644
index 000000000000..8f2e5c718b50
--- /dev/null
+++ b/arch/alpha/kernel/asm-offsets.c
@@ -0,0 +1,43 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <asm/io.h>
+
+#define DEFINE(sym, val) \
+ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+void foo(void)
+{
+ DEFINE(TI_TASK, offsetof(struct thread_info, task));
+ DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+ DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
+ BLANK();
+
+ DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
+ DEFINE(TASK_UID, offsetof(struct task_struct, uid));
+ DEFINE(TASK_EUID, offsetof(struct task_struct, euid));
+ DEFINE(TASK_GID, offsetof(struct task_struct, gid));
+ DEFINE(TASK_EGID, offsetof(struct task_struct, egid));
+ DEFINE(TASK_REAL_PARENT, offsetof(struct task_struct, real_parent));
+ DEFINE(TASK_TGID, offsetof(struct task_struct, tgid));
+ BLANK();
+
+ DEFINE(SIZEOF_PT_REGS, sizeof(struct pt_regs));
+ DEFINE(PT_PTRACED, PT_PTRACED);
+ DEFINE(CLONE_VM, CLONE_VM);
+ DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
+ DEFINE(SIGCHLD, SIGCHLD);
+ BLANK();
+
+ DEFINE(HAE_CACHE, offsetof(struct alpha_machine_vector, hae_cache));
+ DEFINE(HAE_REG, offsetof(struct alpha_machine_vector, hae_register));
+}
diff --git a/arch/alpha/kernel/console.c b/arch/alpha/kernel/console.c
new file mode 100644
index 000000000000..cb3e739fbad8
--- /dev/null
+++ b/arch/alpha/kernel/console.c
@@ -0,0 +1,66 @@
+/*
+ * linux/arch/alpha/kernel/console.c
+ *
+ * Architecture-specific specific support for VGA device on
+ * non-0 I/O hose
+ */
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <asm/vga.h>
+#include <asm/machvec.h>
+
+#ifdef CONFIG_VGA_HOSE
+
+/*
+ * Externally-visible vga hose bases
+ */
+unsigned long __vga_hose_io_base = 0; /* base for default hose */
+unsigned long __vga_hose_mem_base = 0; /* base for default hose */
+
+static struct pci_controller * __init
+default_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2)
+{
+ if (h2->index < h1->index)
+ return h2;
+
+ return h1;
+}
+
+void __init
+set_vga_hose(struct pci_controller *hose)
+{
+ if (hose) {
+ __vga_hose_io_base = hose->io_space->start;
+ __vga_hose_mem_base = hose->mem_space->start;
+ }
+}
+
+void __init
+locate_and_init_vga(void *(*sel_func)(void *, void *))
+{
+ struct pci_controller *hose = NULL;
+ struct pci_dev *dev = NULL;
+
+ if (!sel_func) sel_func = (void *)default_vga_hose_select;
+
+ for(dev=NULL; (dev=pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, dev));) {
+ if (!hose) hose = dev->sysdata;
+ else hose = sel_func(hose, dev->sysdata);
+ }
+
+ /* Did we already inititialize the correct one? */
+ if (conswitchp == &vga_con &&
+ __vga_hose_io_base == hose->io_space->start &&
+ __vga_hose_mem_base == hose->mem_space->start)
+ return;
+
+ /* Set the VGA hose and init the new console */
+ set_vga_hose(hose);
+ take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
+}
+
+#endif
diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c
new file mode 100644
index 000000000000..a27ba12ba35e
--- /dev/null
+++ b/arch/alpha/kernel/core_apecs.c
@@ -0,0 +1,418 @@
+/*
+ * 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 <asm/io.h>
+#include <asm/core_apecs.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/smp.h>
+
+#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, 0);
+ 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 pt_regs * regs)
+{
+ 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, regs, "APECS",
+ (mcheck_expected(0)
+ && (mchk_sysdata->epic_dcsr & 0x0c00UL)));
+}
diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c
new file mode 100644
index 000000000000..fd563064363c
--- /dev/null
+++ b/arch/alpha/kernel/core_cia.c
@@ -0,0 +1,1212 @@
+/*
+ * linux/arch/alpha/kernel/core_cia.c
+ *
+ * Written by David A Rusling (david.rusling@reo.mts.dec.com).
+ * December 1995.
+ *
+ * Copyright (C) 1995 David A Rusling
+ * Copyright (C) 1997, 1998 Jay Estabrook
+ * Copyright (C) 1998, 1999, 2000 Richard Henderson
+ *
+ * Code common to all CIA core logic chips.
+ */
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_cia.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/ptrace.h>
+
+#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.
+ */
+
+#define DEBUG_CONFIG 0
+#if DEBUG_CONFIG
+# define DBGC(args) printk args
+#else
+# define DBGC(args)
+#endif
+
+#define vip volatile int *
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address. 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|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 *bus_dev, unsigned int device_fn, int where,
+ unsigned long *pci_addr, unsigned char *type1)
+{
+ u8 bus = bus_dev->number;
+
+ *type1 = (bus != 0);
+ *pci_addr = (bus << 16) | (device_fn << 8) | where;
+
+ DBGC(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
+ " returning address 0x%p\n"
+ bus, device_fn, where, *pci_addr));
+
+ return 0;
+}
+
+static unsigned int
+conf_read(unsigned long addr, unsigned char type1)
+{
+ unsigned long flags;
+ int stat0, value;
+ int cia_cfg = 0;
+
+ DBGC(("conf_read(addr=0x%lx, type1=%d) ", addr, type1));
+ local_irq_save(flags);
+
+ /* Reset status register to avoid losing errors. */
+ stat0 = *(vip)CIA_IOC_CIA_ERR;
+ *(vip)CIA_IOC_CIA_ERR = stat0;
+ mb();
+ *(vip)CIA_IOC_CIA_ERR; /* re-read to force write */
+
+ /* If Type1 access, must set CIA CFG. */
+ if (type1) {
+ cia_cfg = *(vip)CIA_IOC_CFG;
+ *(vip)CIA_IOC_CFG = (cia_cfg & ~3) | 1;
+ mb();
+ *(vip)CIA_IOC_CFG;
+ }
+
+ mb();
+ draina();
+ mcheck_expected(0) = 1;
+ mcheck_taken(0) = 0;
+ mb();
+
+ /* Access configuration space. */
+ value = *(vip)addr;
+ mb();
+ mb(); /* magic */
+ if (mcheck_taken(0)) {
+ mcheck_taken(0) = 0;
+ value = 0xffffffff;
+ mb();
+ }
+ mcheck_expected(0) = 0;
+ mb();
+
+ /* If Type1 access, must reset IOC CFG so normal IO space ops work. */
+ if (type1) {
+ *(vip)CIA_IOC_CFG = cia_cfg;
+ mb();
+ *(vip)CIA_IOC_CFG;
+ }
+
+ local_irq_restore(flags);
+ DBGC(("done\n"));
+
+ return value;
+}
+
+static void
+conf_write(unsigned long addr, unsigned int value, unsigned char type1)
+{
+ unsigned long flags;
+ int stat0, cia_cfg = 0;
+
+ DBGC(("conf_write(addr=0x%lx, type1=%d) ", addr, type1));
+ local_irq_save(flags);
+
+ /* Reset status register to avoid losing errors. */
+ stat0 = *(vip)CIA_IOC_CIA_ERR;
+ *(vip)CIA_IOC_CIA_ERR = stat0;
+ mb();
+ *(vip)CIA_IOC_CIA_ERR; /* re-read to force write */
+
+ /* If Type1 access, must set CIA CFG. */
+ if (type1) {
+ cia_cfg = *(vip)CIA_IOC_CFG;
+ *(vip)CIA_IOC_CFG = (cia_cfg & ~3) | 1;
+ mb();
+ *(vip)CIA_IOC_CFG;
+ }
+
+ mb();
+ draina();
+ mcheck_expected(0) = 1;
+ mcheck_taken(0) = 0;
+ mb();
+
+ /* Access configuration space. */
+ *(vip)addr = value;
+ mb();
+ *(vip)addr; /* read back to force the write */
+
+ mcheck_expected(0) = 0;
+ mb();
+
+ /* If Type1 access, must reset IOC CFG so normal IO space ops work. */
+ if (type1) {
+ *(vip)CIA_IOC_CFG = cia_cfg;
+ mb();
+ *(vip)CIA_IOC_CFG;
+ }
+
+ local_irq_restore(flags);
+ DBGC(("done\n"));
+}
+
+static int
+cia_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size,
+ u32 *value)
+{
+ unsigned long addr, pci_addr;
+ long mask;
+ unsigned char type1;
+ 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 + CIA_CONF;
+ *value = conf_read(addr, type1) >> (shift);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+cia_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size,
+ u32 value)
+{
+ unsigned long addr, pci_addr;
+ long mask;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ mask = (size - 1) * 8;
+ addr = (pci_addr << 5) + mask + CIA_CONF;
+ conf_write(addr, value << ((where & 3) * 8), type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops cia_pci_ops =
+{
+ .read = cia_read_config,
+ .write = cia_write_config,
+};
+
+/*
+ * CIA Pass 1 and PYXIS Pass 1 and 2 have a broken scatter-gather tlb.
+ * It cannot be invalidated. Rather than hard code the pass numbers,
+ * actually try the tbia to see if it works.
+ */
+
+void
+cia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+ wmb();
+ *(vip)CIA_IOC_PCI_TBIA = 3; /* Flush all locked and unlocked. */
+ mb();
+ *(vip)CIA_IOC_PCI_TBIA;
+}
+
+/*
+ * On PYXIS, even if the tbia works, we cannot use it. It effectively locks
+ * the chip (as well as direct write to the tag registers) if there is a
+ * SG DMA operation in progress. This is true at least for PYXIS rev. 1,
+ * so always use the method below.
+ */
+/*
+ * This is the method NT and NetBSD use.
+ *
+ * Allocate mappings, and put the chip into DMA loopback mode to read a
+ * garbage page. This works by causing TLB misses, causing old entries to
+ * be purged to make room for the new entries coming in for the garbage page.
+ */
+
+#define CIA_BROKEN_TBIA_BASE 0x30000000
+#define CIA_BROKEN_TBIA_SIZE 1024
+
+/* Always called with interrupts disabled */
+void
+cia_pci_tbi_try2(struct pci_controller *hose,
+ dma_addr_t start, dma_addr_t end)
+{
+ void __iomem *bus_addr;
+ int ctrl;
+
+ /* Put the chip into PCI loopback mode. */
+ mb();
+ ctrl = *(vip)CIA_IOC_CIA_CTRL;
+ *(vip)CIA_IOC_CIA_CTRL = ctrl | CIA_CTRL_PCI_LOOP_EN;
+ mb();
+ *(vip)CIA_IOC_CIA_CTRL;
+ mb();
+
+ /* Read from PCI dense memory space at TBI_ADDR, skipping 32k on
+ each read. This forces SG TLB misses. NetBSD claims that the
+ TLB entries are not quite LRU, meaning that we need to read more
+ times than there are actual tags. The 2117x docs claim strict
+ round-robin. Oh well, we've come this far... */
+ /* Even better - as seen on the PYXIS rev 1 the TLB tags 0-3 can
+ be filled by the TLB misses *only once* after being invalidated
+ (by tbia or direct write). Next misses won't update them even
+ though the lock bits are cleared. Tags 4-7 are "quite LRU" though,
+ so use them and read at window 3 base exactly 4 times. Reading
+ more sometimes makes the chip crazy. -ink */
+
+ bus_addr = cia_ioremap(CIA_BROKEN_TBIA_BASE, 32768 * 4);
+
+ cia_readl(bus_addr + 0x00000);
+ cia_readl(bus_addr + 0x08000);
+ cia_readl(bus_addr + 0x10000);
+ cia_readl(bus_addr + 0x18000);
+
+ cia_iounmap(bus_addr);
+
+ /* Restore normal PCI operation. */
+ mb();
+ *(vip)CIA_IOC_CIA_CTRL = ctrl;
+ mb();
+ *(vip)CIA_IOC_CIA_CTRL;
+ mb();
+}
+
+static inline void
+cia_prepare_tbia_workaround(int window)
+{
+ unsigned long *ppte, pte;
+ long i;
+
+ /* Use minimal 1K map. */
+ ppte = __alloc_bootmem(CIA_BROKEN_TBIA_SIZE, 32768, 0);
+ pte = (virt_to_phys(ppte) >> (PAGE_SHIFT - 1)) | 1;
+
+ for (i = 0; i < CIA_BROKEN_TBIA_SIZE / sizeof(unsigned long); ++i)
+ ppte[i] = pte;
+
+ *(vip)CIA_IOC_PCI_Wn_BASE(window) = CIA_BROKEN_TBIA_BASE | 3;
+ *(vip)CIA_IOC_PCI_Wn_MASK(window)
+ = (CIA_BROKEN_TBIA_SIZE*1024 - 1) & 0xfff00000;
+ *(vip)CIA_IOC_PCI_Tn_BASE(window) = virt_to_phys(ppte) >> 2;
+}
+
+static void __init
+verify_tb_operation(void)
+{
+ static int page[PAGE_SIZE/4]
+ __attribute__((aligned(PAGE_SIZE)))
+ __initdata = { 0 };
+
+ struct pci_iommu_arena *arena = pci_isa_hose->sg_isa;
+ int ctrl, addr0, tag0, pte0, data0;
+ int temp, use_tbia_try2 = 0;
+ void __iomem *bus_addr;
+
+ /* pyxis -- tbia is broken */
+ if (pci_isa_hose->dense_io_base)
+ use_tbia_try2 = 1;
+
+ /* Put the chip into PCI loopback mode. */
+ mb();
+ ctrl = *(vip)CIA_IOC_CIA_CTRL;
+ *(vip)CIA_IOC_CIA_CTRL = ctrl | CIA_CTRL_PCI_LOOP_EN;
+ mb();
+ *(vip)CIA_IOC_CIA_CTRL;
+ mb();
+
+ /* Write a valid entry directly into the TLB registers. */
+
+ addr0 = arena->dma_base;
+ tag0 = addr0 | 1;
+ pte0 = (virt_to_phys(page) >> (PAGE_SHIFT - 1)) | 1;
+
+ *(vip)CIA_IOC_TB_TAGn(0) = tag0;
+ *(vip)CIA_IOC_TB_TAGn(1) = 0;
+ *(vip)CIA_IOC_TB_TAGn(2) = 0;
+ *(vip)CIA_IOC_TB_TAGn(3) = 0;
+ *(vip)CIA_IOC_TB_TAGn(4) = 0;
+ *(vip)CIA_IOC_TB_TAGn(5) = 0;
+ *(vip)CIA_IOC_TB_TAGn(6) = 0;
+ *(vip)CIA_IOC_TB_TAGn(7) = 0;
+ *(vip)CIA_IOC_TBn_PAGEm(0,0) = pte0;
+ *(vip)CIA_IOC_TBn_PAGEm(0,1) = 0;
+ *(vip)CIA_IOC_TBn_PAGEm(0,2) = 0;
+ *(vip)CIA_IOC_TBn_PAGEm(0,3) = 0;
+ mb();
+
+ /* Get a usable bus address */
+ bus_addr = cia_ioremap(addr0, 8*PAGE_SIZE);
+
+ /* First, verify we can read back what we've written. If
+ this fails, we can't be sure of any of the other testing
+ we're going to do, so bail. */
+ /* ??? Actually, we could do the work with machine checks.
+ By passing this register update test, we pretty much
+ guarantee that cia_pci_tbi_try1 works. If this test
+ fails, cia_pci_tbi_try2 might still work. */
+
+ temp = *(vip)CIA_IOC_TB_TAGn(0);
+ if (temp != tag0) {
+ printk("pci: failed tb register update test "
+ "(tag0 %#x != %#x)\n", temp, tag0);
+ goto failed;
+ }
+ temp = *(vip)CIA_IOC_TB_TAGn(1);
+ if (temp != 0) {
+ printk("pci: failed tb register update test "
+ "(tag1 %#x != 0)\n", temp);
+ goto failed;
+ }
+ temp = *(vip)CIA_IOC_TBn_PAGEm(0,0);
+ if (temp != pte0) {
+ printk("pci: failed tb register update test "
+ "(pte0 %#x != %#x)\n", temp, pte0);
+ goto failed;
+ }
+ printk("pci: passed tb register update test\n");
+
+ /* Second, verify we can actually do I/O through this entry. */
+
+ data0 = 0xdeadbeef;
+ page[0] = data0;
+ mcheck_expected(0) = 1;
+ mcheck_taken(0) = 0;
+ mb();
+ temp = cia_readl(bus_addr);
+ mb();
+ mcheck_expected(0) = 0;
+ mb();
+ if (mcheck_taken(0)) {
+ printk("pci: failed sg loopback i/o read test (mcheck)\n");
+ goto failed;
+ }
+ if (temp != data0) {
+ printk("pci: failed sg loopback i/o read test "
+ "(%#x != %#x)\n", temp, data0);
+ goto failed;
+ }
+ printk("pci: passed sg loopback i/o read test\n");
+
+ /* Third, try to invalidate the TLB. */
+
+ if (! use_tbia_try2) {
+ cia_pci_tbi(arena->hose, 0, -1);
+ temp = *(vip)CIA_IOC_TB_TAGn(0);
+ if (temp & 1) {
+ use_tbia_try2 = 1;
+ printk("pci: failed tbia test; workaround available\n");
+ } else {
+ printk("pci: passed tbia test\n");
+ }
+ }
+
+ /* Fourth, verify the TLB snoops the EV5's caches when
+ doing a tlb fill. */
+
+ data0 = 0x5adda15e;
+ page[0] = data0;
+ arena->ptes[4] = pte0;
+ mcheck_expected(0) = 1;
+ mcheck_taken(0) = 0;
+ mb();
+ temp = cia_readl(bus_addr + 4*PAGE_SIZE);
+ mb();
+ mcheck_expected(0) = 0;
+ mb();
+ if (mcheck_taken(0)) {
+ printk("pci: failed pte write cache snoop test (mcheck)\n");
+ goto failed;
+ }
+ if (temp != data0) {
+ printk("pci: failed pte write cache snoop test "
+ "(%#x != %#x)\n", temp, data0);
+ goto failed;
+ }
+ printk("pci: passed pte write cache snoop test\n");
+
+ /* Fifth, verify that a previously invalid PTE entry gets
+ filled from the page table. */
+
+ data0 = 0xabcdef12;
+ page[0] = data0;
+ arena->ptes[5] = pte0;
+ mcheck_expected(0) = 1;
+ mcheck_taken(0) = 0;
+ mb();
+ temp = cia_readl(bus_addr + 5*PAGE_SIZE);
+ mb();
+ mcheck_expected(0) = 0;
+ mb();
+ if (mcheck_taken(0)) {
+ printk("pci: failed valid tag invalid pte reload test "
+ "(mcheck; workaround available)\n");
+ /* Work around this bug by aligning new allocations
+ on 4 page boundaries. */
+ arena->align_entry = 4;
+ } else if (temp != data0) {
+ printk("pci: failed valid tag invalid pte reload test "
+ "(%#x != %#x)\n", temp, data0);
+ goto failed;
+ } else {
+ printk("pci: passed valid tag invalid pte reload test\n");
+ }
+
+ /* Sixth, verify machine checks are working. Test invalid
+ pte under the same valid tag as we used above. */
+
+ mcheck_expected(0) = 1;
+ mcheck_taken(0) = 0;
+ mb();
+ temp = cia_readl(bus_addr + 6*PAGE_SIZE);
+ mb();
+ mcheck_expected(0) = 0;
+ mb();
+ printk("pci: %s pci machine check test\n",
+ mcheck_taken(0) ? "passed" : "failed");
+
+ /* Clean up after the tests. */
+ arena->ptes[4] = 0;
+ arena->ptes[5] = 0;
+
+ if (use_tbia_try2) {
+ alpha_mv.mv_pci_tbi = cia_pci_tbi_try2;
+
+ /* Tags 0-3 must be disabled if we use this workaraund. */
+ wmb();
+ *(vip)CIA_IOC_TB_TAGn(0) = 2;
+ *(vip)CIA_IOC_TB_TAGn(1) = 2;
+ *(vip)CIA_IOC_TB_TAGn(2) = 2;
+ *(vip)CIA_IOC_TB_TAGn(3) = 2;
+
+ printk("pci: tbia workaround enabled\n");
+ }
+ alpha_mv.mv_pci_tbi(arena->hose, 0, -1);
+
+exit:
+ /* unmap the bus addr */
+ cia_iounmap(bus_addr);
+
+ /* Restore normal PCI operation. */
+ mb();
+ *(vip)CIA_IOC_CIA_CTRL = ctrl;
+ mb();
+ *(vip)CIA_IOC_CIA_CTRL;
+ mb();
+ return;
+
+failed:
+ printk("pci: disabling sg translation window\n");
+ *(vip)CIA_IOC_PCI_W0_BASE = 0;
+ *(vip)CIA_IOC_PCI_W1_BASE = 0;
+ pci_isa_hose->sg_isa = NULL;
+ alpha_mv.mv_pci_tbi = NULL;
+ goto exit;
+}
+
+#if defined(ALPHA_RESTORE_SRM_SETUP)
+/* Save CIA configuration data as the console had it set up. */
+struct
+{
+ unsigned int hae_mem;
+ unsigned int hae_io;
+ unsigned int pci_dac_offset;
+ unsigned int err_mask;
+ unsigned int cia_ctrl;
+ unsigned int cia_cnfg;
+ struct {
+ unsigned int w_base;
+ unsigned int w_mask;
+ unsigned int t_base;
+ } window[4];
+} saved_config __attribute((common));
+
+void
+cia_save_srm_settings(int is_pyxis)
+{
+ int i;
+
+ /* Save some important registers. */
+ saved_config.err_mask = *(vip)CIA_IOC_ERR_MASK;
+ saved_config.cia_ctrl = *(vip)CIA_IOC_CIA_CTRL;
+ saved_config.hae_mem = *(vip)CIA_IOC_HAE_MEM;
+ saved_config.hae_io = *(vip)CIA_IOC_HAE_IO;
+ saved_config.pci_dac_offset = *(vip)CIA_IOC_PCI_W_DAC;
+
+ if (is_pyxis)
+ saved_config.cia_cnfg = *(vip)CIA_IOC_CIA_CNFG;
+ else
+ saved_config.cia_cnfg = 0;
+
+ /* Save DMA windows configuration. */
+ for (i = 0; i < 4; i++) {
+ saved_config.window[i].w_base = *(vip)CIA_IOC_PCI_Wn_BASE(i);
+ saved_config.window[i].w_mask = *(vip)CIA_IOC_PCI_Wn_MASK(i);
+ saved_config.window[i].t_base = *(vip)CIA_IOC_PCI_Tn_BASE(i);
+ }
+ mb();
+}
+
+void
+cia_restore_srm_settings(void)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ *(vip)CIA_IOC_PCI_Wn_BASE(i) = saved_config.window[i].w_base;
+ *(vip)CIA_IOC_PCI_Wn_MASK(i) = saved_config.window[i].w_mask;
+ *(vip)CIA_IOC_PCI_Tn_BASE(i) = saved_config.window[i].t_base;
+ }
+
+ *(vip)CIA_IOC_HAE_MEM = saved_config.hae_mem;
+ *(vip)CIA_IOC_HAE_IO = saved_config.hae_io;
+ *(vip)CIA_IOC_PCI_W_DAC = saved_config.pci_dac_offset;
+ *(vip)CIA_IOC_ERR_MASK = saved_config.err_mask;
+ *(vip)CIA_IOC_CIA_CTRL = saved_config.cia_ctrl;
+
+ if (saved_config.cia_cnfg) /* Must be pyxis. */
+ *(vip)CIA_IOC_CIA_CNFG = saved_config.cia_cnfg;
+
+ mb();
+}
+#else /* ALPHA_RESTORE_SRM_SETUP */
+#define cia_save_srm_settings(p) do {} while (0)
+#define cia_restore_srm_settings() do {} while (0)
+#endif /* ALPHA_RESTORE_SRM_SETUP */
+
+
+static void __init
+do_init_arch(int is_pyxis)
+{
+ struct pci_controller *hose;
+ int temp, cia_rev, tbia_window;
+
+ cia_rev = *(vip)CIA_IOC_CIA_REV & CIA_REV_MASK;
+ printk("pci: cia revision %d%s\n",
+ cia_rev, is_pyxis ? " (pyxis)" : "");
+
+ if (alpha_using_srm)
+ cia_save_srm_settings(is_pyxis);
+
+ /* Set up error reporting. */
+ temp = *(vip)CIA_IOC_ERR_MASK;
+ temp &= ~(CIA_ERR_CPU_PE | CIA_ERR_MEM_NEM | CIA_ERR_PA_PTE_INV
+ | CIA_ERR_RCVD_MAS_ABT | CIA_ERR_RCVD_TAR_ABT);
+ *(vip)CIA_IOC_ERR_MASK = temp;
+
+ /* Clear all currently pending errors. */
+ temp = *(vip)CIA_IOC_CIA_ERR;
+ *(vip)CIA_IOC_CIA_ERR = temp;
+
+ /* Turn on mchecks. */
+ temp = *(vip)CIA_IOC_CIA_CTRL;
+ temp |= CIA_CTRL_FILL_ERR_EN | CIA_CTRL_MCHK_ERR_EN;
+ *(vip)CIA_IOC_CIA_CTRL = temp;
+
+ /* Clear the CFG 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. */
+ *(vip)CIA_IOC_CFG = 0;
+
+ /* Zero the HAEs. */
+ *(vip)CIA_IOC_HAE_MEM = 0;
+ *(vip)CIA_IOC_HAE_IO = 0;
+
+ /* For PYXIS, we always use BWX bus and i/o accesses. To that end,
+ make sure they're enabled on the controller. At the same time,
+ enable the monster window. */
+ if (is_pyxis) {
+ temp = *(vip)CIA_IOC_CIA_CNFG;
+ temp |= CIA_CNFG_IOA_BWEN | CIA_CNFG_PCI_MWEN;
+ *(vip)CIA_IOC_CIA_CNFG = temp;
+ }
+
+ /* Synchronize with all previous changes. */
+ mb();
+ *(vip)CIA_IOC_CIA_REV;
+
+ /*
+ * Create our single hose.
+ */
+
+ pci_isa_hose = hose = alloc_pci_controller();
+ hose->io_space = &ioport_resource;
+ hose->mem_space = &iomem_resource;
+ hose->index = 0;
+
+ if (! is_pyxis) {
+ struct resource *hae_mem = alloc_resource();
+ hose->mem_space = hae_mem;
+
+ hae_mem->start = 0;
+ hae_mem->end = CIA_MEM_R1_MASK;
+ hae_mem->name = pci_hae0_name;
+ hae_mem->flags = IORESOURCE_MEM;
+
+ if (request_resource(&iomem_resource, hae_mem) < 0)
+ printk(KERN_ERR "Failed to request HAE_MEM\n");
+
+ hose->sparse_mem_base = CIA_SPARSE_MEM - IDENT_ADDR;
+ hose->dense_mem_base = CIA_DENSE_MEM - IDENT_ADDR;
+ hose->sparse_io_base = CIA_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+ } else {
+ hose->sparse_mem_base = 0;
+ hose->dense_mem_base = CIA_BW_MEM - IDENT_ADDR;
+ hose->sparse_io_base = 0;
+ hose->dense_io_base = CIA_BW_IO - IDENT_ADDR;
+ }
+
+ /*
+ * Set up the PCI to main memory translation windows.
+ *
+ * Window 0 is S/G 8MB at 8MB (for isa)
+ * Window 1 is S/G 1MB at 768MB (for tbia) (unused for CIA rev 1)
+ * Window 2 is direct access 2GB at 2GB
+ * Window 3 is DAC access 4GB at 8GB (or S/G for tbia if CIA rev 1)
+ *
+ * ??? NetBSD hints that page tables must be aligned to 32K,
+ * possibly due to a hardware bug. This is over-aligned
+ * from the 8K alignment one would expect for an 8MB window.
+ * No description of what revisions affected.
+ */
+
+ hose->sg_pci = NULL;
+ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 32768);
+
+ __direct_map_base = 0x80000000;
+ __direct_map_size = 0x80000000;
+
+ *(vip)CIA_IOC_PCI_W0_BASE = hose->sg_isa->dma_base | 3;
+ *(vip)CIA_IOC_PCI_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000;
+ *(vip)CIA_IOC_PCI_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2;
+
+ *(vip)CIA_IOC_PCI_W2_BASE = __direct_map_base | 1;
+ *(vip)CIA_IOC_PCI_W2_MASK = (__direct_map_size - 1) & 0xfff00000;
+ *(vip)CIA_IOC_PCI_T2_BASE = 0 >> 2;
+
+ /* On PYXIS we have the monster window, selected by bit 40, so
+ there is no need for window3 to be enabled.
+
+ On CIA, we don't have true arbitrary addressing -- bits <39:32>
+ are compared against W_DAC. We can, however, directly map 4GB,
+ which is better than before. However, due to assumptions made
+ elsewhere, we should not claim that we support DAC unless that
+ 4GB covers all of physical memory.
+
+ On CIA rev 1, apparently W1 and W2 can't be used for SG.
+ At least, there are reports that it doesn't work for Alcor.
+ In that case, we have no choice but to use W3 for the TBIA
+ workaround, which means we can't use DAC at all. */
+
+ tbia_window = 1;
+ if (is_pyxis) {
+ *(vip)CIA_IOC_PCI_W3_BASE = 0;
+ } else if (cia_rev == 1) {
+ *(vip)CIA_IOC_PCI_W1_BASE = 0;
+ tbia_window = 3;
+ } else if (max_low_pfn > (0x100000000UL >> PAGE_SHIFT)) {
+ *(vip)CIA_IOC_PCI_W3_BASE = 0;
+ } else {
+ *(vip)CIA_IOC_PCI_W3_BASE = 0x00000000 | 1 | 8;
+ *(vip)CIA_IOC_PCI_W3_MASK = 0xfff00000;
+ *(vip)CIA_IOC_PCI_T3_BASE = 0 >> 2;
+
+ alpha_mv.pci_dac_offset = 0x200000000UL;
+ *(vip)CIA_IOC_PCI_W_DAC = alpha_mv.pci_dac_offset >> 32;
+ }
+
+ /* Prepare workaround for apparently broken tbia. */
+ cia_prepare_tbia_workaround(tbia_window);
+}
+
+void __init
+cia_init_arch(void)
+{
+ do_init_arch(0);
+}
+
+void __init
+pyxis_init_arch(void)
+{
+ /* On pyxis machines we can precisely calculate the
+ CPU clock frequency using pyxis real time counter.
+ It's especially useful for SX164 with broken RTC.
+
+ Both CPU and chipset are driven by the single 16.666M
+ or 16.667M crystal oscillator. PYXIS_RT_COUNT clock is
+ 66.66 MHz. -ink */
+
+ unsigned int cc0, cc1;
+ unsigned long pyxis_cc;
+
+ __asm__ __volatile__ ("rpcc %0" : "=r"(cc0));
+ pyxis_cc = *(vulp)PYXIS_RT_COUNT;
+ do { } while(*(vulp)PYXIS_RT_COUNT - pyxis_cc < 4096);
+ __asm__ __volatile__ ("rpcc %0" : "=r"(cc1));
+ cc1 -= cc0;
+ hwrpb->cycle_freq = ((cc1 >> 11) * 100000000UL) / 3;
+ hwrpb_update_checksum(hwrpb);
+
+ do_init_arch(1);
+}
+
+void
+cia_kill_arch(int mode)
+{
+ if (alpha_using_srm)
+ cia_restore_srm_settings();
+}
+
+void __init
+cia_init_pci(void)
+{
+ /* Must delay this from init_arch, as we need machine checks. */
+ verify_tb_operation();
+ common_init_pci();
+}
+
+static inline void
+cia_pci_clr_err(void)
+{
+ int jd;
+
+ jd = *(vip)CIA_IOC_CIA_ERR;
+ *(vip)CIA_IOC_CIA_ERR = jd;
+ mb();
+ *(vip)CIA_IOC_CIA_ERR; /* re-read to force write. */
+}
+
+#ifdef CONFIG_VERBOSE_MCHECK
+static void
+cia_decode_pci_error(struct el_CIA_sysdata_mcheck *cia, const char *msg)
+{
+ static const char * const pci_cmd_desc[16] = {
+ "Interrupt Acknowledge", "Special Cycle", "I/O Read",
+ "I/O Write", "Reserved 0x4", "Reserved 0x5", "Memory Read",
+ "Memory Write", "Reserved 0x8", "Reserved 0x9",
+ "Configuration Read", "Configuration Write",
+ "Memory Read Multiple", "Dual Address Cycle",
+ "Memory Read Line", "Memory Write and Invalidate"
+ };
+
+ if (cia->cia_err & (CIA_ERR_COR_ERR
+ | CIA_ERR_UN_COR_ERR
+ | CIA_ERR_MEM_NEM
+ | CIA_ERR_PA_PTE_INV)) {
+ static const char * const window_desc[6] = {
+ "No window active", "Window 0 hit", "Window 1 hit",
+ "Window 2 hit", "Window 3 hit", "Monster window hit"
+ };
+
+ const char *window;
+ const char *cmd;
+ unsigned long addr, tmp;
+ int lock, dac;
+
+ cmd = pci_cmd_desc[cia->pci_err0 & 0x7];
+ lock = (cia->pci_err0 >> 4) & 1;
+ dac = (cia->pci_err0 >> 5) & 1;
+
+ tmp = (cia->pci_err0 >> 8) & 0x1F;
+ tmp = ffs(tmp);
+ window = window_desc[tmp];
+
+ addr = cia->pci_err1;
+ if (dac) {
+ tmp = *(vip)CIA_IOC_PCI_W_DAC & 0xFFUL;
+ addr |= tmp << 32;
+ }
+
+ printk(KERN_CRIT "CIA machine check: %s\n", msg);
+ printk(KERN_CRIT " DMA command: %s\n", cmd);
+ printk(KERN_CRIT " PCI address: %#010lx\n", addr);
+ printk(KERN_CRIT " %s, Lock: %d, DAC: %d\n",
+ window, lock, dac);
+ } else if (cia->cia_err & (CIA_ERR_PERR
+ | CIA_ERR_PCI_ADDR_PE
+ | CIA_ERR_RCVD_MAS_ABT
+ | CIA_ERR_RCVD_TAR_ABT
+ | CIA_ERR_IOA_TIMEOUT)) {
+ static const char * const master_st_desc[16] = {
+ "Idle", "Drive bus", "Address step cycle",
+ "Address cycle", "Data cycle", "Last read data cycle",
+ "Last write data cycle", "Read stop cycle",
+ "Write stop cycle", "Read turnaround cycle",
+ "Write turnaround cycle", "Reserved 0xB",
+ "Reserved 0xC", "Reserved 0xD", "Reserved 0xE",
+ "Unknown state"
+ };
+ static const char * const target_st_desc[16] = {
+ "Idle", "Busy", "Read data cycle", "Write data cycle",
+ "Read stop cycle", "Write stop cycle",
+ "Read turnaround cycle", "Write turnaround cycle",
+ "Read wait cycle", "Write wait cycle",
+ "Reserved 0xA", "Reserved 0xB", "Reserved 0xC",
+ "Reserved 0xD", "Reserved 0xE", "Unknown state"
+ };
+
+ const char *cmd;
+ const char *master, *target;
+ unsigned long addr, tmp;
+ int dac;
+
+ master = master_st_desc[(cia->pci_err0 >> 16) & 0xF];
+ target = target_st_desc[(cia->pci_err0 >> 20) & 0xF];
+ cmd = pci_cmd_desc[(cia->pci_err0 >> 24) & 0xF];
+ dac = (cia->pci_err0 >> 28) & 1;
+
+ addr = cia->pci_err2;
+ if (dac) {
+ tmp = *(volatile int *)CIA_IOC_PCI_W_DAC & 0xFFUL;
+ addr |= tmp << 32;
+ }
+
+ printk(KERN_CRIT "CIA machine check: %s\n", msg);
+ printk(KERN_CRIT " PCI command: %s\n", cmd);
+ printk(KERN_CRIT " Master state: %s, Target state: %s\n",
+ master, target);
+ printk(KERN_CRIT " PCI address: %#010lx, DAC: %d\n",
+ addr, dac);
+ } else {
+ printk(KERN_CRIT "CIA machine check: %s\n", msg);
+ printk(KERN_CRIT " Unknown PCI error\n");
+ printk(KERN_CRIT " PCI_ERR0 = %#08lx", cia->pci_err0);
+ printk(KERN_CRIT " PCI_ERR1 = %#08lx", cia->pci_err1);
+ printk(KERN_CRIT " PCI_ERR2 = %#08lx", cia->pci_err2);
+ }
+}
+
+static void
+cia_decode_mem_error(struct el_CIA_sysdata_mcheck *cia, const char *msg)
+{
+ unsigned long mem_port_addr;
+ unsigned long mem_port_mask;
+ const char *mem_port_cmd;
+ const char *seq_state;
+ const char *set_select;
+ unsigned long tmp;
+
+ /* If this is a DMA command, also decode the PCI bits. */
+ if ((cia->mem_err1 >> 20) & 1)
+ cia_decode_pci_error(cia, msg);
+ else
+ printk(KERN_CRIT "CIA machine check: %s\n", msg);
+
+ mem_port_addr = cia->mem_err0 & 0xfffffff0;
+ mem_port_addr |= (cia->mem_err1 & 0x83UL) << 32;
+
+ mem_port_mask = (cia->mem_err1 >> 12) & 0xF;
+
+ tmp = (cia->mem_err1 >> 8) & 0xF;
+ tmp |= ((cia->mem_err1 >> 20) & 1) << 4;
+ if ((tmp & 0x1E) == 0x06)
+ mem_port_cmd = "WRITE BLOCK or WRITE BLOCK LOCK";
+ else if ((tmp & 0x1C) == 0x08)
+ mem_port_cmd = "READ MISS or READ MISS MODIFY";
+ else if (tmp == 0x1C)
+ mem_port_cmd = "BC VICTIM";
+ else if ((tmp & 0x1E) == 0x0E)
+ mem_port_cmd = "READ MISS MODIFY";
+ else if ((tmp & 0x1C) == 0x18)
+ mem_port_cmd = "DMA READ or DMA READ MODIFY";
+ else if ((tmp & 0x1E) == 0x12)
+ mem_port_cmd = "DMA WRITE";
+ else
+ mem_port_cmd = "Unknown";
+
+ tmp = (cia->mem_err1 >> 16) & 0xF;
+ switch (tmp) {
+ case 0x0:
+ seq_state = "Idle";
+ break;
+ case 0x1:
+ seq_state = "DMA READ or DMA WRITE";
+ break;
+ case 0x2: case 0x3:
+ seq_state = "READ MISS (or READ MISS MODIFY) with victim";
+ break;
+ case 0x4: case 0x5: case 0x6:
+ seq_state = "READ MISS (or READ MISS MODIFY) with no victim";
+ break;
+ case 0x8: case 0x9: case 0xB:
+ seq_state = "Refresh";
+ break;
+ case 0xC:
+ seq_state = "Idle, waiting for DMA pending read";
+ break;
+ case 0xE: case 0xF:
+ seq_state = "Idle, ras precharge";
+ break;
+ default:
+ seq_state = "Unknown";
+ break;
+ }
+
+ tmp = (cia->mem_err1 >> 24) & 0x1F;
+ switch (tmp) {
+ case 0x00: set_select = "Set 0 selected"; break;
+ case 0x01: set_select = "Set 1 selected"; break;
+ case 0x02: set_select = "Set 2 selected"; break;
+ case 0x03: set_select = "Set 3 selected"; break;
+ case 0x04: set_select = "Set 4 selected"; break;
+ case 0x05: set_select = "Set 5 selected"; break;
+ case 0x06: set_select = "Set 6 selected"; break;
+ case 0x07: set_select = "Set 7 selected"; break;
+ case 0x08: set_select = "Set 8 selected"; break;
+ case 0x09: set_select = "Set 9 selected"; break;
+ case 0x0A: set_select = "Set A selected"; break;
+ case 0x0B: set_select = "Set B selected"; break;
+ case 0x0C: set_select = "Set C selected"; break;
+ case 0x0D: set_select = "Set D selected"; break;
+ case 0x0E: set_select = "Set E selected"; break;
+ case 0x0F: set_select = "Set F selected"; break;
+ case 0x10: set_select = "No set selected"; break;
+ case 0x1F: set_select = "Refresh cycle"; break;
+ default: set_select = "Unknown"; break;
+ }
+
+ printk(KERN_CRIT " Memory port command: %s\n", mem_port_cmd);
+ printk(KERN_CRIT " Memory port address: %#010lx, mask: %#lx\n",
+ mem_port_addr, mem_port_mask);
+ printk(KERN_CRIT " Memory sequencer state: %s\n", seq_state);
+ printk(KERN_CRIT " Memory set: %s\n", set_select);
+}
+
+static void
+cia_decode_ecc_error(struct el_CIA_sysdata_mcheck *cia, const char *msg)
+{
+ long syn;
+ long i;
+ const char *fmt;
+
+ cia_decode_mem_error(cia, msg);
+
+ syn = cia->cia_syn & 0xff;
+ if (syn == (syn & -syn)) {
+ fmt = KERN_CRIT " ECC syndrome %#x -- check bit %d\n";
+ i = ffs(syn) - 1;
+ } else {
+ static unsigned char const data_bit[64] = {
+ 0xCE, 0xCB, 0xD3, 0xD5,
+ 0xD6, 0xD9, 0xDA, 0xDC,
+ 0x23, 0x25, 0x26, 0x29,
+ 0x2A, 0x2C, 0x31, 0x34,
+ 0x0E, 0x0B, 0x13, 0x15,
+ 0x16, 0x19, 0x1A, 0x1C,
+ 0xE3, 0xE5, 0xE6, 0xE9,
+ 0xEA, 0xEC, 0xF1, 0xF4,
+ 0x4F, 0x4A, 0x52, 0x54,
+ 0x57, 0x58, 0x5B, 0x5D,
+ 0xA2, 0xA4, 0xA7, 0xA8,
+ 0xAB, 0xAD, 0xB0, 0xB5,
+ 0x8F, 0x8A, 0x92, 0x94,
+ 0x97, 0x98, 0x9B, 0x9D,
+ 0x62, 0x64, 0x67, 0x68,
+ 0x6B, 0x6D, 0x70, 0x75
+ };
+
+ for (i = 0; i < 64; ++i)
+ if (data_bit[i] == syn)
+ break;
+
+ if (i < 64)
+ fmt = KERN_CRIT " ECC syndrome %#x -- data bit %d\n";
+ else
+ fmt = KERN_CRIT " ECC syndrome %#x -- unknown bit\n";
+ }
+
+ printk (fmt, syn, i);
+}
+
+static void
+cia_decode_parity_error(struct el_CIA_sysdata_mcheck *cia)
+{
+ static const char * const cmd_desc[16] = {
+ "NOP", "LOCK", "FETCH", "FETCH_M", "MEMORY BARRIER",
+ "SET DIRTY", "WRITE BLOCK", "WRITE BLOCK LOCK",
+ "READ MISS0", "READ MISS1", "READ MISS MOD0",
+ "READ MISS MOD1", "BCACHE VICTIM", "Spare",
+ "READ MISS MOD STC0", "READ MISS MOD STC1"
+ };
+
+ unsigned long addr;
+ unsigned long mask;
+ const char *cmd;
+ int par;
+
+ addr = cia->cpu_err0 & 0xfffffff0;
+ addr |= (cia->cpu_err1 & 0x83UL) << 32;
+ cmd = cmd_desc[(cia->cpu_err1 >> 8) & 0xF];
+ mask = (cia->cpu_err1 >> 12) & 0xF;
+ par = (cia->cpu_err1 >> 21) & 1;
+
+ printk(KERN_CRIT "CIA machine check: System bus parity error\n");
+ printk(KERN_CRIT " Command: %s, Parity bit: %d\n", cmd, par);
+ printk(KERN_CRIT " Address: %#010lx, Mask: %#lx\n", addr, mask);
+}
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+
+static int
+cia_decode_mchk(unsigned long la_ptr)
+{
+ struct el_common *com;
+ struct el_CIA_sysdata_mcheck *cia;
+
+ com = (void *)la_ptr;
+ cia = (void *)(la_ptr + com->sys_offset);
+
+ if ((cia->cia_err & CIA_ERR_VALID) == 0)
+ return 0;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (!alpha_verbose_mcheck)
+ return 1;
+
+ switch (ffs(cia->cia_err & 0xfff) - 1) {
+ case 0: /* CIA_ERR_COR_ERR */
+ cia_decode_ecc_error(cia, "Corrected ECC error");
+ break;
+ case 1: /* CIA_ERR_UN_COR_ERR */
+ cia_decode_ecc_error(cia, "Uncorrected ECC error");
+ break;
+ case 2: /* CIA_ERR_CPU_PE */
+ cia_decode_parity_error(cia);
+ break;
+ case 3: /* CIA_ERR_MEM_NEM */
+ cia_decode_mem_error(cia, "Access to nonexistent memory");
+ break;
+ case 4: /* CIA_ERR_PCI_SERR */
+ cia_decode_pci_error(cia, "PCI bus system error");
+ break;
+ case 5: /* CIA_ERR_PERR */
+ cia_decode_pci_error(cia, "PCI data parity error");
+ break;
+ case 6: /* CIA_ERR_PCI_ADDR_PE */
+ cia_decode_pci_error(cia, "PCI address parity error");
+ break;
+ case 7: /* CIA_ERR_RCVD_MAS_ABT */
+ cia_decode_pci_error(cia, "PCI master abort");
+ break;
+ case 8: /* CIA_ERR_RCVD_TAR_ABT */
+ cia_decode_pci_error(cia, "PCI target abort");
+ break;
+ case 9: /* CIA_ERR_PA_PTE_INV */
+ cia_decode_pci_error(cia, "PCI invalid PTE");
+ break;
+ case 10: /* CIA_ERR_FROM_WRT_ERR */
+ cia_decode_mem_error(cia, "Write to flash ROM attempted");
+ break;
+ case 11: /* CIA_ERR_IOA_TIMEOUT */
+ cia_decode_pci_error(cia, "I/O timeout");
+ break;
+ }
+
+ if (cia->cia_err & CIA_ERR_LOST_CORR_ERR)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "Correctable ECC error\n");
+ if (cia->cia_err & CIA_ERR_LOST_UN_CORR_ERR)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "Uncorrectable ECC error\n");
+ if (cia->cia_err & CIA_ERR_LOST_CPU_PE)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "System bus parity error\n");
+ if (cia->cia_err & CIA_ERR_LOST_MEM_NEM)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "Access to nonexistent memory\n");
+ if (cia->cia_err & CIA_ERR_LOST_PERR)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "PCI data parity error\n");
+ if (cia->cia_err & CIA_ERR_LOST_PCI_ADDR_PE)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "PCI address parity error\n");
+ if (cia->cia_err & CIA_ERR_LOST_RCVD_MAS_ABT)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "PCI master abort\n");
+ if (cia->cia_err & CIA_ERR_LOST_RCVD_TAR_ABT)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "PCI target abort\n");
+ if (cia->cia_err & CIA_ERR_LOST_PA_PTE_INV)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "PCI invalid PTE\n");
+ if (cia->cia_err & CIA_ERR_LOST_FROM_WRT_ERR)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "Write to flash ROM attempted\n");
+ if (cia->cia_err & CIA_ERR_LOST_IOA_TIMEOUT)
+ printk(KERN_CRIT "CIA lost machine check: "
+ "I/O timeout\n");
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+ return 1;
+}
+
+void
+cia_machine_check(unsigned long vector, unsigned long la_ptr,
+ struct pt_regs * regs)
+{
+ int expected;
+
+ /* Clear the error before any reporting. */
+ mb();
+ mb(); /* magic */
+ draina();
+ cia_pci_clr_err();
+ wrmces(rdmces()); /* reset machine check pending flag. */
+ mb();
+
+ expected = mcheck_expected(0);
+ if (!expected && vector == 0x660)
+ expected = cia_decode_mchk(la_ptr);
+ process_mcheck_info(vector, la_ptr, regs, "CIA", expected);
+}
diff --git a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c
new file mode 100644
index 000000000000..138d497d1cca
--- /dev/null
+++ b/arch/alpha/kernel/core_irongate.c
@@ -0,0 +1,416 @@
+/*
+ * linux/arch/alpha/kernel/core_irongate.c
+ *
+ * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com).
+ *
+ * Copyright (C) 1999 Alpha Processor, Inc.,
+ * (David Daniel, Stig Telfer, Soohoon Lee)
+ *
+ * Code common to all IRONGATE core logic chips.
+ */
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_irongate.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/bootmem.h>
+
+#include <asm/ptrace.h>
+#include <asm/pci.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+igcsr32 *IronECC;
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address 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.
+ *
+ * addr[31:24] reserved
+ * addr[23:16] bus number (8 bits = 128 possible buses)
+ * addr[15:11] Device number (5 bits)
+ * addr[10: 8] function number
+ * addr[ 7: 2] register number
+ *
+ * For IRONGATE:
+ * if (bus = addr[23:16]) == 0
+ * then
+ * type 0 config cycle:
+ * addr_on_pci[31:11] = id selection for device = addr[15:11]
+ * addr_on_pci[10: 2] = addr[10: 2] ???
+ * addr_on_pci[ 1: 0] = 00
+ * else
+ * type 1 config cycle (pass on with no decoding):
+ * addr_on_pci[31:24] = 0
+ * addr_on_pci[23: 2] = addr[23: 2]
+ * addr_on_pci[ 1: 0] = 01
+ * fi
+ *
+ * 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;
+
+ DBG_CFG(("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));
+
+ *type1 = (bus != 0);
+
+ addr = (bus << 16) | (device_fn << 8) | where;
+ addr |= IRONGATE_CONF;
+
+ *pci_addr = addr;
+ DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return 0;
+}
+
+static int
+irongate_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ *value = __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ *value = __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *value = *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+irongate_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ __kernel_stb(value, *(vucp)addr);
+ mb();
+ __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ __kernel_stw(value, *(vusp)addr);
+ mb();
+ __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *(vuip)addr = value;
+ mb();
+ *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops irongate_pci_ops =
+{
+ .read = irongate_read_config,
+ .write = irongate_write_config,
+};
+
+int
+irongate_pci_clr_err(void)
+{
+ unsigned int nmi_ctl=0;
+ unsigned int IRONGATE_jd;
+
+again:
+ IRONGATE_jd = IRONGATE0->stat_cmd;
+ printk("Iron stat_cmd %x\n", IRONGATE_jd);
+ IRONGATE0->stat_cmd = IRONGATE_jd; /* write again clears error bits */
+ mb();
+ IRONGATE_jd = IRONGATE0->stat_cmd; /* re-read to force write */
+
+ IRONGATE_jd = *IronECC;
+ printk("Iron ECC %x\n", IRONGATE_jd);
+ *IronECC = IRONGATE_jd; /* write again clears error bits */
+ mb();
+ IRONGATE_jd = *IronECC; /* re-read to force write */
+
+ /* Clear ALI NMI */
+ nmi_ctl = inb(0x61);
+ nmi_ctl |= 0x0c;
+ outb(nmi_ctl, 0x61);
+ nmi_ctl &= ~0x0c;
+ outb(nmi_ctl, 0x61);
+
+ IRONGATE_jd = *IronECC;
+ if (IRONGATE_jd & 0x300) goto again;
+
+ return 0;
+}
+
+#define IRONGATE_3GB 0xc0000000UL
+
+/* On Albacore (aka UP1500) with 4Gb of RAM we have to reserve some
+ memory for PCI. At this point we just reserve memory above 3Gb. Most
+ of this memory will be freed after PCI setup is done. */
+static void __init
+albacore_init_arch(void)
+{
+ unsigned long memtop = max_low_pfn << PAGE_SHIFT;
+ unsigned long pci_mem = (memtop + 0x1000000UL) & ~0xffffffUL;
+ struct percpu_struct *cpu;
+ int pal_rev, pal_var;
+
+ cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
+ pal_rev = cpu->pal_revision & 0xffff;
+ pal_var = (cpu->pal_revision >> 16) & 0xff;
+
+ /* Consoles earlier than A5.6-18 (OSF PALcode v1.62-2) set up
+ the CPU incorrectly (leave speculative stores enabled),
+ which causes memory corruption under certain conditions.
+ Issue a warning for such consoles. */
+ if (alpha_using_srm &&
+ (pal_rev < 0x13e || (pal_rev == 0x13e && pal_var < 2)))
+ printk(KERN_WARNING "WARNING! Upgrade to SRM A5.6-19 "
+ "or later\n");
+
+ if (pci_mem > IRONGATE_3GB)
+ pci_mem = IRONGATE_3GB;
+ IRONGATE0->pci_mem = pci_mem;
+ alpha_mv.min_mem_address = pci_mem;
+ if (memtop > pci_mem) {
+#ifdef CONFIG_BLK_DEV_INITRD
+ extern unsigned long initrd_start, initrd_end;
+ extern void *move_initrd(unsigned long);
+
+ /* Move the initrd out of the way. */
+ if (initrd_end && __pa(initrd_end) > pci_mem) {
+ unsigned long size;
+
+ size = initrd_end - initrd_start;
+ free_bootmem_node(NODE_DATA(0), __pa(initrd_start),
+ PAGE_ALIGN(size));
+ if (!move_initrd(pci_mem))
+ printk("irongate_init_arch: initrd too big "
+ "(%ldK)\ndisabling initrd\n",
+ size / 1024);
+ }
+#endif
+ reserve_bootmem_node(NODE_DATA(0), pci_mem, memtop - pci_mem);
+ printk("irongate_init_arch: temporarily reserving "
+ "region %08lx-%08lx for PCI\n", pci_mem, memtop - 1);
+ }
+}
+
+static void __init
+irongate_setup_agp(void)
+{
+ /* Disable the GART window. AGPGART doesn't work due to yet
+ unresolved memory coherency issues... */
+ IRONGATE0->agpva = IRONGATE0->agpva & ~0xf;
+ alpha_agpgart_size = 0;
+}
+
+void __init
+irongate_init_arch(void)
+{
+ struct pci_controller *hose;
+ int amd761 = (IRONGATE0->dev_vendor >> 16) > 0x7006; /* Albacore? */
+
+ IronECC = amd761 ? &IRONGATE0->bacsr54_eccms761 : &IRONGATE0->dramms;
+
+ irongate_pci_clr_err();
+
+ if (amd761)
+ albacore_init_arch();
+
+ irongate_setup_agp();
+
+ /*
+ * Create our single hose.
+ */
+
+ pci_isa_hose = hose = alloc_pci_controller();
+ hose->io_space = &ioport_resource;
+ hose->mem_space = &iomem_resource;
+ hose->index = 0;
+
+ /* This is for userland consumption. For some reason, the 40-bit
+ PIO bias that we use in the kernel through KSEG didn't work for
+ the page table based user mappings. So make sure we get the
+ 43-bit PIO bias. */
+ hose->sparse_mem_base = 0;
+ hose->sparse_io_base = 0;
+ hose->dense_mem_base
+ = (IRONGATE_MEM & 0xffffffffffUL) | 0x80000000000UL;
+ hose->dense_io_base
+ = (IRONGATE_IO & 0xffffffffffUL) | 0x80000000000UL;
+
+ hose->sg_isa = hose->sg_pci = NULL;
+ __direct_map_base = 0;
+ __direct_map_size = 0xffffffff;
+}
+
+/*
+ * IO map and AGP support
+ */
+#include <linux/vmalloc.h>
+#include <linux/agp_backend.h>
+#include <linux/agpgart.h>
+#include <asm/pgalloc.h>
+
+#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
+#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr))
+
+#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
+#define GET_GATT(addr) (gatt_pages[GET_PAGE_DIR_IDX(addr)])
+
+void __iomem *
+irongate_ioremap(unsigned long addr, unsigned long size)
+{
+ struct vm_struct *area;
+ unsigned long vaddr;
+ unsigned long baddr, last;
+ u32 *mmio_regs, *gatt_pages, *cur_gatt, pte;
+ unsigned long gart_bus_addr;
+
+ if (!alpha_agpgart_size)
+ return (void __iomem *)(addr + IRONGATE_MEM);
+
+ gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
+ PCI_BASE_ADDRESS_MEM_MASK;
+
+ /*
+ * Check for within the AGP aperture...
+ */
+ do {
+ /*
+ * Check the AGP area
+ */
+ if (addr >= gart_bus_addr && addr + size - 1 <
+ gart_bus_addr + alpha_agpgart_size)
+ break;
+
+ /*
+ * Not found - assume legacy ioremap
+ */
+ return (void __iomem *)(addr + IRONGATE_MEM);
+ } while(0);
+
+ mmio_regs = (u32 *)(((unsigned long)IRONGATE0->bar1 &
+ PCI_BASE_ADDRESS_MEM_MASK) + IRONGATE_MEM);
+
+ gatt_pages = (u32 *)(phys_to_virt(mmio_regs[1])); /* FIXME */
+
+ /*
+ * Adjust the limits (mappings must be page aligned)
+ */
+ if (addr & ~PAGE_MASK) {
+ printk("AGP ioremap failed... addr not page aligned (0x%lx)\n",
+ addr);
+ return (void __iomem *)(addr + IRONGATE_MEM);
+ }
+ last = addr + size - 1;
+ size = PAGE_ALIGN(last) - addr;
+
+#if 0
+ printk("irongate_ioremap(0x%lx, 0x%lx)\n", addr, size);
+ printk("irongate_ioremap: gart_bus_addr 0x%lx\n", gart_bus_addr);
+ printk("irongate_ioremap: gart_aper_size 0x%lx\n", gart_aper_size);
+ printk("irongate_ioremap: mmio_regs %p\n", mmio_regs);
+ printk("irongate_ioremap: gatt_pages %p\n", gatt_pages);
+
+ for(baddr = addr; baddr <= last; baddr += PAGE_SIZE)
+ {
+ cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
+ pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
+ printk("irongate_ioremap: cur_gatt %p pte 0x%x\n",
+ cur_gatt, pte);
+ }
+#endif
+
+ /*
+ * Map it
+ */
+ area = get_vm_area(size, VM_IOREMAP);
+ if (!area) return NULL;
+
+ for(baddr = addr, vaddr = (unsigned long)area->addr;
+ baddr <= last;
+ baddr += PAGE_SIZE, vaddr += PAGE_SIZE)
+ {
+ cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
+ pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
+
+ if (__alpha_remap_area_pages(vaddr,
+ pte, PAGE_SIZE, 0)) {
+ printk("AGP ioremap: FAILED to map...\n");
+ vfree(area->addr);
+ return NULL;
+ }
+ }
+
+ flush_tlb_all();
+
+ vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+#if 0
+ printk("irongate_ioremap(0x%lx, 0x%lx) returning 0x%lx\n",
+ addr, size, vaddr);
+#endif
+ return (void __iomem *)vaddr;
+}
+
+void
+irongate_iounmap(volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (((long)addr >> 41) == -2)
+ return; /* kseg map, nothing to do */
+ if (addr)
+ return vfree((void *)(PAGE_MASK & addr));
+}
diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c
new file mode 100644
index 000000000000..6a5a9145c676
--- /dev/null
+++ b/arch/alpha/kernel/core_lca.c
@@ -0,0 +1,515 @@
+/*
+ * 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 <asm/io.h>
+#include <asm/core_lca.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+
+#include <asm/ptrace.h>
+#include <asm/smp.h>
+
+#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 loosing 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 loosing 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, 0);
+ 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_CMD_SHIFT)
+#define IOC_CODE_SHIFT 8
+#define IOC_CODE (0xf<<IOC_CODE_SHIFT)
+#define IOC_LOST ( 1<<5)
+#define IOC_P_NBR ((__u32) ~((1<<13) - 1))
+
+static void
+mem_error(unsigned long esr, unsigned long ear)
+{
+ printk(" %s %s error to %s occurred at address %x\n",
+ ((esr & ESR_CEE) ? "Correctable" :
+ (esr & ESR_UEE) ? "Uncorrectable" : "A"),
+ (esr & ESR_WRE) ? "write" : "read",
+ (esr & ESR_SOR) ? "memory" : "b-cache",
+ (unsigned) (ear & 0x1ffffff8));
+ if (esr & ESR_CTE) {
+ printk(" A b-cache tag parity error was detected.\n");
+ }
+ if (esr & ESR_MSE) {
+ printk(" Several other correctable errors occurred.\n");
+ }
+ if (esr & ESR_MHE) {
+ printk(" Several other uncorrectable errors occurred.\n");
+ }
+ if (esr & ESR_NXM) {
+ printk(" Attempted to access non-existent memory.\n");
+ }
+}
+
+static void
+ioc_error(__u32 stat0, __u32 stat1)
+{
+ static const char * const pci_cmd[] = {
+ "Interrupt Acknowledge", "Special", "I/O Read", "I/O Write",
+ "Rsvd 1", "Rsvd 2", "Memory Read", "Memory Write", "Rsvd3",
+ "Rsvd4", "Configuration Read", "Configuration Write",
+ "Memory Read Multiple", "Dual Address", "Memory Read Line",
+ "Memory Write and Invalidate"
+ };
+ static const char * const err_name[] = {
+ "exceeded retry limit", "no device", "bad data parity",
+ "target abort", "bad address parity", "page table read error",
+ "invalid page", "data error"
+ };
+ unsigned code = (stat0 & IOC_CODE) >> 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,
+ struct pt_regs *regs)
+{
+ 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, 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 */
+}
+
+/*
+ * The following routines are needed to support the SPEED changing
+ * necessary to successfully manage the thermal problem on the AlphaBook1.
+ */
+
+void
+lca_clock_print(void)
+{
+ long pmr_reg;
+
+ pmr_reg = LCA_READ_PMR;
+
+ printk("Status of clock control:\n");
+ printk("\tPrimary clock divisor\t0x%lx\n", LCA_GET_PRIMARY(pmr_reg));
+ printk("\tOverride clock divisor\t0x%lx\n", LCA_GET_OVERRIDE(pmr_reg));
+ printk("\tInterrupt override is %s\n",
+ (pmr_reg & LCA_PMR_INTO) ? "on" : "off");
+ printk("\tDMA override is %s\n",
+ (pmr_reg & LCA_PMR_DMAO) ? "on" : "off");
+
+}
+
+int
+lca_get_clock(void)
+{
+ long pmr_reg;
+
+ pmr_reg = LCA_READ_PMR;
+ return(LCA_GET_PRIMARY(pmr_reg));
+
+}
+
+void
+lca_clock_fiddle(int divisor)
+{
+ long pmr_reg;
+
+ pmr_reg = LCA_READ_PMR;
+ LCA_SET_PRIMARY_CLOCK(pmr_reg, divisor);
+ /* lca_norm_clock = divisor; */
+ LCA_WRITE_PMR(pmr_reg);
+ mb();
+}
diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c
new file mode 100644
index 000000000000..44866cb26a80
--- /dev/null
+++ b/arch/alpha/kernel/core_marvel.c
@@ -0,0 +1,1154 @@
+/*
+ * linux/arch/alpha/kernel/core_marvel.c
+ *
+ * Code common to all Marvel based systems.
+ */
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_marvel.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/mc146818rtc.h>
+#include <linux/rtc.h>
+#include <linux/module.h>
+#include <linux/bootmem.h>
+
+#include <asm/ptrace.h>
+#include <asm/smp.h>
+#include <asm/gct.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+#include <asm/rtc.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+
+/*
+ * Debug helpers
+ */
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+
+/*
+ * Private data
+ */
+static struct io7 *io7_head = NULL;
+
+
+/*
+ * Helper functions
+ */
+static unsigned long __attribute__ ((unused))
+read_ev7_csr(int pe, unsigned long offset)
+{
+ ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
+ unsigned long q;
+
+ mb();
+ q = ev7csr->csr;
+ mb();
+
+ return q;
+}
+
+static void __attribute__ ((unused))
+write_ev7_csr(int pe, unsigned long offset, unsigned long q)
+{
+ ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
+
+ mb();
+ ev7csr->csr = q;
+ mb();
+}
+
+static char * __init
+mk_resource_name(int pe, int port, char *str)
+{
+ char tmp[80];
+ char *name;
+
+ sprintf(tmp, "PCI %s PE %d PORT %d", str, pe, port);
+ name = alloc_bootmem(strlen(tmp) + 1);
+ strcpy(name, tmp);
+
+ return name;
+}
+
+inline struct io7 *
+marvel_next_io7(struct io7 *prev)
+{
+ return (prev ? prev->next : io7_head);
+}
+
+struct io7 *
+marvel_find_io7(int pe)
+{
+ struct io7 *io7;
+
+ for (io7 = io7_head; io7 && io7->pe != pe; io7 = io7->next)
+ continue;
+
+ return io7;
+}
+
+static struct io7 * __init
+alloc_io7(unsigned int pe)
+{
+ struct io7 *io7;
+ struct io7 *insp;
+ int h;
+
+ if (marvel_find_io7(pe)) {
+ printk(KERN_WARNING "IO7 at PE %d already allocated!\n", pe);
+ return NULL;
+ }
+
+ io7 = alloc_bootmem(sizeof(*io7));
+ io7->pe = pe;
+ spin_lock_init(&io7->irq_lock);
+
+ for (h = 0; h < 4; h++) {
+ io7->ports[h].io7 = io7;
+ io7->ports[h].port = h;
+ io7->ports[h].enabled = 0; /* default to disabled */
+ }
+
+ /*
+ * Insert in pe sorted order.
+ */
+ if (NULL == io7_head) /* empty list */
+ io7_head = io7;
+ else if (io7_head->pe > io7->pe) { /* insert at head */
+ io7->next = io7_head;
+ io7_head = io7;
+ } else { /* insert at position */
+ for (insp = io7_head; insp; insp = insp->next) {
+ if (insp->pe == io7->pe) {
+ printk(KERN_ERR "Too many IO7s at PE %d\n",
+ io7->pe);
+ return NULL;
+ }
+
+ if (NULL == insp->next ||
+ insp->next->pe > io7->pe) { /* insert here */
+ io7->next = insp->next;
+ insp->next = io7;
+ break;
+ }
+ }
+
+ if (NULL == insp) { /* couldn't insert ?!? */
+ printk(KERN_WARNING "Failed to insert IO7 at PE %d "
+ " - adding at head of list\n", io7->pe);
+ io7->next = io7_head;
+ io7_head = io7;
+ }
+ }
+
+ return io7;
+}
+
+void
+io7_clear_errors(struct io7 *io7)
+{
+ io7_port7_csrs *p7csrs;
+ io7_ioport_csrs *csrs;
+ int port;
+
+
+ /*
+ * First the IO ports.
+ */
+ for (port = 0; port < 4; port++) {
+ csrs = IO7_CSRS_KERN(io7->pe, port);
+
+ csrs->POx_ERR_SUM.csr = -1UL;
+ csrs->POx_TLB_ERR.csr = -1UL;
+ csrs->POx_SPL_COMPLT.csr = -1UL;
+ csrs->POx_TRANS_SUM.csr = -1UL;
+ }
+
+ /*
+ * Then the common ones.
+ */
+ p7csrs = IO7_PORT7_CSRS_KERN(io7->pe);
+
+ p7csrs->PO7_ERROR_SUM.csr = -1UL;
+ p7csrs->PO7_UNCRR_SYM.csr = -1UL;
+ p7csrs->PO7_CRRCT_SYM.csr = -1UL;
+}
+
+
+/*
+ * IO7 PCI, PCI/X, AGP configuration.
+ */
+static void __init
+io7_init_hose(struct io7 *io7, int port)
+{
+ static int hose_index = 0;
+
+ struct pci_controller *hose = alloc_pci_controller();
+ struct io7_port *io7_port = &io7->ports[port];
+ io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, port);
+ int i;
+
+ hose->index = hose_index++; /* arbitrary */
+
+ /*
+ * We don't have an isa or legacy hose, but glibc expects to be
+ * able to use the bus == 0 / dev == 0 form of the iobase syscall
+ * to determine information about the i/o system. Since XFree86
+ * relies on glibc's determination to tell whether or not to use
+ * sparse access, we need to point the pci_isa_hose at a real hose
+ * so at least that determination is correct.
+ */
+ if (hose->index == 0)
+ pci_isa_hose = hose;
+
+ io7_port->csrs = csrs;
+ io7_port->hose = hose;
+ hose->sysdata = io7_port;
+
+ hose->io_space = alloc_resource();
+ hose->mem_space = alloc_resource();
+
+ /*
+ * Base addresses for userland consumption. Since these are going
+ * to be mapped, they are pure physical addresses.
+ */
+ hose->sparse_mem_base = hose->sparse_io_base = 0;
+ hose->dense_mem_base = IO7_MEM_PHYS(io7->pe, port);
+ hose->dense_io_base = IO7_IO_PHYS(io7->pe, port);
+
+ /*
+ * Base addresses and resource ranges for kernel consumption.
+ */
+ hose->config_space_base = (unsigned long)IO7_CONF_KERN(io7->pe, port);
+
+ hose->io_space->start = (unsigned long)IO7_IO_KERN(io7->pe, port);
+ hose->io_space->end = hose->io_space->start + IO7_IO_SPACE - 1;
+ hose->io_space->name = mk_resource_name(io7->pe, port, "IO");
+ hose->io_space->flags = IORESOURCE_IO;
+
+ hose->mem_space->start = (unsigned long)IO7_MEM_KERN(io7->pe, port);
+ hose->mem_space->end = hose->mem_space->start + IO7_MEM_SPACE - 1;
+ hose->mem_space->name = mk_resource_name(io7->pe, port, "MEM");
+ hose->mem_space->flags = IORESOURCE_MEM;
+
+ if (request_resource(&ioport_resource, hose->io_space) < 0)
+ printk(KERN_ERR "Failed to request IO on hose %d\n",
+ hose->index);
+ if (request_resource(&iomem_resource, hose->mem_space) < 0)
+ printk(KERN_ERR "Failed to request MEM on hose %d\n",
+ hose->index);
+
+ /*
+ * Save the existing DMA window settings for later restoration.
+ */
+ for (i = 0; i < 4; i++) {
+ io7_port->saved_wbase[i] = csrs->POx_WBASE[i].csr;
+ io7_port->saved_wmask[i] = csrs->POx_WMASK[i].csr;
+ io7_port->saved_tbase[i] = csrs->POx_TBASE[i].csr;
+ }
+
+ /*
+ * Set up the PCI to main memory translation windows.
+ *
+ * Window 0 is scatter-gather 8MB at 8MB
+ * Window 1 is direct access 1GB at 2GB
+ * Window 2 is scatter-gather (up-to) 1GB at 3GB
+ * Window 3 is disabled
+ */
+
+ /*
+ * TBIA before modifying windows.
+ */
+ marvel_pci_tbi(hose, 0, -1);
+
+ /*
+ * Set up window 0 for scatter-gather 8MB at 8MB.
+ */
+ hose->sg_isa = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
+ hose, 0x00800000, 0x00800000, 0);
+ hose->sg_isa->align_entry = 8; /* cache line boundary */
+ csrs->POx_WBASE[0].csr =
+ hose->sg_isa->dma_base | wbase_m_ena | wbase_m_sg;
+ csrs->POx_WMASK[0].csr = (hose->sg_isa->size - 1) & wbase_m_addr;
+ csrs->POx_TBASE[0].csr = virt_to_phys(hose->sg_isa->ptes);
+
+ /*
+ * Set up window 1 for direct-mapped 1GB at 2GB.
+ */
+ csrs->POx_WBASE[1].csr = __direct_map_base | wbase_m_ena;
+ csrs->POx_WMASK[1].csr = (__direct_map_size - 1) & wbase_m_addr;
+ csrs->POx_TBASE[1].csr = 0;
+
+ /*
+ * Set up window 2 for scatter-gather (up-to) 1GB at 3GB.
+ */
+ hose->sg_pci = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
+ hose, 0xc0000000, 0x40000000, 0);
+ hose->sg_pci->align_entry = 8; /* cache line boundary */
+ csrs->POx_WBASE[2].csr =
+ hose->sg_pci->dma_base | wbase_m_ena | wbase_m_sg;
+ csrs->POx_WMASK[2].csr = (hose->sg_pci->size - 1) & wbase_m_addr;
+ csrs->POx_TBASE[2].csr = virt_to_phys(hose->sg_pci->ptes);
+
+ /*
+ * Disable window 3.
+ */
+ csrs->POx_WBASE[3].csr = 0;
+
+ /*
+ * Make sure that the AGP Monster Window is disabled.
+ */
+ csrs->POx_CTRL.csr &= ~(1UL << 61);
+
+#if 1
+ printk("FIXME: disabling master aborts\n");
+ csrs->POx_MSK_HEI.csr &= ~(3UL << 14);
+#endif
+ /*
+ * TBIA after modifying windows.
+ */
+ marvel_pci_tbi(hose, 0, -1);
+}
+
+static void __init
+marvel_init_io7(struct io7 *io7)
+{
+ int i;
+
+ printk("Initializing IO7 at PID %d\n", io7->pe);
+
+ /*
+ * Get the Port 7 CSR pointer.
+ */
+ io7->csrs = IO7_PORT7_CSRS_KERN(io7->pe);
+
+ /*
+ * Init this IO7's hoses.
+ */
+ for (i = 0; i < IO7_NUM_PORTS; i++) {
+ io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, i);
+ if (csrs->POx_CACHE_CTL.csr == 8) {
+ io7->ports[i].enabled = 1;
+ io7_init_hose(io7, i);
+ }
+ }
+}
+
+void
+marvel_io7_present(gct6_node *node)
+{
+ int pe;
+
+ if (node->type != GCT_TYPE_HOSE ||
+ node->subtype != GCT_SUBTYPE_IO_PORT_MODULE)
+ return;
+
+ pe = (node->id >> 8) & 0xff;
+ printk("Found an IO7 at PID %d\n", pe);
+
+ alloc_io7(pe);
+}
+
+static void __init
+marvel_init_vga_hose(void)
+{
+#ifdef CONFIG_VGA_HOSE
+ u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
+
+ if (pu64[7] == 3) { /* TERM_TYPE == graphics */
+ struct pci_controller *hose = NULL;
+ int h = (pu64[30] >> 24) & 0xff; /* TERM_OUT_LOC, hose # */
+ struct io7 *io7;
+ int pid, port;
+
+ /* FIXME - encoding is going to have to change for Marvel
+ * since hose will be able to overflow a byte...
+ * need to fix this decode when the console
+ * changes its encoding
+ */
+ printk("console graphics is on hose %d (console)\n", h);
+
+ /*
+ * The console's hose numbering is:
+ *
+ * hose<n:2>: PID
+ * hose<1:0>: PORT
+ *
+ * We need to find the hose at that pid and port
+ */
+ pid = h >> 2;
+ port = h & 3;
+ if ((io7 = marvel_find_io7(pid)))
+ hose = io7->ports[port].hose;
+
+ if (hose) {
+ printk("Console graphics on hose %d\n", hose->index);
+ pci_vga_hose = hose;
+ }
+ }
+#endif /* CONFIG_VGA_HOSE */
+}
+
+gct6_search_struct gct_wanted_node_list[] = {
+ { GCT_TYPE_HOSE, GCT_SUBTYPE_IO_PORT_MODULE, marvel_io7_present },
+ { 0, 0, NULL }
+};
+
+/*
+ * In case the GCT is not complete, let the user specify PIDs with IO7s
+ * at boot time. Syntax is 'io7=a,b,c,...,n' where a-n are the PIDs (decimal)
+ * where IO7s are connected
+ */
+static int __init
+marvel_specify_io7(char *str)
+{
+ unsigned long pid;
+ struct io7 *io7;
+ char *pchar;
+
+ do {
+ pid = simple_strtoul(str, &pchar, 0);
+ if (pchar != str) {
+ printk("User-specified IO7 at PID %lu\n", pid);
+ io7 = alloc_io7(pid);
+ if (io7) marvel_init_io7(io7);
+ }
+
+ if (pchar == str) pchar++;
+ str = pchar;
+ } while(*str);
+
+ return 0;
+}
+__setup("io7=", marvel_specify_io7);
+
+void __init
+marvel_init_arch(void)
+{
+ struct io7 *io7;
+
+ /* With multiple PCI busses, we play with I/O as physical addrs. */
+ ioport_resource.end = ~0UL;
+
+ /* PCI DMA Direct Mapping is 1GB at 2GB. */
+ __direct_map_base = 0x80000000;
+ __direct_map_size = 0x40000000;
+
+ /* Parse the config tree. */
+ gct6_find_nodes(GCT_NODE_PTR(0), gct_wanted_node_list);
+
+ /* Init the io7s. */
+ for (io7 = NULL; NULL != (io7 = marvel_next_io7(io7)); )
+ marvel_init_io7(io7);
+
+ /* Check for graphic console location (if any). */
+ marvel_init_vga_hose();
+}
+
+void
+marvel_kill_arch(int mode)
+{
+}
+
+
+/*
+ * PCI Configuration Space access functions
+ *
+ * Configuration space addresses have the following format:
+ *
+ * |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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|R|R|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * n:24 reserved for hose base
+ * 23:16 bus number (8 bits = 128 possible buses)
+ * 15:11 Device number (5 bits)
+ * 10:8 function number
+ * 7:2 register number
+ *
+ * Notes:
+ * IO7 determines whether to use a type 0 or type 1 config cycle
+ * based on the bus number. Therefore the bus number must be set
+ * to 0 for the root bus on any hose.
+ *
+ * The function number selects which function of a multi-function device
+ * (e.g., SCSI and Ethernet).
+ *
+ */
+
+static inline unsigned long
+build_conf_addr(struct pci_controller *hose, u8 bus,
+ unsigned int devfn, int where)
+{
+ return (hose->config_space_base | (bus << 16) | (devfn << 8) | where);
+}
+
+static unsigned long
+mk_conf_addr(struct pci_bus *pbus, unsigned int devfn, int where)
+{
+ struct pci_controller *hose = pbus->sysdata;
+ struct io7_port *io7_port;
+ unsigned long addr = 0;
+ u8 bus = pbus->number;
+
+ if (!hose)
+ return addr;
+
+ /* Check for enabled. */
+ io7_port = hose->sysdata;
+ if (!io7_port->enabled)
+ return addr;
+
+ if (!pbus->parent) { /* No parent means peer PCI bus. */
+ /* Don't support idsel > 20 on primary bus. */
+ if (devfn >= PCI_DEVFN(21, 0))
+ return addr;
+ bus = 0;
+ }
+
+ addr = build_conf_addr(hose, bus, devfn, where);
+
+ DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return addr;
+}
+
+static int
+marvel_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr;
+
+ if (0 == (addr = mk_conf_addr(bus, devfn, where)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch(size) {
+ case 1:
+ *value = __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ *value = __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *value = *(vuip)addr;
+ break;
+ default:
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ unsigned long addr;
+
+ if (0 == (addr = mk_conf_addr(bus, devfn, where)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ __kernel_stb(value, *(vucp)addr);
+ mb();
+ __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ __kernel_stw(value, *(vusp)addr);
+ mb();
+ __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *(vuip)addr = value;
+ mb();
+ *(vuip)addr;
+ break;
+ default:
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops marvel_pci_ops =
+{
+ .read = marvel_read_config,
+ .write = marvel_write_config,
+};
+
+
+/*
+ * Other PCI helper functions.
+ */
+void
+marvel_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+ io7_ioport_csrs *csrs = ((struct io7_port *)hose->sysdata)->csrs;
+
+ wmb();
+ csrs->POx_SG_TBIA.csr = 0;
+ mb();
+ csrs->POx_SG_TBIA.csr;
+}
+
+
+
+/*
+ * RTC Support
+ */
+struct marvel_rtc_access_info {
+ unsigned long function;
+ unsigned long index;
+ unsigned long data;
+};
+
+static void
+__marvel_access_rtc(void *info)
+{
+ struct marvel_rtc_access_info *rtc_access = info;
+
+ register unsigned long __r0 __asm__("$0");
+ register unsigned long __r16 __asm__("$16") = rtc_access->function;
+ register unsigned long __r17 __asm__("$17") = rtc_access->index;
+ register unsigned long __r18 __asm__("$18") = rtc_access->data;
+
+ __asm__ __volatile__(
+ "call_pal %4 # cserve rtc"
+ : "=r"(__r16), "=r"(__r17), "=r"(__r18), "=r"(__r0)
+ : "i"(PAL_cserve), "0"(__r16), "1"(__r17), "2"(__r18)
+ : "$1", "$22", "$23", "$24", "$25");
+
+ rtc_access->data = __r0;
+}
+
+static u8
+__marvel_rtc_io(u8 b, unsigned long addr, int write)
+{
+ static u8 index = 0;
+
+ struct marvel_rtc_access_info rtc_access;
+ u8 ret = 0;
+
+ switch(addr) {
+ case 0x70: /* RTC_PORT(0) */
+ if (write) index = b;
+ ret = index;
+ break;
+
+ case 0x71: /* RTC_PORT(1) */
+ rtc_access.index = index;
+ rtc_access.data = BCD_TO_BIN(b);
+ rtc_access.function = 0x48 + !write; /* GET/PUT_TOY */
+
+#ifdef CONFIG_SMP
+ if (smp_processor_id() != boot_cpuid)
+ smp_call_function_on_cpu(__marvel_access_rtc,
+ &rtc_access, 1, 1,
+ cpumask_of_cpu(boot_cpuid));
+ else
+ __marvel_access_rtc(&rtc_access);
+#else
+ __marvel_access_rtc(&rtc_access);
+#endif
+ ret = BIN_TO_BCD(rtc_access.data);
+ break;
+
+ default:
+ printk(KERN_WARNING "Illegal RTC port %lx\n", addr);
+ break;
+ }
+
+ return ret;
+}
+
+
+/*
+ * IO map support.
+ */
+
+#define __marvel_is_mem_vga(a) (((a) >= 0xa0000) && ((a) <= 0xc0000))
+
+void __iomem *
+marvel_ioremap(unsigned long addr, unsigned long size)
+{
+ struct pci_controller *hose;
+ unsigned long baddr, last;
+ struct vm_struct *area;
+ unsigned long vaddr;
+ unsigned long *ptes;
+ unsigned long pfn;
+
+ /*
+ * Adjust the addr.
+ */
+#ifdef CONFIG_VGA_HOSE
+ if (pci_vga_hose && __marvel_is_mem_vga(addr)) {
+ addr += pci_vga_hose->mem_space->start;
+ }
+#endif
+
+ /*
+ * Find the hose.
+ */
+ for (hose = hose_head; hose; hose = hose->next) {
+ if ((addr >> 32) == (hose->mem_space->start >> 32))
+ break;
+ }
+ if (!hose)
+ return NULL;
+
+ /*
+ * We have the hose - calculate the bus limits.
+ */
+ baddr = addr - hose->mem_space->start;
+ last = baddr + size - 1;
+
+ /*
+ * Is it direct-mapped?
+ */
+ if ((baddr >= __direct_map_base) &&
+ ((baddr + size - 1) < __direct_map_base + __direct_map_size)) {
+ addr = IDENT_ADDR | (baddr - __direct_map_base);
+ return (void __iomem *) addr;
+ }
+
+ /*
+ * Check the scatter-gather arena.
+ */
+ if (hose->sg_pci &&
+ baddr >= (unsigned long)hose->sg_pci->dma_base &&
+ last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size) {
+
+ /*
+ * Adjust the limits (mappings must be page aligned)
+ */
+ baddr -= hose->sg_pci->dma_base;
+ last -= hose->sg_pci->dma_base;
+ baddr &= PAGE_MASK;
+ size = PAGE_ALIGN(last) - baddr;
+
+ /*
+ * Map it.
+ */
+ area = get_vm_area(size, VM_IOREMAP);
+ if (!area)
+ return NULL;
+
+ ptes = hose->sg_pci->ptes;
+ for (vaddr = (unsigned long)area->addr;
+ baddr <= last;
+ baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
+ pfn = ptes[baddr >> PAGE_SHIFT];
+ if (!(pfn & 1)) {
+ printk("ioremap failed... pte not valid...\n");
+ vfree(area->addr);
+ return NULL;
+ }
+ pfn >>= 1; /* make it a true pfn */
+
+ if (__alpha_remap_area_pages(vaddr,
+ pfn << PAGE_SHIFT,
+ PAGE_SIZE, 0)) {
+ printk("FAILED to map...\n");
+ vfree(area->addr);
+ return NULL;
+ }
+ }
+
+ flush_tlb_all();
+
+ vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+
+ return (void __iomem *) vaddr;
+ }
+
+ return NULL;
+}
+
+void
+marvel_iounmap(volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr >= VMALLOC_START)
+ vfree((void *)(PAGE_MASK & addr));
+}
+
+int
+marvel_is_mmio(const volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+
+ if (addr >= VMALLOC_START)
+ return 1;
+ else
+ return (addr & 0xFF000000UL) == 0;
+}
+
+#define __marvel_is_port_vga(a) \
+ (((a) >= 0x3b0) && ((a) < 0x3e0) && ((a) != 0x3b3) && ((a) != 0x3d3))
+#define __marvel_is_port_kbd(a) (((a) == 0x60) || ((a) == 0x64))
+#define __marvel_is_port_rtc(a) (((a) == 0x70) || ((a) == 0x71))
+
+void __iomem *marvel_ioportmap (unsigned long addr)
+{
+ if (__marvel_is_port_rtc (addr) || __marvel_is_port_kbd(addr))
+ ;
+#ifdef CONFIG_VGA_HOSE
+ else if (__marvel_is_port_vga (addr) && pci_vga_hose)
+ addr += pci_vga_hose->io_space->start;
+#endif
+ else
+ return NULL;
+ return (void __iomem *)addr;
+}
+
+unsigned int
+marvel_ioread8(void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (__marvel_is_port_kbd(addr))
+ return 0;
+ else if (__marvel_is_port_rtc(addr))
+ return __marvel_rtc_io(0, addr, 0);
+ else
+ return __kernel_ldbu(*(vucp)addr);
+}
+
+void
+marvel_iowrite8(u8 b, void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (__marvel_is_port_kbd(addr))
+ return;
+ else if (__marvel_is_port_rtc(addr))
+ __marvel_rtc_io(b, addr, 1);
+ else
+ __kernel_stb(b, *(vucp)addr);
+}
+
+#ifndef CONFIG_ALPHA_GENERIC
+EXPORT_SYMBOL(marvel_ioremap);
+EXPORT_SYMBOL(marvel_iounmap);
+EXPORT_SYMBOL(marvel_is_mmio);
+EXPORT_SYMBOL(marvel_ioportmap);
+EXPORT_SYMBOL(marvel_ioread8);
+EXPORT_SYMBOL(marvel_iowrite8);
+#endif
+
+/*
+ * NUMA Support
+ */
+/**********
+ * FIXME - for now each cpu is a node by itself
+ * -- no real support for striped mode
+ **********
+ */
+int
+marvel_pa_to_nid(unsigned long pa)
+{
+ int cpuid;
+
+ if ((pa >> 43) & 1) /* I/O */
+ cpuid = (~(pa >> 35) & 0xff);
+ else /* mem */
+ cpuid = ((pa >> 34) & 0x3) | ((pa >> (37 - 2)) & (0x1f << 2));
+
+ return marvel_cpuid_to_nid(cpuid);
+}
+
+int
+marvel_cpuid_to_nid(int cpuid)
+{
+ return cpuid;
+}
+
+unsigned long
+marvel_node_mem_start(int nid)
+{
+ unsigned long pa;
+
+ pa = (nid & 0x3) | ((nid & (0x1f << 2)) << 1);
+ pa <<= 34;
+
+ return pa;
+}
+
+unsigned long
+marvel_node_mem_size(int nid)
+{
+ return 16UL * 1024 * 1024 * 1024; /* 16GB */
+}
+
+
+/*
+ * AGP GART Support.
+ */
+#include <linux/agp_backend.h>
+#include <asm/agp_backend.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+struct marvel_agp_aperture {
+ struct pci_iommu_arena *arena;
+ long pg_start;
+ long pg_count;
+};
+
+static int
+marvel_agp_setup(alpha_agp_info *agp)
+{
+ struct marvel_agp_aperture *aper;
+
+ if (!alpha_agpgart_size)
+ return -ENOMEM;
+
+ aper = kmalloc(sizeof(*aper), GFP_KERNEL);
+ if (aper == NULL) return -ENOMEM;
+
+ aper->arena = agp->hose->sg_pci;
+ aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
+ aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
+ aper->pg_count - 1);
+
+ if (aper->pg_start < 0) {
+ printk(KERN_ERR "Failed to reserve AGP memory\n");
+ kfree(aper);
+ return -ENOMEM;
+ }
+
+ agp->aperture.bus_base =
+ aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
+ agp->aperture.size = aper->pg_count * PAGE_SIZE;
+ agp->aperture.sysdata = aper;
+
+ return 0;
+}
+
+static void
+marvel_agp_cleanup(alpha_agp_info *agp)
+{
+ struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+ int status;
+
+ status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
+ if (status == -EBUSY) {
+ printk(KERN_WARNING
+ "Attempted to release bound AGP memory - unbinding\n");
+ iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
+ status = iommu_release(aper->arena, aper->pg_start,
+ aper->pg_count);
+ }
+ if (status < 0)
+ printk(KERN_ERR "Failed to release AGP memory\n");
+
+ kfree(aper);
+ kfree(agp);
+}
+
+static int
+marvel_agp_configure(alpha_agp_info *agp)
+{
+ io7_ioport_csrs *csrs = ((struct io7_port *)agp->hose->sysdata)->csrs;
+ struct io7 *io7 = ((struct io7_port *)agp->hose->sysdata)->io7;
+ unsigned int new_rate = 0;
+ unsigned long agp_pll;
+
+ /*
+ * Check the requested mode against the PLL setting.
+ * The agpgart_be code has not programmed the card yet,
+ * so we can still tweak mode here.
+ */
+ agp_pll = io7->csrs->POx_RST[IO7_AGP_PORT].csr;
+ switch(IO7_PLL_RNGB(agp_pll)) {
+ case 0x4: /* 2x only */
+ /*
+ * The PLL is only programmed for 2x, so adjust the
+ * rate to 2x, if necessary.
+ */
+ if (agp->mode.bits.rate != 2)
+ new_rate = 2;
+ break;
+
+ case 0x6: /* 1x / 4x */
+ /*
+ * The PLL is programmed for 1x or 4x. Don't go faster
+ * than requested, so if the requested rate is 2x, use 1x.
+ */
+ if (agp->mode.bits.rate == 2)
+ new_rate = 1;
+ break;
+
+ default: /* ??????? */
+ /*
+ * Don't know what this PLL setting is, take the requested
+ * rate, but warn the user.
+ */
+ printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n",
+ __FUNCTION__, IO7_PLL_RNGB(agp_pll), agp_pll);
+ break;
+ }
+
+ /*
+ * Set the new rate, if necessary.
+ */
+ if (new_rate) {
+ printk("Requested AGP Rate %dX not compatible "
+ "with PLL setting - using %dX\n",
+ agp->mode.bits.rate,
+ new_rate);
+
+ agp->mode.bits.rate = new_rate;
+ }
+
+ printk("Enabling AGP on hose %d: %dX%s RQ %d\n",
+ agp->hose->index, agp->mode.bits.rate,
+ agp->mode.bits.sba ? " - SBA" : "", agp->mode.bits.rq);
+
+ csrs->AGP_CMD.csr = agp->mode.lw;
+
+ return 0;
+}
+
+static int
+marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
+{
+ struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+ return iommu_bind(aper->arena, aper->pg_start + pg_start,
+ mem->page_count, mem->memory);
+}
+
+static int
+marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
+{
+ struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+ return iommu_unbind(aper->arena, aper->pg_start + pg_start,
+ mem->page_count);
+}
+
+static unsigned long
+marvel_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
+{
+ struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+ unsigned long baddr = addr - aper->arena->dma_base;
+ unsigned long pte;
+
+ if (addr < agp->aperture.bus_base ||
+ addr >= agp->aperture.bus_base + agp->aperture.size) {
+ printk("%s: addr out of range\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
+ if (!(pte & 1)) {
+ printk("%s: pte not valid\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ return (pte >> 1) << PAGE_SHIFT;
+}
+
+struct alpha_agp_ops marvel_agp_ops =
+{
+ .setup = marvel_agp_setup,
+ .cleanup = marvel_agp_cleanup,
+ .configure = marvel_agp_configure,
+ .bind = marvel_agp_bind_memory,
+ .unbind = marvel_agp_unbind_memory,
+ .translate = marvel_agp_translate
+};
+
+alpha_agp_info *
+marvel_agp_info(void)
+{
+ struct pci_controller *hose;
+ io7_ioport_csrs *csrs;
+ alpha_agp_info *agp;
+ struct io7 *io7;
+
+ /*
+ * Find the first IO7 with an AGP card.
+ *
+ * FIXME -- there should be a better way (we want to be able to
+ * specify and what if the agp card is not video???)
+ */
+ hose = NULL;
+ for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) {
+ struct pci_controller *h;
+ vuip addr;
+
+ if (!io7->ports[IO7_AGP_PORT].enabled)
+ continue;
+
+ h = io7->ports[IO7_AGP_PORT].hose;
+ addr = (vuip)build_conf_addr(h, 0, PCI_DEVFN(5, 0), 0);
+
+ if (*addr != 0xffffffffu) {
+ hose = h;
+ break;
+ }
+ }
+
+ if (!hose || !hose->sg_pci)
+ return NULL;
+
+ printk("MARVEL - using hose %d as AGP\n", hose->index);
+
+ /*
+ * Get the csrs from the hose.
+ */
+ csrs = ((struct io7_port *)hose->sysdata)->csrs;
+
+ /*
+ * Allocate the info structure.
+ */
+ agp = kmalloc(sizeof(*agp), GFP_KERNEL);
+
+ /*
+ * Fill it in.
+ */
+ agp->hose = hose;
+ agp->private = NULL;
+ agp->ops = &marvel_agp_ops;
+
+ /*
+ * Aperture - not configured until ops.setup().
+ */
+ agp->aperture.bus_base = 0;
+ agp->aperture.size = 0;
+ agp->aperture.sysdata = NULL;
+
+ /*
+ * Capabilities.
+ *
+ * NOTE: IO7 reports through AGP_STAT that it can support a read queue
+ * depth of 17 (rq = 0x10). It actually only supports a depth of
+ * 16 (rq = 0xf).
+ */
+ agp->capability.lw = csrs->AGP_STAT.csr;
+ agp->capability.bits.rq = 0xf;
+
+ /*
+ * Mode.
+ */
+ agp->mode.lw = csrs->AGP_CMD.csr;
+
+ return agp;
+}
diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c
new file mode 100644
index 000000000000..28849c894153
--- /dev/null
+++ b/arch/alpha/kernel/core_mcpcia.c
@@ -0,0 +1,618 @@
+/*
+ * linux/arch/alpha/kernel/core_mcpcia.c
+ *
+ * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
+ *
+ * Code common to all MCbus-PCI Adaptor core logic chipsets
+ */
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_mcpcia.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/ptrace.h>
+
+#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_CFG 0
+
+#if DEBUG_CFG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+#define MCPCIA_MAX_HOSES 4
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the MCPCIA_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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|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 unsigned int
+conf_read(unsigned long addr, unsigned char type1,
+ struct pci_controller *hose)
+{
+ unsigned long flags;
+ unsigned long mid = MCPCIA_HOSE2MID(hose->index);
+ unsigned int stat0, value, temp, cpu;
+
+ cpu = smp_processor_id();
+
+ local_irq_save(flags);
+
+ DBG_CFG(("conf_read(addr=0x%lx, type1=%d, hose=%d)\n",
+ addr, type1, mid));
+
+ /* Reset status register to avoid losing errors. */
+ stat0 = *(vuip)MCPCIA_CAP_ERR(mid);
+ *(vuip)MCPCIA_CAP_ERR(mid) = stat0;
+ mb();
+ temp = *(vuip)MCPCIA_CAP_ERR(mid);
+ DBG_CFG(("conf_read: MCPCIA_CAP_ERR(%d) was 0x%x\n", mid, stat0));
+
+ mb();
+ draina();
+ mcheck_expected(cpu) = 1;
+ mcheck_taken(cpu) = 0;
+ mcheck_extra(cpu) = mid;
+ mb();
+
+ /* Access configuration space. */
+ value = *((vuip)addr);
+ mb();
+ mb(); /* magic */
+
+ if (mcheck_taken(cpu)) {
+ mcheck_taken(cpu) = 0;
+ value = 0xffffffffU;
+ mb();
+ }
+ mcheck_expected(cpu) = 0;
+ mb();
+
+ DBG_CFG(("conf_read(): finished\n"));
+
+ local_irq_restore(flags);
+ return value;
+}
+
+static void
+conf_write(unsigned long addr, unsigned int value, unsigned char type1,
+ struct pci_controller *hose)
+{
+ unsigned long flags;
+ unsigned long mid = MCPCIA_HOSE2MID(hose->index);
+ unsigned int stat0, temp, cpu;
+
+ cpu = smp_processor_id();
+
+ local_irq_save(flags); /* avoid getting hit by machine check */
+
+ /* Reset status register to avoid losing errors. */
+ stat0 = *(vuip)MCPCIA_CAP_ERR(mid);
+ *(vuip)MCPCIA_CAP_ERR(mid) = stat0; mb();
+ temp = *(vuip)MCPCIA_CAP_ERR(mid);
+ DBG_CFG(("conf_write: MCPCIA CAP_ERR(%d) was 0x%x\n", mid, stat0));
+
+ draina();
+ mcheck_expected(cpu) = 1;
+ mcheck_extra(cpu) = mid;
+ mb();
+
+ /* Access configuration space. */
+ *((vuip)addr) = value;
+ mb();
+ mb(); /* magic */
+ temp = *(vuip)MCPCIA_CAP_ERR(mid); /* read to force the write */
+ mcheck_expected(cpu) = 0;
+ mb();
+
+ DBG_CFG(("conf_write(): finished\n"));
+ local_irq_restore(flags);
+}
+
+static int
+mk_conf_addr(struct pci_bus *pbus, unsigned int devfn, int where,
+ struct pci_controller *hose, unsigned long *pci_addr,
+ unsigned char *type1)
+{
+ u8 bus = pbus->number;
+ unsigned long addr;
+
+ DBG_CFG(("mk_conf_addr(bus=%d,devfn=0x%x,hose=%d,where=0x%x,"
+ " pci_addr=0x%p, type1=0x%p)\n",
+ bus, devfn, hose->index, where, pci_addr, type1));
+
+ /* Type 1 configuration cycle for *ALL* busses. */
+ *type1 = 1;
+
+ if (!pbus->parent) /* No parent means peer PCI bus. */
+ bus = 0;
+ addr = (bus << 16) | (devfn << 8) | (where);
+ addr <<= 5; /* swizzle for SPARSE */
+ addr |= hose->config_space_base;
+
+ *pci_addr = addr;
+ DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return 0;
+}
+
+static int
+mcpcia_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ struct pci_controller *hose = bus->sysdata;
+ unsigned long addr, w;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, hose, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ addr |= (size - 1) * 8;
+ w = conf_read(addr, type1, hose);
+ switch (size) {
+ case 1:
+ *value = __kernel_extbl(w, where & 3);
+ break;
+ case 2:
+ *value = __kernel_extwl(w, where & 3);
+ break;
+ case 4:
+ *value = w;
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mcpcia_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ struct pci_controller *hose = bus->sysdata;
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, hose, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ addr |= (size - 1) * 8;
+ value = __kernel_insql(value, where & 3);
+ conf_write(addr, value, type1, hose);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops mcpcia_pci_ops =
+{
+ .read = mcpcia_read_config,
+ .write = mcpcia_write_config,
+};
+
+void
+mcpcia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+ wmb();
+ *(vuip)MCPCIA_SG_TBIA(MCPCIA_HOSE2MID(hose->index)) = 0;
+ mb();
+}
+
+static int __init
+mcpcia_probe_hose(int h)
+{
+ int cpu = smp_processor_id();
+ int mid = MCPCIA_HOSE2MID(h);
+ unsigned int pci_rev;
+
+ /* Gotta be REAL careful. If hose is absent, we get an mcheck. */
+
+ mb();
+ mb();
+ draina();
+ wrmces(7);
+
+ mcheck_expected(cpu) = 2; /* indicates probing */
+ mcheck_taken(cpu) = 0;
+ mcheck_extra(cpu) = mid;
+ mb();
+
+ /* Access the bus revision word. */
+ pci_rev = *(vuip)MCPCIA_REV(mid);
+
+ mb();
+ mb(); /* magic */
+ if (mcheck_taken(cpu)) {
+ mcheck_taken(cpu) = 0;
+ pci_rev = 0xffffffff;
+ mb();
+ }
+ mcheck_expected(cpu) = 0;
+ mb();
+
+ return (pci_rev >> 16) == PCI_CLASS_BRIDGE_HOST;
+}
+
+static void __init
+mcpcia_new_hose(int h)
+{
+ struct pci_controller *hose;
+ struct resource *io, *mem, *hae_mem;
+ int mid = MCPCIA_HOSE2MID(h);
+
+ hose = alloc_pci_controller();
+ if (h == 0)
+ pci_isa_hose = hose;
+ io = alloc_resource();
+ mem = alloc_resource();
+ hae_mem = alloc_resource();
+
+ hose->io_space = io;
+ hose->mem_space = hae_mem;
+ hose->sparse_mem_base = MCPCIA_SPARSE(mid) - IDENT_ADDR;
+ hose->dense_mem_base = MCPCIA_DENSE(mid) - IDENT_ADDR;
+ hose->sparse_io_base = MCPCIA_IO(mid) - IDENT_ADDR;
+ hose->dense_io_base = 0;
+ hose->config_space_base = MCPCIA_CONF(mid);
+ hose->index = h;
+
+ io->start = MCPCIA_IO(mid) - MCPCIA_IO_BIAS;
+ io->end = io->start + 0xffff;
+ io->name = pci_io_names[h];
+ io->flags = IORESOURCE_IO;
+
+ mem->start = MCPCIA_DENSE(mid) - MCPCIA_MEM_BIAS;
+ mem->end = mem->start + 0xffffffff;
+ mem->name = pci_mem_names[h];
+ mem->flags = IORESOURCE_MEM;
+
+ hae_mem->start = mem->start;
+ hae_mem->end = mem->start + MCPCIA_MEM_MASK;
+ hae_mem->name = pci_hae0_name;
+ hae_mem->flags = IORESOURCE_MEM;
+
+ if (request_resource(&ioport_resource, io) < 0)
+ printk(KERN_ERR "Failed to request IO on hose %d\n", h);
+ if (request_resource(&iomem_resource, mem) < 0)
+ printk(KERN_ERR "Failed to request MEM on hose %d\n", h);
+ if (request_resource(mem, hae_mem) < 0)
+ printk(KERN_ERR "Failed to request HAE_MEM on hose %d\n", h);
+}
+
+static void
+mcpcia_pci_clr_err(int mid)
+{
+ *(vuip)MCPCIA_CAP_ERR(mid);
+ *(vuip)MCPCIA_CAP_ERR(mid) = 0xffffffff; /* Clear them all. */
+ mb();
+ *(vuip)MCPCIA_CAP_ERR(mid); /* Re-read for force write. */
+}
+
+static void __init
+mcpcia_startup_hose(struct pci_controller *hose)
+{
+ int mid = MCPCIA_HOSE2MID(hose->index);
+ unsigned int tmp;
+
+ mcpcia_pci_clr_err(mid);
+
+ /*
+ * Set up error reporting.
+ */
+ tmp = *(vuip)MCPCIA_CAP_ERR(mid);
+ tmp |= 0x0006; /* master/target abort */
+ *(vuip)MCPCIA_CAP_ERR(mid) = tmp;
+ mb();
+ tmp = *(vuip)MCPCIA_CAP_ERR(mid);
+
+ /*
+ * Set up the PCI->physical memory translation windows.
+ *
+ * Window 0 is scatter-gather 8MB at 8MB (for isa)
+ * Window 1 is scatter-gather (up to) 1GB at 1GB (for pci)
+ * Window 2 is direct access 2GB at 2GB
+ */
+ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+ hose->sg_pci = iommu_arena_new(hose, 0x40000000,
+ size_for_memory(0x40000000), 0);
+
+ __direct_map_base = 0x80000000;
+ __direct_map_size = 0x80000000;
+
+ *(vuip)MCPCIA_W0_BASE(mid) = hose->sg_isa->dma_base | 3;
+ *(vuip)MCPCIA_W0_MASK(mid) = (hose->sg_isa->size - 1) & 0xfff00000;
+ *(vuip)MCPCIA_T0_BASE(mid) = virt_to_phys(hose->sg_isa->ptes) >> 8;
+
+ *(vuip)MCPCIA_W1_BASE(mid) = hose->sg_pci->dma_base | 3;
+ *(vuip)MCPCIA_W1_MASK(mid) = (hose->sg_pci->size - 1) & 0xfff00000;
+ *(vuip)MCPCIA_T1_BASE(mid) = virt_to_phys(hose->sg_pci->ptes) >> 8;
+
+ *(vuip)MCPCIA_W2_BASE(mid) = __direct_map_base | 1;
+ *(vuip)MCPCIA_W2_MASK(mid) = (__direct_map_size - 1) & 0xfff00000;
+ *(vuip)MCPCIA_T2_BASE(mid) = 0;
+
+ *(vuip)MCPCIA_W3_BASE(mid) = 0x0;
+
+ mcpcia_pci_tbi(hose, 0, -1);
+
+ *(vuip)MCPCIA_HBASE(mid) = 0x0;
+ mb();
+
+ *(vuip)MCPCIA_HAE_MEM(mid) = 0U;
+ mb();
+ *(vuip)MCPCIA_HAE_MEM(mid); /* read it back. */
+ *(vuip)MCPCIA_HAE_IO(mid) = 0;
+ mb();
+ *(vuip)MCPCIA_HAE_IO(mid); /* read it back. */
+}
+
+void __init
+mcpcia_init_arch(void)
+{
+ /* With multiple PCI busses, we play with I/O as physical addrs. */
+ ioport_resource.end = ~0UL;
+
+ /* Allocate hose 0. That's the one that all the ISA junk hangs
+ off of, from which we'll be registering stuff here in a bit.
+ Other hose detection is done in mcpcia_init_hoses, which is
+ called from init_IRQ. */
+
+ mcpcia_new_hose(0);
+}
+
+/* This is called from init_IRQ, since we cannot take interrupts
+ before then. Which means we cannot do this in init_arch. */
+
+void __init
+mcpcia_init_hoses(void)
+{
+ struct pci_controller *hose;
+ int hose_count;
+ int h;
+
+ /* First, find how many hoses we have. */
+ hose_count = 0;
+ for (h = 0; h < MCPCIA_MAX_HOSES; ++h) {
+ if (mcpcia_probe_hose(h)) {
+ if (h != 0)
+ mcpcia_new_hose(h);
+ hose_count++;
+ }
+ }
+
+ printk("mcpcia_init_hoses: found %d hoses\n", hose_count);
+
+ /* Now do init for each hose. */
+ for (hose = hose_head; hose; hose = hose->next)
+ mcpcia_startup_hose(hose);
+}
+
+static void
+mcpcia_print_uncorrectable(struct el_MCPCIA_uncorrected_frame_mcheck *logout)
+{
+ struct el_common_EV5_uncorrectable_mcheck *frame;
+ int i;
+
+ frame = &logout->procdata;
+
+ /* Print PAL fields */
+ for (i = 0; i < 24; i += 2) {
+ printk(" paltmp[%d-%d] = %16lx %16lx\n",
+ i, i+1, frame->paltemp[i], frame->paltemp[i+1]);
+ }
+ for (i = 0; i < 8; i += 2) {
+ printk(" shadow[%d-%d] = %16lx %16lx\n",
+ i, i+1, frame->shadow[i],
+ frame->shadow[i+1]);
+ }
+ printk(" Addr of excepting instruction = %16lx\n",
+ frame->exc_addr);
+ printk(" Summary of arithmetic traps = %16lx\n",
+ frame->exc_sum);
+ printk(" Exception mask = %16lx\n",
+ frame->exc_mask);
+ printk(" Base address for PALcode = %16lx\n",
+ frame->pal_base);
+ printk(" Interrupt Status Reg = %16lx\n",
+ frame->isr);
+ printk(" CURRENT SETUP OF EV5 IBOX = %16lx\n",
+ frame->icsr);
+ printk(" I-CACHE Reg %s parity error = %16lx\n",
+ (frame->ic_perr_stat & 0x800L) ?
+ "Data" : "Tag",
+ frame->ic_perr_stat);
+ printk(" D-CACHE error Reg = %16lx\n",
+ frame->dc_perr_stat);
+ if (frame->dc_perr_stat & 0x2) {
+ switch (frame->dc_perr_stat & 0x03c) {
+ case 8:
+ printk(" Data error in bank 1\n");
+ break;
+ case 4:
+ printk(" Data error in bank 0\n");
+ break;
+ case 20:
+ printk(" Tag error in bank 1\n");
+ break;
+ case 10:
+ printk(" Tag error in bank 0\n");
+ break;
+ }
+ }
+ printk(" Effective VA = %16lx\n",
+ frame->va);
+ printk(" Reason for D-stream = %16lx\n",
+ frame->mm_stat);
+ printk(" EV5 SCache address = %16lx\n",
+ frame->sc_addr);
+ printk(" EV5 SCache TAG/Data parity = %16lx\n",
+ frame->sc_stat);
+ printk(" EV5 BC_TAG_ADDR = %16lx\n",
+ frame->bc_tag_addr);
+ printk(" EV5 EI_ADDR: Phys addr of Xfer = %16lx\n",
+ frame->ei_addr);
+ printk(" Fill Syndrome = %16lx\n",
+ frame->fill_syndrome);
+ printk(" EI_STAT reg = %16lx\n",
+ frame->ei_stat);
+ printk(" LD_LOCK = %16lx\n",
+ frame->ld_lock);
+}
+
+static void
+mcpcia_print_system_area(unsigned long la_ptr)
+{
+ struct el_common *frame;
+ struct pci_controller *hose;
+
+ struct IOD_subpacket {
+ unsigned long base;
+ unsigned int whoami;
+ unsigned int rsvd1;
+ unsigned int pci_rev;
+ unsigned int cap_ctrl;
+ unsigned int hae_mem;
+ unsigned int hae_io;
+ unsigned int int_ctl;
+ unsigned int int_reg;
+ unsigned int int_mask0;
+ unsigned int int_mask1;
+ unsigned int mc_err0;
+ unsigned int mc_err1;
+ unsigned int cap_err;
+ unsigned int rsvd2;
+ unsigned int pci_err1;
+ unsigned int mdpa_stat;
+ unsigned int mdpa_syn;
+ unsigned int mdpb_stat;
+ unsigned int mdpb_syn;
+ unsigned int rsvd3;
+ unsigned int rsvd4;
+ unsigned int rsvd5;
+ } *iodpp;
+
+ frame = (struct el_common *)la_ptr;
+ iodpp = (struct IOD_subpacket *) (la_ptr + frame->sys_offset);
+
+ for (hose = hose_head; hose; hose = hose->next, iodpp++) {
+
+ printk("IOD %d Register Subpacket - Bridge Base Address %16lx\n",
+ hose->index, iodpp->base);
+ printk(" WHOAMI = %8x\n", iodpp->whoami);
+ printk(" PCI_REV = %8x\n", iodpp->pci_rev);
+ printk(" CAP_CTRL = %8x\n", iodpp->cap_ctrl);
+ printk(" HAE_MEM = %8x\n", iodpp->hae_mem);
+ printk(" HAE_IO = %8x\n", iodpp->hae_io);
+ printk(" INT_CTL = %8x\n", iodpp->int_ctl);
+ printk(" INT_REG = %8x\n", iodpp->int_reg);
+ printk(" INT_MASK0 = %8x\n", iodpp->int_mask0);
+ printk(" INT_MASK1 = %8x\n", iodpp->int_mask1);
+ printk(" MC_ERR0 = %8x\n", iodpp->mc_err0);
+ printk(" MC_ERR1 = %8x\n", iodpp->mc_err1);
+ printk(" CAP_ERR = %8x\n", iodpp->cap_err);
+ printk(" PCI_ERR1 = %8x\n", iodpp->pci_err1);
+ printk(" MDPA_STAT = %8x\n", iodpp->mdpa_stat);
+ printk(" MDPA_SYN = %8x\n", iodpp->mdpa_syn);
+ printk(" MDPB_STAT = %8x\n", iodpp->mdpb_stat);
+ printk(" MDPB_SYN = %8x\n", iodpp->mdpb_syn);
+ }
+}
+
+void
+mcpcia_machine_check(unsigned long vector, unsigned long la_ptr,
+ struct pt_regs * regs)
+{
+ struct el_common *mchk_header;
+ struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout;
+ unsigned int cpu = smp_processor_id();
+ int expected;
+
+ mchk_header = (struct el_common *)la_ptr;
+ mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr;
+ expected = mcheck_expected(cpu);
+
+ mb();
+ mb(); /* magic */
+ draina();
+
+ switch (expected) {
+ case 0:
+ {
+ /* FIXME: how do we figure out which hose the
+ error was on? */
+ struct pci_controller *hose;
+ for (hose = hose_head; hose; hose = hose->next)
+ mcpcia_pci_clr_err(MCPCIA_HOSE2MID(hose->index));
+ break;
+ }
+ case 1:
+ mcpcia_pci_clr_err(mcheck_extra(cpu));
+ break;
+ default:
+ /* Otherwise, we're being called from mcpcia_probe_hose
+ and there's no hose clear an error from. */
+ break;
+ }
+
+ wrmces(0x7);
+ mb();
+
+ process_mcheck_info(vector, la_ptr, regs, "MCPCIA", expected != 0);
+ if (!expected && vector != 0x620 && vector != 0x630) {
+ mcpcia_print_uncorrectable(mchk_logout);
+ mcpcia_print_system_area(la_ptr);
+ }
+}
diff --git a/arch/alpha/kernel/core_polaris.c b/arch/alpha/kernel/core_polaris.c
new file mode 100644
index 000000000000..277674a500ff
--- /dev/null
+++ b/arch/alpha/kernel/core_polaris.c
@@ -0,0 +1,203 @@
+/*
+ * linux/arch/alpha/kernel/core_polaris.c
+ *
+ * POLARIS chip-specific code
+ */
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_polaris.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address. This is fairly straightforward
+ * on POLARIS, since the chip itself generates Type 0 or Type 1
+ * cycles automatically depending on the bus number (Bus 0 is
+ * hardwired to Type 0, all others are Type 1. Peer bridges
+ * are not supported).
+ *
+ * All types:
+ *
+ * 3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 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 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |1|1|1|1|1|0|0|1|1|1|1|1|1|1|1|0|B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|x|x|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 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, u8 *type1)
+{
+ u8 bus = pbus->number;
+
+ *type1 = (bus == 0) ? 0 : 1;
+ *pci_addr = (bus << 16) | (device_fn << 8) | (where) |
+ POLARIS_DENSE_CONFIG_BASE;
+
+ DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
+ " returning address 0x%p\n"
+ bus, device_fn, where, *pci_addr));
+
+ return 0;
+}
+
+static int
+polaris_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ *value = __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ *value = __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *value = *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+polaris_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ __kernel_stb(value, *(vucp)addr);
+ mb();
+ __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ __kernel_stw(value, *(vusp)addr);
+ mb();
+ __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *(vuip)addr = value;
+ mb();
+ *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops polaris_pci_ops =
+{
+ .read = polaris_read_config,
+ .write = polaris_write_config,
+};
+
+void __init
+polaris_init_arch(void)
+{
+ struct pci_controller *hose;
+
+ /* May need to initialize error reporting (see PCICTL0/1), but
+ * for now assume that the firmware has done the right thing
+ * already.
+ */
+#if 0
+ printk("polaris_init_arch(): trusting firmware for setup\n");
+#endif
+
+ /*
+ * 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 = 0;
+ hose->dense_mem_base = POLARIS_DENSE_MEM_BASE - IDENT_ADDR;
+ hose->sparse_io_base = 0;
+ hose->dense_io_base = POLARIS_DENSE_IO_BASE - IDENT_ADDR;
+
+ hose->sg_isa = hose->sg_pci = NULL;
+
+ /* The I/O window is fixed at 2G @ 2G. */
+ __direct_map_base = 0x80000000;
+ __direct_map_size = 0x80000000;
+}
+
+static inline void
+polaris_pci_clr_err(void)
+{
+ *(vusp)POLARIS_W_STATUS;
+ /* Write 1's to settable bits to clear errors */
+ *(vusp)POLARIS_W_STATUS = 0x7800;
+ mb();
+ *(vusp)POLARIS_W_STATUS;
+}
+
+void
+polaris_machine_check(unsigned long vector, unsigned long la_ptr,
+ struct pt_regs * regs)
+{
+ /* Clear the error before any reporting. */
+ mb();
+ mb();
+ draina();
+ polaris_pci_clr_err();
+ wrmces(0x7);
+ mb();
+
+ process_mcheck_info(vector, la_ptr, regs, "POLARIS",
+ mcheck_expected(0));
+}
diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c
new file mode 100644
index 000000000000..ecce09e3626a
--- /dev/null
+++ b/arch/alpha/kernel/core_t2.c
@@ -0,0 +1,622 @@
+/*
+ * linux/arch/alpha/kernel/core_t2.c
+ *
+ * Written by Jay A Estabrook (jestabro@amt.tay1.dec.com).
+ * December 1996.
+ *
+ * based on CIA code by David A Rusling (david.rusling@reo.mts.dec.com)
+ *
+ * Code common to all T2 core logic chips.
+ */
+
+#define __EXTERN_INLINE
+#include <asm/io.h>
+#include <asm/core_t2.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/delay.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+/* For dumping initial DMA window settings. */
+#define DEBUG_PRINT_INITIAL_SETTINGS 0
+
+/* For dumping final DMA window settings. */
+#define DEBUG_PRINT_FINAL_SETTINGS 0
+
+/*
+ * By default, we direct-map starting at 2GB, in order to allow the
+ * maximum size direct-map window (2GB) to match the maximum amount of
+ * memory (2GB) that can be present on SABLEs. But that limits the
+ * floppy to DMA only via the scatter/gather window set up for 8MB
+ * ISA DMA, since the maximum ISA DMA address is 2GB-1.
+ *
+ * For now, this seems a reasonable trade-off: even though most SABLEs
+ * have less than 1GB of memory, floppy usage/performance will not
+ * really be affected by forcing it to go via scatter/gather...
+ */
+#define T2_DIRECTMAP_2G 1
+
+#if T2_DIRECTMAP_2G
+# define T2_DIRECTMAP_START 0x80000000UL
+# define T2_DIRECTMAP_LENGTH 0x80000000UL
+#else
+# define T2_DIRECTMAP_START 0x40000000UL
+# define T2_DIRECTMAP_LENGTH 0x40000000UL
+#endif
+
+/* The ISA scatter/gather window settings. */
+#define T2_ISA_SG_START 0x00800000UL
+#define T2_ISA_SG_LENGTH 0x00800000UL
+
+/*
+ * 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 DBG(args) printk args
+#else
+# define DBG(args)
+#endif
+
+static volatile unsigned int t2_mcheck_any_expected;
+static volatile unsigned int t2_mcheck_last_taken;
+
+/* Place to save the DMA Window registers as set up by SRM
+ for restoration during shutdown. */
+static struct
+{
+ struct {
+ unsigned long wbase;
+ unsigned long wmask;
+ unsigned long tbase;
+ } window[2];
+ unsigned long hae_1;
+ unsigned long hae_2;
+ unsigned long hae_3;
+ unsigned long hae_4;
+ unsigned long hbase;
+} t2_saved_config __attribute((common));
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the T2_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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|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;
+
+ DBG(("mk_conf_addr(bus=%d, dfn=0x%x, where=0x%x,"
+ " addr=0x%lx, type1=0x%x)\n",
+ bus, device_fn, where, pci_addr, type1));
+
+ if (bus == 0) {
+ int device = device_fn >> 3;
+
+ /* Type 0 configuration cycle. */
+
+ if (device > 8) {
+ DBG(("mk_conf_addr: device (%d)>20, returning -1\n",
+ device));
+ return -1;
+ }
+
+ *type1 = 0;
+ addr = (0x0800L << device) | ((device_fn & 7) << 8) | (where);
+ } else {
+ /* Type 1 configuration cycle. */
+ *type1 = 1;
+ addr = (bus << 16) | (device_fn << 8) | (where);
+ }
+ *pci_addr = addr;
+ DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return 0;
+}
+
+/*
+ * NOTE: both conf_read() and conf_write() may set HAE_3 when needing
+ * to do type1 access. This is protected by the use of spinlock IRQ
+ * primitives in the wrapper functions pci_{read,write}_config_*()
+ * defined in drivers/pci/pci.c.
+ */
+static unsigned int
+conf_read(unsigned long addr, unsigned char type1)
+{
+ unsigned int value, cpu, taken;
+ unsigned long t2_cfg = 0;
+
+ cpu = smp_processor_id();
+
+ DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+
+ /* If Type1 access, must set T2 CFG. */
+ if (type1) {
+ t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL;
+ *(vulp)T2_HAE_3 = 0x40000000UL | t2_cfg;
+ mb();
+ }
+ mb();
+ draina();
+
+ mcheck_expected(cpu) = 1;
+ mcheck_taken(cpu) = 0;
+ t2_mcheck_any_expected |= (1 << cpu);
+ mb();
+
+ /* Access configuration space. */
+ value = *(vuip)addr;
+ mb();
+ mb(); /* magic */
+
+ /* Wait for possible mcheck. Also, this lets other CPUs clear
+ their mchecks as well, as they can reliably tell when
+ another CPU is in the midst of handling a real mcheck via
+ the "taken" function. */
+ udelay(100);
+
+ if ((taken = mcheck_taken(cpu))) {
+ mcheck_taken(cpu) = 0;
+ t2_mcheck_last_taken |= (1 << cpu);
+ value = 0xffffffffU;
+ mb();
+ }
+ mcheck_expected(cpu) = 0;
+ t2_mcheck_any_expected = 0;
+ mb();
+
+ /* If Type1 access, must reset T2 CFG so normal IO space ops work. */
+ if (type1) {
+ *(vulp)T2_HAE_3 = t2_cfg;
+ mb();
+ }
+
+ return value;
+}
+
+static void
+conf_write(unsigned long addr, unsigned int value, unsigned char type1)
+{
+ unsigned int cpu, taken;
+ unsigned long t2_cfg = 0;
+
+ cpu = smp_processor_id();
+
+ /* If Type1 access, must set T2 CFG. */
+ if (type1) {
+ t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL;
+ *(vulp)T2_HAE_3 = t2_cfg | 0x40000000UL;
+ mb();
+ }
+ mb();
+ draina();
+
+ mcheck_expected(cpu) = 1;
+ mcheck_taken(cpu) = 0;
+ t2_mcheck_any_expected |= (1 << cpu);
+ mb();
+
+ /* Access configuration space. */
+ *(vuip)addr = value;
+ mb();
+ mb(); /* magic */
+
+ /* Wait for possible mcheck. Also, this lets other CPUs clear
+ their mchecks as well, as they can reliably tell when
+ this CPU is in the midst of handling a real mcheck via
+ the "taken" function. */
+ udelay(100);
+
+ if ((taken = mcheck_taken(cpu))) {
+ mcheck_taken(cpu) = 0;
+ t2_mcheck_last_taken |= (1 << cpu);
+ mb();
+ }
+ mcheck_expected(cpu) = 0;
+ t2_mcheck_any_expected = 0;
+ mb();
+
+ /* If Type1 access, must reset T2 CFG so normal IO space ops work. */
+ if (type1) {
+ *(vulp)T2_HAE_3 = t2_cfg;
+ mb();
+ }
+}
+
+static int
+t2_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr, pci_addr;
+ unsigned char type1;
+ int shift;
+ long mask;
+
+ 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 + T2_CONF;
+ *value = conf_read(addr, type1) >> (shift);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+t2_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 + T2_CONF;
+ conf_write(addr, value << ((where & 3) * 8), type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops t2_pci_ops =
+{
+ .read = t2_read_config,
+ .write = t2_write_config,
+};
+
+static void __init
+t2_direct_map_window1(unsigned long base, unsigned long length)
+{
+ unsigned long temp;
+
+ __direct_map_base = base;
+ __direct_map_size = length;
+
+ temp = (base & 0xfff00000UL) | ((base + length - 1) >> 20);
+ *(vulp)T2_WBASE1 = temp | 0x80000UL; /* OR in ENABLE bit */
+ temp = (length - 1) & 0xfff00000UL;
+ *(vulp)T2_WMASK1 = temp;
+ *(vulp)T2_TBASE1 = 0;
+
+#if DEBUG_PRINT_FINAL_SETTINGS
+ printk("%s: setting WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
+ __FUNCTION__,
+ *(vulp)T2_WBASE1,
+ *(vulp)T2_WMASK1,
+ *(vulp)T2_TBASE1);
+#endif
+}
+
+static void __init
+t2_sg_map_window2(struct pci_controller *hose,
+ unsigned long base,
+ unsigned long length)
+{
+ unsigned long temp;
+
+ /* Note we can only do 1 SG window, as the other is for direct, so
+ do an ISA SG area, especially for the floppy. */
+ hose->sg_isa = iommu_arena_new(hose, base, length, 0);
+ hose->sg_pci = NULL;
+
+ temp = (base & 0xfff00000UL) | ((base + length - 1) >> 20);
+ *(vulp)T2_WBASE2 = temp | 0xc0000UL; /* OR in ENABLE/SG bits */
+ temp = (length - 1) & 0xfff00000UL;
+ *(vulp)T2_WMASK2 = temp;
+ *(vulp)T2_TBASE2 = virt_to_phys(hose->sg_isa->ptes) >> 1;
+ mb();
+
+ t2_pci_tbi(hose, 0, -1); /* flush TLB all */
+
+#if DEBUG_PRINT_FINAL_SETTINGS
+ printk("%s: setting WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
+ __FUNCTION__,
+ *(vulp)T2_WBASE2,
+ *(vulp)T2_WMASK2,
+ *(vulp)T2_TBASE2);
+#endif
+}
+
+static void __init
+t2_save_configuration(void)
+{
+#if DEBUG_PRINT_INITIAL_SETTINGS
+ printk("%s: HAE_1 was 0x%lx\n", __FUNCTION__, srm_hae); /* HW is 0 */
+ printk("%s: HAE_2 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_2);
+ printk("%s: HAE_3 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_3);
+ printk("%s: HAE_4 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_4);
+ printk("%s: HBASE was 0x%lx\n", __FUNCTION__, *(vulp)T2_HBASE);
+
+ printk("%s: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", __FUNCTION__,
+ *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
+ printk("%s: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", __FUNCTION__,
+ *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
+#endif
+
+ /*
+ * Save the DMA Window registers.
+ */
+ t2_saved_config.window[0].wbase = *(vulp)T2_WBASE1;
+ t2_saved_config.window[0].wmask = *(vulp)T2_WMASK1;
+ t2_saved_config.window[0].tbase = *(vulp)T2_TBASE1;
+ t2_saved_config.window[1].wbase = *(vulp)T2_WBASE2;
+ t2_saved_config.window[1].wmask = *(vulp)T2_WMASK2;
+ t2_saved_config.window[1].tbase = *(vulp)T2_TBASE2;
+
+ t2_saved_config.hae_1 = srm_hae; /* HW is already set to 0 */
+ t2_saved_config.hae_2 = *(vulp)T2_HAE_2;
+ t2_saved_config.hae_3 = *(vulp)T2_HAE_3;
+ t2_saved_config.hae_4 = *(vulp)T2_HAE_4;
+ t2_saved_config.hbase = *(vulp)T2_HBASE;
+}
+
+void __init
+t2_init_arch(void)
+{
+ struct pci_controller *hose;
+ unsigned long temp;
+ unsigned int i;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ mcheck_expected(i) = 0;
+ mcheck_taken(i) = 0;
+ }
+ t2_mcheck_any_expected = 0;
+ t2_mcheck_last_taken = 0;
+
+ /* Enable scatter/gather TLB use. */
+ temp = *(vulp)T2_IOCSR;
+ if (!(temp & (0x1UL << 26))) {
+ printk("t2_init_arch: enabling SG TLB, IOCSR was 0x%lx\n",
+ temp);
+ *(vulp)T2_IOCSR = temp | (0x1UL << 26);
+ mb();
+ *(vulp)T2_IOCSR; /* read it back to make sure */
+ }
+
+ t2_save_configuration();
+
+ /*
+ * 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 = T2_SPARSE_MEM - IDENT_ADDR;
+ hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR;
+ hose->sparse_io_base = T2_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+
+ /*
+ * Set up the PCI->physical memory translation windows.
+ *
+ * Window 1 is direct mapped.
+ * Window 2 is scatter/gather (for ISA).
+ */
+
+ t2_direct_map_window1(T2_DIRECTMAP_START, T2_DIRECTMAP_LENGTH);
+
+ /* Always make an ISA DMA window. */
+ t2_sg_map_window2(hose, T2_ISA_SG_START, T2_ISA_SG_LENGTH);
+
+ *(vulp)T2_HBASE = 0x0; /* Disable HOLES. */
+
+ /* Zero HAE. */
+ *(vulp)T2_HAE_1 = 0; mb(); /* Sparse MEM HAE */
+ *(vulp)T2_HAE_2 = 0; mb(); /* Sparse I/O HAE */
+ *(vulp)T2_HAE_3 = 0; mb(); /* Config Space HAE */
+
+ /*
+ * We also now zero out HAE_4, the dense memory HAE, so that
+ * we need not account for its "offset" when accessing dense
+ * memory resources which we allocated in our normal way. This
+ * HAE would need to stay untouched were we to keep the SRM
+ * resource settings.
+ *
+ * Thus we can now run standard X servers on SABLE/LYNX. :-)
+ */
+ *(vulp)T2_HAE_4 = 0; mb();
+}
+
+void
+t2_kill_arch(int mode)
+{
+ /*
+ * Restore the DMA Window registers.
+ */
+ *(vulp)T2_WBASE1 = t2_saved_config.window[0].wbase;
+ *(vulp)T2_WMASK1 = t2_saved_config.window[0].wmask;
+ *(vulp)T2_TBASE1 = t2_saved_config.window[0].tbase;
+ *(vulp)T2_WBASE2 = t2_saved_config.window[1].wbase;
+ *(vulp)T2_WMASK2 = t2_saved_config.window[1].wmask;
+ *(vulp)T2_TBASE2 = t2_saved_config.window[1].tbase;
+ mb();
+
+ *(vulp)T2_HAE_1 = srm_hae;
+ *(vulp)T2_HAE_2 = t2_saved_config.hae_2;
+ *(vulp)T2_HAE_3 = t2_saved_config.hae_3;
+ *(vulp)T2_HAE_4 = t2_saved_config.hae_4;
+ *(vulp)T2_HBASE = t2_saved_config.hbase;
+ mb();
+ *(vulp)T2_HBASE; /* READ it back to ensure WRITE occurred. */
+}
+
+void
+t2_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+ unsigned long t2_iocsr;
+
+ t2_iocsr = *(vulp)T2_IOCSR;
+
+ /* set the TLB Clear bit */
+ *(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 28);
+ mb();
+ *(vulp)T2_IOCSR; /* read it back to make sure */
+
+ /* clear the TLB Clear bit */
+ *(vulp)T2_IOCSR = t2_iocsr & ~(0x1UL << 28);
+ mb();
+ *(vulp)T2_IOCSR; /* read it back to make sure */
+}
+
+#define SIC_SEIC (1UL << 33) /* System Event Clear */
+
+static void
+t2_clear_errors(int cpu)
+{
+ struct sable_cpu_csr *cpu_regs;
+
+ cpu_regs = (struct sable_cpu_csr *)T2_CPUn_BASE(cpu);
+
+ cpu_regs->sic &= ~SIC_SEIC;
+
+ /* Clear CPU errors. */
+ cpu_regs->bcce |= cpu_regs->bcce;
+ cpu_regs->cbe |= cpu_regs->cbe;
+ cpu_regs->bcue |= cpu_regs->bcue;
+ cpu_regs->dter |= cpu_regs->dter;
+
+ *(vulp)T2_CERR1 |= *(vulp)T2_CERR1;
+ *(vulp)T2_PERR1 |= *(vulp)T2_PERR1;
+
+ mb();
+ mb(); /* magic */
+}
+
+/*
+ * SABLE seems to have a "broadcast" style machine check, in that all
+ * CPUs receive it. And, the issuing CPU, in the case of PCI Config
+ * space read/write faults, will also receive a second mcheck, upon
+ * lowering IPL during completion processing in pci_read_config_byte()
+ * et al.
+ *
+ * Hence all the taken/expected/any_expected/last_taken stuff...
+ */
+void
+t2_machine_check(unsigned long vector, unsigned long la_ptr,
+ struct pt_regs * regs)
+{
+ int cpu = smp_processor_id();
+#ifdef CONFIG_VERBOSE_MCHECK
+ struct el_common *mchk_header = (struct el_common *)la_ptr;
+#endif
+
+ /* Clear the error before any reporting. */
+ mb();
+ mb(); /* magic */
+ draina();
+ t2_clear_errors(cpu);
+
+ /* This should not actually be done until the logout frame is
+ examined, but, since we don't do that, go on and do this... */
+ wrmces(0x7);
+ mb();
+
+ /* Now, do testing for the anomalous conditions. */
+ if (!mcheck_expected(cpu) && t2_mcheck_any_expected) {
+ /*
+ * FUNKY: Received mcheck on a CPU and not
+ * expecting it, but another CPU is expecting one.
+ *
+ * Just dismiss it for now on this CPU...
+ */
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (alpha_verbose_mcheck > 1) {
+ printk("t2_machine_check(cpu%d): any_expected 0x%x -"
+ " (assumed) spurious -"
+ " code 0x%x\n", cpu, t2_mcheck_any_expected,
+ (unsigned int)mchk_header->code);
+ }
+#endif
+ return;
+ }
+
+ if (!mcheck_expected(cpu) && !t2_mcheck_any_expected) {
+ if (t2_mcheck_last_taken & (1 << cpu)) {
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (alpha_verbose_mcheck > 1) {
+ printk("t2_machine_check(cpu%d): last_taken 0x%x - "
+ "unexpected mcheck - code 0x%x\n",
+ cpu, t2_mcheck_last_taken,
+ (unsigned int)mchk_header->code);
+ }
+#endif
+ t2_mcheck_last_taken = 0;
+ mb();
+ return;
+ } else {
+ t2_mcheck_last_taken = 0;
+ mb();
+ }
+ }
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (alpha_verbose_mcheck > 1) {
+ printk("%s t2_mcheck(cpu%d): last_taken 0x%x - "
+ "any_expected 0x%x - code 0x%x\n",
+ (mcheck_expected(cpu) ? "EX" : "UN"), cpu,
+ t2_mcheck_last_taken, t2_mcheck_any_expected,
+ (unsigned int)mchk_header->code);
+ }
+#endif
+
+ process_mcheck_info(vector, la_ptr, regs, "T2", mcheck_expected(cpu));
+}
diff --git a/arch/alpha/kernel/core_titan.c b/arch/alpha/kernel/core_titan.c
new file mode 100644
index 000000000000..3662fef7db9a
--- /dev/null
+++ b/arch/alpha/kernel/core_titan.c
@@ -0,0 +1,806 @@
+/*
+ * linux/arch/alpha/kernel/core_titan.c
+ *
+ * Code common to all TITAN core logic chips.
+ */
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_titan.h>
+#undef __EXTERN_INLINE
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/bootmem.h>
+
+#include <asm/ptrace.h>
+#include <asm/smp.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+/* Save Titan configuration data as the console had it set up. */
+
+struct
+{
+ unsigned long wsba[4];
+ unsigned long wsm[4];
+ unsigned long tba[4];
+} saved_config[4] __attribute__((common));
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+
+/*
+ * Routines to access TIG registers.
+ */
+static inline volatile unsigned long *
+mk_tig_addr(int offset)
+{
+ return (volatile unsigned long *)(TITAN_TIG_SPACE + (offset << 6));
+}
+
+static inline u8
+titan_read_tig(int offset, u8 value)
+{
+ volatile unsigned long *tig_addr = mk_tig_addr(offset);
+ return (u8)(*tig_addr & 0xff);
+}
+
+static inline void
+titan_write_tig(int offset, u8 value)
+{
+ volatile unsigned long *tig_addr = mk_tig_addr(offset);
+ *tig_addr = (unsigned long)value;
+}
+
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address
+ * 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.
+ *
+ * Note that all config space accesses use Type 1 address format.
+ *
+ * Note also that type 1 is determined by non-zero bus 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)
+{
+ struct pci_controller *hose = pbus->sysdata;
+ unsigned long addr;
+ u8 bus = pbus->number;
+
+ DBG_CFG(("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 (!pbus->parent) /* No parent means peer PCI bus. */
+ bus = 0;
+ *type1 = (bus != 0);
+
+ addr = (bus << 16) | (device_fn << 8) | where;
+ addr |= hose->config_space_base;
+
+ *pci_addr = addr;
+ DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return 0;
+}
+
+static int
+titan_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ *value = __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ *value = __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *value = *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+titan_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ __kernel_stb(value, *(vucp)addr);
+ mb();
+ __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ __kernel_stw(value, *(vusp)addr);
+ mb();
+ __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *(vuip)addr = value;
+ mb();
+ *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops titan_pci_ops =
+{
+ .read = titan_read_config,
+ .write = titan_write_config,
+};
+
+
+void
+titan_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+ titan_pachip *pachip =
+ (hose->index & 1) ? TITAN_pachip1 : TITAN_pachip0;
+ titan_pachip_port *port;
+ volatile unsigned long *csr;
+ unsigned long value;
+
+ /* Get the right hose. */
+ port = &pachip->g_port;
+ if (hose->index & 2)
+ port = &pachip->a_port;
+
+ /* We can invalidate up to 8 tlb entries in a go. The flush
+ matches against <31:16> in the pci address.
+ Note that gtlbi* and atlbi* are in the same place in the g_port
+ and a_port, respectively, so the g_port offset can be used
+ even if hose is an a_port */
+ csr = &port->port_specific.g.gtlbia.csr;
+ if (((start ^ end) & 0xffff0000) == 0)
+ csr = &port->port_specific.g.gtlbiv.csr;
+
+ /* For TBIA, it doesn't matter what value we write. For TBI,
+ it's the shifted tag bits. */
+ value = (start & 0xffff0000) >> 12;
+
+ wmb();
+ *csr = value;
+ mb();
+ *csr;
+}
+
+static int
+titan_query_agp(titan_pachip_port *port)
+{
+ union TPAchipPCTL pctl;
+
+ /* set up APCTL */
+ pctl.pctl_q_whole = port->pctl.csr;
+
+ return pctl.pctl_r_bits.apctl_v_agp_present;
+
+}
+
+static void __init
+titan_init_one_pachip_port(titan_pachip_port *port, int index)
+{
+ struct pci_controller *hose;
+
+ hose = alloc_pci_controller();
+ if (index == 0)
+ pci_isa_hose = hose;
+ hose->io_space = alloc_resource();
+ hose->mem_space = alloc_resource();
+
+ /*
+ * This is for userland consumption. The 40-bit PIO bias that we
+ * use in the kernel through KSEG doesn't work in the page table
+ * based user mappings. (43-bit KSEG sign extends the physical
+ * address from bit 40 to hit the I/O bit - mapped addresses don't).
+ * So make sure we get the 43-bit PIO bias.
+ */
+ hose->sparse_mem_base = 0;
+ hose->sparse_io_base = 0;
+ hose->dense_mem_base
+ = (TITAN_MEM(index) & 0xffffffffffUL) | 0x80000000000UL;
+ hose->dense_io_base
+ = (TITAN_IO(index) & 0xffffffffffUL) | 0x80000000000UL;
+
+ hose->config_space_base = TITAN_CONF(index);
+ hose->index = index;
+
+ hose->io_space->start = TITAN_IO(index) - TITAN_IO_BIAS;
+ hose->io_space->end = hose->io_space->start + TITAN_IO_SPACE - 1;
+ hose->io_space->name = pci_io_names[index];
+ hose->io_space->flags = IORESOURCE_IO;
+
+ hose->mem_space->start = TITAN_MEM(index) - TITAN_MEM_BIAS;
+ hose->mem_space->end = hose->mem_space->start + 0xffffffff;
+ hose->mem_space->name = pci_mem_names[index];
+ hose->mem_space->flags = IORESOURCE_MEM;
+
+ if (request_resource(&ioport_resource, hose->io_space) < 0)
+ printk(KERN_ERR "Failed to request IO on hose %d\n", index);
+ if (request_resource(&iomem_resource, hose->mem_space) < 0)
+ printk(KERN_ERR "Failed to request MEM on hose %d\n", index);
+
+ /*
+ * Save the existing PCI window translations. SRM will
+ * need them when we go to reboot.
+ */
+ saved_config[index].wsba[0] = port->wsba[0].csr;
+ saved_config[index].wsm[0] = port->wsm[0].csr;
+ saved_config[index].tba[0] = port->tba[0].csr;
+
+ saved_config[index].wsba[1] = port->wsba[1].csr;
+ saved_config[index].wsm[1] = port->wsm[1].csr;
+ saved_config[index].tba[1] = port->tba[1].csr;
+
+ saved_config[index].wsba[2] = port->wsba[2].csr;
+ saved_config[index].wsm[2] = port->wsm[2].csr;
+ saved_config[index].tba[2] = port->tba[2].csr;
+
+ saved_config[index].wsba[3] = port->wsba[3].csr;
+ saved_config[index].wsm[3] = port->wsm[3].csr;
+ saved_config[index].tba[3] = port->tba[3].csr;
+
+ /*
+ * Set up the PCI to main memory translation windows.
+ *
+ * Note: Window 3 on Titan is Scatter-Gather ONLY.
+ *
+ * Window 0 is scatter-gather 8MB at 8MB (for isa)
+ * Window 1 is direct access 1GB at 2GB
+ * Window 2 is scatter-gather 1GB at 3GB
+ */
+ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+ hose->sg_isa->align_entry = 8; /* 64KB for ISA */
+
+ hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x40000000, 0);
+ hose->sg_pci->align_entry = 4; /* Titan caches 4 PTEs at a time */
+
+ port->wsba[0].csr = hose->sg_isa->dma_base | 3;
+ port->wsm[0].csr = (hose->sg_isa->size - 1) & 0xfff00000;
+ port->tba[0].csr = virt_to_phys(hose->sg_isa->ptes);
+
+ port->wsba[1].csr = __direct_map_base | 1;
+ port->wsm[1].csr = (__direct_map_size - 1) & 0xfff00000;
+ port->tba[1].csr = 0;
+
+ port->wsba[2].csr = hose->sg_pci->dma_base | 3;
+ port->wsm[2].csr = (hose->sg_pci->size - 1) & 0xfff00000;
+ port->tba[2].csr = virt_to_phys(hose->sg_pci->ptes);
+
+ port->wsba[3].csr = 0;
+
+ /* Enable the Monster Window to make DAC pci64 possible. */
+ port->pctl.csr |= pctl_m_mwin;
+
+ /*
+ * If it's an AGP port, initialize agplastwr.
+ */
+ if (titan_query_agp(port))
+ port->port_specific.a.agplastwr.csr = __direct_map_base;
+
+ titan_pci_tbi(hose, 0, -1);
+}
+
+static void __init
+titan_init_pachips(titan_pachip *pachip0, titan_pachip *pachip1)
+{
+ int pchip1_present = TITAN_cchip->csc.csr & 1L<<14;
+
+ /* Init the ports in hose order... */
+ titan_init_one_pachip_port(&pachip0->g_port, 0); /* hose 0 */
+ if (pchip1_present)
+ titan_init_one_pachip_port(&pachip1->g_port, 1);/* hose 1 */
+ titan_init_one_pachip_port(&pachip0->a_port, 2); /* hose 2 */
+ if (pchip1_present)
+ titan_init_one_pachip_port(&pachip1->a_port, 3);/* hose 3 */
+}
+
+static void __init
+titan_init_vga_hose(void)
+{
+#ifdef CONFIG_VGA_HOSE
+ u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
+
+ if (pu64[7] == 3) { /* TERM_TYPE == graphics */
+ struct pci_controller *hose;
+ int h = (pu64[30] >> 24) & 0xff; /* console hose # */
+
+ /*
+ * Our hose numbering matches the console's, so just find
+ * the right one...
+ */
+ for (hose = hose_head; hose; hose = hose->next) {
+ if (hose->index == h) break;
+ }
+
+ if (hose) {
+ printk("Console graphics on hose %d\n", hose->index);
+ pci_vga_hose = hose;
+ }
+ }
+#endif /* CONFIG_VGA_HOSE */
+}
+
+void __init
+titan_init_arch(void)
+{
+#if 0
+ printk("%s: titan_init_arch()\n", __FUNCTION__);
+ printk("%s: CChip registers:\n", __FUNCTION__);
+ printk("%s: CSR_CSC 0x%lx\n", __FUNCTION__, TITAN_cchip->csc.csr);
+ printk("%s: CSR_MTR 0x%lx\n", __FUNCTION__, TITAN_cchip->mtr.csr);
+ printk("%s: CSR_MISC 0x%lx\n", __FUNCTION__, TITAN_cchip->misc.csr);
+ printk("%s: CSR_DIM0 0x%lx\n", __FUNCTION__, TITAN_cchip->dim0.csr);
+ printk("%s: CSR_DIM1 0x%lx\n", __FUNCTION__, TITAN_cchip->dim1.csr);
+ printk("%s: CSR_DIR0 0x%lx\n", __FUNCTION__, TITAN_cchip->dir0.csr);
+ printk("%s: CSR_DIR1 0x%lx\n", __FUNCTION__, TITAN_cchip->dir1.csr);
+ printk("%s: CSR_DRIR 0x%lx\n", __FUNCTION__, TITAN_cchip->drir.csr);
+
+ printk("%s: DChip registers:\n", __FUNCTION__);
+ printk("%s: CSR_DSC 0x%lx\n", __FUNCTION__, TITAN_dchip->dsc.csr);
+ printk("%s: CSR_STR 0x%lx\n", __FUNCTION__, TITAN_dchip->str.csr);
+ printk("%s: CSR_DREV 0x%lx\n", __FUNCTION__, TITAN_dchip->drev.csr);
+#endif
+
+ boot_cpuid = __hard_smp_processor_id();
+
+ /* With multiple PCI busses, we play with I/O as physical addrs. */
+ ioport_resource.end = ~0UL;
+
+ /* PCI DMA Direct Mapping is 1GB at 2GB. */
+ __direct_map_base = 0x80000000;
+ __direct_map_size = 0x40000000;
+
+ /* Init the PA chip(s). */
+ titan_init_pachips(TITAN_pachip0, TITAN_pachip1);
+
+ /* Check for graphic console location (if any). */
+ titan_init_vga_hose();
+}
+
+static void
+titan_kill_one_pachip_port(titan_pachip_port *port, int index)
+{
+ port->wsba[0].csr = saved_config[index].wsba[0];
+ port->wsm[0].csr = saved_config[index].wsm[0];
+ port->tba[0].csr = saved_config[index].tba[0];
+
+ port->wsba[1].csr = saved_config[index].wsba[1];
+ port->wsm[1].csr = saved_config[index].wsm[1];
+ port->tba[1].csr = saved_config[index].tba[1];
+
+ port->wsba[2].csr = saved_config[index].wsba[2];
+ port->wsm[2].csr = saved_config[index].wsm[2];
+ port->tba[2].csr = saved_config[index].tba[2];
+
+ port->wsba[3].csr = saved_config[index].wsba[3];
+ port->wsm[3].csr = saved_config[index].wsm[3];
+ port->tba[3].csr = saved_config[index].tba[3];
+}
+
+static void
+titan_kill_pachips(titan_pachip *pachip0, titan_pachip *pachip1)
+{
+ int pchip1_present = TITAN_cchip->csc.csr & 1L<<14;
+
+ if (pchip1_present) {
+ titan_kill_one_pachip_port(&pachip1->g_port, 1);
+ titan_kill_one_pachip_port(&pachip1->a_port, 3);
+ }
+ titan_kill_one_pachip_port(&pachip0->g_port, 0);
+ titan_kill_one_pachip_port(&pachip0->a_port, 2);
+}
+
+void
+titan_kill_arch(int mode)
+{
+ titan_kill_pachips(TITAN_pachip0, TITAN_pachip1);
+}
+
+
+/*
+ * IO map support.
+ */
+
+void __iomem *
+titan_ioremap(unsigned long addr, unsigned long size)
+{
+ int h = (addr & TITAN_HOSE_MASK) >> TITAN_HOSE_SHIFT;
+ unsigned long baddr = addr & ~TITAN_HOSE_MASK;
+ unsigned long last = baddr + size - 1;
+ struct pci_controller *hose;
+ struct vm_struct *area;
+ unsigned long vaddr;
+ unsigned long *ptes;
+ unsigned long pfn;
+
+ /*
+ * Adjust the addr.
+ */
+#ifdef CONFIG_VGA_HOSE
+ if (pci_vga_hose && __titan_is_mem_vga(addr)) {
+ h = pci_vga_hose->index;
+ addr += pci_vga_hose->mem_space->start;
+ }
+#endif
+
+ /*
+ * Find the hose.
+ */
+ for (hose = hose_head; hose; hose = hose->next)
+ if (hose->index == h)
+ break;
+ if (!hose)
+ return NULL;
+
+ /*
+ * Is it direct-mapped?
+ */
+ if ((baddr >= __direct_map_base) &&
+ ((baddr + size - 1) < __direct_map_base + __direct_map_size)) {
+ vaddr = addr - __direct_map_base + TITAN_MEM_BIAS;
+ return (void __iomem *) vaddr;
+ }
+
+ /*
+ * Check the scatter-gather arena.
+ */
+ if (hose->sg_pci &&
+ baddr >= (unsigned long)hose->sg_pci->dma_base &&
+ last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size){
+
+ /*
+ * Adjust the limits (mappings must be page aligned)
+ */
+ baddr -= hose->sg_pci->dma_base;
+ last -= hose->sg_pci->dma_base;
+ baddr &= PAGE_MASK;
+ size = PAGE_ALIGN(last) - baddr;
+
+ /*
+ * Map it
+ */
+ area = get_vm_area(size, VM_IOREMAP);
+ if (!area)
+ return NULL;
+
+ ptes = hose->sg_pci->ptes;
+ for (vaddr = (unsigned long)area->addr;
+ baddr <= last;
+ baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
+ pfn = ptes[baddr >> PAGE_SHIFT];
+ if (!(pfn & 1)) {
+ printk("ioremap failed... pte not valid...\n");
+ vfree(area->addr);
+ return NULL;
+ }
+ pfn >>= 1; /* make it a true pfn */
+
+ if (__alpha_remap_area_pages(vaddr,
+ pfn << PAGE_SHIFT,
+ PAGE_SIZE, 0)) {
+ printk("FAILED to map...\n");
+ vfree(area->addr);
+ return NULL;
+ }
+ }
+
+ flush_tlb_all();
+
+ vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+ return (void __iomem *) vaddr;
+ }
+
+ return NULL;
+}
+
+void
+titan_iounmap(volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+ if (addr >= VMALLOC_START)
+ vfree((void *)(PAGE_MASK & addr));
+}
+
+int
+titan_is_mmio(const volatile void __iomem *xaddr)
+{
+ unsigned long addr = (unsigned long) xaddr;
+
+ if (addr >= VMALLOC_START)
+ return 1;
+ else
+ return (addr & 0x100000000UL) == 0;
+}
+
+#ifndef CONFIG_ALPHA_GENERIC
+EXPORT_SYMBOL(titan_ioremap);
+EXPORT_SYMBOL(titan_iounmap);
+EXPORT_SYMBOL(titan_is_mmio);
+#endif
+
+/*
+ * AGP GART Support.
+ */
+#include <linux/agp_backend.h>
+#include <asm/agp_backend.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+struct titan_agp_aperture {
+ struct pci_iommu_arena *arena;
+ long pg_start;
+ long pg_count;
+};
+
+static int
+titan_agp_setup(alpha_agp_info *agp)
+{
+ struct titan_agp_aperture *aper;
+
+ if (!alpha_agpgart_size)
+ return -ENOMEM;
+
+ aper = kmalloc(sizeof(struct titan_agp_aperture), GFP_KERNEL);
+ if (aper == NULL)
+ return -ENOMEM;
+
+ aper->arena = agp->hose->sg_pci;
+ aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
+ aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
+ aper->pg_count - 1);
+ if (aper->pg_start < 0) {
+ printk(KERN_ERR "Failed to reserve AGP memory\n");
+ kfree(aper);
+ return -ENOMEM;
+ }
+
+ agp->aperture.bus_base =
+ aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
+ agp->aperture.size = aper->pg_count * PAGE_SIZE;
+ agp->aperture.sysdata = aper;
+
+ return 0;
+}
+
+static void
+titan_agp_cleanup(alpha_agp_info *agp)
+{
+ struct titan_agp_aperture *aper = agp->aperture.sysdata;
+ int status;
+
+ status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
+ if (status == -EBUSY) {
+ printk(KERN_WARNING
+ "Attempted to release bound AGP memory - unbinding\n");
+ iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
+ status = iommu_release(aper->arena, aper->pg_start,
+ aper->pg_count);
+ }
+ if (status < 0)
+ printk(KERN_ERR "Failed to release AGP memory\n");
+
+ kfree(aper);
+ kfree(agp);
+}
+
+static int
+titan_agp_configure(alpha_agp_info *agp)
+{
+ union TPAchipPCTL pctl;
+ titan_pachip_port *port = agp->private;
+ pctl.pctl_q_whole = port->pctl.csr;
+
+ /* Side-Band Addressing? */
+ pctl.pctl_r_bits.apctl_v_agp_sba_en = agp->mode.bits.sba;
+
+ /* AGP Rate? */
+ pctl.pctl_r_bits.apctl_v_agp_rate = 0; /* 1x */
+ if (agp->mode.bits.rate & 2)
+ pctl.pctl_r_bits.apctl_v_agp_rate = 1; /* 2x */
+#if 0
+ if (agp->mode.bits.rate & 4)
+ pctl.pctl_r_bits.apctl_v_agp_rate = 2; /* 4x */
+#endif
+
+ /* RQ Depth? */
+ pctl.pctl_r_bits.apctl_v_agp_hp_rd = 2;
+ pctl.pctl_r_bits.apctl_v_agp_lp_rd = 7;
+
+ /*
+ * AGP Enable.
+ */
+ pctl.pctl_r_bits.apctl_v_agp_en = agp->mode.bits.enable;
+
+ /* Tell the user. */
+ printk("Enabling AGP: %dX%s\n",
+ 1 << pctl.pctl_r_bits.apctl_v_agp_rate,
+ pctl.pctl_r_bits.apctl_v_agp_sba_en ? " - SBA" : "");
+
+ /* Write it. */
+ port->pctl.csr = pctl.pctl_q_whole;
+
+ /* And wait at least 5000 66MHz cycles (per Titan spec). */
+ udelay(100);
+
+ return 0;
+}
+
+static int
+titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
+{
+ struct titan_agp_aperture *aper = agp->aperture.sysdata;
+ return iommu_bind(aper->arena, aper->pg_start + pg_start,
+ mem->page_count, mem->memory);
+}
+
+static int
+titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
+{
+ struct titan_agp_aperture *aper = agp->aperture.sysdata;
+ return iommu_unbind(aper->arena, aper->pg_start + pg_start,
+ mem->page_count);
+}
+
+static unsigned long
+titan_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
+{
+ struct titan_agp_aperture *aper = agp->aperture.sysdata;
+ unsigned long baddr = addr - aper->arena->dma_base;
+ unsigned long pte;
+
+ if (addr < agp->aperture.bus_base ||
+ addr >= agp->aperture.bus_base + agp->aperture.size) {
+ printk("%s: addr out of range\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
+ if (!(pte & 1)) {
+ printk("%s: pte not valid\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ return (pte >> 1) << PAGE_SHIFT;
+}
+
+struct alpha_agp_ops titan_agp_ops =
+{
+ .setup = titan_agp_setup,
+ .cleanup = titan_agp_cleanup,
+ .configure = titan_agp_configure,
+ .bind = titan_agp_bind_memory,
+ .unbind = titan_agp_unbind_memory,
+ .translate = titan_agp_translate
+};
+
+alpha_agp_info *
+titan_agp_info(void)
+{
+ alpha_agp_info *agp;
+ struct pci_controller *hose;
+ titan_pachip_port *port;
+ int hosenum = -1;
+ union TPAchipPCTL pctl;
+
+ /*
+ * Find the AGP port.
+ */
+ port = &TITAN_pachip0->a_port;
+ if (titan_query_agp(port))
+ hosenum = 2;
+ if (hosenum < 0 &&
+ titan_query_agp(port = &TITAN_pachip1->a_port))
+ hosenum = 3;
+
+ /*
+ * Find the hose the port is on.
+ */
+ for (hose = hose_head; hose; hose = hose->next)
+ if (hose->index == hosenum)
+ break;
+
+ if (!hose || !hose->sg_pci)
+ return NULL;
+
+ /*
+ * Allocate the info structure.
+ */
+ agp = kmalloc(sizeof(*agp), GFP_KERNEL);
+
+ /*
+ * Fill it in.
+ */
+ agp->hose = hose;
+ agp->private = port;
+ agp->ops = &titan_agp_ops;
+
+ /*
+ * Aperture - not configured until ops.setup().
+ *
+ * FIXME - should we go ahead and allocate it here?
+ */
+ agp->aperture.bus_base = 0;
+ agp->aperture.size = 0;
+ agp->aperture.sysdata = NULL;
+
+ /*
+ * Capabilities.
+ */
+ agp->capability.lw = 0;
+ agp->capability.bits.rate = 3; /* 2x, 1x */
+ agp->capability.bits.sba = 1;
+ agp->capability.bits.rq = 7; /* 8 - 1 */
+
+ /*
+ * Mode.
+ */
+ pctl.pctl_q_whole = port->pctl.csr;
+ agp->mode.lw = 0;
+ agp->mode.bits.rate = 1 << pctl.pctl_r_bits.apctl_v_agp_rate;
+ agp->mode.bits.sba = pctl.pctl_r_bits.apctl_v_agp_sba_en;
+ agp->mode.bits.rq = 7; /* RQ Depth? */
+ agp->mode.bits.enable = pctl.pctl_r_bits.apctl_v_agp_en;
+
+ return agp;
+}
diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c
new file mode 100644
index 000000000000..8aa305bd6a2c
--- /dev/null
+++ b/arch/alpha/kernel/core_tsunami.c
@@ -0,0 +1,459 @@
+/*
+ * linux/arch/alpha/kernel/core_tsunami.c
+ *
+ * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com).
+ *
+ * Code common to all TSUNAMI core logic chips.
+ */
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_tsunami.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/ptrace.h>
+#include <asm/smp.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+/* Save Tsunami configuration data as the console had it set up. */
+
+struct
+{
+ unsigned long wsba[4];
+ unsigned long wsm[4];
+ unsigned long tba[4];
+} saved_config[2] __attribute__((common));
+
+/*
+ * 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 DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address
+ * 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.
+ *
+ * Note that all config space accesses use Type 1 address format.
+ *
+ * Note also that type 1 is determined by non-zero bus 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)
+{
+ struct pci_controller *hose = pbus->sysdata;
+ unsigned long addr;
+ u8 bus = pbus->number;
+
+ DBG_CFG(("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 (!pbus->parent) /* No parent means peer PCI bus. */
+ bus = 0;
+ *type1 = (bus != 0);
+
+ addr = (bus << 16) | (device_fn << 8) | where;
+ addr |= hose->config_space_base;
+
+ *pci_addr = addr;
+ DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return 0;
+}
+
+static int
+tsunami_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ *value = __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ *value = __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *value = *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+tsunami_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ __kernel_stb(value, *(vucp)addr);
+ mb();
+ __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ __kernel_stw(value, *(vusp)addr);
+ mb();
+ __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *(vuip)addr = value;
+ mb();
+ *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops tsunami_pci_ops =
+{
+ .read = tsunami_read_config,
+ .write = tsunami_write_config,
+};
+
+void
+tsunami_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+ tsunami_pchip *pchip = hose->index ? TSUNAMI_pchip1 : TSUNAMI_pchip0;
+ volatile unsigned long *csr;
+ unsigned long value;
+
+ /* We can invalidate up to 8 tlb entries in a go. The flush
+ matches against <31:16> in the pci address. */
+ csr = &pchip->tlbia.csr;
+ if (((start ^ end) & 0xffff0000) == 0)
+ csr = &pchip->tlbiv.csr;
+
+ /* For TBIA, it doesn't matter what value we write. For TBI,
+ it's the shifted tag bits. */
+ value = (start & 0xffff0000) >> 12;
+
+ *csr = value;
+ mb();
+ *csr;
+}
+
+#ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI
+static long __init
+tsunami_probe_read(volatile unsigned long *vaddr)
+{
+ long dont_care, probe_result;
+ int cpu = smp_processor_id();
+ int s = swpipl(IPL_MCHECK - 1);
+
+ mcheck_taken(cpu) = 0;
+ mcheck_expected(cpu) = 1;
+ mb();
+ dont_care = *vaddr;
+ draina();
+ mcheck_expected(cpu) = 0;
+ probe_result = !mcheck_taken(cpu);
+ mcheck_taken(cpu) = 0;
+ setipl(s);
+
+ printk("dont_care == 0x%lx\n", dont_care);
+
+ return probe_result;
+}
+
+static long __init
+tsunami_probe_write(volatile unsigned long *vaddr)
+{
+ long true_contents, probe_result = 1;
+
+ TSUNAMI_cchip->misc.csr |= (1L << 28); /* clear NXM... */
+ true_contents = *vaddr;
+ *vaddr = 0;
+ draina();
+ if (TSUNAMI_cchip->misc.csr & (1L << 28)) {
+ int source = (TSUNAMI_cchip->misc.csr >> 29) & 7;
+ TSUNAMI_cchip->misc.csr |= (1L << 28); /* ...and unlock NXS. */
+ probe_result = 0;
+ printk("tsunami_probe_write: unit %d at 0x%016lx\n", source,
+ (unsigned long)vaddr);
+ }
+ if (probe_result)
+ *vaddr = true_contents;
+ return probe_result;
+}
+#else
+#define tsunami_probe_read(ADDR) 1
+#endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */
+
+#define FN __FUNCTION__
+
+static void __init
+tsunami_init_one_pchip(tsunami_pchip *pchip, int index)
+{
+ struct pci_controller *hose;
+
+ if (tsunami_probe_read(&pchip->pctl.csr) == 0)
+ return;
+
+ hose = alloc_pci_controller();
+ if (index == 0)
+ pci_isa_hose = hose;
+ hose->io_space = alloc_resource();
+ hose->mem_space = alloc_resource();
+
+ /* This is for userland consumption. For some reason, the 40-bit
+ PIO bias that we use in the kernel through KSEG didn't work for
+ the page table based user mappings. So make sure we get the
+ 43-bit PIO bias. */
+ hose->sparse_mem_base = 0;
+ hose->sparse_io_base = 0;
+ hose->dense_mem_base
+ = (TSUNAMI_MEM(index) & 0xffffffffffL) | 0x80000000000L;
+ hose->dense_io_base
+ = (TSUNAMI_IO(index) & 0xffffffffffL) | 0x80000000000L;
+
+ hose->config_space_base = TSUNAMI_CONF(index);
+ hose->index = index;
+
+ hose->io_space->start = TSUNAMI_IO(index) - TSUNAMI_IO_BIAS;
+ hose->io_space->end = hose->io_space->start + TSUNAMI_IO_SPACE - 1;
+ hose->io_space->name = pci_io_names[index];
+ hose->io_space->flags = IORESOURCE_IO;
+
+ hose->mem_space->start = TSUNAMI_MEM(index) - TSUNAMI_MEM_BIAS;
+ hose->mem_space->end = hose->mem_space->start + 0xffffffff;
+ hose->mem_space->name = pci_mem_names[index];
+ hose->mem_space->flags = IORESOURCE_MEM;
+
+ if (request_resource(&ioport_resource, hose->io_space) < 0)
+ printk(KERN_ERR "Failed to request IO on hose %d\n", index);
+ if (request_resource(&iomem_resource, hose->mem_space) < 0)
+ printk(KERN_ERR "Failed to request MEM on hose %d\n", index);
+
+ /*
+ * Save the existing PCI window translations. SRM will
+ * need them when we go to reboot.
+ */
+
+ saved_config[index].wsba[0] = pchip->wsba[0].csr;
+ saved_config[index].wsm[0] = pchip->wsm[0].csr;
+ saved_config[index].tba[0] = pchip->tba[0].csr;
+
+ saved_config[index].wsba[1] = pchip->wsba[1].csr;
+ saved_config[index].wsm[1] = pchip->wsm[1].csr;
+ saved_config[index].tba[1] = pchip->tba[1].csr;
+
+ saved_config[index].wsba[2] = pchip->wsba[2].csr;
+ saved_config[index].wsm[2] = pchip->wsm[2].csr;
+ saved_config[index].tba[2] = pchip->tba[2].csr;
+
+ saved_config[index].wsba[3] = pchip->wsba[3].csr;
+ saved_config[index].wsm[3] = pchip->wsm[3].csr;
+ saved_config[index].tba[3] = pchip->tba[3].csr;
+
+ /*
+ * Set up the PCI to main memory translation windows.
+ *
+ * Note: Window 3 is scatter-gather only
+ *
+ * Window 0 is scatter-gather 8MB at 8MB (for isa)
+ * Window 1 is scatter-gather (up to) 1GB at 1GB
+ * Window 2 is direct access 2GB at 2GB
+ *
+ * NOTE: we need the align_entry settings for Acer devices on ES40,
+ * specifically floppy and IDE when memory is larger than 2GB.
+ */
+ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+ /* Initially set for 4 PTEs, but will be overridden to 64K for ISA. */
+ hose->sg_isa->align_entry = 4;
+
+ hose->sg_pci = iommu_arena_new(hose, 0x40000000,
+ size_for_memory(0x40000000), 0);
+ hose->sg_pci->align_entry = 4; /* Tsunami caches 4 PTEs at a time */
+
+ __direct_map_base = 0x80000000;
+ __direct_map_size = 0x80000000;
+
+ pchip->wsba[0].csr = hose->sg_isa->dma_base | 3;
+ pchip->wsm[0].csr = (hose->sg_isa->size - 1) & 0xfff00000;
+ pchip->tba[0].csr = virt_to_phys(hose->sg_isa->ptes);
+
+ pchip->wsba[1].csr = hose->sg_pci->dma_base | 3;
+ pchip->wsm[1].csr = (hose->sg_pci->size - 1) & 0xfff00000;
+ pchip->tba[1].csr = virt_to_phys(hose->sg_pci->ptes);
+
+ pchip->wsba[2].csr = 0x80000000 | 1;
+ pchip->wsm[2].csr = (0x80000000 - 1) & 0xfff00000;
+ pchip->tba[2].csr = 0;
+
+ pchip->wsba[3].csr = 0;
+
+ /* Enable the Monster Window to make DAC pci64 possible. */
+ pchip->pctl.csr |= pctl_m_mwin;
+
+ tsunami_pci_tbi(hose, 0, -1);
+}
+
+void __init
+tsunami_init_arch(void)
+{
+#ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI
+ unsigned long tmp;
+
+ /* Ho hum.. init_arch is called before init_IRQ, but we need to be
+ able to handle machine checks. So install the handler now. */
+ wrent(entInt, 0);
+
+ /* NXMs just don't matter to Tsunami--unless they make it
+ choke completely. */
+ tmp = (unsigned long)(TSUNAMI_cchip - 1);
+ printk("%s: probing bogus address: 0x%016lx\n", FN, bogus_addr);
+ printk("\tprobe %s\n",
+ tsunami_probe_write((unsigned long *)bogus_addr)
+ ? "succeeded" : "failed");
+#endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */
+
+#if 0
+ printk("%s: CChip registers:\n", FN);
+ printk("%s: CSR_CSC 0x%lx\n", FN, TSUNAMI_cchip->csc.csr);
+ printk("%s: CSR_MTR 0x%lx\n", FN, TSUNAMI_cchip.mtr.csr);
+ printk("%s: CSR_MISC 0x%lx\n", FN, TSUNAMI_cchip->misc.csr);
+ printk("%s: CSR_DIM0 0x%lx\n", FN, TSUNAMI_cchip->dim0.csr);
+ printk("%s: CSR_DIM1 0x%lx\n", FN, TSUNAMI_cchip->dim1.csr);
+ printk("%s: CSR_DIR0 0x%lx\n", FN, TSUNAMI_cchip->dir0.csr);
+ printk("%s: CSR_DIR1 0x%lx\n", FN, TSUNAMI_cchip->dir1.csr);
+ printk("%s: CSR_DRIR 0x%lx\n", FN, TSUNAMI_cchip->drir.csr);
+
+ printk("%s: DChip registers:\n");
+ printk("%s: CSR_DSC 0x%lx\n", FN, TSUNAMI_dchip->dsc.csr);
+ printk("%s: CSR_STR 0x%lx\n", FN, TSUNAMI_dchip->str.csr);
+ printk("%s: CSR_DREV 0x%lx\n", FN, TSUNAMI_dchip->drev.csr);
+#endif
+ /* With multiple PCI busses, we play with I/O as physical addrs. */
+ ioport_resource.end = ~0UL;
+
+ /* Find how many hoses we have, and initialize them. TSUNAMI
+ and TYPHOON can have 2, but might only have 1 (DS10). */
+
+ tsunami_init_one_pchip(TSUNAMI_pchip0, 0);
+ if (TSUNAMI_cchip->csc.csr & 1L<<14)
+ tsunami_init_one_pchip(TSUNAMI_pchip1, 1);
+}
+
+static void
+tsunami_kill_one_pchip(tsunami_pchip *pchip, int index)
+{
+ pchip->wsba[0].csr = saved_config[index].wsba[0];
+ pchip->wsm[0].csr = saved_config[index].wsm[0];
+ pchip->tba[0].csr = saved_config[index].tba[0];
+
+ pchip->wsba[1].csr = saved_config[index].wsba[1];
+ pchip->wsm[1].csr = saved_config[index].wsm[1];
+ pchip->tba[1].csr = saved_config[index].tba[1];
+
+ pchip->wsba[2].csr = saved_config[index].wsba[2];
+ pchip->wsm[2].csr = saved_config[index].wsm[2];
+ pchip->tba[2].csr = saved_config[index].tba[2];
+
+ pchip->wsba[3].csr = saved_config[index].wsba[3];
+ pchip->wsm[3].csr = saved_config[index].wsm[3];
+ pchip->tba[3].csr = saved_config[index].tba[3];
+}
+
+void
+tsunami_kill_arch(int mode)
+{
+ tsunami_kill_one_pchip(TSUNAMI_pchip0, 0);
+ if (TSUNAMI_cchip->csc.csr & 1L<<14)
+ tsunami_kill_one_pchip(TSUNAMI_pchip1, 1);
+}
+
+static inline void
+tsunami_pci_clr_err_1(tsunami_pchip *pchip)
+{
+ pchip->perror.csr;
+ pchip->perror.csr = 0x040;
+ mb();
+ pchip->perror.csr;
+}
+
+static inline void
+tsunami_pci_clr_err(void)
+{
+ tsunami_pci_clr_err_1(TSUNAMI_pchip0);
+
+ /* TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10) */
+ if (TSUNAMI_cchip->csc.csr & 1L<<14)
+ tsunami_pci_clr_err_1(TSUNAMI_pchip1);
+}
+
+void
+tsunami_machine_check(unsigned long vector, unsigned long la_ptr,
+ struct pt_regs * regs)
+{
+ /* Clear error before any reporting. */
+ mb();
+ mb(); /* magic */
+ draina();
+ tsunami_pci_clr_err();
+ wrmces(0x7);
+ mb();
+
+ process_mcheck_info(vector, la_ptr, regs, "TSUNAMI",
+ mcheck_expected(smp_processor_id()));
+}
diff --git a/arch/alpha/kernel/core_wildfire.c b/arch/alpha/kernel/core_wildfire.c
new file mode 100644
index 000000000000..2b767a1bad96
--- /dev/null
+++ b/arch/alpha/kernel/core_wildfire.c
@@ -0,0 +1,658 @@
+/*
+ * linux/arch/alpha/kernel/core_wildfire.c
+ *
+ * Wildfire support.
+ *
+ * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
+ */
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_wildfire.h>
+#undef __EXTERN_INLINE
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/smp.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+#define DEBUG_CONFIG 0
+#define DEBUG_DUMP_REGS 0
+#define DEBUG_DUMP_CONFIG 1
+
+#if DEBUG_CONFIG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+#if DEBUG_DUMP_REGS
+static void wildfire_dump_pci_regs(int qbbno, int hoseno);
+static void wildfire_dump_pca_regs(int qbbno, int pcano);
+static void wildfire_dump_qsa_regs(int qbbno);
+static void wildfire_dump_qsd_regs(int qbbno);
+static void wildfire_dump_iop_regs(int qbbno);
+static void wildfire_dump_gp_regs(int qbbno);
+#endif
+#if DEBUG_DUMP_CONFIG
+static void wildfire_dump_hardware_config(void);
+#endif
+
+unsigned char wildfire_hard_qbb_map[WILDFIRE_MAX_QBB];
+unsigned char wildfire_soft_qbb_map[WILDFIRE_MAX_QBB];
+#define QBB_MAP_EMPTY 0xff
+
+unsigned long wildfire_hard_qbb_mask;
+unsigned long wildfire_soft_qbb_mask;
+unsigned long wildfire_gp_mask;
+unsigned long wildfire_hs_mask;
+unsigned long wildfire_iop_mask;
+unsigned long wildfire_ior_mask;
+unsigned long wildfire_pca_mask;
+unsigned long wildfire_cpu_mask;
+unsigned long wildfire_mem_mask;
+
+void __init
+wildfire_init_hose(int qbbno, int hoseno)
+{
+ struct pci_controller *hose;
+ wildfire_pci *pci;
+
+ hose = alloc_pci_controller();
+ hose->io_space = alloc_resource();
+ hose->mem_space = alloc_resource();
+
+ /* This is for userland consumption. */
+ hose->sparse_mem_base = 0;
+ hose->sparse_io_base = 0;
+ hose->dense_mem_base = WILDFIRE_MEM(qbbno, hoseno);
+ hose->dense_io_base = WILDFIRE_IO(qbbno, hoseno);
+
+ hose->config_space_base = WILDFIRE_CONF(qbbno, hoseno);
+ hose->index = (qbbno << 3) + hoseno;
+
+ hose->io_space->start = WILDFIRE_IO(qbbno, hoseno) - WILDFIRE_IO_BIAS;
+ hose->io_space->end = hose->io_space->start + WILDFIRE_IO_SPACE - 1;
+ hose->io_space->name = pci_io_names[hoseno];
+ hose->io_space->flags = IORESOURCE_IO;
+
+ hose->mem_space->start = WILDFIRE_MEM(qbbno, hoseno)-WILDFIRE_MEM_BIAS;
+ hose->mem_space->end = hose->mem_space->start + 0xffffffff;
+ hose->mem_space->name = pci_mem_names[hoseno];
+ hose->mem_space->flags = IORESOURCE_MEM;
+
+ if (request_resource(&ioport_resource, hose->io_space) < 0)
+ printk(KERN_ERR "Failed to request IO on qbb %d hose %d\n",
+ qbbno, hoseno);
+ if (request_resource(&iomem_resource, hose->mem_space) < 0)
+ printk(KERN_ERR "Failed to request MEM on qbb %d hose %d\n",
+ qbbno, hoseno);
+
+#if DEBUG_DUMP_REGS
+ wildfire_dump_pci_regs(qbbno, hoseno);
+#endif
+
+ /*
+ * Set up the PCI to main memory translation windows.
+ *
+ * Note: Window 3 is scatter-gather only
+ *
+ * Window 0 is scatter-gather 8MB at 8MB (for isa)
+ * Window 1 is direct access 1GB at 1GB
+ * Window 2 is direct access 1GB at 2GB
+ * Window 3 is scatter-gather 128MB at 3GB
+ * ??? We ought to scale window 3 memory.
+ *
+ */
+ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+ hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0);
+
+ pci = WILDFIRE_pci(qbbno, hoseno);
+
+ pci->pci_window[0].wbase.csr = hose->sg_isa->dma_base | 3;
+ pci->pci_window[0].wmask.csr = (hose->sg_isa->size - 1) & 0xfff00000;
+ pci->pci_window[0].tbase.csr = virt_to_phys(hose->sg_isa->ptes);
+
+ pci->pci_window[1].wbase.csr = 0x40000000 | 1;
+ pci->pci_window[1].wmask.csr = (0x40000000 -1) & 0xfff00000;
+ pci->pci_window[1].tbase.csr = 0;
+
+ pci->pci_window[2].wbase.csr = 0x80000000 | 1;
+ pci->pci_window[2].wmask.csr = (0x40000000 -1) & 0xfff00000;
+ pci->pci_window[2].tbase.csr = 0x40000000;
+
+ pci->pci_window[3].wbase.csr = hose->sg_pci->dma_base | 3;
+ pci->pci_window[3].wmask.csr = (hose->sg_pci->size - 1) & 0xfff00000;
+ pci->pci_window[3].tbase.csr = virt_to_phys(hose->sg_pci->ptes);
+
+ wildfire_pci_tbi(hose, 0, 0); /* Flush TLB at the end. */
+}
+
+void __init
+wildfire_init_pca(int qbbno, int pcano)
+{
+
+ /* Test for PCA existence first. */
+ if (!WILDFIRE_PCA_EXISTS(qbbno, pcano))
+ return;
+
+#if DEBUG_DUMP_REGS
+ wildfire_dump_pca_regs(qbbno, pcano);
+#endif
+
+ /* Do both hoses of the PCA. */
+ wildfire_init_hose(qbbno, (pcano << 1) + 0);
+ wildfire_init_hose(qbbno, (pcano << 1) + 1);
+}
+
+void __init
+wildfire_init_qbb(int qbbno)
+{
+ int pcano;
+
+ /* Test for QBB existence first. */
+ if (!WILDFIRE_QBB_EXISTS(qbbno))
+ return;
+
+#if DEBUG_DUMP_REGS
+ wildfire_dump_qsa_regs(qbbno);
+ wildfire_dump_qsd_regs(qbbno);
+ wildfire_dump_iop_regs(qbbno);
+ wildfire_dump_gp_regs(qbbno);
+#endif
+
+ /* Init all PCAs here. */
+ for (pcano = 0; pcano < WILDFIRE_PCA_PER_QBB; pcano++) {
+ wildfire_init_pca(qbbno, pcano);
+ }
+}
+
+void __init
+wildfire_hardware_probe(void)
+{
+ unsigned long temp;
+ unsigned int hard_qbb, soft_qbb;
+ wildfire_fast_qsd *fast = WILDFIRE_fast_qsd();
+ wildfire_qsd *qsd;
+ wildfire_qsa *qsa;
+ wildfire_iop *iop;
+ wildfire_gp *gp;
+ wildfire_ne *ne;
+ wildfire_fe *fe;
+ int i;
+
+ temp = fast->qsd_whami.csr;
+#if 0
+ printk(KERN_ERR "fast QSD_WHAMI at base %p is 0x%lx\n", fast, temp);
+#endif
+
+ hard_qbb = (temp >> 8) & 7;
+ soft_qbb = (temp >> 4) & 7;
+
+ /* Init the HW configuration variables. */
+ wildfire_hard_qbb_mask = (1 << hard_qbb);
+ wildfire_soft_qbb_mask = (1 << soft_qbb);
+
+ wildfire_gp_mask = 0;
+ wildfire_hs_mask = 0;
+ wildfire_iop_mask = 0;
+ wildfire_ior_mask = 0;
+ wildfire_pca_mask = 0;
+
+ wildfire_cpu_mask = 0;
+ wildfire_mem_mask = 0;
+
+ memset(wildfire_hard_qbb_map, QBB_MAP_EMPTY, WILDFIRE_MAX_QBB);
+ memset(wildfire_soft_qbb_map, QBB_MAP_EMPTY, WILDFIRE_MAX_QBB);
+
+ /* First, determine which QBBs are present. */
+ qsa = WILDFIRE_qsa(soft_qbb);
+
+ temp = qsa->qsa_qbb_id.csr;
+#if 0
+ printk(KERN_ERR "QSA_QBB_ID at base %p is 0x%lx\n", qsa, temp);
+#endif
+
+ if (temp & 0x40) /* Is there an HS? */
+ wildfire_hs_mask = 1;
+
+ if (temp & 0x20) { /* Is there a GP? */
+ gp = WILDFIRE_gp(soft_qbb);
+ temp = 0;
+ for (i = 0; i < 4; i++) {
+ temp |= gp->gpa_qbb_map[i].csr << (i * 8);
+#if 0
+ printk(KERN_ERR "GPA_QBB_MAP[%d] at base %p is 0x%lx\n",
+ i, gp, temp);
+#endif
+ }
+
+ for (hard_qbb = 0; hard_qbb < WILDFIRE_MAX_QBB; hard_qbb++) {
+ if (temp & 8) { /* Is there a QBB? */
+ soft_qbb = temp & 7;
+ wildfire_hard_qbb_mask |= (1 << hard_qbb);
+ wildfire_soft_qbb_mask |= (1 << soft_qbb);
+ }
+ temp >>= 4;
+ }
+ wildfire_gp_mask = wildfire_soft_qbb_mask;
+ }
+
+ /* Next determine each QBBs resources. */
+ for (soft_qbb = 0; soft_qbb < WILDFIRE_MAX_QBB; soft_qbb++) {
+ if (WILDFIRE_QBB_EXISTS(soft_qbb)) {
+ qsd = WILDFIRE_qsd(soft_qbb);
+ temp = qsd->qsd_whami.csr;
+#if 0
+ printk(KERN_ERR "QSD_WHAMI at base %p is 0x%lx\n", qsd, temp);
+#endif
+ hard_qbb = (temp >> 8) & 7;
+ wildfire_hard_qbb_map[hard_qbb] = soft_qbb;
+ wildfire_soft_qbb_map[soft_qbb] = hard_qbb;
+
+ qsa = WILDFIRE_qsa(soft_qbb);
+ temp = qsa->qsa_qbb_pop[0].csr;
+#if 0
+ printk(KERN_ERR "QSA_QBB_POP_0 at base %p is 0x%lx\n", qsa, temp);
+#endif
+ wildfire_cpu_mask |= ((temp >> 0) & 0xf) << (soft_qbb << 2);
+ wildfire_mem_mask |= ((temp >> 4) & 0xf) << (soft_qbb << 2);
+
+ temp = qsa->qsa_qbb_pop[1].csr;
+#if 0
+ printk(KERN_ERR "QSA_QBB_POP_1 at base %p is 0x%lx\n", qsa, temp);
+#endif
+ wildfire_iop_mask |= (1 << soft_qbb);
+ wildfire_ior_mask |= ((temp >> 4) & 0xf) << (soft_qbb << 2);
+
+ temp = qsa->qsa_qbb_id.csr;
+#if 0
+ printk(KERN_ERR "QSA_QBB_ID at %p is 0x%lx\n", qsa, temp);
+#endif
+ if (temp & 0x20)
+ wildfire_gp_mask |= (1 << soft_qbb);
+
+ /* Probe for PCA existence here. */
+ for (i = 0; i < WILDFIRE_PCA_PER_QBB; i++) {
+ iop = WILDFIRE_iop(soft_qbb);
+ ne = WILDFIRE_ne(soft_qbb, i);
+ fe = WILDFIRE_fe(soft_qbb, i);
+
+ if ((iop->iop_hose[i].init.csr & 1) == 1 &&
+ ((ne->ne_what_am_i.csr & 0xf00000300UL) == 0x100000300UL) &&
+ ((fe->fe_what_am_i.csr & 0xf00000300UL) == 0x100000200UL))
+ {
+ wildfire_pca_mask |= 1 << ((soft_qbb << 2) + i);
+ }
+ }
+
+ }
+ }
+#if DEBUG_DUMP_CONFIG
+ wildfire_dump_hardware_config();
+#endif
+}
+
+void __init
+wildfire_init_arch(void)
+{
+ int qbbno;
+
+ /* With multiple PCI buses, we play with I/O as physical addrs. */
+ ioport_resource.end = ~0UL;
+
+
+ /* Probe the hardware for info about configuration. */
+ wildfire_hardware_probe();
+
+ /* Now init all the found QBBs. */
+ for (qbbno = 0; qbbno < WILDFIRE_MAX_QBB; qbbno++) {
+ wildfire_init_qbb(qbbno);
+ }
+
+ /* Normal direct PCI DMA mapping. */
+ __direct_map_base = 0x40000000UL;
+ __direct_map_size = 0x80000000UL;
+}
+
+void
+wildfire_machine_check(unsigned long vector, unsigned long la_ptr,
+ struct pt_regs * regs)
+{
+ mb();
+ mb(); /* magic */
+ draina();
+ /* FIXME: clear pci errors */
+ wrmces(0x7);
+ mb();
+
+ process_mcheck_info(vector, la_ptr, regs, "WILDFIRE",
+ mcheck_expected(smp_processor_id()));
+}
+
+void
+wildfire_kill_arch(int mode)
+{
+}
+
+void
+wildfire_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+ int qbbno = hose->index >> 3;
+ int hoseno = hose->index & 7;
+ wildfire_pci *pci = WILDFIRE_pci(qbbno, hoseno);
+
+ mb();
+ pci->pci_flush_tlb.csr; /* reading does the trick */
+}
+
+static int
+mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where,
+ unsigned long *pci_addr, unsigned char *type1)
+{
+ struct pci_controller *hose = pbus->sysdata;
+ unsigned long addr;
+ u8 bus = pbus->number;
+
+ DBG_CFG(("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 (!pbus->parent) /* No parent means peer PCI bus. */
+ bus = 0;
+ *type1 = (bus != 0);
+
+ addr = (bus << 16) | (device_fn << 8) | where;
+ addr |= hose->config_space_base;
+
+ *pci_addr = addr;
+ DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return 0;
+}
+
+static int
+wildfire_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ *value = __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ *value = __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *value = *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+wildfire_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ unsigned long addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, devfn, where, &addr, &type1))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ switch (size) {
+ case 1:
+ __kernel_stb(value, *(vucp)addr);
+ mb();
+ __kernel_ldbu(*(vucp)addr);
+ break;
+ case 2:
+ __kernel_stw(value, *(vusp)addr);
+ mb();
+ __kernel_ldwu(*(vusp)addr);
+ break;
+ case 4:
+ *(vuip)addr = value;
+ mb();
+ *(vuip)addr;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops wildfire_pci_ops =
+{
+ .read = wildfire_read_config,
+ .write = wildfire_write_config,
+};
+
+
+/*
+ * NUMA Support
+ */
+int wildfire_pa_to_nid(unsigned long pa)
+{
+ return pa >> 36;
+}
+
+int wildfire_cpuid_to_nid(int cpuid)
+{
+ /* assume 4 CPUs per node */
+ return cpuid >> 2;
+}
+
+unsigned long wildfire_node_mem_start(int nid)
+{
+ /* 64GB per node */
+ return (unsigned long)nid * (64UL * 1024 * 1024 * 1024);
+}
+
+unsigned long wildfire_node_mem_size(int nid)
+{
+ /* 64GB per node */
+ return 64UL * 1024 * 1024 * 1024;
+}
+
+#if DEBUG_DUMP_REGS
+
+static void __init
+wildfire_dump_pci_regs(int qbbno, int hoseno)
+{
+ wildfire_pci *pci = WILDFIRE_pci(qbbno, hoseno);
+ int i;
+
+ printk(KERN_ERR "PCI registers for QBB %d hose %d (%p)\n",
+ qbbno, hoseno, pci);
+
+ printk(KERN_ERR " PCI_IO_ADDR_EXT: 0x%16lx\n",
+ pci->pci_io_addr_ext.csr);
+ printk(KERN_ERR " PCI_CTRL: 0x%16lx\n", pci->pci_ctrl.csr);
+ printk(KERN_ERR " PCI_ERR_SUM: 0x%16lx\n", pci->pci_err_sum.csr);
+ printk(KERN_ERR " PCI_ERR_ADDR: 0x%16lx\n", pci->pci_err_addr.csr);
+ printk(KERN_ERR " PCI_STALL_CNT: 0x%16lx\n", pci->pci_stall_cnt.csr);
+ printk(KERN_ERR " PCI_PEND_INT: 0x%16lx\n", pci->pci_pend_int.csr);
+ printk(KERN_ERR " PCI_SENT_INT: 0x%16lx\n", pci->pci_sent_int.csr);
+
+ printk(KERN_ERR " DMA window registers for QBB %d hose %d (%p)\n",
+ qbbno, hoseno, pci);
+ for (i = 0; i < 4; i++) {
+ printk(KERN_ERR " window %d: 0x%16lx 0x%16lx 0x%16lx\n", i,
+ pci->pci_window[i].wbase.csr,
+ pci->pci_window[i].wmask.csr,
+ pci->pci_window[i].tbase.csr);
+ }
+ printk(KERN_ERR "\n");
+}
+
+static void __init
+wildfire_dump_pca_regs(int qbbno, int pcano)
+{
+ wildfire_pca *pca = WILDFIRE_pca(qbbno, pcano);
+ int i;
+
+ printk(KERN_ERR "PCA registers for QBB %d PCA %d (%p)\n",
+ qbbno, pcano, pca);
+
+ printk(KERN_ERR " PCA_WHAT_AM_I: 0x%16lx\n", pca->pca_what_am_i.csr);
+ printk(KERN_ERR " PCA_ERR_SUM: 0x%16lx\n", pca->pca_err_sum.csr);
+ printk(KERN_ERR " PCA_PEND_INT: 0x%16lx\n", pca->pca_pend_int.csr);
+ printk(KERN_ERR " PCA_SENT_INT: 0x%16lx\n", pca->pca_sent_int.csr);
+ printk(KERN_ERR " PCA_STDIO_EL: 0x%16lx\n",
+ pca->pca_stdio_edge_level.csr);
+
+ printk(KERN_ERR " PCA target registers for QBB %d PCA %d (%p)\n",
+ qbbno, pcano, pca);
+ for (i = 0; i < 4; i++) {
+ printk(KERN_ERR " target %d: 0x%16lx 0x%16lx\n", i,
+ pca->pca_int[i].target.csr,
+ pca->pca_int[i].enable.csr);
+ }
+
+ printk(KERN_ERR "\n");
+}
+
+static void __init
+wildfire_dump_qsa_regs(int qbbno)
+{
+ wildfire_qsa *qsa = WILDFIRE_qsa(qbbno);
+ int i;
+
+ printk(KERN_ERR "QSA registers for QBB %d (%p)\n", qbbno, qsa);
+
+ printk(KERN_ERR " QSA_QBB_ID: 0x%16lx\n", qsa->qsa_qbb_id.csr);
+ printk(KERN_ERR " QSA_PORT_ENA: 0x%16lx\n", qsa->qsa_port_ena.csr);
+ printk(KERN_ERR " QSA_REF_INT: 0x%16lx\n", qsa->qsa_ref_int.csr);
+
+ for (i = 0; i < 5; i++)
+ printk(KERN_ERR " QSA_CONFIG_%d: 0x%16lx\n",
+ i, qsa->qsa_config[i].csr);
+
+ for (i = 0; i < 2; i++)
+ printk(KERN_ERR " QSA_QBB_POP_%d: 0x%16lx\n",
+ i, qsa->qsa_qbb_pop[0].csr);
+
+ printk(KERN_ERR "\n");
+}
+
+static void __init
+wildfire_dump_qsd_regs(int qbbno)
+{
+ wildfire_qsd *qsd = WILDFIRE_qsd(qbbno);
+
+ printk(KERN_ERR "QSD registers for QBB %d (%p)\n", qbbno, qsd);
+
+ printk(KERN_ERR " QSD_WHAMI: 0x%16lx\n", qsd->qsd_whami.csr);
+ printk(KERN_ERR " QSD_REV: 0x%16lx\n", qsd->qsd_rev.csr);
+ printk(KERN_ERR " QSD_PORT_PRESENT: 0x%16lx\n",
+ qsd->qsd_port_present.csr);
+ printk(KERN_ERR " QSD_PORT_ACTUVE: 0x%16lx\n",
+ qsd->qsd_port_active.csr);
+ printk(KERN_ERR " QSD_FAULT_ENA: 0x%16lx\n",
+ qsd->qsd_fault_ena.csr);
+ printk(KERN_ERR " QSD_CPU_INT_ENA: 0x%16lx\n",
+ qsd->qsd_cpu_int_ena.csr);
+ printk(KERN_ERR " QSD_MEM_CONFIG: 0x%16lx\n",
+ qsd->qsd_mem_config.csr);
+ printk(KERN_ERR " QSD_ERR_SUM: 0x%16lx\n",
+ qsd->qsd_err_sum.csr);
+
+ printk(KERN_ERR "\n");
+}
+
+static void __init
+wildfire_dump_iop_regs(int qbbno)
+{
+ wildfire_iop *iop = WILDFIRE_iop(qbbno);
+ int i;
+
+ printk(KERN_ERR "IOP registers for QBB %d (%p)\n", qbbno, iop);
+
+ printk(KERN_ERR " IOA_CONFIG: 0x%16lx\n", iop->ioa_config.csr);
+ printk(KERN_ERR " IOD_CONFIG: 0x%16lx\n", iop->iod_config.csr);
+ printk(KERN_ERR " IOP_SWITCH_CREDITS: 0x%16lx\n",
+ iop->iop_switch_credits.csr);
+ printk(KERN_ERR " IOP_HOSE_CREDITS: 0x%16lx\n",
+ iop->iop_hose_credits.csr);
+
+ for (i = 0; i < 4; i++)
+ printk(KERN_ERR " IOP_HOSE_%d_INIT: 0x%16lx\n",
+ i, iop->iop_hose[i].init.csr);
+ for (i = 0; i < 4; i++)
+ printk(KERN_ERR " IOP_DEV_INT_TARGET_%d: 0x%16lx\n",
+ i, iop->iop_dev_int[i].target.csr);
+
+ printk(KERN_ERR "\n");
+}
+
+static void __init
+wildfire_dump_gp_regs(int qbbno)
+{
+ wildfire_gp *gp = WILDFIRE_gp(qbbno);
+ int i;
+
+ printk(KERN_ERR "GP registers for QBB %d (%p)\n", qbbno, gp);
+ for (i = 0; i < 4; i++)
+ printk(KERN_ERR " GPA_QBB_MAP_%d: 0x%16lx\n",
+ i, gp->gpa_qbb_map[i].csr);
+
+ printk(KERN_ERR " GPA_MEM_POP_MAP: 0x%16lx\n",
+ gp->gpa_mem_pop_map.csr);
+ printk(KERN_ERR " GPA_SCRATCH: 0x%16lx\n", gp->gpa_scratch.csr);
+ printk(KERN_ERR " GPA_DIAG: 0x%16lx\n", gp->gpa_diag.csr);
+ printk(KERN_ERR " GPA_CONFIG_0: 0x%16lx\n", gp->gpa_config_0.csr);
+ printk(KERN_ERR " GPA_INIT_ID: 0x%16lx\n", gp->gpa_init_id.csr);
+ printk(KERN_ERR " GPA_CONFIG_2: 0x%16lx\n", gp->gpa_config_2.csr);
+
+ printk(KERN_ERR "\n");
+}
+#endif /* DUMP_REGS */
+
+#if DEBUG_DUMP_CONFIG
+static void __init
+wildfire_dump_hardware_config(void)
+{
+ int i;
+
+ printk(KERN_ERR "Probed Hardware Configuration\n");
+
+ printk(KERN_ERR " hard_qbb_mask: 0x%16lx\n", wildfire_hard_qbb_mask);
+ printk(KERN_ERR " soft_qbb_mask: 0x%16lx\n", wildfire_soft_qbb_mask);
+
+ printk(KERN_ERR " gp_mask: 0x%16lx\n", wildfire_gp_mask);
+ printk(KERN_ERR " hs_mask: 0x%16lx\n", wildfire_hs_mask);
+ printk(KERN_ERR " iop_mask: 0x%16lx\n", wildfire_iop_mask);
+ printk(KERN_ERR " ior_mask: 0x%16lx\n", wildfire_ior_mask);
+ printk(KERN_ERR " pca_mask: 0x%16lx\n", wildfire_pca_mask);
+
+ printk(KERN_ERR " cpu_mask: 0x%16lx\n", wildfire_cpu_mask);
+ printk(KERN_ERR " mem_mask: 0x%16lx\n", wildfire_mem_mask);
+
+ printk(" hard_qbb_map: ");
+ for (i = 0; i < WILDFIRE_MAX_QBB; i++)
+ if (wildfire_hard_qbb_map[i] == QBB_MAP_EMPTY)
+ printk("--- ");
+ else
+ printk("%3d ", wildfire_hard_qbb_map[i]);
+ printk("\n");
+
+ printk(" soft_qbb_map: ");
+ for (i = 0; i < WILDFIRE_MAX_QBB; i++)
+ if (wildfire_soft_qbb_map[i] == QBB_MAP_EMPTY)
+ printk("--- ");
+ else
+ printk("%3d ", wildfire_soft_qbb_map[i]);
+ printk("\n");
+}
+#endif /* DUMP_CONFIG */
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
new file mode 100644
index 000000000000..f0927ee53f29
--- /dev/null
+++ b/arch/alpha/kernel/entry.S
@@ -0,0 +1,957 @@
+/*
+ * arch/alpha/kernel/entry.S
+ *
+ * Kernel entry-points.
+ */
+
+#include <linux/config.h>
+#include <asm/asm_offsets.h>
+#include <asm/thread_info.h>
+#include <asm/pal.h>
+#include <asm/errno.h>
+#include <asm/unistd.h>
+
+ .text
+ .set noat
+
+/* Stack offsets. */
+#define SP_OFF 184
+#define SWITCH_STACK_SIZE 320
+
+/*
+ * This defines the normal kernel pt-regs layout.
+ *
+ * regs 9-15 preserved by C code
+ * regs 16-18 saved by PAL-code
+ * regs 29-30 saved and set up by PAL-code
+ * JRP - Save regs 16-18 in a special area of the stack, so that
+ * the palcode-provided values are available to the signal handler.
+ */
+
+#define SAVE_ALL \
+ subq $sp, SP_OFF, $sp; \
+ stq $0, 0($sp); \
+ stq $1, 8($sp); \
+ stq $2, 16($sp); \
+ stq $3, 24($sp); \
+ stq $4, 32($sp); \
+ stq $28, 144($sp); \
+ lda $2, alpha_mv; \
+ stq $5, 40($sp); \
+ stq $6, 48($sp); \
+ stq $7, 56($sp); \
+ stq $8, 64($sp); \
+ stq $19, 72($sp); \
+ stq $20, 80($sp); \
+ stq $21, 88($sp); \
+ ldq $2, HAE_CACHE($2); \
+ stq $22, 96($sp); \
+ stq $23, 104($sp); \
+ stq $24, 112($sp); \
+ stq $25, 120($sp); \
+ stq $26, 128($sp); \
+ stq $27, 136($sp); \
+ stq $2, 152($sp); \
+ stq $16, 160($sp); \
+ stq $17, 168($sp); \
+ stq $18, 176($sp)
+
+#define RESTORE_ALL \
+ lda $19, alpha_mv; \
+ ldq $0, 0($sp); \
+ ldq $1, 8($sp); \
+ ldq $2, 16($sp); \
+ ldq $3, 24($sp); \
+ ldq $21, 152($sp); \
+ ldq $20, HAE_CACHE($19); \
+ ldq $4, 32($sp); \
+ ldq $5, 40($sp); \
+ ldq $6, 48($sp); \
+ ldq $7, 56($sp); \
+ subq $20, $21, $20; \
+ ldq $8, 64($sp); \
+ beq $20, 99f; \
+ ldq $20, HAE_REG($19); \
+ stq $21, HAE_CACHE($19); \
+ stq $21, 0($20); \
+ ldq $0, 0($sp); \
+ ldq $1, 8($sp); \
+99:; \
+ ldq $19, 72($sp); \
+ ldq $20, 80($sp); \
+ ldq $21, 88($sp); \
+ ldq $22, 96($sp); \
+ ldq $23, 104($sp); \
+ ldq $24, 112($sp); \
+ ldq $25, 120($sp); \
+ ldq $26, 128($sp); \
+ ldq $27, 136($sp); \
+ ldq $28, 144($sp); \
+ addq $sp, SP_OFF, $sp
+
+/*
+ * Non-syscall kernel entry points.
+ */
+
+ .align 4
+ .globl entInt
+ .ent entInt
+entInt:
+ SAVE_ALL
+ lda $8, 0x3fff
+ lda $26, ret_from_sys_call
+ bic $sp, $8, $8
+ mov $sp, $19
+ jsr $31, do_entInt
+.end entInt
+
+ .align 4
+ .globl entArith
+ .ent entArith
+entArith:
+ SAVE_ALL
+ lda $8, 0x3fff
+ lda $26, ret_from_sys_call
+ bic $sp, $8, $8
+ mov $sp, $18
+ jsr $31, do_entArith
+.end entArith
+
+ .align 4
+ .globl entMM
+ .ent entMM
+entMM:
+ SAVE_ALL
+/* save $9 - $15 so the inline exception code can manipulate them. */
+ subq $sp, 56, $sp
+ stq $9, 0($sp)
+ stq $10, 8($sp)
+ stq $11, 16($sp)
+ stq $12, 24($sp)
+ stq $13, 32($sp)
+ stq $14, 40($sp)
+ stq $15, 48($sp)
+ addq $sp, 56, $19
+/* handle the fault */
+ lda $8, 0x3fff
+ bic $sp, $8, $8
+ jsr $26, do_page_fault
+/* reload the registers after the exception code played. */
+ ldq $9, 0($sp)
+ ldq $10, 8($sp)
+ ldq $11, 16($sp)
+ ldq $12, 24($sp)
+ ldq $13, 32($sp)
+ ldq $14, 40($sp)
+ ldq $15, 48($sp)
+ addq $sp, 56, $sp
+/* finish up the syscall as normal. */
+ br ret_from_sys_call
+.end entMM
+
+ .align 4
+ .globl entIF
+ .ent entIF
+entIF:
+ SAVE_ALL
+ lda $8, 0x3fff
+ lda $26, ret_from_sys_call
+ bic $sp, $8, $8
+ mov $sp, $17
+ jsr $31, do_entIF
+.end entIF
+
+ .align 4
+ .globl entUna
+ .ent entUna
+entUna:
+ lda $sp, -256($sp)
+ stq $0, 0($sp)
+ ldq $0, 256($sp) /* get PS */
+ stq $1, 8($sp)
+ stq $2, 16($sp)
+ stq $3, 24($sp)
+ and $0, 8, $0 /* user mode? */
+ stq $4, 32($sp)
+ bne $0, entUnaUser /* yup -> do user-level unaligned fault */
+ stq $5, 40($sp)
+ stq $6, 48($sp)
+ stq $7, 56($sp)
+ stq $8, 64($sp)
+ stq $9, 72($sp)
+ stq $10, 80($sp)
+ stq $11, 88($sp)
+ stq $12, 96($sp)
+ stq $13, 104($sp)
+ stq $14, 112($sp)
+ stq $15, 120($sp)
+ /* 16-18 PAL-saved */
+ stq $19, 152($sp)
+ stq $20, 160($sp)
+ stq $21, 168($sp)
+ stq $22, 176($sp)
+ stq $23, 184($sp)
+ stq $24, 192($sp)
+ stq $25, 200($sp)
+ stq $26, 208($sp)
+ stq $27, 216($sp)
+ stq $28, 224($sp)
+ stq $gp, 232($sp)
+ lda $8, 0x3fff
+ stq $31, 248($sp)
+ bic $sp, $8, $8
+ jsr $26, do_entUna
+ ldq $0, 0($sp)
+ ldq $1, 8($sp)
+ ldq $2, 16($sp)
+ ldq $3, 24($sp)
+ ldq $4, 32($sp)
+ ldq $5, 40($sp)
+ ldq $6, 48($sp)
+ ldq $7, 56($sp)
+ ldq $8, 64($sp)
+ ldq $9, 72($sp)
+ ldq $10, 80($sp)
+ ldq $11, 88($sp)
+ ldq $12, 96($sp)
+ ldq $13, 104($sp)
+ ldq $14, 112($sp)
+ ldq $15, 120($sp)
+ /* 16-18 PAL-saved */
+ ldq $19, 152($sp)
+ ldq $20, 160($sp)
+ ldq $21, 168($sp)
+ ldq $22, 176($sp)
+ ldq $23, 184($sp)
+ ldq $24, 192($sp)
+ ldq $25, 200($sp)
+ ldq $26, 208($sp)
+ ldq $27, 216($sp)
+ ldq $28, 224($sp)
+ ldq $gp, 232($sp)
+ lda $sp, 256($sp)
+ call_pal PAL_rti
+.end entUna
+
+ .align 4
+ .ent entUnaUser
+entUnaUser:
+ ldq $0, 0($sp) /* restore original $0 */
+ lda $sp, 256($sp) /* pop entUna's stack frame */
+ SAVE_ALL /* setup normal kernel stack */
+ lda $sp, -56($sp)
+ stq $9, 0($sp)
+ stq $10, 8($sp)
+ stq $11, 16($sp)
+ stq $12, 24($sp)
+ stq $13, 32($sp)
+ stq $14, 40($sp)
+ stq $15, 48($sp)
+ lda $8, 0x3fff
+ addq $sp, 56, $19
+ bic $sp, $8, $8
+ jsr $26, do_entUnaUser
+ ldq $9, 0($sp)
+ ldq $10, 8($sp)
+ ldq $11, 16($sp)
+ ldq $12, 24($sp)
+ ldq $13, 32($sp)
+ ldq $14, 40($sp)
+ ldq $15, 48($sp)
+ lda $sp, 56($sp)
+ br ret_from_sys_call
+.end entUnaUser
+
+ .align 4
+ .globl entDbg
+ .ent entDbg
+entDbg:
+ SAVE_ALL
+ lda $8, 0x3fff
+ lda $26, ret_from_sys_call
+ bic $sp, $8, $8
+ mov $sp, $16
+ jsr $31, do_entDbg
+.end entDbg
+
+/*
+ * The system call entry point is special. Most importantly, it looks
+ * like a function call to userspace as far as clobbered registers. We
+ * do preserve the argument registers (for syscall restarts) and $26
+ * (for leaf syscall functions).
+ *
+ * So much for theory. We don't take advantage of this yet.
+ *
+ * Note that a0-a2 are not saved by PALcode as with the other entry points.
+ */
+
+ .align 4
+ .globl entSys
+ .globl ret_from_sys_call
+ .ent entSys
+entSys:
+ SAVE_ALL
+ lda $8, 0x3fff
+ bic $sp, $8, $8
+ lda $4, NR_SYSCALLS($31)
+ stq $16, SP_OFF+24($sp)
+ lda $5, sys_call_table
+ lda $27, sys_ni_syscall
+ cmpult $0, $4, $4
+ ldl $3, TI_FLAGS($8)
+ stq $17, SP_OFF+32($sp)
+ s8addq $0, $5, $5
+ stq $18, SP_OFF+40($sp)
+ blbs $3, strace
+ beq $4, 1f
+ ldq $27, 0($5)
+1: jsr $26, ($27), alpha_ni_syscall
+ ldgp $gp, 0($26)
+ blt $0, $syscall_error /* the call failed */
+ stq $0, 0($sp)
+ stq $31, 72($sp) /* a3=0 => no error */
+
+ .align 4
+ret_from_sys_call:
+ cmovne $26, 0, $19 /* $19 = 0 => non-restartable */
+ ldq $0, SP_OFF($sp)
+ and $0, 8, $0
+ beq $0, restore_all
+ret_from_reschedule:
+ /* Make sure need_resched and sigpending don't change between
+ sampling and the rti. */
+ lda $16, 7
+ call_pal PAL_swpipl
+ ldl $5, TI_FLAGS($8)
+ and $5, _TIF_WORK_MASK, $2
+ bne $5, work_pending
+restore_all:
+ RESTORE_ALL
+ call_pal PAL_rti
+
+ .align 3
+$syscall_error:
+ /*
+ * Some system calls (e.g., ptrace) can return arbitrary
+ * values which might normally be mistaken as error numbers.
+ * Those functions must zero $0 (v0) directly in the stack
+ * frame to indicate that a negative return value wasn't an
+ * error number..
+ */
+ ldq $19, 0($sp) /* old syscall nr (zero if success) */
+ beq $19, $ret_success
+
+ ldq $20, 72($sp) /* .. and this a3 */
+ subq $31, $0, $0 /* with error in v0 */
+ addq $31, 1, $1 /* set a3 for errno return */
+ stq $0, 0($sp)
+ mov $31, $26 /* tell "ret_from_sys_call" we can restart */
+ stq $1, 72($sp) /* a3 for return */
+ br ret_from_sys_call
+
+$ret_success:
+ stq $0, 0($sp)
+ stq $31, 72($sp) /* a3=0 => no error */
+ br ret_from_sys_call
+.end entSys
+
+/*
+ * Do all cleanup when returning from all interrupts and system calls.
+ *
+ * Arguments:
+ * $5: TI_FLAGS.
+ * $8: current.
+ * $19: The old syscall number, or zero if this is not a return
+ * from a syscall that errored and is possibly restartable.
+ * $20: Error indication.
+ */
+
+ .align 4
+ .ent work_pending
+work_pending:
+ and $5, _TIF_NEED_RESCHED, $2
+ beq $2, $work_notifysig
+
+$work_resched:
+ subq $sp, 16, $sp
+ stq $19, 0($sp) /* save syscall nr */
+ stq $20, 8($sp) /* and error indication (a3) */
+ jsr $26, schedule
+ ldq $19, 0($sp)
+ ldq $20, 8($sp)
+ addq $sp, 16, $sp
+ /* Make sure need_resched and sigpending don't change between
+ sampling and the rti. */
+ lda $16, 7
+ call_pal PAL_swpipl
+ ldl $5, TI_FLAGS($8)
+ and $5, _TIF_WORK_MASK, $2
+ beq $2, restore_all
+ and $5, _TIF_NEED_RESCHED, $2
+ bne $2, $work_resched
+
+$work_notifysig:
+ mov $sp, $17
+ br $1, do_switch_stack
+ mov $5, $21
+ mov $sp, $18
+ mov $31, $16
+ jsr $26, do_notify_resume
+ bsr $1, undo_switch_stack
+ br restore_all
+.end work_pending
+
+/*
+ * PTRACE syscall handler
+ */
+
+ .align 4
+ .ent strace
+strace:
+ /* set up signal stack, call syscall_trace */
+ bsr $1, do_switch_stack
+ jsr $26, syscall_trace
+ bsr $1, undo_switch_stack
+
+ /* get the system call number and the arguments back.. */
+ ldq $0, 0($sp)
+ ldq $16, SP_OFF+24($sp)
+ ldq $17, SP_OFF+32($sp)
+ ldq $18, SP_OFF+40($sp)
+ ldq $19, 72($sp)
+ ldq $20, 80($sp)
+ ldq $21, 88($sp)
+
+ /* get the system call pointer.. */
+ lda $1, NR_SYSCALLS($31)
+ lda $2, sys_call_table
+ lda $27, alpha_ni_syscall
+ cmpult $0, $1, $1
+ s8addq $0, $2, $2
+ beq $1, 1f
+ ldq $27, 0($2)
+1: jsr $26, ($27), sys_gettimeofday
+ ldgp $gp, 0($26)
+
+ /* check return.. */
+ blt $0, $strace_error /* the call failed */
+ stq $31, 72($sp) /* a3=0 => no error */
+$strace_success:
+ stq $0, 0($sp) /* save return value */
+
+ bsr $1, do_switch_stack
+ jsr $26, syscall_trace
+ bsr $1, undo_switch_stack
+ br $31, ret_from_sys_call
+
+ .align 3
+$strace_error:
+ ldq $19, 0($sp) /* old syscall nr (zero if success) */
+ beq $19, $strace_success
+ ldq $20, 72($sp) /* .. and this a3 */
+
+ subq $31, $0, $0 /* with error in v0 */
+ addq $31, 1, $1 /* set a3 for errno return */
+ stq $0, 0($sp)
+ stq $1, 72($sp) /* a3 for return */
+
+ bsr $1, do_switch_stack
+ mov $19, $9 /* save old syscall number */
+ mov $20, $10 /* save old a3 */
+ jsr $26, syscall_trace
+ mov $9, $19
+ mov $10, $20
+ bsr $1, undo_switch_stack
+
+ mov $31, $26 /* tell "ret_from_sys_call" we can restart */
+ br ret_from_sys_call
+.end strace
+
+/*
+ * Save and restore the switch stack -- aka the balance of the user context.
+ */
+
+ .align 4
+ .ent do_switch_stack
+do_switch_stack:
+ lda $sp, -SWITCH_STACK_SIZE($sp)
+ stq $9, 0($sp)
+ stq $10, 8($sp)
+ stq $11, 16($sp)
+ stq $12, 24($sp)
+ stq $13, 32($sp)
+ stq $14, 40($sp)
+ stq $15, 48($sp)
+ stq $26, 56($sp)
+ stt $f0, 64($sp)
+ stt $f1, 72($sp)
+ stt $f2, 80($sp)
+ stt $f3, 88($sp)
+ stt $f4, 96($sp)
+ stt $f5, 104($sp)
+ stt $f6, 112($sp)
+ stt $f7, 120($sp)
+ stt $f8, 128($sp)
+ stt $f9, 136($sp)
+ stt $f10, 144($sp)
+ stt $f11, 152($sp)
+ stt $f12, 160($sp)
+ stt $f13, 168($sp)
+ stt $f14, 176($sp)
+ stt $f15, 184($sp)
+ stt $f16, 192($sp)
+ stt $f17, 200($sp)
+ stt $f18, 208($sp)
+ stt $f19, 216($sp)
+ stt $f20, 224($sp)
+ stt $f21, 232($sp)
+ stt $f22, 240($sp)
+ stt $f23, 248($sp)
+ stt $f24, 256($sp)
+ stt $f25, 264($sp)
+ stt $f26, 272($sp)
+ stt $f27, 280($sp)
+ mf_fpcr $f0 # get fpcr
+ stt $f28, 288($sp)
+ stt $f29, 296($sp)
+ stt $f30, 304($sp)
+ stt $f0, 312($sp) # save fpcr in slot of $f31
+ ldt $f0, 64($sp) # dont let "do_switch_stack" change fp state.
+ ret $31, ($1), 1
+.end do_switch_stack
+
+ .align 4
+ .ent undo_switch_stack
+undo_switch_stack:
+ ldq $9, 0($sp)
+ ldq $10, 8($sp)
+ ldq $11, 16($sp)
+ ldq $12, 24($sp)
+ ldq $13, 32($sp)
+ ldq $14, 40($sp)
+ ldq $15, 48($sp)
+ ldq $26, 56($sp)
+ ldt $f30, 312($sp) # get saved fpcr
+ ldt $f0, 64($sp)
+ ldt $f1, 72($sp)
+ ldt $f2, 80($sp)
+ ldt $f3, 88($sp)
+ mt_fpcr $f30 # install saved fpcr
+ ldt $f4, 96($sp)
+ ldt $f5, 104($sp)
+ ldt $f6, 112($sp)
+ ldt $f7, 120($sp)
+ ldt $f8, 128($sp)
+ ldt $f9, 136($sp)
+ ldt $f10, 144($sp)
+ ldt $f11, 152($sp)
+ ldt $f12, 160($sp)
+ ldt $f13, 168($sp)
+ ldt $f14, 176($sp)
+ ldt $f15, 184($sp)
+ ldt $f16, 192($sp)
+ ldt $f17, 200($sp)
+ ldt $f18, 208($sp)
+ ldt $f19, 216($sp)
+ ldt $f20, 224($sp)
+ ldt $f21, 232($sp)
+ ldt $f22, 240($sp)
+ ldt $f23, 248($sp)
+ ldt $f24, 256($sp)
+ ldt $f25, 264($sp)
+ ldt $f26, 272($sp)
+ ldt $f27, 280($sp)
+ ldt $f28, 288($sp)
+ ldt $f29, 296($sp)
+ ldt $f30, 304($sp)
+ lda $sp, SWITCH_STACK_SIZE($sp)
+ ret $31, ($1), 1
+.end undo_switch_stack
+
+/*
+ * The meat of the context switch code.
+ */
+
+ .align 4
+ .globl alpha_switch_to
+ .ent alpha_switch_to
+alpha_switch_to:
+ .prologue 0
+ bsr $1, do_switch_stack
+ call_pal PAL_swpctx
+ lda $8, 0x3fff
+ bsr $1, undo_switch_stack
+ bic $sp, $8, $8
+ mov $17, $0
+ ret
+.end alpha_switch_to
+
+/*
+ * New processes begin life here.
+ */
+
+ .globl ret_from_fork
+ .align 4
+ .ent ret_from_fork
+ret_from_fork:
+ lda $26, ret_from_sys_call
+ mov $17, $16
+ jmp $31, schedule_tail
+.end ret_from_fork
+
+/*
+ * kernel_thread(fn, arg, clone_flags)
+ */
+ .align 4
+ .globl kernel_thread
+ .ent kernel_thread
+kernel_thread:
+ /* We can be called from a module. */
+ ldgp $gp, 0($27)
+ .prologue 1
+ subq $sp, SP_OFF+6*8, $sp
+ br $1, 2f /* load start address */
+
+ /* We've now "returned" from a fake system call. */
+ unop
+ blt $0, 1f /* error? */
+ ldi $1, 0x3fff
+ beq $20, 1f /* parent or child? */
+
+ bic $sp, $1, $8 /* in child. */
+ jsr $26, ($27)
+ ldgp $gp, 0($26)
+ mov $0, $16
+ mov $31, $26
+ jmp $31, sys_exit
+
+1: ret /* in parent. */
+
+ .align 4
+2: /* Fake a system call stack frame, as we can't do system calls
+ from kernel space. Note that we store FN and ARG as they
+ need to be set up in the child for the call. Also store $8
+ and $26 for use in the parent. */
+ stq $31, SP_OFF($sp) /* ps */
+ stq $1, SP_OFF+8($sp) /* pc */
+ stq $gp, SP_OFF+16($sp) /* gp */
+ stq $16, 136($sp) /* $27; FN for child */
+ stq $17, SP_OFF+24($sp) /* $16; ARG for child */
+ stq $8, 64($sp) /* $8 */
+ stq $26, 128($sp) /* $26 */
+ /* Avoid the HAE being gratuitously wrong, to avoid restoring it. */
+ ldq $2, alpha_mv+HAE_CACHE
+ stq $2, 152($sp) /* HAE */
+
+ /* Shuffle FLAGS to the front; add CLONE_VM. */
+ ldi $1, CLONE_VM|CLONE_UNTRACED
+ or $18, $1, $16
+ bsr $26, sys_clone
+
+ /* We don't actually care for a3 success widgetry in the kernel.
+ Not for positive errno values. */
+ stq $0, 0($sp) /* $0 */
+ br restore_all
+.end kernel_thread
+
+/*
+ * execve(path, argv, envp)
+ */
+ .align 4
+ .globl execve
+ .ent execve
+execve:
+ /* We can be called from a module. */
+ ldgp $gp, 0($27)
+ lda $sp, -(32+SIZEOF_PT_REGS+8)($sp)
+ .frame $sp, 32+SIZEOF_PT_REGS+8, $26, 0
+ stq $26, 0($sp)
+ stq $16, 8($sp)
+ stq $17, 16($sp)
+ stq $18, 24($sp)
+ .prologue 1
+
+ lda $16, 32($sp)
+ lda $17, 0
+ lda $18, SIZEOF_PT_REGS
+ bsr $26, memset !samegp
+
+ /* Avoid the HAE being gratuitously wrong, which would cause us
+ to do the whole turn off interrupts thing and restore it. */
+ ldq $2, alpha_mv+HAE_CACHE
+ stq $2, 152+32($sp)
+
+ ldq $16, 8($sp)
+ ldq $17, 16($sp)
+ ldq $18, 24($sp)
+ lda $19, 32($sp)
+ bsr $26, do_execve !samegp
+
+ ldq $26, 0($sp)
+ bne $0, 1f /* error! */
+
+ /* Move the temporary pt_regs struct from its current location
+ to the top of the kernel stack frame. See copy_thread for
+ details for a normal process. */
+ lda $16, 0x4000 - SIZEOF_PT_REGS($8)
+ lda $17, 32($sp)
+ lda $18, SIZEOF_PT_REGS
+ bsr $26, memmove !samegp
+
+ /* Take that over as our new stack frame and visit userland! */
+ lda $sp, 0x4000 - SIZEOF_PT_REGS($8)
+ br $31, ret_from_sys_call
+
+1: lda $sp, 32+SIZEOF_PT_REGS+8($sp)
+ ret
+.end execve
+
+
+/*
+ * Special system calls. Most of these are special in that they either
+ * have to play switch_stack games or in some way use the pt_regs struct.
+ */
+ .align 4
+ .globl sys_fork
+ .ent sys_fork
+sys_fork:
+ .prologue 0
+ mov $sp, $21
+ bsr $1, do_switch_stack
+ bis $31, SIGCHLD, $16
+ mov $31, $17
+ mov $31, $18
+ mov $31, $19
+ mov $31, $20
+ jsr $26, alpha_clone
+ bsr $1, undo_switch_stack
+ ret
+.end sys_fork
+
+ .align 4
+ .globl sys_clone
+ .ent sys_clone
+sys_clone:
+ .prologue 0
+ mov $sp, $21
+ bsr $1, do_switch_stack
+ /* $16, $17, $18, $19, $20 come from the user. */
+ jsr $26, alpha_clone
+ bsr $1, undo_switch_stack
+ ret
+.end sys_clone
+
+ .align 4
+ .globl sys_vfork
+ .ent sys_vfork
+sys_vfork:
+ .prologue 0
+ mov $sp, $16
+ bsr $1, do_switch_stack
+ jsr $26, alpha_vfork
+ bsr $1, undo_switch_stack
+ ret
+.end sys_vfork
+
+ .align 4
+ .globl sys_sigreturn
+ .ent sys_sigreturn
+sys_sigreturn:
+ .prologue 0
+ mov $sp, $17
+ lda $18, -SWITCH_STACK_SIZE($sp)
+ lda $sp, -SWITCH_STACK_SIZE($sp)
+ jsr $26, do_sigreturn
+ br $1, undo_switch_stack
+ br ret_from_sys_call
+.end sys_sigreturn
+
+ .align 4
+ .globl sys_rt_sigreturn
+ .ent sys_rt_sigreturn
+sys_rt_sigreturn:
+ .prologue 0
+ mov $sp, $17
+ lda $18, -SWITCH_STACK_SIZE($sp)
+ lda $sp, -SWITCH_STACK_SIZE($sp)
+ jsr $26, do_rt_sigreturn
+ br $1, undo_switch_stack
+ br ret_from_sys_call
+.end sys_rt_sigreturn
+
+ .align 4
+ .globl sys_sigsuspend
+ .ent sys_sigsuspend
+sys_sigsuspend:
+ .prologue 0
+ mov $sp, $17
+ br $1, do_switch_stack
+ mov $sp, $18
+ subq $sp, 16, $sp
+ stq $26, 0($sp)
+ jsr $26, do_sigsuspend
+ ldq $26, 0($sp)
+ lda $sp, SWITCH_STACK_SIZE+16($sp)
+ ret
+.end sys_sigsuspend
+
+ .align 4
+ .globl sys_rt_sigsuspend
+ .ent sys_rt_sigsuspend
+sys_rt_sigsuspend:
+ .prologue 0
+ mov $sp, $18
+ br $1, do_switch_stack
+ mov $sp, $19
+ subq $sp, 16, $sp
+ stq $26, 0($sp)
+ jsr $26, do_rt_sigsuspend
+ ldq $26, 0($sp)
+ lda $sp, SWITCH_STACK_SIZE+16($sp)
+ ret
+.end sys_rt_sigsuspend
+
+ .align 4
+ .globl sys_sethae
+ .ent sys_sethae
+sys_sethae:
+ .prologue 0
+ stq $16, 152($sp)
+ ret
+.end sys_sethae
+
+ .align 4
+ .globl osf_getpriority
+ .ent osf_getpriority
+osf_getpriority:
+ lda $sp, -16($sp)
+ stq $26, 0($sp)
+ .prologue 0
+
+ jsr $26, sys_getpriority
+
+ ldq $26, 0($sp)
+ blt $0, 1f
+
+ /* Return value is the unbiased priority, i.e. 20 - prio.
+ This does result in negative return values, so signal
+ no error by writing into the R0 slot. */
+ lda $1, 20
+ stq $31, 16($sp)
+ subl $1, $0, $0
+ unop
+
+1: lda $sp, 16($sp)
+ ret
+.end osf_getpriority
+
+ .align 4
+ .globl sys_getxuid
+ .ent sys_getxuid
+sys_getxuid:
+ .prologue 0
+ ldq $2, TI_TASK($8)
+ ldl $0, TASK_UID($2)
+ ldl $1, TASK_EUID($2)
+ stq $1, 80($sp)
+ ret
+.end sys_getxuid
+
+ .align 4
+ .globl sys_getxgid
+ .ent sys_getxgid
+sys_getxgid:
+ .prologue 0
+ ldq $2, TI_TASK($8)
+ ldl $0, TASK_GID($2)
+ ldl $1, TASK_EGID($2)
+ stq $1, 80($sp)
+ ret
+.end sys_getxgid
+
+ .align 4
+ .globl sys_getxpid
+ .ent sys_getxpid
+sys_getxpid:
+ .prologue 0
+ ldq $2, TI_TASK($8)
+
+ /* See linux/kernel/timer.c sys_getppid for discussion
+ about this loop. */
+ ldq $3, TASK_REAL_PARENT($2)
+1: ldl $1, TASK_TGID($3)
+#ifdef CONFIG_SMP
+ mov $3, $4
+ mb
+ ldq $3, TASK_REAL_PARENT($2)
+ cmpeq $3, $4, $4
+ beq $4, 1b
+#endif
+ stq $1, 80($sp)
+ ldl $0, TASK_TGID($2)
+ ret
+.end sys_getxpid
+
+ .align 4
+ .globl sys_pipe
+ .ent sys_pipe
+sys_pipe:
+ lda $sp, -16($sp)
+ stq $26, 0($sp)
+ .prologue 0
+
+ lda $16, 8($sp)
+ jsr $26, do_pipe
+
+ ldq $26, 0($sp)
+ bne $0, 1f
+
+ /* The return values are in $0 and $20. */
+ ldl $1, 12($sp)
+ ldl $0, 8($sp)
+
+ stq $1, 80+16($sp)
+1: lda $sp, 16($sp)
+ ret
+.end sys_pipe
+
+ .align 4
+ .globl sys_ptrace
+ .ent sys_ptrace
+sys_ptrace:
+ .prologue 0
+ mov $sp, $20
+ jmp $31, do_sys_ptrace
+.end sys_ptrace
+
+ .align 4
+ .globl sys_execve
+ .ent sys_execve
+sys_execve:
+ .prologue 0
+ mov $sp, $19
+ jmp $31, do_sys_execve
+.end sys_execve
+
+ .align 4
+ .globl osf_sigprocmask
+ .ent osf_sigprocmask
+osf_sigprocmask:
+ .prologue 0
+ mov $sp, $18
+ jmp $31, do_osf_sigprocmask
+.end osf_sigprocmask
+
+ .align 4
+ .globl alpha_ni_syscall
+ .ent alpha_ni_syscall
+alpha_ni_syscall:
+ .prologue 0
+ /* Special because it also implements overflow handling via
+ syscall number 0. And if you recall, zero is a special
+ trigger for "not an error". Store large non-zero there. */
+ lda $0, -ENOSYS
+ unop
+ stq $0, 0($sp)
+ ret
+.end alpha_ni_syscall
diff --git a/arch/alpha/kernel/err_common.c b/arch/alpha/kernel/err_common.c
new file mode 100644
index 000000000000..687580b16b41
--- /dev/null
+++ b/arch/alpha/kernel/err_common.c
@@ -0,0 +1,321 @@
+/*
+ * linux/arch/alpha/kernel/err_common.c
+ *
+ * Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ * Error handling code supporting Alpha systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+#include <asm/err_common.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+/*
+ * err_print_prefix -- error handling print routines should prefix
+ * all prints with this
+ */
+char *err_print_prefix = KERN_NOTICE;
+
+
+/*
+ * Generic
+ */
+void
+mchk_dump_mem(void *data, size_t length, char **annotation)
+{
+ unsigned long *ldata = data;
+ size_t i;
+
+ for (i = 0; (i * sizeof(*ldata)) < length; i++) {
+ if (annotation && !annotation[i])
+ annotation = NULL;
+ printk("%s %08x: %016lx %s\n",
+ err_print_prefix,
+ (unsigned)(i * sizeof(*ldata)), ldata[i],
+ annotation ? annotation[i] : "");
+ }
+}
+
+void
+mchk_dump_logout_frame(struct el_common *mchk_header)
+{
+ printk("%s -- Frame Header --\n"
+ " Frame Size: %d (0x%x) bytes\n"
+ " Flags: %s%s\n"
+ " MCHK Code: 0x%x\n"
+ " Frame Rev: %d\n"
+ " Proc Offset: 0x%08x\n"
+ " Sys Offset: 0x%08x\n"
+ " -- Processor Region --\n",
+ err_print_prefix,
+ mchk_header->size, mchk_header->size,
+ mchk_header->retry ? "RETRY " : "",
+ mchk_header->err2 ? "SECOND_ERR " : "",
+ mchk_header->code,
+ mchk_header->frame_rev,
+ mchk_header->proc_offset,
+ mchk_header->sys_offset);
+
+ mchk_dump_mem((void *)
+ ((unsigned long)mchk_header + mchk_header->proc_offset),
+ mchk_header->sys_offset - mchk_header->proc_offset,
+ NULL);
+
+ printk("%s -- System Region --\n", err_print_prefix);
+ mchk_dump_mem((void *)
+ ((unsigned long)mchk_header + mchk_header->sys_offset),
+ mchk_header->size - mchk_header->sys_offset,
+ NULL);
+ printk("%s -- End of Frame --\n", err_print_prefix);
+}
+
+
+/*
+ * Console Data Log
+ */
+/* Data */
+static struct el_subpacket_handler *subpacket_handler_list = NULL;
+static struct el_subpacket_annotation *subpacket_annotation_list = NULL;
+
+static struct el_subpacket *
+el_process_header_subpacket(struct el_subpacket *header)
+{
+ union el_timestamp timestamp;
+ char *name = "UNKNOWN EVENT";
+ int packet_count = 0;
+ int length = 0;
+
+ if (header->class != EL_CLASS__HEADER) {
+ printk("%s** Unexpected header CLASS %d TYPE %d, aborting\n",
+ err_print_prefix,
+ header->class, header->type);
+ return NULL;
+ }
+
+ switch(header->type) {
+ case EL_TYPE__HEADER__SYSTEM_ERROR_FRAME:
+ name = "SYSTEM ERROR";
+ length = header->by_type.sys_err.frame_length;
+ packet_count =
+ header->by_type.sys_err.frame_packet_count;
+ timestamp.as_int = 0;
+ break;
+ case EL_TYPE__HEADER__SYSTEM_EVENT_FRAME:
+ name = "SYSTEM EVENT";
+ length = header->by_type.sys_event.frame_length;
+ packet_count =
+ header->by_type.sys_event.frame_packet_count;
+ timestamp = header->by_type.sys_event.timestamp;
+ break;
+ case EL_TYPE__HEADER__HALT_FRAME:
+ name = "ERROR HALT";
+ length = header->by_type.err_halt.frame_length;
+ packet_count =
+ header->by_type.err_halt.frame_packet_count;
+ timestamp = header->by_type.err_halt.timestamp;
+ break;
+ case EL_TYPE__HEADER__LOGOUT_FRAME:
+ name = "LOGOUT FRAME";
+ length = header->by_type.logout_header.frame_length;
+ packet_count = 1;
+ timestamp.as_int = 0;
+ break;
+ default: /* Unknown */
+ printk("%s** Unknown header - CLASS %d TYPE %d, aborting\n",
+ err_print_prefix,
+ header->class, header->type);
+ return NULL;
+ }
+
+ printk("%s*** %s:\n"
+ " CLASS %d, TYPE %d\n",
+ err_print_prefix,
+ name,
+ header->class, header->type);
+ el_print_timestamp(&timestamp);
+
+ /*
+ * Process the subpackets
+ */
+ el_process_subpackets(header, packet_count);
+
+ /* return the next header */
+ header = (struct el_subpacket *)
+ ((unsigned long)header + header->length + length);
+ return header;
+}
+
+static struct el_subpacket *
+el_process_subpacket_reg(struct el_subpacket *header)
+{
+ struct el_subpacket *next = NULL;
+ struct el_subpacket_handler *h = subpacket_handler_list;
+
+ for (; h && h->class != header->class; h = h->next);
+ if (h) next = h->handler(header);
+
+ return next;
+}
+
+void
+el_print_timestamp(union el_timestamp *timestamp)
+{
+ if (timestamp->as_int)
+ printk("%s TIMESTAMP: %d/%d/%02d %d:%02d:%0d\n",
+ err_print_prefix,
+ timestamp->b.month, timestamp->b.day,
+ timestamp->b.year, timestamp->b.hour,
+ timestamp->b.minute, timestamp->b.second);
+}
+
+void
+el_process_subpackets(struct el_subpacket *header, int packet_count)
+{
+ struct el_subpacket *subpacket;
+ int i;
+
+ subpacket = (struct el_subpacket *)
+ ((unsigned long)header + header->length);
+
+ for (i = 0; subpacket && i < packet_count; i++) {
+ printk("%sPROCESSING SUBPACKET %d\n", err_print_prefix, i);
+ subpacket = el_process_subpacket(subpacket);
+ }
+}
+
+struct el_subpacket *
+el_process_subpacket(struct el_subpacket *header)
+{
+ struct el_subpacket *next = NULL;
+
+ switch(header->class) {
+ case EL_CLASS__TERMINATION:
+ /* Termination packet, there are no more */
+ break;
+ case EL_CLASS__HEADER:
+ next = el_process_header_subpacket(header);
+ break;
+ default:
+ if (NULL == (next = el_process_subpacket_reg(header))) {
+ printk("%s** Unexpected header CLASS %d TYPE %d"
+ " -- aborting.\n",
+ err_print_prefix,
+ header->class, header->type);
+ }
+ break;
+ }
+
+ return next;
+}
+
+void
+el_annotate_subpacket(struct el_subpacket *header)
+{
+ struct el_subpacket_annotation *a;
+ char **annotation = NULL;
+
+ for (a = subpacket_annotation_list; a; a = a->next) {
+ if (a->class == header->class &&
+ a->type == header->type &&
+ a->revision == header->revision) {
+ /*
+ * We found the annotation
+ */
+ annotation = a->annotation;
+ printk("%s %s\n", err_print_prefix, a->description);
+ break;
+ }
+ }
+
+ mchk_dump_mem(header, header->length, annotation);
+}
+
+static void __init
+cdl_process_console_data_log(int cpu, struct percpu_struct *pcpu)
+{
+ struct el_subpacket *header = (struct el_subpacket *)
+ (IDENT_ADDR | pcpu->console_data_log_pa);
+ int err;
+
+ printk("%s******* CONSOLE DATA LOG FOR CPU %d. *******\n"
+ "*** Error(s) were logged on a previous boot\n",
+ err_print_prefix, cpu);
+
+ for (err = 0; header && (header->class != EL_CLASS__TERMINATION); err++)
+ header = el_process_subpacket(header);
+
+ /* let the console know it's ok to clear the error(s) at restart */
+ pcpu->console_data_log_pa = 0;
+
+ printk("%s*** %d total error(s) logged\n"
+ "**** END OF CONSOLE DATA LOG FOR CPU %d ****\n",
+ err_print_prefix, err, cpu);
+}
+
+void __init
+cdl_check_console_data_log(void)
+{
+ struct percpu_struct *pcpu;
+ unsigned long cpu;
+
+ for (cpu = 0; cpu < hwrpb->nr_processors; cpu++) {
+ pcpu = (struct percpu_struct *)
+ ((unsigned long)hwrpb + hwrpb->processor_offset
+ + cpu * hwrpb->processor_size);
+ if (pcpu->console_data_log_pa)
+ cdl_process_console_data_log(cpu, pcpu);
+ }
+
+}
+
+int __init
+cdl_register_subpacket_annotation(struct el_subpacket_annotation *new)
+{
+ struct el_subpacket_annotation *a = subpacket_annotation_list;
+
+ if (a == NULL) subpacket_annotation_list = new;
+ else {
+ for (; a->next != NULL; a = a->next) {
+ if ((a->class == new->class && a->type == new->type) ||
+ a == new) {
+ printk("Attempted to re-register "
+ "subpacket annotation\n");
+ return -EINVAL;
+ }
+ }
+ a->next = new;
+ }
+ new->next = NULL;
+
+ return 0;
+}
+
+int __init
+cdl_register_subpacket_handler(struct el_subpacket_handler *new)
+{
+ struct el_subpacket_handler *h = subpacket_handler_list;
+
+ if (h == NULL) subpacket_handler_list = new;
+ else {
+ for (; h->next != NULL; h = h->next) {
+ if (h->class == new->class || h == new) {
+ printk("Attempted to re-register "
+ "subpacket handler\n");
+ return -EINVAL;
+ }
+ }
+ h->next = new;
+ }
+ new->next = NULL;
+
+ return 0;
+}
+
diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c
new file mode 100644
index 000000000000..64f59f2fcf5c
--- /dev/null
+++ b/arch/alpha/kernel/err_ev6.c
@@ -0,0 +1,274 @@
+/*
+ * linux/arch/alpha/kernel/err_ev6.c
+ *
+ * Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ * Error handling code supporting Alpha systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+#include <asm/err_common.h>
+#include <asm/err_ev6.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+static int
+ev6_parse_ibox(u64 i_stat, int print)
+{
+ int status = MCHK_DISPOSITION_REPORT;
+
+#define EV6__I_STAT__PAR (1UL << 29)
+#define EV6__I_STAT__ERRMASK (EV6__I_STAT__PAR)
+
+ if (!(i_stat & EV6__I_STAT__ERRMASK))
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+ if (!print)
+ return status;
+
+ if (i_stat & EV6__I_STAT__PAR)
+ printk("%s Icache parity error\n", err_print_prefix);
+
+ return status;
+}
+
+static int
+ev6_parse_mbox(u64 mm_stat, u64 d_stat, u64 c_stat, int print)
+{
+ int status = MCHK_DISPOSITION_REPORT;
+
+#define EV6__MM_STAT__DC_TAG_PERR (1UL << 10)
+#define EV6__MM_STAT__ERRMASK (EV6__MM_STAT__DC_TAG_PERR)
+#define EV6__D_STAT__TPERR_P0 (1UL << 0)
+#define EV6__D_STAT__TPERR_P1 (1UL << 1)
+#define EV6__D_STAT__ECC_ERR_ST (1UL << 2)
+#define EV6__D_STAT__ECC_ERR_LD (1UL << 3)
+#define EV6__D_STAT__SEO (1UL << 4)
+#define EV6__D_STAT__ERRMASK (EV6__D_STAT__TPERR_P0 | \
+ EV6__D_STAT__TPERR_P1 | \
+ EV6__D_STAT__ECC_ERR_ST | \
+ EV6__D_STAT__ECC_ERR_LD | \
+ EV6__D_STAT__SEO)
+
+ if (!(d_stat & EV6__D_STAT__ERRMASK) &&
+ !(mm_stat & EV6__MM_STAT__ERRMASK))
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+ if (!print)
+ return status;
+
+ if (mm_stat & EV6__MM_STAT__DC_TAG_PERR)
+ printk("%s Dcache tag parity error on probe\n",
+ err_print_prefix);
+ if (d_stat & EV6__D_STAT__TPERR_P0)
+ printk("%s Dcache tag parity error - pipe 0\n",
+ err_print_prefix);
+ if (d_stat & EV6__D_STAT__TPERR_P1)
+ printk("%s Dcache tag parity error - pipe 1\n",
+ err_print_prefix);
+ if (d_stat & EV6__D_STAT__ECC_ERR_ST)
+ printk("%s ECC error occurred on a store\n",
+ err_print_prefix);
+ if (d_stat & EV6__D_STAT__ECC_ERR_LD)
+ printk("%s ECC error occurred on a %s load\n",
+ err_print_prefix,
+ c_stat ? "" : "speculative ");
+ if (d_stat & EV6__D_STAT__SEO)
+ printk("%s Dcache second error\n", err_print_prefix);
+
+ return status;
+}
+
+static int
+ev6_parse_cbox(u64 c_addr, u64 c1_syn, u64 c2_syn,
+ u64 c_stat, u64 c_sts, int print)
+{
+ char *sourcename[] = { "UNKNOWN", "UNKNOWN", "UNKNOWN",
+ "MEMORY", "BCACHE", "DCACHE",
+ "BCACHE PROBE", "BCACHE PROBE" };
+ char *streamname[] = { "D", "I" };
+ char *bitsname[] = { "SINGLE", "DOUBLE" };
+ int status = MCHK_DISPOSITION_REPORT;
+ int source = -1, stream = -1, bits = -1;
+
+#define EV6__C_STAT__BC_PERR (0x01)
+#define EV6__C_STAT__DC_PERR (0x02)
+#define EV6__C_STAT__DSTREAM_MEM_ERR (0x03)
+#define EV6__C_STAT__DSTREAM_BC_ERR (0x04)
+#define EV6__C_STAT__DSTREAM_DC_ERR (0x05)
+#define EV6__C_STAT__PROBE_BC_ERR0 (0x06) /* both 6 and 7 indicate... */
+#define EV6__C_STAT__PROBE_BC_ERR1 (0x07) /* ...probe bc error. */
+#define EV6__C_STAT__ISTREAM_MEM_ERR (0x0B)
+#define EV6__C_STAT__ISTREAM_BC_ERR (0x0C)
+#define EV6__C_STAT__DSTREAM_MEM_DBL (0x13)
+#define EV6__C_STAT__DSTREAM_BC_DBL (0x14)
+#define EV6__C_STAT__ISTREAM_MEM_DBL (0x1B)
+#define EV6__C_STAT__ISTREAM_BC_DBL (0x1C)
+#define EV6__C_STAT__SOURCE_MEMORY (0x03)
+#define EV6__C_STAT__SOURCE_BCACHE (0x04)
+#define EV6__C_STAT__SOURCE__S (0)
+#define EV6__C_STAT__SOURCE__M (0x07)
+#define EV6__C_STAT__ISTREAM__S (3)
+#define EV6__C_STAT__ISTREAM__M (0x01)
+#define EV6__C_STAT__DOUBLE__S (4)
+#define EV6__C_STAT__DOUBLE__M (0x01)
+#define EV6__C_STAT__ERRMASK (0x1F)
+#define EV6__C_STS__SHARED (1 << 0)
+#define EV6__C_STS__DIRTY (1 << 1)
+#define EV6__C_STS__VALID (1 << 2)
+#define EV6__C_STS__PARITY (1 << 3)
+
+ if (!(c_stat & EV6__C_STAT__ERRMASK))
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+ if (!print)
+ return status;
+
+ source = EXTRACT(c_stat, EV6__C_STAT__SOURCE);
+ stream = EXTRACT(c_stat, EV6__C_STAT__ISTREAM);
+ bits = EXTRACT(c_stat, EV6__C_STAT__DOUBLE);
+
+ if (c_stat & EV6__C_STAT__BC_PERR) {
+ printk("%s Bcache tag parity error\n", err_print_prefix);
+ source = -1;
+ }
+
+ if (c_stat & EV6__C_STAT__DC_PERR) {
+ printk("%s Dcache tag parity error\n", err_print_prefix);
+ source = -1;
+ }
+
+ if (c_stat == EV6__C_STAT__PROBE_BC_ERR0 ||
+ c_stat == EV6__C_STAT__PROBE_BC_ERR1) {
+ printk("%s Bcache single-bit error on a probe hit\n",
+ err_print_prefix);
+ source = -1;
+ }
+
+ if (source != -1)
+ printk("%s %s-STREAM %s-BIT ECC error from %s\n",
+ err_print_prefix,
+ streamname[stream], bitsname[bits], sourcename[source]);
+
+ printk("%s Address: 0x%016lx\n"
+ " Syndrome[upper.lower]: %02lx.%02lx\n",
+ err_print_prefix,
+ c_addr,
+ c2_syn, c1_syn);
+
+ if (source == EV6__C_STAT__SOURCE_MEMORY ||
+ source == EV6__C_STAT__SOURCE_BCACHE)
+ printk("%s Block status: %s%s%s%s\n",
+ err_print_prefix,
+ (c_sts & EV6__C_STS__SHARED) ? "SHARED " : "",
+ (c_sts & EV6__C_STS__DIRTY) ? "DIRTY " : "",
+ (c_sts & EV6__C_STS__VALID) ? "VALID " : "",
+ (c_sts & EV6__C_STS__PARITY) ? "PARITY " : "");
+
+ return status;
+}
+
+void
+ev6_register_error_handlers(void)
+{
+ /* None right now. */
+}
+
+int
+ev6_process_logout_frame(struct el_common *mchk_header, int print)
+{
+ struct el_common_EV6_mcheck *ev6mchk =
+ (struct el_common_EV6_mcheck *)mchk_header;
+ int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+ status |= ev6_parse_ibox(ev6mchk->I_STAT, print);
+ status |= ev6_parse_mbox(ev6mchk->MM_STAT, ev6mchk->DC_STAT,
+ ev6mchk->C_STAT, print);
+ status |= ev6_parse_cbox(ev6mchk->C_ADDR, ev6mchk->DC1_SYNDROME,
+ ev6mchk->DC0_SYNDROME, ev6mchk->C_STAT,
+ ev6mchk->C_STS, print);
+
+ if (!print)
+ return status;
+
+ if (status != MCHK_DISPOSITION_DISMISS) {
+ char *saved_err_prefix = err_print_prefix;
+
+ /*
+ * Dump some additional information from the frame
+ */
+ printk("%s EXC_ADDR: 0x%016lx IER_CM: 0x%016lx"
+ " ISUM: 0x%016lx\n"
+ " PAL_BASE: 0x%016lx I_CTL: 0x%016lx"
+ " PCTX: 0x%016lx\n",
+ err_print_prefix,
+ ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM,
+ ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX);
+
+ if (status == MCHK_DISPOSITION_UNKNOWN_ERROR) {
+ printk("%s UNKNOWN error, frame follows:\n",
+ err_print_prefix);
+ } else {
+ /* had decode -- downgrade print level for frame */
+ err_print_prefix = KERN_NOTICE;
+ }
+
+ mchk_dump_logout_frame(mchk_header);
+
+ err_print_prefix = saved_err_prefix;
+ }
+
+ return status;
+}
+
+void
+ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+ struct el_common *mchk_header = (struct el_common *)la_ptr;
+
+ /*
+ * Sync the processor
+ */
+ mb();
+ draina();
+
+ /*
+ * Parse the logout frame without printing first. If the only error(s)
+ * found are have a disposition of "dismiss", then just dismiss them
+ * and don't print any message
+ */
+ if (ev6_process_logout_frame(mchk_header, 0) !=
+ MCHK_DISPOSITION_DISMISS) {
+ char *saved_err_prefix = err_print_prefix;
+ err_print_prefix = KERN_CRIT;
+
+ /*
+ * Either a nondismissable error was detected or no
+ * recognized error was detected in the logout frame
+ * -- report the error in either case
+ */
+ printk("%s*CPU %s Error (Vector 0x%x) reported on CPU %d:\n",
+ err_print_prefix,
+ (vector == SCB_Q_PROCERR)?"Correctable":"Uncorrectable",
+ (unsigned int)vector, (int)smp_processor_id());
+
+ ev6_process_logout_frame(mchk_header, 1);
+ dik_show_regs(regs, NULL);
+
+ err_print_prefix = saved_err_prefix;
+ }
+
+ /*
+ * Release the logout frame
+ */
+ wrmces(0x7);
+ mb();
+}
+
diff --git a/arch/alpha/kernel/err_ev7.c b/arch/alpha/kernel/err_ev7.c
new file mode 100644
index 000000000000..bf52ba691957
--- /dev/null
+++ b/arch/alpha/kernel/err_ev7.c
@@ -0,0 +1,289 @@
+/*
+ * linux/arch/alpha/kernel/err_ev7.c
+ *
+ * Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ * Error handling code supporting Alpha systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+#include <asm/err_common.h>
+#include <asm/err_ev7.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+struct ev7_lf_subpackets *
+ev7_collect_logout_frame_subpackets(struct el_subpacket *el_ptr,
+ struct ev7_lf_subpackets *lf_subpackets)
+{
+ struct el_subpacket *subpacket;
+ int i;
+
+ /*
+ * A Marvel machine check frame is always packaged in an
+ * el_subpacket of class HEADER, type LOGOUT_FRAME.
+ */
+ if (el_ptr->class != EL_CLASS__HEADER ||
+ el_ptr->type != EL_TYPE__HEADER__LOGOUT_FRAME)
+ return NULL;
+
+ /*
+ * It is a logout frame header. Look at the one subpacket.
+ */
+ el_ptr = (struct el_subpacket *)
+ ((unsigned long)el_ptr + el_ptr->length);
+
+ /*
+ * It has to be class PAL, type LOGOUT_FRAME.
+ */
+ if (el_ptr->class != EL_CLASS__PAL ||
+ el_ptr->type != EL_TYPE__PAL__LOGOUT_FRAME)
+ return NULL;
+
+ lf_subpackets->logout = (struct ev7_pal_logout_subpacket *)
+ el_ptr->by_type.raw.data_start;
+
+ /*
+ * Process the subpackets.
+ */
+ subpacket = (struct el_subpacket *)
+ ((unsigned long)el_ptr + el_ptr->length);
+ for (i = 0;
+ subpacket && i < lf_subpackets->logout->subpacket_count;
+ subpacket = (struct el_subpacket *)
+ ((unsigned long)subpacket + subpacket->length), i++) {
+ /*
+ * All subpackets should be class PAL.
+ */
+ if (subpacket->class != EL_CLASS__PAL) {
+ printk("%s**UNEXPECTED SUBPACKET CLASS %d "
+ "IN LOGOUT FRAME (packet %d\n",
+ err_print_prefix, subpacket->class, i);
+ return NULL;
+ }
+
+ /*
+ * Remember the subpacket.
+ */
+ switch(subpacket->type) {
+ case EL_TYPE__PAL__EV7_PROCESSOR:
+ lf_subpackets->ev7 =
+ (struct ev7_pal_processor_subpacket *)
+ subpacket->by_type.raw.data_start;
+ break;
+
+ case EL_TYPE__PAL__EV7_RBOX:
+ lf_subpackets->rbox = (struct ev7_pal_rbox_subpacket *)
+ subpacket->by_type.raw.data_start;
+ break;
+
+ case EL_TYPE__PAL__EV7_ZBOX:
+ lf_subpackets->zbox = (struct ev7_pal_zbox_subpacket *)
+ subpacket->by_type.raw.data_start;
+ break;
+
+ case EL_TYPE__PAL__EV7_IO:
+ lf_subpackets->io = (struct ev7_pal_io_subpacket *)
+ subpacket->by_type.raw.data_start;
+ break;
+
+ case EL_TYPE__PAL__ENV__AMBIENT_TEMPERATURE:
+ case EL_TYPE__PAL__ENV__AIRMOVER_FAN:
+ case EL_TYPE__PAL__ENV__VOLTAGE:
+ case EL_TYPE__PAL__ENV__INTRUSION:
+ case EL_TYPE__PAL__ENV__POWER_SUPPLY:
+ case EL_TYPE__PAL__ENV__LAN:
+ case EL_TYPE__PAL__ENV__HOT_PLUG:
+ lf_subpackets->env[ev7_lf_env_index(subpacket->type)] =
+ (struct ev7_pal_environmental_subpacket *)
+ subpacket->by_type.raw.data_start;
+ break;
+
+ default:
+ /*
+ * Don't know what kind of frame this is.
+ */
+ return NULL;
+ }
+ }
+
+ return lf_subpackets;
+}
+
+void
+ev7_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+ struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
+ char *saved_err_prefix = err_print_prefix;
+
+ /*
+ * Sync the processor
+ */
+ mb();
+ draina();
+
+ err_print_prefix = KERN_CRIT;
+ printk("%s*CPU %s Error (Vector 0x%x) reported on CPU %d\n",
+ err_print_prefix,
+ (vector == SCB_Q_PROCERR) ? "Correctable" : "Uncorrectable",
+ (unsigned int)vector, (int)smp_processor_id());
+ el_process_subpacket(el_ptr);
+ err_print_prefix = saved_err_prefix;
+
+ /*
+ * Release the logout frame
+ */
+ wrmces(0x7);
+ mb();
+}
+
+static char *el_ev7_processor_subpacket_annotation[] = {
+ "Subpacket Header", "I_STAT", "DC_STAT",
+ "C_ADDR", "C_SYNDROME_1", "C_SYNDROME_0",
+ "C_STAT", "C_STS", "MM_STAT",
+ "EXC_ADDR", "IER_CM", "ISUM",
+ "PAL_BASE", "I_CTL", "PROCESS_CONTEXT",
+ "CBOX_CTL", "CBOX_STP_CTL", "CBOX_ACC_CTL",
+ "CBOX_LCL_SET", "CBOX_GLB_SET", "BBOX_CTL",
+ "BBOX_ERR_STS", "BBOX_ERR_IDX", "CBOX_DDP_ERR_STS",
+ "BBOX_DAT_RMP", NULL
+};
+
+static char *el_ev7_zbox_subpacket_annotation[] = {
+ "Subpacket Header",
+ "ZBOX(0): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
+ "ZBOX(0): DRAM_ERROR_CTL / DRAM_ERR_STATUS_3",
+ "ZBOX(0): DIFT_TIMEOUT / DRAM_ERR_ADR",
+ "ZBOX(0): FRC_ERR_ADR / DRAM_MAPPER_CTL",
+ "ZBOX(0): reserved / DIFT_ERR_STATUS",
+ "ZBOX(1): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
+ "ZBOX(1): DRAM_ERROR_CTL / DRAM_ERR_STATUS_3",
+ "ZBOX(1): DIFT_TIMEOUT / DRAM_ERR_ADR",
+ "ZBOX(1): FRC_ERR_ADR / DRAM_MAPPER_CTL",
+ "ZBOX(1): reserved / DIFT_ERR_STATUS",
+ "CBOX_CTL", "CBOX_STP_CTL",
+ "ZBOX(0)_ERROR_PA", "ZBOX(1)_ERROR_PA",
+ "ZBOX(0)_ORED_SYNDROME","ZBOX(1)_ORED_SYNDROME",
+ NULL
+};
+
+static char *el_ev7_rbox_subpacket_annotation[] = {
+ "Subpacket Header", "RBOX_CFG", "RBOX_N_CFG",
+ "RBOX_S_CFG", "RBOX_E_CFG", "RBOX_W_CFG",
+ "RBOX_N_ERR", "RBOX_S_ERR", "RBOX_E_ERR",
+ "RBOX_W_ERR", "RBOX_IO_CFG", "RBOX_IO_ERR",
+ "RBOX_L_ERR", "RBOX_WHOAMI", "RBOX_IMASL",
+ "RBOX_INTQ", "RBOX_INT", NULL
+};
+
+static char *el_ev7_io_subpacket_annotation[] = {
+ "Subpacket Header", "IO_ASIC_REV", "IO_SYS_REV",
+ "IO7_UPH", "HPI_CTL", "CRD_CTL",
+ "HEI_CTL", "PO7_ERROR_SUM","PO7_UNCRR_SYM",
+ "PO7_CRRCT_SYM", "PO7_UGBGE_SYM","PO7_ERR_PKT0",
+ "PO7_ERR_PKT1", "reserved", "reserved",
+ "PO0_ERR_SUM", "PO0_TLB_ERR", "PO0_SPL_COMPLT",
+ "PO0_TRANS_SUM", "PO0_FIRST_ERR","PO0_MULT_ERR",
+ "DM CSR PH", "DM CSR PH", "DM CSR PH",
+ "DM CSR PH", "reserved",
+ "PO1_ERR_SUM", "PO1_TLB_ERR", "PO1_SPL_COMPLT",
+ "PO1_TRANS_SUM", "PO1_FIRST_ERR","PO1_MULT_ERR",
+ "DM CSR PH", "DM CSR PH", "DM CSR PH",
+ "DM CSR PH", "reserved",
+ "PO2_ERR_SUM", "PO2_TLB_ERR", "PO2_SPL_COMPLT",
+ "PO2_TRANS_SUM", "PO2_FIRST_ERR","PO2_MULT_ERR",
+ "DM CSR PH", "DM CSR PH", "DM CSR PH",
+ "DM CSR PH", "reserved",
+ "PO3_ERR_SUM", "PO3_TLB_ERR", "PO3_SPL_COMPLT",
+ "PO3_TRANS_SUM", "PO3_FIRST_ERR","PO3_MULT_ERR",
+ "DM CSR PH", "DM CSR PH", "DM CSR PH",
+ "DM CSR PH", "reserved",
+ NULL
+};
+
+static struct el_subpacket_annotation el_ev7_pal_annotations[] = {
+ SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+ EL_TYPE__PAL__EV7_PROCESSOR,
+ 1,
+ "EV7 Processor Subpacket",
+ el_ev7_processor_subpacket_annotation),
+ SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+ EL_TYPE__PAL__EV7_ZBOX,
+ 1,
+ "EV7 ZBOX Subpacket",
+ el_ev7_zbox_subpacket_annotation),
+ SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+ EL_TYPE__PAL__EV7_RBOX,
+ 1,
+ "EV7 RBOX Subpacket",
+ el_ev7_rbox_subpacket_annotation),
+ SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+ EL_TYPE__PAL__EV7_IO,
+ 1,
+ "EV7 IO Subpacket",
+ el_ev7_io_subpacket_annotation)
+};
+
+static struct el_subpacket *
+ev7_process_pal_subpacket(struct el_subpacket *header)
+{
+ struct ev7_pal_subpacket *packet;
+
+ if (header->class != EL_CLASS__PAL) {
+ printk("%s ** Unexpected header CLASS %d TYPE %d, aborting\n",
+ err_print_prefix,
+ header->class, header->type);
+ return NULL;
+ }
+
+ packet = (struct ev7_pal_subpacket *)header->by_type.raw.data_start;
+
+ switch(header->type) {
+ case EL_TYPE__PAL__LOGOUT_FRAME:
+ printk("%s*** MCHK occurred on LPID %ld (RBOX %lx)\n",
+ err_print_prefix,
+ packet->by_type.logout.whami,
+ packet->by_type.logout.rbox_whami);
+ el_print_timestamp(&packet->by_type.logout.timestamp);
+ printk("%s EXC_ADDR: %016lx\n"
+ " HALT_CODE: %lx\n",
+ err_print_prefix,
+ packet->by_type.logout.exc_addr,
+ packet->by_type.logout.halt_code);
+ el_process_subpackets(header,
+ packet->by_type.logout.subpacket_count);
+ break;
+ default:
+ printk("%s ** PAL TYPE %d SUBPACKET\n",
+ err_print_prefix,
+ header->type);
+ el_annotate_subpacket(header);
+ break;
+ }
+
+ return (struct el_subpacket *)((unsigned long)header + header->length);
+}
+
+struct el_subpacket_handler ev7_pal_subpacket_handler =
+ SUBPACKET_HANDLER_INIT(EL_CLASS__PAL, ev7_process_pal_subpacket);
+
+void
+ev7_register_error_handlers(void)
+{
+ int i;
+
+ for(i = 0;
+ i<sizeof(el_ev7_pal_annotations)/sizeof(el_ev7_pal_annotations[1]);
+ i++) {
+ cdl_register_subpacket_annotation(&el_ev7_pal_annotations[i]);
+ }
+ cdl_register_subpacket_handler(&ev7_pal_subpacket_handler);
+}
+
diff --git a/arch/alpha/kernel/err_impl.h b/arch/alpha/kernel/err_impl.h
new file mode 100644
index 000000000000..64e9b73809fa
--- /dev/null
+++ b/arch/alpha/kernel/err_impl.h
@@ -0,0 +1,85 @@
+/*
+ * linux/arch/alpha/kernel/err_impl.h
+ *
+ * Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ * Contains declarations and macros to support Alpha error handling
+ * implementations.
+ */
+
+union el_timestamp;
+struct el_subpacket;
+struct ev7_lf_subpackets;
+
+struct el_subpacket_annotation {
+ struct el_subpacket_annotation *next;
+ u16 class;
+ u16 type;
+ u16 revision;
+ char *description;
+ char **annotation;
+};
+#define SUBPACKET_ANNOTATION(c, t, r, d, a) {NULL, (c), (t), (r), (d), (a)}
+
+struct el_subpacket_handler {
+ struct el_subpacket_handler *next;
+ u16 class;
+ struct el_subpacket *(*handler)(struct el_subpacket *);
+};
+#define SUBPACKET_HANDLER_INIT(c, h) {NULL, (c), (h)}
+
+/*
+ * Manipulate a field from a register given it's name. defines
+ * for the LSB (__S - shift count) and bitmask (__M) are required
+ *
+ * EXTRACT(u, f) - extracts the field and places it at bit position 0
+ * GEN_MASK(f) - creates an in-position mask for the field
+ */
+#define EXTRACT(u, f) (((u) >> f##__S) & f##__M)
+#define GEN_MASK(f) ((u64)f##__M << f##__S)
+
+/*
+ * err_common.c
+ */
+extern char *err_print_prefix;
+
+extern void mchk_dump_mem(void *, size_t, char **);
+extern void mchk_dump_logout_frame(struct el_common *);
+extern void el_print_timestamp(union el_timestamp *);
+extern void el_process_subpackets(struct el_subpacket *, int);
+extern struct el_subpacket *el_process_subpacket(struct el_subpacket *);
+extern void el_annotate_subpacket(struct el_subpacket *);
+extern void cdl_check_console_data_log(void);
+extern int cdl_register_subpacket_annotation(struct el_subpacket_annotation *);
+extern int cdl_register_subpacket_handler(struct el_subpacket_handler *);
+
+/*
+ * err_ev7.c
+ */
+extern struct ev7_lf_subpackets *
+ev7_collect_logout_frame_subpackets(struct el_subpacket *,
+ struct ev7_lf_subpackets *);
+extern void ev7_register_error_handlers(void);
+extern void ev7_machine_check(u64, u64, struct pt_regs *);
+
+/*
+ * err_ev6.c
+ */
+extern void ev6_register_error_handlers(void);
+extern int ev6_process_logout_frame(struct el_common *, int);
+extern void ev6_machine_check(u64, u64, struct pt_regs *);
+
+/*
+ * err_marvel.c
+ */
+extern void marvel_machine_check(u64, u64, struct pt_regs *);
+extern void marvel_register_error_handlers(void);
+
+/*
+ * err_titan.c
+ */
+extern int titan_process_logout_frame(struct el_common *, int);
+extern void titan_machine_check(u64, u64, struct pt_regs *);
+extern void titan_register_error_handlers(void);
+extern int privateer_process_logout_frame(struct el_common *, int);
+extern void privateer_machine_check(u64, u64, struct pt_regs *);
diff --git a/arch/alpha/kernel/err_marvel.c b/arch/alpha/kernel/err_marvel.c
new file mode 100644
index 000000000000..70b38b1d2af3
--- /dev/null
+++ b/arch/alpha/kernel/err_marvel.c
@@ -0,0 +1,1159 @@
+/*
+ * linux/arch/alpha/kernel/err_marvel.c
+ *
+ * Copyright (C) 2001 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/console.h>
+#include <asm/core_marvel.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+#include <asm/err_common.h>
+#include <asm/err_ev7.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+static void
+marvel_print_680_frame(struct ev7_lf_subpackets *lf_subpackets)
+{
+#ifdef CONFIG_VERBOSE_MCHECK
+ struct ev7_pal_environmental_subpacket *env;
+ struct { int type; char *name; } ev_packets[] = {
+ { EL_TYPE__PAL__ENV__AMBIENT_TEMPERATURE,
+ "Ambient Temperature" },
+ { EL_TYPE__PAL__ENV__AIRMOVER_FAN,
+ "AirMover / Fan" },
+ { EL_TYPE__PAL__ENV__VOLTAGE,
+ "Voltage" },
+ { EL_TYPE__PAL__ENV__INTRUSION,
+ "Intrusion" },
+ { EL_TYPE__PAL__ENV__POWER_SUPPLY,
+ "Power Supply" },
+ { EL_TYPE__PAL__ENV__LAN,
+ "LAN" },
+ { EL_TYPE__PAL__ENV__HOT_PLUG,
+ "Hot Plug" },
+ { 0, NULL }
+ };
+ int i;
+
+ for (i = 0; ev_packets[i].type != 0; i++) {
+ env = lf_subpackets->env[ev7_lf_env_index(ev_packets[i].type)];
+ if (!env)
+ continue;
+
+ printk("%s**%s event (cabinet %d, drawer %d)\n",
+ err_print_prefix,
+ ev_packets[i].name,
+ env->cabinet,
+ env->drawer);
+ printk("%s Module Type: 0x%x - Unit ID 0x%x - "
+ "Condition 0x%x\n",
+ err_print_prefix,
+ env->module_type,
+ env->unit_id,
+ env->condition);
+ }
+#endif /* CONFIG_VERBOSE_MCHECK */
+}
+
+static int
+marvel_process_680_frame(struct ev7_lf_subpackets *lf_subpackets, int print)
+{
+ int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+ int i;
+
+ for (i = ev7_lf_env_index(EL_TYPE__PAL__ENV__AMBIENT_TEMPERATURE);
+ i <= ev7_lf_env_index(EL_TYPE__PAL__ENV__HOT_PLUG);
+ i++) {
+ if (lf_subpackets->env[i])
+ status = MCHK_DISPOSITION_REPORT;
+ }
+
+ if (print)
+ marvel_print_680_frame(lf_subpackets);
+
+ return status;
+}
+
+#ifdef CONFIG_VERBOSE_MCHECK
+
+static void
+marvel_print_err_cyc(u64 err_cyc)
+{
+ static char *packet_desc[] = {
+ "No Error",
+ "UNKNOWN",
+ "1 cycle (1 or 2 flit packet)",
+ "2 cycles (3 flit packet)",
+ "9 cycles (18 flit packet)",
+ "10 cycles (19 flit packet)",
+ "UNKNOWN",
+ "UNKNOWN",
+ "UNKNOWN"
+ };
+
+#define IO7__ERR_CYC__ODD_FLT (1UL << 0)
+#define IO7__ERR_CYC__EVN_FLT (1UL << 1)
+#define IO7__ERR_CYC__PACKET__S (6)
+#define IO7__ERR_CYC__PACKET__M (0x7)
+#define IO7__ERR_CYC__LOC (1UL << 5)
+#define IO7__ERR_CYC__CYCLE__S (2)
+#define IO7__ERR_CYC__CYCLE__M (0x7)
+
+ printk("%s Packet In Error: %s\n"
+ "%s Error in %s, cycle %ld%s%s\n",
+ err_print_prefix,
+ packet_desc[EXTRACT(err_cyc, IO7__ERR_CYC__PACKET)],
+ err_print_prefix,
+ (err_cyc & IO7__ERR_CYC__LOC) ? "DATA" : "HEADER",
+ EXTRACT(err_cyc, IO7__ERR_CYC__CYCLE),
+ (err_cyc & IO7__ERR_CYC__ODD_FLT) ? " [ODD Flit]": "",
+ (err_cyc & IO7__ERR_CYC__EVN_FLT) ? " [Even Flit]": "");
+}
+
+static void
+marvel_print_po7_crrct_sym(u64 crrct_sym)
+{
+#define IO7__PO7_CRRCT_SYM__SYN__S (0)
+#define IO7__PO7_CRRCT_SYM__SYN__M (0x7f)
+#define IO7__PO7_CRRCT_SYM__ERR_CYC__S (7) /* ERR_CYC + ODD_FLT + EVN_FLT */
+#define IO7__PO7_CRRCT_SYM__ERR_CYC__M (0x1ff)
+
+
+ printk("%s Correctable Error Symptoms:\n"
+ "%s Syndrome: 0x%lx\n",
+ err_print_prefix,
+ err_print_prefix, EXTRACT(crrct_sym, IO7__PO7_CRRCT_SYM__SYN));
+ marvel_print_err_cyc(EXTRACT(crrct_sym, IO7__PO7_CRRCT_SYM__ERR_CYC));
+}
+
+static void
+marvel_print_po7_uncrr_sym(u64 uncrr_sym, u64 valid_mask)
+{
+ static char *clk_names[] = { "_h[0]", "_h[1]", "_n[0]", "_n[1]" };
+ static char *clk_decode[] = {
+ "No Error",
+ "One extra rising edge",
+ "Two extra rising edges",
+ "Lost one clock"
+ };
+ static char *port_names[] = { "Port 0", "Port 1",
+ "Port 2", "Port 3",
+ "Unknown Port", "Unknown Port",
+ "Unknown Port", "Port 7" };
+ int scratch, i;
+
+#define IO7__PO7_UNCRR_SYM__SYN__S (0)
+#define IO7__PO7_UNCRR_SYM__SYN__M (0x7f)
+#define IO7__PO7_UNCRR_SYM__ERR_CYC__S (7) /* ERR_CYC + ODD_FLT... */
+#define IO7__PO7_UNCRR_SYM__ERR_CYC__M (0x1ff) /* ... + EVN_FLT */
+#define IO7__PO7_UNCRR_SYM__CLK__S (16)
+#define IO7__PO7_UNCRR_SYM__CLK__M (0xff)
+#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__REQ (1UL << 24)
+#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__RIO (1UL << 25)
+#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__WIO (1UL << 26)
+#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__BLK (1UL << 27)
+#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__NBK (1UL << 28)
+#define IO7__PO7_UNCRR_SYM__OVF__READIO (1UL << 29)
+#define IO7__PO7_UNCRR_SYM__OVF__WRITEIO (1UL << 30)
+#define IO7__PO7_UNCRR_SYM__OVF__FWD (1UL << 31)
+#define IO7__PO7_UNCRR_SYM__VICTIM_SP__S (32)
+#define IO7__PO7_UNCRR_SYM__VICTIM_SP__M (0xff)
+#define IO7__PO7_UNCRR_SYM__DETECT_SP__S (40)
+#define IO7__PO7_UNCRR_SYM__DETECT_SP__M (0xff)
+#define IO7__PO7_UNCRR_SYM__STRV_VTR__S (48)
+#define IO7__PO7_UNCRR_SYM__STRV_VTR__M (0x3ff)
+
+#define IO7__STRV_VTR__LSI__INTX__S (0)
+#define IO7__STRV_VTR__LSI__INTX__M (0x3)
+#define IO7__STRV_VTR__LSI__SLOT__S (2)
+#define IO7__STRV_VTR__LSI__SLOT__M (0x7)
+#define IO7__STRV_VTR__LSI__BUS__S (5)
+#define IO7__STRV_VTR__LSI__BUS__M (0x3)
+#define IO7__STRV_VTR__MSI__INTNUM__S (0)
+#define IO7__STRV_VTR__MSI__INTNUM__M (0x1ff)
+#define IO7__STRV_VTR__IS_MSI (1UL << 9)
+
+ printk("%s Uncorrectable Error Symptoms:\n", err_print_prefix);
+ uncrr_sym &= valid_mask;
+
+ if (EXTRACT(valid_mask, IO7__PO7_UNCRR_SYM__SYN))
+ printk("%s Syndrome: 0x%lx\n",
+ err_print_prefix,
+ EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__SYN));
+
+ if (EXTRACT(valid_mask, IO7__PO7_UNCRR_SYM__ERR_CYC))
+ marvel_print_err_cyc(EXTRACT(uncrr_sym,
+ IO7__PO7_UNCRR_SYM__ERR_CYC));
+
+ scratch = EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__CLK);
+ for (i = 0; i < 4; i++, scratch >>= 2) {
+ if (scratch & 0x3)
+ printk("%s Clock %s: %s\n",
+ err_print_prefix,
+ clk_names[i], clk_decode[scratch & 0x3]);
+ }
+
+ if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__REQ)
+ printk("%s REQ Credit Timeout or Overflow\n",
+ err_print_prefix);
+ if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__RIO)
+ printk("%s RIO Credit Timeout or Overflow\n",
+ err_print_prefix);
+ if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__WIO)
+ printk("%s WIO Credit Timeout or Overflow\n",
+ err_print_prefix);
+ if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__BLK)
+ printk("%s BLK Credit Timeout or Overflow\n",
+ err_print_prefix);
+ if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__NBK)
+ printk("%s NBK Credit Timeout or Overflow\n",
+ err_print_prefix);
+
+ if (uncrr_sym & IO7__PO7_UNCRR_SYM__OVF__READIO)
+ printk("%s Read I/O Buffer Overflow\n",
+ err_print_prefix);
+ if (uncrr_sym & IO7__PO7_UNCRR_SYM__OVF__WRITEIO)
+ printk("%s Write I/O Buffer Overflow\n",
+ err_print_prefix);
+ if (uncrr_sym & IO7__PO7_UNCRR_SYM__OVF__FWD)
+ printk("%s FWD Buffer Overflow\n",
+ err_print_prefix);
+
+ if ((scratch = EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__VICTIM_SP))) {
+ int lost = scratch & (1UL << 4);
+ scratch &= ~lost;
+ for (i = 0; i < 8; i++, scratch >>= 1) {
+ if (!(scratch & 1))
+ continue;
+ printk("%s Error Response sent to %s",
+ err_print_prefix, port_names[i]);
+ }
+ if (lost)
+ printk("%s Lost Error sent somewhere else\n",
+ err_print_prefix);
+ }
+
+ if ((scratch = EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__DETECT_SP))) {
+ for (i = 0; i < 8; i++, scratch >>= 1) {
+ if (!(scratch & 1))
+ continue;
+ printk("%s Error Reported by %s",
+ err_print_prefix, port_names[i]);
+ }
+ }
+
+ if (EXTRACT(valid_mask, IO7__PO7_UNCRR_SYM__STRV_VTR)) {
+ char starvation_message[80];
+
+ scratch = EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__STRV_VTR);
+ if (scratch & IO7__STRV_VTR__IS_MSI)
+ sprintf(starvation_message,
+ "MSI Interrupt 0x%x",
+ EXTRACT(scratch, IO7__STRV_VTR__MSI__INTNUM));
+ else
+ sprintf(starvation_message,
+ "LSI INT%c for Bus:Slot (%d:%d)\n",
+ 'A' + EXTRACT(scratch,
+ IO7__STRV_VTR__LSI__INTX),
+ EXTRACT(scratch, IO7__STRV_VTR__LSI__BUS),
+ EXTRACT(scratch, IO7__STRV_VTR__LSI__SLOT));
+
+ printk("%s Starvation Int Trigger By: %s\n",
+ err_print_prefix, starvation_message);
+ }
+}
+
+static void
+marvel_print_po7_ugbge_sym(u64 ugbge_sym)
+{
+ char opcode_str[10];
+
+#define IO7__PO7_UGBGE_SYM__UPH_PKT_OFF__S (6)
+#define IO7__PO7_UGBGE_SYM__UPH_PKT_OFF__M (0xfffffffful)
+#define IO7__PO7_UGBGE_SYM__UPH_OPCODE__S (40)
+#define IO7__PO7_UGBGE_SYM__UPH_OPCODE__M (0xff)
+#define IO7__PO7_UGBGE_SYM__UPH_SRC_PORT__S (48)
+#define IO7__PO7_UGBGE_SYM__UPH_SRC_PORT__M (0xf)
+#define IO7__PO7_UGBGE_SYM__UPH_DEST_PID__S (52)
+#define IO7__PO7_UGBGE_SYM__UPH_DEST_PID__M (0x7ff)
+#define IO7__PO7_UGBGE_SYM__VALID (1UL << 63)
+
+ if (!(ugbge_sym & IO7__PO7_UGBGE_SYM__VALID))
+ return;
+
+ switch(EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE)) {
+ case 0x51:
+ sprintf(opcode_str, "Wr32");
+ break;
+ case 0x50:
+ sprintf(opcode_str, "WrQW");
+ break;
+ case 0x54:
+ sprintf(opcode_str, "WrIPR");
+ break;
+ case 0xD8:
+ sprintf(opcode_str, "Victim");
+ break;
+ case 0xC5:
+ sprintf(opcode_str, "BlkIO");
+ break;
+ default:
+ sprintf(opcode_str, "0x%lx\n",
+ EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE));
+ break;
+ }
+
+ printk("%s Up Hose Garbage Symptom:\n"
+ "%s Source Port: %ld - Dest PID: %ld - OpCode: %s\n",
+ err_print_prefix,
+ err_print_prefix,
+ EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_SRC_PORT),
+ EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_DEST_PID),
+ opcode_str);
+
+ if (0xC5 != EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE))
+ printk("%s Packet Offset 0x%08lx\n",
+ err_print_prefix,
+ EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_PKT_OFF));
+}
+
+static void
+marvel_print_po7_err_sum(struct ev7_pal_io_subpacket *io)
+{
+ u64 uncrr_sym_valid = 0;
+
+#define IO7__PO7_ERRSUM__CR_SBE (1UL << 32)
+#define IO7__PO7_ERRSUM__CR_SBE2 (1UL << 33)
+#define IO7__PO7_ERRSUM__CR_PIO_WBYTE (1UL << 34)
+#define IO7__PO7_ERRSUM__CR_CSR_NXM (1UL << 35)
+#define IO7__PO7_ERRSUM__CR_RPID_ACV (1UL << 36)
+#define IO7__PO7_ERRSUM__CR_RSP_NXM (1UL << 37)
+#define IO7__PO7_ERRSUM__CR_ERR_RESP (1UL << 38)
+#define IO7__PO7_ERRSUM__CR_CLK_DERR (1UL << 39)
+#define IO7__PO7_ERRSUM__CR_DAT_DBE (1UL << 40)
+#define IO7__PO7_ERRSUM__CR_DAT_GRBG (1UL << 41)
+#define IO7__PO7_ERRSUM__MAF_TO (1UL << 42)
+#define IO7__PO7_ERRSUM__UGBGE (1UL << 43)
+#define IO7__PO7_ERRSUM__UN_MAF_LOST (1UL << 44)
+#define IO7__PO7_ERRSUM__UN_PKT_OVF (1UL << 45)
+#define IO7__PO7_ERRSUM__UN_CDT_OVF (1UL << 46)
+#define IO7__PO7_ERRSUM__UN_DEALLOC (1UL << 47)
+#define IO7__PO7_ERRSUM__BH_CDT_TO (1UL << 51)
+#define IO7__PO7_ERRSUM__BH_CLK_HDR (1UL << 52)
+#define IO7__PO7_ERRSUM__BH_DBE_HDR (1UL << 53)
+#define IO7__PO7_ERRSUM__BH_GBG_HDR (1UL << 54)
+#define IO7__PO7_ERRSUM__BH_BAD_CMD (1UL << 55)
+#define IO7__PO7_ERRSUM__HLT_INT (1UL << 56)
+#define IO7__PO7_ERRSUM__HP_INT (1UL << 57)
+#define IO7__PO7_ERRSUM__CRD_INT (1UL << 58)
+#define IO7__PO7_ERRSUM__STV_INT (1UL << 59)
+#define IO7__PO7_ERRSUM__HRD_INT (1UL << 60)
+#define IO7__PO7_ERRSUM__BH_SUM (1UL << 61)
+#define IO7__PO7_ERRSUM__ERR_LST (1UL << 62)
+#define IO7__PO7_ERRSUM__ERR_VALID (1UL << 63)
+
+#define IO7__PO7_ERRSUM__ERR_MASK (IO7__PO7_ERRSUM__ERR_VALID | \
+ IO7__PO7_ERRSUM__CR_SBE)
+
+ /*
+ * Single bit errors aren't covered by ERR_VALID.
+ */
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_SBE) {
+ printk("%s %sSingle Bit Error(s) detected/corrected\n",
+ err_print_prefix,
+ (io->po7_error_sum & IO7__PO7_ERRSUM__CR_SBE2)
+ ? "Multiple " : "");
+ marvel_print_po7_crrct_sym(io->po7_crrct_sym);
+ }
+
+ /*
+ * Neither are the interrupt status bits
+ */
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__HLT_INT)
+ printk("%s Halt Interrupt posted", err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__HP_INT) {
+ printk("%s Hot Plug Event Interrupt posted",
+ err_print_prefix);
+ uncrr_sym_valid |= GEN_MASK(IO7__PO7_UNCRR_SYM__DETECT_SP);
+ }
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CRD_INT)
+ printk("%s Correctable Error Interrupt posted",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__STV_INT) {
+ printk("%s Starvation Interrupt posted", err_print_prefix);
+ uncrr_sym_valid |= GEN_MASK(IO7__PO7_UNCRR_SYM__STRV_VTR);
+ }
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__HRD_INT) {
+ printk("%s Hard Error Interrupt posted", err_print_prefix);
+ uncrr_sym_valid |= GEN_MASK(IO7__PO7_UNCRR_SYM__DETECT_SP);
+ }
+
+ /*
+ * Everything else is valid only with ERR_VALID, so skip to the end
+ * (uncrr_sym check) unless ERR_VALID is set.
+ */
+ if (!(io->po7_error_sum & IO7__PO7_ERRSUM__ERR_VALID))
+ goto check_uncrr_sym;
+
+ /*
+ * Since ERR_VALID is set, VICTIM_SP in uncrr_sym is valid.
+ * For bits [29:0] to also be valid, the following bits must
+ * not be set:
+ * CR_PIO_WBYTE CR_CSR_NXM CR_RSP_NXM
+ * CR_ERR_RESP MAF_TO
+ */
+ uncrr_sym_valid |= GEN_MASK(IO7__PO7_UNCRR_SYM__VICTIM_SP);
+ if (!(io->po7_error_sum & (IO7__PO7_ERRSUM__CR_PIO_WBYTE |
+ IO7__PO7_ERRSUM__CR_CSR_NXM |
+ IO7__PO7_ERRSUM__CR_RSP_NXM |
+ IO7__PO7_ERRSUM__CR_ERR_RESP |
+ IO7__PO7_ERRSUM__MAF_TO)))
+ uncrr_sym_valid |= 0x3ffffffful;
+
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_PIO_WBYTE)
+ printk("%s Write byte into IO7 CSR\n", err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_CSR_NXM)
+ printk("%s PIO to non-existent CSR\n", err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_RPID_ACV)
+ printk("%s Bus Requester PID (Access Violation)\n",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_RSP_NXM)
+ printk("%s Received NXM response from EV7\n",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_ERR_RESP)
+ printk("%s Received ERROR RESPONSE\n", err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_CLK_DERR)
+ printk("%s Clock error on data flit\n", err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_DAT_DBE)
+ printk("%s Double Bit Error Data Error Detected\n",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_DAT_GRBG)
+ printk("%s Garbage Encoding Detected on the data\n",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__UGBGE) {
+ printk("%s Garbage Encoding sent up hose\n",
+ err_print_prefix);
+ marvel_print_po7_ugbge_sym(io->po7_ugbge_sym);
+ }
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__UN_MAF_LOST)
+ printk("%s Orphan response (unexpected response)\n",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__UN_PKT_OVF)
+ printk("%s Down hose packet overflow\n", err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__UN_CDT_OVF)
+ printk("%s Down hose credit overflow\n", err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__UN_DEALLOC)
+ printk("%s Unexpected or bad dealloc field\n",
+ err_print_prefix);
+
+ /*
+ * The black hole events.
+ */
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__MAF_TO)
+ printk("%s BLACK HOLE: Timeout for all responses\n",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_CDT_TO)
+ printk("%s BLACK HOLE: Credit Timeout\n", err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_CLK_HDR)
+ printk("%s BLACK HOLE: Clock check on header\n",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_DBE_HDR)
+ printk("%s BLACK HOLE: Uncorrectable Error on header\n",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_GBG_HDR)
+ printk("%s BLACK HOLE: Garbage on header\n",
+ err_print_prefix);
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_BAD_CMD)
+ printk("%s BLACK HOLE: Bad EV7 command\n",
+ err_print_prefix);
+
+ if (io->po7_error_sum & IO7__PO7_ERRSUM__ERR_LST)
+ printk("%s Lost Error\n", err_print_prefix);
+
+ printk("%s Failing Packet:\n"
+ "%s Cycle 1: %016lx\n"
+ "%s Cycle 2: %016lx\n",
+ err_print_prefix,
+ err_print_prefix, io->po7_err_pkt0,
+ err_print_prefix, io->po7_err_pkt1);
+ /*
+ * If there are any valid bits in UNCRR sym for this err,
+ * print UNCRR_SYM as well.
+ */
+check_uncrr_sym:
+ if (uncrr_sym_valid)
+ marvel_print_po7_uncrr_sym(io->po7_uncrr_sym, uncrr_sym_valid);
+}
+
+static void
+marvel_print_pox_tlb_err(u64 tlb_err)
+{
+ static char *tlb_errors[] = {
+ "No Error",
+ "North Port Signaled Error fetching TLB entry",
+ "PTE invalid or UCC or GBG error on this entry",
+ "Address did not hit any DMA window"
+ };
+
+#define IO7__POX_TLBERR__ERR_VALID (1UL << 63)
+#define IO7__POX_TLBERR__ERRCODE__S (0)
+#define IO7__POX_TLBERR__ERRCODE__M (0x3)
+#define IO7__POX_TLBERR__ERR_TLB_PTR__S (3)
+#define IO7__POX_TLBERR__ERR_TLB_PTR__M (0x7)
+#define IO7__POX_TLBERR__FADDR__S (6)
+#define IO7__POX_TLBERR__FADDR__M (0x3fffffffffful)
+
+ if (!(tlb_err & IO7__POX_TLBERR__ERR_VALID))
+ return;
+
+ printk("%s TLB Error on index 0x%lx:\n"
+ "%s - %s\n"
+ "%s - Addr: 0x%016lx\n",
+ err_print_prefix,
+ EXTRACT(tlb_err, IO7__POX_TLBERR__ERR_TLB_PTR),
+ err_print_prefix,
+ tlb_errors[EXTRACT(tlb_err, IO7__POX_TLBERR__ERRCODE)],
+ err_print_prefix,
+ EXTRACT(tlb_err, IO7__POX_TLBERR__FADDR) << 6);
+}
+
+static void
+marvel_print_pox_spl_cmplt(u64 spl_cmplt)
+{
+ char message[80];
+
+#define IO7__POX_SPLCMPLT__MESSAGE__S (0)
+#define IO7__POX_SPLCMPLT__MESSAGE__M (0x0fffffffful)
+#define IO7__POX_SPLCMPLT__SOURCE_BUS__S (40)
+#define IO7__POX_SPLCMPLT__SOURCE_BUS__M (0xfful)
+#define IO7__POX_SPLCMPLT__SOURCE_DEV__S (35)
+#define IO7__POX_SPLCMPLT__SOURCE_DEV__M (0x1ful)
+#define IO7__POX_SPLCMPLT__SOURCE_FUNC__S (32)
+#define IO7__POX_SPLCMPLT__SOURCE_FUNC__M (0x07ul)
+
+#define IO7__POX_SPLCMPLT__MSG_CLASS__S (28)
+#define IO7__POX_SPLCMPLT__MSG_CLASS__M (0xf)
+#define IO7__POX_SPLCMPLT__MSG_INDEX__S (20)
+#define IO7__POX_SPLCMPLT__MSG_INDEX__M (0xff)
+#define IO7__POX_SPLCMPLT__MSG_CLASSINDEX__S (20)
+#define IO7__POX_SPLCMPLT__MSG_CLASSINDEX__M (0xfff)
+#define IO7__POX_SPLCMPLT__REM_LOWER_ADDR__S (12)
+#define IO7__POX_SPLCMPLT__REM_LOWER_ADDR__M (0x7f)
+#define IO7__POX_SPLCMPLT__REM_BYTE_COUNT__S (0)
+#define IO7__POX_SPLCMPLT__REM_BYTE_COUNT__M (0xfff)
+
+ printk("%s Split Completion Error:\n"
+ "%s Source (Bus:Dev:Func): %ld:%ld:%ld\n",
+ err_print_prefix,
+ err_print_prefix,
+ EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__SOURCE_BUS),
+ EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__SOURCE_DEV),
+ EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__SOURCE_FUNC));
+
+ switch(EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__MSG_CLASSINDEX)) {
+ case 0x000:
+ sprintf(message, "Normal completion");
+ break;
+ case 0x100:
+ sprintf(message, "Bridge - Master Abort");
+ break;
+ case 0x101:
+ sprintf(message, "Bridge - Target Abort");
+ break;
+ case 0x102:
+ sprintf(message, "Bridge - Uncorrectable Write Data Error");
+ break;
+ case 0x200:
+ sprintf(message, "Byte Count Out of Range");
+ break;
+ case 0x201:
+ sprintf(message, "Uncorrectable Split Write Data Error");
+ break;
+ default:
+ sprintf(message, "%08lx\n",
+ EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__MESSAGE));
+ break;
+ }
+ printk("%s Message: %s\n", err_print_prefix, message);
+}
+
+static void
+marvel_print_pox_trans_sum(u64 trans_sum)
+{
+ char *pcix_cmd[] = { "Interrupt Acknowledge",
+ "Special Cycle",
+ "I/O Read",
+ "I/O Write",
+ "Reserved",
+ "Reserved / Device ID Message",
+ "Memory Read",
+ "Memory Write",
+ "Reserved / Alias to Memory Read Block",
+ "Reserved / Alias to Memory Write Block",
+ "Configuration Read",
+ "Configuration Write",
+ "Memory Read Multiple / Split Completion",
+ "Dual Address Cycle",
+ "Memory Read Line / Memory Read Block",
+ "Memory Write and Invalidate / Memory Write Block"
+ };
+
+#define IO7__POX_TRANSUM__PCI_ADDR__S (0)
+#define IO7__POX_TRANSUM__PCI_ADDR__M (0x3fffffffffffful)
+#define IO7__POX_TRANSUM__DAC (1UL << 50)
+#define IO7__POX_TRANSUM__PCIX_MASTER_SLOT__S (52)
+#define IO7__POX_TRANSUM__PCIX_MASTER_SLOT__M (0xf)
+#define IO7__POX_TRANSUM__PCIX_CMD__S (56)
+#define IO7__POX_TRANSUM__PCIX_CMD__M (0xf)
+#define IO7__POX_TRANSUM__ERR_VALID (1UL << 63)
+
+ if (!(trans_sum & IO7__POX_TRANSUM__ERR_VALID))
+ return;
+
+ printk("%s Transaction Summary:\n"
+ "%s Command: 0x%lx - %s\n"
+ "%s Address: 0x%016lx%s\n"
+ "%s PCI-X Master Slot: 0x%lx\n",
+ err_print_prefix,
+ err_print_prefix,
+ EXTRACT(trans_sum, IO7__POX_TRANSUM__PCIX_CMD),
+ pcix_cmd[EXTRACT(trans_sum, IO7__POX_TRANSUM__PCIX_CMD)],
+ err_print_prefix,
+ EXTRACT(trans_sum, IO7__POX_TRANSUM__PCI_ADDR),
+ (trans_sum & IO7__POX_TRANSUM__DAC) ? " (DAC)" : "",
+ err_print_prefix,
+ EXTRACT(trans_sum, IO7__POX_TRANSUM__PCIX_MASTER_SLOT));
+}
+
+static void
+marvel_print_pox_err(u64 err_sum, struct ev7_pal_io_one_port *port)
+{
+#define IO7__POX_ERRSUM__AGP_REQQ_OVFL (1UL << 4)
+#define IO7__POX_ERRSUM__AGP_SYNC_ERR (1UL << 5)
+#define IO7__POX_ERRSUM__MRETRY_TO (1UL << 6)
+#define IO7__POX_ERRSUM__PCIX_UX_SPL (1UL << 7)
+#define IO7__POX_ERRSUM__PCIX_SPLIT_TO (1UL << 8)
+#define IO7__POX_ERRSUM__PCIX_DISCARD_SPL (1UL << 9)
+#define IO7__POX_ERRSUM__DMA_RD_TO (1UL << 10)
+#define IO7__POX_ERRSUM__CSR_NXM_RD (1UL << 11)
+#define IO7__POX_ERRSUM__CSR_NXM_WR (1UL << 12)
+#define IO7__POX_ERRSUM__DMA_TO (1UL << 13)
+#define IO7__POX_ERRSUM__ALL_MABORTS (1UL << 14)
+#define IO7__POX_ERRSUM__MABORT (1UL << 15)
+#define IO7__POX_ERRSUM__MABORT_MASK (IO7__POX_ERRSUM__ALL_MABORTS|\
+ IO7__POX_ERRSUM__MABORT)
+#define IO7__POX_ERRSUM__PT_TABORT (1UL << 16)
+#define IO7__POX_ERRSUM__PM_TABORT (1UL << 17)
+#define IO7__POX_ERRSUM__TABORT_MASK (IO7__POX_ERRSUM__PT_TABORT | \
+ IO7__POX_ERRSUM__PM_TABORT)
+#define IO7__POX_ERRSUM__SERR (1UL << 18)
+#define IO7__POX_ERRSUM__ADDRERR_STB (1UL << 19)
+#define IO7__POX_ERRSUM__DETECTED_SERR (1UL << 20)
+#define IO7__POX_ERRSUM__PERR (1UL << 21)
+#define IO7__POX_ERRSUM__DATAERR_STB_NIOW (1UL << 22)
+#define IO7__POX_ERRSUM__DETECTED_PERR (1UL << 23)
+#define IO7__POX_ERRSUM__PM_PERR (1UL << 24)
+#define IO7__POX_ERRSUM__PT_SCERROR (1UL << 26)
+#define IO7__POX_ERRSUM__HUNG_BUS (1UL << 28)
+#define IO7__POX_ERRSUM__UPE_ERROR__S (51)
+#define IO7__POX_ERRSUM__UPE_ERROR__M (0xffUL)
+#define IO7__POX_ERRSUM__UPE_ERROR GEN_MASK(IO7__POX_ERRSUM__UPE_ERROR)
+#define IO7__POX_ERRSUM__TLB_ERR (1UL << 59)
+#define IO7__POX_ERRSUM__ERR_VALID (1UL << 63)
+
+#define IO7__POX_ERRSUM__TRANS_SUM__MASK (IO7__POX_ERRSUM__MRETRY_TO | \
+ IO7__POX_ERRSUM__PCIX_UX_SPL | \
+ IO7__POX_ERRSUM__PCIX_SPLIT_TO | \
+ IO7__POX_ERRSUM__DMA_TO | \
+ IO7__POX_ERRSUM__MABORT_MASK | \
+ IO7__POX_ERRSUM__TABORT_MASK | \
+ IO7__POX_ERRSUM__SERR | \
+ IO7__POX_ERRSUM__ADDRERR_STB | \
+ IO7__POX_ERRSUM__PERR | \
+ IO7__POX_ERRSUM__DATAERR_STB_NIOW |\
+ IO7__POX_ERRSUM__DETECTED_PERR | \
+ IO7__POX_ERRSUM__PM_PERR | \
+ IO7__POX_ERRSUM__PT_SCERROR | \
+ IO7__POX_ERRSUM__UPE_ERROR)
+
+ if (!(err_sum & IO7__POX_ERRSUM__ERR_VALID))
+ return;
+
+ /*
+ * First the transaction summary errors
+ */
+ if (err_sum & IO7__POX_ERRSUM__MRETRY_TO)
+ printk("%s IO7 Master Retry Timeout expired\n",
+ err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__PCIX_UX_SPL)
+ printk("%s Unexpected Split Completion\n",
+ err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__PCIX_SPLIT_TO)
+ printk("%s IO7 Split Completion Timeout expired\n",
+ err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__DMA_TO)
+ printk("%s Hung bus during DMA transaction\n",
+ err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__MABORT_MASK)
+ printk("%s Master Abort\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__PT_TABORT)
+ printk("%s IO7 Asserted Target Abort\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__PM_TABORT)
+ printk("%s IO7 Received Target Abort\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__ADDRERR_STB) {
+ printk("%s Address or PCI-X Attribute Parity Error\n",
+ err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__SERR)
+ printk("%s IO7 Asserted SERR\n", err_print_prefix);
+ }
+ if (err_sum & IO7__POX_ERRSUM__PERR) {
+ if (err_sum & IO7__POX_ERRSUM__DATAERR_STB_NIOW)
+ printk("%s IO7 Detected Data Parity Error\n",
+ err_print_prefix);
+ else
+ printk("%s Split Completion Response with "
+ "Parity Error\n", err_print_prefix);
+ }
+ if (err_sum & IO7__POX_ERRSUM__DETECTED_PERR)
+ printk("%s PERR detected\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__PM_PERR)
+ printk("%s PERR while IO7 is master\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__PT_SCERROR) {
+ printk("%s IO7 Received Split Completion Error message\n",
+ err_print_prefix);
+ marvel_print_pox_spl_cmplt(port->pox_spl_cmplt);
+ }
+ if (err_sum & IO7__POX_ERRSUM__UPE_ERROR) {
+ unsigned int upe_error = EXTRACT(err_sum,
+ IO7__POX_ERRSUM__UPE_ERROR);
+ int i;
+ static char *upe_errors[] = {
+ "Parity Error on MSI write data",
+ "MSI read (MSI window is write only",
+ "TLB - Invalid WR transaction",
+ "TLB - Invalid RD transaction",
+ "DMA - WR error (see north port)",
+ "DMA - RD error (see north port)",
+ "PPR - WR error (see north port)",
+ "PPR - RD error (see north port)"
+ };
+
+ printk("%s UPE Error:\n", err_print_prefix);
+ for (i = 0; i < 8; i++) {
+ if (upe_error & (1 << i))
+ printk("%s %s\n", err_print_prefix,
+ upe_errors[i]);
+ }
+ }
+
+ /*
+ * POx_TRANS_SUM, if appropriate.
+ */
+ if (err_sum & IO7__POX_ERRSUM__TRANS_SUM__MASK)
+ marvel_print_pox_trans_sum(port->pox_trans_sum);
+
+ /*
+ * Then TLB_ERR.
+ */
+ if (err_sum & IO7__POX_ERRSUM__TLB_ERR) {
+ printk("%s TLB ERROR\n", err_print_prefix);
+ marvel_print_pox_tlb_err(port->pox_tlb_err);
+ }
+
+ /*
+ * And the single bit status errors.
+ */
+ if (err_sum & IO7__POX_ERRSUM__AGP_REQQ_OVFL)
+ printk("%s AGP Request Queue Overflow\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__AGP_SYNC_ERR)
+ printk("%s AGP Sync Error\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__PCIX_DISCARD_SPL)
+ printk("%s Discarded split completion\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__DMA_RD_TO)
+ printk("%s DMA Read Timeout\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__CSR_NXM_RD)
+ printk("%s CSR NXM READ\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__CSR_NXM_WR)
+ printk("%s CSR NXM WRITE\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__DETECTED_SERR)
+ printk("%s SERR detected\n", err_print_prefix);
+ if (err_sum & IO7__POX_ERRSUM__HUNG_BUS)
+ printk("%s HUNG BUS detected\n", err_print_prefix);
+}
+
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+static struct ev7_pal_io_subpacket *
+marvel_find_io7_with_error(struct ev7_lf_subpackets *lf_subpackets)
+{
+ struct ev7_pal_io_subpacket *io = lf_subpackets->io;
+ struct io7 *io7;
+ int i;
+
+ /*
+ * Caller must provide the packet to fill
+ */
+ if (!io)
+ return NULL;
+
+ /*
+ * Fill the subpacket with the console's standard fill pattern
+ */
+ memset(io, 0x55, sizeof(*io));
+
+ for (io7 = NULL; NULL != (io7 = marvel_next_io7(io7)); ) {
+ unsigned long err_sum = 0;
+
+ err_sum |= io7->csrs->PO7_ERROR_SUM.csr;
+ for (i = 0; i < IO7_NUM_PORTS; i++) {
+ if (!io7->ports[i].enabled)
+ continue;
+ err_sum |= io7->ports[i].csrs->POx_ERR_SUM.csr;
+ }
+
+ /*
+ * Is there at least one error?
+ */
+ if (err_sum & (1UL << 63))
+ break;
+ }
+
+ /*
+ * Did we find an IO7 with an error?
+ */
+ if (!io7)
+ return NULL;
+
+ /*
+ * We have an IO7 with an error.
+ *
+ * Fill in the IO subpacket.
+ */
+ io->io_asic_rev = io7->csrs->IO_ASIC_REV.csr;
+ io->io_sys_rev = io7->csrs->IO_SYS_REV.csr;
+ io->io7_uph = io7->csrs->IO7_UPH.csr;
+ io->hpi_ctl = io7->csrs->HPI_CTL.csr;
+ io->crd_ctl = io7->csrs->CRD_CTL.csr;
+ io->hei_ctl = io7->csrs->HEI_CTL.csr;
+ io->po7_error_sum = io7->csrs->PO7_ERROR_SUM.csr;
+ io->po7_uncrr_sym = io7->csrs->PO7_UNCRR_SYM.csr;
+ io->po7_crrct_sym = io7->csrs->PO7_CRRCT_SYM.csr;
+ io->po7_ugbge_sym = io7->csrs->PO7_UGBGE_SYM.csr;
+ io->po7_err_pkt0 = io7->csrs->PO7_ERR_PKT[0].csr;
+ io->po7_err_pkt1 = io7->csrs->PO7_ERR_PKT[1].csr;
+
+ for (i = 0; i < IO7_NUM_PORTS; i++) {
+ io7_ioport_csrs *csrs = io7->ports[i].csrs;
+
+ if (!io7->ports[i].enabled)
+ continue;
+
+ io->ports[i].pox_err_sum = csrs->POx_ERR_SUM.csr;
+ io->ports[i].pox_tlb_err = csrs->POx_TLB_ERR.csr;
+ io->ports[i].pox_spl_cmplt = csrs->POx_SPL_COMPLT.csr;
+ io->ports[i].pox_trans_sum = csrs->POx_TRANS_SUM.csr;
+ io->ports[i].pox_first_err = csrs->POx_FIRST_ERR.csr;
+ io->ports[i].pox_mult_err = csrs->POx_MULT_ERR.csr;
+ io->ports[i].pox_dm_source = csrs->POx_DM_SOURCE.csr;
+ io->ports[i].pox_dm_dest = csrs->POx_DM_DEST.csr;
+ io->ports[i].pox_dm_size = csrs->POx_DM_SIZE.csr;
+ io->ports[i].pox_dm_ctrl = csrs->POx_DM_CTRL.csr;
+
+ /*
+ * Ack this port's errors, if any. POx_ERR_SUM must be last.
+ *
+ * Most of the error registers get cleared and unlocked when
+ * the associated bits in POx_ERR_SUM are cleared (by writing
+ * 1). POx_TLB_ERR is an exception and must be explicitly
+ * cleared.
+ */
+ csrs->POx_TLB_ERR.csr = io->ports[i].pox_tlb_err;
+ csrs->POx_ERR_SUM.csr = io->ports[i].pox_err_sum;
+ mb();
+ csrs->POx_ERR_SUM.csr;
+ }
+
+ /*
+ * Ack any port 7 error(s).
+ */
+ io7->csrs->PO7_ERROR_SUM.csr = io->po7_error_sum;
+ mb();
+ io7->csrs->PO7_ERROR_SUM.csr;
+
+ /*
+ * Correct the io7_pid.
+ */
+ lf_subpackets->io_pid = io7->pe;
+
+ return io;
+}
+
+static int
+marvel_process_io_error(struct ev7_lf_subpackets *lf_subpackets, int print)
+{
+ int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ struct ev7_pal_io_subpacket *io = lf_subpackets->io;
+ int i;
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define MARVEL_IO_ERR_VALID(x) ((x) & (1UL << 63))
+
+ if (!lf_subpackets->logout || !lf_subpackets->io)
+ return status;
+
+ /*
+ * The PALcode only builds an IO subpacket if there is a
+ * locally connected IO7. In the cases of
+ * 1) a uniprocessor kernel
+ * 2) an mp kernel before the local secondary has called in
+ * error interrupts are all directed to the primary processor.
+ * In that case, we may not have an IO subpacket at all and, event
+ * if we do, it may not be the right now.
+ *
+ * If the RBOX indicates an I/O error interrupt, make sure we have
+ * the correct IO7 information. If we don't have an IO subpacket
+ * or it's the wrong one, try to find the right one.
+ *
+ * RBOX I/O error interrupts are indicated by RBOX_INT<29> and
+ * RBOX_INT<10>.
+ */
+ if ((lf_subpackets->io->po7_error_sum & (1UL << 32)) ||
+ ((lf_subpackets->io->po7_error_sum |
+ lf_subpackets->io->ports[0].pox_err_sum |
+ lf_subpackets->io->ports[1].pox_err_sum |
+ lf_subpackets->io->ports[2].pox_err_sum |
+ lf_subpackets->io->ports[3].pox_err_sum) & (1UL << 63))) {
+ /*
+ * Either we have no IO subpacket or no error is
+ * indicated in the one we do have. Try find the
+ * one with the error.
+ */
+ if (!marvel_find_io7_with_error(lf_subpackets))
+ return status;
+ }
+
+ /*
+ * We have an IO7 indicating an error - we're going to report it
+ */
+ status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+
+ if (!print)
+ return status;
+
+ printk("%s*Error occurred on IO7 at PID %u\n",
+ err_print_prefix, lf_subpackets->io_pid);
+
+ /*
+ * Check port 7 first
+ */
+ if (lf_subpackets->io->po7_error_sum & IO7__PO7_ERRSUM__ERR_MASK) {
+ marvel_print_po7_err_sum(io);
+
+#if 0
+ printk("%s PORT 7 ERROR:\n"
+ "%s PO7_ERROR_SUM: %016lx\n"
+ "%s PO7_UNCRR_SYM: %016lx\n"
+ "%s PO7_CRRCT_SYM: %016lx\n"
+ "%s PO7_UGBGE_SYM: %016lx\n"
+ "%s PO7_ERR_PKT0: %016lx\n"
+ "%s PO7_ERR_PKT1: %016lx\n",
+ err_print_prefix,
+ err_print_prefix, io->po7_error_sum,
+ err_print_prefix, io->po7_uncrr_sym,
+ err_print_prefix, io->po7_crrct_sym,
+ err_print_prefix, io->po7_ugbge_sym,
+ err_print_prefix, io->po7_err_pkt0,
+ err_print_prefix, io->po7_err_pkt1);
+#endif
+ }
+
+ /*
+ * Then loop through the ports
+ */
+ for (i = 0; i < IO7_NUM_PORTS; i++) {
+ if (!MARVEL_IO_ERR_VALID(io->ports[i].pox_err_sum))
+ continue;
+
+ printk("%s PID %u PORT %d POx_ERR_SUM: %016lx\n",
+ err_print_prefix,
+ lf_subpackets->io_pid, i, io->ports[i].pox_err_sum);
+ marvel_print_pox_err(io->ports[i].pox_err_sum, &io->ports[i]);
+
+ printk("%s [ POx_FIRST_ERR: %016lx ]\n",
+ err_print_prefix, io->ports[i].pox_first_err);
+ marvel_print_pox_err(io->ports[i].pox_first_err,
+ &io->ports[i]);
+
+ }
+
+
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+ return status;
+}
+
+static int
+marvel_process_logout_frame(struct ev7_lf_subpackets *lf_subpackets, int print)
+{
+ int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+ /*
+ * I/O error?
+ */
+#define EV7__RBOX_INT__IO_ERROR__MASK 0x20000400ul
+ if (lf_subpackets->logout &&
+ (lf_subpackets->logout->rbox_int & 0x20000400ul))
+ status = marvel_process_io_error(lf_subpackets, print);
+
+ /*
+ * Probing behind PCI-X bridges can cause machine checks on
+ * Marvel when the probe is handled by the bridge as a split
+ * completion transaction. The symptom is an ERROR_RESPONSE
+ * to a CONFIG address. Since these errors will happen in
+ * normal operation, dismiss them.
+ *
+ * Dismiss if:
+ * C_STAT = 0x14 (Error Reponse)
+ * C_STS<3> = 0 (C_ADDR valid)
+ * C_ADDR<42> = 1 (I/O)
+ * C_ADDR<31:22> = 111110xxb (PCI Config space)
+ */
+ if (lf_subpackets->ev7 &&
+ (lf_subpackets->ev7->c_stat == 0x14) &&
+ !(lf_subpackets->ev7->c_sts & 0x8) &&
+ ((lf_subpackets->ev7->c_addr & 0x400ff000000ul)
+ == 0x400fe000000ul))
+ status = MCHK_DISPOSITION_DISMISS;
+
+ return status;
+}
+
+void
+marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+ struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
+ int (*process_frame)(struct ev7_lf_subpackets *, int) = NULL;
+ struct ev7_lf_subpackets subpacket_collection = { NULL, };
+ struct ev7_pal_io_subpacket scratch_io_packet = { 0, };
+ struct ev7_lf_subpackets *lf_subpackets = NULL;
+ int disposition = MCHK_DISPOSITION_UNKNOWN_ERROR;
+ char *saved_err_prefix = err_print_prefix;
+ char *error_type = NULL;
+
+ /*
+ * Sync the processor
+ */
+ mb();
+ draina();
+
+ switch(vector) {
+ case SCB_Q_SYSEVENT:
+ process_frame = marvel_process_680_frame;
+ error_type = "System Event";
+ break;
+
+ case SCB_Q_SYSMCHK:
+ process_frame = marvel_process_logout_frame;
+ error_type = "System Uncorrectable Error";
+ break;
+
+ case SCB_Q_SYSERR:
+ process_frame = marvel_process_logout_frame;
+ error_type = "System Correctable Error";
+ break;
+
+ default:
+ /* Don't know it - pass it up. */
+ ev7_machine_check(vector, la_ptr, regs);
+ return;
+ }
+
+ /*
+ * A system event or error has occured, handle it here.
+ *
+ * Any errors in the logout frame have already been cleared by the
+ * PALcode, so just parse it.
+ */
+ err_print_prefix = KERN_CRIT;
+
+ /*
+ * Parse the logout frame without printing first. If the only error(s)
+ * found are classified as "dismissable", then just dismiss them and
+ * don't print any message
+ */
+ lf_subpackets =
+ ev7_collect_logout_frame_subpackets(el_ptr,
+ &subpacket_collection);
+ if (process_frame && lf_subpackets && lf_subpackets->logout) {
+ /*
+ * We might not have the correct (or any) I/O subpacket.
+ * [ See marvel_process_io_error() for explanation. ]
+ * If we don't have one, point the io subpacket in
+ * lf_subpackets at scratch_io_packet so that
+ * marvel_find_io7_with_error() will have someplace to
+ * store the info.
+ */
+ if (!lf_subpackets->io)
+ lf_subpackets->io = &scratch_io_packet;
+
+ /*
+ * Default io_pid to the processor reporting the error
+ * [this will get changed in marvel_find_io7_with_error()
+ * if a different one is needed]
+ */
+ lf_subpackets->io_pid = lf_subpackets->logout->whami;
+
+ /*
+ * Evaluate the frames.
+ */
+ disposition = process_frame(lf_subpackets, 0);
+ }
+ switch(disposition) {
+ case MCHK_DISPOSITION_DISMISS:
+ /* Nothing to do. */
+ break;
+
+ case MCHK_DISPOSITION_REPORT:
+ /* Recognized error, report it. */
+ printk("%s*%s (Vector 0x%x) reported on CPU %d\n",
+ err_print_prefix, error_type,
+ (unsigned int)vector, (int)smp_processor_id());
+ el_print_timestamp(&lf_subpackets->logout->timestamp);
+ process_frame(lf_subpackets, 1);
+ break;
+
+ default:
+ /* Unknown - dump the annotated subpackets. */
+ printk("%s*%s (Vector 0x%x) reported on CPU %d\n",
+ err_print_prefix, error_type,
+ (unsigned int)vector, (int)smp_processor_id());
+ el_process_subpacket(el_ptr);
+ break;
+
+ }
+
+ err_print_prefix = saved_err_prefix;
+
+ /* Release the logout frame. */
+ wrmces(0x7);
+ mb();
+}
+
+void
+marvel_register_error_handlers(void)
+{
+ ev7_register_error_handlers();
+}
diff --git a/arch/alpha/kernel/err_titan.c b/arch/alpha/kernel/err_titan.c
new file mode 100644
index 000000000000..7e6720d45f02
--- /dev/null
+++ b/arch/alpha/kernel/err_titan.c
@@ -0,0 +1,756 @@
+/*
+ * linux/arch/alpha/kernel/err_titan.c
+ *
+ * Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ * Error handling code supporting TITAN systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/core_titan.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+#include <asm/err_common.h>
+#include <asm/err_ev6.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+
+static int
+titan_parse_c_misc(u64 c_misc, int print)
+{
+#ifdef CONFIG_VERBOSE_MCHECK
+ char *src;
+ int nxs = 0;
+#endif
+ int status = MCHK_DISPOSITION_REPORT;
+
+#define TITAN__CCHIP_MISC__NXM (1UL << 28)
+#define TITAN__CCHIP_MISC__NXS__S (29)
+#define TITAN__CCHIP_MISC__NXS__M (0x7)
+
+ if (!(c_misc & TITAN__CCHIP_MISC__NXM))
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (!print)
+ return status;
+
+ nxs = EXTRACT(c_misc, TITAN__CCHIP_MISC__NXS);
+ switch(nxs) {
+ case 0: /* CPU 0 */
+ case 1: /* CPU 1 */
+ case 2: /* CPU 2 */
+ case 3: /* CPU 3 */
+ src = "CPU";
+ /* num is already the CPU number */
+ break;
+ case 4: /* Pchip 0 */
+ case 5: /* Pchip 1 */
+ src = "Pchip";
+ nxs -= 4;
+ break;
+ default:/* reserved */
+ src = "Unknown, NXS =";
+ /* leave num untouched */
+ break;
+ }
+
+ printk("%s Non-existent memory access from: %s %d\n",
+ err_print_prefix, src, nxs);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+ return status;
+}
+
+static int
+titan_parse_p_serror(int which, u64 serror, int print)
+{
+ int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ char *serror_src[] = {"GPCI", "APCI", "AGP HP", "AGP LP"};
+ char *serror_cmd[] = {"DMA Read", "DMA RMW", "SGTE Read", "Reserved"};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_SERROR__LOST_UECC (1UL << 0)
+#define TITAN__PCHIP_SERROR__UECC (1UL << 1)
+#define TITAN__PCHIP_SERROR__CRE (1UL << 2)
+#define TITAN__PCHIP_SERROR__NXIO (1UL << 3)
+#define TITAN__PCHIP_SERROR__LOST_CRE (1UL << 4)
+#define TITAN__PCHIP_SERROR__ECCMASK (TITAN__PCHIP_SERROR__UECC | \
+ TITAN__PCHIP_SERROR__CRE)
+#define TITAN__PCHIP_SERROR__ERRMASK (TITAN__PCHIP_SERROR__LOST_UECC | \
+ TITAN__PCHIP_SERROR__UECC | \
+ TITAN__PCHIP_SERROR__CRE | \
+ TITAN__PCHIP_SERROR__NXIO | \
+ TITAN__PCHIP_SERROR__LOST_CRE)
+#define TITAN__PCHIP_SERROR__SRC__S (52)
+#define TITAN__PCHIP_SERROR__SRC__M (0x3)
+#define TITAN__PCHIP_SERROR__CMD__S (54)
+#define TITAN__PCHIP_SERROR__CMD__M (0x3)
+#define TITAN__PCHIP_SERROR__SYN__S (56)
+#define TITAN__PCHIP_SERROR__SYN__M (0xff)
+#define TITAN__PCHIP_SERROR__ADDR__S (15)
+#define TITAN__PCHIP_SERROR__ADDR__M (0xffffffffUL)
+
+ if (!(serror & TITAN__PCHIP_SERROR__ERRMASK))
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (!print)
+ return status;
+
+ printk("%s PChip %d SERROR: %016lx\n",
+ err_print_prefix, which, serror);
+ if (serror & TITAN__PCHIP_SERROR__ECCMASK) {
+ printk("%s %sorrectable ECC Error:\n"
+ " Source: %-6s Command: %-8s Syndrome: 0x%08x\n"
+ " Address: 0x%lx\n",
+ err_print_prefix,
+ (serror & TITAN__PCHIP_SERROR__UECC) ? "Unc" : "C",
+ serror_src[EXTRACT(serror, TITAN__PCHIP_SERROR__SRC)],
+ serror_cmd[EXTRACT(serror, TITAN__PCHIP_SERROR__CMD)],
+ (unsigned)EXTRACT(serror, TITAN__PCHIP_SERROR__SYN),
+ EXTRACT(serror, TITAN__PCHIP_SERROR__ADDR));
+ }
+ if (serror & TITAN__PCHIP_SERROR__NXIO)
+ printk("%s Non Existent I/O Error\n", err_print_prefix);
+ if (serror & TITAN__PCHIP_SERROR__LOST_UECC)
+ printk("%s Lost Uncorrectable ECC Error\n",
+ err_print_prefix);
+ if (serror & TITAN__PCHIP_SERROR__LOST_CRE)
+ printk("%s Lost Correctable ECC Error\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+ return status;
+}
+
+static int
+titan_parse_p_perror(int which, int port, u64 perror, int print)
+{
+ int cmd;
+ unsigned long addr;
+ int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ char *perror_cmd[] = { "Interrupt Acknowledge", "Special Cycle",
+ "I/O Read", "I/O Write",
+ "Reserved", "Reserved",
+ "Memory Read", "Memory Write",
+ "Reserved", "Reserved",
+ "Configuration Read", "Configuration Write",
+ "Memory Read Multiple", "Dual Address Cycle",
+ "Memory Read Line","Memory Write and Invalidate"
+ };
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_PERROR__LOST (1UL << 0)
+#define TITAN__PCHIP_PERROR__SERR (1UL << 1)
+#define TITAN__PCHIP_PERROR__PERR (1UL << 2)
+#define TITAN__PCHIP_PERROR__DCRTO (1UL << 3)
+#define TITAN__PCHIP_PERROR__SGE (1UL << 4)
+#define TITAN__PCHIP_PERROR__APE (1UL << 5)
+#define TITAN__PCHIP_PERROR__TA (1UL << 6)
+#define TITAN__PCHIP_PERROR__DPE (1UL << 7)
+#define TITAN__PCHIP_PERROR__NDS (1UL << 8)
+#define TITAN__PCHIP_PERROR__IPTPR (1UL << 9)
+#define TITAN__PCHIP_PERROR__IPTPW (1UL << 10)
+#define TITAN__PCHIP_PERROR__ERRMASK (TITAN__PCHIP_PERROR__LOST | \
+ TITAN__PCHIP_PERROR__SERR | \
+ TITAN__PCHIP_PERROR__PERR | \
+ TITAN__PCHIP_PERROR__DCRTO | \
+ TITAN__PCHIP_PERROR__SGE | \
+ TITAN__PCHIP_PERROR__APE | \
+ TITAN__PCHIP_PERROR__TA | \
+ TITAN__PCHIP_PERROR__DPE | \
+ TITAN__PCHIP_PERROR__NDS | \
+ TITAN__PCHIP_PERROR__IPTPR | \
+ TITAN__PCHIP_PERROR__IPTPW)
+#define TITAN__PCHIP_PERROR__DAC (1UL << 47)
+#define TITAN__PCHIP_PERROR__MWIN (1UL << 48)
+#define TITAN__PCHIP_PERROR__CMD__S (52)
+#define TITAN__PCHIP_PERROR__CMD__M (0x0f)
+#define TITAN__PCHIP_PERROR__ADDR__S (14)
+#define TITAN__PCHIP_PERROR__ADDR__M (0x1fffffffful)
+
+ if (!(perror & TITAN__PCHIP_PERROR__ERRMASK))
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+ cmd = EXTRACT(perror, TITAN__PCHIP_PERROR__CMD);
+ addr = EXTRACT(perror, TITAN__PCHIP_PERROR__ADDR) << 2;
+
+ /*
+ * Initializing the BIOS on a video card on a bus without
+ * a south bridge (subtractive decode agent) can result in
+ * master aborts as the BIOS probes the capabilities of the
+ * card. XFree86 does such initialization. If the error
+ * is a master abort (No DevSel as PCI Master) and the command
+ * is an I/O read or write below the address where we start
+ * assigning PCI I/O spaces (SRM uses 0x1000), then mark the
+ * error as dismissable so starting XFree86 doesn't result
+ * in a series of uncorrectable errors being reported. Also
+ * dismiss master aborts to VGA frame buffer space
+ * (0xA0000 - 0xC0000) and legacy BIOS space (0xC0000 - 0x100000)
+ * for the same reason.
+ *
+ * Also mark the error dismissible if it looks like the right
+ * error but only the Lost bit is set. Since the BIOS initialization
+ * can cause multiple master aborts and the error interrupt can
+ * be handled on a different CPU than the BIOS code is run on,
+ * it is possible for a second master abort to occur between the
+ * time the PALcode reads PERROR and the time it writes PERROR
+ * to acknowledge the error. If this timing happens, a second
+ * error will be signalled after the first, and if no additional
+ * errors occur, will look like a Lost error with no additional
+ * errors on the same transaction as the previous error.
+ */
+ if (((perror & TITAN__PCHIP_PERROR__NDS) ||
+ ((perror & TITAN__PCHIP_PERROR__ERRMASK) ==
+ TITAN__PCHIP_PERROR__LOST)) &&
+ ((((cmd & 0xE) == 2) && (addr < 0x1000)) ||
+ (((cmd & 0xE) == 6) && (addr >= 0xA0000) && (addr < 0x100000)))) {
+ status = MCHK_DISPOSITION_DISMISS;
+ }
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (!print)
+ return status;
+
+ printk("%s PChip %d %cPERROR: %016lx\n",
+ err_print_prefix, which,
+ port ? 'A' : 'G', perror);
+ if (perror & TITAN__PCHIP_PERROR__IPTPW)
+ printk("%s Invalid Peer-to-Peer Write\n", err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__IPTPR)
+ printk("%s Invalid Peer-to-Peer Read\n", err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__NDS)
+ printk("%s No DEVSEL as PCI Master [Master Abort]\n",
+ err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__DPE)
+ printk("%s Data Parity Error\n", err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__TA)
+ printk("%s Target Abort\n", err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__APE)
+ printk("%s Address Parity Error\n", err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__SGE)
+ printk("%s Scatter-Gather Error, Invalid PTE\n",
+ err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__DCRTO)
+ printk("%s Delayed-Completion Retry Timeout\n",
+ err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__PERR)
+ printk("%s PERR Asserted\n", err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__SERR)
+ printk("%s SERR Asserted\n", err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__LOST)
+ printk("%s Lost Error\n", err_print_prefix);
+ printk("%s Command: 0x%x - %s\n"
+ " Address: 0x%lx\n",
+ err_print_prefix,
+ cmd, perror_cmd[cmd],
+ addr);
+ if (perror & TITAN__PCHIP_PERROR__DAC)
+ printk("%s Dual Address Cycle\n", err_print_prefix);
+ if (perror & TITAN__PCHIP_PERROR__MWIN)
+ printk("%s Hit in Monster Window\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+ return status;
+}
+
+static int
+titan_parse_p_agperror(int which, u64 agperror, int print)
+{
+ int status = MCHK_DISPOSITION_REPORT;
+#ifdef CONFIG_VERBOSE_MCHECK
+ int cmd, len;
+ unsigned long addr;
+
+ char *agperror_cmd[] = { "Read (low-priority)", "Read (high-priority)",
+ "Write (low-priority)",
+ "Write (high-priority)",
+ "Reserved", "Reserved",
+ "Flush", "Fence"
+ };
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_AGPERROR__LOST (1UL << 0)
+#define TITAN__PCHIP_AGPERROR__LPQFULL (1UL << 1)
+#define TITAN__PCHIP_AGPERROR__HPQFULL (1UL << 2)
+#define TITAN__PCHIP_AGPERROR__RESCMD (1UL << 3)
+#define TITAN__PCHIP_AGPERROR__IPTE (1UL << 4)
+#define TITAN__PCHIP_AGPERROR__PTP (1UL << 5)
+#define TITAN__PCHIP_AGPERROR__NOWINDOW (1UL << 6)
+#define TITAN__PCHIP_AGPERROR__ERRMASK (TITAN__PCHIP_AGPERROR__LOST | \
+ TITAN__PCHIP_AGPERROR__LPQFULL | \
+ TITAN__PCHIP_AGPERROR__HPQFULL | \
+ TITAN__PCHIP_AGPERROR__RESCMD | \
+ TITAN__PCHIP_AGPERROR__IPTE | \
+ TITAN__PCHIP_AGPERROR__PTP | \
+ TITAN__PCHIP_AGPERROR__NOWINDOW)
+#define TITAN__PCHIP_AGPERROR__DAC (1UL << 48)
+#define TITAN__PCHIP_AGPERROR__MWIN (1UL << 49)
+#define TITAN__PCHIP_AGPERROR__FENCE (1UL << 59)
+#define TITAN__PCHIP_AGPERROR__CMD__S (50)
+#define TITAN__PCHIP_AGPERROR__CMD__M (0x07)
+#define TITAN__PCHIP_AGPERROR__ADDR__S (15)
+#define TITAN__PCHIP_AGPERROR__ADDR__M (0xffffffffUL)
+#define TITAN__PCHIP_AGPERROR__LEN__S (53)
+#define TITAN__PCHIP_AGPERROR__LEN__M (0x3f)
+
+ if (!(agperror & TITAN__PCHIP_AGPERROR__ERRMASK))
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (!print)
+ return status;
+
+ cmd = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__CMD);
+ addr = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__ADDR) << 3;
+ len = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__LEN);
+
+ printk("%s PChip %d AGPERROR: %016lx\n", err_print_prefix,
+ which, agperror);
+ if (agperror & TITAN__PCHIP_AGPERROR__NOWINDOW)
+ printk("%s No Window\n", err_print_prefix);
+ if (agperror & TITAN__PCHIP_AGPERROR__PTP)
+ printk("%s Peer-to-Peer set\n", err_print_prefix);
+ if (agperror & TITAN__PCHIP_AGPERROR__IPTE)
+ printk("%s Invalid PTE\n", err_print_prefix);
+ if (agperror & TITAN__PCHIP_AGPERROR__RESCMD)
+ printk("%s Reserved Command\n", err_print_prefix);
+ if (agperror & TITAN__PCHIP_AGPERROR__HPQFULL)
+ printk("%s HP Transaction Received while Queue Full\n",
+ err_print_prefix);
+ if (agperror & TITAN__PCHIP_AGPERROR__LPQFULL)
+ printk("%s LP Transaction Received while Queue Full\n",
+ err_print_prefix);
+ if (agperror & TITAN__PCHIP_AGPERROR__LOST)
+ printk("%s Lost Error\n", err_print_prefix);
+ printk("%s Command: 0x%x - %s, %d Quadwords%s\n"
+ " Address: 0x%lx\n",
+ err_print_prefix, cmd, agperror_cmd[cmd], len,
+ (agperror & TITAN__PCHIP_AGPERROR__FENCE) ? ", FENCE" : "",
+ addr);
+ if (agperror & TITAN__PCHIP_AGPERROR__DAC)
+ printk("%s Dual Address Cycle\n", err_print_prefix);
+ if (agperror & TITAN__PCHIP_AGPERROR__MWIN)
+ printk("%s Hit in Monster Window\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+ return status;
+}
+
+static int
+titan_parse_p_chip(int which, u64 serror, u64 gperror,
+ u64 aperror, u64 agperror, int print)
+{
+ int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+ status |= titan_parse_p_serror(which, serror, print);
+ status |= titan_parse_p_perror(which, 0, gperror, print);
+ status |= titan_parse_p_perror(which, 1, aperror, print);
+ status |= titan_parse_p_agperror(which, agperror, print);
+ return status;
+}
+
+int
+titan_process_logout_frame(struct el_common *mchk_header, int print)
+{
+ struct el_TITAN_sysdata_mcheck *tmchk =
+ (struct el_TITAN_sysdata_mcheck *)
+ ((unsigned long)mchk_header + mchk_header->sys_offset);
+ int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+ status |= titan_parse_c_misc(tmchk->c_misc, print);
+ status |= titan_parse_p_chip(0, tmchk->p0_serror, tmchk->p0_gperror,
+ tmchk->p0_aperror, tmchk->p0_agperror,
+ print);
+ status |= titan_parse_p_chip(1, tmchk->p1_serror, tmchk->p1_gperror,
+ tmchk->p1_aperror, tmchk->p1_agperror,
+ print);
+
+ return status;
+}
+
+void
+titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+ struct el_common *mchk_header = (struct el_common *)la_ptr;
+ struct el_TITAN_sysdata_mcheck *tmchk =
+ (struct el_TITAN_sysdata_mcheck *)
+ ((unsigned long)mchk_header + mchk_header->sys_offset);
+ u64 irqmask;
+
+ /*
+ * Mask of Titan interrupt sources which are reported as machine checks
+ *
+ * 63 - CChip Error
+ * 62 - PChip 0 H_Error
+ * 61 - PChip 1 H_Error
+ * 60 - PChip 0 C_Error
+ * 59 - PChip 1 C_Error
+ */
+#define TITAN_MCHECK_INTERRUPT_MASK 0xF800000000000000UL
+
+ /*
+ * Sync the processor
+ */
+ mb();
+ draina();
+
+ /*
+ * Only handle system errors here
+ */
+ if ((vector != SCB_Q_SYSMCHK) && (vector != SCB_Q_SYSERR)) {
+ ev6_machine_check(vector, la_ptr, regs);
+ return;
+ }
+
+ /*
+ * It's a system error, handle it here
+ *
+ * The PALcode has already cleared the error, so just parse it
+ */
+
+ /*
+ * Parse the logout frame without printing first. If the only error(s)
+ * found are classified as "dismissable", then just dismiss them and
+ * don't print any message
+ */
+ if (titan_process_logout_frame(mchk_header, 0) !=
+ MCHK_DISPOSITION_DISMISS) {
+ char *saved_err_prefix = err_print_prefix;
+ err_print_prefix = KERN_CRIT;
+
+ /*
+ * Either a nondismissable error was detected or no
+ * recognized error was detected in the logout frame
+ * -- report the error in either case
+ */
+ printk("%s"
+ "*System %s Error (Vector 0x%x) reported on CPU %d:\n",
+ err_print_prefix,
+ (vector == SCB_Q_SYSERR)?"Correctable":"Uncorrectable",
+ (unsigned int)vector, (int)smp_processor_id());
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ titan_process_logout_frame(mchk_header, alpha_verbose_mcheck);
+ if (alpha_verbose_mcheck)
+ dik_show_regs(regs, NULL);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+ err_print_prefix = saved_err_prefix;
+
+ /*
+ * Convert any pending interrupts which report as system
+ * machine checks to interrupts
+ */
+ irqmask = tmchk->c_dirx & TITAN_MCHECK_INTERRUPT_MASK;
+ titan_dispatch_irqs(irqmask, regs);
+ }
+
+
+ /*
+ * Release the logout frame
+ */
+ wrmces(0x7);
+ mb();
+}
+
+/*
+ * Subpacket Annotations
+ */
+static char *el_titan_pchip0_extended_annotation[] = {
+ "Subpacket Header", "P0_SCTL", "P0_SERREN",
+ "P0_APCTL", "P0_APERREN", "P0_AGPERREN",
+ "P0_ASPRST", "P0_AWSBA0", "P0_AWSBA1",
+ "P0_AWSBA2", "P0_AWSBA3", "P0_AWSM0",
+ "P0_AWSM1", "P0_AWSM2", "P0_AWSM3",
+ "P0_ATBA0", "P0_ATBA1", "P0_ATBA2",
+ "P0_ATBA3", "P0_GPCTL", "P0_GPERREN",
+ "P0_GSPRST", "P0_GWSBA0", "P0_GWSBA1",
+ "P0_GWSBA2", "P0_GWSBA3", "P0_GWSM0",
+ "P0_GWSM1", "P0_GWSM2", "P0_GWSM3",
+ "P0_GTBA0", "P0_GTBA1", "P0_GTBA2",
+ "P0_GTBA3", NULL
+};
+static char *el_titan_pchip1_extended_annotation[] = {
+ "Subpacket Header", "P1_SCTL", "P1_SERREN",
+ "P1_APCTL", "P1_APERREN", "P1_AGPERREN",
+ "P1_ASPRST", "P1_AWSBA0", "P1_AWSBA1",
+ "P1_AWSBA2", "P1_AWSBA3", "P1_AWSM0",
+ "P1_AWSM1", "P1_AWSM2", "P1_AWSM3",
+ "P1_ATBA0", "P1_ATBA1", "P1_ATBA2",
+ "P1_ATBA3", "P1_GPCTL", "P1_GPERREN",
+ "P1_GSPRST", "P1_GWSBA0", "P1_GWSBA1",
+ "P1_GWSBA2", "P1_GWSBA3", "P1_GWSM0",
+ "P1_GWSM1", "P1_GWSM2", "P1_GWSM3",
+ "P1_GTBA0", "P1_GTBA1", "P1_GTBA2",
+ "P1_GTBA3", NULL
+};
+static char *el_titan_memory_extended_annotation[] = {
+ "Subpacket Header", "AAR0", "AAR1",
+ "AAR2", "AAR3", "P0_SCTL",
+ "P0_GPCTL", "P0_APCTL", "P1_SCTL",
+ "P1_GPCTL", "P1_SCTL", NULL
+};
+
+static struct el_subpacket_annotation el_titan_annotations[] = {
+ SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+ EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED,
+ 1,
+ "Titan PChip 0 Extended Frame",
+ el_titan_pchip0_extended_annotation),
+ SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+ EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED,
+ 1,
+ "Titan PChip 1 Extended Frame",
+ el_titan_pchip1_extended_annotation),
+ SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+ EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED,
+ 1,
+ "Titan Memory Extended Frame",
+ el_titan_memory_extended_annotation),
+ SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+ EL_TYPE__TERMINATION__TERMINATION,
+ 1,
+ "Termination Subpacket",
+ NULL)
+};
+
+static struct el_subpacket *
+el_process_regatta_subpacket(struct el_subpacket *header)
+{
+ int status;
+
+ if (header->class != EL_CLASS__REGATTA_FAMILY) {
+ printk("%s ** Unexpected header CLASS %d TYPE %d, aborting\n",
+ err_print_prefix,
+ header->class, header->type);
+ return NULL;
+ }
+
+ switch(header->type) {
+ case EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME:
+ case EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME:
+ case EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME:
+ case EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT:
+ case EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT:
+ printk("%s ** Occurred on CPU %d:\n",
+ err_print_prefix,
+ (int)header->by_type.regatta_frame.cpuid);
+ status = privateer_process_logout_frame((struct el_common *)
+ header->by_type.regatta_frame.data_start, 1);
+ break;
+ default:
+ printk("%s ** REGATTA TYPE %d SUBPACKET\n",
+ err_print_prefix, header->type);
+ el_annotate_subpacket(header);
+ break;
+ }
+
+
+ return (struct el_subpacket *)((unsigned long)header + header->length);
+}
+
+static struct el_subpacket_handler titan_subpacket_handler =
+ SUBPACKET_HANDLER_INIT(EL_CLASS__REGATTA_FAMILY,
+ el_process_regatta_subpacket);
+
+void
+titan_register_error_handlers(void)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE (el_titan_annotations); i++)
+ cdl_register_subpacket_annotation(&el_titan_annotations[i]);
+
+ cdl_register_subpacket_handler(&titan_subpacket_handler);
+
+ ev6_register_error_handlers();
+}
+
+
+/*
+ * Privateer
+ */
+
+static int
+privateer_process_680_frame(struct el_common *mchk_header, int print)
+{
+ int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+#ifdef CONFIG_VERBOSE_MCHECK
+ struct el_PRIVATEER_envdata_mcheck *emchk =
+ (struct el_PRIVATEER_envdata_mcheck *)
+ ((unsigned long)mchk_header + mchk_header->sys_offset);
+
+ /* TODO - catagorize errors, for now, no error */
+
+ if (!print)
+ return status;
+
+ /* TODO - decode instead of just dumping... */
+ printk("%s Summary Flags: %016lx\n"
+ " CChip DIRx: %016lx\n"
+ " System Management IR: %016lx\n"
+ " CPU IR: %016lx\n"
+ " Power Supply IR: %016lx\n"
+ " LM78 Fault Status: %016lx\n"
+ " System Doors: %016lx\n"
+ " Temperature Warning: %016lx\n"
+ " Fan Control: %016lx\n"
+ " Fatal Power Down Code: %016lx\n",
+ err_print_prefix,
+ emchk->summary,
+ emchk->c_dirx,
+ emchk->smir,
+ emchk->cpuir,
+ emchk->psir,
+ emchk->fault,
+ emchk->sys_doors,
+ emchk->temp_warn,
+ emchk->fan_ctrl,
+ emchk->code);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+ return status;
+}
+
+int
+privateer_process_logout_frame(struct el_common *mchk_header, int print)
+{
+ struct el_common_EV6_mcheck *ev6mchk =
+ (struct el_common_EV6_mcheck *)mchk_header;
+ int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+ /*
+ * Machine check codes
+ */
+#define PRIVATEER_MCHK__CORR_ECC 0x86 /* 630 */
+#define PRIVATEER_MCHK__DC_TAG_PERR 0x9E /* 630 */
+#define PRIVATEER_MCHK__PAL_BUGCHECK 0x8E /* 670 */
+#define PRIVATEER_MCHK__OS_BUGCHECK 0x90 /* 670 */
+#define PRIVATEER_MCHK__PROC_HRD_ERR 0x98 /* 670 */
+#define PRIVATEER_MCHK__ISTREAM_CMOV_PRX 0xA0 /* 670 */
+#define PRIVATEER_MCHK__ISTREAM_CMOV_FLT 0xA2 /* 670 */
+#define PRIVATEER_MCHK__SYS_HRD_ERR 0x202 /* 660 */
+#define PRIVATEER_MCHK__SYS_CORR_ERR 0x204 /* 620 */
+#define PRIVATEER_MCHK__SYS_ENVIRON 0x206 /* 680 */
+
+ switch(ev6mchk->MCHK_Code) {
+ /*
+ * Vector 630 - Processor, Correctable
+ */
+ case PRIVATEER_MCHK__CORR_ECC:
+ case PRIVATEER_MCHK__DC_TAG_PERR:
+ /*
+ * Fall through to vector 670 for processing...
+ */
+ /*
+ * Vector 670 - Processor, Uncorrectable
+ */
+ case PRIVATEER_MCHK__PAL_BUGCHECK:
+ case PRIVATEER_MCHK__OS_BUGCHECK:
+ case PRIVATEER_MCHK__PROC_HRD_ERR:
+ case PRIVATEER_MCHK__ISTREAM_CMOV_PRX:
+ case PRIVATEER_MCHK__ISTREAM_CMOV_FLT:
+ status |= ev6_process_logout_frame(mchk_header, print);
+ break;
+
+ /*
+ * Vector 620 - System, Correctable
+ */
+ case PRIVATEER_MCHK__SYS_CORR_ERR:
+ /*
+ * Fall through to vector 660 for processing...
+ */
+ /*
+ * Vector 660 - System, Uncorrectable
+ */
+ case PRIVATEER_MCHK__SYS_HRD_ERR:
+ status |= titan_process_logout_frame(mchk_header, print);
+ break;
+
+ /*
+ * Vector 680 - System, Environmental
+ */
+ case PRIVATEER_MCHK__SYS_ENVIRON: /* System, Environmental */
+ status |= privateer_process_680_frame(mchk_header, print);
+ break;
+
+ /*
+ * Unknown
+ */
+ default:
+ status |= MCHK_DISPOSITION_REPORT;
+ if (print) {
+ printk("%s** Unknown Error, frame follows\n",
+ err_print_prefix);
+ mchk_dump_logout_frame(mchk_header);
+ }
+
+ }
+
+ return status;
+}
+
+void
+privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+ struct el_common *mchk_header = (struct el_common *)la_ptr;
+ struct el_TITAN_sysdata_mcheck *tmchk =
+ (struct el_TITAN_sysdata_mcheck *)
+ (la_ptr + mchk_header->sys_offset);
+ u64 irqmask;
+ char *saved_err_prefix = err_print_prefix;
+
+#define PRIVATEER_680_INTERRUPT_MASK (0xE00UL)
+#define PRIVATEER_HOTPLUG_INTERRUPT_MASK (0xE00UL)
+
+ /*
+ * Sync the processor.
+ */
+ mb();
+ draina();
+
+ /*
+ * Only handle system events here.
+ */
+ if (vector != SCB_Q_SYSEVENT)
+ return titan_machine_check(vector, la_ptr, regs);
+
+ /*
+ * Report the event - System Events should be reported even if no
+ * error is indicated since the event could indicate the return
+ * to normal status.
+ */
+ err_print_prefix = KERN_CRIT;
+ printk("%s*System Event (Vector 0x%x) reported on CPU %d:\n",
+ err_print_prefix,
+ (unsigned int)vector, (int)smp_processor_id());
+ privateer_process_680_frame(mchk_header, 1);
+ err_print_prefix = saved_err_prefix;
+
+ /*
+ * Convert any pending interrupts which report as 680 machine
+ * checks to interrupts.
+ */
+ irqmask = tmchk->c_dirx & PRIVATEER_680_INTERRUPT_MASK;
+
+ /*
+ * Dispatch the interrupt(s).
+ */
+ titan_dispatch_irqs(irqmask, regs);
+
+ /*
+ * Release the logout frame.
+ */
+ wrmces(0x7);
+ mb();
+}
diff --git a/arch/alpha/kernel/es1888.c b/arch/alpha/kernel/es1888.c
new file mode 100644
index 000000000000..d584c85fea7a
--- /dev/null
+++ b/arch/alpha/kernel/es1888.c
@@ -0,0 +1,49 @@
+/*
+ * linux/arch/alpha/kernel/es1888.c
+ *
+ * Init the built-in ES1888 sound chip (SB16 compatible)
+ */
+
+#include <linux/init.h>
+#include <asm/io.h>
+#include "proto.h"
+
+void __init
+es1888_init(void)
+{
+ /* Sequence of IO reads to init the audio controller */
+ inb(0x0229);
+ inb(0x0229);
+ inb(0x0229);
+ inb(0x022b);
+ inb(0x0229);
+ inb(0x022b);
+ inb(0x0229);
+ inb(0x0229);
+ inb(0x022b);
+ inb(0x0229);
+ inb(0x0220); /* This sets the base address to 0x220 */
+
+ /* Sequence to set DMA channels */
+ outb(0x01, 0x0226); /* reset */
+ inb(0x0226); /* pause */
+ outb(0x00, 0x0226); /* release reset */
+ while (!(inb(0x022e) & 0x80)) /* wait for bit 7 to assert*/
+ continue;
+ inb(0x022a); /* pause */
+ outb(0xc6, 0x022c); /* enable extended mode */
+ inb(0x022a); /* pause, also forces the write */
+ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+ continue;
+ outb(0xb1, 0x022c); /* setup for write to Interrupt CR */
+ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+ continue;
+ outb(0x14, 0x022c); /* set IRQ 5 */
+ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+ continue;
+ outb(0xb2, 0x022c); /* setup for write to DMA CR */
+ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+ continue;
+ outb(0x18, 0x022c); /* set DMA channel 1 */
+ inb(0x022c); /* force the write */
+}
diff --git a/arch/alpha/kernel/gct.c b/arch/alpha/kernel/gct.c
new file mode 100644
index 000000000000..8827687b9f89
--- /dev/null
+++ b/arch/alpha/kernel/gct.c
@@ -0,0 +1,48 @@
+/*
+ * linux/arch/alpha/kernel/gct.c
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#include <asm/hwrpb.h>
+#include <asm/gct.h>
+
+int
+gct6_find_nodes(gct6_node *node, gct6_search_struct *search)
+{
+ gct6_search_struct *wanted;
+ int status = 0;
+
+ /* First check the magic number. */
+ if (node->magic != GCT_NODE_MAGIC) {
+ printk(KERN_ERR "GCT Node MAGIC incorrect - GCT invalid\n");
+ return -EINVAL;
+ }
+
+ /* Check against the search struct. */
+ for (wanted = search;
+ wanted && (wanted->type | wanted->subtype);
+ wanted++) {
+ if (node->type != wanted->type)
+ continue;
+ if (node->subtype != wanted->subtype)
+ continue;
+
+ /* Found it -- call out. */
+ if (wanted->callout)
+ wanted->callout(node);
+ }
+
+ /* Now walk the tree, siblings first. */
+ if (node->next)
+ status |= gct6_find_nodes(GCT_NODE_PTR(node->next), search);
+
+ /* Then the children. */
+ if (node->child)
+ status |= gct6_find_nodes(GCT_NODE_PTR(node->child), search);
+
+ return status;
+}
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
new file mode 100644
index 000000000000..4ca2e404708a
--- /dev/null
+++ b/arch/alpha/kernel/head.S
@@ -0,0 +1,99 @@
+/*
+ * alpha/boot/head.S
+ *
+ * initial boot stuff.. At this point, the bootloader has already
+ * switched into OSF/1 PAL-code, and loaded us at the correct address
+ * (START_ADDR). So there isn't much left for us to do: just set up
+ * the kernel global pointer and jump to the kernel entry-point.
+ */
+
+#include <linux/config.h>
+#include <asm/system.h>
+#include <asm/asm_offsets.h>
+
+.globl swapper_pg_dir
+.globl _stext
+swapper_pg_dir=SWAPPER_PGD
+
+ .set noreorder
+ .globl __start
+ .ent __start
+_stext:
+__start:
+ .prologue 0
+ br $27,1f
+1: ldgp $29,0($27)
+ /* We need to get current_task_info loaded up... */
+ lda $8,init_thread_union
+ /* ... and find our stack ... */
+ lda $30,0x4000 - SIZEOF_PT_REGS($8)
+ /* ... and then we can start the kernel. */
+ jsr $26,start_kernel
+ call_pal PAL_halt
+ .end __start
+
+#ifdef CONFIG_SMP
+ .align 3
+ .globl __smp_callin
+ .ent __smp_callin
+ /* On entry here from SRM console, the HWPCB of the per-cpu
+ slot for this processor has been loaded. We've arranged
+ for the UNIQUE value for this process to contain the PCBB
+ of the target idle task. */
+__smp_callin:
+ .prologue 1
+ ldgp $29,0($27) # First order of business, load the GP.
+
+ call_pal PAL_rduniq # Grab the target PCBB.
+ mov $0,$16 # Install it.
+ call_pal PAL_swpctx
+
+ lda $8,0x3fff # Find "current".
+ bic $30,$8,$8
+
+ jsr $26,smp_callin
+ call_pal PAL_halt
+ .end __smp_callin
+#endif /* CONFIG_SMP */
+
+ #
+ # The following two functions are needed for supporting SRM PALcode
+ # on the PC164 (at least), since that PALcode manages the interrupt
+ # masking, and we cannot duplicate the effort without causing problems
+ #
+
+ .align 3
+ .globl cserve_ena
+ .ent cserve_ena
+cserve_ena:
+ .prologue 0
+ bis $16,$16,$17
+ lda $16,52($31)
+ call_pal PAL_cserve
+ ret ($26)
+ .end cserve_ena
+
+ .align 3
+ .globl cserve_dis
+ .ent cserve_dis
+cserve_dis:
+ .prologue 0
+ bis $16,$16,$17
+ lda $16,53($31)
+ call_pal PAL_cserve
+ ret ($26)
+ .end cserve_dis
+
+ #
+ # It is handy, on occasion, to make halt actually just loop.
+ # Putting it here means we dont have to recompile the whole
+ # kernel.
+ #
+
+ .align 3
+ .globl halt
+ .ent halt
+halt:
+ .prologue 0
+ call_pal PAL_halt
+ .end halt
diff --git a/arch/alpha/kernel/init_task.c b/arch/alpha/kernel/init_task.c
new file mode 100644
index 000000000000..835d09a7b332
--- /dev/null
+++ b/arch/alpha/kernel/init_task.c
@@ -0,0 +1,23 @@
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/fs.h>
+#include <linux/mqueue.h>
+#include <asm/uaccess.h>
+
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_mm);
+EXPORT_SYMBOL(init_task);
+
+union thread_union init_thread_union
+ __attribute__((section(".data.init_thread")))
+ = { INIT_THREAD_INFO(init_task) };
diff --git a/arch/alpha/kernel/io.c b/arch/alpha/kernel/io.c
new file mode 100644
index 000000000000..19c5875ab398
--- /dev/null
+++ b/arch/alpha/kernel/io.c
@@ -0,0 +1,630 @@
+/*
+ * Alpha IO and memory functions.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+/* Out-of-line versions of the i/o routines that redirect into the
+ platform-specific version. Note that "platform-specific" may mean
+ "generic", which bumps through the machine vector. */
+
+unsigned int
+ioread8(void __iomem *addr)
+{
+ unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
+ mb();
+ return ret;
+}
+
+unsigned int ioread16(void __iomem *addr)
+{
+ unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
+ mb();
+ return ret;
+}
+
+unsigned int ioread32(void __iomem *addr)
+{
+ unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
+ mb();
+ return ret;
+}
+
+void iowrite8(u8 b, void __iomem *addr)
+{
+ IO_CONCAT(__IO_PREFIX,iowrite8)(b, addr);
+ mb();
+}
+
+void iowrite16(u16 b, void __iomem *addr)
+{
+ IO_CONCAT(__IO_PREFIX,iowrite16)(b, addr);
+ mb();
+}
+
+void iowrite32(u32 b, void __iomem *addr)
+{
+ IO_CONCAT(__IO_PREFIX,iowrite32)(b, addr);
+ mb();
+}
+
+EXPORT_SYMBOL(ioread8);
+EXPORT_SYMBOL(ioread16);
+EXPORT_SYMBOL(ioread32);
+EXPORT_SYMBOL(iowrite8);
+EXPORT_SYMBOL(iowrite16);
+EXPORT_SYMBOL(iowrite32);
+
+u8 inb(unsigned long port)
+{
+ return ioread8(ioport_map(port, 1));
+}
+
+u16 inw(unsigned long port)
+{
+ return ioread16(ioport_map(port, 2));
+}
+
+u32 inl(unsigned long port)
+{
+ return ioread32(ioport_map(port, 4));
+}
+
+void outb(u8 b, unsigned long port)
+{
+ iowrite8(b, ioport_map(port, 1));
+}
+
+void outw(u16 b, unsigned long port)
+{
+ iowrite16(b, ioport_map(port, 2));
+}
+
+void outl(u32 b, unsigned long port)
+{
+ iowrite32(b, ioport_map(port, 4));
+}
+
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+
+u8 __raw_readb(const volatile void __iomem *addr)
+{
+ return IO_CONCAT(__IO_PREFIX,readb)(addr);
+}
+
+u16 __raw_readw(const volatile void __iomem *addr)
+{
+ return IO_CONCAT(__IO_PREFIX,readw)(addr);
+}
+
+u32 __raw_readl(const volatile void __iomem *addr)
+{
+ return IO_CONCAT(__IO_PREFIX,readl)(addr);
+}
+
+u64 __raw_readq(const volatile void __iomem *addr)
+{
+ return IO_CONCAT(__IO_PREFIX,readq)(addr);
+}
+
+void __raw_writeb(u8 b, volatile void __iomem *addr)
+{
+ IO_CONCAT(__IO_PREFIX,writeb)(b, addr);
+}
+
+void __raw_writew(u16 b, volatile void __iomem *addr)
+{
+ IO_CONCAT(__IO_PREFIX,writew)(b, addr);
+}
+
+void __raw_writel(u32 b, volatile void __iomem *addr)
+{
+ IO_CONCAT(__IO_PREFIX,writel)(b, addr);
+}
+
+void __raw_writeq(u64 b, volatile void __iomem *addr)
+{
+ IO_CONCAT(__IO_PREFIX,writeq)(b, addr);
+}
+
+EXPORT_SYMBOL(__raw_readb);
+EXPORT_SYMBOL(__raw_readw);
+EXPORT_SYMBOL(__raw_readl);
+EXPORT_SYMBOL(__raw_readq);
+EXPORT_SYMBOL(__raw_writeb);
+EXPORT_SYMBOL(__raw_writew);
+EXPORT_SYMBOL(__raw_writel);
+EXPORT_SYMBOL(__raw_writeq);
+
+u8 readb(const volatile void __iomem *addr)
+{
+ u8 ret = __raw_readb(addr);
+ mb();
+ return ret;
+}
+
+u16 readw(const volatile void __iomem *addr)
+{
+ u16 ret = __raw_readw(addr);
+ mb();
+ return ret;
+}
+
+u32 readl(const volatile void __iomem *addr)
+{
+ u32 ret = __raw_readl(addr);
+ mb();
+ return ret;
+}
+
+u64 readq(const volatile void __iomem *addr)
+{
+ u64 ret = __raw_readq(addr);
+ mb();
+ return ret;
+}
+
+void writeb(u8 b, volatile void __iomem *addr)
+{
+ __raw_writeb(b, addr);
+ mb();
+}
+
+void writew(u16 b, volatile void __iomem *addr)
+{
+ __raw_writew(b, addr);
+ mb();
+}
+
+void writel(u32 b, volatile void __iomem *addr)
+{
+ __raw_writel(b, addr);
+ mb();
+}
+
+void writeq(u64 b, volatile void __iomem *addr)
+{
+ __raw_writeq(b, addr);
+ mb();
+}
+
+EXPORT_SYMBOL(readb);
+EXPORT_SYMBOL(readw);
+EXPORT_SYMBOL(readl);
+EXPORT_SYMBOL(readq);
+EXPORT_SYMBOL(writeb);
+EXPORT_SYMBOL(writew);
+EXPORT_SYMBOL(writel);
+EXPORT_SYMBOL(writeq);
+
+
+/*
+ * Read COUNT 8-bit bytes from port PORT into memory starting at SRC.
+ */
+void ioread8_rep(void __iomem *port, void *dst, unsigned long count)
+{
+ while ((unsigned long)dst & 0x3) {
+ if (!count)
+ return;
+ count--;
+ *(unsigned char *)dst = ioread8(port);
+ dst += 1;
+ }
+
+ while (count >= 4) {
+ unsigned int w;
+ count -= 4;
+ w = ioread8(port);
+ w |= ioread8(port) << 8;
+ w |= ioread8(port) << 16;
+ w |= ioread8(port) << 24;
+ *(unsigned int *)dst = w;
+ dst += 4;
+ }
+
+ while (count) {
+ --count;
+ *(unsigned char *)dst = ioread8(port);
+ dst += 1;
+ }
+}
+
+void insb(unsigned long port, void *dst, unsigned long count)
+{
+ ioread8_rep(ioport_map(port, 1), dst, count);
+}
+
+EXPORT_SYMBOL(ioread8_rep);
+EXPORT_SYMBOL(insb);
+
+/*
+ * Read COUNT 16-bit words from port PORT into memory starting at
+ * SRC. SRC must be at least short aligned. This is used by the
+ * IDE driver to read disk sectors. Performance is important, but
+ * the interfaces seems to be slow: just using the inlined version
+ * of the inw() breaks things.
+ */
+void ioread16_rep(void __iomem *port, void *dst, unsigned long count)
+{
+ if (unlikely((unsigned long)dst & 0x3)) {
+ if (!count)
+ return;
+ BUG_ON((unsigned long)dst & 0x1);
+ count--;
+ *(unsigned short *)dst = ioread16(port);
+ dst += 2;
+ }
+
+ while (count >= 2) {
+ unsigned int w;
+ count -= 2;
+ w = ioread16(port);
+ w |= ioread16(port) << 16;
+ *(unsigned int *)dst = w;
+ dst += 4;
+ }
+
+ if (count) {
+ *(unsigned short*)dst = ioread16(port);
+ }
+}
+
+void insw(unsigned long port, void *dst, unsigned long count)
+{
+ ioread16_rep(ioport_map(port, 2), dst, count);
+}
+
+EXPORT_SYMBOL(ioread16_rep);
+EXPORT_SYMBOL(insw);
+
+
+/*
+ * Read COUNT 32-bit words from port PORT into memory starting at
+ * SRC. Now works with any alignment in SRC. Performance is important,
+ * but the interfaces seems to be slow: just using the inlined version
+ * of the inl() breaks things.
+ */
+void ioread32_rep(void __iomem *port, void *dst, unsigned long count)
+{
+ if (unlikely((unsigned long)dst & 0x3)) {
+ while (count--) {
+ struct S { int x __attribute__((packed)); };
+ ((struct S *)dst)->x = ioread32(port);
+ dst += 4;
+ }
+ } else {
+ /* Buffer 32-bit aligned. */
+ while (count--) {
+ *(unsigned int *)dst = ioread32(port);
+ dst += 4;
+ }
+ }
+}
+
+void insl(unsigned long port, void *dst, unsigned long count)
+{
+ ioread32_rep(ioport_map(port, 4), dst, count);
+}
+
+EXPORT_SYMBOL(ioread32_rep);
+EXPORT_SYMBOL(insl);
+
+
+/*
+ * Like insb but in the opposite direction.
+ * Don't worry as much about doing aligned memory transfers:
+ * doing byte reads the "slow" way isn't nearly as slow as
+ * doing byte writes the slow way (no r-m-w cycle).
+ */
+void iowrite8_rep(void __iomem *port, const void *xsrc, unsigned long count)
+{
+ const unsigned char *src = xsrc;
+ while (count--)
+ iowrite8(*src++, port);
+}
+
+void outsb(unsigned long port, const void *src, unsigned long count)
+{
+ iowrite8_rep(ioport_map(port, 1), src, count);
+}
+
+EXPORT_SYMBOL(iowrite8_rep);
+EXPORT_SYMBOL(outsb);
+
+
+/*
+ * Like insw but in the opposite direction. This is used by the IDE
+ * driver to write disk sectors. Performance is important, but the
+ * interfaces seems to be slow: just using the inlined version of the
+ * outw() breaks things.
+ */
+void iowrite16_rep(void __iomem *port, const void *src, unsigned long count)
+{
+ if (unlikely((unsigned long)src & 0x3)) {
+ if (!count)
+ return;
+ BUG_ON((unsigned long)src & 0x1);
+ iowrite16(*(unsigned short *)src, port);
+ src += 2;
+ --count;
+ }
+
+ while (count >= 2) {
+ unsigned int w;
+ count -= 2;
+ w = *(unsigned int *)src;
+ src += 4;
+ iowrite16(w >> 0, port);
+ iowrite16(w >> 16, port);
+ }
+
+ if (count) {
+ iowrite16(*(unsigned short *)src, port);
+ }
+}
+
+void outsw(unsigned long port, const void *src, unsigned long count)
+{
+ iowrite16_rep(ioport_map(port, 2), src, count);
+}
+
+EXPORT_SYMBOL(iowrite16_rep);
+EXPORT_SYMBOL(outsw);
+
+
+/*
+ * Like insl but in the opposite direction. This is used by the IDE
+ * driver to write disk sectors. Works with any alignment in SRC.
+ * Performance is important, but the interfaces seems to be slow:
+ * just using the inlined version of the outl() breaks things.
+ */
+void iowrite32_rep(void __iomem *port, const void *src, unsigned long count)
+{
+ if (unlikely((unsigned long)src & 0x3)) {
+ while (count--) {
+ struct S { int x __attribute__((packed)); };
+ iowrite32(((struct S *)src)->x, port);
+ src += 4;
+ }
+ } else {
+ /* Buffer 32-bit aligned. */
+ while (count--) {
+ iowrite32(*(unsigned int *)src, port);
+ src += 4;
+ }
+ }
+}
+
+void outsl(unsigned long port, const void *src, unsigned long count)
+{
+ iowrite32_rep(ioport_map(port, 4), src, count);
+}
+
+EXPORT_SYMBOL(iowrite32_rep);
+EXPORT_SYMBOL(outsl);
+
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ * This needs to be optimized.
+ */
+void memcpy_fromio(void *to, const volatile void __iomem *from, long count)
+{
+ /* Optimize co-aligned transfers. Everything else gets handled
+ a byte at a time. */
+
+ if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) {
+ count -= 8;
+ do {
+ *(u64 *)to = __raw_readq(from);
+ count -= 8;
+ to += 8;
+ from += 8;
+ } while (count >= 0);
+ count += 8;
+ }
+
+ if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) {
+ count -= 4;
+ do {
+ *(u32 *)to = __raw_readl(from);
+ count -= 4;
+ to += 4;
+ from += 4;
+ } while (count >= 0);
+ count += 4;
+ }
+
+ if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) {
+ count -= 2;
+ do {
+ *(u16 *)to = __raw_readw(from);
+ count -= 2;
+ to += 2;
+ from += 2;
+ } while (count >= 0);
+ count += 2;
+ }
+
+ while (count > 0) {
+ *(u8 *) to = __raw_readb(from);
+ count--;
+ to++;
+ from++;
+ }
+ mb();
+}
+
+EXPORT_SYMBOL(memcpy_fromio);
+
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ * This needs to be optimized.
+ */
+void memcpy_toio(volatile void __iomem *to, const void *from, long count)
+{
+ /* Optimize co-aligned transfers. Everything else gets handled
+ a byte at a time. */
+ /* FIXME -- align FROM. */
+
+ if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) {
+ count -= 8;
+ do {
+ __raw_writeq(*(const u64 *)from, to);
+ count -= 8;
+ to += 8;
+ from += 8;
+ } while (count >= 0);
+ count += 8;
+ }
+
+ if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) {
+ count -= 4;
+ do {
+ __raw_writel(*(const u32 *)from, to);
+ count -= 4;
+ to += 4;
+ from += 4;
+ } while (count >= 0);
+ count += 4;
+ }
+
+ if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) {
+ count -= 2;
+ do {
+ __raw_writew(*(const u16 *)from, to);
+ count -= 2;
+ to += 2;
+ from += 2;
+ } while (count >= 0);
+ count += 2;
+ }
+
+ while (count > 0) {
+ __raw_writeb(*(const u8 *) from, to);
+ count--;
+ to++;
+ from++;
+ }
+ mb();
+}
+
+EXPORT_SYMBOL(memcpy_toio);
+
+
+/*
+ * "memset" on IO memory space.
+ */
+void _memset_c_io(volatile void __iomem *to, unsigned long c, long count)
+{
+ /* Handle any initial odd byte */
+ if (count > 0 && ((u64)to & 1)) {
+ __raw_writeb(c, to);
+ to++;
+ count--;
+ }
+
+ /* Handle any initial odd halfword */
+ if (count >= 2 && ((u64)to & 2)) {
+ __raw_writew(c, to);
+ to += 2;
+ count -= 2;
+ }
+
+ /* Handle any initial odd word */
+ if (count >= 4 && ((u64)to & 4)) {
+ __raw_writel(c, to);
+ to += 4;
+ count -= 4;
+ }
+
+ /* Handle all full-sized quadwords: we're aligned
+ (or have a small count) */
+ count -= 8;
+ if (count >= 0) {
+ do {
+ __raw_writeq(c, to);
+ to += 8;
+ count -= 8;
+ } while (count >= 0);
+ }
+ count += 8;
+
+ /* The tail is word-aligned if we still have count >= 4 */
+ if (count >= 4) {
+ __raw_writel(c, to);
+ to += 4;
+ count -= 4;
+ }
+
+ /* The tail is half-word aligned if we have count >= 2 */
+ if (count >= 2) {
+ __raw_writew(c, to);
+ to += 2;
+ count -= 2;
+ }
+
+ /* And finally, one last byte.. */
+ if (count) {
+ __raw_writeb(c, to);
+ }
+ mb();
+}
+
+EXPORT_SYMBOL(_memset_c_io);
+
+/* A version of memcpy used by the vga console routines to move data around
+ arbitrarily between screen and main memory. */
+
+void
+scr_memcpyw(u16 *d, const u16 *s, unsigned int count)
+{
+ const u16 __iomem *ios = (const u16 __iomem *) s;
+ u16 __iomem *iod = (u16 __iomem *) d;
+ int s_isio = __is_ioaddr(s);
+ int d_isio = __is_ioaddr(d);
+
+ if (s_isio) {
+ if (d_isio) {
+ /* FIXME: Should handle unaligned ops and
+ operation widening. */
+
+ count /= 2;
+ while (count--) {
+ u16 tmp = __raw_readw(ios++);
+ __raw_writew(tmp, iod++);
+ }
+ }
+ else
+ memcpy_fromio(d, ios, count);
+ } else {
+ if (d_isio)
+ memcpy_toio(iod, s, count);
+ else
+ memcpy(d, s, count);
+ }
+}
+
+EXPORT_SYMBOL(scr_memcpyw);
+
+void __iomem *ioport_map(unsigned long port, unsigned int size)
+{
+ return IO_CONCAT(__IO_PREFIX,ioportmap) (port);
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+}
+
+EXPORT_SYMBOL(ioport_map);
+EXPORT_SYMBOL(ioport_unmap);
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
new file mode 100644
index 000000000000..b6114f5c0d2b
--- /dev/null
+++ b/arch/alpha/kernel/irq.c
@@ -0,0 +1,774 @@
+/*
+ * linux/arch/alpha/kernel/irq.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/profile.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+/*
+ * Controller mappings for all interrupt sources:
+ */
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
+ [0 ... NR_IRQS-1] = {
+ .handler = &no_irq_type,
+ .lock = SPIN_LOCK_UNLOCKED
+ }
+};
+
+static void register_irq_proc(unsigned int irq);
+
+volatile unsigned long irq_err_count;
+
+/*
+ * Special irq handlers.
+ */
+
+irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ return IRQ_NONE;
+}
+
+/*
+ * Generic no controller code
+ */
+
+static void no_irq_enable_disable(unsigned int irq) { }
+static unsigned int no_irq_startup(unsigned int irq) { return 0; }
+
+static void
+no_irq_ack(unsigned int irq)
+{
+ irq_err_count++;
+ printk(KERN_CRIT "Unexpected IRQ trap at vector %u\n", irq);
+}
+
+struct hw_interrupt_type no_irq_type = {
+ .typename = "none",
+ .startup = no_irq_startup,
+ .shutdown = no_irq_enable_disable,
+ .enable = no_irq_enable_disable,
+ .disable = no_irq_enable_disable,
+ .ack = no_irq_ack,
+ .end = no_irq_enable_disable,
+};
+
+int
+handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+ struct irqaction *action)
+{
+ int status = 1; /* Force the "do bottom halves" bit */
+ int ret;
+
+ do {
+ if (!(action->flags & SA_INTERRUPT))
+ local_irq_enable();
+ else
+ local_irq_disable();
+
+ ret = action->handler(irq, action->dev_id, regs);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ action = action->next;
+ } while (action);
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ local_irq_disable();
+
+ return status;
+}
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
+void inline
+disable_irq_nosync(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ if (!desc->depth++) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/*
+ * Synchronous version of the above, making sure the IRQ is
+ * no longer running on any other IRQ..
+ */
+void
+disable_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ synchronize_irq(irq);
+}
+
+void
+enable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ switch (desc->depth) {
+ case 1: {
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+ desc->status = status;
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ desc->status = status | IRQ_REPLAY;
+ hw_resend_irq(desc->handler,irq);
+ }
+ desc->handler->enable(irq);
+ /* fall-through */
+ }
+ default:
+ desc->depth--;
+ break;
+ case 0:
+ printk(KERN_ERR "enable_irq() unbalanced from %p\n",
+ __builtin_return_address(0));
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+int
+setup_irq(unsigned int irq, struct irqaction * new)
+{
+ int shared = 0;
+ struct irqaction *old, **p;
+ unsigned long flags;
+ irq_desc_t *desc = irq_desc + irq;
+
+ if (desc->handler == &no_irq_type)
+ return -ENOSYS;
+
+ /*
+ * Some drivers like serial.c use request_irq() heavily,
+ * so we have to be careful not to interfere with a
+ * running system.
+ */
+ if (new->flags & SA_SAMPLE_RANDOM) {
+ /*
+ * This function might sleep, we want to call it first,
+ * outside of the atomic block.
+ * Yes, this might clear the entropy pool if the wrong
+ * driver is attempted to be loaded, without actually
+ * installing a new handler, but is this really a problem,
+ * only the sysadmin is able to do this.
+ */
+ rand_initialize_irq(irq);
+ }
+
+ /*
+ * The following block of code has to be executed atomically
+ */
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return -EBUSY;
+ }
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ *p = new;
+
+ if (!shared) {
+ desc->depth = 0;
+ desc->status &=
+ ~(IRQ_DISABLED|IRQ_AUTODETECT|IRQ_WAITING|IRQ_INPROGRESS);
+ desc->handler->startup(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ return 0;
+}
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir[NR_IRQS];
+
+#ifdef CONFIG_SMP
+static struct proc_dir_entry * smp_affinity_entry[NR_IRQS];
+static char irq_user_affinity[NR_IRQS];
+static cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
+
+static void
+select_smp_affinity(int irq)
+{
+ static int last_cpu;
+ int cpu = last_cpu + 1;
+
+ if (! irq_desc[irq].handler->set_affinity || irq_user_affinity[irq])
+ return;
+
+ while (!cpu_possible(cpu))
+ cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
+ last_cpu = cpu;
+
+ irq_affinity[irq] = cpumask_of_cpu(cpu);
+ irq_desc[irq].handler->set_affinity(irq, cpumask_of_cpu(cpu));
+}
+
+static int
+irq_affinity_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
+ if (count - len < 2)
+ return -EINVAL;
+ len += sprintf(page + len, "\n");
+ return len;
+}
+
+static int
+irq_affinity_write_proc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ int irq = (long) data, full_count = count, err;
+ cpumask_t new_value;
+
+ if (!irq_desc[irq].handler->set_affinity)
+ return -EIO;
+
+ err = cpumask_parse(buffer, count, new_value);
+
+ /* The special value 0 means release control of the
+ affinity to kernel. */
+ cpus_and(new_value, new_value, cpu_online_map);
+ if (cpus_empty(new_value)) {
+ irq_user_affinity[irq] = 0;
+ select_smp_affinity(irq);
+ }
+ /* Do not allow disabling IRQs completely - it's a too easy
+ way to make the system unusable accidentally :-) At least
+ one online CPU still has to be targeted. */
+ else {
+ irq_affinity[irq] = new_value;
+ irq_user_affinity[irq] = 1;
+ irq_desc[irq].handler->set_affinity(irq, new_value);
+ }
+
+ return full_count;
+}
+
+#endif /* CONFIG_SMP */
+
+#define MAX_NAMELEN 10
+
+static void
+register_irq_proc (unsigned int irq)
+{
+ char name [MAX_NAMELEN];
+
+ if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+ irq_dir[irq])
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ sprintf(name, "%d", irq);
+
+ /* create /proc/irq/1234 */
+ irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+#ifdef CONFIG_SMP
+ if (irq_desc[irq].handler->set_affinity) {
+ struct proc_dir_entry *entry;
+ /* create /proc/irq/1234/smp_affinity */
+ entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+ if (entry) {
+ entry->nlink = 1;
+ entry->data = (void *)(long)irq;
+ entry->read_proc = irq_affinity_read_proc;
+ entry->write_proc = irq_affinity_write_proc;
+ }
+
+ smp_affinity_entry[irq] = entry;
+ }
+#endif
+}
+
+void
+init_irq_proc (void)
+{
+ int i;
+
+ /* create /proc/irq */
+ root_irq_dir = proc_mkdir("irq", NULL);
+
+#ifdef CONFIG_SMP
+ /* create /proc/irq/prof_cpu_mask */
+ create_prof_cpu_mask(root_irq_dir);
+#endif
+
+ /*
+ * Create entries for all existing IRQs.
+ */
+ for (i = 0; i < ACTUAL_NR_IRQS; i++) {
+ if (irq_desc[i].handler == &no_irq_type)
+ continue;
+ register_irq_proc(i);
+ }
+}
+
+int
+request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
+{
+ int retval;
+ struct irqaction * action;
+
+ if (irq >= ACTUAL_NR_IRQS)
+ return -EINVAL;
+ if (!handler)
+ return -EINVAL;
+
+#if 1
+ /*
+ * Sanity-check: shared interrupts should REALLY pass in
+ * a real dev-ID, otherwise we'll have trouble later trying
+ * to figure out which interrupt is which (messes up the
+ * interrupt freeing logic etc).
+ */
+ if ((irqflags & SA_SHIRQ) && !dev_id) {
+ printk(KERN_ERR
+ "Bad boy: %s (at %p) called us without a dev_id!\n",
+ devname, __builtin_return_address(0));
+ }
+#endif
+
+ action = (struct irqaction *)
+ kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ cpus_clear(action->mask);
+ action->name = devname;
+ action->next = NULL;
+ action->dev_id = dev_id;
+
+#ifdef CONFIG_SMP
+ select_smp_affinity(irq);
+#endif
+
+ retval = setup_irq(irq, action);
+ if (retval)
+ kfree(action);
+ return retval;
+}
+
+EXPORT_SYMBOL(request_irq);
+
+void
+free_irq(unsigned int irq, void *dev_id)
+{
+ irq_desc_t *desc;
+ struct irqaction **p;
+ unsigned long flags;
+
+ if (irq >= ACTUAL_NR_IRQS) {
+ printk(KERN_CRIT "Trying to free IRQ%d\n", irq);
+ return;
+ }
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ for (;;) {
+ struct irqaction * action = *p;
+ if (action) {
+ struct irqaction **pp = p;
+ p = &action->next;
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found - now remove it from the list of entries. */
+ *pp = action->next;
+ if (!desc->action) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->shutdown(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+#ifdef CONFIG_SMP
+ /* Wait to make sure it's not being used on
+ another CPU. */
+ while (desc->status & IRQ_INPROGRESS)
+ barrier();
+#endif
+ kfree(action);
+ return;
+ }
+ printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return;
+ }
+}
+
+EXPORT_SYMBOL(free_irq);
+
+int
+show_interrupts(struct seq_file *p, void *v)
+{
+#ifdef CONFIG_SMP
+ int j;
+#endif
+ int i = *(loff_t *) v;
+ struct irqaction * action;
+ unsigned long flags;
+
+#ifdef CONFIG_SMP
+ if (i == 0) {
+ seq_puts(p, " ");
+ for (i = 0; i < NR_CPUS; i++)
+ if (cpu_online(i))
+ seq_printf(p, "CPU%d ", i);
+ seq_putc(p, '\n');
+ }
+#endif
+
+ if (i < ACTUAL_NR_IRQS) {
+ spin_lock_irqsave(&irq_desc[i].lock, flags);
+ action = irq_desc[i].action;
+ if (!action)
+ goto unlock;
+ seq_printf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+ seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+ for (j = 0; j < NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+ seq_printf(p, " %14s", irq_desc[i].handler->typename);
+ seq_printf(p, " %c%s",
+ (action->flags & SA_INTERRUPT)?'+':' ',
+ action->name);
+
+ for (action=action->next; action; action = action->next) {
+ seq_printf(p, ", %c%s",
+ (action->flags & SA_INTERRUPT)?'+':' ',
+ action->name);
+ }
+
+ seq_putc(p, '\n');
+unlock:
+ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+ } else if (i == ACTUAL_NR_IRQS) {
+#ifdef CONFIG_SMP
+ seq_puts(p, "IPI: ");
+ for (i = 0; i < NR_CPUS; i++)
+ if (cpu_online(i))
+ seq_printf(p, "%10lu ", cpu_data[i].ipi_count);
+ seq_putc(p, '\n');
+#endif
+ seq_printf(p, "ERR: %10lu\n", irq_err_count);
+ }
+ return 0;
+}
+
+
+/*
+ * handle_irq handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+
+#define MAX_ILLEGAL_IRQS 16
+
+void
+handle_irq(int irq, struct pt_regs * regs)
+{
+ /*
+ * We ack quickly, we don't want the irq controller
+ * thinking we're snobs just because some other CPU has
+ * disabled global interrupts (we have already done the
+ * INT_ACK cycles, it's too late to try to pretend to the
+ * controller that we aren't taking the interrupt).
+ *
+ * 0 return value means that this irq is already being
+ * handled by some other CPU. (or is disabled)
+ */
+ int cpu = smp_processor_id();
+ irq_desc_t *desc = irq_desc + irq;
+ struct irqaction * action;
+ unsigned int status;
+ static unsigned int illegal_count=0;
+
+ if ((unsigned) irq > ACTUAL_NR_IRQS && illegal_count < MAX_ILLEGAL_IRQS ) {
+ irq_err_count++;
+ illegal_count++;
+ printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
+ irq);
+ return;
+ }
+
+ irq_enter();
+ kstat_cpu(cpu).irqs[irq]++;
+ spin_lock_irq(&desc->lock); /* mask also the higher prio events */
+ desc->handler->ack(irq);
+ /*
+ * REPLAY is when Linux resends an IRQ that was dropped earlier.
+ * WAITING is used by probe to mark irqs that are being tested.
+ */
+ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+ status |= IRQ_PENDING; /* we _want_ to handle it */
+
+ /*
+ * If the IRQ is disabled for whatever reason, we cannot
+ * use the action we have.
+ */
+ action = NULL;
+ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+ action = desc->action;
+ status &= ~IRQ_PENDING; /* we commit to handling */
+ status |= IRQ_INPROGRESS; /* we are handling it */
+ }
+ desc->status = status;
+
+ /*
+ * If there is no IRQ handler or it was disabled, exit early.
+ * Since we set PENDING, if another processor is handling
+ * a different instance of this same irq, the other processor
+ * will take care of it.
+ */
+ if (!action)
+ goto out;
+
+ /*
+ * Edge triggered interrupts need to remember pending events.
+ * This applies to any hw interrupts that allow a second
+ * instance of the same irq to arrive while we are in handle_irq
+ * or in the handler. But the code here only handles the _second_
+ * instance of the irq, not the third or fourth. So it is mostly
+ * useful for irq hardware that does not mask cleanly in an
+ * SMP environment.
+ */
+ for (;;) {
+ spin_unlock(&desc->lock);
+ handle_IRQ_event(irq, regs, action);
+ spin_lock(&desc->lock);
+
+ if (!(desc->status & IRQ_PENDING)
+ || (desc->status & IRQ_LEVEL))
+ break;
+ desc->status &= ~IRQ_PENDING;
+ }
+ desc->status &= ~IRQ_INPROGRESS;
+out:
+ /*
+ * The ->end() handler has to deal with interrupts which got
+ * disabled while the handler was running.
+ */
+ desc->handler->end(irq);
+ spin_unlock(&desc->lock);
+
+ irq_exit();
+}
+
+/*
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
+ */
+unsigned long
+probe_irq_on(void)
+{
+ int i;
+ irq_desc_t *desc;
+ unsigned long delay;
+ unsigned long val;
+
+ /* Something may have generated an irq long ago and we want to
+ flush such a longstanding irq before considering it as spurious. */
+ for (i = NR_IRQS-1; i >= 0; i--) {
+ desc = irq_desc + i;
+
+ spin_lock_irq(&desc->lock);
+ if (!irq_desc[i].action)
+ irq_desc[i].handler->startup(i);
+ spin_unlock_irq(&desc->lock);
+ }
+
+ /* Wait for longstanding interrupts to trigger. */
+ for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+ /* about 20ms delay */ barrier();
+
+ /* enable any unassigned irqs (we must startup again here because
+ if a longstanding irq happened in the previous stage, it may have
+ masked itself) first, enable any unassigned irqs. */
+ for (i = NR_IRQS-1; i >= 0; i--) {
+ desc = irq_desc + i;
+
+ spin_lock_irq(&desc->lock);
+ if (!desc->action) {
+ desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+ if (desc->handler->startup(i))
+ desc->status |= IRQ_PENDING;
+ }
+ spin_unlock_irq(&desc->lock);
+ }
+
+ /*
+ * Wait for spurious interrupts to trigger
+ */
+ for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+ /* about 100ms delay */ barrier();
+
+ /*
+ * Now filter out any obviously spurious interrupts
+ */
+ val = 0;
+ for (i=0; i<NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ /* It triggered already - consider it spurious. */
+ if (!(status & IRQ_WAITING)) {
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ } else
+ if (i < 32)
+ val |= 1 << i;
+ }
+ spin_unlock_irq(&desc->lock);
+ }
+
+ return val;
+}
+
+EXPORT_SYMBOL(probe_irq_on);
+
+/*
+ * Return a mask of triggered interrupts (this
+ * can handle only legacy ISA interrupts).
+ */
+unsigned int
+probe_irq_mask(unsigned long val)
+{
+ int i;
+ unsigned int mask;
+
+ mask = 0;
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ /* We only react to ISA interrupts */
+ if (!(status & IRQ_WAITING)) {
+ if (i < 16)
+ mask |= 1 << i;
+ }
+
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ }
+ spin_unlock_irq(&desc->lock);
+ }
+
+ return mask & val;
+}
+
+/*
+ * Get the result of the IRQ probe.. A negative result means that
+ * we have several candidates (but we return the lowest-numbered
+ * one).
+ */
+
+int
+probe_irq_off(unsigned long val)
+{
+ int i, irq_found, nr_irqs;
+
+ nr_irqs = 0;
+ irq_found = 0;
+ for (i=0; i<NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ if (!(status & IRQ_WAITING)) {
+ if (!nr_irqs)
+ irq_found = i;
+ nr_irqs++;
+ }
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ }
+ spin_unlock_irq(&desc->lock);
+ }
+
+ if (nr_irqs > 1)
+ irq_found = -irq_found;
+ return irq_found;
+}
+
+EXPORT_SYMBOL(probe_irq_off);
+
+#ifdef CONFIG_SMP
+void synchronize_irq(unsigned int irq)
+{
+ /* is there anything to synchronize with? */
+ if (!irq_desc[irq].action)
+ return;
+
+ while (irq_desc[irq].status & IRQ_INPROGRESS)
+ barrier();
+}
+#endif
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
new file mode 100644
index 000000000000..e6ded33c6e22
--- /dev/null
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -0,0 +1,252 @@
+/*
+ * Alpha specific irq code.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/machvec.h>
+#include <asm/dma.h>
+
+#include "proto.h"
+#include "irq_impl.h"
+
+/* Hack minimum IPL during interrupt processing for broken hardware. */
+#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+int __min_ipl;
+#endif
+
+/*
+ * Performance counter hook. A module can override this to
+ * do something useful.
+ */
+static void
+dummy_perf(unsigned long vector, struct pt_regs *regs)
+{
+ irq_err_count++;
+ printk(KERN_CRIT "Performance counter interrupt!\n");
+}
+
+void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf;
+
+/*
+ * The main interrupt entry point.
+ */
+
+asmlinkage void
+do_entInt(unsigned long type, unsigned long vector,
+ unsigned long la_ptr, struct pt_regs *regs)
+{
+ switch (type) {
+ case 0:
+#ifdef CONFIG_SMP
+ handle_ipi(regs);
+ return;
+#else
+ irq_err_count++;
+ printk(KERN_CRIT "Interprocessor interrupt? "
+ "You must be kidding!\n");
+#endif
+ break;
+ case 1:
+#ifdef CONFIG_SMP
+ {
+ long cpu;
+ smp_percpu_timer_interrupt(regs);
+ cpu = smp_processor_id();
+ if (cpu != boot_cpuid) {
+ kstat_cpu(cpu).irqs[RTC_IRQ]++;
+ } else {
+ handle_irq(RTC_IRQ, regs);
+ }
+ }
+#else
+ handle_irq(RTC_IRQ, regs);
+#endif
+ return;
+ case 2:
+ alpha_mv.machine_check(vector, la_ptr, regs);
+ return;
+ case 3:
+ alpha_mv.device_interrupt(vector, regs);
+ return;
+ case 4:
+ perf_irq(la_ptr, regs);
+ return;
+ default:
+ printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n",
+ type, vector);
+ }
+ printk(KERN_CRIT "PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
+}
+
+void __init
+common_init_isa_dma(void)
+{
+ outb(0, DMA1_RESET_REG);
+ outb(0, DMA2_RESET_REG);
+ outb(0, DMA1_CLR_MASK_REG);
+ outb(0, DMA2_CLR_MASK_REG);
+}
+
+void __init
+init_IRQ(void)
+{
+ /* Just in case the platform init_irq() causes interrupts/mchecks
+ (as is the case with RAWHIDE, at least). */
+ wrent(entInt, 0);
+
+ alpha_mv.init_irq();
+}
+
+/*
+ * machine error checks
+ */
+#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_OS_BUGCHECK 0x008A
+#define MCHK_K_PAL_BUGCHECK 0x0090
+
+#ifndef CONFIG_SMP
+struct mcheck_info __mcheck_info;
+#endif
+
+void
+process_mcheck_info(unsigned long vector, unsigned long la_ptr,
+ struct pt_regs *regs, const char *machine,
+ int expected)
+{
+ struct el_common *mchk_header;
+ const char *reason;
+
+ /*
+ * See if the machine check is due to a badaddr() and if so,
+ * ignore it.
+ */
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (alpha_verbose_mcheck > 1) {
+ printk(KERN_CRIT "%s machine check %s\n", machine,
+ expected ? "expected." : "NOT expected!!!");
+ }
+#endif
+
+ if (expected) {
+ int cpu = smp_processor_id();
+ mcheck_expected(cpu) = 0;
+ mcheck_taken(cpu) = 1;
+ return;
+ }
+
+ mchk_header = (struct el_common *)la_ptr;
+
+ printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n",
+ machine, vector, regs->pc, mchk_header->code);
+
+ switch (mchk_header->code) {
+ /* Machine check reasons. Defined according to PALcode sources. */
+ case 0x80: reason = "tag parity error"; break;
+ case 0x82: reason = "tag control parity error"; break;
+ case 0x84: reason = "generic hard error"; break;
+ case 0x86: reason = "correctable ECC error"; break;
+ case 0x88: reason = "uncorrectable ECC error"; break;
+ case 0x8A: reason = "OS-specific PAL bugcheck"; break;
+ case 0x90: reason = "callsys in kernel mode"; break;
+ case 0x96: reason = "i-cache read retryable error"; break;
+ case 0x98: reason = "processor detected hard error"; break;
+
+ /* System specific (these are for Alcor, at least): */
+ case 0x202: reason = "system detected hard error"; break;
+ case 0x203: reason = "system detected uncorrectable ECC error"; break;
+ case 0x204: reason = "SIO SERR occurred on PCI bus"; break;
+ case 0x205: reason = "parity error detected by core logic"; break;
+ case 0x206: reason = "SIO IOCHK occurred on ISA bus"; break;
+ case 0x207: reason = "non-existent memory error"; break;
+ case 0x208: reason = "MCHK_K_DCSR"; break;
+ case 0x209: reason = "PCI SERR detected"; break;
+ case 0x20b: reason = "PCI data parity error detected"; break;
+ case 0x20d: reason = "PCI address parity error detected"; break;
+ case 0x20f: reason = "PCI master abort error"; break;
+ case 0x211: reason = "PCI target abort error"; break;
+ case 0x213: reason = "scatter/gather PTE invalid error"; break;
+ case 0x215: reason = "flash ROM write error"; break;
+ case 0x217: reason = "IOA timeout detected"; break;
+ case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break;
+ case 0x21b: reason = "EISA fail-safe timer timeout"; break;
+ case 0x21d: reason = "EISA bus time-out"; break;
+ case 0x21f: reason = "EISA software generated NMI"; break;
+ case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break;
+ default: reason = "unknown"; break;
+ }
+
+ printk(KERN_CRIT "machine check type: %s%s\n",
+ reason, mchk_header->retry ? " (retryable)" : "");
+
+ dik_show_regs(regs, NULL);
+
+#ifdef CONFIG_VERBOSE_MCHECK
+ if (alpha_verbose_mcheck > 1) {
+ /* Dump the logout area to give all info. */
+ unsigned long *ptr = (unsigned long *)la_ptr;
+ long i;
+ for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+ printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+ i*sizeof(long), ptr[i], ptr[i+1]);
+ }
+ }
+#endif /* CONFIG_VERBOSE_MCHECK */
+}
+
+/*
+ * The special RTC interrupt type. The interrupt itself was
+ * processed by PALcode, and comes in via entInt vector 1.
+ */
+
+static void rtc_enable_disable(unsigned int irq) { }
+static unsigned int rtc_startup(unsigned int irq) { return 0; }
+
+struct irqaction timer_irqaction = {
+ .handler = timer_interrupt,
+ .flags = SA_INTERRUPT,
+ .name = "timer",
+};
+
+static struct hw_interrupt_type rtc_irq_type = {
+ .typename = "RTC",
+ .startup = rtc_startup,
+ .shutdown = rtc_enable_disable,
+ .enable = rtc_enable_disable,
+ .disable = rtc_enable_disable,
+ .ack = rtc_enable_disable,
+ .end = rtc_enable_disable,
+};
+
+void __init
+init_rtc_irq(void)
+{
+ irq_desc[RTC_IRQ].status = IRQ_DISABLED;
+ irq_desc[RTC_IRQ].handler = &rtc_irq_type;
+ setup_irq(RTC_IRQ, &timer_irqaction);
+}
+
+/* Dummy irqactions. */
+struct irqaction isa_cascade_irqaction = {
+ .handler = no_action,
+ .name = "isa-cascade"
+};
+
+struct irqaction timer_cascade_irqaction = {
+ .handler = no_action,
+ .name = "timer-cascade"
+};
+
+struct irqaction halt_switch_irqaction = {
+ .handler = no_action,
+ .name = "halt-switch"
+};
diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c
new file mode 100644
index 000000000000..b188683b83fd
--- /dev/null
+++ b/arch/alpha/kernel/irq_i8259.c
@@ -0,0 +1,183 @@
+/*
+ * linux/arch/alpha/kernel/irq_i8259.c
+ *
+ * This is the 'legacy' 8259A Programmable Interrupt Controller,
+ * present in the majority of PC/AT boxes.
+ *
+ * Started hacking from linux-2.3.30pre6/arch/i386/kernel/i8259.c.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/cache.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+
+#include "proto.h"
+#include "irq_impl.h"
+
+
+/* Note mask bit is true for DISABLED irqs. */
+static unsigned int cached_irq_mask = 0xffff;
+static DEFINE_SPINLOCK(i8259_irq_lock);
+
+static inline void
+i8259_update_irq_hw(unsigned int irq, unsigned long mask)
+{
+ int port = 0x21;
+ if (irq & 8) mask >>= 8;
+ if (irq & 8) port = 0xA1;
+ outb(mask, port);
+}
+
+inline void
+i8259a_enable_irq(unsigned int irq)
+{
+ spin_lock(&i8259_irq_lock);
+ i8259_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
+ spin_unlock(&i8259_irq_lock);
+}
+
+static inline void
+__i8259a_disable_irq(unsigned int irq)
+{
+ i8259_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
+}
+
+void
+i8259a_disable_irq(unsigned int irq)
+{
+ spin_lock(&i8259_irq_lock);
+ __i8259a_disable_irq(irq);
+ spin_unlock(&i8259_irq_lock);
+}
+
+void
+i8259a_mask_and_ack_irq(unsigned int irq)
+{
+ spin_lock(&i8259_irq_lock);
+ __i8259a_disable_irq(irq);
+
+ /* Ack the interrupt making it the lowest priority. */
+ if (irq >= 8) {
+ outb(0xE0 | (irq - 8), 0xa0); /* ack the slave */
+ irq = 2;
+ }
+ outb(0xE0 | irq, 0x20); /* ack the master */
+ spin_unlock(&i8259_irq_lock);
+}
+
+unsigned int
+i8259a_startup_irq(unsigned int irq)
+{
+ i8259a_enable_irq(irq);
+ return 0; /* never anything pending */
+}
+
+void
+i8259a_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ i8259a_enable_irq(irq);
+}
+
+struct hw_interrupt_type i8259a_irq_type = {
+ .typename = "XT-PIC",
+ .startup = i8259a_startup_irq,
+ .shutdown = i8259a_disable_irq,
+ .enable = i8259a_enable_irq,
+ .disable = i8259a_disable_irq,
+ .ack = i8259a_mask_and_ack_irq,
+ .end = i8259a_end_irq,
+};
+
+void __init
+init_i8259a_irqs(void)
+{
+ static struct irqaction cascade = {
+ .handler = no_action,
+ .name = "cascade",
+ };
+
+ long i;
+
+ outb(0xff, 0x21); /* mask all of 8259A-1 */
+ outb(0xff, 0xA1); /* mask all of 8259A-2 */
+
+ for (i = 0; i < 16; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &i8259a_irq_type;
+ }
+
+ setup_irq(2, &cascade);
+}
+
+
+#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)
+# define IACK_SC PYXIS_IACK_SC
+#elif defined(CONFIG_ALPHA_TITAN)
+# define IACK_SC TITAN_IACK_SC
+#elif defined(CONFIG_ALPHA_TSUNAMI)
+# define IACK_SC TSUNAMI_IACK_SC
+#elif defined(CONFIG_ALPHA_IRONGATE)
+# define IACK_SC IRONGATE_IACK_SC
+#endif
+/* Note that CONFIG_ALPHA_POLARIS is intentionally left out here, since
+ sys_rx164 wants to use isa_no_iack_sc_device_interrupt for some reason. */
+
+#if defined(IACK_SC)
+void
+isa_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
+ /*
+ * Generate a PCI interrupt acknowledge cycle. The PIC will
+ * respond with the interrupt vector of the highest priority
+ * interrupt that is pending. The PALcode sets up the
+ * interrupts vectors such that irq level L generates vector L.
+ */
+ int j = *(vuip) IACK_SC;
+ j &= 0xff;
+ handle_irq(j, regs);
+}
+#endif
+
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC)
+void
+isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
+ unsigned long pic;
+
+ /*
+ * It seems to me that the probability of two or more *device*
+ * interrupts occurring at almost exactly the same time is
+ * pretty low. So why pay the price of checking for
+ * additional interrupts here if the common case can be
+ * handled so much easier?
+ */
+ /*
+ * The first read of gives you *all* interrupting lines.
+ * Therefore, read the mask register and and out those lines
+ * not enabled. Note that some documentation has 21 and a1
+ * write only. This is not true.
+ */
+ pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */
+ pic &= 0xFFFB; /* mask out cascade & hibits */
+
+ while (pic) {
+ int j = ffz(~pic);
+ pic &= pic - 1;
+ handle_irq(j, regs);
+ }
+}
+#endif
diff --git a/arch/alpha/kernel/irq_impl.h b/arch/alpha/kernel/irq_impl.h
new file mode 100644
index 000000000000..f201d8ffc0d9
--- /dev/null
+++ b/arch/alpha/kernel/irq_impl.h
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/alpha/kernel/irq_impl.h
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright (C) 1998, 2000 Richard Henderson
+ *
+ * This file contains declarations and inline functions for interfacing
+ * with the IRQ handling routines in irq.c.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+
+
+#define RTC_IRQ 8
+
+extern void isa_device_interrupt(unsigned long, struct pt_regs *);
+extern void isa_no_iack_sc_device_interrupt(unsigned long, struct pt_regs *);
+extern void srm_device_interrupt(unsigned long, struct pt_regs *);
+extern void pyxis_device_interrupt(unsigned long, struct pt_regs *);
+
+extern struct irqaction timer_irqaction;
+extern struct irqaction isa_cascade_irqaction;
+extern struct irqaction timer_cascade_irqaction;
+extern struct irqaction halt_switch_irqaction;
+
+extern void init_srm_irqs(long, unsigned long);
+extern void init_pyxis_irqs(unsigned long);
+extern void init_rtc_irq(void);
+
+extern void common_init_isa_dma(void);
+
+extern void i8259a_enable_irq(unsigned int);
+extern void i8259a_disable_irq(unsigned int);
+extern void i8259a_mask_and_ack_irq(unsigned int);
+extern unsigned int i8259a_startup_irq(unsigned int);
+extern void i8259a_end_irq(unsigned int);
+extern struct hw_interrupt_type i8259a_irq_type;
+extern void init_i8259a_irqs(void);
+
+extern void handle_irq(int irq, struct pt_regs * regs);
diff --git a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c
new file mode 100644
index 000000000000..146a20b9e3d5
--- /dev/null
+++ b/arch/alpha/kernel/irq_pyxis.c
@@ -0,0 +1,127 @@
+/*
+ * linux/arch/alpha/kernel/irq_pyxis.c
+ *
+ * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
+ *
+ * IRQ Code common to all PYXIS core logic chips.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/core_cia.h>
+
+#include "proto.h"
+#include "irq_impl.h"
+
+
+/* Note mask bit is true for ENABLED irqs. */
+static unsigned long cached_irq_mask;
+
+static inline void
+pyxis_update_irq_hw(unsigned long mask)
+{
+ *(vulp)PYXIS_INT_MASK = mask;
+ mb();
+ *(vulp)PYXIS_INT_MASK;
+}
+
+static inline void
+pyxis_enable_irq(unsigned int irq)
+{
+ pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+}
+
+static void
+pyxis_disable_irq(unsigned int irq)
+{
+ pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+}
+
+static unsigned int
+pyxis_startup_irq(unsigned int irq)
+{
+ pyxis_enable_irq(irq);
+ return 0;
+}
+
+static void
+pyxis_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ pyxis_enable_irq(irq);
+}
+
+static void
+pyxis_mask_and_ack_irq(unsigned int irq)
+{
+ unsigned long bit = 1UL << (irq - 16);
+ unsigned long mask = cached_irq_mask &= ~bit;
+
+ /* Disable the interrupt. */
+ *(vulp)PYXIS_INT_MASK = mask;
+ wmb();
+ /* Ack PYXIS PCI interrupt. */
+ *(vulp)PYXIS_INT_REQ = bit;
+ mb();
+ /* Re-read to force both writes. */
+ *(vulp)PYXIS_INT_MASK;
+}
+
+static struct hw_interrupt_type pyxis_irq_type = {
+ .typename = "PYXIS",
+ .startup = pyxis_startup_irq,
+ .shutdown = pyxis_disable_irq,
+ .enable = pyxis_enable_irq,
+ .disable = pyxis_disable_irq,
+ .ack = pyxis_mask_and_ack_irq,
+ .end = pyxis_end_irq,
+};
+
+void
+pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
+ unsigned long pld;
+ unsigned int i;
+
+ /* Read the interrupt summary register of PYXIS */
+ pld = *(vulp)PYXIS_INT_REQ;
+ pld &= cached_irq_mask;
+
+ /*
+ * 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 == 7)
+ isa_device_interrupt(vector, regs);
+ else
+ handle_irq(16+i, regs);
+ }
+}
+
+void __init
+init_pyxis_irqs(unsigned long ignore_mask)
+{
+ long i;
+
+ *(vulp)PYXIS_INT_MASK = 0; /* disable all */
+ *(vulp)PYXIS_INT_REQ = -1; /* flush all */
+ mb();
+
+ /* Send -INTA pulses to clear any pending interrupts ...*/
+ *(vuip) CIA_IACK_SC;
+
+ for (i = 16; i < 48; ++i) {
+ if ((ignore_mask >> i) & 1)
+ continue;
+ irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
+ irq_desc[i].handler = &pyxis_irq_type;
+ }
+
+ setup_irq(16+7, &isa_cascade_irqaction);
+}
diff --git a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c
new file mode 100644
index 000000000000..0a87e466918c
--- /dev/null
+++ b/arch/alpha/kernel/irq_srm.c
@@ -0,0 +1,79 @@
+/*
+ * Handle interrupts from the SRM, assuming no additional weirdness.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+
+#include "proto.h"
+#include "irq_impl.h"
+
+
+/*
+ * Is the palcode SMP safe? In other words: can we call cserve_ena/dis
+ * at the same time in multiple CPUs? To be safe I added a spinlock
+ * but it can be removed trivially if the palcode is robust against smp.
+ */
+DEFINE_SPINLOCK(srm_irq_lock);
+
+static inline void
+srm_enable_irq(unsigned int irq)
+{
+ spin_lock(&srm_irq_lock);
+ cserve_ena(irq - 16);
+ spin_unlock(&srm_irq_lock);
+}
+
+static void
+srm_disable_irq(unsigned int irq)
+{
+ spin_lock(&srm_irq_lock);
+ cserve_dis(irq - 16);
+ spin_unlock(&srm_irq_lock);
+}
+
+static unsigned int
+srm_startup_irq(unsigned int irq)
+{
+ srm_enable_irq(irq);
+ return 0;
+}
+
+static void
+srm_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ srm_enable_irq(irq);
+}
+
+/* Handle interrupts from the SRM, assuming no additional weirdness. */
+static struct hw_interrupt_type srm_irq_type = {
+ .typename = "SRM",
+ .startup = srm_startup_irq,
+ .shutdown = srm_disable_irq,
+ .enable = srm_enable_irq,
+ .disable = srm_disable_irq,
+ .ack = srm_disable_irq,
+ .end = srm_end_irq,
+};
+
+void __init
+init_srm_irqs(long max, unsigned long ignore_mask)
+{
+ long i;
+
+ for (i = 16; i < max; ++i) {
+ if (i < 64 && ((ignore_mask >> i) & 1))
+ continue;
+ irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
+ irq_desc[i].handler = &srm_irq_type;
+ }
+}
+
+void
+srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+ int irq = (vector - 0x800) >> 4;
+ handle_irq(irq, regs);
+}
diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h
new file mode 100644
index 000000000000..4959b7a3e1e6
--- /dev/null
+++ b/arch/alpha/kernel/machvec_impl.h
@@ -0,0 +1,150 @@
+/*
+ * linux/arch/alpha/kernel/machvec.h
+ *
+ * Copyright (C) 1997, 1998 Richard Henderson
+ *
+ * This file has goodies to help simplify instantiation of machine vectors.
+ */
+
+#include <linux/config.h>
+#include <asm/pgalloc.h>
+
+/* Whee. These systems don't have an HAE:
+ IRONGATE, MARVEL, POLARIS, TSUNAMI, TITAN, WILDFIRE
+ Fix things up for the GENERIC kernel by defining the HAE address
+ to be that of the cache. Now we can read and write it as we like. ;-) */
+#define IRONGATE_HAE_ADDRESS (&alpha_mv.hae_cache)
+#define MARVEL_HAE_ADDRESS (&alpha_mv.hae_cache)
+#define POLARIS_HAE_ADDRESS (&alpha_mv.hae_cache)
+#define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache)
+#define TITAN_HAE_ADDRESS (&alpha_mv.hae_cache)
+#define WILDFIRE_HAE_ADDRESS (&alpha_mv.hae_cache)
+
+#ifdef CIA_ONE_HAE_WINDOW
+#define CIA_HAE_ADDRESS (&alpha_mv.hae_cache)
+#endif
+#ifdef MCPCIA_ONE_HAE_WINDOW
+#define MCPCIA_HAE_ADDRESS (&alpha_mv.hae_cache)
+#endif
+
+/* Only a few systems don't define IACK_SC, handling all interrupts through
+ the SRM console. But splitting out that one case from IO() below
+ seems like such a pain. Define this to get things to compile. */
+#define JENSEN_IACK_SC 1
+#define T2_IACK_SC 1
+#define WILDFIRE_IACK_SC 1 /* FIXME */
+
+/*
+ * Some helpful macros for filling in the blanks.
+ */
+
+#define CAT1(x,y) x##y
+#define CAT(x,y) CAT1(x,y)
+
+#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, \
+ .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, \
+ .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, \
+ .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), \
+ .iack_sc = CAT(UP,_IACK_SC), \
+ .mv_ioread8 = CAT(low,_ioread8), \
+ .mv_ioread16 = CAT(low,_ioread16), \
+ .mv_ioread32 = CAT(low,_ioread32), \
+ .mv_iowrite8 = CAT(low,_iowrite8), \
+ .mv_iowrite16 = CAT(low,_iowrite16), \
+ .mv_iowrite32 = CAT(low,_iowrite32), \
+ .mv_readb = CAT(low,_readb), \
+ .mv_readw = CAT(low,_readw), \
+ .mv_readl = CAT(low,_readl), \
+ .mv_readq = CAT(low,_readq), \
+ .mv_writeb = CAT(low,_writeb), \
+ .mv_writew = CAT(low,_writew), \
+ .mv_writel = CAT(low,_writel), \
+ .mv_writeq = CAT(low,_writeq), \
+ .mv_ioportmap = CAT(low,_ioportmap), \
+ .mv_ioremap = CAT(low,_ioremap), \
+ .mv_iounmap = CAT(low,_iounmap), \
+ .mv_is_ioaddr = CAT(low,_is_ioaddr), \
+ .mv_is_mmio = CAT(low,_is_mmio) \
+
+#define IO(UP,low) \
+ IO_LITE(UP,low), \
+ .pci_ops = &CAT(low,_pci_ops), \
+ .mv_pci_tbi = CAT(low,_pci_tbi)
+
+#define DO_APECS_IO IO(APECS,apecs)
+#define DO_CIA_IO IO(CIA,cia)
+#define DO_IRONGATE_IO IO(IRONGATE,irongate)
+#define DO_LCA_IO IO(LCA,lca)
+#define DO_MARVEL_IO IO(MARVEL,marvel)
+#define DO_MCPCIA_IO IO(MCPCIA,mcpcia)
+#define DO_POLARIS_IO IO(POLARIS,polaris)
+#define DO_T2_IO IO(T2,t2)
+#define DO_TSUNAMI_IO IO(TSUNAMI,tsunami)
+#define DO_TITAN_IO IO(TITAN,titan)
+#define DO_WILDFIRE_IO IO(WILDFIRE,wildfire)
+
+#define DO_PYXIS_IO IO_LITE(CIA,cia_bwx), \
+ .pci_ops = &cia_pci_ops, \
+ .mv_pci_tbi = cia_pci_tbi
+
+/*
+ * In a GENERIC kernel, we have lots of these vectors floating about,
+ * all but one of which we want to go away. In a non-GENERIC kernel,
+ * we want only one, ever.
+ *
+ * Accomplish this in the GENERIC kernel by putting all of the vectors
+ * in the .init.data section where they'll go away. We'll copy the
+ * one we want to the real alpha_mv vector in setup_arch.
+ *
+ * Accomplish this in a non-GENERIC kernel by ifdef'ing out all but
+ * one of the vectors, which will not reside in .init.data. We then
+ * alias this one vector to alpha_mv, so no copy is needed.
+ *
+ * Upshot: set __initdata to nothing for non-GENERIC kernels.
+ */
+
+#ifdef CONFIG_ALPHA_GENERIC
+#define __initmv __initdata
+#define ALIAS_MV(x)
+#else
+#define __initmv
+
+/* GCC actually has a syntax for defining aliases, but is under some
+ delusion that you shouldn't be able to declare it extern somewhere
+ else beforehand. Fine. We'll do it ourselves. */
+#if 0
+#define ALIAS_MV(system) \
+ struct alpha_machine_vector alpha_mv __attribute__((alias(#system "_mv")));
+#else
+#define ALIAS_MV(system) \
+ asm(".global alpha_mv\nalpha_mv = " #system "_mv");
+#endif
+#endif /* GENERIC */
diff --git a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c
new file mode 100644
index 000000000000..fc271e316a38
--- /dev/null
+++ b/arch/alpha/kernel/module.c
@@ -0,0 +1,311 @@
+/* Kernel module help for Alpha.
+ Copyright (C) 2002 Richard Henderson.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+void *
+module_alloc(unsigned long size)
+{
+ if (size == 0)
+ return NULL;
+ return vmalloc(size);
+}
+
+void
+module_free(struct module *mod, void *module_region)
+{
+ vfree(module_region);
+}
+
+/* Allocate the GOT at the end of the core sections. */
+
+struct got_entry {
+ struct got_entry *next;
+ Elf64_Addr r_offset;
+ int got_offset;
+};
+
+static inline void
+process_reloc_for_got(Elf64_Rela *rela,
+ struct got_entry *chains, Elf64_Xword *poffset)
+{
+ unsigned long r_sym = ELF64_R_SYM (rela->r_info);
+ unsigned long r_type = ELF64_R_TYPE (rela->r_info);
+ Elf64_Addr r_offset = rela->r_offset;
+ struct got_entry *g;
+
+ if (r_type != R_ALPHA_LITERAL)
+ return;
+
+ for (g = chains + r_sym; g ; g = g->next)
+ if (g->r_offset == r_offset) {
+ if (g->got_offset == 0) {
+ g->got_offset = *poffset;
+ *poffset += 8;
+ }
+ goto found_entry;
+ }
+
+ g = kmalloc (sizeof (*g), GFP_KERNEL);
+ g->next = chains[r_sym].next;
+ g->r_offset = r_offset;
+ g->got_offset = *poffset;
+ *poffset += 8;
+ chains[r_sym].next = g;
+
+ found_entry:
+ /* Trick: most of the ELF64_R_TYPE field is unused. There are
+ 42 valid relocation types, and a 32-bit field. Co-opt the
+ bits above 256 to store the got offset for this reloc. */
+ rela->r_info |= g->got_offset << 8;
+}
+
+int
+module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs,
+ char *secstrings, struct module *me)
+{
+ struct got_entry *chains;
+ Elf64_Rela *rela;
+ Elf64_Shdr *esechdrs, *symtab, *s, *got;
+ unsigned long nsyms, nrela, i;
+
+ esechdrs = sechdrs + hdr->e_shnum;
+ symtab = got = NULL;
+
+ /* Find out how large the symbol table is. Allocate one got_entry
+ head per symbol. Normally this will be enough, but not always.
+ We'll chain different offsets for the symbol down each head. */
+ for (s = sechdrs; s < esechdrs; ++s)
+ if (s->sh_type == SHT_SYMTAB)
+ symtab = s;
+ else if (!strcmp(".got", secstrings + s->sh_name)) {
+ got = s;
+ me->arch.gotsecindex = s - sechdrs;
+ }
+
+ if (!symtab) {
+ printk(KERN_ERR "module %s: no symbol table\n", me->name);
+ return -ENOEXEC;
+ }
+ if (!got) {
+ printk(KERN_ERR "module %s: no got section\n", me->name);
+ return -ENOEXEC;
+ }
+
+ nsyms = symtab->sh_size / sizeof(Elf64_Sym);
+ chains = kmalloc(nsyms * sizeof(struct got_entry), GFP_KERNEL);
+ memset(chains, 0, nsyms * sizeof(struct got_entry));
+
+ got->sh_size = 0;
+ got->sh_addralign = 8;
+ got->sh_type = SHT_NOBITS;
+
+ /* Examine all LITERAL relocations to find out what GOT entries
+ are required. This sizes the GOT section as well. */
+ for (s = sechdrs; s < esechdrs; ++s)
+ if (s->sh_type == SHT_RELA) {
+ nrela = s->sh_size / sizeof(Elf64_Rela);
+ rela = (void *)hdr + s->sh_offset;
+ for (i = 0; i < nrela; ++i)
+ process_reloc_for_got(rela+i, chains,
+ &got->sh_size);
+ }
+
+ /* Free the memory we allocated. */
+ for (i = 0; i < nsyms; ++i) {
+ struct got_entry *g, *n;
+ for (g = chains[i].next; g ; g = n) {
+ n = g->next;
+ kfree(g);
+ }
+ }
+ kfree(chains);
+
+ return 0;
+}
+
+int
+apply_relocate(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex,
+ unsigned int relsec, struct module *me)
+{
+ printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name);
+ return -ENOEXEC;
+}
+
+int
+apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab,
+ unsigned int symindex, unsigned int relsec,
+ struct module *me)
+{
+ Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+ unsigned long i, n = sechdrs[relsec].sh_size / sizeof(*rela);
+ Elf64_Sym *symtab, *sym;
+ void *base, *location;
+ unsigned long got, gp;
+
+ DEBUGP("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+
+ base = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr;
+ symtab = (Elf64_Sym *)sechdrs[symindex].sh_addr;
+
+ /* The small sections were sorted to the end of the segment.
+ The following should definitely cover them. */
+ gp = (u64)me->module_core + me->core_size - 0x8000;
+ got = sechdrs[me->arch.gotsecindex].sh_addr;
+
+ for (i = 0; i < n; i++) {
+ unsigned long r_sym = ELF64_R_SYM (rela[i].r_info);
+ unsigned long r_type = ELF64_R_TYPE (rela[i].r_info);
+ unsigned long r_got_offset = r_type >> 8;
+ unsigned long value, hi, lo;
+ r_type &= 0xff;
+
+ /* This is where to make the change. */
+ location = base + rela[i].r_offset;
+
+ /* This is the symbol it is referring to. Note that all
+ unresolved symbols have been resolved. */
+ sym = symtab + r_sym;
+ value = sym->st_value + rela[i].r_addend;
+
+ switch (r_type) {
+ case R_ALPHA_NONE:
+ break;
+ case R_ALPHA_REFQUAD:
+ /* BUG() can produce misaligned relocations. */
+ ((u32 *)location)[0] = value;
+ ((u32 *)location)[1] = value >> 32;
+ break;
+ case R_ALPHA_GPREL32:
+ value -= gp;
+ if ((int)value != value)
+ goto reloc_overflow;
+ *(u32 *)location = value;
+ break;
+ case R_ALPHA_LITERAL:
+ hi = got + r_got_offset;
+ lo = hi - gp;
+ if ((short)lo != lo)
+ goto reloc_overflow;
+ *(u16 *)location = lo;
+ *(u64 *)hi = value;
+ break;
+ case R_ALPHA_LITUSE:
+ break;
+ case R_ALPHA_GPDISP:
+ value = gp - (u64)location;
+ lo = (short)value;
+ hi = (int)(value - lo);
+ if (hi + lo != value)
+ goto reloc_overflow;
+ *(u16 *)location = hi >> 16;
+ *(u16 *)(location + rela[i].r_addend) = lo;
+ break;
+ case R_ALPHA_BRSGP:
+ /* BRSGP is only allowed to bind to local symbols.
+ If the section is undef, this means that the
+ value was resolved from somewhere else. */
+ if (sym->st_shndx == SHN_UNDEF)
+ goto reloc_overflow;
+ if ((sym->st_other & STO_ALPHA_STD_GPLOAD) ==
+ STO_ALPHA_STD_GPLOAD)
+ /* Omit the prologue. */
+ value += 8;
+ /* FALLTHRU */
+ case R_ALPHA_BRADDR:
+ value -= (u64)location + 4;
+ if (value & 3)
+ goto reloc_overflow;
+ value = (long)value >> 2;
+ if (value + (1<<21) >= 1<<22)
+ goto reloc_overflow;
+ value &= 0x1fffff;
+ value |= *(u32 *)location & ~0x1fffff;
+ *(u32 *)location = value;
+ break;
+ case R_ALPHA_HINT:
+ break;
+ case R_ALPHA_SREL32:
+ value -= (u64)location;
+ if ((int)value != value)
+ goto reloc_overflow;
+ *(u32 *)location = value;
+ break;
+ case R_ALPHA_SREL64:
+ value -= (u64)location;
+ *(u64 *)location = value;
+ break;
+ case R_ALPHA_GPRELHIGH:
+ value = (long)(value - gp + 0x8000) >> 16;
+ if ((short) value != value)
+ goto reloc_overflow;
+ *(u16 *)location = value;
+ break;
+ case R_ALPHA_GPRELLOW:
+ value -= gp;
+ *(u16 *)location = value;
+ break;
+ case R_ALPHA_GPREL16:
+ value -= gp;
+ if ((short) value != value)
+ goto reloc_overflow;
+ *(u16 *)location = value;
+ break;
+ default:
+ printk(KERN_ERR "module %s: Unknown relocation: %lu\n",
+ me->name, r_type);
+ return -ENOEXEC;
+ reloc_overflow:
+ if (ELF64_ST_TYPE (sym->st_info) == STT_SECTION)
+ printk(KERN_ERR
+ "module %s: Relocation overflow vs section %d\n",
+ me->name, sym->st_shndx);
+ else
+ printk(KERN_ERR
+ "module %s: Relocation overflow vs %s\n",
+ me->name, strtab + sym->st_name);
+ return -ENOEXEC;
+ }
+ }
+
+ return 0;
+}
+
+int
+module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ return 0;
+}
+
+void
+module_arch_cleanup(struct module *mod)
+{
+}
diff --git a/arch/alpha/kernel/ns87312.c b/arch/alpha/kernel/ns87312.c
new file mode 100644
index 000000000000..342b56d24c20
--- /dev/null
+++ b/arch/alpha/kernel/ns87312.c
@@ -0,0 +1,38 @@
+/*
+ * linux/arch/alpha/kernel/ns87312.c
+ */
+
+#include <linux/init.h>
+#include <asm/io.h>
+#include "proto.h"
+
+
+/*
+ * The SRM console *disables* the IDE interface, this code ensures it's
+ * enabled.
+ *
+ * This code bangs on a control register of the 87312 Super I/O chip
+ * that implements parallel port/serial ports/IDE/FDI. Depending on
+ * the motherboard, the Super I/O chip can be configured through a
+ * pair of registers that are located either at I/O ports 0x26e/0x26f
+ * or 0x398/0x399. Unfortunately, autodetecting which base address is
+ * in use works only once (right after a reset). The Super I/O chip
+ * has the additional quirk that configuration register data must be
+ * written twice (I believe this is a safety feature to prevent
+ * accidental modification---fun, isn't it?).
+ */
+
+void __init
+ns87312_enable_ide(long ide_base)
+{
+ int data;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ outb(0, ide_base); /* set the index register for reg #0 */
+ data = inb(ide_base+1); /* read the current contents */
+ outb(0, ide_base); /* set the index register for reg #0 */
+ outb(data | 0x40, ide_base+1); /* turn on IDE */
+ outb(data | 0x40, ide_base+1); /* turn on IDE, really! */
+ local_irq_restore(flags);
+}
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
new file mode 100644
index 000000000000..b5d0fd2bb10a
--- /dev/null
+++ b/arch/alpha/kernel/osf_sys.c
@@ -0,0 +1,1345 @@
+/*
+ * linux/arch/alpha/kernel/osf_sys.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+/*
+ * This file handles some of the stranger OSF/1 system call interfaces.
+ * Some of the system calls expect a non-C calling standard, others have
+ * special parameter blocks..
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/syscalls.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/utsname.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/major.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/shm.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/types.h>
+#include <linux/ipc.h>
+#include <linux/namei.h>
+#include <linux/uio.h>
+#include <linux/vfs.h>
+
+#include <asm/fpu.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/sysinfo.h>
+#include <asm/hwrpb.h>
+#include <asm/processor.h>
+
+extern int do_pipe(int *);
+
+/*
+ * Brk needs to return an error. Still support Linux's brk(0) query idiom,
+ * which OSF programs just shouldn't be doing. We're still not quite
+ * identical to OSF as we don't return 0 on success, but doing otherwise
+ * would require changes to libc. Hopefully this is good enough.
+ */
+asmlinkage unsigned long
+osf_brk(unsigned long brk)
+{
+ unsigned long retval = sys_brk(brk);
+ if (brk && brk != retval)
+ retval = -ENOMEM;
+ return retval;
+}
+
+/*
+ * This is pure guess-work..
+ */
+asmlinkage int
+osf_set_program_attributes(unsigned long text_start, unsigned long text_len,
+ unsigned long bss_start, unsigned long bss_len)
+{
+ struct mm_struct *mm;
+
+ lock_kernel();
+ mm = current->mm;
+ mm->end_code = bss_start + bss_len;
+ mm->brk = bss_start + bss_len;
+#if 0
+ printk("set_program_attributes(%lx %lx %lx %lx)\n",
+ text_start, text_len, bss_start, bss_len);
+#endif
+ unlock_kernel();
+ return 0;
+}
+
+/*
+ * OSF/1 directory handling functions...
+ *
+ * The "getdents()" interface is much more sane: the "basep" stuff is
+ * braindamage (it can't really handle filesystems where the directory
+ * offset differences aren't the same as "d_reclen").
+ */
+#define NAME_OFFSET offsetof (struct osf_dirent, d_name)
+#define ROUND_UP(x) (((x)+3) & ~3)
+
+struct osf_dirent {
+ unsigned int d_ino;
+ unsigned short d_reclen;
+ unsigned short d_namlen;
+ char d_name[1];
+};
+
+struct osf_dirent_callback {
+ struct osf_dirent __user *dirent;
+ long __user *basep;
+ unsigned int count;
+ int error;
+};
+
+static int
+osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
+ ino_t ino, unsigned int d_type)
+{
+ struct osf_dirent __user *dirent;
+ struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
+ unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1);
+
+ buf->error = -EINVAL; /* only used if we fail */
+ if (reclen > buf->count)
+ return -EINVAL;
+ if (buf->basep) {
+ if (put_user(offset, buf->basep))
+ return -EFAULT;
+ buf->basep = NULL;
+ }
+ dirent = buf->dirent;
+ put_user(ino, &dirent->d_ino);
+ put_user(namlen, &dirent->d_namlen);
+ put_user(reclen, &dirent->d_reclen);
+ if (copy_to_user(dirent->d_name, name, namlen) ||
+ put_user(0, dirent->d_name + namlen))
+ return -EFAULT;
+ dirent = (void __user *)dirent + reclen;
+ buf->dirent = dirent;
+ buf->count -= reclen;
+ return 0;
+}
+
+asmlinkage int
+osf_getdirentries(unsigned int fd, struct osf_dirent __user *dirent,
+ unsigned int count, long __user *basep)
+{
+ int error;
+ struct file *file;
+ struct osf_dirent_callback buf;
+
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ buf.dirent = dirent;
+ buf.basep = basep;
+ buf.count = count;
+ buf.error = 0;
+
+ error = vfs_readdir(file, osf_filldir, &buf);
+ if (error < 0)
+ goto out_putf;
+
+ error = buf.error;
+ if (count != buf.count)
+ error = count - buf.count;
+
+ out_putf:
+ fput(file);
+ out:
+ return error;
+}
+
+#undef ROUND_UP
+#undef NAME_OFFSET
+
+asmlinkage unsigned long
+osf_mmap(unsigned long addr, unsigned long len, unsigned long prot,
+ unsigned long flags, unsigned long fd, unsigned long off)
+{
+ struct file *file = NULL;
+ unsigned long ret = -EBADF;
+
+#if 0
+ if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
+ printk("%s: unimplemented OSF mmap flags %04lx\n",
+ current->comm, flags);
+#endif
+ if (!(flags & MAP_ANONYMOUS)) {
+ file = fget(fd);
+ if (!file)
+ goto out;
+ }
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ down_write(&current->mm->mmap_sem);
+ ret = do_mmap(file, addr, len, prot, flags, off);
+ up_write(&current->mm->mmap_sem);
+ if (file)
+ fput(file);
+ out:
+ return ret;
+}
+
+
+/*
+ * The OSF/1 statfs structure is much larger, but this should
+ * match the beginning, at least.
+ */
+struct osf_statfs {
+ short f_type;
+ short f_flags;
+ int f_fsize;
+ int f_bsize;
+ int f_blocks;
+ int f_bfree;
+ int f_bavail;
+ int f_files;
+ int f_ffree;
+ __kernel_fsid_t f_fsid;
+};
+
+static int
+linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *osf_stat,
+ unsigned long bufsiz)
+{
+ struct osf_statfs tmp_stat;
+
+ tmp_stat.f_type = linux_stat->f_type;
+ tmp_stat.f_flags = 0; /* mount flags */
+ tmp_stat.f_fsize = linux_stat->f_frsize;
+ tmp_stat.f_bsize = linux_stat->f_bsize;
+ tmp_stat.f_blocks = linux_stat->f_blocks;
+ tmp_stat.f_bfree = linux_stat->f_bfree;
+ tmp_stat.f_bavail = linux_stat->f_bavail;
+ tmp_stat.f_files = linux_stat->f_files;
+ tmp_stat.f_ffree = linux_stat->f_ffree;
+ tmp_stat.f_fsid = linux_stat->f_fsid;
+ if (bufsiz > sizeof(tmp_stat))
+ bufsiz = sizeof(tmp_stat);
+ return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
+}
+
+static int
+do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer,
+ unsigned long bufsiz)
+{
+ struct kstatfs linux_stat;
+ int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat);
+ if (!error)
+ error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
+ return error;
+}
+
+asmlinkage int
+osf_statfs(char __user *path, struct osf_statfs __user *buffer, unsigned long bufsiz)
+{
+ struct nameidata nd;
+ int retval;
+
+ retval = user_path_walk(path, &nd);
+ if (!retval) {
+ retval = do_osf_statfs(nd.dentry, buffer, bufsiz);
+ path_release(&nd);
+ }
+ return retval;
+}
+
+asmlinkage int
+osf_fstatfs(unsigned long fd, struct osf_statfs __user *buffer, unsigned long bufsiz)
+{
+ struct file *file;
+ int retval;
+
+ retval = -EBADF;
+ file = fget(fd);
+ if (file) {
+ retval = do_osf_statfs(file->f_dentry, buffer, bufsiz);
+ fput(file);
+ }
+ return retval;
+}
+
+/*
+ * Uhh.. OSF/1 mount parameters aren't exactly obvious..
+ *
+ * Although to be frank, neither are the native Linux/i386 ones..
+ */
+struct ufs_args {
+ char __user *devname;
+ int flags;
+ uid_t exroot;
+};
+
+struct cdfs_args {
+ char __user *devname;
+ int flags;
+ uid_t exroot;
+
+ /* This has lots more here, which Linux handles with the option block
+ but I'm too lazy to do the translation into ASCII. */
+};
+
+struct procfs_args {
+ char __user *devname;
+ int flags;
+ uid_t exroot;
+};
+
+/*
+ * We can't actually handle ufs yet, so we translate UFS mounts to
+ * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS
+ * layout is so braindead it's a major headache doing it.
+ *
+ * Just how long ago was it written? OTOH our UFS driver may be still
+ * unhappy with OSF UFS. [CHECKME]
+ */
+static int
+osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags)
+{
+ int retval;
+ struct cdfs_args tmp;
+ char *devname;
+
+ retval = -EFAULT;
+ if (copy_from_user(&tmp, args, sizeof(tmp)))
+ goto out;
+ devname = getname(tmp.devname);
+ retval = PTR_ERR(devname);
+ if (IS_ERR(devname))
+ goto out;
+ retval = do_mount(devname, dirname, "ext2", flags, NULL);
+ putname(devname);
+ out:
+ return retval;
+}
+
+static int
+osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags)
+{
+ int retval;
+ struct cdfs_args tmp;
+ char *devname;
+
+ retval = -EFAULT;
+ if (copy_from_user(&tmp, args, sizeof(tmp)))
+ goto out;
+ devname = getname(tmp.devname);
+ retval = PTR_ERR(devname);
+ if (IS_ERR(devname))
+ goto out;
+ retval = do_mount(devname, dirname, "iso9660", flags, NULL);
+ putname(devname);
+ out:
+ return retval;
+}
+
+static int
+osf_procfs_mount(char *dirname, struct procfs_args __user *args, int flags)
+{
+ struct procfs_args tmp;
+
+ if (copy_from_user(&tmp, args, sizeof(tmp)))
+ return -EFAULT;
+
+ return do_mount("", dirname, "proc", flags, NULL);
+}
+
+asmlinkage int
+osf_mount(unsigned long typenr, char __user *path, int flag, void __user *data)
+{
+ int retval = -EINVAL;
+ char *name;
+
+ lock_kernel();
+
+ name = getname(path);
+ retval = PTR_ERR(name);
+ if (IS_ERR(name))
+ goto out;
+ switch (typenr) {
+ case 1:
+ retval = osf_ufs_mount(name, data, flag);
+ break;
+ case 6:
+ retval = osf_cdfs_mount(name, data, flag);
+ break;
+ case 9:
+ retval = osf_procfs_mount(name, data, flag);
+ break;
+ default:
+ printk("osf_mount(%ld, %x)\n", typenr, flag);
+ }
+ putname(name);
+ out:
+ unlock_kernel();
+ return retval;
+}
+
+asmlinkage int
+osf_utsname(char __user *name)
+{
+ int error;
+
+ down_read(&uts_sem);
+ error = -EFAULT;
+ if (copy_to_user(name + 0, system_utsname.sysname, 32))
+ goto out;
+ if (copy_to_user(name + 32, system_utsname.nodename, 32))
+ goto out;
+ if (copy_to_user(name + 64, system_utsname.release, 32))
+ goto out;
+ if (copy_to_user(name + 96, system_utsname.version, 32))
+ goto out;
+ if (copy_to_user(name + 128, system_utsname.machine, 32))
+ goto out;
+
+ error = 0;
+ out:
+ up_read(&uts_sem);
+ return error;
+}
+
+asmlinkage unsigned long
+sys_getpagesize(void)
+{
+ return PAGE_SIZE;
+}
+
+asmlinkage unsigned long
+sys_getdtablesize(void)
+{
+ return NR_OPEN;
+}
+
+/*
+ * For compatibility with OSF/1 only. Use utsname(2) instead.
+ */
+asmlinkage int
+osf_getdomainname(char __user *name, int namelen)
+{
+ unsigned len;
+ int i;
+
+ if (!access_ok(VERIFY_WRITE, name, namelen))
+ return -EFAULT;
+
+ len = namelen;
+ if (namelen > 32)
+ len = 32;
+
+ down_read(&uts_sem);
+ for (i = 0; i < len; ++i) {
+ __put_user(system_utsname.domainname[i], name + i);
+ if (system_utsname.domainname[i] == '\0')
+ break;
+ }
+ up_read(&uts_sem);
+
+ return 0;
+}
+
+asmlinkage long
+osf_shmat(int shmid, void __user *shmaddr, int shmflg)
+{
+ unsigned long raddr;
+ long err;
+
+ err = do_shmat(shmid, shmaddr, shmflg, &raddr);
+
+ /*
+ * This works because all user-level addresses are
+ * non-negative longs!
+ */
+ return err ? err : (long)raddr;
+}
+
+
+/*
+ * The following stuff should move into a header file should it ever
+ * be labeled "officially supported." Right now, there is just enough
+ * support to avoid applications (such as tar) printing error
+ * messages. The attributes are not really implemented.
+ */
+
+/*
+ * Values for Property list entry flag
+ */
+#define PLE_PROPAGATE_ON_COPY 0x1 /* cp(1) will copy entry
+ by default */
+#define PLE_FLAG_MASK 0x1 /* Valid flag values */
+#define PLE_FLAG_ALL -1 /* All flag value */
+
+struct proplistname_args {
+ unsigned int pl_mask;
+ unsigned int pl_numnames;
+ char **pl_names;
+};
+
+union pl_args {
+ struct setargs {
+ char __user *path;
+ long follow;
+ long nbytes;
+ char __user *buf;
+ } set;
+ struct fsetargs {
+ long fd;
+ long nbytes;
+ char __user *buf;
+ } fset;
+ struct getargs {
+ char __user *path;
+ long follow;
+ struct proplistname_args __user *name_args;
+ long nbytes;
+ char __user *buf;
+ int __user *min_buf_size;
+ } get;
+ struct fgetargs {
+ long fd;
+ struct proplistname_args __user *name_args;
+ long nbytes;
+ char __user *buf;
+ int __user *min_buf_size;
+ } fget;
+ struct delargs {
+ char __user *path;
+ long follow;
+ struct proplistname_args __user *name_args;
+ } del;
+ struct fdelargs {
+ long fd;
+ struct proplistname_args __user *name_args;
+ } fdel;
+};
+
+enum pl_code {
+ PL_SET = 1, PL_FSET = 2,
+ PL_GET = 3, PL_FGET = 4,
+ PL_DEL = 5, PL_FDEL = 6
+};
+
+asmlinkage long
+osf_proplist_syscall(enum pl_code code, union pl_args __user *args)
+{
+ long error;
+ int __user *min_buf_size_ptr;
+
+ lock_kernel();
+ switch (code) {
+ case PL_SET:
+ if (get_user(error, &args->set.nbytes))
+ error = -EFAULT;
+ break;
+ case PL_FSET:
+ if (get_user(error, &args->fset.nbytes))
+ error = -EFAULT;
+ break;
+ case PL_GET:
+ error = get_user(min_buf_size_ptr, &args->get.min_buf_size);
+ if (error)
+ break;
+ error = put_user(0, min_buf_size_ptr);
+ break;
+ case PL_FGET:
+ error = get_user(min_buf_size_ptr, &args->fget.min_buf_size);
+ if (error)
+ break;
+ error = put_user(0, min_buf_size_ptr);
+ break;
+ case PL_DEL:
+ case PL_FDEL:
+ error = 0;
+ break;
+ default:
+ error = -EOPNOTSUPP;
+ break;
+ };
+ unlock_kernel();
+ return error;
+}
+
+asmlinkage int
+osf_sigstack(struct sigstack __user *uss, struct sigstack __user *uoss)
+{
+ unsigned long usp = rdusp();
+ unsigned long oss_sp = current->sas_ss_sp + current->sas_ss_size;
+ unsigned long oss_os = on_sig_stack(usp);
+ int error;
+
+ if (uss) {
+ void __user *ss_sp;
+
+ error = -EFAULT;
+ if (get_user(ss_sp, &uss->ss_sp))
+ goto out;
+
+ /* If the current stack was set with sigaltstack, don't
+ swap stacks while we are on it. */
+ error = -EPERM;
+ if (current->sas_ss_sp && on_sig_stack(usp))
+ goto out;
+
+ /* Since we don't know the extent of the stack, and we don't
+ track onstack-ness, but rather calculate it, we must
+ presume a size. Ho hum this interface is lossy. */
+ current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
+ current->sas_ss_size = SIGSTKSZ;
+ }
+
+ if (uoss) {
+ error = -EFAULT;
+ if (! access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))
+ || __put_user(oss_sp, &uoss->ss_sp)
+ || __put_user(oss_os, &uoss->ss_onstack))
+ goto out;
+ }
+
+ error = 0;
+ out:
+ return error;
+}
+
+asmlinkage long
+osf_sysinfo(int command, char __user *buf, long count)
+{
+ static char * sysinfo_table[] = {
+ system_utsname.sysname,
+ system_utsname.nodename,
+ system_utsname.release,
+ system_utsname.version,
+ system_utsname.machine,
+ "alpha", /* instruction set architecture */
+ "dummy", /* hardware serial number */
+ "dummy", /* hardware manufacturer */
+ "dummy", /* secure RPC domain */
+ };
+ unsigned long offset;
+ char *res;
+ long len, err = -EINVAL;
+
+ offset = command-1;
+ if (offset >= sizeof(sysinfo_table)/sizeof(char *)) {
+ /* Digital UNIX has a few unpublished interfaces here */
+ printk("sysinfo(%d)", command);
+ goto out;
+ }
+
+ down_read(&uts_sem);
+ res = sysinfo_table[offset];
+ len = strlen(res)+1;
+ if (len > count)
+ len = count;
+ if (copy_to_user(buf, res, len))
+ err = -EFAULT;
+ else
+ err = 0;
+ up_read(&uts_sem);
+ out:
+ return err;
+}
+
+asmlinkage unsigned long
+osf_getsysinfo(unsigned long op, void __user *buffer, unsigned long nbytes,
+ int __user *start, void __user *arg)
+{
+ unsigned long w;
+ struct percpu_struct *cpu;
+
+ switch (op) {
+ case GSI_IEEE_FP_CONTROL:
+ /* Return current software fp control & status bits. */
+ /* Note that DU doesn't verify available space here. */
+
+ w = current_thread_info()->ieee_state & IEEE_SW_MASK;
+ w = swcr_update_status(w, rdfpcr());
+ if (put_user(w, (unsigned long __user *) buffer))
+ return -EFAULT;
+ return 0;
+
+ case GSI_IEEE_STATE_AT_SIGNAL:
+ /*
+ * Not sure anybody will ever use this weird stuff. These
+ * ops can be used (under OSF/1) to set the fpcr that should
+ * be used when a signal handler starts executing.
+ */
+ break;
+
+ case GSI_UACPROC:
+ if (nbytes < sizeof(unsigned int))
+ return -EINVAL;
+ w = (current_thread_info()->flags >> UAC_SHIFT) & UAC_BITMASK;
+ if (put_user(w, (unsigned int __user *)buffer))
+ return -EFAULT;
+ return 1;
+
+ case GSI_PROC_TYPE:
+ if (nbytes < sizeof(unsigned long))
+ return -EINVAL;
+ cpu = (struct percpu_struct*)
+ ((char*)hwrpb + hwrpb->processor_offset);
+ w = cpu->type;
+ if (put_user(w, (unsigned long __user*)buffer))
+ return -EFAULT;
+ return 1;
+
+ case GSI_GET_HWRPB:
+ if (nbytes < sizeof(*hwrpb))
+ return -EINVAL;
+ if (copy_to_user(buffer, hwrpb, nbytes) != 0)
+ return -EFAULT;
+ return 1;
+
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+asmlinkage unsigned long
+osf_setsysinfo(unsigned long op, void __user *buffer, unsigned long nbytes,
+ int __user *start, void __user *arg)
+{
+ switch (op) {
+ case SSI_IEEE_FP_CONTROL: {
+ unsigned long swcr, fpcr;
+ unsigned int *state;
+
+ /*
+ * Alpha Architecture Handbook 4.7.7.3:
+ * To be fully IEEE compiant, we must track the current IEEE
+ * exception state in software, because spurrious bits can be
+ * set in the trap shadow of a software-complete insn.
+ */
+
+ if (get_user(swcr, (unsigned long __user *)buffer))
+ return -EFAULT;
+ state = &current_thread_info()->ieee_state;
+
+ /* Update softare trap enable bits. */
+ *state = (*state & ~IEEE_SW_MASK) | (swcr & IEEE_SW_MASK);
+
+ /* Update the real fpcr. */
+ fpcr = rdfpcr() & FPCR_DYN_MASK;
+ fpcr |= ieee_swcr_to_fpcr(swcr);
+ wrfpcr(fpcr);
+
+ return 0;
+ }
+
+ case SSI_IEEE_RAISE_EXCEPTION: {
+ unsigned long exc, swcr, fpcr, fex;
+ unsigned int *state;
+
+ if (get_user(exc, (unsigned long __user *)buffer))
+ return -EFAULT;
+ state = &current_thread_info()->ieee_state;
+ exc &= IEEE_STATUS_MASK;
+
+ /* Update softare trap enable bits. */
+ swcr = (*state & IEEE_SW_MASK) | exc;
+ *state |= exc;
+
+ /* Update the real fpcr. */
+ fpcr = rdfpcr();
+ fpcr |= ieee_swcr_to_fpcr(swcr);
+ wrfpcr(fpcr);
+
+ /* If any exceptions set by this call, and are unmasked,
+ send a signal. Old exceptions are not signaled. */
+ fex = (exc >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr;
+ if (fex) {
+ siginfo_t info;
+ int si_code = 0;
+
+ if (fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND;
+ if (fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES;
+ if (fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND;
+ if (fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF;
+ if (fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV;
+ if (fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV;
+
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = si_code;
+ info.si_addr = NULL; /* FIXME */
+ send_sig_info(SIGFPE, &info, current);
+ }
+ return 0;
+ }
+
+ case SSI_IEEE_STATE_AT_SIGNAL:
+ case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
+ /*
+ * Not sure anybody will ever use this weird stuff. These
+ * ops can be used (under OSF/1) to set the fpcr that should
+ * be used when a signal handler starts executing.
+ */
+ break;
+
+ case SSI_NVPAIRS: {
+ unsigned long v, w, i;
+ unsigned int old, new;
+
+ for (i = 0; i < nbytes; ++i) {
+
+ if (get_user(v, 2*i + (unsigned int __user *)buffer))
+ return -EFAULT;
+ if (get_user(w, 2*i + 1 + (unsigned int __user *)buffer))
+ return -EFAULT;
+ switch (v) {
+ case SSIN_UACPROC:
+ again:
+ old = current_thread_info()->flags;
+ new = old & ~(UAC_BITMASK << UAC_SHIFT);
+ new = new | (w & UAC_BITMASK) << UAC_SHIFT;
+ if (cmpxchg(&current_thread_info()->flags,
+ old, new) != old)
+ goto again;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+ return 0;
+ }
+
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+/* Translations due to the fact that OSF's time_t is an int. Which
+ affects all sorts of things, like timeval and itimerval. */
+
+extern struct timezone sys_tz;
+extern int do_adjtimex(struct timex *);
+
+struct timeval32
+{
+ int tv_sec, tv_usec;
+};
+
+struct itimerval32
+{
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
+
+static inline long
+get_tv32(struct timeval *o, struct timeval32 __user *i)
+{
+ return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
+ (__get_user(o->tv_sec, &i->tv_sec) |
+ __get_user(o->tv_usec, &i->tv_usec)));
+}
+
+static inline long
+put_tv32(struct timeval32 __user *o, struct timeval *i)
+{
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+ (__put_user(i->tv_sec, &o->tv_sec) |
+ __put_user(i->tv_usec, &o->tv_usec)));
+}
+
+static inline long
+get_it32(struct itimerval *o, struct itimerval32 __user *i)
+{
+ return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
+ (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
+ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
+ __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
+ __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
+}
+
+static inline long
+put_it32(struct itimerval32 __user *o, struct itimerval *i)
+{
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+ (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
+ __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
+ __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
+ __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
+}
+
+static inline void
+jiffies_to_timeval32(unsigned long jiffies, struct timeval32 *value)
+{
+ value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
+ value->tv_sec = jiffies / HZ;
+}
+
+asmlinkage int
+osf_gettimeofday(struct timeval32 __user *tv, struct timezone __user *tz)
+{
+ if (tv) {
+ struct timeval ktv;
+ do_gettimeofday(&ktv);
+ if (put_tv32(tv, &ktv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage int
+osf_settimeofday(struct timeval32 __user *tv, struct timezone __user *tz)
+{
+ struct timespec kts;
+ struct timezone ktz;
+
+ if (tv) {
+ if (get_tv32((struct timeval *)&kts, tv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_from_user(&ktz, tz, sizeof(*tz)))
+ return -EFAULT;
+ }
+
+ kts.tv_nsec *= 1000;
+
+ return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
+}
+
+asmlinkage int
+osf_getitimer(int which, struct itimerval32 __user *it)
+{
+ struct itimerval kit;
+ int error;
+
+ error = do_getitimer(which, &kit);
+ if (!error && put_it32(it, &kit))
+ error = -EFAULT;
+
+ return error;
+}
+
+asmlinkage int
+osf_setitimer(int which, struct itimerval32 __user *in, struct itimerval32 __user *out)
+{
+ struct itimerval kin, kout;
+ int error;
+
+ if (in) {
+ if (get_it32(&kin, in))
+ return -EFAULT;
+ } else
+ memset(&kin, 0, sizeof(kin));
+
+ error = do_setitimer(which, &kin, out ? &kout : NULL);
+ if (error || !out)
+ return error;
+
+ if (put_it32(out, &kout))
+ return -EFAULT;
+
+ return 0;
+
+}
+
+asmlinkage int
+osf_utimes(char __user *filename, struct timeval32 __user *tvs)
+{
+ struct timeval ktvs[2];
+
+ if (tvs) {
+ if (get_tv32(&ktvs[0], &tvs[0]) ||
+ get_tv32(&ktvs[1], &tvs[1]))
+ return -EFAULT;
+ }
+
+ return do_utimes(filename, tvs ? ktvs : NULL);
+}
+
+#define MAX_SELECT_SECONDS \
+ ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+
+asmlinkage int
+osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
+ struct timeval32 __user *tvp)
+{
+ fd_set_bits fds;
+ char *bits;
+ size_t size;
+ long timeout;
+ int ret = -EINVAL;
+
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ if (tvp) {
+ time_t sec, usec;
+
+ if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
+ || __get_user(sec, &tvp->tv_sec)
+ || __get_user(usec, &tvp->tv_usec)) {
+ ret = -EFAULT;
+ goto out_nofds;
+ }
+
+ if (sec < 0 || usec < 0)
+ goto out_nofds;
+
+ if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+ timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
+ timeout += sec * (unsigned long) HZ;
+ }
+ }
+
+ if (n < 0 || n > current->files->max_fdset)
+ goto out_nofds;
+
+ /*
+ * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
+ * since we used fdset we need to allocate memory in units of
+ * long-words.
+ */
+ ret = -ENOMEM;
+ size = FDS_BYTES(n);
+ bits = kmalloc(6 * size, GFP_KERNEL);
+ if (!bits)
+ goto out_nofds;
+ fds.in = (unsigned long *) bits;
+ fds.out = (unsigned long *) (bits + size);
+ fds.ex = (unsigned long *) (bits + 2*size);
+ fds.res_in = (unsigned long *) (bits + 3*size);
+ fds.res_out = (unsigned long *) (bits + 4*size);
+ fds.res_ex = (unsigned long *) (bits + 5*size);
+
+ if ((ret = get_fd_set(n, inp->fds_bits, fds.in)) ||
+ (ret = get_fd_set(n, outp->fds_bits, fds.out)) ||
+ (ret = get_fd_set(n, exp->fds_bits, fds.ex)))
+ goto out;
+ zero_fd_set(n, fds.res_in);
+ zero_fd_set(n, fds.res_out);
+ zero_fd_set(n, fds.res_ex);
+
+ ret = do_select(n, &fds, &timeout);
+
+ /* OSF does not copy back the remaining time. */
+
+ if (ret < 0)
+ goto out;
+ if (!ret) {
+ ret = -ERESTARTNOHAND;
+ if (signal_pending(current))
+ goto out;
+ ret = 0;
+ }
+
+ if (set_fd_set(n, inp->fds_bits, fds.res_in) ||
+ set_fd_set(n, outp->fds_bits, fds.res_out) ||
+ set_fd_set(n, exp->fds_bits, fds.res_ex))
+ ret = -EFAULT;
+
+ out:
+ kfree(bits);
+ out_nofds:
+ return ret;
+}
+
+struct rusage32 {
+ struct timeval32 ru_utime; /* user time used */
+ struct timeval32 ru_stime; /* system time used */
+ long ru_maxrss; /* maximum resident set size */
+ long ru_ixrss; /* integral shared memory size */
+ long ru_idrss; /* integral unshared data size */
+ long ru_isrss; /* integral unshared stack size */
+ long ru_minflt; /* page reclaims */
+ long ru_majflt; /* page faults */
+ long ru_nswap; /* swaps */
+ long ru_inblock; /* block input operations */
+ long ru_oublock; /* block output operations */
+ long ru_msgsnd; /* messages sent */
+ long ru_msgrcv; /* messages received */
+ long ru_nsignals; /* signals received */
+ long ru_nvcsw; /* voluntary context switches */
+ long ru_nivcsw; /* involuntary " */
+};
+
+asmlinkage int
+osf_getrusage(int who, struct rusage32 __user *ru)
+{
+ struct rusage32 r;
+
+ if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
+ return -EINVAL;
+
+ memset(&r, 0, sizeof(r));
+ switch (who) {
+ case RUSAGE_SELF:
+ jiffies_to_timeval32(current->utime, &r.ru_utime);
+ jiffies_to_timeval32(current->stime, &r.ru_stime);
+ r.ru_minflt = current->min_flt;
+ r.ru_majflt = current->maj_flt;
+ break;
+ case RUSAGE_CHILDREN:
+ jiffies_to_timeval32(current->signal->cutime, &r.ru_utime);
+ jiffies_to_timeval32(current->signal->cstime, &r.ru_stime);
+ r.ru_minflt = current->signal->cmin_flt;
+ r.ru_majflt = current->signal->cmaj_flt;
+ break;
+ }
+
+ return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
+}
+
+asmlinkage long
+osf_wait4(pid_t pid, int __user *ustatus, int options,
+ struct rusage32 __user *ur)
+{
+ struct rusage r;
+ long ret, err;
+ mm_segment_t old_fs;
+
+ if (!ur)
+ return sys_wait4(pid, ustatus, options, NULL);
+
+ old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_wait4(pid, ustatus, options, (struct rusage __user *) &r);
+ set_fs (old_fs);
+
+ if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur)))
+ return -EFAULT;
+
+ err = 0;
+ err |= __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec);
+ err |= __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec);
+ err |= __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec);
+ err |= __put_user(r.ru_stime.tv_usec, &ur->ru_stime.tv_usec);
+ err |= __put_user(r.ru_maxrss, &ur->ru_maxrss);
+ err |= __put_user(r.ru_ixrss, &ur->ru_ixrss);
+ err |= __put_user(r.ru_idrss, &ur->ru_idrss);
+ err |= __put_user(r.ru_isrss, &ur->ru_isrss);
+ err |= __put_user(r.ru_minflt, &ur->ru_minflt);
+ err |= __put_user(r.ru_majflt, &ur->ru_majflt);
+ err |= __put_user(r.ru_nswap, &ur->ru_nswap);
+ err |= __put_user(r.ru_inblock, &ur->ru_inblock);
+ err |= __put_user(r.ru_oublock, &ur->ru_oublock);
+ err |= __put_user(r.ru_msgsnd, &ur->ru_msgsnd);
+ err |= __put_user(r.ru_msgrcv, &ur->ru_msgrcv);
+ err |= __put_user(r.ru_nsignals, &ur->ru_nsignals);
+ err |= __put_user(r.ru_nvcsw, &ur->ru_nvcsw);
+ err |= __put_user(r.ru_nivcsw, &ur->ru_nivcsw);
+
+ return err ? err : ret;
+}
+
+/*
+ * I don't know what the parameters are: the first one
+ * seems to be a timeval pointer, and I suspect the second
+ * one is the time remaining.. Ho humm.. No documentation.
+ */
+asmlinkage int
+osf_usleep_thread(struct timeval32 __user *sleep, struct timeval32 __user *remain)
+{
+ struct timeval tmp;
+ unsigned long ticks;
+
+ if (get_tv32(&tmp, sleep))
+ goto fault;
+
+ ticks = tmp.tv_usec;
+ ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
+ ticks += tmp.tv_sec * HZ;
+
+ current->state = TASK_INTERRUPTIBLE;
+ ticks = schedule_timeout(ticks);
+
+ if (remain) {
+ tmp.tv_sec = ticks / HZ;
+ tmp.tv_usec = ticks % HZ;
+ if (put_tv32(remain, &tmp))
+ goto fault;
+ }
+
+ return 0;
+ fault:
+ return -EFAULT;
+}
+
+
+struct timex32 {
+ unsigned int modes; /* mode selector */
+ long offset; /* time offset (usec) */
+ long freq; /* frequency offset (scaled ppm) */
+ long maxerror; /* maximum error (usec) */
+ long esterror; /* estimated error (usec) */
+ int status; /* clock command/status */
+ long constant; /* pll time constant */
+ long precision; /* clock precision (usec) (read only) */
+ long tolerance; /* clock frequency tolerance (ppm)
+ * (read only)
+ */
+ struct timeval32 time; /* (read only) */
+ long tick; /* (modified) usecs between clock ticks */
+
+ long ppsfreq; /* pps frequency (scaled ppm) (ro) */
+ long jitter; /* pps jitter (us) (ro) */
+ int shift; /* interval duration (s) (shift) (ro) */
+ long stabil; /* pps stability (scaled ppm) (ro) */
+ long jitcnt; /* jitter limit exceeded (ro) */
+ long calcnt; /* calibration intervals (ro) */
+ long errcnt; /* calibration errors (ro) */
+ long stbcnt; /* stability limit exceeded (ro) */
+
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
+};
+
+asmlinkage int
+sys_old_adjtimex(struct timex32 __user *txc_p)
+{
+ struct timex txc;
+ int ret;
+
+ /* copy relevant bits of struct timex. */
+ if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) ||
+ copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) -
+ offsetof(struct timex32, time)))
+ return -EFAULT;
+
+ ret = do_adjtimex(&txc);
+ if (ret < 0)
+ return ret;
+
+ /* copy back to timex32 */
+ if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) ||
+ (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) -
+ offsetof(struct timex32, tick))) ||
+ (put_tv32(&txc_p->time, &txc.time)))
+ return -EFAULT;
+
+ return ret;
+}
+
+/* Get an address range which is currently unmapped. Similar to the
+ generic version except that we know how to honor ADDR_LIMIT_32BIT. */
+
+static unsigned long
+arch_get_unmapped_area_1(unsigned long addr, unsigned long len,
+ unsigned long limit)
+{
+ struct vm_area_struct *vma = find_vma(current->mm, addr);
+
+ while (1) {
+ /* At this point: (!vma || addr < vma->vm_end). */
+ if (limit - len < addr)
+ return -ENOMEM;
+ if (!vma || addr + len <= vma->vm_start)
+ return addr;
+ addr = vma->vm_end;
+ vma = vma->vm_next;
+ }
+}
+
+unsigned long
+arch_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ unsigned long limit;
+
+ /* "32 bit" actually means 31 bit, since pointers sign extend. */
+ if (current->personality & ADDR_LIMIT_32BIT)
+ limit = 0x80000000;
+ else
+ limit = TASK_SIZE;
+
+ if (len > limit)
+ return -ENOMEM;
+
+ /* First, see if the given suggestion fits.
+
+ The OSF/1 loader (/sbin/loader) relies on us returning an
+ address larger than the requested if one exists, which is
+ a terribly broken way to program.
+
+ That said, I can see the use in being able to suggest not
+ merely specific addresses, but regions of memory -- perhaps
+ this feature should be incorporated into all ports? */
+
+ if (addr) {
+ addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit);
+ if (addr != (unsigned long) -ENOMEM)
+ return addr;
+ }
+
+ /* Next, try allocating at TASK_UNMAPPED_BASE. */
+ addr = arch_get_unmapped_area_1 (PAGE_ALIGN(TASK_UNMAPPED_BASE),
+ len, limit);
+ if (addr != (unsigned long) -ENOMEM)
+ return addr;
+
+ /* Finally, try allocating in low memory. */
+ addr = arch_get_unmapped_area_1 (PAGE_SIZE, len, limit);
+
+ return addr;
+}
+
+#ifdef CONFIG_OSF4_COMPAT
+
+/* Clear top 32 bits of iov_len in the user's buffer for
+ compatibility with old versions of OSF/1 where iov_len
+ was defined as int. */
+static int
+osf_fix_iov_len(const struct iovec __user *iov, unsigned long count)
+{
+ unsigned long i;
+
+ for (i = 0 ; i < count ; i++) {
+ int __user *iov_len_high = (int __user *)&iov[i].iov_len + 1;
+
+ if (put_user(0, iov_len_high))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage ssize_t
+osf_readv(unsigned long fd, const struct iovec __user * vector, unsigned long count)
+{
+ if (unlikely(personality(current->personality) == PER_OSF4))
+ if (osf_fix_iov_len(vector, count))
+ return -EFAULT;
+ return sys_readv(fd, vector, count);
+}
+
+asmlinkage ssize_t
+osf_writev(unsigned long fd, const struct iovec __user * vector, unsigned long count)
+{
+ if (unlikely(personality(current->personality) == PER_OSF4))
+ if (osf_fix_iov_len(vector, count))
+ return -EFAULT;
+ return sys_writev(fd, vector, count);
+}
+
+#endif
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
new file mode 100644
index 000000000000..582a3519fb28
--- /dev/null
+++ b/arch/alpha/kernel/pci-noop.c
@@ -0,0 +1,214 @@
+/*
+ * linux/arch/alpha/kernel/pci-noop.c
+ *
+ * Stub PCI interfaces for Jensen-specific kernels.
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.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 = alloc_bootmem(sizeof(*hose));
+
+ *hose_tail = hose;
+ hose_tail = &hose->next;
+
+ return hose;
+}
+
+struct resource * __init
+alloc_resource(void)
+{
+ struct resource *res;
+
+ res = alloc_bootmem(sizeof(*res));
+
+ return res;
+}
+
+asmlinkage long
+sys_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;
+}
+
+asmlinkage long
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len, void *buf)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ else
+ return -ENODEV;
+}
+
+asmlinkage long
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len, void *buf)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ else
+ return -ENODEV;
+}
+
+/* Stubs for the routines in pci_iommu.c: */
+
+void *
+pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
+{
+ return NULL;
+}
+
+void
+pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr,
+ dma_addr_t dma_addr)
+{
+}
+
+dma_addr_t
+pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size,
+ int direction)
+{
+ return (dma_addr_t) 0;
+}
+
+void
+pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
+ int direction)
+{
+}
+
+int
+pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
+ int direction)
+{
+ return 0;
+}
+
+void
+pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
+ int direction)
+{
+}
+
+int
+pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+ return 0;
+}
+
+/* Generic DMA mapping functions: */
+
+void *
+dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, int gfp)
+{
+ void *ret;
+
+ if (!dev || *dev->dma_mask >= 0xffffffffUL)
+ gfp &= ~GFP_DMA;
+ ret = (void *)__get_free_pages(gfp, get_order(size));
+ if (ret) {
+ memset(ret, 0, size);
+ *dma_handle = virt_to_bus(ret);
+ }
+ return ret;
+}
+
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ int i;
+
+ for (i = 0; i < nents; i++ ) {
+ void *va;
+
+ BUG_ON(!sg[i].page);
+ va = page_address(sg[i].page) + sg[i].offset;
+ sg_dma_address(sg + i) = (dma_addr_t)virt_to_bus(va);
+ sg_dma_len(sg + i) = sg[i].length;
+ }
+
+ return nents;
+}
+
+EXPORT_SYMBOL(dma_map_sg);
+
+int
+dma_set_mask(struct device *dev, u64 mask)
+{
+ if (!