]> git.neil.brown.name Git - history.git/commitdiff
- Alan Cox: synch. PA-RISC arch and bitops cleanups 2.4.0-test12pre6
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:40:34 +0000 (15:40 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:40:34 +0000 (15:40 -0500)
- Maciej Rozycki: even more proper apic setup order.
- Andrew Morton: exec_usermodehelper fixes
- Adam Richter, Kai Germaschewski, Linus: PCI irq routing.
- revert A20 code changes. We really need to use the keyboard
  controller if one exists.
- Johannes Erdfelt: USB updates
- Ralf Baechle: MIPS memmove() fix.

246 files changed:
CREDITS
Documentation/Configure.help
Documentation/parisc/00-INDEX [new file with mode: 0644]
Documentation/parisc/IODC.txt [new file with mode: 0644]
Documentation/parisc/debugging [new file with mode: 0644]
Documentation/parisc/mm [new file with mode: 0644]
Documentation/parisc/registers [new file with mode: 0644]
Documentation/usb/URB.txt
Documentation/usb/error-codes.txt
Documentation/usb/usb-help.txt
Documentation/usb/usb-serial.txt
MAINTAINERS
arch/i386/boot/setup.S
arch/i386/kernel/apic.c
arch/i386/kernel/pci-irq.c
arch/i386/kernel/setup.c
arch/m68k/atari/atakeyb.c
arch/mips/lib/Makefile
arch/mips/lib/memcpy.S
arch/mips/lib/memset.S
arch/mips64/lib/Makefile
arch/mips64/lib/memcpy.S
arch/mips64/lib/memset.S
arch/parisc/Makefile [new file with mode: 0644]
arch/parisc/config.in [new file with mode: 0644]
arch/parisc/defconfig [new file with mode: 0644]
arch/parisc/hpux/Makefile [new file with mode: 0644]
arch/parisc/hpux/entry_hpux.S [new file with mode: 0644]
arch/parisc/hpux/fs.c [new file with mode: 0644]
arch/parisc/hpux/gate.S [new file with mode: 0644]
arch/parisc/hpux/ioctl.c [new file with mode: 0644]
arch/parisc/hpux/sys_hpux.c [new file with mode: 0644]
arch/parisc/hpux/wrappers.S [new file with mode: 0644]
arch/parisc/kernel/Makefile [new file with mode: 0644]
arch/parisc/kernel/cache.c [new file with mode: 0644]
arch/parisc/kernel/ccio-dma.c [new file with mode: 0644]
arch/parisc/kernel/ccio-rm-dma.c [new file with mode: 0644]
arch/parisc/kernel/drivers.c [new file with mode: 0644]
arch/parisc/kernel/entry.S [new file with mode: 0644]
arch/parisc/kernel/hardware.c [new file with mode: 0644]
arch/parisc/kernel/head.S [new file with mode: 0644]
arch/parisc/kernel/hpmc.S [new file with mode: 0644]
arch/parisc/kernel/init_task.c [new file with mode: 0644]
arch/parisc/kernel/inventory.c [new file with mode: 0644]
arch/parisc/kernel/iosapic.c [new file with mode: 0644]
arch/parisc/kernel/iosapic_private.h [new file with mode: 0644]
arch/parisc/kernel/irq.c [new file with mode: 0644]
arch/parisc/kernel/keyboard.c [new file with mode: 0644]
arch/parisc/kernel/lasimap.map [new file with mode: 0644]
arch/parisc/kernel/lba_pci.c [new file with mode: 0644]
arch/parisc/kernel/led.c [new file with mode: 0644]
arch/parisc/kernel/pa7300lc.c [new file with mode: 0644]
arch/parisc/kernel/parisc_ksyms.c [new file with mode: 0644]
arch/parisc/kernel/pci-dma.c [new file with mode: 0644]
arch/parisc/kernel/pci.c [new file with mode: 0644]
arch/parisc/kernel/pdc.c [new file with mode: 0644]
arch/parisc/kernel/pdc_cons.c [new file with mode: 0644]
arch/parisc/kernel/process.c [new file with mode: 0644]
arch/parisc/kernel/ptrace.c [new file with mode: 0644]
arch/parisc/kernel/real1.c [new file with mode: 0644]
arch/parisc/kernel/real2.S [new file with mode: 0644]
arch/parisc/kernel/sba_iommu.c [new file with mode: 0644]
arch/parisc/kernel/semaphore.c [new file with mode: 0644]
arch/parisc/kernel/setup.c [new file with mode: 0644]
arch/parisc/kernel/signal.c [new file with mode: 0644]
arch/parisc/kernel/sys_parisc.c [new file with mode: 0644]
arch/parisc/kernel/syscall.S [new file with mode: 0644]
arch/parisc/kernel/time.c [new file with mode: 0644]
arch/parisc/kernel/traps.c [new file with mode: 0644]
arch/parisc/lib/Makefile [new file with mode: 0644]
arch/parisc/lib/bitops.c [new file with mode: 0644]
arch/parisc/lib/checksum.c [new file with mode: 0644]
arch/parisc/lib/lusercopy.S [new file with mode: 0644]
arch/parisc/mm/Makefile [new file with mode: 0644]
arch/parisc/mm/extable.c [new file with mode: 0644]
arch/parisc/mm/fault.c [new file with mode: 0644]
arch/parisc/mm/init.c [new file with mode: 0644]
arch/parisc/mm/kmap.c [new file with mode: 0644]
arch/parisc/mm/pa11.c [new file with mode: 0644]
arch/parisc/mm/pa20.c [new file with mode: 0644]
arch/parisc/tools/Makefile [new file with mode: 0644]
arch/parisc/tools/offset.c [new file with mode: 0644]
arch/parisc/vmlinux.lds [new file with mode: 0644]
drivers/block/ataflop.c
drivers/ide/q40ide.c
drivers/isdn/avmb1/capi.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/l3ni1.c
drivers/isdn/hisax/netjet.c
drivers/md/xor.c
drivers/media/video/tvaudio.c
drivers/net/3c503.c
drivers/net/3c505.h
drivers/net/aironet4500.h
drivers/net/arlan.c
drivers/net/arlan.h
drivers/net/bagetlance.c
drivers/net/dgrs.c
drivers/net/dmfe.c
drivers/net/e2100.c
drivers/net/eepro.c
drivers/net/eexpress.c
drivers/net/es3210.c
drivers/net/hplance.c
drivers/net/lance.c
drivers/net/lasi_82596.c [new file with mode: 0644]
drivers/net/ne.c
drivers/net/ne2.c
drivers/net/ne2k-pci.c
drivers/net/ne3210.c
drivers/net/plip.c
drivers/net/tokenring/abyss.c
drivers/net/tokenring/olympic.c
drivers/net/tokenring/tmspci.c
drivers/net/tulip/tulip_core.c
drivers/pci/pci.c
drivers/scsi/wd33c93.c
drivers/sound/ymfpci.c
drivers/usb/acm.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/uhci.c
drivers/usb/usb.c
drivers/video/dummycon.c
drivers/video/fbcon-sti.c [new file with mode: 0644]
drivers/video/fbmem.c
drivers/video/sti-bmode.h [new file with mode: 0644]
drivers/video/sti.h [new file with mode: 0644]
drivers/video/sticon-bmode.c [new file with mode: 0644]
drivers/video/sticon.c [new file with mode: 0644]
drivers/video/sticore.c [new file with mode: 0644]
drivers/video/stifb.c [new file with mode: 0644]
fs/file_table.c
fs/smbfs/file.c
fs/stat.c
fs/udf/inode.c
include/asm-m68k/keyboard.h
include/asm-m68k/motorola_pgtable.h
include/asm-m68k/pgalloc.h
include/asm-parisc/a.out.h [new file with mode: 0644]
include/asm-parisc/asmregs.h [new file with mode: 0644]
include/asm-parisc/assembly.h [new file with mode: 0644]
include/asm-parisc/atomic.h [new file with mode: 0644]
include/asm-parisc/bitops.h [new file with mode: 0644]
include/asm-parisc/bootdata.h [new file with mode: 0644]
include/asm-parisc/bugs.h [new file with mode: 0644]
include/asm-parisc/byteorder.h [new file with mode: 0644]
include/asm-parisc/cache.h [new file with mode: 0644]
include/asm-parisc/checksum.h [new file with mode: 0644]
include/asm-parisc/current.h [new file with mode: 0644]
include/asm-parisc/delay.h [new file with mode: 0644]
include/asm-parisc/div64.h [new file with mode: 0644]
include/asm-parisc/elf.h [new file with mode: 0644]
include/asm-parisc/errno.h [new file with mode: 0644]
include/asm-parisc/fcntl.h [new file with mode: 0644]
include/asm-parisc/fixmap.h [new file with mode: 0644]
include/asm-parisc/gsc.h [new file with mode: 0644]
include/asm-parisc/hardirq.h [new file with mode: 0644]
include/asm-parisc/hardware.h [new file with mode: 0644]
include/asm-parisc/hdreg.h [new file with mode: 0644]
include/asm-parisc/hil.h [new file with mode: 0644]
include/asm-parisc/hw_irq.h [new file with mode: 0644]
include/asm-parisc/ide.h [new file with mode: 0644]
include/asm-parisc/io.h [new file with mode: 0644]
include/asm-parisc/ioctl.h [new file with mode: 0644]
include/asm-parisc/ioctls.h [new file with mode: 0644]
include/asm-parisc/iosapic.h [new file with mode: 0644]
include/asm-parisc/ipcbuf.h [new file with mode: 0644]
include/asm-parisc/irq.h [new file with mode: 0644]
include/asm-parisc/keyboard.h [new file with mode: 0644]
include/asm-parisc/led.h [new file with mode: 0644]
include/asm-parisc/linux_logo.h [new file with mode: 0644]
include/asm-parisc/machdep.h [new file with mode: 0644]
include/asm-parisc/mc146818rtc.h [new file with mode: 0644]
include/asm-parisc/md.h [new file with mode: 0644]
include/asm-parisc/mman.h [new file with mode: 0644]
include/asm-parisc/mmu.h [new file with mode: 0644]
include/asm-parisc/mmu_context.h [new file with mode: 0644]
include/asm-parisc/msgbuf.h [new file with mode: 0644]
include/asm-parisc/namei.h [new file with mode: 0644]
include/asm-parisc/page.h [new file with mode: 0644]
include/asm-parisc/param.h [new file with mode: 0644]
include/asm-parisc/parport.h [new file with mode: 0644]
include/asm-parisc/parport_gsc.h [new file with mode: 0644]
include/asm-parisc/pci.h [new file with mode: 0644]
include/asm-parisc/pdc.h [new file with mode: 0644]
include/asm-parisc/pdcpat.h [new file with mode: 0644]
include/asm-parisc/pgalloc.h [new file with mode: 0644]
include/asm-parisc/pgtable.h [new file with mode: 0644]
include/asm-parisc/poll.h [new file with mode: 0644]
include/asm-parisc/posix_types.h [new file with mode: 0644]
include/asm-parisc/processor.h [new file with mode: 0644]
include/asm-parisc/psw.h [new file with mode: 0644]
include/asm-parisc/ptrace.h [new file with mode: 0644]
include/asm-parisc/real.h [new file with mode: 0644]
include/asm-parisc/resource.h [new file with mode: 0644]
include/asm-parisc/runway.h [new file with mode: 0644]
include/asm-parisc/scatterlist.h [new file with mode: 0644]
include/asm-parisc/segment.h [new file with mode: 0644]
include/asm-parisc/semaphore-helper.h [new file with mode: 0644]
include/asm-parisc/semaphore.h [new file with mode: 0644]
include/asm-parisc/sembuf.h [new file with mode: 0644]
include/asm-parisc/serial.h [new file with mode: 0644]
include/asm-parisc/setup.h [new file with mode: 0644]
include/asm-parisc/shmbuf.h [new file with mode: 0644]
include/asm-parisc/shmparam.h [new file with mode: 0644]
include/asm-parisc/sigcontext.h [new file with mode: 0644]
include/asm-parisc/siginfo.h [new file with mode: 0644]
include/asm-parisc/signal.h [new file with mode: 0644]
include/asm-parisc/smp.h [new file with mode: 0644]
include/asm-parisc/smplock.h [new file with mode: 0644]
include/asm-parisc/socket.h [new file with mode: 0644]
include/asm-parisc/sockios.h [new file with mode: 0644]
include/asm-parisc/softirq.h [new file with mode: 0644]
include/asm-parisc/som.h [new file with mode: 0644]
include/asm-parisc/spinlock.h [new file with mode: 0644]
include/asm-parisc/stat.h [new file with mode: 0644]
include/asm-parisc/statfs.h [new file with mode: 0644]
include/asm-parisc/string.h [new file with mode: 0644]
include/asm-parisc/system.h [new file with mode: 0644]
include/asm-parisc/termbits.h [new file with mode: 0644]
include/asm-parisc/termios.h [new file with mode: 0644]
include/asm-parisc/timex.h [new file with mode: 0644]
include/asm-parisc/traps.h [new file with mode: 0644]
include/asm-parisc/types.h [new file with mode: 0644]
include/asm-parisc/uaccess.h [new file with mode: 0644]
include/asm-parisc/ucontext.h [new file with mode: 0644]
include/asm-parisc/unaligned.h [new file with mode: 0644]
include/asm-parisc/unistd.h [new file with mode: 0644]
include/asm-parisc/user.h [new file with mode: 0644]
include/linux/hdlcdrv.h
include/linux/highuid.h
include/linux/module.h
include/linux/sched.h
include/linux/stallion.h
include/linux/tty.h
include/linux/usb.h
include/linux/wanrouter.h
init/main.c
kernel/context.c
kernel/dma.c
kernel/kmod.c
mm/mprotect.c
net/sunrpc/sched.c

diff --git a/CREDITS b/CREDITS
index 1a013c565b308a64893e6fc0d4926a5d1e941ee7..a9ad20d9d45dcd07b185cba4128b6b5240f2c45d 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -341,6 +341,7 @@ D: Texas Instruments PCILynx IEEE 1394 driver
 N: Al Borchers
 E: alborchers@steinerpoint.com
 D: Author/maintainer of Digi AccelePort USB driver
+D: work on usbserial and keyspan_pda drivers
 S: 4912 Zenith Ave. S.
 S: Minneapolis, MN  55410
 S: USA
@@ -410,6 +411,10 @@ N: Zach Brown
 E: zab@zabbo.net
 D: maestro pci sound
 
+N: Gary Brubaker
+E: xavyer@ix.netcom.com
+D: USB Serial Empeg Empeg-car Mark I/II Driver
+
 N: Ray Burr
 E: ryb@nightmare.com
 D: Original author of Amiga FFS filesystem
index eef5afa3da8a3823cd7779d15ba1dd7bec4650f8..7e813107d15a7c8e64a93950d0db7e2fa8357253 100644 (file)
@@ -10372,6 +10372,9 @@ CONFIG_USB_SERIAL_DIGI_ACCELEPORT
   parallel port on the USB 2 appears as a third serial port on Linux.
   The Digi Acceleport USB 8 is not yet supported by this driver.
 
+  This driver works under SMP with the usb-uhci driver.  It does not
+  work under SMP with the uhci driver.
+
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called digi_acceleport.o. If you want to compile 
@@ -10380,7 +10383,9 @@ CONFIG_USB_SERIAL_DIGI_ACCELEPORT
 USB Empeg empeg-car Mark I/II Driver
 CONFIG_USB_SERIAL_EMPEG
   Say Y here if you want to connect to your Empeg empeg-car Mark I/II
-  mp3 player via USB.
+  mp3 player via USB.  The driver uses a single ttyUSB{0,1,2,...}
+  device node.  See Documentation/usb/usb-serial.txt for more
+  tidbits of information.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
diff --git a/Documentation/parisc/00-INDEX b/Documentation/parisc/00-INDEX
new file mode 100644 (file)
index 0000000..7c8494e
--- /dev/null
@@ -0,0 +1,10 @@
+00-INDEX
+       - this file.
+IODC.txt
+       - Documentation IODC
+debugging
+       - some debugging hints for real-mode code
+mm
+       - Documentation on parisc mm status
+registers
+       - current/planned usage of registers
diff --git a/Documentation/parisc/IODC.txt b/Documentation/parisc/IODC.txt
new file mode 100644 (file)
index 0000000..d686536
--- /dev/null
@@ -0,0 +1,68 @@
+Some notes on IODC, its general brokenness, and how to work around it.
+
+Short Version
+
+IODC is HP's pre-PCI standard for device identification (a la PCI vendor,
+device IDs), detection, configuration, initialization and so on.
+
+It also can provide firmware function to do the actual IO, which are slow,
+not really defined for runtime usage and generally not desirable.  (There
+are other firmware standards, such as STI, to do real IO).
+
+Usually, there are two parts to IODC.  The actual ROMs, which are laid out,
+detected aso in a bus-specific manner (IO_DC_ADDRESS / IO_DC_DATA on
+GSC/Runway, PCI spec - compliant ROMs for PCI, God-only-knows how on EISA),
+and the slightly cooked data read by PDC_IODC.
+
+The ROM layout is generally icky (only one byte out of every 4-byte-word
+might be valid, and many devices don't implement required options), so
+using PDC_IODC is highly recommended.  (In fact, you should use the device
+lists set up by the kernel proper instead of calling PDC_IODC yourself).
+
+Now, let's have a look at what the cooked ROM looks like (see iodc.pdf for
+the details, this is the simplified version).
+
+Basically, the first 8 bytes of IODC contain two 32-bit ids called HVERSION
+and SVERSION.  Those are further split up into bit fields, and
+unfortunately just ignoring this split up isn't an option.
+
+SVERSION consists of a 4-bit revision field, a 20-bit model field and a
+8-bit opt field.  Now, forget the revision and opt fields exist.  Basically,
+the model field is equivalent to a PCI device id (there is no vendor id.
+this is proprietary hardware we're talking about).  That is, all your
+driver cares for, in 90 % of the cases, is to find all devices that match
+the model field.
+
+The rev field is - you guessed it - roughly equivalent to the revision
+byte for PCI, with the exception that higher revisions should be strict
+supersets of lower revisions.
+
+The last byte of HVERSION, "type", and the last byte of SVERSION, "opt",
+belong together;  type gives a very rough indication of what the device
+is supposed to do, and opt contains some type-specific information. (For
+example, the "bus converter" (ie bus bridge) type encodes the kind of
+bus behind the bridge in the opt field.
+
+The rest of HVERSION contains, in most cases, a number identifying the
+machine the chip was used in, or a revision indicator that just fixed
+bugs and didn't add any features (or was done in a shrinked process or
+whatever).
+
+So, here's the interface you actually should use to find your devices:
+
+
+/* Find a device, matching the model field of sversion only (from=NULL
+ * for the first call */
+struct iodc_dev *iodc_find_device(u32 sversion, struct iodc_dev *from);
+
+
+Here's a function you should use if you have special requirements, such
+as finding devices by type rather than by model.  Generally, if you're
+using this, you should be me).
+
+/* Find a device, masking out bits as specified */
+struct iodc_dev *iodc_find_device_mask(u32 hversion, u32 sversion,
+       u32 hversion_mask, u32 sversion_mask, struct iodc_dev *from);
+
+
+       Philipp Rumpf <prumpf@tux.org>
diff --git a/Documentation/parisc/debugging b/Documentation/parisc/debugging
new file mode 100644 (file)
index 0000000..5e06091
--- /dev/null
@@ -0,0 +1,39 @@
+okay, here are some hints for debugging the lower-level parts of
+linux/parisc.
+
+
+1. Absolute addresses
+
+A lot of the assembly code currently runs in real mode, which means
+absolute addresses are used instead of virtual addresses as in the
+rest of the kernel.  To translate an absolute address to a virtual
+address you can lookup in System.map, add __PAGE_OFFSET (0xc0000000
+currently).
+
+
+2. HPMCs
+
+When real-mode code tries to access non-existent memory, you'll get
+an HPMC instead of a kernel oops.  To debug an HPMC, try to find
+the System Responder/Requestor addresses.  The System Requestor
+address should match (one of the) processor HPAs (high addresses in
+the I/O range); the System Responder address is the address real-mode
+code tried to access.
+
+Typical values for the System Responder address are addresses larger
+than __PAGE_OFFSET (0xc0000000) which mean a virtual address didn't
+get translated to a physical address before real-mode code tried to
+access it.
+
+
+3. Q bit fun
+
+Certain, very critical code has to clear the Q bit in the PSW.  What
+happens when the Q bit is cleared is the CPU does not update the
+registers interruption handlers read to find out where the machine
+was interrupted - so if you get an interruption between the instruction
+that clears the Q bit and the RFI that sets it again you don't know
+where exactly it happened.  If you're lucky the IAOQ will point to the
+instrucion that cleared the Q bit, if you're not it points anywhere
+at all.  Usually Q bit problems will show themselves in unexplainable
+system hangs or running off the end of physical memory.
diff --git a/Documentation/parisc/mm b/Documentation/parisc/mm
new file mode 100644 (file)
index 0000000..d53b295
--- /dev/null
@@ -0,0 +1,31 @@
+
+The current state of Linux/PA-RISC mm is BROKEN.
+
+Someone needs to sit down and thoroughly rewrite all the cache flushing
+macro definitions.  Here are some of the problems, followed by what I
+think needs to be done about them.
+
+(1) We're using fdce / fice everywhere.  This has to stop (except in
+the routines which flush the entire cache).  The right instructions to
+be using are fdc/fic.
+
+(2) fdc/fic will throw exceptions if the address they reference isn't
+mapped.  Therefore we need to check the page is mapped before flushing
+(we're guaranteed not to have the page dirty if we don't have a software
+mapping for it any longer, right?)
+
+(3) the flush macros are right now tunnelled down to one routine to flush
+the data cache and one routine to flush the insn cache.  this is wrong.
+we should take hints from how we're called and optimise our routines
+accordingly.
+
+(4) fdc/fic actually take space register arguments.  fic takes an 3-bit sr
+argument and fdc takes a 2-bit sr argument.  right now, there's a lot of
+pissing about with %sr1 and all the macros use %sr1.  This is crazy.  We
+normally _know_ what's being referred to, and it's the current task.  So
+if we want to flush that, just use %sr3.  If it happens to be kernel,
+use %sr0 for fdc and %sr4 for fic.
+
+(5) we need to write flush_kernel_dcache_range and use it on kernel
+addresses.  all the macros are defined to work on the _current task's_
+virtual address space.
diff --git a/Documentation/parisc/registers b/Documentation/parisc/registers
new file mode 100644 (file)
index 0000000..28097fe
--- /dev/null
@@ -0,0 +1,126 @@
+Register Usage for Linux/PA-RISC
+
+[ an asterisk is used for planned usage which is currently unimplemented ]
+
+       General Registers as specified by ABI
+
+       FPU Registers must not be used in kernel mode
+
+       Control Registers
+
+CR 0 (Recovery Counter)                used for ptrace
+CR 1-CR 7(undefined)           unused
+CR 8 (Protection ID)           per-process value*
+CR 9, 12, 13 (PIDS)            unused
+CR10 (CCR)                     lazy FPU saving*
+CR11                           as specified by ABI
+CR14 (interruption vector)     initialized to fault_vector
+CR15 (EIEM)                    initialized to all ones*
+CR16 (Interval Timer)          timer interrupt
+CR17-CR22                      interruption parameters
+CR23 (EIRR)                    read for pending interrupts
+CR24 (TR 0)                    Kernel Space Page Directory Pointer
+CR25 (TR 1)                    User   Space Page Directory Pointer
+CR26 (TR 2)
+CR27 (TR 3)
+CR28 (TR 4)                    used by interruption handlers
+CR29 (TR 5)                    used by interruption handlers
+CR30 (TR 6)                    current / 0
+CR31 (TR 7)                    used by interruption handlers
+
+       Space Registers (kernel mode)
+
+SR0                            temporary space register
+SR4-SR7                        set to 0
+SR1                            temporary space register
+SR2                            unused
+SR3                            used for userspace accesses (current process)*
+
+       Space Registers (user mode)
+
+SR0                            temporary space register
+SR1                             temporary space register
+SR2                             holds space of linux gateway page
+SR3                             holds user address space value while in kernel
+SR4-SR7                         Defines short address space for user/kernel
+
+
+       Processor Status Word
+
+W (64-bit addresses)           0
+E (Little-endian)              0
+S (Secure Interval Timer)      0
+T (Taken Branch Trap)          0
+H (Higher-privilege trap)      0
+L (Lower-privilege trap)       0
+N (Nullify next instruction)   used by C code
+X (Data memory break disable)  0
+B (Taken Branch)               used by C code
+C (code address translation)   1, 0 while executing real-mode code
+V (divide step correction)     used by C code
+M (HPMC mask)                  0, 1 while executing HPMC handler*
+C/B (carry/borrow bits)                used by C code
+O (ordered references)         1*
+F (performance monitor)                0
+R (Recovery Counter trap)      0
+Q (collect interruption state) 1 (0 in code directly preceding an rfi)
+P (Protection Identifiers)     1*
+D (Data address translation)   1, 0 while executing real-mode code
+I (external interrupt mask)    used by cli()/sti() macros
+
+       "Invisible" Registers
+
+PSW default W value            0
+PSW default E value            0
+Shadow Registers               used by interruption handler code
+TOC enable bit                 1
+
+=========================================================================
+Info from John Marvin:
+
+From: "John Marvin" <jsm@udlkern.fc.hp.com>
+To: randolf@tausq.org
+Subject: Re: parisc asm questions
+
+[...]
+
+For the general registers:
+
+r1,r2,r19-r26,r28,r29 & r31 can be used without saving them first. And of
+course, you need to save them if you care about them, before calling
+another procedure. Some of the above registers do have special meanings
+that you should be aware of:
+
+    r1: The addil instruction is hardwired to place its result in r1,
+       so if you use that instruction be aware of that.
+
+    r2: This is the return pointer. In general you don't want to
+       use this, since you need the pointer to get back to your
+       caller. However, it is grouped with this set of registers
+       since the caller can't rely on the value being the same
+       when you return, i.e. you can copy r2 to another register
+       and return through that register after trashing r2, and
+       that should not cause a problem for the calling routine.
+
+    r19-r22: these are generally regarded as temporary registers.
+       Note that in 64 bit they are arg7-arg4.
+
+    r23-r26: these are arg3-arg0, i.e. you can use them if you
+       don't care about the values that were passed in anymore.
+
+    r28,r29: are ret0 and ret1. They are what you pass return values
+       in. r28 is the primary return. I'm not sure I remember
+       under what circumstances stuff is returned in r29 (millicode
+       perhaps).
+
+    r31: the ble instruction puts the return pointer in here.
+
+
+r3-r18,r27,r30 need to be saved and restored. r3-r18 are just
+    general purpose registers. r27 is the data pointer, and is
+    used to make references to global variables easier. r30 is
+    the stack pointer.
+
+John
+
+
index 7d99567adcdd753ad7fdf98d0c50057dd71e7d5a..234c75cf3614b228f5564cd60e3a8527591770cd 100644 (file)
@@ -1,3 +1,5 @@
+Revised: 2000-Dec-05.
+
 1. Specification of the API
 
 1.1. Basic concept or 'What is an URB?'
@@ -8,16 +10,16 @@ called USB Request Block, or URB for short.
 - An URB consists of all relevant information to execute any USB transaction 
 and deliver the data and status back. 
 
-- Execution of an URB is an inherently asynchronous operation, i.e. the 
-submit_urb(urb) call returns immediately after it has successfully queued 
+- Execution of an URB is inherently an asynchronous operation, i.e. the 
+usb_submit_urb(urb) call returns immediately after it has successfully queued 
 the requested action. 
 
 - Ongoing transfers for one URB (e.g. ISO) can simply be canceled with
-unlink_urb(urb) at any time. 
+usb_unlink_urb(urb) at any time. 
 
 - Each URB has a completion handler, which is called after the action
 has been successfully completed or canceled (INT transfers behave a bit
-different, see below). The URB also contains a context-pointer for free 
+differently, see below). The URB also contains a context-pointer for free 
 usage and information passing to the completion handler.
 
 - URBs can be linked. After completing one URB, the next one can be
@@ -31,6 +33,8 @@ URB-machinery.
 
 typedef struct urb
 {
+       spinlock_t lock;                // lock for the URB
+
 // ignore, for host controller/URB machine internal use
        void *hcpriv;                   // private data for host controller
        struct list_head urb_list;      // list pointer to all active urbs 
@@ -39,12 +43,12 @@ typedef struct urb
        struct urb* next;               // pointer to next URB  
        struct usb_device *dev;         // pointer to associated USB device
 
-// pipe is assembled by the various well known pipe-macros in usb.h
+// pipe is assembled by the various well-known pipe macros in usb.h
        unsigned int pipe;              // pipe information
 
 // status after each completion
        int status;                     // returned status
-       unsigned int transfer_flags;    // ASAP, SP_OK, etc.
+       unsigned int transfer_flags;    // ASAP, DISABLE_SPD, etc.
 
 // for data stage (CTRL), BULK, INT and ISO
        void *transfer_buffer;          // associated data buffer
@@ -55,7 +59,7 @@ typedef struct urb
 
 // setup stage for CTRL (always 8 bytes!)
        unsigned char* setup_packet;    // setup packet (control only)
-       
+
 // with ASAP, start_frame is set to the determined frame
        int start_frame;                // start frame (iso/irq)
        int number_of_packets;          // # of packets (iso/int)
@@ -66,7 +70,7 @@ typedef struct urb
        usb_complete_t complete;        // pointer to completion routine
        //
 // specification of the requested data offsets and length for ISO
-       iso_packet_descriptor_t  iso_frame_desc[0];
+       iso_packet_descriptor_t iso_frame_desc[0];
 } urb_t, *purb_t;
 
 
@@ -74,7 +78,7 @@ typedef struct urb
 
 URBs are allocated with the following call
 
-       purb_t alloc_urb(int isoframes)
+       purb_t usb_alloc_urb(int isoframes)
 
 Return value is a pointer to the allocated URB, 0 if allocation failed.
 The parameter isoframes specifies the number of isochronous transfer frames
@@ -82,7 +86,7 @@ you want to schedule. For CTRL/BULK/INT, use 0.
 
 To free an URB, use
 
-       void free_urb(purb_t purb)
+       void usb_free_urb(purb_t purb)
 
 This call also may free internal (host controller specific) memory in the
 future.
@@ -91,12 +95,13 @@ future.
 1.4. What has to be filled in?
 
 Depending on the type of transaction, there are some macros 
-(FILL_CONTROL_URB, FILL_BULK_URB, and FILL_INT_URB, defined in uhci.h)
+(FILL_CONTROL_URB, FILL_CONTROL_URB_TO, FILL_BULK_URB,
+FILL_BULK_URB_TO, and FILL_INT_URB, defined in usb.h)
 that simplify the URB creation. In general, all macros need the usb
-device pointer, the pipe (usual format), the transfer buffer, the 
-desired transfer length, the completion  handler, and its context. 
-Take a look at the uhci_control_msg-function that convert the old API 
-into an URB.
+device pointer, the pipe (usual format from usb.h), the transfer buffer,
+the desired transfer length, the completion  handler, and its context. 
+Take a look at the usb_control_msg function that converts the old API 
+into the URB API.
 
 Flags:
 For ISO there are two startup behaviors: Specified start_frame or ASAP.
@@ -114,7 +119,7 @@ re-submission for INT transfers that are being continued.
 
 Just call
 
-       int submit_urb(purb_t purb)
+       int usb_submit_urb(purb_t purb)
 
 It immediately returns, either with status 0 (request queued) or some
 error code, usually caused by the following:
@@ -128,7 +133,7 @@ error code, usually caused by the following:
 - Invalid INT interval (-EINVAL)
 - More than one packet for INT (-EINVAL)
 
-After submission, urb->status is USB_ST_URB_PENDING.
+After submission, urb->status is USB_ST_URB_PENDING (-EINPROGRESS).
 
 For isochronous endpoints, subsequent submitting of URBs to the same endpoint
 with the ASAP flag result in a seamless ISO streaming. Exception: The 
@@ -142,18 +147,18 @@ independent of the transfer flags (implicitly ASAP).
 For an URB which you've submitted, but which hasn't been returned to
 your driver by the host controller, call
 
-       int unlink_urb(purb_t purb)
+       int usb_unlink_urb(purb_t purb)
 
 It removes the urb from the internal list and frees all allocated
 HW descriptors. The status is changed to USB_ST_URB_KILLED. After 
-unlink_urb() returns, you can safely free the URB with free_urb(urb)
+usb_unlink_urb() returns, you can safely free the URB with usb_free_urb(urb)
 and all other possibly associated data (urb->context etc.)
 
 There is also an asynchronous unlink mode.  To use this, set the
 the USB_ASYNC_UNLINK flag in urb->transfer flags before calling
 usb_unlink_urb().  When using async unlinking, the URB will not
-normally be unlinked when unlink_urb() returns.  Instead, wait for
-the completion handler to be called.
+normally be unlinked when usb_unlink_urb() returns.  Instead, wait
+for the completion handler to be called.
 
 
 1.7. What about the completion handler?
@@ -187,13 +192,13 @@ in completion handlers.
 1.8. How to do isochronous (ISO) transfers?
 
 For ISO transfers you have to append the iso_packet_descriptor_t structure 
-to the URB for each frame you want to schedule. When using alloc_urb(n)
-(recommended), the isoframe-parameter n can be used to allocate the
-structures for n frames.
+to the URB for each frame you want to schedule. When using usb_alloc_urb(n)
+(recommended), the iso_packets parameter can be used to allocate the
+structures for iso_packets frames.
 
 For each entry you have to specify the data offset for this frame (base is
 transfer_buffer), and the length you want to write/expect to read.
-After completion, actual_length contains the actual transfered length and 
+After completion, actual_length contains the actual transferred length and 
 status contains the resulting USB-status for the ISO transfer for this frame.
 It is allowed to specify a varying length from frame to frame (e.g. for
 audio synchronisation/adaptive transfer rates). You can also use the length 
@@ -217,7 +222,7 @@ for 1, 2, 4,... 128ms. Only one URB is allocated for each interrupt. After
 calling the completion handler, that URB is recycled by the host controller
 driver (HCD).
 With the submission of one URB, the interrupt is scheduled until it is
-canceled by unlink_urb.
-
-The submit_urb()-call modifies urb->interval to the rounded value.
+canceled by usb_unlink_urb.
 
+The usb_submit_urb() call modifies urb->interval to the implemented interval
+value that is less than or equal to the requested interval value.
index d1dccece539c08e90b043b9c94fd83631f01d926..e42ab36e07c6fd4cf1c6290bb2b87a6015b1ff06 100644 (file)
@@ -1,12 +1,12 @@
-$Id: README.error-codes,v 1.1 1999/12/14 14:03:02 fliegl Exp $
+Revised: 2000-Dec-05.
 
 This is the documentation of (hopefully) all possible error codes (and
-their interpretation) that can be returned from the hostcontroller driver 
+their interpretation) that can be returned from the host controller drivers 
 and from usbcore.
 
 NOTE:
-The USB_ST_* codes are deferred and are only listed for compatibility, new
-software should use only -E* instead!
+The USB_ST_* codes are deprecated and are only listed for compatibility;
+new software should use only -E* instead!
 
 
 
@@ -25,12 +25,16 @@ USB-specific:
 
 -ENODEV                specified USB-device or bus doesn't exist
 
--ENXIO         specified endpoint doesn't exist on the device
+USB_ST_REQUEST_ERROR
+-ENXIO         a) specified endpoint doesn't exist on the device
+               b) an URB is already queued to this endpoint and
+                  USB_QUEUE_BULK wasn't used (UHCI HCDs only)
 
 USB_ST_URB_INVALID_ERROR
 -EINVAL                a) Invalid transfer type specified (or not supported)
                b) Invalid interrupt interval (0<=n<256)
                c) more than one interrupt packet requested
+               d) ISO: number_of_packets is < 0
 
 -EAGAIN                a) specified ISO start frame too early
                b) (using ISO-ASAP) too much scheduled for the future
@@ -38,6 +42,7 @@ USB_ST_URB_INVALID_ERROR
 
 -EFBIG         too much ISO frames requested (currently uhci>900)
 
+USB_ST_STALL
 -EPIPE         specified pipe-handle is already stalled
 
 -EMSGSIZE      endpoint message size is zero, do interface/alternate setting
@@ -59,7 +64,7 @@ USB_ST_NOERROR
 0                      Transfer completed successfully
 
 USB_ST_URB_KILLED
--ENOENT                        URB was canceled by unlink_urb
+-ENOENT                        URB was canceled by usb_unlink_urb
 
 USB_ST_URB_PENDING
 -EINPROGRESS           URB still pending, no results yet
@@ -73,12 +78,28 @@ USB_ST_INTERNALERROR
 USB_ST_CRC
 -EILSEQ                        CRC mismatch
 
+USB_ST_STALL
 -EPIPE                 a) babble detect
                        b) endpoint stalled
 
-USB_ST_BUFFERUNDERRUN
--ENOST                 buffer error
+USB_ST_BUFFEROVERRUN
+-ECOMM                 During an IN transfer, the host controller
+                       received data from an endpoint faster than it
+                       could be written to system memory
 
+USB_ST_BUFFERUNDERRUN
+-ENOSR                 During an OUT transfer, the host controller
+                       could not retrieve data from system memory fast
+                       enough to keep up with the USB data rate
+
+USB_ST_DATAOVERRUN
+-EOVERFLOW             The amount of data returned by the endpoint was
+                       greater than either the max packet size of the
+                       endpoint or the remaining buffer size
+
+USB_ST_DATAUNDERRUN
+-EREMOTEIO             The endpoint returned less than max packet size
+                       and that amount did not fill the specified buffer
 USB_ST_NORESPONSE
 USB_ST_TIMEOUT
 -ETIMEDOUT             transfer timed out, NAK
@@ -104,14 +125,7 @@ USB_ST_URB_INVALID_ERROR
 **************************************************************************
 
 usb_register():
-USB_ST_NOTSUPPORTED
 -EINVAL                        error during registering new driver
 
-usb_terminate_bulk():
-USB_ST_REMOVED
--ENODEV                        urb already removed
-
 usb_get_*/usb_set_*():
                        All USB errors (submit/status) can occur
-
-
index 5ad2aaa57b85bc095d11cc64da42d5a74e7644bc..98ade189e61b9c5012933bcb5e47151505a5742d 100644 (file)
@@ -7,6 +7,7 @@ linux/Documentation/usb/*, see the following:
 Linux-USB project:  http://www.linux-usb.org
   mirrors at        http://www.suse.cz/development/linux-usb/
          and        http://usb.in.tum.de/linux-usb/
+         and        http://it.linux-usb.org
 Linux USB Guide:    http://linux-usb.sourceforge.net
 Linux-USB device overview (working devices and drivers):
                     http://www.qbik.ch/usb/devices/
index 00ce3dfd444927a8508637b4c9a228f4a03ab9dc..d4740c4048e4ddfef44e8ae816608b4eaaa6cd85 100644 (file)
@@ -139,6 +139,9 @@ Digi AccelePort Driver
   (plus a parallel port) and 4 port USB serial converters.  The driver
   does NOT yet support the Digi AccelePort USB 8.
 
+  This driver works under SMP with the usb-uhci driver.  It does not
+  work under SMP with the uhci driver.
+
   The driver is generally working, though we still have a few more ioctls
   to implement and final testing and debugging to do.  The paralled port
   on the USB 2 is supported as a serial to parallel converter; in other
@@ -187,6 +190,12 @@ Empeg empeg-car Mark I/II Driver (empeg.c)
   This is an experimental driver to provide connectivity support for the
   client synchronization tools for an Empeg empeg-car mp3 player.
 
+  Tips:
+
+    * Don't forget to create the device nodes for ttyUSB{0,1,2,...}
+    * modprobe empeg (modprobe is your friend)
+    * emptool --usb /dev/ttyUSB0 (or whatever you named your device node)
+
   The driver is still pretty new, so some testing 'in the wild' would be
   helpful. :)
 
index c42849b99e450bba42a2a50d5f1f11cfb9a6bd8d..a6ae5d123e20d594c0f2adf4f8309b05563b7e01 100644 (file)
@@ -1325,7 +1325,7 @@ M:        pberger@brimson.com
 M:     alborchers@steinerpoint.com
 L:     linux-usb-users@lists.sourceforge.net
 L:     linux-usb-devel@lists.sourceforge.net
-S:     Supported
+S:     Maintained
 
 USB SERIAL KEYSPAN DRIVER
 P:     Hugh Blemings
@@ -1351,6 +1351,13 @@ L:       linux-usb-users@lists.sourceforge.net
 L:     linux-usb-devel@lists.sourceforge.net
 S:     Maintained
 
+USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER
+P:     Gary Brubaker
+M:     xavyer@ix.netcom.com
+L:     linux-usb-users@lists.sourceforge.net
+L:     linux-usb-devel@lists.sourceforge.net
+S:     Maintained
+
 USB MASS STORAGE DRIVER
 P:     Matthew Dharm
 M:     mdharm-usb@one-eyed-alien.net
index 276c6336878886cbb4b3ce3ab2316a68f820ee37..c52b170ecdcaebe2e0ff0ef6d165659bf39e724a 100644 (file)
@@ -631,43 +631,39 @@ end_move_self:                                    # now we are at the right place
                                                # appropriate
 
 # that was painless, now we enable a20
-
-#
-# First, try the "fast A20 gate".
-#
-       inb     $0x92,%al
-       orb     $0x02,%al                       # Fast A20 on
-       andb    $0xfe,%al                       # Don't reset CPU!
-       outb    %al,$0x92
-
-#
-# Now comes the tricky part: some machines don't have a KBC and thus
-# would end up looping almost indefinitely here.  HOWEVER, once we
-# have done the first command write, we must not stop the sequence.
-# Therefore, the first empty_8042 should check to see if the fast A20
-# did the trick and stop its probing at that stage; but subsequent ones
-# must not do so.
-#
-       movb    $0x01,%dl                       # A20-sensitive
        call    empty_8042
-       jnz     a20_wait                        # A20 already on?
 
        movb    $0xD1, %al                      # command write
        outb    %al, $0x64
-       call    empty_8042_no_a20_exit
+       call    empty_8042
 
        movb    $0xDF, %al                      # A20 on
        outb    %al, $0x60
-       call    empty_8042_no_a20_exit
+       call    empty_8042
+
+#
+#      You must preserve the other bits here. Otherwise embarrasing things
+#      like laptops powering off on boot happen. Corrected version by Kira
+#      Brown from Linux 2.2
+#
+       inb     $0x92, %al                      # 
+       orb     $02, %al                        # "fast A20" version
+       outb    %al, $0x92                      # some chips have only this
 
 # wait until a20 really *is* enabled; it can take a fair amount of
 # time on certain systems; Toshiba Tecras are known to have this
 # problem.  The memory location used here (0x200) is the int 0x80
 # vector, which should be safe to use.
 
+       xorw    %ax, %ax                        # segment 0x0000
+       movw    %ax, %fs
+       decw    %ax                             # segment 0xffff (HMA)
+       movw    %ax, %gs
 a20_wait:
-       call    a20_test
-       jz      a20_wait
+       incw    %ax                             # unused memory location <0xfff0
+       movw    %ax, %fs:(0x200)                # we use the "int 0x80" vector
+       cmpw    %gs:(0x210), %ax                # and its corresponding HMA addr
+       je      a20_wait                        # loop until no longer aliased
 
 # make sure any possible coprocessor is properly reset..
        xorw    %ax, %ax
@@ -830,25 +826,21 @@ bootsect_panic_mess:
 # Some machines have delusions that the keyboard buffer is always full
 # with no keyboard attached...
 #
-# If %dl is nonzero on entry, terminate with ZF=0 if A20 becomes alive,
-# otherwise terminate with ZF=1.
+# If there is no keyboard controller, we will usually get 0xff
+# to all the reads.  With each IO taking a microsecond and
+# a timeout of 100,000 iterations, this can take about half a
+# second ("delay" == outb to port 0x80). That should be ok,
+# and should also be plenty of time for a real keyboard controller
+# to empty.
+#
 
-empty_8042_no_a20_exit:
-       xorb    %dl,%dl                         # Not A20-sensitive
 empty_8042:
        pushl   %ecx
-       movl    $0x000FFFFF, %ecx
+       movl    $100000, %ecx
 
 empty_8042_loop:
        decl    %ecx
-       jz      empty_8042_end_loop             # ZF=1
-
-       # Always call the test routine to keep delays constant
-       call    a20_test
-       jz      ignore_a20
-       and     %dl,%dl
-       jnz     empty_8042_end_loop             # ZF=0
-ignore_a20:
+       jz      empty_8042_end_loop
 
        call    delay
 
@@ -863,38 +855,10 @@ ignore_a20:
 no_output:
        testb   $2, %al                         # is input buffer full?
        jnz     empty_8042_loop                 # yes - loop
-       # ZF=1
-
 empty_8042_end_loop:
        popl    %ecx
        ret
 
-a20_test:
-       pushw   %ax
-       pushw   %cx
-       pushw   %fs
-       pushw   %gs
-       xorw    %ax, %ax                        # segment 0x0000
-       movw    %ax, %fs
-       decw    %ax                             # segment 0xffff (HMA)
-       movw    %ax, %gs
-       movw    0x100,%cx
-       movw    %fs:(0x200),%ax                 # So we keep cycling...
-       pushw   %ax                             # Be extra paranoid...
-a20_loop:
-       incw    %ax                             # unused memory location <0xfff0
-       movw    %ax, %fs:(0x200)                # we use the "int 0x80" vector
-       cmpw    %gs:(0x210), %ax                # and its corresponding HMA addr
-       jnz     a20_ret                         # if ZF not set A20 is functional
-       loop    a20_loop
-a20_ret:
-       popw    %fs:(0x200)
-       popw    %gs
-       popw    %fs
-       popw    %cx
-       popw    %ax
-       ret                                     # if ZF set A20 is not operational
-
 # Read the cmos clock. Return the seconds in al
 gettime:
        pushw   %cx
@@ -911,7 +875,6 @@ gettime:
 
 # Delay is needed after doing I/O
 delay:
-       outb    %al,$0x80                       # What the main kernel uses
        outb    %al,$0x80
        ret
 
index fc54896f8e272b18175f67faba9098858bd89af3..4179c8f13b3674e96c7a2cf61e8b6e3225831735 100644 (file)
@@ -220,66 +220,19 @@ void __init setup_local_APIC (void)
                BUG();
 
        /*
-        * Set up LVT0, LVT1:
-        *
-        * set up through-local-APIC on the BP's LINT0. This is not
-        * strictly necessery in pure symmetric-IO mode, but sometimes
-        * we delegate interrupts to the 8259A.
-        */
-       /*
-        * TODO: set up through-local-APIC from through-I/O-APIC? --macro
-        */
-       value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
-       if (!smp_processor_id() && (pic_mode || !value)) {
-               value = APIC_DM_EXTINT;
-               printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
-       } else {
-               value = APIC_DM_EXTINT | APIC_LVT_MASKED;
-               printk("masked ExtINT on CPU#%d\n", smp_processor_id());
-       }
-       apic_write_around(APIC_LVT0, value);
-
-       /*
-        * only the BP should see the LINT1 NMI signal, obviously.
+        * Intel recommends to set DFR, LDR and TPR before enabling
+        * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
+        * document number 292116).  So here it goes...
         */
-       if (!smp_processor_id())
-               value = APIC_DM_NMI;
-       else
-               value = APIC_DM_NMI | APIC_LVT_MASKED;
-       if (!APIC_INTEGRATED(ver))              /* 82489DX */
-               value |= APIC_LVT_LEVEL_TRIGGER;
-       apic_write_around(APIC_LVT1, value);
-
-       if (APIC_INTEGRATED(ver)) {             /* !82489DX */
-               maxlvt = get_maxlvt();
-               if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
-                       apic_write(APIC_ESR, 0);
-               value = apic_read(APIC_ESR);
-               printk("ESR value before enabling vector: %08lx\n", value);
-
-               value = ERROR_APIC_VECTOR;      // enables sending errors
-               apic_write_around(APIC_LVTERR, value);
-               /*
-                * spec says clear errors after enabling vector.
-                */
-               if (maxlvt > 3)
-                       apic_write(APIC_ESR, 0);
-               value = apic_read(APIC_ESR);
-               printk("ESR value after enabling vector: %08lx\n", value);
-       } else
-               printk("No ESR for 82489DX.\n");
 
        /*
-        * Set Task Priority to 'accept all'. We never change this
-        * later on.
+        * Put the APIC into flat delivery mode.
+        * Must be "all ones" explicitly for 82489DX.
         */
-       value = apic_read(APIC_TASKPRI);
-       value &= ~APIC_TPRI_MASK;
-       apic_write_around(APIC_TASKPRI, value);
+       apic_write_around(APIC_DFR, 0xffffffff);
 
        /*
-        * Set up the logical destination ID and put the
-        * APIC into flat delivery mode.
+        * Set up the logical destination ID.
         */
        value = apic_read(APIC_LDR);
        value &= ~APIC_LDR_MASK;
@@ -287,9 +240,12 @@ void __init setup_local_APIC (void)
        apic_write_around(APIC_LDR, value);
 
        /*
-        * Must be "all ones" explicitly for 82489DX.
+        * Set Task Priority to 'accept all'. We never change this
+        * later on.
         */
-       apic_write_around(APIC_DFR, 0xffffffff);
+       value = apic_read(APIC_TASKPRI);
+       value &= ~APIC_TPRI_MASK;
+       apic_write_around(APIC_TASKPRI, value);
 
        /*
         * Now that we are all set up, enable the APIC
@@ -326,6 +282,56 @@ void __init setup_local_APIC (void)
         */
        value |= SPURIOUS_APIC_VECTOR;
        apic_write_around(APIC_SPIV, value);
+
+       /*
+        * Set up LVT0, LVT1:
+        *
+        * set up through-local-APIC on the BP's LINT0. This is not
+        * strictly necessery in pure symmetric-IO mode, but sometimes
+        * we delegate interrupts to the 8259A.
+        */
+       /*
+        * TODO: set up through-local-APIC from through-I/O-APIC? --macro
+        */
+       value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
+       if (!smp_processor_id() && (pic_mode || !value)) {
+               value = APIC_DM_EXTINT;
+               printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
+       } else {
+               value = APIC_DM_EXTINT | APIC_LVT_MASKED;
+               printk("masked ExtINT on CPU#%d\n", smp_processor_id());
+       }
+       apic_write_around(APIC_LVT0, value);
+
+       /*
+        * only the BP should see the LINT1 NMI signal, obviously.
+        */
+       if (!smp_processor_id())
+               value = APIC_DM_NMI;
+       else
+               value = APIC_DM_NMI | APIC_LVT_MASKED;
+       if (!APIC_INTEGRATED(ver))              /* 82489DX */
+               value |= APIC_LVT_LEVEL_TRIGGER;
+       apic_write_around(APIC_LVT1, value);
+
+       if (APIC_INTEGRATED(ver)) {             /* !82489DX */
+               maxlvt = get_maxlvt();
+               if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
+                       apic_write(APIC_ESR, 0);
+               value = apic_read(APIC_ESR);
+               printk("ESR value before enabling vector: %08lx\n", value);
+
+               value = ERROR_APIC_VECTOR;      // enables sending errors
+               apic_write_around(APIC_LVTERR, value);
+               /*
+                * spec says clear errors after enabling vector.
+                */
+               if (maxlvt > 3)
+                       apic_write(APIC_ESR, 0);
+               value = apic_read(APIC_ESR);
+               printk("ESR value after enabling vector: %08lx\n", value);
+       } else
+               printk("No ESR for 82489DX.\n");
 }
 
 void __init init_apic_mappings(void)
index d9bd520ac541dc085b4285c363e1de4166935e2d..58984fd080bcb189e61f0e7b2f449c3867f50795 100644 (file)
@@ -424,9 +424,12 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
        DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
        mask &= pcibios_irq_mask;
 
-       /* Find the best IRQ to assign */
-       newirq = 0;
-       if (assign) {
+       /*
+        * Find the best IRQ to assign: use the one
+        * reported by the device if possible.
+        */
+       newirq = dev->irq;
+       if (!newirq && assign) {
                for (i = 0; i < 16; i++) {
                        if (!(mask & (1 << i)))
                                continue;
@@ -436,13 +439,18 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
                                newirq = i;
                        }
                }
-               DBG(" -> newirq=%d", newirq);
        }
+       DBG(" -> newirq=%d", newirq);
 
        /* Try to get current IRQ */
        if (r->get && (irq = r->get(pirq_router_dev, d, pirq))) {
                DBG(" -> got IRQ %d\n", irq);
                msg = "Found";
+               /* We refuse to override the dev->irq information. Give a warning! */
+               if (dev->irq && dev->irq != irq) {
+                       printk("IRQ routing conflict in pirq table! Try 'pci=autoirq'\n");
+                       return 0;
+               }
        } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
                DBG(" -> assigning IRQ %d", newirq);
                if (r->set(pirq_router_dev, d, pirq, newirq)) {
@@ -576,19 +584,17 @@ void pcibios_penalize_isa_irq(int irq)
 
 void pcibios_enable_irq(struct pci_dev *dev)
 {
-       if (!dev->irq) {
-               u8 pin;
-               pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-               if (pin && !pcibios_lookup_irq(dev, 1)) {
-                       char *msg;
-                       if (io_apic_assign_pci_irqs)
-                               msg = " Probably buggy MP table.";
-                       else if (pci_probe & PCI_BIOS_IRQ_SCAN)
-                               msg = "";
-                       else
-                               msg = " Please try using pci=biosirq.";
-                       printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
-                              'A' + pin - 1, dev->slot_name, msg);
-               }
+       u8 pin;
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
+               char *msg;
+               if (io_apic_assign_pci_irqs)
+                       msg = " Probably buggy MP table.";
+               else if (pci_probe & PCI_BIOS_IRQ_SCAN)
+                       msg = "";
+               else
+                       msg = " Please try using pci=biosirq.";
+               printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
+                      'A' + pin - 1, dev->slot_name, msg);
        }
 }
index eef85b801d3fdb3f62eb04e378b77a6cad634dae..b0bbdb759c85e18d6c26d9d10dfaab5f2c3ddb51 100644 (file)
@@ -2172,7 +2172,7 @@ int get_cpuinfo(char * buffer)
                                "fpu_exception\t: %s\n"
                                "cpuid level\t: %d\n"
                                "wp\t\t: %s\n"
-                               "flags\t:",
+                               "flags\t\t:",
                             c->fdiv_bug ? "yes" : "no",
                             c->hlt_works_ok ? "no" : "yes",
                             c->f00f_bug ? "yes" : "no",
index 36d88a6eddc9d550c0801c33f612d2da93fc921c..f4f284a9adc731d564ecbfa4de74b42ab34ec224 100644 (file)
@@ -13,6 +13,7 @@
  * enhanced by Bjoern Brauel and Roman Hodek
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
index 844c83cbe6e01de63277296bd1e20967317ce705..52331d2333e13d95f576b492f5854b72d9053b17 100644 (file)
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.11 1999/10/17 19:55:22 harald Exp $
 #
 # Makefile for MIPS-specific library files..
 #
index 4850b09cea0eacdf6b7749f6494db1ea8b448c7a..a7f1e43c868a17f3571a154b5b050dc012a02ab9 100644 (file)
@@ -3,8 +3,6 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * $Id: memcpy.S,v 1.3 1998/07/10 01:14:49 ralf Exp $
- *
  * Unified implementation of memcpy, memmove and the __copy_user backend.
  * For __rmemcpy and memmove an exception is always a kernel bug, therefore
  * they're not protected.  In order to keep the exception fixup routine
@@ -410,6 +408,7 @@ LEAF(memmove)
        sltu    t0, v0, a1                      # dst + len < src -> non-
        bnez    t0, __memcpy                    # overlapping, can use memcpy
         move   v0, a0                          /* return value */
+       beqz    a2, r_out
        END(memmove)
 
 LEAF(__rmemcpy)                                        /* a0=dst a1=src a2=len */
index 32f175756c9f7507e9be469587f2736f810053ac..0340cc2a143a733cc47cb062d2053d2fee890413 100644 (file)
@@ -1,13 +1,9 @@
 /*
- * include/asm-mips/types.h
- *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
  * Copyright (C) 1998 by Ralf Baechle
- *
- * $Id: memset.S,v 1.2 1998/04/25 17:01:45 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/offset.h>
index 3e61ae79edeb28870633f30a592cd81e2ac9b139..b8392d527caf754965c91a91d9532dd1842d60b7 100644 (file)
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.2 1999/11/19 20:35:22 ralf Exp $
 #
 # Makefile for MIPS-specific library files..
 #
index eb51e10692e76d0e2a08dfb9c00065d67130c520..494193c787c48e6b684b4d5bdaaec8a8794cf061 100644 (file)
@@ -458,6 +458,7 @@ LEAF(memmove)
        sltu    ta0, v0, a1                     # dst + len < src -> non-
        bnez    ta0, __memcpy                   # overlapping, can use memcpy
         move   v0, a0                          /* return value */
+       beqz    a2, r_out
        END(memmove)
 
 LEAF(__rmemcpy)                                        /* a0=dst a1=src a2=len */
index 4a051cebff43fc033f53d8ae5f1a8e56dcea0bd9..ca5218210af218be0d84245fd5973aabf9d4c214 100644 (file)
@@ -1,15 +1,16 @@
-/* $Id: memset.S,v 1.3 2000/01/15 23:48:55 ralf Exp $
- *
+/*
  * 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) 1998, 1999 by Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1998, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
 #include <asm/asm.h>
 #include <asm/offset.h>
 #include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
 
 #define EX(insn,reg,addr,handler)                      \
 9:     insn    reg, addr;                              \
@@ -34,8 +35,6 @@
  * a1: char to fill with
  * a2: size of area to clear
  */
-#include <asm/mipsregs.h>
-#include <asm/stackframe.h>
        .set    noreorder
        .align  5
 LEAF(memset)
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
new file mode 100644 (file)
index 0000000..ec27df6
--- /dev/null
@@ -0,0 +1,91 @@
+#
+# parisc/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# 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
+# Portions Copyright (C) 1999 The Puffin Group
+#
+# Modified for PA-RISC Linux by Paul Lahaie, Alex deVries, 
+# Mike Shaver, Helge Deller and Martin K. Petersen
+#
+
+FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align 
+
+CPP=$(CC) -E
+OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
+LDFLAGS =
+LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux.lds $(LDFLAGS)
+
+CFLAGS_PIPE := -pipe
+CFLAGS_NSR  := -fno-strength-reduce
+CFLAGS := $(CFLAGS) -D__linux__ $(CFLAGS_PIPE) $(CFLAGS_NSR)
+
+# These should be on for older toolchains or SOM toolchains that don't
+# enable them by default.
+CFLAGS += -mno-space-regs -mfast-indirect-calls
+
+# If we become able to compile for specific platforms, this should be
+# conditional on that.
+CFLAGS += -mschedule=7200
+
+# No fixed-point multiply
+CFLAGS += -mdisable-fpregs
+
+HEAD = arch/parisc/kernel/head.o 
+
+SUBDIRS := $(SUBDIRS) $(addprefix arch/parisc/, tools kernel mm lib hpux)
+CORE_FILES :=  $(addprefix arch/parisc/, kernel/pdc_cons.o kernel/process.o \
+       lib/lib.a mm/mm.o kernel/kernel.o hpux/hpux.o) \
+       $(CORE_FILES) arch/parisc/kernel/init_task.o
+LIBS := `$(CC) -print-libgcc-file-name` $(TOPDIR)/arch/parisc/lib/lib.a $(LIBS) 
+
+ifdef CONFIG_MATH_EMULATION
+SUBDIRS := $(SUBDIRS) arch/parisc/math-emu
+DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.a
+endif
+
+ifdef CONFIG_KWDB
+SUBDIRS := $(SUBDIRS) arch/parisc/kdb
+DRIVERS := $(DRIVERS) arch/parisc/kdb/kdb.o
+
+arch/parisc/kdb: dummy
+       $(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kdb
+endif
+
+arch/parisc/kernel: dummy
+       $(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kernel
+
+arch/parisc/mm: dummy
+       $(MAKE) linuxsubdirs SUBDIRS=arch/parisc/mm
+
+palo: vmlinux
+       export TOPDIR=`pwd`; export CONFIG_STI_CONSOLE=$(CONFIG_STI_CONSOLE); \
+       unset STRIP LDFLAGS CPP CPPFLAGS AFLAGS CFLAGS CC LD; cd ../palo && make lifimage
+
+Image: palo
+
+Image-clean:
+
+ramdisk.o:
+
+zImage: palo
+
+bzImage: palo
+
+compressed: zImage
+
+install: 
+
+archclean:
+
+archmrproper:
+
+archdep:
diff --git a/arch/parisc/config.in b/arch/parisc/config.in
new file mode 100644 (file)
index 0000000..eed8018
--- /dev/null
@@ -0,0 +1,208 @@
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+
+mainmenu_name "Linux Kernel Configuration"
+
+define_bool CONFIG_PARISC y
+define_bool CONFIG_UID16 n
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'General options'
+
+# bool 'Symmetric multi-processing support' CONFIG_SMP
+define_bool CONFIG_SMP n
+
+bool 'Kernel Debugger support' CONFIG_KWDB
+# define_bool CONFIG_KWDB n
+
+# bool 'GSC/Gecko bus support' CONFIG_GSC y
+define_bool CONFIG_GSC y
+
+bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y
+bool 'LASI I/O support' CONFIG_GSC_LASI y
+
+bool 'PCI bus support' CONFIG_PCI y
+
+if [ "$CONFIG_PCI" = "y" ]; then
+       bool 'GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y
+       bool 'LBA/Elroy PCI support' CONFIG_PCI_LBA n
+fi 
+
+if [ "$CONFIG_PCI_LBA" = "y" ]; then
+       define_bool CONFIG_IOSAPIC y
+       define_bool CONFIG_IOMMU_SBA y
+fi
+
+#
+# if [ "$CONFIG_PCI_EPIC" = "y" ]; then...
+#
+
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+  bool 'Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Networking support' CONFIG_NET
+
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
+fi
+
+endmenu
+
+##source drivers/parport/Config.in
+mainmenu_option next_comment
+comment 'Parallel port support'
+
+tristate 'Parallel port support' CONFIG_PARPORT
+if [ "$CONFIG_PARPORT" != "n" ]; then
+   if [ "$CONFIG_PCI" = "y" ]; then
+     dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+     if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+        bool '    Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
+        if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+           bool '    SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO
+        fi
+     fi
+   fi
+   if [ "$CONFIG_GSC_LASI" = "y" ]; then
+      dep_tristate '  LASI/ASP builtin parallel-port' CONFIG_PARPORT_GSC $CONFIG_PARPORT
+   else
+      define_tristate CONFIG_PARPORT_GSC n
+   fi
+
+   # If exactly one hardware type is selected then parport will optimise away
+   # support for loading any others.  Defeat this if the user is keen.
+   bool '  Support foreign hardware' CONFIG_PARPORT_OTHER
+
+   bool '  IEEE 1284 transfer modes' CONFIG_PARPORT_1284
+fi
+endmenu
+
+
+source drivers/block/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+  source net/Config.in
+fi
+
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+  comment 'SCSI support type (disk, tape, CDrom)'
+
+  dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
+  if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
+    int  'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
+  fi
+
+  dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
+  dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+  if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
+    bool '  Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
+    int  'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2
+  fi
+  dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
+
+  comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
+  bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
+  bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+
+  mainmenu_option next_comment
+  comment 'SCSI low-level drivers'
+  if [ "$CONFIG_GSC_LASI" = "y" ]; then
+    dep_tristate 'Lasi SCSI support' CONFIG_SCSI_LASI $CONFIG_SCSI
+    dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_SCSI
+  fi
+  if [ "$CONFIG_PCI" = "y" ]; then
+    dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
+  fi
+  if [ "$CONFIG_SCSI_ZALON" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+    int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
+    int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
+    int  '  synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20
+    bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
+    bool '  use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED
+  fi
+  endmenu
+fi
+endmenu
+
+if [ "$CONFIG_NET" = "y" ]; then
+  mainmenu_option next_comment
+  comment 'Network device support'
+
+  bool 'Network device support' CONFIG_NETDEVICES
+
+  if [ "$CONFIG_NETDEVICES" = "y" ]; then
+    if [ "$CONFIG_GSC_LASI" = "y" ]; then
+      tristate 'Lasi ethernet' CONFIG_LASI_82596
+    fi
+    source drivers/net/Config.in
+  fi
+  endmenu
+fi
+
+source drivers/char/Config.in
+
+source fs/Config.in
+
+mainmenu_option next_comment
+comment 'Sound Drivers'
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+   source drivers/sound/Config.in
+fi
+endmenu
+
+if [ "$CONFIG_VT" = "y" ]; then
+  mainmenu_option next_comment
+  comment 'Console drivers'
+  source drivers/video/Config.in
+
+#  bool 'IODC console' CONFIG_IODC_CONSOLE
+  bool 'STI console' CONFIG_STI_CONSOLE
+  if [ "$CONFIG_IODC_CONSOLE" = "n" ]; then
+    if [ "$CONFIG_GSC_PS2" = "y" ]; then
+      define_bool CONFIG_DUMMY_CONSOLE y
+    fi
+  fi
+  if [ "$CONFIG_STI_CONSOLE" = "y" ]; then
+    define_bool CONFIG_DUMMY_CONSOLE y
+  fi
+  endmenu
+fi
+# endmenu
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+endmenu
+
diff --git a/arch/parisc/defconfig b/arch/parisc/defconfig
new file mode 100644 (file)
index 0000000..352fa78
--- /dev/null
@@ -0,0 +1,363 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_PARISC=y
+# CONFIG_UID16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# General options
+#
+# CONFIG_SMP is not set
+# CONFIG_KWDB is not set
+CONFIG_GSC=y
+CONFIG_IOMMU_CCIO=y
+CONFIG_GSC_LASI=y
+CONFIG_PCI=y
+CONFIG_GSC_DINO=y
+CONFIG_PCI_LBA=y
+CONFIG_IOSAPIC=y
+CONFIG_IOMMU_SBA=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_SOM=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=y
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_GSC=y
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_SCSI_LASI=y
+CONFIG_SCSI_ZALON=y
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_LASI_82596=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL 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_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_DE4X5 is not set
+CONFIG_TULIP=y
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_LNE390 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_RTL8129 is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_GSC_PS2=y
+CONFIG_HIL=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_GSC=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_PRINTER=y
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_GENRTC=y
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# 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
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Sound Drivers
+#
+# CONFIG_SOUND is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+# CONFIG_STI_CONSOLE is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
diff --git a/arch/parisc/hpux/Makefile b/arch/parisc/hpux/Makefile
new file mode 100644 (file)
index 0000000..d946959
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+all: hpux.o
+O_TARGET = hpux.o
+O_OBJS = entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o
+
+.o.S:  $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/parisc/hpux/entry_hpux.S b/arch/parisc/hpux/entry_hpux.S
new file mode 100644 (file)
index 0000000..165aeb6
--- /dev/null
@@ -0,0 +1,537 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+ *
+ * modified by Matthew Wilcox <willy@bofh.ai> 1999-07-26
+ */
+
+
+#define ASSEMBLY
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+
+
+       .text
+
+#define ENTRY_NAME(_name_) .word _name_
+
+       .align 4
+       .export hpux_call_table
+hpux_call_table:
+       ENTRY_NAME(sys_ni_syscall)      /* 0 */
+       ENTRY_NAME(sys_exit)
+       ENTRY_NAME(hpux_fork_wrapper)
+       ENTRY_NAME(sys_read)
+       ENTRY_NAME(sys_write)
+       ENTRY_NAME(sys_open)    /* 5 */
+       ENTRY_NAME(sys_close)
+       ENTRY_NAME(hpux_wait)
+       ENTRY_NAME(sys_creat)
+       ENTRY_NAME(sys_link)
+       ENTRY_NAME(sys_unlink)  /* 10 */
+       ENTRY_NAME(hpux_execv_wrapper)
+       ENTRY_NAME(sys_chdir)
+       ENTRY_NAME(sys_time)
+       ENTRY_NAME(sys_mknod)
+       ENTRY_NAME(sys_chmod)   /* 15 */
+       ENTRY_NAME(sys_chown)
+       ENTRY_NAME(hpux_brk)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_lseek)
+       ENTRY_NAME(sys_getpid)  /* 20 */
+       ENTRY_NAME(hpux_mount)
+       ENTRY_NAME(sys_oldumount)
+       ENTRY_NAME(sys_setuid)
+       ENTRY_NAME(sys_getuid)
+       ENTRY_NAME(sys_stime)   /* 25 */
+       ENTRY_NAME(hpux_ptrace)
+       ENTRY_NAME(sys_alarm)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_pause)
+       ENTRY_NAME(sys_utime)   /* 30 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_access)
+       ENTRY_NAME(hpux_nice)
+       ENTRY_NAME(sys_ni_syscall)      /* 35 */
+       ENTRY_NAME(sys_sync)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_newstat)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_newlstat)        /* 40 */
+       ENTRY_NAME(sys_dup)
+       ENTRY_NAME(hpux_pipe_wrapper)
+       ENTRY_NAME(sys_times)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 45 */
+       ENTRY_NAME(sys_setgid)
+       ENTRY_NAME(sys_getgid)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 50 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(hpux_ioctl)
+       ENTRY_NAME(sys_ni_syscall)      /* 55 */
+       ENTRY_NAME(sys_symlink)
+       ENTRY_NAME(hpux_utssys)
+       ENTRY_NAME(sys_readlink)
+       ENTRY_NAME(hpux_execve_wrapper)
+       ENTRY_NAME(sys_umask)   /* 60 */
+       ENTRY_NAME(sys_chroot)
+       ENTRY_NAME(sys_fcntl)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 65 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(hpux_sbrk)
+       ENTRY_NAME(sys_ni_syscall)      /* 70 */
+       ENTRY_NAME(sys_mmap)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 75 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 80 */
+       ENTRY_NAME(sys_getpgid)
+       ENTRY_NAME(sys_setpgid)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 85 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_dup2)            /* 90 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_newfstat)
+       ENTRY_NAME(sys_select)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 95 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 100 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 105 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 110 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 115 */
+       ENTRY_NAME(sys_gettimeofday)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 120 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_fchown)
+       ENTRY_NAME(sys_fchmod)
+       ENTRY_NAME(sys_ni_syscall)      /* 125 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_rename)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 130 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(hpux_sysconf)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 135 */
+       ENTRY_NAME(sys_mkdir)
+       ENTRY_NAME(sys_rmdir)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 140 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 145 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 150 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 155 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 160 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 165 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 170 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 175 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 180 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 185 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 190 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(hpux_getdomainname)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 195 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_waitpid) /* 200 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 205 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 210 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 215 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 220 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 225 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 230 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 235 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 240 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 245 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 250 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 255 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 260 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 265 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 270 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_fchdir)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_accept)          /* 275 */
+       ENTRY_NAME(sys_bind)
+       ENTRY_NAME(sys_connect)
+       ENTRY_NAME(sys_getpeername)
+       ENTRY_NAME(sys_getsockname)
+       ENTRY_NAME(sys_getsockopt)      /* 280 */
+       ENTRY_NAME(sys_listen)
+       ENTRY_NAME(sys_recv)
+       ENTRY_NAME(sys_recvfrom)
+       ENTRY_NAME(sys_recvmsg)
+       ENTRY_NAME(sys_send)            /* 285 */
+       ENTRY_NAME(sys_sendmsg)
+       ENTRY_NAME(sys_sendto)
+       ENTRY_NAME(sys_setsockopt)
+       ENTRY_NAME(sys_shutdown)
+       ENTRY_NAME(sys_socket)          /* 290 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 295 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 300 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 305 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 310 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 315 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 320 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 325 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 330 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_lchown)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 335 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 340 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 345 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 350 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_nanosleep)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 355 */
+       ENTRY_NAME(hpux_getdents)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 360 */
+       ENTRY_NAME(hpux_fstat64)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 365 */
+       ENTRY_NAME(hpux_lstat64)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(hpux_stat64)
+       ENTRY_NAME(sys_ni_syscall)      /* 370 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 375 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 380 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 385 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 390 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 395 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 400 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 405 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 410 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 415 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 420 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 425 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 430 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 435 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 440 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 445 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 450 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 455 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 460 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 465 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 470 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 475 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 480 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 485 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 490 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 495 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 500 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 505 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)      /* 510 */
+       ENTRY_NAME(sys_ni_syscall)
+       ENTRY_NAME(sys_ni_syscall)
+.end
+
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
new file mode 100644 (file)
index 0000000..4957a05
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * linux/arch/parisc/kernel/sys_hpux.c
+ *
+ * implements HPUX syscalls.
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+int hpux_execve(struct pt_regs *regs)
+{
+       int error;
+       char *filename;
+
+       filename = getname((char *) regs->gr[26]);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               goto out;
+
+       error = do_execve(filename, (char **) regs->gr[25],
+               (char **)regs->gr[24], regs);
+
+       if (error == 0)
+               current->ptrace &= ~PT_DTRACE;
+       putname(filename);
+
+out:
+       return error;
+}
+
+struct hpux_dirent {
+       long    d_off_pad; /* we only have a 32-bit off_t */
+       long    d_off;
+       ino_t   d_ino;
+       short   d_reclen;
+       short   d_namlen;
+       char    d_name[1];
+};
+
+struct getdents_callback {
+       struct hpux_dirent *current_dir;
+       struct hpux_dirent *previous;
+       int count;
+       int error;
+};
+
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
+
+static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+{
+       struct hpux_dirent * dirent;
+       struct getdents_callback * buf = (struct getdents_callback *) __buf;
+       int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+       buf->error = -EINVAL;   /* only used if we fail.. */
+       if (reclen > buf->count)
+               return -EINVAL;
+       dirent = buf->previous;
+       if (dirent)
+               put_user(offset, &dirent->d_off);
+       dirent = buf->current_dir;
+       buf->previous = dirent;
+       put_user(ino, &dirent->d_ino);
+       put_user(reclen, &dirent->d_reclen);
+       put_user(namlen, &dirent->d_namlen);
+       copy_to_user(dirent->d_name, name, namlen);
+       put_user(0, dirent->d_name + namlen);
+       ((char *) dirent) += reclen;
+       buf->current_dir = dirent;
+       buf->count -= reclen;
+       return 0;
+}
+
+#undef NAME_OFFSET
+#undef ROUND_UP
+
+int hpux_getdents(unsigned int fd, struct hpux_dirent *dirent, unsigned int count)
+{
+       struct file * file;
+       struct dentry * dentry;
+       struct inode * inode;
+       struct hpux_dirent * lastdirent;
+       struct getdents_callback buf;
+       int error;
+
+       lock_kernel();
+       error = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+
+       dentry = file->f_dentry;
+       if (!dentry)
+               goto out_putf;
+
+       inode = dentry->d_inode;
+       if (!inode)
+               goto out_putf;
+
+       buf.current_dir = dirent;
+       buf.previous = NULL;
+       buf.count = count;
+       buf.error = 0;
+
+       error = -ENOTDIR;
+       if (!file->f_op || !file->f_op->readdir)
+               goto out_putf;
+
+       /*
+        * Get the inode's semaphore to prevent changes
+        * to the directory while we read it.
+        */
+       down(&inode->i_sem);
+       error = file->f_op->readdir(file, &buf, filldir);
+       up(&inode->i_sem);
+       if (error < 0)
+               goto out_putf;
+       error = buf.error;
+       lastdirent = buf.previous;
+       if (lastdirent) {
+               put_user(file->f_pos, &lastdirent->d_off);
+               error = count - buf.count;
+       }
+
+out_putf:
+       fput(file);
+out:
+       unlock_kernel();
+       return error;
+}
+
+int hpux_mount(const char *fs, const char *path, int mflag,
+               const char *fstype, const char *dataptr, int datalen)
+{
+       return -ENOSYS;
+}
+
+static int cp_hpux_stat(struct inode * inode, struct hpux_stat64 * statbuf)
+{
+       struct hpux_stat64 tmp;
+       unsigned int blocks, indirect;
+
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.st_dev = kdev_t_to_nr(inode->i_dev);
+       tmp.st_ino = inode->i_ino;
+       tmp.st_mode = inode->i_mode;
+       tmp.st_nlink = inode->i_nlink;
+       tmp.st_uid = inode->i_uid;
+       tmp.st_gid = inode->i_gid;
+       tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
+       tmp.st_size = inode->i_size;
+       tmp.st_atime = inode->i_atime;
+       tmp.st_mtime = inode->i_mtime;
+       tmp.st_ctime = inode->i_ctime;
+
+#define D_B   7
+#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
+
+       if (!inode->i_blksize) {
+               blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+               if (blocks > D_B) {
+                       indirect = (blocks - D_B + I_B - 1) / I_B;
+                       blocks += indirect;
+                       if (indirect > 1) {
+                               indirect = (indirect - 1 + I_B - 1) / I_B;
+                               blocks += indirect;
+                               if (indirect > 1)
+                                       blocks++;
+                       }
+               }
+               tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
+               tmp.st_blksize = BLOCK_SIZE;
+       } else {
+               tmp.st_blocks = inode->i_blocks;
+               tmp.st_blksize = inode->i_blksize;
+       }
+       return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
+
+/*
+ * Revalidate the inode. This is required for proper NFS attribute caching.
+ * Blatently copied wholesale from fs/stat.c
+ */
+static __inline__ int
+do_revalidate(struct dentry *dentry)
+{
+       struct inode * inode = dentry->d_inode;
+       if (inode->i_op && inode->i_op->revalidate)
+               return inode->i_op->revalidate(dentry);
+       return 0;
+}
+
+long hpux_stat64(const char *path, struct hpux_stat64 *buf)
+{
+       struct nameidata nd;
+       int error;
+
+       lock_kernel();
+       error = user_path_walk(path, &nd);
+       if (!error) {
+               error = do_revalidate(nd.dentry);
+               if (!error)
+                       error = cp_hpux_stat(nd.dentry->d_inode, buf);
+               path_release(&nd);
+       }
+       unlock_kernel();
+       return error;
+}
+
+long hpux_fstat64(unsigned int fd, struct hpux_stat64 *statbuf)
+{
+       struct file * f;
+       int err = -EBADF;
+
+       lock_kernel();
+       f = fget(fd);
+       if (f) {
+               struct dentry * dentry = f->f_dentry;
+
+               err = do_revalidate(dentry);
+               if (!err)
+                       err = cp_hpux_stat(dentry->d_inode, statbuf);
+               fput(f);
+       }
+       unlock_kernel();
+       return err;
+}
+
+long hpux_lstat64(char *filename, struct hpux_stat64 *statbuf)
+{
+       struct nameidata nd;
+       int error;
+
+       lock_kernel();
+       error = user_path_walk_link(filename, &nd);
+       if (!error) {
+               error = do_revalidate(nd.dentry);
+               if (!error)
+                       error = cp_hpux_stat(nd.dentry->d_inode, statbuf);
+               path_release(&nd);
+       }
+       unlock_kernel();
+       return error;
+}
diff --git a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S
new file mode 100644 (file)
index 0000000..5e0bf3c
--- /dev/null
@@ -0,0 +1,74 @@
+/* ------------------------------------------------------------------------------
+ *
+ * Linux/PARISC Project (http://www.thepuffingroup.com/parisc)
+ *
+ * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>
+ * Licensed under the GNU GPL.
+ * thanks to Philipp Rumpf, Mike Shaver and various others
+ * sorry about the wall, puffin..
+ */
+
+#define __ASSEMBLY__
+#include <asm/assembly.h>
+#include <asm/offset.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#define __ASSEMBLY__
+#include <asm/assembly.h>      /* for STREG/LDREG */
+
+       .text
+
+       .import hpux_call_table
+       .import hpux_syscall_exit,code
+       .export hpux_gateway_page
+
+       .align 4096
+hpux_gateway_page:
+       nop
+       mfsp    %sr7,%r1                        ;! we must set sr3 to the space
+       mtsp    %r1,%sr3                        ;! of the user before the gate
+#ifdef __LP64__
+#warning NEEDS WORK for 64-bit
+#endif
+       ldw     -64(%r30), %r28                 ;! 8th argument
+       ldw     -60(%r30), %r19                 ;! 7th argument
+       ldw     -56(%r30), %r20                 ;! 6th argument
+       ldw     -52(%r30), %r21                 ;! 5th argument
+       gate    .+8, %r0                        ;! become privileged
+       mtsp    %r0,%sr4                        ;! get kernel space into sr4
+       mtsp    %r0,%sr5                        ;! get kernel space into sr5
+       mtsp    %r0,%sr6                        ;! get kernel space into sr6
+       mtsp    %r0,%sr7                        ;! get kernel space into sr7
+       mfctl   %cr30,%r1                       ;! get the kernel task ptr
+       mtctl   %r0,%cr30                       ;! zero it (flag)
+       STREG   %r30,TASK_PT_GR30(%r1)          ;! preserve userspace sp
+       STREG   %r2,TASK_PT_GR2(%r1)            ;! preserve rp
+       STREG   %r27,TASK_PT_GR27(%r1)          ;! user dp
+       STREG   %r31,TASK_PT_GR31(%r1)          ;! preserve syscall return ptr
+
+       loadgp                                  ;! setup kernel dp
+
+       ldo     TASK_SZ_ALGN+64(%r1),%r30       ;! set up kernel stack
+
+       stw     %r21, -52(%r30)                 ;! 5th argument
+       stw     %r20, -56(%r30)                 ;! 6th argument
+       stw     %r19, -60(%r30)                 ;! 7th argument
+       stw     %r28, -64(%r30)                 ;! 8th argument
+
+       ldil    L%hpux_call_table, %r21
+       ldo     R%hpux_call_table(%r21), %r21
+       comiclr,>>=     __NR_HPUX_syscalls, %r22, %r0
+       b,n     syscall_nosys
+       ldwx,s  %r22(%r21), %r21
+       ldil    L%hpux_syscall_exit,%r2
+       be      0(%sr7,%r21)
+       ldo     R%hpux_syscall_exit(%r2),%r2
+
+syscall_nosys:
+       ldil    L%hpux_syscall_exit,%r1
+       be      R%hpux_syscall_exit(%sr7,%r1)
+       ldo     -ENOSYS(%r0),%r28
+
+       .align 4096
+       .export end_hpux_gateway_page
+end_hpux_gateway_page:
diff --git a/arch/parisc/hpux/ioctl.c b/arch/parisc/hpux/ioctl.c
new file mode 100644 (file)
index 0000000..9087123
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * linux/arch/parisc/hpux/ioctl.c
+ *
+ * implements some necessary HPUX ioctls.
+ */
+
+/*
+ * Supported ioctls:
+ *   TCGETA
+ *   TCSETA
+ *   TCSETAW
+ *   TCSETAF
+ *   TCSBRK
+ *   TCXONC
+ *   TCFLSH
+ *   TIOCGWINSZ
+ *   TIOCSWINSZ
+ *   TIOCGPGRP
+ *   TIOCSPGRP
+ */
+
+#include <linux/smp_lock.h>
+#include <asm/errno.h>
+#include <asm/ioctl.h>
+#include <asm/termios.h>
+#include <asm/uaccess.h>
+
+int sys_ioctl(unsigned int, unsigned int, unsigned long);
+static int hpux_ioctl_t(int fd, unsigned long cmd, unsigned long arg)
+{
+       int result = -EOPNOTSUPP;
+       int nr = _IOC_NR(cmd);
+       switch (nr) {
+       case 106:
+               result = sys_ioctl(fd, TIOCSWINSZ, arg);
+               break;
+       case 107:
+               result = sys_ioctl(fd, TIOCGWINSZ, arg);
+               break;
+       }
+       return result;
+}
+
+int hpux_ioctl(int fd, unsigned long cmd, unsigned long arg)
+{
+       int result = -EOPNOTSUPP;
+       int type = _IOC_TYPE(cmd);
+       switch (type) {
+       case 'T':
+               /* Our structures are now compatible with HPUX's */
+               result = sys_ioctl(fd, cmd, arg);
+               break;
+       case 't':
+               result = hpux_ioctl_t(fd, cmd, arg);
+               break;
+       default:
+               /* If my mother ever sees this, I hope she disowns me.
+                * Take this out after NYLWE. */
+               result = sys_ioctl(fd, cmd, arg);
+       }
+       return result;
+}
diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c
new file mode 100644 (file)
index 0000000..e0c832e
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * linux/arch/parisc/kernel/sys_hpux.c
+ *
+ * implements HPUX syscalls.
+ */
+
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/utsname.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+unsigned long sys_brk(unsigned long addr);
+unsigned long hpux_brk(unsigned long addr)
+{
+       /* Sigh.  Looks like HP/UX libc relies on kernel bugs. */
+       return sys_brk(addr + PAGE_SIZE);
+}
+
+int hpux_sbrk(void)
+{
+       return -ENOSYS;
+}
+
+/* Random other syscalls */
+
+int hpux_nice(int priority_change)
+{
+       return -ENOSYS;
+}
+
+int hpux_ptrace(void)
+{
+       return -ENOSYS;
+}
+
+int hpux_wait(int *stat_loc)
+{
+       extern int sys_waitpid(int, int *, int);
+       return sys_waitpid(-1, stat_loc, 0);
+}
+
+#define _SC_CPU_VERSION        10001
+#define _SC_OPEN_MAX   4
+#define CPU_PA_RISC1_1 0x210
+
+int hpux_sysconf(int which)
+{
+       switch (which) {
+       case _SC_CPU_VERSION:
+               return CPU_PA_RISC1_1;
+       case _SC_OPEN_MAX:
+               return INT_MAX;
+       default:
+               return -EINVAL;
+       }
+}
+
+/*****************************************************************************/
+
+#define HPUX_UTSLEN 9
+#define HPUX_SNLEN 15
+
+struct hpux_utsname {
+       char sysname[HPUX_UTSLEN];
+       char nodename[HPUX_UTSLEN];
+       char release[HPUX_UTSLEN];
+       char version[HPUX_UTSLEN];
+       char machine[HPUX_UTSLEN];
+       char idnumber[HPUX_SNLEN];
+} ;
+
+struct hpux_ustat {
+       int32_t         f_tfree;        /* total free (daddr_t)  */
+       u_int32_t       f_tinode;       /* total inodes free (ino_t)  */
+       char            f_fname[6];     /* filsys name */
+       char            f_fpack[6];     /* filsys pack name */
+       u_int32_t       f_blksize;      /* filsys block size (int) */
+};
+
+/*
+ * HPUX's utssys() call.  It's a collection of miscellaneous functions,
+ * alas, so there's no nice way of splitting them up.
+ */
+
+/*  This function is called from hpux_utssys(); HP-UX implements
+ *  ustat() as an option to utssys().
+ *
+ *  Now, struct ustat on HP-UX is exactly the same as on Linux, except
+ *  that it contains one addition field on the end, int32_t f_blksize.
+ *  So, we could have written this function to just call the Linux
+ *  sys_ustat(), (defined in linux/fs/super.c), and then just
+ *  added this additional field to the user's structure.  But I figure
+ *  if we're gonna be digging through filesystem structures to get
+ *  this, we might as well just do the whole enchilada all in one go.
+ *
+ *  So, most of this function is almost identical to sys_ustat().
+ *  I have placed comments at the few lines changed or added, to
+ *  aid in porting forward if and when sys_ustat() is changed from
+ *  its form in kernel 2.2.5.
+ */
+static int hpux_ustat(dev_t dev, struct hpux_ustat *ubuf)
+{
+       struct super_block *s;
+       struct hpux_ustat tmp;  /* Changed to hpux_ustat */
+       struct statfs sbuf;
+       int err = -EINVAL;
+
+       lock_kernel();
+       s = get_super(to_kdev_t(dev));
+       if (s == NULL)
+               goto out;
+       err = vfs_statfs(s, &sbuf);
+       if (err)
+               goto out;
+
+       memset(&tmp,0,sizeof(struct hpux_ustat));  /* Changed to hpux_ustat */
+
+       tmp.f_tfree = (int32_t)sbuf.f_bfree;
+       tmp.f_tinode = (u_int32_t)sbuf.f_ffree;
+       tmp.f_blksize = (u_int32_t)sbuf.f_bsize;  /*  Added this line  */
+
+       /* Changed to hpux_ustat:  */
+       err = copy_to_user(ubuf,&tmp,sizeof(struct hpux_ustat)) ? -EFAULT : 0;
+out:
+       unlock_kernel();
+       return err;
+}
+
+
+/*  This function is called from hpux_utssys(); HP-UX implements
+ *  uname() as an option to utssys().
+ *
+ *  The form of this function is pretty much copied from sys_olduname(),
+ *  defined in linux/arch/i386/kernel/sys_i386.c.
+ */
+/*  TODO: Are these put_user calls OK?  Should they pass an int?
+ *        (I copied it from sys_i386.c like this.)
+ */
+static int hpux_uname(struct hpux_utsname *name)
+{
+       int error;
+
+       if (!name)
+               return -EFAULT;
+       if (!access_ok(VERIFY_WRITE,name,sizeof(struct hpux_utsname)))
+               return -EFAULT;
+
+       down_read(&uts_sem);
+
+       error = __copy_to_user(&name->sysname,&system_utsname.sysname,HPUX_UTSLEN-1);
+       error |= __put_user(0,name->sysname+HPUX_UTSLEN-1);
+       error |= __copy_to_user(&name->nodename,&system_utsname.nodename,HPUX_UTSLEN-1);
+       error |= __put_user(0,name->nodename+HPUX_UTSLEN-1);
+       error |= __copy_to_user(&name->release,&system_utsname.release,HPUX_UTSLEN-1);
+       error |= __put_user(0,name->release+HPUX_UTSLEN-1);
+       error |= __copy_to_user(&name->version,&system_utsname.version,HPUX_UTSLEN-1);
+       error |= __put_user(0,name->version+HPUX_UTSLEN-1);
+       error |= __copy_to_user(&name->machine,&system_utsname.machine,HPUX_UTSLEN-1);
+       error |= __put_user(0,name->machine+HPUX_UTSLEN-1);
+
+       up_read(&uts_sem);
+
+       /*  HP-UX  utsname has no domainname field.  */
+
+       /*  TODO:  Implement idnumber!!!  */
+#if 0
+       error |= __put_user(0,name->idnumber);
+       error |= __put_user(0,name->idnumber+HPUX_SNLEN-1);
+#endif
+
+       error = error ? -EFAULT : 0;
+
+       return error;
+}
+
+int sys_sethostname(char *, int);
+int sys_gethostname(char *, int);
+
+/*  Note: HP-UX just uses the old suser() function to check perms
+ *  in this system call.  We'll use capable(CAP_SYS_ADMIN).
+ */
+int hpux_utssys(char *ubuf, int n, int type)
+{
+       int len;
+       int error;
+       switch( type ) {
+       case 0:
+               /*  uname():  */
+               return( hpux_uname( (struct hpux_utsname *)ubuf ) );
+               break ;
+       case 1:
+               /*  Obsolete (used to be umask().)  */
+               return -EFAULT ;
+               break ;
+       case 2:
+               /*  ustat():  */
+               return( hpux_ustat((dev_t)n, (struct hpux_ustat *)ubuf) );
+               break ;
+       case 3:
+               /*  setuname():
+                *
+                *  On linux (unlike HP-UX), utsname.nodename
+                *  is the same as the hostname.
+                *
+                *  sys_sethostname() is defined in linux/kernel/sys.c.
+                */
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               /*  Unlike Linux, HP-UX returns an error if n==0:  */
+               if ( n <= 0 )
+                       return -EINVAL ;
+               /*  Unlike Linux, HP-UX truncates it if n is too big:  */
+               len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
+               return( sys_sethostname(ubuf, len) );
+               break ;
+       case 4:
+               /*  sethostname():
+                *
+                *  sys_sethostname() is defined in linux/kernel/sys.c.
+                */
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               /*  Unlike Linux, HP-UX returns an error if n==0:  */
+               if ( n <= 0 )
+                       return -EINVAL ;
+               /*  Unlike Linux, HP-UX truncates it if n is too big:  */
+               len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
+               return( sys_sethostname(ubuf, len) );
+               break ;
+       case 5:
+               /*  gethostname():
+                *
+                *  sys_gethostname() is defined in linux/kernel/sys.c.
+                */
+               /*  Unlike Linux, HP-UX returns an error if n==0:  */
+               if ( n <= 0 )
+                       return -EINVAL ;
+               return( sys_gethostname(ubuf, n) );
+               break ;
+       case 6:
+               /*  Supposedly called from setuname() in libc.
+                *  TODO: When and why is this called?
+                *        Is it ever even called?
+                *
+                *  This code should look a lot like sys_sethostname(),
+                *  defined in linux/kernel/sys.c.  If that gets updated,
+                *  update this code similarly.
+                */
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               /*  Unlike Linux, HP-UX returns an error if n==0:  */
+               if ( n <= 0 )
+                       return -EINVAL ;
+               /*  Unlike Linux, HP-UX truncates it if n is too big:  */
+               len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
+               /**/
+               /*  TODO:  print a warning about using this?  */
+               down_write(&uts_sem);
+               error = -EFAULT;
+               if (!copy_from_user(system_utsname.sysname, ubuf, len)) {
+                       system_utsname.sysname[len] = 0;
+                       error = 0;
+               }
+               up_write(&uts_sem);
+               return error;
+               break ;
+       case 7:
+               /*  Sets utsname.release, if you're allowed.
+                *  Undocumented.  Used by swinstall to change the
+                *  OS version, during OS updates.  Yuck!!!
+                *
+                *  This code should look a lot like sys_sethostname()
+                *  in linux/kernel/sys.c.  If that gets updated, update
+                *  this code similarly.
+                */
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               /*  Unlike Linux, HP-UX returns an error if n==0:  */
+               if ( n <= 0 )
+                       return -EINVAL ;
+               /*  Unlike Linux, HP-UX truncates it if n is too big:  */
+               len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
+               /**/
+               /*  TODO:  print a warning about this?  */
+               down_write(&uts_sem);
+               error = -EFAULT;
+               if (!copy_from_user(system_utsname.release, ubuf, len)) {
+                       system_utsname.release[len] = 0;
+                       error = 0;
+               }
+               up_write(&uts_sem);
+               return error;
+               break ;
+       default:
+               /*  This system call returns -EFAULT if given an unknown type.
+                *  Why not -EINVAL?  I don't know, it's just not what they did.
+                */
+               return -EFAULT ;
+       }
+}
+
+int hpux_getdomainname(char *name, int len)
+{
+       int nlen;
+       int err = -EFAULT;
+       
+       down_read(&uts_sem);
+       
+       nlen = strlen(system_utsname.domainname) + 1;
+
+       if (nlen < len)
+               len = nlen;
+       if(len > __NEW_UTS_LEN)
+               goto done;
+       if(copy_to_user(name, system_utsname.domainname, len))
+               goto done;
+       err = 0;
+done:
+       up_read(&uts_sem);
+       return err;
+       
+}
+
+int hpux_pipe(int *kstack_fildes)
+{
+       int error;
+
+       lock_kernel();
+       error = do_pipe(kstack_fildes);
+       unlock_kernel();
+       return error;
+}
diff --git a/arch/parisc/hpux/wrappers.S b/arch/parisc/hpux/wrappers.S
new file mode 100644 (file)
index 0000000..c150783
--- /dev/null
@@ -0,0 +1,244 @@
+/*------------------------------------------------------------------------------
+ * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+ *
+ * HP-UX System Call Wrapper routines and System Call Return Path
+ *
+ * Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __LP64__
+#warning Must be changed for PA64
+#endif
+
+#include <asm/offset.h>
+
+       .level          1.1
+       .text
+
+#define __ASSEMBLY__
+#include <asm/assembly.h>
+#include <asm/signal.h>
+
+       /* These should probably go in a header file somewhere.
+        * They are duplicated in kernel/wrappers.S
+        * Possibly we should consider consolidating these
+        * register save/restore macros.
+        */
+       .macro  reg_save regs
+#ifdef __LP64__
+#warning NEEDS WORK for 64-bit
+#endif
+       stw     %r3, PT_GR3(\regs)
+       stw     %r4, PT_GR4(\regs)
+       stw     %r5, PT_GR5(\regs)
+       stw     %r6, PT_GR6(\regs)
+       stw     %r7, PT_GR7(\regs)
+       stw     %r8, PT_GR8(\regs)
+       stw     %r9, PT_GR9(\regs)
+       stw    %r10,PT_GR10(\regs)
+       stw    %r11,PT_GR11(\regs)
+       stw    %r12,PT_GR12(\regs)
+       stw    %r13,PT_GR13(\regs)
+       stw    %r14,PT_GR14(\regs)
+       stw    %r15,PT_GR15(\regs)
+       stw    %r16,PT_GR16(\regs)
+       stw    %r17,PT_GR17(\regs)
+       stw    %r18,PT_GR18(\regs)
+       .endm
+
+       .macro  reg_restore regs
+       ldw     PT_GR3(\regs), %r3
+       ldw     PT_GR4(\regs), %r4
+       ldw     PT_GR5(\regs), %r5
+       ldw     PT_GR6(\regs), %r6
+       ldw     PT_GR7(\regs), %r7
+       ldw     PT_GR8(\regs), %r8
+       ldw     PT_GR9(\regs), %r9
+       ldw    PT_GR10(\regs),%r10
+       ldw    PT_GR11(\regs),%r11
+       ldw    PT_GR12(\regs),%r12
+       ldw    PT_GR13(\regs),%r13
+       ldw    PT_GR14(\regs),%r14
+       ldw    PT_GR15(\regs),%r15
+       ldw    PT_GR16(\regs),%r16
+       ldw    PT_GR17(\regs),%r17
+       ldw    PT_GR18(\regs),%r18
+       .endm
+
+
+       .export hpux_fork_wrapper
+       .import sys_fork
+
+hpux_fork_wrapper:
+       ldo     TASK_REGS-TASK_SZ_ALGN-64(%r30),%r1         ;! get pt regs
+                                                           ;! pointer in task
+       reg_save %r1
+
+       stw     %r2,-20(%r30)
+       ldo     64(%r30),%r30
+       stw     %r2,PT_GR19(%r1)        ;! save for child
+       stw     %r30,PT_GR20(%r1)       ;! save for child
+       ldil    L%child_return,%r3
+       ldo     R%child_return(%r3),%r3
+       stw     %r3,PT_GR21(%r1)        ;! save for child
+
+       ldw     TASK_PT_GR30(%r1),%r25
+       copy    %r1,%r24
+       bl      sys_clone,%r2
+       ldi     SIGCHLD,%r26
+
+       ldw -84(%r30),%r2
+fork_return:
+       ldo     -64(%r30),%r30
+       ldo     TASK_REGS-TASK_SZ_ALGN-64(%r30),%r1         ;! get pt regs
+
+       reg_restore %r1
+
+       /*
+        * HP-UX wants pid (child gets parent pid, parent gets child pid)
+        * in r28 and a flag in r29 (r29 == 1 for child, 0 for parent).
+        * Linux fork returns 0 for child, pid for parent. Since HP-UX
+        * libc stub throws away parent pid and returns 0 for child,
+        * we'll just return 0 for parent pid now. Only applications
+        * that jump directly to the gateway page (not supported) will
+        * know the difference. We can fix this later if necessary.
+        */
+
+       ldo -1024(%r0),%r1
+       comb,>>=,n %r28,%r1,fork_exit  /* just let the syscall exit handle it */
+       or,= %r28,%r0,%r0
+       or,tr %r0,%r0,%r29      /* r28 <> 0, we are parent, set r29 to 0 */
+       ldo 1(%r0),%r29         /* r28 == 0, we are child,  set r29 to 1 */
+
+fork_exit:
+       bv %r0(%r2)
+       nop
+
+       /* Set the return value for the child */
+
+child_return:
+       ldw TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
+       b fork_return
+       copy %r0,%r28
+
+       .export hpux_execve_wrapper
+       .export hpux_execv_wrapper
+       .import hpux_execve
+
+hpux_execv_wrapper:
+       copy %r0,%r24  /* NULL environment */
+
+hpux_execve_wrapper:
+
+       ldo     TASK_REGS-TASK_SZ_ALGN-64(%r30),%r1         ;! get pt regs
+
+       /*
+        * Do we need to save/restore r3-r18 here?
+        * I don't think so. why would new thread need old
+        * threads registers?
+        */
+
+       /* Store arg0, arg1 and arg2 so that hpux_execve will find them */
+
+       stw %r26,PT_GR26(%r1)
+       stw %r25,PT_GR25(%r1)
+       stw %r24,PT_GR24(%r1)
+
+       stw %r2,-20(%r30)
+       ldo 64(%r30),%r30
+       bl hpux_execve,%r2
+       copy %r1,%arg0
+
+       ldo -64(%r30),%r30
+       ldw -20(%r30),%r2
+
+       /* If exec succeeded we need to load the args */
+
+       ldo -1024(%r0),%r1
+       comb,>>= %r28,%r1,exec_error
+       copy %r2,%r19
+       ldo     -TASK_SZ_ALGN-64(%r30),%r1         ;! get task ptr
+       ldw TASK_PT_GR26(%r1),%r26
+       ldw TASK_PT_GR25(%r1),%r25
+       ldw TASK_PT_GR24(%r1),%r24
+       ldw TASK_PT_GR23(%r1),%r23
+       copy %r0,%r2    /* Flag to syscall_exit not to clear args */
+
+exec_error:
+       bv %r0(%r19)
+       nop
+
+       .export hpux_pipe_wrapper
+       .import hpux_pipe
+
+       /* HP-UX expects pipefd's returned in r28 & r29 */
+
+hpux_pipe_wrapper:
+       stw %r2,-20(%r30)
+       ldo 64(%r30),%r30
+       bl hpux_pipe,%r2
+       ldo -56(%r30),%r26 /* pass local array to hpux_pipe */
+
+
+       ldo -1024(%r0),%r1
+       comb,>>= %r28,%r1,pipe_exit /* let syscall exit handle it */
+       ldw -84(%r30),%r2
+
+       /* if success, load fd's from stack array */
+
+       ldw -56(%r30),%r28
+       ldw -52(%r30),%r29
+
+pipe_exit:
+       bv %r0(%r2)
+       ldo -64(%r30),%r30
+
+       .export hpux_syscall_exit
+       .import syscall_exit
+
+hpux_syscall_exit:
+
+       /*
+        *
+        * HP-UX call return conventions:
+        *
+        * if error:
+        *       r22 = 1
+        *       r28 = errno value
+        *       r29 = secondary return value
+        * else
+        *       r22 = 0
+        *       r28 = return value
+        *       r29 = secondary return value
+        *
+        * For now, we'll just check to see if r28 is < (unsigned long)-1024
+        * (to handle addresses > 2 Gb) and if so set r22 to zero. If not,
+        * we'll complement r28 and set r22 to 1. Wrappers will be
+        * needed for syscalls that care about the secondary return value.
+        * The wrapper may also need a way of avoiding the following code,
+        * but we'll deal with that when it becomes necessary.
+        */
+
+       ldo -1024(%r0),%r1
+       comb,<< %r28,%r1,no_error
+       copy %r0,%r22
+       subi 0,%r28,%r28
+       ldo 1(%r0),%r22
+
+no_error:
+       b syscall_exit
+       nop
diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile
new file mode 100644 (file)
index 0000000..03ce8e5
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+all: kernel.o init_task.o pdc_cons.o process.o head.o
+O_TARGET = kernel.o
+O_OBJS = 
+
+# Object file lists.
+
+obj-y          :=
+obj-m          :=
+obj-n          :=
+obj-           :=
+
+obj-y          += cache.o setup.o traps.o time.o irq.o \
+               syscall.o entry.o sys_parisc.o pdc.o ptrace.o hardware.o \
+               inventory.o drivers.o semaphore.o pa7300lc.o pci-dma.o \
+               signal.o hpmc.o \
+               real1.o real2.o led.o parisc_ksyms.o
+
+export-objs    := parisc_ksyms.o
+
+
+obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_VT) += keyboard.o
+obj-$(CONFIG_PCI_LBA) += lba_pci.o
+# I/O SAPIC is also on IA64 platforms.
+# The two could be merged into a common source some day.
+obj-$(CONFIG_IOSAPIC) += iosapic.o
+obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o
+# Only use one of them: ccio-rm-dma is for PCX-W systems *only*
+# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o
+obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
+
+.o.S:  $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
+
+# Translate to Rules.make lists.
+
+O_OBJS          := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS         := $(filter     $(export-objs), $(obj-y))
+M_OBJS          := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS         := $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS                := $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS       := $(sort $(filter     $(export-objs), $(int-m)))
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
new file mode 100644 (file)
index 0000000..713a8b3
--- /dev/null
@@ -0,0 +1,253 @@
+/* $Id: cache.c,v 1.4 2000/01/25 00:11:38 prumpf Exp $
+ *
+ * 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) 1999 Helge Deller (07-13-1999)
+ * Copyright (C) 1999 SuSE GmbH Nuernberg
+ * Copyright (C) 2000 Philipp Rumpf (prumpf@tux.org)
+ *
+ * Cache and TLB management
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include <asm/pdc.h>
+#include <asm/cache.h>
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+
+struct pdc_cache_info cache_info;
+#ifndef __LP64__
+static struct pdc_btlb_info btlb_info;
+#endif
+
+
+void __flush_page_to_ram(unsigned long address)
+{
+       __flush_dcache_range(address, PAGE_SIZE);
+       __flush_icache_range(address, PAGE_SIZE);
+}
+
+
+
+void flush_data_cache(void)
+{
+       register unsigned long base   = cache_info.dc_base;
+       register unsigned long count  = cache_info.dc_count;
+       register unsigned long loop   = cache_info.dc_loop;
+       register unsigned long stride = cache_info.dc_stride;
+       register unsigned long addr;
+       register long i, j;
+
+       for(i=0,addr=base; i<count; i++,addr+=stride)
+               for(j=0; j<loop; j++)
+                       fdce(addr);
+}
+               
+static inline void flush_data_tlb_space(void)
+{
+       unsigned long base   = cache_info.dt_off_base;
+       unsigned long count  = cache_info.dt_off_count;
+       unsigned long stride = cache_info.dt_off_stride;
+       unsigned long loop   = cache_info.dt_loop;
+
+       unsigned long addr;
+       long i,j;
+       
+       for(i=0,addr=base; i<count; i++,addr+=stride)
+               for(j=0; j<loop; j++)
+                       pdtlbe(addr);
+}
+
+
+
+void flush_data_tlb(void)
+{
+       unsigned long base   = cache_info.dt_sp_base;
+       unsigned long count  = cache_info.dt_sp_count;
+       unsigned long stride = cache_info.dt_sp_stride;
+       unsigned long space;
+       unsigned long old_sr1;
+       long i;
+       
+       old_sr1 = mfsp(1);
+       
+       for(i=0,space=base; i<count; i++, space+=stride) {
+               mtsp(space,1);
+               flush_data_tlb_space();
+       }
+
+       mtsp(old_sr1, 1);
+}
+
+static inline void flush_instruction_tlb_space(void)
+{
+       unsigned long base   = cache_info.it_off_base;
+       unsigned long count  = cache_info.it_off_count;
+       unsigned long stride = cache_info.it_off_stride;
+       unsigned long loop   = cache_info.it_loop;
+
+       unsigned long addr;
+       long i,j;
+       
+       for(i=0,addr=base; i<count; i++,addr+=stride)
+               for(j=0; j<loop; j++)
+                       pitlbe(addr);
+}
+
+void flush_instruction_tlb(void)
+{
+       unsigned long base   = cache_info.it_sp_base;
+       unsigned long count  = cache_info.it_sp_count;
+       unsigned long stride = cache_info.it_sp_stride;
+       unsigned long space;
+       unsigned long old_sr1;
+       unsigned int i;
+       
+       old_sr1 = mfsp(1);
+       
+       for(i=0,space=base; i<count; i++, space+=stride) {
+               mtsp(space,1);
+               flush_instruction_tlb_space();
+       }
+
+       mtsp(old_sr1, 1);
+}
+
+
+void __flush_tlb_space(unsigned long space)
+{
+       unsigned long old_sr1;
+
+       old_sr1 = mfsp(1);
+       mtsp(space, 1);
+       
+       flush_data_tlb_space();
+       flush_instruction_tlb_space();
+
+       mtsp(old_sr1, 1);
+}
+
+
+void flush_instruction_cache(void)
+{
+       register unsigned long base   = cache_info.ic_base;
+       register unsigned long count  = cache_info.ic_count;
+       register unsigned long loop   = cache_info.ic_loop;
+       register unsigned long stride = cache_info.ic_stride;
+       register unsigned long addr;
+       register long i, j;
+       unsigned long old_sr1;
+       
+       old_sr1 = mfsp(1);
+       mtsp(0,1);
+
+       /*
+        * Note: fice instruction has 3 bit space field, so one must
+        *       be specified (otherwise you are justing using whatever
+        *       happens to be in sr0).
+        */
+
+       for(i=0,addr=base; i<count; i++,addr+=stride)
+               for(j=0; j<loop; j++)
+                       fice(addr);
+
+       mtsp(old_sr1, 1);
+}
+
+/* not yet ... fdc() needs to be implemented in cache.h !
+void flush_datacache_range( unsigned int base, unsigned int end )
+{
+    register long offset,offset_add;
+    offset_add = ( (1<<(cache_info.dc_conf.cc_block-1)) * 
+                   cache_info.dc_conf.cc_line ) << 4;
+    for (offset=base; offset<=end; offset+=offset_add)
+       fdc(space,offset);
+    fdc(space,end);
+}
+*/
+
+/* flushes code and data-cache */
+void flush_all_caches(void)
+{
+       flush_instruction_cache();
+       flush_data_cache();
+
+       flush_instruction_tlb();
+       flush_data_tlb();
+
+       asm volatile("sync");
+       asm volatile("syncdma");
+       asm volatile("sync");
+}
+
+int get_cache_info(char *buffer)
+{
+       char *p = buffer;
+
+       p += sprintf(p, "I-cache\t\t: %ld KB\n", 
+               cache_info.ic_size/1024 );
+       p += sprintf(p, "D-cache\t\t: %ld KB (%s)%s\n", 
+               cache_info.dc_size/1024,
+               (cache_info.dc_conf.cc_wt ? "WT":"WB"),
+               (cache_info.dc_conf.cc_sh ? " - shared I/D":"")
+       );
+
+       p += sprintf(p, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
+               cache_info.it_size,
+               cache_info.dt_size,
+               cache_info.dt_conf.tc_sh ? " - shared with ITLB":""
+       );
+               
+#ifndef __LP64__
+       /* BTLB - Block TLB */
+       if (btlb_info.max_size==0) {
+               p += sprintf(p, "BTLB\t\t: not supported\n" );
+       } else {
+               p += sprintf(p, 
+               "BTLB fixed\t: max. %d pages, pagesize=%d (%dMB)\n"
+               "BTLB fix-entr.\t: %d instruction, %d data (%d combined)\n"
+               "BTLB var-entr.\t: %d instruction, %d data (%d combined)\n",
+               btlb_info.max_size, (int)4096,
+               btlb_info.max_size>>8,
+               btlb_info.fixed_range_info.num_i,
+               btlb_info.fixed_range_info.num_d,
+               btlb_info.fixed_range_info.num_comb, 
+               btlb_info.variable_range_info.num_i,
+               btlb_info.variable_range_info.num_d,
+               btlb_info.variable_range_info.num_comb
+               );
+       }
+#endif
+
+       return p - buffer;
+}
+
+
+void __init 
+cache_init(void)
+{
+       if(pdc_cache_info(&cache_info)<0)
+               panic("cache_init: pdc_cache_info failed");
+
+#if 0
+       printk("ic_size %lx dc_size %lx it_size %lx pdc_cache_info %d*long pdc_cache_cf %d\n",
+           cache_info.ic_size,
+           cache_info.dc_size,
+           cache_info.it_size,
+           sizeof (struct pdc_cache_info) / sizeof (long),
+           sizeof (struct pdc_cache_cf)
+       );
+#endif
+#ifndef __LP64__
+       if(pdc_btlb_info(&btlb_info)<0) {
+               memset(&btlb_info, 0, sizeof btlb_info);
+       }
+#endif
+}
diff --git a/arch/parisc/kernel/ccio-dma.c b/arch/parisc/kernel/ccio-dma.c
new file mode 100644 (file)
index 0000000..2dcd325
--- /dev/null
@@ -0,0 +1,1208 @@
+/*
+** ccio-dma.c:
+**     DMA management routines for first generation cache-coherent machines.
+**     Program U2/Uturn in "Virtual Mode" and use the I/O MMU.
+**
+**     (c) Copyright 2000 Grant Grundler
+**     (c) Copyright 2000 Ryan Bradetich
+**     (c) Copyright 2000 Hewlett-Packard Company
+**
+** 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.
+**
+**
+**  "Real Mode" operation refers to U2/Uturn chip operation.
+**  U2/Uturn were designed to perform coherency checks w/o using
+**  the I/O MMU - basically what x86 does.
+**
+**  Philipp Rumpf has a "Real Mode" driver for PCX-W machines at:
+**      CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc
+**      cvs -z3 co linux/arch/parisc/kernel/dma-rm.c
+**
+**  I've rewritten his code to work under TPG's tree. See ccio-rm-dma.c.
+**
+**  Drawbacks of using Real Mode are:
+**     o outbound DMA is slower - U2 won't prefetch data (GSC+ XQL signal).
+**      o Inbound DMA less efficient - U2 can't use DMA_FAST attribute.
+**     o Ability to do scatter/gather in HW is lost.
+**     o Doesn't work under PCX-U/U+ machines since they didn't follow
+**        the coherency design originally worked out. Only PCX-W does.
+*/
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+
+#include <asm/byteorder.h>
+#include <asm/cache.h>         /* for L1_CACHE_BYTES */
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/page.h>
+
+#include <asm/io.h>
+#include <asm/gsc.h>           /* for gsc_writeN()... */
+
+/* 
+** Choose "ccio" since that's what HP-UX calls it.
+** Make it easier for folks to migrate from one to the other :^)
+*/
+#define MODULE_NAME "ccio"
+
+/*
+#define DEBUG_CCIO_RES
+#define DEBUG_CCIO_RUN
+#define DEBUG_CCIO_INIT
+#define DUMP_RESMAP
+*/
+
+#include <linux/proc_fs.h>
+#include <asm/runway.h>                /* for proc_runway_root */
+
+#ifdef DEBUG_CCIO_INIT
+#define DBG_INIT(x...)  printk(x)
+#else
+#define DBG_INIT(x...)
+#endif
+
+#ifdef DEBUG_CCIO_RUN
+#define DBG_RUN(x...)   printk(x)
+#else
+#define DBG_RUN(x...)
+#endif
+
+#ifdef DEBUG_CCIO_RES
+#define DBG_RES(x...)   printk(x)
+#else
+#define DBG_RES(x...)
+#endif
+
+#define CCIO_INLINE    /* inline */
+#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
+
+#define U2_IOA_RUNWAY 0x580
+#define U2_BC_GSC     0x501
+#define UTURN_IOA_RUNWAY 0x581
+#define UTURN_BC_GSC     0x502
+/* We *can't* support JAVA (T600). Venture there at your own risk. */
+
+static void dump_resmap(void);
+
+static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *);
+
+static struct pa_iodc_driver ccio_drivers_for[] = {
+
+   {HPHW_IOA, U2_IOA_RUNWAY, 0x0, 0xb, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback},
+
+   {HPHW_IOA, UTURN_IOA_RUNWAY, 0x0, 0xb, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback},
+
+/*
+** FIXME: The following claims the GSC bus port, not the IOA.
+**        And there are two busses below a single I/O TLB.
+**
+** These should go away once we have a real PA bus walk.
+** Firmware wants to tell the PA bus walk code about the GSC ports
+** since they are not "architected" PA I/O devices. Ie a PA bus walk
+** wouldn't discover them. But the PA bus walk code could check
+** the "fixed module table" to add such devices to an I/O Tree
+** and proceed with the recursive, depth first bus walk.
+*/
+   {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xc, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "U2 GSC+ BC", (void *) ccio_driver_callback},
+
+   {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xc, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "Uturn GSC+ BC", (void *) ccio_driver_callback},
+
+   {0,0,0,0,0,0,
+   0,
+   (char *) NULL, (char *) NULL, (void *) NULL }
+};
+
+
+#define IS_U2(id) ( \
+    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \
+    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC))  \
+)
+
+#define IS_UTURN(id) ( \
+    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \
+    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC))  \
+)
+
+
+#define IOA_NORMAL_MODE      0x00020080 /* IO_CONTROL to turn on CCIO        */
+#define CMD_TLB_DIRECT_WRITE 35         /* IO_COMMAND for I/O TLB Writes     */
+#define CMD_TLB_PURGE        33         /* IO_COMMAND to Purge I/O TLB entry */
+
+struct ioa_registers {
+        /* Runway Supervisory Set */
+        volatile int32_t    unused1[12];
+        volatile uint32_t   io_command;             /* Offset 12 */
+        volatile uint32_t   io_status;              /* Offset 13 */
+        volatile uint32_t   io_control;             /* Offset 14 */
+        volatile int32_t    unused2[1];
+
+        /* Runway Auxiliary Register Set */
+        volatile uint32_t   io_err_resp;            /* Offset  0 */
+        volatile uint32_t   io_err_info;            /* Offset  1 */
+        volatile uint32_t   io_err_req;             /* Offset  2 */
+        volatile uint32_t   io_err_resp_hi;         /* Offset  3 */
+        volatile uint32_t   io_tlb_entry_m;         /* Offset  4 */
+        volatile uint32_t   io_tlb_entry_l;         /* Offset  5 */
+        volatile uint32_t   unused3[1];
+        volatile uint32_t   io_pdir_base;           /* Offset  7 */
+        volatile uint32_t   io_io_low_hv;           /* Offset  8 */
+        volatile uint32_t   io_io_high_hv;          /* Offset  9 */
+        volatile uint32_t   unused4[1];
+        volatile uint32_t   io_chain_id_mask;       /* Offset 11 */
+        volatile uint32_t   unused5[2];
+        volatile uint32_t   io_io_low;              /* Offset 14 */
+        volatile uint32_t   io_io_high;             /* Offset 15 */
+};
+
+
+struct ccio_device {
+       struct ccio_device    *next;  /* list of LBA's in system */
+       struct hp_device      *iodc;  /* data about dev from firmware */
+       spinlock_t            ccio_lock;
+
+       struct ioa_registers   *ccio_hpa; /* base address */
+       u64   *pdir_base;   /* physical base address */
+       char  *res_map;     /* resource map, bit == pdir entry */
+
+       int   res_hint; /* next available IOVP - circular search */
+       int   res_size; /* size of resource map in bytes */
+       int   chainid_shift; /* specify bit location of chain_id */
+       int   flags;         /* state/functionality enabled */
+#ifdef DELAYED_RESOURCE_CNT
+       dma_addr_t res_delay[DELAYED_RESOURCE_CNT];
+#endif
+
+       /* STUFF We don't need in performance path */
+       int  pdir_size;     /* in bytes, determined by IOV Space size */
+       int  hw_rev;        /* HW revision of chip */
+};
+
+
+/* Ratio of Host MEM to IOV Space size */
+static unsigned long ccio_mem_ratio = 4;
+static struct ccio_device *ccio_list = NULL;
+
+static int ccio_proc_info(char *buffer, char **start, off_t offset, int length);
+static unsigned long ccio_used_bytes = 0;
+static unsigned long ccio_used_pages = 0;
+static int ccio_cujo_bug = 0;
+
+static unsigned long ccio_alloc_size = 0;
+static unsigned long ccio_free_size = 0;
+
+/**************************************************************
+*
+*   I/O Pdir Resource Management
+*
+*   Bits set in the resource map are in use.
+*   Each bit can represent a number of pages.
+*   LSbs represent lower addresses (IOVA's).
+*
+*   This was was copied from sba_iommu.c. Don't try to unify
+*   the two resource managers unless a way to have different
+*   allocation policies is also adjusted. We'd like to avoid
+*   I/O TLB thrashing by having resource allocation policy
+*   match the I/O TLB replacement policy.
+*
+***************************************************************/
+#define PAGES_PER_RANGE 1      /* could increase this to 4 or 8 if needed */
+#define IOVP_SIZE PAGE_SIZE
+#define IOVP_SHIFT PAGE_SHIFT
+#define IOVP_MASK PAGE_MASK
+
+/* Convert from IOVP to IOVA and vice versa. */
+#define CCIO_IOVA(iovp,offset) ((iovp) | (offset))
+#define CCIO_IOVP(iova) ((iova) & ~(IOVP_SIZE-1) )
+
+#define PDIR_INDEX(iovp)    ((iovp)>>IOVP_SHIFT)
+#define MKIOVP(pdir_idx)    ((long)(pdir_idx) << IOVP_SHIFT)
+#define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset)
+
+/* CUJO20 KLUDGE start */
+#define CUJO_20_BITMASK    0x0ffff000  /* upper nibble is a don't care   */
+#define CUJO_20_STEP       0x10000000  /* inc upper nibble */
+#define CUJO_20_BADPAGE1   0x01003000  /* pages that hpmc on raven U+    */
+#define CUJO_20_BADPAGE2   0x01607000  /* pages that hpmc on firehawk U+ */
+#define CUJO_20_BADHVERS   0x6821      /* low nibble 1 is cujo rev 2.0 */
+#define CUJO_RAVEN_LOC     0xf1000000UL        /* cujo location on raven U+ */
+#define CUJO_FIREHAWK_LOC  0xf1604000UL        /* cujo location on firehawk U+ */
+/* CUJO20 KLUDGE end */
+
+/*
+** Don't worry about the 150% average search length on a miss.
+** If the search wraps around, and passes the res_hint, it will
+** cause the kernel to panic anyhow.
+*/
+
+/* ioa->res_hint = idx + (size >> 3); \ */
+
+#define CCIO_SEARCH_LOOP(ioa, idx, mask, size)  \
+       for(; res_ptr < res_end; ++res_ptr) \
+       { \
+               if(0 == ((*res_ptr) & mask)) { \
+                       *res_ptr |= mask; \
+                       idx = (int)((unsigned long)res_ptr - (unsigned long)ioa->res_map); \
+                       ioa->res_hint = 0;\
+                       goto resource_found; \
+               } \
+       }
+
+#define CCIO_FIND_FREE_MAPPING(ioa, idx, mask, size)  { \
+       u##size *res_ptr = (u##size *)&((ioa)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \
+       u##size *res_end = (u##size *)&(ioa)->res_map[ioa->res_size]; \
+       CCIO_SEARCH_LOOP(ioa, idx, mask, size); \
+       res_ptr = (u##size *)&(ioa)->res_map[0]; \
+       CCIO_SEARCH_LOOP(ioa, idx, mask, size); \
+}
+
+/*
+** Find available bit in this ioa's resource map.
+** Use a "circular" search:
+**   o Most IOVA's are "temporary" - avg search time should be small.
+** o keep a history of what happened for debugging
+** o KISS.
+**
+** Perf optimizations:
+** o search for log2(size) bits at a time.
+** o search for available resource bits using byte/word/whatever.
+** o use different search for "large" (eg > 4 pages) or "very large"
+**   (eg > 16 pages) mappings.
+*/
+static int
+ccio_alloc_range(struct ccio_device *ioa, size_t size)
+{
+       int res_idx;
+       unsigned long mask, flags;
+       unsigned int pages_needed = size >> PAGE_SHIFT;
+
+       ASSERT(pages_needed);
+       ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE);
+       ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT));
+
+       mask = (unsigned long) -1L;
+       mask >>= BITS_PER_LONG - pages_needed;
+
+       DBG_RES(__FUNCTION__ " size: %d pages_needed %d pages_mask 0x%08lx\n", 
+               size, pages_needed, mask);
+
+       spin_lock_irqsave(&ioa->ccio_lock, flags);
+
+       /*
+       ** "seek and ye shall find"...praying never hurts either...
+       ** ggg sacrafices another 710 to the computer gods.
+       */
+
+       if(pages_needed <= 8) {
+               CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 8);
+       } else if(pages_needed <= 16) {
+               CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 16);
+       } else if(pages_needed <= 32) {
+               CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 32);
+#ifdef __LP64__
+       } else if(pages_needed <= 64) {
+               CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 64)
+#endif
+       } else {
+               panic(__FILE__ ":" __FUNCTION__ "() Too many pages to map.\n");
+       }
+
+#ifdef DUMP_RESMAP
+       dump_resmap();
+#endif
+       panic(__FILE__ ":" __FUNCTION__ "() I/O MMU is out of mapping resources\n");
+       
+resource_found:
+       
+       DBG_RES(__FUNCTION__ " res_idx %d mask 0x%08lx res_hint: %d\n",
+               res_idx, mask, ioa->res_hint);
+
+       ccio_used_pages += pages_needed;
+       ccio_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1);
+
+       spin_unlock_irqrestore(&ioa->ccio_lock, flags);
+
+#ifdef DUMP_RESMAP
+       dump_resmap();
+#endif
+
+       /* 
+       ** return the bit address (convert from byte to bit).
+       */
+       return (res_idx << 3);
+}
+
+
+#define CCIO_FREE_MAPPINGS(ioa, idx, mask, size) \
+        u##size *res_ptr = (u##size *)&((ioa)->res_map[idx + (((size >> 3) - 1) & ~((size >> 3) - 1))]); \
+        ASSERT((*res_ptr & mask) == mask); \
+        *res_ptr &= ~mask;
+
+/*
+** clear bits in the ioa's resource map
+*/
+static void
+ccio_free_range(struct ccio_device *ioa, dma_addr_t iova, size_t size)
+{
+       unsigned long mask, flags;
+       unsigned long iovp = CCIO_IOVP(iova);
+       unsigned int res_idx = PDIR_INDEX(iovp)>>3;
+       unsigned int pages_mapped = (size >> IOVP_SHIFT) + !!(size & ~IOVP_MASK);
+
+       ASSERT(pages_needed);
+       ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE);
+       ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT));
+
+       mask = (unsigned long) -1L;
+       mask >>= BITS_PER_LONG - pages_mapped;
+
+       DBG_RES(__FUNCTION__ " res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", 
+               res_idx, size, pages_mapped, mask);
+
+       spin_lock_irqsave(&ioa->ccio_lock, flags);
+
+       if(pages_mapped <= 8) {
+               CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 8);
+       } else if(pages_mapped <= 16) {
+               CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 16);
+       } else if(pages_mapped <= 32) {
+               CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 32);
+#ifdef __LP64__
+       } else if(pages_mapped <= 64) {
+               CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 64);
+#endif
+       } else {
+               panic(__FILE__ ":" __FUNCTION__ "() Too many pages to unmap.\n");
+       }
+       
+       ccio_used_pages -= (pages_mapped ? pages_mapped : 1);
+       ccio_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1);
+
+       spin_unlock_irqrestore(&ioa->ccio_lock, flags);
+
+#ifdef DUMP_RESMAP
+       dump_resmap();
+#endif
+}
+
+
+/****************************************************************
+**
+**          CCIO dma_ops support routines
+**
+*****************************************************************/
+
+typedef unsigned long space_t;
+#define KERNEL_SPACE 0
+
+
+/*
+** DMA "Page Type" and Hints 
+** o if SAFE_DMA isn't set, mapping is for FAST_DMA. SAFE_DMA should be
+**   set for subcacheline DMA transfers since we don't want to damage the
+**   other part of a cacheline.
+** o SAFE_DMA must be set for "memory" allocated via pci_alloc_consistent().
+**   This bit tells U2 to do R/M/W for partial cachelines. "Streaming"
+**   data can avoid this if the mapping covers full cache lines.
+** o STOP_MOST is needed for atomicity across cachelines.
+**   Apperently only "some EISA devices" need this.
+**   Using CONFIG_ISA is hack. Only the IOA with EISA under it needs
+**   to use this hint iff the EISA devices needs this feature.
+**   According to the U2 ERS, STOP_MOST enabled pages hurt performance.
+** o PREFETCH should *not* be set for cases like Multiple PCI devices
+**   behind GSCtoPCI (dino) bus converter. Only one cacheline per GSC
+**   device can be fetched and multiply DMA streams will thrash the
+**   prefetch buffer and burn memory bandwidth. See 6.7.3 "Prefetch Rules
+**   and Invalidation of Prefetch Entries".
+**
+** FIXME: the default hints need to be per GSC device - not global.
+** 
+** HP-UX dorks: linux device driver programming model is totally different
+**    than HP-UX's. HP-UX always sets HINT_PREFETCH since it's drivers
+**    do special things to work on non-coherent platforms...linux has to
+**    be much more careful with this.
+*/
+#define IOPDIR_VALID    0x01UL
+#define HINT_SAFE_DMA   0x02UL /* used for pci_alloc_consistent() pages */
+#ifdef CONFIG_ISA      /* EISA support really */
+#define HINT_STOP_MOST  0x04UL /* LSL support */
+#else
+#define HINT_STOP_MOST  0x00UL /* only needed for "some EISA devices" */
+#endif
+#define HINT_UDPATE_ENB 0x08UL  /* not used/supported by U2 */
+#define HINT_PREFETCH   0x10UL /* for outbound pages which are not SAFE */
+
+
+/*
+** Use direction (ie PCI_DMA_TODEVICE) to pick hint.
+** ccio_alloc_consistent() depends on this to get SAFE_DMA
+** when it passes in BIDIRECTIONAL flag.
+*/
+static u32 hint_lookup[] = {
+       [PCI_DMA_BIDIRECTIONAL]  HINT_STOP_MOST | HINT_SAFE_DMA | IOPDIR_VALID,
+       [PCI_DMA_TODEVICE]       HINT_STOP_MOST | HINT_PREFETCH | IOPDIR_VALID,
+       [PCI_DMA_FROMDEVICE]     HINT_STOP_MOST | IOPDIR_VALID,
+       [PCI_DMA_NONE]           0,            /* not valid */
+};
+
+/*
+** Initialize an I/O Pdir entry
+**
+** Given a virtual address (vba, arg2) and space id, (sid, arg1),
+** load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir
+** entry consists of 8 bytes as shown below (MSB == bit 0):
+**
+**
+** WORD 0:
+** +------+----------------+-----------------------------------------------+
+** | Phys | Virtual Index  |               Phys                            |
+** | 0:3  |     0:11       |               4:19                            |
+** |4 bits|   12 bits      |              16 bits                          |
+** +------+----------------+-----------------------------------------------+
+** WORD 1:
+** +-----------------------+-----------------------------------------------+
+** |      Phys    |  Rsvd  | Prefetch |Update |Rsvd  |Lock  |Safe  |Valid  |
+** |     20:39    |        | Enable   |Enable |      |Enable|DMA   |       |
+** |    20 bits   | 5 bits | 1 bit    |1 bit  |2 bits|1 bit |1 bit |1 bit  |
+** +-----------------------+-----------------------------------------------+
+**
+** The virtual index field is filled with the results of the LCI
+** (Load Coherence Index) instruction.  The 8 bits used for the virtual
+** index are bits 12:19 of the value returned by LCI.
+*/
+
+void CCIO_INLINE
+ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, void * vba, unsigned long hints)
+{
+       register unsigned long pa = (volatile unsigned long) vba;
+       register unsigned long ci; /* coherent index */
+
+       /* We currently only support kernel addresses */
+       ASSERT(sid == 0);
+       ASSERT(((unsigned long) vba & 0xf0000000UL) == 0xc0000000UL);
+
+       mtsp(sid,1);
+
+       /*
+       ** WORD 1 - low order word
+       ** "hints" parm includes the VALID bit!
+       ** "dep" clobbers the physical address offset bits as well.
+       */
+       pa = virt_to_phys(vba);
+       asm volatile("depw  %1,31,12,%0" : "+r" (pa) : "r" (hints));
+       ((u32 *)pdir_ptr)[1] = (u32) pa;
+
+       /*
+       ** WORD 0 - high order word
+       */
+
+#ifdef __LP64__
+       /*
+       ** get bits 12:15 of physical address
+       ** shift bits 16:31 of physical address
+       ** and deposit them
+       */
+       asm volatile ("extrd,u %1,15,4,%0" : "=r" (ci) : "r" (pa));
+       asm volatile ("extrd,u %1,31,16,%0" : "+r" (ci) : "r" (ci));
+       asm volatile ("depd  %1,35,4,%0" : "+r" (pa) : "r" (ci));
+#else
+       pa = 0;
+#endif
+       /*
+       ** get CPU coherency index bits
+       ** Grab virtual index [0:11]
+       ** Deposit virt_idx bits into I/O PDIR word
+       */
+       asm volatile ("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
+       asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci));
+       asm volatile ("depw  %1,15,12,%0" : "+r" (pa) : "r" (ci));
+
+       ((u32 *)pdir_ptr)[0] = (u32) pa;
+
+
+       /* FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
+       **        PCX-U/U+ do. (eg C200/C240)
+       **        PCX-T'? Don't know. (eg C110 or similar K-class)
+       **
+       ** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit".
+       ** Hopefully we can patch (NOP) these out at boot time somehow.
+       **
+       ** "Since PCX-U employs an offset hash that is incompatible with
+       ** the real mode coherence index generation of U2, the PDIR entry
+       ** must be flushed to memory to retain coherence."
+       */
+       asm volatile("fdc 0(%0)" : : "r" (pdir_ptr));
+       asm volatile("sync");
+}
+
+
+/*
+** Remove stale entries from the I/O TLB.
+** Need to do this whenever an entry in the PDIR is marked invalid.
+*/
+static CCIO_INLINE void
+ccio_clear_io_tlb( struct ccio_device *d, dma_addr_t iovp, size_t byte_cnt)
+{
+       u32 chain_size = 1 << d->chainid_shift;
+
+       iovp &= ~(IOVP_SIZE-1); /* clear offset bits, just want pagenum */
+       byte_cnt += chain_size;
+
+        while (byte_cnt > chain_size) {
+               WRITE_U32(CMD_TLB_PURGE | iovp, &d->ccio_hpa->io_command);
+                iovp += chain_size;
+               byte_cnt -= chain_size;
+        }
+}
+
+
+/***********************************************************
+ *
+ * Mark the I/O Pdir entries invalid and blow away the
+ * corresponding I/O TLB entries.
+ *
+ * FIXME: at some threshhold it might be "cheaper" to just blow
+ *        away the entire I/O TLB instead of individual entries.
+ *
+ * FIXME: Uturn has 256 TLB entries. We don't need to purge every
+ *        PDIR entry - just once for each possible TLB entry.
+ *        (We do need to maker I/O PDIR entries invalid regardless).
+ ***********************************************************/
+static CCIO_INLINE void
+ccio_mark_invalid(struct ccio_device *d, dma_addr_t iova, size_t byte_cnt)
+{
+       u32 iovp = (u32) CCIO_IOVP(iova);
+       size_t saved_byte_cnt;
+
+       /* round up to nearest page size */
+       saved_byte_cnt = byte_cnt = (byte_cnt + IOVP_SIZE - 1) & IOVP_MASK;
+
+       while (byte_cnt > 0) {
+               /* invalidate one page at a time */
+               unsigned int idx = PDIR_INDEX(iovp);
+               char *pdir_ptr = (char *) &(d->pdir_base[idx]);
+
+               ASSERT( idx < (d->pdir_size/sizeof(u64)));
+
+               pdir_ptr[7] = 0;        /* clear only VALID bit */
+
+               /*
+               ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
+               **   PCX-U/U+ do. (eg C200/C240)
+               ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit".
+               **
+               ** Hopefully someone figures out how to patch (NOP) the
+               ** FDC/SYNC out at boot time.
+               */
+               asm volatile("fdc 0(%0)" : : "r" (pdir_ptr[7]));
+
+               iovp     += IOVP_SIZE;
+               byte_cnt -= IOVP_SIZE;
+       }
+
+       asm volatile("sync");
+       ccio_clear_io_tlb(d, CCIO_IOVP(iova), saved_byte_cnt);
+}
+
+
+/****************************************************************
+**
+**          CCIO dma_ops
+**
+*****************************************************************/
+
+void __init ccio_init(void)
+{
+       register_driver(ccio_drivers_for);
+}
+
+
+static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask)
+{
+       if (dev == NULL) {
+               printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
+               BUG();
+               return(0);
+       }
+
+       dev->dma_mask = mask;   /* save it */
+
+       /* only support 32-bit devices (ie PCI/GSC) */
+       return((int) (mask >= 0xffffffffUL));
+}
+
+/*
+** Dump a hex representation of the resource map.
+*/
+
+#ifdef DUMP_RESMAP
+static 
+void dump_resmap()
+{
+       struct ccio_device *ioa = ccio_list;
+       unsigned long *res_ptr = (unsigned long *)ioa->res_map;
+       unsigned long i = 0;
+
+       printk("res_map: ");
+       for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr)
+               printk("%08lx ", *res_ptr);
+
+       printk("\n");
+}
+#endif
+
+/*
+** map_single returns a fully formed IOVA
+*/
+static dma_addr_t ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
+{
+       struct ccio_device *ioa = ccio_list;  /* FIXME : see Multi-IOC below */
+       dma_addr_t iovp;
+       dma_addr_t offset;
+       u64 *pdir_start;
+       unsigned long hint = hint_lookup[direction];
+       int idx;
+
+       ASSERT(size > 0);
+
+       /* save offset bits */
+       offset = ((dma_addr_t) addr) & ~IOVP_MASK;
+
+       /* round up to nearest IOVP_SIZE */
+       size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK;
+
+       idx = ccio_alloc_range(ioa, size);
+       iovp = (dma_addr_t) MKIOVP(idx);
+
+       DBG_RUN(__FUNCTION__ " 0x%p -> 0x%lx", addr, (long) iovp | offset);
+
+       pdir_start = &(ioa->pdir_base[idx]);
+
+       /* If not cacheline aligned, force SAFE_DMA on the whole mess */
+       if ((size % L1_CACHE_BYTES) || ((unsigned long) addr % L1_CACHE_BYTES))
+               hint |= HINT_SAFE_DMA;
+
+       /* round up to nearest IOVP_SIZE */
+       size = (size + IOVP_SIZE - 1) & IOVP_MASK;
+
+       while (size > 0) {
+
+               ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint);
+
+               DBG_RUN(" pdir %p %08x%08x\n",
+                       pdir_start,
+                       (u32) (((u32 *) pdir_start)[0]),
+                       (u32) (((u32 *) pdir_start)[1])
+                       );
+               addr += IOVP_SIZE;
+               size -= IOVP_SIZE;
+               pdir_start++;
+       }
+       /* form complete address */
+       return CCIO_IOVA(iovp, offset);
+}
+
+
+static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction)
+{
+#ifdef FIXME
+/* Multi-IOC (ie N-class) :  need to lookup IOC from dev
+** o If we can't know about lba PCI data structs, that eliminates ->sysdata.
+** o walking up pcidev->parent dead ends at elroy too
+** o leaves hashing dev->bus->number into some lookup.
+**   (may only work for N-class)
+*/
+       struct ccio_device *ioa = dev->sysdata
+#else
+       struct ccio_device *ioa = ccio_list;
+#endif
+       dma_addr_t offset;
+       
+       offset = iova & ~IOVP_MASK;
+
+       /* round up to nearest IOVP_SIZE */
+       size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK;
+
+       /* Mask off offset */
+       iova &= IOVP_MASK;
+
+       DBG_RUN(__FUNCTION__ " iovp 0x%lx\n", (long) iova);
+
+#ifdef DELAYED_RESOURCE_CNT
+       if (ioa->saved_cnt < DELAYED_RESOURCE_CNT) {
+               ioa->saved_iova[ioa->saved_cnt] = iova;
+               ioa->saved_size[ioa->saved_cnt] = size;
+               ccio_saved_cnt++;
+       } else {
+               do {
+#endif
+                       ccio_mark_invalid(ioa, iova, size);
+                       ccio_free_range(ioa, iova, size);
+
+#ifdef DELAYED_RESOURCE_CNT
+                       d->saved_cnt--;
+                       iova = ioa->saved_iova[ioa->saved_cnt];
+                       size = ioa->saved_size[ioa->saved_cnt];
+               } while (ioa->saved_cnt)
+       }
+#endif
+}
+
+
+static void * ccio_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+{
+       void *ret;
+       unsigned long flags;
+       struct ccio_device *ioa = ccio_list;
+
+       DBG_RUN(__FUNCTION__ " size 0x%x\n",  size);
+
+#if 0
+/* GRANT Need to establish hierarchy for non-PCI devs as well
+** and then provide matching gsc_map_xxx() functions for them as well.
+*/
+       if (!hwdev) {
+               /* only support PCI */
+               *dma_handle = 0;
+               return 0;
+       }
+#endif
+       spin_lock_irqsave(&ioa->ccio_lock, flags);
+       ccio_alloc_size += get_order(size);
+       spin_unlock_irqrestore(&ioa->ccio_lock, flags);
+
+        ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size));
+
+       if (ret) {
+               memset(ret, 0, size);
+               *dma_handle = ccio_map_single(hwdev, ret, size, PCI_DMA_BIDIRECTIONAL);
+       }
+       DBG_RUN(__FUNCTION__ " ret %p\n",  ret);
+
+       return ret;
+}
+
+
+static void ccio_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
+{
+       unsigned long flags;
+       struct ccio_device *ioa = ccio_list;
+
+       spin_lock_irqsave(&ioa->ccio_lock, flags);
+       ccio_free_size += get_order(size);
+       spin_unlock_irqrestore(&ioa->ccio_lock, flags);
+
+       ccio_unmap_single(hwdev, dma_handle, size, 0);
+       free_pages((unsigned long) vaddr, get_order(size));
+}
+
+
+static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+{
+       int tmp = nents;
+
+       DBG_RUN(KERN_WARNING __FUNCTION__ " START\n");
+
+        /* KISS: map each buffer seperately. */
+       while (nents) {
+               sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction);
+               sg_dma_len(sglist) = sglist->length;
+               nents--;
+               sglist++;
+       }
+
+       DBG_RUN(KERN_WARNING __FUNCTION__ " DONE\n");
+       return tmp;
+}
+
+
+static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+{
+       DBG_RUN(KERN_WARNING __FUNCTION__ " : unmapping %d entries\n", nents);
+       while (nents) {
+               ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
+               nents--;
+               sglist++;
+       }
+       return;
+}
+
+
+static struct pci_dma_ops ccio_ops = {
+       ccio_dma_supported,
+       ccio_alloc_consistent,
+       ccio_free_consistent,
+       ccio_map_single,
+       ccio_unmap_single,
+       ccio_map_sg,
+       ccio_unmap_sg,
+       NULL,                   /* dma_sync_single : NOP for U2/Uturn */
+       NULL,                   /* dma_sync_sg     : ditto */
+};
+
+#if 0
+/* GRANT -  is this needed for U2 or not? */
+
+/*
+** Get the size of the I/O TLB for this I/O MMU.
+**
+** If spa_shift is non-zero (ie probably U2),
+** then calculate the I/O TLB size using spa_shift.
+**
+** Otherwise we are supposed to get the IODC entry point ENTRY TLB
+** and execute it. However, both U2 and Uturn firmware supplies spa_shift.
+** I think only Java (K/D/R-class too?) systems don't do this.
+*/
+static int
+ccio_get_iotlb_size(struct hp_device *d)
+{
+       if(d->spa_shift == 0) {
+               panic(__FUNCTION__ ": Can't determine I/O TLB size.\n");
+       }
+       return(1 << d->spa_shift);
+}
+#else
+
+/* Uturn supports 256 TLB entries */
+#define CCIO_CHAINID_SHIFT     8
+#define CCIO_CHAINID_MASK      0xff
+
+#endif /* 0 */
+
+
+/*
+** Figure out how big the I/O PDIR should be and alloc it.
+** Also sets variables which depend on pdir size.
+*/
+static void
+ccio_alloc_pdir(struct ccio_device *ioa)
+{
+       extern unsigned long mem_max;          /* arch.../setup.c */
+
+       u32 iova_space_size = 0;
+       void * pdir_base;
+       int pdir_size, iov_order;
+
+       /*
+       ** Determine IOVA Space size from memory size.
+       ** Using "mem_max" is a kluge.
+       **
+       ** Ideally, PCI drivers would register the maximum number
+       ** of DMA they can have outstanding for each device they
+       ** own.  Next best thing would be to guess how much DMA
+       ** can be outstanding based on PCI Class/sub-class. Both
+       ** methods still require some "extra" to support PCI
+       ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD).
+       */
+       /* limit IOVA space size to 1MB-1GB */
+       if (mem_max < (ccio_mem_ratio*1024*1024)) {
+               iova_space_size = 1024*1024;
+#ifdef __LP64__
+       } else if (mem_max > (ccio_mem_ratio*512*1024*1024)) {
+               iova_space_size = 512*1024*1024;
+#endif
+       } else {
+               iova_space_size = (u32) (mem_max/ccio_mem_ratio);
+       }
+
+       /*
+       ** iova space must be log2() in size.
+       ** thus, pdir/res_map will also be log2().
+       */
+
+       /* We could use larger page sizes in order to *decrease* the number
+       ** of mappings needed.  (ie 8k pages means 1/2 the mappings).
+        **
+       ** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either
+       **   since the pages must also be physically contiguous - typically
+       **   this is the case under linux."
+       */
+
+       iov_order = get_order(iova_space_size);
+       ASSERT(iov_order <= (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
+       ASSERT(iov_order >= (20 - IOVP_SHIFT));   /* iova_space_size >= 1MB */
+       iova_space_size = 1 << (iov_order + IOVP_SHIFT);
+
+       ioa->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
+
+       ASSERT(pdir_size < 4*1024*1024);   /* max pdir size < 4MB */
+
+       /* Verify it's a power of two */
+       ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT));
+
+       DBG_INIT(__FUNCTION__ " hpa 0x%p mem %dMB IOV %dMB (%d bits)\n    PDIR size 0x%0x",
+               ioa->ccio_hpa, (int) (mem_max>>20), iova_space_size>>20,
+               iov_order + PAGE_SHIFT, pdir_size);
+
+       ioa->pdir_base =
+       pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
+       if (NULL == pdir_base)
+       {
+               panic(__FILE__ ":" __FUNCTION__ "() could not allocate I/O Page Table\n");
+       }
+       memset(pdir_base, 0, pdir_size);
+
+       ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
+
+       DBG_INIT(" base %p", pdir_base);
+
+       /*
+       ** Chainid is the upper most bits of an IOVP used to determine
+       ** which TLB entry an IOVP will use.
+       */
+       ioa->chainid_shift = get_order(iova_space_size)+PAGE_SHIFT-CCIO_CHAINID_SHIFT;
+
+       DBG_INIT(" chainid_shift 0x%x\n", ioa->chainid_shift);
+}
+
+
+static void
+ccio_hw_init(struct ccio_device *ioa)
+{
+       int i;
+
+       /*
+       ** Initialize IOA hardware
+       */
+       WRITE_U32(CCIO_CHAINID_MASK << ioa->chainid_shift, &ioa->ccio_hpa->io_chain_id_mask);
+       WRITE_U32(virt_to_phys(ioa->pdir_base), &ioa->ccio_hpa->io_pdir_base);
+
+
+       /*
+       ** Go to "Virtual Mode"
+       */
+       WRITE_U32(IOA_NORMAL_MODE, &ioa->ccio_hpa->io_control);
+
+       /*
+       ** Initialize all I/O TLB entries to 0 (Valid bit off).
+       */
+       WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_m);
+       WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_l);
+
+       for (i = 1 << CCIO_CHAINID_SHIFT; i ; i--) {
+               WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioa->chainid_shift)),
+                                       &ioa->ccio_hpa->io_command);
+       }
+
+}
+
+
+static void
+ccio_resmap_init(struct ccio_device *ioa)
+{
+       u32 res_size;
+
+       /*
+       ** Ok...we do more than just init resource map
+       */
+       ioa->ccio_lock = SPIN_LOCK_UNLOCKED;
+
+       ioa->res_hint = 16;    /* next available IOVP - circular search */
+
+       /* resource map size dictated by pdir_size */
+       res_size = ioa->pdir_size/sizeof(u64); /* entries */
+       res_size >>= 3; /* convert bit count to byte count */
+       DBG_INIT(__FUNCTION__ "() res_size 0x%x\n", res_size);
+
+       ioa->res_size = res_size;
+       ioa->res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
+       if (NULL == ioa->res_map)
+       {
+               panic(__FILE__ ":" __FUNCTION__ "() could not allocate resource map\n");
+       }
+       memset(ioa->res_map, 0, res_size);
+}
+
+/* CUJO20 KLUDGE start */
+static struct {
+               u16 hversion;
+               u8  spa;
+               u8  type;
+               u32     foo[3]; /* 16 bytes total */
+} cujo_iodc __attribute__ ((aligned (64)));
+static unsigned long cujo_result[32] __attribute__ ((aligned (16))) = {0,0,0,0};
+
+/*
+** CUJO 2.0 incorrectly decodes a memory access for specific
+** pages (every page at specific iotlb locations dependent
+** upon where the cujo is flexed - diff on raven/firehawk.
+** resulting in an hpmc and/or silent data corruption.
+** Workaround is to prevent use of those I/O TLB entries
+** by marking the suspect bitmap range entries as busy.
+*/
+static void
+ccio_cujo20_hack(struct ccio_device *ioa)
+{
+       unsigned long status;
+       unsigned int idx;
+       u8 *res_ptr = ioa->res_map;
+       u32 iovp=0x0;
+       unsigned long mask;
+
+       status = pdc_iodc_read( &cujo_result, (void *) CUJO_RAVEN_LOC, 0, &cujo_iodc, 16);
+       if (status == 0) {
+               if (cujo_iodc.hversion==CUJO_20_BADHVERS)
+                       iovp = CUJO_20_BADPAGE1;
+       } else {
+               status = pdc_iodc_read( &cujo_result, (void *) CUJO_FIREHAWK_LOC, 0, &cujo_iodc, 16);
+               if (status == 0) {
+                       if (cujo_iodc.hversion==CUJO_20_BADHVERS)
+                               iovp = CUJO_20_BADPAGE2;
+               } else {
+                       /* not a defective system */
+                       return;
+               }
+       }
+
+       printk(MODULE_NAME ": Cujo 2.0 bug needs a work around\n");
+       ccio_cujo_bug = 1;
+
+       /*
+       ** mark bit entries that match "bad page"
+       */
+       idx = PDIR_INDEX(iovp)>>3;
+       mask = 0xff;
+       
+       while(idx * sizeof(u8) < ioa->res_size) {
+               res_ptr[idx] |= mask;
+               idx += (PDIR_INDEX(CUJO_20_STEP)>>3);
+               ccio_used_pages += 8;
+               ccio_used_bytes += 1;
+       }
+}
+/* CUJO20 KLUDGE end */
+
+#ifdef CONFIG_PROC_FS
+static int ccio_proc_info(char *buf, char **start, off_t offset, int len)
+{
+       unsigned long i = 0;
+       struct ccio_device *ioa = ccio_list;
+       unsigned long *res_ptr = (unsigned long *)ioa->res_map;
+       unsigned long total_pages = ioa->res_size << 3;            /* 8 bits per byte */
+
+       sprintf(buf, "%s\nCujo 2.0 bug    : %s\n",
+               parisc_getHWdescription(ioa->iodc->hw_type, ioa->iodc->hversion,
+                                       ioa->iodc->sversion),
+               (ccio_cujo_bug ? "yes" : "no"));
+
+       sprintf(buf, "%sIO pdir size    : %d bytes (%d entries)\n",
+               buf, ((ioa->res_size << 3) * sizeof(u64)), /* 8 bits per byte */
+               ioa->res_size << 3);                       /* 8 bits per byte */
+       
+       sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", 
+               buf, ioa->res_size, ioa->res_size << 3);   /* 8 bits per byte */
+
+       strcat(buf,  "            total:    free:    used:   % used:\n");
+       sprintf(buf, "%sblocks  %8d %8ld %8ld %8ld%%\n", buf, ioa->res_size,
+               ioa->res_size - ccio_used_bytes, ccio_used_bytes,
+               (ccio_used_bytes * 100) / ioa->res_size);
+
+       sprintf(buf, "%spages   %8ld %8ld %8ld %8ld%%\n", buf, total_pages,
+               total_pages - ccio_used_pages, ccio_used_pages,
+               (ccio_used_pages * 100 / total_pages));
+
+       sprintf(buf, "%sconsistent       %8ld %8ld\n", buf,
+               ccio_alloc_size, ccio_free_size);
+       strcat(buf, "\nResource bitmap:\n");
+
+       for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr)
+               len += sprintf(buf, "%s%08lx ", buf, *res_ptr);
+
+       strcat(buf, "\n");
+       return strlen(buf);
+}
+#endif
+
+/*
+** Determine if ccio should claim this chip (return 0) or not (return 1).
+** If so, initialize the chip and tell other partners in crime they
+** have work to do.
+*/
+static int
+ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+{
+       struct ccio_device *ioa;
+
+       printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa);
+
+       if (ccio_list) {
+               printk(MODULE_NAME ": already initialized one device\n");
+               return(0);
+       }
+
+       ioa = kmalloc(sizeof(struct ccio_device), GFP_KERNEL);
+       if (NULL == ioa)
+       {
+               printk(MODULE_NAME " - couldn't alloc ccio_device\n");
+               return(1);
+       }
+       memset(ioa, 0, sizeof(struct ccio_device));
+
+       /*
+       ** ccio list is used mainly as a kluge to support a single instance. 
+       ** Eventually, with core dumps, it'll be useful for debugging.
+       */
+       ccio_list = ioa;
+       ioa->iodc = d;
+
+#if 1
+/* KLUGE: determine IOA hpa based on GSC port value.
+** Needed until we have a PA bus walk. Can only discover IOA via
+** walking the architected PA MMIO space as described by the I/O ACD.
+** "Legacy" PA Firmware only tells us about unarchitected devices
+** that can't be detected by PA/EISA/PCI bus walks.
+*/
+       switch((long) d->hpa) {
+       case 0xf3fbf000L:       /* C110 IOA0 LBC (aka GSC port) */
+               /* ccio_hpa same as C200 IOA0 */
+       case 0xf203f000L:       /* C180/C200/240/C360 IOA0 LBC (aka GSC port) */
+               ioa->ccio_hpa = (struct ioa_registers *) 0xfff88000L;
+               break;
+       case 0xf103f000L:       /* C180/C200/240/C360 IOA1 LBC (aka GSC port) */
+               ioa->ccio_hpa = (struct ioa_registers *) 0xfff8A000L;
+               break;
+       default:
+               panic("ccio-dma.c doesn't know this GSC port Address!\n");
+               break;
+       };
+#else
+       ioa->ccio_hpa = d->hpa;
+#endif
+
+       ccio_alloc_pdir(ioa);
+       ccio_hw_init(ioa);
+       ccio_resmap_init(ioa);
+
+       /* CUJO20 KLUDGE start */
+       ccio_cujo20_hack(ioa);
+       /* CUJO20 KLUDGE end */
+
+       hppa_dma_ops = &ccio_ops;
+
+       create_proc_info_entry(MODULE_NAME, 0, proc_runway_root, ccio_proc_info);
+       return(0);
+}
+
+
+
diff --git a/arch/parisc/kernel/ccio-rm-dma.c b/arch/parisc/kernel/ccio-rm-dma.c
new file mode 100644 (file)
index 0000000..25ec90c
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * ccio-rm-dma.c:
+ *     DMA management routines for first generation cache-coherent machines.
+ *     "Real Mode" operation refers to U2/Uturn chip operation. The chip
+ *      can perform coherency checks w/o using the I/O MMU. That's all we
+ *      need until support for more than 4GB phys mem is needed.
+ * 
+ *     This is the trivial case - basically what x86 does.
+ *
+ *     Drawbacks of using Real Mode are:
+ *     o outbound DMA is slower since one isn't using the prefetching
+ *       U2 can do for outbound DMA.
+ *     o Ability to do scatter/gather in HW is also lost.
+ *      o only known to work with PCX-W processor. (eg C360)
+ *        (PCX-U/U+ are not coherent with U2 in real mode.)
+ *
+ *
+ * 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.
+ *
+ *
+ * Original version/author:
+ *      CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc
+ *      cvs -z3 co linux/arch/parisc/kernel/dma-rm.c
+ *
+ *     (C) Copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ *
+ * Adopted for The Puffin Group's parisc-linux port by Grant Grundler.
+ *     (C) Copyright 2000 Grant Grundler <grundler@puffin.external.hp.com>
+ *     
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/page.h>
+
+/* Only chose "ccio" since that's what HP-UX calls it....
+** Make it easier for folks to migrate from one to the other :^)
+*/
+#define MODULE_NAME "ccio"
+
+#define U2_IOA_RUNWAY 0x580
+#define U2_BC_GSC     0x501
+#define UTURN_IOA_RUNWAY 0x581
+#define UTURN_BC_GSC     0x502
+
+static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *);
+
+static struct pa_iodc_driver ccio_drivers_for[] = {
+
+   {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xb, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback},
+
+   {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xb, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback},
+
+   {0,0,0,0,0,0,
+   0,
+   (char *) NULL, (char *) NULL, (void *) NULL }
+};
+
+
+#define IS_U2(id) ( \
+    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \
+    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC))  \
+)
+
+#define IS_UTURN(id) ( \
+    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \
+    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC))  \
+)
+
+
+void __init ccio_init(void)
+{
+       register_driver(ccio_drivers_for);
+}
+
+
+static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask)  
+{
+       if (dev == NULL) {
+               printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
+               BUG();
+               return(0);
+       }
+
+       dev->dma_mask = mask;   /* save it */
+
+       /* only support 32-bit devices (ie PCI/GSC) */
+       return((int) (mask >= 0xffffffffUL));
+}
+
+
+static void *ccio_alloc_consistent(struct pci_dev *dev, size_t size,
+                                dma_addr_t *handle)
+{
+       void *ret;
+       
+       ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
+
+       if (ret != NULL) {
+               memset(ret, 0, size);
+               *handle = virt_to_phys(ret);
+       }
+       return ret;
+}
+       
+static void ccio_free_consistent(struct pci_dev *dev, size_t size,
+                              void *vaddr, dma_addr_t handle)
+{
+       free_pages((unsigned long)vaddr, get_order(size));
+}
+
+static dma_addr_t ccio_map_single(struct pci_dev *dev, void *ptr, size_t size,
+                         int direction)
+{
+       return virt_to_phys(ptr);
+}
+
+static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t dma_addr,
+                           size_t size, int direction)
+{
+       /* Nothing to do */
+}
+
+
+static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+{
+       int tmp = nents;
+
+        /* KISS: map each buffer seperately. */
+       while (nents) {
+               sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction);
+               sg_dma_len(sglist) = sglist->length;
+               nents--;
+               sglist++;
+       }
+
+       return tmp;
+}
+
+
+static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+{
+#if 0
+       while (nents) {
+               ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
+               nents--;
+               sglist++;
+       }
+       return;
+#else
+       /* Do nothing (copied from current ccio_unmap_single()  :^) */
+#endif
+}
+
+
+static struct pci_dma_ops ccio_ops = {
+       ccio_dma_supported,
+       ccio_alloc_consistent,
+       ccio_free_consistent,
+       ccio_map_single,
+       ccio_unmap_single,
+       ccio_map_sg,
+       ccio_unmap_sg,
+       NULL,                   /* dma_sync_single : NOP for U2 */
+       NULL,                   /* dma_sync_sg     : ditto */
+
+
+};
+
+
+/*
+** Determine if u2 should claim this chip (return 0) or not (return 1).
+** If so, initialize the chip and tell other partners in crime they
+** have work to do.
+*/
+static int
+ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+{
+       printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa);
+
+/*
+** FIXME - should check U2 registers to verify it's really running
+** in "Real Mode".
+*/
+
+#if 0
+/* will need this for "Virtual Mode" operation */
+       ccio_hw_init(ccio_dev);
+       ccio_common_init(ccio_dev);
+#endif
+       hppa_dma_ops = &ccio_ops;
+       return 0;
+}
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
new file mode 100644 (file)
index 0000000..c2d9f82
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+
+drivers.c
+
+Copyright (c) 1999 The Puffin Group 
+
+This is a collection of routines intended to register all the devices
+in a system, and register device drivers.
+
+*/
+
+#include <linux/slab.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/pdc.h>
+
+
+extern struct hp_hardware *parisc_get_reference(
+       unsigned short hw_type, unsigned long hversion, 
+       unsigned long sversion );
+
+
+/* I'm assuming there'll never be 64 devices.  We should probably make 
+   this more flexible.  */
+
+#define MAX_DEVICES 64
+
+unsigned int num_devices = 0;
+
+struct hp_device devices[MAX_DEVICES];
+
+static unsigned long pdc_result[32] __attribute__ ((aligned (16))) = {0,0,0,0};
+static  u8 iodc_data[32] __attribute__ ((aligned (64)));
+
+/*
+ *     XXX should we be using a locked array ?
+ */
+int register_driver(struct pa_iodc_driver *driver)
+{
+       unsigned int i;
+       struct hp_device * device;
+
+       for (;driver->check;driver++)  {
+
+               for (i=0;i<num_devices;i++) {
+                       device = &devices[i];
+
+                       if (device->managed) continue;
+
+                       if ((driver->check & DRIVER_CHECK_HWTYPE) &&
+                           (driver->hw_type != device->hw_type))
+                               continue;
+                       if ((driver->check & DRIVER_CHECK_HVERSION) &&
+                           (driver->hversion != device->hversion))
+                               continue;
+                       if ((driver->check & DRIVER_CHECK_HVERSION_REV) &&
+                           (driver->hversion_rev != device->hversion_rev))
+                               continue;
+                       if ((driver->check & DRIVER_CHECK_SVERSION) &&
+                           (driver->sversion != device->sversion))
+                               continue;
+                       if ((driver->check & DRIVER_CHECK_SVERSION_REV) &&
+                           (driver->sversion_rev != device->sversion_rev))
+                               continue;
+                       if ((driver->check & DRIVER_CHECK_OPT) &&
+                           (driver->opt != device->opt))
+                               continue;
+                       if ( (*driver->callback)(device,driver) ==0) {
+                               device->managed=1;
+                       } else {
+                               printk("Warning : device (%d, 0x%x, 0x%x, 0x%x, 0x%x) NOT claimed by %s %s\n",
+                                       device->hw_type,
+                                       device->hversion, device->hversion_rev,
+                                       device->sversion, device->sversion_rev,
+                                       driver->name, driver->version);
+                       }
+               }
+       }
+       return 0;
+}
+
+
+struct hp_device * register_module(void *hpa)
+{
+
+       struct hp_device * d;
+       int status;
+
+       d = &devices[num_devices];
+       status = pdc_iodc_read(&pdc_result,hpa,0,&iodc_data,32 );
+       if (status !=PDC_RET_OK) {
+               /* There is no device here, so we'll skip it */
+               return 0;
+       }
+
+       d->hw_type = iodc_data[3]&0x1f;
+       d->hversion = (iodc_data[0]<<4)|((iodc_data[1]&0xf0)>>4);
+       d->sversion = 
+               ((iodc_data[4]&0x0f)<<16)|(iodc_data[5]<<8)|(iodc_data[6]);
+       d->hversion_rev = iodc_data[1]&0x0f;
+       d->sversion_rev = iodc_data[4]>>4;
+       d->opt = iodc_data[7];
+       d->hpa = hpa;
+       d->managed=0;
+       d->reference = parisc_get_reference(d->hw_type, d->hversion, 
+                                                               d->sversion);
+               
+       num_devices++;  
+
+       return d;
+}      
+
+void print_devices(char * buf) {
+
+       int i;
+       struct hp_device *d;
+       printk("Found devices:\n");
+       for (i=0;i<num_devices;i++) {   
+               d = &devices[i];
+               printk(KERN_INFO 
+               "%d. %s (%d) at 0x%p, versions 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 
+               i+1,
+               (d->reference) ? d->reference->name : "Unknown device",
+               d->hw_type,d->hpa, d->hversion, d->hversion_rev,
+               d->sversion, d->sversion_rev, d->opt);
+
+       }
+       printk("That's a total of %d devices.\n",num_devices);
+}
+
+
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
new file mode 100644 (file)
index 0000000..437df82
--- /dev/null
@@ -0,0 +1,1866 @@
+/*------------------------------------------------------------------------------
+ * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+ *
+ * kernel entry points (interruptions, system call wrappers)
+ *  Copyright (C) 1999,2000 Philipp Rumpf 
+ *  Copyright (C) 1999 SuSE GmbH Nuernberg 
+ *  Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ *  Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/offset.h>
+
+/* the following is the setup i think we should follow:
+ * whenever the CPU is interruptible, the following has to be true:
+ *  CR30 is the kernel sp or 0 if we currently use the kernel stack
+ *  CR31 is the kernel gp */ 
+
+/* we have the following possibilities to act on an interruption:
+ *  - handle in assembly and use shadowed registers only
+ *  - save registers to kernel stack and handle in assembly or C */
+
+       .text
+
+#ifdef __LP64__
+       .level 2.0w
+#endif
+
+#define __ASSEMBLY__
+#include <asm/assembly.h>      /* for LDREG/STREG defines */
+#include <asm/pgtable.h>
+#include <asm/psw.h>
+#include <asm/signal.h>
+
+#ifdef __LP64__
+#define FRAME_SIZE     64
+#else
+#define FRAME_SIZE     64
+#endif
+
+       /* Switch to virtual mapping, trashing only %r1 */
+       .macro  virt_map rfi_type
+       mtsm    %r0
+       tovirt  %r29
+       tovirt  %r30
+       mfsp    %sr7, %r1
+       mtsp    %r1, %sr3
+       mtsp    %r0, %sr4
+       mtsp    %r0, %sr5
+       mtsp    %r0, %sr6
+       mtsp    %r0, %sr7
+       ldil    L%KERNEL_PSW, %r1
+       ldo     R%KERNEL_PSW(%r1), %r1
+       LDIL_FIXUP(%r1)
+       mtctl   %r1, %cr22
+       mtctl   %r0, %cr17
+       mtctl   %r0, %cr17
+       ldil    L%.+28, %r1
+       ldo     R%.+24(%r1), %r1
+       LDIL_FIXUP(%r1)
+       mtctl   %r1, %cr18
+       ldo     4(%r1), %r1
+       mtctl   %r1, %cr18
+       \rfi_type
+       nop
+       .endm
+
+       .macro  get_stack
+       mfctl   %cr30, %r1 
+       comib,=,n 0, %r1, 0f   /* forward so predicted not taken */
+
+       /* we save the registers in the task struct */
+       ldo     TASK_REGS(%r1), %r29
+       tophys  %r29
+       STREG   %r30, PT_GR30(%r29)
+       STREG   %r1,  PT_CR30(%r29)
+       ldo     TASK_SZ_ALGN(%r1), %r30
+       b       1f                  /* unconditional so predicted taken */      
+       mtctl   %r0,%cr30
+0:
+       /* we put a struct pt_regs on the stack and save the registers there */
+       copy    %r30,%r29
+       ldo     PT_SZ_ALGN(%r30),%r30
+       tophys  %r29
+       STREG   %r30,PT_GR30(%r29)
+       STREG   %r0,PT_CR30(%r29)
+1:
+       .endm
+
+       .macro  rest_stack regs
+       LDREG   PT_CR30(\regs), %r1
+       comib,=,n 0, %r1, 2f/* forward so predicted not taken */
+
+       /* we restore the registers out of the task struct */
+       mtctl   %r1, %cr30
+       LDREG   PT_GR1(\regs), %r1
+       LDREG   PT_GR30(\regs),%r30
+       b       3f
+       LDREG   PT_GR29(\regs),%r29
+2:
+       /* we take a struct pt_regs off the stack */
+       LDREG   PT_GR1(\regs),  %r1
+       LDREG   PT_GR29(\regs), %r29
+       ldo     -PT_SZ_ALGN(%r30), %r30
+3:
+       .endm
+
+#ifdef OLD
+       /* fixme interruption handler */
+       .macro  def code
+       /* WARNING!!! THIS IS DEBUG CODE ONLY!!! */
+       b       unimplemented_64bitirq
+       ldi     \code, %r1
+       .align  32
+       .endm
+
+       /* Use def to enable break - KWDB wants em
+        * (calls traps.c:handle_interruption) */
+       .macro  pass_break code
+
+#else
+       /* default interruption handler
+        * (calls traps.c:handle_interruption) */
+       .macro  def code
+#endif
+       mtctl   %r29, %cr31
+       mtctl   %r1,  %cr28
+       ldi     \code, %r1
+       b       intr_save
+       mtctl   %r1, %cr29
+       .align  32
+       .endm
+
+       /* Interrupt interruption handler
+        * (calls irq.c:do_irq_mask) */
+       .macro  extint code
+       mtctl   %r29, %cr31
+       mtctl   %r1,  %cr28
+       mfctl   %cr23, %r1
+       mtctl   %r1, %cr23
+       b       intr_extint
+       mtctl   %r1, %cr29
+       .align  32
+       .endm   
+
+       .import os_hpmc, code
+
+       /* HPMC handler */
+       .macro  hpmc code
+       nop                     /* must be a NOP, will be patched later */
+       ldil    L%PA(os_hpmc), %r3
+       ldo     R%PA(os_hpmc)(%r3), %r3
+       bv,n    0(%r3)
+       nop
+       .word   0               /* checksum (will be patched) */
+       .word   PA(os_hpmc)     /* address of handler */
+       .word   0               /* length of handler */
+       .endm
+
+       /*
+        * Performance Note: Instructions will be moved up into
+        * this part of the code later on, once we are sure
+        * that the tlb miss handlers are close to final form.
+        */
+
+       /* Register definitions for tlb miss handler macros */
+
+       va  = r8        /* virtual address for which the trap occured */
+       spc = r24       /* space for which the trap occured */
+
+#ifndef __LP64__
+
+       /*
+        * itlb miss interruption handler (parisc 1.1 - 32 bit)
+        */
+
+       .macro  itlb_11 code
+
+       mfctl   %pcsq, spc
+       b       itlb_miss_11
+       mfctl   %pcoq, va
+
+       .align          32
+       .endm
+#endif
+       
+       /*
+        * itlb miss interruption handler (parisc 2.0)
+        */
+
+       .macro  itlb_20 code
+
+       mfctl   %pcsq, spc
+#ifdef __LP64__
+       b       itlb_miss_20w
+#else
+       b       itlb_miss_20
+#endif
+       mfctl   %pcoq, va
+
+       .align          32
+       .endm
+       
+#ifndef __LP64__
+       /*
+        * naitlb miss interruption handler (parisc 1.1 - 32 bit)
+        *
+        * Note: naitlb misses will be treated
+        * as an ordinary itlb miss for now.
+        * However, note that naitlb misses
+        * have the faulting address in the
+        * IOR/ISR.
+        */
+
+       .macro  naitlb_11 code
+
+       mfctl   %isr,spc
+       b       itlb_miss_11
+       mfctl   %ior,va
+       /* FIXME: If user causes a naitlb miss, the priv level may not be in
+        * lower bits of va, where the itlb miss handler is expecting them
+        */
+
+       .align          32
+       .endm
+#endif
+       
+       /*
+        * naitlb miss interruption handler (parisc 2.0)
+        *
+        * Note: naitlb misses will be treated
+        * as an ordinary itlb miss for now.
+        * However, note that naitlb misses
+        * have the faulting address in the
+        * IOR/ISR.
+        */
+
+       .macro  naitlb_20 code
+
+       mfctl   %isr,spc
+#ifdef __LP64__
+       b       itlb_miss_20w
+#else
+       b       itlb_miss_20
+#endif
+       mfctl   %ior,va
+       /* FIXME: If user causes a naitlb miss, the priv level may not be in
+        * lower bits of va, where the itlb miss handler is expecting them
+        */
+
+       .align          32
+       .endm
+       
+#ifndef __LP64__
+       /*
+        * dtlb miss interruption handler (parisc 1.1 - 32 bit)
+        */
+
+       .macro  dtlb_11 code
+
+       mfctl   %isr, spc
+       b       dtlb_miss_11
+       mfctl   %ior, va
+
+       .align          32
+       .endm
+#endif
+
+       /*
+        * dtlb miss interruption handler (parisc 2.0)
+        */
+
+       .macro  dtlb_20 code
+
+       mfctl   %isr, spc
+#ifdef __LP64__
+       b       dtlb_miss_20w
+#else
+       b       dtlb_miss_20
+#endif
+       mfctl   %ior, va
+
+       .align          32
+       .endm
+       
+#ifndef __LP64__
+       /* nadtlb miss interruption handler (parisc 1.1 - 32 bit)
+        *
+        * Note: nadtlb misses will be treated
+        * as an ordinary dtlb miss for now.
+        *
+        */
+
+       .macro  nadtlb_11 code
+
+       mfctl   %isr,spc
+       b       dtlb_miss_11
+       mfctl   %ior,va
+
+       .align          32
+       .endm
+#endif
+       
+       /* nadtlb miss interruption handler (parisc 2.0)
+        *
+        * Note: nadtlb misses will be treated
+        * as an ordinary dtlb miss for now.
+        *
+        */
+
+       .macro  nadtlb_20 code
+
+       mfctl   %isr,spc
+#ifdef __LP64__
+       b       dtlb_miss_20w
+#else
+       b       dtlb_miss_20
+#endif
+       mfctl   %ior,va
+
+       .align          32
+       .endm
+       
+#ifndef __LP64__
+       /*
+        * dirty bit trap interruption handler (parisc 1.1 - 32 bit)
+        */
+
+       .macro  dbit_11 code
+
+       mfctl   %isr,spc
+       b       dbit_trap_11
+       mfctl   %ior,va
+
+       .align          32
+       .endm
+#endif
+
+       /*
+        * dirty bit trap interruption handler (parisc 2.0)
+        */
+
+       .macro  dbit_20 code
+
+       mfctl   %isr,spc
+#ifdef __LP64__
+       b       dbit_trap_20w
+#else
+       b       dbit_trap_20
+#endif
+       mfctl   %ior,va
+
+       .align          32
+       .endm
+
+       /*
+        * Align fault_vector_20 on 4K boundary so that both
+        * fault_vector_11 and fault_vector_20 are on the
+        * same page. This is only necessary as long as we
+        * write protect the kernel text, which we may stop
+        * doing once we use large parge translations to cover
+        * the static part of the kernel address space.
+        */
+
+
+       .export fault_vector_20
+
+       .align 4096
+
+fault_vector_20:
+       /* First vector is invalid (0) */
+       .ascii  "cows can fly"
+       .byte 0
+       .align 32
+
+       hpmc             1
+       def              2
+       def              3
+       extint           4
+       def              5
+       itlb_20          6
+       def              7
+       def              8
+       def              9
+       def             10
+       def             11
+       def             12
+       def             13
+       def             14
+       dtlb_20         15
+       naitlb_20       16
+       nadtlb_20       17
+       def             18
+       def             19
+       dbit_20         20
+       def             21
+       def             22
+       def             23
+       def             24
+       def             25
+       def             26
+       def             27
+       def             28
+       def             29
+       def             30
+       def             31
+
+#ifndef __LP64__
+
+       .export fault_vector_11
+       
+       .align 2048
+
+fault_vector_11:
+       /* First vector is invalid (0) */
+       .ascii  "cows can fly"
+       .byte 0
+       .align 32
+
+       hpmc             1
+       def              2
+       def              3
+       extint           4
+       def              5
+       itlb_11          6
+       def              7
+       def              8
+       def              9
+       def             10
+       def             11
+       def             12
+       def             13
+       def             14
+       dtlb_11         15
+       naitlb_11       16
+       nadtlb_11       17
+       def             18
+       def             19
+       dbit_11         20
+       def             21
+       def             22
+       def             23
+       def             24
+       def             25
+       def             26
+       def             27
+       def             28
+       def             29
+       def             30
+       def             31
+
+#endif
+
+       .import         handle_interruption,code
+       .import         handle_real_interruption,code
+       .import         do_irq_mask,code
+       .import         parisc_stopkernel,code
+       .import         cpu_irq_region,data
+
+       /*
+        * r26 = function to be called
+        * r25 = argument to pass in
+        * r24 = flags for do_fork()
+        *
+        * Kernel threads don't ever return, so they don't need
+        * a true register context. We just save away the arguments
+        * for copy_thread/ret_ to properly set up the child.
+        */
+
+#define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
+
+       .export __kernel_thread, code
+       .import do_fork
+__kernel_thread:
+       STREG   %r2, -RP_OFFSET(%r30)
+
+       copy    %r30, %r1
+       ldo     PT_SZ_ALGN(%r30),%r30
+#ifdef __LP64__
+       /* Yo, function pointers in wide mode are little structs... -PB */
+       /* XXX FIXME do we need to honor the fptr's %dp value too? */
+       ldd     16(%r26), %r26
+#endif
+       STREG   %r26, PT_GR26(%r1)  /* Store function & argument for child */
+       STREG   %r25, PT_GR25(%r1)
+       ldo     CLONE_VM(%r0), %r26   /* Force CLONE_VM since only init_mm */
+       or      %r26, %r24, %r26      /* will have kernel mappings.      */
+       copy    %r0, %r25
+       bl      do_fork, %r2
+       copy    %r1, %r24
+
+       /* Parent Returns here */
+
+       ldo     -PT_SZ_ALGN(%r30), %r30
+       LDREG   -RP_OFFSET(%r30), %r2
+       bv      %r0(%r2)
+       nop
+
+       /*
+        * Child Returns here
+        *
+        * copy_thread moved args from temp save area set up above
+        * into task save area.
+        */
+
+       .export ret_from_kernel_thread
+ret_from_kernel_thread:
+
+       LDREG   TASK_PT_GR26-TASK_SZ_ALGN(%r30), %r1
+       LDREG   TASK_PT_GR25-TASK_SZ_ALGN(%r30), %r26
+       ble     0(%sr7, %r1)
+       copy    %r31, %r2
+
+       b       sys_exit
+       ldi     0, %r26
+
+       .import sys_execve, code
+       .export __execve, code
+__execve:
+       copy    %r2, %r15
+       copy    %r23, %r17
+       copy    %r30, %r16
+       ldo     PT_SZ_ALGN(%r30), %r30
+       STREG   %r26, PT_GR26(%r16)
+       STREG   %r25, PT_GR25(%r16)
+       STREG   %r24, PT_GR24(%r16)
+       bl      sys_execve, %r2
+       copy    %r16, %r26
+
+       comib,<>,n 0,%r28,__execve_failed
+
+       b       intr_return
+       STREG   %r17, PT_CR30(%r16)
+
+__execve_failed:
+       /* yes, this will trap and die. */
+       copy    %r15, %r2
+       bv      %r0(%r2)
+       nop
+
+       .align 4
+
+       /*
+        * struct task_struct *_switch_to(struct task_struct *prev,
+        *      struct task_struct *next)
+        *
+        * switch kernel stacks and return prev */
+       .export _switch_to, code
+_switch_to:
+       STREG    %r2, -RP_OFFSET(%r30)
+
+       callee_save
+
+       ldil    L%_switch_to_ret, %r2
+       ldo     R%_switch_to_ret(%r2), %r2
+       LDIL_FIXUP(%r2)
+
+       STREG   %r2, TASK_PT_KPC(%r26)
+       LDREG   TASK_PT_KPC(%r25), %r2
+
+       STREG   %r30, TASK_PT_KSP(%r26)
+       LDREG   TASK_PT_KSP(%r25), %r30
+
+       bv      %r0(%r2)
+       nop
+
+_switch_to_ret:
+       mtctl   %r0, %cr0               /* Needed for single stepping */
+       callee_rest
+
+       LDREG   -RP_OFFSET(%r30), %r2
+       bv      %r0(%r2)
+       copy    %r26, %r28
+
+       /*
+        * Common rfi return path for interruptions, kernel execve, and some
+        * syscalls.  The sys_rt_sigreturn syscall will return via this path
+        * if the signal was received when the process was running; if the
+        * process was blocked on a syscall then the normal syscall_exit
+        * path is used.  All syscalls for traced proceses exit via
+        * intr_restore.
+        * Note that the following code uses a "relied upon translation". See
+        * the parisc ACD for details. The ssm is necessary due to a PCXT bug.
+        */
+
+       .align 4096
+
+       .export syscall_exit_rfi
+syscall_exit_rfi:
+       copy    %r30,%r16
+       /* FIXME! depi below has hardcoded dependency on kernel stack size */
+       depi    0,31,14,%r16 /* get task pointer */
+       ldo     TASK_REGS(%r16),%r16
+       /* Force iaoq to userspace, as the user has had access to our current
+        * context via sigcontext.
+        * XXX do we need any other protection here?
+        */
+       LDREG   PT_IAOQ0(%r16),%r19
+       depi    3,31,2,%r19
+       STREG   %r19,PT_IAOQ0(%r16)
+       LDREG   PT_IAOQ1(%r16),%r19
+       depi    3,31,2,%r19
+       STREG   %r19,PT_IAOQ1(%r16)
+       
+intr_return:
+
+       /* Check for software interrupts */
+
+       .import irq_stat,data
+
+       ldil    L%irq_stat,%r19
+       ldo     R%irq_stat(%r19),%r19
+       LDIL_FIXUP(%r19)
+
+#ifdef CONFIG_SMP
+       copy    %r30,%r1
+       /* FIXME! depi below has hardcoded dependency on kernel stack size */
+       depi    0,31,14,%r1 /* get task pointer */
+       ldw     TASK_PROCESSOR(%r1),%r20 /* get cpu # - int */
+#if (IRQSTAT_SZ == 32)
+       dep     %r20,26,27,%r20 /* shift left 5 bits */
+#else
+#error IRQSTAT_SZ changed, fix dep
+#endif /* IRQSTAT_SZ */
+       add     %r19,%r20,%r19
+#endif /* CONFIG_SMP */
+
+       ldw     IRQSTAT_SI_ACTIVE(%r19),%r20    /* hardirq.h: unsigned int */
+       ldw     IRQSTAT_SI_MASK(%r19),%r19      /* hardirq.h: unsigned int */
+       and     %r19,%r20,%r20
+       comib,<>,n 0,%r20,intr_do_softirq /* forward */
+
+intr_check_resched:
+
+       /* check for reschedule */
+       copy    %r30,%r1
+       /* FIXME! depi below has hardcoded dependency on kernel stack size */
+       depi    0,31,14,%r1 /* get task pointer */
+       LDREG     TASK_NEED_RESCHED(%r1),%r19   /* sched.h: long need_resched */
+       comib,<>,n 0,%r19,intr_do_resched /* forward */
+
+intr_check_sig:
+       /* As above */
+       copy    %r30,%r1
+       depi    0,31,14,%r1 /* get task pointer */
+       ldw     TASK_SIGPENDING(%r1),%r19       /* sched.h: int sigpending */
+       comib,<>,n 0,%r19,intr_do_signal /* forward */
+
+intr_restore:
+       copy            %r16, %r29
+       ldo             PT_FR31(%r29), %r29
+       rest_fp         %r29
+       copy            %r16, %r29
+       rest_general    %r29
+       ssm             0,%r0
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       tophys          %r29
+       mtsm            %r0
+       rest_specials   %r29
+       rest_stack      %r29
+       rfi
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+
+       .import do_softirq,code
+intr_do_softirq:
+       bl      do_softirq,%r2
+       nop
+       b       intr_check_resched
+       nop
+
+       .import schedule,code
+intr_do_resched:
+       /* Only do reschedule if we are returning to user space */
+       LDREG     PT_SR7(%r16), %r20
+       comib,= 0,%r20,intr_restore /* backward */
+       nop
+
+       bl      schedule,%r2
+       ssm     PSW_SM_I, %r0
+
+       /* It's OK to leave I bit on */
+       b       intr_return /* start over if we got a resched */
+       nop
+
+       .import do_signal,code
+intr_do_signal:
+       /* Only do signals if we are returning to user space */
+       LDREG   PT_SR7(%r16), %r20
+       comib,= 0,%r20,intr_restore /* backward */
+       nop
+
+       copy    %r0, %r24                       /* unsigned long in_syscall */
+       copy    %r16, %r25                      /* struct pt_regs *regs */
+       ssm     PSW_SM_I, %r0
+       bl      do_signal,%r2
+       copy    %r0, %r26                       /* sigset_t *oldset = NULL */
+
+       b       intr_restore
+       nop
+
+       /* CR28 - saved GR1
+        * CR29 - argument for do_irq_mask */
+
+       /* External interrupts */
+intr_extint:
+       get_stack
+       save_specials   %r29
+       virt_map        rfi
+       save_general    %r29
+
+       ldo             PT_FR0(%r29), %r24
+       save_fp         %r24
+       
+       loadgp
+
+       copy            %r29, %r24      /* arg2 is pt_regs */
+       copy            %r29, %r16      /* save pt_regs */
+#ifdef CONFIG_KWDB
+       copy            %r29, %r3       /* KWDB - update frame pointer (gr3) */
+#endif
+
+       /* sorry to put this cruft in the interrupt path */
+       ldil            L%cpu_irq_region, %r25
+       ldo             R%cpu_irq_region(%r25), %r25
+       bl              do_irq_mask,%r2
+#ifdef __LP64__
+       LDIL_FIXUP(%r25)
+#else
+       nop
+#endif
+
+       b               intr_return
+       nop
+
+       /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
+
+       .export         intr_save, code /* for os_hpmc */
+
+intr_save:
+       get_stack
+       save_specials   %r29
+
+       mfctl           %cr20, %r1
+       STREG           %r1, PT_ISR(%r29)
+       mfctl           %cr21, %r1
+       STREG           %r1, PT_IOR(%r29)
+
+       virt_map        rfi
+       save_general    %r29
+
+       ldo             PT_FR0(%r29), %r25
+       save_fp         %r25
+       
+       loadgp
+
+       copy            %r29, %r25      /* arg1 is pt_regs */
+#ifdef CONFIG_KWDB
+       copy            %r29, %r3       /* KWDB - update frame pointer (gr3) */
+#endif
+
+       bl              handle_interruption,%r2
+       copy            %r29, %r16      /* save pt_regs */
+
+       b               intr_return
+       nop
+
+       /*
+        * Note for all tlb miss handlers:
+        *
+        * cr24 contains a pointer to the kernel address space
+        * page directory.
+        *
+        * cr25 contains a pointer to the current user address
+        * space page directory.
+        *
+        * sr3 will contain the space id of the user address space
+        * of the current running thread while that thread is
+        * running in the kernel.
+        */
+
+       /*
+        * register number allocations.  Note that these are all
+        * in the shadowed registers
+        */
+
+       t0 = r1         /* temporary register 0 */
+       va = r8         /* virtual address for which the trap occured */
+       t1 = r9         /* temporary register 1 */
+       pte  = r16      /* pte/phys page # */
+       prot = r17      /* prot bits */
+       spc  = r24      /* space for which the trap occured */
+       ptp = r25       /* page directory/page table pointer */
+
+#ifdef __LP64__
+
+dtlb_miss_20w:
+
+       extrd,u         spc,31,7,t1     /* adjust va */
+       depd            t1,31,7,va      /* adjust va */
+       depdi           0,31,7,spc      /* adjust space */
+       mfctl           %cr25,ptp       /* Assume user space miss */
+       or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
+       mfctl           %cr24,ptp       /* Load kernel pgd instead */
+       extrd,u         va,33,9,t1      /* Get pgd index */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
+       comb,<>,n       t0,spc,dtlb_fault /* forward */
+
+       /* First level page table lookup */
+
+       ldd,s           t1(ptp),ptp
+       extrd,u         va,42,9,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_fault
+       depdi           0,63,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       ldd,s           t0(ptp),ptp
+       extrd,u         va,51,9,t0     /* get third-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_fault
+       depdi           0,63,12,ptp     /* clear prot bits */
+
+       /* Third level page table lookup */
+
+       shladd           t0,3,ptp,ptp
+       ldi             _PAGE_ACCESSED,t1
+       ldd              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_fault
+
+       /* Check whether the "accessed" bit was set, otherwise do so */
+
+       or              t1,pte,t0       /* t0 has R bit set */
+       and,*<>         t1,pte,%r0      /* test and nullify if already set */
+       std             t0,0(ptp)       /* write back pte */
+
+       copy            spc,prot        /* init prot with faulting space */
+       
+       depd            pte,8,7,prot
+       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
+       depdi           1,12,1,prot
+       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
+       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for idtlbt */
+
+       depdi           0,63,12,pte
+       extrd,u         pte,56,32,pte
+       idtlbt          %r16,%r17
+
+       rfir
+       nop
+#else
+
+dtlb_miss_11:
+       mfctl           %cr25,ptp       /* Assume user space miss */
+       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
+       mfctl           %cr24,ptp       /* Load kernel pgd instead */
+       extru           va,9,10,t1      /* Get pgd index */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
+       comb,<>,n       t0,spc,dtlb_fault /* forward */
+
+       /* First level page table lookup */
+
+       ldwx,s          t1(ptp),ptp
+       extru           va,19,10,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_fault
+       depi            0,31,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       sh2addl          t0,ptp,ptp
+       ldi             _PAGE_ACCESSED,t1
+       ldw              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_fault
+
+       /* Check whether the "accessed" bit was set, otherwise do so */
+
+       or              t1,pte,t0       /* t0 has R bit set */
+       and,<>          t1,pte,%r0      /* test and nullify if already set */
+       stw             t0,0(ptp)       /* write back pte */
+
+       copy            spc,prot        /* init prot with faulting space */
+       dep             pte,8,7,prot
+
+       extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
+       depi            1,12,1,prot
+       extru,=         pte,_PAGE_USER_BIT,1,r0
+       depi            7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extru,=         pte,_PAGE_GATEWAY_BIT,1,r0
+       depi            0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for idtlba */
+
+       depi            0,31,12,pte
+       extru           pte,24,25,pte
+
+       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mtsp            spc,%sr1
+
+       idtlba          pte,(%sr1,va)
+       idtlbp          prot,(%sr1,va)
+
+       mtsp            t0, %sr1        /* Restore sr1 */
+
+       rfir
+       nop
+
+dtlb_miss_20:
+       .level 2.0
+
+       mfctl           %cr25,ptp       /* Assume user space miss */
+       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
+       mfctl           %cr24,ptp       /* Load kernel pgd instead */
+       extru           va,9,10,t1      /* Get pgd index */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
+       comb,<>,n       t0,spc,dtlb_fault /* forward */
+
+       /* First level page table lookup */
+
+       ldwx,s          t1(ptp),ptp
+       extru           va,19,10,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_fault
+       depi            0,31,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       sh2addl          t0,ptp,ptp
+       ldi             _PAGE_ACCESSED,t1
+       ldw              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_fault
+
+       /* Check whether the "accessed" bit was set, otherwise do so */
+
+       or              t1,pte,t0       /* t0 has R bit set */
+       and,<>          t1,pte,%r0      /* test and nullify if already set */
+       stw             t0,0(ptp)       /* write back pte */
+
+       copy            spc,prot        /* init prot with faulting space */
+       
+       depd            pte,8,7,prot
+       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
+       depdi           1,12,1,prot
+       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
+       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for idtlbt */
+
+       depdi           0,63,12,pte
+       extrd,u         pte,56,25,pte
+       idtlbt          %r16,%r17
+
+       .level          1.1
+
+       rfir
+       nop
+#endif
+
+#ifdef __LP64__
+itlb_miss_20w:
+
+       /*
+        * I miss is a little different, since we allow users to fault
+        * on the gateway page which is in the kernel address space.
+        */
+
+       extrd,u         spc,31,7,t1     /* adjust va */
+       depd            t1,31,7,va      /* adjust va */
+       depdi           0,31,7,spc      /* adjust space */
+       cmpib,*=        0,spc,itlb_miss_kernel_20w
+       extrd,u         va,33,9,t1      /* Get pgd index */
+
+       mfctl           %cr25,ptp       /* load user pgd */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
+       cmpb,*<>,n      t0,spc,itlb_fault /* forward */
+
+       /* First level page table lookup */
+
+itlb_miss_common_20w:
+       ldd,s           t1(ptp),ptp
+       extrd,u         va,42,9,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,itlb_fault
+       depdi           0,63,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       ldd,s           t0(ptp),ptp
+       extrd,u         va,51,9,t0     /* get third-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,itlb_fault
+       depdi           0,63,12,ptp     /* clear prot bits */
+
+       /* Third level page table lookup */
+
+       shladd           t0,3,ptp,ptp
+       ldi             _PAGE_ACCESSED,t1
+       ldd              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,itlb_fault
+
+       /* Check whether the "accessed" bit was set, otherwise do so */
+
+       or              t1,pte,t0       /* t0 has R bit set */
+       and,*<>         t1,pte,%r0      /* test and nullify if already set */
+       std             t0,0(ptp)       /* write back pte */
+
+       copy            spc,prot        /* init prot with faulting space */
+       
+       depd            pte,8,7,prot
+       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
+       depdi           1,12,1,prot
+       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
+       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for iitlbt */
+
+       depdi           0,63,12,pte
+       extrd,u         pte,56,32,pte
+       iitlbt          %r16,%r17
+
+       rfir
+       nop
+
+itlb_miss_kernel_20w:
+       b               itlb_miss_common_20w
+       mfctl           %cr24,ptp       /* Load kernel pgd */
+#else
+
+itlb_miss_11:
+
+       /*
+        * I miss is a little different, since we allow users to fault
+        * on the gateway page which is in the kernel address space.
+        */
+
+       comib,=         0,spc,itlb_miss_kernel_11
+       extru           va,9,10,t1      /* Get pgd index */
+
+       mfctl           %cr25,ptp       /* load user pgd */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
+       comb,<>,n       t0,spc,itlb_fault /* forward */
+
+       /* First level page table lookup */
+
+itlb_miss_common_11:
+       ldwx,s          t1(ptp),ptp
+       extru           va,19,10,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,itlb_fault
+       depi            0,31,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       sh2addl          t0,ptp,ptp
+       ldi             _PAGE_ACCESSED,t1
+       ldw              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,itlb_fault
+
+       /* Check whether the "accessed" bit was set, otherwise do so */
+
+       or              t1,pte,t0       /* t0 has R bit set */
+       and,<>          t1,pte,%r0      /* test and nullify if already set */
+       stw             t0,0(ptp)       /* write back pte */
+
+       copy            spc,prot        /* init prot with faulting space */
+       dep             pte,8,7,prot
+
+       extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
+       depi            1,12,1,prot
+       extru,=         pte,_PAGE_USER_BIT,1,r0
+       depi            7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extru,=         pte,_PAGE_GATEWAY_BIT,1,r0
+       depi            0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for iitlba */
+
+       depi            0,31,12,pte
+       extru           pte,24,25,pte
+
+       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mtsp            spc,%sr1
+
+       iitlba          pte,(%sr1,va)
+       iitlbp          prot,(%sr1,va)
+
+       mtsp            t0, %sr1        /* Restore sr1 */
+
+       rfir
+       nop
+
+itlb_miss_kernel_11:
+       b               itlb_miss_common_11
+       mfctl           %cr24,ptp       /* Load kernel pgd */
+
+itlb_miss_20:
+
+       /*
+        * I miss is a little different, since we allow users to fault
+        * on the gateway page which is in the kernel address space.
+        */
+
+       comib,=         0,spc,itlb_miss_kernel_20
+       extru           va,9,10,t1      /* Get pgd index */
+
+       mfctl           %cr25,ptp       /* load user pgd */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
+       comb,<>,n       t0,spc,itlb_fault /* forward */
+
+       /* First level page table lookup */
+
+itlb_miss_common_20:
+       ldwx,s          t1(ptp),ptp
+       extru           va,19,10,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,itlb_fault
+       depi            0,31,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       sh2addl          t0,ptp,ptp
+       ldi             _PAGE_ACCESSED,t1
+       ldw              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,itlb_fault
+
+       /* Check whether the "accessed" bit was set, otherwise do so */
+
+       or              t1,pte,t0       /* t0 has R bit set */
+       and,<>          t1,pte,%r0      /* test and nullify if already set */
+       stw             t0,0(ptp)       /* write back pte */
+
+       copy            spc,prot        /* init prot with faulting space */
+       
+       .level 2.0
+
+       depd            pte,8,7,prot
+       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
+       depdi           1,12,1,prot
+       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
+       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for iitlbt */
+
+       depdi           0,63,12,pte
+       extrd,u         pte,56,25,pte
+       iitlbt          %r16,%r17
+       .level          1.1
+
+       rfir
+       nop
+
+
+itlb_miss_kernel_20:
+       b               itlb_miss_common_20
+       mfctl           %cr24,ptp       /* Load kernel pgd */
+#endif
+
+#ifdef __LP64__
+
+dbit_trap_20w:
+
+       extrd,u         spc,31,7,t1     /* adjust va */
+       depd            t1,31,7,va      /* adjust va */
+       depdi           0,1,2,va        /* adjust va */
+       depdi           0,31,7,spc      /* adjust space */
+       mfctl           %cr25,ptp       /* Assume user space miss */
+       or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
+       mfctl           %cr24,ptp       /* Load kernel pgd instead */
+       extrd,u         va,33,9,t1      /* Get pgd index */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
+       comb,<>,n       t0,spc,dbit_fault /* forward */
+
+       /* First level page table lookup */
+
+       ldd,s           t1(ptp),ptp
+       extrd,u         va,42,9,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
+       depdi           0,63,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       ldd,s           t0(ptp),ptp
+       extrd,u         va,51,9,t0     /* get third-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
+       depdi           0,63,12,ptp     /* clear prot bits */
+
+       /* Third level page table lookup */
+
+       shladd           t0,3,ptp,ptp
+       ldi             (_PAGE_ACCESSED|_PAGE_DIRTY),t1
+       ldd              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
+
+       /* Set Accessed and Dirty bits in the pte */
+
+       or              t1,pte,pte
+       std             pte,0(ptp)      /* write back pte */
+
+       copy            spc,prot        /* init prot with faulting space */
+       
+       depd            pte,8,7,prot
+       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
+       depdi           1,12,1,prot
+       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
+       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for idtlbt */
+
+       depdi           0,63,12,pte
+       extrd,u         pte,56,32,pte
+       idtlbt          %r16,%r17
+
+       rfir
+       nop
+#else
+
+dbit_trap_11:
+       mfctl           %cr25,ptp       /* Assume user space trap */
+       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
+       mfctl           %cr24,ptp       /* Load kernel pgd instead */
+       extru           va,9,10,t1      /* Get pgd index */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
+       comb,<>,n       t0,spc,dbit_fault /* forward */
+
+       /* First level page table lookup */
+
+       ldwx,s          t1(ptp),ptp
+       extru           va,19,10,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
+       depi            0,31,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       sh2addl          t0,ptp,ptp
+       ldi             (_PAGE_ACCESSED|_PAGE_DIRTY),t1
+       ldw              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
+
+       /* Set Accessed and Dirty bits in the pte */
+
+       or              t1,pte,pte
+       stw             pte,0(ptp)      /* write back pte */
+
+       copy            spc,prot        /* init prot with faulting space */
+       dep             pte,8,7,prot
+
+       extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
+       depi            1,12,1,prot
+       extru,=         pte,_PAGE_USER_BIT,1,r0
+       depi            7,11,3,prot /* Set for user space (1 rsvd for read) */
+       extru,=         pte,_PAGE_GATEWAY_BIT,1,r0
+       depi            0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for idtlba */
+
+       depi            0,31,12,pte
+       extru           pte,24,25,pte
+
+       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mtsp            spc,%sr1
+
+       idtlba          pte,(%sr1,va)
+       idtlbp          prot,(%sr1,va)
+
+       mtsp            t0, %sr1     /* Restore sr1 */
+
+       rfir
+       nop
+
+dbit_trap_20:
+       mfctl           %cr25,ptp       /* Assume user space trap */
+       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
+       mfctl           %cr24,ptp       /* Load kernel pgd instead */
+       extru           va,9,10,t1      /* Get pgd index */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
+       comb,<>,n       t0,spc,dbit_fault /* forward */
+
+       /* First level page table lookup */
+
+       ldwx,s          t1(ptp),ptp
+       extru           va,19,10,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
+       depi            0,31,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       sh2addl          t0,ptp,ptp
+       ldi             (_PAGE_ACCESSED|_PAGE_DIRTY),t1
+       ldw              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
+
+       /* Set Accessed and Dirty bits in the pte */
+
+       or              t1,pte,pte
+       stw             pte,0(ptp)      /* write back pte */
+
+       copy            spc,prot        /* init prot with faulting space */
+       
+       .level 2.0
+
+       depd            pte,8,7,prot
+       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
+       depdi           1,12,1,prot
+       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
+       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for idtlbt */
+
+       depdi           0,63,12,pte
+       extrd,u         pte,56,25,pte
+       idtlbt          %r16,%r17
+
+       .level          1.1
+
+       rfir
+       nop
+#endif
+
+       .import handle_interruption,code
+
+kernel_bad_space:
+       b               tlb_fault
+       ldi             31,%r1  /* Use an unused code */
+
+dbit_fault:
+       b               tlb_fault
+       ldi             20,%r1
+
+itlb_fault:
+       b               tlb_fault
+       ldi             6,%r1
+
+dtlb_fault:
+       ldi             15,%r1
+
+       /* Fall Through */
+
+tlb_fault:
+       mtctl           %r1,%cr29
+       mtctl           %r29,%cr31
+
+       get_stack
+       save_specials   %r29            /* Note this saves a trashed r1 */
+
+       SAVE_CR         (%cr20, PT_ISR(%r29))
+       SAVE_CR         (%cr21, PT_IOR(%r29))
+
+       virt_map        rfir
+
+       STREG           %r1,PT_GR1(%r29)        /* save good value after rfir */
+
+       save_general    %r29
+
+       ldo     PT_FR0(%r29), %r25
+       save_fp         %r25
+       
+       loadgp
+
+       copy            %r29, %r25
+
+       bl              handle_interruption, %r2
+       copy            %r29, %r16
+
+       b               intr_return
+       nop
+
+       /* Register saving semantics for system calls:
+
+          %r1             clobbered by system call macro in userspace
+          %r2             saved in PT_REGS by gateway page
+          %r3  - %r18     preserved by C code (saved by signal code)
+          %r19 - %r20     saved in PT_REGS by gateway page
+          %r21 - %r22     non-standard syscall args
+                          stored in kernel stack by gateway page
+          %r23 - %r26     arg3-arg0, saved in PT_REGS by gateway page
+          %r27 - %r30     saved in PT_REGS by gateway page
+          %r31            syscall return pointer
+        */
+
+       /* Floating point registers (FIXME: what do we do with these?)
+
+          %fr0  - %fr3    status/exception, not preserved
+          %fr4  - %fr7    arguments
+          %fr8  - %fr11   not preserved by C code
+          %fr12 - %fr21   preserved by C code
+          %fr22 - %fr31   not preserved by C code
+        */
+
+       .macro  reg_save regs
+       STREG   %r3, PT_GR3(\regs)
+       STREG   %r4, PT_GR4(\regs)
+       STREG   %r5, PT_GR5(\regs)
+       STREG   %r6, PT_GR6(\regs)
+       STREG   %r7, PT_GR7(\regs)
+       STREG   %r8, PT_GR8(\regs)
+       STREG   %r9, PT_GR9(\regs)
+       STREG   %r10,PT_GR10(\regs)
+       STREG   %r11,PT_GR11(\regs)
+       STREG   %r12,PT_GR12(\regs)
+       STREG   %r13,PT_GR13(\regs)
+       STREG   %r14,PT_GR14(\regs)
+       STREG   %r15,PT_GR15(\regs)
+       STREG   %r16,PT_GR16(\regs)
+       STREG   %r17,PT_GR17(\regs)
+       STREG   %r18,PT_GR18(\regs)
+       .endm
+
+       .macro  reg_restore regs
+       LDREG   PT_GR3(\regs), %r3
+       LDREG   PT_GR4(\regs), %r4
+       LDREG   PT_GR5(\regs), %r5
+       LDREG   PT_GR6(\regs), %r6
+       LDREG   PT_GR7(\regs), %r7
+       LDREG   PT_GR8(\regs), %r8
+       LDREG   PT_GR9(\regs), %r9
+       LDREG   PT_GR10(\regs),%r10
+       LDREG   PT_GR11(\regs),%r11
+       LDREG   PT_GR12(\regs),%r12
+       LDREG   PT_GR13(\regs),%r13
+       LDREG   PT_GR14(\regs),%r14
+       LDREG   PT_GR15(\regs),%r15
+       LDREG   PT_GR16(\regs),%r16
+       LDREG   PT_GR17(\regs),%r17
+       LDREG   PT_GR18(\regs),%r18
+       .endm
+
+       .export sys_fork_wrapper
+sys_fork_wrapper:
+       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1     /* get pt regs */
+       reg_save %r1
+
+       STREG   %r2,-RP_OFFSET(%r30)
+       ldo     FRAME_SIZE(%r30),%r30
+
+       /* These are call-clobbered registers and therefore
+          also syscall-clobbered (we hope). */
+       STREG   %r2,PT_GR19(%r1)        /* save for child */
+       STREG   %r30,PT_GR20(%r1)
+       ldil    L%child_return, %r3
+       ldo     R%child_return(%r3), %r3
+       LDIL_FIXUP(%r3)
+       STREG   %r3,PT_GR21(%r1)        /* save for child */
+
+       LDREG   PT_GR30(%r1),%r25
+       copy    %r1,%r24
+       bl      sys_clone,%r2
+       ldi     SIGCHLD,%r26
+
+       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
+wrapper_exit:
+       ldo     -FRAME_SIZE(%r30),%r30          /* get the stackframe */
+       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1    /* get pt regs */
+
+       reg_restore %r1
+
+       bv %r0(%r2)
+       nop
+
+       /* Set the return value for the child */
+child_return:
+       LDREG   TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
+       b       wrapper_exit
+       copy    %r0,%r28
+
+       
+       .export sys_clone_wrapper
+sys_clone_wrapper:
+       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1     /* get pt regs */
+       reg_save %r1
+
+       STREG   %r2,-RP_OFFSET(%r30)
+       ldo     FRAME_SIZE(%r30),%r30
+
+       STREG   %r30,PT_GR20(%r1)
+       ldil    L%child_return,%r3
+       ldo     R%child_return(%r3),%r3
+       LDIL_FIXUP(%r3)
+
+       bl      sys_clone,%r2
+       STREG   %r3,PT_GR21(%r1)        /* save for child */
+
+       b       wrapper_exit
+       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
+
+
+       .export sys_vfork_wrapper
+sys_vfork_wrapper:
+       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1     /* get pt regs */
+       reg_save %r1
+
+       STREG   %r2,-RP_OFFSET(%r30)
+       ldo     FRAME_SIZE(%r30),%r30
+
+       STREG   %r30,PT_GR20(%r1)
+       ldil    L%child_return,%r3
+       ldo     R%child_return(%r3),%r3
+       LDIL_FIXUP(%r3)
+       STREG   %r3,PT_GR21(%r1)        /* save for child */
+
+       bl      sys_vfork,%r2
+       copy    %r1,%r26
+
+       b       wrapper_exit
+       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
+
+       
+       .macro  execve_wrapper execve
+       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get pt regs */
+
+       /*
+        * Do we need to save/restore r3-r18 here?
+        * I don't think so. why would new thread need old
+        * threads registers?
+        */
+
+       /* %arg0 - %arg3 are already saved for us. */
+
+       STREG %r2,-RP_OFFSET(%r30)
+       ldo FRAME_SIZE(%r30),%r30
+       bl \execve,%r2
+       copy %r1,%arg0
+
+       ldo -FRAME_SIZE(%r30),%r30
+       LDREG -RP_OFFSET(%r30),%r2
+
+       /* If exec succeeded we need to load the args */
+
+       ldo -1024(%r0),%r1
+       comb,>>= %r28,%r1,error_\execve
+       copy %r2,%r19
+
+error_\execve:
+       bv %r0(%r19)
+       nop
+       .endm
+
+       .export sys_execve_wrapper
+       .import sys_execve
+
+sys_execve_wrapper:
+       execve_wrapper sys_execve
+
+#ifdef __LP64__
+       .export sys32_execve_wrapper
+       .import sys32_execve
+
+sys32_execve_wrapper:
+       execve_wrapper sys32_execve
+#endif
+
+       .export sys_rt_sigreturn_wrapper
+sys_rt_sigreturn_wrapper:
+       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r26
+       /* Don't save regs, we are going to restore them from sigcontext. */
+       STREG   %r2, -RP_OFFSET(%r30)
+       bl      sys_rt_sigreturn,%r2
+       ldo     FRAME_SIZE(%r30), %r30
+
+       ldo     -FRAME_SIZE(%r30), %r30
+       LDREG   -RP_OFFSET(%r30), %r2
+
+       /* FIXME: I think we need to restore a few more things here. */
+       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get pt regs */
+       reg_restore %r1
+
+       /* If the signal was received while the process was blocked on a
+        * syscall, then r2 will take us to syscall_exit; otherwise r2 will
+        * take us to syscall_exit_rfi and on to intr_return.
+        */
+       bv      %r0(%r2)
+       LDREG   PT_GR28(%r1),%r28  /* reload original r28 for syscall_exit */
+
+       .export sys_sigaltstack_wrapper
+sys_sigaltstack_wrapper:
+       /* Get the user stack pointer */
+       LDREG   -TASK_SZ_ALGN-FRAME_SIZE+TASK_PT_GR30(%r30), %r24
+       STREG   %r2, -RP_OFFSET(%r30)
+       bl      do_sigaltstack,%r2
+       ldo     FRAME_SIZE(%r30), %r30
+
+       ldo     -FRAME_SIZE(%r30), %r30
+       LDREG   -RP_OFFSET(%r30), %r2
+       bv      %r0(%r2)
+       nop
+
+       .export sys_rt_sigsuspend_wrapper
+sys_rt_sigsuspend_wrapper:
+       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r24
+       reg_save %r24
+
+       STREG   %r2, -RP_OFFSET(%r30)
+       bl      sys_rt_sigsuspend,%r2
+       ldo     FRAME_SIZE(%r30), %r30
+
+       ldo     -FRAME_SIZE(%r30), %r30
+       LDREG   -RP_OFFSET(%r30), %r2
+
+       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1
+       reg_restore %r1
+
+       bv      %r0(%r2)
+       nop
+
+       .export syscall_exit
+syscall_exit:
+       /* NOTE: HP-UX syscalls also come through here
+          after hpux_syscall_exit fixes up return
+          values. */
+       /* NOTE: Not all syscalls exit this way.  rt_sigreturn will exit
+        * via syscall_exit_rfi if the signal was received while the process
+        * was running.  All traced processes will probably exit via
+        * syscall_exit_rfi in the future.
+        */
+
+       /* save return value now */
+
+       STREG     %r28,TASK_PT_GR28-TASK_SZ_ALGN-FRAME_SIZE(%r30)
+
+syscall_check_bh:
+
+/* #ifdef NOTNOW */
+       /* Check for software interrupts */
+
+       .import irq_stat,data
+
+       ldil    L%irq_stat,%r19
+       ldo     R%irq_stat(%r19),%r19
+       LDIL_FIXUP(%r19)
+
+#ifdef CONFIG_SMP
+       /* sched.h: int processor */
+       ldw     TASK_PROCESSOR-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r20 /* get cpu # */
+#if (IRQSTAT_SZ == 32)
+       dep     %r20,26,27,%r20 /* shift left 5 bits */
+#else
+#error IRQSTAT_SZ changed, fix dep
+#endif /* IRQSTAT_SZ */
+       add     %r19,%r20,%r19
+#endif /* CONFIG_SMP */
+
+       ldw     IRQSTAT_SI_ACTIVE(%r19),%r20    /* hardirq.h: unsigned int */
+       ldw     IRQSTAT_SI_MASK(%r19),%r19      /* hardirq.h: unsigned int */
+       and     %r19,%r20,%r20
+       comib,<>,n 0,%r20,syscall_do_softirq /* forward */
+/* #endif */
+
+
+syscall_check_resched:
+
+       /* check for reschedule */
+
+       LDREG  TASK_NEED_RESCHED-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19     /* long */
+       comib,<>,n 0,%r19,syscall_do_resched /* forward */
+
+syscall_check_sig:
+       ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get task ptr */
+       /* check for pending signals */
+       ldw     TASK_SIGPENDING(%r1),%r19
+       comib,<>,n 0,%r19,syscall_do_signal  /* forward */
+
+syscall_restore:
+       /* disable interrupts while dicking with the kernel stack, */
+       /* or life can become unpleasant */
+       rsm     PSW_SM_I, %r20
+       LDREG   TASK_PTRACE(%r1), %r19          /* Are we being ptraced? */
+       bb,<,n  %r19,31,syscall_restore_rfi
+       LDREG   TASK_PT_GR20(%r1),%r19
+       mtctl   %r19, %cr27
+
+       LDREG   TASK_PT_GR2(%r1),%r2               /* restore user rp */
+       LDREG   TASK_PT_GR21(%r1),%r21
+       LDREG   TASK_PT_GR22(%r1),%r22
+       LDREG   TASK_PT_GR23(%r1),%r23
+       LDREG   TASK_PT_GR24(%r1),%r24
+       LDREG   TASK_PT_GR25(%r1),%r25
+       LDREG   TASK_PT_GR26(%r1),%r26
+       LDREG   TASK_PT_GR27(%r1),%r27     /* restore user dp */
+       LDREG   TASK_PT_GR28(%r1),%r28     /* syscall return value */
+       LDREG   TASK_PT_GR29(%r1),%r29
+       LDREG   TASK_PT_GR30(%r1),%r30     /* restore user sp */
+       LDREG   TASK_PT_GR31(%r1),%r31     /* restore syscall rp */
+       ldo     TASK_PT_FR31(%r1),%r19             /* reload fpregs */
+       rest_fp %r19
+       LDREG   TASK_PT_SAR(%r1),%r19              /* restore SAR */
+       mtsar   %r19
+       LDREG   TASK_PT_GR19(%r1),%r19
+
+       mtctl   %r1,%cr30                          /* intrhandler okay. */
+       mfsp    %sr3,%r1                           /* Get users space id */
+       mtsp    %r1,%sr4                           /* Restore sr4 */
+       mtsp    %r1,%sr5                           /* Restore sr5 */
+       mtsp    %r1,%sr6                           /* Restore sr6 */
+
+       depi    3,31,2,%r31                        /* ensure return to user mode. */
+
+       mtsm    %r20                               /* restore irq state  */
+       mfctl   %cr27,%r20
+       
+       /*
+        * Due to a dependency in the tlb miss handlers on sr7, it
+        * is essential that sr7 get set in the delay slot.
+        */
+
+#ifdef __LP64__
+
+       /* Note the be (and mtsp) is executed in narrow mode. This is OK
+        * for 32 bit processes, but won't work once we support 64 bit
+        * processes.
+        */
+
+       rsm     PSW_SM_W, %r0
+       be      0(%sr3,%r31)                       /* return to user space */
+       mtsp    %r1,%sr7                           /* Restore sr7 */
+#else
+       be      0(%sr3,%r31)                       /* return to user space */
+       mtsp    %r1,%sr7                           /* Restore sr7 */
+#endif
+
+       /* We have to return via an RFI, so that PSW T and R bits can be set
+        * appropriately.
+        * This sets up pt_regs so we can return via intr_restore, which is not
+        * the most efficient way of doing things, but it works.
+        */
+syscall_restore_rfi:
+       ldo     -1(%r0),%r2                        /* Set recovery cntr to -1 */
+       mtctl   %r2,%cr0                           /*   for immediate trap */
+       copy    %r0,%r2                            /* Create a reasonable PSW */
+       /* XXX W bit??? */
+       depi    -1,13,1,%r2
+       depi    -1,28,1,%r2
+       depi    -1,30,1,%r2
+       depi    -1,31,1,%r2
+       bb,<,n  %r19,15,set_rbit                   /* PT_SINGLESTEP */
+       bb,>=,n %r19,14,set_nobit                  /* PT_BLOCKSTEP, see ptrace.c */
+set_tbit:
+       depi    -1,7,1,%r2
+       b,n     set_nobit
+set_rbit:
+       depi    -1,27,1,%r2
+set_nobit:
+       STREG   %r2,TASK_PT_PSW(%r1)
+       STREG   %r1,TASK_PT_CR30(%r1)
+       mfsp    %sr0,%r2
+       STREG   %r2,TASK_PT_SR0(%r1)
+       mfsp    %sr1,%r2
+       STREG   %r2,TASK_PT_SR1(%r1)
+       mfsp    %sr2,%r2
+       STREG   %r2,TASK_PT_SR2(%r1)
+       mfsp    %sr3,%r2
+       STREG   %r2,TASK_PT_SR3(%r1)
+       STREG   %r2,TASK_PT_SR4(%r1)
+       STREG   %r2,TASK_PT_SR5(%r1)
+       STREG   %r2,TASK_PT_SR6(%r1)
+       STREG   %r2,TASK_PT_SR7(%r1)
+       STREG   %r2,TASK_PT_IASQ0(%r1)
+       STREG   %r2,TASK_PT_IASQ1(%r1)
+       LDREG   TASK_PT_GR31(%r1),%r2
+       depi    3,31,2,%r2                         /* ensure return to user mode. */
+       STREG   %r2,TASK_PT_IAOQ0(%r1)
+       ldo     4(%r2),%r2
+       STREG   %r2,TASK_PT_IAOQ1(%r1)
+       ldo     TASK_REGS(%r1),%r25
+       reg_save %r25                              /* Save r3 to r18 */
+       copy    %r25,%r16
+       b       intr_restore
+       nop
+
+       .import do_softirq,code
+syscall_do_softirq:
+       bl      do_softirq,%r2
+       nop
+       b       syscall_check_resched
+       ssm     PSW_SM_I, %r0  /* do_softirq returns with I bit off */
+
+       .import schedule,code
+syscall_do_resched:
+       bl      schedule,%r2
+       nop
+       b       syscall_check_bh  /* if resched, we start over again */
+       nop
+
+       .import do_signal,code
+syscall_do_signal:
+       /* Save callee-save registers (for sigcontext).
+          FIXME: After this point the process structure should be
+          consistent with all the relevant state of the process
+          before the syscall.  We need to verify this. */
+       ldo     TASK_REGS(%r1), %r25            /* struct pt_regs *regs */
+       reg_save %r25
+
+       ldi     1, %r24                         /* unsigned long in_syscall */
+
+       bl      do_signal,%r2
+       copy    %r0, %r26                       /* sigset_t *oldset = NULL */
+
+       ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30), %r1     /* reload task ptr */
+       ldo     TASK_REGS(%r1), %r20            /* reload pt_regs */
+       reg_restore %r20
+
+       b,n     syscall_restore
+
+#ifdef __LP64__
+unimplemented_64bitirq:
+       ssm PSW_SM_Q+PSW_SM_I, %r0
+       /* indicate that we had an interrupt */
+       ldi     0x77, %r28
+       ldi     0x77, %r29
+       /* save interrupt registers in GRs for diagnosis */
+       mfctl %cr17, %r17
+       mfctl %cr18, %r18
+       mfctl %cr19, %r19
+       mfctl %cr20, %r20
+       mfctl %cr21, %r21
+       mfctl %cr22, %r22
+       b,n .
+       nop
+#endif
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
new file mode 100644 (file)
index 0000000..75d5c66
--- /dev/null
@@ -0,0 +1,1446 @@
+/*
+ *    Hardware descriptions for HP 9000 based hardware, including
+ *    system types, SCSI controllers, DMA controllers, HPPB controllers
+ *    and lots more.
+ * 
+ *    Based on the document "PA-RISC 1.1 I/O Firmware Architecture 
+ *    Reference Specification", March 7, 1999, version 0.96.  This
+ *    is available at ?.
+ *
+ *    Copyright 1999 by Alex deVries <adevries@thepuffingroup.com>
+ *    and copyright 1999 The Puffin Group Inc.
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <asm/hardware.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+
+#define HPHW_NUM_TYPES 3431
+
+static char * hw_type_name[16] = {
+       "Processor",
+       "Memory",
+       "B DMA",
+       "Obsolete",
+       "A DMA",
+       "A Direct",
+       "Obsolete",
+       "Bus Converter Port",
+       "HP CIO Adapter",
+       "Console",
+       "Foreign I/O Module",
+       "Bus Adapter",
+       "IOA (?)",
+       "Bus Bridge to Foreign Bus",
+       "HP Clothing: Fabric Component"
+};
+
+/*
+ *     XXX     Could this be __init ??
+ */
+static struct hp_hardware hp_hardware_list[] = {
+       {HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"},
+       {HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"},
+       {HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"},
+       {HPHW_NPROC,0xB,0x4,0x01,"Technical Shogun (845, 645)"},
+       {HPHW_NPROC,0xF,0x4,0x01,"Commercial Shogun (949)"},
+       {HPHW_NPROC,0xC,0x4,0x01,"Cheetah (850, 950)"},
+       {HPHW_NPROC,0x80,0x4,0x01,"Cheetah (950S)"},
+       {HPHW_NPROC,0x81,0x4,0x01,"Jaguar (855, 955)"},
+       {HPHW_NPROC,0x82,0x4,0x01,"Cougar (860, 960)"},
+       {HPHW_NPROC,0x83,0x4,0x13,"Panther (865, 870, 980)"},
+       {HPHW_NPROC,0x100,0x4,0x01,"Burgundy (810)"},
+       {HPHW_NPROC,0x101,0x4,0x01,"SilverFox Low (822, 922)"},
+       {HPHW_NPROC,0x102,0x4,0x01,"SilverFox High (832, 932)"},
+       {HPHW_NPROC,0x103,0x4,0x01,"Lego, SilverLite (815, 808, 920)"},
+       {HPHW_NPROC,0x104,0x4,0x03,"SilverBullet Low (842, 948)"},
+       {HPHW_NPROC,0x105,0x4,0x03,"SilverBullet High (852, 958)"},
+       {HPHW_NPROC,0x106,0x4,0x81,"Oboe"},
+       {HPHW_NPROC,0x180,0x4,0x12,"Dragon"},
+       {HPHW_NPROC,0x181,0x4,0x13,"Chimera (890, 990, 992)"},
+       {HPHW_NPROC,0x182,0x4,0x91,"TNT 100 (891,T500)"},
+       {HPHW_NPROC,0x183,0x4,0x91,"TNT 120 (892,T520)"},
+       {HPHW_NPROC,0x184,0x4,0x91,"Jade 180 U (893,T540)"},
+       {HPHW_NPROC,0x1FF,0x4,0x91,"Hitachi X Processor"},
+       {HPHW_NPROC,0x200,0x4,0x81,"Cobra (720)"},
+       {HPHW_NPROC,0x201,0x4,0x81,"Coral (750)"},
+       {HPHW_NPROC,0x202,0x4,0x81,"King Cobra (730)"},
+       {HPHW_NPROC,0x203,0x4,0x81,"Hardball (735/99)"},
+       {HPHW_NPROC,0x204,0x4,0x81,"Coral II (755/99)"},
+       {HPHW_NPROC,0x205,0x4,0x81,"Coral II (755/125)"},
+       {HPHW_NPROC,0x205,0x4,0x91,"Snake Eagle "},
+       {HPHW_NPROC,0x206,0x4,0x81,"Snake Cheetah (735/130)"},
+       {HPHW_NPROC,0x280,0x4,0x81,"Nova Low (817, 827, 957, 957LX)"},
+       {HPHW_NPROC,0x281,0x4,0x81,"Nova High (837, 847, 857, 967, 967LX)"},
+       {HPHW_NPROC,0x282,0x4,0x81,"Nova8 (807, 917, 917LX, 927,927LX, 937, 937LX, 947,947LX)"},
+       {HPHW_NPROC,0x283,0x4,0x81,"Nova64 (867, 877, 977)"},
+       {HPHW_NPROC,0x284,0x4,0x81,"TNova (887, 897, 987)"},
+       {HPHW_NPROC,0x285,0x4,0x81,"TNova64"},
+       {HPHW_NPROC,0x286,0x4,0x91,"Hydra64 (Nova)"},
+       {HPHW_NPROC,0x287,0x4,0x91,"Hydra96 (Nova)"},
+       {HPHW_NPROC,0x288,0x4,0x81,"TNova96"},
+       {HPHW_NPROC,0x300,0x4,0x81,"Bushmaster (710)"},
+       {HPHW_NPROC,0x302,0x4,0x81,"Flounder (705)"},
+       {HPHW_NPROC,0x310,0x4,0x81,"Scorpio (715/50)"},
+       {HPHW_NPROC,0x311,0x4,0x81,"Scorpio Jr.(715/33)"},
+       {HPHW_NPROC,0x312,0x4,0x81,"Strider-50 (715S/50)"},
+       {HPHW_NPROC,0x313,0x4,0x81,"Strider-33 (715S/33)"},
+       {HPHW_NPROC,0x314,0x4,0x81,"Trailways-50 (715T/50)"},
+       {HPHW_NPROC,0x315,0x4,0x81,"Trailways-33 (715T/33)"},
+       {HPHW_NPROC,0x316,0x4,0x81,"Scorpio Sr.(715/75)"},
+       {HPHW_NPROC,0x317,0x4,0x81,"Scorpio 100 (715/100)"},
+       {HPHW_NPROC,0x318,0x4,0x81,"Spectra (725/50)"},
+       {HPHW_NPROC,0x319,0x4,0x81,"Spectra (725/75)"},
+       {HPHW_NPROC,0x320,0x4,0x81,"Spectra (725/100)"},
+       {HPHW_NPROC,0x401,0x4,0x81,"Pace (745i, 747i)"},
+       {HPHW_NPROC,0x402,0x4,0x81,"Sidewinder (742i)"},
+       {HPHW_NPROC,0x403,0x4,0x81,"Fast Pace"},
+       {HPHW_NPROC,0x480,0x4,0x81,"Orville (E23)"},
+       {HPHW_NPROC,0x481,0x4,0x81,"Wilbur (E25)"},
+       {HPHW_NPROC,0x482,0x4,0x81,"WB-80 (E35)"},
+       {HPHW_NPROC,0x483,0x4,0x81,"WB-96 (E45)"},
+       {HPHW_NPROC,0x48,0x4,0x81,"UL Proc L-100 (811/D210,D310)"},
+       {HPHW_NPROC,0x48,0x4,0x81,"UL Proc L-75 (801/D200)"},
+       {HPHW_NPROC,0x501,0x4,0x81,"Merlin L2 132 (9000/778/B132L)"},
+       {HPHW_NPROC,0x502,0x4,0x81,"Merlin L2 160 (9000/778/B160L)"},
+       {HPHW_NPROC,0x503,0x4,0x81,"Merlin L2+ 132 (9000/778/B132L)"},
+       {HPHW_NPROC,0x504,0x4,0x81,"Merlin L2+ 180 (9000/778/B180L)"},
+       {HPHW_NPROC,0x505,0x4,0x81,"Raven L2 132 (9000/778/C132L)"},
+       {HPHW_NPROC,0x506,0x4,0x81,"Raven L2 160 (9000/779/C160L)"},
+       {HPHW_NPROC,0x507,0x4,0x81,"Raven L2 180 (9000/779/C180L)"},
+       {HPHW_NPROC,0x508,0x4,0x81,"Raven L2 160 (9000/779/C160L)"},
+       {HPHW_NPROC,0x509,0x4,0x81,"712/132 L2 Upgrade"},
+       {HPHW_NPROC,0x50A,0x4,0x81,"712/160 L2 Upgrade"},
+       {HPHW_NPROC,0x50B,0x4,0x81,"715/132 L2 Upgrade"},
+       {HPHW_NPROC,0x50C,0x4,0x81,"715/160 L2 Upgrade"},
+       {HPHW_NPROC,0x50D,0x4,0x81,"Rocky2 L2 120"},
+       {HPHW_NPROC,0x50E,0x4,0x81,"Rocky2 L2 150"},
+       {HPHW_NPROC,0x50F,0x4,0x81,"Anole L2 132 (744)"},
+       {HPHW_NPROC,0x510,0x4,0x81,"Anole L2 165 (744)"},
+       {HPHW_NPROC,0x511,0x4,0x81,"Kiji L2 132"},
+       {HPHW_NPROC,0x512,0x4,0x81,"UL L2 132 (803/D220,D320)"},
+       {HPHW_NPROC,0x513,0x4,0x81,"UL L2 160 (813/D220,D320)"},
+       {HPHW_NPROC,0x514,0x4,0x81,"Merlin Jr L2 132"},
+       {HPHW_NPROC,0x515,0x4,0x81,"Staccato L2 132"},
+       {HPHW_NPROC,0x516,0x4,0x81,"Staccato L2 180 (A Class 180)"},
+       {HPHW_NPROC,0x580,0x4,0x81,"KittyHawk DC2-100 (K100)"},
+       {HPHW_NPROC,0x581,0x4,0x91,"KittyHawk DC3-120 (K210)"},
+       {HPHW_NPROC,0x582,0x4,0x91,"KittyHawk DC3 100 (K400)"},
+       {HPHW_NPROC,0x583,0x4,0x91,"KittyHawk DC3 120 (K410)"},
+       {HPHW_NPROC,0x584,0x4,0x91,"LighteningHawk T120"},
+       {HPHW_NPROC,0x585,0x4,0x91,"SkyHawk 100"},
+       {HPHW_NPROC,0x586,0x4,0x91,"SkyHawk 120"},
+       {HPHW_NPROC,0x587,0x4,0x81,"UL Proc 1-way T'120"},
+       {HPHW_NPROC,0x588,0x4,0x91,"UL Proc 2-way T'120"},
+       {HPHW_NPROC,0x589,0x4,0x81,"UL Proc 1-way T'100 (821/D250,D350)"},
+       {HPHW_NPROC,0x58A,0x4,0x91,"UL Proc 2-way T'100 (831/D250,D350)"},
+       {HPHW_NPROC,0x58B,0x4,0x91,"KittyHawk DC2 100 (K200)"},
+       {HPHW_NPROC,0x58C,0x4,0x91,"ThunderHawk DC3- 120 1M (K220)"},
+       {HPHW_NPROC,0x58D,0x4,0x91,"ThunderHawk DC3 120 1M (K420)"},
+       {HPHW_NPROC,0x58E,0x4,0x81,"Raven 120 T'"},
+       {HPHW_NPROC,0x58F,0x4,0x91,"Mohawk 160 U 1M DC3 (K450)"},
+       {HPHW_NPROC,0x590,0x4,0x91,"Mohawk 180 U 1M DC3 (K460)"},
+       {HPHW_NPROC,0x591,0x4,0x91,"Mohawk 200 U 1M DC3"},
+       {HPHW_NPROC,0x592,0x4,0x81,"Raven 100 T'"},
+       {HPHW_NPROC,0x593,0x4,0x91,"FireHawk 160 U"},
+       {HPHW_NPROC,0x594,0x4,0x91,"FireHawk 180 U"},
+       {HPHW_NPROC,0x595,0x4,0x91,"FireHawk 220 U"},
+       {HPHW_NPROC,0x596,0x4,0x91,"FireHawk 240 U"},
+       {HPHW_NPROC,0x597,0x4,0x91,"SPP2000 processor"},
+       {HPHW_NPROC,0x598,0x4,0x81,"Raven U 230 (9000/780/C230)"},
+       {HPHW_NPROC,0x599,0x4,0x81,"Raven U 240 (9000/780/C240)"},
+       {HPHW_NPROC,0x59A,0x4,0x91,"Unlisted but reserved"},
+       {HPHW_NPROC,0x59A,0x4,0x81,"Unlisted but reserved"},
+       {HPHW_NPROC,0x59B,0x4,0x81,"Raven U 160 (9000/780/C160)"},
+       {HPHW_NPROC,0x59D,0x4,0x81,"Raven U 200 (9000/780/C200)"},
+       {HPHW_NPROC,0x59E,0x4,0x91,"ThunderHawk T' 120"},
+       {HPHW_NPROC,0x59F,0x4,0x91,"Raven U 180+ (9000/780/\?\?\?\?)"},
+       {HPHW_NPROC,0x5A0,0x4,0x81,"UL 1w T120 1MB/1MB (841/D260,D360)"},
+       {HPHW_NPROC,0x5A1,0x4,0x91,"UL 2w T120 1MB/1MB (851/D260,D360)"},
+       {HPHW_NPROC,0x5A2,0x4,0x81,"UL 1w U160 512K/512K (861/D270,D370)"},
+       {HPHW_NPROC,0x5A3,0x4,0x91,"UL 2w U160 512K/512K (871/D270,D370)"},
+       {HPHW_NPROC,0x5A4,0x4,0x91,"Mohawk 160 U 1M DC3- (K250)"},
+       {HPHW_NPROC,0x5A5,0x4,0x91,"Mohawk 180 U 1M DC3- (K260)"},
+       {HPHW_NPROC,0x5A6,0x4,0x91,"Mohawk 200 U 1M DC3-"},
+       {HPHW_NPROC,0x5A7,0x4,0x81,"UL proc 1-way U160 1M/1M"},
+       {HPHW_NPROC,0x5A8,0x4,0x91,"UL proc 2-way U160 1M/1M"},
+       {HPHW_NPROC,0x5A9,0x4,0x81,"UL proc 1-way U180 1M/1M"},
+       {HPHW_NPROC,0x5AA,0x4,0x91,"UL proc 2-way U180 1M/1M"},
+       {HPHW_NPROC,0x5AB,0x4,0x91,"Obsolete"},
+       {HPHW_NPROC,0x5AB,0x4,0x81,"Obsolete"},
+       {HPHW_NPROC,0x5AC,0x4,0x91,"Obsolete"},
+       {HPHW_NPROC,0x5AC,0x4,0x81,"Obsolete"},
+       {HPHW_NPROC,0x5AD,0x4,0x91,"BraveHawk 180MHz DC3-"},
+       {HPHW_NPROC,0x5AE,0x4,0x91,"BraveHawk 200MHz DC3- (898/K370)"},
+       {HPHW_NPROC,0x5AF,0x4,0x91,"BraveHawk 220MHz DC3-"},
+       {HPHW_NPROC,0x5B0,0x4,0x91,"BraveHawk 180MHz DC3"},
+       {HPHW_NPROC,0x5B1,0x4,0x91,"BraveHawk 200MHz DC3 (899/K570)"},
+       {HPHW_NPROC,0x5B2,0x4,0x91,"BraveHawk 220MHz DC3"},
+       {HPHW_NPROC,0x5B3,0x4,0x91,"FireHawk 200"},
+       {HPHW_NPROC,0x5B4,0x4,0x91,"SPP2500"},
+       {HPHW_NPROC,0x5B5,0x4,0x91,"SummitHawk U+"},
+       {HPHW_NPROC,0x5B6,0x4,0x91,"DragonHawk U+ 240 DC3"},
+       {HPHW_NPROC,0x5B7,0x4,0x91,"DragonHawk U+ 240 DC3-"},
+       {HPHW_NPROC,0x5B8,0x4,0x91,"SPP2250 240 MHz"},
+       {HPHW_NPROC,0x5B9,0x4,0x81,"UL 1w U+/240 (350/550)"},
+       {HPHW_NPROC,0x5BA,0x4,0x91,"UL 2w U+/240 (350/550)"},
+       {HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W "},
+       {HPHW_NPROC,0x5BC,0x4,0x91,"AllegroLow W"},
+       {HPHW_NPROC,0x5BD,0x4,0x91,"Forte W 2-way"},
+       {HPHW_NPROC,0x5BE,0x4,0x91,"Prelude W"},
+       {HPHW_NPROC,0x5BF,0x4,0x91,"Forte W 4-way"},
+       {HPHW_NPROC,0x5C0,0x4,0x91,"M2250"},
+       {HPHW_NPROC,0x5C1,0x4,0x91,"M2500"},
+       {HPHW_NPROC,0x5C2,0x4,0x91,"Sonata 440"},
+       {HPHW_NPROC,0x5C3,0x4,0x91,"Sonata 360"},
+       {HPHW_NPROC,0x5C4,0x4,0x91,"Rhapsody 440"},
+       {HPHW_NPROC,0x5C5,0x4,0x91,"Rhapsody 360"},
+       {HPHW_NPROC,0x5C6,0x4,0x91,"Raven W 360 (9000/780/\?\?\?\?)"},
+       {HPHW_NPROC,0x5C7,0x4,0x91,"Halfdome W 440"},
+       {HPHW_NPROC,0x5C8,0x4,0x81,"Lego 360 processor"},
+       {HPHW_NPROC,0x5C9,0x4,0x91,"Rhapsody DC- 440"},
+       {HPHW_NPROC,0x5CA,0x4,0x91,"Rhapsody DC- 360"},
+       {HPHW_NPROC,0x5CB,0x4,0x91,"Crescendo 440"},
+       {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
+       {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
+       {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
+       {HPHW_NPROC,0x602,0x4,0x81,"Gecko 100 (712/100)"},
+       {HPHW_NPROC,0x603,0x4,0x81,"Anole 64 (743/64)"},
+       {HPHW_NPROC,0x604,0x4,0x81,"Anole 100 (743/100)"},
+       {HPHW_NPROC,0x605,0x4,0x81,"Gecko 120 (712/120)"},
+       {HPHW_NPROC,0x606,0x4,0x81,"Gila 80"},
+       {HPHW_NPROC,0x607,0x4,0x81,"Gila 100"},
+       {HPHW_NPROC,0x608,0x4,0x81,"Gila 120"},
+       {HPHW_NPROC,0x609,0x4,0x81,"Scorpio-L 80"},
+       {HPHW_NPROC,0x60A,0x4,0x81,"Mirage Jr (715/64)"},
+       {HPHW_NPROC,0x60B,0x4,0x81,"Mirage 100"},
+       {HPHW_NPROC,0x60C,0x4,0x81,"Mirage 100+"},
+       {HPHW_NPROC,0x60D,0x4,0x81,"Electra 100"},
+       {HPHW_NPROC,0x60E,0x4,0x81,"Electra 120"},
+       {HPHW_NPROC,0x610,0x4,0x81,"Scorpio-L 100"},
+       {HPHW_NPROC,0x611,0x4,0x81,"Scorpio-L 120"},
+       {HPHW_NPROC,0x612,0x4,0x81,"Spectra-L 80"},
+       {HPHW_NPROC,0x613,0x4,0x81,"Spectra-L 100"},
+       {HPHW_NPROC,0x614,0x4,0x81,"Spectra-L 120"},
+       {HPHW_NPROC,0x615,0x4,0x81,"Piranha 100"},
+       {HPHW_NPROC,0x616,0x4,0x81,"Piranha 120"},
+       {HPHW_NPROC,0x617,0x4,0x81,"Jason 50"},
+       {HPHW_NPROC,0x618,0x4,0x81,"Jason 100"},
+       {HPHW_NPROC,0x619,0x4,0x81,"Mirage 80 "},
+       {HPHW_NPROC,0x61A,0x4,0x81,"SAIC L-80"},
+       {HPHW_NPROC,0x61B,0x4,0x81,"Rocky1 L-60"},
+       {HPHW_NPROC,0x61C,0x4,0x81,"Anole T (743/T)"},
+       {HPHW_NPROC,0x67E,0x4,0x81,"Hitachi Tiny 80"},
+       {HPHW_NPROC,0x67F,0x4,0x81,"Hitachi Tiny 64"},
+       {HPHW_NPROC,0x700,0x4,0x91,"NEC Aska Processor"},
+       {HPHW_A_DIRECT, 0x004, 0x0000D, 0x00, "Arrakis MUX"}, 
+       {HPHW_A_DIRECT, 0x005, 0x0000D, 0x00, "Dyun Kiuh MUX"}, 
+       {HPHW_A_DIRECT, 0x006, 0x0000D, 0x00, "Baat Kiuh AP/MUX (40299B)"}, 
+       {HPHW_A_DIRECT, 0x007, 0x0000D, 0x00, "Dino AP"}, 
+       {HPHW_A_DIRECT, 0x009, 0x0000D, 0x00, "Solaris Direct Connect MUX (J2092A)"}, 
+       {HPHW_A_DIRECT, 0x00A, 0x0000D, 0x00, "Solaris RS-422/423 MUX (J2093A)"}, 
+       {HPHW_A_DIRECT, 0x00B, 0x0000D, 0x00, "Solaris RS-422/423 Quadriloops MUX"}, 
+       {HPHW_A_DIRECT, 0x00C, 0x0000D, 0x00, "Solaris Modem MUX (J2094A)"}, 
+       {HPHW_A_DIRECT, 0x00D, 0x0000D, 0x00, "Twins Direct Connect MUX"}, 
+       {HPHW_A_DIRECT, 0x00E, 0x0000D, 0x00, "Twins Modem MUX"}, 
+       {HPHW_A_DIRECT, 0x00F, 0x0000D, 0x00, "Nautilus RS-485"}, 
+       {HPHW_A_DIRECT, 0x010, 0x0000D, 0x00, "UltraLight CAP/MUX"}, 
+       {HPHW_A_DIRECT, 0x015, 0x0000D, 0x00, "Eole CAP/MUX"}, 
+       {HPHW_A_DIRECT, 0x024, 0x0000D, 0x00, "Sahp Kiuh AP/MUX"}, 
+       {HPHW_A_DIRECT, 0x034, 0x0000D, 0x00, "Sahp Kiuh Low AP/MUX"}, 
+       {HPHW_A_DIRECT, 0x044, 0x0000D, 0x00, "Sahp Baat Kiuh AP/MUX"}, 
+       {HPHW_A_DIRECT, 0x004, 0x0000E, 0x80, "Burgundy RS-232"}, 
+       {HPHW_A_DIRECT, 0x005, 0x0000E, 0x80, "Silverfox RS-232"}, 
+       {HPHW_A_DIRECT, 0x006, 0x0000E, 0x80, "Lego RS-232"}, 
+       {HPHW_A_DIRECT, 0x004, 0x0000F, 0x00, "Peacock Graphics"}, 
+       {HPHW_A_DIRECT, 0x004, 0x00014, 0x80, "Burgundy HIL"}, 
+       {HPHW_A_DIRECT, 0x005, 0x00014, 0x80, "Peacock HIL"}, 
+       {HPHW_A_DIRECT, 0x004, 0x00015, 0x80, "Leonardo"}, 
+       {HPHW_A_DIRECT, 0x004, 0x00016, 0x80, "HP-PB HRM"}, 
+       {HPHW_A_DIRECT, 0x004, 0x00017, 0x80, "HP-PB HRC"}, 
+       {HPHW_A_DIRECT, 0x004, 0x0003A, 0x80, "Skunk Centronics (28655A)"}, 
+       {HPHW_A_DIRECT, 0x024, 0x0003A, 0x80, "Sahp Kiuh Centronics"}, 
+       {HPHW_A_DIRECT, 0x044, 0x0003A, 0x80, "Sahp Baat Kiuh Centronics"}, 
+       {HPHW_A_DIRECT, 0x004, 0x0004E, 0x80, "AT&T DataKit (AMSO)"}, 
+       {HPHW_A_DIRECT, 0x004, 0x0009B, 0x80, "Test&Meas GSC HPIB"}, 
+       {HPHW_A_DIRECT, 0x004, 0x000A8, 0x00, "Rocky2-120 Front Keyboard"}, 
+       {HPHW_A_DIRECT, 0x005, 0x000A8, 0x00, "Rocky2-150 Front Keyboard"}, 
+       {HPHW_A_DIRECT, 0x004, 0x00101, 0x80, "Hitachi Console Module"}, 
+       {HPHW_A_DIRECT, 0x004, 0x00102, 0x80, "Hitachi Boot Module"}, 
+       {HPHW_A_DIRECT, 0x004, 0x00203, 0x80, "MELCO HBMLA MLAIT"}, 
+       {HPHW_A_DIRECT, 0x004, 0x00208, 0x80, "MELCO HBDPC"}, 
+       {HPHW_A_DIRECT, 0x004, 0x00300, 0x00, "DCI TWINAX TERM IO MUX"}, 
+       {HPHW_A_DMA, 0x004, 0x00039, 0x80, "Skunk SCSI (28655A)"}, 
+       {HPHW_A_DMA, 0x005, 0x00039, 0x80, "KittyHawk CSY Core SCSI"}, 
+       {HPHW_A_DMA, 0x014, 0x00039, 0x80, "Diablo SCSI"}, 
+       {HPHW_A_DMA, 0x024, 0x00039, 0x80, "Sahp Kiuh SCSI"}, 
+       {HPHW_A_DMA, 0x034, 0x00039, 0x80, "Sahp Kiuh Low SCSI"}, 
+       {HPHW_A_DMA, 0x044, 0x00039, 0x80, "Sahp Baat Kiuh SCSI"}, 
+       {HPHW_A_DMA, 0x004, 0x0003B, 0x80, "Wizard SCSI"}, 
+       {HPHW_A_DMA, 0x005, 0x0003B, 0x80, "KittyHawk CSY Core FW-SCSI"}, 
+       {HPHW_A_DMA, 0x006, 0x0003B, 0x80, "Symbios EPIC FW-SCSI"}, 
+       {HPHW_A_DMA, 0x004, 0x00040, 0x80, "HP-PB Shazam HPIB (28650A)"}, 
+       {HPHW_A_DMA, 0x005, 0x00040, 0x80, "Burgundy HPIB"}, 
+       {HPHW_A_DMA, 0x004, 0x00041, 0x80, "HP-PB HP-FL"}, 
+       {HPHW_A_DMA, 0x004, 0x00042, 0x80, "HP-PB LoQuix HPIB (28650B)"}, 
+       {HPHW_A_DMA, 0x004, 0x00043, 0x80, "HP-PB Crypt LoQuix"}, 
+       {HPHW_A_DMA, 0x004, 0x00044, 0x80, "HP-PB Shazam GPIO (28651A)"}, 
+       {HPHW_A_DMA, 0x004, 0x00045, 0x80, "HP-PB LoQuix GPIO"}, 
+       {HPHW_A_DMA, 0x004, 0x00046, 0x80, "2-Port X.25 NIO_ACC (AMSO)"}, 
+       {HPHW_A_DMA, 0x004, 0x00047, 0x80, "4-Port X.25 NIO_ACC (AMSO)"}, 
+       {HPHW_A_DMA, 0x004, 0x0004B, 0x80, "LGB Control"}, 
+       {HPHW_A_DMA, 0x004, 0x0004C, 0x80, "Martian RTI (AMSO)"}, 
+       {HPHW_A_DMA, 0x004, 0x0004D, 0x80, "ACC Mux (AMSO)"}, 
+       {HPHW_A_DMA, 0x004, 0x00050, 0x80, "Lanbrusca 802.3 (36967A)"}, 
+       {HPHW_A_DMA, 0x004, 0x00056, 0x80, "HP-PB LoQuix FDDI"}, 
+       {HPHW_A_DMA, 0x004, 0x00057, 0x80, "HP-PB LoQuix FDDI (28670A)"}, 
+       {HPHW_A_DMA, 0x012, 0x00089, 0x80, "Barracuda Add-on FW-SCSI"}, 
+       {HPHW_A_DMA, 0x013, 0x00089, 0x80, "Bluefish Add-on FW-SCSI"}, 
+       {HPHW_A_DMA, 0x014, 0x00089, 0x80, "Shrike Add-on FW-SCSI"}, 
+       {HPHW_A_DMA, 0x015, 0x00089, 0x80, "KittyHawk GSY Core FW-SCSI"}, 
+       {HPHW_A_DMA, 0x017, 0x00089, 0x80, "Shrike Jade Add-on FW-SCSI (A3644A)"}, 
+       {HPHW_A_DMA, 0x01F, 0x00089, 0x80, "SkyHawk 100/120 FW-SCSI"}, 
+       {HPHW_A_DMA, 0x027, 0x00089, 0x80, "Piranha 100 FW-SCSI"}, 
+       {HPHW_A_DMA, 0x032, 0x00089, 0x80, "Raven T' Core FW-SCSI"}, 
+       {HPHW_A_DMA, 0x03d, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"},
+       {HPHW_A_DMA, 0x044, 0x00089, 0x80, "Mohawk Core FW-SCSI"}, 
+       {HPHW_A_DMA, 0x051, 0x00089, 0x80, "Firehawk FW-SCSI"}, 
+       {HPHW_A_DMA, 0x058, 0x00089, 0x80, "FireHawk 200 FW-SCSI"}, 
+       {HPHW_A_DMA, 0x05C, 0x00089, 0x80, "SummitHawk 230 Ultra-SCSI"}, 
+       {HPHW_A_DMA, 0x014, 0x00091, 0x80, "Baby Hugo Add-on Net FC (A3406A)"}, 
+       {HPHW_A_DMA, 0x020, 0x00091, 0x80, "Baby Jade Add-on Net FC (A3638A)"}, 
+       {HPHW_A_DMA, 0x004, 0x00092, 0x80, "GSC+ YLIASTER ATM"}, 
+       {HPHW_A_DMA, 0x004, 0x00095, 0x80, "Hamlyn GSC+ Network Card"}, 
+       {HPHW_A_DMA, 0x004, 0x00098, 0x80, "Lo-fat Emulator"}, 
+       {HPHW_A_DMA, 0x004, 0x0009A, 0x80, "GSC+ Venus ATM"}, 
+       {HPHW_A_DMA, 0x005, 0x0009A, 0x80, "GSC+ Samorobrive ATM"}, 
+       {HPHW_A_DMA, 0x004, 0x0009D, 0x80, "HP HSC-PCI Cards"}, 
+       {HPHW_A_DMA, 0x004, 0x0009E, 0x80, "Alaxis GSC+ 155Mb ATM"}, 
+       {HPHW_A_DMA, 0x005, 0x0009E, 0x80, "Alaxis GSC+ 622Mb ATM"}, 
+       {HPHW_A_DMA, 0x05C, 0x0009F, 0x80, "SummitHawk 230 USB"}, 
+       {HPHW_A_DMA, 0x05C, 0x000A0, 0x80, "SummitHawk 230 100BaseT"}, 
+       {HPHW_A_DMA, 0x015, 0x000A7, 0x80, "Baby Hugo Add-on mass FC (A3404A)"}, 
+       {HPHW_A_DMA, 0x018, 0x000A7, 0x80, "Mombasa GS Add-on mass FC (A3591)"}, 
+       {HPHW_A_DMA, 0x021, 0x000A7, 0x80, "Baby Jade Add-on mass FC (A3636A)"}, 
+       {HPHW_A_DMA, 0x004, 0x00201, 0x80, "MELCO HCMAP"}, 
+       {HPHW_A_DMA, 0x004, 0x00202, 0x80, "MELCO HBMLA MLAMA"}, 
+       {HPHW_A_DMA, 0x004, 0x00205, 0x80, "MELCO HBRFU"}, 
+       {HPHW_A_DMA, 0x004, 0x00380, 0x80, "Interphase NIO-FC"}, 
+       {HPHW_A_DMA, 0x004, 0x00381, 0x80, "Interphase NIO-ATM"}, 
+       {HPHW_A_DMA, 0x004, 0x00382, 0x80, "Interphase NIO-100BaseTX"}, 
+       {HPHW_BA, 0x004, 0x00070, 0x0, "Cobra Core BA"}, 
+       {HPHW_BA, 0x005, 0x00070, 0x0, "Coral Core BA"}, 
+       {HPHW_BA, 0x006, 0x00070, 0x0, "Bushmaster Core BA"}, 
+       {HPHW_BA, 0x007, 0x00070, 0x0, "Scorpio Core BA"}, 
+       {HPHW_BA, 0x008, 0x00070, 0x0, "Flounder Core BA"}, 
+       {HPHW_BA, 0x009, 0x00070, 0x0, "Outfield Core BA"}, 
+       {HPHW_BA, 0x00A, 0x00070, 0x0, "CoralII Core BA"}, 
+       {HPHW_BA, 0x00B, 0x00070, 0x0, "Scorpio Jr. Core BA"}, 
+       {HPHW_BA, 0x00C, 0x00070, 0x0, "Strider-50 Core BA"}, 
+       {HPHW_BA, 0x00D, 0x00070, 0x0, "Strider-33 Core BA"}, 
+       {HPHW_BA, 0x00E, 0x00070, 0x0, "Trailways-50 Core BA"}, 
+       {HPHW_BA, 0x00F, 0x00070, 0x0, "Trailways-33 Core BA"}, 
+       {HPHW_BA, 0x010, 0x00070, 0x0, "Pace Core BA"}, 
+       {HPHW_BA, 0x011, 0x00070, 0x0, "Sidewinder Core BA"}, 
+       {HPHW_BA, 0x019, 0x00070, 0x0, "Scorpio Sr. Core BA"}, 
+       {HPHW_BA, 0x020, 0x00070, 0x0, "Scorpio 100 Core BA"}, 
+       {HPHW_BA, 0x021, 0x00070, 0x0, "Spectra 50 Core BA"}, 
+       {HPHW_BA, 0x022, 0x00070, 0x0, "Spectra 75 Core BA"}, 
+       {HPHW_BA, 0x023, 0x00070, 0x0, "Spectra 100 Core BA"}, 
+       {HPHW_BA, 0x024, 0x00070, 0x0, "Fast Pace Core BA"}, 
+       {HPHW_BA, 0x026, 0x00070, 0x0, "CoralII Jaguar Core BA"}, 
+       {HPHW_BA, 0x004, 0x00076, 0x0, "Cobra EISA BA"}, 
+       {HPHW_BA, 0x005, 0x00076, 0x0, "Coral EISA BA"}, 
+       {HPHW_BA, 0x007, 0x00076, 0x0, "Scorpio EISA BA"}, 
+       {HPHW_BA, 0x00A, 0x00076, 0x0, "CoralII EISA BA"}, 
+       {HPHW_BA, 0x00B, 0x00076, 0x0, "Scorpio Jr. EISA BA"}, 
+       {HPHW_BA, 0x00C, 0x00076, 0x0, "Strider-50 Core EISA"}, 
+       {HPHW_BA, 0x00D, 0x00076, 0x0, "Strider-33 Core EISA"}, 
+       {HPHW_BA, 0x00E, 0x00076, 0x0, "Trailways-50 Core EISA"}, 
+       {HPHW_BA, 0x00F, 0x00076, 0x0, "Trailways-33 Core EISA"}, 
+       {HPHW_BA, 0x010, 0x00076, 0x0, "Pace Core EISA"}, 
+       {HPHW_BA, 0x019, 0x00076, 0x0, "Scorpio Sr. EISA BA"}, 
+       {HPHW_BA, 0x020, 0x00076, 0x0, "Scorpio 100 EISA BA"}, 
+       {HPHW_BA, 0x021, 0x00076, 0x0, "Spectra 50 EISA BA"}, 
+       {HPHW_BA, 0x022, 0x00076, 0x0, "Spectra 75 EISA BA"}, 
+       {HPHW_BA, 0x023, 0x00076, 0x0, "Spectra 100 EISA BA"}, 
+       {HPHW_BA, 0x026, 0x00076, 0x0, "CoralII Jaguar EISA BA"}, 
+       {HPHW_BA, 0x010, 0x00078, 0x0, "Pace VME BA"}, 
+       {HPHW_BA, 0x011, 0x00078, 0x0, "Sidewinder VME BA"}, 
+       {HPHW_BA, 0x01A, 0x00078, 0x0, "Anole 64 VME BA"}, 
+       {HPHW_BA, 0x01B, 0x00078, 0x0, "Anole 100 VME BA"}, 
+       {HPHW_BA, 0x024, 0x00078, 0x0, "Fast Pace VME BA"}, 
+       {HPHW_BA, 0x034, 0x00078, 0x0, "Anole T VME BA"}, 
+       {HPHW_BA, 0x04A, 0x00078, 0x0, "Anole L2 132 BME BA"}, 
+       {HPHW_BA, 0x04C, 0x00078, 0x0, "Anole L2 165 VME BA"}, 
+       {HPHW_BA, 0x011, 0x00081, 0x0, "WB-96 Core BA"}, 
+       {HPHW_BA, 0x012, 0x00081, 0x0, "Orville UX Core BA"}, 
+       {HPHW_BA, 0x013, 0x00081, 0x0, "Wilbur UX Core BA"}, 
+       {HPHW_BA, 0x014, 0x00081, 0x0, "WB-80 Core BA"}, 
+       {HPHW_BA, 0x015, 0x00081, 0x0, "KittyHawk GSY Core BA"}, 
+       {HPHW_BA, 0x016, 0x00081, 0x0, "Gecko Core BA"}, 
+       {HPHW_BA, 0x018, 0x00081, 0x0, "Gecko Optional BA"}, 
+       {HPHW_BA, 0x01A, 0x00081, 0x0, "Anole 64 Core BA"}, 
+       {HPHW_BA, 0x01B, 0x00081, 0x0, "Anole 100 Core BA"}, 
+       {HPHW_BA, 0x01C, 0x00081, 0x0, "Gecko 80 Core BA"}, 
+       {HPHW_BA, 0x01D, 0x00081, 0x0, "Gecko 100 Core BA"}, 
+       {HPHW_BA, 0x01F, 0x00081, 0x0, "SkyHawk 100/120 Core BA"}, 
+       {HPHW_BA, 0x027, 0x00081, 0x0, "Piranha 100 Core BA"}, 
+       {HPHW_BA, 0x028, 0x00081, 0x0, "Mirage Jr Core BA"}, 
+       {HPHW_BA, 0x029, 0x00081, 0x0, "Mirage Core BA"}, 
+       {HPHW_BA, 0x02A, 0x00081, 0x0, "Electra Core BA"}, 
+       {HPHW_BA, 0x02B, 0x00081, 0x0, "Mirage 80 Core BA"}, 
+       {HPHW_BA, 0x02C, 0x00081, 0x0, "Mirage 100+ Core BA"}, 
+       {HPHW_BA, 0x02E, 0x00081, 0x0, "UL 350 Lasi Core BA"}, 
+       {HPHW_BA, 0x02F, 0x00081, 0x0, "UL 550 Lasi Core BA"}, 
+       {HPHW_BA, 0x032, 0x00081, 0x0, "Raven T' Core BA"}, 
+       {HPHW_BA, 0x033, 0x00081, 0x0, "Anole T Core BA"}, 
+       {HPHW_BA, 0x034, 0x00081, 0x0, "SAIC L-80 Core BA"}, 
+       {HPHW_BA, 0x035, 0x00081, 0x0, "PCX-L2 712/132 Core BA"}, 
+       {HPHW_BA, 0x036, 0x00081, 0x0, "PCX-L2 712/160 Core BA"}, 
+       {HPHW_BA, 0x03B, 0x00081, 0x0, "Raven U/L2 Core BA"}, 
+       {HPHW_BA, 0x03C, 0x00081, 0x0, "Merlin 132 Core BA"}, 
+       {HPHW_BA, 0x03D, 0x00081, 0x0, "Merlin 160 Core BA"}, 
+       {HPHW_BA, 0x03E, 0x00081, 0x0, "Merlin+ 132 Core BA"}, 
+       {HPHW_BA, 0x03F, 0x00081, 0x0, "Merlin+ 180 Core BA"}, 
+       {HPHW_BA, 0x044, 0x00081, 0x0, "Mohawk Core BA"}, 
+       {HPHW_BA, 0x045, 0x00081, 0x0, "Rocky1 Core BA"}, 
+       {HPHW_BA, 0x046, 0x00081, 0x0, "Rocky2 120 Core BA"}, 
+       {HPHW_BA, 0x047, 0x00081, 0x0, "Rocky2 150 Core BA"}, 
+       {HPHW_BA, 0x04B, 0x00081, 0x0, "Anole L2 132 Core BA"}, 
+       {HPHW_BA, 0x04D, 0x00081, 0x0, "Anole L2 165 Core BA"}, 
+       {HPHW_BA, 0x04E, 0x00081, 0x0, "Kiji L2 132 Core BA"}, 
+       {HPHW_BA, 0x050, 0x00081, 0x0, "Merlin Jr 132 Core BA"}, 
+       {HPHW_BA, 0x051, 0x00081, 0x0, "Firehawk Core BA"}, 
+       {HPHW_BA, 0x056, 0x00081, 0x0, "Raven+ w SE FWSCSI Core BA"}, 
+       {HPHW_BA, 0x057, 0x00081, 0x0, "Raven+ w Diff FWSCSI Core BA"}, 
+       {HPHW_BA, 0x058, 0x00081, 0x0, "FireHawk 200 Core BA"}, 
+       {HPHW_BA, 0x05C, 0x00081, 0x0, "SummitHawk 230 Core BA"}, 
+       {HPHW_BA, 0x05E, 0x00081, 0x0, "Staccato 132 Core BA"}, 
+       {HPHW_BA, 0x05E, 0x00081, 0x0, "Staccato 180 Core BA"}, 
+       {HPHW_BA, 0x05F, 0x00081, 0x0, "Staccato 180 Lasi"}, 
+       {HPHW_BA, 0x800, 0x00081, 0x0, "Hitachi Tiny 64 Core BA"}, 
+       {HPHW_BA, 0x801, 0x00081, 0x0, "Hitachi Tiny 80 Core BA"}, 
+       {HPHW_BA, 0x004, 0x0008B, 0x0, "Anole Optional PCMCIA BA"}, 
+       {HPHW_BA, 0x004, 0x0008E, 0x0, "GSC ITR Wax BA"}, 
+       {HPHW_BA, 0x011, 0x0008E, 0x0, "SuperPace Wax BA"}, 
+       {HPHW_BA, 0x012, 0x0008E, 0x0, "Mirage Jr Wax BA"}, 
+       {HPHW_BA, 0x013, 0x0008E, 0x0, "Mirage Wax BA"}, 
+       {HPHW_BA, 0x014, 0x0008E, 0x0, "Electra Wax BA"}, 
+       {HPHW_BA, 0x017, 0x0008E, 0x0, "Raven Backplane Wax BA"}, 
+       {HPHW_BA, 0x01E, 0x0008E, 0x0, "Raven T' Wax BA"}, 
+       {HPHW_BA, 0x01F, 0x0008E, 0x0, "SkyHawk Wax BA"}, 
+       {HPHW_BA, 0x023, 0x0008E, 0x0, "Rocky1 Wax BA"}, 
+       {HPHW_BA, 0x02B, 0x0008E, 0x0, "Mirage 80 Wax BA"}, 
+       {HPHW_BA, 0x02C, 0x0008E, 0x0, "Mirage 100+ Wax BA"}, 
+       {HPHW_BA, 0x030, 0x0008E, 0x0, "UL 350 Core Wax BA"}, 
+       {HPHW_BA, 0x031, 0x0008E, 0x0, "UL 550 Core Wax BA"}, 
+       {HPHW_BA, 0x034, 0x0008E, 0x0, "SAIC L-80 Wax BA"}, 
+       {HPHW_BA, 0x03A, 0x0008E, 0x0, "Merlin+ Wax BA"}, 
+       {HPHW_BA, 0x040, 0x0008E, 0x0, "Merlin 132 Wax BA"}, 
+       {HPHW_BA, 0x041, 0x0008E, 0x0, "Merlin 160 Wax BA"}, 
+       {HPHW_BA, 0x043, 0x0008E, 0x0, "Merlin 132/160 Wax BA"}, 
+       {HPHW_BA, 0x052, 0x0008E, 0x0, "Raven+ Hi Power Backplane w/EISA Wax BA"}, 
+       {HPHW_BA, 0x054, 0x0008E, 0x0, "Raven+ Lo Power Backplane w/EISA Wax BA"}, 
+       {HPHW_BA, 0x059, 0x0008E, 0x0, "FireHawk 200 Wax BA"}, 
+       {HPHW_BA, 0x05A, 0x0008E, 0x0, "Raven+ L2 Backplane w/EISA Wax BA"}, 
+       {HPHW_BA, 0x05D, 0x0008E, 0x0, "SummitHawk Wax BA"}, 
+       {HPHW_BA, 0x800, 0x0008E, 0x0, "Hitachi Tiny 64 Wax BA"}, 
+       {HPHW_BA, 0x801, 0x0008E, 0x0, "Hitachi Tiny 80 Wax BA"}, 
+       {HPHW_BA, 0x011, 0x00090, 0x0, "SuperPace Wax EISA BA"}, 
+       {HPHW_BA, 0x017, 0x00090, 0x0, "Raven Backplane Wax EISA BA"}, 
+       {HPHW_BA, 0x01E, 0x00090, 0x0, "Raven T' Wax EISA BA"}, 
+       {HPHW_BA, 0x01F, 0x00090, 0x0, "SkyHawk 100/120 Wax EISA BA"}, 
+       {HPHW_BA, 0x027, 0x00090, 0x0, "Piranha 100 Wax EISA BA"}, 
+       {HPHW_BA, 0x028, 0x00090, 0x0, "Mirage Jr Wax EISA BA"}, 
+       {HPHW_BA, 0x029, 0x00090, 0x0, "Mirage Wax EISA BA"}, 
+       {HPHW_BA, 0x02A, 0x00090, 0x0, "Electra Wax EISA BA"}, 
+       {HPHW_BA, 0x02B, 0x00090, 0x0, "Mirage 80 Wax EISA BA"}, 
+       {HPHW_BA, 0x02C, 0x00090, 0x0, "Mirage 100+ Wax EISA BA"}, 
+       {HPHW_BA, 0x030, 0x00090, 0x0, "UL 350 Wax EISA BA"}, 
+       {HPHW_BA, 0x031, 0x00090, 0x0, "UL 550 Wax EISA BA"}, 
+       {HPHW_BA, 0x034, 0x00090, 0x0, "SAIC L-80 Wax EISA BA"}, 
+       {HPHW_BA, 0x03A, 0x00090, 0x0, "Merlin+ Wax EISA BA"}, 
+       {HPHW_BA, 0x040, 0x00090, 0x0, "Merlin 132 Wax EISA BA"}, 
+       {HPHW_BA, 0x041, 0x00090, 0x0, "Merlin 160 Wax EISA BA"}, 
+       {HPHW_BA, 0x043, 0x00090, 0x0, "Merlin 132/160 Wax EISA BA"}, 
+       {HPHW_BA, 0x052, 0x00090, 0x0, "Raven Hi Power Backplane Wax EISA BA"}, 
+       {HPHW_BA, 0x054, 0x00090, 0x0, "Raven Lo Power Backplane Wax EISA BA"}, 
+       {HPHW_BA, 0x059, 0x00090, 0x0, "FireHawk 200 Wax EISA BA"}, 
+       {HPHW_BA, 0x05A, 0x00090, 0x0, "Raven L2 Backplane Wax EISA BA"}, 
+       {HPHW_BA, 0x05D, 0x00090, 0x0, "SummitHawk Wax EISA BA"}, 
+       {HPHW_BA, 0x800, 0x00090, 0x0, "Hitachi Tiny 64 Wax EISA BA"}, 
+       {HPHW_BA, 0x801, 0x00090, 0x0, "Hitachi Tiny 80 Wax EISA BA"}, 
+       {HPHW_BA, 0x01A, 0x00093, 0x0, "Anole 64 TIMI BA"}, 
+       {HPHW_BA, 0x01B, 0x00093, 0x0, "Anole 64 TIMI BA"}, 
+       {HPHW_BA, 0x034, 0x00093, 0x0, "Anole T TIMI BA"}, 
+       {HPHW_BA, 0x04A, 0x00093, 0x0, "Anole L2 132 TIMI BA"}, 
+       {HPHW_BA, 0x04C, 0x00093, 0x0, "Anole L2 165 TIMI BA"}, 
+       {HPHW_BA, 0x582, 0x000A5, 0x00, "Epic PCI Bridge"}, 
+       {HPHW_BCPORT, 0x504, 0x00000, 0x00, "Phantom PseudoBC GSC+ Port"}, 
+       {HPHW_BCPORT, 0x505, 0x00000, 0x00, "Phantom PseudoBC GSC+ Port"}, 
+       {HPHW_BCPORT, 0x503, 0x0000C, 0x00, "Java BC GSC+ Port"}, 
+       {HPHW_BCPORT, 0x57F, 0x0000C, 0x00, "Hitachi Ghostview GSC+ Port"}, 
+       {HPHW_BCPORT, 0x501, 0x0000C, 0x00, "U2-IOA BC GSC+ Port"}, 
+       {HPHW_BCPORT, 0x502, 0x0000C, 0x00, "Uturn-IOA BC GSC+ Port"}, 
+       {HPHW_BCPORT, 0x780, 0x0000C, 0x00, "Astro BC Ropes Port"}, 
+       {HPHW_BCPORT, 0x506, 0x0000C, 0x00, "NEC-IOS BC HSC Port"}, 
+       {HPHW_BCPORT, 0x004, 0x0000C, 0x00, "Cheetah BC SMB Port"}, 
+       {HPHW_BCPORT, 0x006, 0x0000C, 0x00, "Cheetah BC MID_BUS Port"}, 
+       {HPHW_BCPORT, 0x005, 0x0000C, 0x00, "Condor BC MID_BUS Port"}, 
+       {HPHW_BCPORT, 0x100, 0x0000C, 0x00, "Condor BC HP-PB Port"}, 
+       {HPHW_BCPORT, 0x184, 0x0000C, 0x00, "Summit BC Port"}, 
+       {HPHW_BCPORT, 0x101, 0x0000C, 0x00, "Summit BC HP-PB Port"}, 
+       {HPHW_BCPORT, 0x102, 0x0000C, 0x00, "HP-PB Port (prefetch)"}, 
+       {HPHW_BCPORT, 0x500, 0x0000C, 0x00, "Gecko BOA BC GSC+ Port"}, 
+       {HPHW_BCPORT, 0x103, 0x0000C, 0x00, "Gecko BOA BC HP-PB Port"}, 
+       {HPHW_BCPORT, 0x507, 0x0000C, 0x00, "Keyaki BC GSC+ Port"}, 
+       {HPHW_BCPORT, 0x508, 0x0000C, 0x00, "Keyaki-DX BC GSC+ Port"}, 
+       {HPHW_BCPORT, 0x584, 0x0000C, 0x10, "DEW BC Runway Port"}, 
+       {HPHW_BCPORT, 0x800, 0x0000C, 0x10, "DEW BC Merced Port"}, 
+       {HPHW_BCPORT, 0x801, 0x0000C, 0x10, "SMC Bus Interface Merced Bus0"}, 
+       {HPHW_BCPORT, 0x802, 0x0000C, 0x10, "SMC Bus INterface Merced Bus1"}, 
+       {HPHW_BCPORT, 0x803, 0x0000C, 0x10, "IKE I/O Bus Converter Merced Port"}, 
+       {HPHW_BCPORT, 0x781, 0x0000C, 0x00, "IKE I/O Bus Converter Ropes Port"}, 
+       {HPHW_BCPORT, 0x804, 0x0000C, 0x10, "REO I/O Bus Converter Merced Port"}, 
+       {HPHW_BCPORT, 0x782, 0x0000C, 0x00, "REO I/O Bus Converter Ropes Port"}, 
+       {HPHW_BRIDGE, 0x680, 0x0000A, 0x00, "Dino PCI Bridge"}, 
+       {HPHW_BRIDGE, 0x682, 0x0000A, 0x00, "Cujo PCI Bridge"}, 
+       {HPHW_BRIDGE, 0x782, 0x0000A, 0x00, "Elroy PCI Bridge"}, 
+       {HPHW_BRIDGE, 0x583, 0x000A5, 0x00, "Saga PCI Bridge"}, 
+       {HPHW_B_DMA, 0x004, 0x00018, 0x00, "Parallel I/O"}, 
+       {HPHW_B_DMA, 0x004, 0x00019, 0x00, "Parallel RDB"}, 
+       {HPHW_B_DMA, 0x004, 0x00020, 0x80, "MID_BUS PSI"}, 
+       {HPHW_B_DMA, 0x004, 0x0002F, 0x80, "HP-PB Transit PSI (36960A)"}, 
+       {HPHW_B_DMA, 0x008, 0x00051, 0x80, "HP-PB Transit 802.3"}, 
+       {HPHW_B_DMA, 0x004, 0x00052, 0x80, "Miura LAN/Console (J2146A)"}, 
+       {HPHW_B_DMA, 0x008, 0x00058, 0x80, "HP-PB Transit 802.4"}, 
+       {HPHW_B_DMA, 0x005, 0x00060, 0x80, "KittyHawk CSY Core LAN/Console"}, 
+       {HPHW_B_DMA, 0x014, 0x00060, 0x80, "Diablo LAN/Console"}, 
+       {HPHW_B_DMA, 0x054, 0x00060, 0x80, "Countach LAN/Console"}, 
+       {HPHW_B_DMA, 0x004, 0x00094, 0x80, "KittyHawk GSC+ Exerciser"}, 
+       {HPHW_B_DMA, 0x004, 0x00100, 0x80, "HP-PB HF Interface"}, 
+       {HPHW_B_DMA, 0x000, 0x00206, 0x80, "MELCO HMPHA"}, 
+       {HPHW_B_DMA, 0x005, 0x00206, 0x80, "MELCO HMPHA_10"}, 
+       {HPHW_B_DMA, 0x006, 0x00206, 0x80, "MELCO HMQHA"}, 
+       {HPHW_B_DMA, 0x007, 0x00206, 0x80, "MELCO HMQHA_10"}, 
+       {HPHW_B_DMA, 0x004, 0x207, 0x80, "MELCO HNDWA MDWS-70"}, 
+       {HPHW_CIO, 0x004, 0x00010, 0x00, "VLSI CIO"}, 
+       {HPHW_CIO, 0x005, 0x00010, 0x00, "Silverfox CIO"}, 
+       {HPHW_CIO, 0x006, 0x00010, 0x00, "Emerald CIO"}, 
+       {HPHW_CIO, 0x008, 0x00010, 0x00, "Discrete CIO"}, 
+       {HPHW_CONSOLE, 0x004, 0x0001C, 0x00, "Cheetah console"}, 
+       {HPHW_CONSOLE, 0x005, 0x0001C, 0x00, "Emerald console"}, 
+       {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, 
+       {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, 
+       {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, 
+       {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, 
+       {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, 
+       {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, 
+       {HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"}, 
+       {HPHW_FIO, 0x004, 0x00071, 0x0, "Cobra Core SCSI"}, 
+       {HPHW_FIO, 0x005, 0x00071, 0x0, "Coral Core SCSI"}, 
+       {HPHW_FIO, 0x006, 0x00071, 0x0, "Bushmaster Core SCSI"}, 
+       {HPHW_FIO, 0x007, 0x00071, 0x0, "Scorpio Core SCSI"}, 
+       {HPHW_FIO, 0x008, 0x00071, 0x0, "Flounder Core SCSI"}, 
+       {HPHW_FIO, 0x009, 0x00071, 0x0, "Outfield Core SCSI"}, 
+       {HPHW_FIO, 0x00A, 0x00071, 0x0, "CoralII Core SCSI"}, 
+       {HPHW_FIO, 0x00B, 0x00071, 0x0, "Scorpio Jr. Core SCSI"}, 
+       {HPHW_FIO, 0x00C, 0x00071, 0x0, "Strider-50 Core SCSI"}, 
+       {HPHW_FIO, 0x00D, 0x00071, 0x0, "Strider-33 Core SCSI"}, 
+       {HPHW_FIO, 0x00E, 0x00071, 0x0, "Trailways-50 Core SCSI"}, 
+       {HPHW_FIO, 0x00F, 0x00071, 0x0, "Trailways-33 Core SCSI"}, 
+       {HPHW_FIO, 0x010, 0x00071, 0x0, "Pace Core SCSI"}, 
+       {HPHW_FIO, 0x011, 0x00071, 0x0, "Sidewinder Core SCSI"}, 
+       {HPHW_FIO, 0x019, 0x00071, 0x0, "Scorpio Sr. Core SCSI"}, 
+       {HPHW_FIO, 0x020, 0x00071, 0x0, "Scorpio 100 Core SCSI"}, 
+       {HPHW_FIO, 0x021, 0x00071, 0x0, "Spectra 50 Core SCSI"}, 
+       {HPHW_FIO, 0x022, 0x00071, 0x0, "Spectra 75 Core SCSI"}, 
+       {HPHW_FIO, 0x023, 0x00071, 0x0, "Spectra 100 Core SCSI"}, 
+       {HPHW_FIO, 0x024, 0x00071, 0x0, "Fast Pace Core SCSI"}, 
+       {HPHW_FIO, 0x026, 0x00071, 0x0, "CoralII Jaguar Core SCSI"}, 
+       {HPHW_FIO, 0x004, 0x00072, 0x0, "Cobra Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x005, 0x00072, 0x0, "Coral Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x006, 0x00072, 0x0, "Bushmaster Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x007, 0x00072, 0x0, "Scorpio Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x008, 0x00072, 0x0, "Flounder Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x009, 0x00072, 0x0, "Outfield Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x00A, 0x00072, 0x0, "CoralII Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x00B, 0x00072, 0x0, "Scorpio Jr. Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x00C, 0x00072, 0x0, "Strider-50 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x00D, 0x00072, 0x0, "Strider-33 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x00E, 0x00072, 0x0, "Trailways-50 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x00F, 0x00072, 0x0, "Trailways-33 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x010, 0x00072, 0x0, "Pace Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x011, 0x00072, 0x0, "Sidewinder Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x019, 0x00072, 0x0, "Scorpio Sr. Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x020, 0x00072, 0x0, "Scorpio 100 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x021, 0x00072, 0x0, "Spectra 50 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x022, 0x00072, 0x0, "Spectra 75 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x023, 0x00072, 0x0, "Spectra 100 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x024, 0x00072, 0x0, "Fast Pace Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x026, 0x00072, 0x0, "CoralII Jaguar Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x004, 0x00073, 0x0, "Cobra Core HIL"}, 
+       {HPHW_FIO, 0x005, 0x00073, 0x0, "Coral Core HIL"}, 
+       {HPHW_FIO, 0x006, 0x00073, 0x0, "Bushmaster Core HIL"}, 
+       {HPHW_FIO, 0x007, 0x00073, 0x0, "Scorpio Core HIL"}, 
+       {HPHW_FIO, 0x008, 0x00073, 0x0, "Flounder Core HIL"}, 
+       {HPHW_FIO, 0x009, 0x00073, 0x0, "Outfield Core HIL"}, 
+       {HPHW_FIO, 0x00A, 0x00073, 0x0, "CoralII Core HIL"}, 
+       {HPHW_FIO, 0x00B, 0x00073, 0x0, "Scorpio Jr. Core HIL"}, 
+       {HPHW_FIO, 0x00C, 0x00073, 0x0, "Strider-50 Core HIL"}, 
+       {HPHW_FIO, 0x00D, 0x00073, 0x0, "Strider-33 Core HIL"}, 
+       {HPHW_FIO, 0x00E, 0x00073, 0x0, "Trailways-50 Core HIL"}, 
+       {HPHW_FIO, 0x00F, 0x00073, 0x0, "Trailways-33 Core HIL"}, 
+       {HPHW_FIO, 0x010, 0x00073, 0x0, "Pace Core HIL"}, 
+       {HPHW_FIO, 0x011, 0x00073, 0xcc, "SuperPace Wax HIL"}, 
+       {HPHW_FIO, 0x012, 0x00073, 0x0, "Mirage Jr Wax HIL"}, 
+       {HPHW_FIO, 0x013, 0x00073, 0x0, "Mirage 100 Wax HIL"}, 
+       {HPHW_FIO, 0x014, 0x00073, 0x0, "Electra Wax HIL"}, 
+       {HPHW_FIO, 0x017, 0x00073, 0x0, "Raven Backplane Wax HIL"}, 
+       {HPHW_FIO, 0x019, 0x00073, 0x0, "Scorpio Sr. Core HIL"}, 
+       {HPHW_FIO, 0x01E, 0x00073, 0x0, "Raven T' Wax HIL"}, 
+       {HPHW_FIO, 0x01F, 0x00073, 0x0, "SkyHawk 100/120 Wax HIL"}, 
+       {HPHW_FIO, 0x020, 0x00073, 0x0, "Scorpio 100 Core HIL"}, 
+       {HPHW_FIO, 0x021, 0x00073, 0x0, "Spectra 50 Core HIL"}, 
+       {HPHW_FIO, 0x022, 0x00073, 0x0, "Spectra 75 Core HIL"}, 
+       {HPHW_FIO, 0x023, 0x00073, 0x0, "Spectra 100 Core HIL"}, 
+       {HPHW_FIO, 0x024, 0x00073, 0x0, "Fast Pace Core HIL"}, 
+       {HPHW_FIO, 0x026, 0x00073, 0x0, "CoralII Jaguar Core HIL"}, 
+       {HPHW_FIO, 0x02B, 0x00073, 0x0, "Mirage 80 Wax HIL"}, 
+       {HPHW_FIO, 0x02C, 0x00073, 0x0, "Mirage 100+ Wax HIL"}, 
+       {HPHW_FIO, 0x03A, 0x00073, 0x0, "Merlin+ Wax HIL"}, 
+       {HPHW_FIO, 0x040, 0x00073, 0x0, "Merlin 132 Wax HIL"}, 
+       {HPHW_FIO, 0x041, 0x00073, 0x0, "Merlin 160 Wax HIL"}, 
+       {HPHW_FIO, 0x043, 0x00073, 0x0, "Merlin 132/160 Wax HIL"}, 
+       {HPHW_FIO, 0x052, 0x00073, 0x0, "Raven+ Hi Power Backplane w/EISA Wax HIL"}, 
+       {HPHW_FIO, 0x053, 0x00073, 0x0, "Raven+ Hi Power Backplane wo/EISA Wax HIL"}, 
+       {HPHW_FIO, 0x054, 0x00073, 0x0, "Raven+ Lo Power Backplane w/EISA Wax HIL"}, 
+       {HPHW_FIO, 0x055, 0x00073, 0x0, "Raven+ Lo Power Backplane wo/EISA Wax HIL"}, 
+       {HPHW_FIO, 0x059, 0x00073, 0x0, "FireHawk 200 Wax HIL"}, 
+       {HPHW_FIO, 0x05A, 0x00073, 0x0, "Raven+ L2 Backplane w/EISA Wax HIL"}, 
+       {HPHW_FIO, 0x05B, 0x00073, 0x0, "Raven+ L2 Backplane wo/EISA Wax HIL"}, 
+       {HPHW_FIO, 0x05D, 0x00073, 0x0, "SummitHawk Wax HIL"}, 
+       {HPHW_FIO, 0x800, 0x00073, 0x0, "Hitachi Tiny 64 Wax HIL"}, 
+       {HPHW_FIO, 0x801, 0x00073, 0x0, "Hitachi Tiny 80 Wax HIL"}, 
+       {HPHW_FIO, 0x004, 0x00074, 0x0, "Cobra Core Centronics"}, 
+       {HPHW_FIO, 0x005, 0x00074, 0x0, "Coral Core Centronics"}, 
+       {HPHW_FIO, 0x006, 0x00074, 0x0, "Bushmaster Core Centronics"}, 
+       {HPHW_FIO, 0x007, 0x00074, 0x0, "Scorpio Core Centronics"}, 
+       {HPHW_FIO, 0x008, 0x00074, 0x0, "Flounder Core Centronics"}, 
+       {HPHW_FIO, 0x009, 0x00074, 0x0, "Outfield Core Centronics"}, 
+       {HPHW_FIO, 0x00A, 0x00074, 0x0, "CoralII Core Centronics"}, 
+       {HPHW_FIO, 0x00B, 0x00074, 0x0, "Scorpio Jr. Core Centronics"}, 
+       {HPHW_FIO, 0x00C, 0x00074, 0x0, "Strider-50 Core Centronics"}, 
+       {HPHW_FIO, 0x00D, 0x00074, 0x0, "Strider-33 Core Centronics"}, 
+       {HPHW_FIO, 0x00E, 0x00074, 0x0, "Trailways-50 Core Centronics"}, 
+       {HPHW_FIO, 0x00F, 0x00074, 0x0, "Trailways-33 Core Centronics"}, 
+       {HPHW_FIO, 0x010, 0x00074, 0x0, "Pace Core Centronics"}, 
+       {HPHW_FIO, 0x011, 0x00074, 0x0, "Sidewinder Core Centronics"}, 
+       {HPHW_FIO, 0x015, 0x00074, 0x0, "KittyHawk GSY Core Centronics"}, 
+       {HPHW_FIO, 0x016, 0x00074, 0x0, "Gecko Core Centronics"}, 
+       {HPHW_FIO, 0x019, 0x00074, 0x0, "Scorpio Sr. Core Centronics"}, 
+       {HPHW_FIO, 0x01A, 0x00074, 0x0, "Anole 64 Core Centronics"}, 
+       {HPHW_FIO, 0x01B, 0x00074, 0x0, "Anole 100 Core Centronics"}, 
+       {HPHW_FIO, 0x01C, 0x00074, 0x0, "Gecko 80 Core Centronics"}, 
+       {HPHW_FIO, 0x01D, 0x00074, 0x0, "Gecko 100 Core Centronics"}, 
+       {HPHW_FIO, 0x01F, 0x00074, 0x0, "SkyHawk 100/120 Core Centronics"}, 
+       {HPHW_FIO, 0x020, 0x00074, 0x0, "Scorpio 100 Core Centronics"}, 
+       {HPHW_FIO, 0x021, 0x00074, 0x0, "Spectra 50 Core Centronics"}, 
+       {HPHW_FIO, 0x022, 0x00074, 0x0, "Spectra 75 Core Centronics"}, 
+       {HPHW_FIO, 0x023, 0x00074, 0x0, "Spectra 100 Core Centronics"}, 
+       {HPHW_FIO, 0x024, 0x00074, 0x0, "Fast Pace Core Centronics"}, 
+       {HPHW_FIO, 0x026, 0x00074, 0x0, "CoralII Jaguar Core Centronics"}, 
+       {HPHW_FIO, 0x027, 0x00074, 0x0, "Piranha 100 Core Centronics"}, 
+       {HPHW_FIO, 0x028, 0x00074, 0x0, "Mirage Jr Core Centronics"}, 
+       {HPHW_FIO, 0x029, 0x00074, 0x0, "Mirage Core Centronics"}, 
+       {HPHW_FIO, 0x02A, 0x00074, 0x0, "Electra Core Centronics"}, 
+       {HPHW_FIO, 0x02B, 0x00074, 0x0, "Mirage 80 Core Centronics"}, 
+       {HPHW_FIO, 0x02C, 0x00074, 0x0, "Mirage 100+ Core Centronics"}, 
+       {HPHW_FIO, 0x02E, 0x00074, 0x0, "UL 350 Core Centronics"}, 
+       {HPHW_FIO, 0x02F, 0x00074, 0x0, "UL 550 Core Centronics"}, 
+       {HPHW_FIO, 0x032, 0x00074, 0x0, "Raven T' Core Centronics"}, 
+       {HPHW_FIO, 0x033, 0x00074, 0x0, "Anole T Core Centronics"}, 
+       {HPHW_FIO, 0x034, 0x00074, 0x0, "SAIC L-80 Core Centronics"}, 
+       {HPHW_FIO, 0x035, 0x00074, 0x0, "PCX-L2 712/132 Core Centronics"}, 
+       {HPHW_FIO, 0x036, 0x00074, 0x0, "PCX-L2 712/160 Core Centronics"}, 
+       {HPHW_FIO, 0x03B, 0x00074, 0x0, "Raven U/L2 Core Centronics"}, 
+       {HPHW_FIO, 0x03C, 0x00074, 0x0, "Merlin 132 Core Centronics"}, 
+       {HPHW_FIO, 0x03D, 0x00074, 0x0, "Merlin 160 Core Centronics"}, 
+       {HPHW_FIO, 0x03E, 0x00074, 0x0, "Merlin+ 132 Core Centronics"}, 
+       {HPHW_FIO, 0x03F, 0x00074, 0x0, "Merlin+ 180 Core Centronics"}, 
+       {HPHW_FIO, 0x044, 0x00074, 0x0, "Mohawk Core Centronics"}, 
+       {HPHW_FIO, 0x045, 0x00074, 0x0, "Rocky1 Core Centronics"}, 
+       {HPHW_FIO, 0x046, 0x00074, 0x0, "Rocky2 120 Core Centronics"}, 
+       {HPHW_FIO, 0x047, 0x00074, 0x0, "Rocky2 150 Core Centronics"}, 
+       {HPHW_FIO, 0x04B, 0x00074, 0x0, "Anole L2 132 Core Centronics"}, 
+       {HPHW_FIO, 0x04D, 0x00074, 0x0, "Anole L2 165 Core Centronics"}, 
+       {HPHW_FIO, 0x050, 0x00074, 0x0, "Merlin Jr 132 Core Centronics"}, 
+       {HPHW_FIO, 0x051, 0x00074, 0x0, "Firehawk Core Centronics"}, 
+       {HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ wSE FWSCSI Core Centronics"}, 
+       {HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ wDiff FWSCSI Core Centronics"}, 
+       {HPHW_FIO, 0x058, 0x00074, 0x0, "FireHawk 200 Core Centronics"}, 
+       {HPHW_FIO, 0x05C, 0x00074, 0x0, "SummitHawk 230 Core Centronics"}, 
+       {HPHW_FIO, 0x800, 0x00074, 0x0, "Hitachi Tiny 64 Core Centronics"}, 
+       {HPHW_FIO, 0x801, 0x00074, 0x0, "Hitachi Tiny 80 Core Centronics"}, 
+       {HPHW_FIO, 0x004, 0x00075, 0x0, "Cobra Core RS-232"}, 
+       {HPHW_FIO, 0x005, 0x00075, 0x0, "Coral Core RS-232"}, 
+       {HPHW_FIO, 0x006, 0x00075, 0x0, "Bushmaster Core RS-232"}, 
+       {HPHW_FIO, 0x007, 0x00075, 0x0, "Scorpio Core RS-232"}, 
+       {HPHW_FIO, 0x008, 0x00075, 0x0, "Flounder Core RS-232"}, 
+       {HPHW_FIO, 0x009, 0x00075, 0x0, "Outfield Core RS-232"}, 
+       {HPHW_FIO, 0x00A, 0x00075, 0x0, "CoralII Core RS-232"}, 
+       {HPHW_FIO, 0x00B, 0x00075, 0x0, "Scorpio Jr. Core RS-232"}, 
+       {HPHW_FIO, 0x00C, 0x00075, 0x0, "Strider-50 Core RS-232"}, 
+       {HPHW_FIO, 0x00D, 0x00075, 0x0, "Strider-33 Core RS-232"}, 
+       {HPHW_FIO, 0x00E, 0x00075, 0x0, "Trailways-50 Core RS-232"}, 
+       {HPHW_FIO, 0x00F, 0x00075, 0x0, "Trailways-33 Core RS-232"}, 
+       {HPHW_FIO, 0x010, 0x00075, 0x0, "Pace Core RS-232"}, 
+       {HPHW_FIO, 0x011, 0x00075, 0x0, "Sidewinder Core RS-232"}, 
+       {HPHW_FIO, 0x019, 0x00075, 0x0, "Scorpio Sr. Core RS-232"}, 
+       {HPHW_FIO, 0x020, 0x00075, 0x0, "Scorpio 100 Core RS-232"}, 
+       {HPHW_FIO, 0x021, 0x00075, 0x0, "Spectra 50 Core RS-232"}, 
+       {HPHW_FIO, 0x022, 0x00075, 0x0, "Spectra 75 Core RS-232"}, 
+       {HPHW_FIO, 0x023, 0x00075, 0x0, "Spectra 100 Core RS-232"}, 
+       {HPHW_FIO, 0x024, 0x00075, 0x0, "Fast Pace Core RS-232"}, 
+       {HPHW_FIO, 0x026, 0x00075, 0x0, "CoralII Jaguar Core RS-232"}, 
+       {HPHW_FIO, 0x004, 0x00077, 0x0, "Coral SGC Graphics"}, 
+       {HPHW_FIO, 0x005, 0x00077, 0x0, "Hyperdrive Optional Graphics"}, 
+       {HPHW_FIO, 0x006, 0x00077, 0x0, "Stinger Optional Graphics"}, 
+       {HPHW_FIO, 0x007, 0x00077, 0x0, "Scorpio Builtin Graphics"}, 
+       {HPHW_FIO, 0x008, 0x00077, 0x0, "Anole Hyperdrive Optional Graphics"}, 
+       {HPHW_FIO, 0x009, 0x00077, 0x0, "Thunder II graphics EISA form"}, 
+       {HPHW_FIO, 0x00A, 0x00077, 0x0, "Thunder II graphics GSA form"}, 
+       {HPHW_FIO, 0x00B, 0x00077, 0x0, "Scorpio Jr Builtin Graphics"}, 
+       {HPHW_FIO, 0x00C, 0x00077, 0x0, "Strider-50 SSC Graphics"}, 
+       {HPHW_FIO, 0x00D, 0x00077, 0x0, "Strider-33 SSC Graphics"}, 
+       {HPHW_FIO, 0x00E, 0x00077, 0x0, "Trailways-50 SSC Graphics"}, 
+       {HPHW_FIO, 0x00F, 0x00077, 0x0, "Trailways-33 SSC Graphics"}, 
+       {HPHW_FIO, 0x010, 0x00077, 0x0, "Pace SGC Graphics"}, 
+       {HPHW_FIO, 0x011, 0x00077, 0x0, "Mohawk Opt. 2D Graphics (Kid)"}, 
+       {HPHW_FIO, 0x012, 0x00077, 0x0, "Raven Opt. 2D Graphics (Goat)"}, 
+       {HPHW_FIO, 0x016, 0x00077, 0x0, "Lego 24 SCG Graphics"}, 
+       {HPHW_FIO, 0x017, 0x00077, 0x0, "Lego 24Z SCG Graphics"}, 
+       {HPHW_FIO, 0x018, 0x00077, 0x0, "Lego 48Z SCG Graphics"}, 
+       {HPHW_FIO, 0x019, 0x00077, 0x0, "Scorpio Sr Builtin Graphics"}, 
+       {HPHW_FIO, 0x020, 0x00077, 0x0, "Scorpio 100 Builtin Graphics"}, 
+       {HPHW_FIO, 0x021, 0x00077, 0x0, "Spectra 50 Builtin Graphics"}, 
+       {HPHW_FIO, 0x022, 0x00077, 0x0, "Spectra 75 Builtin Graphics"}, 
+       {HPHW_FIO, 0x023, 0x00077, 0x0, "Spectra 100 Builtin Graphics"}, 
+       {HPHW_FIO, 0x024, 0x00077, 0x0, "Fast Pace SGC Graphics"}, 
+       {HPHW_FIO, 0x006, 0x0007A, 0x0, "Bushmaster Audio"}, 
+       {HPHW_FIO, 0x008, 0x0007A, 0x0, "Flounder Audio"}, 
+       {HPHW_FIO, 0x004, 0x0007B, 0x0, "UL Optional Audio"}, 
+       {HPHW_FIO, 0x007, 0x0007B, 0x0, "Scorpio Audio"}, 
+       {HPHW_FIO, 0x00B, 0x0007B, 0x0, "Scorpio Jr. Audio"}, 
+       {HPHW_FIO, 0x00C, 0x0007B, 0x0, "Strider-50 Audio"}, 
+       {HPHW_FIO, 0x00D, 0x0007B, 0x0, "Strider-33 Audio"}, 
+       {HPHW_FIO, 0x00E, 0x0007B, 0x0, "Trailways-50 Audio"}, 
+       {HPHW_FIO, 0x00F, 0x0007B, 0x0, "Trailways-33 Audio"}, 
+       {HPHW_FIO, 0x016, 0x0007B, 0x0, "Gecko Audio"}, 
+       {HPHW_FIO, 0x019, 0x0007B, 0x0, "Scorpio Sr. Audio"}, 
+       {HPHW_FIO, 0x01A, 0x0007B, 0x0, "Anole 64 Audio"}, 
+       {HPHW_FIO, 0x01B, 0x0007B, 0x0, "Anole 100 Audio"}, 
+       {HPHW_FIO, 0x01C, 0x0007B, 0x0, "Gecko 80 Audio"}, 
+       {HPHW_FIO, 0x01D, 0x0007B, 0x0, "Gecko 100 Audio"}, 
+       {HPHW_FIO, 0x01F, 0x0007B, 0x0, "SkyHawk 100/120 Audio"}, 
+       {HPHW_FIO, 0x020, 0x0007B, 0x0, "Scorpio 100 Audio"}, 
+       {HPHW_FIO, 0x021, 0x0007B, 0x0, "Spectra 50 Audio"}, 
+       {HPHW_FIO, 0x022, 0x0007B, 0x0, "Spectra 75 Audio"}, 
+       {HPHW_FIO, 0x023, 0x0007B, 0x0, "Spectra 100 Audio"}, 
+       {HPHW_FIO, 0x028, 0x0007B, 0x0, "Mirage Jr Audio"}, 
+       {HPHW_FIO, 0x029, 0x0007B, 0x0, "Mirage Audio"}, 
+       {HPHW_FIO, 0x02A, 0x0007B, 0x0, "Electra Audio"}, 
+       {HPHW_FIO, 0x02B, 0x0007B, 0x0, "Mirage 80 Audio"}, 
+       {HPHW_FIO, 0x02C, 0x0007B, 0x0, "Mirage 100+ Audio"}, 
+       {HPHW_FIO, 0x032, 0x0007B, 0x0, "Raven T' Audio"}, 
+       {HPHW_FIO, 0x034, 0x0007B, 0x0, "SAIC L-80 Audio"}, 
+       {HPHW_FIO, 0x035, 0x0007B, 0x0, "PCX-L2 712/132 Core Audio"}, 
+       {HPHW_FIO, 0x036, 0x0007B, 0x0, "PCX-L2 712/160 Core Audio"}, 
+       {HPHW_FIO, 0x03B, 0x0007B, 0x0, "Raven U/L2 Core Audio"}, 
+       {HPHW_FIO, 0x03C, 0x0007B, 0x0, "Merlin 132 Core Audio"}, 
+       {HPHW_FIO, 0x03D, 0x0007B, 0x0, "Merlin 160 Core Audio"}, 
+       {HPHW_FIO, 0x03E, 0x0007B, 0x0, "Merlin+ 132 Core Audio"}, 
+       {HPHW_FIO, 0x03F, 0x0007B, 0x0, "Merlin+ 180 Core Audio"}, 
+       {HPHW_FIO, 0x044, 0x0007B, 0x0, "Mohawk Core Audio"}, 
+       {HPHW_FIO, 0x046, 0x0007B, 0x0, "Rocky2 120 Core Audio"}, 
+       {HPHW_FIO, 0x047, 0x0007B, 0x0, "Rocky2 150 Core Audio"}, 
+       {HPHW_FIO, 0x04B, 0x0007B, 0x0, "Anole L2 132 Core Audio"}, 
+       {HPHW_FIO, 0x04D, 0x0007B, 0x0, "Anole L2 165 Core Audio"}, 
+       {HPHW_FIO, 0x04E, 0x0007B, 0x0, "Kiji L2 132 Core Audio"}, 
+       {HPHW_FIO, 0x050, 0x0007B, 0x0, "Merlin Jr 132 Core Audio"}, 
+       {HPHW_FIO, 0x051, 0x0007B, 0x0, "Firehawk Audio"}, 
+       {HPHW_FIO, 0x056, 0x0007B, 0x0, "Raven+ w SE FWSCSU Core Audio"}, 
+       {HPHW_FIO, 0x057, 0x0007B, 0x0, "Raven+ w Diff FWSCSU Core Audio"}, 
+       {HPHW_FIO, 0x058, 0x0007B, 0x0, "FireHawk 200 Audio"}, 
+       {HPHW_FIO, 0x05C, 0x0007B, 0x0, "SummitHawk 230 Core Audio"}, 
+       {HPHW_FIO, 0x800, 0x0007B, 0x0, "Hitachi Tiny 64 Audio"}, 
+       {HPHW_FIO, 0x801, 0x0007B, 0x0, "Hitachi Tiny 80 Audio"}, 
+       {HPHW_FIO, 0x009, 0x0007C, 0x0, "Outfield FW SCSI"}, 
+       {HPHW_FIO, 0x00A, 0x0007C, 0x0, "CoralII FW SCSI"}, 
+       {HPHW_FIO, 0x026, 0x0007C, 0x0, "CoralII Jaguar FW SCSI"}, 
+       {HPHW_FIO, 0x009, 0x0007D, 0x0, "Outfield FDDI"}, 
+       {HPHW_FIO, 0x00A, 0x0007D, 0x0, "CoralII FDDI"}, 
+       {HPHW_FIO, 0x026, 0x0007D, 0x0, "CoralII Jaguar FDDI"}, 
+       {HPHW_FIO, 0x010, 0x0007E, 0x0, "Pace Audio"}, 
+       {HPHW_FIO, 0x024, 0x0007E, 0x0, "Fast Pace Audio"}, 
+       {HPHW_FIO, 0x009, 0x0007F, 0x0, "Outfield Audio"}, 
+       {HPHW_FIO, 0x00A, 0x0007F, 0x0, "CoralII Audio"}, 
+       {HPHW_FIO, 0x026, 0x0007F, 0x0, "CoralII Jaguar Audio"}, 
+       {HPHW_FIO, 0x010, 0x00080, 0x0, "Pace Core HPIB"}, 
+       {HPHW_FIO, 0x024, 0x00080, 0x0, "Fast Pace Core HPIB"}, 
+       {HPHW_FIO, 0x016, 0x00082, 0x0, "Gecko Core SCSI"}, 
+       {HPHW_FIO, 0x01A, 0x00082, 0x0, "Anole 64 Core SCSI"}, 
+       {HPHW_FIO, 0x01B, 0x00082, 0x0, "Anole 100 Core SCSI"}, 
+       {HPHW_FIO, 0x01C, 0x00082, 0x0, "Gecko 80 Core SCSI"}, 
+       {HPHW_FIO, 0x01D, 0x00082, 0x0, "Gecko 100 Core SCSI"}, 
+       {HPHW_FIO, 0x01F, 0x00082, 0x0, "SkyHawk 100/120 Core SCSI"}, 
+       {HPHW_FIO, 0x027, 0x00082, 0x0, "Piranha 100 Core SCSI"}, 
+       {HPHW_FIO, 0x028, 0x00082, 0x0, "Mirage Jr Core SCSI"}, 
+       {HPHW_FIO, 0x029, 0x00082, 0x0, "Mirage Core SCSI"}, 
+       {HPHW_FIO, 0x02A, 0x00082, 0x0, "Electra Core SCSI"}, 
+       {HPHW_FIO, 0x02B, 0x00082, 0x0, "Mirage 80 Core SCSI"}, 
+       {HPHW_FIO, 0x02C, 0x00082, 0x0, "Mirage 100+ Core SCSI"}, 
+       {HPHW_FIO, 0x02E, 0x00082, 0x0, "UL 350 Core SCSI"}, 
+       {HPHW_FIO, 0x02F, 0x00082, 0x0, "UL 550 Core SCSI"}, 
+       {HPHW_FIO, 0x032, 0x00082, 0x0, "Raven T' Core SCSI"}, 
+       {HPHW_FIO, 0x033, 0x00082, 0x0, "Anole T Core SCSI"}, 
+       {HPHW_FIO, 0x034, 0x00082, 0x0, "SAIC L-80 Core SCSI"}, 
+       {HPHW_FIO, 0x035, 0x00082, 0x0, "PCX-L2 712/132 Core SCSI"}, 
+       {HPHW_FIO, 0x036, 0x00082, 0x0, "PCX-L2 712/160 Core SCSI"}, 
+       {HPHW_FIO, 0x03B, 0x00082, 0x0, "Raven U/L2 Core SCSI"}, 
+       {HPHW_FIO, 0x03C, 0x00082, 0x0, "Merlin 132 Core SCSI"}, 
+       {HPHW_FIO, 0x03D, 0x00082, 0x0, "Merlin 160 Core SCSI"}, 
+       {HPHW_FIO, 0x03E, 0x00082, 0x0, "Merlin+ 132 Core SCSI"}, 
+       {HPHW_FIO, 0x03F, 0x00082, 0x0, "Merlin+ 180 Core SCSI"}, 
+       {HPHW_FIO, 0x044, 0x00082, 0x0, "Mohawk Core SCSI"}, 
+       {HPHW_FIO, 0x045, 0x00082, 0x0, "Rocky1 Core SCSI"}, 
+       {HPHW_FIO, 0x046, 0x00082, 0x0, "Rocky2 120 Core SCSI"}, 
+       {HPHW_FIO, 0x047, 0x00082, 0x0, "Rocky2 150 Core SCSI"}, 
+       {HPHW_FIO, 0x04B, 0x00082, 0x0, "Anole L2 132 Core SCSI"}, 
+       {HPHW_FIO, 0x04D, 0x00082, 0x0, "Anole L2 165 Core SCSI"}, 
+       {HPHW_FIO, 0x04E, 0x00082, 0x0, "Kiji L2 132 Core SCSI"}, 
+       {HPHW_FIO, 0x050, 0x00082, 0x0, "Merlin Jr 132 Core SCSI"}, 
+       {HPHW_FIO, 0x051, 0x00082, 0x0, "Firehawk Core SCSI"}, 
+       {HPHW_FIO, 0x056, 0x00082, 0x0, "Raven+ w SE FWSCSI Core SCSI"}, 
+       {HPHW_FIO, 0x057, 0x00082, 0x0, "Raven+ w Diff FWSCSI Core SCSI"}, 
+       {HPHW_FIO, 0x058, 0x00082, 0x0, "FireHawk 200 Core SCSI"}, 
+       {HPHW_FIO, 0x05C, 0x00082, 0x0, "SummitHawk 230 Core SCSI"}, 
+       {HPHW_FIO, 0x05E, 0x00082, 0x0, "Staccato 132 Core SCSI"}, 
+       {HPHW_FIO, 0x05F, 0x00082, 0x0, "Staccato 180 Core SCSI"}, 
+       {HPHW_FIO, 0x800, 0x00082, 0x0, "Hitachi Tiny 64 Core SCSI"}, 
+       {HPHW_FIO, 0x801, 0x00082, 0x0, "Hitachi Tiny 80 Core SCSI"}, 
+       {HPHW_FIO, 0x016, 0x00083, 0x0, "Gecko Core PC Floppy"}, 
+       {HPHW_FIO, 0x01C, 0x00083, 0x0, "Gecko 80 Core PC Floppy"}, 
+       {HPHW_FIO, 0x01D, 0x00083, 0x0, "Gecko 100 Core PC Floppy"}, 
+       {HPHW_FIO, 0x051, 0x00083, 0x0, "Firehawk Core PC Floppy"}, 
+       {HPHW_FIO, 0x058, 0x00083, 0x0, "FireHawk 200 Core PC Floppy"}, 
+       {HPHW_FIO, 0x027, 0x00083, 0x0, "Piranha 100 Core PC Floppy"}, 
+       {HPHW_FIO, 0x028, 0x00083, 0x0, "Mirage Jr Core PC Floppy"}, 
+       {HPHW_FIO, 0x029, 0x00083, 0x0, "Mirage Core PC Floppy"}, 
+       {HPHW_FIO, 0x02A, 0x00083, 0x0, "Electra Core PC Floppy"}, 
+       {HPHW_FIO, 0x02B, 0x00083, 0x0, "Mirage 80 Core PC Floppy"}, 
+       {HPHW_FIO, 0x02C, 0x00083, 0x0, "Mirage 100+ Core PC Floppy"}, 
+       {HPHW_FIO, 0x02E, 0x00083, 0x0, "UL 350 Core PC Floppy"}, 
+       {HPHW_FIO, 0x02F, 0x00083, 0x0, "UL 550 Core PC Floppy"}, 
+       {HPHW_FIO, 0x032, 0x00083, 0x0, "Raven T' Core PC Floppy"}, 
+       {HPHW_FIO, 0x034, 0x00083, 0x0, "SAIC L-80 Core PC Floopy"}, 
+       {HPHW_FIO, 0x035, 0x00083, 0x0, "PCX-L2 712/132 Core Floopy"}, 
+       {HPHW_FIO, 0x036, 0x00083, 0x0, "PCX-L2 712/160 Core Floopy"}, 
+       {HPHW_FIO, 0x03B, 0x00083, 0x0, "Raven U/L2 Core PC Floopy"}, 
+       {HPHW_FIO, 0x03C, 0x00083, 0x0, "Merlin 132 Core PC Floopy"}, 
+       {HPHW_FIO, 0x03D, 0x00083, 0x0, "Merlin 160 Core PC Floopy"}, 
+       {HPHW_FIO, 0x03E, 0x00083, 0x0, "Merlin+ 132 Core PC Floopy"}, 
+       {HPHW_FIO, 0x03F, 0x00083, 0x0, "Merlin+ 180 Core PC Floopy"}, 
+       {HPHW_FIO, 0x045, 0x00083, 0x0, "Rocky1 Core PC Floopy"}, 
+       {HPHW_FIO, 0x046, 0x00083, 0x0, "Rocky2 120 Core PC Floopy"}, 
+       {HPHW_FIO, 0x047, 0x00083, 0x0, "Rocky2 150 Core PC Floopy"}, 
+       {HPHW_FIO, 0x04E, 0x00083, 0x0, "Kiji L2 132 Core PC Floopy"}, 
+       {HPHW_FIO, 0x050, 0x00083, 0x0, "Merlin Jr 132 Core PC Floopy"}, 
+       {HPHW_FIO, 0x056, 0x00083, 0x0, "Raven+ w SE FWSCSI Core PC Floopy"}, 
+       {HPHW_FIO, 0x057, 0x00083, 0x0, "Raven+ w Diff FWSCSI Core PC Floopy"}, 
+       {HPHW_FIO, 0x800, 0x00083, 0x0, "Hitachi Tiny 64 Core PC Floopy"}, 
+       {HPHW_FIO, 0x801, 0x00083, 0x0, "Hitachi Tiny 80 Core PC Floopy"}, 
+       {HPHW_FIO, 0x015, 0x00084, 0x0, "KittyHawk GSY Core PC Keyboard"}, 
+       {HPHW_FIO, 0x016, 0x00084, 0x0, "Gecko Core PC Keyboard"}, 
+       {HPHW_FIO, 0x018, 0x00084, 0x0, "Gecko Optional PC Keyboard"}, 
+       {HPHW_FIO, 0x01A, 0x00084, 0x0, "Anole 64 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x01B, 0x00084, 0x0, "Anole 100 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x01C, 0x00084, 0x0, "Gecko 80 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x01D, 0x00084, 0x0, "Gecko 100 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x01F, 0x00084, 0x0, "SkyHawk 100/120 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x027, 0x00084, 0x0, "Piranha 100 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x028, 0x00084, 0x0, "Mirage Jr Core PC Keyboard"}, 
+       {HPHW_FIO, 0x029, 0x00084, 0x0, "Mirage Core PC Keyboard"}, 
+       {HPHW_FIO, 0x02A, 0x00084, 0x0, "Electra Core PC Keyboard"}, 
+       {HPHW_FIO, 0x02B, 0x00084, 0x0, "Mirage 80 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x02C, 0x00084, 0x0, "Mirage 100+ Core PC Keyboard"}, 
+       {HPHW_FIO, 0x02E, 0x00084, 0x0, "UL 350 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x02F, 0x00084, 0x0, "UL 550 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x032, 0x00084, 0x0, "Raven T' Core PC Keyboard"}, 
+       {HPHW_FIO, 0x033, 0x00084, 0x0, "Anole T Core PC Keyboard"}, 
+       {HPHW_FIO, 0x034, 0x00084, 0x0, "SAIC L-80 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x035, 0x00084, 0x0, "PCX-L2 712/132 Core Keyboard"}, 
+       {HPHW_FIO, 0x036, 0x00084, 0x0, "PCX-L2 712/160 Core Keyboard"}, 
+       {HPHW_FIO, 0x03B, 0x00084, 0x0, "Raven U/L2 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x03C, 0x00084, 0x0, "Merlin 132 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x03D, 0x00084, 0x0, "Merlin 160 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x03E, 0x00084, 0x0, "Merlin+ 132 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x03F, 0x00084, 0x0, "Merlin+ 180 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x044, 0x00084, 0x0, "Mohawk Core PC Keyboard"}, 
+       {HPHW_FIO, 0x045, 0x00084, 0x0, "Rocky1 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x046, 0x00084, 0x0, "Rocky2 120 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x047, 0x00084, 0x0, "Rocky2 150 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x048, 0x00084, 0x0, "Rocky2 120 Dino PC Keyboard"}, 
+       {HPHW_FIO, 0x049, 0x00084, 0x0, "Rocky2 150 Dino PC Keyboard"}, 
+       {HPHW_FIO, 0x04B, 0x00084, 0x0, "Anole L2 132 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x04D, 0x00084, 0x0, "Anole L2 165 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x04E, 0x00084, 0x0, "Kiji L2 132 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x050, 0x00084, 0x0, "Merlin Jr 132 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x051, 0x00084, 0x0, "Firehawk Core PC Keyboard"}, 
+       {HPHW_FIO, 0x056, 0x00084, 0x0, "Raven+ w SE FWSCSI Core PC Keyboard"}, 
+       {HPHW_FIO, 0x057, 0x00084, 0x0, "Raven+ w Diff FWSCSI Core PC Keyboard"}, 
+       {HPHW_FIO, 0x058, 0x00084, 0x0, "FireHawk 200 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x05C, 0x00084, 0x0, "SummitHawk 230 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x800, 0x00084, 0x0, "Hitachi Tiny 64 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x801, 0x00084, 0x0, "Hitachi Tiny 80 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x004, 0x00085, 0x0, "Solo GSC Optional Graphics"}, 
+       {HPHW_FIO, 0x005, 0x00085, 0x0, "Duet GSC Optional Graphics"}, 
+       {HPHW_FIO, 0x008, 0x00085, 0x0, "Anole Artist Optional Graphics"}, 
+       {HPHW_FIO, 0x010, 0x00085, 0x0, "Mirage 80 GSC Builtin Graphics"}, 
+       {HPHW_FIO, 0x011, 0x00085, 0x0, "Mirage 100+ GSC Builtin Graphics"}, 
+       {HPHW_FIO, 0x012, 0x00085, 0x0, "Mirage Jr GSC Builtin Graphics"}, 
+       {HPHW_FIO, 0x013, 0x00085, 0x0, "Mirage GSC Builtin Graphics"}, 
+       {HPHW_FIO, 0x014, 0x00085, 0x0, "Electra GSC Builtin Graphics"}, 
+       {HPHW_FIO, 0x016, 0x00085, 0x0, "Gecko GSC Core Graphics"}, 
+       {HPHW_FIO, 0x017, 0x00085, 0x0, "Gecko GSC Optional Graphics"}, 
+       {HPHW_FIO, 0x01A, 0x00085, 0x0, "Anole 64 Artist Builtin Graphics"}, 
+       {HPHW_FIO, 0x01B, 0x00085, 0x0, "Anole 100 Artist Builtin Graphics"}, 
+       {HPHW_FIO, 0x01C, 0x00085, 0x0, "Gecko 80 GSC Core Graphics"}, 
+       {HPHW_FIO, 0x01D, 0x00085, 0x0, "Gecko 100 GSC Core Graphics"}, 
+       {HPHW_FIO, 0x032, 0x00085, 0x0, "Raven T' GSC Core Graphics"}, 
+       {HPHW_FIO, 0x033, 0x00085, 0x0, "Anole T Artist Builtin Graphics"}, 
+       {HPHW_FIO, 0x034, 0x00085, 0x0, "SAIC L-80 GSC Core Graphics"}, 
+       {HPHW_FIO, 0x035, 0x00085, 0x0, "PCX-L2 712/132 Core Graphics"}, 
+       {HPHW_FIO, 0x036, 0x00085, 0x0, "PCX-L2 712/160 Core Graphics"}, 
+       {HPHW_FIO, 0x03B, 0x00085, 0x0, "Raven U/L2 Core Graphics"}, 
+       {HPHW_FIO, 0x03C, 0x00085, 0x0, "Merlin 132 Core Graphics"}, 
+       {HPHW_FIO, 0x03D, 0x00085, 0x0, "Merlin 160 Core Graphics"}, 
+       {HPHW_FIO, 0x03E, 0x00085, 0x0, "Merlin+ 132 Core Graphics"}, 
+       {HPHW_FIO, 0x03F, 0x00085, 0x0, "Merlin+ 180 Core Graphics"}, 
+       {HPHW_FIO, 0x045, 0x00085, 0x0, "Rocky1 Core Graphics"}, 
+       {HPHW_FIO, 0x046, 0x00085, 0x0, "Rocky2 120 Core Graphics"}, 
+       {HPHW_FIO, 0x047, 0x00085, 0x0, "Rocky2 150 Core Graphics"}, 
+       {HPHW_FIO, 0x04B, 0x00085, 0x0, "Anole L2 132 Core Graphics"}, 
+       {HPHW_FIO, 0x04D, 0x00085, 0x0, "Anole L2 165 Core Graphics"}, 
+       {HPHW_FIO, 0x04E, 0x00085, 0x0, "Kiji L2 132 Core Graphics"}, 
+       {HPHW_FIO, 0x050, 0x00085, 0x0, "Merlin Jr 132 Core Graphics"}, 
+       {HPHW_FIO, 0x056, 0x00085, 0x0, "Raven+ w SE FWSCSI Core Graphics"}, 
+       {HPHW_FIO, 0x057, 0x00085, 0x0, "Raven+ w Diff FWSCSI Core Graphics"}, 
+       {HPHW_FIO, 0x800, 0x00085, 0x0, "Hitachi Tiny 64 Core Graphics"}, 
+       {HPHW_FIO, 0x801, 0x00085, 0x0, "Hitachi Tiny 80 Core Graphics"}, 
+       {HPHW_FIO, 0x004, 0x00086, 0x0, "GSC IBM Token Ring"}, 
+       {HPHW_FIO, 0x015, 0x00087, 0x0, "Gecko Optional ISDN"}, 
+       {HPHW_FIO, 0x016, 0x00087, 0x0, "Gecko Core ISDN"}, 
+       {HPHW_FIO, 0x01C, 0x00087, 0x0, "Gecko 80 Core ISDN"}, 
+       {HPHW_FIO, 0x01D, 0x00087, 0x0, "Gecko 100 Core ISDN"}, 
+       {HPHW_FIO, 0x010, 0x00088, 0x0, "Pace VME Networking"}, 
+       {HPHW_FIO, 0x011, 0x00088, 0x0, "Sidewinder VME Networking"}, 
+       {HPHW_FIO, 0x01A, 0x00088, 0x0, "Anole 64 VME Networking"}, 
+       {HPHW_FIO, 0x01B, 0x00088, 0x0, "Anole 100 VME Networking"}, 
+       {HPHW_FIO, 0x024, 0x00088, 0x0, "Fast Pace VME Networking"}, 
+       {HPHW_FIO, 0x034, 0x00088, 0x0, "Anole T VME Networking"}, 
+       {HPHW_FIO, 0x04A, 0x00088, 0x0, "Anole L2 132 VME Networking"}, 
+       {HPHW_FIO, 0x04C, 0x00088, 0x0, "Anole L2 165 VME Networking"}, 
+       {HPHW_FIO, 0x03B, 0x00089, 0x0, "Raven U/L2 Core FW-SCSI"}, 
+       {HPHW_FIO, 0x011, 0x0008A, 0x0, "WB-96 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x012, 0x0008A, 0x0, "Orville Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x013, 0x0008A, 0x0, "Wilbur Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x014, 0x0008A, 0x0, "WB-80 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x015, 0x0008A, 0x0, "KittyHawk GSY Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x016, 0x0008A, 0x0, "Gecko Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x018, 0x0008A, 0x0, "Gecko Optional Lan (802.3)"}, 
+       {HPHW_FIO, 0x01A, 0x0008A, 0x0, "Anole 64 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x01B, 0x0008A, 0x0, "Anole 100 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x01C, 0x0008A, 0x0, "Gecko 80 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x01D, 0x0008A, 0x0, "Gecko 100 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x01F, 0x0008A, 0x0, "SkyHawk 100/120 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x027, 0x0008A, 0x0, "Piranha 100 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x028, 0x0008A, 0x0, "Mirage Jr Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x029, 0x0008A, 0x0, "Mirage Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x02A, 0x0008A, 0x0, "Electra Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x02B, 0x0008A, 0x0, "Mirage 80 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x02C, 0x0008A, 0x0, "Mirage 100+ Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x02E, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x02F, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x032, 0x0008A, 0x0, "Raven T' Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x033, 0x0008A, 0x0, "Anole T Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x034, 0x0008A, 0x0, "SAIC L-80 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x035, 0x0008A, 0x0, "PCX-L2 712/132 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x036, 0x0008A, 0x0, "PCX-L2 712/160 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x03B, 0x0008A, 0x0, "Raven U/L2 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x03C, 0x0008A, 0x0, "Merlin 132 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x03D, 0x0008A, 0x0, "Merlin 160 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x044, 0x0008A, 0x0, "Mohawk Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x045, 0x0008A, 0x0, "Rocky1 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x046, 0x0008A, 0x0, "Rocky2 120 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x047, 0x0008A, 0x0, "Rocky2 150 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x04B, 0x0008A, 0x0, "Anole L2 132 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x04D, 0x0008A, 0x0, "Anole L2 165 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x04E, 0x0008A, 0x0, "Kiji L2 132 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x050, 0x0008A, 0x0, "Merlin Jr 132 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x058, 0x0008A, 0x0, "FireHawk 200 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x800, 0x0008A, 0x0, "Hitachi Tiny 64 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x801, 0x0008A, 0x0, "Hitachi Tiny 80 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x004, 0x0008C, 0x0, "SkyHawk 100/120 Wax RS-232"}, 
+       {HPHW_FIO, 0x005, 0x0008C, 0x0, "SAIC L-80 Wax RS-232"}, 
+       {HPHW_FIO, 0x006, 0x0008C, 0x0, "Raven U/L2 Dino RS-232"}, 
+       {HPHW_FIO, 0x007, 0x0008C, 0x0, "Dino RS-232"}, 
+       {HPHW_FIO, 0x008, 0x0008C, 0x0, "Merlin 132 Dino RS-232"}, 
+       {HPHW_FIO, 0x009, 0x0008C, 0x0, "Merlin 160 Dino RS-232"}, 
+       {HPHW_FIO, 0x00A, 0x0008C, 0x0, "Merlin Jr 132 Dino RS-232"}, 
+       {HPHW_FIO, 0x010, 0x0008C, 0x0, "Mirage 80 Wax RS-232"}, 
+       {HPHW_FIO, 0x011, 0x0008C, 0x0, "Mirage 100+ Wax RS-232"}, 
+       {HPHW_FIO, 0x012, 0x0008C, 0x0, "Mirage Jr Wax RS-232"}, 
+       {HPHW_FIO, 0x013, 0x0008C, 0x0, "Mirage Wax RS-232"}, 
+       {HPHW_FIO, 0x014, 0x0008C, 0x0, "Electra Wax RS-232"}, 
+       {HPHW_FIO, 0x015, 0x0008C, 0x0, "KittyHawk GSY Core RS-232"}, 
+       {HPHW_FIO, 0x016, 0x0008C, 0x0, "Gecko Core RS-232"}, 
+       {HPHW_FIO, 0x017, 0x0008C, 0x0, "Raven Backplane RS-232"}, 
+       {HPHW_FIO, 0x018, 0x0008C, 0x0, "Gecko Optional RS-232"}, 
+       {HPHW_FIO, 0x019, 0x0008C, 0x0, "Merlin+ 180 Dino RS-232"}, 
+       {HPHW_FIO, 0x01A, 0x0008C, 0x0, "Anole 64 Core RS-232"}, 
+       {HPHW_FIO, 0x01B, 0x0008C, 0x0, "Anole 100 Core RS-232"}, 
+       {HPHW_FIO, 0x01C, 0x0008C, 0x0, "Gecko 80 Core RS-232"}, 
+       {HPHW_FIO, 0x01D, 0x0008C, 0x0, "Gecko 100 Core RS-232"}, 
+       {HPHW_FIO, 0x01E, 0x0008C, 0x0, "Raven T' Wax RS-232"}, 
+       {HPHW_FIO, 0x01F, 0x0008C, 0x0, "SkyHawk 100/120 Core RS-232"}, 
+       {HPHW_FIO, 0x020, 0x0008C, 0x0, "Anole 64 Timi RS-232"}, 
+       {HPHW_FIO, 0x021, 0x0008C, 0x0, "Anole 100 Timi RS-232"}, 
+       {HPHW_FIO, 0x022, 0x0008C, 0x0, "Merlin+ 132 Dino RS-232"}, 
+       {HPHW_FIO, 0x023, 0x0008C, 0x0, "Rocky1 Wax RS-232"}, 
+       {HPHW_FIO, 0x025, 0x0008C, 0x0, "Armyknife Optional RS-232"}, 
+       {HPHW_FIO, 0x026, 0x0008C, 0x0, "Piranha 100 Wax RS-232"}, 
+       {HPHW_FIO, 0x027, 0x0008C, 0x0, "Piranha 100 Core RS-232"}, 
+       {HPHW_FIO, 0x028, 0x0008C, 0x0, "Mirage Jr Core RS-232"}, 
+       {HPHW_FIO, 0x029, 0x0008C, 0x0, "Mirage Core RS-232"}, 
+       {HPHW_FIO, 0x02A, 0x0008C, 0x0, "Electra Core RS-232"}, 
+       {HPHW_FIO, 0x02B, 0x0008C, 0x0, "Mirage 80 Core RS-232"}, 
+       {HPHW_FIO, 0x02C, 0x0008C, 0x0, "Mirage 100+ Core RS-232"}, 
+       {HPHW_FIO, 0x02E, 0x0008C, 0x0, "UL 350 Lasi Core RS-232"}, 
+       {HPHW_FIO, 0x02F, 0x0008C, 0x0, "UL 550 Lasi Core RS-232"}, 
+       {HPHW_FIO, 0x030, 0x0008C, 0x0, "UL 350 Wax Core RS-232"}, 
+       {HPHW_FIO, 0x031, 0x0008C, 0x0, "UL 550 Wax Core RS-232"}, 
+       {HPHW_FIO, 0x032, 0x0008C, 0x0, "Raven T' Lasi Core RS-232"}, 
+       {HPHW_FIO, 0x033, 0x0008C, 0x0, "Anole T Core RS-232"}, 
+       {HPHW_FIO, 0x034, 0x0008C, 0x0, "SAIC L-80 Core RS-232"}, 
+       {HPHW_FIO, 0x035, 0x0008C, 0x0, "PCX-L2 712/132 Core RS-232"}, 
+       {HPHW_FIO, 0x036, 0x0008C, 0x0, "PCX-L2 712/160 Core RS-232"}, 
+       {HPHW_FIO, 0x03A, 0x0008C, 0x0, "Merlin+ Wax RS-232"}, 
+       {HPHW_FIO, 0x03B, 0x0008C, 0x0, "Raven U/L2 Core RS-232"}, 
+       {HPHW_FIO, 0x03C, 0x0008C, 0x0, "Merlin 132 Core RS-232"}, 
+       {HPHW_FIO, 0x03D, 0x0008C, 0x0, "Merlin 160 Core RS-232"}, 
+       {HPHW_FIO, 0x03E, 0x0008C, 0x0, "Merlin+ 132 Core RS-232"}, 
+       {HPHW_FIO, 0x03F, 0x0008C, 0x0, "Merlin+ 180 Core RS-232"}, 
+       {HPHW_FIO, 0x040, 0x0008C, 0x0, "Merlin 132 Wax RS-232"}, 
+       {HPHW_FIO, 0x041, 0x0008C, 0x0, "Merlin 160 Wax RS-232"}, 
+       {HPHW_FIO, 0x043, 0x0008C, 0x0, "Merlin 132/160 Wax RS-232"}, 
+       {HPHW_FIO, 0x044, 0x0008C, 0x0, "Mohawk Core RS-232"}, 
+       {HPHW_FIO, 0x045, 0x0008C, 0x0, "Rocky1 Core RS-232"}, 
+       {HPHW_FIO, 0x046, 0x0008C, 0x0, "Rocky2 120 Core RS-232"}, 
+       {HPHW_FIO, 0x047, 0x0008C, 0x0, "Rocky2 150 Core RS-232"}, 
+       {HPHW_FIO, 0x048, 0x0008C, 0x0, "Rocky2 120 Dino RS-232"}, 
+       {HPHW_FIO, 0x049, 0x0008C, 0x0, "Rocky2 150 Dino RS-232"}, 
+       {HPHW_FIO, 0x04A, 0x0008C, 0x0, "Anole L2 132 TIMI RS-232"}, 
+       {HPHW_FIO, 0x04B, 0x0008C, 0x0, "Anole L2 l32 Core RS-232"}, 
+       {HPHW_FIO, 0x04C, 0x0008D, 0x0, "Anole L2 165 TIMI RS-232"}, 
+       {HPHW_FIO, 0x04D, 0x0008C, 0x0, "Anole L2 165 Core RS-232"}, 
+       {HPHW_FIO, 0x04E, 0x0008C, 0x0, "Kiji L2 132 Core RS-232"}, 
+       {HPHW_FIO, 0x04F, 0x0008C, 0x0, "Kiji L2 132 Dino RS-232"}, 
+       {HPHW_FIO, 0x050, 0x0008C, 0x0, "Merlin Jr 132 Core RS-232"}, 
+       {HPHW_FIO, 0x051, 0x0008C, 0x0, "Firehawk Core RS-232"}, 
+       {HPHW_FIO, 0x052, 0x0008C, 0x0, "Raven+ Hi Power Backplane w EISA RS-232"}, 
+       {HPHW_FIO, 0x053, 0x0008C, 0x0, "Raven+ Hi Power Backplane w/o EISA RS-232"}, 
+       {HPHW_FIO, 0x054, 0x0008C, 0x0, "Raven+ Lo Power Backplane w EISA RS-232"}, 
+       {HPHW_FIO, 0x055, 0x0008C, 0x0, "Raven+ Lo Power Backplane w/o EISA RS-232"}, 
+       {HPHW_FIO, 0x056, 0x0008C, 0x0, "Raven+ w SE FWSCSI Core RS-232"}, 
+       {HPHW_FIO, 0x057, 0x0008C, 0x0, "Raven+ w Diff FWSCSI Core RS-232"}, 
+       {HPHW_FIO, 0x058, 0x0008C, 0x0, "FireHawk 200 Core RS-232"}, 
+       {HPHW_FIO, 0x059, 0x0008C, 0x0, "FireHawk 200 Wax RS-232"}, 
+       {HPHW_FIO, 0x05A, 0x0008C, 0x0, "Raven+ L2 Backplane w EISA RS-232"}, 
+       {HPHW_FIO, 0x05B, 0x0008C, 0x0, "Raven+ L2 Backplane w/o EISA RS-232"}, 
+       {HPHW_FIO, 0x05D, 0x0008C, 0x0, "SummitHawk Dino RS-232"}, 
+       {HPHW_FIO, 0x05E, 0x0008C, 0x0, "Staccato 132 Core LAN RS-232"}, 
+       {HPHW_FIO, 0x05F, 0x0008C, 0x0, "Staccato 180 Core LAN RS-232"}, 
+       {HPHW_FIO, 0x800, 0x0008C, 0x0, "Hitachi Tiny 64 Core RS-232"}, 
+       {HPHW_FIO, 0x801, 0x0008C, 0x0, "Hitachi Tiny 80 Core RS-232"}, 
+       {HPHW_FIO, 0x015, 0x0008D, 0x0, "Gecko Optional RJ-16"}, 
+       {HPHW_FIO, 0x016, 0x0008D, 0x0, "Gecko Core RJ-16"}, 
+       {HPHW_FIO, 0x01C, 0x0008D, 0x0, "Gecko 80 Core RJ-16"}, 
+       {HPHW_FIO, 0x01D, 0x0008D, 0x0, "Gecko 100 Core RJ-16"}, 
+       {HPHW_FIO, 0x004, 0x0008F, 0x0, "Anole Boot Rom"}, 
+       {HPHW_FIO, 0x005, 0x0008F, 0x0, "Rocky1 Boot Rom"}, 
+       {HPHW_FIO, 0x006, 0x0008F, 0x0, "Rocky2 120 Boot Rom"}, 
+       {HPHW_FIO, 0x007, 0x0008F, 0x0, "Rocky2 150 Boot Rom"}, 
+       {HPHW_FIO, 0x006, 0x00096, 0x0, "Raven U/L2 Dino PS2 Keyboard"}, 
+       {HPHW_FIO, 0x007, 0x00096, 0x0, "Dino PS2 Keyboard"}, 
+       {HPHW_FIO, 0x008, 0x00096, 0x0, "Merlin 132 Dino PS2 Keyboard"}, 
+       {HPHW_FIO, 0x009, 0x00096, 0x0, "Merlin 160 Dino PS2 Keyboard"}, 
+       {HPHW_FIO, 0x00A, 0x00096, 0x0, "Merlin Jr 132 Dino PS2 Keyboard"}, 
+       {HPHW_FIO, 0x019, 0x00096, 0x0, "Merlin+ 180 Dino PS2 Keyboard"}, 
+       {HPHW_FIO, 0x022, 0x00096, 0x0, "Merlin+ 132 Dino PS2 Keyboard"}, 
+       {HPHW_FIO, 0x004, 0x00097, 0x0, "Cascade EISA 100VG lan"}, 
+       {HPHW_FIO, 0x023, 0x00099, 0x0, "Rocky1 Wax HPIB"}, 
+       {HPHW_FIO, 0x048, 0x00099, 0x0, "Rocky2 120 Clark/Dino HPIB"}, 
+       {HPHW_FIO, 0x049, 0x00099, 0x0, "Rocky2 150 Clark/Dino HPIB"}, 
+       {HPHW_FIO, 0x004, 0x000A1, 0x0, "SPP2000 Console TTY"}, 
+       {HPHW_FIO, 0x004, 0x000A2, 0x0, "Forte Core PCI 10/100BT LAN"}, 
+       {HPHW_FIO, 0x005, 0x000A2, 0x0, "AllegroLow PCI 10/100BT LAN"}, 
+       {HPHW_FIO, 0x006, 0x000A2, 0x0, "AllegroHIgh Core PCI 10/100BT LAN"}, 
+       {HPHW_FIO, 0x007, 0x000A2, 0x0, "PCI Plug-in Lan"}, 
+       {HPHW_FIO, 0x00A, 0x000A2, 0x0, "Lego 360 Core PCI 10/100BT Lan"}, 
+       {HPHW_FIO, 0x03E, 0x000A2, 0x0, "Merlin+ 132 Core PCI Lan"}, 
+       {HPHW_FIO, 0x03F, 0x000A2, 0x0, "Merlin+ 180 Core PCI Lan"}, 
+       {HPHW_FIO, 0x056, 0x000A2, 0x0, "Raven+ w SE FWSCSI Core PCI Lan"}, 
+       {HPHW_FIO, 0x057, 0x000A2, 0x0, "Raven+ w Diff FWSCSI Core PCI Lan"}, 
+       {HPHW_FIO, 0x05E, 0x000A2, 0x0, "Staccato 132 PCI Lan"}, 
+       {HPHW_FIO, 0x05F, 0x000A2, 0x0, "Staccato 180 PCI Lan"}, 
+       {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI LVD Ultra2 SCSI"}, 
+       {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI SE UltraSCSI"}, 
+       {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI IDE/ATAPI CD-ROM"}, 
+       {HPHW_FIO, 0x005, 0x000A3, 0x0, "AllegroLow Core PCI LVD Ultra2 SCSI"}, 
+       {HPHW_FIO, 0x005, 0x000A3, 0x0, "AllegroLow Core PCI IDE/ATAPI CD-ROM"}, 
+       {HPHW_FIO, 0x006, 0x000A3, 0x0, "AllegroHigh Core PCI LVD Ultra2 SCSI"}, 
+       {HPHW_FIO, 0x006, 0x000A3, 0x0, "AllegroHigh Core PCI IDE/ATAPI CD-ROM"}, 
+       {HPHW_FIO, 0x007, 0x000A3, 0x0, "PCI Plug-in Disk"}, 
+       {HPHW_FIO, 0x008, 0x000A3, 0x0, "A5158A S FC Tachlite HBA"}, 
+       {HPHW_FIO, 0x009, 0x000A3, 0x0, "A5157A D FC HBA"}, 
+       {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI LVD Ultra2 SCSI"}, 
+       {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI NSE UltraSCSI"}, 
+       {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI WSE UltraSCSI"}, 
+       {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI IDE/ATAPI CD-ROM"}, 
+       {HPHW_FIO, 0x03E, 0x000A3, 0x0, "Merlin+ 132 Core SE FWSCSI PCI Disk"}, 
+       {HPHW_FIO, 0x03F, 0x000A3, 0x0, "Merlin+ 180 Core SE FWSCSI PCI Disk"}, 
+       {HPHW_FIO, 0x056, 0x000A3, 0x0, "Raven+ w SE FWSCSI Core PCI Disk"}, 
+       {HPHW_FIO, 0x057, 0x000A3, 0x0, "Raven+ w Diff FWSCSI Core PCI Disk"}, 
+       {HPHW_FIO, 0x004, 0x000A4, 0x0, "SPP2000 Core BA"}, 
+       {HPHW_FIO, 0x004, 0x000A6, 0x0, "Sonic Ethernet 802.3 Card"}, 
+       {HPHW_FIO, 0x004, 0x000A9, 0x00, "Forte Core PCI SuperIO RS-232"}, 
+       {HPHW_FIO, 0x004, 0x000A9, 0x00, "Forte Core PCI USB KB"}, 
+       {HPHW_FIO, 0x005, 0x000A9, 0x00, "AllegroLow Core PCI SuperIO RS-232"}, 
+       {HPHW_FIO, 0x005, 0x000A9, 0x00, "AllegroLow Core PCI USB KB"}, 
+       {HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI SuperIO RS-232"}, 
+       {HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI USB KB"}, 
+       {HPHW_FIO, 0x007, 0x000A9, 0x0, "Miscelaneous PCI Plug-in"}, 
+       {HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI SuperIO RS-232"}, 
+       {HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI USB KB"}, 
+       {HPHW_FIO, 0x004, 0x00320, 0x0, "Metheus Frame Buffer"}, 
+       {HPHW_FIO, 0x004, 0x00340, 0x0, "BARCO CX4500 VME Grphx Cnsl"}, 
+       {HPHW_FIO, 0x004, 0x00360, 0x0, "Hughes TOG VME FDDI"}, 
+       {HPHW_IOA, 0x185, 0x0000B, 0x00, "Java BC Summit Port"}, 
+       {HPHW_IOA, 0x1FF, 0x0000B, 0x00, "Hitachi Ghostview Summit Port"}, 
+       {HPHW_IOA, 0x580, 0x0000B, 0x10, "U2-IOA BC Runway Port"}, 
+       {HPHW_IOA, 0x581, 0x0000B, 0x10, "Uturn-IOA BC Runway Port"}, 
+       {HPHW_IOA, 0x582, 0x0000B, 0x10, "Astro BC Runway Port"}, 
+       {HPHW_IOA, 0x700, 0x0000B, 0x00, "NEC-IOS BC System Bus Port"}, 
+       {HPHW_MEMORY, 0x002, 0x00008, 0x00, "MID_BUS"}, 
+       {HPHW_MEMORY, 0x00C, 0x00008, 0x08, "Kahlua 8MB"}, 
+       {HPHW_MEMORY, 0x00D, 0x00008, 0x08, "Kahlua 4MB"}, 
+       {HPHW_MEMORY, 0x00E, 0x00008, 0x08, "Tequila 16MB"}, 
+       {HPHW_MEMORY, 0x00F, 0x00008, 0x08, "Tequila 32MB"}, 
+       {HPHW_MEMORY, 0x040, 0x00008, 0x00, "Hitachi"}, 
+       {HPHW_MEMORY, 0x004, 0x00009, 0x00, "Cheetah"}, 
+       {HPHW_MEMORY, 0x005, 0x00009, 0x00, "Emerald"}, 
+       {HPHW_MEMORY, 0x008, 0x00009, 0x00, "Indigo 3MB/5MB"}, 
+       {HPHW_MEMORY, 0x00C, 0x00009, 0x00, "Indigo 8MB"}, 
+       {HPHW_MEMORY, 0x00D, 0x00009, 0x00, "Paradise 4MB"}, 
+       {HPHW_MEMORY, 0x00E, 0x00009, 0x00, "Burgundy Onboard"}, 
+       {HPHW_MEMORY, 0x012, 0x00009, 0x00, "Indigo 12MB/20MB"}, 
+       {HPHW_MEMORY, 0x013, 0x00009, 0x00, "Cobra"}, 
+       {HPHW_MEMORY, 0x014, 0x00009, 0x00, "Nova"}, 
+       {HPHW_MEMORY, 0x015, 0x00009, 0x00, "Coral"}, 
+       {HPHW_MEMORY, 0x016, 0x00009, 0x00, "Bushmaster"}, 
+       {HPHW_MEMORY, 0x017, 0x00009, 0x00, "Scorpio"}, 
+       {HPHW_MEMORY, 0x018, 0x00009, 0x00, "Flounder"}, 
+       {HPHW_MEMORY, 0x019, 0x00009, 0x00, "Hardball"}, 
+       {HPHW_MEMORY, 0x01A, 0x00009, 0x00, "CoralII 99"}, 
+       {HPHW_MEMORY, 0x01B, 0x00009, 0x00, "Scorpio Jr."}, 
+       {HPHW_MEMORY, 0x01C, 0x00009, 0x00, "Strider-50 (715T)"}, 
+       {HPHW_MEMORY, 0x01D, 0x00009, 0x00, "Strider-33 (707T)"}, 
+       {HPHW_MEMORY, 0x01E, 0x00009, 0x00, "Trailways-50 (715S)"}, 
+       {HPHW_MEMORY, 0x01F, 0x00009, 0x00, "Trailways-33 (707S)"}, 
+       {HPHW_MEMORY, 0x020, 0x00009, 0x00, "Pace"}, 
+       {HPHW_MEMORY, 0x021, 0x00009, 0x00, "Sidewinder"}, 
+       {HPHW_MEMORY, 0x022, 0x00009, 0x00, "Orville"}, 
+       {HPHW_MEMORY, 0x023, 0x00009, 0x00, "Wilbur"}, 
+       {HPHW_MEMORY, 0x026, 0x00009, 0x00, "Gecko"}, 
+       {HPHW_MEMORY, 0x027, 0x00009, 0x00, "Scorpio Sr."}, 
+       {HPHW_MEMORY, 0x028, 0x00009, 0x00, "Scorpio 100"}, 
+       {HPHW_MEMORY, 0x029, 0x00009, 0x00, "Spectra 50"}, 
+       {HPHW_MEMORY, 0x02A, 0x00009, 0x00, "CoralII 132"}, 
+       {HPHW_MEMORY, 0x02F, 0x00009, 0x00, "KittyHawk DC2-"}, 
+       {HPHW_MEMORY, 0x030, 0x00009, 0x00, "Spectra 75"}, 
+       {HPHW_MEMORY, 0x031, 0x00009, 0x00, "Spectra 100"}, 
+       {HPHW_MEMORY, 0x032, 0x00009, 0x00, "KittyHawk DC3"}, 
+       {HPHW_MEMORY, 0x033, 0x00009, 0x00, "Fast Pace"}, 
+       {HPHW_MEMORY, 0x034, 0x00009, 0x00, "Snake Eagle"}, 
+       {HPHW_MEMORY, 0x035, 0x00009, 0x00, "Anole 64"}, 
+       {HPHW_MEMORY, 0x036, 0x00009, 0x00, "Anole 100"}, 
+       {HPHW_MEMORY, 0x037, 0x00009, 0x00, "Snake Cheetah"}, 
+       {HPHW_MEMORY, 0x038, 0x00009, 0x00, "Gecko 80"}, 
+       {HPHW_MEMORY, 0x039, 0x00009, 0x00, "Gecko 100"}, 
+       {HPHW_MEMORY, 0x03A, 0x00009, 0x00, "Gecko 120"}, 
+       {HPHW_MEMORY, 0x03B, 0x00009, 0x00, "Gila 80"}, 
+       {HPHW_MEMORY, 0x03C, 0x00009, 0x00, "Gila 100"}, 
+       {HPHW_MEMORY, 0x03D, 0x00009, 0x00, "Gila 120"}, 
+       {HPHW_MEMORY, 0x03E, 0x00009, 0x00, "Scorpio-L 80"}, 
+       {HPHW_MEMORY, 0x03F, 0x00009, 0x00, "Scorpio-L 100"}, 
+       {HPHW_MEMORY, 0x040, 0x00009, 0x00, "Scorpio-L 120"}, 
+       {HPHW_MEMORY, 0x041, 0x00009, 0x00, "Spectra-L 80"}, 
+       {HPHW_MEMORY, 0x042, 0x00009, 0x00, "Spectra-L 100"}, 
+       {HPHW_MEMORY, 0x043, 0x00009, 0x00, "Spectra-L 120"}, 
+       {HPHW_MEMORY, 0x044, 0x00009, 0x00, "Piranha 100"}, 
+       {HPHW_MEMORY, 0x045, 0x00009, 0x00, "Piranha 120"}, 
+       {HPHW_MEMORY, 0x046, 0x00009, 0x00, "Jason 50"}, 
+       {HPHW_MEMORY, 0x047, 0x00009, 0x00, "Jason 100"}, 
+       {HPHW_MEMORY, 0x049, 0x00009, 0x00, "SkyHawk 100/120"}, 
+       {HPHW_MEMORY, 0x04A, 0x00009, 0x00, "Mirage Jr"}, 
+       {HPHW_MEMORY, 0x04B, 0x00009, 0x00, "Mirage 100"}, 
+       {HPHW_MEMORY, 0x04C, 0x00009, 0x00, "Mirage 100+"}, 
+       {HPHW_MEMORY, 0x04D, 0x00009, 0x00, "Electra 100"}, 
+       {HPHW_MEMORY, 0x04E, 0x00009, 0x00, "Electra 120"}, 
+       {HPHW_MEMORY, 0x04F, 0x00009, 0x00, "Mirage 80"}, 
+       {HPHW_MEMORY, 0x050, 0x00009, 0x00, "UL Proc 1 way T'100"}, 
+       {HPHW_MEMORY, 0x051, 0x00009, 0x00, "UL Proc 1 way T'120"}, 
+       {HPHW_MEMORY, 0x052, 0x00009, 0x00, "UL Proc 2 way T'100"}, 
+       {HPHW_MEMORY, 0x053, 0x00009, 0x00, "KittyHawk DC3-"}, 
+       {HPHW_MEMORY, 0x054, 0x00009, 0x00, "UL Proc 2 way T'120"}, 
+       {HPHW_MEMORY, 0x055, 0x00009, 0x00, "Raven 120 mem"}, 
+       {HPHW_MEMORY, 0x056, 0x00009, 0x00, "UL Proc L 75"}, 
+       {HPHW_MEMORY, 0x057, 0x00009, 0x00, "UL Proc L 100"}, 
+       {HPHW_MEMORY, 0x058, 0x00009, 0x00, "Anole T"}, 
+       {HPHW_MEMORY, 0x059, 0x00009, 0x00, "SAIC L-80"}, 
+       {HPHW_MEMORY, 0x05A, 0x00009, 0x00, "Merlin+ L2 180"}, 
+       {HPHW_MEMORY, 0x05B, 0x00009, 0x00, "Raven U 200 2-way"}, 
+       {HPHW_MEMORY, 0x05C, 0x00009, 0x00, "Raven U 180+"}, 
+       {HPHW_MEMORY, 0x05D, 0x00009, 0x00, "Raven U 200"}, 
+       {HPHW_MEMORY, 0x05E, 0x00009, 0x00, "Rocky2 150 Memory"}, 
+       {HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, 
+       {HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, 
+       {HPHW_MEMORY, 0x05F, 0x00009, 0x00, "SPP2000 Memory"}, 
+       {HPHW_MEMORY, 0x060, 0x00009, 0x00, "Merlin L2 132"}, 
+       {HPHW_MEMORY, 0x061, 0x00009, 0x00, "Merlin+ L2 132"}, 
+       {HPHW_MEMORY, 0x063, 0x00009, 0x00, "712/132 L2 Upgrade"}, 
+       {HPHW_MEMORY, 0x064, 0x00009, 0x00, "712/160 L2 Upgrade"}, 
+       {HPHW_MEMORY, 0x065, 0x00009, 0x00, "715/132 L2 Upgrade"}, 
+       {HPHW_MEMORY, 0x066, 0x00009, 0x00, "715/160 L2 Upgrade"}, 
+       {HPHW_MEMORY, 0x067, 0x00009, 0x00, "Merlin 160/ThunderHawk Memory"}, 
+       {HPHW_MEMORY, 0x068, 0x00009, 0x00, "LightningHawk Memory"}, 
+       {HPHW_MEMORY, 0x069, 0x00009, 0x00, "Rocky1 Memory"}, 
+       {HPHW_MEMORY, 0x06A, 0x00009, 0x00, "Raven L2 132"}, 
+       {HPHW_MEMORY, 0x06B, 0x00009, 0x00, "Raven L2 160"}, 
+       {HPHW_MEMORY, 0x06C, 0x00009, 0x00, "Raven L2 187"}, 
+       {HPHW_MEMORY, 0x06D, 0x00009, 0x00, "Raven L2 200"}, 
+       {HPHW_MEMORY, 0x06E, 0x00009, 0x00, "Raven U 230"}, 
+       {HPHW_MEMORY, 0x06F, 0x00009, 0x00, "Raven U 240"}, 
+       {HPHW_MEMORY, 0x070, 0x00009, 0x00, "Rocky2 120 Memory"}, 
+       {HPHW_MEMORY, 0x071, 0x00009, 0x00, "Raven U 160"}, 
+       {HPHW_MEMORY, 0x072, 0x00009, 0x00, "Raven U 180"}, 
+       {HPHW_MEMORY, 0x072, 0x00009, 0x00, "UL Proc 1 way T'120 1MB/1MB"}, 
+       {HPHW_MEMORY, 0x073, 0x00009, 0x00, "UL Proc 2 way T'120 1MB/1MB"}, 
+       {HPHW_MEMORY, 0x074, 0x00009, 0x00, "Anole L2 132 memory"}, 
+       {HPHW_MEMORY, 0x075, 0x00009, 0x00, "Anole L2 165 memory"}, 
+       {HPHW_MEMORY, 0x076, 0x00009, 0x00, "UL 1 way U160 512K/512K memory"}, 
+       {HPHW_MEMORY, 0x077, 0x00009, 0x00, "UL 2 way U160 512K/512K memory"}, 
+       {HPHW_MEMORY, 0x078, 0x00009, 0x00, "Kiji L2 132 memory"}, 
+       {HPHW_MEMORY, 0x079, 0x00009, 0x00, "UL 1 way U160 1M/1M memory"}, 
+       {HPHW_MEMORY, 0x07A, 0x00009, 0x00, "UL 2 way U160 1M/1M memory"}, 
+       {HPHW_MEMORY, 0x07B, 0x00009, 0x00, "UL 1 way U180 1M/1M memory"}, 
+       {HPHW_MEMORY, 0x07C, 0x00009, 0x00, "UL 2 way U180 1M/1M memory"}, 
+       {HPHW_MEMORY, 0x07D, 0x00009, 0x00, "UL 1 way U240 U+ 2M/2M memory"}, 
+       {HPHW_MEMORY, 0x07E, 0x00009, 0x00, "UL 2 way U240 U+ 2M/2M memory"}, 
+       {HPHW_MEMORY, 0x07F, 0x00009, 0x00, "UL L2 132 memory"}, 
+       {HPHW_MEMORY, 0x080, 0x00009, 0x00, "UL L2 160 memory"}, 
+       {HPHW_MEMORY, 0x081, 0x00009, 0x00, "Merlin Jr 132 memory"}, 
+       {HPHW_MEMORY, 0x082, 0x00009, 0x00, "FireHawk 200 Memory"}, 
+       {HPHW_MEMORY, 0x083, 0x00009, 0x00, "SummitHawk Memory"}, 
+       {HPHW_MEMORY, 0x084, 0x00009, 0x00, "Jade Upgrade Memory"}, 
+       {HPHW_MEMORY, 0x085, 0x00009, 0x00, "SPP2500 Memory"}, 
+       {HPHW_MEMORY, 0x086, 0x00009, 0x00, "AllegroHigh Memory"}, 
+       {HPHW_MEMORY, 0x087, 0x00009, 0x00, "AllegroLow Memory"}, 
+       {HPHW_MEMORY, 0x088, 0x00009, 0x00, "Forte 2w Memory"}, 
+       {HPHW_MEMORY, 0x089, 0x00009, 0x00, "Forte 4w Memory"}, 
+       {HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, 
+       {HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, 
+       {HPHW_MEMORY, 0x090, 0x00009, 0x00, "Prelude SMC Memory"}, 
+       {HPHW_MEMORY, 0x091, 0x00009, 0x00, "Lego 360 Memory"}, 
+       {HPHW_MEMORY, 0x7FF, 0x00009, 0x00, "NEC Aska memory"}, 
+       {HPHW_MEMORY, 0x800, 0x00009, 0x00, "Hitachi Tiny 64"}, 
+       {HPHW_MEMORY, 0x801, 0x00009, 0x00, "Hitachi Tiny 80"}, 
+       {HPHW_MEMORY, 0x8FF, 0x00009, 0x00, "Hitachi X memory"}, 
+       {HPHW_MEMORY, 0x091, 0x00009, 0x00, "M2250 Memory"}, 
+       {HPHW_MEMORY, 0x092, 0x00009, 0x00, "M2500 Memory"}, 
+       {HPHW_MEMORY, 0x093, 0x00009, 0x00, "Sonata 440 Memory"}, 
+       {HPHW_MEMORY, 0x094, 0x00009, 0x00, "Sonata 360 Memory"}, 
+       {HPHW_MEMORY, 0x095, 0x00009, 0x00, "Rhapsody 440 Memory"}, 
+       {HPHW_MEMORY, 0x096, 0x00009, 0x00, "Rhapsody 360 Memory"}, 
+       {HPHW_MEMORY, 0x097, 0x00009, 0x00, "Raven W 360 Memory"}, 
+       {HPHW_MEMORY, 0x098, 0x00009, 0x00, "Halfdome W 440 Memory"}, 
+       {HPHW_MEMORY, 0x099, 0x00009, 0x00, "Rhapsody DC- 440 Memory"}, 
+       {HPHW_MEMORY, 0x09A, 0x00009, 0x00, "Rhapsody DC- 360 Memory"}, 
+       {HPHW_MEMORY, 0x09B, 0x00009, 0x00, "Crescendo Memory"}, 
+       {HPHW_OTHER, 0x004, 0x00030, 0x00, "Master"}, 
+       {HPHW_OTHER, 0x004, 0x00034, 0x00, "Slave"}, 
+       {HPHW_OTHER, 0x004, 0x00038, 0x00, "EDU"}, 
+       {HPHW_OTHER, 0x004, 0x00049, 0x00, "LGB Control"}, 
+        {0, }                  /* leave the last entry empty ! */
+};
+
+
+static struct hp_cpu_type_mask {
+       unsigned short model;
+       unsigned short mask;
+       enum cpu_type cpu;
+} hp_cpu_type_mask_list[] = {
+
+       { 0x0000, 0x0ff0, pcx    },  /* 0x0000 - 0x000f */
+       { 0x0048, 0x0ff0, pcxl   },  /* 0x0040 - 0x004f */
+       { 0x0080, 0x0ff0, pcx    },  /* 0x0080 - 0x008f */
+       { 0x0100, 0x0ff0, pcx    },  /* 0x0100 - 0x010f */
+       { 0x0182, 0x0ffe, pcx    },  /* 0x0182 - 0x0183 */
+       { 0x0182, 0x0ffe, pcxt   },  /* 0x0182 - 0x0183 */
+       { 0x0184, 0x0fff, pcxu   },  /* 0x0184 - 0x0184 */
+       { 0x0200, 0x0ffe, pcxs   },  /* 0x0200 - 0x0201 */
+       { 0x0202, 0x0fff, pcxs   },  /* 0x0202 - 0x0202 */
+       { 0x0203, 0x0fff, pcxt   },  /* 0x0203 - 0x0203 */
+       { 0x0204, 0x0ffc, pcxt   },  /* 0x0204 - 0x0207 */
+       { 0x0280, 0x0ffc, pcxs   },  /* 0x0280 - 0x0283 */
+       { 0x0284, 0x0ffc, pcxt   },  /* 0x0284 - 0x0287 */
+       { 0x0288, 0x0fff, pcxt   },  /* 0x0288 - 0x0288 */
+       { 0x0300, 0x0ffc, pcxs   },  /* 0x0300 - 0x0303 */
+       { 0x0310, 0x0ff0, pcxt   },  /* 0x0310 - 0x031f */
+       { 0x0320, 0x0ff0, pcxt   },  /* 0x0320 - 0x032f */
+       { 0x0400, 0x0ff0, pcxt   },  /* 0x0400 - 0x040f */
+       { 0x0480, 0x0ff0, pcxl   },  /* 0x0480 - 0x048f */
+       { 0x0500, 0x0ff0, pcxl2  },  /* 0x0500 - 0x050f */
+       { 0x0510, 0x0ff0, pcxl2  },  /* 0x0510 - 0x051f */
+       { 0x0580, 0x0ff8, pcxt_  },  /* 0x0580 - 0x0587 */
+       { 0x0588, 0x0ffc, pcxt_  },  /* 0x0588 - 0x058b */
+       { 0x058c, 0x0ffe, pcxt_  },  /* 0x058c - 0x058d */
+       { 0x058e, 0x0fff, pcxt_  },  /* 0x058e - 0x058e */
+       { 0x058f, 0x0fff, pcxu   },  /* 0x058f - 0x058f */
+       { 0x0590, 0x0ffe, pcxu   },  /* 0x0590 - 0x0591 */
+       { 0x0592, 0x0fff, pcxt_  },  /* 0x0592 - 0x0592 */
+       { 0x0593, 0x0fff, pcxu   },  /* 0x0593 - 0x0593 */
+       { 0x0594, 0x0ffc, pcxu   },  /* 0x0594 - 0x0597 */
+       { 0x0598, 0x0ffc, pcxu   },  /* 0x0598 - 0x059b */
+       { 0x059c, 0x0ffe, pcxu_  },  /* 0x059c - 0x059d */
+       { 0x059e, 0x0fff, pcxt_  },  /* 0x059e - 0x059e */
+       { 0x059f, 0x0fff, pcxu   },  /* 0x059f - 0x059f */
+       { 0x05a0, 0x0ffe, pcxt_  },  /* 0x05a0 - 0x05a1 */
+       { 0x05a2, 0x0ffe, pcxu   },  /* 0x05a2 - 0x05a3 */
+       { 0x05a4, 0x0ffc, pcxu   },  /* 0x05a4 - 0x05a7 */
+       { 0x05a8, 0x0ffc, pcxu   },  /* 0x05a8 - 0x05ab */
+       { 0x05ad, 0x0fff, pcxu_  },  /* 0x05ad - 0x05ad */
+       { 0x05ae, 0x0ffe, pcxu_  },  /* 0x05ae - 0x05af */
+       { 0x05b0, 0x0ffe, pcxu_  },  /* 0x05b0 - 0x05b1 */
+       { 0x05b2, 0x0fff, pcxu_  },  /* 0x05b2 - 0x05b2 */
+       { 0x05b3, 0x0fff, pcxu   },  /* 0x05b3 - 0x05b3 */
+       { 0x05b4, 0x0fff, pcxw   },  /* 0x05b4 - 0x05b4 */
+       { 0x05b5, 0x0fff, pcxu_  },  /* 0x05b5 - 0x05b5 */
+       { 0x05b6, 0x0ffe, pcxu_  },  /* 0x05b6 - 0x05b7 */
+       { 0x05b8, 0x0ffe, pcxu_  },  /* 0x05b8 - 0x05b9 */
+       { 0x05ba, 0x0fff, pcxu_  },  /* 0x05ba - 0x05ba */
+       { 0x05bb, 0x0fff, pcxw   },  /* 0x05bb - 0x05bb */
+       { 0x05bc, 0x0ffc, pcxw   },  /* 0x05bc - 0x05bf */
+       { 0x05c0, 0x0fc0, pcxw   },  /* 0x05c0 - 0x05ff */
+       { 0x0600, 0x0ff0, pcxl   },  /* 0x0600 - 0x060f */
+       { 0x0610, 0x0ff0, pcxl   },  /* 0x0610 - 0x061f */
+       { 0x0000, 0x0000, pcx    }      /* terminate table */
+};
+
+char *cpu_name_version[][2] = {
+       [pcx]   { "PA7000 (PCX)",       "1.0" },
+       [pcxs]  { "PA7000 (PCX-S)",     "1.1a" },
+       [pcxt]  { "PA7100 (PCX-T)",     "1.1b" },
+       [pcxt_] { "PA7200 (PCX-T')",    "1.1c" },
+       [pcxl]  { "PA7100LC (PCX-L)",   "1.1d" },
+       [pcxl2] { "PA7300LC (PCX-L2)",  "1.1e" },
+       [pcxu]  { "PA8000 (PCX-U)",     "2.0" },
+       [pcxu_] { "PA8200 (PCX-U+)",    "2.0" },
+       [pcxw]  { "PA8500 (PCX-W)",     "2.0" },
+       [pcxw_] { "PA8600 (PCX-W+)",    "2.0" }
+};
+
+char *parisc_getHWtype(unsigned short hw_type)
+{
+       if (hw_type <= HPHW_CIO) {
+               return hw_type_name[hw_type];
+       } else {
+               return "Unknown Type";
+       }
+}
+
+char *parisc_getHWdescription(unsigned short hw_type, unsigned long hversion,
+               unsigned long sversion)
+{
+       struct hp_hardware *listptr;
+       
+       for (listptr = hp_hardware_list; listptr->name; listptr++) {
+               if ((listptr->hw_type==hw_type) &&
+                               (listptr->hversion==hversion) &&
+                               (listptr->sversion==sversion)){
+                       return listptr->name;
+               }
+       }
+       return "unknown device";
+}
+
+
+/* Interpret hversion (ret[0]) from PDC_MODEL(4)/PDC_MODEL_INFO(0) */
+enum cpu_type parisc_get_cpu_type(unsigned long hversion)
+{
+       struct hp_cpu_type_mask *ptr;
+       unsigned short model = ((unsigned short) (hversion)) >> 4;
+
+       for (ptr = hp_cpu_type_mask_list; 0 != ptr->mask; ptr++) {
+               if (ptr->model == (model & ptr->mask))
+                       return ptr->cpu;
+       }
+       panic("parisc_get_cpu_type() could not identify CPU type\n");
+
+       return pcx;     /* not reached: */
+}
+
+
+struct hp_hardware *parisc_get_reference(unsigned short hw_type,
+               unsigned long hversion, unsigned long sversion)
+{
+       struct hp_hardware *listptr = hp_hardware_list;
+
+       for (listptr = hp_hardware_list; listptr->name; listptr++) {
+               if ((listptr->hw_type == hw_type) &&
+                               (listptr->hversion == hversion) &&
+                               (listptr->sversion == sversion)) {
+                       return listptr;
+               }
+       }
+       return NULL;
+}
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
new file mode 100644 (file)
index 0000000..ce45dd6
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ *
+ * 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) 1999 by Helge Deller
+ * Copyright 1999 SuSE GmbH (Philipp Rumpf)
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ *
+ * Initial Version 04-23-1999 by Helge Deller (helge.deller@ruhr-uni-bochum.de)
+ */
+
+
+#include <asm/offset.h>
+#include <asm/psw.h>
+
+#define __ASSEMBLY__
+/*********
+#include <asm/pdc.h>
+*********/
+#include <asm/assembly.h>
+#include <asm/pgtable.h>
+
+
+       .level 1.1
+
+       .section        .initcall.init
+       .align          4
+       .export __initcall_start
+__initcall_start:
+       .export __initcall_end
+__initcall_end:
+       .export __setup_start
+__setup_start:
+       .export __setup_end
+__setup_end:
+
+       .text
+       .align  4       
+       .import init_task_union,data
+       .import $global$                /* forward declaration */
+       .import fault_vector_11,code    /* IVA parisc 1.1 32 bit */
+       .import fault_vector_20,code    /* IVA parisc 2.0 32 bit */
+       .import start_parisc,code       /* then enable VM and go here */
+
+       .export stext
+       .export _stext,data             /* Kernel want it this way! */
+_stext:
+stext:
+       .proc
+       .callinfo
+
+       /* Make sure sr4-sr7 are set to zero for the kernel address space */
+
+       mtsp            %r0,%sr4
+       mtsp            %r0,%sr5
+       mtsp            %r0,%sr6
+       mtsp            %r0,%sr7
+
+       /* Initialize startup VM. Just map first 8 MB of memory */
+
+       ldil            L%PA(pg0),%r1
+       ldo             R%PA(pg0)(%r1),%r1
+       ldo             _PAGE_TABLE(%r1),%r3
+       ldil            L%PA(swapper_pg_dir),%r4
+       ldo             R%PA(swapper_pg_dir)(%r4),%r4
+       mtctl           %r4,%cr24       /* Initialize kernel root pointer */
+       mtctl           %r4,%cr25       /* Initialize user root pointer */
+       stw             %r3,0xc00(%r4)  /* Hardwired 0xc0000000 kernel vaddr start */
+       ldo             0x1000(%r3),%r3
+       stw             %r3,0xc04(%r4)
+       ldo             _PAGE_KERNEL(%r0),%r3 /* Hardwired 0x0 phys addr start */
+$pgt_fill_loop:
+       stwm            %r3,4(%r1)
+       ldo             0x1000(%r3),%r3
+       bb,>=           %r3,8,$pgt_fill_loop
+       nop
+
+       /* Initialize the global data pointer */
+       ldil            L%$global$,%dp
+       ldo             R%$global$(%dp),%dp
+       
+       /* And the stack pointer, physical too */
+       ldil            L%init_task_union+TASK_SZ_ALGN,%sp
+       ldo             R%init_task_union+TASK_SZ_ALGN(%sp),%sp
+
+       /* we need this to take interruptions directly after the rfi below */
+       /* (which we need for PA2.0 boxes) */
+       mtctl           %r0, %cr30
+       
+       /*
+        * Set up our interrupt table.  HPMCs might not work after this! 
+        *
+        * We need to install the correct iva for PA1.1 or PA2.0. The
+        * following short sequence of instructions can determine this
+        * (without being illegal on a PA1.1 machine).
+        */
+       
+       ldi             32,%r10
+       mtctl           %r10,%cr11
+       .level 2.0
+       mfctl,w         %cr11,%r10
+       .level 1.1
+       comib,<>,n      0,%r10,$is_pa20
+       ldil            L%PA(fault_vector_11),%r10
+       b               $install_iva
+       ldo             R%PA(fault_vector_11)(%r10),%r10
+
+$is_pa20:
+       ldil            L%PA(fault_vector_20),%r10
+       ldo             R%PA(fault_vector_20)(%r10),%r10
+
+$install_iva:
+       mtctl           %r10,%cr14
+
+       /* Disable (most) interruptions */
+       mtsm            %r0                     
+       
+       /* kernel PSW:
+        *  - no interruptions except for HPMC and TOC (which are handled by PDC)
+        *  - Q bit set (IODC / PDC interruptions)
+        *  - big-endian
+        *  - virtually mapped
+        */
+
+       ldil            L%KERNEL_PSW,%r10
+       ldo             R%KERNEL_PSW(%r10),%r10
+       mtctl           %r10,%ipsw
+       
+       /* Set the space pointers for the post-RFI world */
+       mtctl           %r0,%cr17               /* Clear two-level IIA Space Queue */
+       mtctl           %r0,%cr17               /*    effectively setting kernel space. */
+
+       /* And the return address(es) too */
+       ldil            L%start_parisc,%r10
+       ldo             R%start_parisc(%r10),%r10
+       mtctl           %r10,%cr18
+       ldo             4(%r10),%r10
+       mtctl           %r10,%cr18
+
+       /* Jump to hyperspace */
+       rfi
+       nop
+
+       .procend
+
+       .data
+
+       .align  4
+       .export $global$,data
+
+       .type   $global$,@object
+       .size   $global$,4
+$global$:      
+       .word 0
diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S
new file mode 100644 (file)
index 0000000..c77aee0
--- /dev/null
@@ -0,0 +1,319 @@
+/* 
+ * HPMC (High Priority Machine Check) handler.
+ *
+ * Copyright (C) 1999 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
+ * Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * This HPMC handler retrieves the HPMC pim data, resets IO and
+ * returns to the default trap handler with code set to 1 (HPMC).
+ * The default trap handler calls handle interruption, which
+ * does a stack and register dump. This at least allows kernel
+ * developers to get back to C code in virtual mode, where they
+ * have the option to examine and print values from memory that
+ * would help in debugging an HPMC caused by a software bug.
+ *
+ * There is more to do here:
+ *
+ *      1) On MP systems we need to synchronize processors
+ *         before calling pdc/iodc.
+ *      2) We should be checking the system state and not
+ *         returning to the fault handler if things are really
+ *         bad.
+ *
+ */
+
+       .level          1.1
+       .data
+
+#define __ASSEMBLY__
+#include <asm/assembly.h>
+#include <asm/pdc.h>
+
+       /*
+        * stack for os_hpmc, the HPMC handler.
+        * buffer for IODC procedures (for the HPMC handler).
+        *
+        * IODC requires 7K byte stack.  That leaves 1K byte for os_hpmc.
+        */
+
+       .align 4096
+hpmc_stack:
+       .block 16384
+
+#define HPMC_IODC_BUF_SIZE 0x8000
+
+       .align 4096
+hpmc_iodc_buf:
+       .block HPMC_IODC_BUF_SIZE
+
+       .align 8
+hpmc_raddr:
+       .block 128
+
+#define HPMC_PIM_DATA_SIZE 896 /* Enough to hold all architected 2.0 state */
+
+       .export hpmc_pim_data, data
+       .align 8
+hpmc_pim_data:
+       .block HPMC_PIM_DATA_SIZE
+
+       .text
+
+       .export os_hpmc, code
+       .import intr_save, code
+
+os_hpmc:
+
+       /*
+        * registers modified:
+        *
+        *   Using callee saves registers without saving them.  The
+        *   original values are in the pim dump if we need them.
+        *
+        *   r2   (rp)  return pointer
+        *   r3   address of PDCE_PROC
+        *   r4   scratch
+        *   r5   scratch
+        *   r23  (arg3) procedure arg
+        *   r24  (arg2) procedure arg
+        *   r25  (arg1) procedure arg
+        *   r26  (arg0) procedure arg
+        *   r30  (sp)   stack pointer
+        *
+        * registers read:
+        *
+        *   r26  contains address of PDCE_PROC on entry
+        *   r28  (ret0) return value from procedure
+        */
+
+       copy    arg0, %r3       /* save address of PDCE_PROC */
+
+       /*
+        *  disable nested HPMCs
+        *
+        * Increment os_hpmc checksum to invalidate it.
+        * Do this before turning the PSW M bit off.
+        */
+
+       mfctl   %cr14, %r4
+       ldw     52(%r4),%r5
+       addi    1,%r5,%r5
+       stw     %r5,52(%r4)
+
+       /* MP_FIXME: synchronize all processors. */
+
+       /* Setup stack pointer. */
+
+       ldil    L%PA(hpmc_stack),sp
+       ldo     R%PA(hpmc_stack)(sp),sp
+       
+       ldo     128(sp),sp /* leave room for arguments */
+
+       /*
+        * Most PDC routines require that the M bit be off.
+        * So turn on the Q bit and turn off the M bit.
+        */
+
+       ldo     8(%r0),%r4                       /* PSW Q on, PSW M off */
+       mtctl   %r4,ipsw
+       mtctl   %r0,pcsq
+       mtctl   %r0,pcsq
+       ldil    L%PA(os_hpmc_1),%r4
+       ldo     R%PA(os_hpmc_1)(%r4),%r4
+       mtctl   %r4,pcoq
+       ldo     4(%r4),%r4
+       mtctl   %r4,pcoq
+       rfi
+       nop
+
+os_hpmc_1:
+
+       /* Call PDC_PIM to get HPMC pim info */
+
+       /*
+        * Note that on some newer boxes, PDC_PIM must be called
+        * before PDC_IO if you want IO to be reset. PDC_PIM sets
+        * a flag that PDC_IO examines.
+        */
+
+       ldo     PDC_PIM(%r0), arg0
+       ldo     PDC_PIM_HPMC(%r0),arg1          /* Transfer HPMC data */
+       ldil    L%PA(hpmc_raddr),arg2
+       ldo     R%PA(hpmc_raddr)(arg2),arg2
+       ldil    L%PA(hpmc_pim_data),arg3
+       ldo     R%PA(hpmc_pim_data)(arg3),arg3
+       ldil    L%HPMC_PIM_DATA_SIZE,%r4
+       ldo     R%HPMC_PIM_DATA_SIZE(%r4),%r4
+       stw     %r4,-52(sp)
+
+       ldil    L%PA(os_hpmc_2), rp
+       bv      (r3)                            /* call pdce_proc */
+       ldo     R%PA(os_hpmc_2)(rp), rp
+
+os_hpmc_2:
+       comib,<>  0,ret0, os_hpmc_fail
+
+       /* Reset IO by calling the hversion dependent PDC_IO routine */
+
+       ldo     PDC_IO(%r0),arg0
+       ldo     0(%r0),arg1                     /* log IO errors */
+       ldo     0(%r0),arg2                     /* reserved */
+       ldo     0(%r0),arg3                     /* reserved */
+       stw     %r0,-52(sp)                     /* reserved */
+
+       ldil    L%PA(os_hpmc_3),rp
+       bv      (%r3)                           /* call pdce_proc */
+       ldo     R%PA(os_hpmc_3)(rp),rp
+
+os_hpmc_3:
+
+       /* FIXME? Check for errors from PDC_IO (-1 might be OK) */
+
+       /*
+        * Initialize the IODC console device (HPA,SPA, path etc.
+        * are stored on page 0.
+        */
+
+       /*
+        * Load IODC into hpmc_iodc_buf by calling PDC_IODC.
+        * Note that PDC_IODC handles flushing the appropriate
+        * data and instruction cache lines.
+        */
+
+       ldo     PDC_IODC(%r0),arg0
+       ldo     PDC_IODC_READ(%r0),arg1
+       ldil    L%PA(hpmc_raddr),arg2
+       ldo     R%PA(hpmc_raddr)(arg2),arg2
+       ldw     BOOT_CONSOLE_HPA_OFFSET(%r0),arg3 /* console hpa */
+       ldo     PDC_IODC_RI_INIT(%r0),%r4
+       stw     %r4,-52(sp)
+       ldil    L%PA(hpmc_iodc_buf),%r4
+       ldo     R%PA(hpmc_iodc_buf)(%r4),%r4
+       stw     %r4,-56(sp)
+       ldil    L%HPMC_IODC_BUF_SIZE,%r4
+       ldo     R%HPMC_IODC_BUF_SIZE(%r4),%r4
+       stw     %r4,-60(sp)
+
+       ldil    L%PA(os_hpmc_4),rp
+       bv      (%r3)                            /* call pdce_proc */
+       ldo     R%PA(os_hpmc_4)(rp),rp
+
+os_hpmc_4:
+       comib,<>  0,ret0,os_hpmc_fail
+
+       /* Call the entry init (just loaded by PDC_IODC) */
+
+       ldw     BOOT_CONSOLE_HPA_OFFSET(%r0),arg0  /* console hpa */
+       ldo     ENTRY_INIT_MOD_DEV(%r0), arg1
+       ldw     BOOT_CONSOLE_SPA_OFFSET(%r0),arg2  /* console spa */
+       depi    0,31,11,arg2                       /* clear bits 21-31    */
+       ldo     BOOT_CONSOLE_PATH_OFFSET(%r0),arg3 /* console path */
+       ldil    L%PA(hpmc_raddr),%r4
+       ldo     R%PA(hpmc_raddr)(%r4),%r4
+       stw     %r4, -52(sp)
+       stw     %r0, -56(sp)                    /* HV                  */
+       stw     %r0, -60(sp)                    /* HV                  */
+       stw     %r0, -64(sp)                    /* HV                  */
+       stw     %r0, -68(sp)                    /* lang, must be zero  */
+
+       ldil    L%PA(hpmc_iodc_buf),%r5
+       ldo     R%PA(hpmc_iodc_buf)(%r5),%r5
+       ldil    L%PA(os_hpmc_5),rp
+       bv      (%r5)
+       ldo     R%PA(os_hpmc_5)(rp),rp
+
+os_hpmc_5:
+       comib,<>  0,ret0,os_hpmc_fail
+
+       /* Prepare to call intr_save */
+
+       /*
+        * Load kernel page directory (load into user also, since
+        * we don't intend to ever return to user land anyway)
+        */
+
+       ldil            L%PA(swapper_pg_dir),%r4
+       ldo             R%PA(swapper_pg_dir)(%r4),%r4
+       mtctl           %r4,%cr24       /* Initialize kernel root pointer */
+       mtctl           %r4,%cr25       /* Initialize user root pointer */
+
+       /* Clear sr4-sr7 */
+
+       mtsp    %r0, %sr4
+       mtsp    %r0, %sr5
+       mtsp    %r0, %sr6
+       mtsp    %r0, %sr7
+
+       tovirt  %r30        /* make sp virtual */
+
+       rsm 8,%r0           /* Clear Q bit */
+       ldi     1,%r1
+       mtctl   %r1,%cr29   /* Set trap code to "1" for HPMC */
+       mtctl   %r0,%cr30   /* Force interruptions to use hpmc stack */
+       ldil    L%PA(intr_save), %r1
+       ldo     R%PA(intr_save)(%r1), %r1
+       be      0(%sr7,%r1)
+       nop
+
+os_hpmc_fail:
+
+       /*
+        * Reset the system
+        *
+        * Some systems may lockup from a broadcast reset, so try the
+        * hversion PDC_BROADCAST_RESET() first.
+        * MP_FIXME: reset all processors if more than one central bus.
+        */
+
+       /* PDC_BROADCAST_RESET() */
+
+       ldo     PDC_BROADCAST_RESET(%r0),arg0
+       ldo     0(%r0),arg1                     /* do reset */
+
+       ldil    L%PA(os_hpmc_6),rp
+       bv      (%r3)                           /* call pdce_proc */
+       ldo     R%PA(os_hpmc_6)(rp),rp
+
+os_hpmc_6:
+
+       /*
+        * possible return values:
+        *  -1  non-existent procedure
+        *  -2  non-existent option
+        *  -16 unaligned stack
+        *
+        * If call returned, do a broadcast reset.
+        */
+
+       ldil    L%0xfffc0000,%r4        /* IO_BROADCAST */
+       ldo     5(%r0),%r5
+       stw     %r5,48(%r4)             /*  CMD_RESET to IO_COMMAND offset */
+
+       b .
+       nop
+
+       /* this label used to compute os_hpmc checksum */
+
+       .export os_hpmc_end, code
+
+os_hpmc_end:
+
+       nop
diff --git a/arch/parisc/kernel/init_task.c b/arch/parisc/kernel/init_task.c
new file mode 100644 (file)
index 0000000..a838548
--- /dev/null
@@ -0,0 +1,29 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 16384-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union task_union init_task_union 
+       __attribute__((section("init_task"), aligned(4096))) = { INIT_TASK(init_task_union.task) };
+
+unsigned long swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(4096))) = { 0, };
+#ifdef __LP64__
+unsigned long pmd0[PTRS_PER_PMD] __attribute__ ((aligned(4096))) = { 0, };
+#endif
+unsigned long pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((aligned(4096))) = { 0, };
diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c
new file mode 100644 (file)
index 0000000..f625381
--- /dev/null
@@ -0,0 +1,398 @@
+
+/* Copyright (c) 1999 The Puffin Group */
+/* Written by David Kennedy and Alex deVries */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/pdc.h>
+
+/*
+** Debug options
+**    DEBUG_PAT        Dump details which PDC PAT provides about ranges/devices.
+*/
+#undef DEBUG_PAT
+
+extern char *parisc_getHWtype(unsigned short hw_type);
+
+extern struct hp_device * register_module(void *hpa);
+extern void print_devices(char * buf);
+
+
+int pdc_hpa_processor(void *address);
+
+#ifndef __LP64__ 
+static u8 iodc_data[32] __attribute__ ((aligned (64)));
+static struct pdc_model model __attribute__ ((aligned (8)));
+#endif
+static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
+static struct pdc_hpa processor_hpa __attribute__ ((aligned (8)));
+static struct pdc_system_map module_result __attribute__ ((aligned (8)));
+static struct pdc_module_path module_path __attribute__ ((aligned (8)));
+
+#ifdef __LP64__
+#include <asm/pdcpat.h>
+
+int pdc_pat = 0;
+
+/*
+**  The module object is filled via PDC_PAT_CELL[Return Cell Module].
+**  If a module is found, register module will get the IODC bytes via
+**  pdc_iodc_read() using the PA view of conf_base_addr for the hpa parameter.
+**
+**  The IO view can be used by PDC_PAT_CELL[Return Cell Module]
+**  only for SBAs and LBAs.  This view will cause an invalid
+**  argument error for all other cell module types.
+**
+*/
+
+static int
+pat_query_module( ulong pcell_loc, ulong mod_index)
+{
+       extern int num_devices;
+       extern struct hp_device devices[];
+
+       pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+        struct hp_device * dev = &devices[num_devices];
+       uint64_t temp;             /* 64-bit scratch value */
+       long status;               /* PDC return value status */
+
+       /* return cell module (PA or Processor view) */
+       status = pdc_pat_cell_module(& pdc_result, pcell_loc, mod_index,
+               PA_VIEW, & pa_pdc_cell);
+
+       if (status != PDC_RET_OK) {
+               /* no more cell modules or error */
+               return status;
+       }
+
+       /*
+       ** save parameters in the hp_device
+       ** (The idea being the device driver will call pdc_pat_cell_module()
+       ** and store the results in it's own data structure.)
+       */
+       dev->pcell_loc = pcell_loc;
+       dev->mod_index = mod_index;
+
+       /* save generic info returned from the call */
+       /* REVISIT: who is the consumer of this? not sure yet... */
+       dev->mod_info = pa_pdc_cell.mod_info;   /* pass to PAT_GET_ENTITY() */
+       dev->pmod_loc = pa_pdc_cell.mod_location;
+       dev->mod_path = pa_pdc_cell.mod_path;
+
+       temp = pa_pdc_cell.cba;
+       register_module((void *) PAT_GET_CBA(temp));    /* fills in dev->hpa */
+
+#ifdef DEBUG_PAT
+       /* dump what we see so far... */
+       switch (PAT_GET_ENTITY(dev->mod_info)) {
+               ulong i;
+
+       case PAT_ENTITY_PROC:
+               printk ("PAT_ENTITY_PROC: id_eid 0x%lx\n", pa_pdc_cell.mod[0]);
+               break;
+
+       case PAT_ENTITY_MEM:
+               printk ("PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
+                       pa_pdc_cell.mod[0],
+                       pa_pdc_cell.mod[1],
+                       pa_pdc_cell.mod[2]);
+               break;
+       case PAT_ENTITY_CA:
+               printk ("PAT_ENTITY_CA: %ld\n",pcell_loc);
+               break;
+
+       case PAT_ENTITY_PBC:
+               printk ("PAT_ENTITY_PBC: ");
+               goto print_ranges;
+
+       case PAT_ENTITY_SBA:
+               printk ("PAT_ENTITY_SBA: ");
+               goto print_ranges;
+
+       case PAT_ENTITY_LBA:
+               printk ("PAT_ENTITY_LBA: ");
+
+print_ranges:
+               printk ("ranges %ld\n", pa_pdc_cell.mod[1]);
+               for (i = 0; i < pa_pdc_cell.mod[1]; i++) {
+                       printk ("       %ld: 0x%016lx 0x%016lx 0x%016lx\n", i,
+                               pa_pdc_cell.mod[2+i*3], /* type */
+                               pa_pdc_cell.mod[3+i*3], /* start */
+                               pa_pdc_cell.mod[4+i*3]);        /* finish (ie end) */
+               }
+               printk("\n");
+               break;
+       }
+#endif /* DEBUG_PAT */
+       return PDC_RET_OK;
+}
+
+
+static int do_pat_inventory(void)
+{
+       ulong mod_index=0;
+       int status;
+       ulong cell_num;
+       ulong pcell_loc;
+
+       pdc_pat = (pdc_pat_cell_get_number(&pdc_result) == PDC_OK);
+       if (!pdc_pat)
+       {
+               return 0;
+       }
+
+       cell_num = pdc_result[0];       /* Cell number call was made */
+
+       /* As of PDC PAT ARS 2.5, ret[1] is NOT architected! */
+       pcell_loc = pdc_result[1];      /* Physical location of the cell */
+
+#ifdef DEBUG_PAT
+       printk("CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_num, pcell_loc);
+#endif
+
+        status = pdc_pat_cell_num_to_loc(&pdc_result, cell_num);
+        if (status == PDC_BAD_OPTION)
+       {
+               /* Prelude (and it's successors: Lclass, A400/500) only
+               ** implement PDC_PAT_CELL sub-options 0 and 2.
+               ** "Home cook'n is best anyhow!"
+               */
+       } else if (PDC_OK == status) {
+               /* so far only Halfdome supports this */
+               pcell_loc = pdc_result[0];
+       } else {
+               panic("WTF? CELL_GET_NUMBER give me invalid cell number?");
+       }
+
+       while (PDC_RET_OK == pat_query_module(pcell_loc, mod_index))
+       {
+               mod_index++;
+       }
+
+       return mod_index;
+}
+#endif /* __LP64__ */
+
+static int do_newer_workstation_inventory(void)
+{
+       long status;
+       int i, num = 0;
+
+       /* So the idea here is to simply try one SYSTEM_MAP call.  If 
+          that one works, great, otherwise do it another way */
+
+       status = pdc_system_map_find_mods(&module_result,&module_path,0);
+
+       if (status == PDC_RET_OK) {
+               /* This is for newer non-PDC-PAT boxes */
+
+               printk("a newer box...\n");
+               for(i=0, status=PDC_RET_OK; status != PDC_RET_NE_PROC && 
+                       status != PDC_RET_NE_MOD ;i++) {
+
+                       status = pdc_system_map_find_mods(&module_result,&module_path,i);
+                       if (status == PDC_RET_OK) {
+                               num++;
+                               register_module(module_result.mod_addr);
+                       }
+               }
+       }
+
+       return (num > 0);
+}
+
+#ifndef __LP64__
+static struct  pdc_memory_map r_addr __attribute__ ((aligned (8)));
+
+static int really_do_oldhw_inventory(void)
+{
+       int i, mod, num = 0;
+       int status;
+       unsigned int hw_type;
+       unsigned int func;
+
+       /* This is undocumented at the time of writing, but basically 
+          we're setting up mod_path so that bc[0..4]=0xff, and step
+          through mod to get the "Path Structure for GSC Modules".  If
+          it works, use the returned HPA and determine the hardware type.  */
+
+       for (i=0;i<6;i++) module_path.bc[i]=0xff;
+
+       for (mod=0;mod<16;mod++) {
+               char *stype = NULL;
+
+               module_path.mod=mod;
+               status = pdc_mem_map_hpa(&r_addr, &module_path);
+               if (status!=PDC_RET_OK) continue;
+       
+               status = pdc_iodc_read(&pdc_result,(void *) r_addr.hpa,
+                       0, &iodc_data,32 );
+               if (status!=PDC_RET_OK) continue;
+               hw_type = iodc_data[3]&0x1f;
+
+               switch (hw_type)
+               {
+               case HPHW_NPROC:        /* 0 */
+                       stype="Processor"; break;
+
+               case HPHW_MEMORY:       /* 1 */
+                       stype="Memory"; break;
+
+               case HPHW_B_DMA:        /* 2 */
+                       stype="Type B DMA"; break;
+
+               case HPHW_A_DMA:        /* 4 */
+                       stype="Type A DMA"; break;
+
+               case HPHW_A_DIRECT:     /* 5 */
+                       stype="Type A Direct"; break;
+
+               case HPHW_BCPORT:       /* 7 */
+                       stype="Bus Converter Port"; break;
+
+               case HPHW_CONSOLE:      /* 9 */
+                       stype="Console"; break;
+
+               case HPHW_FIO:          /* 10 - Graphics */
+                       stype="Foreign I/O (Graphics)"; break;
+
+               case HPHW_BA:           /* 11 - Bus Adapter */
+                       stype="Bus Adapter"; break;
+
+               case HPHW_IOA:          /* 12 */
+                       stype="I/O Adapter"; break;
+
+               case HPHW_BRIDGE:       /* 13 */
+                       stype="Bridge"; break;
+
+               case HPHW_FABRIC:       /* 14 */
+                       stype="Fabric"; break;
+
+               case HPHW_FAULTY:       /* 31 */
+                       stype="Faulty HW"; break;
+
+               case HPHW_OTHER:        /* 42 */
+               default:        
+                       printk("Don't know this hw_type: %d\n", hw_type);
+                       break;
+               }
+
+               // This is kluged. But don't want to replicate code for
+               // most of the above cases.
+               if (stype) {
+#ifdef DBG_PDC_QUERY
+                       // parisc/kernel/drivers.c
+                       extern int num_devices; 
+                       extern struct hp_device devices[];
+                       struct hp_hardware *h;
+#endif
+
+                       status = pdc_mem_map_hpa(&r_addr, &module_path);
+                       if (status==PDC_RET_OK && register_module((void *) r_addr.hpa) != NULL)
+                                       num++;
+
+
+                   if (hw_type == HPHW_BA) {
+                       /* Now, we're checking for devices for each
+                          module.  I seem to think that the
+                          modules in question are Lasi (2), 2nd Lasi (6)
+                          Wax (5).  To do this, set bc[5]=0, and set
+                          bc[4] to the module, and step through the
+                          functions. */
+
+                       for (i=0;i<4;i++) module_path.bc[i]=0xff;
+                       module_path.bc[4]=mod;
+                       for (func=0;func<16;func++) {
+                               module_path.mod = func;
+                               module_path.bc[5]=0;
+                               status = pdc_mem_map_hpa(&r_addr, &module_path);
+                               if (status!=PDC_RET_OK) continue;
+                               if (register_module((void *) r_addr.hpa) != NULL) 
+                                       num++;
+                       }
+               }
+               // reset module_path.bc[]
+               for (i=0;i<6;i++) module_path.bc[i]=0xff;
+
+
+#ifdef DBG_PDC_QUERY
+//
+// Let print_devices() dump everything which is registered.
+//
+                       h = devices[num_devices-1].reference;
+
+                       if (h) stype = h->name;
+                       printk("Found %s at %d\n", stype, module_path.mod);
+#endif
+               }
+       }
+       return num;
+}
+
+static int
+do_old_inventory(void)
+{
+        unsigned int bus_id;
+       long status;
+       int ok = 0;
+
+       printk(" an older box...\n");
+
+       /* Here, we're going to check the model, and decide
+          if we should even bother trying. */
+
+       status = pdc_model_info(&model);
+
+       bus_id = (model.hversion >> (4+7) ) &0x1f;
+
+       /* Here, we're checking the HVERSION of the CPU.
+          We're only checking the 0th CPU, since it'll
+          be the same on an SMP box. */
+
+       switch (bus_id) {
+               case 0x4:       /* 720, 730, 750, 735, 755 */
+               case 0x6:       /* 705, 710 */
+               case 0x7:       /* 715, 725 */
+               case 0x8:       /* 745, 747, 742 */
+               case 0xA:       /* 712 and similiar */
+               case 0xC:       /* 715/64, at least */
+
+               /* Do inventory using MEM_MAP */
+               really_do_oldhw_inventory();
+               ok = 1;
+               break;
+       default:        /* Everything else */
+               printk("This is a very very old machine, with a bus_id of 0x%x.\n",bus_id);
+               panic("This will probably never run Linux.\n");
+       }
+
+       return ok;
+}
+
+#endif /* !__LP64__ */
+
+void do_inventory(void){
+       if((pdc_hpa_processor(&processor_hpa))<0){
+               printk(KERN_INFO "Couldn't get the HPA of the processor.\n" );
+       }
+
+       printk("Searching for devices in PDC firmware... ");
+       printk("processor hpa 0x%lx\n", processor_hpa.hpa);
+
+       if (!(
+               do_newer_workstation_inventory()
+#ifdef __LP64__
+               || do_pat_inventory()
+#else /* __LP64__ */
+               || do_old_inventory()
+#endif /* __LP64__ */
+           ))
+       {
+           panic("I can't get the hardware inventory on this machine");
+       }
+       print_devices(NULL);
+}
+
diff --git a/arch/parisc/kernel/iosapic.c b/arch/parisc/kernel/iosapic.c
new file mode 100644 (file)
index 0000000..c38fe0b
--- /dev/null
@@ -0,0 +1,1101 @@
+/*
+** I/O Sapic Driver - PCI interrupt line support
+**
+**      (c) Copyright 1999 Grant Grundler
+**      (c) Copyright 1999 Hewlett-Packard Company
+**
+**      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.
+**
+** The I/O sapic driver manages the Interrupt Redirection Table which is
+** the control logic to convert PCI line based interrupts into a Message
+** Signaled Interrupt (aka Transaction Based Interrupt, TBI).
+**
+** Acronyms
+** --------
+** HPA  Hard Physical Address (aka MMIO address)
+** IRQ  Interrupt ReQuest. Implies Line based interrupt.
+** IRT Interrupt Routing Table (provided by PAT firmware)
+** IRdT Interrupt Redirection Table. IRQ line to TXN ADDR/DATA
+**      table which is implemented in I/O SAPIC.
+** ISR  Interrupt Service Routine. aka Interrupt handler.
+** MSI Message Signaled Interrupt. PCI 2.2 functionality.
+**      aka Transaction Based Interrupt (or TBI).
+** PA   Precision Architecture. HP's RISC architecture.
+** RISC Reduced Instruction Set Computer.
+**
+**
+** What's a Message Signalled Interrupt?
+** -------------------------------------
+** MSI is a write transaction which targets a processor and is similar
+** to a processor write to memory or MMIO. MSIs can be generated by I/O
+** devices as well as processors and require *architecture* to work.
+**
+** PA only supports MSI. So I/O subsystems must either natively generate
+** MSIs (e.g. GSC or HP-PB) or convert line based interrupts into MSIs
+** (e.g. PCI and EISA).  IA64 supports MSIs via a "local SAPIC" which
+** acts on behalf of a processor.
+**
+** MSI allows any I/O device to interrupt any processor. This makes
+** load balancing of the interrupt processing possible on an SMP platform.
+** Interrupts are also ordered WRT to DMA data.  It's possible on I/O
+** coherent systems to completely eliminate PIO reads from the interrupt
+** path. The device and driver must be designed and implemented to
+** guarantee all DMA has been issued (issues about atomicity here)
+** before the MSI is issued. I/O status can then safely be read from
+** DMA'd data by the ISR.
+**
+**
+** PA Firmware
+** -----------
+** PA-RISC platforms have two fundementally different types of firmware.
+** For PCI devices, "Legacy" PDC initializes the "INTERRUPT_LINE" register
+** and BARs similar to a traditional PC BIOS.
+** The newer "PAT" firmware supports PDC calls which return tables.
+** PAT firmware only initializes PCI Console and Boot interface.
+** With these tables, the OS can progam all other PCI devices.
+**
+** One such PAT PDC call returns the "Interrupt Routing Table" (IRT).
+** The IRT maps each PCI slot's INTA-D "output" line to an I/O SAPIC
+** input line.  If the IRT is not available, this driver assumes
+** INTERRUPT_LINE register has been programmed by firmware. The latter
+** case also means online addition of PCI cards can NOT be supported
+** even if HW support is present.
+**
+** All platforms with PAT firmware to date (Oct 1999) use one Interrupt
+** Routing Table for the entire platform.
+**
+** Where's the iosapic?
+** --------------------
+** I/O sapic is part of the "Core Electronics Complex". And on HP platforms
+** it's integrated as part of the PCI bus adapter, "lba".  So no bus walk
+** will discover I/O Sapic. I/O Sapic driver learns about each device
+** when lba driver advertises the presence of the I/O sapic by calling
+** iosapic_register().
+**
+**
+** IRQ region notes
+** ----------------
+** The data passed to iosapic_interrupt() is per IRQ line.
+** Each IRQ line will get one txn_addr/data pair. Thus each IRQ region,
+** will have several txn_addr/data pairs (up to 7 for current I/O SAPIC
+** implementations).  The IRQ region "sysdata" will NOT be directly passed
+** to the interrupt handler like GSCtoPCI (dino.c).
+**
+** iosapic interrupt handler will NOT call do_irq_mask().
+** It doesn't need to read a bit mask to determine which IRQ line was pulled
+** since it already knows based on vector_info passed to iosapic_interrupt().
+**
+** One IRQ number represents both an IRQ line and a driver ISR.
+** The I/O sapic driver can't manage shared IRQ lines because
+** additional data besides the IRQ number must be passed via
+** irq_region_ops. do_irq() and request_irq() must manage
+** a sharing a bit in the mask.
+**
+** iosapic_interrupt() replaces do_irq_mask() and calls do_irq().
+** Which IRQ line was asserted is already known since each
+** line has unique data associated with it. We could omit
+** iosapic_interrupt() from the calling path if it did NOT need
+** to write EOI. For unshared lines, it really doesn't.
+**
+** Unfortunately, can't optimize out EOI if IRQ line isn't "shared".
+** N-class console "device" and some sort of heartbeat actually share
+** one line though only one driver is registered...<sigh>...this was
+** true for HP-UX at least. May not be true for parisc-linux.
+**
+**
+** Overview of exported iosapic functions
+** --------------------------------------
+** (caveat: code isn't finished yet - this is just the plan)
+**
+** iosapic_init:
+**   o initialize globals (lock, etc)
+**   o try to read IRT. Presence of IRT determines if this is
+**     a PAT platform or not.
+**
+** iosapic_register():
+**   o create iosapic_info instance data structure
+**   o allocate vector_info array for this iosapic
+**   o initialize vector_info - read corresponding IRdT?
+**
+** iosapic_xlate_pin: (only called by fixup_irq for PAT platform)
+**   o intr_pin = read cfg (INTERRUPT_PIN);
+**   o if (device under PCI-PCI bridge)
+**               translate slot/pin
+**
+** iosapic_fixup_irq:
+**   o if PAT platform (IRT present)
+**        intr_pin = iosapic_xlate_pin(isi,pcidev):
+**         intr_line = find IRT entry(isi, PCI_SLOT(pcidev), intr_pin)
+**         save IRT entry into vector_info later
+**         write cfg INTERRUPT_LINE (with intr_line)?
+**     else
+**         intr_line = pcidev->irq
+**         IRT pointer = NULL
+**     endif
+**   o locate vector_info (needs: isi, intr_line)
+**   o allocate processor "irq" and get txn_addr/data
+**   o request_irq(processor_irq,  iosapic_interrupt, vector_info,...)
+**   o pcidev->irq = isi->isi_region...base + intr_line;
+**
+** iosapic_interrupt:
+**   o call do_irq(vector->isi->irq_region, vector->irq_line, regs)
+**   o assume level triggered and write EOI
+**
+** iosapic_enable_irq:
+**   o clear any pending IRQ on that line
+**   o enable IRdT - call enable_irq(vector[line]->processor_irq)
+**   o write EOI in case line is already asserted.
+**
+** iosapic_disable_irq:
+**   o disable IRdT - call disable_irq(vector[line]->processor_irq)
+**
+** FIXME: mask/unmask
+*/
+
+
+/* FIXME: determine which include files are really needed */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>         /* pci cfg accessor functions  */
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>   /* irqaction */
+#include <linux/irq.h>         /* irq_region support */
+
+#include <asm/byteorder.h>     /* get in-line asm for swab */
+#include <asm/pdc.h>
+#include <asm/pdcpat.h>
+#include <asm/page.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/gsc.h>           /* gsc_read/write functions */
+
+#include <asm/iosapic.h>
+#include "./iosapic_private.h"
+
+#define MODULE_NAME "iosapic"
+
+/* "local" compile flags */
+#undef IOSAPIC_CALLBACK
+#undef PCI_BRIDGE_FUNCS
+#undef DEBUG_IOSAPIC
+#undef DEBUG_IOSAPIC_IRT
+
+
+#ifdef DEBUG_IOSAPIC
+static char assert_buf[128];
+
+static int
+assert_failed (char *a, char *f, int l)
+{
+        sprintf(assert_buf,
+                       "ASSERT(%s) failed!\nline %d in %s\n",
+                       a,      /* assertion text */
+                       l,      /* line number */
+                       f);     /* file name */
+        panic(assert_buf);
+       return 0;
+}
+
+#undef ASSERT
+#define ASSERT(EX) { if (!(EX)) assert_failed(# EX, __FILE__, __LINE__); }
+
+#define DBG(x...) printk(x)
+
+#else /* DEBUG_IOSAPIC */
+
+#define DBG(x...)
+#define ASSERT(EX)
+
+#endif /* DEBUG_IOSAPIC */
+
+#ifdef DEBUG_IOSAPIC_IRT
+#define DBG_IRT(x...) printk(x)
+#else
+#define DBG_IRT(x...)
+#endif
+
+
+#define READ_U8(addr)  gsc_readb(addr)
+#define READ_U16(addr) le16_to_cpu(gsc_readw((u16 *) (addr)))
+#define READ_U32(addr) le32_to_cpu(gsc_readl((u32 *) (addr)))
+#define READ_REG16(addr) gsc_readw((u16 *) (addr))
+#define READ_REG32(addr) gsc_readl((u32 *) (addr))
+#define WRITE_U8(value, addr) gsc_writeb(value, addr)
+#define WRITE_U16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr))
+#define WRITE_U32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr))
+#define WRITE_REG16(value, addr) gsc_writew(value, (u16 *) (addr))
+#define WRITE_REG32(value, addr) gsc_writel(value, (u32 *) (addr))
+
+
+#define IOSAPIC_REG_SELECT              0
+#define IOSAPIC_REG_WINDOW              0x10
+#define IOSAPIC_REG_EOI                 0x40
+
+#define IOSAPIC_REG_VERSION            0x1
+
+#define IOSAPIC_IRDT_ENTRY(idx)                (0x10+(idx)*2)
+#define IOSAPIC_IRDT_ENTRY_HI(idx)     (0x11+(idx)*2)
+
+/*
+** FIXME: revisit which GFP flags we should really be using.
+**     GFP_KERNEL includes __GFP_WAIT flag and that may not
+**     be acceptable. Since this is boot time, we shouldn't have
+**     to wait ever and this code should (will?) never get called
+**     from the interrrupt context.
+*/
+#define        IOSAPIC_KALLOC(a_type, cnt) \
+                       (a_type *) kmalloc(sizeof(a_type)*(cnt), GFP_KERNEL)
+#define IOSAPIC_FREE(addr, f_type, cnt) kfree((void *)addr)
+
+
+#define        IOSAPIC_LOCK(lck)       spin_lock_irqsave(lck, irqflags)
+#define        IOSAPIC_UNLOCK(lck)     spin_unlock_irqrestore(lck, irqflags)
+
+
+#define IOSAPIC_VERSION_MASK            0x000000ff
+#define IOSAPIC_VERSION_SHIFT           0x0
+#define        IOSAPIC_VERSION(ver)                            \
+               (int) ((ver & IOSAPIC_VERSION_MASK) >> IOSAPIC_VERSION_SHIFT)
+
+#define IOSAPIC_MAX_ENTRY_MASK          0x00ff0000
+
+#define IOSAPIC_MAX_ENTRY_SHIFT         0x10
+#define        IOSAPIC_IRDT_MAX_ENTRY(ver)                     \
+               (int) ((ver&IOSAPIC_MAX_ENTRY_MASK) >> IOSAPIC_MAX_ENTRY_SHIFT)
+
+/* bits in the "low" I/O Sapic IRdT entry */
+#define IOSAPIC_IRDT_ENABLE       0x10000
+#define IOSAPIC_IRDT_PO_LOW       0x02000
+#define IOSAPIC_IRDT_LEVEL_TRIG   0x08000
+#define IOSAPIC_IRDT_MODE_LPRI    0x00100
+
+/* bits in the "high" I/O Sapic IRdT entry */
+#define IOSAPIC_IRDT_ID_EID_SHIFT              0x10
+
+
+
+#define        IOSAPIC_EOI(eoi_addr, eoi_data) gsc_writel(eoi_data, eoi_addr)
+
+#if IOSAPIC_CALLBACK
+/*
+** Shouldn't use callback since SAPIC doesn't have an officially assigned
+** H or S version numbers. Slight long term risk the number chosen would
+** collide with something else.
+** But benefit is cleaner lba/sapic interface.
+** Might be worth it but for just use direct calls for now.
+**
+** Entry below is copied from lba driver.
+** Only thing different is hw_type.
+*/
+static struct pa_iodc_driver iosapic_driver_for[] = {
+       {HPHW_OTHER, 0x782, 0, 0x0000A, 0, 0x00,
+       DRIVER_CHECK_HWTYPE + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION,
+       "I/O Sapic", "",(void *) iosapic_callback},     
+       {0,0,0,0,0,0,
+       0,
+       (char *) NULL,(char *) NULL,(void *) NULL}                     
+};
+#endif /* IOSAPIO_CALLBACK */
+
+
+static struct iosapic_info *iosapic_list;
+static spinlock_t iosapic_lock;
+static int iosapic_count;
+
+
+/*
+** REVISIT: future platforms may have more than one IRT.
+** If so, the following three fields form a structure which
+** then be linked into a list. Names are chosen to make searching
+** for them easy - not necessarily accurate (eg "cell").
+**
+** Alternative: iosapic_info could point to the IRT it's in.
+** iosapic_register() could search a list of IRT's.
+*/
+static struct irt_entry *irt_cell;
+static size_t irt_num_entry;
+
+
+
+/*
+** iosapic_load_irt
+**
+** The "Get PCI INT Routing Table Size" option returns the number of 
+** entries in the PCI interrupt routing table for the cell specified 
+** in the cell_number argument.  The cell number must be for a cell 
+** within the caller's protection domain.
+**
+** The "Get PCI INT Routing Table" option returns, for the cell 
+** specified in the cell_number argument, the PCI interrupt routing 
+** table in the caller allocated memory pointed to by mem_addr.
+** We assume the IRT only contains entries for I/O SAPIC and
+** calculate the size based on the size of I/O sapic entries.
+**
+** The PCI interrupt routing table entry format is derived from the
+** IA64 SAL Specification 2.4.   The PCI interrupt routing table defines
+** the routing of PCI interrupt signals between the PCI device output
+** "pins" and the IO SAPICs' input "lines" (including core I/O PCI
+** devices).  This table does NOT include information for devices/slots
+** behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec.
+** for the architected method of routing of IRQ's behind PPB's.
+*/
+
+
+static int __init /* return number of entries as success/fail flag */
+iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
+{
+       struct pdc_pat_io_num pdc_io_num; /* PAT PDC return block */
+       long status;              /* PDC return value status */
+       struct irt_entry *table = NULL;  /* start of interrupt routing tbl */
+       unsigned long num_entries = 0UL;
+
+       ASSERT(NULL != irt);
+       /* FIXME ASSERT(((&pdc_io_num) & (0x3f)) == 0);  enforce 32-byte alignment */
+
+       /* Try PAT_PDC to get interrupt routing table size */
+       DBG(KERN_DEBUG "calling get_irt_size\n");
+       status = pdc_pat_get_irt_size( &pdc_io_num, cell_num);
+       DBG(KERN_DEBUG "get_irt_size: %ld\n", status);
+
+       switch(status) {
+
+       case PDC_RET_OK:        /* PAT box. Proceed to get the IRT */
+
+               /* save the number of entries in the table */
+               num_entries = pdc_io_num.num;
+               ASSERT(0UL != num_entries);
+
+               /*
+               ** allocate memory for interrupt routing table
+               ** This interface isn't really right. We are assuming
+               ** the contents of the table are exclusively
+               ** for I/O sapic devices.
+               */
+               table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
+               if (table == NULL) {
+                       printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n");
+                       return 0;
+               }
+
+               /* get PCI INT routing table */
+               status = pdc_pat_get_irt( (void *) table, cell_num);
+               DBG(KERN_DEBUG "pdc_pat_get_irt: %ld\n", status);
+               ASSERT(status == PDC_RET_OK);
+               break;
+
+       case PDC_RET_NE_PROC: /* Not a PAT platform. Try PDC_PCI extensions */
+               /*
+               ** C3000/J5000 (and similar) platforms with "legacy" PDC
+               ** will return exactly one IRT.
+               ** So if we have one, don't need to get it again.
+               */
+               if (NULL != irt_cell)
+                       break;
+
+               status = pdc_pci_irt_size( (void *)&pdc_io_num,
+                               /* elroy HPA (really a NOP) */ 0);
+               DBG(KERN_WARNING "pdc_pci_irt_size: %ld\n", status);
+
+               if (PDC_RET_OK != status) {
+                       /* Not a "legacy" system with I/O SAPIC either */
+                       return 0;
+               }
+
+               num_entries = pdc_io_num.num;
+               ASSERT(0UL != num_entries);
+
+               table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
+               if (table == NULL) {
+                       printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n");
+                       return 0;
+               }
+
+               status = pdc_pci_irt( (void *) &pdc_io_num,
+                               (void *) NULL, /* Elroy HPA - not used */
+                               (void *) table);
+
+               ASSERT(PDC_RET_OK == status);
+               break;
+
+       default:
+               printk(KERN_WARNING MODULE_NAME ": PDC_PAT_IO call failed with %ld\n", status);
+               break;
+       }
+
+       /* return interrupt table address */
+       *irt = table;
+
+
+#ifdef DEBUG_IOSAPIC_IRT
+       {
+       struct irt_entry *p = table;
+       int i;
+
+       printk(MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num);
+       printk(MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n",
+               table,
+               num_entries,
+               (int) sizeof(struct irt_entry));
+
+       for (i = 0 ; i < num_entries ; i++, p++)
+       {
+               printk(MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n",
+               p->entry_type, p->entry_length, p->interrupt_type,
+               p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id,
+               p->src_seg_id, p->dest_iosapic_intin,
+               ((u32 *) p)[2],
+               ((u32 *) p)[3]
+               );
+       }
+       }
+#endif /* DEBUG_IOSAPIC_IRT */
+
+       return num_entries;
+}
+
+
+
+void __init
+iosapic_init(void)
+{
+       /* init global data */
+       iosapic_lock = SPIN_LOCK_UNLOCKED;
+        iosapic_list = (struct iosapic_info *) NULL;
+       iosapic_count = 0;
+
+       DBG("iosapic_init()\n");
+
+       /*
+       **  get IRT for this cell.
+       */
+       irt_num_entry =  iosapic_load_irt(0L, &irt_cell);
+       if (0 == irt_num_entry)
+               irt_cell = NULL;        /* old PDC w/o iosapic */
+
+#ifdef IOSAPIC_CALLBACK
+       /*
+       ** When new I/O SAPICs are discovered, this callback
+       ** will get invoked. Implies lba driver will register
+       ** I/O Sapic as a device it "discovered" with faked
+       ** IODC data.
+       */
+       register_driver(iosapic_driver_for);
+#endif /* IOSAPIC_CALLBACK */
+}
+
+
+/*
+** Return the IRT entry in case we need to look something else up.
+*/
+static struct irt_entry *
+irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin)
+{
+       struct irt_entry *i = irt_cell;
+       int cnt;        /* track how many entries we've looked at */
+       u8 irq_devno = (slot << IRT_DEV_SHIFT) | (intr_pin-1);
+
+       DBG_IRT("irt_find_irqline() SLOT %d pin %d\n", slot, intr_pin);
+
+       for (cnt=0; cnt < irt_num_entry; cnt++, i++) {
+
+               /*
+               ** Validate: entry_type, entry_length, interrupt_type
+               **
+               ** Difference between validate vs compare is the former
+               ** should print debug info and is not expected to "fail"
+               ** on current platforms.
+               */
+               if (i->entry_type != IRT_IOSAPIC_TYPE) {
+                       DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d type %d\n", i, cnt, i->entry_type);
+                       continue;
+               }
+               
+               if (i->entry_length != IRT_IOSAPIC_LENGTH) {
+                       DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d  length %d\n", i, cnt, i->entry_length);
+                       continue;
+               }
+
+               if (i->interrupt_type != IRT_VECTORED_INTR) {
+                       DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry  %d interrupt_type %d\n", i, cnt, i->interrupt_type);
+                       continue;
+               }
+
+               /*
+               ** Compare: dest_iosapic_addr, src_bus_irq_devno
+               */
+               if (i->dest_iosapic_addr != (u64) ((long) isi->isi_hpa))
+                       continue;
+
+               if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno)
+                       continue;
+
+               /*
+               ** Ignore: src_bus_id and rc_seg_id correlate with
+               **         iosapic_info->isi_hpa on HP platforms.
+               **         If needed, pass in "PFA" (aka config space addr)
+               **         instead of slot.
+               */
+
+               /* Found it! */
+               return i;
+       }
+
+       printk(KERN_WARNING MODULE_NAME ": 0x%p : no IRT entry for slot %d, pin %d\n",
+                       isi->isi_hpa, slot, intr_pin);
+       return NULL;
+}
+
+
+/*
+** xlate_pin() supports the skewing of IRQ lines done by subsidiary bridges.
+** Legacy PDC already does this translation for us and stores it in INTR_LINE.
+**
+** PAT PDC needs to basically do what legacy PDC does:
+** o read PIN
+** o adjust PIN in case device is "behind" a PPB
+**     (eg 4-port 100BT and SCSI/LAN "Combo Card")
+** o convert slot/pin to I/O SAPIC input line.
+**
+** HP platforms only support:
+** o one level of skewing for any number of PPBs
+** o only support PCI-PCI Bridges.
+*/
+static struct irt_entry *
+iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev)
+{
+       u8 intr_pin, intr_slot;
+
+       (void) pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);
+
+       DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n", PCI_SLOT(pcidev->devfn), intr_pin);
+
+       if (0 == intr_pin)
+       {
+               /*
+               ** The device does NOT support/use IRQ lines.
+               */
+               return NULL;
+       }
+
+       /* Check if pcidev behind a PPB */
+       if (NULL != pcidev->bus->self)
+       {
+               /* Convert pcidev INTR_PIN into something we
+               ** can lookup in the IRT.
+               */
+#ifdef PCI_BRIDGE_FUNCS
+               /*
+               ** Proposal #1:
+               **
+               ** call implementation specific translation function
+               ** This is architecturally "cleaner". HP-UX doesn't
+               ** support other secondary bus types (eg. E/ISA) directly.
+               ** May be needed for other processor (eg IA64) architectures
+               ** or by some ambitous soul who wants to watch TV.
+               */
+               if (pci_bridge_funcs->xlate_intr_line) {
+                       intr_pin = (*pci_bridge_funcs->xlate_intr_line)(pcidev);
+               }
+#else  /* PCI_BRIDGE_FUNCS */
+               struct pci_bus *p = pcidev->bus;
+               /*
+               ** Proposal #2:
+               ** The "pin" is skewed ((pin + dev - 1) % 4).
+               **
+               ** This isn't very clean since I/O SAPIC must assume:
+               **   - all platforms only have PCI busses.
+               **   - only PCI-PCI bridge (eg not PCI-EISA, PCI-PCMCIA)
+               **   - IRQ routing is only skewed once regardless of
+               **     the number of PPB's between iosapic and device.
+               **     (Bit3 expansion chassis follows this rule)
+               **
+               ** Advantage is it's really easy to implement.
+               */
+               intr_pin = ((intr_pin-1)+PCI_SLOT(pcidev->devfn)) % 4;
+               intr_pin++;     /* convert back to INTA-D (1-4) */
+#endif /* PCI_BRIDGE_FUNCS */
+
+               /*
+               ** Locate the host slot the PPB nearest the Host bus
+               ** adapter.
+               */
+               while (NULL != p->parent->self)
+                       p = p->parent;
+
+               intr_slot = PCI_SLOT(p->self->devfn);
+       } else {
+               intr_slot = PCI_SLOT(pcidev->devfn);
+       }
+       DBG_IRT("iosapic_xlate_pin:  bus %d slot %d pin %d\n",
+                               pcidev->bus->secondary, intr_slot, intr_pin);
+
+       return irt_find_irqline(isi, intr_slot, intr_pin);
+}
+
+
+static void
+iosapic_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct vector_info *vi = (struct vector_info *)dev_id;
+       extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
+       int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline;
+
+       DBG("iosapic_interrupt(): irq %d line %d eoi %p\n", irq, vi->vi_irqline,
+                               vi->vi_eoi_addr);
+
+/* FIXME: Need to mask/unmask? processor IRQ is already masked... */
+       do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs);
+
+       /*
+       ** PCI only supports level triggered in order to share IRQ lines.
+       ** I/O SAPIC must always issue EOI.
+       */
+       IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data);
+}
+
+
+int
+iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
+{
+       struct iosapic_info *isi = (struct iosapic_info *)isi_obj;
+       struct irt_entry *irte = NULL;  /* only used if PAT PDC */
+       struct vector_info *vi;
+       int isi_line;   /* line used by device */
+       int tmp;
+
+       if (NULL == isi) {
+               printk(KERN_WARNING MODULE_NAME ": 0x%p hpa not registered\n", isi->isi_hpa);
+               return(-1);
+       }
+
+       /* lookup IRT entry for isi/slot/pin set */
+       irte = iosapic_xlate_pin(isi, pcidev);
+       if (NULL == irte) {
+               return(-1);
+       }
+       DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n",
+               irte,
+               irte->entry_type,
+               irte->entry_length,
+               irte->polarity_trigger,
+               irte->src_bus_irq_devno,
+               irte->src_bus_id,
+               irte->src_seg_id,
+               irte->dest_iosapic_intin,
+               (u32) irte->dest_iosapic_addr);
+       isi_line = irte->dest_iosapic_intin;
+
+       /* get vector info for this input line */
+       ASSERT(NULL != isi->isi_vector);
+       vi = &(isi->isi_vector[isi_line]);
+       DBG_IRT("iosapic_fixup_irq:  line %d vi 0x%p\n", isi_line, vi);
+       vi->vi_irte = irte;
+
+       /* Allocate processor IRQ */
+       vi->vi_txn_irq = txn_alloc_irq();
+
+/* XXX/FIXME The txn_alloc_irq() code and related code should be moved
+** to enable_irq(). That way we only allocate processor IRQ bits
+** for devices that actually have drivers claiming them.
+** Right now we assign an IRQ to every PCI device present regardless
+** of whether it's used or not.
+*/
+       if (vi->vi_txn_irq < 0)
+               panic("I/O sapic: couldn't get TXN IRQ\n");
+
+       /* enable_irq() will use txn_* to program IRdT */
+       vi->vi_txn_addr = txn_alloc_addr(vi->vi_txn_irq);
+       vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8);
+        ASSERT(vi->vi_txn_data < 256);  /* matches 8 above */
+
+       tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, "iosapic", vi);
+       ASSERT(tmp == 0);
+
+       vi->vi_eoi_addr = ((void *) isi->isi_hpa) + IOSAPIC_REG_EOI;
+       vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline);
+
+       ASSERT(NULL != isi->isi_region);
+       /*
+       ** pcidev->irq still needs to be virtualized.
+       */
+       pcidev->irq = isi->isi_region->data.irqbase + isi_line;
+
+       DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", PCI_SLOT(pcidev->devfn),
+       PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
+
+       return(pcidev->irq);
+}
+
+
+static void
+iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1)
+{
+       struct iosapic_info *isp = vi->vi_ios;
+       u8 idx = vi->vi_irqline;
+
+       /* point the window register to the lower word */
+       WRITE_U32(IOSAPIC_IRDT_ENTRY(idx), isp->isi_hpa+IOSAPIC_REG_SELECT);
+       *dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);
+
+       /* point the window register to the higher word */
+       WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(idx), isp->isi_hpa+IOSAPIC_REG_SELECT);
+       *dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);
+}
+
+
+static void
+iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1)
+{
+       struct iosapic_info *isp = vi->vi_ios;
+
+       ASSERT(NULL != isp);
+       ASSERT(NULL != isp->isi_hpa);
+       DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p  0x%x 0x%x\n",
+               vi->vi_irqline,
+               isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW,
+               dp0, dp1);
+
+       /* point the window register to the lower word */
+       WRITE_U32(IOSAPIC_IRDT_ENTRY(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT);
+       WRITE_U32( dp0, isp->isi_hpa+IOSAPIC_REG_WINDOW);
+
+       /* Read the window register to flush the writes down to HW  */
+       dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);
+
+       /* point the window register to the higher word */
+       WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT);
+       WRITE_U32( dp1, isp->isi_hpa+IOSAPIC_REG_WINDOW);
+
+       /* Read the window register to flush the writes down to HW  */
+       dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);
+}
+
+
+/*
+** set_irt prepares the data (dp0, dp1) according to the vector_info
+** and target cpu (id_eid).  dp0/dp1 are then used to program I/O SAPIC
+** IRdT for the given "vector" (aka IRQ line).
+*/
+static void
+iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
+{
+       u32 mode = 0;
+       struct irt_entry *p = vi->vi_irte;
+       ASSERT(NULL != vi->vi_irte);
+
+       if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO)
+               mode |= IOSAPIC_IRDT_PO_LOW;
+
+       if (((p->polarity_trigger >> IRT_EL_SHIFT) & IRT_EL_MASK) == IRT_LEVEL_TRIG)
+               mode |= IOSAPIC_IRDT_LEVEL_TRIG;
+
+       /*
+       ** IA64 REVISIT
+       ** PA doesn't support EXTINT or LPRIO bits.
+       */
+
+       ASSERT(vi->vi_txn_data);
+       *dp0 = mode | (u32) vi->vi_txn_data;
+
+       /*
+       ** Extracting id_eid isn't a real clean way of getting it.
+       ** But the encoding is the same for both PA and IA64 platforms.
+       */
+#ifdef __LP64__
+       if (pdc_pat) {
+               /*
+               ** PAT PDC just hands it to us "right".
+               ** vi_txn_addr comes from cpu_data[x].txn_addr.
+               */
+               *dp1 = (u32) (vi->vi_txn_addr);
+       } else
+#endif
+       {
+               /* 
+               ** eg if base_addr == 0xfffa0000),
+               **    we want to get 0xa0ff0000.
+               **
+               ** eid  0x0ff00000 -> 0x00ff0000
+               ** id   0x000ff000 -> 0xff000000
+               */
+               *dp1 = (((u32)vi->vi_txn_addr & 0x0ff00000) >> 4) |
+                       (((u32)vi->vi_txn_addr & 0x000ff000) << 12);
+       }
+       DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1);
+}
+
+
+static void
+iosapic_disable_irq(void *irq_dev, int irq)
+{
+       ulong irqflags;
+       struct vector_info *vi = &(((struct vector_info *) irq_dev)[irq]);
+       u32 d0, d1;
+
+       ASSERT(NULL != vi);
+
+       IOSAPIC_LOCK(&iosapic_lock);
+
+#ifdef REVISIT_DESIGN_ISSUE
+/* 
+** XXX/FIXME
+
+disable_irq()/enable_irq(): drawback of using IRQ as a "handle"
+
+Current disable_irq interface only allows the irq_region support routines
+to manage sharing of "irq" objects.  The problem is the disable_irq()
+interface specifies which IRQ line needs to be disabled but does not
+identify the particular ISR which needs to be disabled.  IO sapic
+(and similar code in Dino) can only support one handler per IRQ
+since they don't further encode the meaning of the IRQ number.
+irq_region support has to hide it's implementation of "shared IRQ"
+behind a function call.
+
+Encoding the IRQ would be possible by I/O SAPIC but makes life really
+complicated for the IRQ handler and not help performance.
+
+Need more info on how Linux supports shared IRQ lines on a PC.
+*/
+#endif /* REVISIT_DESIGN_ISSUE */
+
+       iosapic_rd_irt_entry(vi, &d0, &d1);
+       d0 |= IOSAPIC_IRDT_ENABLE;
+       iosapic_wr_irt_entry(vi, d0, d1);
+
+       IOSAPIC_UNLOCK(&iosapic_lock);
+
+       /* disable ISR for parent */
+       disable_irq(vi->vi_txn_irq);
+}
+
+
+static void
+iosapic_enable_irq(void *dev, int irq)
+{
+       struct vector_info *vi = &(((struct vector_info *) dev)[irq]);
+       u32 d0, d1;
+
+       ASSERT(NULL != vi);
+       ASSERT(NULL != vi->vi_irte);
+
+       /* data is initialized by fixup_irq */
+       ASSERT(0 < vi->vi_txn_irq);
+       ASSERT(0UL != vi->vi_txn_addr);
+       ASSERT(0UL != vi->vi_txn_data);
+
+       iosapic_set_irt_data(vi, &d0, &d1);
+       iosapic_wr_irt_entry(vi, d0, d1);
+
+
+#ifdef DEBUG_IOSAPIC_IRT
+{
+u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);
+printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);
+while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));
+printk("\n");
+}
+
+printk("iosapic_enable_irq(): sel ");
+{
+       struct iosapic_info *isp = vi->vi_ios;
+
+       for (d0=0x10; d0<0x1e; d0++) {
+               /* point the window register to the lower word */
+               WRITE_U32(d0, isp->isi_hpa+IOSAPIC_REG_SELECT);
+
+               /* read the word */
+               d1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);
+               printk(" %x", d1);
+       }
+}
+printk("\n");
+#endif
+
+       /*
+       ** KLUGE: IRQ should not be asserted when Drivers enabling their IRQ.
+       **        PCI supports level triggered in order to share IRQ lines.
+       **
+       ** Issueing I/O SAPIC an EOI causes an interrupt iff IRQ line is
+       ** asserted.
+       */
+       IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data);
+}
+
+
+static void
+iosapic_mask_irq(void *dev, int irq)
+{
+       BUG();
+}
+
+
+static void
+iosapic_unmask_irq(void *dev, int irq)
+{
+       BUG();
+}
+
+
+static struct irq_region_ops iosapic_irq_ops = {
+       iosapic_disable_irq,
+       iosapic_enable_irq,
+       iosapic_mask_irq,
+       iosapic_unmask_irq
+};
+
+
+/*
+** squirrel away the I/O Sapic Version
+*/
+static unsigned int
+iosapic_rd_version(struct iosapic_info *isi)
+{
+       ASSERT(isi);
+       ASSERT(isi->isi_hpa);
+
+       /* point window to the version register */
+       WRITE_U32(IOSAPIC_REG_VERSION, isi->isi_hpa+IOSAPIC_REG_SELECT);
+
+       /* now read the version register */
+       return (READ_U32(isi->isi_hpa+IOSAPIC_REG_WINDOW));
+}
+
+
+#ifndef IOSAPIC_CALLBACK
+/*
+** iosapic_register() is the alternative to iosapic_driver_for().
+** (Only one or the other should be implemented.)
+*/
+
+/*
+** iosapic_register() is called by "drivers" with an integrated I/O SAPIC.
+** Caller must be certain they have an I/O SAPIC and know it's MMIO address.
+**
+**     o allocate iosapic_info and add it to the list
+**     o read iosapic version and squirrel that away
+**     o read size of IRdT.
+**     o allocate and initialize isi_vector[]
+**     o allocate isi_region (registers region handlers)
+*/
+void *
+iosapic_register(void *hpa)
+{
+       struct iosapic_info *isi = NULL;
+       struct irt_entry *irte = irt_cell;
+       struct vector_info *vip;
+       int cnt;        /* track how many entries we've looked at */
+
+       /*
+       ** Astro based platforms can't support PCI OLARD if they
+       ** implement the legacy PDC (not PAT). Though Legacy PDC
+       ** supports an IRT, LBA's with no device under them
+       ** are *not* listed in the IRT.
+       ** Search the IRT and ignore iosapic's which aren't
+       ** in the IRT.
+       */
+       ASSERT(NULL != irte);   /* always have built-in devices */
+       for (cnt=0; cnt < irt_num_entry; cnt++, irte++) {
+               ASSERT(IRT_IOSAPIC_TYPE == irte->entry_type);
+               /*
+               ** We need sign extension of the hpa on 32-bit kernels.
+               ** The address in the IRT is *always* 64 bit and really
+               ** is an unsigned quantity (like all physical addresses).
+               */ 
+               if (irte->dest_iosapic_addr == (s64) ((long) hpa))
+                       break;
+       }
+
+       if (cnt  >= irt_num_entry)
+               return (NULL);
+
+       if ((isi = IOSAPIC_KALLOC(struct iosapic_info, 1)) == NULL) {
+               BUG();
+               return (NULL);
+       }
+
+       memset(isi, 0, sizeof(struct iosapic_info));
+
+       isi->isi_hpa         = (unsigned char *) hpa;
+       isi->isi_version     = iosapic_rd_version(isi);
+       isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
+
+       vip = isi->isi_vector =
+                IOSAPIC_KALLOC(struct vector_info, isi->isi_num_vectors);
+
+       if (vip == NULL) {
+               IOSAPIC_FREE(isi, struct iosapic_info, 1);
+               return (NULL);
+       }
+
+       memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors);
+
+       /*
+       ** Initialize vector array
+       */
+       for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
+               vip->vi_irqline = (unsigned char) cnt;
+               vip->vi_ios = isi;
+       }
+
+       isi->isi_region = alloc_irq_region(isi->isi_num_vectors,
+                               &iosapic_irq_ops, IRQ_REG_DIS|IRQ_REG_MASK,
+                               "I/O Sapic", (void *) isi->isi_vector);
+
+       ASSERT(NULL != isi->isi_region);
+       return ((void *) isi);
+}
+#endif /* !IOSAPIC_CALLBACK */
+
+
+
+#ifdef DEBUG_IOSAPIC
+
+static void
+iosapic_prt_irt(void *irt, long num_entry)
+{
+       unsigned int i, *irp = (unsigned int *) irt;
+
+       ASSERT(NULL != irt);
+
+       printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry);
+
+       for (i=0; i<num_entry; i++, irp += 4) {
+               printk(KERN_DEBUG "%p : %2d %.8x %.8x %.8x %.8x\n",
+                                       irp, i, irp[0], irp[1], irp[2], irp[3]);
+       }
+}
+
+
+static void
+iosapic_prt_vi(struct vector_info *vi)
+{
+       ASSERT(NULL != vi);
+
+       printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->vi_irqline, vi);
+       printk(KERN_DEBUG "\t\tvi_status:        %.4x\n", vi->vi_status);
+       printk(KERN_DEBUG "\t\tvi_txn_irq:  %d\n",  vi->vi_txn_irq);
+       printk(KERN_DEBUG "\t\tvi_txn_addr: %lx\n", vi->vi_txn_addr);
+       printk(KERN_DEBUG "\t\tvi_txn_data: %lx\n", vi->vi_txn_data);
+       printk(KERN_DEBUG "\t\tvi_eoi_addr: %p\n",  vi->vi_eoi_addr);
+       printk(KERN_DEBUG "\t\tvi_eoi_data: %x\n",  vi->vi_eoi_data);
+}
+
+
+static void
+iosapic_prt_isi(struct iosapic_info *isi)
+{
+       ASSERT(NULL != isi);
+       printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi);
+       printk(KERN_DEBUG "\t\tisi_hpa: %p\n", isi->isi_hpa);
+       printk(KERN_DEBUG "\t\tisi_satus:     %x\n", isi->isi_status);
+       printk(KERN_DEBUG "\t\tisi_version:   %x\n", isi->isi_version);
+       printk(KERN_DEBUG "\t\tisi_vector:    %p\n", isi->isi_vector);
+}
+#endif /* DEBUG_IOSAPIC */
diff --git a/arch/parisc/kernel/iosapic_private.h b/arch/parisc/kernel/iosapic_private.h
new file mode 100644 (file)
index 0000000..f310501
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+** This file is private to iosapic driver.
+** If stuff needs to be used by another driver, move it to a common file.
+**
+** WARNING: fields most data structures here are ordered to make sure
+**          they pack nicely for 64-bit compilation. (ie sizeof(long) == 8)
+*/
+
+
+/*
+** Interrupt Routing Stuff
+** -----------------------
+** The interrupt routing table consists of entries derived from
+** MP Specification Draft 1.5. There is one interrupt routing 
+** table per cell.  N- and L-class consist of a single cell.
+*/
+struct irt_entry {
+
+       /* Entry Type 139 identifies an I/O SAPIC interrupt entry */
+       u8 entry_type;
+
+       /* Entry Length 16 indicates entry is 16 bytes long */
+       u8 entry_length;
+
+       /* 
+       ** Interrupt Type of 0 indicates a vectored interrupt, 
+       ** all other values are reserved 
+       */
+       u8 interrupt_type;
+
+       /* 
+       ** PO and EL
+       ** Polarity of SAPIC I/O input signals: 
+       **    00 = Reserved 
+       **    01 = Active high 
+       **    10 = Reserved 
+       **    11 = Active low 
+       ** Trigger mode of SAPIC I/O input signals: 
+       **    00 = Reserved 
+       **    01 = Edge-triggered 
+       **    10 = Reserved 
+       **    11 = Level-triggered
+       */
+       u8 polarity_trigger;
+
+       /* 
+       ** IRQ and DEVNO
+       ** irq identifies PCI interrupt signal where
+       **    0x0 corresponds to INT_A#, 
+       **    0x1 corresponds to INT_B#, 
+       **    0x2 corresponds to INT_C# 
+       **    0x3 corresponds to INT_D# 
+       ** PCI device number where interrupt originates 
+       */
+       u8 src_bus_irq_devno;
+
+       /* Source Bus ID identifies the bus where interrupt signal comes from */
+       u8 src_bus_id;
+
+       /* 
+       ** Segment ID is unique across a protection domain and
+       ** identifies a segment of PCI buses (reserved in 
+       ** MP Specification Draft 1.5) 
+       */
+       u8 src_seg_id;
+
+       /* 
+       ** Destination I/O SAPIC INTIN# identifies the INTIN n pin 
+       ** to which the signal is connected 
+       */
+       u8 dest_iosapic_intin;
+
+       /* 
+       ** Destination I/O SAPIC Address identifies the I/O SAPIC 
+       ** to which the signal is connected 
+       */
+       u64 dest_iosapic_addr;
+};
+
+#define IRT_IOSAPIC_TYPE   139
+#define IRT_IOSAPIC_LENGTH 16
+
+#define IRT_VECTORED_INTR  0
+
+#define IRT_PO_MASK        0x3
+#define IRT_ACTIVE_HI      1
+#define IRT_ACTIVE_LO      3
+
+#define IRT_EL_MASK        0x3
+#define IRT_EL_SHIFT       2
+#define IRT_EDGE_TRIG      1
+#define IRT_LEVEL_TRIG     3
+
+#define IRT_IRQ_MASK       0x3
+#define IRT_DEV_MASK       0x1f
+#define IRT_DEV_SHIFT      2
+
+#define IRT_IRQ_DEVNO_MASK     ((IRT_DEV_MASK << IRT_DEV_SHIFT) | IRT_IRQ_MASK)
+
+#ifdef SUPPORT_MULTI_CELL
+struct iosapic_irt {
+        struct iosapic_irt *irt_next;  /* next routing table */
+        struct irt_entry *irt_base;             /* intr routing table address */
+        size_t  irte_count;            /* number of entries in the table */
+        size_t  irte_size;             /* size (bytes) of each entry */
+};
+#endif
+
+struct vector_info {
+       struct iosapic_info *vi_ios;    /* I/O SAPIC this vector is on */
+       struct irt_entry *vi_irte;      /* IRT entry */
+       u32     *vi_eoi_addr;   /* precalculate EOI reg address */
+       u32     vi_eoi_data;    /* IA64: ?       PA: swapped txn_data */
+       u8      vi_status;      /* status/flags */
+       u8      vi_irqline;     /* INTINn(IRQ) */
+       int     vi_txn_irq;     /* virtual IRQ number for processor */
+       ulong   vi_txn_addr;    /* IA64: id_eid  PA: partial HPA */
+       ulong   vi_txn_data;    /* IA64: vector  PA: EIR bit */
+};
+
+
+struct iosapic_info {
+       struct iosapic_info  *isi_next;      /* list of I/O SAPIC          */
+       volatile void        *isi_hpa;       /* physical base address      */
+       struct irq_region    *isi_region;    /* each I/O SAPIC is one region */
+       struct vector_info   *isi_vector;    /* IRdT (IRQ line) array  */
+       int                  isi_num_vectors; /* size of IRdT array */
+       int                  isi_status;     /* status/flags               */
+       unsigned int         isi_version;    /* DEBUG: data fr version reg */
+};
+
+
+
+#ifdef __IA64__
+/*
+** PA risc does NOT have any local sapics. IA64 does.
+** PIB (Processor Interrupt Block) is handled by Astro or Dew (Stretch CEC).
+**
+** PA: Get id_eid from IRT and hardcode PIB to 0xfeeNNNN0
+**     Emulate the data on PAT platforms.
+*/
+struct local_sapic_info {
+       struct local_sapic_info *lsi_next;      /* point to next CPU info */
+       int                     *lsi_cpu_id;    /* point to logical CPU id */
+       unsigned long           *lsi_id_eid;    /* point to IA-64 CPU id */
+       int                     *lsi_status;    /* point to CPU status   */
+       void                    *lsi_private;   /* point to special info */
+};
+
+/*
+** "root" data structure which ties everything together.
+** Should always be able to start with sapic_root and locate
+** the desired information.
+*/
+struct sapic_info {
+       struct sapic_info       *si_next;       /* info is per cell */
+       int                     si_cellid;      /* cell id */
+       unsigned int            si_status;       /* status  */
+       char                    *si_pib_base;   /* intr blk base address */
+       local_sapic_info_t      *si_local_info;
+       io_sapic_info_t         *si_io_info;
+       extint_info_t           *si_extint_info;/* External Intr info      */
+};
+#endif
+
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
new file mode 100644 (file)
index 0000000..0fdf3b0
--- /dev/null
@@ -0,0 +1,537 @@
+/* $Id: irq.c,v 1.8 2000/02/08 02:01:17 grundler Exp $
+ *
+ * Code to handle x86 style IRQs plus some generic interrupt stuff.
+ *
+ * This is not in any way SMP-clean.
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
+ * Copyright (C) 1999 SuSE GmbH (Author: Philipp Rumpf, prumpf@tux.org)
+ * Copyright (C) 2000 Hewlett Packard Corp (Co-Author: Grant Grundler, grundler@cup.hp.com)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/bitops.h>
+#include <asm/bitops.h>
+#include <asm/pdc.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/cache.h>
+
+#undef DEBUG_IRQ
+
+extern void timer_interrupt(int, void *, struct pt_regs *);
+extern void ipi_interrupt(int, void *, struct pt_regs *);
+
+#ifdef DEBUG_IRQ
+#define DBG_IRQ(x...)   printk(x)
+#else /* DEBUG_IRQ */
+#define DBG_IRQ(x...)
+#endif /* DEBUG_IRQ */
+
+#define EIEM_MASK(irq) (1L<<(MAX_CPU_IRQ-IRQ_OFFSET(irq)))
+#define CLEAR_EIEM_BIT(irq) set_eiem(get_eiem() & ~EIEM_MASK(irq))
+#define SET_EIEM_BIT(irq) set_eiem(get_eiem() | EIEM_MASK(irq))
+
+static void disable_cpu_irq(void *unused, int irq)
+{
+       CLEAR_EIEM_BIT(irq);
+}
+
+static void enable_cpu_irq(void *unused, int irq)
+{
+       unsigned long mask = EIEM_MASK(irq);
+
+       mtctl(mask, 23);
+       SET_EIEM_BIT(irq);
+}
+
+static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
+       [IRQ_OFFSET(TIMER_IRQ)] { timer_interrupt, 0, 0, "timer", NULL, NULL },
+       [IRQ_OFFSET(IPI_IRQ)]   { ipi_interrupt, 0, 0, "IPI", NULL, NULL },
+};
+
+struct irq_region cpu_irq_region = {
+       { disable_cpu_irq, enable_cpu_irq, NULL, NULL },
+       { &cpu_data[0], "PA-PIC", IRQ_REG_MASK|IRQ_REG_DIS, IRQ_FROM_REGION(CPU_IRQ_REGION)},
+       cpu_irq_actions
+};
+
+struct irq_region *irq_region[NR_IRQ_REGS] = {
+       [ 0 ] NULL,             /* abuse will data page fault (aka code 15) */
+       [ CPU_IRQ_REGION ] &cpu_irq_region,
+};
+
+
+
+/* we special-case the real IRQs here, which feels right given the relatively
+ * high cost of indirect calls.  If anyone is bored enough to benchmark this
+ * and find out whether I am right, feel free to.   prumpf */
+
+static inline void mask_irq(int irq)
+{
+       struct irq_region *region;
+       
+#ifdef DEBUG_IRQ
+       if (irq != TIMER_IRQ)
+#endif
+       DBG_IRQ("mask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+
+       if(IRQ_REGION(irq) != CPU_IRQ_REGION) {
+               region = irq_region[IRQ_REGION(irq)];
+               if(region->data.flags & IRQ_REG_MASK)
+                       region->ops.mask_irq(region->data.dev, IRQ_OFFSET(irq));
+       } else {
+               CLEAR_EIEM_BIT(irq);
+       }
+}
+
+static inline void unmask_irq(int irq)
+{
+       struct irq_region *region;
+
+#ifdef DEBUG_IRQ
+       if (irq != TIMER_IRQ)
+#endif
+       DBG_IRQ("unmask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+
+       if(IRQ_REGION(irq) != CPU_IRQ_REGION) {
+               region = irq_region[IRQ_REGION(irq)];
+               if(region->data.flags & IRQ_REG_MASK)
+                       region->ops.unmask_irq(region->data.dev, IRQ_OFFSET(irq));
+       } else {
+               SET_EIEM_BIT(irq);
+       }
+}
+
+void disable_irq(int irq)
+{
+       struct irq_region *region;
+
+#ifdef DEBUG_IRQ
+       if (irq != TIMER_IRQ)
+#endif
+       DBG_IRQ("disable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+       region = irq_region[IRQ_REGION(irq)];
+
+       if(region->data.flags & IRQ_REG_DIS)
+               region->ops.disable_irq(region->data.dev, IRQ_OFFSET(irq));
+       else
+               BUG();
+}
+
+void enable_irq(int irq) 
+{
+       struct irq_region *region;
+
+#ifdef DEBUG_IRQ
+       if (irq != TIMER_IRQ)
+#endif
+       DBG_IRQ("enable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+       region = irq_region[IRQ_REGION(irq)];
+
+       if(region->data.flags & IRQ_REG_DIS)
+               region->ops.enable_irq(region->data.dev, IRQ_OFFSET(irq));
+       else
+               BUG();
+}
+
+int get_irq_list(char *buf)
+{
+#ifdef CONFIG_PROC_FS
+       char *p = buf;
+       int i, j;
+       int regnr, irq_no;
+       struct irq_region *region;
+       struct irqaction *action, *mainaction;
+
+       p += sprintf(p, "           ");
+       for (j=0; j<smp_num_cpus; j++)
+               p += sprintf(p, "CPU%d       ",j);
+       *p++ = '\n';
+
+       for (regnr = 0; regnr < NR_IRQ_REGS; regnr++) {
+           region = irq_region[regnr];
+           if (!region || !region->action)
+               continue;
+           
+           mainaction = region->action;
+
+           for (i = 0; i <= MAX_CPU_IRQ; i++) {
+               action = mainaction++;
+               if (!action || !action->name)
+                   continue;
+               
+               irq_no = IRQ_FROM_REGION(regnr) + i;
+               
+               p += sprintf(p, "%3d: ", irq_no);
+#ifndef CONFIG_SMP
+               p += sprintf(p, "%10u ", kstat_irqs(irq_no));
+#else
+               for (j = 0; j < smp_num_cpus; j++)
+                   p += sprintf(p, "%10u ",
+                           kstat.irqs[cpu_logical_map(j)][irq_no]);
+#endif
+               p += sprintf(p, " %14s", 
+                           region->data.name ? region->data.name : "N/A");
+               p += sprintf(p, "  %s", action->name);
+
+               for (action=action->next; action; action = action->next)
+                   p += sprintf(p, ", %s", action->name);
+               *p++ = '\n';
+           }                
+       }  
+
+       p += sprintf(p, "\n");
+#if CONFIG_SMP
+       p += sprintf(p, "LOC: ");
+       for (j = 0; j < smp_num_cpus; j++)
+               p += sprintf(p, "%10u ",
+                       apic_timer_irqs[cpu_logical_map(j)]);
+       p += sprintf(p, "\n");
+#endif
+
+       return p - buf;
+
+#else  /* CONFIG_PROC_FS */
+
+       return 0;       
+
+#endif /* CONFIG_PROC_FS */
+}
+
+
+
+/*
+** The following form a "set": Virtual IRQ, Transaction Address, Trans Data.
+** Respectively, these map to IRQ region+EIRR, Processor HPA, EIRR bit.
+**
+** To use txn_XXX() interfaces, get a Virtual IRQ first.
+** Then use that to get the Transaction address and data.
+*/
+
+int
+txn_alloc_irq(void)
+{
+       int irq;
+
+       /* never return irq 0 cause that's the interval timer */
+       for(irq=1; irq<=MAX_CPU_IRQ; irq++) {
+               if(cpu_irq_region.action[irq].handler == NULL) {
+                       return (IRQ_FROM_REGION(CPU_IRQ_REGION) + irq);
+               }
+       }
+
+       /* unlikely, but be prepared */
+       return -1;
+}
+
+int
+txn_claim_irq(int irq)
+{
+       if (irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)].handler ==NULL)
+       {
+               return irq;
+       }
+
+       /* unlikely, but be prepared */
+       return -1;
+}
+
+unsigned long
+txn_alloc_addr(int virt_irq)
+{
+       struct cpuinfo_parisc *dev = (struct cpuinfo_parisc *) (irq_region[IRQ_REGION(virt_irq)]->data.dev);
+
+       if (0==dev) {
+               printk(KERN_ERR "txn_alloc_addr(0x%x): CPU IRQ region? dev %p\n",
+                       virt_irq,dev);
+               return(0UL);
+       }
+       return (dev->txn_addr);
+}
+
+
+/*
+** The alloc process needs to accept a parameter to accomodate limitations
+** of the HW/SW which use these bits:
+** Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register)
+** V-class (EPIC):          6 bits
+** N/L-class/A500:          8 bits (iosapic)
+** PCI 2.2 MSI:             16 bits (I think)
+** Existing PCI devices:    32-bits (NCR c720/ATM/GigE/HyperFabric)
+**
+** On the service provider side:
+** o PA 1.1 (and PA2.0 narrow mode)     5-bits (width of EIR register)
+** o PA 2.0 wide mode                   6-bits (per processor)
+** o IA64                               8-bits (0-256 total)
+**
+** So a Legacy PA I/O device on a PA 2.0 box can't use all
+** the bits supported by the processor...and the N/L-class
+** I/O subsystem supports more bits than PA2.0 has. The first
+** case is the problem.
+*/
+unsigned int
+txn_alloc_data(int virt_irq, unsigned int bits_wide)
+{
+       /* XXX FIXME : bits_wide indicates how wide the transaction
+       ** data is allowed to be...we may need a different virt_irq
+       ** if this one won't work. Another reason to index virtual
+       ** irq's into a table which can manage CPU/IRQ bit seperately.
+       */
+       if (IRQ_OFFSET(virt_irq) > (1 << (bits_wide -1)))
+       {
+               panic("Sorry -- didn't allocate valid IRQ for this device\n");
+       }
+
+       return(IRQ_OFFSET(virt_irq));
+}
+
+
+/* FIXME: SMP, flags, bottom halves, rest */
+void do_irq(struct irqaction *action, int irq, struct pt_regs * regs)
+{
+       int cpu = smp_processor_id();
+
+       irq_enter(cpu, irq);
+
+#ifdef DEBUG_IRQ
+       if (irq != TIMER_IRQ)
+#endif
+       DBG_IRQ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+       if (action->handler == NULL)
+               printk(KERN_ERR "No handler for interrupt %d !\n", irq);
+
+       for(; action && action->handler; action = action->next) {
+               action->handler(irq, action->dev_id, regs);
+       }
+       
+       irq_exit(cpu, irq);
+
+       /* don't need to care about unmasking and stuff */
+       do_softirq();
+}
+
+void do_irq_mask(unsigned long mask, struct irq_region *region, struct pt_regs *regs)
+{
+       unsigned long bit;
+       int irq;
+       int cpu = smp_processor_id();
+
+#ifdef DEBUG_IRQ
+       if (mask != (1L << MAX_CPU_IRQ))
+           printk("do_irq_mask %08lx %p %p\n", mask, region, regs);
+#endif
+
+       for(bit=(1L<<MAX_CPU_IRQ), irq = 0; mask && bit; bit>>=1, irq++) {
+               int irq_num;
+               if(!(bit&mask))
+                       continue;
+
+               irq_num = region->data.irqbase + irq;
+
+               ++kstat.irqs[cpu][IRQ_FROM_REGION(CPU_IRQ_REGION) | irq];
+               if (IRQ_REGION(irq_num) != CPU_IRQ_REGION)
+                   ++kstat.irqs[cpu][irq_num];
+
+               mask_irq(irq_num);
+               do_irq(&region->action[irq], irq_num, regs);
+               unmask_irq(irq_num);
+       }
+}
+
+static inline int alloc_irqregion(void)
+{
+       int irqreg;
+
+       for(irqreg=1; irqreg<=(NR_IRQ_REGS); irqreg++) {
+               if(irq_region[irqreg] == NULL)
+                       return irqreg;
+       }
+
+       return 0;
+}
+
+struct irq_region *alloc_irq_region(
+       int count, struct irq_region_ops *ops, unsigned long flags,
+       const char *name, void *dev)
+{
+       struct irq_region *region;
+       int index;
+
+       index = alloc_irqregion();
+
+       if((IRQ_REGION(count-1)))
+               return NULL;
+       
+       if (count < IRQ_PER_REGION) {
+           DBG_IRQ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n", 
+                       IRQ_PER_REGION, name, count);
+           count = IRQ_PER_REGION;
+       }
+
+       if(flags & IRQ_REG_MASK)
+               if(!(ops->mask_irq && ops->unmask_irq))
+                       return NULL;
+                       
+       if(flags & IRQ_REG_DIS)
+               if(!(ops->disable_irq && ops->enable_irq))
+                       return NULL;
+
+       if((irq_region[index]))
+               return NULL;
+
+       region = kmalloc(sizeof *region, GFP_ATOMIC);
+       if(!region)
+               return NULL;
+
+       region->action = kmalloc(sizeof *region->action * count, GFP_ATOMIC);
+       if(!region->action) {
+               kfree(region);
+               return NULL;
+       }
+       memset(region->action, 0, sizeof *region->action * count);
+
+       region->ops = *ops;
+       region->data.irqbase = IRQ_FROM_REGION(index);
+       region->data.flags = flags;
+       region->data.name = name;
+       region->data.dev = dev;
+
+       irq_region[index] = region;
+
+       return irq_region[index];
+}
+       
+
+       
+/* FIXME: SMP, flags, bottom halves, rest */
+
+int request_irq(unsigned int irq, 
+               void (*handler)(int, void *, struct pt_regs *),
+               unsigned long irqflags, 
+               const char * devname,
+               void *dev_id)
+{
+       struct irqaction * action;
+
+#if 0
+       printk(KERN_INFO "request_irq(%d, %p, 0x%lx, %s, %p)\n",irq, handler, irqflags, devname, dev_id);
+#endif
+       if(!handler) {
+               printk(KERN_ERR "request_irq(%d,...): Augh! No handler for irq!\n",
+                       irq);
+               return -EINVAL;
+       }
+
+       if ((IRQ_REGION(irq) == 0) || irq_region[IRQ_REGION(irq)] == NULL) {
+               /*
+               ** Bug catcher for drivers which use "char" or u8 for
+               ** the IRQ number. They lose the region number which
+               ** is in pcidev->irq (an int).
+               */
+               printk(KERN_ERR "%p (%s?) called request_irq with an invalid irq %d\n",
+                       __builtin_return_address(0), devname, irq);
+               return -EINVAL;
+       }
+
+       action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)];
+
+       if(action->handler) {
+               while(action->next)
+                       action = action->next;
+
+               action->next = kmalloc(sizeof *action, GFP_ATOMIC);
+
+               action = action->next;
+       }                       
+
+       if(!action) {
+               printk(KERN_ERR "request_irq():Augh! No action!\n") ;
+               return -ENOMEM;
+       }
+
+       action->handler = handler;
+       action->flags = irqflags;
+       action->mask = 0;
+       action->name = devname;
+       action->next = NULL;
+       action->dev_id = dev_id;
+
+       enable_irq(irq);
+       return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+       struct irqaction *action, **p;
+
+       action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)];
+
+       if(action->dev_id == dev_id) {
+               if(action->next == NULL)
+                       action->handler = NULL;
+               else
+                       memcpy(action, action->next, sizeof *action);
+
+               return;
+       }
+
+       p = &action->next;
+       action = action->next;
+
+       for (; (action = *p) != NULL; p = &action->next) {
+               if (action->dev_id != dev_id)
+                       continue;
+
+               /* Found it - now free it */
+               *p = action->next;
+               kfree(action);
+
+               return;
+       }
+
+       printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+}
+
+unsigned long probe_irq_on (void)
+{
+       return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+       return 0;
+}
+
+
+void __init init_IRQ(void)
+{
+}
+
+void init_irq_proc(void)
+{
+}
diff --git a/arch/parisc/kernel/keyboard.c b/arch/parisc/kernel/keyboard.c
new file mode 100644 (file)
index 0000000..05044db
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  linux/arch/parisc/kernel/keyboard.c
+ *
+ *  Alex deVries <adevries@thepuffingroup.com>
+ *  Copyright (1999) The Puffin Group
+ *  Mostly rewritten by Philipp Rumpf <prumpf@tux.org>
+ *  Copyright 2000 Philipp Rumpf
+ */
+
+#include <linux/keyboard.h>
+#include <asm/keyboard.h>
+
+static int def_setkeycode(unsigned int x, unsigned int y)
+{
+       return 0;
+}
+
+static int def_getkeycode(unsigned int x)
+{
+       return 0;
+}
+
+static int def_translate(unsigned char scancode, unsigned char *keycode,
+       char raw)
+{
+       *keycode = scancode;
+
+       return 1;
+}
+
+static char def_unexpected_up(unsigned char c)
+{
+       return 128;
+}
+
+static void def_leds(unsigned char leds)
+{
+}
+
+static void def_init_hw(void)
+{
+}
+
+static char def_sysrq_xlate[NR_KEYS];
+
+static struct kbd_ops def_kbd_ops = {
+       setkeycode:     def_setkeycode,
+       getkeycode:     def_getkeycode,
+       translate:      def_translate,
+       unexpected_up:  def_unexpected_up,
+       leds:           def_leds,
+       init_hw:        def_init_hw,
+
+       sysrq_key:      0xff,
+       sysrq_xlate:    def_sysrq_xlate,
+};
+
+struct kbd_ops *kbd_ops = &def_kbd_ops;
+
+void register_kbd_ops(struct kbd_ops *ops)
+{
+       if(ops->setkeycode)
+               kbd_ops->setkeycode = ops->setkeycode;
+       
+       if(ops->getkeycode)
+               kbd_ops->getkeycode = ops->getkeycode;
+       
+       if(ops->translate)
+               kbd_ops->translate = ops->translate;
+       
+       if(ops->unexpected_up)
+               kbd_ops->unexpected_up = ops->unexpected_up;
+       
+       if(ops->leds)
+               kbd_ops->leds = ops->leds;
+       
+       if(ops->init_hw)
+               kbd_ops->init_hw = ops->init_hw;
+       
+       kbd_ops->sysrq_key = ops->sysrq_key;
+       kbd_ops->sysrq_xlate = ops->sysrq_xlate;
+}
diff --git a/arch/parisc/kernel/lasimap.map b/arch/parisc/kernel/lasimap.map
new file mode 100644 (file)
index 0000000..2a9ee22
--- /dev/null
@@ -0,0 +1,322 @@
+# HP 712 kernel keymap. This uses 7 modifier combinations.
+
+keymaps 0-2,4-5,8,12
+# ie, plain,  Shift,  AltGr,  Control, Control+Shift, Alt and Control+Alt
+
+
+# Change the above line into
+#      keymaps 0-2,4-6,8,12
+# in case you want the entries
+#      altgr   control keycode  83 = Boot            
+#      altgr   control keycode 111 = Boot            
+# below.
+#
+# In fact AltGr is used very little, and one more keymap can
+# be saved by mapping AltGr to Alt (and adapting a few entries):
+# keycode 100 = Alt
+#
+keycode   1 = F9       F19     Console_21
+       control keycode 1 = F9
+       alt     keycode 1 = Console_9
+       control alt     keycode 1 = Console_9
+keycode   2 =
+keycode   3 = F5       F15     Console_17
+       control keycode 3 = F5
+       alt     keycode 3 = Console_5
+       control alt     keycode 3 = Console_5
+keycode   4 = F3       F13     Console_15
+       control keycode 4 = F3
+       alt     keycode 4 = Console_3
+       control alt     keycode 4 = Console_3
+keycode   5 = F1       F11     Console_13
+       control keycode 5 = F1
+       alt     keycode 5 = Console_1
+       control alt     keycode 5 = Console_1
+keycode   6 = F2       F12     Console_14
+       control keycode 6 = F2
+       alt     keycode 6 = Console_2
+       control alt     keycode 6 = Console_2
+keycode   7 = F12      F12     Console_24
+       control keycode 7 = F12
+       alt     keycode 7 = Console_12
+       control alt     keycode 7 = Console_12
+keycode   8 = 
+keycode   9 = F10      F20     Console_22
+       control keycode 9 = F10
+       alt     keycode 9 = Console_10
+       control alt     keycode 9 = Console_10
+keycode  10 = F8       F18     Console_20
+       control keycode 10 = F8
+       alt     keycode 10 = Console_8
+       control alt     keycode 10 = Console_8
+keycode  11 = F6       F16     Console_18
+       control keycode 11 = F6
+       alt     keycode 11 = Console_6
+       control alt     keycode 11 = Console_6
+keycode  12 = F4       F14     Console_16
+       control keycode 12 = F4
+       alt     keycode 12 = Console_4
+       control alt     keycode 12 = Console_4
+keycode  13 = Tab      Tab
+       alt     keycode 13 = Meta_Tab
+keycode  14 = grave    asciitilde
+       control keycode 14 = nul
+       alt     keycode 14 = Meta_grave
+keycode  15 = 
+keycode  16 =
+keycode  17 = Alt
+keycode  18 = Shift
+keycode  19 =
+keycode  20 = Control
+keycode  21 = q
+keycode  22 = one      exclam  exclam
+keycode  23 =
+keycode  24 =
+keycode  25 =
+keycode  26 = z
+keycode  27 = s
+keycode  28 = a
+       altgr   keycode 28 = Hex_A
+keycode  29 = w
+keycode  30 = two      at      at
+keycode  31 =
+keycode  32 =
+keycode  33 = c
+       altgr   keycode 46 = Hex_C
+keycode  34 = x
+keycode  35 = d
+       altgr   keycode 35 = Hex_D
+keycode  36 = e
+       altgr   keycode 36 = Hex_E
+keycode  37 = four     dollar
+keycode  38 = three    numbersign
+keycode  39 =
+keycode  40 =
+keycode  41 =
+keycode  42 = v
+keycode  43 = f
+        altgr  keycode 43 = Hex_F
+keycode  44 = t
+keycode  45 = r
+keycode  46 = five     percent
+keycode  47 =
+keycode  48 =
+keycode  49 = n
+keycode  50 = b
+       altgr   keycode 50 = Hex_B
+keycode  51 = h
+keycode  52 = g
+keycode  53 = y
+keycode  54 = six      asciicircum
+keycode  55 =
+keycode  56 =
+keycode  57 =
+keycode  58 = m
+keycode  59 = j
+keycode  60 = u
+keycode  61 = seven    ampersand
+keycode  62 = eight    asterisk        asterisk
+keycode  63 =
+keycode  64 =        
+keycode  65 = comma    less
+       alt     keycode 65 = Meta_comma
+keycode  66 = k
+keycode  67 = i
+keycode  68 = o
+keycode  69 = zero     parenright      bracketright
+keycode  70 = nine     parenleft       bracketleft
+keycode  71 = 
+keycode  72 =
+keycode  73 = period   greater
+       control keycode 73 = Compose
+       alt     keycode 73 = Meta_period
+keycode  74 = slash    question
+       control keycode 74 = Delete
+       alt     keycode 53 = Meta_slash
+keycode  75 = l
+keycode  76 = semicolon        colon
+       alt     keycode 39 = Meta_semicolon
+keycode  77 = p
+keycode  78 = minus    underscore
+keycode  79 =
+keycode  80 =
+keycode  81 =
+keycode  82 = apostrophe       quotedbl
+       control keycode 82 = Control_g
+       alt     keycode 40 = Meta_apostrophe
+keycode  83 =
+keycode  84 = bracketleft      braceleft
+       control keycode 84 = Escape
+       alt     keycode 26 = Meta_bracketleft
+keycode  85 = equal    plus
+keycode  86 = 
+keycode  87 = 
+keycode  88 = Caps_Lock
+keycode  88 =
+keycode  89 =
+keycode  89 =
+keycode  89 =
+keycode  90 = Return
+        alt  keycode   90 = Meta_Control_m
+keycode  91 = bracketright     braceright      asciitilde
+       control keycode 91 = Control_bracketright
+       alt     keycode 91 = Meta_bracketright
+keycode  92 =
+keycode  93 = backslash                bar
+       control keycode 43 = Control_backslash
+       alt     keycode 43 = Meta_backslash
+keycode  94 =
+keycode  95 =
+keycode  96 =
+keycode  97 =
+keycode  98 =
+keycode  99 =
+keycode 100 =
+keycode 101 =
+keycode 102 = BackSpace
+keycode 103 =
+keycode 104 =
+keycode 105 = KP_1
+       alt     keycode 105 = Ascii_1
+       altgr   keycode 105 = Hex_1
+keycode 106 =
+keycode 107 = KP_4
+       alt     keycode 107 = Ascii_4
+       altgr   keycode 107 = Hex_4
+keycode 108 = KP_7
+       alt     keycode 108 = Ascii_7
+       altgr   keycode 108 = Hex_7
+keycode 109 =
+keycode 110 =
+keycode 111 =
+keycode 112 = KP_0
+       alt     keycode 82 = Ascii_0
+       altgr   keycode 82 = Hex_0
+keycode 113 = KP_Period
+keycode 114 = KP_2
+       alt     keycode 114 = Ascii_2
+       altgr   keycode 114 = Hex_2
+keycode 115 = KP_5
+       alt     keycode 115 = Ascii_5
+       altgr   keycode 115 = Hex_5
+keycode 116 = KP_6
+       alt     keycode 116 = Ascii_6
+       altgr   keycode 116 = Hex_6
+keycode 117 = KP_8
+       alt     keycode 117 = Ascii_8
+       altgr   keycode 117 = Hex_8
+keycode 118 = Escape
+keycode 119 =
+keycode 120 = F11
+keycode 121 = KP_Add
+keycode 122 = KP_3
+       alt     keycode 122 = Ascii_3
+       altgr   keycode 122 = Hex_3
+keycode 123 = KP_Subtract
+keycode 124 = KP_Multiply
+keycode 125 = KP_9
+       alt     keycode 125 = Ascii_9
+       altgr   keycode 125 = Hex_9
+keycode 126 =
+# 131!!
+keycode 127 = F7       F17     Console_19
+       control keycode 127 = F7
+       alt     keycode 127 = Console_7
+       control alt     keycode 127 = Console_7
+
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff --git a/arch/parisc/kernel/lba_pci.c b/arch/parisc/kernel/lba_pci.c
new file mode 100644 (file)
index 0000000..b81e6b2
--- /dev/null
@@ -0,0 +1,1347 @@
+/*
+**  PCI Lower Bus Adapter (LBA) manager
+**
+**     (c) Copyright 1999,2000 Grant Grundler
+**     (c) Copyright 1999,2000 Hewlett-Packard Company
+**
+**     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 module primarily provides access to PCI bus (config/IOport
+** spaces) on platforms with an SBA/LBA chipset. A/B/C/J/L/N-class
+** with 4 digit model numbers - eg C3000 (and A400...sigh).
+**
+** LBA driver isn't as simple as the Dino driver because:
+**   (a) this chip has substantial bug fixes between revisions
+**       (Only one Dino bug has a software workaround :^(  )
+**   (b) has more options which we don't (yet) support (DMA hints, OLARD)
+**   (c) IRQ support lives in the I/O SAPIC driver (not with PCI driver)
+**   (d) play nicely with both PAT and "Legacy" PA-RISC firmware (PDC).
+**       (dino only deals with "Legacy" PDC)
+**
+** LBA driver passes the I/O SAPIC HPA to the I/O SAPIC driver.
+** (I/O SAPIC is integratd in the LBA chip).
+**
+** FIXME: Add support to SBA and LBA drivers for DMA hint sets
+** FIXME: Add support for PCI card hot-plug (OLARD).
+*/
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>                /* for __init and __devinit */
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>           /* for struct irq_region support */
+#include <asm/pdc.h>
+#include <asm/pdcpat.h>
+#include <asm/page.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <asm/hardware.h>      /* for register_driver() stuff */
+#include <asm/iosapic.h>       /* for iosapic_register() */
+#include <asm/gsc.h>           /* gsc_read/write stuff */
+
+
+#ifndef TRUE
+#define TRUE (1 == 1)
+#define FALSE (1 == 0)
+#endif
+
+#undef DEBUG_LBA       /* general stuff */
+#undef DEBUG_LBA_PORT  /* debug I/O Port access */
+#undef DEBUG_LBA_CFG   /* debug Config Space Access (ie PCI Bus walk) */
+#undef DEBUG_LBA_PAT   /* debug PCI Resource Mgt code - PDC PAT only */
+
+#ifdef DEBUG_LBA
+#define DBG(x...)      printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#ifdef DEBUG_LBA_PORT
+#define DBG_PORT(x...) printk(x)
+#else
+#define DBG_PORT(x...)
+#endif
+
+#ifdef DEBUG_LBA_CFG
+#define DBG_CFG(x...)  printk(x)
+#else
+#define DBG_CFG(x...)
+#endif
+
+#ifdef DEBUG_LBA_PAT
+#define DBG_PAT(x...)  printk(x)
+#else
+#define DBG_PAT(x...)
+#endif
+
+/*
+** Config accessor functions only pass in the 8-bit bus number and not
+** the 8-bit "PCI Segment" number. Each LBA will be assigned a PCI bus
+** number based on what firmware wrote into the scratch register.
+**
+** The "secondary" bus number is set to this before calling
+** pci_register_ops(). If any PPB's are present, the scan will
+** discover them and update the "secondary" and "subordinate"
+** fields in the pci_bus structure.
+**
+** Changes in the configuration *may* result in a different
+** bus number for each LBA depending on what firmware does.
+*/
+
+#define MODULE_NAME "lba"
+
+static int lba_driver_callback(struct hp_device *, struct pa_iodc_driver *);
+
+
+static struct pa_iodc_driver lba_drivers_for[]= {
+
+   {HPHW_BRIDGE, 0x782, 0x0, 0xa, 0,0,
+               DRIVER_CHECK_HVERSION + 
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "tbd", (void *) lba_driver_callback},
+
+   {0,0,0,0,0,0,
+   0,
+   (char *) NULL, (char *) NULL, (void *) NULL}
+};
+
+
+#define LBA_FUNC_ID    0x0000  /* function id */
+#define LBA_FCLASS     0x0008  /* function class, bist, header, rev... */
+#define LBA_CAPABLE    0x0030  /* capabilities register */
+
+#define LBA_PCI_CFG_ADDR       0x0040  /* poke CFG address here */
+#define LBA_PCI_CFG_DATA       0x0048  /* read or write data here */
+
+#define LBA_PMC_MTLT   0x0050  /* Firmware sets this - read only. */
+#define LBA_FW_SCRATCH 0x0058  /* Firmware writes the PCI bus number here. */
+#define LBA_ERROR_ADDR 0x0070  /* On error, address gets logged here */
+
+#define LBA_ARB_MASK   0x0080  /* bit 0 enable arbitration. PAT/PDC enables */
+#define LBA_ARB_PRI    0x0088  /* firmware sets this. */
+#define LBA_ARB_MODE   0x0090  /* firmware sets this. */
+#define LBA_ARB_MTLT   0x0098  /* firmware sets this. */
+
+#define LBA_MOD_ID     0x0100  /* Module ID. PDC_PAT_CELL reports 4 */
+
+#define LBA_STAT_CTL   0x0108  /* Status & Control */
+#define   HF_ENABLE    0x40    /*    enable HF mode (default is -1 mode) */
+
+#define LBA_LMMIO_BASE 0x0200  /* < 4GB I/O address range */
+#define LBA_LMMIO_MASK 0x0208
+
+#define LBA_GMMIO_BASE 0x0210  /* > 4GB I/O address range */
+#define LBA_GMMIO_MASK 0x0218
+
+#define LBA_WLMMIO_BASE        0x0220  /* All < 4GB ranges under the same *SBA* */
+#define LBA_WLMMIO_MASK        0x0228
+
+#define LBA_WGMMIO_BASE        0x0230  /* All > 4GB ranges under the same *SBA* */
+#define LBA_WGMMIO_MASK        0x0238
+
+#define LBA_IOS_BASE   0x0240  /* I/O port space for this LBA */
+#define LBA_IOS_MASK   0x0248
+
+#define LBA_ELMMIO_BASE        0x0250  /* Extra LMMIO range */
+#define LBA_ELMMIO_MASK        0x0258
+
+#define LBA_EIOS_BASE  0x0260  /* Extra I/O port space */
+#define LBA_EIOS_MASK  0x0268
+
+#define LBA_DMA_CTL    0x0278  /* firmware sets this */
+
+/* RESET: ignore DMA stuff until we can measure performance */
+#define LBA_IBASE      0x0300  /* DMA support */
+#define LBA_IMASK      0x0308
+#define LBA_HINT_CFG   0x0310
+#define LBA_HINT_BASE  0x0380  /* 14 registers at every 8 bytes. */
+
+/* ERROR regs are needed for config cycle kluges */
+#define LBA_ERROR_CONFIG 0x0680
+#define LBA_ERROR_STATUS 0x0688
+
+#define LBA_IOSAPIC_BASE       0x800 /* Offset of IRQ logic */
+
+/* non-postable I/O port space, densely packed */
+#ifdef __LP64__
+#define LBA_ASTRO_PORT_BASE    (0xfffffffffee00000UL)
+#else
+#define LBA_ASTRO_PORT_BASE    (0xfee00000UL)
+#endif
+
+
+/*
+** lba_device: Per instance Elroy data structure
+*/
+struct lba_device {
+       struct pci_hba_data hba;
+
+       spinlock_t      lba_lock;
+       void            *iosapic_obj;
+
+#ifdef __LP64__
+       unsigned long   lmmio_base;  /* PA_VIEW - fixup MEM addresses */
+       unsigned long   gmmio_base;  /* PA_VIEW - Not used (yet) */
+       unsigned long   iop_base;    /* PA_VIEW - for IO port accessor funcs */
+#endif
+
+       int             flags;       /* state/functionality enabled */
+       int             hw_rev;      /* HW revision of chip */
+};
+
+
+static u32 lba_t32;
+
+/*
+** lba "flags"
+*/
+#define LBA_FLAG_NO_DMA_DURING_CFG     0x01
+#define LBA_FLAG_SKIP_PROBE    0x10
+
+/* Tape Release 4 == hw_rev 5 */
+#define LBA_TR4PLUS(d)      ((d)->hw_rev > 0x4)
+#define LBA_DMA_DURING_CFG_DISABLED(d) ((d)->flags & LBA_FLAG_NO_DMA_DURING_CFG)
+#define LBA_SKIP_PROBE(d) ((d)->flags & LBA_FLAG_SKIP_PROBE)
+
+
+/* Looks nice and keeps the compiler happy */
+#define LBA_DEV(d) ((struct lba_device *) (d))
+
+
+/*
+** Only allow 8 subsidiary busses per LBA
+** Problem is the PCI bus numbering is globally shared.
+*/
+#define LBA_MAX_NUM_BUSES 8
+
+/************************************
+ * LBA register read and write support
+ *
+ * BE WARNED: register writes are posted.
+ *  (ie follow writes which must reach HW with a read)
+ */
+#define READ_U8(addr)  gsc_readb(addr)
+#define READ_U16(addr) gsc_readw((u16 *) (addr))
+#define READ_U32(addr) gsc_readl((u32 *) (addr))
+#define WRITE_U8(value, addr) gsc_writeb(value, addr)
+#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr))
+#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
+
+#define READ_REG8(addr)  gsc_readb(addr)
+#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr)))
+#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr)))
+#define WRITE_REG8(value, addr) gsc_writeb(value, addr)
+#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr))
+#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr))
+
+
+#define LBA_CFG_TOK(bus,dfn) ((u32) ((bus)<<16 | (dfn)<<8))
+#define LBA_CFG_BUS(tok)  ((u8) ((tok)>>16))
+#define LBA_CFG_DEV(tok)  ((u8) ((tok)>>11) & 0x1f)
+#define LBA_CFG_FUNC(tok) ((u8) ((tok)>>8 ) & 0x7)
+
+
+#ifdef DEBUG_LBA
+/* Extract LBA (Rope) number from HPA */
+#define LBA_NUM(x)    ((((uintptr_t) x) >> 13) & 0xf)
+#endif /* DEBUG_LBA */
+
+#ifdef __LP64__
+/* PDC_PAT */
+static  unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
+#endif
+
+/*
+** One time initialization to let the world know the LBA was found.
+** This is the only routine which is NOT static.
+** Must be called exactly once before pci_init().
+*/
+void __init lba_init(void)
+{
+       register_driver(lba_drivers_for);
+}
+
+
+static void
+lba_dump_res(struct resource *r, int d)
+{
+       int i;
+
+       if (NULL == r)
+               return;
+
+       printk("(%p)", r->parent);
+       for (i = d; i ; --i) printk(" ");
+       printk("%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags);
+       lba_dump_res(r->child, d+2);
+       lba_dump_res(r->sibling, d);
+}
+
+
+/*
+** LBA rev 2.0, 2.1, 2.2, and 3.0 bus walks require a complex
+** workaround for cfg cycles:
+**     -- preserve  LBA state
+**     -- LBA_FLAG_NO_DMA_DURING_CFG workaround
+**     -- turn on smart mode
+**     -- probe with config writes before doing config reads
+**     -- check ERROR_STATUS
+**     -- clear ERROR_STATUS
+**     -- restore LBA state
+**
+** The workaround is only used for device discovery.
+*/
+
+static int
+lba_device_present( u8 bus, u8 dfn, struct lba_device *d)
+{
+       u8 first_bus = d->hba.hba_bus->secondary;
+       u8 last_sub_bus = d->hba.hba_bus->subordinate;
+#if 0
+/* FIXME - see below in this function */
+        u8 dev = PCI_SLOT(dfn);
+        u8 func = PCI_FUNC(dfn);
+#endif
+
+       ASSERT(bus >= first_bus);
+       ASSERT(bus <= last_sub_bus);
+       ASSERT((bus - first_bus) < LBA_MAX_NUM_BUSES);
+
+       if ((bus < first_bus) ||
+           (bus > last_sub_bus) ||
+           ((bus - first_bus) >= LBA_MAX_NUM_BUSES))
+       {
+           /* devices that fall into any of these cases won't get claimed */
+           return(FALSE);
+       }
+
+#if 0
+/*
+** FIXME: Need to implement code to fill the devices bitmap based
+** on contents of the local pci_bus tree "data base".
+** pci_register_ops() walks the bus for us and builds the tree.
+** For now, always do the config cycle.
+*/
+       bus -= first_bus;
+
+       return (((d->devices[bus][dev]) >> func) & 0x1);
+#else
+       return TRUE;
+#endif
+}
+
+
+
+#define LBA_CFG_SETUP(d, tok) {                                \
+    /* Save contents of error config register.  */                     \
+    error_config = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG);            \
+\
+    /* Save contents of status control register.  */                   \
+    status_control = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);              \
+\
+    /* For LBA rev 2.0, 2.1, 2.2, and 3.0, we must disable DMA         \
+    ** arbitration for full bus walks.                                 \
+    */                                                                 \
+    if (LBA_DMA_DURING_CFG_DISABLED(d)) {                              \
+       /* Save contents of arb mask register. */                       \
+       arb_mask = READ_REG32(d->hba.base_addr + LBA_ARB_MASK);         \
+\
+       /*                                                              \
+        * Turn off all device arbitration bits (i.e. everything        \
+        * except arbitration enable bit).                              \
+        */                                                             \
+       WRITE_REG32(0x1, d->hba.base_addr + LBA_ARB_MASK);                      \
+    }                                                                  \
+\
+    /*                                                                 \
+     * Set the smart mode bit so that master aborts don't cause                \
+     * LBA to go into PCI fatal mode (required).                       \
+     */                                                                        \
+    WRITE_REG32(error_config | 0x20, d->hba.base_addr + LBA_ERROR_CONFIG);     \
+}
+
+
+#define LBA_CFG_PROBE(d, tok) {                                \
+    /*                                                                 \
+     * Setup Vendor ID write and read back the address register                \
+     * to make sure that LBA is the bus master.                                \
+     */                                                                        \
+    WRITE_REG32(tok | PCI_VENDOR_ID, (d)->hba.base_addr + LBA_PCI_CFG_ADDR);\
+    /*                                                                 \
+     * Read address register to ensure that LBA is the bus master,     \
+     * which implies that DMA traffic has stopped when DMA arb is off. \
+     */                                                                        \
+    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);               \
+    /*                                                                 \
+     * Generate a cfg write cycle (will have no affect on              \
+     * Vendor ID register since read-only).                            \
+     */                                                                        \
+    WRITE_REG32(~0, (d)->hba.base_addr + LBA_PCI_CFG_DATA);            \
+    /*                                                                 \
+     * Make sure write has completed before proceeding further,                \
+     * i.e. before setting clear enable.                               \
+     */                                                                        \
+    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);               \
+}
+
+
+/*
+ * HPREVISIT:
+ *   -- Can't tell if config cycle got the error.
+ *
+ *             OV bit is broken until rev 4.0, so can't use OV bit and
+ *             LBA_ERROR_LOG_ADDR to tell if error belongs to config cycle.
+ *
+ *             As of rev 4.0, no longer need the error check.
+ *
+ *   -- Even if we could tell, we still want to return -1
+ *     for **ANY** error (not just master abort).
+ *
+ *   -- Only clear non-fatal errors (we don't want to bring
+ *     LBA out of pci-fatal mode).
+ *
+ *             Actually, there is still a race in which
+ *             we could be clearing a fatal error.  We will
+ *             live with this during our real mode bus walk
+ *             until rev 4.0 (no driver activity during
+ *             real mode bus walk).  The real mode bus walk
+ *             has race conditions concerning the use of
+ *             smart mode as well.
+ */
+
+#define LBA_MASTER_ABORT_ERROR 0xc
+#define LBA_FATAL_ERROR 0x10
+
+#define LBA_CFG_MASTER_ABORT_CHECK(d, base, tok, error) {              \
+    u32 error_status = 0;                                              \
+    /*                                                                 \
+     * Set clear enable (CE) bit. Unset by HW when new                 \
+     * errors are logged -- LBA HW ERS section 14.3.3).                \
+     */                                                                        \
+    WRITE_REG32(status_control | 0x20, base + LBA_STAT_CTL);   \
+    error_status = READ_REG32(base + LBA_ERROR_STATUS);                \
+    if ((error_status & 0x1f) != 0) {                                  \
+       /*                                                              \
+        * Fail the config read request.                                \
+        */                                                             \
+       error = 1;                                                      \
+       if ((error_status & LBA_FATAL_ERROR) == 0) {                    \
+           /*                                                          \
+            * Clear error status (if fatal bit not set) by setting     \
+            * clear error log bit (CL).                                \
+            */                                                         \
+           WRITE_REG32(status_control | 0x10, base + LBA_STAT_CTL);    \
+       }                                                               \
+    }                                                                  \
+}
+
+#define LBA_CFG_TR4_ADDR_SETUP(d, addr) \
+    WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR)
+
+#define LBA_CFG_ADDR_SETUP(d, addr) {                          \
+    WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); \
+    /*                                                                 \
+     * HPREVISIT:                                                      \
+     *       --        Potentially could skip this once DMA bug fixed.         \
+     *                                                                 \
+     * Read address register to ensure that LBA is the bus master,     \
+     * which implies that DMA traffic has stopped when DMA arb is off. \
+     */                                                                        \
+    lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR);               \
+}
+
+
+#define LBA_CFG_RESTORE(d, base) {                                     \
+    /*                                                                 \
+     * Restore status control register (turn off clear enable).                \
+     */                                                                        \
+    WRITE_REG32(status_control, base + LBA_STAT_CTL);                  \
+    /*                                                                 \
+     * Restore error config register (turn off smart mode).            \
+     */                                                                        \
+    WRITE_REG32(error_config, base + LBA_ERROR_CONFIG);                        \
+    if (LBA_DMA_DURING_CFG_DISABLED(d)) {                              \
+       /*                                                              \
+        * Restore arb mask register (reenables DMA arbitration).       \
+        */                                                             \
+       WRITE_REG32(arb_mask, base + LBA_ARB_MASK);                     \
+    }                                                                  \
+}
+
+
+
+static unsigned int
+lba_rd_cfg( struct lba_device *d, u32 tok, u8 reg, u32 size)
+{
+       u32 data = ~0;
+       int error = 0;
+       u32 arb_mask = 0;       /* used by LBA_CFG_SETUP/RESTORE */
+       u32 error_config = 0;   /* used by LBA_CFG_SETUP/RESTORE */
+       u32 status_control = 0; /* used by LBA_CFG_SETUP/RESTORE */
+
+       ASSERT((size == sizeof(u8)) ||
+               (size == sizeof(u16)) ||
+               (size == sizeof(u32)));
+
+       if ((size != sizeof(u8)) &&
+               (size != sizeof(u16)) &&
+               (size != sizeof(u32))) {
+               return(data);
+       }
+
+       LBA_CFG_SETUP(d, tok);
+       LBA_CFG_PROBE(d, tok);
+       LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error);
+       if (!error) {
+               LBA_CFG_ADDR_SETUP(d, tok | reg);
+               switch (size) {
+               case sizeof(u8):
+                       data = (u32) READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 3));
+                       break;
+               case sizeof(u16):
+                       data = (u32) READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 2));
+                       break;
+               case sizeof(u32):
+                       data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA);
+                       break;
+               default:
+                       break; /* leave data as -1 */
+               }
+       }
+       LBA_CFG_RESTORE(d, d->hba.base_addr);
+       return(data);
+}
+
+
+
+#define LBA_CFG_RD(size, mask) \
+static int lba_cfg_read##size (struct pci_dev *dev, int pos, u##size *data) \
+{ \
+       struct lba_device *d = LBA_DEV(dev->bus->sysdata); \
+       u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \
+       u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \
+ \
+       if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \
+               /* original - Generate config cycle on broken elroy \
+                 with risk we will miss PCI bus errors. */ \
+               *data = (u##size) lba_rd_cfg(d, tok, pos, sizeof(u##size)); \
+               DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, *data); \
+               return(*data == (u##size) -1); \
+       } \
+ \
+       if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) \
+       { \
+               DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> -1 (b)\n", __FUNCTION__, dev->slot_name, pos, *data); \
+               /* either don't want to look or know device isn't present. */ \
+               *data = (u##size) -1; \
+               return(0); \
+       } \
+ \
+       /* Basic Algorithm \
+       ** Should only get here on fully working LBA rev. \
+       ** This is how simple the code should have been. \
+       */ \
+       LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \
+       *data = READ_REG##size(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask));\
+       DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, *data);\
+       return(*data == (u##size) -1); \
+}
+
+LBA_CFG_RD( 8, 3) 
+LBA_CFG_RD(16, 2) 
+LBA_CFG_RD(32, 0) 
+
+
+
+static void
+lba_wr_cfg( struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size)
+{
+       int error = 0;
+       u32 arb_mask = 0;
+       u32 error_config = 0;
+       u32 status_control = 0;
+
+       ASSERT((size == sizeof(u8)) ||
+               (size == sizeof(u16)) ||
+               (size == sizeof(u32)));
+
+       if ((size != sizeof(u8)) &&
+               (size != sizeof(u16)) &&
+               (size != sizeof(u32))) {
+                       return;
+       }
+
+       LBA_CFG_SETUP(d, tok);
+       LBA_CFG_ADDR_SETUP(d, tok | reg);
+       switch (size) {
+       case sizeof(u8):
+               WRITE_REG8((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA + (reg&3));
+               break;
+       case sizeof(u16):
+               WRITE_REG16((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA +(reg&2));
+               break;
+       case sizeof(u32):
+               WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA);
+               break;
+       default:
+               break;
+       }
+       LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error);
+       LBA_CFG_RESTORE(d, d->hba.base_addr);
+}
+
+
+/*
+ * LBA 4.0 config write code implements non-postable semantics
+ * by doing a read of CONFIG ADDR after the write.
+ */
+
+#define LBA_CFG_WR(size, mask) \
+static int lba_cfg_write##size (struct pci_dev *dev, int pos, u##size data) \
+{ \
+       struct lba_device *d = LBA_DEV(dev->bus->sysdata); \
+       u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \
+       u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \
+ \
+       ASSERT((tok & 0xff) == 0); \
+       ASSERT(pos < 0x100); \
+ \
+       if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \
+               /* Original Workaround */ \
+               lba_wr_cfg(d, tok, pos, (u32) data, sizeof(u##size)); \
+               DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, data); \
+               return 0; \
+       } \
+ \
+       if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) { \
+               DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (b)\n", __FUNCTION__, dev->slot_name, pos, data); \
+               return 1; /* New Workaround */ \
+       } \
+ \
+       DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, data); \
+       /* Basic Algorithm */ \
+       LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \
+       WRITE_REG##size(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask)); \
+       lba_t32 = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_ADDR); \
+       return 0; \
+}
+
+
+LBA_CFG_WR( 8, 3) 
+LBA_CFG_WR(16, 2) 
+LBA_CFG_WR(32, 0) 
+
+static struct pci_ops lba_cfg_ops = {
+        lba_cfg_read8, lba_cfg_read16, lba_cfg_read32,
+       lba_cfg_write8, lba_cfg_write16, lba_cfg_write32
+
+};
+
+
+
+static void
+lba_bios_init(void)
+{
+       DBG(KERN_DEBUG MODULE_NAME ": lba_bios_init\n");
+}
+
+
+#ifdef __LP64__
+
+/*
+** Determine if a device is already configured.
+** If so, reserve it resources.
+**
+** Read PCI cfg command register and see if I/O or MMIO is enabled.
+** PAT has to enable the devices it's using.
+**
+** Note: resources are fixed up before we try to claim them.
+*/
+static void
+lba_claim_dev_resources(struct pci_dev *dev)
+{
+       u16 cmd;
+       int i, srch_flags;
+
+       (void) lba_cfg_read16(dev, PCI_COMMAND, &cmd);
+
+       srch_flags  = (cmd & PCI_COMMAND_IO) ? IORESOURCE_IO : 0;
+       if (cmd & PCI_COMMAND_MEMORY)
+               srch_flags |= IORESOURCE_MEM;
+
+       if (!srch_flags)
+               return;
+
+       for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+               if (dev->resource[i].flags & srch_flags) {
+                       pci_claim_resource(dev, i);
+                       DBG("   claimed %s %d [%lx,%lx]/%x\n",
+                               dev->slot_name, i,
+                               dev->resource[i].start,
+                               dev->resource[i].end,
+                               (int) dev->resource[i].flags
+                               );
+               }
+       }
+}
+#endif
+
+
+/*
+** The algorithm is generic code.
+** But it needs to access local data structures to get the IRQ base.
+** Could make this a "pci_fixup_irq(bus, region)" but not sure
+** it's worth it.
+**
+** Called by do_pci_scan_bus() immediately after each PCI bus is walked.
+** Resources aren't allocated until recursive buswalk below HBA is completed.
+*/
+static void
+lba_fixup_bus(struct pci_bus *bus)
+{
+       struct list_head *ln;
+        struct pci_dev *dev;
+       u16 fbb_enable = PCI_STATUS_FAST_BACK;
+       u16 status;
+       struct lba_device *ldev = LBA_DEV(bus->sysdata);
+#ifdef __LP64__
+       int i;
+#endif
+       DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n",
+                               bus, bus->secondary, bus->sysdata);
+
+       /*
+       ** Properly Setup MMIO resources for this bus.
+       ** pci_alloc_primary_bus() mangles this.
+       */
+       if (NULL == bus->self) {
+               int err;
+
+               DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
+                       ldev->hba.io_space.name,
+                       ldev->hba.io_space.start,
+                       ldev->hba.io_space.end,
+                       (int) ldev->hba.io_space.flags);
+               DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
+                       ldev->hba.mem_space.name,
+                       ldev->hba.mem_space.start,
+                       ldev->hba.mem_space.end,
+                       (int) ldev->hba.mem_space.flags);
+
+               err = request_resource(&ioport_resource, &(ldev->hba.io_space));
+               if (err < 0) {
+                       BUG();
+                       lba_dump_res(&ioport_resource, 2);
+               }
+               err = request_resource(&iomem_resource, &(ldev->hba.mem_space));
+               if (err < 0) {
+                       BUG();
+                       lba_dump_res(&iomem_resource, 2);
+               }
+
+               bus->resource[0] = &(ldev->hba.io_space);
+               bus->resource[1] = &(ldev->hba.mem_space);
+       }
+
+       list_for_each(ln, &bus->devices) {
+
+               dev = pci_dev_b(ln);
+
+#ifdef __LP64__
+               /*
+               ** 0-5 are the "standard PCI regions"
+               ** (see comments near PCI_NUM_RESOURCES in include/linux/pci.h)
+               */
+               for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+                       struct resource *res = &(dev->resource[i]);
+
+                       if (res->flags & IORESOURCE_MEM) {
+                               /* "Globalize" PCI address */
+                               res->start |= ldev->lmmio_base;
+                               res->end   |= ldev->lmmio_base;
+                       }
+               }
+#endif
+
+               /*
+               ** If one device does not support FBB transfers,
+               ** No one on the bus can be allowed to use them.
+               */
+               (void) lba_cfg_read16(dev, PCI_STATUS, &status);
+               fbb_enable &= status;
+
+#ifdef __LP64__
+               if (pdc_pat) {
+                       /* Claim resources for PDC's devices */
+                       lba_claim_dev_resources(dev);
+               }
+#endif /* __LP64__ */
+
+                /*
+               ** P2PB's have no IRQs. ignore them.
+               */
+               if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+                       continue;
+
+               /* Adjust INTERRUPT_LINE for this dev */
+               iosapic_fixup_irq(LBA_DEV(bus->sysdata)->iosapic_obj, dev);
+       }
+
+#if 0
+/* FIXME/REVISIT - finish figuring out to set FBB on both
+** pbus_set_ranges() clobbers PCI_BRIDGE_CONTROL.
+** Can't fixup here anyway....garr...
+*/
+       if (fbb_enable) {
+               if (bus->self) {
+                       u8 control;
+                       /* enable on PPB */
+                       (void) lba_cfg_read8(bus->self, PCI_BRIDGE_CONTROL, &control);
+                       (void) lba_cfg_write8(bus->self, PCI_BRIDGE_CONTROL, control | PCI_STATUS_FAST_BACK);
+
+               } else {
+                       /* enable on LBA */
+               }
+               fbb_enable = PCI_COMMAND_FAST_BACK;
+       }
+
+       /* Lastly enable FBB/PERR/SERR on all devices too */
+       list_for_each(ln, &bus->devices) {
+               (void) lba_cfg_read16(dev, PCI_COMMAND, &status);
+               status |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR | fbb_enable;
+               (void) lba_cfg_write16(dev, PCI_COMMAND, status);
+       }
+#endif
+}
+
+
+struct pci_bios_ops lba_bios_ops = {
+       lba_bios_init,
+       lba_fixup_bus  /* void lba_fixup_bus(struct pci_bus *bus) */
+};
+
+
+
+
+/*******************************************************
+**
+** LBA Sprockets "I/O Port" Space Accessor Functions
+**
+** This set of accessor functions is intended for use with
+** "legacy firmware" (ie Sprockets on Allegro/Forte boxes).
+**
+** Many PCI devices don't require use of I/O port space (eg Tulip,
+** NCR720) since they export the same registers to both MMIO and
+** I/O port space. In general I/O port space is slower than
+** MMIO since drivers are designed so PIO writes can be posted.
+**
+********************************************************/
+
+#define LBA_PORT_IN(size, mask) \
+static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \
+{ \
+       u##size t; \
+       ASSERT(bus != NULL); \
+       DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, bus, addr); \
+       t = READ_REG##size(LBA_ASTRO_PORT_BASE + addr); \
+       DBG_PORT(" 0x%x\n", t); \
+       return (t); \
+}
+
+LBA_PORT_IN( 8, 3)
+LBA_PORT_IN(16, 2)
+LBA_PORT_IN(32, 0)
+
+
+
+/*
+** BUG X4107:  Ordering broken - DMA RD return can bypass PIO WR
+**
+** Fixed in Elroy 2.2. The READ_U32(..., LBA_FUNC_ID) below is
+** guarantee non-postable completion semantics - not avoid X4107.
+** The READ_U32 only guarantees the write data gets to elroy but
+** out to the PCI bus. We can't read stuff from I/O port space
+** since we don't know what has side-effects. Attempting to read
+** from configuration space would be suicidal given the number of
+** bugs in that elroy functionality.
+**
+**      Description:
+**          DMA read results can improperly pass PIO writes (X4107).  The
+**          result of this bug is that if a processor modifies a location in
+**          memory after having issued PIO writes, the PIO writes are not
+**          guaranteed to be completed before a PCI device is allowed to see
+**          the modified data in a DMA read.
+**
+**          Note that IKE bug X3719 in TR1 IKEs will result in the same
+**          symptom.
+**
+**      Workaround:
+**          The workaround for this bug is to always follow a PIO write with
+**          a PIO read to the same bus before starting DMA on that PCI bus.
+**
+*/
+#define LBA_PORT_OUT(size, mask) \
+static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \
+{ \
+       ASSERT(bus != NULL); \
+       DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
+       WRITE_REG##size(val, LBA_ASTRO_PORT_BASE + addr); \
+       if (LBA_DEV(d)->hw_rev < 3) \
+               lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \
+}
+
+LBA_PORT_OUT( 8, 3)
+LBA_PORT_OUT(16, 2)
+LBA_PORT_OUT(32, 0)
+
+
+static struct pci_port_ops lba_astro_port_ops = {
+       lba_astro_in8, lba_astro_in16, lba_astro_in32,
+       lba_astro_out8, lba_astro_out16, lba_astro_out32
+};
+
+
+#ifdef __LP64__
+
+#define PIOP_TO_GMMIO(lba, addr) \
+       ((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3))
+
+/*******************************************************
+**
+** LBA PAT "I/O Port" Space Accessor Functions
+**
+** This set of accessor functions is intended for use with
+** "PAT PDC" firmware (ie Prelude/Rhapsody/Piranha boxes).
+**
+** This uses the PIOP space located in the first 64MB of GMMIO.
+** Each rope gets a full 64*KB* (ie 4 bytes per page) this way.
+** bits 1:0 stay the same.  bits 15:2 become 25:12.
+** Then add the base and we can generate an I/O Port cycle.
+********************************************************/
+#undef LBA_PORT_IN
+#define LBA_PORT_IN(size, mask) \
+static u##size lba_pat_in##size (struct pci_hba_data *l, u16 addr) \
+{ \
+       u##size t; \
+       ASSERT(bus != NULL); \
+       DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \
+       t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \
+       DBG_PORT(" 0x%x\n", t); \
+       return (t); \
+}
+
+LBA_PORT_IN( 8, 3)
+LBA_PORT_IN(16, 2)
+LBA_PORT_IN(32, 0)
+
+
+#undef LBA_PORT_OUT
+#define LBA_PORT_OUT(size, mask) \
+static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \
+{ \
+       void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \
+       ASSERT(bus != NULL); \
+       DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
+       WRITE_REG##size(val, where); \
+       /* flush the I/O down to the elroy at least */ \
+       lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \
+}
+
+LBA_PORT_OUT( 8, 3)
+LBA_PORT_OUT(16, 2)
+LBA_PORT_OUT(32, 0)
+
+
+static struct pci_port_ops lba_pat_port_ops = {
+       lba_pat_in8, lba_pat_in16, lba_pat_in32,
+       lba_pat_out8, lba_pat_out16, lba_pat_out32
+};
+
+
+
+/*
+** make range information from PDC available to PCI subsystem.
+** We make the PDC call here in order to get the PCI bus range
+** numbers. The rest will get forwarded in pcibios_fixup_bus().
+** We don't have a struct pci_bus assigned to us yet.
+*/
+static void
+lba_pat_resources( struct hp_device *d, struct lba_device *lba_dev)
+{
+       pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;     /* PA_VIEW */
+#ifdef DONT_NEED_THIS_FOR_ASTRO
+       pdc_pat_cell_mod_maddr_block_t io_pdc_cell;     /* IO_VIEW */
+       long io_count;
+#endif
+       long status;    /* PDC return status */
+       long pa_count;
+       int i;
+
+       /* return cell module (IO view) */
+       status = pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index,
+                               PA_VIEW, & pa_pdc_cell);
+       pa_count = pa_pdc_cell.mod[1];
+
+#ifdef DONT_NEED_THIS_FOR_ASTRO
+       status |= pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index,
+                               IO_VIEW, & io_pdc_cell);
+       io_count = io_pdc_cell.mod[1];
+#endif
+
+       /* We've already done this once for device discovery...*/
+       if (status != PDC_RET_OK) {
+               panic("pdc_pat_cell_module() call failed for LBA!\n");
+       }
+
+       if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) {
+               panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n");
+       }
+
+       /*
+       ** Inspect the resources PAT tells us about
+       */
+       for (i = 0; i < pa_count; i++) {
+               struct {
+                       unsigned long type;
+                       unsigned long start;
+                       unsigned long end;      /* aka finish */
+               } *p;
+               struct resource *r;
+
+               p = (void *) &(pa_pdc_cell.mod[2+i*3]);
+
+               /* Convert the PAT range data to PCI "struct resource" */
+               switch(p->type & 0xff) {
+               case PAT_PBNUM:
+                       lba_dev->hba.bus_num.start = p->start;
+                       lba_dev->hba.bus_num.end   = p->end;
+                       break;
+               case PAT_LMMIO:
+                       /* used to fix up pre-initialized MEM BARs */
+                       lba_dev->lmmio_base = p->start;
+
+                       r = &(lba_dev->hba.mem_space);
+                       r->name   = "LBA LMMIO";
+                       r->start  = p->start;
+                       r->end    = p->end;
+                       r->flags  = IORESOURCE_MEM;
+                       r->parent = r->sibling = r->child = NULL;
+                       break;
+               case PAT_GMMIO:
+                       printk(KERN_WARNING MODULE_NAME
+                               " range[%d] : ignoring GMMIO (0x%lx)\n",
+                               i, p->start);
+                       lba_dev->gmmio_base = p->start;
+                       break;
+               case PAT_NPIOP:
+                       printk(KERN_WARNING MODULE_NAME
+                               " range[%d] : ignoring NPIOP (0x%lx)\n",
+                               i, p->start);
+                       break;
+               case PAT_PIOP:
+                       /*
+                       ** Postable I/O port space is per PCI host adapter.
+                       */
+
+                       /* save base of 64MB PIOP region */
+                       lba_dev->iop_base = p->start;
+
+                       r = &(lba_dev->hba.io_space);
+                       r->name   = "LBA I/O Port";
+                       r->start = lba_dev->hba.hba_num << 16;
+                       r->end   = r->start + 0xffffUL;
+                       r->flags  = IORESOURCE_IO;
+                       r->parent = r->sibling = r->child = NULL;
+                       break;
+               default:
+                       printk(KERN_WARNING MODULE_NAME
+                               " range[%d] : unknown pat range type (0x%lx)\n",
+                               i, p->type & 0xff);
+                       break;
+               }
+       }
+}
+#endif /* __LP64__ */
+
+
+static void
+lba_legacy_resources( struct hp_device *d, struct lba_device *lba_dev)
+{
+       int lba_num;
+       struct resource *r;
+#ifdef __LP64__
+       /*
+       ** Used to sign extend instead BAR values are only 32-bit.
+       ** 64-bit BARs have the upper 32-bit's zero'd by firmware.
+       ** "Sprockets" PDC initializes for 32-bit OS.
+       */
+       lba_dev->lmmio_base = 0xffffffff00000000UL;
+#endif
+
+       /*
+       ** With "legacy" firmware, the lowest byte of FW_SCRATCH
+       ** represents bus->secondary and the second byte represents
+       ** bus->subsidiary (i.e. highest PPB programmed by firmware).
+       ** PCI bus walk *should* end up with the same result.
+       ** FIXME: But we don't have sanity checks in PCI or LBA.
+       */
+       lba_num = READ_REG32(d->hpa + LBA_FW_SCRATCH);
+       r = &(lba_dev->hba.bus_num);
+       r->name = "LBA PCI Busses";
+       r->start = lba_num & 0xff;
+       r->end = (lba_num>>8) & 0xff;
+
+       /* Set up local PCI Bus resources - we don't really need
+       ** them for Legacy boxes but it's nice to see in /proc.
+       */
+       r = &(lba_dev->hba.mem_space);
+       r->name  = "LBA PCI LMMIO";
+       r->flags = IORESOURCE_MEM;
+       r->start = READ_REG32(d->hpa + LBA_LMMIO_BASE);
+       r->end   = r->start + ~ (READ_REG32(d->hpa + LBA_LMMIO_MASK));
+
+       r = &(lba_dev->hba.io_space);
+       r->name  = "LBA PCI I/O Ports";
+       r->flags = IORESOURCE_IO;
+       r->start = READ_REG32(d->hpa + LBA_IOS_BASE);
+       r->end   = r->start + (READ_REG32(d->hpa + LBA_IOS_MASK) ^ 0xffff);
+
+       lba_num = lba_dev->hba.hba_num << 16;
+       r->start |= lba_num;
+       r->end   |= lba_num;
+}
+
+
+/**************************************************************************
+**
+**   LBA initialization code (HW and SW)
+**
+**   o identify LBA chip itself
+**   o initialize LBA chip modes (HardFail)
+**   o FIXME: initialize DMA hints for reasonable defaults
+**   o enable configuration functions
+**   o call pci_register_ops() to discover devs (fixup/fixup_bus get invoked)
+**
+**************************************************************************/
+
+static void
+lba_hw_init(struct lba_device *d)
+{
+       u32 stat;
+
+       /* Set HF mode as the default (vs. -1 mode). */
+        stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);
+       WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
+
+       /*
+       ** FIXME: Hint registers are programmed with default hint
+       ** values by firmware. Hints should be sane even if we
+       ** can't reprogram them the way drivers want.
+       */
+}
+
+
+
+static void
+lba_common_init(struct lba_device *lba_dev)
+{
+       pci_bios = &lba_bios_ops;
+       pcibios_register_hba((struct pci_hba_data *)lba_dev);
+       lba_dev->lba_lock = SPIN_LOCK_UNLOCKED; 
+
+       /*
+       ** Set flags which depend on hw_rev
+       */
+       if (!LBA_TR4PLUS(lba_dev)) {
+               lba_dev->flags |= LBA_FLAG_NO_DMA_DURING_CFG;
+       }
+}
+
+
+
+/*
+** Determine if lba should claim this chip (return 0) or not (return 1).
+** If so, initialize the chip and tell other partners in crime they
+** have work to do.
+*/
+static __init int
+lba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+{
+       struct lba_device *lba_dev;
+       struct pci_bus *lba_bus;
+       u32 func_class;
+       void *tmp_obj;
+
+       /* from drivers/pci/setup-bus.c */
+       extern void __init pbus_set_ranges(struct pci_bus *, struct pbus_set_ranges_data *);
+
+       /* Read HW Rev First */
+       func_class = READ_REG32(d->hpa + LBA_FCLASS);
+       func_class &= 0xf;
+
+       switch (func_class) {
+       case 0: dri->version = "TR1.0"; break;
+       case 1: dri->version = "TR2.0"; break;
+       case 2: dri->version = "TR2.1"; break;
+       case 3: dri->version = "TR2.2"; break;
+       case 4: dri->version = "TR3.0"; break;
+       case 5: dri->version = "TR4.0"; break;
+       default: dri->version = "TR4+";
+       }
+
+       printk("%s version %s (0x%x) found at 0x%p\n", dri->name, dri->version, func_class & 0xf, d->hpa);
+
+       /* Just in case we find some prototypes... */
+       if (func_class < 2) {
+               printk(KERN_WARNING "Can't support LBA older than TR2.1 "
+                       "- continuing under adversity.\n");
+       }
+
+       /*
+       ** Tell I/O SAPIC driver we have a IRQ handler/region.
+       */
+       tmp_obj = iosapic_register(d->hpa+LBA_IOSAPIC_BASE);
+       if (NULL == tmp_obj) {
+               /* iosapic may have failed. But more likely the
+               ** slot isn't occupied and thus has no IRT entries.
+               ** iosapic_register looks for this iosapic in the IRT
+               ** before bothering to allocating data structures
+               ** we don't need.
+               */
+               DBG(KERN_WARNING MODULE_NAME ": iosapic_register says not used\n");
+               return (1);
+       }
+
+       lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL);
+       if (NULL == lba_dev)
+       {
+               printk("lba_init_chip - couldn't alloc lba_device\n");
+               return(1);
+       }
+
+       memset(lba_dev, 0, sizeof(struct lba_device));
+
+
+       /* ---------- First : initialize data we already have --------- */
+
+       /*
+       ** Need hw_rev to adjust configuration space behavior.
+       ** LBA_TR4PLUS macro uses hw_rev field.
+       */
+       lba_dev->hw_rev = func_class;
+
+       lba_dev->hba.base_addr = d->hpa;  /* faster access */
+       lba_dev->iosapic_obj = tmp_obj;  /* save interrupt handle */
+
+       /* ------------ Second : initialize common stuff ---------- */
+       lba_common_init(lba_dev);
+       lba_hw_init(lba_dev);
+
+       /* ---------- Third : setup I/O Port and MMIO resources  --------- */
+#ifdef __LP64__
+
+       if (pdc_pat) {
+               /* PDC PAT firmware uses PIOP region of GMMIO space. */
+               pci_port = &lba_pat_port_ops;
+
+               /* Go ask PDC PAT what resources this LBA has */
+               lba_pat_resources(d, lba_dev);
+
+       } else {
+#endif
+               /* Sprockets PDC uses NPIOP region */
+               pci_port = &lba_astro_port_ops;
+
+               /* Poke the chip a bit for /proc output */
+               lba_legacy_resources(d, lba_dev);
+#ifdef __LP64__
+       }
+#endif
+
+       /* 
+       ** Tell PCI support another PCI bus was found.
+       ** Walks PCI bus for us too.
+       */
+       lba_bus = lba_dev->hba.hba_bus =
+               pci_scan_bus( lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev);
+
+#ifdef __LP64__
+       if (pdc_pat) {
+
+               /* determine window sizes needed by PCI-PCI bridges */
+               DBG_PAT("LBA pcibios_size_bridge()\n");
+               pcibios_size_bridge(lba_bus, NULL);
+
+               /* assign resources to un-initialized devices */
+               DBG_PAT("LBA pcibios_assign_unassigned_resources()\n");
+               pcibios_assign_unassigned_resources(lba_bus);
+
+#ifdef DEBUG_LBA_PAT
+               DBG_PAT("\nLBA PIOP resource tree\n");
+               lba_dump_res(&lba_dev->hba.io_space, 2);
+               DBG_PAT("\nLBA LMMIO resource tree\n");
+               lba_dump_res(&lba_dev->hba.mem_space, 2);
+#endif
+
+               /* program *all* PCI-PCI bridge range registers */
+               DBG_PAT("LBA pbus_set_ranges()\n");
+               pbus_set_ranges(lba_bus, NULL);
+       }
+#endif /* __LP64__ */
+
+       /*
+       ** Once PCI register ops has walked the bus, access to config
+       ** space is restricted. Avoids master aborts on config cycles.
+       ** Early LBA revs go fatal on *any* master abort.
+       */
+       if (!LBA_TR4PLUS(lba_dev)) {
+               lba_dev->flags |= LBA_FLAG_SKIP_PROBE;
+       }
+
+       /* Whew! Finally done! Tell services we got this one covered. */
+       return 0;
+}
+
+
+/*
+** Initialize the IBASE/IMASK registers for LBA (Elroy).
+** Only called from sba_iommu.c initialization sequence.
+*/
+void lba_init_iregs(void *sba_hpa, u32 ibase, u32 imask)
+{
+       extern struct pci_hba_data *hba_list;   /* arch/parisc/kernel/pci.c */
+       struct pci_hba_data *lba;
+
+       imask <<= 2;    /* adjust for hints - 2 more bits */
+
+       ASSERT((ibase & 0x003fffff) == 0);
+       ASSERT((imask & 0x003fffff) == 0);
+       
+       /* FIXME: sba_hpa is intended to search some table to
+       **      determine which LBA's belong to the caller's SBA.
+       ** IS_ASTRO: just assume only one SBA for now.
+       */
+       ASSERT(NULL != hba_list);
+       DBG(KERN_DEBUG "%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);
+
+       for (lba = hba_list; NULL != lba; lba = lba->next) {
+               DBG(KERN_DEBUG "%s() base_addr %p\n", __FUNCTION__, lba->base_addr);
+               WRITE_REG32( imask, lba->base_addr + LBA_IMASK);
+               WRITE_REG32( ibase, lba->base_addr + LBA_IBASE);
+       }
+       DBG(KERN_DEBUG "%s() done\n", __FUNCTION__);
+}
+
diff --git a/arch/parisc/kernel/led.c b/arch/parisc/kernel/led.c
new file mode 100644 (file)
index 0000000..6e6ee77
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ *    Chassis LCD/LED driver for HP-PARISC workstations
+ *
+ *      (c) Copyright 2000 Red Hat Software
+ *      (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <asm/gsc.h>
+#include <asm/processor.h>
+#include <asm/hardware.h>
+#include <asm/param.h>         /* HZ */
+#include <asm/led.h>
+
+
+/* define to disable all LED functions */
+#undef  DISABLE_LEDS
+
+
+#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF)
+
+
+struct lcd_block {
+       unsigned char command;  /* stores the command byte      */
+       unsigned char on;       /* value for turning LED on     */
+       unsigned char off;      /* value for turning LED off    */
+};
+
+/* Structure returned by PDC_RETURN_CHASSIS_INFO */
+struct pdc_chassis_lcd_info_ret_block {
+       unsigned long model:16;         /* DISPLAY_MODEL_XXXX (see below)  */
+       unsigned long lcd_width:16;     /* width of the LCD in chars (DISPLAY_MODEL_LCD only) */
+       char *lcd_cmd_reg_addr;         /* ptr to LCD cmd-register & data ptr for LED */
+       char *lcd_data_reg_addr;        /* ptr to LCD data-register (LCD only) */
+       unsigned int min_cmd_delay;     /* delay in uS after cmd-write (LCD only) */
+       unsigned char reset_cmd1;       /* command #1 for writing LCD string (LCD only) */
+       unsigned char reset_cmd2;       /* command #2 for writing LCD string (LCD only) */
+       unsigned char act_enable;       /* 0 = no activity (LCD only) */
+       struct lcd_block heartbeat;
+       struct lcd_block disk_io;
+       struct lcd_block lan_rcv;
+       struct lcd_block lan_tx;
+       char _pad;
+};
+
+/* values for pdc_chassis_lcd_info_ret_block.model: */
+#define DISPLAY_MODEL_LCD  0   /* KittyHawk LED or LCD */
+#define DISPLAY_MODEL_NONE 1   /* no LED or LCD */
+#define DISPLAY_MODEL_LASI 2   /* LASI style 8 bit LED */
+#define DISPLAY_MODEL_OLD_ASP 0x7F /* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */
+
+
+/* LCD_CMD and LCD_DATA for KittyHawk machines */
+#ifdef __LP64__
+#define KITTYHAWK_LCD_CMD 0xfffffffff0190000L
+#else
+#define KITTYHAWK_LCD_CMD 0xf0190000
+#endif
+#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD + 1)
+
+
+/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's */
+static struct pdc_chassis_lcd_info_ret_block
+lcd_info __attribute__((aligned(8))) =
+{
+      model:DISPLAY_MODEL_LCD,
+      lcd_width:16,
+      lcd_cmd_reg_addr:(char *) KITTYHAWK_LCD_CMD,
+      lcd_data_reg_addr:(char *) KITTYHAWK_LCD_DATA,
+      min_cmd_delay:40,
+      reset_cmd1:0x80,
+      reset_cmd2:0xc0,
+};
+
+
+/* direct access to some of the lcd_info variables */
+#define LCD_CMD_REG    lcd_info.lcd_cmd_reg_addr        
+#define LCD_DATA_REG   lcd_info.lcd_data_reg_addr       
+#define LED_DATA_REG   lcd_info.lcd_cmd_reg_addr       /* LASI & ASP only */
+
+
+
+
+/*
+   ** 
+   ** led_ASP_driver()
+   ** 
+ */
+#define        LED_DATA        0x01    /* data to shift (0:on 1:off) */
+#define        LED_STROBE      0x02    /* strobe to clock data */
+static void led_ASP_driver(unsigned char leds)
+{
+       int i;
+
+       leds = ~leds;
+       for (i = 0; i < 8; i++) {
+               unsigned char value;
+               value = (leds & 0x80) >> 7;
+               gsc_writeb( value,               LED_DATA_REG );
+               gsc_writeb( value | LED_STROBE,  LED_DATA_REG );
+               leds <<= 1;
+       }
+}
+
+
+/*
+   ** 
+   ** led_LASI_driver()
+   ** 
+ */
+static void led_LASI_driver(unsigned char leds)
+{
+       leds = ~leds;
+       gsc_writeb( leds, LED_DATA_REG );
+}
+
+
+/*
+   ** 
+   ** led_LCD_driver()
+   ** 
+   ** The logic of the LCD driver is, that we write at every interrupt
+   ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers.
+   ** That way we don't need to let this interrupt routine busywait
+   ** the "min_cmd_delay", since idlewaiting in an interrupt-routine is
+   ** allways a BAD IDEA !
+   **
+   ** TODO: check the value of "min_cmd_delay" against the value of HZ.
+   **   
+ */
+
+static void led_LCD_driver(unsigned char leds)
+{
+       static int last_index;  /* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */
+       static int last_was_cmd;/* 0: CMD was written last, 1: DATA was last */
+       struct lcd_block *block_ptr;
+       int value;
+       
+       // leds = ~leds;        /* needed ? */ 
+
+       switch (last_index) {
+           case 0:     block_ptr = &lcd_info.heartbeat;
+                       value = leds & LED_HEARTBEAT;
+                       break;
+           case 1:     block_ptr = &lcd_info.disk_io;
+                       value = leds & LED_DISK_IO;
+                       break;                                  
+           case 2:     block_ptr = &lcd_info.lan_rcv;
+                       value = leds & LED_LAN_RCV;
+                       break;                                  
+           case 3:     block_ptr = &lcd_info.lan_tx;
+                       value = leds & LED_LAN_TX;
+                       break;
+           default:    /* should never happen: */
+                       BUG();
+                       return;
+       }
+
+       if (last_was_cmd) {
+           /* write the value to the LCD data port */
+           gsc_writeb( value ? block_ptr->on : block_ptr->off, LCD_DATA_REG );
+       } else {
+           /* write the command-byte to the LCD command register */
+           gsc_writeb( block_ptr->command, LCD_CMD_REG );
+       }    
+       
+       /* now update the vars for the next interrupt iteration */ 
+       if (++last_was_cmd == 2) {
+           last_was_cmd = 0;
+           if (++last_index == 4)
+               last_index = 0;
+       }
+}
+
+
+
+static char currentleds;       /* stores current value of the LEDs */
+
+static void (*led_func_ptr) (unsigned char); /* ptr to LCD/LED-specific function */
+
+/*
+   ** led_interrupt_func()
+   ** 
+   ** is called at every timer interrupt from time.c,
+   ** updates the chassis LCD/LED 
+ */
+
+#define HEARTBEAT_LEN  (HZ/16)
+
+void led_interrupt_func(void)
+{
+#ifndef DISABLE_LEDS
+       static int count;
+       static int lastleds = -1;
+       static int nr;
+
+       /* exit, if not initialized */
+       if (!led_func_ptr)
+           return;
+       
+       /* increment the local counter */
+       if (count == (HZ-1))
+           count = 0;
+       else
+           count++;
+
+       /* calculate the Heartbeat */
+       if ((count % (HZ/2)) < HEARTBEAT_LEN) 
+           currentleds |= LED_HEARTBEAT;
+       else
+           currentleds &= ~LED_HEARTBEAT;
+
+       /* roll LEDs 0..2 */
+       if (count == 0) {
+           if (nr++ >= 2) 
+               nr = 0;
+           currentleds &= ~7;
+           currentleds |= (1 << nr);
+       }
+
+       /* now update the LEDs */
+       if (currentleds != lastleds) {
+           led_func_ptr(currentleds);
+           lastleds = currentleds;
+       }
+#endif
+}
+
+
+/*
+   ** register_led_driver()
+   ** 
+   ** All information in lcd_info needs to be set up prior
+   ** calling this function. 
+ */
+
+static void __init register_led_driver(void)
+{
+#ifndef DISABLE_LEDS
+       switch (lcd_info.model) {
+       case DISPLAY_MODEL_LCD:
+               printk(KERN_INFO "LCD display at (%p,%p)\n",
+                 LCD_CMD_REG , LCD_DATA_REG);
+               led_func_ptr = led_LCD_driver;
+               break;
+
+       case DISPLAY_MODEL_LASI:
+               printk(KERN_INFO "LED display at %p\n",
+                      LED_DATA_REG);
+               led_func_ptr = led_LASI_driver;
+               break;
+
+       case DISPLAY_MODEL_OLD_ASP:
+               printk(KERN_INFO "LED (ASP-style) display at %p\n",
+                      LED_DATA_REG);
+               led_func_ptr = led_ASP_driver;
+               break;
+
+       default:
+               printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n",
+                      __FUNCTION__, lcd_info.model);
+               return;
+       }
+#endif
+}
+
+/*
+ * XXX - could this move to lasi.c ??
+ */
+
+/*
+   ** lasi_led_init()
+   ** 
+   ** lasi_led_init() is called from lasi.c with the base hpa  
+   ** of the lasi controller chip. 
+   ** Since Mirage and Electra machines use a different LED
+   ** address register, we need to check for these machines 
+   ** explicitly.
+ */
+
+#ifdef CONFIG_GSC_LASI
+void __init lasi_led_init(unsigned long lasi_hpa)
+{
+       if (lcd_info.model != DISPLAY_MODEL_NONE ||
+           lasi_hpa == 0)
+               return;
+
+       printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION);
+
+       /* Mirage and Electra machines need special offsets */
+       switch (CPU_HVERSION) {
+       case 0x60A:             /* Mirage Jr (715/64) */
+       case 0x60B:             /* Mirage 100 */
+       case 0x60C:             /* Mirage 100+ */
+       case 0x60D:             /* Electra 100 */
+       case 0x60E:             /* Electra 120 */
+               LED_DATA_REG = (char *) (lasi_hpa - 0x00020000);
+               break;
+       default:
+               LED_DATA_REG = (char *) (lasi_hpa + 0x0000C000);
+               break;
+       }                       /* switch() */
+
+       lcd_info.model = DISPLAY_MODEL_LASI;
+       register_led_driver();
+}
+#endif
+
+
+/*
+   ** asp_led_init()
+   ** 
+   ** asp_led_init() is called from asp.c with the ptr 
+   ** to the LED display.
+ */
+
+#ifdef CONFIG_GSC_LASI
+void __init asp_led_init(unsigned long led_ptr)
+{
+       if (lcd_info.model != DISPLAY_MODEL_NONE ||
+           led_ptr == 0)
+               return;
+
+       lcd_info.model = DISPLAY_MODEL_OLD_ASP;
+       LED_DATA_REG = (char *) led_ptr;
+
+       register_led_driver();
+}
+
+#endif
+
+
+
+/*
+   ** register_led_regions()
+   ** 
+   ** Simple function, which registers the LCD/LED regions for /procfs.
+   ** At bootup - where the initialisation of the LCD/LED normally happens - 
+   ** not all internal structures of request_region() are properly set up,
+   ** so that we delay the registration until busdevice.c is executed.
+   **
+ */
+
+void __init register_led_regions(void)
+{
+       switch (lcd_info.model) {
+       case DISPLAY_MODEL_LCD:
+               request_region((unsigned long)LCD_CMD_REG,  1, "lcd_cmd");
+               request_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
+               break;
+       case DISPLAY_MODEL_LASI:
+       case DISPLAY_MODEL_OLD_ASP:
+               request_region((unsigned long)LED_DATA_REG, 1, "led_data");
+               break;
+       }
+}
+
+
+
+/*
+   ** led_init()
+   ** 
+   ** led_init() is called very early in the bootup-process from setup.c 
+   ** and asks the PDC for an usable chassis LCD or LED.
+   ** If the PDC doesn't return any info, then the LED
+   ** is detected by lasi.c or asp.c and registered with the
+   ** above functions lasi_led_init() or asp_led_init().
+   ** KittyHawk machines have often a buggy PDC, so that
+   ** we explicitly check for those machines here.
+ */
+
+int __init led_init(void)
+{
+#ifndef DISABLE_LEDS
+       long pdc_result[32];
+
+       printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION);
+
+       /* Work around the buggy PDC of KittyHawk-machines */
+       switch (CPU_HVERSION) {
+       case 0x580:             /* KittyHawk DC2-100 (K100) */
+       case 0x581:             /* KittyHawk DC3-120 (K210) */
+       case 0x582:             /* KittyHawk DC3 100 (K400) */
+       case 0x583:             /* KittyHawk DC3 120 (K410) */
+       case 0x58B:             /* KittyHawk DC2 100 (K200) */
+               printk("%s: KittyHawk-Machine found !!\n", __FUNCTION__);
+               goto found;     /* use the preinitialized values of lcd_info */
+
+       default:
+               break;
+       }
+
+       /* initialize pdc_result, so we can check the return values of pdc_chassis_info() */
+       pdc_result[0] = pdc_result[1] = 0;
+
+       if (pdc_chassis_info(&pdc_result, &lcd_info, sizeof(lcd_info)) == PDC_OK) {
+               printk("%s: chassis info: model %d, ret0=%d, ret1=%d\n",
+                __FUNCTION__, lcd_info.model, pdc_result[0], pdc_result[1]);
+
+               /* check the results. Some machines have a buggy PDC */
+               if (pdc_result[0] <= 0 || pdc_result[0] != pdc_result[1])
+                       goto not_found;
+
+               switch (lcd_info.model) {
+               case DISPLAY_MODEL_LCD: /* LCD display */
+                       if (pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block)
+                           && pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) - 1)
+                                goto not_found;
+                       printk("%s: min_cmd_delay = %d uS\n",
+                            __FUNCTION__, lcd_info.min_cmd_delay);
+                       break;
+
+               case DISPLAY_MODEL_NONE:        /* no LED or LCD available */
+                       goto not_found;
+
+               case DISPLAY_MODEL_LASI:        /* Lasi style 8 bit LED display */
+                       if (pdc_result[0] != 8 && pdc_result[0] != 32)
+                               goto not_found;
+                       break;
+
+               default:
+                       printk(KERN_WARNING "Unknown LCD/LED model %d\n",
+                              lcd_info.model);
+                       goto not_found;
+               }               /* switch() */
+
+found:
+               /* register the LCD/LED driver */
+               register_led_driver();
+               return 0;
+
+       }                       /* if() */
+
+not_found:
+       lcd_info.model = DISPLAY_MODEL_NONE;
+       return 1;
+#endif
+}
diff --git a/arch/parisc/kernel/pa7300lc.c b/arch/parisc/kernel/pa7300lc.c
new file mode 100644 (file)
index 0000000..307e4b2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *   linux/arch/parisc/kernel/pa7300lc.c
+ *     - PA7300LC-specific functions   
+ *
+ *   Copyright (C) 2000 Philipp Rumpf */
+
+#include <asm/gsc.h>
+#include <asm/ptrace.h>
+#include <asm/machdep.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
+
+/* CPU register indices */
+
+#define MIOC_STATUS    0xf040
+#define MIOC_CONTROL   0xf080
+#define MDERRADD       0xf0e0
+#define DMAERR         0xf0e8
+#define DIOERR         0xf0ec
+#define HIDMAMEM       0xf0f4
+
+/* read CPU Diagnose register index */
+static u32 diag_read(int index)
+{
+       return 0;
+}
+
+/* this returns the HPA of the CPU it was called on */
+static u32 cpu_hpa(void)
+{
+       return 0xfffb0000;
+}
+
+static void pa7300lc_lpmc(int code, struct pt_regs *regs)
+{
+       u32 hpa;
+       printk(KERN_WARNING "LPMC on CPU %d\n", smp_processor_id());
+
+       show_regs(regs);
+
+       hpa = cpu_hpa();
+       printk(KERN_WARNING
+               "MIOC_CONTROL %08x\n" "MIOC_STATUS  %08x\n"
+               "MDERRADD     %08x\n" "DMAERR       %08x\n"
+               "DIOERR       %08x\n" "HIDMAMEM     %08x\n",
+               gsc_readl(hpa+MIOC_CONTROL), gsc_readl(hpa+MIOC_STATUS),
+               gsc_readl(hpa+MDERRADD), gsc_readl(hpa+DMAERR),
+               gsc_readl(hpa+DIOERR), gsc_readl(hpa+HIDMAMEM));
+}
+
+void pa7300lc_init(void)
+{
+       cpu_lpmc = pa7300lc_lpmc;
+}
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
new file mode 100644 (file)
index 0000000..2b4dbd7
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Architecture-specific kernel symbols
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/string.h>
+EXPORT_SYMBOL_NOVERS(memscan);
+EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strtok);
+
+#include <linux/pci.h>
+EXPORT_SYMBOL(hppa_dma_ops);
+
+#include <asm/irq.h>
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+
+#include <asm/processor.h>
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(boot_cpu_data);
+
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(synchronize_irq);
+
+#include <asm/smplock.h>
+EXPORT_SYMBOL(kernel_flag);
+
+#include <asm/system.h>
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+
+#endif
+
+#include <asm/uaccess.h>
+EXPORT_SYMBOL(lcopy_to_user);
+EXPORT_SYMBOL(lcopy_from_user);
+
+/* Needed so insmod can set dp value */
+
+extern int data_start;
+
+EXPORT_SYMBOL_NOVERS(data_start);
+
+#include <asm/gsc.h>
+EXPORT_SYMBOL(_gsc_writeb);
+EXPORT_SYMBOL(_gsc_writew);
+EXPORT_SYMBOL(_gsc_writel);
+EXPORT_SYMBOL(_gsc_readb);
+EXPORT_SYMBOL(_gsc_readw);
+EXPORT_SYMBOL(_gsc_readl);
+EXPORT_SYMBOL(busdevice_alloc_irq);
+EXPORT_SYMBOL(register_driver);
+EXPORT_SYMBOL(gsc_alloc_irq);
+EXPORT_SYMBOL(pdc_iodc_read);
+
+extern void $$divI(void);
+extern void $$divU(void);
+extern void $$remI(void);
+extern void $$remU(void);
+extern void $$mulI(void);
+extern void $$mulU(void);
+extern void $$divU_3(void);
+extern void $$divU_5(void);
+extern void $$divU_6(void);
+extern void $$divU_9(void);
+extern void $$divU_10(void);
+extern void $$divU_12(void);
+extern void $$divU_7(void);
+extern void $$divU_14(void);
+extern void $$divU_15(void);
+extern void $$divI_3(void);
+extern void $$divI_5(void);
+extern void $$divI_6(void);
+extern void $$divI_7(void);
+extern void $$divI_9(void);
+extern void $$divI_10(void);
+extern void $$divI_12(void);
+extern void $$divI_14(void);
+extern void $$divI_15(void);
+
+EXPORT_SYMBOL_NOVERS($$divI);
+EXPORT_SYMBOL_NOVERS($$divU);
+EXPORT_SYMBOL_NOVERS($$remI);
+EXPORT_SYMBOL_NOVERS($$remU);
+EXPORT_SYMBOL_NOVERS($$mulI);
+EXPORT_SYMBOL_NOVERS($$mulU);
+EXPORT_SYMBOL_NOVERS($$divU_3);
+EXPORT_SYMBOL_NOVERS($$divU_5);
+EXPORT_SYMBOL_NOVERS($$divU_6);
+EXPORT_SYMBOL_NOVERS($$divU_9);
+EXPORT_SYMBOL_NOVERS($$divU_10);
+EXPORT_SYMBOL_NOVERS($$divU_12);
+EXPORT_SYMBOL_NOVERS($$divU_7);
+EXPORT_SYMBOL_NOVERS($$divU_14);
+EXPORT_SYMBOL_NOVERS($$divU_15);
+EXPORT_SYMBOL_NOVERS($$divI_3);
+EXPORT_SYMBOL_NOVERS($$divI_5);
+EXPORT_SYMBOL_NOVERS($$divI_6);
+EXPORT_SYMBOL_NOVERS($$divI_7);
+EXPORT_SYMBOL_NOVERS($$divI_9);
+EXPORT_SYMBOL_NOVERS($$divI_10);
+EXPORT_SYMBOL_NOVERS($$divI_12);
+EXPORT_SYMBOL_NOVERS($$divI_14);
+EXPORT_SYMBOL_NOVERS($$divI_15);
+
+extern void __ashrdi3(void);
+
+EXPORT_SYMBOL_NOVERS(__ashrdi3);
+
+#ifdef __LP64__
+extern void __divdi3(void);
+extern void __udivdi3(void);
+
+EXPORT_SYMBOL_NOVERS(__divdi3);
+EXPORT_SYMBOL_NOVERS(__udivdi3);
+#endif
+
+#ifndef __LP64__
+extern void $$dyncall(void);
+EXPORT_SYMBOL_NOVERS($$dyncall);
+#endif
+
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
new file mode 100644 (file)
index 0000000..88a9ddc
--- /dev/null
@@ -0,0 +1,547 @@
+/*
+** Dynamic DMA mapping support.
+** See Documentation/DMA-mapping.txt for interface definitions.
+**
+**      (c) Copyright 1999,2000 Hewlett-Packard Company
+**      (c) Copyright 2000 Grant Grundler
+**     (c) Copyright 2000 Philipp Rumpf <prumpf@tux.org>
+**      (c) Copyright 2000 John Marvin
+**
+** This implementation is for PA-RISC platforms that do not support
+** I/O TLBs (aka DMA address translation hardware).
+**
+** "leveraged" from 2.3.47: arch/ia64/kernel/pci-dma.c.
+** (I assume it's from David Mosberger-Tang but there was no Copyright)
+**
+** AFAIK, all PA7100LC and PA7300LC platforms can use this code.
+** All PA2.0 machines but V-class can alias xxx_alloc_consistent()
+** to use regular cacheable memory.
+**
+** - ggg
+*/
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+
+#include <asm/io.h>
+#include <asm/page.h>  /* get_order */
+#include <asm/dma.h>    /* for DMA_CHUNK_SIZE */
+
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry * proc_gsc_root = NULL;
+static int pcxl_proc_info(char *buffer, char **start, off_t offset, int length);
+static unsigned long pcxl_used_bytes = 0;
+static unsigned long pcxl_used_pages = 0;
+
+extern unsigned long pcxl_dma_start; /* Start of pcxl dma mapping area */
+static spinlock_t   pcxl_res_lock;
+static char    *pcxl_res_map;
+static int     pcxl_res_hint;
+static int     pcxl_res_size;
+
+#ifdef DEBUG_PCXL_RESOURCE
+#define DBG_RES(x...)  printk(x)
+#else
+#define DBG_RES(x...)
+#endif
+
+
+/*
+** Dump a hex representation of the resource map.
+*/
+
+#ifdef DUMP_RESMAP
+static
+void dump_resmap(void)
+{
+       u_long *res_ptr = (unsigned long *)pcxl_res_map;
+       u_long i = 0;
+
+       printk("res_map: ");
+       for(; i < (pcxl_res_size / sizeof(unsigned long)); ++i, ++res_ptr)
+               printk("%08lx ", *res_ptr);
+
+       printk("\n");
+}
+#else
+static inline void dump_resmap(void) {;}
+#endif
+
+static int pa11_dma_supported( struct pci_dev *dev, dma_addr_t mask)
+{
+       return 1;
+}
+
+static inline int map_pte_uncached(pte_t * pte,
+               unsigned long vaddr,
+               unsigned long size, unsigned long *paddr_ptr)
+{
+       unsigned long end;
+       unsigned long orig_vaddr = vaddr;
+
+       vaddr &= ~PMD_MASK;
+       end = vaddr + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       do {
+               if (!pte_none(*pte))
+                       printk(KERN_ERR "map_pte_uncached: page already exists\n");
+               set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC));
+               pdtlb_kernel(orig_vaddr);
+               vaddr += PAGE_SIZE;
+               orig_vaddr += PAGE_SIZE;
+               (*paddr_ptr) += PAGE_SIZE;
+               pte++;
+       } while (vaddr < end);
+       return 0;
+}
+
+static inline int map_pmd_uncached(pmd_t * pmd, unsigned long vaddr,
+               unsigned long size, unsigned long *paddr_ptr)
+{
+       unsigned long end;
+       unsigned long orig_vaddr = vaddr;
+
+       vaddr &= ~PGDIR_MASK;
+       end = vaddr + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       do {
+               pte_t * pte = pte_alloc_kernel(pmd, vaddr);
+               if (!pte)
+                       return -ENOMEM;
+               if (map_pte_uncached(pte, orig_vaddr, end - vaddr, paddr_ptr))
+                       return -ENOMEM;
+               vaddr = (vaddr + PMD_SIZE) & PMD_MASK;
+               orig_vaddr += PMD_SIZE;
+               pmd++;
+       } while (vaddr < end);
+       return 0;
+}
+
+static inline int map_uncached_pages(unsigned long vaddr, unsigned long size,
+               unsigned long paddr)
+{
+       pgd_t * dir;
+       unsigned long end = vaddr + size;
+
+       dir = pgd_offset_k(vaddr);
+       do {
+               pmd_t *pmd;
+               
+               pmd = pmd_alloc_kernel(dir, vaddr);
+               if (!pmd)
+                       return -ENOMEM;
+               if (map_pmd_uncached(pmd, vaddr, end - vaddr, &paddr))
+                       return -ENOMEM;
+               vaddr = vaddr + PGDIR_SIZE;
+               dir++;
+       } while (vaddr && (vaddr < end));
+       return 0;
+}
+
+static inline void unmap_uncached_pte(pmd_t * pmd, unsigned long vaddr,
+               unsigned long size)
+{
+       pte_t * pte;
+       unsigned long end;
+       unsigned long orig_vaddr = vaddr;
+
+       if (pmd_none(*pmd))
+               return;
+       if (pmd_bad(*pmd)) {
+               pmd_ERROR(*pmd);
+               pmd_clear(pmd);
+               return;
+       }
+       pte = pte_offset(pmd, vaddr);
+       vaddr &= ~PMD_MASK;
+       end = vaddr + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       do {
+               pte_t page = *pte;
+               pte_clear(pte);
+               pdtlb_kernel(orig_vaddr);
+               vaddr += PAGE_SIZE;
+               orig_vaddr += PAGE_SIZE;
+               pte++;
+               if (pte_none(page) || pte_present(page))
+                       continue;
+               printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n");
+       } while (vaddr < end);
+}
+
+static inline void unmap_uncached_pmd(pgd_t * dir, unsigned long vaddr,
+               unsigned long size)
+{
+       pmd_t * pmd;
+       unsigned long end;
+       unsigned long orig_vaddr = vaddr;
+
+       if (pgd_none(*dir))
+               return;
+       if (pgd_bad(*dir)) {
+               pgd_ERROR(*dir);
+               pgd_clear(dir);
+               return;
+       }
+       pmd = pmd_offset(dir, vaddr);
+       vaddr &= ~PGDIR_MASK;
+       end = vaddr + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       do {
+               unmap_uncached_pte(pmd, orig_vaddr, end - vaddr);
+               vaddr = (vaddr + PMD_SIZE) & PMD_MASK;
+               orig_vaddr += PMD_SIZE;
+               pmd++;
+       } while (vaddr < end);
+}
+
+static void unmap_uncached_pages(unsigned long vaddr, unsigned long size)
+{
+       pgd_t * dir;
+       unsigned long end = vaddr + size;
+
+       dir = pgd_offset_k(vaddr);
+       do {
+               unmap_uncached_pmd(dir, vaddr, end - vaddr);
+               vaddr = vaddr + PGDIR_SIZE;
+               dir++;
+       } while (vaddr && (vaddr < end));
+}
+
+#define PCXL_SEARCH_LOOP(idx, mask, size)  \
+       for(; res_ptr < res_end; ++res_ptr) \
+       { \
+               if(0 == ((*res_ptr) & mask)) { \
+                       *res_ptr |= mask; \
+                      idx = (int)((u_long)res_ptr - (u_long)pcxl_res_map); \
+                      pcxl_res_hint = idx + (size >> 3); \
+                       goto resource_found; \
+               } \
+       }
+
+#define PCXL_FIND_FREE_MAPPING(idx, mask, size)  { \
+       u##size *res_ptr = (u##size *)&(pcxl_res_map[pcxl_res_hint & ~((size >> 3) - 1)]); \
+       u##size *res_end = (u##size *)&pcxl_res_map[pcxl_res_size]; \
+       PCXL_SEARCH_LOOP(idx, mask, size); \
+       res_ptr = (u##size *)&pcxl_res_map[0]; \
+       PCXL_SEARCH_LOOP(idx, mask, size); \
+}
+
+unsigned long
+pcxl_alloc_range(size_t size)
+{
+       int res_idx;
+       u_long mask, flags;
+       unsigned int pages_needed = size >> PAGE_SHIFT;
+
+       ASSERT(pages_needed);
+       ASSERT((pages_needed * PAGE_SIZE) < DMA_CHUNK_SIZE);
+       ASSERT(pages_needed < (BITS_PER_LONG - PAGE_SHIFT));
+
+       mask = (u_long) -1L;
+       mask >>= BITS_PER_LONG - pages_needed;
+
+       DBG_RES("pcxl_alloc_range() size: %d pages_needed %d pages_mask 0x%08lx\n", 
+               size, pages_needed, mask);
+
+       spin_lock_irqsave(&pcxl_res_lock, flags);
+
+       if(pages_needed <= 8) {
+               PCXL_FIND_FREE_MAPPING(res_idx, mask, 8);
+       } else if(pages_needed <= 16) {
+               PCXL_FIND_FREE_MAPPING(res_idx, mask, 16);
+       } else if(pages_needed <= 32) {
+               PCXL_FIND_FREE_MAPPING(res_idx, mask, 32);
+       } else {
+               panic(__FILE__ ": pcxl_alloc_range() Too many pages to map.\n");
+       }
+
+       dump_resmap();
+       panic(__FILE__ ": pcxl_alloc_range() out of dma mapping resources\n");
+       
+resource_found:
+       
+       DBG_RES("pcxl_alloc_range() res_idx %d mask 0x%08lx res_hint: %d\n",
+               res_idx, mask, pcxl_res_hint);
+
+       pcxl_used_pages += pages_needed;
+       pcxl_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1);
+
+       spin_unlock_irqrestore(&pcxl_res_lock, flags);
+
+       dump_resmap();
+
+       /* 
+       ** return the corresponding vaddr in the pcxl dma map
+       */
+       return (pcxl_dma_start + (res_idx << (PAGE_SHIFT + 3)));
+}
+
+#define PCXL_FREE_MAPPINGS(idx, m, size) \
+               u##size *res_ptr = (u##size *)&(pcxl_res_map[(idx) + (((size >> 3) - 1) & (~((size >> 3) - 1)))]); \
+               ASSERT((*res_ptr & m) == m); \
+               *res_ptr &= ~m;
+
+/*
+** clear bits in the pcxl resource map
+*/
+static void
+pcxl_free_range(unsigned long vaddr, size_t size)
+{
+       u_long mask, flags;
+       unsigned int res_idx = (vaddr - pcxl_dma_start) >> (PAGE_SHIFT + 3);
+       unsigned int pages_mapped = size >> PAGE_SHIFT;
+
+       ASSERT(pages_mapped);
+       ASSERT((pages_mapped * PAGE_SIZE) < DMA_CHUNK_SIZE);
+       ASSERT(pages_mapped < (BITS_PER_LONG - PAGE_SHIFT));
+
+       mask = (u_long) -1L;
+       mask >>= BITS_PER_LONG - pages_mapped;
+
+       DBG_RES("pcxl_free_range() res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", 
+               res_idx, size, pages_mapped, mask);
+
+       spin_lock_irqsave(&pcxl_res_lock, flags);
+
+       if(pages_mapped <= 8) {
+               PCXL_FREE_MAPPINGS(res_idx, mask, 8);
+       } else if(pages_mapped <= 16) {
+               PCXL_FREE_MAPPINGS(res_idx, mask, 16);
+       } else if(pages_mapped <= 32) {
+               PCXL_FREE_MAPPINGS(res_idx, mask, 32);
+       } else {
+               panic(__FILE__ ": pcxl_free_range() Too many pages to unmap.\n");
+       }
+       
+       pcxl_used_pages -= (pages_mapped ? pages_mapped : 1);
+       pcxl_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1);
+
+       spin_unlock_irqrestore(&pcxl_res_lock, flags);
+
+       dump_resmap();
+}
+
+static int __init
+pcxl_dma_init(void)
+{
+    if (pcxl_dma_start == 0)
+       return 0;
+
+    spin_lock_init(&pcxl_res_lock);
+    pcxl_res_size = PCXL_DMA_MAP_SIZE >> (PAGE_SHIFT + 3);
+    pcxl_res_hint = 0;
+    pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL,
+                                           get_order(pcxl_res_size));
+
+    proc_gsc_root = proc_mkdir("gsc", 0);
+    create_proc_info_entry("dino", 0, proc_gsc_root, pcxl_proc_info);
+    return 0;
+}
+
+__initcall(pcxl_dma_init);
+
+static void * pa11_dma_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+{
+       unsigned long vaddr;
+       unsigned long paddr;
+       int order;
+
+       order = get_order(size);
+       size = 1 << (order + PAGE_SHIFT);
+       vaddr = pcxl_alloc_range(size);
+       paddr = __get_free_pages(GFP_ATOMIC, order);
+       flush_kernel_dcache_range(paddr, size);
+       paddr = __pa(paddr);
+       map_uncached_pages(vaddr, size, paddr);
+       *dma_handle = (dma_addr_t) paddr;
+
+#if 0
+/* This probably isn't needed to support EISA cards.
+** ISA cards will certainly only support 24-bit DMA addressing.
+** Not clear if we can, want, or need to support ISA.
+*/
+       if (!hwdev || hwdev->dma_mask != 0xffffffff)
+               gfp |= GFP_DMA;
+#endif
+       return (void *)vaddr;
+}
+
+static void pa11_dma_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
+{
+       int order;
+
+       order = get_order(size);
+       size = 1 << (order + PAGE_SHIFT);
+       unmap_uncached_pages((unsigned long)vaddr, size);
+       pcxl_free_range((unsigned long)vaddr, size);
+       free_pages((unsigned long)__va(dma_handle), order);
+}
+
+static dma_addr_t pa11_dma_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
+{
+       if (direction == PCI_DMA_NONE) {
+               printk(KERN_ERR "pa11_dma_map_single(PCI_DMA_NONE) called by %p\n", __builtin_return_address(0));
+               BUG();
+       }
+
+       flush_kernel_dcache_range((unsigned long) addr, size);
+       return virt_to_phys(addr);
+}
+
+static void pa11_dma_unmap_single(struct pci_dev *dev, dma_addr_t dma_handle, size_t size, int direction)
+{
+       if (direction == PCI_DMA_NONE) {
+               printk(KERN_ERR "pa11_dma_unmap_single(PCI_DMA_NONE) called by %p\n", __builtin_return_address(0));
+               BUG();
+       }
+
+       if (direction == PCI_DMA_TODEVICE)
+           return;
+
+       /*
+        * For PCI_DMA_FROMDEVICE this flush is not necessary for the
+        * simple map/unmap case. However, it IS necessary if if
+        * pci_dma_sync_single has been called and the buffer reused.
+        */
+
+       flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size);
+       return;
+}
+
+static int pa11_dma_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+{
+       int i;
+
+       if (direction == PCI_DMA_NONE)
+           BUG();
+
+       for (i = 0; i < nents; i++, sglist++ ) {
+               sg_dma_address(sglist) = (dma_addr_t) virt_to_phys(sglist->address);
+               sg_dma_len(sglist) = sglist->length;
+               flush_kernel_dcache_range((unsigned long)sglist->address,
+                               sglist->length);
+       }
+       return nents;
+}
+
+static void pa11_dma_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+{
+       int i;
+
+       if (direction == PCI_DMA_NONE)
+           BUG();
+
+       if (direction == PCI_DMA_TODEVICE)
+           return;
+
+       /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
+
+       for (i = 0; i < nents; i++, sglist++ )
+               flush_kernel_dcache_range((unsigned long) sglist->address, sglist->length);
+       return;
+}
+
+static void pa11_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_handle, size_t size, int direction)
+{
+       if (direction == PCI_DMA_NONE)
+           BUG();
+
+       flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size);
+}
+
+static void pa11_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+{
+       int i;
+
+       /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
+
+       for (i = 0; i < nents; i++, sglist++ )
+               flush_kernel_dcache_range((unsigned long) sglist->address, sglist->length);
+}
+
+struct pci_dma_ops pcxl_dma_ops = {
+       pa11_dma_supported,                     /* dma_support */
+       pa11_dma_alloc_consistent,
+       pa11_dma_free_consistent,
+       pa11_dma_map_single,                    /* map_single */
+       pa11_dma_unmap_single,                  /* unmap_single */
+       pa11_dma_map_sg,                        /* map_sg */
+       pa11_dma_unmap_sg,                      /* unmap_sg */
+       pa11_dma_sync_single,                   /* dma_sync_single */
+       pa11_dma_sync_sg                        /* dma_sync_sg */
+};
+
+static void *fail_alloc_consistent(struct pci_dev *hwdev, size_t size,
+               dma_addr_t *dma_handle)
+{
+       return NULL;
+}
+
+static void fail_free_consistent(struct pci_dev *dev, size_t size,
+               void *vaddr, dma_addr_t iova)
+{
+       return;
+}
+
+struct pci_dma_ops pcx_dma_ops = {
+       pa11_dma_supported,                     /* dma_support */
+       fail_alloc_consistent,
+       fail_free_consistent,
+       pa11_dma_map_single,                    /* map_single */
+       pa11_dma_unmap_single,                  /* unmap_single */
+       pa11_dma_map_sg,                        /* map_sg */
+       pa11_dma_unmap_sg,                      /* unmap_sg */
+       pa11_dma_sync_single,                   /* dma_sync_single */
+       pa11_dma_sync_sg                        /* dma_sync_sg */
+};
+
+struct pci_dma_ops *hppa_dma_ops;
+
+static int pcxl_proc_info(char *buf, char **start, off_t offset, int len)
+{
+       u_long i = 0;
+       unsigned long *res_ptr = (u_long *)pcxl_res_map;
+       unsigned long total_pages = pcxl_res_size << 3;        /* 8 bits per byte */
+
+       sprintf(buf, "\nDMA Mapping Area size    : %d bytes (%d pages)\n",
+               PCXL_DMA_MAP_SIZE,
+               (pcxl_res_size << 3) ); /* 1 bit per page */
+       
+       sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", 
+               buf, pcxl_res_size, pcxl_res_size << 3);   /* 8 bits per byte */
+
+       strcat(buf,  "            total:    free:    used:   % used:\n");
+       sprintf(buf, "%sblocks  %8d %8ld %8ld %8ld%%\n", buf, pcxl_res_size,
+               pcxl_res_size - pcxl_used_bytes, pcxl_used_bytes,
+               (pcxl_used_bytes * 100) / pcxl_res_size);
+
+       sprintf(buf, "%spages   %8ld %8ld %8ld %8ld%%\n", buf, total_pages,
+               total_pages - pcxl_used_pages, pcxl_used_pages,
+               (pcxl_used_pages * 100 / total_pages));
+       
+       strcat(buf, "\nResource bitmap:");
+
+       for(; i < (pcxl_res_size / sizeof(u_long)); ++i, ++res_ptr) {
+               if ((i & 7) == 0)
+                   strcat(buf,"\n   ");
+               sprintf(buf, "%s %08lx", buf, *res_ptr);
+       }
+       strcat(buf, "\n");
+       return strlen(buf);
+}
+
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
new file mode 100644 (file)
index 0000000..ad9d9d4
--- /dev/null
@@ -0,0 +1,534 @@
+/* $Id: pci.c,v 1.6 2000/01/29 00:12:05 grundler Exp $
+ *
+ * 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) 1997, 1998 Ralf Baechle
+ * Copyright (C) 1999 SuSE GmbH
+ * Copyright (C) 1999 Hewlett-Packard Company
+ * Copyright (C) 1999, 2000 Grant Grundler
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>                /* for __init and __devinit */
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>      /* for memcpy() */
+
+#include <asm/system.h>
+
+#ifdef CONFIG_PCI
+
+#undef DEBUG_RESOURCES
+
+#ifdef DEBUG_RESOURCES
+#define DBG_RES(x...)  printk(x)
+#else
+#define DBG_RES(x...)
+#endif
+
+/* To be used as: mdelay(pci_post_reset_delay);
+**
+** post_reset is the time the kernel should stall to prevent anyone from
+** accessing the PCI bus once #RESET is de-asserted. 
+** PCI spec somewhere says 1 second but with multi-PCI bus systems,
+** this makes the boot time much longer than necessary.
+** 20ms seems to work for all the HP PCI implementations to date.
+*/
+int pci_post_reset_delay = 50;
+
+struct pci_port_ops *pci_port;
+struct pci_bios_ops *pci_bios;
+
+struct pci_hba_data *hba_list = NULL;
+int hba_count = 0;
+
+/*
+** parisc_pci_hba used by pci_port->in/out() ops to lookup bus data.
+*/
+#define PCI_HBA_MAX 32
+static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX];
+
+
+/********************************************************************
+**
+** I/O port space support
+**
+*********************************************************************/
+
+#define PCI_PORT_HBA(a) ((a)>>16)
+#define PCI_PORT_ADDR(a) ((a) & 0xffffUL)
+
+/* KLUGE : inb needs to be defined differently for PCI devices than
+** for other bus interfaces. Doing this at runtime sucks but is the
+** only way one driver binary can support devices on different bus types.
+**
+*/
+
+#define PCI_PORT_IN(type, size) \
+u##size in##type (int addr) \
+{ \
+       int b = PCI_PORT_HBA(addr); \
+       u##size d = (u##size) -1; \
+       ASSERT(pci_port); /* make sure services are defined */ \
+       ASSERT(parisc_pci_hba[b]); /* make sure ioaddr are "fixed up" */ \
+       if (parisc_pci_hba[b] == NULL) { \
+               printk(KERN_WARNING "\nPCI Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \
+       } else { \
+               d = pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \
+       } \
+       return d; \
+}
+
+PCI_PORT_IN(b,  8)
+PCI_PORT_IN(w, 16)
+PCI_PORT_IN(l, 32)
+
+
+#define PCI_PORT_OUT(type, size) \
+void out##type (u##size d, int addr) \
+{ \
+       int b = PCI_PORT_HBA(addr); \
+       ASSERT(pci_port); \
+       pci_port->out##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr), d); \
+}
+
+PCI_PORT_OUT(b,  8)
+PCI_PORT_OUT(w, 16)
+PCI_PORT_OUT(l, 32)
+
+
+
+/*
+ * BIOS32 replacement.
+ */
+void pcibios_init(void)
+{
+       ASSERT(pci_bios != NULL);
+
+       if (pci_bios)
+       {
+               if (pci_bios->init) {
+                       (*pci_bios->init)();
+               } else {
+                       printk(KERN_WARNING "pci_bios != NULL but init() is!\n");
+               }
+       }
+}
+
+
+/* Called from pci_do_scan_bus() *after* walking a bus but before walking PPBs. */
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+       ASSERT(pci_bios != NULL);
+
+        /* If this is a bridge, get the current bases */
+       if (bus->self) {
+               pci_read_bridge_bases(bus);
+       }
+
+       if (pci_bios) {
+               if (pci_bios->fixup_bus) {
+                       (*pci_bios->fixup_bus)(bus);
+               } else {
+                       printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
+               }
+       }
+}
+
+
+char *pcibios_setup(char *str)
+{
+       return str;
+}
+
+#endif /* defined(CONFIG_PCI) */
+
+
+
+/* -------------------------------------------------------------------
+** linux-2.4: NEW STUFF 
+** --------------------
+*/
+
+/*
+** Used in drivers/pci/quirks.c
+*/
+struct pci_fixup pcibios_fixups[] = { {0} };
+
+
+/*
+** called by drivers/pci/setup.c:pdev_fixup_irq()
+*/
+void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+/*
+** updates IRQ_LINE cfg register to reflect PCI-PCI bridge skewing.
+**
+** Calling path for Alpha is:
+**  alpha/kernel/pci.c:common_init_pci(swizzle_func, pci_map_irq_func )
+**     drivers/pci/setup.c:pci_fixup_irqs()
+**         drivers/pci/setup.c:pci_fixup_irq() (for each PCI device)
+**             invoke swizzle and map functions
+**             alpha/kernel/pci.c:pcibios_update_irq()
+**
+** Don't need this for PA legacy PDC systems.
+**
+** On PAT PDC systems, We only support one "swizzle" for any number
+** of PCI-PCI bridges deep. That's how bit3 PCI expansion chassis
+** are implemented. The IRQ lines are "skewed" for all devices but
+** *NOT* routed through the PCI-PCI bridge. Ie any device "0" will
+** share an IRQ line. Legacy PDC is expecting this IRQ line routing
+** as well.
+**
+** Unfortunately, PCI spec allows the IRQ lines to be routed
+** around the PCI bridge as long as the IRQ lines are skewed
+** based on the device number...<sigh>...
+**
+** Lastly, dino.c might be able to use pci_fixup_irq() to
+** support RS-232 and PS/2 children. Not sure how but it's
+** something to think about.
+*/
+}
+
+
+/* ------------------------------------
+**
+** Program one BAR in PCI config space.
+**
+** ------------------------------------
+** PAT PDC systems need this routine. PA legacy PDC does not.
+**
+** Used by alpha/arm: 
+** alpha/kernel/pci.c:common_init_pci()
+** (or arm/kernel/pci.c:pcibios_init())
+**    drivers/pci/setup.c:pci_assign_unassigned_resources()
+**        drivers/pci/setup.c:pdev_assign_unassigned_resources()
+**            arch/<foo>/kernel/pci.c:pcibios_update_resource()
+**
+** When BAR's are configured by linux, this routine
+** will update configuration space with the "normalized"
+** address. "root" indicates where the range starts and res
+** is some portion of that range.
+**
+** For all PA-RISC systems except V-class, root->start would be zero.
+**
+** PAT PDC can tell us which MMIO ranges are available or already in use.
+** I/O port space and such are not memory mapped anyway for PA-Risc.
+*/
+void __devinit
+pcibios_update_resource(
+       struct pci_dev *dev,
+       struct resource *root,
+       struct resource *res,
+       int barnum
+       )
+{
+       int where;
+       u32 barval = 0;
+
+       DBG_RES("pcibios_update_resource(%s, ..., %d) [%lx,%lx]/%x\n",
+               dev->slot_name,
+               barnum, res->start, res->end, (int) res->flags);
+
+       if (barnum >= PCI_BRIDGE_RESOURCES) {
+               /* handled in pbus_set_ranges_data() */
+               return;
+       }
+
+       if (barnum == PCI_ROM_RESOURCE) {
+               where = PCI_ROM_ADDRESS;
+       } else {
+               /* 0-5  standard PCI "regions" */
+               where = PCI_BASE_ADDRESS_0 + (barnum * 4);
+       }
+
+       if (res->flags & IORESOURCE_IO) {
+               barval = PCI_PORT_ADDR(res->start);
+       } else if (res->flags & IORESOURCE_MEM) {
+               /* This should work for VCLASS too */
+               barval = res->start & 0xffffffffUL;
+       } else {
+               panic("pcibios_update_resource() WTF? flags not IO or MEM");
+       }
+
+       pci_write_config_dword(dev, where, barval);
+
+/* XXX FIXME - Elroy does support 64-bit (dual cycle) addressing.
+** But at least one device (Symbios 53c896) which has 64-bit BAR
+** doesn't actually work right with dual cycle addresses.
+** So ignore the whole mess for now.
+*/
+
+       if ((res->flags & (PCI_BASE_ADDRESS_SPACE
+                          | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+           == (PCI_BASE_ADDRESS_SPACE_MEMORY
+               | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+               pci_write_config_dword(dev, where+4, 0);
+               printk(KERN_WARNING "PCI: dev %s type 64-bit\n", dev->name);
+       }
+}
+
+/*
+** Called by pci_set_master() - a driver interface.
+**
+** Legacy PDC guarantees to set:
+**      Map Memory BAR's into PA IO space.
+**      Map Expansion ROM BAR into one common PA IO space per bus.
+**      Map IO BAR's into PCI IO space.
+**      Command (see below)
+**      Cache Line Size
+**      Latency Timer
+**      Interrupt Line
+**     PPB: secondary latency timer, io/mmio base/limit,
+**             bus numbers, bridge control
+**
+*/
+void
+pcibios_set_master(struct pci_dev *dev)
+{
+       u8 lat;
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+       if (lat >= 16) return;
+
+       /*
+       ** HP generally has fewer devices on the bus than other architectures.
+       */
+       printk("PCIBIOS: Setting latency timer of %s to 128\n", dev->slot_name);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+}
+
+
+/*
+** called by drivers/pci/setup-res.c:pbus_set_ranges().
+*/
+void pcibios_fixup_pbus_ranges(
+       struct pci_bus *bus,
+       struct pbus_set_ranges_data *ranges
+       )
+{
+       /*
+       ** I/O space may see busnumbers here. Something
+       ** in the form of 0xbbxxxx where bb is the bus num
+       ** and xxxx is the I/O port space address.
+       ** Remaining address translation are done in the
+       ** PCI Host adapter specific code - ie dino_out8.
+       */
+       ranges->io_start = PCI_PORT_ADDR(ranges->io_start);
+       ranges->io_end   = PCI_PORT_ADDR(ranges->io_end);
+
+       DBG_RES("pcibios_fixup_pbus_ranges(%02x, [%lx,%lx %lx,%lx])\n", bus->number,
+               ranges->io_start, ranges->io_end,
+               ranges->mem_start, ranges->mem_end);
+}
+
+#define MAX(val1, val2)   ((val1) > (val2) ? (val1) : (val2))
+
+
+/*
+** pcibios align resources() is called everytime generic PCI code
+** wants to generate a new address. The process of looking for
+** an available address, each candidate is first "aligned" and
+** then checked if the resource is available until a match is found.
+**
+** Since we are just checking candidates, don't use any fields other
+** than res->start.
+*/
+void __devinit
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+       unsigned long mask, align;
+
+       DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx)\n",
+               ((struct pci_dev *) data)->slot_name,
+               res->parent, res->start, res->end, (int) res->flags, size);
+
+       /* has resource already been aligned/assigned? */
+       if (res->parent)
+               return;
+
+       /* If it's not IO, then it's gotta be MEM */
+       align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
+
+       /* Align to largest of MIN or input size */
+       mask = MAX(size, align) - 1;
+       res->start += mask;
+       res->start &= ~mask;
+
+       /*
+       ** WARNING : caller is expected to update "end" field.
+       ** We can't since it might really represent the *size*.
+       ** The difference is "end = start + size" vs "end += size".
+       */
+}
+
+
+#define ROUND_UP(x, a)         (((x) + (a) - 1) & ~((a) - 1))
+
+void __devinit
+pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
+{
+       struct pbus_set_ranges_data inner;
+       struct pci_dev *dev;
+       struct pci_dev *bridge = bus->self;
+       struct list_head *ln;
+
+       /* set reasonable default "window" for pcibios_align_resource */
+       inner.io_start  = inner.io_end  = 0;
+       inner.mem_start = inner.mem_end = 0;
+
+       /* Collect information about how our direct children are layed out. */
+       for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+               int i;
+               dev = pci_dev_b(ln);
+
+               /* Skip bridges here - we'll catch them below */
+               if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+                       continue;
+
+               for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+                       struct resource res;
+                       unsigned long size;
+
+                       if (dev->resource[i].flags == 0)
+                               continue;
+
+                       memcpy(&res, &dev->resource[i], sizeof(res));
+                       size = res.end - res.start + 1;
+
+                       if (res.flags & IORESOURCE_IO) {
+                               res.start = inner.io_end;
+                               pcibios_align_resource(dev, &res, size);
+                               inner.io_end += res.start + size;
+                       } else if (res.flags & IORESOURCE_MEM) {
+                               res.start = inner.mem_end;
+                               pcibios_align_resource(dev, &res, size);
+                               inner.mem_end = res.start + size;
+                       }
+
+               DBG_RES("    %s  inner size %lx/%x IO %lx MEM %lx\n",
+                       dev->slot_name,
+                       size, res.flags, inner.io_end, inner.mem_end);
+               }
+       }
+
+       /* And for all of the subordinate busses. */
+       for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
+               pcibios_size_bridge(pci_bus_b(ln), &inner);
+
+       /* turn the ending locations into sizes (subtract start) */
+       inner.io_end -= inner.io_start - 1;
+       inner.mem_end -= inner.mem_start - 1;
+
+       /* Align the sizes up by bridge rules */
+       inner.io_end = ROUND_UP(inner.io_end, 4*1024) - 1;
+       inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024) - 1;
+
+       /* PPB - PCI bridge Device will normaller also have "outer" != NULL. */
+       if (bridge) {
+               /* Adjust the bus' allocation requirements */
+               /* PPB's pci device Bridge resources */
+
+               bus->resource[0] = &bridge->resource[PCI_BRIDGE_RESOURCES];
+               bus->resource[1] = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
+               
+               bus->resource[0]->start = bus->resource[1]->start  = 0;
+               bus->resource[0]->parent= bus->resource[1]->parent = NULL;
+
+               bus->resource[0]->end    = inner.io_end;
+               bus->resource[0]->flags  = IORESOURCE_IO;
+
+               bus->resource[1]->end    = inner.mem_end;
+               bus->resource[1]->flags  = IORESOURCE_MEM;
+       }
+
+       /* adjust parent's resource requirements */
+       if (outer) {
+               outer->io_end = ROUND_UP(outer->io_end, 4*1024);
+               outer->io_end += inner.io_end;
+
+               outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024);
+               outer->mem_end += inner.mem_end;
+       }
+}
+
+#undef ROUND_UP
+
+
+int __devinit
+pcibios_enable_device(struct pci_dev *dev)
+{
+       u16 cmd, old_cmd;
+       int idx;
+
+       /*
+       ** The various platform PDC's (aka "BIOS" for PCs) don't
+       ** enable all the same bits. We just make sure they are here.
+       */
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       old_cmd = cmd;
+
+       /*
+       ** See if any resources have been allocated
+       */
+        for (idx=0; idx<6; idx++) {
+               struct resource *r = &dev->resource[idx];
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+
+       /*
+       ** System error and Parity Error reporting are enabled by default.
+       ** Devices that do NOT want those behaviors should clear them
+       ** (eg PCI graphics, possibly networking).
+       ** Interfaces like SCSI certainly should not. We want the
+       ** system to crash if a system or parity error is detected.
+       ** At least until the device driver can recover from such an error.
+       */
+       cmd |= (PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+
+       if (cmd != old_cmd) {
+               printk("PCIBIOS: Enabling device %s (%04x -> %04x)\n",
+                       dev->slot_name, old_cmd, cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+
+       return 0;
+}
+
+
+void __devinit
+pcibios_assign_unassigned_resources(struct pci_bus *bus)
+{
+       struct list_head *ln;
+
+        for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next)
+       {
+               pdev_assign_unassigned_resources(pci_dev_b(ln));
+       }
+
+        /* And for all of the sub-busses.  */
+       for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
+               pcibios_assign_unassigned_resources(pci_bus_b(ln));
+
+}
+
+/*
+** PARISC specific (unfortunately)
+*/
+void pcibios_register_hba(struct pci_hba_data *hba)
+{
+       hba->next = hba_list;
+       hba_list = hba;
+
+       ASSERT(hba_count < PCI_HBA_MAX);
+
+       /*
+       ** pci_port->in/out() uses parisc_pci_hba to lookup parameter.
+       */
+       parisc_pci_hba[hba_count] = hba;
+       hba->hba_num = hba_count++;
+}
diff --git a/arch/parisc/kernel/pdc.c b/arch/parisc/kernel/pdc.c
new file mode 100644 (file)
index 0000000..4fa4327
--- /dev/null
@@ -0,0 +1,217 @@
+/* arch/parisc/kernel/pdc.c  - safe pdc access routines
+ *
+ * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
+ * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
+ *
+ * only these routines should be used out of the real kernel (i.e. everything
+ * using virtual addresses) for obvious reasons */
+
+/*     I think it would be in everyone's best interest to follow this
+ *     guidelines when writing PDC wrappers:
+ *
+ *      - the name of the pdc wrapper should match one of the macros
+ *        used for the first two arguments
+ *      - don't use caps for random parts of the name
+ *      - use ASSERT_ALIGN to ensure the aligment of the arguments is
+ *        correct
+ *      - use __pa() to convert virtual (kernel) pointers to physical
+ *        ones.
+ *      - the name of the struct used for pdc return values should equal
+ *        one of the macros used for the first two arguments to the
+ *        corresponding PDC call
+ *      - keep the order of arguments
+ *      - don't be smart (setting trailing NUL bytes for strings, return
+ *        something useful even if the call failed) unless you are sure
+ *        it's not going to affect functionality or performance
+ *
+ *     Example:
+ *     int pdc_cache_info(struct pdc_cache_info *cache_info )
+ *     {
+ *             ASSERT_ALIGN(cache_info, 8);
+ *     
+ *             return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
+ *     }
+ *                                     prumpf  991016  
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/real.h>
+#include <asm/system.h>
+
+
+#define ASSERT_ALIGN(ptr, align)                                       \
+       do { if(((unsigned long)(ptr)) & (align-1)) {                   \
+               printk("PDC: %s:%d  %s() called with "  \
+                       "unaligned argument from %p", __FILE__, __LINE__, \
+                       __FUNCTION__, __builtin_return_address(0));     \
+                                                                       \
+               return -1;                                              \
+       } } while(0)
+       
+/* verify address can be accessed without an HPMC */
+int pdc_add_valid(void *address)
+{
+       ASSERT_ALIGN(address, 4);
+
+       return mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, (unsigned long)address);
+}
+
+#if 0
+int pdc_chassis_warn(struct pdc_chassis_warn *address)
+{
+       ASSERT_ALIGN(address, 4);
+
+       return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(address), 0);
+}
+#endif
+
+int pdc_chassis_disp(unsigned long disp)
+{
+       return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp);
+}
+
+int pdc_chassis_info(void *pdc_result, void *chassis_info, unsigned long len)
+{
+       ASSERT_ALIGN(pdc_result, 4);
+       ASSERT_ALIGN(chassis_info, 4);
+       return mem_pdc_call(PDC_CHASSIS,PDC_RETURN_CHASSIS_INFO, 
+               __pa(pdc_result), __pa(chassis_info), len);
+}
+
+int pdc_hpa_processor(void *address)
+{
+       /* We're using 0 for the last parameter just to make sure.
+          It's actually HVERSION dependant.  And remember, life is
+          hard without a backspace. */
+       ASSERT_ALIGN(address, 4);
+
+       return mem_pdc_call(PDC_HPA, PDC_HPA_PROCESSOR, __pa(address),0);
+}
+
+#if 0
+int pdc_hpa_modules(void *address)
+{
+       return mem_pdc_call(PDC_HPA, PDC_HPA_MODULES, address);
+}
+#endif
+
+int pdc_iodc_read(void *address, void * hpa, unsigned int index,
+       void * iodc_data, unsigned int iodc_data_size)
+{
+       ASSERT_ALIGN(address, 4);
+       ASSERT_ALIGN(iodc_data, 8);
+       return mem_pdc_call(PDC_IODC, PDC_IODC_READ, 
+               __pa(address), hpa, index, __pa(iodc_data), iodc_data_size);
+}
+
+
+int pdc_system_map_find_mods(void *pdc_mod_info, 
+       void *mod_path, int index)
+{
+       return mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE,
+               __pa(pdc_mod_info), __pa(mod_path), (long)index);
+}
+
+
+int pdc_model_info(struct pdc_model *model) {
+       ASSERT_ALIGN(model, 8);
+       return mem_pdc_call(PDC_MODEL,PDC_MODEL_INFO,__pa(model),0);
+}
+
+/* get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L) */ 
+int pdc_model_sysmodel(char * name)
+{
+       struct pdc_model_sysmodel sys_model;
+       int retval;
+       
+       ASSERT_ALIGN(&sys_model, 8);
+       ASSERT_ALIGN(name, 4);
+
+       sys_model.mod_len = 0;
+       retval = mem_pdc_call(PDC_MODEL,PDC_MODEL_SYSMODEL,__pa(&sys_model),
+                   OS_ID_HPUX,__pa(name));
+       
+       if (retval == PDC_RET_OK) 
+           name[sys_model.mod_len] = '\0'; /* add trailing '\0' */
+       else
+           name[0] = 0;
+       
+       return retval;
+}
+
+/* id: 0 = cpu revision, 1 = boot-rom-version */
+int pdc_model_versions(struct pdc_model_cpuid *cpu_id, int id) {
+       return mem_pdc_call(PDC_MODEL,PDC_MODEL_VERSIONS,__pa(cpu_id),id);
+}
+
+int pdc_model_cpuid(struct pdc_model_cpuid *cpu_id) {
+       cpu_id->cpuid = 0; /* preset zero (call maybe not implemented!) */
+       return mem_pdc_call(PDC_MODEL,6,__pa(cpu_id),0);  /* 6="return CPU ID" */
+}
+
+int pdc_cache_info(struct pdc_cache_info *cache_info) {
+       ASSERT_ALIGN(cache_info, 8);
+
+       return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
+}
+
+#ifndef __LP64__
+int pdc_btlb_info( struct pdc_btlb_info *btlb ) {
+       int status;
+       status = mem_pdc_call(PDC_BLOCK_TLB,PDC_BTLB_INFO,__pa(btlb),0);
+       if (status<0) btlb->max_size = 0;
+       return status;
+}
+
+int pdc_mem_map_hpa(void *r_addr, void *mod_path) {
+       return mem_pdc_call(PDC_MEM_MAP,PDC_MEM_MAP_HPA,
+               __pa(r_addr),__pa(mod_path));
+}
+
+int pdc_lan_station_id(char *lan_addr, void *net_hpa) {
+       struct pdc_lan_station_id id;
+       unsigned char *addr;
+       
+       if (mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ,
+                       __pa(&id), net_hpa) < 0)
+               addr = 0;       /* FIXME: else read MAC from NVRAM */
+           else
+               addr = id.addr;
+       if (addr)
+               memmove( lan_addr, addr, PDC_LAN_STATION_ID_SIZE);
+           else
+               memset( lan_addr, 0, PDC_LAN_STATION_ID_SIZE);
+       return (addr != 0);
+}
+#endif
+
+
+/* Similar to PDC_PAT stuff in pdcpat.c - but added for Forte/Allegro boxes */
+int pdc_pci_irt_size(void *r_addr, void *hpa)
+{
+       return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE,
+               __pa(r_addr), hpa);
+
+}
+
+int pdc_pci_irt(void *r_addr, void *hpa, void *tbl)
+{
+       return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL,
+               __pa(r_addr), hpa, __pa(tbl));
+}
+
+/* access the TOD clock */
+int pdc_tod_read(struct pdc_tod *tod)
+{
+       ASSERT_ALIGN(tod, 8);
+       return mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(tod), 0);
+}
+
+int pdc_tod_set(unsigned long sec, unsigned long usec)
+{
+       return mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec);
+}
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
new file mode 100644 (file)
index 0000000..f2d4586
--- /dev/null
@@ -0,0 +1,179 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/page.h>
+#include <asm/types.h>
+#include <asm/system.h>
+#include <asm/pdc.h>   /* for iodc_call() proto and friends */
+#include <asm/real.h>
+
+static int __attribute__((aligned(8)))   iodc_retbuf[32];
+static char __attribute__((aligned(64))) iodc_dbuf[4096];
+
+/*
+ * pdc_putc:
+ * Console character print using IODC.
+ *
+ * Note that only these special chars are architected for console IODC io:
+ * BEL, BS, CR, and LF. Others are passed through.
+ * Since the HP console requires CR+LF to perform a 'newline', we translate
+ * "\n" to "\r\n".
+ */
+
+static int posx;       /* for simple TAB-Simulation... */
+
+/* XXX Should we spinlock posx usage */
+
+void pdc_putc(unsigned char c)
+{
+       unsigned int n;
+       unsigned long flags;
+
+       switch (c) {
+       case '\n':
+               iodc_dbuf[0] = '\r'; 
+               iodc_dbuf[1] = '\n';
+                       n = 2;
+                       posx = 0;
+               break;
+       case '\t':
+               pdc_putc(' ');
+               while (posx & 7)        /* expand TAB */
+                       pdc_putc(' ');
+               return;         /* return since IODC can't handle this */
+       case '\b':
+               posx-=2;                /* BS */
+       default:
+               iodc_dbuf[0] = c;
+               n = 1;
+               posx++;
+               break;
+       }
+       {
+               real32_call(PAGE0->mem_cons.iodc_io,
+                       (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
+                       PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
+                       __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
+       }
+}
+
+static void pdc_console_write(struct console *co, const char *s, unsigned count)
+{
+       while(count--)
+               pdc_putc(*s++);
+}
+
+int pdc_console_wait_key(struct console *co)
+{
+       int ch = 'X';
+       int status;
+
+       /* Bail if no console input device. */
+       if (!PAGE0->mem_kbd.iodc_io)
+               return 0;
+       
+       /* wait for a keyboard (rs232)-input */
+       do {
+               unsigned long flags;
+
+               save_flags(flags);
+               cli();
+               status = real32_call(PAGE0->mem_kbd.iodc_io,
+                       (unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN,
+                       PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers),
+                       __pa(iodc_retbuf), 0, __pa(iodc_dbuf), 1, 0);
+               restore_flags(flags);
+               ch = *iodc_dbuf;        /* save the character directly to ch */
+       } while (*iodc_retbuf == 0);    /* wait for a key */
+       return ch;
+}
+
+int pdc_getc(void)
+{
+       return pdc_console_wait_key(NULL);
+}
+
+static int pdc_console_setup(struct console *co, char *options)
+{
+       return 0;
+}
+
+static struct console pdc_cons = {
+       name:           "ttyB",
+       write:          pdc_console_write,
+       read:           NULL,
+       device:         NULL, 
+       wait_key:       pdc_console_wait_key,
+       unblank:        NULL,
+       setup:          pdc_console_setup,
+       flags:          CON_PRINTBUFFER|CON_ENABLED,  // |CON_CONSDEV,
+       index:          -1,
+};
+
+static int pdc_console_initialized;
+
+void pdc_console_init(void)
+{
+       if (pdc_console_initialized)
+               return;
+       ++pdc_console_initialized;
+       
+       /* If the console is duplex then copy the COUT parameters to CIN. */
+       if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
+               memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons));
+
+       pdc_console_write(0, "PDC Console Initialized\n", 24);
+       /* register the pdc console */
+       register_console(&pdc_cons);
+}
+
+
+/* Unregister the pdc console with the printk console layer */
+void pdc_console_die(void)
+{
+       printk("Switching from PDC console\n");
+       if (!pdc_console_initialized)
+               return;
+       --pdc_console_initialized;
+       
+#ifdef CONFIG_VT_CONSOLE
+       {
+           /* fixme (needed?): Wait for console-tasklet to finish !*/
+           extern struct tasklet_struct console_tasklet;
+           tasklet_schedule(&console_tasklet);
+       }
+#endif
+
+       unregister_console(&pdc_cons);
+}
+
+
+/*
+ * Used for emergencies. Currently only used if an HPMC occurs. If an
+ * HPMC occurs, it is possible that the current console may not be
+ * properly initialed after the PDC IO reset. This routine unregisters all
+ * of the current consoles, reinitializes the pdc console and
+ * registers it.
+ */
+
+void pdc_console_restart(void)
+{
+       struct console *console;
+       extern int log_size;
+
+       if (pdc_console_initialized)
+               return;
+
+       while ((console = console_drivers) != (struct console *)0)
+               unregister_console(console_drivers);
+
+       log_size = 0;
+       pdc_console_init();
+       printk("Switched to PDC console\n");
+       return;
+}
+
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
new file mode 100644 (file)
index 0000000..4094638
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ *  linux/arch/parisc/kernel/process.c
+ *     based on the work for i386
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
+#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/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/unistd.h>
+#include <linux/smp.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/elf.h>
+
+#include <asm/machdep.h>
+#include <asm/offset.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/gsc.h>
+#include <asm/processor.h>
+
+spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
+
+#ifdef __LP64__
+/* The 64-bit code should work equally well in 32-bit land but I didn't
+ * want to take the time to confirm that.  -PB
+ */
+extern unsigned int ret_from_kernel_thread;
+#else
+asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
+#endif
+
+
+int hlt_counter=0;
+
+void disable_hlt(void)
+{
+       hlt_counter++;
+}
+
+void enable_hlt(void)
+{
+       hlt_counter--;
+}
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+       /* endless idle loop with no priority at all */
+       init_idle();
+       current->nice = 20;
+       current->counter = -100;
+
+       while (1) {
+               while (!current->need_resched) {
+               }
+               schedule();
+               check_pgt_cache();
+       }
+}
+
+void __init reboot_setup(char *str, int *ints)
+{
+}
+
+struct notifier_block *mach_notifier;
+
+void machine_restart(char *ptr)
+{
+       notifier_call_chain(&mach_notifier, MACH_RESTART, ptr);
+}
+
+void machine_halt(void)
+{
+       notifier_call_chain(&mach_notifier, MACH_HALT, NULL);
+}
+
+void machine_power_on(void)
+{
+       notifier_call_chain(&mach_notifier, MACH_POWER_ON, NULL);
+}
+
+void machine_power_off(void)
+{
+       notifier_call_chain(&mach_notifier, MACH_POWER_OFF, NULL);
+}
+
+
+void machine_heartbeat(void)
+{
+}
+
+
+/*
+ * Create a kernel thread
+ */
+
+extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+
+       /*
+        * FIXME: Once we are sure we don't need any debug here,
+        *        kernel_thread can become a #define.
+        */
+
+       return __kernel_thread(fn, arg, flags);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+       set_fs(USER_DS);
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+}
+
+/*
+ * Fill in the FPU structure for a core dump.
+ */
+int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r)
+{
+       memcpy(r, regs->fr, sizeof *r);
+       return 1;
+}
+
+/* Note that "fork()" is implemented in terms of clone, with
+   parameters (SIGCHLD, regs->gr[30], regs). */
+int
+sys_clone(unsigned long clone_flags, unsigned long usp,
+         struct pt_regs *regs)
+{
+       return do_fork(clone_flags, usp, regs, 0);
+}
+
+int
+sys_vfork(struct pt_regs *regs)
+{
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+                      regs->gr[30], regs, 0);
+}
+
+int
+copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+           unsigned long unused,       /* in ia64 this is "user_stack_size" */
+           struct task_struct * p, struct pt_regs * pregs)
+{
+       struct pt_regs * cregs = &(p->thread.regs);
+       long ksp;
+
+       *cregs = *pregs;
+
+       /* Set the return value for the child.  Note that this is not
+           actually restored by the syscall exit path, but we put it
+           here for consistency in case of signals. */
+       cregs->gr[28] = 0; /* child */
+
+       /*
+        * We need to differentiate between a user fork and a
+        * kernel fork. We can't use user_mode, because the
+        * the syscall path doesn't save iaoq. Right now
+        * We rely on the fact that kernel_thread passes
+        * in zero for usp.
+        */
+       if (usp == 0) {
+               /* Kernel Thread */
+               ksp = (((unsigned long)(p)) + TASK_SZ_ALGN);
+               cregs->ksp = ksp;           /* always return to kernel */
+#ifdef __LP64__
+               cregs->kpc = (unsigned long) &ret_from_kernel_thread;
+#else
+               cregs->kpc = (unsigned long) ret_from_kernel_thread;
+#endif
+
+               /*
+                * Copy function and argument to be called from
+                * ret_from_kernel_thread.
+                */
+               cregs->gr[26] = pregs->gr[26];
+               cregs->gr[25] = pregs->gr[25];
+
+       } else {
+               /* User Thread:
+                *
+                * Use same stack depth as parent when in wrapper
+                *
+                * Note that the fork wrappers are responsible
+                * for setting gr[20] and gr[21].
+                */
+
+               cregs->ksp = ((unsigned long)(p))
+                       + (pregs->gr[20] & (INIT_TASK_SIZE - 1));
+               cregs->kpc = pregs->gr[21];
+       }
+
+       return 0;
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+
+asmlinkage int sys_execve(struct pt_regs *regs)
+{
+       int error;
+       char *filename;
+
+       filename = getname((char *) regs->gr[26]);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               goto out;
+       error = do_execve(filename, (char **) regs->gr[25],
+               (char **) regs->gr[24], regs);
+       if (error == 0)
+               current->ptrace &= ~PT_DTRACE;
+       putname(filename);
+out:
+
+       return error;
+}
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
new file mode 100644 (file)
index 0000000..176b438
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * Kernel support for the ptrace() and syscall tracing interfaces.
+ *
+ * Copyright (C) 2000 Hewlett-Packard Co, Linuxcare Inc.
+ * Copyright (C) 2000 Matthew Wilcox <matthew@wil.cx>
+ * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/offset.h>
+
+/* These are used in entry.S, syscall_restore_rfi.  We need to record the
+ * current stepping mode somewhere other than in PSW, because there is no
+ * concept of saving and restoring the users PSW over a syscall.  We choose
+ * to use these two bits in task->ptrace.  These bits must not clash with
+ * any PT_* defined in include/linux/sched.h, and must match with the bit
+ * tests in entry.S
+ */
+#define PT_SINGLESTEP  0x10000
+#define PT_BLOCKSTEP   0x20000
+
+long sys_ptrace(long request, pid_t pid, long addr, long data)
+{
+       struct task_struct *child;
+       long ret;
+
+       lock_kernel();
+       ret = -EPERM;
+       if (request == PTRACE_TRACEME) {
+               /* are we already being traced? */
+               if (current->ptrace & PT_PTRACED)
+                       goto out;
+               /* set the ptrace bit in the process flags. */
+               current->ptrace |= PT_PTRACED;
+               ret = 0;
+               goto out;
+       }
+
+       ret = -ESRCH;
+       read_lock(&tasklist_lock);
+       child = find_task_by_pid(pid);
+       if (child)
+               get_task_struct(child);
+       read_unlock(&tasklist_lock);
+       if (!child)
+               goto out;
+       ret = -EPERM;
+       if (pid == 1)           /* no messing around with init! */
+               goto out_tsk;
+
+       if (request == PTRACE_ATTACH) {
+               if (child == current)
+                       goto out_tsk;
+               if ((!child->dumpable ||
+                   (current->uid != child->euid) ||
+                   (current->uid != child->suid) ||
+                   (current->uid != child->uid) ||
+                   (current->gid != child->egid) ||
+                   (current->gid != child->sgid) ||
+                   (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+                   (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+                       goto out_tsk;
+               /* the same process cannot be attached many times */
+               if (child->ptrace & PT_PTRACED)
+                       goto out_tsk;
+               child->ptrace |= PT_PTRACED;
+               if (child->p_pptr != current) {
+                       unsigned long flags;
+
+                       write_lock_irqsave(&tasklist_lock, flags);
+                       REMOVE_LINKS(child);
+                       child->p_pptr = current;
+                       SET_LINKS(child);
+                       write_unlock_irqrestore(&tasklist_lock, flags);
+               }
+               send_sig(SIGSTOP, child, 1);
+               ret = 0;
+               goto out_tsk;
+       }
+       ret = -ESRCH;
+       if (!(child->ptrace & PT_PTRACED))
+               goto out_tsk;
+       if (child->state != TASK_STOPPED) {
+               if (request != PTRACE_KILL)
+                       goto out_tsk;
+       }
+       if (child->p_pptr != current)
+               goto out_tsk;
+
+       switch (request) {
+       case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+       case PTRACE_PEEKDATA: {
+               unsigned long tmp;
+               int copied;
+
+               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+               ret = -EIO;
+               if (copied != sizeof(tmp))
+                       goto out_tsk;
+               ret = put_user(tmp,(unsigned long *) data);
+               goto out_tsk;
+       }
+
+       /* when I and D space are separate, this will have to be fixed. */
+       case PTRACE_POKETEXT: /* write the word at location addr. */
+       case PTRACE_POKEDATA:
+               ret = 0;
+               if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+                       goto out_tsk;
+               ret = -EIO;
+               goto out_tsk;
+
+       /* Read the word at location addr in the USER area.  This will need
+          to change when the kernel no longer saves all regs on a syscall. */
+       case PTRACE_PEEKUSR: {
+               unsigned long tmp;
+
+               ret = -EIO;
+               if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
+                       goto out_tsk;
+
+               tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
+               ret = put_user(tmp, (unsigned long *) data);
+               goto out_tsk;
+       }
+
+       /* Write the word at location addr in the USER area.  This will need
+          to change when the kernel no longer saves all regs on a syscall.
+          FIXME.  There is a problem at the moment in that r3-r18 are only
+          saved if the process is ptraced on syscall entry, and even then
+          those values are overwritten by actual register values on syscall
+          exit. */
+       case PTRACE_POKEUSR:
+               ret = -EIO;
+               if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
+                       goto out_tsk;
+               /* XXX This test probably needs adjusting.  We probably want to
+                * allow writes to some bits of PSW, and may want to block writes
+                * to (some) space registers.  Some register values written here
+                * may be ignored in entry.S:syscall_restore_rfi; e.g. iaoq is
+                * written with r31/r31+4, and not with the values in pt_regs.
+                */
+               /* Allow writing of gr1-gr31, fr*, sr*, iasq*, iaoq*, sar */
+               if (addr == PT_PSW || (addr > PT_IAOQ1 && addr != PT_SAR))
+                       goto out_tsk;
+
+               *(unsigned long *) ((char *) task_regs(child) + addr) = data;
+               ret = 0;
+               goto out_tsk;
+
+       case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+       case PTRACE_CONT:
+               ret = -EIO;
+               if ((unsigned long) data > _NSIG)
+                       goto out_tsk;
+               child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
+               if (request == PTRACE_SYSCALL)
+                       child->ptrace |= PT_TRACESYS;
+               else
+                       child->ptrace &= ~PT_TRACESYS;
+               child->exit_code = data;
+               goto out_wake_notrap;
+
+       case PTRACE_KILL:
+               /*
+                * make the child exit.  Best I can do is send it a
+                * sigkill.  perhaps it should be put in the status
+                * that it wants to exit.
+                */
+               if (child->state == TASK_ZOMBIE)        /* already dead */
+                       goto out_tsk;
+               child->exit_code = SIGKILL;
+               goto out_wake_notrap;
+
+       case PTRACE_SINGLEBLOCK:
+               ret = -EIO;
+               if ((unsigned long) data > _NSIG)
+                       goto out_tsk;
+               child->ptrace &= ~(PT_TRACESYS|PT_SINGLESTEP);
+               child->ptrace |= PT_BLOCKSTEP;
+               child->exit_code = data;
+
+               /* Enable taken branch trap. */
+               pa_psw(child)->r = 0;
+               pa_psw(child)->t = 1;
+               pa_psw(child)->h = 0;
+               pa_psw(child)->l = 0;
+               goto out_wake;
+
+       case PTRACE_SINGLESTEP:
+               ret = -EIO;
+               if ((unsigned long) data > _NSIG)
+                       goto out_tsk;
+               child->ptrace &= ~(PT_TRACESYS|PT_BLOCKSTEP);
+               child->ptrace |= PT_SINGLESTEP;
+               child->exit_code = data;
+
+               if (pa_psw(child)->n) {
+                       struct siginfo si;
+
+                       /* Nullified, just crank over the queue. */
+                       task_regs(child)->iaoq[0] = task_regs(child)->iaoq[1];
+                       task_regs(child)->iasq[0] = task_regs(child)->iasq[1];
+                       task_regs(child)->iaoq[1] = task_regs(child)->iaoq[0] + 4;
+                       pa_psw(child)->n = 0;
+                       pa_psw(child)->x = 0;
+                       pa_psw(child)->y = 0;
+                       pa_psw(child)->z = 0;
+                       pa_psw(child)->b = 0;
+                       pa_psw(child)->r = 0;
+                       pa_psw(child)->t = 0;
+                       pa_psw(child)->h = 0;
+                       pa_psw(child)->l = 0;
+                       /* Don't wake up the child, but let the
+                          parent know something happened. */
+                       si.si_code = TRAP_TRACE;
+                       si.si_addr = (void *) (task_regs(child)->iaoq[0] & ~3);
+                       si.si_signo = SIGTRAP;
+                       si.si_errno = 0;
+                       force_sig_info(SIGTRAP, &si, child);
+                       //notify_parent(child, SIGCHLD);
+                       //ret = 0;
+                       goto out_wake;
+               }
+
+               /* Enable recovery counter traps.  The recovery counter
+                * itself will be set to zero on a task switch.  If the
+                * task is suspended on a syscall then the syscall return
+                * path will overwrite the recovery counter with a suitable
+                * value such that it traps once back in user space.  We
+                * disable interrupts in the childs PSW here also, to avoid
+                * interrupts while the recovery counter is decrementing.
+                */
+               pa_psw(child)->r = 1;
+               pa_psw(child)->t = 0;
+               pa_psw(child)->h = 0;
+               pa_psw(child)->l = 0;
+               /* give it a chance to run. */
+               goto out_wake;
+
+       case PTRACE_DETACH:
+               ret = -EIO;
+               if ((unsigned long) data > _NSIG)
+                       goto out_tsk;
+               child->ptrace &= ~(PT_PTRACED|PT_TRACESYS|PT_SINGLESTEP|PT_BLOCKSTEP);
+               child->exit_code = data;
+               write_lock_irq(&tasklist_lock);
+               REMOVE_LINKS(child);
+               child->p_pptr = child->p_opptr;
+               SET_LINKS(child);
+               write_unlock_irq(&tasklist_lock);
+               goto out_wake_notrap;
+
+       default:
+               ret = -EIO;
+               goto out_tsk;
+       }
+
+out_wake_notrap:
+       /* make sure the trap bits are not set */
+       pa_psw(child)->r = 0;
+       pa_psw(child)->t = 0;
+       pa_psw(child)->h = 0;
+       pa_psw(child)->l = 0;
+out_wake:
+       wake_up_process(child);
+       ret = 0;
+out_tsk:
+       free_task_struct(child);
+out:
+       unlock_kernel();
+       return ret;
+}
+
+void syscall_trace(void)
+{
+       if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
+                       (PT_PTRACED|PT_TRACESYS))
+               return;
+       current->exit_code = SIGTRAP;
+       current->state = TASK_STOPPED;
+       notify_parent(current, SIGCHLD);
+       schedule();
+       /*
+        * this isn't the same as continuing with a signal, but it will do
+        * for normal use.  strace only continues with a signal if the
+        * stopping signal is not SIGTRAP.  -brl
+        */
+       if (current->exit_code) {
+               send_sig(current->exit_code, current, 1);
+               current->exit_code = 0;
+       }
+}
diff --git a/arch/parisc/kernel/real1.c b/arch/parisc/kernel/real1.c
new file mode 100644 (file)
index 0000000..2bb26bc
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ *
+ * 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) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com)
+ *
+ * most of these calls might reasonably be moved to ../kernel -PB
+ *
+ * The basic principle is to construct a stack frame in C then call
+ * some assembly which adopts that stack, does some rfi magic, may
+ * switch wide/narrow mode, and calls the routine described by the
+ * 'fn' parameter WHICH IS NOT A FUNCTION POINTER!!!!!!!!!!!!!!!!
+ */
+#include <linux/spinlock.h>
+#include <asm/system.h>
+#include <stdarg.h>
+#include <asm/pgtable.h>               /* for __pa() */
+#include <asm/pdc.h>
+
+static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED;
+
+/***************** 32-bit real-mode calls ***********/
+/* The struct below is used
+ * to overlay real_stack (real2.S), preparing a 32-bit call frame.
+ * real32_call_asm() then uses this stack in narrow real mode
+ */
+
+struct narrow_stack {
+    /* use int, not long which is 64 bits */
+    unsigned int arg13;
+    unsigned int arg12;
+    unsigned int arg11;
+    unsigned int arg10;
+    unsigned int arg9;
+    unsigned int arg8;
+    unsigned int arg7;
+    unsigned int arg6;
+    unsigned int arg5;
+    unsigned int arg4;
+    unsigned int arg3;
+    unsigned int arg2;
+    unsigned int arg1;
+    unsigned int arg0;
+    unsigned int frame_marker[8];
+    unsigned int sp;
+    /* in reality, there's nearly 8k of stack after this */
+};
+
+long
+real32_call(unsigned long fn, ...)
+{
+    unsigned long r;
+    va_list args;
+    unsigned long flags;
+    extern struct narrow_stack real_stack;
+    extern unsigned long real32_call_asm(unsigned int *,
+                               unsigned int *, unsigned int);
+    
+    va_start(args, fn);
+    real_stack.arg0 = va_arg(args, unsigned int);
+    real_stack.arg1 = va_arg(args, unsigned int);
+    real_stack.arg2 = va_arg(args, unsigned int);
+    real_stack.arg3 = va_arg(args, unsigned int);
+    real_stack.arg4 = va_arg(args, unsigned int);
+    real_stack.arg5 = va_arg(args, unsigned int);
+    real_stack.arg6 = va_arg(args, unsigned int);
+    real_stack.arg7 = va_arg(args, unsigned int);
+    real_stack.arg8 = va_arg(args, unsigned int);
+    real_stack.arg9 = va_arg(args, unsigned int);
+    real_stack.arg10 = va_arg(args, unsigned int);
+    real_stack.arg11 = va_arg(args, unsigned int);
+    real_stack.arg12 = va_arg(args, unsigned int);
+    real_stack.arg13 = va_arg(args, unsigned int);
+    va_end(args);
+
+    if (fn == 0) {
+           /* mem_pdc call */
+           fn = PAGE0->mem_pdc;
+    }
+
+    spin_lock_irqsave(&pdc_lock, flags);
+    r = real32_call_asm(&real_stack.sp, &real_stack.arg0, fn);
+    spin_unlock_irqrestore(&pdc_lock, flags);
+
+    return r;
+}
+
+#ifdef __LP64__
+/***************** 64-bit real-mode calls ***********/
+
+struct wide_stack {
+    unsigned long arg0;
+    unsigned long arg1;
+    unsigned long arg2;
+    unsigned long arg3;
+    unsigned long arg4;
+    unsigned long arg5;
+    unsigned long arg6;
+    unsigned long arg7;
+    unsigned long arg8;
+    unsigned long arg9;
+    unsigned long arg10;
+    unsigned long arg11;
+    unsigned long arg12;
+    unsigned long arg13;
+    unsigned long frame_marker[2];     /* rp, previous sp */
+    unsigned long sp;
+    /* in reality, there's nearly 8k of stack after this */
+};
+
+long
+real64_call(unsigned long fn, ...)
+{
+    unsigned long r;
+    va_list args;
+    unsigned long flags;
+    extern struct wide_stack real_stack;
+    extern unsigned long real64_call_asm(unsigned long *,
+                               unsigned long *, unsigned long);
+    
+    va_start(args, fn);
+    real_stack.arg0 = va_arg(args, unsigned long);
+    real_stack.arg1 = va_arg(args, unsigned long);
+    real_stack.arg2 = va_arg(args, unsigned long);
+    real_stack.arg3 = va_arg(args, unsigned long);
+    real_stack.arg4 = va_arg(args, unsigned long);
+    real_stack.arg5 = va_arg(args, unsigned long);
+    real_stack.arg6 = va_arg(args, unsigned long);
+    real_stack.arg7 = va_arg(args, unsigned long);
+    real_stack.arg8 = va_arg(args, unsigned long);
+    real_stack.arg9 = va_arg(args, unsigned long);
+    real_stack.arg10 = va_arg(args, unsigned long);
+    real_stack.arg11 = va_arg(args, unsigned long);
+    real_stack.arg12 = va_arg(args, unsigned long);
+    real_stack.arg13 = va_arg(args, unsigned long);
+    va_end(args);
+
+    if (fn == 0) {
+           /* mem_pdc call */
+           fn = PAGE0->mem_pdc_hi;
+           fn <<= 32;
+           fn |= PAGE0->mem_pdc;
+    }
+
+    spin_lock_irqsave(&pdc_lock, flags);
+    r = real64_call_asm(&real_stack.sp, &real_stack.arg0, fn);
+    spin_unlock_irqrestore(&pdc_lock, flags);
+
+    return r;
+}
+
+#endif
diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S
new file mode 100644 (file)
index 0000000..eb1425e
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ *
+ * 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) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com)
+ *
+ */
+#define __ASSEMBLY__
+#include <asm/assembly.h>
+#include <asm/psw.h>
+
+       .section        .bss
+       .export real_stack
+       .align  64
+real_stack:
+       .block  8192
+
+#ifdef __LP64__
+#  define REG_SZ 8
+#else
+#  define REG_SZ 4
+#endif
+
+#define N_SAVED_REGS 9
+
+save_cr_space:
+       .block  REG_SZ * N_SAVED_REGS
+
+
+/************************ 32-bit real-mode calls ***********************/
+/* This can be called in both narrow and wide kernels */
+       .text
+       .export real32_call_asm
+       /* unsigned long real32_call_asm(unsigned int *sp,
+        *              unsigned int *arg0p,
+        *              unsigned int iodc_fn)
+        *      sp is value of stack pointer to adopt before calling PDC (virt)
+        *      arg0p points to where saved arg values may be found
+        *      iodc_fn is the IODC function to call
+        */
+real32_call_asm:
+       STREG   %rp, -RP_OFFSET(%sp)    /* save RP */
+#ifdef __LP64__
+       callee_save
+       ldo     2*REG_SZ(%sp), %sp      /* room for a couple more saves */
+       STREG   %r27, -1*REG_SZ(%sp)
+       STREG   %r29, -2*REG_SZ(%sp)
+#endif
+       STREG   %sp, -REG_SZ(%arg0)     /* save SP on real-mode stack */
+       copy    %arg0, %sp              /* adopt the real-mode SP */
+
+       /* save iodc_fn */
+       copy    %arg2, %r31
+
+       /* load up the arg registers from the saved arg area */
+       /* 32-bit calling convention passes first 4 args in registers */
+       ldw     0(%arg1), %arg0         /* note overwriting arg0 */
+       ldw     -8(%arg1), %arg2
+       ldw     -12(%arg1), %arg3
+       ldw     -4(%arg1), %arg1        /* obviously must do this one last! */
+
+       tophys  %sp
+
+       b,l     rfi_virt2real,%r2
+       nop
+
+       b,l     save_control_regs,%r2           /* modifies r1, r2, r28 */
+       nop
+
+#ifdef __LP64__
+       rsm     PSW_SM_W, %r0           /* go narrow */
+#endif
+
+       ldil    L%PA(ric_ret), %r2
+       ldo     R%PA(ric_ret)(%r2), %r2
+       bv      0(%r31)
+       nop
+ric_ret:
+#ifdef __LP64__
+       ssm     PSW_SM_W, %r0           /* go wide */
+#endif
+       /* restore CRs before going virtual in case we page fault */
+       b,l     restore_control_regs, %r2       /* modifies r1, r2, r26 */
+       nop
+
+       b,l     rfi_real2virt,%r2
+       nop
+
+       tovirt  %sp
+       LDREG   -REG_SZ(%sp), %sp       /* restore SP */
+#ifdef __LP64__
+       LDREG   -1*REG_SZ(%sp), %r27
+       LDREG   -2*REG_SZ(%sp), %r29
+       ldo     -2*REG_SZ(%sp), %sp
+       callee_rest
+#endif
+       LDREG   -RP_OFFSET(%sp), %rp    /* restore RP */
+       bv      0(%rp)
+       nop
+
+
+#  define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where)
+#  define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r
+
+       .text
+save_control_regs:
+       load32  PA(save_cr_space), %r28
+       PUSH_CR(%cr24, %r28)
+       PUSH_CR(%cr25, %r28)
+       PUSH_CR(%cr26, %r28)
+       PUSH_CR(%cr27, %r28)
+       PUSH_CR(%cr28, %r28)
+       PUSH_CR(%cr29, %r28)
+       PUSH_CR(%cr30, %r28)
+       PUSH_CR(%cr31, %r28)
+       PUSH_CR(%cr15, %r28)
+       bv 0(%r2)
+       nop
+
+restore_control_regs:
+       load32  PA(save_cr_space + (N_SAVED_REGS * REG_SZ)), %r26
+       POP_CR(%cr15, %r26)
+       POP_CR(%cr31, %r26)
+       POP_CR(%cr30, %r26)
+       POP_CR(%cr29, %r26)
+       POP_CR(%cr28, %r26)
+       POP_CR(%cr27, %r26)
+       POP_CR(%cr26, %r26)
+       POP_CR(%cr25, %r26)
+       POP_CR(%cr24, %r26)
+       bv 0(%r2)
+       nop
+
+/* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for
+ * more general-purpose use by the several places which need RFIs
+ */
+       .align 128
+       .text
+rfi_virt2real:
+       /* switch to real mode... */
+       ssm             0,0             /* See "relied upon translation" */
+       nop                             /* comment in interruption.S */
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       
+       mtsm            0               /* disable interruptions */
+       mtctl           0, %cr17        /* space 0 */
+       mtctl           0, %cr17
+       load32          PA(rfi_v2r_1), %r1
+       mtctl           %r1, %cr18
+       ldo             4(%r1), %r1
+       mtctl           %r1, %cr18
+       load32          PDC_PSW, %r1
+       mtctl           %r1, %cr22
+       rfi
+       
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+rfi_v2r_1:
+       tophys  %r2
+       bv      0(%r2)
+       nop
+
+       .text
+       .align 128
+rfi_real2virt:
+       ssm             0,0             /* See "relied upon translation" */
+       nop                             /* comment in interruption.S */
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       
+       mtsm            0               /* disable interruptions */
+       mtctl           0, %cr17        /* space 0 */
+       mtctl           0, %cr17
+       load32          (rfi_r2v_1), %r1
+       mtctl           %r1, %cr18
+       ldo             4(%r1), %r1
+       mtctl           %r1, %cr18
+       load32          KERNEL_PSW, %r1
+       mtctl           %r1, %cr22
+       rfi
+       
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+rfi_r2v_1:
+       tovirt  %r2
+       bv      0(%r2)
+       nop
+
+#ifdef __LP64__
+
+/************************ 64-bit real-mode calls ***********************/
+/* This is only usable in wide kernels right now and will probably stay so */
+       .text
+       .export real64_call_asm
+       /* unsigned long real64_call_asm(unsigned long *sp,
+        *              unsigned long *arg0p,
+        *              unsigned long fn)
+        *      sp is value of stack pointer to adopt before calling PDC (virt)
+        *      arg0p points to where saved arg values may be found
+        *      iodc_fn is the IODC function to call
+        */
+real64_call_asm:
+       std     %rp, -0x10(%sp)         /* save RP */
+       std     %sp, -8(%arg0)          /* save SP on real-mode stack */
+       copy    %arg0, %sp              /* adopt the real-mode SP */
+
+       /* save fn */
+       copy    %arg2, %r31
+
+       /* set up the new ap */
+       ldo     64(%arg1), %r29
+
+       /* load up the arg registers from the saved arg area */
+       /* 32-bit calling convention passes first 4 args in registers */
+       ldd     0*REG_SZ(%arg1), %arg0          /* note overwriting arg0 */
+       ldd     2*REG_SZ(%arg1), %arg2
+       ldd     3*REG_SZ(%arg1), %arg3
+       ldd     4*REG_SZ(%arg1), %r22
+       ldd     5*REG_SZ(%arg1), %r21
+       ldd     6*REG_SZ(%arg1), %r20
+       ldd     7*REG_SZ(%arg1), %r19
+       ldd     1*REG_SZ(%arg1), %arg1          /* do this one last! */
+
+       tophys  %sp
+
+       b,l     rfi_virt2real,%r2
+       nop
+
+       b,l     save_control_regs,%r2           /* modifies r1, r2, r28 */
+       nop
+
+       load32  PA(r64_ret), %r2
+       bv      0(%r31)
+       nop
+r64_ret:
+       /* restore CRs before going virtual in case we page fault */
+       b,l     restore_control_regs, %r2       /* modifies r1, r2, r26 */
+       nop
+
+       b,l     rfi_real2virt,%r2
+       nop
+
+       tovirt  %sp
+       ldd     -8(%sp), %sp            /* restore SP */
+       ldd     -0x10(%sp), %rp         /* restore RP */
+       bv      0(%rp)
+       nop
+
+#endif
diff --git a/arch/parisc/kernel/sba_iommu.c b/arch/parisc/kernel/sba_iommu.c
new file mode 100644 (file)
index 0000000..b7b5414
--- /dev/null
@@ -0,0 +1,1752 @@
+/*
+**  System Bus Adapter (SBA) I/O MMU manager
+**
+**     (c) Copyright 2000 Grant Grundler
+**     (c) Copyright 2000 Hewlett-Packard Company
+**
+**     Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code)
+**
+**     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 module initializes the IOC (I/O Controller) found on B1000/C3000/
+** J5000/J7000/N-class/L-class machines and their successors.
+**
+** FIXME: Multi-IOC support missing - depends on hp_device data
+** FIXME: add DMA hint support programming in both sba and lba modules.
+*/
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#include <linux/mm.h>
+#include <linux/string.h>
+#define PCI_DEBUG              /* for ASSERT */
+#include <linux/pci.h>
+#undef PCI_DEBUG
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/dma.h>           /* for DMA_CHUNK_SIZE */
+
+#include <asm/hardware.h>      /* for register_driver() stuff */
+#include <asm/gsc.h>           /* FIXME: for gsc_read/gsc_write */
+
+#include <linux/proc_fs.h>
+#include <asm/runway.h>                /* for proc_runway_root */
+
+
+#define MODULE_NAME "SBA"
+
+/*
+** The number of debug flags is a clue - this code is fragile.
+** Don't even think about messing with it unless you have
+** plenty of 710's to sacrafice to the computer gods. :^)
+*/
+#undef DEBUG_SBA_INIT
+#undef DEBUG_SBA_RUN
+#undef DEBUG_SBA_RUN_SG
+#undef DEBUG_SBA_RESOURCE
+#undef ASSERT_PDIR_SANITY
+#undef DEBUG_LARGE_SG_ENTRIES
+
+#if 1
+#define SBA_INLINE
+#else
+#define SBA_INLINE     __inline__
+#endif
+
+#ifdef DEBUG_SBA_INIT
+#define DBG_INIT(x...) printk(x)
+#else
+#define DBG_INIT(x...)
+#endif
+
+#ifdef DEBUG_SBA_RUN
+#define DBG_RUN(x...)  printk(x)
+#else
+#define DBG_RUN(x...)
+#endif
+
+#ifdef DEBUG_SBA_RUN_SG
+#define DBG_RUN_SG(x...)       printk(x)
+#else
+#define DBG_RUN_SG(x...)
+#endif
+
+
+#ifdef DEBUG_SBA_RESOURCE
+#define DBG_RES(x...)  printk(x)
+#else
+#define DBG_RES(x...)
+#endif
+
+/*
+** The number of pdir entries to "free" before issueing
+** a read to PCOM register to flush out PCOM writes.
+** Interacts with allocation granularity (ie 4 or 8 entries
+** allocated and free'd/purged at a time might make this
+** less interesting).
+*/
+#if 0
+#define DELAYED_RESOURCE_CNT   16
+#else
+#undef DELAYED_RESOURCE_CNT
+#endif
+
+#define DEFAULT_DMA_HINT_REG   0
+
+#define ASTRO_RUNWAY_PORT    0x582
+#define ASTRO_ROPES_PORT     0x780
+
+#define IKE_MERCED_PORT      0x803
+#define IKE_ROPES_PORT       0x781
+
+int sba_driver_callback(struct hp_device *, struct pa_iodc_driver *);
+
+static struct pa_iodc_driver sba_drivers_for[] = {
+
+/* FIXME: why is SVERSION checked? */
+
+   {HPHW_IOA, ASTRO_RUNWAY_PORT, 0x0, 0xb, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
+
+   {HPHW_BCPORT, ASTRO_ROPES_PORT, 0x0, 0xb, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
+
+#if 0
+/* FIXME : N-class! Use a different "callback"? */
+   {HPHW_BCPORT, IKE_MERCED_PORT, 0x0, 0xb, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
+
+   {HPHW_BCPORT, IKE_ROPES_PORT, 0x0, 0xb, 0, 0x10,
+               DRIVER_CHECK_HVERSION +
+               DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
+                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
+#endif
+
+   {0,0,0,0,0,0,
+   0,
+   (char *) NULL, (char *) NULL, (void *) NULL }
+};
+
+
+#define SBA_FUNC_ID    0x0000  /* function id */
+#define SBA_FCLASS     0x0008  /* function class, bist, header, rev... */
+
+#define IS_ASTRO(id) ( \
+    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == ASTRO_RUNWAY_PORT)) || \
+    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == ASTRO_ROPES_PORT))  \
+)
+
+#define CONFIG_FUNC_SIZE 4096   /* SBA configuration function reg set */
+
+#define ASTRO_IOC_OFFSET 0x20000
+/* Ike's IOC's occupy functions 2 and 3 (not 0 and 1) */
+#define IKE_IOC_OFFSET(p) ((p+2)*CONFIG_FUNC_SIZE)
+
+#define IOC_CTRL          0x8  /* IOC_CTRL offset */
+#define IOC_CTRL_TE       (0x1 << 0) /* TOC Enable */
+#define IOC_CTRL_RM       (0x1 << 8) /* Real Mode */
+#define IOC_CTRL_NC       (0x1 << 9) /* Non Coherent Mode */
+
+#define MAX_IOC                2       /* per Ike. Astro only has 1 */
+
+
+/*
+** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
+** Firmware programs this stuff. Don't touch it.
+*/
+#define IOS_DIST_BASE  0x390
+#define IOS_DIST_MASK  0x398
+#define IOS_DIST_ROUTE 0x3A0
+
+#define IOS_DIRECT_BASE        0x3C0
+#define IOS_DIRECT_MASK        0x3C8
+#define IOS_DIRECT_ROUTE 0x3D0
+
+/*
+** Offsets into I/O TLB (Function 2 and 3 on Ike)
+*/
+#define ROPE0_CTL      0x200  /* "regbus pci0" */
+#define ROPE1_CTL      0x208
+#define ROPE2_CTL      0x210
+#define ROPE3_CTL      0x218
+#define ROPE4_CTL      0x220
+#define ROPE5_CTL      0x228
+#define ROPE6_CTL      0x230
+#define ROPE7_CTL      0x238
+
+#define HF_ENABLE      0x40
+
+
+#define IOC_IBASE      0x300   /* IO TLB */
+#define IOC_IMASK      0x308
+#define IOC_PCOM       0x310
+#define IOC_TCNFG      0x318
+#define IOC_PDIR_BASE  0x320
+
+#define IOC_IOVA_SPACE_BASE    0       /* IOVA ranges start at 0 */
+
+/*
+** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
+** It's safer (avoid memory corruption) to keep DMA page mappings
+** equivalently sized to VM PAGE_SIZE.
+**
+** We really can't avoid generating a new mapping for each
+** page since the Virtual Coherence Index has to be generated
+** and updated for each page.
+**
+** IOVP_SIZE could only be greater than PAGE_SIZE if we are
+** confident the drivers really only touch the next physical
+** page iff that driver instance owns it.
+*/
+#define IOVP_SIZE      PAGE_SIZE
+#define IOVP_SHIFT     PAGE_SHIFT
+#define IOVP_MASK      PAGE_MASK
+
+#define SBA_PERF_CFG   0x708   /* Performance Counter stuff */
+#define SBA_PERF_MASK1 0x718
+#define SBA_PERF_MASK2 0x730
+
+
+/*
+** Offsets into PCI Performance Counters (functions 12 and 13)
+** Controlled by PERF registers in function 2 & 3 respectively.
+*/
+#define SBA_PERF_CNT1  0x200
+#define SBA_PERF_CNT2  0x208
+#define SBA_PERF_CNT3  0x210
+
+
+struct ioc {
+       char    *ioc_hpa;       /* I/O MMU base address */
+       char    *res_map;       /* resource map, bit == pdir entry */
+       u64     *pdir_base;     /* physical base address */
+
+       unsigned long   *res_hint;      /* next available IOVP - circular search */
+       unsigned int    res_bitshift;   /* from the LEFT! */
+       unsigned int    res_size;       /* size of resource map in bytes */
+       unsigned int    hint_shift_pdir;
+       spinlock_t      res_lock;
+       unsigned long   hint_mask_pdir;         /* bits used for DMA hints */
+#ifdef DELAYED_RESOURCE_CNT
+       dma_addr_t res_delay[DELAYED_RESOURCE_CNT];
+#endif
+
+#ifdef CONFIG_PROC_FS
+#define SBA_SEARCH_SAMPLE      0x100
+       unsigned long avg_search[SBA_SEARCH_SAMPLE];
+       unsigned long avg_idx;  /* current index into avg_search */
+       unsigned long used_pages;
+       unsigned long msingle_calls;
+       unsigned long msingle_pages;
+       unsigned long msg_calls;
+       unsigned long msg_pages;
+       unsigned long usingle_calls;
+       unsigned long usingle_pages;
+       unsigned long usg_calls;
+       unsigned long usg_pages;
+#endif
+
+       /* STUFF We don't need in performance path */
+       unsigned int    pdir_size;      /* in bytes, determined by IOV Space size */
+       unsigned long   ibase;          /* pdir IOV Space base - shared w/lba_pci */
+       unsigned long   imask;          /* pdir IOV Space mask - shared w/lba_pci */
+};
+
+struct sba_device {
+       struct sba_device       *next;  /* list of LBA's in system */
+       struct hp_device        *iodc;  /* data about dev from firmware */
+       char                    *sba_hpa; /* base address */
+       spinlock_t              sba_lock;
+       unsigned int                    flags;  /* state/functionality enabled */
+       unsigned int                    hw_rev;  /* HW revision of chip */
+
+       unsigned int                    num_ioc;  /* number of on-board IOC's */
+       struct ioc              ioc[MAX_IOC];
+};
+
+
+static struct sba_device *sba_list;
+static int sba_count;
+
+/* Ratio of Host MEM to IOV Space size */
+static unsigned long sba_mem_ratio = 4;
+
+/* Looks nice and keeps the compiler happy */
+#define SBA_DEV(d) ((struct sba_device *) (d))
+
+
+#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
+
+
+/************************************
+** SBA register read and write support
+**
+** BE WARNED: register writes are posted.
+**  (ie follow writes which must reach HW with a read)
+*/
+#define READ_U8(addr)  gsc_readb(addr)
+#define READ_U16(addr) gsc_readw((u16 *) (addr))
+#define READ_U32(addr) gsc_readl((u32 *) (addr))
+#define WRITE_U8(value, addr) gsc_writeb(value, addr)
+#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr))
+#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
+
+#define READ_REG8(addr)  gsc_readb(addr)
+#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr)))
+#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr)))
+#define READ_REG64(addr) le64_to_cpu(gsc_readq((u64 *) (addr)))
+#define WRITE_REG8(value, addr) gsc_writeb(value, addr)
+#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr))
+#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr))
+#define WRITE_REG64(value, addr) gsc_writeq(cpu_to_le64(value), (u64 *) (addr))
+
+#ifdef DEBUG_SBA_INIT
+
+static void
+sba_dump_ranges(char *hpa)
+{
+       printk("SBA at 0x%p\n", hpa);
+       printk("IOS_DIST_BASE   : %08x %08x\n",
+                       READ_REG32(hpa+IOS_DIST_BASE+4),
+                       READ_REG32(hpa+IOS_DIST_BASE));
+       printk("IOS_DIST_MASK   : %08x %08x\n",
+                       READ_REG32(hpa+IOS_DIST_MASK+4),
+                       READ_REG32(hpa+IOS_DIST_MASK));
+       printk("IOS_DIST_ROUTE  : %08x %08x\n",
+                       READ_REG32(hpa+IOS_DIST_ROUTE+4),
+                       READ_REG32(hpa+IOS_DIST_ROUTE));
+       printk("\n");
+       printk("IOS_DIRECT_BASE : %08x %08x\n",
+                       READ_REG32(hpa+IOS_DIRECT_BASE+4),
+                       READ_REG32(hpa+IOS_DIRECT_BASE));
+       printk("IOS_DIRECT_MASK : %08x %08x\n",
+                       READ_REG32(hpa+IOS_DIRECT_MASK+4),
+                       READ_REG32(hpa+IOS_DIRECT_MASK));
+       printk("IOS_DIRECT_ROUTE: %08x %08x\n",
+                       READ_REG32(hpa+IOS_DIRECT_ROUTE+4),
+                       READ_REG32(hpa+IOS_DIRECT_ROUTE));
+}
+
+static void
+sba_dump_tlb(char *hpa)
+{
+       printk("IO TLB at 0x%p\n", hpa);
+       printk("IOC_IBASE   : %08x %08x\n",
+                       READ_REG32(hpa+IOC_IBASE+4),
+                       READ_REG32(hpa+IOC_IBASE));
+       printk("IOC_IMASK   : %08x %08x\n",
+                       READ_REG32(hpa+IOC_IMASK+4),
+                       READ_REG32(hpa+IOC_IMASK));
+       printk("IOC_TCNFG   : %08x %08x\n",
+                       READ_REG32(hpa+IOC_TCNFG+4),
+                       READ_REG32(hpa+IOC_TCNFG));
+       printk("IOC_PDIR_BASE: %08x %08x\n",
+                       READ_REG32(hpa+IOC_PDIR_BASE+4),
+                       READ_REG32(hpa+IOC_PDIR_BASE));
+       printk("\n");
+}
+#endif
+
+
+#ifdef ASSERT_PDIR_SANITY
+
+static void
+sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
+{
+       /* start printing from lowest pde in rval */
+       u64 *ptr = &(ioc->pdir_base[pide & (~0U * BITS_PER_LONG)]);
+       unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]);
+       uint rcnt;
+
+       printk("SBA: %s rp %p bit %d rval 0x%lx\n",
+                msg,
+                rptr, pide & (BITS_PER_LONG - 1), *rptr);
+
+       rcnt = 0;
+       while (rcnt < BITS_PER_LONG) {
+               printk("%s %2d %p %016Lx\n",
+                       (rcnt == (pide & (BITS_PER_LONG - 1)))
+                               ? "    -->" : "       ",
+                       rcnt, ptr, *ptr );
+               rcnt++;
+               ptr++;
+       }
+       printk(msg);
+}
+
+
+/* Verify the resource map and pdir state is consistent */
+static int
+sba_check_pdir(struct ioc *ioc, char *msg)
+{
+       u32 *rptr_end = (u32 *) &(ioc->res_map[ioc->res_size]);
+       u32 *rptr = (u32 *) ioc->res_map;       /* resource map ptr */
+       u64 *pptr = ioc->pdir_base;     /* pdir ptr */
+       uint pide = 0;
+
+       while (rptr < rptr_end) {
+               u32 rval = *rptr;
+               int rcnt = 32;  /* number of bits we might check */
+
+               while (rcnt) {
+                       /* Get last byte and highest bit from that */
+                       u32 pde = ((u32) (((char *)pptr)[7])) << 24;
+                       if ((rval ^ pde) & 0x80000000)
+                       {
+                               /*
+                               ** BUMMER!  -- res_map != pdir --
+                               ** Dump rval and matching pdir entries
+                               */
+                               sba_dump_pdir_entry(ioc, msg, pide);
+                               return(1);
+                       }
+                       rcnt--;
+                       rval <<= 1;     /* try the next bit */
+                       pptr++;
+                       pide++;
+               }
+               rptr++; /* look at next word of res_map */
+       }
+       /* It'd be nice if we always got here :^) */
+       return 0;
+}
+
+
+static void
+sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
+{
+       while (nents-- > 0) {
+               printk(" %d : %08lx/%05x %p/%05x\n",
+                               nents,
+                               (unsigned long) sg_dma_address(startsg),
+                               sg_dma_len(startsg),
+                               startsg->address, startsg->length);
+               startsg++;
+       }
+}
+
+#endif /* ASSERT_PDIR_SANITY */
+
+
+
+/*
+** One time initialization to let the world know the LBA was found.
+** This is the only routine which is NOT static.
+** Must be called exactly once before pci_init().
+*/
+void __init
+sba_init(void)
+{
+       sba_list = (struct sba_device *) NULL;
+       sba_count = 0;
+
+#ifdef DEBUG_SBA_INIT
+       sba_dump_ranges((char *) 0xFED00000L);
+#endif
+
+       register_driver(sba_drivers_for);
+}
+
+
+
+/**************************************************************
+*
+*   I/O Pdir Resource Management
+*
+*   Bits set in the resource map are in use.
+*   Each bit can represent a number of pages.
+*   LSbs represent lower addresses (IOVA's).
+*
+***************************************************************/
+#define PAGES_PER_RANGE 1      /* could increase this to 4 or 8 if needed */
+
+/* Convert from IOVP to IOVA and vice versa. */
+#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir)))
+#define SBA_IOVP(ioc,iova) ((iova) & ioc->hint_mask_pdir)
+
+/* FIXME : review these macros to verify correctness and usage */
+#define PDIR_INDEX(iovp)   ((iovp)>>IOVP_SHIFT)
+#define MKIOVP(dma_hint,pide)  (dma_addr_t)((long)(dma_hint) | ((long)(pide) << IOVP_SHIFT))
+#define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset)
+
+#define RESMAP_MASK(n)    (~0UL << (BITS_PER_LONG - (n)))
+#define RESMAP_IDX_MASK   (sizeof(unsigned long) - 1)
+
+
+/*
+** Perf optimizations:
+** o search for log2(size) bits at a time.
+**
+** Search should use register width as "stride" to search the res_map. 
+*/
+
+static SBA_INLINE unsigned long
+sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted)
+{
+       unsigned long *res_ptr = ioc->res_hint;
+       unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]);
+       unsigned long pide = ~0UL;
+
+       ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0);
+       ASSERT(res_ptr < res_end);
+       if (bits_wanted > (BITS_PER_LONG/2)) {
+               /* Search word at a time - no mask needed */
+               for(; res_ptr < res_end; ++res_ptr) {
+                       if (*res_ptr == 0) {
+                               *res_ptr = RESMAP_MASK(bits_wanted);
+                               pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+                               pide <<= 3;     /* convert to bit address */
+                               ASSERT(0 != pide);
+                               break;
+                       }
+               }
+               /* point to the next word on next pass */
+               res_ptr++;
+               ioc->res_bitshift = 0;
+       } else {
+               /*
+               ** Search the resource bit map on well-aligned values.
+               ** "o" is the alignment.
+               ** We need the alignment to invalidate I/O TLB using
+               ** SBA HW features in the unmap path.
+               */
+               unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT);
+               uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o);
+               unsigned long mask;
+
+               if (bitshiftcnt >= BITS_PER_LONG) {
+                       bitshiftcnt = 0;
+                       res_ptr++;
+               }
+               mask = RESMAP_MASK(bits_wanted) >> bitshiftcnt;
+
+               DBG_RES("sba_search_bitmap() o %ld %p", o, res_ptr);
+               while(res_ptr < res_end)
+               { 
+                       DBG_RES("    %p %lx %lx\n", res_ptr, mask, *res_ptr);
+                       ASSERT(0 != mask);
+                       if(0 == ((*res_ptr) & mask)) {
+                               *res_ptr |= mask;     /* mark resources busy! */
+                               pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+                               pide <<= 3;     /* convert to bit address */
+                               pide += bitshiftcnt;
+                               ASSERT(0 != pide);
+                               break;
+                       }
+                       mask >>= o;
+                       bitshiftcnt += o;
+                       if (0 == mask) {
+                               mask = RESMAP_MASK(bits_wanted);
+                               bitshiftcnt=0;
+                               res_ptr++;
+                       }
+               }
+               /* look in the same word on the next pass */
+               ioc->res_bitshift = bitshiftcnt + bits_wanted;
+       }
+
+       /* wrapped ? */
+       ioc->res_hint = (res_end == res_ptr) ? (unsigned long *) ioc->res_map : res_ptr;
+       return (pide);
+}
+
+
+static int
+sba_alloc_range(struct ioc *ioc, size_t size)
+{
+       unsigned int pages_needed = size >> IOVP_SHIFT;
+#ifdef CONFIG_PROC_FS
+       unsigned long cr_start = mfctl(16);
+#endif
+       unsigned long pide;
+
+       ASSERT(pages_needed);
+       ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE);
+       ASSERT(pages_needed < BITS_PER_LONG);
+       ASSERT(0 == (size & ~IOVP_MASK));
+
+       /*
+       ** "seek and ye shall find"...praying never hurts either...
+       ** ggg sacrifices another 710 to the computer gods.
+       */
+
+       pide = sba_search_bitmap(ioc, pages_needed);
+       if (pide >= (ioc->res_size << 3)) {
+               pide = sba_search_bitmap(ioc, pages_needed);
+               if (pide >= (ioc->res_size << 3))
+                       panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", ioc->ioc_hpa);
+       }
+
+#ifdef ASSERT_PDIR_SANITY
+       /* verify the first enable bit is clear */
+       if(0x00 != ((u8 *) ioc->pdir_base)[pide*sizeof(u64) + 7]) {
+               sba_dump_pdir_entry(ioc, "sba_search_bitmap() botched it?", pide);
+       }
+#endif
+
+       DBG_RES("sba_alloc_range(%x) %d -> %lx hint %x/%x\n",
+               size, pages_needed, pide,
+               (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
+               ioc->res_bitshift );
+
+#ifdef CONFIG_PROC_FS
+       {
+               unsigned long cr_end = mfctl(16);
+               unsigned long tmp = cr_end - cr_start;
+               /* check for roll over */
+               cr_start = (cr_end < cr_start) ?  -(tmp) : (tmp);
+       }
+       ioc->avg_search[ioc->avg_idx++] = cr_start;
+       ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1;
+
+       ioc->used_pages += pages_needed;
+#endif
+
+       return (pide);
+}
+
+
+/*
+** clear bits in the ioc's resource map
+*/
+static SBA_INLINE void
+sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
+{
+       unsigned long iovp = SBA_IOVP(ioc, iova);
+       unsigned int pide = PDIR_INDEX(iovp);
+       unsigned int ridx = pide >> 3;  /* convert bit to byte address */
+       unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]);
+
+       int bits_not_wanted = size >> IOVP_SHIFT;
+
+       /* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */
+       unsigned long m = RESMAP_MASK(bits_not_wanted) >> (pide & (BITS_PER_LONG - 1));
+
+       DBG_RES("sba_free_range( ,%x,%x) %x/%lx %x %p %lx\n",
+               (uint) iova, size,
+               bits_not_wanted, m, pide, res_ptr, *res_ptr);
+
+#ifdef CONFIG_PROC_FS
+       ioc->used_pages -= bits_not_wanted;
+#endif
+
+       ASSERT(m != 0);
+       ASSERT(bits_not_wanted);
+       ASSERT((bits_not_wanted * IOVP_SIZE) < DMA_CHUNK_SIZE);
+       ASSERT(bits_not_wanted < BITS_PER_LONG);
+       ASSERT((*res_ptr & m) == m); /* verify same bits are set */
+       *res_ptr &= ~m;
+}
+
+
+/**************************************************************
+*
+*   "Dynamic DMA Mapping" support (aka "Coherent I/O")
+*
+***************************************************************/
+
+#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir)
+
+
+typedef unsigned long space_t;
+#define KERNEL_SPACE 0
+
+/*
+* SBA Mapping Routine
+*
+* Given a virtual address (vba, arg2) and space id, (sid, arg1)
+* sba_io_pdir_entry() loads the I/O PDIR entry pointed to by
+* pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as
+* shown below (MSB == bit 0):
+*
+*  0                    19                                 51   55       63
+* +-+---------------------+----------------------------------+----+--------+
+* |V|        U            |            PPN[43:12]            | U  |   VI   |
+* +-+---------------------+----------------------------------+----+--------+
+*
+*  V  == Valid Bit
+*  U  == Unused
+* PPN == Physical Page Number
+* VI  == Virtual Index (aka Coherent Index)
+*
+* The physical address fields are filled with the results of the LPA
+* instruction.  The virtual index field is filled with the results of
+* of the LCI (Load Coherence Index) instruction.  The 8 bits used for
+* the virtual index are bits 12:19 of the value returned by LCI.
+*
+* We need to pre-swap the bytes since PCX-W is Big Endian.
+*/
+
+void SBA_INLINE
+sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba)
+{
+       u64 pa; /* physical address */
+       register unsigned ci; /* coherent index */
+
+       /* We currently only support kernel addresses */
+       ASSERT(sid == 0);
+       ASSERT(((unsigned long) vba & 0xc0000000UL) == 0xc0000000UL);
+
+       pa = virt_to_phys(vba);
+       pa &= ~4095ULL;                 /* clear out offset bits */
+
+       mtsp(sid,1);
+       asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
+       pa |= (ci >> 12) & 0xff;  /* move CI (8 bits) into lowest byte */
+
+       pa |= 0x8000000000000000ULL;    /* set "valid" bit */
+       *pdir_ptr = cpu_to_le64(pa);    /* swap and store into I/O Pdir */
+}
+
+
+/***********************************************************
+ * The Ike PCOM (Purge Command Register) is to purge
+ * stale entries in the IO TLB when unmapping entries.
+ *
+ * The PCOM register supports purging of multiple pages, with a minium
+ * of 1 page and a maximum of 2GB. Hardware requires the address be
+ * aligned to the size of the range being purged. The size of the range
+ * must be a power of 2.
+ ***********************************************************/
+static SBA_INLINE void
+sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
+{
+       u32 iovp = (u32) SBA_IOVP(ioc,iova);
+
+       /* Even though this is a big-endian machine, the entries
+       ** in the iopdir are swapped. That's why we clear the byte
+       ** at +7 instead of at +0.
+       */
+       int off = PDIR_INDEX(iovp)*sizeof(u64)+7;
+
+       /* Must be non-zero and rounded up */
+       ASSERT(byte_cnt > 0);
+       ASSERT(0 == (byte_cnt & ~IOVP_MASK));
+
+#ifdef ASSERT_PDIR_SANITY
+       /* Assert first pdir entry is set */
+       if (0x80 != (((u8 *) ioc->pdir_base)[off])) {
+               sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp));
+       }
+#endif
+
+       if (byte_cnt <= IOVP_SIZE)
+       {
+               ASSERT( off < ioc->pdir_size);
+
+               iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
+
+               /*
+               ** clear I/O PDIR entry "valid" bit
+               ** Do NOT clear the rest - save it for debugging.
+               ** We should only clear bits that have previously
+               ** been enabled.
+               */
+               ((u8 *)(ioc->pdir_base))[off] = 0;
+       } else {
+               u32 t = get_order(byte_cnt) + PAGE_SHIFT;
+
+               iovp |= t;
+               ASSERT(t <= 31);   /* 2GB! Max value of "size" field */
+
+               do {
+                       /* verify this pdir entry is enabled */
+                       ASSERT(0x80 == (((u8 *) ioc->pdir_base)[off] & 0x80));
+                       /* clear I/O Pdir entry "valid" bit first */
+                       ((u8 *)(ioc->pdir_base))[off] = 0;
+                       off += sizeof(u64);
+                       byte_cnt -= IOVP_SIZE;
+               } while (byte_cnt > 0);
+       }
+
+       WRITE_REG32(iovp, ioc->ioc_hpa+IOC_PCOM);
+}
+
+static int
+sba_dma_supported( struct pci_dev *dev, dma_addr_t mask)
+{
+       if (dev == NULL) {
+               printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
+               BUG();
+               return(0);
+       }
+
+       dev->dma_mask = mask;   /* save it */
+
+       /* only support PCI devices */
+       return((int) (mask >= 0xffffffff));
+}
+
+
+/*
+** map_single returns a fully formed IOVA
+*/
+static dma_addr_t
+sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
+{
+       struct ioc *ioc = &sba_list->ioc[0];  /* FIXME : see Multi-IOC below */
+       unsigned long flags; 
+       dma_addr_t iovp;
+       dma_addr_t offset;
+       u64 *pdir_start;
+       int pide;
+
+       ASSERT(size > 0);
+
+       /* save offset bits */
+       offset = ((dma_addr_t) addr) & ~IOVP_MASK;
+
+       /* round up to nearest IOVP_SIZE */
+       size = (size + offset + ~IOVP_MASK) & IOVP_MASK;
+
+       spin_lock_irqsave(&ioc->res_lock, flags);
+#ifdef ASSERT_PDIR_SANITY
+       sba_check_pdir(ioc,"Check before sba_map_single()");
+#endif
+
+#ifdef CONFIG_PROC_FS
+       ioc->msingle_calls++;
+       ioc->msingle_pages += size >> IOVP_SHIFT;
+#endif
+       pide = sba_alloc_range(ioc, size);
+       iovp = (dma_addr_t) pide << IOVP_SHIFT;
+
+       DBG_RUN("sba_map_single() 0x%p -> 0x%lx", addr, (long) iovp | offset);
+
+       pdir_start = &(ioc->pdir_base[pide]);
+
+       while (size > 0) {
+               ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */
+               sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr);
+
+               DBG_RUN(" pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n",
+                       pdir_start,
+                       (u8) (((u8 *) pdir_start)[7]),
+                       (u8) (((u8 *) pdir_start)[6]),
+                       (u8) (((u8 *) pdir_start)[5]),
+                       (u8) (((u8 *) pdir_start)[4]),
+                       (u8) (((u8 *) pdir_start)[3]),
+                       (u8) (((u8 *) pdir_start)[2]),
+                       (u8) (((u8 *) pdir_start)[1]),
+                       (u8) (((u8 *) pdir_start)[0])
+                       );
+
+               addr += IOVP_SIZE;
+               size -= IOVP_SIZE;
+               pdir_start++;
+       }
+       /* form complete address */
+#ifdef ASSERT_PDIR_SANITY
+       sba_check_pdir(ioc,"Check after sba_map_single()");
+#endif
+       spin_unlock_irqrestore(&ioc->res_lock, flags);
+       return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG);
+}
+
+
+static void
+sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction)
+{
+#ifdef FIXME
+/* Multi-IOC (ie N-class) :  need to lookup IOC from dev
+** o If we can't know about lba PCI data structs, that eliminates ->sysdata.
+** o walking up pcidev->parent dead ends at elroy too
+** o leaves hashing dev->bus->number into some lookup.
+**   (may only work for N-class)
+** o use (struct pci_hba) and put fields in there for DMA.
+**   (ioc and per device dma_hint.)
+**
+** Last one seems the clearest and most promising.
+** sba_dma_supported() fill in those fields when the driver queries
+** the system for support.
+*/
+       struct ioc *ioc = (struct ioc *) ((struct pci_hba *) (dev->sysdata))->dma_data;
+#else
+       struct ioc *ioc = &sba_list->ioc[0];
+#endif
+       
+       unsigned long flags; 
+       dma_addr_t offset;
+       offset = iova & ~IOVP_MASK;
+
+       DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long) iova, size);
+
+       iova ^= offset;        /* clear offset bits */
+       size += offset;
+       size = ROUNDUP(size, IOVP_SIZE);
+
+       ASSERT(0 != iova);
+
+       spin_lock_irqsave(&ioc->res_lock, flags);
+#ifdef CONFIG_PROC_FS
+       ioc->usingle_calls++;
+       ioc->usingle_pages += size >> IOVP_SHIFT;
+#endif
+#ifdef DELAYED_RESOURCE_CNT
+       if (ioc->saved_cnt < DELAYED_RESOURCE_CNT) {
+               ioc->saved_iova[ioc->saved_cnt] = iova;
+               ioc->saved_size[ioc->saved_cnt] = size;
+               ioc_saved_cnt++;
+       } else {
+               do {
+#endif
+                       sba_mark_invalid(ioc, iova, size);
+                       sba_free_range(ioc, iova, size);
+
+#ifdef DELAYED_RESOURCE_CNT
+                       ioc->saved_cnt--;
+                       iova = ioc->saved_iova[ioc->saved_cnt];
+                       size = ioc->saved_size[ioc->saved_cnt];
+               } while (ioc->saved_cnt)
+
+               /* flush purges */
+               (void) (volatile) READ_REG32(ioc->ioc_hpa+IOC_PCOM);
+       }
+#else
+       /* flush purges */
+       READ_REG32(ioc->ioc_hpa+IOC_PCOM);
+#endif
+       spin_unlock_irqrestore(&ioc->res_lock, flags);
+}
+
+
+static void *
+sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+{
+       void *ret;
+
+       if (!hwdev) {
+               /* only support PCI */
+               *dma_handle = 0;
+               return 0;
+       }
+
+        ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size));
+
+       if (ret) {
+               memset(ret, 0, size);
+               *dma_handle = sba_map_single(hwdev, ret, size, 0);
+       }
+
+       return ret;
+}
+
+
+static void
+sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
+{
+       sba_unmap_single(hwdev, dma_handle, size, 0);
+       free_pages((unsigned long) vaddr, get_order(size));
+}
+
+/*
+** Two address ranges are "virtually contiguous" iff:
+** 1) end of prev == start of next, or...       append case
+** 3) end of next == start of prev              prepend case
+**
+** and they are DMA contiguous *iff*:
+** 2) end of prev and start of next are both on a page boundry
+**
+** (shift left is a quick trick to mask off upper bits)
+*/
+#define DMA_CONTIG(__X, __Y) \
+       (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
+
+/*
+** Assumption is two transactions are mutually exclusive.
+** ie both go to different parts of memory.
+** If both are true, then both transaction are on the same page.
+*/
+#define DMA_SAME_PAGE(s1,e1,s2,e2) \
+       ( ((((s1) ^ (s2)) >> PAGE_SHIFT) == 0) \
+               && ((((e1) ^ (e2)) >> PAGE_SHIFT) == 0) )
+
+/*
+** Since 0 is a valid pdir_base index value, can't use that
+** to determine if a value is valid or not. Use a flag to indicate
+** the SG list entry contains a valid pdir index.
+*/
+#define PIDE_FLAG 0x80000000UL
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+int dump_run_sg = 0;
+#endif
+
+static SBA_INLINE int
+sba_fill_pdir(
+       struct ioc *ioc,
+       struct scatterlist *startsg,
+       int nents)
+{
+       struct scatterlist *dma_sg = startsg;   /* pointer to current DMA */
+       int n_mappings = 0;
+       u64 *pdirp = 0;
+       unsigned long dma_offset = 0;
+
+       dma_sg--;
+       while (nents-- > 0) {
+               int     cnt = sg_dma_len(startsg);
+               sg_dma_len(startsg) = 0;
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+               if (dump_run_sg)
+                       printk(" %d : %08lx/%05x %p/%05x\n",
+                               nents,
+                               (unsigned long) sg_dma_address(startsg), cnt,
+                               startsg->address, startsg->length
+               );
+#else
+               DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n",
+                               nents,
+                               (unsigned long) sg_dma_address(startsg), cnt,
+                               startsg->address, startsg->length
+               );
+#endif
+               /*
+               ** Look for the start of a new DMA stream
+               */
+               if (sg_dma_address(startsg) & PIDE_FLAG) {
+                       u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG;
+                       dma_offset = (unsigned long) pide & ~IOVP_MASK;
+                       pide >>= IOVP_SHIFT;
+                       pdirp = &(ioc->pdir_base[pide]);
+                       sg_dma_address(startsg) = 0;
+                       ++dma_sg;
+                       sg_dma_address(dma_sg) = (pide << IOVP_SHIFT) + dma_offset;
+                       n_mappings++;
+               }
+
+               /*
+               ** Look for a VCONTIG chunk
+               */
+               if (cnt) {
+                       unsigned long vaddr = (unsigned long) startsg->address;
+                       ASSERT(pdirp);
+
+                       sg_dma_len(dma_sg) += cnt;
+                       cnt += dma_offset;
+                       dma_offset=0;   /* only want offset on first chunk */
+                       cnt = ROUNDUP(cnt, IOVP_SIZE);
+#ifdef CONFIG_PROC_FS
+                       ioc->msg_pages += cnt >> IOVP_SHIFT;
+#endif
+                       do {
+                               sba_io_pdir_entry(pdirp, KERNEL_SPACE, vaddr);
+                               vaddr += IOVP_SIZE;
+                               cnt -= IOVP_SIZE;
+                               pdirp++;
+                       } while (cnt > 0);
+               }
+               startsg++;
+       }
+#ifdef DEBUG_LARGE_SG_ENTRIES
+       dump_run_sg = 0;
+#endif
+       return(n_mappings);
+}
+
+
+
+/*
+** First pass is to walk the SG list and determine where the breaks are
+** in the DMA stream. Allocates PDIR entries but does not fill them.
+** Returns the number of DMA chunks.
+**
+** Doing the fill seperate from the coalescing/allocation keeps the
+** code simpler. Future enhancement could make one pass through
+** the sglist do both.
+*/
+static SBA_INLINE int
+sba_coalesce_chunks( struct ioc *ioc,
+       struct scatterlist *startsg,
+       int nents)
+{
+       int n_mappings = 0;
+
+       while (nents > 0) {
+               struct scatterlist *dma_sg;  /* next DMA stream head */
+               unsigned long dma_offset, dma_len;   /* start/len of DMA stream */
+               struct scatterlist *chunksg; /* virtually contig chunk head */
+               unsigned long chunk_addr, chunk_len; /* start/len of VCONTIG chunk */
+
+               /*
+               ** Prepare for first/next DMA stream
+               */
+               dma_sg = chunksg = startsg;
+               dma_len = chunk_len  = startsg->length;
+               chunk_addr = (unsigned long) startsg->address;
+               dma_offset = 0UL;
+
+               /*
+               ** This loop terminates one iteration "early" since
+               ** it's always looking one "ahead".
+               */
+               while (--nents > 0) {
+                       /* ptr to coalesce prev and next */
+                       struct scatterlist *prev_sg = startsg;
+                       unsigned long prev_end = (unsigned long) prev_sg->address + prev_sg->length;
+                       unsigned long current_end;
+
+                       /* PARANOID: clear entries */
+                       sg_dma_address(startsg) = 0;
+                       sg_dma_len(startsg) = 0;
+
+                       /* Now start looking ahead */
+                       startsg++;
+                       current_end  = (unsigned long) startsg->address + startsg->length;
+
+                       /*
+                       ** First look for virtually contiguous blocks.
+                       ** PARISC needs this since it's cache is virtually
+                       ** indexed and we need the associated virtual
+                       ** address for each I/O address we map.
+                       **
+                       ** 1) can we *prepend* the next transaction?
+                       */
+                       if (current_end == (unsigned long) prev_sg->address)
+                       {
+                               /* prepend : get new offset */
+                               chunksg = startsg;
+                               chunk_addr = (unsigned long) prev_sg->address;
+                               chunk_len += startsg->length;
+                               dma_len   += startsg->length;
+                               continue;
+                       }
+
+                       /*
+                       ** 2) or append the next transaction?
+                       */
+                       if  (prev_end == (unsigned long) startsg->address)
+                       {
+                               chunk_len += startsg->length;
+                               dma_len   += startsg->length;
+                               continue;
+                       }
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+                       dump_run_sg = (chunk_len > IOVP_SIZE);
+#endif
+                       /*
+                       ** Not virtually contigous.
+                       ** Terminate prev chunk.
+                       ** Start a new chunk.
+                       **
+                       ** Once we start a new VCONTIG chunk, the offset
+                       ** can't change. And we need the offset from the first
+                       ** chunk - not the last one. Ergo Successive chunks
+                       ** must start on page boundaries and dove tail
+                       ** with it's predecessor.
+                       */
+                       sg_dma_len(prev_sg) = chunk_len;
+
+                       chunk_len = startsg->length;
+                       dma_offset |= (chunk_addr & ~IOVP_MASK);
+                       ASSERT((0 == (chunk_addr & ~IOVP_MASK)) ||
+                               (dma_offset == (chunk_addr & ~IOVP_MASK)));
+
+#if 0
+                       /*
+                       ** 4) do the chunks end/start on page boundaries?
+                       **  Easier than 3 since no offsets are involved.
+                       */
+                       if (DMA_CONTIG(prev_end, startsg->address))
+                       {
+                               /*
+                               ** Yes.
+                               ** Reset chunk ptr.
+                               */
+                               chunksg = startsg;
+                               chunk_addr = (unsigned long) startsg->address;
+
+                               continue;
+                       } else
+#endif
+                       {
+                               break;
+                       }
+               }
+
+               /*
+               ** End of DMA Stream
+               ** Terminate chunk.
+               ** Allocate space for DMA stream.
+               */
+               sg_dma_len(startsg) = chunk_len;
+               dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
+               sg_dma_address(dma_sg) =
+                       PIDE_FLAG 
+                       | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
+                       | dma_offset;
+               n_mappings++;
+       }
+
+       return n_mappings;
+}
+
+
+/*
+** And this algorithm still generally only ends up coalescing entries
+** that happens to be on the same page due to how sglists are assembled.
+*/
+static int
+sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+{
+       struct ioc *ioc = &sba_list->ioc[0];  /* FIXME : see Multi-IOC below */
+       int coalesced, filled = 0;
+       unsigned long flags;
+
+       DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+
+       /* Fast path single entry scatterlists. */
+       if (nents == 1) {
+               sg_dma_address(sglist)= sba_map_single(dev, sglist->address,
+                                               sglist->length, direction);
+               sg_dma_len(sglist)= sglist->length;
+               return 1;
+       }
+
+       spin_lock_irqsave(&ioc->res_lock, flags);
+
+#ifdef ASSERT_PDIR_SANITY
+       if (sba_check_pdir(ioc,"Check before sba_map_sg()"))
+       {
+               sba_dump_sg(ioc, sglist, nents);
+               panic("Check before sba_map_sg()");
+       }
+#endif
+
+#ifdef CONFIG_PROC_FS
+       ioc->msg_calls++;
+#endif
+
+       /*
+       ** First coalesce the chunks and allocate I/O pdir space
+       **
+       ** If this is one DMA stream, we can properly map using the
+       ** correct virtual address associated with each DMA page.
+       ** w/o this association, we wouldn't have coherent DMA!
+       ** Access to the virtual address is what forces a two pass algorithm.
+       */
+       coalesced = sba_coalesce_chunks(ioc, sglist, nents);
+
+       /*
+       ** Program the I/O Pdir
+       **
+       ** map the virtual addresses to the I/O Pdir
+       ** o dma_address will contain the pdir index
+       ** o dma_len will contain the number of bytes to map 
+       ** o address contains the virtual address.
+       */
+       filled = sba_fill_pdir(ioc, sglist, nents);
+
+#ifdef ASSERT_PDIR_SANITY
+       if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
+       {
+               sba_dump_sg(ioc, sglist, nents);
+               panic("Check after sba_map_sg()\n");
+       }
+#endif
+
+       spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+       ASSERT(coalesced == filled);
+       DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
+
+       return filled;
+}
+
+
+static void 
+sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+{
+       struct ioc *ioc = &sba_list->ioc[0];  /* FIXME : see Multi-IOC below */
+#ifdef ASSERT_PDIR_SANITY
+       unsigned long flags;
+#endif
+
+       DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
+               __FUNCTION__, nents, sglist->address, sglist->length);
+
+#ifdef CONFIG_PROC_FS
+       ioc->usg_calls++;
+#endif
+
+#ifdef ASSERT_PDIR_SANITY
+       spin_lock_irqsave(&ioc->res_lock, flags);
+       sba_check_pdir(ioc,"Check before sba_unmap_sg()");
+       spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+
+       while (sg_dma_len(sglist) && nents--) {
+
+#ifdef CONFIG_PROC_FS
+       ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
+#endif
+               sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
+               ++sglist;
+       }
+
+       DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__,  nents);
+
+#ifdef ASSERT_PDIR_SANITY
+       spin_lock_irqsave(&ioc->res_lock, flags);
+       sba_check_pdir(ioc,"Check after sba_unmap_sg()");
+       spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+
+}
+
+static struct pci_dma_ops sba_ops = {
+       sba_dma_supported,
+       sba_alloc_consistent,   /* allocate cacheable host mem */
+       sba_free_consistent,    /* release cacheable host mem */
+       sba_map_single,
+       sba_unmap_single,
+       sba_map_sg,
+       sba_unmap_sg,
+       NULL,                   /* dma_sync_single */
+       NULL                    /* dma_sync_sg */
+};
+
+
+/**************************************************************************
+**
+**   SBA PAT PDC support
+**
+**   o call pdc_pat_cell_module()
+**   o store ranges in PCI "resource" structures
+**
+**************************************************************************/
+
+static void
+sba_get_pat_resources(struct sba_device *sba_dev)
+{
+#if 0
+/*
+** TODO/REVISIT/FIXME: support for directed ranges requires calls to
+**      PAT PDC to program the SBA/LBA directed range registers...this
+**      burden may fall on the LBA code since it directly supports the
+**      PCI subsystem. It's not clear yet. - ggg
+*/
+PAT_MOD(mod)->mod_info.mod_pages   = PAT_GET_MOD_PAGES(temp);
+       FIXME : ???
+PAT_MOD(mod)->mod_info.dvi         = PAT_GET_DVI(temp);
+       Tells where the dvi bits are located in the address.
+PAT_MOD(mod)->mod_info.ioc         = PAT_GET_IOC(temp);
+       FIXME : ???
+#endif
+}
+
+
+/**************************************************************
+*
+*   Initialization and claim
+*
+***************************************************************/
+
+
+static void
+sba_ioc_init(struct ioc *ioc)
+{
+       extern unsigned long mem_max;          /* arch.../setup.c */
+       extern void lba_init_iregs(void *, u32, u32);   /* arch.../lba_pci.c */
+
+       u32 iova_space_size, iova_space_mask;
+       void * pdir_base;
+       int pdir_size, iov_order;
+
+       /*
+       ** Determine IOVA Space size from memory size.
+       ** Using "mem_max" is a kluge.
+       **
+       ** Ideally, PCI drivers would register the maximum number
+       ** of DMA they can have outstanding for each device they
+       ** own.  Next best thing would be to guess how much DMA
+       ** can be outstanding based on PCI Class/sub-class. Both
+       ** methods still require some "extra" to support PCI
+       ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD).
+       **
+       ** While we have 32-bits "IOVA" space, top two 2 bits are used
+       ** for DMA hints - ergo only 30 bits max.
+       */
+       /* limit IOVA space size to 1MB-1GB */
+       if (mem_max < (sba_mem_ratio*1024*1024)) {
+               iova_space_size = 1024*1024;
+#ifdef __LP64__
+       } else if (mem_max > (sba_mem_ratio*512*1024*1024)) {
+               iova_space_size = 512*1024*1024;
+#endif
+       } else {
+               iova_space_size = (u32) (mem_max/sba_mem_ratio);
+       }
+
+       /*
+       ** iova space must be log2() in size.
+       ** thus, pdir/res_map will also be log2().
+       */
+       iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT));
+       ASSERT(iov_order <= (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
+       ASSERT(iov_order >= (20 - IOVP_SHIFT));   /* iova_space_size >= 1MB */
+       iova_space_size = 1 << (iov_order + IOVP_SHIFT);
+
+       ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
+
+       ASSERT(pdir_size < 4*1024*1024);   /* max pdir size < 4MB */
+
+       /* Verify it's a power of two */
+       ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT));
+
+       DBG_INIT("%s() hpa 0x%p mem %dMBIOV %dMB (%d bits) PDIR size 0x%0x",
+               __FUNCTION__, ioc->ioc_hpa, (int) (mem_max>>20),
+               iova_space_size>>20, iov_order + PAGE_SHIFT, pdir_size);
+
+       /* FIXME : DMA HINTs not used */
+       ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
+       ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
+
+       ioc->pdir_base =
+       pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
+       if (NULL == pdir_base)
+       {
+               panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
+       }
+       memset(pdir_base, 0, pdir_size);
+
+       DBG_INIT("sba_ioc_init() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
+               pdir_base, pdir_size,
+               ioc->hint_shift_pdir, ioc->hint_mask_pdir);
+
+       ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
+       WRITE_REG64(virt_to_phys(pdir_base), (u64 *)(ioc->ioc_hpa+IOC_PDIR_BASE));
+
+       DBG_INIT(" base %p\n", pdir_base);
+
+       /* build IMASK for IOC and Elroy */
+       iova_space_mask =  0xffffffff;
+       iova_space_mask <<= (iov_order + PAGE_SHIFT);
+
+       /*
+       ** On C3000 w/512MB mem, HP-UX 10.20 reports:
+       **     ibase=0, imask=0xFE000000, size=0x2000000.
+       */
+       ioc->ibase = IOC_IOVA_SPACE_BASE | 1;   /* bit 0 == enable bit */
+       ioc->imask = iova_space_mask;   /* save it */
+
+       DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", __FUNCTION__,
+               ioc->ibase, ioc->imask);
+
+       /*
+       ** FIXME: Hint registers are programmed with default hint
+       ** values during boot, so hints should be sane even if we
+       ** can't reprogram them the way drivers want.
+       */
+
+       /*
+       ** setup Elroy IBASE/IMASK registers as well.
+       */
+       lba_init_iregs(ioc->ioc_hpa, ioc->ibase, ioc->imask);
+
+       /*
+       ** Program the IOC's ibase and enable IOVA translation
+       */
+       WRITE_REG32(ioc->ibase, ioc->ioc_hpa+IOC_IBASE);
+       WRITE_REG32(ioc->imask, ioc->ioc_hpa+IOC_IMASK);
+
+       /* Set I/O PDIR Page size to 4K */
+       WRITE_REG32(0, ioc->ioc_hpa+IOC_TCNFG);
+
+       /*
+       ** Clear I/O TLB of any possible entries.
+       ** (Yes. This is a it paranoid...but so what)
+       */
+       WRITE_REG32(0 | 31, ioc->ioc_hpa+IOC_PCOM);
+
+       DBG_INIT("%s() DONE\n", __FUNCTION__);
+}
+
+
+
+/**************************************************************************
+**
+**   SBA initialization code (HW and SW)
+**
+**   o identify SBA chip itself
+**   o initialize SBA chip modes (HardFail)
+**   o initialize SBA chip modes (HardFail)
+**   o FIXME: initialize DMA hints for reasonable defaults
+**
+**************************************************************************/
+
+static void
+sba_hw_init(struct sba_device *sba_dev)
+{ 
+       int i;
+       int num_ioc;
+       u32 ioc_ctl;
+
+       ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL);
+       DBG_INIT("%s() hpa 0x%p ioc_ctl 0x%x ->", __FUNCTION__, sba_dev->sba_hpa, ioc_ctl );
+       ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC);
+       ASSERT(ioc_ctl & IOC_CTRL_TE);  /* astro: firmware enables this */
+
+       WRITE_REG32(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL);
+
+#ifdef SBA_DEBUG_INIT
+       ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL);
+       DBG_INIT(" 0x%x\n", ioc_ctl );
+#endif
+
+       if (IS_ASTRO(sba_dev->iodc)) {
+               /* PAT_PDC (L-class) also reports the same goofy base */
+               sba_dev->ioc[0].ioc_hpa = (char *) ASTRO_IOC_OFFSET;
+               num_ioc = 1;
+       } else {
+               sba_dev->ioc[0].ioc_hpa = sba_dev->ioc[1].ioc_hpa = 0;
+               num_ioc = 2;
+       }
+
+       sba_dev->num_ioc = num_ioc;
+       for( i = 0; i < num_ioc; i++)
+       {
+               (unsigned long) sba_dev->ioc[i].ioc_hpa += (unsigned long) sba_dev->sba_hpa + IKE_IOC_OFFSET(i);
+
+               /*
+               ** Make sure the box crashes if we get any errors on a rope.
+               */
+               WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL);
+               WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL);
+               WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL);
+               WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL);
+               WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL);
+               WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL);
+               WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL);
+               WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
+
+               /* flush out the writes */
+               READ_REG32(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
+
+               sba_ioc_init(&(sba_dev->ioc[i]));
+       }
+}
+
+static void
+sba_common_init(struct sba_device *sba_dev)
+{
+       int i;
+
+       /* add this one to the head of the list (order doesn't matter)
+       ** This will be useful for debugging - especially if we get coredumps
+       */
+       sba_dev->next = sba_list;
+       sba_list = sba_dev;
+       sba_count++;
+
+       for(i=0; i< sba_dev->num_ioc; i++) {
+               int res_size;
+#ifdef CONFIG_DMB_TRAP
+               extern void iterate_pages(unsigned long , unsigned long ,
+                                         void (*)(pte_t * , unsigned long),
+                                         unsigned long );
+               void set_data_memory_break(pte_t * , unsigned long);
+#endif
+               /* resource map size dictated by pdir_size */
+               res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */
+               res_size >>= 3;  /* convert bit count to byte count */
+               DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, res_size);
+
+               sba_dev->ioc[i].res_size = res_size;
+               sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
+
+#ifdef CONFIG_DMB_TRAP
+               iterate_pages( sba_dev->ioc[i].res_map, res_size,
+                               set_data_memory_break, 0);
+#endif
+
+               if (NULL == sba_dev->ioc[i].res_map)
+               {
+                       panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ );
+               }
+
+               memset(sba_dev->ioc[i].res_map, 0, res_size);
+               /* next available IOVP - circular search */
+               sba_dev->ioc[i].res_hint = (unsigned long *)
+                               &(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]);
+
+#ifdef ASSERT_PDIR_SANITY
+               /* Mark first bit busy - ie no IOVA 0 */
+               sba_dev->ioc[i].res_map[0] = 0x80;
+               sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL;
+#endif
+
+#ifdef CONFIG_DMB_TRAP
+               iterate_pages( sba_dev->ioc[i].res_map, res_size,
+                               set_data_memory_break, 0);
+               iterate_pages( sba_dev->ioc[i].pdir_base, sba_dev->ioc[i].pdir_size,
+                               set_data_memory_break, 0);
+#endif
+
+               DBG_INIT("sba_common_init() %d res_map %x %p\n",
+                                       i, res_size, sba_dev->ioc[i].res_map);
+       }
+
+       sba_dev->sba_lock = SPIN_LOCK_UNLOCKED;
+}
+
+#ifdef CONFIG_PROC_FS
+static int sba_proc_info(char *buf, char **start, off_t offset, int len)
+{
+       struct sba_device *sba_dev = sba_list;
+/* FIXME: Multi-IOC support broken! */
+       struct ioc *ioc = &sba_dev->ioc[0];
+       int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
+       unsigned long i = 0, avg = 0, min, max;
+
+       sprintf(buf, "%s rev %d.%d\n",
+               parisc_getHWdescription(sba_dev->iodc->hw_type,
+                       sba_dev->iodc->hversion, sba_dev->iodc->sversion),
+               (sba_dev->hw_rev & 0x7) + 1,
+               (sba_dev->hw_rev & 0x18) >> 3
+               );
+       sprintf(buf, "%sIO PDIR size    : %d bytes (%d entries)\n",
+               buf,
+               ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits per byte */
+               total_pages);                  /* 8 bits per byte */
+
+       sprintf(buf, "%sIO PDIR entries : %ld free  %ld used (%d%%)\n", buf,
+               total_pages - ioc->used_pages, ioc->used_pages,
+               (int) (ioc->used_pages * 100 / total_pages));
+       
+       sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", 
+               buf, ioc->res_size, ioc->res_size << 3);   /* 8 bits per byte */
+
+       min = max = ioc->avg_search[0];
+       for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
+               avg += ioc->avg_search[i];
+               if (ioc->avg_search[i] > max) max = ioc->avg_search[i];
+               if (ioc->avg_search[i] < min) min = ioc->avg_search[i];
+       }
+       avg /= SBA_SEARCH_SAMPLE;
+       sprintf(buf, "%s  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+               buf, min, avg, max);
+
+       sprintf(buf, "%spci_map_single(): %8ld calls  %8ld pages (avg %d/1000)\n",
+               buf, ioc->msingle_calls, ioc->msingle_pages,
+               (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
+
+       /* KLUGE - unmap_sg calls unmap_single for each mapped page */
+       min = ioc->usingle_calls - ioc->usg_calls;
+       max = ioc->usingle_pages - ioc->usg_pages;
+       sprintf(buf, "%spci_unmap_single: %8ld calls  %8ld pages (avg %d/1000)\n",
+               buf, min, max,
+               (int) ((max * 1000)/min));
+
+       sprintf(buf, "%spci_map_sg()    : %8ld calls  %8ld pages (avg %d/1000)\n",
+               buf, ioc->msg_calls, ioc->msg_pages,
+               (int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
+
+       sprintf(buf, "%spci_unmap_sg()  : %8ld calls  %8ld pages (avg %d/1000)\n",
+               buf, ioc->usg_calls, ioc->usg_pages,
+               (int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
+
+       return strlen(buf);
+}
+
+static int
+sba_resource_map(char *buf, char **start, off_t offset, int len)
+{
+       struct sba_device *sba_dev = sba_list;
+       struct ioc *ioc = &sba_dev->ioc[0];
+       unsigned long *res_ptr = (unsigned long *)ioc->res_map;
+       int i;
+
+       for(i = 0; i < (ioc->res_size / sizeof(unsigned long)); ++i, ++res_ptr) {
+               if ((i & 7) == 0)
+                   strcat(buf,"\n   ");
+               sprintf(buf, "%s %08lx", buf, *res_ptr);
+       }
+       strcat(buf, "\n");
+
+       return strlen(buf);
+}
+#endif
+
+/*
+** Determine if lba should claim this chip (return 0) or not (return 1).
+** If so, initialize the chip and tell other partners in crime they
+** have work to do.
+*/
+int
+sba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+{
+       struct sba_device *sba_dev;
+       u32 func_class;
+       int i;
+
+       if (IS_ASTRO(d)) {
+               static char astro_rev[]="Astro ?.?";
+
+               /* Read HW Rev First */
+               func_class = READ_REG32(d->hpa);
+
+               astro_rev[6] = '1' + (char) (func_class & 0x7);
+               astro_rev[8] = '0' + (char) ((func_class & 0x18) >> 3);
+               dri->version = astro_rev;
+       } else {
+               static char ike_rev[]="Ike rev ?";
+
+               /* Read HW Rev First */
+               func_class = READ_REG32(d->hpa + SBA_FCLASS);
+
+               ike_rev[8] = '0' + (char) (func_class & 0xff);
+               dri->version = ike_rev;
+       }
+
+       printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa);
+
+       sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
+       if (NULL == sba_dev)
+       {
+               printk(MODULE_NAME " - couldn't alloc sba_device\n");
+               return(1);
+       }
+       memset(sba_dev, 0, sizeof(struct sba_device));
+       for(i=0; i<MAX_IOC; i++)
+               spin_lock_init(&(sba_dev->ioc[i].res_lock));
+
+
+       sba_dev->hw_rev = func_class;
+       sba_dev->iodc = d;
+       sba_dev->sba_hpa = d->hpa;  /* faster access */
+
+       sba_get_pat_resources(sba_dev);
+       sba_hw_init(sba_dev);
+       sba_common_init(sba_dev);
+
+       hppa_dma_ops = &sba_ops;
+
+#ifdef CONFIG_PROC_FS
+       if (IS_ASTRO(d)) {
+               create_proc_info_entry("Astro", 0, proc_runway_root, sba_proc_info);
+       } else {
+               create_proc_info_entry("Ike", 0, proc_runway_root, sba_proc_info);
+       }
+       create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map);
+#endif
+       return 0;
+}
diff --git a/arch/parisc/kernel/semaphore.c b/arch/parisc/kernel/semaphore.c
new file mode 100644 (file)
index 0000000..81156de
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Just taken from alpha implementation.
+ * This can't work well, perhaps.
+ */
+/*
+ *  Generic semaphore code. Buyer beware. Do your own
+ * specific changes in <asm/semaphore-helper.h>
+ */
+
+#include <linux/sched.h>
+#include <asm/semaphore-helper.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit.  ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore.  The others will go back
+ * to sleep.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+void __up(struct semaphore *sem)
+{
+       wake_one_more(sem);
+       wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function.  Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible.  This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return.  If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+
+#define DOWN_HEAD(task_state)                                          \
+                                                                       \
+                                                                       \
+       current->state = (task_state);                                  \
+       add_wait_queue(&sem->wait, &wait);                              \
+                                                                       \
+       /*                                                              \
+        * Ok, we're set up.  sem->count is known to be less than zero  \
+        * so we must wait.                                             \
+        *                                                              \
+        * We can let go the lock for purposes of waiting.              \
+        * We re-acquire it after awaking so as to protect              \
+        * all semaphore operations.                                    \
+        *                                                              \
+        * If "up()" is called before we call waking_non_zero() then    \
+        * we will catch it right away.  If it is called later then     \
+        * we will have to go through a wakeup cycle to catch it.       \
+        *                                                              \
+        * Multiple waiters contend for the semaphore lock to see       \
+        * who gets to gate through and who has to wait some more.      \
+        */                                                             \
+       for (;;) {
+
+#define DOWN_TAIL(task_state)                  \
+               current->state = (task_state);  \
+       }                                       \
+       current->state = TASK_RUNNING;          \
+       remove_wait_queue(&sem->wait, &wait);
+
+void __down(struct semaphore * sem)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+       if (waking_non_zero(sem))
+               break;
+       schedule();
+       DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __down_interruptible(struct semaphore * sem)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int ret = 0;
+
+       DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+       ret = waking_non_zero_interruptible(sem, current);
+       if (ret)
+       {
+               if (ret == 1)
+                       /* ret != 0 only if we get interrupted -arca */
+                       ret = 0;
+               break;
+       }
+       schedule();
+       DOWN_TAIL(TASK_INTERRUPTIBLE)
+       return ret;
+}
+
+int __down_trylock(struct semaphore * sem)
+{
+       return waking_non_zero_trylock(sem);
+}
+
+
+/* Wait for the lock to become unbiased.  Readers
+ * are non-exclusive. =)
+ */
+void down_read_failed(struct rw_semaphore *sem)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       __up_read(sem); /* this takes care of granting the lock */
+
+       add_wait_queue(&sem->wait, &wait);
+
+       while (atomic_read(&sem->count) < 0) {
+               set_task_state(current, TASK_UNINTERRUPTIBLE);
+               if (atomic_read(&sem->count) >= 0)
+                       break;
+               schedule();
+       }
+
+       remove_wait_queue(&sem->wait, &wait);
+       current->state = TASK_RUNNING;
+}
+
+void down_read_failed_biased(struct rw_semaphore *sem)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(&sem->wait, &wait);      /* put ourselves at the head of the list */
+
+       for (;;) {
+               if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
+                       break;
+               set_task_state(current, TASK_UNINTERRUPTIBLE);
+                if (!sem->read_bias_granted)
+                       schedule();
+       }
+
+       remove_wait_queue(&sem->wait, &wait);
+       current->state = TASK_RUNNING;
+}
+
+
+/* Wait for the lock to become unbiased. Since we're
+ * a writer, we'll make ourselves exclusive.
+ */
+void down_write_failed(struct rw_semaphore *sem)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       __up_write(sem);        /* this takes care of granting the lock */
+
+       add_wait_queue_exclusive(&sem->wait, &wait);
+
+       while (atomic_read(&sem->count) < 0) {
+               set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+               if (atomic_read(&sem->count) >= 0)
+                       break;  /* we must attempt to aquire or bias the lock */
+               schedule();
+       }
+
+       remove_wait_queue(&sem->wait, &wait);
+       current->state = TASK_RUNNING;
+}
+
+void down_write_failed_biased(struct rw_semaphore *sem)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
+
+       for (;;) {
+               if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
+                       break;
+               set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+               if (!sem->write_bias_granted)
+                       schedule();
+       }
+
+       remove_wait_queue(&sem->write_bias_wait, &wait);
+       current->state = TASK_RUNNING;
+
+       /* if the lock is currently unbiased, awaken the sleepers
+        * FIXME: this wakes up the readers early in a bit of a
+        * stampede -> bad!
+        */
+       if (atomic_read(&sem->count) >= 0)
+               wake_up(&sem->wait);
+}
+
+
+/* Called when someone has done an up that transitioned from
+ * negative to non-negative, meaning that the lock has been
+ * granted to whomever owned the bias.
+ */
+void rwsem_wake_readers(struct rw_semaphore *sem)
+{
+       if (xchg(&sem->read_bias_granted, 1))
+               BUG();
+       wake_up(&sem->wait);
+}
+
+void rwsem_wake_writer(struct rw_semaphore *sem)
+{
+       if (xchg(&sem->write_bias_granted, 1))
+               BUG();
+       wake_up(&sem->write_bias_wait);
+}
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
new file mode 100644 (file)
index 0000000..ec8f3cf
--- /dev/null
@@ -0,0 +1,616 @@
+/*    $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $
+ *
+ *    Initial setup-routines for HP 9000 based hardware.
+ * 
+ *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *    Modifications for PA-RISC (C) 1999 Helge Deller <helge.deller@ruhr-uni-bochum.de>
+ *    Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
+ *    Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
+ *    Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ *    Initial PA-RISC Version: 04-23-1999 by Helge Deller
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/user.h>
+#include <linux/tty.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/console.h>
+#include <linux/bootmem.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/threads.h>
+
+#include <asm/cache.h>
+#include <asm/hardware.h>      /* for register_driver() stuff */
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/led.h>
+#include <asm/real.h>
+#include <asm/system.h>
+#include <asm/machdep.h>       /* for pa7300lc_init() proto */
+
+#include <asm/irq.h>           /* for struct irq_region */
+#include <asm/pdc.h>           /* for mem_pdc_call() proto */
+#include <asm/pdcpat.h>                /* for PA_VIEW PDC_PAT_CPU_GET_NUMBER etc */
+
+#include <linux/proc_fs.h>
+#include <asm/cache.h>          /* for get_cache_info() proto */
+
+#define COMMAND_LINE_SIZE 1024
+char   saved_command_line[COMMAND_LINE_SIZE];
+
+/*
+** KLUGE ALERT!
+**
+** We *really* should be using a combination of request_resource()
+** and request_region()! But request_region() requires kmalloc since
+** returns a new struct resource. And kmalloc just isn't available
+** until after mem_init() is called from start_kernel().
+**
+** FIXME: assume contiguous memory initially.
+**     Additional chunks of memory might be added to sysram_resource.sibling.
+*/
+static struct resource sysrom_resource  = {
+       name: "System ROM", start: 0x0f0000000UL, end: 0x0f00fffffUL,
+       flags: IORESOURCE_BUSY | IORESOURCE_MEM,
+       parent: &iomem_resource, sibling: NULL, child: NULL };
+
+static struct resource pdcdata_resource;
+
+static struct resource sysram_resource  = {
+       name: "System RAM", start: 0UL, end: ~0UL /* bogus */,
+       flags: IORESOURCE_MEM,
+       parent: &iomem_resource, sibling: &sysrom_resource, child: &pdcdata_resource};
+
+extern char _text;     /* start of kernel code, defined by linker */
+extern int  data_start; 
+extern char _edata;    /* end of data, begin BSS, defined by linker */
+extern char _end;      /* end of BSS, defined by linker */
+
+static struct resource data_resource    = {
+       name: "kernel Data", start: virt_to_phys(&data_start), end: virt_to_phys(&_end)-1,
+       flags: IORESOURCE_BUSY | IORESOURCE_MEM,
+       parent: &sysram_resource, sibling: NULL, child: NULL};
+
+static struct resource code_resource = {
+       name: "Kernel Code", start: virt_to_phys(&_text), end: virt_to_phys(&data_start)-1,
+       flags: IORESOURCE_BUSY | IORESOURCE_MEM,
+       parent: &sysram_resource, sibling: &data_resource, child: NULL};
+
+static struct resource pdcdata_resource = {
+       name: "PDC data (Page Zero)", start: 0, end: 0x9ff,
+       flags: IORESOURCE_BUSY | IORESOURCE_MEM,
+       parent: &sysram_resource, sibling: &code_resource, child: NULL};
+
+
+
+
+struct system_cpuinfo_parisc boot_cpu_data;
+struct cpuinfo_parisc cpu_data[NR_CPUS];
+
+extern void do_inventory(void);
+extern void cache_init(void);
+extern struct hp_device * register_module(void *hpa);
+
+static int cpu_driver_callback(struct hp_device *, struct pa_iodc_driver *);
+
+static struct pa_iodc_driver cpu_drivers_for[] = {
+       {HPHW_NPROC, 0x0, 0x0, 0x0, 0, 0,
+               DRIVER_CHECK_HWTYPE,
+               "CPU", "PARISC", (void *) cpu_driver_callback},
+       {0,0,0,0,0,0,
+               0,
+               (char *) NULL, (char *) NULL, (void *) NULL }
+};
+
+static long fallback_cpu_hpa[] = { 0xfffa0000L, 0xfffbe000L, 0x0 };
+
+
+/*
+**     PARISC CPU driver - claim "device" and initialize CPU data structures.
+**
+** Consolidate per CPU initialization into (mostly) one module.
+** Monarch CPU will initialize boot_cpu_data which shouldn't
+** change once the system has booted.
+**
+** The callback *should* do per-instance initialization of
+** everything including the monarch. Some of the code that's
+** in setup.c:start_parisc() should migrate here and start_parisc()
+** should "register_driver(cpu_driver_for)" before calling
+** do_inventory().
+**
+** The goal of consolidating CPU initialization into one place is
+** to make sure all CPU's get initialized the same way.
+** It would be nice if the even the manarch through the exact same code path.
+** (up to rendevous at least).
+*/
+#undef ASSERT
+#define ASSERT(expr) \
+       if(!(expr)) { \
+               printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
+               panic(#expr); \
+       }
+
+static int
+cpu_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+{
+#ifdef __LP64__
+       extern int pdc_pat;     /* arch/parisc/kernel/inventory.c */
+       static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
+#endif
+       struct cpuinfo_parisc *p;
+
+#ifndef CONFIG_SMP
+       if (boot_cpu_data.cpu_count > 0) {
+               printk(KERN_INFO "CONFIG_SMP disabled - not claiming addional CPUs\n");
+               return(1);
+       }
+#endif
+
+       p = &cpu_data[boot_cpu_data.cpu_count];
+       boot_cpu_data.cpu_count++;
+
+/* TODO: Enable FP regs - done early in start_parisc() now */
+
+       /* initialize counters */
+       memset(p, 0, sizeof(struct cpuinfo_parisc));
+
+       p->hpa = (unsigned long) d->hpa; /* save CPU hpa */
+
+#ifdef __LP64__
+       if (pdc_pat) {
+               ulong status;
+               pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+
+               status = pdc_pat_cell_module(& pdc_result, d->pcell_loc,
+                       d->mod_index, PA_VIEW, & pa_pdc_cell);
+
+               ASSERT(PDC_RET_OK == status);
+
+               /* verify it's the same as what do_pat_inventory() found */
+               ASSERT(d->mod_info == pa_pdc_cell.mod_info);
+               ASSERT(d->pmod_loc == pa_pdc_cell.mod_location);
+               ASSERT(d->mod_path == pa_pdc_cell.mod_path);
+
+               p->txn_addr = pa_pdc_cell.mod[0];   /* id_eid for IO sapic */
+
+               /* get the cpu number */
+               status = mem_pdc_call( PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
+                               __pa(& pdc_result), d->hpa);
+
+               ASSERT(PDC_RET_OK == status);
+
+               p->cpuid = pdc_result[0];
+
+       } else
+#endif
+       {
+               p->txn_addr = (unsigned long) d->hpa;   /* for normal parisc */
+
+               /* logical CPU ID and update global counter */
+               p->cpuid = boot_cpu_data.cpu_count - 1;
+       }
+
+       /*
+       ** itimer and ipi IRQ handlers are statically initialized in
+       ** arch/parisc/kernel/irq.c
+       */
+       p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+
+       return(0);
+}
+
+
+void __xchg_called_with_bad_pointer(void)
+{
+    printk(KERN_EMERG "xchg() called with bad pointer !\n");
+}
+
+
+/* Some versions of IODC don't list the CPU, and since we don't walk
+ * the bus yet, we have to probe for processors at well known hpa
+ * addresses.  
+ */
+
+void __init register_fallback_cpu (void)
+{
+       struct hp_device *d = NULL;
+       int i = 0;
+       
+#ifdef CONFIG_SMP
+#error "Revisit CPU fallback addresses for SMP (Assuming bus walk hasn't been implemented)"
+#endif
+       printk ("No CPUs reported by firmware - probing...\n");
+       
+       while (fallback_cpu_hpa[i]) {
+               
+               d = register_module ((void *) fallback_cpu_hpa[i]);
+               
+               if (d > 0) {
+                       printk ("Found CPU at %lx\n", fallback_cpu_hpa[i]);
+                       cpu_driver_callback (d, 0);
+                       return;
+               }
+               
+               i++;
+       }
+       
+       panic ("No CPUs found.  System halted.\n");
+       return;
+}
+
+
+/*
+ * Get CPU information and store it in the boot_cpu_data structure.  */
+void __init collect_boot_cpu_data(void)
+{
+       memset(&boot_cpu_data,0,sizeof(boot_cpu_data));
+
+       boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
+
+       /* get CPU-Model Information... */
+#define p ((unsigned long *)&boot_cpu_data.pdc.model)
+       if(pdc_model_info(&boot_cpu_data.pdc.model)==0)
+               printk("model   %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+                       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
+#undef p
+
+       if(pdc_model_versions(&boot_cpu_data.pdc.versions, 0)==0)
+               printk("vers    %08lx\n", boot_cpu_data.pdc.versions.cpuid);
+
+       if(pdc_model_cpuid(&boot_cpu_data.pdc.cpuid)==0)
+               printk("cpuid   %08lx\n", boot_cpu_data.pdc.cpuid.cpuid);
+       
+       printk("CPUID   vers %ld rev %ld\n",
+               (boot_cpu_data.pdc.cpuid.cpuid >> 5) & 127,
+               boot_cpu_data.pdc.cpuid.cpuid & 31);
+
+       if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name)==0)
+               printk("model   %s\n",boot_cpu_data.pdc.sys_model_name);
+
+       boot_cpu_data.model_name = parisc_getHWdescription(HPHW_NPROC,
+               boot_cpu_data.pdc.model.hversion>>4,
+               boot_cpu_data.pdc.model.sversion>>8);
+       
+       boot_cpu_data.hversion =  boot_cpu_data.pdc.model.hversion;
+       boot_cpu_data.sversion =  boot_cpu_data.pdc.model.sversion;
+
+       boot_cpu_data.cpu_type =
+                       parisc_get_cpu_type(boot_cpu_data.pdc.model.hversion);
+
+       boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
+       boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
+}
+
+
+#ifdef __LP64__
+#define COMMAND_GLOBAL  0xfffffffffffe0030UL
+#else
+#define COMMAND_GLOBAL  0xfffe0030
+#endif
+
+#define CMD_RESET       5       /* reset any module */
+
+/*
+** The Wright Brothers and Gecko systems have a H/W problem
+** (Lasi...'nuf said) may cause a broadcast reset to lockup
+** the system. An HVERSION dependent PDC call was developed
+** to perform a "safe", platform specific broadcast reset instead
+** of kludging up all the code.
+**
+** Older machines which do not implement PDC_BROADCAST_RESET will
+** return (with an error) and the regular broadcast reset can be
+** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
+** the PDC call will not return (the system will be reset).
+*/
+static int
+reset_parisc(struct notifier_block *self, unsigned long command, void *ptr)
+{
+       printk("%s: %s(cmd=%lu)\n", __FILE__, __FUNCTION__, command);
+
+       switch(command) {
+       case MACH_RESTART:
+#ifdef FASTBOOT_SELFTEST_SUPPORT
+               /*
+               ** If user has modified the Firmware Selftest Bitmap,
+               ** run the tests specified in the bitmap after the
+               ** system is rebooted w/PDC_DO_RESET.
+               **
+               ** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
+               **
+               ** Using "directed resets" at each processor with the MEM_TOC
+               ** vector cleared will also avoid running destructive
+               ** memory self tests. (Not implemented yet)
+               */
+               if (ftc_bitmap) {
+                       mem_pdc_call( PDC_BROADCAST_RESET,
+                               PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC,
+                               ftc_bitmap);
+               }
+#endif
+
+               /* "Normal" system reset */
+               (void) mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET,
+                       0L, 0L, 0L);
+
+               /* Nope...box should reset with just CMD_RESET now */
+               gsc_writel(CMD_RESET, COMMAND_GLOBAL);
+
+               /* Wait for RESET to lay us to rest. */
+               while (1) ;
+
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block parisc_block = { reset_parisc, NULL, 0 };
+
+
+/*  start_parisc() will be called from head.S to setup our new memory_start 
+    and actually start our kernel !
+    Memory-Layout is:
+       - Kernel-Image (code+data+BSS)
+       - Stack (stack-size see below!, stack-setup-code is in head.S)
+       - memory_start at end of stack..
+*/
+
+unsigned long mem_start, mem_max;
+unsigned long start_pfn, max_pfn;
+extern asmlinkage void __init start_kernel(void);
+
+#define PFN_UP(x)      (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)    ((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)    ((x) << PAGE_SHIFT)
+
+void __init start_parisc(unsigned arg0, unsigned arg1,
+                        unsigned arg2, unsigned arg3)
+{
+       register unsigned long ccr;
+       unsigned long memory_start;
+
+       /* Clear BSS */
+
+       {
+               char *p = &_edata, *q = &_end;
+
+               while (p < q) {
+                       *p++ = 0;
+               }
+       }
+
+
+       pdc_console_init();
+
+#ifdef __LP64__
+       printk("The 64-bit Kernel has started...\n");
+#else
+       printk("The 32-bit Kernel has started...\n");
+#endif
+
+       /*
+       ** Enable FP coprocessor
+       **
+       ** REVISIT: ccr should be set by PDC_COPROC results to support PA1.0.
+       ** Hardcoding works for PA1.1 processors.
+       **
+       ** REVISIT: this could be done in the "code 22" trap handler.
+       ** (frowands idea - that way we know which processes need FP
+       ** registers saved on the interrupt stack.)
+       **
+       ** NEWS FLASH: wide kernels need FP coprocessor enabled to handle
+       ** formatted printing of %lx for example (double divides I think)
+       */
+       ccr = 0xc0;
+       mtctl(ccr, 10);
+       printk("Enabled FP coprocessor\n");
+
+#ifdef __LP64__
+       printk( "If this is the LAST MESSAGE YOU SEE, you're probably using\n"
+               "32-bit millicode by mistake.\n");
+#endif
+
+       memory_start = (unsigned long) &_end;
+       memory_start = (memory_start + PAGE_SIZE) & PAGE_MASK;
+       printk("Free memory starts at: 0x%lx\n", memory_start);
+
+       /* Collect stuff passed in from the boot loader */
+       printk(KERN_WARNING  "%s(0x%x,0x%x,0x%x,0x%x)\n", 
+                   __FUNCTION__, arg0, arg1, arg2, arg3);
+
+       /* arg0 is free-mem start, arg1 is ptr to command line */
+       if (arg0 < 64) {
+               /* called from hpux boot loader */
+               saved_command_line[0] = '\0';
+       } else {
+               strcpy(saved_command_line, (char *)__va(arg1));
+               printk("PALO command line: '%s'\nPALO initrd %x-%x\n",
+                   saved_command_line, arg2, arg3);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+               if (arg2 != 0) /* did palo pass us a ramdisk? */
+               {
+                   initrd_start = (unsigned long)__va(arg2);
+                   initrd_end = (unsigned long)__va(arg3);
+               }
+#endif
+       }
+
+       mem_start = __pa(memory_start);
+#define MAX_MEM (512*1024*1024)
+       mem_max = (PAGE0->imm_max_mem > MAX_MEM ? MAX_MEM : PAGE0->imm_max_mem);
+
+       collect_boot_cpu_data();
+
+       /* initialize the LCD/LED after boot_cpu_data is available ! */
+        led_init();                            /* LCD/LED initialization */
+
+       do_inventory();                         /* probe for hardware */
+        register_driver(cpu_drivers_for);      /* claim all the CPUs */
+
+       if (boot_cpu_data.cpu_count == 0)
+           register_fallback_cpu();
+
+       printk("CPU(s): %d x %s at %d.%06d MHz\n", 
+                       boot_cpu_data.cpu_count,
+                       boot_cpu_data.cpu_name,
+                       boot_cpu_data.cpu_hz / 1000000, 
+                       boot_cpu_data.cpu_hz % 1000000  );
+
+       switch (boot_cpu_data.cpu_type) {
+       case pcx:
+       case pcxs:
+       case pcxt:
+               hppa_dma_ops = &pcx_dma_ops;
+               break;
+       case pcxl2:
+               pa7300lc_init();
+       case pcxl: /* falls through */
+               hppa_dma_ops = &pcxl_dma_ops;
+               break;
+       default:
+               break;
+       }
+
+#if 1
+       /* KLUGE! this really belongs in kernel/resource.c! */
+       iomem_resource.end = ~0UL;
+#endif
+       sysram_resource.end = mem_max - 1;
+       notifier_chain_register(&mach_notifier, &parisc_block);
+       start_kernel();         /* now back to arch-generic code... */
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+       unsigned long bootmap_size;
+       unsigned long start_pfn;
+       unsigned long mem_free;
+
+       *cmdline_p = saved_command_line;
+
+       /* initialize bootmem */
+
+       start_pfn = PFN_UP(mem_start);
+       max_pfn = PFN_DOWN(mem_max);
+
+       bootmap_size = init_bootmem(start_pfn, max_pfn);
+
+       mem_start += bootmap_size;
+       mem_free = mem_max - mem_start;
+
+       /* free_bootmem handles rounding nicely */
+       printk("free_bootmem(0x%lx, 0x%lx)\n", (unsigned long)mem_start,
+                       (unsigned long)mem_free);
+       free_bootmem(mem_start, mem_free);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       printk("initrd: %08x-%08x\n", (int) initrd_start, (int) initrd_end);
+
+       if (initrd_end != 0) {
+               initrd_below_start_ok = 1;
+               reserve_bootmem(__pa(initrd_start), initrd_end - initrd_start);
+       }
+#endif
+
+       cache_init();
+
+       paging_init();
+
+       if((unsigned long)&init_task_union&(INIT_TASK_SIZE - 1)) {
+               printk("init_task_union not aligned.  Please recompile the kernel after changing the first line in arch/parisc/kernel/init_task.c from \n\"#define PAD 0\" to\n\"#define PAD 1\" or vice versa\n");
+               for(;;);
+       }
+
+
+#ifdef CONFIG_SERIAL_CONSOLE
+       /* nothing */
+#elif CONFIG_VT
+#if   defined(CONFIG_STI_CONSOLE)
+       conswitchp = &dummy_con;        /* we use take_over_console() later ! */
+#elif defined(CONFIG_IODC_CONSOLE)
+       conswitchp = &prom_con;         /* it's currently really "prom_con" */
+#elif defined(CONFIG_DUMMY_CONSOLE)
+       conswitchp = &dummy_con;
+#endif
+#endif
+
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ *     Get CPU information for use by procfs.
+ */
+
+int get_cpuinfo(char *buffer)
+{
+       char              *p = buffer;
+       int               n;
+
+       for(n=0; n<boot_cpu_data.cpu_count; n++) {
+#ifdef CONFIG_SMP
+               if (!(cpu_online_map & (1<<n)))
+                       continue;
+#endif
+               p += sprintf(p, "processor\t: %d\n"
+                               "cpu family\t: PA-RISC %s\n",
+                               n, boot_cpu_data.family_name);
+
+               p += sprintf(p, "cpu\t\t: %s\n",  boot_cpu_data.cpu_name );
+       
+               /* cpu MHz */
+               p += sprintf(p, "cpu MHz\t\t: %d.%06d\n",
+                                boot_cpu_data.cpu_hz / 1000000, 
+                                boot_cpu_data.cpu_hz % 1000000  );
+
+               p += sprintf(p, "model\t\t: %s\n"
+                               "model name\t: %s\n",
+                               boot_cpu_data.pdc.sys_model_name,
+                               boot_cpu_data.model_name);
+
+               p += sprintf(p, "hversion\t: 0x%08x\n"
+                               "sversion\t: 0x%08x\n",
+                               boot_cpu_data.hversion,
+                               boot_cpu_data.sversion );
+
+               p += get_cache_info(p);
+               /* print cachesize info ? */
+               p += sprintf(p, "bogomips\t: %lu.%02lu\n",
+                            (loops_per_sec+2500)/500000,
+                            ((loops_per_sec+2500)/5000) % 100);
+       }
+       return p - buffer;
+}
+#endif
+
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
new file mode 100644 (file)
index 0000000..a910f43
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ *  linux/arch/parisc/kernel/signal.c: Architecture-specific signal
+ *  handling support.
+ *
+ *  Copyright (C) 2000 David Huggins-Daines <dhd@debian.org>
+ *  Copyright (C) 2000 Linuxcare, Inc.
+ *
+ *  Based on the ia64, i386, and alpha versions.
+ *
+ *  Like the IA-64, we are a recent enough port (we are *starting*
+ *  with glibc2.2) that we do not need to support the old non-realtime
+ *  Linux signals.  Therefore we don't.  HP/UX signals will go in
+ *  arch/parisc/hpux/signal.c when we figure out how to do them.
+ */
+
+#include <linux/config.h>
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+extern long sys_wait4 (int, int *, int, struct rusage *);
+int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall);
+
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+       if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+               return -EFAULT;
+       if (from->si_code < 0)
+               return __copy_to_user(to, from, sizeof(siginfo_t));
+       else {
+               int err;
+
+               /*
+                * If you change siginfo_t structure, please be sure
+                * this code is fixed accordingly.  It should never
+                * copy any pad contained in the structure to avoid
+                * security leaks, but must copy the generic 3 ints
+                * plus the relevant union member.
+                */
+               err = __put_user(from->si_signo, &to->si_signo);
+               err |= __put_user(from->si_errno, &to->si_errno);
+               err |= __put_user((short)from->si_code, &to->si_code);
+               switch (from->si_code >> 16) {
+                     case __SI_FAULT >> 16:
+                       /* FIXME: should we put the interruption code here? */
+                     case __SI_POLL >> 16:
+                       err |= __put_user(from->si_addr, &to->si_addr);
+                       break;
+                     case __SI_CHLD >> 16:
+                       err |= __put_user(from->si_utime, &to->si_utime);
+                       err |= __put_user(from->si_stime, &to->si_stime);
+                       err |= __put_user(from->si_status, &to->si_status);
+                     default:
+                       err |= __put_user(from->si_uid, &to->si_uid);
+                       err |= __put_user(from->si_pid, &to->si_pid);
+                       break;
+                     /* case __SI_RT: This is not generated by the kernel as of now.  */
+               }
+               return err;
+       }
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+#ifdef __LP64__
+#include "sys32.h"
+#endif
+
+asmlinkage int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
+{
+       sigset_t saveset, newset;
+#ifdef __LP64__
+       /* XXX FIXME -- assumes 32-bit user app! */
+       sigset_t32 newset32;
+
+       /* XXX: Don't preclude handling different sized sigset_t's.  */
+       if (sigsetsize != sizeof(sigset_t32))
+               return -EINVAL;
+
+       if (copy_from_user(&newset32, (sigset_t32 *)unewset, sizeof(newset32)))
+               return -EFAULT;
+
+       newset.sig[0] = newset32.sig[0] | ((unsigned long)newset32.sig[1] << 32);
+#else
+
+       /* XXX: Don't preclude handling different sized sigset_t's.  */
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+
+       if (copy_from_user(&newset, unewset, sizeof(newset)))
+               return -EFAULT;
+#endif
+       sigdelsetmask(&newset, ~_BLOCKABLE);
+
+       spin_lock_irq(&current->sigmask_lock);
+       saveset = current->blocked;
+       current->blocked = newset;
+       recalc_sigpending(current);
+       spin_unlock_irq(&current->sigmask_lock);
+
+       regs->gr[28] = -EINTR;
+       while (1) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+               if (do_signal(&saveset, regs, 1))
+                       return -EINTR;
+       }
+}
+
+/*
+ * Do a signal return - restore sigcontext.
+ */
+
+struct rt_sigframe {
+       unsigned int tramp[4];
+       struct siginfo info;
+       struct ucontext uc;
+};
+
+/* Trampoline for calling rt_sigreturn() */
+#define INSN_LDI_R25_0  0x34190000 /* ldi  0,%r25 (in_syscall=0) */
+#define INSN_LDI_R25_1  0x34190002 /* ldi  1,%r25 (in_syscall=1) */
+#define INSN_LDI_R20    0x3414015a /* ldi  __NR_rt_sigreturn,%r20 */
+#define INSN_BLE_SR2_R0  0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */
+#define INSN_NOP        0x80000240 /* nop */
+/* For debugging */
+#define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */
+
+/*
+ * The 32-bit ABI wants at least 48 bytes for a function call frame:
+ * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of
+ * which Linux/parisc uses is sp-20 for the saved return pointer...)
+ * Then, the stack pointer must be rounded to a cache line (64 bytes).
+ */
+#define PARISC_RT_SIGFRAME_SIZE                                        \
+       (((sizeof(struct rt_sigframe) + 48) + 63) & -64)
+
+static long
+restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
+{
+       long err = 0;
+
+       err |= __copy_from_user(regs->gr, sc->sc_gr, sizeof(regs->gr));
+       err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr));
+       err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq));
+       err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq));
+       err |= __get_user(regs->sar, &sc->sc_sar);
+
+#if DEBUG_SIG
+       printk("restore_sigcontext: r28 is %ld\n", regs->gr[28]);
+#endif
+       return err;
+}
+
+void
+sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
+{
+       struct rt_sigframe *frame;
+       struct siginfo si;
+       sigset_t set;
+       unsigned long usp = regs->gr[30];
+
+       /* Unwind the user stack to get the rt_sigframe structure. */
+       frame = (struct rt_sigframe *)
+               (usp - PARISC_RT_SIGFRAME_SIZE);
+#if DEBUG_SIG
+       printk("in sys_rt_sigreturn, frame is %p\n", frame);
+#endif
+
+       /* Verify that it's a good sigcontext before using it */
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto give_sigsegv;
+       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+               goto give_sigsegv;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(&current->sigmask_lock);
+       current->blocked = set;
+       recalc_sigpending(current);
+       spin_unlock_irq(&current->sigmask_lock);
+
+       /* Good thing we saved the old gr[30], eh? */
+       if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
+               goto give_sigsegv;
+
+#if DEBUG_SIG
+       printk("usp: %#08lx stack %p",
+              usp, &frame->uc.uc_stack);
+#endif
+
+       /* I don't know why everyone else assumes they can call this
+           with a pointer to a stack_t on the kernel stack.  That
+           makes no sense.  Anyway we'll do it like m68k, since we
+           also are using segmentation in the same way as them. */
+       if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT)
+               goto give_sigsegv;
+
+       /* If we are on the syscall path IAOQ will not be restored, and
+        * if we are on the interrupt path we must not corrupt gr31.
+        */
+       if (in_syscall)
+               regs->gr[31] = regs->iaoq[0];
+#if DEBUG_SIG
+       printk("returning to %#lx\n", regs->iaoq[0]);
+       printk("in sys_rt_sigreturn:\n");
+       show_regs(regs);
+#endif
+       return;
+
+give_sigsegv:
+#if DEBUG_SIG
+       printk("fuckup in sys_rt_sigreturn, sending SIGSEGV\n");
+#endif
+       si.si_signo = SIGSEGV;
+       si.si_errno = 0;
+       si.si_code = SI_KERNEL;
+       si.si_pid = current->pid;
+       si.si_uid = current->uid;
+       si.si_addr = &frame->uc;
+       force_sig_info(SIGSEGV, &si, current);
+       return;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+static inline void *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+       if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+               sp = current->sas_ss_sp + current->sas_ss_size;
+
+       return (void *) sp; /* Stacks grow up.  Fun. */
+}
+
+static long
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, int in_syscall)
+                
+{
+       unsigned long flags = 0;
+       long err = 0;
+
+       if (on_sig_stack((unsigned long) sc))
+               flags |= PARISC_SC_FLAG_ONSTACK;
+       if (in_syscall) {
+               flags |= PARISC_SC_FLAG_IN_SYSCALL;
+               /* regs->iaoq is undefined in the syscall return path */
+               err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]);
+               err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]);
+#if DEBUG_SIG
+               printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->gr[31], regs->gr[31]);
+#endif
+       } else {
+               err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq));
+               err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq));
+#if DEBUG_SIG
+               printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->iaoq[0], regs->iaoq[1]);
+#endif
+       }
+
+       err |= __put_user(flags, &sc->sc_flags);
+       err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr));
+       err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
+       err |= __put_user(regs->sar, &sc->sc_sar);
+#if DEBUG_SIG
+       printk("setup_sigcontext: r28 is %ld\n", regs->gr[28]);
+#endif
+
+       return err;
+}
+
+static long
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+              sigset_t *set, struct pt_regs *regs, int in_syscall)
+{
+       struct rt_sigframe *frame;
+       unsigned long rp, usp, haddr;
+       struct siginfo si;
+       int err = 0;
+
+       usp = regs->gr[30];
+       /* access_ok is broken, so do a simplistic "are we stomping on
+           kernel space" assertion. */
+       if (usp > PAGE_OFFSET) {
+               printk("setup_rt_frame: called on kernel space (usp=%#lx),  NOW YOU MUST DIE!!!\n",
+                      usp);
+               show_regs(regs);
+               while(1);
+       }
+               
+       frame = get_sigframe(ka, usp, sizeof(*frame));
+       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+               goto give_sigsegv;
+
+#if DEBUG_SIG
+       printk("setup_rt_frame 1: frame %p info %p\n", frame, info);
+#endif
+
+       err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t));
+       err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+       err |= __put_user(sas_ss_flags(regs->gr[30]),
+                         &frame->uc.uc_stack.ss_flags);
+       err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall);
+       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+       if (err)
+               goto give_sigsegv;
+
+       /* Set up to return from userspace.  If provided, use a stub
+          already in userspace.  */
+       err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0,
+                       &frame->tramp[0]);
+       err |= __put_user(INSN_LDI_R20, &frame->tramp[1]);
+       err |= __put_user(INSN_BLE_SR2_R0, &frame->tramp[2]);
+       err |= __put_user(INSN_NOP, &frame->tramp[3]);
+
+#if DEBUG_SIG
+       /* Assert that we're flushing in the correct space... */
+       {
+               int sid;
+               asm ("mfsp %%sr3,%0" : "=r" (sid));
+               printk("flushing 64 bytes at space %#x offset %p\n",
+                      sid, frame->tramp);
+       }
+#endif
+
+#if CACHE_FLUSHING_IS_NOT_BROKEN
+       flush_icache_range((unsigned long) &frame->tramp[0],
+                          (unsigned long) &frame->tramp[4]);
+#else
+       /* It should *always* be cache line-aligned, but the compiler
+           sometimes screws up. */
+       asm volatile("fdc 0(%%sr3,%0)\n\t"
+                    "fdc %1(%%sr3,%0)\n\t"
+                    "sync\n\t"
+                    "fic 0(%%sr3,%0)\n\t"
+                    "fic %1(%%sr3,%0)\n\t"
+                    "sync\n\t"
+                    : : "r" (frame->tramp), "r" (L1_CACHE_BYTES));
+#endif
+       rp = (unsigned long) frame->tramp;
+
+       if (err)
+               goto give_sigsegv;
+
+#ifdef __LP64__
+/* Much more has to happen with signals than this -- but it'll at least */
+/* provide a pointer to some places which definitely need a look. */
+#define HACK unsigned int
+#else
+#define HACK unsigned long
+#endif
+       haddr = (HACK) ka->sa.sa_handler;
+       /* ARGH!  Fucking brain damage.  You don't want to know. */
+       if (haddr & 2) {
+               HACK *plabel;
+               HACK ltp;
+
+               plabel = (HACK *) (haddr & ~3);
+               err |= __get_user(haddr, plabel);
+               err |= __get_user(ltp, plabel + 1);
+               if (err)
+                       goto give_sigsegv;
+               regs->gr[19] = ltp;
+       }
+
+       /* The syscall return path will create IAOQ values from r31.
+        */
+       if (in_syscall)
+               regs->gr[31] = (HACK) haddr;
+       else {
+               regs->iaoq[0] = (HACK) haddr | 3;
+               regs->iaoq[1] = regs->iaoq[0] + 4;
+       }
+
+       regs->gr[2]  = rp;                /* userland return pointer */
+       regs->gr[26] = sig;               /* signal number */
+       regs->gr[25] = (HACK) &frame->info; /* siginfo pointer */
+       regs->gr[24] = (HACK) &frame->uc;   /* ucontext pointer */
+#if DEBUG_SIG
+       printk("making sigreturn frame: %#lx + %#lx = %#lx\n",
+              regs->gr[30], PARISC_RT_SIGFRAME_SIZE,
+              regs->gr[30] + PARISC_RT_SIGFRAME_SIZE);
+#endif
+       /* Raise the user stack pointer to make a proper call frame. */
+       regs->gr[30] = ((HACK) frame + PARISC_RT_SIGFRAME_SIZE);
+
+#if DEBUG_SIG
+       printk("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
+              current->comm, current->pid, frame, regs->gr[30],
+              regs->iaoq[0], regs->iaoq[1], rp);
+#endif
+
+       return 1;
+
+give_sigsegv:
+#if DEBUG_SIG
+       printk("fuckup in setup_rt_frame, sending SIGSEGV\n");
+#endif
+       if (sig == SIGSEGV)
+               ka->sa.sa_handler = SIG_DFL;
+       si.si_signo = SIGSEGV;
+       si.si_errno = 0;
+       si.si_code = SI_KERNEL;
+       si.si_pid = current->pid;
+       si.si_uid = current->uid;
+       si.si_addr = frame;
+       force_sig_info(SIGSEGV, &si, current);
+       return 0;
+}
+
+/*
+ * OK, we're invoking a handler.
+ */    
+
+static long
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+             siginfo_t *info, sigset_t *oldset,
+             struct pt_regs *regs, int in_syscall)
+{
+#if DEBUG_SIG
+       printk("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",
+              sig, ka, info, oldset, regs);
+#endif
+       /* Set up the stack frame */
+       if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
+               return 0;
+
+       if (ka->sa.sa_flags & SA_ONESHOT)
+               ka->sa.sa_handler = SIG_DFL;
+
+       if (!(ka->sa.sa_flags & SA_NODEFER)) {
+               spin_lock_irq(&current->sigmask_lock);
+               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+               sigaddset(&current->blocked,sig);
+               recalc_sigpending(current);
+               spin_unlock_irq(&current->sigmask_lock);
+       }
+       return 1;
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * We need to be able to restore the syscall arguments (r21-r26) to
+ * restart syscalls.  Thus, the syscall path should save them in the
+ * pt_regs structure (it's okay to do so since they are caller-save
+ * registers).  As noted below, the syscall number gets restored for
+ * us due to the magic of delayed branching.
+ */
+asmlinkage int
+do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
+{
+       siginfo_t info;
+       struct k_sigaction *ka;
+
+#if DEBUG_SIG
+       printk("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",
+              oldset, regs, regs->sr[7], current->sigpending, in_syscall);
+#endif
+       /* Everyone else checks to see if they are in kernel mode at
+          this point and exits if that's the case.  I'm not sure why
+          we would be called in that case, but for some reason we
+          are. */
+
+       if (!oldset)
+               oldset = &current->blocked;
+
+#if DEBUG_SIG
+       printk("do_signal: oldset %08lx:%08lx\n", oldset->sig[0], oldset->sig[1]);
+#endif
+
+       for (;;) {
+               unsigned long signr;
+
+               spin_lock_irq(&current->sigmask_lock);
+               signr = dequeue_signal(&current->blocked, &info);
+               spin_unlock_irq(&current->sigmask_lock);
+#if DEBUG_SIG
+               printk("do_signal: signr=%ld, pid=%d\n", signr, current->pid);
+#endif
+
+               if (!signr)
+                       break;
+
+               if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+                       /* Let the debugger run.  */
+                       current->exit_code = signr;
+                       set_current_state(TASK_STOPPED);
+                       notify_parent(current, SIGCHLD);
+                       schedule();
+
+                       /* We're back.  Did the debugger cancel the sig?  */
+                       if (!(signr = current->exit_code))
+                               continue;
+                       current->exit_code = 0;
+
+                       /* The debugger continued.  Ignore SIGSTOP.  */
+                       if (signr == SIGSTOP)
+                               continue;
+
+                       /* Update the siginfo structure.  Is this good?  */
+                       if (signr != info.si_signo) {
+                               info.si_signo = signr;
+                               info.si_errno = 0;
+                               info.si_code = SI_USER;
+                               info.si_pid = current->p_pptr->pid;
+                               info.si_uid = current->p_pptr->uid;
+                       }
+
+                       /* If the (new) signal is now blocked, requeue it.  */
+                       if (sigismember(&current->blocked, signr)) {
+                               send_sig_info(signr, &info, current);
+                               continue;
+                       }
+               }
+
+               ka = &current->sig->action[signr-1];
+#if DEBUG_SIG
+               printk("sa_handler is %lx\n", ka->sa.sa_handler);
+#endif
+               if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_IGN) {
+                       if (signr != SIGCHLD)
+                               continue;
+                       while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+                               /* nothing */;
+                       continue;
+               }
+
+               if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_DFL) {
+                       int exit_code = signr;
+
+                       /* Init gets no signals it doesn't want.  */
+                       if (current->pid == 1)
+                               continue;
+
+                       switch (signr) {
+                       case SIGCONT: case SIGCHLD: case SIGWINCH:
+                               continue;
+
+                       case SIGTSTP: case SIGTTIN: case SIGTTOU:
+                               if (is_orphaned_pgrp(current->pgrp))
+                                       continue;
+                               /* FALLTHRU */
+
+                       case SIGSTOP:
+                               set_current_state(TASK_STOPPED);
+                               current->exit_code = signr;
+                               if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+                                       notify_parent(current, SIGCHLD);
+                               schedule();
+                               continue;
+
+                       case SIGQUIT: case SIGILL: case SIGTRAP:
+                       case SIGABRT: case SIGFPE: case SIGSEGV:
+                       case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
+                               if (signr == SIGQUIT) /* Userspace debugging */
+                                       show_regs(regs);
+                               if (do_coredump(signr, regs))
+                                       exit_code |= 0x80;
+                               /* FALLTHRU */
+
+                       default:
+                               lock_kernel();
+                               sigaddset(&current->pending.signal, signr);
+                               recalc_sigpending(current);
+                               current->flags |= PF_SIGNALED;
+                               do_exit(exit_code);
+                               /* NOTREACHED */
+                       }
+               }
+
+               /* Restart a system call if necessary. */
+               if (in_syscall) {
+                       /* Check the return code */
+                       switch (regs->gr[28]) {
+                       case -ERESTARTNOHAND:
+#if DEBUG_SIG
+                               printk("ERESTARTNOHAND: returning -EINTR\n");
+#endif
+                               regs->gr[28] = -EINTR;
+                               break;
+
+                       case -ERESTARTSYS:
+                               if (!(ka->sa.sa_flags & SA_RESTART)) {
+#if DEBUG_SIG
+                                       printk("ERESTARTSYS: putting -EINTR\n");
+#endif
+                                       regs->gr[28] = -EINTR;
+                                       break;
+                               }
+                       /* fallthrough */
+                       case -ERESTARTNOINTR:
+                               /* A syscall is just a branch, so all
+                                   we have to do is fiddle the return
+                                   pointer. */
+                               regs->gr[31] -= 8; /* delayed branching */
+                               /* Preserve original r28. */
+                               regs->gr[28] = regs->orig_r28;
+                               break;
+                       }
+               }
+               /* Whee!  Actually deliver the signal.  If the
+                  delivery failed, we need to continue to iterate in
+                  this loop so we can deliver the SIGSEGV... */
+               if (handle_signal(signr, ka, &info, oldset, regs, in_syscall)) {
+#if DEBUG_SIG
+                       printk("Exiting do_signal (success), regs->gr[28] = %ld\n", regs->gr[28]);
+#endif
+                       return 1;
+               }
+       }
+
+       /* Did we come from a system call? */
+       if (in_syscall) {
+               /* Restart the system call - no handlers present */
+               if (regs->gr[28] == -ERESTARTNOHAND ||
+                   regs->gr[28] == -ERESTARTSYS ||
+                   regs->gr[28] == -ERESTARTNOINTR) {
+                       /* Hooray for delayed branching.  We don't
+                           have to restore %r20 (the system call
+                           number) because it gets loaded in the delay
+                           slot of the branch external instruction. */
+                       regs->gr[31] -= 8;
+                       /* Preserve original r28. */
+                       regs->gr[28] = regs->orig_r28;
+               }
+       }
+#if DEBUG_SIG
+       printk("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", regs->gr[28]);
+#endif
+       return 0;
+}
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
new file mode 100644 (file)
index 0000000..85aca70
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * linux/arch/parisc/kernel/sys_parisc.c
+ *
+ * this implements the missing syscalls.
+ */
+
+#include <asm/uaccess.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/smp_lock.h>
+
+/* for some reason, "old_readdir" is the only syscall which does not begin
+ * with "sys_", which breaks the ENTRY_* macros in syscall.S so I "fixed"
+ * it here.
+ */
+
+int sys_old_readdir(unsigned int fd, void *dirent, unsigned int count)
+{
+    return old_readdir(fd, dirent, count);
+}
+
+int sys_pipe(int *fildes)
+{
+       int fd[2];
+       int error;
+
+       lock_kernel();
+       error = do_pipe(fd);
+       unlock_kernel();
+       if (!error) {
+               if (copy_to_user(fildes, fd, 2*sizeof(int)))
+                       error = -EFAULT;
+       }
+       return error;
+}
+
+int sys_pause(void)
+{
+       current->state = TASK_INTERRUPTIBLE;
+       schedule();
+       return -ERESTARTNOHAND;
+}
+
+int sys_mmap(unsigned long addr, unsigned long len,
+               unsigned long prot, unsigned long flags, unsigned long fd,
+               unsigned long offset)
+{
+       struct file * file = NULL;
+       int error;
+
+       down(&current->mm->mmap_sem);
+       lock_kernel();
+       if (!(flags & MAP_ANONYMOUS)) {
+               error = -EBADF;
+               file = fget(fd);
+               if (!file)
+                       goto out;
+       }
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+       error = do_mmap(file, addr, len, prot, flags, offset);
+       if (file != NULL)
+               fput(file);
+out:
+       unlock_kernel();
+       up(&current->mm->mmap_sem);
+       return error;
+}
+
+int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+       return -ENOSYS;
+}
+
+long sys_shmat_wrapper(int shmid, void *shmaddr, int shmflag)
+{
+       extern int sys_shmat(int shmid, char *shmaddr, int shmflg,
+                            unsigned long * raddr);
+       unsigned long raddr;
+       int r;
+
+       r = sys_shmat(shmid, shmaddr, shmflag, &raddr);
+       if (r < 0)
+               return r;
+       return raddr;
+}
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
new file mode 100644 (file)
index 0000000..bfa7574
--- /dev/null
@@ -0,0 +1,563 @@
+/* 
+ * Linux/PARISC Project (http://www.thepuffingroup.com/parisc)
+ * 
+ * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>
+ * Licensed under the GNU GPL.
+ * thanks to Philipp Rumpf, Mike Shaver and various others
+ * sorry about the wall, puffin..
+ */
+
+#include <asm/offset.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/psw.h>
+
+#define __ASSEMBLY__
+#include <asm/assembly.h>
+#include <asm/processor.h>
+#include <linux/version.h>
+
+#ifdef __LP64__
+       .level          2.0w
+#else
+       .level          1.1
+#endif
+       .text
+       
+       .import syscall_exit,code
+       .import syscall_exit_rfi,code
+       .export linux_gateway_page
+
+       /* Linux gateway page is aliased to virtual page 0 in the kernel
+        * address space. Since it is a gateway page it cannot be
+        * dereferenced, so null pointers will still fault. We start
+        * the actual entry point at 0x100. We put break instructions
+        * at the beginning of the page to trap null indirect function
+        * pointers.
+        */
+
+       .align 4096
+linux_gateway_page:
+
+       break   0,0
+
+       .align 256
+linux_gateway_entry:
+       mfsp    %sr7,%r1                        /* we must set sr3 to the space */
+       mtsp    %r1,%sr3                        /* of the user before the gate */
+       gate    .+8, %r0                        /* become privileged */
+       mtsp    %r0,%sr4                        /* get kernel space into sr4 */
+       mtsp    %r0,%sr5                        /* get kernel space into sr5 */
+       mtsp    %r0,%sr6                        /* get kernel space into sr6 */
+       mtsp    %r0,%sr7                        /* get kernel space into sr7 */
+#ifdef __LP64__
+       /* for now we can *always* set the W bit on entry to the syscall
+        * since we don't support wide userland processes.  We could
+        * also save the current SM other than in r0 and restore it on
+        * exit from the syscall, and also use that value to know
+        * whether to do narrow or wide syscalls. -PB
+        */
+       ssm     PSW_SM_W, %r0
+#endif
+       mtctl   %r28,%cr27
+       rsm     PSW_I, %r28                     /* no ints for a bit  */
+       mfctl   %cr30,%r1                       /* get the kernel task ptr */
+       mtctl   %r0,%cr30                       /* zero it (flag) */
+
+       /* Save some registers for sigcontext and potential task
+          switch (see entry.S for the details of which ones are
+          saved/restored) */
+       STREG   %r2,  TASK_PT_GR2(%r1)          /* preserve rp */
+       STREG   %r19, TASK_PT_GR19(%r1)
+       STREG   %r20, TASK_PT_GR20(%r1)
+       STREG   %r21, TASK_PT_GR21(%r1)
+       STREG   %r22, TASK_PT_GR22(%r1)
+       STREG   %r23, TASK_PT_GR23(%r1)         /* 4th argument */
+       STREG   %r24, TASK_PT_GR24(%r1)         /* 3rd argument */
+       STREG   %r25, TASK_PT_GR25(%r1)         /* 2nd argument */
+       STREG   %r26, TASK_PT_GR26(%r1)         /* 1st argument */
+       STREG   %r27, TASK_PT_GR27(%r1)         /* user dp */
+       mfctl   %cr27,%r19
+       STREG   %r19, TASK_PT_GR28(%r1)         /* return value 0 */
+       STREG   %r19, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
+       STREG   %r29, TASK_PT_GR29(%r1)         /* return value 1 */
+       STREG   %r30, TASK_PT_GR30(%r1)         /* preserve userspace sp */
+       STREG   %r31, TASK_PT_GR31(%r1)         /* preserve syscall return ptr */
+       
+       ldo     TASK_PT_FR0(%r1), %r27          /* save fpregs from the kernel */
+       save_fp %r27                            /* or potential task switch  */
+
+       mfctl   %cr11, %r27                     /* i.e. SAR */
+       STREG   %r27, TASK_PT_SAR(%r1)
+
+       loadgp
+
+       ldo     TASK_SZ_ALGN+64(%r1),%r30       /* set up kernel stack */
+
+#ifndef __LP64__
+       /* no need to save these on stack because in wide mode the first 8
+        * args are passed in registers */
+       stw     %r22, -52(%r30)                 /* 5th argument */
+       stw     %r21, -56(%r30)                 /* 6th argument */
+#endif
+
+       /* for some unknown reason, task_struct.ptrace is an unsigned long so use LDREG */
+       LDREG   TASK_PTRACE(%r1), %r19          /* Are we being ptraced? */
+       mtsm    %r28                            /* irqs back  */
+
+       bb,<,n  %r19, 31, .Ltracesys            /* must match PT_PTRACE bit */
+       
+       /* Note!  We cannot use the syscall table that is mapped
+       nearby since the gateway page is mapped execute-only. */
+
+       ldil    L%sys_call_table, %r1
+       ldo     R%sys_call_table(%r1), %r19
+       LDIL_FIXUP(%r19)
+       
+       comiclr,>>=     __NR_Linux_syscalls, %r20, %r0
+       b,n     .Lsyscall_nosys
+       
+#ifdef __LP64__
+       ldd,s   %r20(%r19), %r19
+#else
+       ldwx,s  %r20(%r19), %r19
+#endif
+       /* If this is a sys_rt_sigreturn call, and the signal was received
+        * when not in_syscall, then we want to return via syscall_exit_rfi,
+        * not syscall_exit.  Signal no. in r20, in_syscall in r25 (see
+        * trampoline code in signal.c).
+        */
+       ldi     __NR_rt_sigreturn,%r2
+       comb,=  %r2,%r20,.Lrt_sigreturn
+.Lin_syscall:
+       ldil    L%syscall_exit,%r2
+       LDIL_FIXUP(%r2)
+       be      0(%sr7,%r19)
+       ldo     R%syscall_exit(%r2),%r2
+.Lrt_sigreturn:
+       comib,<> 0,%r25,.Lin_syscall
+       ldil    L%syscall_exit_rfi,%r2
+       LDIL_FIXUP(%r2)
+       be      0(%sr7,%r19)
+       ldo     R%syscall_exit_rfi(%r2),%r2
+
+       /* Note!  Because we are not running where we were linked, any
+       calls to functions external to this file must be indirect.  To
+       be safe, we apply the opposite rule to functions within this
+       file, with local labels given to them to ensure correctness. */
+       
+.Lsyscall_nosys:
+syscall_nosys:
+       ldil    L%syscall_exit,%r1
+       LDIL_FIXUP(%r1)
+       be      R%syscall_exit(%sr7,%r1)
+       ldo     -ENOSYS(%r0),%r28                  /* set errno */
+
+
+/* Warning! This trace code is a virtual duplicate of the code above so be
+ * sure to maintain both! */
+.Ltracesys:
+tracesys:
+       /* Need to save more registers so the debugger can see where we
+        * are.
+        */
+       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+       ssm     0,%r2                           /* Lower 8 bits only!! */
+       STREG   %r2,TASK_PT_PSW(%r1)
+       STREG   %r1,TASK_PT_CR30(%r1)
+       mfsp    %sr0,%r2
+       STREG   %r2,TASK_PT_SR0(%r1)
+       mfsp    %sr1,%r2
+       STREG   %r2,TASK_PT_SR1(%r1)
+       mfsp    %sr2,%r2
+       STREG   %r2,TASK_PT_SR2(%r1)
+       mfsp    %sr3,%r2
+       STREG   %r2,TASK_PT_SR3(%r1)
+       STREG   %r2,TASK_PT_SR4(%r1)
+       STREG   %r2,TASK_PT_SR5(%r1)
+       STREG   %r2,TASK_PT_SR6(%r1)
+       STREG   %r2,TASK_PT_SR7(%r1)
+       STREG   %r2,TASK_PT_IASQ0(%r1)
+       STREG   %r2,TASK_PT_IASQ1(%r1)
+       LDREG   TASK_PT_GR31(%r1),%r2
+       STREG   %r2,TASK_PT_IAOQ0(%r1)
+       ldo     4(%r2),%r2
+       STREG   %r2,TASK_PT_IAOQ1(%r1)
+       ldo     TASK_REGS(%r1),%r2
+       /* reg_save %r2 */
+       STREG   %r3,PT_GR3(%r2)
+       STREG   %r4,PT_GR4(%r2)
+       STREG   %r5,PT_GR5(%r2)
+       STREG   %r6,PT_GR6(%r2)
+       STREG   %r7,PT_GR7(%r2)
+       STREG   %r8,PT_GR8(%r2)
+       STREG   %r9,PT_GR9(%r2)
+       STREG   %r10,PT_GR10(%r2)
+       STREG   %r11,PT_GR11(%r2)
+       STREG   %r12,PT_GR12(%r2)
+       STREG   %r13,PT_GR13(%r2)
+       STREG   %r14,PT_GR14(%r2)
+       STREG   %r15,PT_GR15(%r2)
+       STREG   %r16,PT_GR16(%r2)
+       STREG   %r17,PT_GR17(%r2)
+       STREG   %r18,PT_GR18(%r2)
+       /* Finished saving things for the debugger */
+
+       ldil    L%syscall_trace,%r1
+       LDIL_FIXUP(%r1)
+       ldil    L%tracesys_next,%r2
+       LDIL_FIXUP(%r2)
+       be      R%syscall_trace(%sr7,%r1)
+       ldo     R%tracesys_next(%r2),%r2
+       
+tracesys_next: 
+       ldil    L%sys_call_table,%r1
+       LDIL_FIXUP(%r1)
+       ldo     R%sys_call_table(%r1), %r19
+
+       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+       LDREG   TASK_PT_GR20(%r1), %r20
+       LDREG   TASK_PT_GR26(%r1), %r26         /* Restore the users args */
+       LDREG   TASK_PT_GR25(%r1), %r25
+       LDREG   TASK_PT_GR24(%r1), %r24
+       LDREG   TASK_PT_GR23(%r1), %r23
+#ifdef __LP64__
+       LDREG   TASK_PT_GR22(%r1), %r22
+       LDREG   TASK_PT_GR21(%r1), %r21
+#endif
+
+       comiclr,>>=     __NR_Linux_syscalls, %r20, %r0
+       b,n     .Lsyscall_nosys
+
+#ifdef __LP64__
+       ldd,s   %r20(%r19), %r19
+#else
+       ldwx,s  %r20(%r19), %r19
+#endif
+       /* If this is a sys_rt_sigreturn call, and the signal was received
+        * when not in_syscall, then we want to return via syscall_exit_rfi,
+        * not syscall_exit.  Signal no. in r20, in_syscall in r25 (see
+        * trampoline code in signal.c).
+        */
+       ldi     __NR_rt_sigreturn,%r2
+       comb,=  %r2,%r20,.Ltrace_rt_sigreturn
+.Ltrace_in_syscall:
+       ldil    L%tracesys_exit,%r2
+       LDIL_FIXUP(%r2)
+       be      0(%sr7,%r19)
+       ldo     R%tracesys_exit(%r2),%r2
+
+       /* Do *not* call this function on the gateway page, because it
+       makes a direct call to syscall_trace. */
+       
+tracesys_exit:
+       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+       bl      syscall_trace, %r2
+       STREG   %r28,TASK_PT_GR28(%r1)          /* save return value now */
+       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+       LDREG   TASK_PT_GR28(%r1), %r28         /* Restore return val. */
+
+       ldil    L%syscall_exit,%r1
+       LDIL_FIXUP(%r1)
+       be,n    R%syscall_exit(%sr7,%r1)
+
+.Ltrace_rt_sigreturn:
+       comib,<> 0,%r25,.Ltrace_in_syscall
+       ldil    L%tracesys_sigexit,%r2
+       LDIL_FIXUP(%r2)
+       be      0(%sr7,%r19)
+       ldo     R%tracesys_sigexit(%r2),%r2
+
+tracesys_sigexit:
+       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+       bl      syscall_trace, %r2
+       nop
+
+       ldil    L%syscall_exit_rfi,%r1
+       LDIL_FIXUP(%r1)
+       be,n    R%syscall_exit_rfi(%sr7,%r1)
+
+#ifdef __LP64__
+/* Use ENTRY_SAME for 32-bit syscalls which are the same on wide and
+ * narrow palinux.  Use ENTRY_DIFF for those where a 32-bit specific
+ * implementation is required on wide palinux.
+ */
+#define ENTRY_SAME(_name_) .dword sys_##_name_
+#define ENTRY_DIFF(_name_) .dword sys32_##_name_
+#define ENTRY_UHOH(_name_) .dword sys32_unimplemented
+#else
+#define ENTRY_SAME(_name_) .word sys_##_name_
+#define ENTRY_DIFF(_name_) .word sys_##_name_
+#define ENTRY_UHOH(_name_) .word sys_##_name_
+#endif
+
+       .align 8
+       .export sys_call_table
+.Lsys_call_table:
+sys_call_table:
+       ENTRY_SAME(ni_syscall)  /* 0  -  old "setup()" system call*/
+       ENTRY_SAME(exit)
+       ENTRY_SAME(fork_wrapper)
+       ENTRY_SAME(read)
+       ENTRY_SAME(write)
+       ENTRY_SAME(open)                /* 5 */
+       ENTRY_SAME(close)
+       ENTRY_SAME(waitpid)
+       ENTRY_SAME(creat)
+       ENTRY_SAME(link)
+       ENTRY_SAME(unlink)              /* 10 */
+       ENTRY_DIFF(execve_wrapper)
+       ENTRY_SAME(chdir)
+       /* See comments in kernel/time.c!!! Maybe we don't need this? */
+       ENTRY_DIFF(time)
+       ENTRY_SAME(mknod)
+       ENTRY_SAME(chmod)               /* 15 */
+       ENTRY_SAME(lchown)
+       ENTRY_SAME(socket)
+       /* struct stat is MAYBE identical wide and narrow ?? */
+       ENTRY_DIFF(newstat)
+       ENTRY_SAME(lseek)
+       ENTRY_SAME(getpid)              /* 20 */
+       /* the 'void * data' parameter may need re-packing in wide */
+       ENTRY_DIFF(mount)
+       /* concerned about struct sockaddr in wide/narrow */
+       /* ---> I think sockaddr is OK unless the compiler packs the struct */
+       /*      differently to align the char array */
+       ENTRY_SAME(bind)
+       ENTRY_SAME(setuid)
+       ENTRY_SAME(getuid)
+       ENTRY_SAME(stime)               /* 25 */
+       ENTRY_SAME(ptrace)
+       ENTRY_SAME(alarm)
+       /* see stat comment */
+       ENTRY_DIFF(newfstat)
+       ENTRY_SAME(pause)
+       /* struct utimbuf uses time_t which might vary */
+       ENTRY_DIFF(utime)               /* 30 */
+       /* struct sockaddr... */
+       ENTRY_SAME(connect)
+       ENTRY_SAME(listen)
+       ENTRY_SAME(access)
+       ENTRY_SAME(nice)
+       /* struct sockaddr... */
+       ENTRY_SAME(accept)              /* 35 */
+       ENTRY_SAME(sync)
+       ENTRY_SAME(kill)
+       ENTRY_SAME(rename)
+       ENTRY_SAME(mkdir)
+       ENTRY_SAME(rmdir)               /* 40 */
+       ENTRY_SAME(dup)
+       ENTRY_SAME(pipe)
+       ENTRY_DIFF(times)
+       /* struct sockaddr... */
+       ENTRY_SAME(getsockname)
+       /* it seems possible brk() could return a >4G pointer... */
+       ENTRY_SAME(brk)         /* 45 */
+       ENTRY_SAME(setgid)
+       ENTRY_SAME(getgid)
+       ENTRY_SAME(signal)
+       ENTRY_SAME(geteuid)
+       ENTRY_SAME(getegid)             /* 50 */
+       ENTRY_SAME(acct)
+       ENTRY_SAME(umount)
+       /* struct sockaddr... */
+       ENTRY_SAME(getpeername)
+       /* This one's a huge ugly mess */
+       ENTRY_DIFF(ioctl)
+       /* struct flock? */
+       ENTRY_DIFF(fcntl)               /* 55 */
+       ENTRY_SAME(socketpair)
+       ENTRY_SAME(setpgid)
+       ENTRY_SAME(send)
+       ENTRY_SAME(newuname)
+       ENTRY_SAME(umask)               /* 60 */
+       ENTRY_SAME(chroot)
+       ENTRY_SAME(ustat)
+       ENTRY_SAME(dup2)
+       ENTRY_SAME(getppid)
+       ENTRY_SAME(getpgrp)             /* 65 */
+       ENTRY_SAME(setsid)
+       ENTRY_SAME(pivot_root)
+       /* I don't like this */
+       ENTRY_UHOH(sgetmask)
+       ENTRY_UHOH(ssetmask)
+       ENTRY_SAME(setreuid)    /* 70 */
+       ENTRY_SAME(setregid)
+       ENTRY_SAME(mincore)
+       ENTRY_DIFF(sigpending)
+       ENTRY_SAME(sethostname)
+       /* Following 3 have linux-common-code structs containing longs -( */
+       ENTRY_DIFF(setrlimit)   /* 75 */
+       ENTRY_DIFF(getrlimit)
+       ENTRY_DIFF(getrusage)
+       /* struct timeval and timezone are maybe?? consistent wide and narrow */
+       ENTRY_SAME(gettimeofday)
+       ENTRY_SAME(settimeofday)
+       ENTRY_SAME(getgroups)   /* 80 */
+       ENTRY_SAME(setgroups)
+       /* struct socketaddr... */
+       ENTRY_SAME(sendto)
+       ENTRY_SAME(symlink)
+       /* see stat comment */
+       ENTRY_DIFF(newlstat)
+       ENTRY_SAME(readlink)    /* 85 */
+       /* suspect we'll need some work for narrow shlibs on wide kernel */
+       ENTRY_UHOH(uselib)
+       ENTRY_SAME(swapon)
+       ENTRY_SAME(reboot)
+       /* argh! struct dirent contains a long */
+       ENTRY_UHOH(old_readdir)
+       /* I'm not certain about off_t... */
+       ENTRY_SAME(mmap)                /* 90 */
+       ENTRY_SAME(munmap)
+       ENTRY_SAME(truncate)
+       ENTRY_SAME(ftruncate)
+       ENTRY_SAME(fchmod)
+       ENTRY_SAME(fchown)              /* 95 */
+       ENTRY_SAME(getpriority)
+       ENTRY_SAME(setpriority)
+       ENTRY_SAME(recv)
+       ENTRY_DIFF(statfs)
+       ENTRY_DIFF(fstatfs)             /* 100 */
+       ENTRY_SAME(ni_syscall)
+       /* don't think hppa glibc even provides an entry pt for this
+        * so disable for now */
+       ENTRY_UHOH(socketcall)
+       ENTRY_SAME(syslog)
+       /* even though manpage says struct timeval contains longs, ours has
+        * time_t and suseconds_t -- both of which are safe wide/narrow */
+       ENTRY_SAME(setitimer)
+       ENTRY_SAME(getitimer)   /* 105 */
+       ENTRY_SAME(capget)
+       ENTRY_SAME(capset)
+       ENTRY_SAME(pread)
+       ENTRY_SAME(pwrite)
+       ENTRY_SAME(getcwd)              /* 110 */
+       ENTRY_SAME(vhangup)
+       ENTRY_SAME(ni_syscall)
+       ENTRY_SAME(vfork_wrapper)
+       /* struct rusage contains longs... */
+       ENTRY_DIFF(wait4)
+       ENTRY_SAME(swapoff)             /* 115 */
+       /* struct sysinfo contains longs */
+       ENTRY_SAME(sysinfo)
+       ENTRY_SAME(shutdown)
+       ENTRY_SAME(fsync)
+       ENTRY_SAME(madvise)
+       ENTRY_SAME(clone_wrapper)       /* 120 */
+       ENTRY_SAME(setdomainname)
+       ENTRY_SAME(sendfile)
+       /* struct sockaddr... */
+       ENTRY_SAME(recvfrom)
+       /* struct timex contains longs */
+       ENTRY_UHOH(adjtimex)
+       ENTRY_SAME(mprotect)    /* 125 */
+       /* old_sigset_t forced to 32 bits.  Beware glibc sigset_t */
+       ENTRY_DIFF(sigprocmask)
+       ENTRY_SAME(create_module)
+       /* struct module contains longs, but insmod builds a 64 bit struct
+        * if running under a 64 bit kernel */
+       ENTRY_SAME(init_module)
+       ENTRY_SAME(delete_module)
+       /* struct kernel_sym contains a long. Linus never heard of size_t? */
+       ENTRY_DIFF(get_kernel_syms)     /* 130 */
+       ENTRY_SAME(quotactl)
+       ENTRY_SAME(getpgid)
+       ENTRY_SAME(fchdir)
+       /* bdflush(func, addr) where func has least-significant-bit set means
+        * addr is a pointer to long :-( */
+       ENTRY_UHOH(bdflush)
+       ENTRY_SAME(sysfs)               /* 135 */
+       ENTRY_SAME(personality)
+       ENTRY_SAME(ni_syscall)  /* for afs_syscall */
+       ENTRY_SAME(setfsuid)
+       ENTRY_SAME(setfsgid)
+       /* I think this might work */
+       ENTRY_SAME(llseek)              /* 140 */
+       /* struct linux_dirent has longs, like 'unsigned long d_ino' which
+        * almost definitely should be 'ino_t d_ino' but it's too late now */
+       ENTRY_DIFF(getdents)
+       /* it is POSSIBLE that select will be OK because even though fd_set
+        * contains longs, the macros and sizes are clever. */
+       ENTRY_SAME(select)
+       ENTRY_SAME(flock)
+       ENTRY_SAME(msync)
+       /* struct iovec contains pointers */
+       ENTRY_UHOH(readv)               /* 145 */
+       ENTRY_UHOH(writev)
+       ENTRY_SAME(getsid)
+       ENTRY_SAME(fdatasync)
+       /* struct __sysctl_args is a mess */
+       ENTRY_DIFF(sysctl)
+       ENTRY_SAME(mlock)               /* 150 */
+       ENTRY_SAME(munlock)
+       ENTRY_SAME(mlockall)
+       ENTRY_SAME(munlockall)
+       /* struct sched_param is ok for now */
+       ENTRY_SAME(sched_setparam)
+       ENTRY_SAME(sched_getparam)      /* 155 */
+       ENTRY_SAME(sched_setscheduler)
+       ENTRY_SAME(sched_getscheduler)
+       ENTRY_SAME(sched_yield)
+       ENTRY_SAME(sched_get_priority_max)
+       ENTRY_SAME(sched_get_priority_min)      /* 160 */
+       /* These 2 would've worked if someone had defined struct timespec
+        * carefully, like timeval for example (which is about the same).
+        * Unfortunately it contains a long :-( */
+       ENTRY_DIFF(sched_rr_get_interval)
+       ENTRY_DIFF(nanosleep)
+       ENTRY_SAME(mremap)
+       ENTRY_SAME(setresuid)
+       ENTRY_SAME(getresuid)   /* 165 */
+       /* might work, but in general signals need a thorough review */
+       ENTRY_UHOH(sigaltstack_wrapper)
+       /* struct passed back to user can contain long symbol values */
+       ENTRY_DIFF(query_module)
+       ENTRY_SAME(poll)
+       /* structs contain pointers and an in_addr... */
+       ENTRY_UHOH(nfsservctl)
+       ENTRY_SAME(setresgid)   /* 170 */
+       ENTRY_SAME(getresgid)
+       ENTRY_SAME(prctl)
+       /* signals need a careful review */
+       ENTRY_SAME(rt_sigreturn_wrapper)
+       ENTRY_DIFF(rt_sigaction)
+       ENTRY_DIFF(rt_sigprocmask)      /* 175 */
+       ENTRY_DIFF(rt_sigpending)
+       ENTRY_UHOH(rt_sigtimedwait)
+       ENTRY_UHOH(rt_sigqueueinfo)
+       ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
+       ENTRY_SAME(chown)               /* 180 */
+       /* *sockopt() might work... */
+       ENTRY_SAME(setsockopt)
+       ENTRY_SAME(getsockopt)
+       /* struct msghdr contains pointers... */
+       ENTRY_UHOH(sendmsg)
+       ENTRY_UHOH(recvmsg)
+       ENTRY_SAME(semop)               /* 185 */
+       ENTRY_SAME(semget)
+       /* needs a more careful review */
+       ENTRY_UHOH(semctl)
+       /* struct msgbuf contains a long */
+       ENTRY_UHOH(msgsnd)
+       ENTRY_UHOH(msgrcv)
+       ENTRY_SAME(msgget)              /* 190 */
+       /* struct msqid_ds contains pointers */
+       ENTRY_UHOH(msgctl)
+       ENTRY_SAME(shmat_wrapper)
+       ENTRY_SAME(shmdt)
+       ENTRY_SAME(shmget)
+       /***************/
+       /* struct shmid_ds contains pointers */
+       ENTRY_UHOH(shmctl)              /* 195 */
+       ENTRY_SAME(ni_syscall)          /* streams1 */
+       ENTRY_SAME(ni_syscall)          /* streams2 */
+
+.end
+
+       /* Make sure nothing else is placed on this page */
+
+       .align 4096
+       .export end_linux_gateway_page
+end_linux_gateway_page:
+
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
new file mode 100644 (file)
index 0000000..c9d3e50
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *  linux/arch/arm/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *  Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King
+ *  Copyright (C) 1999 SuSE GmbH, (Philipp Rumpf, prumpf@tux.org)
+ *
+ * 1994-07-02  Alan Modra
+ *             fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
+ * 1998-12-20  Updated NTP code according to technical memorandum Jan '96
+ *             "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/param.h>
+#include <asm/pdc.h>
+#include <asm/led.h>
+
+#include <linux/timex.h>
+
+extern rwlock_t xtime_lock;
+
+static int timer_value;
+static int timer_delta;
+static struct pdc_tod tod_data __attribute__((aligned(8)));
+
+void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int old;
+       int lost = 0;
+       int cr16;
+       
+       old = timer_value;
+
+       cr16 = mfctl(16);
+       while((timer_value - cr16) < (timer_delta / 2)) {
+               timer_value += timer_delta;
+               lost++;
+       }
+
+       mtctl(timer_value ,16);
+
+       do_timer(regs);
+    
+       led_interrupt_func();
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+       unsigned long flags;
+       
+       read_lock_irqsave(&xtime_lock, flags);
+       tv->tv_sec = xtime.tv_sec;
+       tv->tv_usec = xtime.tv_usec;
+       read_unlock_irqrestore(&xtime_lock, flags);
+
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+       write_lock_irq(&xtime_lock);
+       xtime.tv_sec = tv->tv_sec;
+       xtime.tv_usec = tv->tv_usec;
+       write_unlock_irq(&xtime_lock);
+}
+
+void __init time_init(void)
+{
+       timer_delta = (100 * PAGE0->mem_10msec) / HZ;
+
+       /* make the first timer interrupt go off in one second */
+       timer_value = mfctl(16) + (HZ * timer_delta);
+       mtctl(timer_value, 16);
+
+
+       if(pdc_tod_read(&tod_data) == 0) {
+               xtime.tv_sec = tod_data.tod_sec;
+               xtime.tv_usec = tod_data.tod_usec;
+       } else {
+               printk(KERN_ERR "Error reading tod clock\n");
+               xtime.tv_sec = 0;
+               xtime.tv_usec = 0;
+       }
+
+}
+
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
new file mode 100644 (file)
index 0000000..b61591b
--- /dev/null
@@ -0,0 +1,896 @@
+/*
+ *  linux/arch/parisc/traps.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1999, 2000  Philipp Rumpf <prumpf@tux.org>
+ */
+
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'asm.s'.
+ */
+
+#include <linux/autoconf.h>    /* for CONFIG_KWDB */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#include <asm/smp.h>
+#include <asm/pdc.h>
+
+#ifdef CONFIG_KWDB
+#include <kdb/break.h>         /* for BI2_KGDB_GDB */
+#include <kdb/kgdb_types.h>    /* for __() */
+#include <kdb/save_state.h>    /* for struct save_state */
+#include <kdb/kgdb_machine.h>  /* for pt_regs_to_ssp and ssp_to_pt_regs */
+#include <kdb/trap.h>          /* for I_BRK_INST */
+#endif /* CONFIG_KWDB */
+
+
+static inline void console_verbose(void)
+{
+       extern int console_loglevel;
+       console_loglevel = 15;
+}
+
+
+void page_exception(void);
+
+/*
+ * These constants are for searching for possible module text
+ * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
+ * a guess of how much space is likely to be vmalloced.
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define MODULE_RANGE (8*1024*1024)
+
+int kstack_depth_to_print = 24;
+
+static void printbinary(unsigned long x, int nbits)
+{
+       unsigned long mask = 1UL << (nbits - 1);
+       while (mask != 0) {
+               printk(mask & x ? "1" : "0");
+               mask >>= 1;
+       }
+}
+
+void show_regs(struct pt_regs *regs)
+{
+       int i;
+#ifdef __LP64__
+#define RFMT " %016lx"
+#else
+#define RFMT " %08lx"
+#endif
+
+       printk("\n"); /* don't want to have that pretty register dump messed up */
+
+       printk("     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\nPSW: ");
+       printbinary(regs->gr[0], 32);
+       printk("\n");
+
+       for (i = 0; i < 32; i += 4) {
+               int j;
+               printk("r%d-%d\t", i, i + 3);
+               for (j = 0; j < 4; j++) {
+                       printk(RFMT, i + j == 0 ? 0 : regs->gr[i + j]);
+               }
+               printk("\n");
+       }
+
+       for (i = 0; i < 8; i += 4) {
+               int j;
+               printk("sr%d-%d\t", i, i + 4);
+               for (j = 0; j < 4; j++) {
+                       printk(RFMT, regs->sr[i + j]);
+               }
+               printk("\n");
+       }
+
+#if REDICULOUSLY_VERBOSE
+       for (i = 0; i < 32; i++) {
+               printk("FR%2d : %016lx  ", i, regs->fr[i]);
+               if ((i & 1) == 1)
+                       printk("\n");
+       }
+#endif
+
+       printk("\nIASQ:" RFMT RFMT " IAOQ:" RFMT RFMT "\n",
+              regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);
+       printk(" IIR: %08lx    ISR:" RFMT "  IOR:" RFMT "\nORIG_R28:" RFMT
+              "\n", regs->iir, regs->isr, regs->ior, regs->orig_r28);
+}
+
+void
+die_if_kernel (char *str, struct pt_regs *regs, long err)
+{
+       if (user_mode(regs)) {
+#if 1
+               if (err == 0)
+                       return; /* STFU */
+
+               /* XXX for debugging only */
+               printk ("!!die_if_kernel: %s(%d): %s %ld\n",
+                       current->comm, current->pid, str, err);
+               show_regs(regs);
+#endif
+               return;
+       }
+
+       printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
+
+       show_regs(regs);
+
+       /* Wot's wrong wif bein' racy? */
+       if (current->thread.flags & PARISC_KERNEL_DEATH) {
+               printk("die_if_kernel recursion detected.\n");
+               sti();
+               while (1);
+       }
+       current->thread.flags |= PARISC_KERNEL_DEATH;
+       do_exit(SIGSEGV);
+}
+
+asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code)
+{
+}
+
+asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
+{
+}
+
+#ifndef CONFIG_MATH_EMULATION
+
+asmlinkage void math_emulate(long arg)
+{
+}
+
+#endif /* CONFIG_MATH_EMULATION */
+
+int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs)
+{
+       return syscall(regs);
+}
+
+struct {
+       int retval;
+
+       int (*func) (void *, struct pt_regs *);
+       void * data;
+} ipi_action[NR_CPUS];
+
+void ipi_interrupt(int irq, void *unused, struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       if(!ipi_action[cpu].func)
+               BUG();
+
+       ipi_action[cpu].retval =
+               ipi_action[cpu].func(ipi_action[cpu].data, regs);
+}
+
+/* gdb uses break 4,8 */
+#define GDB_BREAK_INSN 0x10004
+void handle_gdb_break(struct pt_regs *regs, int wot)
+{
+       struct siginfo si;
+
+       si.si_code = wot;
+       si.si_addr = (void *) (regs->iaoq[0] & ~3);
+       si.si_signo = SIGTRAP;
+       si.si_errno = 0;
+       force_sig_info(SIGTRAP, &si, current);
+}
+
+void handle_break(unsigned iir, struct pt_regs *regs)
+{
+       struct siginfo si;
+#ifdef CONFIG_KWDB
+       struct save_state ssp;
+#endif /* CONFIG_KWDB */   
+
+       flush_all_caches();
+       switch(iir) {
+       case 0x00:
+               /* show registers, halt */
+               cli();
+               printk("break 0,0: pid=%d command='%s'\n",
+                      current->pid, current->comm);
+               die_if_kernel("Breakpoint", regs, 0);
+               show_regs(regs);
+               si.si_code = TRAP_BRKPT;
+               si.si_addr = (void *) (regs->iaoq[0] & ~3);
+               si.si_signo = SIGTRAP;
+               force_sig_info(SIGTRAP, &si, current);
+               break;
+
+       case GDB_BREAK_INSN:
+               die_if_kernel("Breakpoint", regs, 0);
+               handle_gdb_break(regs, TRAP_BRKPT);
+               break;
+
+#ifdef CONFIG_KWDB
+
+       case KGDB_BREAK_INSN:
+               mtctl(0, 15);
+               pt_regs_to_ssp(regs, &ssp);
+               kgdb_trap(I_BRK_INST, &ssp, 1);
+               ssp_to_pt_regs(&ssp, regs);
+               break;
+
+       case KGDB_INIT_BREAK_INSN:
+               mtctl(0, 15);
+               pt_regs_to_ssp(regs, &ssp);
+               kgdb_trap(I_BRK_INST, &ssp, 1);
+               ssp_to_pt_regs(&ssp, regs);
+
+               /* Advance pcoq to skip break */
+               regs->iaoq[0] = regs->iaoq[1];
+               regs->iaoq[1] += 4;
+               break;
+
+#endif /* CONFIG_KWDB */
+
+       default:
+               set_eiem(0);
+               printk("break %#08x: pid=%d command='%s'\n",
+                      iir, current->pid, current->comm);
+               show_regs(regs);
+               si.si_signo = SIGTRAP;
+               si.si_code = TRAP_BRKPT;
+               si.si_addr = (void *) (regs->iaoq[0] & ~3);
+               force_sig_info(SIGTRAP, &si, current);
+               return;
+       }
+}
+
+/* Format of the floating-point exception registers. */
+struct exc_reg {
+       unsigned int exception : 6;
+       unsigned int ei : 26;
+};
+
+/* Macros for grabbing bits of the instruction format from the 'ei'
+   field above. */
+/* Major opcode 0c and 0e */
+#define FP0CE_UID(i) (((i) >> 6) & 3)
+#define FP0CE_CLASS(i) (((i) >> 9) & 3)
+#define FP0CE_SUBOP(i) (((i) >> 13) & 7)
+#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
+#define FP0C_FORMAT(i) (((i) >> 11) & 3)
+#define FP0E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 0c, uid 2 (performance monitoring) */
+#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
+
+/* Major opcode 2e (fused operations).   */
+#define FP2E_SUBOP(i)  (((i) >> 5) & 1)
+#define FP2E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 26 (FMPYSUB) */
+/* Major opcode 06 (FMPYADD) */
+#define FPx6_FORMAT(i) ((i) & 0x1f)
+
+/* Flags and enable bits of the status word. */
+#define FPSW_FLAGS(w) ((w) >> 27)
+#define FPSW_ENABLE(w) ((w) & 0x1f)
+#define FPSW_V (1<<4)
+#define FPSW_Z (1<<3)
+#define FPSW_O (1<<2)
+#define FPSW_U (1<<1)
+#define FPSW_I (1<<0)
+
+/* Emulate a floating point instruction if necessary and possible
+   (this will be moved elsewhere eventually).  Return zero if
+   successful or if emulation was not required, -1 if the instruction
+   is actually illegal or unimplemented.  The status word passed as
+   the first parameter will be modified to signal exceptions, if
+   any. */
+
+/* FIXME!!!  This is really incomplete and, at the moment, most
+   illegal FP instructions will simply act as no-ops.  Obviously that
+   is *not* what we want.  Also we don't even try to handle exception
+   types other than the 'unimplemented' ones. */
+int
+fp_emul_insn(u32 *sw, struct exc_reg exc, struct pt_regs *regs)
+{
+       switch (exc.exception) {
+       case 0x3:  /* Unimplemented, opcode 06 */
+               break;
+       case 0x9:  /* Unimplemented, opcode 0c */
+               /* We do not support quadword operations, end of
+                   story.  There's no support for them in GCC. */
+               if (FP0C_FORMAT(exc.ei) == 3)
+                       return -1; /* SIGILL */
+               /* Fall through. */
+       case 0xa:  /* Unimplemented, opcode 0e */
+               if (FP0CE_CLASS(exc.ei) == 1) {
+                       /* FCNV instructions of various sorts. */
+               } else {
+                       if (FP0CE_CLASS(exc.ei == 0)
+                           && FP0CE_SUBOP(exc.ei == 5)) {
+                               /* FRND instructions should be
+                                   emulated, at some point, I
+                                   guess. */
+                               return -1; /* SIGILL */
+                       }
+               }
+               break;
+       case 0x23: /* Unimplemented, opcode 26 */
+               break;
+       case 0x2b: /* Unimplemented, opcode 2e */
+               break;
+       case 0x1:  /* Unimplemented, opcode 0e/0c */
+               /* FIXME: How the hell are we supposed to tell which
+                   opcode it is? */
+               break;
+       default:
+               return -1; /* Punt */
+       }
+
+       return 0;
+}
+
+/* Handle a floating point exception.  Return zero if the faulting
+   instruction can be completed successfully. */
+int
+handle_fpe(struct pt_regs *regs)
+{
+       struct siginfo si;
+       union {
+               struct fpsw {
+                       /* flag bits */
+                       unsigned int fv : 1;
+                       unsigned int fz : 1;
+                       unsigned int fo : 1;
+                       unsigned int fu : 1;
+                       unsigned int fi : 1;
+
+                       unsigned int c : 1;
+                       unsigned int pad1 : 4;
+                       unsigned int cq : 11;
+                       unsigned int rm : 2;
+                       unsigned int pad2 : 2;
+                       unsigned int t : 1;
+                       unsigned int d : 1;
+
+                       /* enable bits */
+                       unsigned int ev : 1;
+                       unsigned int ez : 1;
+                       unsigned int eo : 1;
+                       unsigned int eu : 1;
+                       unsigned int ei : 1;
+               } status;
+               u32 word;
+       } sw;
+       struct exc_reg excepts[7];
+       unsigned int code = 0;
+       unsigned int throw;
+
+       /* Status word = FR0L. */
+       memcpy(&sw, regs->fr, sizeof(sw));
+       /* Exception words = FR0R-FR3R. */
+       memcpy(excepts, ((char *) regs->fr) + 4, sizeof(excepts));
+
+       /* This is all CPU dependent.  Since there is no public
+           documentation on the PA2.0 processors we will just assume
+           everything is like the 7100/7100LC/7300LC for now.
+
+          Specifically: All exceptions are marked as "unimplemented"
+          in the exception word, and the only exception word used is
+          excepts[1]. */
+
+       /* Try to emulate the instruction.  Also determine if it is
+           really an illegal instruction in the process.
+
+          FIXME: fp_emul_insn() only checks for the "unimplemented"
+          exceptions at the moment.  So this may break horribly on
+          PA2.0, where we may want to also check to see if we should
+          just send SIGFPE (or maybe not, let's see the documentation
+          first...) */
+       if (fp_emul_insn(&sw.word, excepts[1], regs) == -1)
+               goto send_sigill;
+
+       /* Take the intersection of the flag bits in the FPSW and the
+           enable bits in the FPSW. */
+       throw = FPSW_FLAGS(sw.word) & FPSW_ENABLE(sw.word);
+
+       /* Concoct an appropriate si_code.  Of course we don't know
+           what to do if multiple exceptions were enabled and multiple
+           flags were set.  Maybe that's why HP/UX doesn't implement
+           feenableexcept(). */
+
+       if (throw == 0)
+               goto success; /* Duh. */
+       else if (throw & FPSW_V)
+               code = FPE_FLTINV;
+       else if (throw & FPSW_Z)
+               code = FPE_FLTDIV;
+       else if (throw & FPSW_O)
+               code = FPE_FLTOVF;
+       else if (throw & FPSW_U)
+               code = FPE_FLTUND;
+       else if (throw & FPSW_I)
+               code = FPE_FLTRES;
+
+#if 1 /* Debugging... */
+       printk("Unemulated floating point exception, pid=%d (%s)\n",
+              current->pid, current->comm);
+       show_regs(regs);
+       {
+               int i;
+               printk("FP Status: %08x\n", sw.word);
+               printk("FP Exceptions:\n");
+               for (i = 0; i < 7; i++) {
+                       printk("\tExcept%d: exception %03x insn %06x\n",
+                              i, excepts[i].exception, excepts[i].ei);
+               }
+       }
+#endif
+
+       /* FIXME: Should we clear the flag bits, T bit, and exception
+           registers here? */
+
+       si.si_signo = SIGFPE;
+       si.si_errno = 0;
+       si.si_code = code;
+       si.si_addr = (void *) regs->iaoq[0];
+       force_sig_info(SIGFPE, &si, current);
+       return -1;
+
+ send_sigill:
+       si.si_signo = SIGILL;
+       si.si_errno = 0;
+       si.si_code = ILL_COPROC;
+       si.si_addr = (void *) regs->iaoq[0];
+       force_sig_info(SIGILL, &si, current);
+       return -1;
+
+ success:
+       /* We absolutely have to clear the T bit and exception
+           registers to allow the process to recover.  Otherwise every
+           subsequent floating point instruction will trap. */
+       sw.status.t = 0;
+       memset(excepts, 0, sizeof(excepts));
+
+       memcpy(regs->fr, &sw, sizeof(sw));
+       memcpy(((char *) regs->fr) + 4,excepts , sizeof(excepts));
+       return 0;
+}
+
+int handle_toc(void)
+{
+       return 0;
+}
+
+void default_trap(int code, struct pt_regs *regs)
+{
+       printk("Trap %d on CPU %d\n", code, smp_processor_id());
+
+       show_regs(regs);
+}
+
+void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
+
+
+#ifdef CONFIG_KWDB
+int
+debug_call (void) {
+    printk ("Debug call.\n");
+    return 0;
+}
+
+int
+debug_call_leaf (void) {
+    return 0;
+}
+#endif /* CONFIG_KWDB */
+
+extern void do_page_fault(struct pt_regs *, int, unsigned long);
+extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long);
+extern void transfer_pim_to_trap_frame(struct pt_regs *);
+extern void pdc_console_restart(void);
+
+void handle_interruption(int code, struct pt_regs *regs)
+{
+       unsigned long fault_address = 0;
+       unsigned long fault_space = 0;
+       struct siginfo si;
+#ifdef CONFIG_KWDB
+       struct save_state ssp;
+#endif /* CONFIG_KWDB */   
+
+       if (code == 1)
+           pdc_console_restart();  /* switch back to pdc if HPMC */
+       else
+           sti();
+
+#ifdef __LP64__
+
+       /*
+        * FIXME:
+        * For 32 bit processes we don't want the b bits (bits 0 & 1)
+        * in the ior. This is more appropriately handled in the tlb
+        * miss handlers. Changes need to be made to support addresses
+        * >32 bits for 64 bit processes.
+        */
+
+       regs->ior &= 0x3FFFFFFFFFFFFFFFUL;
+#endif
+
+#if 0
+       printk("interrupted with code %d, regs %p\n", code, regs);
+       show_regs(regs);
+#endif
+
+       switch(code) {
+       case  1:
+               parisc_terminate("High Priority Machine Check (HPMC)",regs,code,0);
+               /* NOT REACHED */
+       case  3: /* Recovery counter trap */
+               regs->gr[0] &= ~PSW_R;
+               if (regs->iasq[0])
+                       handle_gdb_break(regs, TRAP_TRACE);
+               /* else this must be the start of a syscall - just let it
+                * run.
+                */
+               return;
+
+       case  5:
+               flush_all_caches();
+               cpu_lpmc(5, regs);
+               return;
+
+       case  6:
+               fault_address = regs->iaoq[0];
+               fault_space   = regs->iasq[0];
+               break;
+
+       case  9: /* Break Instruction */
+               handle_break(regs->iir,regs);
+               return;
+
+       case 14:
+               /* Assist Exception Trap, i.e. floating point exception. */
+               die_if_kernel("Floating point exception", regs, 0); /* quiet */
+               handle_fpe(regs);
+               return;
+       case 15:
+       case 16:  /* Non-Access TLB miss faulting address is in IOR */
+       case 17:
+       case 26:
+               fault_address = regs->ior;
+               fault_space   = regs->isr;
+
+               if (code == 26 && fault_space == 0)
+                   parisc_terminate("Data access rights fault in kernel",regs,code,fault_address);
+               break;
+
+       case 19:
+               regs->gr[0] |= PSW_X; /* So we can single-step over the trap */
+               /* fall thru */
+       case 21:
+               handle_gdb_break(regs, TRAP_HWBKPT);
+               return;
+
+       case 25: /* Taken branch trap */
+               regs->gr[0] &= ~PSW_T;
+               if (regs->iasq[0])
+                       handle_gdb_break(regs, TRAP_BRANCH);
+               /* else this must be the start of a syscall - just let it
+                * run.
+                */
+               return;
+
+#if 0 /* def CONFIG_KWDB */
+       case I_TAKEN_BR:        /* 25 */
+               mtctl(0, 15);
+               pt_regs_to_ssp(regs, &ssp);
+               kgdb_trap(I_TAKEN_BR, &ssp, 1);
+               ssp_to_pt_regs(&ssp, regs);
+               break;
+#endif /* CONFIG_KWDB */
+
+       case  8:
+               die_if_kernel("Illegal instruction", regs, code);
+               si.si_code = ILL_ILLOPC;
+               goto give_sigill;
+
+       case 10:
+               die_if_kernel("Priviledged operation - shouldn't happen!", regs, code);
+               si.si_code = ILL_PRVOPC;
+               goto give_sigill;
+       case 11:
+               die_if_kernel("Priviledged register - shouldn't happen!", regs, code);
+               si.si_code = ILL_PRVREG;
+       give_sigill:
+               si.si_signo = SIGILL;
+               si.si_errno = 0;
+               si.si_addr = (void *) regs->iaoq[0];
+               force_sig_info(SIGILL, &si, current);
+               return;
+
+       case 28:  /* Unaligned just causes SIGBUS for now */
+               die_if_kernel("Unaligned data reference", regs, code);
+               si.si_code = BUS_ADRALN;
+               si.si_signo = SIGBUS;
+               si.si_errno = 0;
+               si.si_addr = (void *) regs->ior;
+               force_sig_info(SIGBUS, &si, current);
+               return;
+
+       default:
+               if (user_mode(regs)) {
+                       printk("\nhandle_interruption() pid=%d command='%s'\n",
+                           current->pid, current->comm);
+                       show_regs(regs);
+                       /* SIGBUS, for lack of a better one. */
+                       si.si_signo = SIGBUS;
+                       si.si_code = BUS_OBJERR;
+                       si.si_errno = 0;
+                       si.si_addr = (void *) regs->ior;
+                       force_sig_info(SIGBUS, &si, current);
+                       return;
+               }
+               parisc_terminate("Unexpected Interruption!",regs,code,0);
+               /* NOT REACHED */
+       }
+
+       if (user_mode(regs)) {
+           if (fault_space != regs->sr[7]) {
+               if (fault_space == 0)
+                       printk("User Fault on Kernel Space ");
+               else /* this case should never happen, but whatever... */
+                       printk("User Fault (long pointer) ");
+               printk("pid=%d command='%s'\n", current->pid, current->comm);
+               show_regs(regs);
+               si.si_signo = SIGSEGV;
+               si.si_errno = 0;
+               si.si_code = SEGV_MAPERR;
+               si.si_addr = (void *) regs->ior;
+               force_sig_info(SIGSEGV, &si, current);
+               return;
+           }
+       }
+       else {
+
+           /*
+            * The kernel should never fault on its own address space.
+            */
+
+           if (fault_space == 0)
+                   parisc_terminate("Kernel Fault",regs,code,fault_address);
+       }
+
+#ifdef CONFIG_KWDB
+       debug_call_leaf ();
+#endif /* CONFIG_KWDB */
+
+       do_page_fault(regs, code, fault_address);
+
+       /*
+        * This should not be necessary.
+        * However, we do not currently
+        * implement flush_page_to_ram.
+        *
+        * The problem is that if we just
+        * brought in some code through the
+        * D-cache, the I-cache may not see
+        * it since it hasn't been flushed
+        * to ram.
+        */
+
+/*     flush_all_caches(); */
+
+#if 0
+       printk("returning %p\n", regs);
+/*     show_regs(regs); */
+#endif
+
+       return;
+
+}
+
+void show_stack(unsigned long sp)
+{
+#if 1
+       if ((sp & 0xc0000000UL) == 0xc0000000UL) {
+
+           __u32 *stackptr;
+           __u32 *dumpptr;
+
+           /* Stack Dump! */
+
+           stackptr = (__u32 *)sp;
+           dumpptr  = (__u32 *)(sp & ~(INIT_TASK_SIZE - 1));
+           printk("\nDumping Stack from %p to %p:\n",dumpptr,stackptr);
+           while (dumpptr < stackptr) {
+               printk("%04x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+                   ((__u32)dumpptr) & 0xffff,
+                   dumpptr[0], dumpptr[1], dumpptr[2], dumpptr[3],
+                   dumpptr[4], dumpptr[5], dumpptr[6], dumpptr[7]);
+               dumpptr += 8;
+           }
+       }
+#endif
+}
+
+
+void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset)
+{
+       set_eiem(0);
+       cli();
+
+       if (code == 1)
+           transfer_pim_to_trap_frame(regs);
+
+#if 1
+       show_stack(regs->gr[30]);
+#endif
+
+       printk("\n%s: Code=%d regs=%p (Addr=%08lx)\n",msg,code,regs,offset);
+       show_regs(regs);
+
+       for(;;)
+           ;
+}
+
+void transfer_pim_to_trap_frame(struct pt_regs *regs)
+{
+    register int i;
+    extern unsigned int hpmc_pim_data[];
+    struct pdc_hpmc_pim_11 *pim_narrow;
+    struct pdc_hpmc_pim_20 *pim_wide;
+
+    if (boot_cpu_data.cpu_type >= pcxu) {
+
+       pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;
+
+       /*
+        * Note: The following code will probably generate a
+        * bunch of truncation error warnings from the compiler.
+        * Could be handled with an ifdef, but perhaps there
+        * is a better way.
+        */
+
+       regs->gr[0] = pim_wide->cr[22];
+
+       for (i = 1; i < 32; i++)
+           regs->gr[i] = pim_wide->gr[i];
+
+       for (i = 0; i < 32; i++)
+           regs->fr[i] = pim_wide->fr[i];
+
+       for (i = 0; i < 8; i++)
+           regs->sr[i] = pim_wide->sr[i];
+
+       regs->iasq[0] = pim_wide->cr[17];
+       regs->iasq[1] = pim_wide->iasq_back;
+       regs->iaoq[0] = pim_wide->cr[18];
+       regs->iaoq[1] = pim_wide->iaoq_back;
+
+       regs->cr30 = pim_wide->cr[30];
+       regs->sar  = pim_wide->cr[11];
+       regs->iir  = pim_wide->cr[19];
+       regs->isr  = pim_wide->cr[20];
+       regs->ior  = pim_wide->cr[21];
+    }
+    else {
+       pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;
+
+       regs->gr[0] = pim_narrow->cr[22];
+
+       for (i = 1; i < 32; i++)
+           regs->gr[i] = pim_narrow->gr[i];
+
+       for (i = 0; i < 32; i++)
+           regs->fr[i] = pim_narrow->fr[i];
+
+       for (i = 0; i < 8; i++)
+           regs->sr[i] = pim_narrow->sr[i];
+
+       regs->iasq[0] = pim_narrow->cr[17];
+       regs->iasq[1] = pim_narrow->iasq_back;
+       regs->iaoq[0] = pim_narrow->cr[18];
+       regs->iaoq[1] = pim_narrow->iaoq_back;
+
+       regs->cr30 = pim_narrow->cr[30];
+       regs->sar  = pim_narrow->cr[11];
+       regs->iir  = pim_narrow->cr[19];
+       regs->isr  = pim_narrow->cr[20];
+       regs->ior  = pim_narrow->cr[21];
+    }
+
+    /*
+     * The following fields only have meaning if we came through
+     * another path. So just zero them here.
+     */
+
+    regs->ksp = 0;
+    regs->kpc = 0;
+    regs->orig_r28 = 0;
+}
+
+int __init check_ivt(void *iva)
+{
+       int i;
+       u32 check = 0;
+       u32 *ivap;
+       u32 *hpmcp;
+       u32 length;
+       extern void os_hpmc(void);
+       extern void os_hpmc_end(void);
+
+       if(strcmp((char *)iva, "cows can fly"))
+               return -1;
+
+       ivap = (u32 *)iva;
+
+       for (i = 0; i < 8; i++)
+           *ivap++ = 0;
+
+       /* Compute Checksum for HPMC handler */
+
+       length = (u32)((unsigned long)os_hpmc_end - (unsigned long)os_hpmc);
+       ivap[7] = length;
+
+       hpmcp = (u32 *)os_hpmc;
+
+       for(i=0; i<length/4; i++)
+           check += *hpmcp++;
+
+       for(i=0; i<8; i++)
+           check += ivap[i];
+
+       ivap[5] = -check;
+
+       return 0;
+}
+       
+#ifndef __LP64__
+extern const void fault_vector_11;
+#endif
+extern const void fault_vector_20;
+
+void __init trap_init(void)
+{
+       volatile long eiem;
+       void *iva;
+
+       printk("trap_init\n");
+       
+       if (boot_cpu_data.cpu_type >= pcxu)
+               iva = (void *) &fault_vector_20;
+       else
+#ifdef __LP64__
+               panic("Can't boot 64-bit OS on PA1.1 processor!");
+#else
+               iva = (void *) &fault_vector_11;
+#endif
+
+       if(check_ivt(iva))
+               panic("IVT invalid");
+
+       mtctl(0, 30);
+       mtctl(90000000, 16);
+       set_eiem(-1L);
+       mtctl(-1L, 23);
+       asm volatile ("rsm 0,%0" : "=r" (eiem));
+}
diff --git a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile
new file mode 100644 (file)
index 0000000..9f06706
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for parisc-specific library files..
+#
+
+
+L_TARGET = lib.a
+L_OBJS = lusercopy.o bitops.o checksum.o
+
+
+.S.o:
+       $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/parisc/lib/bitops.c b/arch/parisc/lib/bitops.c
new file mode 100644 (file)
index 0000000..37797ee
--- /dev/null
@@ -0,0 +1,59 @@
+/* atomic.c: atomic operations which got too long to be inlined all over
+ * the place.
+ * 
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+
+#ifdef CONFIG_SMP
+spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] = {
+       [0 ... (ATOMIC_HASH_SIZE-1)]  = SPIN_LOCK_UNLOCKED
+};
+#endif
+
+spinlock_t __atomic_lock = SPIN_LOCK_UNLOCKED;
+
+#ifndef __LP64__
+unsigned long __xchg(unsigned long x, unsigned long *ptr, int size)
+{
+       unsigned long temp, flags;
+
+       if (size != sizeof x) {
+               printk("__xchg called with bad pointer\n");
+       }
+       spin_lock_irqsave(&__atomic_lock, flags);
+       temp = *ptr;
+       *ptr = x;
+       spin_unlock_irqrestore(&__atomic_lock, flags);
+       return temp;
+}
+#else
+unsigned long __xchg(unsigned long x, unsigned long *ptr, int size)
+{
+       unsigned long temp, flags;
+       unsigned int *ptr32;
+
+       if (size == 8) {
+try_long:
+               spin_lock_irqsave(&__atomic_lock, flags);
+               temp = *ptr;
+               *ptr = x;
+               spin_unlock_irqrestore(&__atomic_lock, flags);
+               return temp;
+       }
+       if (size == 4) {
+               ptr32 = (unsigned int *)ptr;
+               spin_lock_irqsave(&__atomic_lock, flags);
+               temp = (unsigned long)*ptr32;
+               *ptr32 = (unsigned int)x;
+               spin_unlock_irqrestore(&__atomic_lock, flags);
+               return temp;
+       }
+
+       printk("__xchg called with bad pointer\n");
+       goto try_long;
+}
+#endif
diff --git a/arch/parisc/lib/checksum.c b/arch/parisc/lib/checksum.c
new file mode 100644 (file)
index 0000000..fa02027
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             MIPS specific IP/TCP/UDP checksumming routines
+ *
+ * Authors:    Ralf Baechle, <ralf@waldorf-gmbh.de>
+ *             Lots of code moved from tcp.c and ip.c; see those files
+ *             for more names.
+ *
+ *             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.
+ *
+ * $Id: checksum.c,v 1.3 1997/12/01 17:57:34 ralf Exp $
+ */
+#include <net/checksum.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+static inline unsigned short from32to16(unsigned int x)
+{
+       /* 32 bits --> 16 bits + carry */
+       x = (x & 0xffff) + (x >> 16);
+       /* 16 bits + carry --> 16 bits including carry */
+       x = (x & 0xffff) + (x >> 16);
+       return (unsigned short)x;
+}
+
+static inline unsigned int do_csum(const unsigned char * buff, int len)
+{
+       int odd, count;
+       unsigned int result = 0;
+
+       if (len <= 0)
+               goto out;
+       odd = 1 & (unsigned long) buff;
+       if (odd) {
+               result = be16_to_cpu(*buff);
+               len--;
+               buff++;
+       }
+       count = len >> 1;               /* nr of 16-bit words.. */
+       if (count) {
+               if (2 & (unsigned long) buff) {
+                       result += *(unsigned short *) buff;
+                       count--;
+                       len -= 2;
+                       buff += 2;
+               }
+               count >>= 1;            /* nr of 32-bit words.. */
+               if (count) {
+                       unsigned int carry = 0;
+                       do {
+                               unsigned int w = *(unsigned int *) buff;
+                               count--;
+                               buff += 4;
+                               result += carry;
+                               result += w;
+                               carry = (w > result);
+                       } while (count);
+                       result += carry;
+                       result = (result & 0xffff) + (result >> 16);
+               }
+               if (len & 2) {
+                       result += *(unsigned short *) buff;
+                       buff += 2;
+               }
+       }
+       if (len & 1)
+               result += le16_to_cpu(*buff);
+       result = from32to16(result);
+       if (odd)
+               result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+out:
+       return result;
+}
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
+{
+       unsigned int result = do_csum(buff, len);
+
+       /* add in old sum, and carry.. */
+       result += sum;
+       if(sum > result)
+               result += 1;
+       return result;
+}
+
+/*
+ * copy while checksumming, otherwise like csum_partial
+ */
+unsigned int csum_partial_copy(const char *src, char *dst, 
+                               int len, unsigned int sum)
+{
+       /*
+        * It's 2:30 am and I don't feel like doing it real ...
+        * This is lots slower than the real thing (tm)
+        */
+       sum = csum_partial(src, len, sum);
+       memcpy(dst, src, len);
+
+       return sum;
+}
+
+/*
+ * Copy from userspace and compute checksum.  If we catch an exception
+ * then zero the rest of the buffer.
+ */
+unsigned int csum_partial_copy_from_user (const char *src, char *dst,
+                                          int len, unsigned int sum,
+                                          int *err_ptr)
+{
+       int missing;
+
+       missing = copy_from_user(dst, src, len);
+       if (missing) {
+               memset(dst + len - missing, 0, missing);
+               *err_ptr = -EFAULT;
+       }
+               
+       return csum_partial(dst, len, sum);
+}
diff --git a/arch/parisc/lib/lusercopy.S b/arch/parisc/lib/lusercopy.S
new file mode 100644 (file)
index 0000000..b4b88b5
--- /dev/null
@@ -0,0 +1,242 @@
+/*------------------------------------------------------------------------------
+ * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+ *
+ * Assembly Language User Access Routines
+ *  Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * These routines still have plenty of room for optimization
+ * (word & doubleword load/store, dual issue, store hints, etc.).
+ */
+
+/*
+ * The following routines assume that space register 3 (sr3) contains
+ * the space id associated with the current users address space.
+ */
+
+
+       .level          1.1
+       .text
+       
+#include <asm/assembly.h>
+#include <asm/errno.h>
+
+       /*
+        * get_sr gets the appropriate space value into
+        * sr1 for kernel/user space access, depending
+        * on the flag stored in the task structure.
+        */
+
+       /* FIXME! depi below has hardcoded idea of kernel stack size */
+
+       .macro  get_sr
+       copy        %r30,%r1        ;! Get task structure
+       depi        0,31,14,%r1     ;! into r1
+       ldw         TASK_SEGMENT(%r1),%r22
+       mfsp        %sr3,%r1
+       or,<>       %r22,%r0,%r0
+       copy        %r0,%r1
+       mtsp        %r1,%sr1
+       .endm
+
+       /*
+        * unsigned long
+        * lcopy_to_user(void *to, const void *from, unsigned long n)
+        *
+        * Returns 0 for success.
+        * otherwise, returns number of bytes not transferred.
+        */
+
+       .export lcopy_to_user,code
+lcopy_to_user:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+       comib,=,n   0,%r24,$lctu_done
+       get_sr
+$lctu_loop:
+       ldbs,ma     1(%r25),%r1
+       addib,<>    -1,%r24,$lctu_loop
+1:      stbs,ma     %r1,1(%sr1,%r26)
+$lctu_done:
+       bv          %r0(%r2)
+       copy        %r24,%r28
+       .exit
+
+2:      b $lctu_done
+       ldo         1(%r24),%r24
+
+       .section __ex_table,"a"
+       .word       1b,(2b-1b)
+       .previous
+
+       .procend
+
+       /*
+        * unsigned long
+        * lcopy_from_user(void *to, const void *from, unsigned long n)
+        *
+        * Returns 0 for success.
+        * otherwise, returns number of bytes not transferred.
+        *
+        * NOTE: This routine will also zero any bytes in the
+        *       destination that were not copied due to a fault.
+        *
+        */
+
+       .export lcopy_from_user,code
+lcopy_from_user:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+       comib,=,n   0,%r24,$lcfu_done
+       get_sr
+$lcfu_loop:
+1:      ldbs,ma     1(%sr1,%r25),%r1
+       addib,<>    -1,%r24,$lcfu_loop
+       stbs,ma     %r1,1(%r26)
+$lcfu_done:
+       bv          %r0(%r2)
+       copy        %r24,%r28
+       .exit
+
+2:      copy        %r24,%r23
+$lcfu_zero_loop:
+       addib,<>    -1,%r23,$lcfu_zero_loop
+       stbs,ma     %r0,1(%r26)
+       b           $lcfu_done
+       nop
+
+       .section __ex_table,"a"
+       .word       1b,(2b-1b)
+       .previous
+
+       .procend
+
+       /*
+        * long lstrncpy_from_user(char *dst, const char *src, long n)
+        *
+        * Returns -EFAULT if exception before terminator,
+        *         N if the entire buffer filled,
+        *         otherwise strlen + 1 (i.e. includes zero byte)
+        */
+
+       .export lstrncpy_from_user,code
+lstrncpy_from_user:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+       comib,=     0,%r24,$lsfu_done
+       copy        %r26,%r23
+       get_sr
+1:      ldbs,ma     1(%sr1,%r25),%r1
+$lsfu_loop:
+       stbs,ma     %r1,1(%r26)
+       comib,=,n   0,%r1,$lsfu_done
+       addib,<>,n  -1,%r24,$lsfu_loop
+2:      ldbs,ma     1(%sr1,%r25),%r1
+$lsfu_done:
+       sub         %r26,%r23,%r28
+$lsfu_exit:
+       bv          %r0(%r2)
+       nop
+       .exit
+
+3:      b           $lsfu_exit
+       ldi         -EFAULT,%r28
+
+       .section __ex_table,"a"
+       .word       1b,(3b-1b)
+       .word       2b,(2b-1b)
+       .previous
+
+       .procend
+
+       /*
+        * unsigned long lclear_user(void *to, unsigned long n)
+        *
+        * Returns 0 for success.
+        * otherwise, returns number of bytes not transferred.
+        */
+
+       .export lclear_user,code
+lclear_user:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+       comib,=,n   0,%r25,$lclu_done
+       get_sr
+$lclu_loop:
+       addib,<>    -1,%r25,$lclu_loop
+1:      stbs,ma     %r0,1(%sr1,%r26)
+
+$lclu_done:
+       bv          %r0(%r2)
+       copy        %r25,%r28
+       .exit
+
+2:      b $lclu_done
+       ldo        1(%r25),%r25
+
+       .section __ex_table,"a"
+       .word       1b,(2b-1b)
+       .previous
+
+       .procend
+
+       /*
+        * long lstrnlen_user(char *s, long n)
+        *
+        * Returns 0 if exception before zero byte or reaching N,
+        *         N+1 if N would be exceeded,
+        *         else strlen + 1 (i.e. includes zero byte).
+        */
+
+       .export lstrnlen_user,code
+lstrnlen_user:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+       comib,=     0,%r25,$lslen_nzero
+       copy        %r26,%r24
+       get_sr
+1:      ldbs,ma     1(%sr1,%r26),%r1
+$lslen_loop:
+       comib,=,n   0,%r1,$lslen_done
+       addib,<>    -1,%r25,$lslen_loop
+2:      ldbs,ma     1(%sr1,%r26),%r1
+$lslen_done:
+       bv          %r0(%r2)
+       sub         %r26,%r24,%r28
+       .exit
+
+$lslen_nzero:
+       b           $lslen_done
+       ldo         1(%r26),%r26 /* special case for N == 0 */
+
+3:      b           $lslen_done
+       copy        %r24,%r26    /* reset r26 so 0 is returned on fault */
+
+       .section __ex_table,"a"
+       .word       1b,(3b-1b)
+       .word       2b,(2b-1b)
+       .previous
+
+       .procend
+
+       .end
diff --git a/arch/parisc/mm/Makefile b/arch/parisc/mm/Makefile
new file mode 100644 (file)
index 0000000..819872a
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux parisc-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := mm.o
+O_OBJS  := init.o fault.o kmap.o extable.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/parisc/mm/extable.c b/arch/parisc/mm/extable.c
new file mode 100644 (file)
index 0000000..7056889
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Kernel exception handling table support.  Derived from arch/i386/mm/extable.c.
+ *
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 John Marvin (jsm@fc.hp.com)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+#include <asm/uaccess.h>
+
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline const struct exception_table_entry *
+search_one_table (const struct exception_table_entry *first,
+                 const struct exception_table_entry *last,
+                 unsigned long addr)
+{
+       /* Abort early if the search value is out of range.  */
+
+       if ((addr < first->addr) || (addr > last->addr))
+               return 0;
+
+        while (first <= last) {
+               const struct exception_table_entry *mid;
+               long diff;
+
+               mid = first + ((last - first)/2);
+               diff = mid->addr - addr;
+
+                if (diff == 0)
+                        return mid;
+                else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+
+        return 0;
+}
+
+const struct exception_table_entry *
+search_exception_table (unsigned long addr)
+{
+#ifndef CONFIG_MODULE
+       /* There is only the kernel to search.  */
+       return search_one_table(__start___ex_table, 
+                                __stop___ex_table - 1, 
+                                addr);
+#else
+       struct exception_table_entry *ret;
+       /* The kernel is the last "module" -- no need to treat it special. */
+       struct module *mp;
+
+       for (mp = module_list; mp ; mp = mp->next) {
+               if (!mp->ex_table_start)
+                       continue;
+               ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1,
+                                      addr);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+#endif
+}
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
new file mode 100644 (file)
index 0000000..68d4614
--- /dev/null
@@ -0,0 +1,283 @@
+/* $Id: fault.c,v 1.5 2000/01/26 16:20:29 jsm Exp $
+ *
+ * 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) 1995, 1996, 1997, 1998 by Ralf Baechle
+ * Copyright 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org)
+ * Copyright 1999 Hewlett Packard Co.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include <asm/uaccess.h>
+
+
+/* Defines for parisc_acctyp() */
+#define READ           0
+#define WRITE          1
+
+/* Various important other fields */
+#define bit22set(x)            (x & 0x00000200)
+#define bits23_25set(x)                (x & 0x000001c0)
+#define isGraphicsFlushRead(x) ((x & 0xfc003fdf) == 0x04001a80)
+                               /* extended opcode is 0x6a */
+
+#define BITSSET                0x1c0   /* for identifying LDCW */
+
+/*
+ * parisc_acctyp(unsigned int inst) --
+ *    Given a PA-RISC memory access instruction, determine if the
+ *    the instruction would perform a memory read or memory write
+ *    operation.
+ *
+ *    This function assumes that the given instruction is a memory access
+ *    instruction (i.e. you should really only call it if you know that
+ *    the instruction has generated some sort of a memory access fault).
+ *
+ * Returns:
+ *   VM_READ  if read operation
+ *   VM_WRITE if write operation
+ *   VM_EXEC  if execute operation
+ */
+static unsigned long
+parisc_acctyp(unsigned long code, unsigned int inst)
+{
+       if (code == 6 || code == 16)
+           return VM_EXEC;
+
+       switch (inst & 0xf0000000) {
+       case 0x40000000: /* load */
+       case 0x50000000: /* new load */
+               return VM_READ;
+
+       case 0x60000000: /* store */
+       case 0x70000000: /* new store */
+               return VM_WRITE;
+
+       case 0x20000000: /* coproc */
+       case 0x30000000: /* coproc2 */
+               if (bit22set(inst))
+                       return VM_WRITE;
+
+       case 0x0: /* indexed/memory management */
+               if (bit22set(inst)) {
+                       /*
+                        * Check for the 'Graphics Flush Read' instruction.
+                        * It resembles an FDC instruction, except for bits
+                        * 20 and 21. Any combination other than zero will
+                        * utilize the block mover functionality on some
+                        * older PA-RISC platforms.  The case where a block
+                        * move is performed from VM to graphics IO space
+                        * should be treated as a READ.
+                        *
+                        * The significance of bits 20,21 in the FDC
+                        * instruction is:
+                        *
+                        *   00  Flush data cache (normal instruction behavior)
+                        *   01  Graphics flush write  (IO space -> VM)
+                        *   10  Graphics flush read   (VM -> IO space)
+                        *   11  Graphics flush read/write (VM <-> IO space)
+                        */
+                       if (isGraphicsFlushRead(inst))
+                               return VM_READ;
+                       return VM_WRITE;
+               } else {
+                       /*
+                        * Check for LDCWX and LDCWS (semaphore instructions).
+                        * If bits 23 through 25 are all 1's it is one of
+                        * the above two instructions and is a write.
+                        *
+                        * Note: With the limited bits we are looking at,
+                        * this will also catch PROBEW and PROBEWI. However,
+                        * these should never get in here because they don't
+                        * generate exceptions of the type:
+                        *   Data TLB miss fault/data page fault
+                        *   Data memory protection trap
+                        */
+                       if (bits23_25set(inst) == BITSSET)
+                               return VM_WRITE;
+               }
+               return VM_READ; /* Default */
+       }
+       return VM_READ; /* Default */
+}
+
+#undef bit22set
+#undef bits23_25set
+#undef isGraphicsFlushRead
+#undef BITSSET
+
+/* This is similar to expand_stack(), except that it is for stacks
+ * that grow upwards.
+ */
+
+static inline int expand_stackup(struct vm_area_struct * vma, unsigned long address)
+{
+       unsigned long grow;
+
+       address += 4 + PAGE_SIZE - 1;
+       address &= PAGE_MASK;
+       grow = (address - vma->vm_end) >> PAGE_SHIFT;
+       if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur ||
+           ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)
+               return -ENOMEM;
+       vma->vm_end = address;
+       vma->vm_mm->total_vm += grow;
+       if (vma->vm_flags & VM_LOCKED)
+               vma->vm_mm->locked_vm += grow;
+       return 0;
+}
+
+
+/* This is similar to find_vma(), except that it understands that stacks
+ * grow up rather than down.
+ * XXX Optimise by making use of cache and avl tree as per find_vma().
+ */
+
+struct vm_area_struct * pa_find_vma(struct mm_struct * mm, unsigned long addr)
+{
+       struct vm_area_struct *vma = NULL;
+
+       if (mm) {
+               vma = mm->mmap;
+               if (!vma || addr < vma->vm_start)
+                       return NULL;
+               while (vma->vm_next && addr >= vma->vm_next->vm_start)
+                       vma = vma->vm_next;
+       }
+       return vma;
+}
+
+
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long);
+
+void do_page_fault(struct pt_regs *regs, unsigned long code,
+                             unsigned long address)
+{
+       struct vm_area_struct * vma;
+       struct task_struct *tsk = current;
+       struct mm_struct *mm = tsk->mm;
+       const struct exception_table_entry *fix;
+       unsigned long acc_type;
+
+       if (in_interrupt() || !mm)
+               goto no_context;
+
+       down(&mm->mmap_sem);
+       vma = pa_find_vma(mm, address);
+       if (!vma)
+               goto bad_area;
+       if (address < vma->vm_end)
+               goto good_area;
+       if (!(vma->vm_flags & VM_GROWSUP) || expand_stackup(vma, address))
+               goto bad_area;
+/*
+ * Ok, we have a good vm_area for this memory access. We still need to
+ * check the access permissions.
+ */
+
+good_area:
+
+       acc_type = parisc_acctyp(code,regs->iir);
+
+       if ((vma->vm_flags & acc_type) != acc_type)
+               goto bad_area;
+
+       /*
+        * If for any reason at all we couldn't handle the fault, make
+        * sure we exit gracefully rather than endlessly redo the
+        * fault.
+        */
+
+       switch (handle_mm_fault(mm, vma, address, (acc_type & VM_WRITE) != 0)) {
+             case 1:
+               ++current->min_flt;
+               break;
+             case 2:
+               ++current->maj_flt;
+               break;
+             case 0:
+               /*
+                * We ran out of memory, or some other thing happened
+                * to us that made us unable to handle the page fault
+                * gracefully.
+                */
+               goto bad_area;
+             default:
+               goto out_of_memory;
+       }
+       up(&mm->mmap_sem);
+       return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ */
+bad_area:
+       up(&mm->mmap_sem);
+
+       if (user_mode(regs)) {
+               struct siginfo si;
+
+               printk("\ndo_page_fault() pid=%d command='%s'\n",
+                   tsk->pid, tsk->comm);
+               show_regs(regs);
+               /* FIXME: actually we need to get the signo and code correct */
+               si.si_signo = SIGSEGV;
+               si.si_errno = 0;
+               si.si_code = SEGV_MAPERR;
+               si.si_addr = (void *) address;
+               force_sig_info(SIGSEGV, &si, current);
+               return;
+       }
+
+no_context:
+
+       if (!user_mode(regs)) {
+
+               fix = search_exception_table(regs->iaoq[0]);
+
+               if (fix) {
+
+                       if (fix->skip & 1) 
+                               regs->gr[8] = -EFAULT;
+                       if (fix->skip & 2)
+                               regs->gr[9] = 0;
+
+                       regs->iaoq[0] += ((fix->skip) & ~3);
+
+                       /*
+                        * NOTE: In some cases the faulting instruction
+                        * may be in the delay slot of a branch. We
+                        * don't want to take the branch, so we don't
+                        * increment iaoq[1], instead we set it to be
+                        * iaoq[0]+4, and clear the B bit in the PSW
+                        */
+
+                       regs->iaoq[1] = regs->iaoq[0] + 4;
+                       regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */
+
+                       return;
+               }
+       }
+
+       parisc_terminate("Bad Address (null pointer deref?)",regs,code,address);
+
+  out_of_memory:
+       up(&mm->mmap_sem);
+       printk("VM: killing process %s\n", current->comm);
+       if (user_mode(regs))
+               do_exit(SIGKILL);
+       goto no_context;
+}
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
new file mode 100644 (file)
index 0000000..c3e16c4
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ *  linux/arch/parisc/mm/init.c
+ *
+ *  Copyright (C) 1995 Linus Torvalds
+ *  Copyright 1999 SuSE GmbH
+ *    changed by Philipp Rumpf
+ *  Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ *
+ */
+
+#include <linux/config.h>
+
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>         /* for hppa_dma_ops and pcxl_dma_ops */
+#include <linux/swap.h>
+#include <linux/unistd.h>
+
+#include <asm/pgalloc.h>
+
+static unsigned long totalram_pages;
+extern unsigned long max_pfn, mem_max;
+
+void free_initmem(void)  {
+}
+
+/*
+ * Just an arbitrary offset to serve as a "hole" between mapping areas
+ * (between top of physical memory and a potential pcxl dma mapping
+ * area, and below the vmalloc mapping area).
+ *
+ * The current 32K value just means that there will be a 32K "hole"
+ * between mapping areas. That means that  any out-of-bounds memory
+ * accesses will hopefully be caught. The vmalloc() routines leaves
+ * a hole of 4kB between each vmalloced area for the same reason.
+ */
+
+#define VM_MAP_OFFSET  (32*1024)
+#define SET_MAP_OFFSET(x) ((void *)(((unsigned long)(x) + VM_MAP_OFFSET) \
+                                    & ~(VM_MAP_OFFSET-1)))
+
+void *vmalloc_start;
+unsigned long pcxl_dma_start;
+
+void __init mem_init(void)
+{
+       max_mapnr = num_physpages = max_low_pfn;
+       high_memory = __va(max_low_pfn * PAGE_SIZE);
+
+       totalram_pages += free_all_bootmem();
+       printk("Memory: %luk available\n", totalram_pages << (PAGE_SHIFT-10));
+
+       if (hppa_dma_ops == &pcxl_dma_ops) {
+           pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(high_memory);
+           vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start + PCXL_DMA_MAP_SIZE);
+       }
+       else {
+           pcxl_dma_start = 0;
+           vmalloc_start = SET_MAP_OFFSET(high_memory);
+       }
+}
+
+void __bad_pgd(pgd_t *pgd)
+{
+       printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+       pgd_val(*pgd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+}
+
+void __bad_pmd(pmd_t *pmd)
+{
+       printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+       pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+       pte_t *pte;
+
+       pte = (pte_t *) __get_free_page(GFP_KERNEL);
+
+       if (pmd_none(*pmd)) {
+               if (pte) {
+                       clear_page(pte);
+                       pmd_val(*pmd) = _PAGE_TABLE + __pa((unsigned long)pte);
+                       return pte + offset;
+               }
+               pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+               return NULL;
+       }
+
+       free_page((unsigned long)pte);
+
+       if (pmd_bad(*pmd)) {
+               __bad_pmd(pmd);
+               return NULL;
+       }
+
+       return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+int do_check_pgt_cache(int low, int high)
+{
+       return 0;
+}
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving an inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+pte_t * __bad_pagetable(void)
+{
+       return (pte_t *) NULL;
+}
+
+unsigned long *empty_zero_page;
+unsigned long *empty_bad_page;
+
+pte_t __bad_page(void)
+{
+       return *(pte_t *)NULL;
+}
+
+void show_mem(void)
+{
+       int i,free = 0,total = 0,reserved = 0;
+       int shared = 0, cached = 0;
+
+       printk("Mem-info:\n");
+       show_free_areas();
+       printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+       i = max_mapnr;
+       while (i-- > 0) {
+               total++;
+               if (PageReserved(mem_map+i))
+                       reserved++;
+               else if (PageSwapCache(mem_map+i))
+                       cached++;
+               else if (!atomic_read(&mem_map[i].count))
+                       free++;
+               else
+                       shared += atomic_read(&mem_map[i].count) - 1;
+       }
+       printk("%d pages of RAM\n",total);
+       printk("%d reserved pages\n",reserved);
+       printk("%d pages shared\n",shared);
+       printk("%d pages swap cached\n",cached);
+       show_buffers();
+}
+
+void set_pte_phys (unsigned long vaddr, unsigned long phys)
+{
+}
+
+
+/*
+ * pagetable_init() sets up the page tables
+ *
+ * Note that gateway_init() places the Linux gateway page at page 0.
+ * Since gateway pages cannot be dereferenced this has the desirable
+ * side effect of trapping those pesky NULL-reference errors in the
+ * kernel.
+ */
+static void __init pagetable_init(void)
+{
+       pgd_t *pg_dir;
+       pmd_t *pmd;
+       pte_t *pg_table;
+       unsigned long tmp1;
+       unsigned long tmp2;
+       unsigned long address;
+       unsigned long ro_start;
+       unsigned long ro_end;
+       unsigned long fv_addr;
+       extern  const int stext;
+       extern  int data_start;
+       extern  const unsigned long fault_vector_20;
+
+       ro_start = __pa((unsigned long)&stext);
+       ro_end   = __pa((unsigned long)&data_start);
+       fv_addr  = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
+
+       printk("pagetable_init\n");
+
+       /* Map whole memory from PAGE_OFFSET */
+       pg_dir = (pgd_t *)swapper_pg_dir + USER_PGD_PTRS;
+
+       address = 0;
+       while (address < mem_max) {
+               /* XXX: BTLB should be done here */
+
+#if PTRS_PER_PMD == 1
+               pmd = (pmd_t *)__pa(pg_dir);
+#else
+               pmd = (pmd_t *) (PAGE_MASK & pgd_val(*pg_dir));
+
+               /*
+                * pmd is physical at this point
+                */
+
+               if (!pmd) {
+                       pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+                       pmd = (pmd_t *) __pa(pmd);
+               }
+
+               pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pmd;
+#endif
+               pg_dir++;
+
+               /* now change pmd to kernel virtual addresses */
+
+               pmd = (pmd_t *) __va(pmd);
+               for (tmp1 = 0 ; tmp1 < PTRS_PER_PMD ; tmp1++,pmd++) {
+
+                       /*
+                        * pg_table is physical at this point
+                        */
+
+                       pg_table = (pte_t *) (PAGE_MASK & pmd_val(*pmd));
+                       if (!pg_table) {
+                               pg_table = (pte_t *)
+                                       alloc_bootmem_low_pages(PAGE_SIZE);
+                               pg_table = (pte_t *) __pa(pg_table);
+                       }
+
+                       pmd_val(*pmd) = _PAGE_TABLE |
+                                          (unsigned long) pg_table;
+
+                       /* now change pg_table to kernel virtual addresses */
+
+                       pg_table = (pte_t *) __va(pg_table);
+                       for (tmp2=0; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
+                               pte_t pte;
+
+#if !defined(CONFIG_KWDB) && !defined(CONFIG_STI_CONSOLE)
+#warning STI console should explicitly allocate executable pages but does not
+/* KWDB needs to write kernel text when setting break points.
+**
+** The right thing to do seems like KWDB modify only the pte which
+** has a break point on it...otherwise we might mask worse bugs.
+*/
+                               if (address >= ro_start && address < ro_end
+                                                       && address != fv_addr)
+                                   pte = __mk_pte(address, PAGE_KERNEL_RO);
+                               else
+#endif
+                                   pte = __mk_pte(address, PAGE_KERNEL);
+
+                               if (address >= mem_max)
+                                       pte_val(pte) = 0;
+
+                               set_pte(pg_table, pte);
+
+                               address += PAGE_SIZE;
+                       }
+
+                       if (address >= mem_max)
+                           break;
+               }
+       }
+
+       empty_zero_page = alloc_bootmem_pages(PAGE_SIZE);
+       memset(empty_zero_page, 0, PAGE_SIZE);
+}
+
+unsigned long gateway_pgd_offset;
+unsigned long gateway_pgd_entry;
+
+static void __init gateway_init(void)
+{
+       unsigned long hpux_gateway_page_addr;
+       unsigned long linux_gateway_page_addr;
+       pgd_t *pg_dir;
+       pmd_t *pmd_base;
+       pmd_t *pmd;
+       pte_t *pg_table_base;
+       pte_t *pg_table;
+       /* FIXME: These are 'const' in order to trick the compiler
+           into not treating them as DP-relative data. */
+       extern void * const hpux_gateway_page;
+       extern void * const linux_gateway_page;
+       pte_t pte;
+
+       hpux_gateway_page_addr = HPUX_GATEWAY_ADDR & PAGE_MASK;
+       linux_gateway_page_addr = LINUX_GATEWAY_ADDR & PAGE_MASK;
+
+       gateway_pgd_offset = hpux_gateway_page_addr >> PGDIR_SHIFT;
+
+       /*
+        * Setup Linux Gateway page.
+        *
+        * The Linux gateway page will reside in kernel space (on virtual
+        * page 0), so it doesn't need to be aliased into user space.
+        */
+
+       pg_dir = (pgd_t *)swapper_pg_dir;
+
+#if PTRS_PER_PMD == 1
+       pmd_base = (pmd_t *)pg_dir;
+       pmd = pmd_base +
+               ((linux_gateway_page_addr) >> PGDIR_SHIFT);
+
+#else
+       pmd_base = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
+       pgd_val(*(pg_dir + (linux_gateway_page_addr >> PGDIR_SHIFT))) =
+               _PAGE_TABLE | __pa(pmd_base);
+
+       pmd = pmd_base +
+               ((linux_gateway_page_addr & (PMD_MASK) & (PGDIR_SIZE - 1)) >>
+                                                               PMD_SHIFT);
+#endif
+
+       pg_table_base = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
+
+       pmd_val(*pmd) = _PAGE_TABLE | __pa(pg_table_base);
+
+       pte = __mk_pte(__pa(&linux_gateway_page), PAGE_GATEWAY);
+
+       pg_table = pg_table_base +
+               ((linux_gateway_page_addr & (PAGE_MASK) & (PMD_SIZE - 1)) >>
+                                                               PAGE_SHIFT);
+
+       set_pte(pg_table,pte);
+
+       /*
+        * Setup HP-UX gateway page.
+        * This page will be aliased into each user address space.
+        */
+
+       pg_table_base = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
+
+       pte = __mk_pte(__pa(&hpux_gateway_page), PAGE_GATEWAY);
+       pg_table = pg_table_base +
+               ((hpux_gateway_page_addr & (PAGE_MASK) & (PMD_SIZE - 1)) >>
+                                                               PAGE_SHIFT);
+
+       set_pte(pg_table,pte);
+
+
+#if PTRS_PER_PMD == 1
+       pmd_base = (pmd_t *)pg_table_base;
+#else
+       pmd_base = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
+       pmd = pmd_base +
+               ((hpux_gateway_page_addr & (PMD_MASK) & (PGDIR_SIZE - 1)) >>
+                                                               PMD_SHIFT);
+       pmd_val(*pmd) = _PAGE_TABLE | __pa(pg_table_base);
+#endif
+
+       gateway_pgd_entry = _PAGE_TABLE | __pa(pmd_base);
+
+       /*
+        * We will be aliasing the HP-UX gateway page into all HP-UX
+        * user spaces at the same address (not counting the space register
+        * value) that will be equivalently mapped as long as space register
+        * hashing is disabled. It will be a problem if anyone touches
+        * the gateway pages at its "kernel" address, since that is
+        * NOT equivalently mapped. We'll flush the caches at this
+        * point, just in case some code has touched those addresses
+        * previous to this, but all bets are off if they get touched
+        * after this point.
+        */
+
+       flush_all_caches();
+
+       return;
+}
+
+void __init paging_init(void)
+{
+       pagetable_init();
+       gateway_init();
+
+       {
+               unsigned long zones_size[MAX_NR_ZONES] = { max_pfn/2, max_pfn/2, };
+
+               free_area_init(zones_size);
+       }
+}
+
+#define NR_SPACE_IDS   8192
+
+static unsigned long space_id[NR_SPACE_IDS / (8 * sizeof(long))];
+static unsigned long space_id_index;
+static unsigned long free_space_ids = NR_SPACE_IDS;
+
+/*
+ * XXX: We should probably unfold the set_bit / test_bit / clear_bit
+ * locking out of these two functions and have a single spinlock on the
+ * space_id data structures.
+ *
+ * Don't bother. This is all going to be significantly changed in the
+ * very near future.
+ */
+
+#define SPACEID_SHIFT (PAGE_SHIFT + (PT_NLEVELS)*(PAGE_SHIFT - PT_NLEVELS) - 32)
+
+unsigned long alloc_sid(void)
+{
+       unsigned long index;
+
+       if (free_space_ids == 0)
+               BUG();
+
+       free_space_ids--;
+
+       do {
+               index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index);
+       } while(test_and_set_bit(index, space_id));
+
+       space_id_index = index;
+
+       return index << SPACEID_SHIFT;
+}
+
+void free_sid(unsigned long spaceid)
+{
+       unsigned long index = spaceid >> SPACEID_SHIFT;
+       if (index < 0)
+               BUG();
+
+       clear_bit(index, space_id);
+
+       if (space_id_index > index) {
+               space_id_index = index;
+       }
+       free_space_ids++;
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+#if 0
+       for (; start < end; start += PAGE_SIZE) {
+               ClearPageReserved(mem_map + MAP_NR(start));
+               set_page_count(mem_map+MAP_NR(start), 1);
+               free_page(start);
+               totalram_pages++;
+       }
+       printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+#endif
+}
+#endif
+
+void si_meminfo(struct sysinfo *val)
+{
+       int i;
+
+       i = max_mapnr;
+       val->totalram = totalram_pages;
+       val->sharedram = 0;
+       val->freeram = nr_free_pages();
+       val->bufferram = atomic_read(&buffermem_pages);
+#if 0
+       while (i-- > 0)  {
+               if (PageReserved(mem_map+i))
+                       continue;
+               val->totalram++;
+               if (!atomic_read(&mem_map[i].count))
+                       continue;
+               val->sharedram += atomic_read(&mem_map[i].count) - 1;
+       }
+       val->totalram <<= PAGE_SHIFT;
+       val->sharedram <<= PAGE_SHIFT;
+#endif
+       val->totalhigh = 0;
+       val->freehigh = 0;
+       return;
+}
diff --git a/arch/parisc/mm/kmap.c b/arch/parisc/mm/kmap.c
new file mode 100644 (file)
index 0000000..686d540
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+** Stolen mostly from arch/parisc/kernel/pci-dma.c
+*/
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+
+#include <asm/io.h>
+#include <asm/page.h>          /* get_order */
+
+#undef flush_cache_all
+#define flush_cache_all flush_all_caches
+
+typedef void (*pte_iterator_t) (pte_t * pte, unsigned long arg);
+
+#if 0
+/* XXX This routine could be used with iterate_page() to replace
+ * unmap_uncached_page() and save a little code space but I didn't
+ * do that since I'm not certain whether this is the right path. -PB
+ */
+static void unmap_cached_pte(pte_t * pte, unsigned long arg)
+{
+       pte_t page = *pte;
+       pte_clear(pte);
+       if (!pte_none(page)) {
+               if (pte_present(page)) {
+                       unsigned long map_nr = pte_pagenr(page);
+                       if (map_nr < max_mapnr)
+                               __free_page(mem_map + map_nr);
+               } else {
+                       printk(KERN_CRIT
+                              "Whee.. Swapped out page in kernel page table\n");
+               }
+       }
+}
+#endif
+
+/* These two routines should probably check a few things... */
+static void set_uncached(pte_t * pte, unsigned long arg)
+{
+       pte_val(*pte) |= _PAGE_NO_CACHE;
+}
+
+static void set_cached(pte_t * pte, unsigned long arg)
+{
+       pte_val(*pte) &= ~_PAGE_NO_CACHE;
+}
+
+static inline void iterate_pte(pmd_t * pmd, unsigned long address,
+                              unsigned long size, pte_iterator_t op,
+                              unsigned long arg)
+{
+       pte_t *pte;
+       unsigned long end;
+
+       if (pmd_none(*pmd))
+               return;
+       if (pmd_bad(*pmd)) {
+               pmd_ERROR(*pmd);
+               pmd_clear(pmd);
+               return;
+       }
+       pte = pte_offset(pmd, address);
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       do {
+               op(pte, arg);
+               address += PAGE_SIZE;
+               pte++;
+       } while (address < end);
+}
+
+static inline void iterate_pmd(pgd_t * dir, unsigned long address,
+                              unsigned long size, pte_iterator_t op,
+                              unsigned long arg)
+{
+       pmd_t *pmd;
+       unsigned long end;
+
+       if (pgd_none(*dir))
+               return;
+       if (pgd_bad(*dir)) {
+               pgd_ERROR(*dir);
+               pgd_clear(dir);
+               return;
+       }
+       pmd = pmd_offset(dir, address);
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       do {
+               iterate_pte(pmd, address, end - address, op, arg);
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address < end);
+}
+
+static void iterate_pages(unsigned long address, unsigned long size,
+                         pte_iterator_t op, unsigned long arg)
+{
+       pgd_t *dir;
+       unsigned long end = address + size;
+
+       dir = pgd_offset_k(address);
+       flush_cache_all();
+       do {
+               iterate_pmd(dir, address, end - address, op, arg);
+               address = (address + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
+       } while (address && (address < end));
+       flush_tlb_all();
+}
+
+void
+kernel_set_cachemode(unsigned long vaddr, unsigned long size, int what)
+{
+       switch (what) {
+       case IOMAP_FULL_CACHING:
+               iterate_pages(vaddr, size, set_cached, 0);
+               flush_tlb_range(&init_mm, vaddr, size);
+               break;
+       case IOMAP_NOCACHE_SER:
+               iterate_pages(vaddr, size, set_uncached, 0);
+               flush_tlb_range(&init_mm, vaddr, size);
+               break;
+       default:
+               printk(KERN_CRIT
+                      "kernel_set_cachemode mode %d not understood\n",
+                      what);
+               break;
+       }
+}
diff --git a/arch/parisc/mm/pa11.c b/arch/parisc/mm/pa11.c
new file mode 100644 (file)
index 0000000..42f0d57
--- /dev/null
@@ -0,0 +1,170 @@
+/* $Id: pa11.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $
+ *
+ * pa11.c: PA 1.1 specific mmu/cache code.
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/sgialib.h>
+#include <asm/mmu_context.h>
+
+extern unsigned long mips_tlb_entries;
+
+/* page functions */
+void pa11_clear_page(unsigned long page)
+{
+}
+
+static void pa11_copy_page(unsigned long to, unsigned long from)
+{
+}
+
+/* Cache operations. */
+static inline void pa11_flush_cache_all(void) { }
+static void pa11_flush_cache_mm(struct mm_struct *mm) { }
+static void pa11_flush_cache_range(struct mm_struct *mm,
+                                   unsigned long start,
+                                   unsigned long end)
+{
+}
+
+static void pa11_flush_cache_page(struct vm_area_struct *vma,
+                                  unsigned long page)
+{
+}
+
+static void pa11_flush_page_to_ram(unsigned long page)
+{
+}
+
+static void pa11_flush_cache_sigtramp(unsigned long page)
+{
+}
+
+/* TLB operations. */
+static inline void pa11_flush_tlb_all(void)
+{
+       unsigned long flags;
+       int entry;
+
+       save_and_cli(flags);
+/* Here we will need to flush all the TLBs */
+       restore_flags(flags);
+}
+
+static void pa11_flush_tlb_mm(struct mm_struct *mm)
+{
+/* This is what the MIPS does..  Is it the right thing for PA-RISC? */
+       if(mm == current->mm)
+               pa11_flush_tlb_all();
+}
+
+static void pa11_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+                                 unsigned long end)
+{
+       if(mm == current->mm)
+               pa11_flush_tlb_all();
+}
+
+static void pa11_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+       if(vma->vm_mm == current->mm)
+               pa11_flush_tlb_all();
+}
+
+static void pa11_load_pgd(unsigned long pg_dir)
+{
+       unsigned long flags;
+    /* We need to do the right thing here */
+}
+
+/*
+ * Initialize new page directory with pointers to invalid ptes
+ */
+static void pa11_pgd_init(unsigned long page)
+{
+       unsigned long dummy1, dummy2;
+
+}
+
+static void pa11_update_mmu_cache(struct vm_area_struct * vma,
+                                  unsigned long address, pte_t pte)
+{
+       pa11_flush_tlb_page(vma, address);
+}
+
+static void pa11_show_regs(struct pt_regs * regs)
+{
+       /*
+        * Saved main processor registers
+        */
+       printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2],
+              (unsigned long) regs->regs[3], (unsigned long) regs->regs[4],
+              (unsigned long) regs->regs[5], (unsigned long) regs->regs[6],
+              (unsigned long) regs->regs[7]);
+       printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              (unsigned long) regs->regs[8], (unsigned long) regs->regs[9],
+              (unsigned long) regs->regs[10], (unsigned long) regs->regs[11],
+               (unsigned long) regs->regs[12], (unsigned long) regs->regs[13],
+              (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]);
+       printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              (unsigned long) regs->regs[16], (unsigned long) regs->regs[17],
+              (unsigned long) regs->regs[18], (unsigned long) regs->regs[19],
+               (unsigned long) regs->regs[20], (unsigned long) regs->regs[21],
+              (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]);
+       printk("$24: %08lx %08lx                   %08lx %08lx %08lx %08lx\n",
+              (unsigned long) regs->regs[24], (unsigned long) regs->regs[25],
+              (unsigned long) regs->regs[28], (unsigned long) regs->regs[29],
+               (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]);
+
+       /*
+        * Saved cp0 registers
+        */
+       printk("epc  : %08lx\nStatus: %08x\nCause : %08x\n",
+              (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status,
+              (unsigned int) regs->cp0_cause);
+}
+
+static int pa11_user_mode(struct pt_regs *regs)
+{
+       /* Return user mode stuff?? */
+}
+
+__initfunc(void ld_mmu_pa11(void))
+{
+
+    /* Taken directly from the MIPS arch..  Lots of bad things here */
+       clear_page = pa11_clear_page;
+       copy_page = pa11_copy_page;
+
+       flush_cache_all = pa11_flush_cache_all;
+       flush_cache_mm = pa11_flush_cache_mm;
+       flush_cache_range = pa11_flush_cache_range;
+       flush_cache_page = pa11_flush_cache_page;
+       flush_cache_sigtramp = pa11_flush_cache_sigtramp;
+       flush_page_to_ram = pa11_flush_page_to_ram;
+
+       flush_tlb_all = pa11_flush_tlb_all;
+       flush_tlb_mm = pa11_flush_tlb_mm;
+       flush_tlb_range = pa11_flush_tlb_range;
+       flush_tlb_page = pa11_flush_tlb_page;
+       pa11_asid_setup();
+
+       load_pgd = pa11_load_pgd;
+       pgd_init = pa11_pgd_init;
+       update_mmu_cache = pa11_update_mmu_cache;
+
+       show_regs = pa11_show_regs;
+    
+        add_wired_entry = pa11_add_wired_entry;
+
+       user_mode = pa11_user_mode;
+       flush_tlb_all();
+}
diff --git a/arch/parisc/mm/pa20.c b/arch/parisc/mm/pa20.c
new file mode 100644 (file)
index 0000000..cbc0343
--- /dev/null
@@ -0,0 +1,170 @@
+/* $Id: pa20.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $
+ *
+ * pa20.c: PA 2.0 specific mmu/cache code.
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/sgialib.h>
+#include <asm/mmu_context.h>
+
+extern unsigned long mips_tlb_entries;
+
+/* page functions */
+void pa20_clear_page(unsigned long page)
+{
+}
+
+static void pa20_copy_page(unsigned long to, unsigned long from)
+{
+}
+
+/* Cache operations. */
+static inline void pa20_flush_cache_all(void) { }
+static void pa20_flush_cache_mm(struct mm_struct *mm) { }
+static void pa20_flush_cache_range(struct mm_struct *mm,
+                                   unsigned long start,
+                                   unsigned long end)
+{
+}
+
+static void pa20_flush_cache_page(struct vm_area_struct *vma,
+                                  unsigned long page)
+{
+}
+
+static void pa20_flush_page_to_ram(unsigned long page)
+{
+}
+
+static void pa20_flush_cache_sigtramp(unsigned long page)
+{
+}
+
+/* TLB operations. */
+static inline void pa20_flush_tlb_all(void)
+{
+       unsigned long flags;
+       int entry;
+
+       save_and_cli(flags);
+/* Here we will need to flush all the TLBs */
+       restore_flags(flags);
+}
+
+static void pa20_flush_tlb_mm(struct mm_struct *mm)
+{
+/* This is what the MIPS does..  Is it the right thing for PA-RISC? */
+       if(mm == current->mm)
+               pa20_flush_tlb_all();
+}
+
+static void pa20_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+                                 unsigned long end)
+{
+       if(mm == current->mm)
+               pa20_flush_tlb_all();
+}
+
+static void pa20_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+       if(vma->vm_mm == current->mm)
+               pa20_flush_tlb_all();
+}
+
+static void pa20_load_pgd(unsigned long pg_dir)
+{
+       unsigned long flags;
+    /* We need to do the right thing here */
+}
+
+/*
+ * Initialize new page directory with pointers to invalid ptes
+ */
+static void pa20_pgd_init(unsigned long page)
+{
+       unsigned long dummy1, dummy2;
+
+}
+
+static void pa20_update_mmu_cache(struct vm_area_struct * vma,
+                                  unsigned long address, pte_t pte)
+{
+       pa20_flush_tlb_page(vma, address);
+}
+
+static void pa20_show_regs(struct pt_regs * regs)
+{
+       /*
+        * Saved main processor registers
+        */
+       printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2],
+              (unsigned long) regs->regs[3], (unsigned long) regs->regs[4],
+              (unsigned long) regs->regs[5], (unsigned long) regs->regs[6],
+              (unsigned long) regs->regs[7]);
+       printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              (unsigned long) regs->regs[8], (unsigned long) regs->regs[9],
+              (unsigned long) regs->regs[10], (unsigned long) regs->regs[11],
+               (unsigned long) regs->regs[12], (unsigned long) regs->regs[13],
+              (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]);
+       printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+              (unsigned long) regs->regs[16], (unsigned long) regs->regs[17],
+              (unsigned long) regs->regs[18], (unsigned long) regs->regs[19],
+               (unsigned long) regs->regs[20], (unsigned long) regs->regs[21],
+              (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]);
+       printk("$24: %08lx %08lx                   %08lx %08lx %08lx %08lx\n",
+              (unsigned long) regs->regs[24], (unsigned long) regs->regs[25],
+              (unsigned long) regs->regs[28], (unsigned long) regs->regs[29],
+               (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]);
+
+       /*
+        * Saved cp0 registers
+        */
+       printk("epc  : %08lx\nStatus: %08x\nCause : %08x\n",
+              (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status,
+              (unsigned int) regs->cp0_cause);
+}
+
+static int pa20_user_mode(struct pt_regs *regs)
+{
+       /* Return user mode stuff?? */
+}
+
+__initfunc(void ld_mmu_pa20(void))
+{
+
+    /* Taken directly from the MIPS arch..  Lots of bad things here */
+       clear_page = pa20_clear_page;
+       copy_page = pa20_copy_page;
+
+       flush_cache_all = pa20_flush_cache_all;
+       flush_cache_mm = pa20_flush_cache_mm;
+       flush_cache_range = pa20_flush_cache_range;
+       flush_cache_page = pa20_flush_cache_page;
+       flush_cache_sigtramp = pa20_flush_cache_sigtramp;
+       flush_page_to_ram = pa20_flush_page_to_ram;
+
+       flush_tlb_all = pa20_flush_tlb_all;
+       flush_tlb_mm = pa20_flush_tlb_mm;
+       flush_tlb_range = pa20_flush_tlb_range;
+       flush_tlb_page = pa20_flush_tlb_page;
+       pa20_asid_setup();
+
+       load_pgd = pa20_load_pgd;
+       pgd_init = pa20_pgd_init;
+       update_mmu_cache = pa20_update_mmu_cache;
+
+       show_regs = pa20_show_regs;
+    
+        add_wired_entry = pa20_add_wired_entry;
+
+       user_mode = pa20_user_mode;
+       flush_tlb_all();
+}
diff --git a/arch/parisc/tools/Makefile b/arch/parisc/tools/Makefile
new file mode 100644 (file)
index 0000000..54fad56
--- /dev/null
@@ -0,0 +1,28 @@
+# Makefile for MIPS kernel build tools.
+#
+# Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+# Copyright (C) 1997 Ralf Baechle (ralf@gnu.ai.mit.edu)
+#
+# $Id: Makefile,v 1.3 1999/09/29 05:19:56 grundler Exp $
+#
+TARGET := $(TOPDIR)/include/asm-$(ARCH)/offset.h
+
+.S.s:
+       $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+       $(CC) $(CFLAGS) -c $< -o $*.o
+
+all: $(TARGET)
+
+$(TARGET): offset.h
+       cmp -s $^ $@ || (cp $^ $(TARGET).new && mv $(TARGET).new $(TARGET))
+
+offset.h: offset.s
+       sed -n '/^@@@/s///p' $^ >$@
+
+offset.s: offset.c
+
+clean:
+       rm -f offset.[hs] $(TARGET).new
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/parisc/tools/offset.c b/arch/parisc/tools/offset.c
new file mode 100644 (file)
index 0000000..167087f
--- /dev/null
@@ -0,0 +1,326 @@
+/* $Id: offset.c,v 1.2 2000/01/31 13:42:59 jsm Exp $
+ *
+ * offset.c: Calculate pt_regs and task_struct offsets.
+ *
+ * Copyright (C) 1996 David S. Miller
+ * Made portable by Ralf Baechle
+ * Adapted to parisc by Philipp Rumpf, (C) 1999 SuSE GmbH Nuernberg */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+
+#define text(t) __asm__("\n@@@" t)
+#define _offset(type, member) (&(((type *)NULL)->member))
+
+#define offset(string, ptr, member) \
+       __asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member)))
+#define size(string, size) \
+       __asm__("\n@@@" string "%0" : : "i" (sizeof(size)))
+#define align(x,y) (((x)+(2*(y))-1)-(((x)+(y)-1)%(y)))
+#define size_align(string, size, algn) \
+       __asm__("\n@@@" string "%0" : : "i" \
+               align(sizeof(size),algn))
+#define linefeed text("")
+
+text("/* DO NOT TOUCH, AUTOGENERATED BY OFFSET.C */");
+linefeed;
+text("#ifndef _PARISC_OFFSET_H");
+text("#define _PARISC_OFFSET_H");
+linefeed;
+
+void output_task_ptreg_defines(void)
+{
+       text("/* PA-RISC task pt_regs offsets. */");
+       offset("#define TASK_REGS       ", struct task_struct, thread.regs);
+       offset("#define TASK_PT_PSW     ", struct task_struct, thread.regs.gr[ 0]);
+       offset("#define TASK_PT_GR1     ", struct task_struct, thread.regs.gr[ 1]);
+       offset("#define TASK_PT_GR2     ", struct task_struct, thread.regs.gr[ 2]);
+       offset("#define TASK_PT_GR3     ", struct task_struct, thread.regs.gr[ 3]);
+       offset("#define TASK_PT_GR4     ", struct task_struct, thread.regs.gr[ 4]);
+       offset("#define TASK_PT_GR5     ", struct task_struct, thread.regs.gr[ 5]);
+       offset("#define TASK_PT_GR6     ", struct task_struct, thread.regs.gr[ 6]);
+       offset("#define TASK_PT_GR7     ", struct task_struct, thread.regs.gr[ 7]);
+       offset("#define TASK_PT_GR8     ", struct task_struct, thread.regs.gr[ 8]);
+       offset("#define TASK_PT_GR9     ", struct task_struct, thread.regs.gr[ 9]);
+       offset("#define TASK_PT_GR10    ", struct task_struct, thread.regs.gr[10]);
+       offset("#define TASK_PT_GR11    ", struct task_struct, thread.regs.gr[11]);
+       offset("#define TASK_PT_GR12    ", struct task_struct, thread.regs.gr[12]);
+       offset("#define TASK_PT_GR13    ", struct task_struct, thread.regs.gr[13]);
+       offset("#define TASK_PT_GR14    ", struct task_struct, thread.regs.gr[14]);
+       offset("#define TASK_PT_GR15    ", struct task_struct, thread.regs.gr[15]);
+       offset("#define TASK_PT_GR16    ", struct task_struct, thread.regs.gr[16]);
+       offset("#define TASK_PT_GR17    ", struct task_struct, thread.regs.gr[17]);
+       offset("#define TASK_PT_GR18    ", struct task_struct, thread.regs.gr[18]);
+       offset("#define TASK_PT_GR19    ", struct task_struct, thread.regs.gr[19]);
+       offset("#define TASK_PT_GR20    ", struct task_struct, thread.regs.gr[20]);
+       offset("#define TASK_PT_GR21    ", struct task_struct, thread.regs.gr[21]);
+       offset("#define TASK_PT_GR22    ", struct task_struct, thread.regs.gr[22]);
+       offset("#define TASK_PT_GR23    ", struct task_struct, thread.regs.gr[23]);
+       offset("#define TASK_PT_GR24    ", struct task_struct, thread.regs.gr[24]);
+       offset("#define TASK_PT_GR25    ", struct task_struct, thread.regs.gr[25]);
+       offset("#define TASK_PT_GR26    ", struct task_struct, thread.regs.gr[26]);
+       offset("#define TASK_PT_GR27    ", struct task_struct, thread.regs.gr[27]);
+       offset("#define TASK_PT_GR28    ", struct task_struct, thread.regs.gr[28]);
+       offset("#define TASK_PT_GR29    ", struct task_struct, thread.regs.gr[29]);
+       offset("#define TASK_PT_GR30    ", struct task_struct, thread.regs.gr[30]);
+       offset("#define TASK_PT_GR31    ", struct task_struct, thread.regs.gr[31]);
+       offset("#define TASK_PT_FR0     ", struct task_struct, thread.regs.fr[ 0]);
+       offset("#define TASK_PT_FR1     ", struct task_struct, thread.regs.fr[ 1]);
+       offset("#define TASK_PT_FR2     ", struct task_struct, thread.regs.fr[ 2]);
+       offset("#define TASK_PT_FR3     ", struct task_struct, thread.regs.fr[ 3]);
+       offset("#define TASK_PT_FR4     ", struct task_struct, thread.regs.fr[ 4]);
+       offset("#define TASK_PT_FR5     ", struct task_struct, thread.regs.fr[ 5]);
+       offset("#define TASK_PT_FR6     ", struct task_struct, thread.regs.fr[ 6]);
+       offset("#define TASK_PT_FR7     ", struct task_struct, thread.regs.fr[ 7]);
+       offset("#define TASK_PT_FR8     ", struct task_struct, thread.regs.fr[ 8]);
+       offset("#define TASK_PT_FR9     ", struct task_struct, thread.regs.fr[ 9]);
+       offset("#define TASK_PT_FR10    ", struct task_struct, thread.regs.fr[10]);
+       offset("#define TASK_PT_FR11    ", struct task_struct, thread.regs.fr[11]);
+       offset("#define TASK_PT_FR12    ", struct task_struct, thread.regs.fr[12]);
+       offset("#define TASK_PT_FR13    ", struct task_struct, thread.regs.fr[13]);
+       offset("#define TASK_PT_FR14    ", struct task_struct, thread.regs.fr[14]);
+       offset("#define TASK_PT_FR15    ", struct task_struct, thread.regs.fr[15]);
+       offset("#define TASK_PT_FR16    ", struct task_struct, thread.regs.fr[16]);
+       offset("#define TASK_PT_FR17    ", struct task_struct, thread.regs.fr[17]);
+       offset("#define TASK_PT_FR18    ", struct task_struct, thread.regs.fr[18]);
+       offset("#define TASK_PT_FR19    ", struct task_struct, thread.regs.fr[19]);
+       offset("#define TASK_PT_FR20    ", struct task_struct, thread.regs.fr[20]);
+       offset("#define TASK_PT_FR21    ", struct task_struct, thread.regs.fr[21]);
+       offset("#define TASK_PT_FR22    ", struct task_struct, thread.regs.fr[22]);
+       offset("#define TASK_PT_FR23    ", struct task_struct, thread.regs.fr[23]);
+       offset("#define TASK_PT_FR24    ", struct task_struct, thread.regs.fr[24]);
+       offset("#define TASK_PT_FR25    ", struct task_struct, thread.regs.fr[25]);
+       offset("#define TASK_PT_FR26    ", struct task_struct, thread.regs.fr[26]);
+       offset("#define TASK_PT_FR27    ", struct task_struct, thread.regs.fr[27]);
+       offset("#define TASK_PT_FR28    ", struct task_struct, thread.regs.fr[28]);
+       offset("#define TASK_PT_FR29    ", struct task_struct, thread.regs.fr[29]);
+       offset("#define TASK_PT_FR30    ", struct task_struct, thread.regs.fr[30]);
+       offset("#define TASK_PT_FR31    ", struct task_struct, thread.regs.fr[31]);
+       offset("#define TASK_PT_SR0     ", struct task_struct, thread.regs.sr[ 0]);
+       offset("#define TASK_PT_SR1     ", struct task_struct, thread.regs.sr[ 1]);
+       offset("#define TASK_PT_SR2     ", struct task_struct, thread.regs.sr[ 2]);
+       offset("#define TASK_PT_SR3     ", struct task_struct, thread.regs.sr[ 3]);
+       offset("#define TASK_PT_SR4     ", struct task_struct, thread.regs.sr[ 4]);
+       offset("#define TASK_PT_SR5     ", struct task_struct, thread.regs.sr[ 5]);
+       offset("#define TASK_PT_SR6     ", struct task_struct, thread.regs.sr[ 6]);
+       offset("#define TASK_PT_SR7     ", struct task_struct, thread.regs.sr[ 7]);
+       offset("#define TASK_PT_IASQ0   ", struct task_struct, thread.regs.iasq[0]);
+       offset("#define TASK_PT_IASQ1   ", struct task_struct, thread.regs.iasq[1]);
+       offset("#define TASK_PT_IAOQ0   ", struct task_struct, thread.regs.iaoq[0]);
+       offset("#define TASK_PT_IAOQ1   ", struct task_struct, thread.regs.iaoq[1]);
+       offset("#define TASK_PT_CR24    ", struct task_struct, thread.regs.cr24);
+       offset("#define TASK_PT_CR25    ", struct task_struct, thread.regs.cr25);
+       offset("#define TASK_PT_CR26    ", struct task_struct, thread.regs.cr26);
+       offset("#define TASK_PT_CR27    ", struct task_struct, thread.regs.cr27);
+       offset("#define TASK_PT_CR30    ", struct task_struct, thread.regs.cr30);
+       offset("#define TASK_PT_ORIG_R28 ", struct task_struct, thread.regs.orig_r28);
+       offset("#define TASK_PT_KSP     ", struct task_struct, thread.regs.ksp);
+       offset("#define TASK_PT_KPC     ", struct task_struct, thread.regs.kpc);
+       offset("#define TASK_PT_SAR     ", struct task_struct, thread.regs.sar);
+       offset("#define TASK_PT_CR11    ", struct task_struct, thread.regs.sar);
+       offset("#define TASK_PT_IIR     ", struct task_struct, thread.regs.iir);
+       offset("#define TASK_PT_ISR     ", struct task_struct, thread.regs.isr);
+       offset("#define TASK_PT_IOR     ", struct task_struct, thread.regs.ior);
+       offset("#define TASK_PT_CR_PID0 ", struct task_struct, thread.regs.cr_pid[0]);
+       offset("#define TASK_PT_CR_PID1 ", struct task_struct, thread.regs.cr_pid[1]);
+       offset("#define TASK_PT_CR_PID2 ", struct task_struct, thread.regs.cr_pid[2]);
+       offset("#define TASK_PT_CR_PID3 ", struct task_struct, thread.regs.cr_pid[3]);
+       size("#define TASK_SZ      ", struct task_struct);
+       size_align("#define TASK_SZ_ALGN  ", struct task_struct, 64);
+       linefeed;
+}
+
+void output_ptreg_defines(void)
+{
+       text("/* PA-RISC pt_regs offsets. */");
+       offset("#define PT_PSW     ", struct pt_regs, gr[ 0]);
+       offset("#define PT_GR1     ", struct pt_regs, gr[ 1]);
+       offset("#define PT_GR2     ", struct pt_regs, gr[ 2]);
+       offset("#define PT_GR3     ", struct pt_regs, gr[ 3]);
+       offset("#define PT_GR4     ", struct pt_regs, gr[ 4]);
+       offset("#define PT_GR5     ", struct pt_regs, gr[ 5]);
+       offset("#define PT_GR6     ", struct pt_regs, gr[ 6]);
+       offset("#define PT_GR7     ", struct pt_regs, gr[ 7]);
+       offset("#define PT_GR8     ", struct pt_regs, gr[ 8]);
+       offset("#define PT_GR9     ", struct pt_regs, gr[ 9]);
+       offset("#define PT_GR10    ", struct pt_regs, gr[10]);
+       offset("#define PT_GR11    ", struct pt_regs, gr[11]);
+       offset("#define PT_GR12    ", struct pt_regs, gr[12]);
+       offset("#define PT_GR13    ", struct pt_regs, gr[13]);
+       offset("#define PT_GR14    ", struct pt_regs, gr[14]);
+       offset("#define PT_GR15    ", struct pt_regs, gr[15]);
+       offset("#define PT_GR16    ", struct pt_regs, gr[16]);
+       offset("#define PT_GR17    ", struct pt_regs, gr[17]);
+       offset("#define PT_GR18    ", struct pt_regs, gr[18]);
+       offset("#define PT_GR19    ", struct pt_regs, gr[19]);
+       offset("#define PT_GR20    ", struct pt_regs, gr[20]);
+       offset("#define PT_GR21    ", struct pt_regs, gr[21]);
+       offset("#define PT_GR22    ", struct pt_regs, gr[22]);
+       offset("#define PT_GR23    ", struct pt_regs, gr[23]);
+       offset("#define PT_GR24    ", struct pt_regs, gr[24]);
+       offset("#define PT_GR25    ", struct pt_regs, gr[25]);
+       offset("#define PT_GR26    ", struct pt_regs, gr[26]);
+       offset("#define PT_GR27    ", struct pt_regs, gr[27]);
+       offset("#define PT_GR28    ", struct pt_regs, gr[28]);
+       offset("#define PT_GR29    ", struct pt_regs, gr[29]);
+       offset("#define PT_GR30    ", struct pt_regs, gr[30]);
+       offset("#define PT_GR31    ", struct pt_regs, gr[31]);
+       offset("#define PT_FR0     ", struct pt_regs, fr[ 0]);
+       offset("#define PT_FR1     ", struct pt_regs, fr[ 1]);
+       offset("#define PT_FR2     ", struct pt_regs, fr[ 2]);
+       offset("#define PT_FR3     ", struct pt_regs, fr[ 3]);
+       offset("#define PT_FR4     ", struct pt_regs, fr[ 4]);
+       offset("#define PT_FR5     ", struct pt_regs, fr[ 5]);
+       offset("#define PT_FR6     ", struct pt_regs, fr[ 6]);
+       offset("#define PT_FR7     ", struct pt_regs, fr[ 7]);
+       offset("#define PT_FR8     ", struct pt_regs, fr[ 8]);
+       offset("#define PT_FR9     ", struct pt_regs, fr[ 9]);
+       offset("#define PT_FR10    ", struct pt_regs, fr[10]);
+       offset("#define PT_FR11    ", struct pt_regs, fr[11]);
+       offset("#define PT_FR12    ", struct pt_regs, fr[12]);
+       offset("#define PT_FR13    ", struct pt_regs, fr[13]);
+       offset("#define PT_FR14    ", struct pt_regs, fr[14]);
+       offset("#define PT_FR15    ", struct pt_regs, fr[15]);
+       offset("#define PT_FR16    ", struct pt_regs, fr[16]);
+       offset("#define PT_FR17    ", struct pt_regs, fr[17]);
+       offset("#define PT_FR18    ", struct pt_regs, fr[18]);
+       offset("#define PT_FR19    ", struct pt_regs, fr[19]);
+       offset("#define PT_FR20    ", struct pt_regs, fr[20]);
+       offset("#define PT_FR21    ", struct pt_regs, fr[21]);
+       offset("#define PT_FR22    ", struct pt_regs, fr[22]);
+       offset("#define PT_FR23    ", struct pt_regs, fr[23]);
+       offset("#define PT_FR24    ", struct pt_regs, fr[24]);
+       offset("#define PT_FR25    ", struct pt_regs, fr[25]);
+       offset("#define PT_FR26    ", struct pt_regs, fr[26]);
+       offset("#define PT_FR27    ", struct pt_regs, fr[27]);
+       offset("#define PT_FR28    ", struct pt_regs, fr[28]);
+       offset("#define PT_FR29    ", struct pt_regs, fr[29]);
+       offset("#define PT_FR30    ", struct pt_regs, fr[30]);
+       offset("#define PT_FR31    ", struct pt_regs, fr[31]);
+       offset("#define PT_SR0     ", struct pt_regs, sr[ 0]);
+       offset("#define PT_SR1     ", struct pt_regs, sr[ 1]);
+       offset("#define PT_SR2     ", struct pt_regs, sr[ 2]);
+       offset("#define PT_SR3     ", struct pt_regs, sr[ 3]);
+       offset("#define PT_SR4     ", struct pt_regs, sr[ 4]);
+       offset("#define PT_SR5     ", struct pt_regs, sr[ 5]);
+       offset("#define PT_SR6     ", struct pt_regs, sr[ 6]);
+       offset("#define PT_SR7     ", struct pt_regs, sr[ 7]);
+       offset("#define PT_IASQ0   ", struct pt_regs, iasq[0]);
+       offset("#define PT_IASQ1   ", struct pt_regs, iasq[1]);
+       offset("#define PT_IAOQ0   ", struct pt_regs, iaoq[0]);
+       offset("#define PT_IAOQ1   ", struct pt_regs, iaoq[1]);
+       offset("#define PT_CR24    ", struct pt_regs, cr24);
+       offset("#define PT_CR25    ", struct pt_regs, cr25);
+       offset("#define PT_CR26    ", struct pt_regs, cr26);
+       offset("#define PT_CR27    ", struct pt_regs, cr27);
+       offset("#define PT_CR30    ", struct pt_regs, cr30);
+       offset("#define PT_ORIG_R28 ", struct pt_regs, orig_r28);
+       offset("#define PT_KSP     ", struct pt_regs, ksp);
+       offset("#define PT_KPC     ", struct pt_regs, kpc);
+       offset("#define PT_SAR     ", struct pt_regs, sar);
+       offset("#define PT_CR11    ", struct pt_regs, sar);
+       offset("#define PT_IIR     ", struct pt_regs, iir);
+       offset("#define PT_ISR     ", struct pt_regs, isr);
+       offset("#define PT_IOR     ", struct pt_regs, ior);
+       offset("#define PT_CR_PID0 ", struct pt_regs, cr_pid[0]);
+       offset("#define PT_CR_PID1 ", struct pt_regs, cr_pid[1]);
+       offset("#define PT_CR_PID2 ", struct pt_regs, cr_pid[2]);
+       offset("#define PT_CR_PID3 ", struct pt_regs, cr_pid[3]);
+       size("#define PT_SIZE    ", struct pt_regs);
+       size_align("#define PT_SZ_ALGN  ", struct pt_regs, 64);
+       linefeed;
+}
+
+void output_task_defines(void)
+{
+       text("/* PARISC task_struct offsets. */");
+       offset("#define TASK_STATE         ", struct task_struct, state);
+       offset("#define TASK_FLAGS         ", struct task_struct, flags);
+       offset("#define TASK_SIGPENDING    ", struct task_struct, sigpending);
+       offset("#define TASK_SEGMENT       ", struct task_struct, addr_limit);
+       offset("#define TASK_NEED_RESCHED  ", struct task_struct, need_resched);
+       offset("#define TASK_COUNTER       ", struct task_struct, counter);
+       offset("#define TASK_PTRACE        ", struct task_struct, ptrace);
+       offset("#define TASK_NICE          ", struct task_struct, nice);
+       offset("#define TASK_MM            ", struct task_struct, mm);
+       offset("#define TASK_PROCESSOR     ", struct task_struct, processor);
+       size  ("#define TASK_SZ          ", struct task_struct);
+       size_align("#define TASK_SZ_ALGN       ", struct task_struct, 64);
+       linefeed;
+}
+
+void output_irq_stat_defines(void)
+{
+       text("/* PARISC irq_cpustat_t offsets. */");
+       offset("#define IRQSTAT_SI_ACTIVE  ", irq_cpustat_t, __softirq_active);
+       offset("#define IRQSTAT_SI_MASK    ", irq_cpustat_t, __softirq_mask);
+       size  ("#define IRQSTAT_SZ         ", irq_cpustat_t);
+       linefeed;
+}
+
+#ifdef PRUMPF_HAD_MORE_TIME
+void output_thread_defines(void)
+{
+       text("/* PARISC specific thread_struct offsets. */");
+       offset("#define THREAD_REG16   ", struct task_struct, thread.reg16);
+       offset("#define THREAD_REG17   ", struct task_struct, thread.reg17);
+       offset("#define THREAD_REG18   ", struct task_struct, thread.reg18);
+       offset("#define THREAD_REG19   ", struct task_struct, thread.reg19);
+       offset("#define THREAD_REG20   ", struct task_struct, thread.reg20);
+       offset("#define THREAD_REG21   ", struct task_struct, thread.reg21);
+       offset("#define THREAD_REG22   ", struct task_struct, thread.reg22);
+       offset("#define THREAD_REG23   ", struct task_struct, thread.reg23);
+       offset("#define THREAD_REG29   ", struct task_struct, thread.reg29);
+       offset("#define THREAD_REG30   ", struct task_struct, thread.reg30);
+       offset("#define THREAD_REG31   ", struct task_struct, thread.reg31);
+       offset("#define THREAD_STATUS  ", struct task_struct, thread.cp0_status);
+       offset("#define THREAD_FPU     ", struct task_struct, thread.fpu);
+       offset("#define THREAD_BVADDR  ", struct task_struct, thread.cp0_badvaddr);
+       offset("#define THREAD_BUADDR  ", struct task_struct, thread.cp0_baduaddr);
+       offset("#define THREAD_ECODE   ", struct task_struct, thread.error_code);
+       offset("#define THREAD_TRAPNO  ", struct task_struct, thread.trap_no);
+       offset("#define THREAD_PGDIR   ", struct task_struct, thread.pg_dir);
+       offset("#define THREAD_MFLAGS  ", struct task_struct, thread.mflags);
+       offset("#define THREAD_CURDS   ", struct task_struct, thread.current_ds);
+       offset("#define THREAD_TRAMP   ", struct task_struct, thread.irix_trampoline);
+       offset("#define THREAD_OLDCTX  ", struct task_struct, thread.irix_oldctx);
+       linefeed;
+}
+
+void output_mm_defines(void)
+{
+       text("/* Linux mm_struct offsets. */");
+       offset("#define MM_COUNT      ", struct mm_struct, count);
+       offset("#define MM_PGD        ", struct mm_struct, pgd);
+       offset("#define MM_CONTEXT    ", struct mm_struct, context);
+       linefeed;
+}
+
+void output_sc_defines(void)
+{
+       text("/* Linux sigcontext offsets. */");
+       offset("#define SC_REGMASK    ", struct sigcontext, sc_regmask);
+       offset("#define SC_STATUS     ", struct sigcontext, sc_status);
+       offset("#define SC_PC         ", struct sigcontext, sc_pc);
+       offset("#define SC_REGS       ", struct sigcontext, sc_regs);
+       offset("#define SC_FPREGS     ", struct sigcontext, sc_fpregs);
+       offset("#define SC_OWNEDFP    ", struct sigcontext, sc_ownedfp);
+       offset("#define SC_FPC_CSR    ", struct sigcontext, sc_fpc_csr);
+       offset("#define SC_FPC_EIR    ", struct sigcontext, sc_fpc_eir);
+       offset("#define SC_SSFLAGS    ", struct sigcontext, sc_ssflags);
+       offset("#define SC_MDHI       ", struct sigcontext, sc_mdhi);
+       offset("#define SC_MDLO       ", struct sigcontext, sc_mdlo);
+       offset("#define SC_CAUSE      ", struct sigcontext, sc_cause);
+       offset("#define SC_BADVADDR   ", struct sigcontext, sc_badvaddr);
+       offset("#define SC_SIGSET     ", struct sigcontext, sc_sigset);
+       linefeed;
+}
+
+#endif
+
+text("#endif /* !(_PARISC_OFFSET_H) */");
diff --git a/arch/parisc/vmlinux.lds b/arch/parisc/vmlinux.lds
new file mode 100644 (file)
index 0000000..268fc59
--- /dev/null
@@ -0,0 +1,79 @@
+/* ld script to make hppa Linux kernel */
+OUTPUT_FORMAT("elf32-hppa")
+OUTPUT_ARCH(hppa)
+ENTRY(_stext)
+SECTIONS
+{
+
+/* right now use 0x10000/0x11000, later when we don't use Console and
+ * Boot-Device IODC, we will change this to 0x8000 !!!
+ */
+
+  . = 0xc0100000;   
+/*     . = 0x10000;  */
+
+  _text = .;                   /* Text and read-only data */
+  .text BLOCK(16) : {
+       *(.text*)
+       *(.PARISC.unwind)
+       *(.fixup)
+       *(.lock.text)           /* out-of-line lock text */
+       *(.gnu.warning)
+       } = 0
+
+  . = ALIGN(16);
+  .rodata : { *(.rodata) }
+  .kstrtab : { *(.kstrtab) }
+
+  _etext = .;                  /* End of text section */
+  
+  .data BLOCK(8192) : {                        /* Data without special */
+       data_start = .;
+       *(.data)
+       }
+
+  . = ALIGN(16);               /* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;       /* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+
+  . = ALIGN(16384);
+  __init_begin = .;
+  .init.text : { *(.init.text) }
+  .init.data : { *(.init.data) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) } 
+  __initcall_end = .;
+  __init_end = .;
+
+
+  init_task BLOCK(16384) : { *(init_task) }  /* The initial task and kernel stack */
+
+  _edata = .;                  /* End of data section */
+
+
+  .bss : { *(.bss) *(COMMON) }         /* BSS */
+
+
+  _end = . ;
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note 0 : { *(.note) }       
+       
+}
index 96c5df3870291a24cab1482773c033dbc04a6a08..0ae7379a98733919ec08979dbf6caa1cce02c969 100644 (file)
@@ -317,7 +317,7 @@ static volatile int fdc_busy = 0;
 static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
 static DECLARE_WAIT_QUEUE_HEAD(format_wait);
 
-static unsigned int changed_floppies = 0xff, fake_change = 0;
+static unsigned long changed_floppies = 0xff, fake_change = 0;
 #define        CHECK_CHANGE_DELAY      HZ/2
 
 #define        FD_MOTOR_OFF_DELAY      (3*HZ)
index 4582d45563e0210211bf0330bedf1841713af571..cbc99d25f2663747d742a585efd7e80a6fa98976 100644 (file)
@@ -10,7 +10,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
index 22f63442cb3c358314021f5d1099c64e16b816a8..73846f660d73e45ace07b009c45813c6f53d3f79 100644 (file)
 #include <linux/kernelcapi.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
-#include <linux/init.h>
 #include "capiutil.h"
 #include "capicmd.h"
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
index 499970ea202a96253dc88d4b5672ff4f6ffc4c50..b7812b83002956cd7267a1ac778d4a8c4d8492c6 100644 (file)
@@ -1298,7 +1298,7 @@ HiSax_reportcard(int cardnr, int sel)
        printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
                (ulong) & HiSax_reportcard);
        printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
-       printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc1 flg %x\n",
+       printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n",
                cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
        printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
                cs->bcs[0].mode, cs->bcs[0].channel);
index 97211bc4cf331bf25942e3fdf3c9d85adabb75a1..22cf911b316efed3c008d9cc44abc80eccf9c504 100644 (file)
@@ -202,7 +202,7 @@ struct Layer1 {
        void *hardware;
        struct BCState *bcs;
        struct PStack **stlistp;
-       int Flags;
+       long Flags;
        struct FsmInst l1m;
        struct FsmTimer timer;
        void (*l1l2) (struct PStack *, int, void *);
@@ -241,7 +241,7 @@ struct Layer2 {
        int tei;
        int sap;
        int maxlen;
-       unsigned int flag;
+       unsigned long flag;
        unsigned int vs, va, vr;
        int rc;
        unsigned int window;
@@ -366,7 +366,7 @@ struct w6692B_hw {
 };
 
 struct isar_reg {
-       unsigned int Flags;
+       unsigned long Flags;
        volatile u_char bstat;
        volatile u_char iis;
        volatile u_char cmsb;
@@ -484,7 +484,7 @@ struct amd7930_hw {
 struct BCState {
        int channel;
        int mode;
-       int Flag;
+       long Flag; /* long req'd for set_bit --RR */
        struct IsdnCardState *cs;
        int tx_cnt;             /* B-Channel transmit counter */
        struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
@@ -529,7 +529,8 @@ struct Channel {
        int data_open;
        struct l3_process *proc;
        setup_parm setup;       /* from isdnif.h numbers and Serviceindicator */
-       int Flags;              /* for remembering action done in l4 */
+       long Flags;             /* for remembering action done in l4 */
+                               /* long req'd for set_bit --RR */
        int leased;
 };
 
@@ -866,7 +867,7 @@ struct IsdnCardState {
        int protocol;
        unsigned int irq;
        unsigned long irq_flags;
-       int HW_Flags;
+       long HW_Flags;
        int *busy_flag;
         int chanlimit; /* limited number of B-chans to use */
         int logecho; /* log echo if supported by card */
@@ -933,7 +934,7 @@ struct IsdnCardState {
        int rcvidx;
        struct sk_buff *tx_skb;
        int tx_cnt;
-       int event;
+       long event;
        struct tq_struct tqueue;
        struct timer_list dbusytimer;
 #ifdef ERROR_STATISTIC
index 46274ae342d664a0e5d6ef3414d4c7c8e2ad734d..8f4ccf4215a48c7ed776854b1eab330941e65a51 100644 (file)
@@ -24,7 +24,6 @@
 #include "isdnl3.h"
 #include "l3ni1.h"
 #include <linux/ctype.h>
-#include <linux/config.h>
 
 extern char *HiSax_getrev(const char *revision);
 const char *ni1_revision = "$Revision: 2.5 $";
index 6f0bfe3be757d3e31002ec510d12eb1765aa61d4..9dede4757836e13c660a4d02b0ef88b0921ea5a6 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #define __NO_VERSION__
-#include <linux/config.h>
 #include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
index f58463ebc9bee14052d0910629f534c78c915221..b9b1cefe9e945133d5452cf7d8d9c9fd8e7d8437 100644 (file)
@@ -16,7 +16,6 @@
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/config.h>
 #define BH_TRACE 0
 #include <linux/module.h>
 #include <linux/raid/md.h>
index da052eff57e6deab32118d391104befc640d61cc..5a9c4575c4fb9ba29cd900e568168383b305f43a 100644 (file)
@@ -14,6 +14,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
index 6db67d8179419adba2d0a5a73365b8b0722be6f5..0a6609eccc0d5a6c874253e8f796bbb142e7b0c3 100644 (file)
@@ -88,7 +88,7 @@ el2_probe(struct net_device *dev)
     int base_addr = dev->base_addr;
 
     SET_MODULE_OWNER(dev);
-
+    
     if (base_addr > 0x1ff)     /* Check a single specified location. */
        return el2_probe1(dev, base_addr);
     else if (base_addr != 0)           /* Don't probe at all. */
@@ -319,6 +319,7 @@ out:
 static int
 el2_open(struct net_device *dev)
 {
+    int retval = -EAGAIN;
 
     if (dev->irq < 2) {
        int irqlist[] = {5, 9, 3, 4, 0};
@@ -331,18 +332,19 @@ el2_open(struct net_device *dev)
                unsigned long cookie = probe_irq_on();
                outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
                outb_p(0x00, E33G_IDCFR);
-               if (*irqp == probe_irq_off(cookie)       /* It's a good IRQ line! */
-                   && request_irq (dev->irq = *irqp, ei_interrupt, 0, ei_status.name, dev) == 0)
+               if (*irqp == probe_irq_off(cookie)      /* It's a good IRQ line! */
+                   && ((retval = request_irq(dev->irq = *irqp, 
+                   ei_interrupt, 0, dev->name, dev)) == 0))
                    break;
            }
        } while (*++irqp);
        if (*irqp == 0) {
            outb(EGACFR_IRQOFF, E33G_GACFR);    /* disable interrupts. */
-           return -EAGAIN;
+           return retval;
        }
     } else {
-       if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev)) {
-           return -EAGAIN;
+       if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
+           return retval;
        }
     }
 
index 1cbf41fae9e1c50f1199dcfcf238e63679252e90..23714facc7fcbc75fc6f8b3b803826f76defecc7 100644 (file)
@@ -284,7 +284,7 @@ typedef struct {
 
        /* flags */
        unsigned long send_pcb_semaphore;
-       unsigned int dmaing;
+       unsigned long dmaing;
        unsigned long busy;
 
        unsigned int rx_active;  /* number of receive PCBs */
index 92f2dd4c144dbefefcd768782bd7db9b49c86c01..6a8956e85a53f35ec9a3f1401f957d7ebf75fb17 100644 (file)
@@ -1487,7 +1487,7 @@ struct awc_private {
        volatile int            ejected;
        volatile int            bh_running;
        volatile int            bh_active;
-       volatile int            tx_chain_active;
+       volatile long           tx_chain_active;
        volatile u16            enabled_interrupts;
        volatile u16            waiting_interrupts;
        volatile int            interrupt_count;
index cec860fe0a52714dd08c78575a43feb10ad4f1e9..aee2bcbddf0ebd909284a114b33cca9cf33acfe3 100644 (file)
@@ -205,7 +205,7 @@ int arlan_command(struct net_device *dev, int command_p)
                priv->card_polling_interval = 1;
 
        if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS)
-               printk(KERN_DEBUG "arlan_command, %lx lock %x  commandByte %x waiting %x incoming %x \n",
+               printk(KERN_DEBUG "arlan_command, %lx lock %lx  commandByte %x waiting %x incoming %x \n",
                jiffies, priv->command_lock, READSHMB(arlan->commandByte),
                       priv->waiting_command_mask, command_p);
 
index e28982bdb9295ad158535f08aaaff50f3b1dca89..0f3d5da3e6aa36e96d62af887ad97e6623192a4b 100644 (file)
@@ -388,7 +388,7 @@ struct arlan_private {
       volatile int     tx_chain_active;
       volatile int     timer_chain_active;
       volatile int     interrupt_ack_requested;
-      volatile int     command_lock;
+      volatile long    command_lock;
       volatile int     rx_command_needed;
       volatile int     tx_command_needed;
       volatile int     waiting_command_mask;
@@ -398,8 +398,8 @@ struct arlan_private {
       volatile int     under_reset;
       volatile int     under_config;
       volatile int     rx_command_given;
-      volatile int     tx_command_given;
-      volatile int     interrupt_processing_active;
+      volatile long    tx_command_given;
+      volatile long    interrupt_processing_active;
       volatile long long       last_tx_time;
       volatile long long       last_rx_time;
       volatile long long       last_rx_int_ack_time;
index 9df9a4b1a6bf22bd34583d35f187b4629d810508..916f2e857becab02c5bce487f50fd7b0af3e00e9 100644 (file)
@@ -224,9 +224,9 @@ struct lance_private {
                                                /* copy function */
        void                            *(*memcpy_f)( void *, const void *, size_t );
        struct net_device_stats stats;
-/* These two must be ints for set_bit() */
-       int                                     tx_full;
-       int                                     lock;
+/* These two must be longs for set_bit() */
+       long                            tx_full;
+       long                            lock;
 };
 
 /* I/O register access macros */
index a947845d81e45cc39a12096787897e52c14ec14d..2de40294430f0ab4db039e55a3b458fa278f8692 100644 (file)
@@ -130,6 +130,14 @@ typedef unsigned int bool;
 #include "dgrs_asstruct.h"
 #include "dgrs_bcomm.h"
 
+#if LINUX_VERSION_CODE >= 0x20400
+static struct pci_device_id dgrs_pci_tbl[] __initdata = {
+       { SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
+       { }                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl);
+#endif /* LINUX_VERSION_CODE >= 0x20400 */
+
 /*
  *     Firmware.  Compiled separately for local compilation,
  *     but #included for Linux distribution.
@@ -788,9 +796,6 @@ static int
 dgrs_open( struct net_device *dev )
 {
        netif_start_queue(dev);
-
-       MOD_INC_USE_COUNT;
-
        return (0);
 }
 
@@ -800,9 +805,6 @@ dgrs_open( struct net_device *dev )
 static int dgrs_close( struct net_device *dev )
 {
        netif_stop_queue(dev);
-
-       MOD_DEC_USE_COUNT;
-
        return (0);
 }
 
@@ -1268,6 +1270,7 @@ dgrs_found_device(
        priv->devtbl[0] = dev;
 
        dev->init = dgrs_probe1;
+       SET_MODULE_OWNER(dev);
        ether_setup(dev);
        priv->next_dev = dgrs_root_dev;
        dgrs_root_dev = dev;
@@ -1303,6 +1306,7 @@ dgrs_found_device(
                privN->chan = i+1;
                priv->devtbl[i] = devN;
                devN->init = dgrs_initclone;
+               SET_MODULE_OWNER(dev);
                ether_setup(devN);
                privN->next_dev = dgrs_root_dev;
                dgrs_root_dev = devN;
index c344722000fea19349e06cb786523774502bb987..481b28700ff0b9cf98f176ff73e7b843bf45f28b 100644 (file)
@@ -393,6 +393,7 @@ static int __init dmfe_init_one (struct pci_dev *pdev,
        dev = init_etherdev(NULL, sizeof(*db));
        if (dev == NULL)
                goto err_out;
+       SET_MODULE_OWNER(dev);
 
        /* IO range check */
        if (!request_region(pci_iobase, CHK_IO_SIZE(pdev, dev_rev), dev->name)) {
@@ -461,12 +462,14 @@ static void __exit dmfe_remove_one (struct pci_dev *pdev)
  
 static int dmfe_open(struct net_device *dev)
 {
+       int ret;
        struct dmfe_board_info *db = dev->priv;
 
        DMFE_DBUG(0, "dmfe_open", 0);
 
-       if (request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev))
-               return -EAGAIN;
+       ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev);
+       if (ret)
+               return ret;
 
        /* Allocated Tx/Rx descriptor memory */
        db->desc_pool_ptr = kmalloc(sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, GFP_KERNEL | GFP_DMA);
@@ -511,9 +514,6 @@ static int dmfe_open(struct net_device *dev)
        /* Initilize DM910X board */
        dmfe_init_dm910x(dev);
 
-       /* Active System Interface */
-       MOD_INC_USE_COUNT;
-
        /* set and active a timer process */
        init_timer(&db->timer);
        db->timer.expires = DMFE_TIMER_WUT;
@@ -657,7 +657,7 @@ static int dmfe_stop(struct net_device *dev)
        DELAY_5US;
 
        /* deleted timer */
-       del_timer(&db->timer);
+       del_timer_sync(&db->timer);
 
        /* free interrupt */
        free_irq(dev->irq, dev);
@@ -669,8 +669,6 @@ static int dmfe_stop(struct net_device *dev)
        kfree(db->desc_pool_ptr);
        kfree(db->buf_pool_ptr);
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index 3d632145cb749e95e9e5f9f563238508101e0f3d..680f043eb1c7f7a4fc8599d37ddd9e34bc169581 100644 (file)
@@ -96,7 +96,7 @@ extern inline void mem_off(short port)
 #define E21_TX_START_PG                E21_RX_STOP_PG  /* First page of TX buffer */
 
 int e2100_probe(struct net_device *dev);
-int e21_probe1(struct net_device *dev, int ioaddr);
+static int e21_probe1(struct net_device *dev, int ioaddr);
 
 static int e21_open(struct net_device *dev);
 static void e21_reset_8390(struct net_device *dev);
@@ -122,6 +122,8 @@ int  __init e2100_probe(struct net_device *dev)
        int *port;
        int base_addr = dev->base_addr;
 
+       SET_MODULE_OWNER(dev);
+
        if (base_addr > 0x1ff)          /* Check a single specified location. */
                return e21_probe1(dev, base_addr);
        else if (base_addr != 0)        /* Don't probe at all. */
@@ -134,14 +136,14 @@ int  __init e2100_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-int __init e21_probe1(struct net_device *dev, int ioaddr)
+static int __init e21_probe1(struct net_device *dev, int ioaddr)
 {
        int i, status, retval;
        unsigned char *station_addr = dev->dev_addr;
        static unsigned version_printed = 0;
 
-       if (!request_region(ioaddr, E21_IO_EXTENT, "e2100"))
-               return -ENODEV;
+       if (!request_region(ioaddr, E21_IO_EXTENT, dev->name))
+               return -EBUSY;
 
        /* First check the station address for the Ctron prefix. */
        if (inb(ioaddr + E21_SAPROM + 0) != 0x00
@@ -255,10 +257,10 @@ static int
 e21_open(struct net_device *dev)
 {
        short ioaddr = dev->base_addr;
+       int retval;
 
-       if (request_irq(dev->irq, ei_interrupt, 0, "e2100", dev)) {
-               return -EBUSY;
-       }
+       if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)))
+               return retval;
 
        /* Set the interrupt line and memory base on the hardware. */
        inb(ioaddr + E21_IRQ_LOW);
@@ -270,7 +272,6 @@ e21_open(struct net_device *dev)
        outb(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7));
 
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -369,8 +370,6 @@ e21_close(struct net_device *dev)
           really bad things happen if it isn't. */
        mem_off(ioaddr);
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index cff64211b0c603e25aed79b80659a0bf7c741634..6943b7f873cc643fa8ffd36ee85dbec1adbe312b 100644 (file)
@@ -533,8 +533,9 @@ static unsigned eeprom_reg = EEPROM_REG_PRO;
 int __init eepro_probe(struct net_device *dev)
 {
        int i;
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
 
+       SET_MODULE_OWNER(dev);
 
 #ifdef PnPWakeup
        /* XXXX for multiple cards should this only be run once? */
@@ -643,7 +644,7 @@ void printEEPROMInfo(short ioaddr, struct net_device *dev)
    probes on the ISA bus.  A good device probe avoids doing writes, and
    verifies that the correct device exists and functions.  */
 
-int eepro_probe1(struct net_device *dev, short ioaddr)
+static int eepro_probe1(struct net_device *dev, short ioaddr)
 {
        unsigned short station_addr[6], id, counter;
        int i,j, irqMask;
@@ -1078,7 +1079,6 @@ static int eepro_open(struct net_device *dev)
        /* enabling rx */
        eepro_en_rx(ioaddr);
 
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -1234,7 +1234,6 @@ static int eepro_close(struct net_device *dev)
 
        /* Update the statistics here. What statistics? */
 
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1732,7 +1731,7 @@ eepro_transmit_interrupt(struct net_device *dev)
 static struct net_device dev_eepro[MAX_EEPRO];
 
 static int io[MAX_EEPRO];
-static int irq[MAX_EEPRO] = { [0 ... MAX_EEPRO-1] = 0 };
+static int irq[MAX_EEPRO];
 static int mem[MAX_EEPRO] = {  /* Size of the rx buffer in KB */
   [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024
 };
index 5f1f697bc5493b9429f98584698b8ae26f8f422d..102704b0cd8760f5aa4f5a697619af86d795bd37 100644 (file)
@@ -344,6 +344,8 @@ int __init express_probe(struct net_device *dev)
        static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 };
        unsigned short ioaddr = dev->base_addr;
 
+       SET_MODULE_OWNER(dev);
+
        dev->if_port = 0xff; /* not set */
 
 #ifdef CONFIG_MCA
@@ -420,7 +422,7 @@ int __init express_probe(struct net_device *dev)
 
 static int eexp_open(struct net_device *dev)
 {
-       int irq = dev->irq;
+       int ret;
        unsigned short ioaddr = dev->base_addr;
        struct net_local *lp = (struct net_local *)dev->priv;
 
@@ -428,11 +430,11 @@ static int eexp_open(struct net_device *dev)
        printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
 #endif
 
-       if (!irq || !irqrmap[irq])
+       if (!dev->irq || !irqrmap[dev->irq])
                return -ENXIO;
 
-       if (request_irq(irq,&eexp_irq,0,"EtherExpress",dev))
-               return -EAGAIN;
+       ret = request_irq(dev->irq,&eexp_irq,0,dev->name,dev);
+       if (ret) return ret;
 
        request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress");
        request_region(ioaddr+0x4000, 16, "EtherExpress shadow");
@@ -445,7 +447,6 @@ static int eexp_open(struct net_device *dev)
        }
 
        eexp_hw_init586(dev);
-       MOD_INC_USE_COUNT;
        netif_start_queue(dev);
 #if NET_DEBUG > 6
        printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
@@ -477,7 +478,6 @@ static int eexp_close(struct net_device *dev)
        release_region(ioaddr+0x8000, 16);
        release_region(ioaddr+0xc000, 16);
 
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1625,14 +1625,9 @@ eexp_set_multicast(struct net_device *dev)
 
 #define EEXP_MAX_CARDS     4    /* max number of cards to support */
 
-static struct net_device dev_eexp[EEXP_MAX_CARDS] =
-{
-        { "",
-         0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe },
-};
-
-static int irq[EEXP_MAX_CARDS] = {0, };
-static int io[EEXP_MAX_CARDS] = {0, };
+static struct net_device dev_eexp[EEXP_MAX_CARDS];
+static int irq[EEXP_MAX_CARDS];
+static int io[EEXP_MAX_CARDS];
 
 MODULE_PARM(io, "1-" __MODULE_STRING(EEXP_MAX_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(EEXP_MAX_CARDS) "i");
@@ -1649,6 +1644,7 @@ int init_module(void)
                struct net_device *dev = &dev_eexp[this_dev];
                dev->irq = irq[this_dev];
                dev->base_addr = io[this_dev];
+               dev->init = express_probe;
                if (io[this_dev] == 0) {
                        if (this_dev) break;
                        printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
index 86a09b4d4834aa41e383ddb42e106df05371f171..0c4c241ac4d46ad7d6d76fa9903a8fa1c74e2466 100644 (file)
@@ -62,7 +62,7 @@ static const char *version =
 #include "8390.h"
 
 int es_probe(struct net_device *dev);
-int es_probe1(struct net_device *dev, int ioaddr);
+static int es_probe1(struct net_device *dev, int ioaddr);
 
 static int es_open(struct net_device *dev);
 static int es_close(struct net_device *dev);
@@ -128,6 +128,8 @@ int __init es_probe(struct net_device *dev)
 {
        unsigned short ioaddr = dev->base_addr;
 
+       SET_MODULE_OWNER(dev);
+
        if (ioaddr > 0x1ff)             /* Check a single specified location. */
                return es_probe1(dev, ioaddr);
        else if (ioaddr > 0)            /* Don't probe at all. */
@@ -148,7 +150,7 @@ int __init es_probe(struct net_device *dev)
        return -ENODEV;
 }
 
-int __init es_probe1(struct net_device *dev, int ioaddr)
+static int __init es_probe1(struct net_device *dev, int ioaddr)
 {
        int i, retval;
        unsigned long eisa_id;
@@ -357,9 +359,6 @@ static void es_block_output(struct net_device *dev, int count,
 static int es_open(struct net_device *dev)
 {
        ei_open(dev);
-
-       MOD_INC_USE_COUNT;
-
        return 0;
 }
 
@@ -370,24 +369,13 @@ static int es_close(struct net_device *dev)
                printk("%s: Shutting down ethercard.\n", dev->name);
 
        ei_close(dev);
-
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
 #ifdef MODULE
 #define MAX_ES_CARDS   4       /* Max number of ES3210 cards per module */
 #define NAMELEN                8       /* # of chars for storing dev->name */
-static struct net_device dev_es3210[MAX_ES_CARDS] = {
-       {
-               "",             /* device name is inserted by net_init.c */
-               0, 0, 0, 0,
-               0, 0,
-               0, 0, 0, NULL, NULL
-       },
-};
-
+static struct net_device dev_es3210[MAX_ES_CARDS];
 static int io[MAX_ES_CARDS];
 static int irq[MAX_ES_CARDS];
 static int mem[MAX_ES_CARDS];
index 63fdd734bccca05888f0703bf94e229bc5bcbcec..d80e5c9c04490b541f37a67878f507ee02ceb87c 100644 (file)
@@ -116,6 +116,7 @@ static int __init hplance_init(struct net_device *dev, int scode)
                return -ENOMEM;
        memset(dev->priv, 0, sizeof(struct hplance_private));
 #endif
+       SET_MODULE_OWNER(dev);
 
         printk("%s: HP LANCE; select code %d, addr", dev->name, scode);
 
@@ -212,7 +213,6 @@ static int hplance_open(struct net_device *dev)
         /* enable interrupts at board level. */
         writeb(LE_IE, &(hpregs->status));
 
-        MOD_INC_USE_COUNT;
         return 0;
 }
 
@@ -222,7 +222,6 @@ static int hplance_close(struct net_device *dev)
         struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
         writeb(0,&(hpregs->status));              /* disable interrupts at boardlevel */
         lance_close(dev);
-        MOD_DEC_USE_COUNT;
         return 0;
 }
 
index 6a67457046b49f89f8903564bba7537bfdd2786d..4351442911fc61a2fbb69f7bea30d28b11aef4b8 100644 (file)
@@ -37,7 +37,6 @@
 
 static const char *version = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
new file mode 100644 (file)
index 0000000..049ebcc
--- /dev/null
@@ -0,0 +1,1550 @@
+/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
+   munged into HPPA boxen .
+
+   This driver is based upon 82596.c, original credits are below...
+   but there were too many hoops which HP wants jumped through to
+   keep this code in there in a sane manner.
+
+   3 primary sources of the mess -- 
+   1) hppa needs *lots* of cacheline flushing to keep this kind of
+   MMIO running.
+
+   2) The 82596 needs to see all of its pointers as their physical
+   address.  Thus virt_to_bus/bus_to_virt are *everywhere*.
+
+   3) The implementation HP is using seems to be significantly pickier 
+   about when and how the command and RX units are started.  some
+   command ordering was changed.
+
+   Examination of the mach driver leads one to believe that there
+   might be a saner way to pull this off...  anyone who feels like a
+   full rewrite can be my guest.
+
+   Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
+   
+   02/01/2000  Initial modifications for parisc by Helge Deller (deller@gmx.de)
+   03/02/2000  changes for better/correct(?) cache-flushing (deller)
+*/
+
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+   Based on Apricot.c
+   Written 1994 by Mark Evans.
+   This driver is for the Apricot 82596 bus-master interface
+
+   Modularised 12/94 Mark Evans
+
+
+   Modified to support the 82596 ethernet chips on 680x0 VME boards.
+   by Richard Hirst <richard@sleepie.demon.co.uk>
+   Renamed to be 82596.c
+
+   980825:  Changed to receive directly in to sk_buffs which are
+   allocated at open() time.  Eliminates copy on incoming frames
+   (small ones are still copied).  Shared data now held in a
+   non-cached page, so we can run on 68060 in copyback mode.
+
+   TBD:
+   * look at deferring rx frames rather than discarding (as per tulip)
+   * handle tx ring full as per tulip
+   * performace test to tune rx_copybreak
+
+   Most of my modifications relate to the braindead big-endian
+   implementation by Intel.  When the i596 is operating in
+   'big-endian' mode, it thinks a 32 bit value of 0x12345678
+   should be stored as 0x56781234.  This is a real pain, when
+   you have linked lists which are shared by the 680x0 and the
+   i596.
+
+   Driver skeleton
+   Written 1993 by Donald Becker.
+   Copyright 1993 United States Government as represented by the Director,
+   National Security Agency. This software may only be used and distributed
+   according to the terms of the GNU Public License as modified by SRC,
+   incorporated herein by reference.
+
+   The author may be reached as becker@super.org or
+   C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+ */
+
+static const char *version = "82596.c $Revision: 1.14 $\n";
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/irq.h>
+
+#include <asm/pdc.h>
+#include <asm/gsc.h>
+#include <asm/cache.h>
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT       0x0001
+#define DEB_PROBE      0x0002
+#define DEB_SERIOUS    0x0004
+#define DEB_ERRORS     0x0008
+#define DEB_MULTI      0x0010
+#define DEB_TDR                0x0020
+#define DEB_OPEN       0x0040
+#define DEB_RESET      0x0080
+#define DEB_ADDCMD     0x0100
+#define DEB_STATUS     0x0200
+#define DEB_STARTTX    0x0400
+#define DEB_RXADDR     0x0800
+#define DEB_TXADDR     0x1000
+#define DEB_RXFRAME    0x2000
+#define DEB_INTS       0x4000
+#define DEB_STRUCT     0x8000
+#define DEB_ANY                0xffff
+
+
+#define DEB(x,y)       if (i596_debug & (x)) y
+
+
+#define  CHECK_WBACK(addr,len) \
+       do { if (!dma_consistent) dma_cache_wback((unsigned long)addr,len); } while (0)
+
+#define  CHECK_INV(addr,len) \
+       do { if (!dma_consistent) dma_cache_inv((unsigned long)addr,len); } while(0)
+
+#define  CHECK_WBACK_INV(addr,len) \
+       do { if (!dma_consistent) dma_cache_wback_inv((unsigned long)addr,len); } while (0)
+
+
+#define PA_I82596_RESET                0       /* Offsets relative to LASI-LAN-Addr.*/
+#define PA_CPU_PORT_L_ACCESS   4
+#define PA_CHANNEL_ATTENTION   8
+
+
+/*
+ * Define various macros for Channel Attention, word swapping etc., dependent
+ * on architecture.  MVME and BVME are 680x0 based, otherwise it is Intel.
+ */
+
+#ifdef __BIG_ENDIAN
+#define WSWAPrfd(x)  ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPrbd(x)  ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPscb(x)  ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPcmd(x)  ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPtbd(x)  ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPchar(x) ((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define ISCP_BUSY      0x00010000
+#define MACH_IS_APRICOT        0
+#else
+#define WSWAPrfd(x)     ((struct i596_rfd *)(x))
+#define WSWAPrbd(x)     ((struct i596_rbd *)(x))
+#define WSWAPiscp(x)    ((struct i596_iscp *)(x))
+#define WSWAPscb(x)     ((struct i596_scb *)(x))
+#define WSWAPcmd(x)     ((struct i596_cmd *)(x))
+#define WSWAPtbd(x)     ((struct i596_tbd *)(x))
+#define WSWAPchar(x)    ((char *)(x))
+#define ISCP_BUSY      0x0001
+#define MACH_IS_APRICOT        1
+#endif
+
+/*
+ * The MPU_PORT command allows direct access to the 82596. With PORT access
+ * the following commands are available (p5-18). The 32-bit port command
+ * must be word-swapped with the most significant word written first.
+ * This only applies to VME boards.
+ */
+#define PORT_RESET             0x00    /* reset 82596 */
+#define PORT_SELFTEST          0x01    /* selftest */
+#define PORT_ALTSCP            0x02    /* alternate SCB address */
+#define PORT_ALTDUMP           0x03    /* Alternate DUMP address */
+
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);  
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_PARM(i596_debug, "i");
+
+
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PKT_BUF_SZ     1536
+#define MAX_MC_CNT     64
+
+#define I596_TOTAL_SIZE 17
+
+#define I596_NULL ((void *)0xffffffff)
+
+#define CMD_EOL                0x8000  /* The last command of the list, stop. */
+#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
+#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
+
+#define CMD_FLEX       0x0008  /* Enable flexible memory model */
+
+enum commands {
+       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
+};
+
+#define STAT_C         0x8000  /* Set to 0 after execution */
+#define STAT_B         0x4000  /* Command being executed */
+#define STAT_OK                0x2000  /* Command executed ok */
+#define STAT_A         0x1000  /* Command aborted */
+
+#define         CUC_START      0x0100
+#define         CUC_RESUME     0x0200
+#define         CUC_SUSPEND    0x0300
+#define         CUC_ABORT      0x0400
+#define         RX_START       0x0010
+#define         RX_RESUME      0x0020
+#define         RX_SUSPEND     0x0030
+#define         RX_ABORT       0x0040
+
+#define TX_TIMEOUT     5
+
+#define OPT_SWAP_PORT  0x0001  /* Need to wordswp on the MPU port */
+
+
+struct i596_reg {
+       unsigned short porthi;
+       unsigned short portlo;
+       unsigned long ca;
+};
+
+#define EOF            0x8000
+#define SIZE_MASK      0x3fff
+
+struct i596_tbd {
+       unsigned short size;
+       unsigned short pad;
+       struct i596_tbd *next;
+       char *data;
+       long cache_pad[5];              /* Total 32 bytes... */
+};
+
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596.  The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next.  It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+       struct i596_cmd *v_next;        /* Address from CPUs viewpoint */
+       unsigned short status;
+       unsigned short command;
+       struct i596_cmd *b_next;        /* Address from i596 viewpoint */
+};
+
+struct tx_cmd {
+       struct i596_cmd cmd;
+       struct i596_tbd *tbd;
+       unsigned short size;
+       unsigned short pad;
+       struct sk_buff *skb;            /* So we can free it after tx */
+       dma_addr_t dma_addr;
+       long cache_pad[1];              /* Total 32 bytes... */
+};
+
+struct tdr_cmd {
+       struct i596_cmd cmd;
+       unsigned short status;
+       unsigned short pad;
+};
+
+struct mc_cmd {
+       struct i596_cmd cmd;
+       short mc_cnt;
+       char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+       struct i596_cmd cmd;
+       char eth_addr[8];
+};
+
+struct cf_cmd {
+       struct i596_cmd cmd;
+       char i596_config[16];
+};
+
+struct i596_rfd {
+       unsigned short stat;
+       unsigned short cmd;
+       struct i596_rfd *b_next;        /* Address from i596 viewpoint */
+       struct i596_rbd *rbd;
+       unsigned short count;
+       unsigned short size;
+       struct i596_rfd *v_next;        /* Address from CPUs viewpoint */
+       struct i596_rfd *v_prev;
+       long cache_pad[2];              /* Total 32 bytes... */
+};
+
+struct i596_rbd {
+    unsigned short count;
+    unsigned short zero1;
+    struct i596_rbd *b_next;
+    unsigned char *b_data;             /* Address from i596 viewpoint */
+    unsigned short size;
+    unsigned short zero2;
+    struct sk_buff *skb;
+    struct i596_rbd *v_next;
+    struct i596_rbd *b_addr;           /* This rbd addr from i596 view */
+    unsigned char *v_data;             /* Address from CPUs viewpoint */
+                                       /* Total 32 bytes... */
+};
+
+/* These values as chosen so struct i596_private fits in one page... */
+
+#define TX_RING_SIZE 32
+#define RX_RING_SIZE 16
+
+struct i596_scb {
+       unsigned short status;
+       unsigned short command;
+       struct i596_cmd *cmd;
+       struct i596_rfd *rfd;
+       unsigned long crc_err;
+       unsigned long align_err;
+       unsigned long resource_err;
+       unsigned long over_err;
+       unsigned long rcvdt_err;
+       unsigned long short_err;
+       unsigned short t_on;
+       unsigned short t_off;
+};
+
+struct i596_iscp {
+       unsigned long stat;
+       struct i596_scb *scb;
+};
+
+struct i596_scp {
+       unsigned long sysbus;
+       unsigned long pad;
+       struct i596_iscp *iscp;
+};
+
+struct i596_private {
+       volatile struct i596_scp scp            __attribute__((aligned(32)));
+       volatile struct i596_iscp iscp          __attribute__((aligned(32)));
+       volatile struct i596_scb scb            __attribute__((aligned(32)));
+       struct sa_cmd sa_cmd                    __attribute__((aligned(32)));
+       struct cf_cmd cf_cmd                    __attribute__((aligned(32)));
+       struct tdr_cmd tdr_cmd                  __attribute__((aligned(32)));
+       struct mc_cmd mc_cmd                    __attribute__((aligned(32)));
+       struct i596_rfd rfds[RX_RING_SIZE]      __attribute__((aligned(32)));
+       struct i596_rbd rbds[RX_RING_SIZE]      __attribute__((aligned(32)));
+       struct tx_cmd tx_cmds[TX_RING_SIZE]     __attribute__((aligned(32)));
+       struct i596_tbd tbds[TX_RING_SIZE]      __attribute__((aligned(32)));
+       unsigned long stat;
+       int last_restart;
+       struct i596_rfd *rfd_head;
+       struct i596_rbd *rbd_head;
+       struct i596_cmd *cmd_tail;
+       struct i596_cmd *cmd_head;
+       int cmd_backlog;
+       unsigned long last_cmd;
+       struct net_device_stats stats;
+       int next_tx_cmd;
+       int options;
+       spinlock_t lock;
+       dma_addr_t dma_addr;
+};
+
+char init_setup[] =
+{
+       0x8E,                   /* length, prefetch on */
+       0xC8,                   /* fifo to 8, monitor off */
+       0x80,                   /* don't save bad frames */
+       0x2E,                   /* No source address insertion, 8 byte preamble */
+       0x00,                   /* priority and backoff defaults */
+       0x60,                   /* interframe spacing */
+       0x00,                   /* slot time LSB */
+       0xf2,                   /* slot time and retries */
+       0x00,                   /* promiscuous mode */
+       0x00,                   /* collision detect */
+       0x40,                   /* minimum frame length */
+       0xff,
+       0x00,
+       0x7f /*  *multi IA */ };
+
+static int dma_consistent = 1; /* Zero if pci_alloc_consistent() fails */
+
+static int i596_open(struct net_device *dev);
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int i596_close(struct net_device *dev);
+static struct net_device_stats *i596_get_stats(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void i596_tx_timeout (struct net_device *dev);
+static void print_eth(unsigned char *buf, char *str);
+static void set_multicast_list(struct net_device *dev);
+
+static int rx_ring_size = RX_RING_SIZE;
+static int ticks_limit = 100;
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
+
+static inline void CA(struct net_device *dev)
+{
+       gsc_writel(0, (void*)(dev->base_addr + PA_CHANNEL_ATTENTION));
+}
+
+
+static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+
+       u32 v = (u32) (c) | (u32) (x);
+
+       if (lp->options & OPT_SWAP_PORT)
+               v = ((u32) (v) << 16) | ((u32) (v) >> 16);
+
+       gsc_writel(v & 0xffff, (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS));
+       udelay(1);
+       gsc_writel(v >> 16,    (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS));
+}
+
+
+static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+       CHECK_INV(&(lp->iscp), sizeof(struct i596_iscp));
+       while (--delcnt && lp->iscp.stat) {
+               udelay(10);
+               CHECK_INV(&(lp->iscp), sizeof(struct i596_iscp));
+       }
+       if (!delcnt) {
+               printk("%s: %s, iscp.stat %04lx, didn't clear\n",
+                    dev->name, str, lp->iscp.stat);
+               return -1;
+       }
+       else
+               return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+       CHECK_INV(&(lp->scb), sizeof(struct i596_scb));
+       while (--delcnt && lp->scb.command) {
+               udelay(10);
+               CHECK_INV(&(lp->scb), sizeof(struct i596_scb));
+       }
+       if (!delcnt) {
+               printk("%s: %s, status %4.4x, cmd %4.4x.\n",
+                    dev->name, str, lp->scb.status, lp->scb.command);
+               return -1;
+       }
+       else
+               return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+       struct i596_cmd *cmd;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+
+       printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
+              &lp->scp, lp->scp.sysbus, lp->scp.iscp);
+       printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n",
+              &lp->iscp, lp->iscp.stat, lp->iscp.scb);
+       printk("scb at %p, scb.status = %04x, .command = %04x,"
+               " .cmd = %p, .rfd = %p\n",
+              &lp->scb, lp->scb.status, lp->scb.command,
+               lp->scb.cmd, lp->scb.rfd);
+       printk("   errors: crc %lx, align %lx, resource %lx,"
+               " over %lx, rcvdt %lx, short %lx\n",
+               lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
+               lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
+       cmd = lp->cmd_head;
+       while (cmd != I596_NULL) {
+               printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
+                 cmd, cmd->status, cmd->command, cmd->b_next);
+               cmd = cmd->v_next;
+       }
+       rfd = lp->rfd_head;
+       printk("rfd_head = %p\n", rfd);
+       do {
+               printk ("   %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
+                        " count %04x\n",
+                       rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
+                       rfd->count);
+               rfd = rfd->v_next;
+       } while (rfd != lp->rfd_head);
+       rbd = lp->rbd_head;
+       printk("rbd_head = %p\n", rbd);
+       do {
+               printk("   %p .count %04x, b_next %p, b_data %p, size %04x\n",
+                       rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
+               rbd = rbd->v_next;
+       } while (rbd != lp->rbd_head);
+       CHECK_INV(lp, sizeof(struct i596_private));
+}
+
+
+#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
+static void i596_error(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct net_device *dev = dev_id;
+       volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
+
+       pcc2[0x28] = 1;
+       pcc2[0x2b] = 0x1d;
+       printk("%s: Error interrupt\n", dev->name);
+       i596_display_data(dev);
+}
+#endif
+
+#define virt_to_dma(lp,v) ((char *)(v)-(char *)(lp)+(char *)((lp)->dma_addr))
+
+static inline void init_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *)dev->priv;
+       int i;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+
+       /* First build the Receive Buffer Descriptor List */
+
+       for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+               dma_addr_t dma_addr;
+               struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ + 4);
+
+               if (skb == NULL)
+                       panic("82596: alloc_skb() failed");
+               skb_reserve(skb, 2);
+               dma_addr = pci_map_single(NULL, skb->tail,PKT_BUF_SZ,
+                                       PCI_DMA_FROMDEVICE);
+               skb->dev = dev;
+               rbd->v_next = rbd+1;
+               rbd->b_next = WSWAPrbd(virt_to_dma(lp,rbd+1));
+               rbd->b_addr = WSWAPrbd(virt_to_dma(lp,rbd));
+               rbd->skb = skb;
+               rbd->v_data = skb->tail;
+               rbd->b_data = WSWAPchar(dma_addr);
+               rbd->size = PKT_BUF_SZ;
+       }
+       lp->rbd_head = lp->rbds;
+       rbd = lp->rbds + rx_ring_size - 1;
+       rbd->v_next = lp->rbds;
+       rbd->b_next = WSWAPrbd(virt_to_dma(lp,lp->rbds));
+
+       /* Now build the Receive Frame Descriptor List */
+
+       for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
+               rfd->rbd = I596_NULL;
+               rfd->v_next = rfd+1;
+               rfd->v_prev = rfd-1;
+               rfd->b_next = WSWAPrfd(virt_to_dma(lp,rfd+1));
+               rfd->cmd = CMD_FLEX;
+       }
+       lp->rfd_head = lp->rfds;
+       lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
+       rfd = lp->rfds;
+       rfd->rbd = lp->rbd_head;
+       rfd->v_prev = lp->rfds + rx_ring_size - 1;
+       rfd = lp->rfds + rx_ring_size - 1;
+       rfd->v_next = lp->rfds;
+       rfd->b_next = WSWAPrfd(virt_to_dma(lp,lp->rfds));
+       rfd->cmd = CMD_EOL|CMD_FLEX;
+
+       CHECK_WBACK_INV(lp, sizeof(struct i596_private));
+}
+
+static inline void remove_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *)dev->priv;
+       struct i596_rbd *rbd;
+       int i;
+
+       for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+               if (rbd->skb == NULL)
+                       break;
+               pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+               dev_kfree_skb(rbd->skb);
+       }
+}
+
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+       int i;
+
+       /* Ensure rx frame/buffer descriptors are tidy */
+
+       for (i = 0; i < rx_ring_size; i++) {
+               lp->rfds[i].rbd = I596_NULL;
+               lp->rfds[i].cmd = CMD_FLEX;
+       }
+       lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
+       lp->rfd_head = lp->rfds;
+       lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
+       lp->rbd_head = lp->rbds;
+       lp->rfds[0].rbd = WSWAPrbd(virt_to_dma(lp,lp->rbds));
+
+       CHECK_WBACK_INV(lp, sizeof(struct i596_private));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+       unsigned long flags;
+
+       disable_irq(dev->irq);  /* disable IRQs from LAN */
+       DEB(DEB_INIT,
+               printk("RESET 82596 port: %08lX (with IRQ%d disabled)\n",
+                      dev->base_addr + PA_I82596_RESET,
+                      dev->irq));
+       
+       gsc_writel(0, (void*)(dev->base_addr + PA_I82596_RESET)); /* Hard Reset */
+       udelay(100);                    /* Wait 100us - seems to help */
+
+       /* change the scp address */
+
+       lp->last_cmd = jiffies;
+
+
+       lp->scp.sysbus = 0x0000006c;
+       lp->scp.iscp = WSWAPiscp(virt_to_dma(lp,&(lp->iscp)));
+       lp->iscp.scb = WSWAPscb(virt_to_dma(lp,&(lp->scb)));
+       lp->iscp.stat = ISCP_BUSY;
+       lp->cmd_backlog = 0;
+
+       lp->cmd_head = lp->scb.cmd = I596_NULL;
+
+       DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name));
+
+       CHECK_WBACK(&(lp->scp), sizeof(struct i596_scp));
+       CHECK_WBACK(&(lp->iscp), sizeof(struct i596_iscp));
+
+       MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_dma(lp,&lp->scp));   
+
+       CA(dev);
+
+       if (wait_istat(dev,lp,1000,"initialization timed out"))
+               goto failed;
+       DEB(DEB_INIT,printk("%s: i82596 initialization successful\n", dev->name));
+
+       /* Ensure rx frame/buffer descriptors are tidy */
+       rebuild_rx_bufs(dev);
+
+       lp->scb.command = 0;
+       CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb));
+
+       enable_irq(dev->irq);   /* enable IRQs from LAN */
+
+       DEB(DEB_INIT,printk("%s: queuing CmdConfigure\n", dev->name));
+       memcpy(lp->cf_cmd.i596_config, init_setup, 14);
+       lp->cf_cmd.cmd.command = CmdConfigure;
+       CHECK_WBACK(&(lp->cf_cmd), sizeof(struct cf_cmd));
+       i596_add_cmd(dev, &lp->cf_cmd.cmd);
+
+       DEB(DEB_INIT,printk("%s: queuing CmdSASetup\n", dev->name));
+       memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
+       lp->sa_cmd.cmd.command = CmdSASetup;
+       CHECK_WBACK(&(lp->sa_cmd), sizeof(struct sa_cmd));
+       i596_add_cmd(dev, &lp->sa_cmd.cmd);
+
+       DEB(DEB_INIT,printk("%s: queuing CmdTDR\n", dev->name));
+       lp->tdr_cmd.cmd.command = CmdTDR;
+       CHECK_WBACK(&(lp->tdr_cmd), sizeof(struct tdr_cmd));
+       i596_add_cmd(dev, &lp->tdr_cmd.cmd);
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) {
+               spin_unlock_irqrestore (&lp->lock, flags);
+               goto failed;
+       }
+       DEB(DEB_INIT,printk("%s: Issuing RX_START\n", dev->name));
+       lp->scb.command = RX_START;
+       lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
+       CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb));
+
+       CA(dev);
+
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       if (wait_cmd(dev,lp,1000,"RX_START not processed"))
+               goto failed;
+       DEB(DEB_INIT,printk("%s: Receive unit started OK\n", dev->name));
+
+       return 0;
+
+failed:
+       printk("%s: Failed to initialise 82596\n", dev->name);
+       MPU_PORT(dev, PORT_RESET, 0);
+       return -1;
+}
+
+
+static inline int i596_rx(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *)dev->priv;
+       struct i596_rfd *rfd;
+       struct i596_rbd *rbd;
+       int frames = 0;
+
+       DEB(DEB_RXFRAME,printk ("i596_rx(), rfd_head %p, rbd_head %p\n",
+                       lp->rfd_head, lp->rbd_head));
+
+
+       rfd = lp->rfd_head;             /* Ref next frame to check */
+
+       CHECK_INV(rfd, sizeof(struct i596_rfd));
+       while ((rfd->stat) & STAT_C) {  /* Loop while complete frames */
+               if (rfd->rbd == I596_NULL)
+                       rbd = I596_NULL;
+               else if (rfd->rbd == lp->rbd_head->b_addr) {
+                       rbd = lp->rbd_head;
+                       CHECK_INV(rbd, sizeof(struct i596_rbd));
+               }
+               else {
+                       printk("%s: rbd chain broken!\n", dev->name);
+                       /* XXX Now what? */
+                       rbd = I596_NULL;
+               }
+               DEB(DEB_RXFRAME, printk("  rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+                       rfd, rfd->rbd, rfd->stat));
+               
+               if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
+                       /* a good frame */
+                       int pkt_len = rbd->count & 0x3fff;
+                       struct sk_buff *skb = rbd->skb;
+                       int rx_in_place = 0;
+
+                       DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
+                       frames++;
+
+                       /* Check if the packet is long enough to just accept
+                        * without copying to a properly sized skbuff.
+                        */
+
+                       if (pkt_len > rx_copybreak) {
+                               struct sk_buff *newskb;
+                               dma_addr_t dma_addr;
+
+                               pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+                               /* Get fresh skbuff to replace filled one. */
+                               newskb = dev_alloc_skb(PKT_BUF_SZ + 4);
+                               if (newskb == NULL) {
+                                       skb = NULL;     /* drop pkt */
+                                       goto memory_squeeze;
+                               }
+                               skb_reserve(newskb, 2);
+
+                               /* Pass up the skb already on the Rx ring. */
+                               skb_put(skb, pkt_len);
+                               rx_in_place = 1;
+                               rbd->skb = newskb;
+                               newskb->dev = dev;
+                               dma_addr = pci_map_single(NULL, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+                               rbd->v_data = newskb->tail;
+                               rbd->b_data = WSWAPchar(dma_addr);
+                               CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
+                       }
+                       else
+                               skb = dev_alloc_skb(pkt_len + 2);
+memory_squeeze:
+                       if (skb == NULL) {
+                               /* XXX tulip.c can defer packets here!! */
+                               printk ("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
+                               lp->stats.rx_dropped++;
+                       }
+                       else {
+                               skb->dev = dev;
+                               if (!rx_in_place) {
+                                       /* 16 byte align the data fields */
+                                       pci_dma_sync_single(NULL, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+                                       skb_reserve(skb, 2);
+                                       memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
+                               }
+                               skb->len = pkt_len;
+                               skb->protocol=eth_type_trans(skb,dev);
+                               netif_rx(skb);
+                               lp->stats.rx_packets++;
+                               lp->stats.rx_bytes+=pkt_len;
+                       }
+               }
+               else {
+                       DEB(DEB_ERRORS, printk("%s: Error, rfd.stat = 0x%04x\n",
+                                       dev->name, rfd->stat));
+                       lp->stats.rx_errors++;
+                       if ((rfd->stat) & 0x0001)
+                               lp->stats.collisions++;
+                       if ((rfd->stat) & 0x0080)
+                               lp->stats.rx_length_errors++;
+                       if ((rfd->stat) & 0x0100)
+                               lp->stats.rx_over_errors++;
+                       if ((rfd->stat) & 0x0200)
+                               lp->stats.rx_fifo_errors++;
+                       if ((rfd->stat) & 0x0400)
+                               lp->stats.rx_frame_errors++;
+                       if ((rfd->stat) & 0x0800)
+                               lp->stats.rx_crc_errors++;
+                       if ((rfd->stat) & 0x1000)
+                               lp->stats.rx_length_errors++;
+               }
+
+               /* Clear the buffer descriptor count and EOF + F flags */
+
+               if (rbd != I596_NULL && (rbd->count & 0x4000)) {
+                       rbd->count = 0;
+                       lp->rbd_head = rbd->v_next;
+                       CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
+               }
+
+               /* Tidy the frame descriptor, marking it as end of list */
+
+               rfd->rbd = I596_NULL;
+               rfd->stat = 0;
+               rfd->cmd = CMD_EOL|CMD_FLEX;
+               rfd->count = 0;
+
+               /* Remove end-of-list from old end descriptor */
+
+               rfd->v_prev->cmd = CMD_FLEX;
+
+               /* Update record of next frame descriptor to process */
+
+               lp->scb.rfd = rfd->b_next;
+               lp->rfd_head = rfd->v_next;
+               CHECK_WBACK_INV(rfd->v_prev, sizeof(struct i596_rfd));
+               CHECK_WBACK_INV(rfd, sizeof(struct i596_rfd));
+               rfd = lp->rfd_head;
+               CHECK_INV(rfd, sizeof(struct i596_rfd));
+       }
+
+       DEB(DEB_RXFRAME,printk ("frames %d\n", frames));
+
+       return 0;
+}
+
+
+static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
+{
+       struct i596_cmd *ptr;
+
+       while (lp->cmd_head != I596_NULL) {
+               ptr = lp->cmd_head;
+               lp->cmd_head = ptr->v_next;
+               lp->cmd_backlog--;
+
+               switch ((ptr->command) & 0x7) {
+               case CmdTx:
+                       {
+                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+                               struct sk_buff *skb = tx_cmd->skb;
+                               pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
+
+                               dev_kfree_skb(skb);
+
+                               lp->stats.tx_errors++;
+                               lp->stats.tx_aborted_errors++;
+
+                               ptr->v_next = ptr->b_next = I596_NULL;
+                               tx_cmd->cmd.command = 0;  /* Mark as free */
+                               break;
+                       }
+               default:
+                       ptr->v_next = ptr->b_next = I596_NULL;
+               }
+               CHECK_WBACK_INV(ptr, sizeof(struct i596_cmd));
+       }
+
+       wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out");
+       lp->scb.cmd = I596_NULL;
+       CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb));
+}
+
+
+static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr)
+{
+       unsigned long flags;
+
+       DEB(DEB_RESET,printk("i596_reset\n"));
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       wait_cmd(dev,lp,100,"i596_reset timed out");
+
+       netif_stop_queue(dev);
+
+       /* FIXME: this command might cause an lpmc */
+       lp->scb.command = CUC_ABORT | RX_ABORT;
+       CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb));
+       CA(dev);
+
+       /* wait for shutdown */
+       wait_cmd(dev,lp,1000,"i596_reset 2 timed out");
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       i596_cleanup_cmd(dev,lp);
+       i596_rx(dev);
+
+       netif_start_queue(dev);
+       init_i596_mem(dev);
+}
+
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+       int ioaddr = dev->base_addr;
+       unsigned long flags;
+
+       DEB(DEB_ADDCMD,printk("i596_add_cmd cmd_head %p\n", lp->cmd_head));
+
+       cmd->status = 0;
+       cmd->command |= (CMD_EOL | CMD_INTR);
+       cmd->v_next = cmd->b_next = I596_NULL;
+       CHECK_WBACK(cmd, sizeof(struct i596_cmd));
+
+       spin_lock_irqsave (&lp->lock, flags);
+
+       if (lp->cmd_head != I596_NULL) {
+               lp->cmd_tail->v_next = cmd;
+               lp->cmd_tail->b_next = WSWAPcmd(virt_to_dma(lp,&cmd->status));
+               CHECK_WBACK(lp->cmd_tail, sizeof(struct i596_cmd));
+       } else {
+               lp->cmd_head = cmd;
+               wait_cmd(dev,lp,100,"i596_add_cmd timed out");
+               lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&cmd->status));
+               lp->scb.command = CUC_START;
+               CHECK_WBACK(&(lp->scb), sizeof(struct i596_scb));
+               CA(dev);
+       }
+       lp->cmd_tail = cmd;
+       lp->cmd_backlog++;
+
+       spin_unlock_irqrestore (&lp->lock, flags);
+
+       if (lp->cmd_backlog > max_cmd_backlog) {
+               unsigned long tickssofar = jiffies - lp->last_cmd;
+
+               if (tickssofar < ticks_limit)
+                       return;
+
+               printk("%s: command unit timed out, status resetting.\n", dev->name);
+#if 1
+               i596_reset(dev, lp, ioaddr);
+#endif
+       }
+}
+
+#if 0
+/* this function makes a perfectly adequate probe...  but we have a
+   device list */
+static int i596_test(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+       volatile int *tint;
+       u32 data;
+
+       tint = (volatile int *)(&(lp->scp));
+       data = virt_to_dma(lp,tint);
+       
+       tint[1] = -1;
+       CHECK_WBACK(tint,PAGE_SIZE);
+
+       MPU_PORT(dev, 1, data);
+
+       for(data = 1000000; data; data--) {
+               CHECK_INV(tint,PAGE_SIZE);
+               if(tint[1] != -1)
+                       break;
+
+       }
+
+       printk("i596_test result %d\n", tint[1]);
+
+}
+#endif
+
+
+static int i596_open(struct net_device *dev)
+{
+       int res = 0;
+
+       DEB(DEB_OPEN,printk("%s: i596_open() irq %d.\n", dev->name, dev->irq));
+
+       if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) {
+               printk("%s: IRQ %d not free\n", dev->name, dev->irq);
+               return -EAGAIN;
+       }
+
+       request_region(dev->base_addr, 12, dev->name);
+
+       init_rx_bufs(dev);
+
+       netif_start_queue(dev);
+
+       MOD_INC_USE_COUNT;
+
+       /* Initialize the 82596 memory */
+       if (init_i596_mem(dev)) {
+               res = -EAGAIN;
+               free_irq(dev->irq, dev);
+       }
+
+       return res;
+}
+
+static void i596_tx_timeout (struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+       int ioaddr = dev->base_addr;
+
+       /* Transmitter timeout, serious problems. */
+       DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n",
+                       dev->name));
+
+       lp->stats.tx_errors++;
+
+       /* Try to restart the adaptor */
+       if (lp->last_restart == lp->stats.tx_packets) {
+               DEB(DEB_ERRORS,printk ("Resetting board.\n"));
+               /* Shutdown and restart */
+               i596_reset (dev, lp, ioaddr);
+       } else {
+               /* Issue a channel attention signal */
+               DEB(DEB_ERRORS,printk ("Kicking board.\n"));
+               lp->scb.command = CUC_START | RX_START;
+               CHECK_WBACK_INV(&(lp->scb), sizeof(struct i596_scb));
+               CA (dev);
+               lp->last_restart = lp->stats.tx_packets;
+       }
+
+       dev->trans_start = jiffies;
+       netif_wake_queue (dev);
+}
+
+
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+       struct tx_cmd *tx_cmd;
+       struct i596_tbd *tbd;
+       short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+       dev->trans_start = jiffies;
+
+       DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
+                               skb->len, (unsigned int)skb->data));
+
+       netif_stop_queue(dev);
+
+       tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
+       tbd = lp->tbds + lp->next_tx_cmd;
+
+       if (tx_cmd->cmd.command) {
+               DEB(DEB_ERRORS,printk ("%s: xmit ring full, dropping packet.\n",
+                               dev->name));
+               lp->stats.tx_dropped++;
+
+               dev_kfree_skb(skb);
+       } else {
+               if (++lp->next_tx_cmd == TX_RING_SIZE)
+                       lp->next_tx_cmd = 0;
+               tx_cmd->tbd = WSWAPtbd(virt_to_dma(lp,tbd));
+               tbd->next = I596_NULL;
+
+               tx_cmd->cmd.command = CMD_FLEX | CmdTx;
+               tx_cmd->skb = skb;
+
+               tx_cmd->pad = 0;
+               tx_cmd->size = 0;
+               tbd->pad = 0;
+               tbd->size = EOF | length;
+
+               tx_cmd->dma_addr = pci_map_single(NULL, skb->data, skb->len, 
+                               PCI_DMA_TODEVICE);
+               tbd->data = WSWAPchar(tx_cmd->dma_addr);
+
+               DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
+               CHECK_WBACK_INV(tx_cmd, sizeof(struct tx_cmd));
+               CHECK_WBACK_INV(tbd, sizeof(struct i596_tbd));
+               i596_add_cmd(dev, &tx_cmd->cmd);
+
+               lp->stats.tx_packets++;
+               lp->stats.tx_bytes += length;
+       }
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+static void print_eth(unsigned char *add, char *str)
+{
+       int i;
+
+       printk("i596 0x%p, ", add);
+       for (i = 0; i < 6; i++)
+               printk(" %02X", add[i + 6]);
+       printk(" -->");
+       for (i = 0; i < 6; i++)
+               printk(" %02X", add[i]);
+       printk(" %02X%02X, %s\n", add[12], add[13], str);
+}
+
+
+#define LAN_PROM_ADDR  0xF0810000
+
+static int __init i82596_probe(struct net_device *dev, int options)
+{
+       int i;
+       struct i596_private *lp;
+       char eth_addr[6];
+       dma_addr_t dma_addr;
+
+       /* This lot is ensure things have been cache line aligned. */
+       if (sizeof(struct i596_rfd) != 32) {
+           printk("82596: sizeof(struct i596_rfd) = %d\n",
+                           sizeof(struct i596_rfd));
+           return -ENODEV;
+       }
+       if (sizeof(struct i596_rbd) != 32) {
+           printk("82596: sizeof(struct i596_rbd) = %d\n",
+                           sizeof(struct i596_rbd));
+           return -ENODEV;
+       }
+       if (sizeof(struct tx_cmd) != 32) {
+           printk("82596: sizeof(struct tx_cmd) = %d\n",
+                           sizeof(struct tx_cmd));
+           return -ENODEV;
+       }
+       if (sizeof(struct i596_tbd) != 32) {
+           printk("82596: sizeof(struct i596_tbd) = %d\n",
+                           sizeof(struct i596_tbd));
+           return -ENODEV;
+       }
+       if (sizeof(struct i596_private) > 4096) {
+           printk("82596: sizeof(struct i596_private) = %d\n",
+                           sizeof(struct i596_private));
+           return -ENODEV;
+       }
+
+       /* FIXME:
+           Currently this works only, if set-up from lasi.c.
+           This should be changed to use probing too !
+       */
+
+       if (!dev->base_addr || !dev->irq)
+           return -ENODEV;
+
+       if (!pdc_lan_station_id( (char*)&eth_addr, (void*)dev->base_addr)) {
+           for(i=0;i<6;i++)
+               eth_addr[i] = gsc_readb(LAN_PROM_ADDR+i);
+           printk("82596.c: MAC of HP700 LAN blindely read from the prom!\n");
+       }
+
+       dev->mem_start = (int)pci_alloc_consistent( NULL, 
+               sizeof(struct i596_private), &dma_addr);
+       if (!dev->mem_start) {
+               printk("%s: Couldn't get consistent shared memory\n", dev->name);
+               dma_consistent = 0;
+               dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
+               if (!dev->mem_start) {
+                       printk("%s: Couldn't get shared memory\n", dev->name);
+#ifdef ENABLE_APRICOT
+                       release_region(dev->base_addr, I596_TOTAL_SIZE);
+#endif
+                       return -ENOMEM;
+               }
+               dma_addr = virt_to_bus(dev->mem_start);
+       }
+
+       ether_setup(dev);
+       DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr));
+
+       for (i = 0; i < 6; i++)
+               DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));
+
+       DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));
+
+       DEB(DEB_PROBE,printk(version));
+
+       /* The 82596-specific entries in the device structure. */
+       dev->open = i596_open;
+       dev->stop = i596_close;
+       dev->hard_start_xmit = i596_start_xmit;
+       dev->get_stats = i596_get_stats;
+       dev->set_multicast_list = set_multicast_list;
+       dev->tx_timeout = i596_tx_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
+
+       dev->priv = (void *)(dev->mem_start);
+
+       lp = (struct i596_private *) dev->priv;
+       DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
+                       dev->name, (unsigned long)lp,
+                       sizeof(struct i596_private), (unsigned long)&lp->scb));
+       memset((void *) lp, 0, sizeof(struct i596_private));
+
+#if 0
+       kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER);
+#endif
+       lp->options = options;
+       lp->scb.command = 0;
+       lp->scb.cmd = I596_NULL;
+       lp->scb.rfd = I596_NULL;
+       lp->lock = SPIN_LOCK_UNLOCKED;
+       lp->dma_addr = dma_addr;
+
+       CHECK_WBACK_INV(dev->mem_start, sizeof(struct i596_private));
+
+       return 0;
+}
+
+
+int __init lasi_i82596_probe(struct net_device *dev)
+{
+       return i82596_probe(dev, 0);
+}
+
+
+int __init asp_i82596_probe(struct net_device *dev)
+{
+       return i82596_probe(dev, OPT_SWAP_PORT);
+}
+
+
+static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct net_device *dev = dev_id;
+       struct i596_private *lp;
+       unsigned short status, ack_cmd = 0;
+
+       if (dev == NULL) {
+               printk("i596_interrupt(): irq %d for unknown device.\n", irq);
+               return;
+       }
+
+       lp = (struct i596_private *) dev->priv;
+
+       spin_lock (&lp->lock);
+
+       wait_cmd(dev,lp,100,"i596 interrupt, timeout");
+       status = lp->scb.status;
+
+       DEB(DEB_INTS,printk("%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+                       dev->name, irq, status));
+
+       ack_cmd = status & 0xf000;
+
+       if (!ack_cmd) {
+               DEB(DEB_ERRORS, printk("%s: interrupt with no events\n", dev->name));
+               spin_unlock (&lp->lock);
+               return;
+       }
+
+       if ((status & 0x8000) || (status & 0x2000)) {
+               struct i596_cmd *ptr;
+
+               if ((status & 0x8000))
+                       DEB(DEB_INTS,printk("%s: i596 interrupt completed command.\n", dev->name));
+               if ((status & 0x2000))
+                       DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
+
+               while (lp->cmd_head != I596_NULL) {
+                       CHECK_INV(lp->cmd_head, sizeof(struct i596_cmd));
+                       if (!(lp->cmd_head->status & STAT_C))
+                               break;
+
+                       ptr = lp->cmd_head;
+
+                       DEB(DEB_STATUS,printk("cmd_head->status = %04x, ->command = %04x\n",
+                                      lp->cmd_head->status, lp->cmd_head->command));
+                       lp->cmd_head = ptr->v_next;
+                       lp->cmd_backlog--;
+
+                       switch ((ptr->command) & 0x7) {
+                       case CmdTx:
+                           {
+                               struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+                               struct sk_buff *skb = tx_cmd->skb;
+
+                               if ((ptr->status) & STAT_OK) {
+                                       DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
+                               } else {
+                                       lp->stats.tx_errors++;
+                                       if ((ptr->status) & 0x0020)
+                                               lp->stats.collisions++;
+                                       if (!((ptr->status) & 0x0040))
+                                               lp->stats.tx_heartbeat_errors++;
+                                       if ((ptr->status) & 0x0400)
+                                               lp->stats.tx_carrier_errors++;
+                                       if ((ptr->status) & 0x0800)
+                                               lp->stats.collisions++;
+                                       if ((ptr->status) & 0x1000)
+                                               lp->stats.tx_aborted_errors++;
+                               }
+                               pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
+                               dev_kfree_skb_irq(skb);
+
+                               tx_cmd->cmd.command = 0; /* Mark free */
+                               break;
+                           }
+                       case CmdTDR:
+                           {
+                               unsigned short status = ((struct tdr_cmd *)ptr)->status;
+
+                               if (status & 0x8000) {
+                                       DEB(DEB_ANY,printk("%s: link ok.\n", dev->name));
+                               } else {
+                                       if (status & 0x4000)
+                                               printk("%s: Transceiver problem.\n", dev->name);
+                                       if (status & 0x2000)
+                                               printk("%s: Termination problem.\n", dev->name);
+                                       if (status & 0x1000)
+                                               printk("%s: Short circuit.\n", dev->name);
+
+                                       DEB(DEB_TDR,printk("%s: Time %d.\n", dev->name, status & 0x07ff));
+                               }
+                               break;
+                           }
+                       case CmdConfigure:
+                               /* Zap command so set_multicast_list() knows it is free */
+                               ptr->command = 0;
+                               break;
+                       }
+                       ptr->v_next = ptr->b_next = I596_NULL;
+                       CHECK_WBACK(ptr, sizeof(struct i596_cmd));
+                       lp->last_cmd = jiffies;
+               }
+
+               /* This mess is arranging that only the last of any outstanding
+                * commands has the interrupt bit set.  Should probably really
+                * only add to the cmd queue when the CU is stopped.
+                */
+               ptr = lp->cmd_head;
+               while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
+                       struct i596_cmd *prev = ptr;
+
+                       ptr->command &= 0x1fff;
+                       ptr = ptr->v_next;
+                       CHECK_WBACK_INV(prev, sizeof(struct i596_cmd));
+               }
+
+               if ((lp->cmd_head != I596_NULL))
+                       ack_cmd |= CUC_START;
+               lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&lp->cmd_head->status));
+               CHECK_WBACK_INV(&lp->scb, sizeof(struct i596_scb));
+       }
+       if ((status & 0x1000) || (status & 0x4000)) {
+               if ((status & 0x4000))
+                       DEB(DEB_INTS,printk("%s: i596 interrupt received a frame.\n", dev->name));
+               i596_rx(dev);
+               /* Only RX_START if stopped - RGH 07-07-96 */
+               if (status & 0x1000) {
+                       if (netif_running(dev)) {
+                               DEB(DEB_ERRORS,printk("%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
+                               ack_cmd |= RX_START;
+                               lp->stats.rx_errors++;
+                               lp->stats.rx_fifo_errors++;
+                               rebuild_rx_bufs(dev);
+                       }
+               }
+       }
+       wait_cmd(dev,lp,100,"i596 interrupt, timeout");
+       lp->scb.command = ack_cmd;
+       CHECK_WBACK(&lp->scb, sizeof(struct i596_scb));
+
+       /* DANGER: I suspect that some kind of interrupt
+        acknowledgement aside from acking the 82596 might be needed 
+        here...  but it's running acceptably without */
+
+       CA(dev);
+
+       wait_cmd(dev,lp,100,"i596 interrupt, exit timeout");
+       DEB(DEB_INTS,printk("%s: exiting interrupt.\n", dev->name));
+
+       spin_unlock (&lp->lock);
+       return;
+}
+
+static int i596_close(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+       unsigned long flags;
+
+       netif_stop_queue(dev);
+
+       DEB(DEB_INIT,printk("%s: Shutting down ethercard, status was %4.4x.\n",
+                      dev->name, lp->scb.status));
+
+       save_flags(flags);
+       cli();
+
+       wait_cmd(dev,lp,100,"close1 timed out");
+       lp->scb.command = CUC_ABORT | RX_ABORT;
+       CHECK_WBACK(&lp->scb, sizeof(struct i596_scb));
+
+       CA(dev);
+
+       wait_cmd(dev,lp,100,"close2 timed out");
+       restore_flags(flags);
+       DEB(DEB_STRUCT,i596_display_data(dev));
+       i596_cleanup_cmd(dev,lp);
+
+       disable_irq(dev->irq);
+
+       free_irq(dev->irq, dev);
+       remove_rx_bufs(dev);
+
+       release_region(dev->base_addr, 12);
+
+       MOD_DEC_USE_COUNT;
+
+       return 0;
+}
+
+static struct net_device_stats *
+ i596_get_stats(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+
+       return &lp->stats;
+}
+
+/*
+ *    Set or clear the multicast filter for this adaptor.
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+       struct i596_private *lp = (struct i596_private *) dev->priv;
+       int config = 0, cnt;
+
+       DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
+
+       if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
+               lp->cf_cmd.i596_config[8] |= 0x01;
+               config = 1;
+       }
+       if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
+               lp->cf_cmd.i596_config[8] &= ~0x01;
+               config = 1;
+       }
+       if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
+               lp->cf_cmd.i596_config[11] &= ~0x20;
+               config = 1;
+       }
+       if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
+               lp->cf_cmd.i596_config[11] |= 0x20;
+               config = 1;
+       }
+       if (config) {
+               if (lp->cf_cmd.cmd.command)
+                       printk("%s: config change request already queued\n",
+                              dev->name);
+               else {
+                       lp->cf_cmd.cmd.command = CmdConfigure;
+                       CHECK_WBACK_INV(&lp->cf_cmd, sizeof(struct cf_cmd));
+                       i596_add_cmd(dev, &lp->cf_cmd.cmd);
+               }
+       }
+
+       cnt = dev->mc_count;
+       if (cnt > MAX_MC_CNT)
+       {
+               cnt = MAX_MC_CNT;
+               printk("%s: Only %d multicast addresses supported",
+                       dev->name, cnt);
+       }
+       
+       if (dev->mc_count > 0) {
+               struct dev_mc_list *dmi;
+               unsigned char *cp;
+               struct mc_cmd *cmd;
+
+               cmd = &lp->mc_cmd;
+               cmd->cmd.command = CmdMulticastList;
+               cmd->mc_cnt = dev->mc_count * 6;
+               cp = cmd->mc_addrs;
+               for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
+                       memcpy(cp, dmi->dmi_addr, 6);
+                       if (i596_debug > 1)
+                               DEB(DEB_MULTI,printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
+                                               dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));
+               }
+               CHECK_WBACK_INV(&lp->mc_cmd, sizeof(struct mc_cmd));
+               i596_add_cmd(dev, &cmd->cmd);
+       }
+}
+
+#ifdef HAVE_DEVLIST
+static unsigned int i596_portlist[] __initdata =
+{0x300, 0};
+struct netdev_entry i596_drv =
+{"lasi_i82596", lasi_i82596_probe, I596_TOTAL_SIZE, i596_portlist};
+#endif
+
+#ifdef MODULE
+static char devicename[9] =
+{0,};
+static struct net_device dev_82596 =
+{
+       devicename,     /* device name inserted by drivers/net/net_init.c */
+       0, 0, 0, 0,
+       0, 0,           /* base, irq */
+       0, 0, 0, NULL, lasi_i82596_probe};
+
+
+MODULE_PARM(debug, "i");
+static int debug = -1;
+
+int init_module(void)
+{
+       if (debug >= 0)
+               i596_debug = debug;
+       if (register_netdev(&dev_82596) != 0)
+               return -EIO;
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       unregister_netdev(&dev_82596);
+       lp = (struct i596_private *) dev_82596.priv;
+
+       if (dma_consistent)
+               pci_free_consistent( NULL, sizeof( struct i596_private), 
+                       dev_82596.mem_start, lp->dma_addr);
+       else
+               free_page ((u32)(dev_82596.mem_start));
+
+       dev_82596.priv = NULL;
+}
+
+#endif                         /* MODULE */
+
index 133e8d1a199c5acc550f10a95e3c7991947c1d92..5292c4a35aedf1b57a428fa296843757a52f5386 100644 (file)
@@ -157,7 +157,9 @@ static void ne_block_output(struct net_device *dev, const int count,
 
 int __init ne_probe(struct net_device *dev)
 {
-       unsigned int base_addr = dev ? dev->base_addr : 0;
+       unsigned int base_addr = dev->base_addr;
+
+       SET_MODULE_OWNER(dev);
 
        /* First check any supplied i/o locations. User knows best. <cough> */
        if (base_addr > 0x1ff)  /* Check a single specified location. */
@@ -469,7 +471,6 @@ err_out:
 static int ne_open(struct net_device *dev)
 {
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -478,7 +479,6 @@ static int ne_close(struct net_device *dev)
        if (ei_debug > 1)
                printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
        ei_close(dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
index 3ff0ef14158c581478c00d5135040b3ec8b45074..9bb252dc5c5b6b28ec142be479eb07a97ec6d743 100644 (file)
@@ -152,6 +152,8 @@ int __init ne2_probe(struct net_device *dev)
        int i;
        int adapter_found = 0;
 
+       SET_MODULE_OWNER(dev);
+
        /* Do not check any supplied i/o locations. 
           POS registers usually don't fail :) */
 
@@ -371,7 +373,6 @@ out:
 static int ne_open(struct net_device *dev)
 {
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -380,7 +381,6 @@ static int ne_close(struct net_device *dev)
        if (ei_debug > 1)
                printk("%s: Shutting down ethercard.\n", dev->name);
        ei_close(dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
index 3ba20f197fbb3e862fd7a75ab42d068e899ed3ed..b404574fea8ad3b107b788ca9225aec0d85b845b 100644 (file)
@@ -244,6 +244,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
                printk (KERN_ERR "ne2k-pci: cannot allocate ethernet device\n");
                goto err_out_free_res;
        }
+       SET_MODULE_OWNER(dev);
 
        /* Reset card. Who knows what dain-bramaged state it was left in. */
        {
@@ -358,11 +359,10 @@ err_out_free_res:
 
 static int ne2k_pci_open(struct net_device *dev)
 {
-       MOD_INC_USE_COUNT;
-       if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev)) {
-               MOD_DEC_USE_COUNT;
-               return -EAGAIN;
-       }
+       int ret = request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev);
+       if (ret)
+               return ret;
+
        /* Set full duplex for the chips that we know about. */
        if (ei_status.ne2k_flags & FORCE_FDX) {
                long ioaddr = dev->base_addr;
@@ -380,7 +380,6 @@ static int ne2k_pci_close(struct net_device *dev)
 {
        ei_close(dev);
        free_irq(dev->irq, dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
index e57551271df535df0246359d508ba47731cfd91c..eae50f902f3278a1dada319f854b3c0346113d73 100644 (file)
@@ -99,6 +99,8 @@ int __init ne3210_probe(struct net_device *dev)
 {
        unsigned short ioaddr = dev->base_addr;
 
+       SET_MODULE_OWNER(dev);
+
        if (ioaddr > 0x1ff)             /* Check a single specified location. */
                return ne3210_probe1(dev, ioaddr);
        else if (ioaddr > 0)            /* Don't probe at all. */
@@ -345,7 +347,6 @@ static void ne3210_block_output(struct net_device *dev, int count,
 static int ne3210_open(struct net_device *dev)
 {
        ei_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -356,7 +357,6 @@ static int ne3210_close(struct net_device *dev)
                printk("%s: Shutting down ethercard.\n", dev->name);
 
        ei_close(dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
index ee7ef15784fdd8333201233dd2bcb64e705c49ea..43c0e7bcdb4e0fbc8fbf7044d2228697c6056919 100644 (file)
@@ -286,6 +286,7 @@ plip_init_dev(struct net_device *dev, struct parport *pb)
        struct net_local *nl;
        struct pardevice *pardev;
 
+       SET_MODULE_OWNER(dev);
        dev->irq = pb->irq;
        dev->base_addr = pb->base;
 
@@ -1164,7 +1165,6 @@ plip_open(struct net_device *dev)
 
        netif_start_queue (dev);
 
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -1212,7 +1212,6 @@ plip_close(struct net_device *dev)
        /* Reset. */
        outb(0x00, PAR_CONTROL(dev));
 #endif
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
index 3db04bdee4f1efbb930096f09682075f4e45de53..a020b21ddc71362c119aec80c52e76a591acb078 100644 (file)
@@ -15,6 +15,7 @@
  *  Modification History:
  *     30-Dec-99       AF      Split off from the tms380tr driver.
  *     22-Jan-00       AF      Updated to use indirect read/writes 
+ *     23-Nov-00       JG      New PCI API, cleanups
  *
  *
  *  TODO:
@@ -23,7 +24,6 @@
  *             config registers)
  *
  */
-static const char *version = "abyss.c: v1.01 22/01/2000 by Adam Fritzler\n";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -41,9 +41,18 @@ static const char *version = "abyss.c: v1.01 22/01/2000 by Adam Fritzler\n";
 #include "tms380tr.h"
 #include "abyss.h"            /* Madge-specific constants */
 
+static char version[] __initdata =
+"abyss.c: v1.02 23/11/2000 by Adam Fritzler\n";
+
 #define ABYSS_IO_EXTENT 64
 
-int abyss_probe(void);
+static struct pci_device_id abyss_pci_tbl[] __initdata = {
+       { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_MK2,
+         PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_TOKEN_RING << 8, 0x00ffffff, },
+       { }                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, abyss_pci_tbl);
+
 static int abyss_open(struct net_device *dev);
 static int abyss_close(struct net_device *dev);
 static void abyss_enable(struct net_device *dev);
@@ -51,17 +60,16 @@ static int abyss_chipset_init(struct net_device *dev);
 static void abyss_read_eeprom(struct net_device *dev);
 static unsigned short abyss_setnselout_pins(struct net_device *dev);
 
-void at24_writedatabyte(unsigned long regaddr, unsigned char byte);
-int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr);
-int at24_sendcmd(unsigned long regaddr, unsigned char cmd);
-unsigned char at24_readdatabit(unsigned long regaddr);
-unsigned char at24_readdatabyte(unsigned long regaddr);
-int at24_waitforack(unsigned long regaddr);
-int at24_waitfornack(unsigned long regaddr);
-void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data);
-void at24_start(unsigned long regaddr);
-void at24_stop(unsigned long regaddr);
-unsigned char at24_readb(unsigned long regaddr, unsigned char addr);
+static void at24_writedatabyte(unsigned long regaddr, unsigned char byte);
+static int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr);
+static int at24_sendcmd(unsigned long regaddr, unsigned char cmd);
+static unsigned char at24_readdatabit(unsigned long regaddr);
+static unsigned char at24_readdatabyte(unsigned long regaddr);
+static int at24_waitforack(unsigned long regaddr);
+static int at24_waitfornack(unsigned long regaddr);
+static void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data);
+static void at24_start(unsigned long regaddr);
+static unsigned char at24_readb(unsigned long regaddr, unsigned char addr);
 
 static unsigned short abyss_sifreadb(struct net_device *dev, unsigned short reg)
 {
@@ -83,129 +91,100 @@ static void abyss_sifwritew(struct net_device *dev, unsigned short val, unsigned
        outw(val, dev->base_addr + reg);
 }
 
-struct tms_abyss_card {
-       struct net_device *dev;
-       struct pci_dev *pci_dev;
-       struct tms_abyss_card *next;
-};
-static struct tms_abyss_card *abyss_card_list = NULL;
-
-int __init abyss_probe(void)
+static int __init abyss_attach(struct pci_dev *pdev, const struct pci_device_id *ent)
 {      
-       static int versionprinted = 0;
-       struct pci_dev *pdev = NULL ; 
+       static int versionprinted;
        struct net_device *dev;
        struct net_local *tp;
-       int i;
-       
-       if (!pci_present())
-               return (-1);    /* No PCI present. */
+       int i, ret, pci_irq_line;
+       unsigned long pci_ioaddr;
        
-       while ( (pdev=pci_find_class(PCI_CLASS_NETWORK_TOKEN_RING<<8, pdev))) { 
-               unsigned int pci_irq_line;
-               unsigned long pci_ioaddr;
-               struct tms_abyss_card *card;
-               
-               /* We only support Madge Smart 16/4 PCI Mk2 (Abyss) cards */
-               if ( (pdev->vendor != PCI_VENDOR_ID_MADGE) ||
-                    (pdev->device != PCI_DEVICE_ID_MADGE_MK2) )
-                       continue;
-               
-               if (versionprinted++ == 0)
-                       printk("%s", version);
+       if (versionprinted++ == 0)
+               printk("%s", version);
 
-               if (pci_enable_device(pdev))
-                       continue;
+       if (pci_enable_device(pdev))
+               return -EIO;
 
-               /* Remove I/O space marker in bit 0. */
-               pci_irq_line = pdev->irq;
-               pci_ioaddr = pci_resource_start (pdev, 0);
-               
-               if(!request_region(pci_ioaddr, ABYSS_IO_EXTENT, "abyss"))
-                       continue;
+       /* Remove I/O space marker in bit 0. */
+       pci_irq_line = pdev->irq;
+       pci_ioaddr = pci_resource_start (pdev, 0);
                
-               /* At this point we have found a valid card. */
+       /* At this point we have found a valid card. */
                
-               dev = init_trdev(NULL, 0);
-               if (!dev) {
-                       release_region(pci_ioaddr, ABYSS_IO_EXTENT);
-                       continue;
-               }
+       dev = init_trdev(NULL, 0);
+       if (!dev)
+               return -ENOMEM;
+       SET_MODULE_OWNER(dev);
+
+       if (!request_region(pci_ioaddr, ABYSS_IO_EXTENT, dev->name)) {
+               ret = -EBUSY;
+               goto err_out_trdev;
+       }
                
-               if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
-                              "abyss", dev)) { 
-                       release_region(pci_ioaddr, ABYSS_IO_EXTENT) ; 
-                       /* XXX free trdev */
-                       continue; /*return (-ENODEV);*/ /* continue; ?? */
-               }
+       ret = request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
+                         dev->name, dev);
+       if (ret)
+               goto err_out_region;
                
-               /*
-                 if (load_tms380_module("abyss.c")) {
-                 return 0;
-                 }
-               */
-
-               dev->base_addr  = pci_ioaddr;
-               dev->irq                = pci_irq_line;
-               dev->dma                = 0;
+       dev->base_addr  = pci_ioaddr;
+       dev->irq        = pci_irq_line;
                
-               printk("%s: Madge Smart 16/4 PCI Mk2 (Abyss)\n", dev->name);
-               printk("%s:    IO: %#4lx  IRQ: %d\n",
-                      dev->name, pci_ioaddr, dev->irq);
-               /*
-                * The TMS SIF registers lay 0x10 above the card base address.
-                */
-               dev->base_addr += 0x10;
+       printk("%s: Madge Smart 16/4 PCI Mk2 (Abyss)\n", dev->name);
+       printk("%s:    IO: %#4lx  IRQ: %d\n",
+              dev->name, pci_ioaddr, dev->irq);
+       /*
+        * The TMS SIF registers lay 0x10 above the card base address.
+        */
+       dev->base_addr += 0x10;
                
-               if (tmsdev_init(dev)) {
-                       printk("%s: unable to get memory for dev->priv.\n", 
-                              dev->name);
-                       return 0;
-               }
+       ret = tmsdev_init(dev);
+       if (ret) {
+               printk("%s: unable to get memory for dev->priv.\n", 
+                      dev->name);
+               goto err_out_irq;
+       }
 
-               abyss_read_eeprom(dev);
+       abyss_read_eeprom(dev);
                
-               printk("%s:    Ring Station Address: ", dev->name);
-               printk("%2.2x", dev->dev_addr[0]);
-               for (i = 1; i < 6; i++)
-                       printk(":%2.2x", dev->dev_addr[i]);
-               printk("\n");
-
-               tp = (struct net_local *)dev->priv;
-               tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */
-               tp->setnselout = abyss_setnselout_pins;
-               tp->sifreadb = abyss_sifreadb;
-               tp->sifreadw = abyss_sifreadw;
-               tp->sifwriteb = abyss_sifwriteb;
-               tp->sifwritew = abyss_sifwritew;
-
-               memcpy(tp->ProductID, "Madge PCI 16/4 Mk2", PROD_ID_SIZE + 1);
+       printk("%s:    Ring Station Address: ", dev->name);
+       printk("%2.2x", dev->dev_addr[0]);
+       for (i = 1; i < 6; i++)
+               printk(":%2.2x", dev->dev_addr[i]);
+       printk("\n");
+
+       tp = dev->priv;
+       tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */
+       tp->setnselout = abyss_setnselout_pins;
+       tp->sifreadb = abyss_sifreadb;
+       tp->sifreadw = abyss_sifreadw;
+       tp->sifwriteb = abyss_sifwriteb;
+       tp->sifwritew = abyss_sifwritew;
+
+       memcpy(tp->ProductID, "Madge PCI 16/4 Mk2", PROD_ID_SIZE + 1);
                
-               dev->open = abyss_open;
-               dev->stop = abyss_close;
-               
-               if (register_trdev(dev) == 0) {
-                       /* Enlist in the card list */
-                       card = kmalloc(sizeof(struct tms_abyss_card), 
-                                      GFP_KERNEL);
-                       card->next = abyss_card_list;
-                       abyss_card_list = card;
-                       card->dev = dev;
-                       card->pci_dev = pdev;
-               } else {
-                       printk("abyss: register_trdev() returned non-zero.\n");
-                       kfree(dev->priv);
-                       kfree(dev);
-                       return -1;
-               }
-       }
-       
-       if (abyss_card_list)
-               return 0;
-       return (-1);
+       dev->open = abyss_open;
+       dev->stop = abyss_close;
+
+       ret = register_trdev(dev);
+       if (ret)
+               goto err_out_tmsdev;
+
+       pci_set_drvdata(pdev, dev);
+       return 0;
+
+err_out_tmsdev:
+       kfree(dev->priv);
+err_out_irq:
+       free_irq(pdev->irq, dev);
+err_out_region:
+       release_region(pci_ioaddr, ABYSS_IO_EXTENT);
+err_out_trdev:
+       unregister_netdev(dev);
+       kfree(dev);
+       return ret;
 }
 
-unsigned short abyss_setnselout_pins(struct net_device *dev)
+static unsigned short abyss_setnselout_pins(struct net_device *dev)
 {
        unsigned short val = 0;
        struct net_local *tp = (struct net_local *)dev->priv;
@@ -228,7 +207,7 @@ unsigned short abyss_setnselout_pins(struct net_device *dev)
  * These access an Atmel AT24 SEEPROM using their glue chip registers. 
  *
  */
-void at24_writedatabyte(unsigned long regaddr, unsigned char byte)
+static void at24_writedatabyte(unsigned long regaddr, unsigned char byte)
 {
        int i;
        
@@ -239,7 +218,7 @@ void at24_writedatabyte(unsigned long regaddr, unsigned char byte)
        }
 }
 
-int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr)
+static int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr)
 {
        if (at24_sendcmd(regaddr, cmd)) {
                at24_writedatabyte(regaddr, addr);
@@ -248,7 +227,7 @@ int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char add
        return 0;
 }
 
-int at24_sendcmd(unsigned long regaddr, unsigned char cmd)
+static int at24_sendcmd(unsigned long regaddr, unsigned char cmd)
 {
        int i;
        
@@ -261,7 +240,7 @@ int at24_sendcmd(unsigned long regaddr, unsigned char cmd)
        return 0;
 }
 
-unsigned char at24_readdatabit(unsigned long regaddr)
+static unsigned char at24_readdatabit(unsigned long regaddr)
 {
        unsigned char val;
 
@@ -273,7 +252,7 @@ unsigned char at24_readdatabit(unsigned long regaddr)
        return val;
 }
 
-unsigned char at24_readdatabyte(unsigned long regaddr)
+static unsigned char at24_readdatabyte(unsigned long regaddr)
 {
        unsigned char data = 0;
        int i;
@@ -286,7 +265,7 @@ unsigned char at24_readdatabyte(unsigned long regaddr)
        return data;
 }
 
-int at24_waitforack(unsigned long regaddr)
+static int at24_waitforack(unsigned long regaddr)
 {
        int i;
        
@@ -297,7 +276,7 @@ int at24_waitforack(unsigned long regaddr)
        return 0;
 }
 
-int at24_waitfornack(unsigned long regaddr)
+static int at24_waitfornack(unsigned long regaddr)
 {
        int i;
        for (i = 0; i < 10; i++) {
@@ -307,10 +286,9 @@ int at24_waitfornack(unsigned long regaddr)
        return 0;
 }
 
-void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data)
+static void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data)
 {
-       unsigned char val;
-       val = AT24_ENABLE;
+       unsigned char val = AT24_ENABLE;
        if (clock)
                val |= AT24_CLOCK;
        if (data)
@@ -320,25 +298,15 @@ void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char dat
        tms380tr_wait(20); /* Very necessary. */
 }
 
-void at24_start(unsigned long regaddr)
+static void at24_start(unsigned long regaddr)
 {
        at24_setlines(regaddr, 0, 1);
        at24_setlines(regaddr, 1, 1);
        at24_setlines(regaddr, 1, 0);
        at24_setlines(regaddr, 0, 1);
-       return;
 }
 
-void at24_stop(unsigned long regaddr)
-{
-       at24_setlines(regaddr, 0, 0);
-       at24_setlines(regaddr, 1, 0);
-       at24_setlines(regaddr, 1, 1);
-       at24_setlines(regaddr, 0, 1);
-       return;
-}
-     
-unsigned char at24_readb(unsigned long regaddr, unsigned char addr)
+static unsigned char at24_readb(unsigned long regaddr, unsigned char addr)
 {
        unsigned char data = 0xff;
        
@@ -367,7 +335,6 @@ static void abyss_enable(struct net_device *dev)
        reset_reg |= PCIBM2_RESET_REG_CHIP_NRES;
        outb(reset_reg, ioaddr + PCIBM2_RESET_REG);
        tms380tr_wait(100);
-       return;
 }
 
 /*
@@ -411,14 +378,12 @@ static int abyss_chipset_init(struct net_device *dev)
        return 0;
 }
 
-void abyss_chipset_close(struct net_device *dev)
+static inline void abyss_chipset_close(struct net_device *dev)
 {
        unsigned long ioaddr;
        
        ioaddr = dev->base_addr;
        outb(0, ioaddr + PCIBM2_RESET_REG);
-       
-       return;
 }
 
 /*
@@ -451,15 +416,12 @@ static void abyss_read_eeprom(struct net_device *dev)
        for (i = 0; i < 6; i++) 
                dev->dev_addr[i] = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, 
                                              PCIBM2_SEEPROM_BIA+i);
-       
-       return;
 }
 
 static int abyss_open(struct net_device *dev)
 {  
        abyss_chipset_init(dev);
        tms380tr_open(dev);
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -467,41 +429,49 @@ static int abyss_close(struct net_device *dev)
 {
        tms380tr_close(dev);
        abyss_chipset_close(dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
-#ifdef MODULE
+static void __exit abyss_detach (struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       
+       if (!dev)
+               BUG();
+       unregister_netdev(dev);
+       release_region(dev->base_addr-0x10, ABYSS_IO_EXTENT);
+       free_irq(dev->irq, dev);
+       kfree(dev->priv);
+       kfree(dev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver abyss_driver = {
+       name:           "abyss",
+       id_table:       abyss_pci_tbl,
+       probe:          abyss_attach,
+       remove:         abyss_detach,
+};
 
-int init_module(void)
+static int __init abyss_init (void)
 {
-       /* Probe for cards. */
-       if (abyss_probe()) {
-               printk(KERN_NOTICE "abyss.c: No cards found.\n");
+       int rc = pci_register_driver (&abyss_driver);
+       if (rc < 0)
+               return rc;
+       if (rc == 0) {
+               pci_unregister_driver (&abyss_driver);
+               return -ENODEV;
        }
-       /* lock_tms380_module(); */
-       return (0);
+       return 0;
 }
 
-void cleanup_module(void)
+static void __exit abyss_rmmod (void)
 {
-       struct net_device *dev;
-       struct tms_abyss_card *this_card;
-       
-       while (abyss_card_list) {
-               dev = abyss_card_list->dev;
-               unregister_netdev(dev);
-               release_region(dev->base_addr-0x10, ABYSS_IO_EXTENT);
-               free_irq(dev->irq, dev);
-               kfree(dev->priv);
-               kfree(dev);
-               this_card = abyss_card_list;
-               abyss_card_list = this_card->next;
-               kfree(this_card);
-       }
-       /* unlock_tms380_module(); */
+       pci_unregister_driver (&abyss_driver);
 }
-#endif /* MODULE */
+
+module_init(abyss_init);
+module_exit(abyss_rmmod);
 
 \f
 /*
index b8784bb29feb34a14a612be10e95a2ac5870895e..c42f3f6eb5888914318bf4ee537cb1f3270b5095 100644 (file)
 static char *version = 
 "Olympic.c v0.5.0 3/10/00 - Peter De Schrijver & Mike Phillips" ; 
 
+static struct pci_device_id olympic_pci_tbl[] __initdata = {
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, PCI_ANY_ID, PCI_ANY_ID, },
+       { }                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, olympic_pci_tbl);
+
+
 static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
                                   "Address Verification", "Neighbor Notification (Ring Poll)",
                                   "Request Parameters","FDX Registration Request",
index 029e0cdfa8132a355a116ed1842d21a677b5bf80..216154db560f13d4d65188447ee8fc474ee81e1c 100644 (file)
  *  Modification History:
  *     30-Dec-99       AF      Split off from the tms380tr driver.
  *     22-Jan-00       AF      Updated to use indirect read/writes
+ *     23-Nov-00       JG      New PCI API, cleanups
  *
  *  TODO:
  *     1. See if we can use MMIO instead of port accesses
  *
  */
-static const char *version = "tmspci.c: v1.01 22/01/2000 by Adam Fritzler\n";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -41,33 +41,32 @@ static const char *version = "tmspci.c: v1.01 22/01/2000 by Adam Fritzler\n";
 #include <linux/trdevice.h>
 #include "tms380tr.h"
 
+static char version[] __initdata =
+"tmspci.c: v1.02 23/11/2000 by Adam Fritzler\n";
+
 #define TMS_PCI_IO_EXTENT 32
 
-struct cardinfo_table {
-       int vendor_id; /* PCI info */
-       int device_id;
-       int registeroffset; /* SIF offset from dev->base_addr */
+struct card_info {
        unsigned char nselout[2]; /* NSELOUT vals for 4mb([0]) and 16mb([1]) */
        char *name;
 };
 
-struct cardinfo_table probelist[] = {
-       { 0, 0,
-         0x0000, {0x00, 0x00}, "Unknown TMS380 Token Ring Adapter"},
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, 
-         0x0000, {0x03, 0x01}, "Compaq 4/16 TR PCI"},
-       { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, 
-         0x0000, {0x03, 0x01}, "SK NET TR 4/16 PCI"},
-       { PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING,
-         0x0000, {0x03, 0x01}, "Thomas-Conrad TC4048 PCI 4/16"},
-       { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C339,
-         0x0000, {0x03, 0x01}, "3Com Token Link Velocity"},
-       { 0, 0, 0, {0x00, 0x00}, NULL}
+static struct card_info card_info_table[] = {
+       { {0x03, 0x01}, "Compaq 4/16 TR PCI"},
+       { {0x03, 0x01}, "SK NET TR 4/16 PCI"},
+       { {0x03, 0x01}, "Thomas-Conrad TC4048 PCI 4/16"},
+       { {0x03, 0x01}, "3Com Token Link Velocity"},
+};
+
+static struct pci_device_id tmspci_pci_tbl[] __initdata = {
+       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+       { PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+       { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C339, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+       { }                     /* Terminating entry */
 };
+MODULE_DEVICE_TABLE(pci, tmspci_pci_tbl);
 
-int tms_pci_probe(void);
-static int tms_pci_open(struct net_device *dev);
-static int tms_pci_close(struct net_device *dev);
 static void tms_pci_read_eeprom(struct net_device *dev);
 static unsigned short tms_pci_setnselout_pins(struct net_device *dev);
 
@@ -91,145 +90,97 @@ static void tms_pci_sifwritew(struct net_device *dev, unsigned short val, unsign
        outw(val, dev->base_addr + reg);
 }
 
-struct tms_pci_card {
-       struct net_device *dev;
-       struct pci_dev *pci_dev;
-       struct cardinfo_table *cardinfo;
-       struct tms_pci_card *next;
-};
-static struct tms_pci_card *tms_pci_card_list = NULL;
-
-
-struct cardinfo_table * __init tms_pci_getcardinfo(unsigned short vendor, 
-                                                  unsigned short device)
-{
-       int cur;
-       for (cur = 1; probelist[cur].name != NULL; cur++) {
-               if ((probelist[cur].vendor_id == vendor) && 
-                   (probelist[cur].device_id == device))
-                       return &probelist[cur];
-       }
-       
-       return NULL;
-}
-
-int __init tms_pci_probe(void)
+static int __init tms_pci_attach(struct pci_dev *pdev, const struct pci_device_id *ent)
 {      
-       static int versionprinted = 0;
-       struct pci_dev *pdev = NULL ; 
+       static int versionprinted;
        struct net_device *dev;
        struct net_local *tp;
-       int i;
-
-       if (!pci_present())
-               return (-1);    /* No PCI present. */
-  
-       while ( (pdev=pci_find_class(PCI_CLASS_NETWORK_TOKEN_RING<<8, pdev))) { 
-               unsigned int pci_irq_line;
-               unsigned long pci_ioaddr;
-               struct tms_pci_card *card;
-               struct cardinfo_table *cardinfo;
+       int i, ret;
+       unsigned int pci_irq_line;
+       unsigned long pci_ioaddr;
+       struct card_info *cardinfo = &card_info_table[ent->driver_data];
                
-               if ((cardinfo = 
-                    tms_pci_getcardinfo(pdev->vendor, pdev->device)) == NULL)
-                       continue;       
+       if (versionprinted++ == 0)
+               printk("%s", version);
 
-               if (versionprinted++ == 0)
-                       printk("%s", version);
+       if (pci_enable_device(pdev))
+               return -EIO;
 
-               if (pci_enable_device(pdev))
-                       continue;
+       /* Remove I/O space marker in bit 0. */
+       pci_irq_line = pdev->irq;
+       pci_ioaddr = pci_resource_start (pdev, 0);
 
-               /* Remove I/O space marker in bit 0. */
-               pci_irq_line = pdev->irq;
-               pci_ioaddr = pci_resource_start (pdev, 0);
+       /* At this point we have found a valid card. */
+       dev = init_trdev(NULL, 0);
+       if (!dev)
+               return -ENOMEM;
+       SET_MODULE_OWNER(dev);
                
-               if(check_region(pci_ioaddr, TMS_PCI_IO_EXTENT))
-                       continue;
-    
-               /* At this point we have found a valid card. */
-    
-               dev = init_trdev(NULL, 0);
-               if (!dev) {
-                       continue; /*return (-ENOMEM);*/ /* continue; ?? */
-               }
-               
-               request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, cardinfo->name); /* XXX check return */
-               if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
-                              cardinfo->name, dev)) { 
-                       release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); 
-                       /* XXX free trdev */
-                       continue; /*return (-ENODEV);*/ /* continue; ?? */
-               }
-
-               /*
-                 if (load_tms380_module("tmspci.c")) {
-                 return 0;
-                 }
-               */
-
-               pci_ioaddr &= ~3 ; 
-               dev->base_addr  = pci_ioaddr;
-               dev->irq                = pci_irq_line;
-               dev->dma                = 0;
-               
-               printk("%s: %s\n", dev->name, cardinfo->name);
-               printk("%s:    IO: %#4lx  IRQ: %d\n",
-                      dev->name, dev->base_addr, dev->irq);
-               /*
-                * Some cards have their TMS SIF registers offset from
-                * their given base address.  Account for that here. 
-                */
-               dev->base_addr += cardinfo->registeroffset;
+       if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) {
+               ret = -EBUSY;
+               goto err_out_trdev;
+       }
+
+       ret = request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
+                         dev->name, dev);
+       if (ret)
+               goto err_out_region;
+
+       dev->base_addr  = pci_ioaddr;
+       dev->irq        = pci_irq_line;
+       dev->dma        = 0;
+
+       printk("%s: %s\n", dev->name, cardinfo->name);
+       printk("%s:    IO: %#4lx  IRQ: %d\n",
+              dev->name, dev->base_addr, dev->irq);
                
-               tms_pci_read_eeprom(dev);
+       tms_pci_read_eeprom(dev);
 
-               printk("%s:    Ring Station Address: ", dev->name);
-               printk("%2.2x", dev->dev_addr[0]);
-               for (i = 1; i < 6; i++)
-                       printk(":%2.2x", dev->dev_addr[i]);
-               printk("\n");
+       printk("%s:    Ring Station Address: ", dev->name);
+       printk("%2.2x", dev->dev_addr[0]);
+       for (i = 1; i < 6; i++)
+               printk(":%2.2x", dev->dev_addr[i]);
+       printk("\n");
                
-               if (tmsdev_init(dev)) {
-                       printk("%s: unable to get memory for dev->priv.\n", dev->name);
-                       return 0;
-               }
-
-               tp = (struct net_local *)dev->priv;
-               tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */
-               tp->setnselout = tms_pci_setnselout_pins;
+       ret = tmsdev_init(dev);
+       if (ret) {
+               printk("%s: unable to get memory for dev->priv.\n", dev->name);
+               goto err_out_irq;
+       }
+
+       tp = dev->priv;
+       tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */
+       tp->setnselout = tms_pci_setnselout_pins;
                
-               tp->sifreadb = tms_pci_sifreadb;
-               tp->sifreadw = tms_pci_sifreadw;
-               tp->sifwriteb = tms_pci_sifwriteb;
-               tp->sifwritew = tms_pci_sifwritew;
+       tp->sifreadb = tms_pci_sifreadb;
+       tp->sifreadw = tms_pci_sifreadw;
+       tp->sifwriteb = tms_pci_sifwriteb;
+       tp->sifwritew = tms_pci_sifwritew;
                
-               memcpy(tp->ProductID, cardinfo->name, PROD_ID_SIZE + 1);
-
-               tp->tmspriv = cardinfo;
-
-               dev->open = tms_pci_open;
-               dev->stop = tms_pci_close;
-
-               if (register_trdev(dev) == 0) {
-                       /* Enlist in the card list */
-                       card = kmalloc(sizeof(struct tms_pci_card), GFP_KERNEL);
-                       card->next = tms_pci_card_list;
-                       tms_pci_card_list = card;
-                       card->dev = dev;
-                       card->pci_dev = pdev;
-                       card->cardinfo = cardinfo;
-               } else {
-                       printk("%s: register_trdev() returned non-zero.\n", dev->name);
-                       kfree(dev->priv);
-                       kfree(dev);
-                       return -1;
-               }
-       }
+       memcpy(tp->ProductID, cardinfo->name, PROD_ID_SIZE + 1);
+
+       tp->tmspriv = cardinfo;
+
+       dev->open = tms380tr_open;
+       dev->stop = tms380tr_close;
+
+       ret = register_trdev(dev);
+       if (!ret)
+               goto err_out_tmsdev;
        
-       if (tms_pci_card_list)
-               return 0;
-       return (-1);
+       pci_set_drvdata(pdev, dev);
+       return 0;
+
+err_out_tmsdev:
+       kfree(dev->priv);
+err_out_irq:
+       free_irq(pdev->irq, dev);
+err_out_region:
+       release_region(pci_ioaddr, TMS_PCI_IO_EXTENT);
+err_out_trdev:
+       unregister_netdev(dev);
+       kfree(dev);
+       return ret;
 }
 
 /*
@@ -255,11 +206,11 @@ static void tms_pci_read_eeprom(struct net_device *dev)
                dev->dev_addr[i] = tms_pci_sifreadw(dev, SIFINC) >> 8;
 }
 
-unsigned short tms_pci_setnselout_pins(struct net_device *dev)
+static unsigned short tms_pci_setnselout_pins(struct net_device *dev)
 {
        unsigned short val = 0;
-       struct net_local *tp = (struct net_local *)dev->priv;
-       struct cardinfo_table *cardinfo = (struct cardinfo_table *)tp->tmspriv;
+       struct net_local *tp = dev->priv;
+       struct card_info *cardinfo = tp->tmspriv;
   
        if(tp->DataRate == SPEED_4)
                val |= cardinfo->nselout[0];    /* Set 4Mbps */
@@ -268,65 +219,46 @@ unsigned short tms_pci_setnselout_pins(struct net_device *dev)
        return val;
 }
 
-static int tms_pci_open(struct net_device *dev)
-{  
-       tms380tr_open(dev);
-       MOD_INC_USE_COUNT;
-       return 0;
-}
-
-static int tms_pci_close(struct net_device *dev)
+static void __exit tms_pci_detach (struct pci_dev *pdev)
 {
-       tms380tr_close(dev);
-       MOD_DEC_USE_COUNT;
-       return 0;
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       if (!dev)
+               BUG();
+       unregister_netdev(dev);
+       release_region(dev->base_addr, TMS_PCI_IO_EXTENT);
+       free_irq(dev->irq, dev);
+       kfree(dev->priv);
+       kfree(dev);
+       pci_set_drvdata(pdev, NULL);
 }
 
-#ifdef MODULE
+static struct pci_driver tms_pci_driver = {
+       name:           "tmspci",
+       id_table:       tmspci_pci_tbl,
+       probe:          tms_pci_attach,
+       remove:         tms_pci_detach,
+};
 
-int init_module(void)
+static int __init tms_pci_init (void)
 {
-       /* Probe for cards. */
-       if (tms_pci_probe()) {
-               printk(KERN_NOTICE "tmspci.c: No cards found.\n");
+       int rc = pci_register_driver (&tms_pci_driver);
+       if (rc < 0)
+               return rc;
+       if (rc == 0) {
+               pci_unregister_driver (&tms_pci_driver);
+               return -ENODEV;
        }
-       /* lock_tms380_module(); */
-       return (0);
+       return 0;
 }
 
-void cleanup_module(void)
+static void __exit tms_pci_rmmod (void)
 {
-       struct net_device *dev;
-       struct tms_pci_card *this_card;
-
-       while (tms_pci_card_list) {
-               dev = tms_pci_card_list->dev;
-               
-               /*
-                * If we used a register offset, revert here.
-                */
-               if (dev->priv)
-               {       
-                       struct net_local *tp;
-                       struct cardinfo_table *cardinfo;
-
-                       tp = (struct net_local *)dev->priv;
-                       cardinfo = (struct cardinfo_table *)tp->tmspriv;
-                       
-                       dev->base_addr -= cardinfo->registeroffset;
-               }
-               unregister_netdev(dev);
-               release_region(dev->base_addr, TMS_PCI_IO_EXTENT);
-               free_irq(dev->irq, dev);
-               kfree(dev->priv);
-               kfree(dev);
-               this_card = tms_pci_card_list;
-               tms_pci_card_list = this_card->next;
-               kfree(this_card);
-       }
-       /* unlock_tms380_module(); */
+       pci_unregister_driver (&tms_pci_driver);
 }
-#endif /* MODULE */
+
+module_init(tms_pci_init);
+module_exit(tms_pci_rmmod);
 
 \f
 /*
index de4af6890a688424dfa18938ada0d258a119b2fc..e91f3b0cc610c487744f53145014580f36cb4dce 100644 (file)
@@ -73,9 +73,9 @@ static int rx_copybreak = 100;
 
 #if defined(__alpha__)
 static int csr0 = 0x01A00000 | 0xE000;
-#elif defined(__i386__) || defined(__powerpc__) || defined(__hppa__)
+#elif defined(__i386__) || defined(__powerpc__)
 static int csr0 = 0x01A00000 | 0x8000;
-#elif defined(__sparc__)
+#elif defined(__sparc__) || defined(__hppa__)
 /* The UltraSparc PCI controllers will disconnect at every 64-byte
  * crossing anyways so it makes no sense to tell Tulip to burst
  * any more than that.
index 99ed14b8fbd526ebfaa229230295d965e4c017f4..72a8ec211b2e2fc41a3519bde3389c9348f7bacf 100644 (file)
@@ -573,10 +573,10 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
                        res->start |= ((unsigned long) l) << 32;
                        res->end = res->start + sz;
                        pci_write_config_dword(dev, reg+4, ~0);
-                       pci_read_config_dword(dev, reg+4, &tmp);
+                       pci_read_config_dword(dev, reg+4, &sz);
                        pci_write_config_dword(dev, reg+4, l);
-                       if (l)
-                               res->end = res->start + (((unsigned long) ~l) << 32);
+                       if (sz)
+                               res->end = res->start + (((unsigned long) ~sz) << 32);
 #else
                        if (l) {
                                printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
index 0aa3b1670d43a0e64eb0bc3d369852fc409de137..155f32b22e04aaaf17e9b7f9cf637d0ce3c84d31 100644 (file)
@@ -73,6 +73,7 @@
  *     Richard Hirst <richard@sleepie.demon.co.uk>  August 2000
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <asm/system.h>
index 0bd691e8238f8ca7ebdaec900e0554bb51f5fae7..d66d24e240e0e6da80c956f18bedbfb81c7c15cc 100644 (file)
@@ -2264,10 +2264,13 @@ ymf_install(struct pci_dev *pcidev, int instance, int devx)
        codec->inst = instance;
        codec->irq = pcidev->irq;
        codec->device_id = pcidev->device;
+
+       pci_enable_device(pcidev);
+       pci_set_master(pcidev);
+
        pci_read_config_byte(pcidev, PCI_REVISION_ID, (u8 *)&codec->rev);
        codec->reg_area_phys = pci_resource_start(pcidev, 0);
        codec->reg_area_virt = (unsigned long)ioremap(codec->reg_area_phys, 0x8000);
-       pci_set_master(pcidev);
 
        /* XXX KERN_INFO */
        printk("ymfpci%d: %s at 0x%lx IRQ %d\n", instance,
index 91f75f234eb2d43522a93a86b32fcd703ebe52f3..88112996668c83c0cc6de39c0ee593300d6a88f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * acm.c  Version 0.16
+ * acm.c  Version 0.18
  *
  * Copyright (c) 1999 Armin Fuerst     <fuerst@in.tum.de>
  * Copyright (c) 1999 Pavel Machek     <pavel@suse.cz>
@@ -19,6 +19,8 @@
  *     v0.14 - sized down struct acm
  *     v0.15 - fixed flow control again - characters could be lost
  *     v0.16 - added code for modems with swapped data and control interfaces
+ *     v0.17 - added new style probing
+ *     v0.18 - fixed new style probing for devices with more configurations
  */
 
 /*
@@ -144,7 +146,7 @@ struct acm {
 
 static struct usb_driver acm_driver;
 static struct tty_driver acm_tty_driver;
-static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, /* .... */ };
+static struct acm *acm_table[ACM_TTY_MINORS];
 
 #define ACM_READY(acm) (acm && acm->dev && acm->used)
 
@@ -185,7 +187,7 @@ static void acm_ctrl_irq(struct urb *urb)
        switch (dr->request) {
 
                case ACM_IRQ_NETWORK:
-       
+
                        dbg("%s network", data[0] ? "connected to" : "disconnected from");
                        return;
 
@@ -267,7 +269,7 @@ static void acm_softint(void *private)
        struct acm *acm = private;
        struct tty_struct *tty = acm->tty;
 
-       if (!ACM_READY(acm)) return;
+       if (!ACM_READY(acm)) return;
 
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
                (tty->ldisc.write_wakeup)(tty);
@@ -420,15 +422,15 @@ static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int
                                case TIOCMBIS: newctrl |=  mask; break;
                                case TIOCMBIC: newctrl &= ~mask; break;
                        }
-       
-                       if (acm->ctrlout == newctrl) return 0; 
+
+                       if (acm->ctrlout == newctrl) return 0;
                        return acm_set_control(acm, acm->ctrlout = newctrl);
        }
 
        return -ENOIOCTLCMD;
 }
 
-static __u32 acm_tty_speed[] = { 
+static __u32 acm_tty_speed[] = {
        0, 50, 75, 110, 134, 150, 200, 300, 600,
        1200, 1800, 2400, 4800, 9600, 19200, 38400,
        57600, 115200, 230400, 460800, 500000, 576000,
@@ -457,7 +459,7 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
        newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
 
        acm->clocal = termios->c_cflag & CLOCAL;
-       
+
        if (!newline.speed) {
                newline.speed = acm->line.speed;
                newctrl &= ~ACM_CTRL_DTR;
@@ -484,106 +486,114 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
        struct usb_config_descriptor *cfacm;
        struct usb_interface_descriptor *ifcom, *ifdata;
        struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
-       int readsize, ctrlsize, minor;
+       int readsize, ctrlsize, minor, i;
        unsigned char *buf;
 
-       /* Since 0 is treated as a wildcard by the USB pattern matching,
-          we explicitly check bDeviceSubClass and bDeviceProtocol
-          here. */
-       if (dev->descriptor.bDeviceSubClass != 0
-               || dev->descriptor.bDeviceProtocol != 0) return NULL;
+/*
+ * Since 0 is treated as a wildcard by the USB pattern matching,
+ * we explicitly check bDeviceSubClass and bDeviceProtocol here.
+ */
 
-       cfacm = dev->actconfig;
+       if (dev->descriptor.bDeviceSubClass != 0 ||
+           dev->descriptor.bDeviceProtocol != 0)
+               return NULL;
 
-       dbg("probing config %d", cfacm->bConfigurationValue);
+       for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 
-       if (cfacm->bNumInterfaces != 2 || 
-           usb_interface_claimed(cfacm->interface + 0) ||
-           usb_interface_claimed(cfacm->interface + 1))
-               return NULL;
+               cfacm = dev->config + i;
 
-       ifcom = cfacm->interface[0].altsetting + 0;
-       ifdata = cfacm->interface[1].altsetting + 0;
+               dbg("probing config %d", cfacm->bConfigurationValue);
 
-       if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) {
-               ifcom = cfacm->interface[1].altsetting + 0;
-               ifdata = cfacm->interface[0].altsetting + 0;
-               if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
-                       return NULL;
-       }
+               if (cfacm->bNumInterfaces != 2 ||
+                   usb_interface_claimed(cfacm->interface + 0) ||
+                   usb_interface_claimed(cfacm->interface + 1))
+                       continue;
 
-       if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
-           ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints < 1)
-                       return NULL;
+               ifcom = cfacm->interface[0].altsetting + 0;
+               ifdata = cfacm->interface[1].altsetting + 0;
 
-       epctrl = ifcom->endpoint + 0;
-       epread = ifdata->endpoint + 0;
-       epwrite = ifdata->endpoint + 1;
+               if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
+                       ifcom = cfacm->interface[1].altsetting + 0;
+                       ifdata = cfacm->interface[0].altsetting + 0;
+                       if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
+                               continue;
+               }
 
-       if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
-           (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
-           ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
-               return NULL;
+               if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
+                   ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints < 1)
+                       continue;
 
-       if ((epread->bEndpointAddress & 0x80) != 0x80) {
-               epread = ifdata->endpoint + 1;
-               epwrite = ifdata->endpoint + 0;
-       }
+               epctrl = ifcom->endpoint + 0;
+               epread = ifdata->endpoint + 0;
+               epwrite = ifdata->endpoint + 1;
 
-       usb_set_configuration(dev, cfacm->bConfigurationValue);
+               if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
+                  (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
+                  ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
+                       continue;
 
-       for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
-       if (acm_table[minor]) {
-               err("no more free acm devices");
-               return NULL;
-       }
+               if ((epread->bEndpointAddress & 0x80) != 0x80) {
+                       epread = ifdata->endpoint + 1;
+                       epwrite = ifdata->endpoint + 0;
+               }
 
-       if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
-               err("out of memory");
-               return NULL;
-       }
-       memset(acm, 0, sizeof(struct acm));
+               usb_set_configuration(dev, cfacm->bConfigurationValue);
 
-       ctrlsize = epctrl->wMaxPacketSize;
-       readsize = epread->wMaxPacketSize;
-       acm->writesize = epwrite->wMaxPacketSize;
-       acm->iface = cfacm->interface;
-       acm->minor = minor;
-       acm->dev = dev;
+               for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
+               if (acm_table[minor]) {
+                       err("no more free acm devices");
+                       return NULL;
+               }
 
-       acm->tqueue.routine = acm_softint;
-       acm->tqueue.data = acm;
+               if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
+                       err("out of memory");
+                       return NULL;
+               }
+               memset(acm, 0, sizeof(struct acm));
 
-       if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
-               err("out of memory");
-               kfree(acm);
-               return NULL;
-       }
+               ctrlsize = epctrl->wMaxPacketSize;
+               readsize = epread->wMaxPacketSize;
+               acm->writesize = epwrite->wMaxPacketSize;
+               acm->iface = cfacm->interface;
+               acm->minor = minor;
+               acm->dev = dev;
 
-       FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
-               buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+               acm->tqueue.routine = acm_softint;
+               acm->tqueue.data = acm;
 
-       FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
-               buf += ctrlsize, readsize, acm_read_bulk, acm);
-       acm->readurb.transfer_flags |= USB_NO_FSBR;
+               if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
+                       err("out of memory");
+                       kfree(acm);
+                       return NULL;
+               }
+
+               FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
+                       buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
 
-       FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
-               buf += readsize, acm->writesize, acm_write_bulk, acm);
-       acm->writeurb.transfer_flags |= USB_NO_FSBR;
+               FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+                       buf += ctrlsize, readsize, acm_read_bulk, acm);
+               acm->readurb.transfer_flags |= USB_NO_FSBR;
 
-       printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+               FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+                       buf += readsize, acm->writesize, acm_write_bulk, acm);
+               acm->writeurb.transfer_flags |= USB_NO_FSBR;
 
-       acm_set_control(acm, acm->ctrlout);
+               printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
 
-       acm->line.speed = cpu_to_le32(9600);
-       acm->line.databits = 8;
-       acm_set_line(acm, &acm->line);
+               acm_set_control(acm, acm->ctrlout);
 
-       usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
-       usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+               acm->line.speed = cpu_to_le32(9600);
+               acm->line.databits = 8;
+               acm_set_line(acm, &acm->line);
+
+               usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
+               usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+
+               tty_register_devfs(&acm_tty_driver, 0, minor);
+               return acm_table[minor] = acm;
+       }
 
-       tty_register_devfs(&acm_tty_driver, 0, minor);
-       return acm_table[minor] = acm;
+       return NULL;
 }
 
 static void acm_disconnect(struct usb_device *dev, void *ptr)
@@ -621,10 +631,9 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
  * USB driver structure.
  */
 
-static struct usb_device_id acm_ids [] = {
-    { bDeviceClass: 2},
-    { bInterfaceClass: 2, bInterfaceSubClass: 2, bInterfaceProtocol: 1},
-    { }                                                /* Terminating entry */
+static struct usb_device_id acm_ids[] = {
+       { bDeviceClass: 2, bDeviceSubClass: 0, bDeviceProtocol: 0},
+       { }
 };
 
 MODULE_DEVICE_TABLE (usb, acm_ids);
index a22694d4e42b1a06b4dd31be10c23b1ae62a7c96..63b5458e5472db2e4add06c4b18517904c21be64 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (12/03/2000) gb
+ *     Added port->tty->ldisc.set_termios(port->tty, NULL) to empeg_open()
+ *      This notifies the tty driver that the termios have changed.
+ * 
  * (11/13/2000) gb
  *     Moved tty->low_latency = 1 from empeg_read_bulk_callback() to empeg_open()
  *     (It only needs to be set once - Doh!)
@@ -162,6 +166,15 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp)
        port->tty->termios->c_cflag
                |= CS8;
 
+       /* gb - 2000/12/03
+        *
+        * Contributed by Borislav Deianov
+        *
+        * Notify the tty driver that the termios have changed!!
+        *
+        */
+        port->tty->ldisc.set_termios(port->tty, NULL);
+
        /* gb - 2000/11/05
         *
         * force low_latency on
index fcdf71e841ea01b9879299c419a1497a671ba198..c52ad0b37200d358668a877eb0947b4fad44e05a 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info
+ *     and extra documentation
+ *       
+ * (12/3/2000) Bill Ryder
+ *     Added support for 8U232AM device.
+ *     Moved PID and VIDs into header file only.
+ *     Turned on low-latency for the tty (device will do high baudrates)
+ *     Added shutdown routine to close files when device removed.
+ *     More debug and error message cleanups.
+ *     
+ *
  * (11/13/2000) Bill Ryder
  *     Added spinlock protected open code and close code.
- *     Multiple opens work (sort of - see webpage).
+ *     Multiple opens work (sort of - see webpage mentioned above).
  *     Cleaned up comments. Removed multiple PID/VID definitions.
  *     Factorised cts/dtr code
  *     Made use of __FUNCTION__ in dbg's
  *     driver is a loadable module now.
  *
  * (04/04/2000) Bill Ryder 
- *         Fixed bugs in TCGET/TCSET ioctls (by removing them - they are 
- *             handled elsewhere in the serial driver chain).
+ *      Fixed bugs in TCGET/TCSET ioctls (by removing them - they are 
+ *        handled elsewhere in the tty io driver chain).
  *
  * (03/30/2000) Bill Ryder 
- *         Implemented lots of ioctls
+ *      Implemented lots of ioctls
  *     Fixed a race condition in write
  *     Changed some dbg's to errs
  *
@@ -50,6 +61,7 @@
 /* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
 /* Thanx to FTDI for so kindly providing details of the protocol required */
 /*   to talk to the device */
+/* Thanx to gkh and the rest of the usb dev group for all code I have assimilated :-) */
 
 
 #include <linux/config.h>
 
 #include "ftdi_sio.h"
 
-#define FTDI_VENDOR_ID                 FTDI_VID
-#define FTDI_SIO_SERIAL_CONVERTER_ID   FTDI_SIO_PID
-#define FTDI_8U232AM_PID               0x6001
 
 static __devinitdata struct usb_device_id id_table_sio [] = {
     { idVendor: FTDI_VID, idProduct: FTDI_SIO_PID },
     { }                                                /* Terminating entry */
 };
 
-MODULE_DEVICE_TABLE (usb, id_table_sio);
+/* THe 8U232AM has the same API as the sio - but it can support MUCH 
+   higher baudrates (921600 at 48MHz/230400 at 12MHz 
+   so .. it's baudrate setting codes are different */
+
+   
+static __devinitdata struct usb_device_id id_table_8U232AM [] = {
+    { idVendor: FTDI_VID, idProduct: FTDI_8U232AM_PID },
+    { }                                                /* Terminating entry */
+};
+
+
+static __devinitdata struct usb_device_id id_table_combined [] = {
+    { idVendor: FTDI_VID, idProduct: FTDI_SIO_PID },
+    { idVendor: FTDI_VID, idProduct: FTDI_8U232AM_PID },
+    { }                                                /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 
+struct ftdi_private {
+       ftdi_type_t ftdi_type;
+       char last_status_byte; /* device sends this every 40ms when open */
+       
+       
+};
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_startup           (struct usb_serial *serial);
+static int  ftdi_8U232AM_startup       (struct usb_serial *serial);
+static void ftdi_sio_shutdown          (struct usb_serial *serial);
 static int  ftdi_sio_open              (struct usb_serial_port *port, struct file *filp);
 static void ftdi_sio_close             (struct usb_serial_port *port, struct file *filp);
 static int  ftdi_sio_write             (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
@@ -100,13 +134,15 @@ static void ftdi_sio_read_bulk_callback   (struct urb *urb);
 static void ftdi_sio_set_termios       (struct usb_serial_port *port, struct termios * old);
 static int  ftdi_sio_ioctl             (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
 
-/* All of the device info needed for the FTDI SIO serial converter */
+/* Should rename most ftdi_sio's to ftdi_ now since there are two devices 
+   which share common code */ 
+
 struct usb_serial_device_type ftdi_sio_device = {
        name:                   "FTDI SIO",
        id_table:               id_table_sio,
-       needs_interrupt_in:     MUST_HAVE_NOT,          /* this device must not have an interrupt in endpoint */
-       needs_bulk_in:          MUST_HAVE,              /* this device must have a bulk in endpoint */
-       needs_bulk_out:         MUST_HAVE,              /* this device must have a bulk out endpoint */
+       needs_interrupt_in:     MUST_HAVE_NOT,
+       needs_bulk_in:          MUST_HAVE,
+       needs_bulk_out:         MUST_HAVE,
        num_interrupt_in:       0,
        num_bulk_in:            1,
        num_bulk_out:           1,
@@ -119,17 +155,35 @@ struct usb_serial_device_type ftdi_sio_device = {
        ioctl:                  ftdi_sio_ioctl,
        set_termios:            ftdi_sio_set_termios,
        startup:                ftdi_sio_startup,
+        shutdown:               ftdi_sio_shutdown,
 };
 
+struct usb_serial_device_type ftdi_8U232AM_device = {
+       name:                   "FTDI 8U232AM",
+       id_table:               id_table_8U232AM,
+       needs_interrupt_in:     DONT_CARE,
+       needs_bulk_in:          MUST_HAVE,
+       needs_bulk_out:         MUST_HAVE,
+       num_interrupt_in:       0,
+       num_bulk_in:            1,
+       num_bulk_out:           1,
+       num_ports:              1,
+       open:                   ftdi_sio_open,
+       close:                  ftdi_sio_close,
+       write:                  ftdi_sio_write,
+       read_bulk_callback:     ftdi_sio_read_bulk_callback,
+       write_bulk_callback:    ftdi_sio_write_bulk_callback,
+       ioctl:                  ftdi_sio_ioctl,
+       set_termios:            ftdi_sio_set_termios,
+       startup:                ftdi_8U232AM_startup,
+        shutdown:               ftdi_sio_shutdown,
+};
+
+
 /*
  * ***************************************************************************
  * FTDI SIO Serial Converter specific driver functions
  * ***************************************************************************
- *
- *    See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date
- *     testing information
- * 
- *
  */
 
 #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
@@ -165,15 +219,59 @@ static int set_dtr(struct usb_device *dev,
 }
 
 
-/* do some startup allocations not currently performed by usb_serial_probe() */
+
 static int ftdi_sio_startup (struct usb_serial *serial)
 {
+       struct ftdi_private *priv;
+       
        init_waitqueue_head(&serial->port[0].write_wait);
+       
+       priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
+       if (!priv){
+               err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
+               return -ENOMEM;
+       }
 
+       priv->ftdi_type = sio;
        
        return (0);
 }
 
+
+static int ftdi_8U232AM_startup (struct usb_serial *serial)
+{
+       struct ftdi_private *priv;
+       init_waitqueue_head(&serial->port[0].write_wait);
+
+       priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
+       if (!priv){
+               err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
+               return -ENOMEM;
+       }
+
+       priv->ftdi_type = F8U232AM;
+       
+       return (0);
+}
+
+static void ftdi_sio_shutdown (struct usb_serial *serial)
+{
+       
+       dbg (__FUNCTION__);
+
+       /* Close ports if they are open */
+       while (serial->port[0].open_count > 0) {
+               ftdi_sio_close (&serial->port[0], NULL);
+       }
+       if (serial->port->private){
+               kfree(serial->port->private);
+               serial->port->private = NULL;
+       }
+}
+
+
+
 static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
 { /* ftdi_sio_open */
        struct termios tmp_termios;
@@ -182,7 +280,7 @@ static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
        int result;
        char buf[1]; /* Needed for the usb_control_msg I think */
 
-       dbg(__FUNCTION__ " port %d", port->number);
+       dbg(__FUNCTION__);
 
        spin_lock_irqsave (&port->port_lock, flags);
        
@@ -191,29 +289,33 @@ static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
 
        if (!port->active){
                port->active = 1;
+
                spin_unlock_irqrestore (&port->port_lock, flags);
 
+               /* do not allow a task to be queued to deliver received data */
+               port->tty->low_latency = 1;
+
+               /* No error checking for this (will get errors later anyway) */
                /* See ftdi_sio.h for description of what is reset */
                usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                                FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
                                FTDI_SIO_RESET_SIO, 
                                0, buf, 0, WDR_TIMEOUT);
 
-               /* Setup termios */
+               /* Setup termios defaults. According to tty_io.c the 
+                  settings are driver specific */
                port->tty->termios->c_cflag =
                        B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 
                /* ftdi_sio_set_termios  will send usb control messages */
-               /* ftdi_sio_set_termios will set up port according to above list */
-               
                ftdi_sio_set_termios(port, &tmp_termios);       
 
-               /* Turn on RTS and DTR since we are not flow controlling*/
+               /* Turn on RTS and DTR since we are not flow controlling by default */
                if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
-                       err("Error from DTR HIGH urb");
+                       err(__FUNCTION__ " Error from DTR HIGH urb");
                }
                if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
-                       err("Error from RTS HIGH urb");
+                       err(__FUNCTION__ " Error from RTS HIGH urb");
                }
        
                /* Start reading from the device */
@@ -224,7 +326,7 @@ static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
                result = usb_submit_urb(port->read_urb);
                if (result)
                        err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-       } else { /* the port was already active - so no initialisation was done */
+       } else { /* the port was already active - so no initialisation is done */
                spin_unlock_irqrestore (&port->port_lock, flags);
        }
 
@@ -239,7 +341,7 @@ static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
        char buf[1];
        unsigned long flags;
 
-       dbg( __FUNCTION__ " port %d", port->number);
+       dbg( __FUNCTION__);
 
        spin_lock_irqsave (&port->port_lock, flags);
        --port->open_count;
@@ -271,14 +373,18 @@ static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
                usb_unlink_urb (port->read_urb);
                port->active = 0;
                port->open_count = 0;
-       } else { 
+       } else {  
                spin_unlock_irqrestore (&port->port_lock, flags);
+
+               /* Send a HUP if necessary */
+               if (!(port->tty->termios->c_cflag & CLOCAL)){
+                       tty_hangup(port->tty);
+               }
+               
        }
 
        MOD_DEC_USE_COUNT;
 
-
-
 } /* ftdi_sio_close */
 
 
@@ -292,7 +398,8 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
                           const unsigned char *buf, int count)
 { /* ftdi_sio_write */
        struct usb_serial *serial = port->serial;
-       const int data_offset = 1;
+       struct ftdi_private *priv = (struct ftdi_private *)port->private;
+       int data_offset ;
        int rc; 
        int result;
        DECLARE_WAITQUEUE(wait, current);
@@ -303,24 +410,25 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
                err("write request of 0 bytes");
                return 0;
        }
+       
+       if (priv->ftdi_type == sio){
+               data_offset = 1;
+       } else {
+               data_offset = 0;
+       }
+        dbg("data_offset set to %d",data_offset);
 
        /* only do something if we have a bulk out endpoint */
        if (serial->num_bulk_out) {
                unsigned char *first_byte = port->write_urb->transfer_buffer;
 
                /* Was seeing a race here, got a read callback, then write callback before
-                  hitting interuptible_sleep_on  - so wrapping in add_wait_queue stuff */
+                  hitting interuptible_sleep_on  - so wrapping in a wait_queue */
 
                add_wait_queue(&port->write_wait, &wait);
                set_current_state (TASK_INTERRUPTIBLE);
                while (port->write_urb->status == -EINPROGRESS) {
                        dbg(__FUNCTION__ " write in progress - retrying");
-                       if (0 /* file->f_flags & O_NONBLOCK */) {
-                               remove_wait_queue(&port->write_wait, &wait);
-                               set_current_state(TASK_RUNNING);
-                               rc = -EAGAIN;
-                               goto err;
-                       }
                        if (signal_pending(current)) {
                                current->state = TASK_RUNNING;
                                remove_wait_queue(&port->write_wait, &wait);
@@ -328,7 +436,6 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
                                goto err;
                        }
                        schedule();
-                       set_current_state (TASK_INTERRUPTIBLE);
                }               
                remove_wait_queue(&port->write_wait, &wait);
                set_current_state(TASK_RUNNING);
@@ -349,11 +456,13 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
                               buf, count - data_offset );
                }  
 
-               /* Write the control byte at the front of the packet*/
                first_byte = port->write_urb->transfer_buffer;
-               *first_byte = 1 | ((count-data_offset) << 2) ; 
+               if (data_offset > 0){
+                       /* Write the control byte at the front of the packet*/
+                       *first_byte = 1 | ((count-data_offset) << 2) ; 
+               }
 
-               dbg(__FUNCTION__ "Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+               dbg(__FUNCTION__ " Bytes: %d, First Byte: 0o%03o",count, first_byte[0]);
                usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
                
                /* send the data out the bulk port */
@@ -412,6 +521,7 @@ static void ftdi_sio_write_bulk_callback (struct urb *urb)
 static void ftdi_sio_read_bulk_callback (struct urb *urb)
 { /* ftdi_sio_serial_buld_callback */
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct ftdi_private *priv = (struct ftdi_private *)port->private;
        struct usb_serial *serial;
                struct tty_struct *tty = port->tty ;
                unsigned char *data = urb->transfer_buffer;
@@ -443,8 +553,10 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
                 dbg("Just status");
         }
 
+       priv->last_status_byte = data[0]; /* this has modem control lines */
+
        /* TO DO -- check for hung up line and handle appropriately: */
-       /*   send hangup (need to find out how to do this) */
+       /*   send hangup  */
        /* See acm.c - you do a tty_hangup  - eg tty_hangup(tty) */
        /* if CD is dropped and the line is not CLOCAL then we should hangup */
 
@@ -469,6 +581,53 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
        return;
 } /* ftdi_sio_serial_read_bulk_callback */
 
+
+__u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) 
+{ /* translate_baudrate_to_ftdi */
+       
+       __u16 urb_value = ftdi_sio_b9600;
+
+       if (ftdi_type == sio){
+               switch(cflag & CBAUD){
+               case B0: break; /* ignored by this */
+               case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
+               case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
+               case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
+               case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
+               case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
+               case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
+               case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
+               case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
+               case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
+               case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
+               default: dbg(__FUNCTION__ " FTDI_SIO does not support the baudrate (%d) requested",
+                            (cflag & CBAUD)); 
+                  break;
+               }
+       } else { /* it is 8U232AM */
+               switch(cflag & CBAUD){
+               case B0: break; /* ignored by this */
+               case B300: urb_value = ftdi_8U232AM_48MHz_b300; dbg("Set to 300"); break;
+               case B600: urb_value = ftdi_8U232AM_48MHz_b600; dbg("Set to 600") ; break;
+               case B1200: urb_value = ftdi_8U232AM_48MHz_b1200; dbg("Set to 1200") ; break;
+               case B2400: urb_value = ftdi_8U232AM_48MHz_b2400; dbg("Set to 2400") ; break;
+               case B4800: urb_value = ftdi_8U232AM_48MHz_b4800; dbg("Set to 4800") ; break;
+               case B9600: urb_value = ftdi_8U232AM_48MHz_b9600; dbg("Set to 9600") ; break;
+               case B19200: urb_value = ftdi_8U232AM_48MHz_b19200; dbg("Set to 19200") ; break;
+               case B38400: urb_value = ftdi_8U232AM_48MHz_b38400; dbg("Set to 38400") ; break;
+               case B57600: urb_value = ftdi_8U232AM_48MHz_b57600; dbg("Set to 57600") ; break;
+               case B115200: urb_value = ftdi_8U232AM_48MHz_b115200; dbg("Set to 115200") ; break;
+               case B230400: urb_value = ftdi_8U232AM_48MHz_b230400; dbg("Set to 230400") ; break;
+               case B460800: urb_value = ftdi_8U232AM_48MHz_b460800; dbg("Set to 460800") ; break;
+               case B921600: urb_value = ftdi_8U232AM_48MHz_b921600; dbg("Set to 921600") ; break;
+               default: dbg(__FUNCTION__ " The baudrate (%d) requested is not implemented",
+                            (cflag & CBAUD)); 
+                  break;
+               }
+       }
+       return(urb_value);
+}
+
 /* As I understand this - old_termios contains the original termios settings */
 /*  and tty->termios contains the new setting to be used */
 /* */
@@ -478,10 +637,12 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
 { /* ftdi_sio_set_termios */
        struct usb_serial *serial = port->serial;
        unsigned int cflag = port->tty->termios->c_cflag;
+       struct ftdi_private *priv = (struct ftdi_private *)port->private;       
        __u16 urb_value; /* will hold the new flags */
        char buf[1]; /* Perhaps I should dynamically alloc this? */
        
-       dbg(__FUNCTION__ " port %d", port->number);
+       
+       dbg(__FUNCTION__);
 
 
        /* FIXME -For this cut I don't care if the line is really changing or 
@@ -515,26 +676,12 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
                            urb_value , 0,
                            buf, 0, 100) < 0) {
-               err("FAILED to set databits/stopbits/parity");
+               err(__FUNCTION__ " FAILED to set databits/stopbits/parity");
        }          
 
        /* Now do the baudrate */
-
-       switch(cflag & CBAUD){
-       case B0: break; /* Handled below */
-       case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
-       case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
-       case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
-       case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
-       case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
-       case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
-       case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
-       case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
-       case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
-       case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
-       default: dbg(__FUNCTION__ "FTDI_SIO does not support the baudrate requested"); 
-               /* FIXME - how to return an error for this? */ break;
-       }
+       urb_value = translate_baudrate_to_ftdi((cflag & CBAUD), priv->ftdi_type);
+       
        if ((cflag & CBAUD) == B0 ) {
                /* Disable flow control */
                if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -542,30 +689,31 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                    0, 0, 
                                    buf, 0, WDR_TIMEOUT) < 0) {
-                       err("error from disable flowcontrol urb");
+                       err(__FUNCTION__ " error from disable flowcontrol urb");
                }           
                /* Drop RTS and DTR */
                if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
-                       err("Error from DTR LOW urb");
+                       err(__FUNCTION__ " Error from DTR LOW urb");
                }
                if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
-                       err("Error from RTS LOW urb");
+                       err(__FUNCTION__ " Error from RTS LOW urb");
                }       
                
        } else {
+               /* set the baudrate determined before */
                if (usb_control_msg(serial->dev, 
                                    usb_sndctrlpipe(serial->dev, 0),
                                    FTDI_SIO_SET_BAUDRATE_REQUEST, 
                                    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
                                    urb_value, 0, 
                                    buf, 0, 100) < 0) {
-                       err("urb failed to set baurdrate");
+                       err(__FUNCTION__ " urb failed to set baurdrate");
                }
        }
        /* Set flow control */
        /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
        if (cflag & CRTSCTS) {
-               dbg(__FUNCTION__ "Setting to CRTSCTS flow control");
+               dbg(__FUNCTION__ " Setting to CRTSCTS flow control");
                if (usb_control_msg(serial->dev, 
                                    usb_sndctrlpipe(serial->dev, 0),
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
@@ -576,9 +724,8 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
                }               
                
        } else { 
-               /* CHECK Assuming XON/XOFF handled by stack - not by device */
-               /* Disable flow control */
-               dbg(__FUNCTION__ "Turning off hardware flow control");
+               /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
+               dbg(__FUNCTION__ " Turning off hardware flow control");
                if (usb_control_msg(serial->dev, 
                                    usb_sndctrlpipe(serial->dev, 0),
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
@@ -595,6 +742,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
 static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
 {
        struct usb_serial *serial = port->serial;
+       struct ftdi_private *priv = (struct ftdi_private *)port->private;
        __u16 urb_value=0; /* Will hold the new flags */
        char buf[1];
        int  ret, mask;
@@ -605,16 +753,27 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
        switch (cmd) {
 
        case TIOCMGET:
-               dbg(__FUNCTION__ "TIOCMGET");
-               /* Request the status from the device */
-               if ((ret = usb_control_msg(serial->dev, 
-                                          usb_rcvctrlpipe(serial->dev, 0),
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                                          0, 0, 
-                                          buf, 1, HZ * 5)) < 0 ) {
-                       dbg(__FUNCTION__ "Get not get modem status of device");
-                       return(ret);
+               dbg(__FUNCTION__ " TIOCMGET");
+               /* The MODEM_STATUS_REQUEST works for the sio but not the 232 */
+               if (priv->ftdi_type == sio){
+                       /* TO DECIDE - use the 40ms status packets or not? */
+                       /*   PRO: No need to send urb */
+                       /*   CON: Could be 40ms out of date */
+
+                       /* Request the status from the device */
+                       if ((ret = usb_control_msg(serial->dev, 
+                                                  usb_rcvctrlpipe(serial->dev, 0),
+                                                  FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
+                                                  FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+                                                  0, 0, 
+                                                  buf, 1, WDR_TIMEOUT)) < 0 ) {
+                               err(__FUNCTION__ " Could not get modem status of device - err: %d",
+                                   ret);
+                               return(ret);
+                       }
+               } else {
+                       /* This gets updated every 40ms - so just copy it in */
+                       buf[0] = priv->last_status_byte;
                }
 
                return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
@@ -625,32 +784,20 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
                break;
 
        case TIOCMSET: /* Turns on and off the lines as specified by the mask */
-               dbg(__FUNCTION__ "TIOCMSET");
+               dbg(__FUNCTION__ " TIOCMSET");
                if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
-               urb_value = ((mask & TIOCM_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW);
-               if ((ret = usb_control_msg(serial->dev, 
-                                   usb_sndctrlpipe(serial->dev, 0),
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                   urb_value , 0,
-                                   buf, 0, WDR_TIMEOUT)) < 0){
-                       err("Urb to set DTR failed");
-                       return(ret);
-               }
-               urb_value = ((mask & TIOCM_RTS) ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW);
-               if ((ret = usb_control_msg(serial->dev, 
-                                   usb_sndctrlpipe(serial->dev, 0),
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                   urb_value , 0,
-                                   buf, 0, WDR_TIMEOUT)) < 0){
-                       err("Urb to set RTS failed");
-                       return(ret);
+               urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
+               if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
+                       err("Error from DTR set urb (TIOCMSET)");
                }
+               urb_value = ((mask & TIOCM_RTS) ? HIGH : LOW);
+               if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
+                       err("Error from RTS set urb (TIOCMSET)");
+               }       
                break;
                                        
        case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
-               dbg(__FUNCTION__ "TIOCMBIS");
+               dbg(__FUNCTION__ " TIOCMBIS");
                if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
                if (mask & TIOCM_DTR){
                        if ((ret = set_dtr(serial->dev, 
@@ -671,7 +818,7 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
                                        break;
 
        case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
-               dbg(__FUNCTION__ "TIOCMBIC");
+               dbg(__FUNCTION__ " TIOCMBIC");
                if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
                if (mask & TIOCM_DTR){
                        if ((ret = set_dtr(serial->dev, 
@@ -704,25 +851,28 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
          /* This is not an error - turns out the higher layers will do 
           *  some ioctls itself (see comment above)
           */
-               dbg(__FUNCTION__ "arg not supported - it was 0x%04x",cmd);
+               dbg(__FUNCTION__ " arg not supported - it was 0x%04x",cmd);
                return(-ENOIOCTLCMD);
                break;
        }
-       dbg(__FUNCTION__ " returning 0");
        return 0;
 } /* ftdi_sio_ioctl */
 
 
 static int __init ftdi_sio_init (void)
 {
+       dbg(__FUNCTION__);
        usb_serial_register (&ftdi_sio_device);
+       usb_serial_register (&ftdi_8U232AM_device);
        return 0;
 }
 
 
 static void __exit ftdi_sio_exit (void)
 {
+       dbg(__FUNCTION__);
        usb_serial_deregister (&ftdi_sio_device);
+       usb_serial_deregister (&ftdi_8U232AM_device);
 }
 
 
@@ -730,4 +880,4 @@ module_init(ftdi_sio_init);
 module_exit(ftdi_sio_exit);
 
 MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>");
-MODULE_DESCRIPTION("USB FTDI SIO driver");
+MODULE_DESCRIPTION("USB FTDI RS232 converters driver");
index fe5f545db327d6088b583bbf2b95dca8c208e7e2..626aeb6773150fcac63768cc645bde9bb033792f 100644 (file)
@@ -20,9 +20,9 @@
  */
 
 #define FTDI_VID       0x0403  /* Vendor Id */
-#define FTDI_SIO_PID   0x8372  /* Product Id */
+#define FTDI_SIO_PID   0x8372  /* Product Id SIO application of 8U100AX  */
+#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
 
-/* Vendor Request Interface */
 #define FTDI_SIO_RESET                 0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL    1 /* Set the modem control register */
 #define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
  * Data:           None
  */
 
+typedef enum {
+       sio = 1,
+       F8U232AM = 2,
+} ftdi_type_t;
+
+
 typedef enum {
  ftdi_sio_b300 = 0, 
  ftdi_sio_b600 = 1, 
@@ -98,6 +104,38 @@ typedef enum {
  ftdi_sio_b115200 = 9
 } FTDI_SIO_baudrate_t ;
 
+
+typedef enum {
+  ftdi_8U232AM_12MHz_b300 = 0x09c4,
+  ftdi_8U232AM_12MHz_b600 = 0x04E2,
+  ftdi_8U232AM_12MHz_b1200 = 0x0271,
+  ftdi_8U232AM_12MHz_b2400 = 0x4138,
+  ftdi_8U232AM_12MHz_b4800 = 0x809c,
+  ftdi_8U232AM_12MHz_b9600 = 0xc04e,
+  ftdi_8U232AM_12MHz_b19200 = 0x0027,
+  ftdi_8U232AM_12MHz_b38400 = 0x4013,
+  ftdi_8U232AM_12MHz_b57600 = 0x000d,
+  ftdi_8U232AM_12MHz_b115200 = 0x4006,
+  ftdi_8U232AM_12MHz_b230400 = 0x8003,
+} FTDI_8U232AM_12MHz_baudrate_t;
+/* Apparently all devices are 48MHz */
+typedef enum {
+  ftdi_8U232AM_48MHz_b300 = 0x2710,
+  ftdi_8U232AM_48MHz_b600 = 0x1388,
+  ftdi_8U232AM_48MHz_b1200 = 0x09c4,
+  ftdi_8U232AM_48MHz_b2400 = 0x04e2,
+  ftdi_8U232AM_48MHz_b4800 = 0x0271,
+  ftdi_8U232AM_48MHz_b9600 = 0x4138,
+  ftdi_8U232AM_48MHz_b19200 = 0x809c,
+  ftdi_8U232AM_48MHz_b38400 = 0xc04e,
+  ftdi_8U232AM_48MHz_b57600 = 0x0034,
+  ftdi_8U232AM_48MHz_b115200 = 0x001a,
+  ftdi_8U232AM_48MHz_b230400 = 0x000d,
+  ftdi_8U232AM_48MHz_b460800 = 0x4006,
+  ftdi_8U232AM_48MHz_b921600 = 0x8003,
+
+} FTDI_8U232AM_48MHz_baudrate_t;
+
 #define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
 #define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
 #define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 )
index ec039aaa24db5533551822d4047fbc9e9debfd60..12a69c1e7c009168a732f69ba25bfe4e6e19b2f8 100644 (file)
@@ -25,6 +25,7 @@
  *  - working around the horridness of the rest
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
index 7fc5e5cb32f2636c6723c26bf52d7956a083faff..e97f458cf739faaa2e568851ff8a2a537eab04d6 100644 (file)
@@ -88,7 +88,7 @@ int usb_register(struct usb_driver *new_driver)
        init_MUTEX(&new_driver->serialize);
 
        /* Add it to the list of known drivers */
-       list_add(&new_driver->driver_list, &usb_driver_list);
+       list_add_tail(&new_driver->driver_list, &usb_driver_list);
 
        usb_scan_devices();
 
@@ -560,7 +560,7 @@ usb_match_id(struct usb_device *dev, struct usb_interface *interface,
                        continue;
 
                if (id->bDeviceSubClass &&
-                   id->bDeviceSubClass!= dev->descriptor.bDeviceClass)
+                   id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)
                        continue;
 
                if (id->bDeviceProtocol &&
index 3e08ebcb2df27e9ee791946e717e38404ececac0..f7a09a5d093b3b961cfa678908a86c257f5fa4f3 100644 (file)
@@ -20,6 +20,9 @@
 #if defined(__arm__)
 #define DUMMY_COLUMNS  ORIG_VIDEO_COLS
 #define DUMMY_ROWS     ORIG_VIDEO_LINES
+#elif defined(__hppa__)
+#define DUMMY_COLUMNS  80      /* fixme ! (mine uses 160x64 at 1280x1024) */
+#define DUMMY_ROWS     25
 #else
 #define DUMMY_COLUMNS  80
 #define DUMMY_ROWS     25
diff --git a/drivers/video/fbcon-sti.c b/drivers/video/fbcon-sti.c
new file mode 100644 (file)
index 0000000..174ad05
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * linux/drivers/video/fbcon-sti.c -- Low level frame buffer
+ *     operations for generic HP video boards using STI (standard
+ *     text interface) firmware
+ *
+ *  Based on linux/drivers/video/fbcon-artist.c
+ *     Created 5 Apr 1997 by Geert Uytterhoeven
+ *     Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ * 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.  */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/delay.h>
+#include <asm/types.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+
+#include "sti.h"
+
+/* Translate an address as it would be found in a 2048x2048x1 bit frame
+ * buffer into a logical address Artist actually expects.  Addresses fed
+ * into Artist look like this:
+ *  fixed          Y               X
+ * FFFF FFFF LLLL LLLL LLLC CCCC CCCC CC00
+ *
+ * our "RAM" addresses look like this:
+ * 
+ * FFFF FFFF 0000 0LLL LLLL LLLL CCCC CCCC [CCC]
+ *
+ * */
+
+static inline u32
+ram2log(void * addr)
+{
+       u32 a = (unsigned long) addr;
+       u32 r;
+
+#if 0
+       r  =   a & 0xff000000;          /* fixed part */
+       r += ((a & 0x000000ff) << 5);
+       r += ((a & 0x00ffff00) << 3);
+#else
+       r  =   a & 0xff000000;          /* fixed part */
+       r += ((a & 0x000000ff) << 5);
+       r += ((a & 0x0007ff00) << 5);
+#endif
+
+       return r;
+}
+
+/* All those functions need better names. */
+
+static void
+memcpy_fromhp_tohp(void *dest, void *src, int count)
+{
+       unsigned long d = ram2log(dest);
+       unsigned long s = ram2log(src);
+
+       count += 3;
+       count &= ~3; /* XXX */
+
+       while(count) {
+               count --;
+               gsc_writel(~gsc_readl(s), d);
+               d += 32*4;
+               s += 32*4;
+       }
+}
+
+static void
+memcpy_tohp(void *dest, void *src, int count)
+{
+       unsigned long d = (unsigned long) dest;
+       u32 *s = (u32 *)src;
+
+       count += 3;
+       count &= ~3; /* XXX */
+
+       d = ram2log(dest);
+
+       while(count) {
+               count--;
+               gsc_writel(*s++, d);
+               d += 32*4;
+       }
+}
+
+static void
+memcopy_fromhp(void *dest, void *src, int count)
+{
+       /* FIXME */
+       printk("uhm ...\n");
+}
+
+static void
+memset_tohp(void *dest, u32 word, int count)
+{
+       unsigned long d = ram2log(dest);
+
+       count += 3;
+       count &= ~3;
+
+       while(count) {
+               count--;
+               gsc_writel(word, d);
+               d += 32;
+       }
+}
+
+static u8
+readb_hp(void *src)
+{
+       unsigned long s = ram2log(src);
+
+       return ~gsc_readb(s);
+}
+
+static void
+writeb_hp(u8 b, void *dst)
+{
+       unsigned long d = ram2log(dst);
+
+       if((d&0xf0000000) != 0xf0000000) {
+               printk("writeb_hp %02x %p (%08lx) (%p)\n",
+                       b, dst, d, __builtin_return_address(0));
+               return;
+       }
+
+       gsc_writeb(b, d);
+}
+
+static void
+fbcon_sti_setup(struct display *p)
+{
+       if (p->line_length)
+               p->next_line = p->line_length;
+       else
+               p->next_line = p->var.xres_virtual>>3;
+       p->next_plane = 0;
+}
+
+static void
+fbcon_sti_bmove(struct display *p, int sy, int sx,
+               int dy, int dx,
+               int height, int width)
+{
+#if 0 /* Unfortunately, still broken */
+       sti_bmove(&default_sti /* FIXME */, sy, sx, dy, dx, height, width);
+#else
+       u8 *src, *dest;
+       u_int rows;
+
+       if (sx == 0 && dx == 0 && width == p->next_line) {
+               src = p->screen_base+sy*fontheight(p)*width;
+               dest = p->screen_base+dy*fontheight(p)*width;
+               memcpy_fromhp_tohp(dest, src, height*fontheight(p)*width);
+       } else if (dy <= sy) {
+               src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
+               dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
+               for (rows = height*fontheight(p); rows--;) {
+                       memcpy_fromhp_tohp(dest, src, width);
+                       src += p->next_line;
+                       dest += p->next_line;
+               }
+       } else {
+               src = p->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx;
+               dest = p->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx;
+               for (rows = height*fontheight(p); rows--;) {
+                       memcpy_fromhp_tohp(dest, src, width);
+                       src -= p->next_line;
+                       dest -= p->next_line;
+               }
+       }
+#endif
+}
+
+static void
+fbcon_sti_clear(struct vc_data *conp,
+               struct display *p, int sy, int sx,
+               int height, int width)
+{
+       u8 *dest;
+       u_int rows;
+       int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
+
+       dest = p->screen_base+sy*fontheight(p)*p->next_line+sx;
+
+       if (sx == 0 && width == p->next_line) {
+               if (inverse)
+                       memset_tohp(dest, ~0, height*fontheight(p)*width);
+               else
+                       memset_tohp(dest,  0, height*fontheight(p)*width);
+       } else
+               for (rows = height*fontheight(p); rows--; dest += p->next_line)
+                       if (inverse)
+                               memset_tohp(dest, 0xffffffff, width);
+                       else
+                               memset_tohp(dest, 0x00000000, width);
+}
+
+static void fbcon_sti_putc(struct vc_data *conp,
+                          struct display *p, int c,
+                          int yy, int xx)
+{
+       u8 *dest, *cdat;
+       u_int rows, bold, revs, underl;
+       u8 d;
+
+       dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+       cdat = p->fontdata+(c&p->charmask)*fontheight(p);
+       bold = attr_bold(p,c);
+       revs = attr_reverse(p,c);
+       underl = attr_underline(p,c);
+
+       for (rows = fontheight(p); rows--; dest += p->next_line) {
+               d = *cdat++;
+               if (underl && !rows)
+                       d = 0xff;
+               else if (bold)
+                       d |= d>>1;
+               if (revs)
+                       d = ~d;
+               writeb_hp (d, dest);
+       }
+}
+
+static void fbcon_sti_putcs(struct vc_data *conp,
+                           struct display *p, 
+                           const unsigned short *s,
+                           int count, int yy, int xx)
+{
+       u8 *dest, *dest0, *cdat;
+       u_int rows, bold, revs, underl;
+       u8 d;
+       u16 c;
+
+       if(((unsigned)xx > 200) || ((unsigned) yy > 200)) {
+               printk("refusing to putcs %p %p %p %d %d %d (%p)\n",
+                       conp, p, s, count, yy, xx, __builtin_return_address(0));
+               return;
+       }       
+
+
+       dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+       if(((u32)dest0&0xf0000000)!=0xf0000000) {
+               printk("refusing to putcs %p %p %p %d %d %d (%p) %p = %p + %d * %d * %ld + %d\n",
+                       conp, p, s, count, yy, xx, __builtin_return_address(0),
+                       dest0, p->screen_base, yy, fontheight(p), p->next_line,
+                       xx);
+               return;
+       }       
+
+       bold = attr_bold(p,scr_readw(s));
+       revs = attr_reverse(p,scr_readw(s));
+       underl = attr_underline(p,scr_readw(s));
+
+       while (count--) {
+               c = scr_readw(s++) & p->charmask;
+               dest = dest0++;
+               cdat = p->fontdata+c*fontheight(p);
+               for (rows = fontheight(p); rows--; dest += p->next_line) {
+                       d = *cdat++;
+                       if (0 && underl && !rows)
+                               d = 0xff;
+                       else if (0 && bold)
+                               d |= d>>1;
+                       if (revs)
+                               d = ~d;
+                       writeb_hp (d, dest);
+               }
+       }
+}
+
+static void fbcon_sti_revc(struct display *p,
+                          int xx, int yy)
+{
+       u8 *dest, d;
+       u_int rows;
+
+
+       dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+       for (rows = fontheight(p); rows--; dest += p->next_line) {
+               d = readb_hp(dest);
+               writeb_hp (~d, dest);
+       }
+}
+
+static void
+fbcon_sti_clear_margins(struct vc_data *conp,
+                       struct display *p,
+                       int bottom_only)
+{
+       u8 *dest;
+       int height, bottom;
+       int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
+
+
+       /* XXX Need to handle right margin? */
+
+       height = p->var.yres - conp->vc_rows * fontheight(p);
+       if (!height)
+               return;
+       bottom = conp->vc_rows + p->yscroll;
+       if (bottom >= p->vrows)
+               bottom -= p->vrows;
+       dest = p->screen_base + bottom * fontheight(p) * p->next_line;
+       if (inverse)
+               memset_tohp(dest, 0xffffffff, height * p->next_line);
+       else
+               memset_tohp(dest, 0x00000000, height * p->next_line);
+}
+
+
+    /*
+     *  `switch' for the low level operations
+     */
+
+struct display_switch fbcon_sti = {
+       fbcon_sti_setup, fbcon_sti_bmove, fbcon_sti_clear,
+       fbcon_sti_putc, fbcon_sti_putcs, fbcon_sti_revc,
+       NULL, NULL, fbcon_sti_clear_margins,
+       FONTWIDTH(8)
+};
index 7b3d4982251e218c088143b0577928081a4ef0fe..49b232c7e03b913a8d863a294c8e81548a19446b 100644 (file)
@@ -113,6 +113,8 @@ extern int tdfxfb_init(void);
 extern int tdfxfb_setup(char*);
 extern int sisfb_init(void);
 extern int sisfb_setup(char*);
+extern int stifb_init(void);
+extern int stifb_setup(char*);
 
 static struct {
        const char *name;
@@ -198,6 +200,9 @@ static struct {
         * management!
         */
 
+#ifdef CONFIG_FB_STI
+       { "stifb", stifb_init, stifb_setup },
+#endif
 #ifdef CONFIG_FB_OF
        { "offb", offb_init, NULL },
 #endif
diff --git a/drivers/video/sti-bmode.h b/drivers/video/sti-bmode.h
new file mode 100644 (file)
index 0000000..4aa38f6
--- /dev/null
@@ -0,0 +1,287 @@
+#define STI_REGION_MAX 8
+#define STI_DEV_NAME_LENGTH 32
+
+typedef struct {
+        u8 res[3];
+        u8 data;
+} __attribute__((packed)) sti_u8;
+
+typedef struct {
+       sti_u8 data[2];
+} __attribute__((packed)) sti_u16;
+
+typedef struct {
+       sti_u8 data[4];
+} __attribute__((packed)) sti_u32;
+
+#define  STI_U8( u8) ((u8).data)
+#define STI_U16(u16) ((STI_U8((u16).data[0])<<8) | STI_U8((u16).data[1]))
+#define STI_U32(u32) ((STI_U8((u32).data[0])<<24) | \
+                     (STI_U8((u32).data[1])<<16) | \
+                     (STI_U8((u32).data[2])<< 8) | \
+                     (STI_U8((u32).data[3])<< 0))
+
+struct sti_rom_region {
+       sti_u32 region;
+};
+
+struct sti_rom_font {
+       sti_u16 first_char;
+       sti_u16 last_char;
+        sti_u8 width;
+        sti_u8 height;
+        sti_u8 font_type;
+        sti_u8 bytes_per_char;
+       sti_u32 next_font;
+        sti_u8 underline_height;
+        sti_u8 underline_pos;
+        sti_u8 res008[2];
+};
+
+struct sti_rom {
+        sti_u8 type;
+        sti_u8 num_mons;
+        sti_u8 revno[2];
+
+        sti_u8 graphics_id[8];                 /* 0x010 */
+
+       sti_u32 font_start;                     /* 0x030 */
+       sti_u32 statesize;
+       sti_u32 last_addr;
+       sti_u32 region_list;
+
+       sti_u16 reentsize;                      /* 0x070 */
+       sti_u16 maxtime;
+       sti_u32 mon_tbl_addr;
+       sti_u32 user_data_addr;
+       sti_u32 sti_mem_req;
+
+       sti_u32 user_data_size;                 /* 0x0b0 */
+       sti_u16 power;                          /* 0x0c0 */
+        sti_u8 bus_support;
+        sti_u8 ext_bus_support;
+        sti_u8 alt_code_type;                  /* 0x0d0 */
+        sti_u8 ext_dd_struct[3];
+       sti_u32 cfb_addr;                       /* 0x0e0 */
+       
+        sti_u8 res0f0[4];                      
+
+       sti_u32 init_graph;             /* 0x0e0 */
+       sti_u32 state_mgmt;
+       sti_u32 font_unpmv;
+       sti_u32 block_move;
+       sti_u32 self_test;
+       sti_u32 excep_hdlr;
+       sti_u32 inq_conf;
+       sti_u32 set_cm_entry;
+       sti_u32 dma_ctrl;
+       sti_u32 flow_ctrl;
+       sti_u32 user_timing;
+       sti_u32 process_mgr;
+       sti_u32 sti_util;
+       sti_u32 end_addr;
+       sti_u32 res0b8;
+       sti_u32 res0bc;
+
+       sti_u32 init_graph_m68k;                /* 0x0e0 */
+       sti_u32 state_mgmt_m68k;
+       sti_u32 font_unpmv_m68k;
+       sti_u32 block_move_m68k;
+       sti_u32 self_test_m68k;
+       sti_u32 excep_hdlr_m68k;
+       sti_u32 inq_conf_m68k;
+       sti_u32 set_cm_entry_m68k;
+       sti_u32 dma_ctrl_m68k;
+       sti_u32 flow_ctrl_m68k;
+       sti_u32 user_timing_m68k;
+       sti_u32 process_mgr_m68k;
+       sti_u32 sti_util_m68k;
+       sti_u32 end_addr_m68k;
+       sti_u32 res0b8_m68k;
+       sti_u32 res0bc_m68k;
+
+        sti_u8 res040[7 * 4];
+};
+       
+struct sti_cooked_font {
+       struct sti_rom_font *raw;
+       struct sti_cooked_font *next_font;
+};
+
+struct sti_cooked_rom {
+       struct sti_rom *raw;
+       struct sti_cooked_font *font_start;
+       u32 *region_list;
+};
+
+struct sti_glob_cfg_ext {
+        u8 curr_mon;
+        u8 friendly_boot;
+       s16 power;
+       s32 freq_ref;
+       s32 *sti_mem_addr;
+       s32 *future_ptr;
+};
+
+struct sti_glob_cfg {
+       s32 text_planes;
+       s16 onscreen_x;
+       s16 onscreen_y;
+       s16 offscreen_x;
+       s16 offscreen_y;
+       s16 total_x;
+       s16 total_y;
+       u32 region_ptrs[STI_REGION_MAX];
+       s32 reent_lvl;
+       s32 *save_addr;
+       struct sti_glob_cfg_ext *ext_ptr;
+};
+
+struct sti_init_flags {
+       u32 wait : 1;
+       u32 reset : 1;
+       u32 text : 1;
+       u32 nontext : 1;
+       u32 clear : 1;
+       u32 cmap_blk : 1;
+       u32 enable_be_timer : 1;
+       u32 enable_be_int : 1;
+       u32 no_chg_tx : 1;
+       u32 no_chg_ntx : 1;
+       u32 no_chg_bet : 1;
+       u32 no_chg_bei : 1;
+       u32 init_cmap_tx : 1;
+       u32 cmt_chg : 1;
+       u32 retain_ie : 1;
+       u32 pad : 17;
+
+       s32 *future_ptr;
+};
+
+struct sti_init_inptr_ext {
+       u8  config_mon_type;
+       u8  pad[1];
+       u16 inflight_data;
+       s32 *future_ptr;
+};
+
+struct sti_init_inptr {
+       s32 text_planes;
+       struct sti_init_inptr_ext *ext_ptr;
+};
+
+struct sti_init_outptr {
+       s32 errno;
+       s32 text_planes;
+       s32 *future_ptr;
+};
+
+struct sti_conf_flags {
+       u32 wait : 1;
+       u32 pad : 31;
+       s32 *future_ptr;
+};
+
+struct sti_conf_inptr {
+       s32 *future_ptr;
+};
+
+struct sti_conf_outptr_ext {
+       u32 crt_config[3];
+       u32 crt_hdw[3];
+       s32 *future_ptr;
+};
+
+struct sti_conf_outptr {
+       s32 errno;
+       s16 onscreen_x;
+       s16 onscreen_y;
+       s16 offscreen_x;
+       s16 offscreen_y;
+       s16 total_x;
+       s16 total_y;
+       s32 bits_per_pixel;
+       s32 bits_used;
+       s32 planes;
+        u8 dev_name[STI_DEV_NAME_LENGTH];
+       u32 attributes;
+       struct sti_conf_outptr_ext *ext_ptr;
+};
+
+
+struct sti_font_inptr {
+       u32 font_start_addr;
+       s16 index;
+       u8 fg_color;
+       u8 bg_color;
+       s16 dest_x;
+       s16 dest_y;
+       s32 *future_ptr;
+};
+
+struct sti_font_flags {
+       u32 wait : 1;
+       u32 non_text : 1;
+       u32 pad : 30;
+
+       s32 *future_ptr;
+};
+       
+struct sti_font_outptr {
+       s32 errno;
+       s32 *future_ptr;
+};
+
+struct sti_blkmv_flags {
+       u32 wait : 1;
+       u32 color : 1;
+       u32 clear : 1;
+       u32 non_text : 1;
+       u32 pad : 28;
+       s32 *future_ptr;
+};
+
+struct sti_blkmv_inptr {
+       u8 fg_color;
+       u8 bg_color;
+       s16 src_x;
+       s16 src_y;
+       s16 dest_x;
+       s16 dest_y;
+       s16 width;
+       s16 height;
+       s32 *future_ptr;
+};
+
+struct sti_blkmv_outptr {
+       s32 errno;
+       s32 *future_ptr;
+};
+
+struct sti_struct {
+       spinlock_t lock;
+
+       struct sti_cooked_rom *rom;
+
+       unsigned long font_unpmv;
+       unsigned long block_move;
+       unsigned long init_graph;
+       unsigned long inq_conf;
+
+       struct sti_glob_cfg *glob_cfg;
+       struct sti_rom_font *font;
+
+       s32 text_planes;
+
+       char **mon_strings;
+       u32 *regions;
+        u8 *pci_regions;
+};
+
+#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \
+       ({                                                      \
+               real32_call( func, (unsigned long)STI_PTR(flags), \
+                                   STI_PTR(inptr), STI_PTR(outptr), \
+                                   glob_cfg); \
+       })
+
diff --git a/drivers/video/sti.h b/drivers/video/sti.h
new file mode 100644 (file)
index 0000000..feea4fb
--- /dev/null
@@ -0,0 +1,289 @@
+#define STI_REGION_MAX 8
+#define STI_DEV_NAME_LENGTH 32
+
+struct sti_rom_font {
+       u16 first_char;
+       u16 last_char;
+        u8 width;
+        u8 height;
+        u8 font_type;
+        u8 bytes_per_char;
+       u32 next_font;
+        u8 underline_height;
+        u8 underline_pos;
+        u8 res008[2];
+};
+
+struct sti_rom {
+        u8 type[4];
+        u8 res004;
+        u8 num_mons;
+        u8 revno[2];
+        u8 graphics_id[8];
+
+       u32 font_start;
+       u32 statesize;
+       u32 last_addr;
+       u32 region_list;
+
+       u16 reentsize;
+       u16 maxtime;
+       u32 mon_tbl_addr;
+       u32 user_data_addr;
+       u32 sti_mem_req;
+
+       u32 user_data_size;
+       u16 power;
+        u8 bus_support;
+        u8 ext_bus_support;
+        u8 alt_code_type;
+        u8 ext_dd_struct[3];
+       u32 cfb_addr;
+       
+       u32 init_graph;
+       u32 state_mgmt;
+       u32 font_unpmv;
+       u32 block_move;
+       u32 self_test;
+       u32 excep_hdlr;
+       u32 inq_conf;
+       u32 set_cm_entry;
+       u32 dma_ctrl;
+        u8 res040[7 * 4];
+       
+       u32 init_graph_m68k;
+       u32 flow_ctrl;
+       u32 user_timing;
+       u32 process_mgr;
+       u32 sti_util;
+       u32 end_addr;
+       u32 res0b8;
+       u32 res0bc;
+};
+       
+struct sti_cooked_font {
+       struct sti_rom_font *raw;
+       struct sti_cooked_font *next_font;
+};
+
+struct sti_cooked_rom {
+       struct sti_rom *raw;
+       struct sti_cooked_font *font_start;
+       u32 *region_list;
+};
+
+struct sti_glob_cfg_ext {
+       u8  curr_mon;
+       u8  friendly_boot;
+       s16 power;
+       s32 freq_ref;
+       s32 *sti_mem_addr;
+       s32 *future_ptr;
+};
+
+struct sti_glob_cfg {
+       s32 text_planes;
+       s16 onscreen_x;
+       s16 onscreen_y;
+       s16 offscreen_x;
+       s16 offscreen_y;
+       s16 total_x;
+       s16 total_y;
+       u32 region_ptrs[STI_REGION_MAX];
+       s32 reent_lvl;
+       s32 *save_addr;
+       struct sti_glob_cfg_ext *ext_ptr;
+};
+
+struct sti_init_flags {
+       u32 wait : 1;
+       u32 reset : 1;
+       u32 text : 1;
+       u32 nontext : 1;
+       u32 clear : 1;
+       u32 cmap_blk : 1;
+       u32 enable_be_timer : 1;
+       u32 enable_be_int : 1;
+       u32 no_chg_tx : 1;
+       u32 no_chg_ntx : 1;
+       u32 no_chg_bet : 1;
+       u32 no_chg_bei : 1;
+       u32 init_cmap_tx : 1;
+       u32 cmt_chg : 1;
+       u32 retain_ie : 1;
+       u32 pad : 17;
+
+       s32 *future_ptr;
+};
+
+struct sti_init_inptr_ext {
+       u8  config_mon_type;
+       u8  pad[1];
+       u16 inflight_data;
+       s32 *future_ptr;
+};
+
+struct sti_init_inptr {
+       s32 text_planes;
+       struct sti_init_inptr_ext *ext_ptr;
+};
+
+struct sti_init_outptr {
+       s32 errno;
+       s32 text_planes;
+       s32 *future_ptr;
+};
+
+struct sti_conf_flags {
+       u32 wait : 1;
+       u32 pad : 31;
+       s32 *future_ptr;
+};
+
+struct sti_conf_inptr {
+       s32 *future_ptr;
+};
+
+struct sti_conf_outptr_ext {
+       u32 crt_config[3];
+       u32 crt_hdw[3];
+       s32 *future_ptr;
+};
+
+struct sti_conf_outptr {
+       s32 errno;
+       s16 onscreen_x;
+       s16 onscreen_y;
+       s16 offscreen_x;
+       s16 offscreen_y;
+       s16 total_x;
+       s16 total_y;
+       s32 bits_per_pixel;
+       s32 bits_used;
+       s32 planes;
+        u8 dev_name[STI_DEV_NAME_LENGTH];
+       u32 attributes;
+       struct sti_conf_outptr_ext *ext_ptr;
+};
+
+
+struct sti_font_inptr {
+       u32 font_start_addr;
+       s16 index;
+       u8 fg_color;
+       u8 bg_color;
+       s16 dest_x;
+       s16 dest_y;
+       s32 *future_ptr;
+};
+
+struct sti_font_flags {
+       u32 wait : 1;
+       u32 non_text : 1;
+       u32 pad : 30;
+
+       s32 *future_ptr;
+};
+       
+struct sti_font_outptr {
+       s32 errno;
+       s32 *future_ptr;
+};
+
+struct sti_blkmv_flags {
+       u32 wait : 1;
+       u32 color : 1;
+       u32 clear : 1;
+       u32 non_text : 1;
+       u32 pad : 28;
+       s32 *future_ptr;
+};
+
+struct sti_blkmv_inptr {
+       u8 fg_color;
+       u8 bg_color;
+       s16 src_x;
+       s16 src_y;
+       s16 dest_x;
+       s16 dest_y;
+       s16 width;
+       s16 height;
+       s32 *future_ptr;
+};
+
+struct sti_blkmv_outptr {
+       s32 errno;
+       s32 *future_ptr;
+};
+
+struct sti_struct {
+       spinlock_t lock;
+
+       struct sti_cooked_rom *rom;
+
+       unsigned long font_unpmv;
+       unsigned long block_move;
+       unsigned long init_graph;
+       unsigned long inq_conf;
+
+       struct sti_glob_cfg *glob_cfg;
+       struct sti_rom_font *font;
+
+       s32 text_planes;
+
+       char **mon_strings;
+       u32 *regions;
+        u8 *pci_regions;
+};
+
+#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \
+       ({                                                      \
+               real32_call( func, (unsigned long)STI_PTR(flags), \
+                                   STI_PTR(inptr), STI_PTR(outptr), \
+                                   glob_cfg); \
+       })
+
+/* The latency of the STI functions cannot really be reduced by setting
+ * this to 0;  STI doesn't seem to be designed to allow calling a different
+ * function (or the same function with different arguments) after a
+ * function exited with 1 as return value.
+ *
+ * As all of the functions below could be called from interrupt context,
+ * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1)
+ * block.  Really bad latency there.
+ *
+ * Probably the best solution to all this is have the generic code manage
+ * the screen buffer and a kernel thread to call STI occasionally.
+ * 
+ * Luckily, the frame buffer guys have the same problem so we can just wait
+ * for them to fix it and steal their solution.   prumpf
+ *
+ * Actually, another long-term viable solution is to completely do STI
+ * support in userspace - that way we avoid the potential license issues
+ * of using proprietary fonts, too. */
+#define STI_WAIT 1
+#define STI_PTR(p) ( (typeof(p)) virt_to_phys(p))
+#define PTR_STI(p) ( (typeof(p)) phys_to_virt((unsigned long)p) )
+
+#define sti_onscreen_x(sti) (PTR_STI(sti->glob_cfg)->onscreen_x)
+#define sti_onscreen_y(sti) (PTR_STI(sti->glob_cfg)->onscreen_y)
+#define sti_font_x(sti) (PTR_STI(sti->font)->width)
+#define sti_font_y(sti) (PTR_STI(sti->font)->height)
+
+extern struct sti_struct * sti_init_roms(void);
+
+void sti_init_graph(struct sti_struct *sti);
+void sti_inq_conf(struct sti_struct *sti);
+void sti_putc(struct sti_struct *sti, int c, int y, int x);
+void sti_set(struct sti_struct *sti, int src_y, int src_x,
+            int height, int width, u8 color);
+void sti_clear(struct sti_struct *sti, int src_y, int src_x,
+              int height, int width);
+void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
+              int dst_y, int dst_x, int height, int width);
+
+/* XXX: this probably should not be here, but we rely on STI being
+   initialized early and independently of stifb at the moment, so
+   there's no other way for stifb to find it. */
+extern struct sti_struct default_sti;
diff --git a/drivers/video/sticon-bmode.c b/drivers/video/sticon-bmode.c
new file mode 100644 (file)
index 0000000..57cad3d
--- /dev/null
@@ -0,0 +1,920 @@
+/*
+TPG CVS users: please don't commit changes to this file directly, send
+them to prumpf@tux.org and wait for a new version instead.  Otherwise,
+your changes will get lost when prumpf releases the next version, as
+this file *will* be replaced with it.  You have been warned.
+
+2000-05-30, <deller@gmx.de>
+*/
+#if 1
+#define DPRINTK(x)     printk x
+#else
+#define DPRINTK(x)
+#endif
+
+/*
+ *  linux/drivers/video/sticon.c  - console driver using HP's STI firmware
+ *
+ *     Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ *  Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
+ *  which were
+ *
+ *     Created 28 Sep 1997 by Geert Uytterhoeven
+ *     Rewritten by Martin Mares <mj@ucw.cz>, July 1998
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *                         1995  Jay Estabrook
+ *     Copyright (C) 1995 Geert Uytterhoeven
+ *     Copyright (C) 1993 Bjoern Brauel
+ *                        Roman Hodek
+ *     Copyright (C) 1993 Hamish Macdonald
+ *                        Greg Harp
+ *     Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
+ *
+ *           with work by William Rucklidge (wjr@cs.cornell.edu)
+ *                        Geert Uytterhoeven
+ *                        Jes Sorensen (jds@kom.auc.dk)
+ *                        Martin Apel
+ *           with work by Guenther Kelleter
+ *                        Martin Schaller
+ *                        Andreas Schwab
+ *                        Emmanuel Marty (core@ggi-project.org)
+ *                        Jakub Jelinek (jj@ultra.linux.cz)
+ *                        Martin Mares <mj@ucw.cz>
+ *
+ *  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.
+ */
+/*
+ *  TODO:
+ *   - call STI in virtual mode rather than in real mode
+ *   - support for PCI-only STI ROMs (which don't have a traditional region
+ *     list)
+ *   - safe detection (i.e. verify there is a graphics device at a given
+ *     address first, not just read a random device's io space)
+ *   - support for multiple STI devices in one machine
+ *   - support for byte-mode STI ROMs
+ *   - support for just using STI to switch to a colour fb (stifb ?)
+ *   - try to make it work on m68k hp workstations ;)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/kd.h>
+#include <linux/malloc.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/real.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/kd.h>
+#include <linux/malloc.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <video/fbcon.h>
+#include <video/font.h>
+
+#include "sti-bmode.h"
+
+/* The latency of the STI functions cannot really be reduced by setting
+ * this to 0;  STI doesn't seem to be designed to allow calling a different
+ * function (or the same function with different arguments) after a
+ * function exited with 1 as return value.
+ *
+ * As all of the functions below could be called from interrupt context,
+ * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1)
+ * block.  Really bad latency there.
+ *
+ * Probably the best solution to all this is have the generic code manage
+ * the screen buffer and a kernel thread to call STI occasionally.
+ * 
+ * Luckily, the frame buffer guys have the same problem so we can just wait
+ * for them to fix it and steal their solution.   prumpf
+ *
+ * Actually, another long-term viable solution is to completely do STI
+ * support in userspace - that way we avoid the potential license issues
+ * of using proprietary fonts, too. */
+#define STI_WAIT 1
+#define STI_PTR(p) ( (typeof(p)) virt_to_phys(p))
+#define PTR_STI(p) ( (typeof(p)) phys_to_virt((unsigned long)p) )
+
+static struct sti_struct default_sti = {
+       SPIN_LOCK_UNLOCKED,
+};
+
+static struct sti_font_flags default_font_flags = {
+       STI_WAIT, 0, 0, NULL
+};
+
+/* The colour indices used by STI are
+ *   0 - Black
+ *   1 - White
+ *   2 - Red
+ *   3 - Yellow/Brown
+ *   4 - Green
+ *   5 - Cyan
+ *   6 - Blue
+ *   7 - Magenta
+ *
+ * So we have the same colours as VGA (basically one bit each for R, G, B),
+ * but have to translate them, anyway. */
+
+static u8 col_trans[8] = {
+        0, 6, 4, 5,
+        2, 7, 3, 1
+};
+
+#define c_fg(sti, c) col_trans[((c>> 8) & 7)]
+#define c_bg(sti, c) col_trans[((c>>11) & 7)]
+#define c_index(sti, c) (c&0xff)
+
+#define sti_onscreen_x(sti) (PTR_STI(sti->glob_cfg)->onscreen_x)
+#define sti_onscreen_y(sti) (PTR_STI(sti->glob_cfg)->onscreen_y)
+#define sti_font_x(sti) (STI_U8(PTR_STI(sti->font)->width))
+#define sti_font_y(sti) (STI_U8(PTR_STI(sti->font)->height))
+
+static struct sti_init_flags default_init_flags = {
+       STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL
+};
+
+static void sti_init_graph(struct sti_struct *sti) 
+{
+       struct sti_init_inptr_ext inptr_ext = {
+               0, { 0 }, 0, NULL
+       };
+       struct sti_init_inptr inptr = {
+               3, STI_PTR(&inptr_ext)
+       };
+       struct sti_init_outptr outptr = { 0 };
+       unsigned long flags;
+       s32 ret;
+
+       spin_lock_irqsave(&sti->lock, flags);
+
+       ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr,
+               &outptr, sti->glob_cfg);
+
+       spin_unlock_irqrestore(&sti->lock, flags);
+
+       sti->text_planes = outptr.text_planes;
+}
+
+#if 0
+static struct sti_conf_flags default_conf_flags = {
+       STI_WAIT, 0, NULL
+};
+
+static void sti_inq_conf(struct sti_struct *sti)
+{
+       struct sti_conf_inptr inptr = { NULL };
+       struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL };
+       struct sti_conf_outptr outptr = {
+               ext_ptr: STI_PTR(&outptr_ext)
+       };
+       unsigned long flags;
+       s32 ret;
+       
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->inq_conf, &default_conf_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+#endif
+
+static void sti_putc(struct sti_struct *sti, int c, int y, int x)
+{
+       struct sti_font_inptr inptr = {
+               (u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
+               x * sti_font_x(sti), y * sti_font_y(sti), NULL
+       };
+       struct sti_font_outptr outptr = {
+               0, NULL
+       };
+       s32 ret;
+       unsigned long flags;
+
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->font_unpmv, &default_font_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+
+static struct sti_blkmv_flags clear_blkmv_flags = {
+       STI_WAIT, 1, 1, 0, 0, NULL
+};
+
+static void sti_set(struct sti_struct *sti, int src_y, int src_x,
+       int height, int width, u8 color)
+{
+       struct sti_blkmv_inptr inptr = {
+               color, color,
+               src_x, src_y ,
+               src_x, src_y ,
+               width, height,
+               NULL
+       };
+       struct sti_blkmv_outptr outptr = { 0, NULL };
+       s32 ret = 0;
+       unsigned long flags;
+       
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+
+static void sti_clear(struct sti_struct *sti, int src_y, int src_x,
+       int height, int width)
+{
+       struct sti_blkmv_inptr inptr = {
+               0, 0,
+               src_x * sti_font_x(sti), src_y * sti_font_y(sti),
+               src_x * sti_font_x(sti), src_y * sti_font_y(sti),
+               width * sti_font_x(sti), height* sti_font_y(sti),
+               NULL
+       };
+       struct sti_blkmv_outptr outptr = { 0, NULL };
+       s32 ret = 0;
+       unsigned long flags;
+
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+
+static struct sti_blkmv_flags default_blkmv_flags = {
+       STI_WAIT, 0, 0, 0, 0, NULL
+};
+
+static void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
+       int dst_y, int dst_x, int height, int width)
+{
+       struct sti_blkmv_inptr inptr = {
+               0, 0,
+               src_x * sti_font_x(sti), src_y * sti_font_y(sti),
+               dst_x * sti_font_x(sti), dst_y * sti_font_y(sti),
+               width * sti_font_x(sti), height* sti_font_y(sti),
+               NULL
+       };
+       struct sti_blkmv_outptr outptr = { 0, NULL };
+       s32 ret = 0;
+       unsigned long flags;
+
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->block_move, &default_blkmv_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+
+
+/* STICON */
+
+static const char __init *sticon_startup(void)
+{
+       return "STI console";
+}
+
+static int sticon_set_palette(struct vc_data *c, unsigned char *table)
+{
+       return -EINVAL;
+}
+static int sticon_font_op(struct vc_data *c, struct console_font_op *op)
+{
+       return -ENOSYS;
+}
+
+static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
+{
+       sti_putc(&default_sti, c, ypos, xpos);
+}
+
+static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
+       int count, int ypos, int xpos)
+{
+       while(count--) {
+               sti_putc(&default_sti, *s++, ypos, xpos++);
+       }
+}
+
+static void sticon_cursor(struct vc_data *conp, int mode)
+{
+}
+
+static int sticon_scroll(struct vc_data *conp, int t, int b, int dir,
+                       int count)
+{
+       struct sti_struct *sti = &default_sti;
+
+       if(console_blanked)
+               return 0;
+
+       sticon_cursor(conp, CM_ERASE);
+
+       switch(dir) {
+       case SM_UP:
+               sti_bmove(sti, t+count, 0, t, 0, b-t-count, conp->vc_cols);
+               sti_clear(sti, b-count, 0, count, conp->vc_cols);
+
+               break;
+
+       case SM_DOWN:
+               sti_bmove(sti, t, 0, t+count, 0, b-t-count, conp->vc_cols);
+               sti_clear(sti, t, 0, count, conp->vc_cols);
+
+               break;
+       }
+
+       return 0;
+}
+       
+static void sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+       int height, int width)
+{
+       sti_bmove(&default_sti, sy, sx, dy, dx, height, width);
+}
+
+static void sticon_init(struct vc_data *c, int init)
+{
+       struct sti_struct *sti = &default_sti;
+       int vc_cols, vc_rows;
+
+       sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
+       c->vc_can_do_color = 1;
+       vc_cols = PTR_STI(sti->glob_cfg)->onscreen_x / sti_font_x(sti);
+       vc_rows = PTR_STI(sti->glob_cfg)->onscreen_y / sti_font_y(sti);
+
+       vc_resize_con(vc_rows, vc_cols, c->vc_num);
+}
+
+static void sticon_deinit(struct vc_data *c)
+{
+}
+
+static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
+                       int width)
+{
+       sti_clear(&default_sti, sy, sx, height, width);
+}
+
+static int sticon_switch(struct vc_data *conp)
+{
+       return 0;
+}
+
+static int sticon_blank(struct vc_data *conp, int blank)
+{
+       return 0;
+}
+
+static int sticon_scrolldelta(struct vc_data *conp, int lines)
+{
+       return 0;
+}
+
+static int sticon_set_origin(struct vc_data *conp)
+{
+       return 0;
+}
+
+static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
+{
+       return NULL;
+}
+
+static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, int *px, int *py)
+{
+       return 0;
+}
+
+static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse)
+{
+       u8 attr = ((color & 0x70) >> 1) | ((color & 7));
+
+       if(reverse) {
+               color = ((color>>3)&0x7) | ((color &0x7)<<3);
+       }
+
+
+       return attr;
+}
+
+static struct consw sti_con = {
+       con_startup:            sticon_startup, 
+       con_init:               sticon_init,
+       con_deinit:             sticon_deinit,
+       con_clear:              sticon_clear,
+       con_putc:               sticon_putc,
+       con_putcs:              sticon_putcs,
+       con_cursor:             sticon_cursor,
+       con_scroll:             sticon_scroll,
+       con_bmove:              sticon_bmove,
+       con_switch:             sticon_switch,
+       con_blank:              sticon_blank,
+       con_font_op:            sticon_font_op,
+       con_set_palette:        sticon_set_palette,
+       con_scrolldelta:        sticon_scrolldelta,
+       con_set_origin:         sticon_set_origin,
+       con_save_screen:        NULL,
+       con_build_attr:         sticon_build_attr,
+       con_invert_region:      NULL,
+       con_screen_pos:         sticon_screen_pos,
+       con_getxy:              sticon_getxy,
+};
+
+#include <asm/pgalloc.h>       /* need cache flush routines */
+static void __init sti_rom_copy(unsigned long base, unsigned long offset,
+                               unsigned long count, void *dest)
+{
+       void *savedest = dest;
+       int savecount = count;
+
+       while(count >= 4) {
+               count -= 4;
+               *(u32 *)dest = gsc_readl(base + offset);
+#if 0
+               DPRINTK(("%08x\n", *(u32 *)dest));
+               if(*(u32 *)dest == 0x64646464) {
+                 DPRINTK(("!!!!\n"));
+                 { u32 foo = 0; while(foo += 0x100); }
+               }
+#endif
+               offset += 4;
+               dest += 4;
+       }
+       while(count) {
+               count--;
+               *(u8 *)dest = gsc_readb(base + offset);
+               offset++;
+               dest++;
+       }
+       __flush_dcache_range(dest, count);
+       __flush_icache_range(dest, count);
+}
+
+static void dump_sti_rom(struct sti_rom *rom)
+{
+       printk("STI byte mode ROM type %d\n", STI_U8(rom->type));
+       printk(" supports %d monitors\n", STI_U8(rom->num_mons));
+       printk(" conforms to STI ROM spec revision %d.%02x\n",
+               STI_U8(rom->revno[0]) >> 4, STI_U8(rom->revno[0]) & 0x0f);
+       printk(__FUNCTION__ ": %d\n", __LINE__);
+       printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n",
+               (unsigned int) STI_U8(rom->graphics_id[0]), 
+               (unsigned int) STI_U8(rom->graphics_id[1]), 
+               (unsigned int) STI_U8(rom->graphics_id[2]), 
+               (unsigned int) STI_U8(rom->graphics_id[3]), 
+               (unsigned int) STI_U8(rom->graphics_id[4]), 
+               (unsigned int) STI_U8(rom->graphics_id[5]), 
+               (unsigned int) STI_U8(rom->graphics_id[6]), 
+               (unsigned int) STI_U8(rom->graphics_id[7]));
+       printk(__FUNCTION__ ": %d\n", __LINE__);
+       printk(" font start %08x\n",  STI_U32(rom->font_start));
+       printk(__FUNCTION__ ": %d\n", __LINE__);
+       printk(" region list %08x\n", STI_U32(rom->region_list));
+       printk(__FUNCTION__ ": %d\n", __LINE__);
+       printk(" init_graph %08x\n",  STI_U32(rom->init_graph));
+       printk(__FUNCTION__ ": %d\n", __LINE__);
+       printk(" alternate code type %d\n", STI_U8(rom->alt_code_type));
+       printk(__FUNCTION__ ": %d\n", __LINE__);
+}
+
+static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
+                                 struct sti_rom *raw_rom)
+{
+       struct sti_rom_font *raw_font;
+       struct sti_cooked_font *cooked_font;
+       struct sti_rom_font *font_start;
+
+       cooked_font =
+               kmalloc(sizeof *cooked_font, GFP_KERNEL);
+       if(!cooked_font)
+               return;
+
+       cooked_rom->font_start = cooked_font;
+
+#if 0
+       DPRINTK(("%p = %p + %08x\n",
+              ((void *)raw_rom) + (STI_U32(raw_rom->font_start)),
+              ((void *)raw_rom), (STI_U32(raw_rom->font_start))));
+#endif
+       raw_font = ((void *)raw_rom) + STI_U32(raw_rom->font_start) - 3;
+
+       font_start = raw_font;
+       cooked_font->raw = raw_font;
+
+       DPRINTK(("next font %08x\n", STI_U32(raw_font->next_font)));
+
+       while(0 && STI_U32(raw_font->next_font)) {
+               raw_font = ((void *)font_start) + STI_U32(raw_font->next_font);
+               
+               cooked_font->next_font =
+                       kmalloc(sizeof *cooked_font, GFP_KERNEL);
+               if(!cooked_font->next_font)
+                       return;
+
+               cooked_font = cooked_font->next_font;
+
+//             cooked_font->raw = raw_font;
+
+               DPRINTK(("raw_font %p\n",
+                      raw_font));
+               DPRINTK(("next_font %08x %p\n",
+                      STI_U32(raw_font->next_font),
+                      ((void *)font_start) + STI_U32(raw_font->next_font)));
+       }
+
+       cooked_font->next_font = NULL;
+}
+
+static unsigned long __init sti_cook_function(void *function,
+                                             u32 size)
+{
+       sti_u32 *func = (sti_u32 *)function;
+       u32 *ret;
+       int i;
+
+       ret = kmalloc(size, GFP_KERNEL);
+       if(!ret) {
+               printk(KERN_ERR __FILE__ ": could not get memory.\n");
+               return 0;
+       }
+
+       for(i=0; i<(size/4); i++)
+           ret[i] = STI_U32(func[i]);
+
+       flush_all_caches();
+       
+       return virt_to_phys(ret);
+}
+
+static int font_index, font_height, font_width;
+
+static int __init sti_search_font(struct sti_cooked_rom *rom,
+                                 int height, int width)
+{
+       struct sti_cooked_font *font;
+       int i = 0;
+       
+       for(font = rom->font_start; font; font = font->next_font, i++) {
+               if((STI_U8(font->raw->width) == width) &&
+                  (STI_U8(font->raw->height) == height))
+                       return i;
+       }
+
+       return 0;
+}
+
+static struct sti_cooked_font * __init
+sti_select_font(struct sti_cooked_rom *rom)
+{
+       struct sti_cooked_font *font;
+       int i;
+
+       if(font_width && font_height)
+               font_index = sti_search_font(rom, font_height, font_width);
+
+       for(font = rom->font_start, i = font_index;
+           font && (i > 0);
+           font = font->next_font, i--);
+
+       if(font)
+               return font;
+       else
+               return rom->font_start;
+}
+       
+/* address is a pointer to a word mode or pci rom */
+static struct sti_struct * __init sti_read_rom(unsigned long address)
+{
+       struct sti_struct *ret = NULL;
+       struct sti_cooked_rom *cooked = NULL;
+       struct sti_rom *raw = NULL;
+       unsigned long size;
+
+       ret = &default_sti;
+
+       if(!ret)
+               goto out_err;
+
+       cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
+       raw = kmalloc(sizeof *raw, GFP_KERNEL);
+       
+       if(!(raw && cooked))
+               goto out_err;
+
+       /* reallocate raw */
+       sti_rom_copy(address, 0, sizeof *raw, raw);
+
+       dump_sti_rom(raw);
+
+       size = STI_U32(raw->last_addr) + 1;
+       size = 128*1024;
+//     DPRINTK(("size %08lx\n", size));
+//     DPRINTK(("font_start %08x\n", STI_U32(raw->font_start)));
+//     kfree(raw);
+       raw = kmalloc(size, GFP_KERNEL);
+       if(!raw)
+               goto out_err;
+       sti_rom_copy(address, 0, size-1, raw);
+
+       sti_cook_fonts(cooked, raw);
+//     sti_cook_regions(cooked, raw);
+//     sti_cook_functions(cooked, raw);
+
+       if(STI_U32(raw->region_list)) {
+               struct sti_rom_region *region =
+                       ((void *)raw) + STI_U32(raw->region_list) - 3;
+
+//             DPRINTK(("region_list %08x\n", STI_U32(raw->region_list)));
+
+               ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME!! */
+
+               ret->regions[0] = STI_U32(region[0].region);
+               ret->regions[1] = STI_U32(region[1].region);
+               ret->regions[2] = STI_U32(region[2].region);
+               ret->regions[3] = STI_U32(region[3].region);
+               ret->regions[4] = STI_U32(region[4].region);
+               ret->regions[5] = STI_U32(region[5].region);
+               ret->regions[6] = STI_U32(region[6].region);
+               ret->regions[7] = STI_U32(region[7].region);
+       }
+
+       address = virt_to_phys(raw);
+
+#if 0
+       DPRINTK(("init_graph %08x %08x\n"
+              "state_mgmt %08x %08x\n"
+              "font_unpmv %08x %08x\n"
+              "block_move %08x %08x\n"
+              "self_test  %08x %08x\n"
+              "excep_hdlr %08x %08x\n"
+              "irq_conf   %08x %08x\n"
+              "set_cm_e   %08x %08x\n"
+              "dma_ctrl   %08x %08x\n"
+              "flow_ctrl  %08x %08x\n"
+              "user_timin %08x %08x\n"
+              "process_m  %08x %08x\n"
+              "sti_util   %08x %08x\n"
+              "end_addr   %08x %08x\n",
+              STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
+              STI_U32(raw->state_mgmt), STI_U32(raw->state_mgmt_m68k),
+              STI_U32(raw->font_unpmv), STI_U32(raw->font_unpmv_m68k),
+              STI_U32(raw->block_move), STI_U32(raw->block_move_m68k),
+              STI_U32(raw->self_test), STI_U32(raw->self_test_m68k),
+              STI_U32(raw->excep_hdlr), STI_U32(raw->excep_hdlr_m68k),
+              STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
+              STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
+              STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
+              STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
+              STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
+              STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
+              STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
+              STI_U32(raw->end_addr), STI_U32(raw->end_addr_m68k) ) );
+#endif
+
+       ret->init_graph = sti_cook_function(((void *)raw)+STI_U32(raw->init_graph)-3,
+                                           (STI_U32(raw->state_mgmt) -
+                                            STI_U32(raw->init_graph))/4);
+
+
+       ret->font_unpmv = sti_cook_function(((void *)raw)+STI_U32(raw->font_unpmv)-3,
+                                           (STI_U32(raw->block_move) -
+                                            STI_U32(raw->font_unpmv))/4);
+
+       ret->block_move = sti_cook_function(((void *)raw)+STI_U32(raw->block_move)-3,
+                                           (STI_U32(raw->self_test) -
+                                            STI_U32(raw->block_move))/4);
+
+       ret->inq_conf = sti_cook_function(((void *)raw)+STI_U32(raw->inq_conf),
+                                         STI_U32(raw->set_cm_entry) -
+                                         STI_U32(raw->inq_conf));
+
+       ret->rom = cooked;
+       ret->rom->raw = raw;
+
+       ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw);
+
+       return ret;
+
+out_err:
+       if(raw)
+               kfree(raw);
+       if(cooked)
+               kfree(cooked);
+
+       return NULL;
+}
+
+#if 0
+static void dump_globcfg_ext(struct sti_glob_cfg_ext *cfg)
+{
+       DPRINTK(("monitor %d\n"
+               "in friendly mode: %d\n"
+               "power consumption %d watts\n"
+               "freq ref %d\n"
+               "sti_mem_addr %p\n",
+               cfg->curr_mon,
+               cfg->friendly_boot,
+               cfg->power,
+               cfg->freq_ref,
+               cfg->sti_mem_addr));
+}
+
+static void dump_globcfg(struct sti_glob_cfg *glob_cfg)
+{
+       DPRINTK(("%d text planes\n"
+               "%4d x %4d screen resolution\n"
+               "%4d x %4d offscreen\n"
+               "%4d x %4d layout\n"
+               "regions at %08x %08x %08x %08x\n"
+               "regions at %08x %08x %08x %08x\n"
+               "reent_lvl %d\n"
+               "save_addr %p\n",
+               glob_cfg->text_planes,
+               glob_cfg->onscreen_x, glob_cfg->onscreen_y,
+               glob_cfg->offscreen_x, glob_cfg->offscreen_y,
+               glob_cfg->total_x, glob_cfg->total_y,
+               glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
+               glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
+               glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
+               glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
+               glob_cfg->reent_lvl,
+               glob_cfg->save_addr));
+       dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr));
+}
+#endif
+               
+static void __init sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa,
+                                    unsigned long rom_address)
+{
+       struct sti_glob_cfg *glob_cfg;
+       struct sti_glob_cfg_ext *glob_cfg_ext;
+       void *save_addr;
+       void *sti_mem_addr;
+
+       glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL);
+       glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL);
+       save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL);
+       sti_mem_addr = kmalloc(1024, GFP_KERNEL);
+
+       if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr))
+               return;
+
+       memset(glob_cfg, 0, sizeof *glob_cfg);
+       memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext);
+       memset(save_addr, 0, 1024);
+       memset(sti_mem_addr, 0, 1024);
+
+       glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
+       glob_cfg->save_addr = STI_PTR(save_addr);
+       glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address;
+       glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa;
+
+       glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
+
+       sti->glob_cfg = STI_PTR(glob_cfg);
+}
+
+static void __init sti_try_rom(unsigned long address, unsigned long hpa)
+{
+       struct sti_struct *sti = NULL;
+       u16 sig;
+       
+       /* if we can't read the ROM, bail out early.  Not being able
+        * to read the hpa is okay, for romless sti */
+       if(pdc_add_valid((void*)address))
+               return;
+
+       printk("found potential STI ROM at %08lx\n", address);
+
+       sig = le16_to_cpu(gsc_readw(address));
+
+       if((sig&0xff) == 0x01) {
+               sti = sti_read_rom(address);
+       }
+
+       if(sig == 0x0303) {
+               printk("STI word mode ROM at %08lx, ignored\n",
+                      address);
+
+               sti = NULL;
+       }
+
+       if(!sti)
+               return;
+
+       /* this is hacked.  We need a better way to find out the HPA for
+        * romless STI (eg search for the graphics devices we know about
+        * by sversion) */
+       if (!pdc_add_valid((void *)0xf5000000)) DPRINTK(("f4000000 b\n"));
+       if (!pdc_add_valid((void *)0xf7000000)) DPRINTK(("f6000000 b\n"));
+       if (!pdc_add_valid((void *)0xf9000000)) DPRINTK(("f8000000 b\n"));
+       if (!pdc_add_valid((void *)0xfb000000)) DPRINTK(("fa000000 b\n"));
+       sti_init_glob_cfg(sti, hpa, address);
+
+       sti_init_graph(sti);
+
+       //sti_inq_conf(sti);
+#if !defined(SERIAL_CONSOLE)   
+       { 
+           extern void pdc_console_die(void);  
+           pdc_console_die(); 
+       }
+#endif
+               
+       take_over_console(&sti_con, 0, MAX_NR_CONSOLES-1, 1);
+
+       /* sti_inq_conf(sti); */
+}
+
+static unsigned long sti_address;
+static unsigned long sti_hpa;
+
+static void __init sti_init_roms(void)
+{
+       /* handle the command line */
+       if(sti_address && sti_hpa) {
+               sti_try_rom(sti_address, sti_hpa);
+
+               return;
+       }
+
+       /* 712, 715, some other boxes don't have a separate STI ROM,
+        * but use part of the regular flash */
+       if(PAGE0->proc_sti) {
+               printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti);
+               if(!pdc_add_valid((void *)0xf9000000))
+                       sti_try_rom(PAGE0->proc_sti, 0xf8000000);
+               else if(!pdc_add_valid((void *)0xf5000000))
+                       sti_try_rom(PAGE0->proc_sti, 0xf4000000);
+               else if(!pdc_add_valid((void *)0xf7000000))
+                       sti_try_rom(PAGE0->proc_sti, 0xf6000000);
+               else if(!pdc_add_valid((void *)0xfb000000))
+                       sti_try_rom(PAGE0->proc_sti, 0xfa000000);
+       }
+
+       /* standard locations for GSC graphic devices */
+       if(!pdc_add_valid((void *)0xf4000000))
+               sti_try_rom(0xf4000000, 0xf4000000);
+       if(!pdc_add_valid((void *)0xf6000000))
+               sti_try_rom(0xf6000000, 0xf6000000);
+       if(!pdc_add_valid((void *)0xf8000000))
+               sti_try_rom(0xf8000000, 0xf8000000);
+       if(!pdc_add_valid((void *)0xfa000000))
+               sti_try_rom(0xfa000000, 0xfa000000);
+}
+
+static int __init sti_init(void)
+{
+       printk("searching for byte mode STI ROMs\n");
+       sti_init_roms();
+       return 0;
+}
+
+module_init(sti_init)
diff --git a/drivers/video/sticon.c b/drivers/video/sticon.c
new file mode 100644 (file)
index 0000000..ba3f116
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ *  linux/drivers/video/sticon.c  - console driver using HP's STI firmware
+ *
+ *     Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ *  Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
+ *  which were
+ *
+ *     Created 28 Sep 1997 by Geert Uytterhoeven
+ *     Rewritten by Martin Mares <mj@ucw.cz>, July 1998
+ *     Copyright (C) 1991, 1992  Linus Torvalds
+ *                         1995  Jay Estabrook
+ *     Copyright (C) 1995 Geert Uytterhoeven
+ *     Copyright (C) 1993 Bjoern Brauel
+ *                        Roman Hodek
+ *     Copyright (C) 1993 Hamish Macdonald
+ *                        Greg Harp
+ *     Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
+ *
+ *           with work by William Rucklidge (wjr@cs.cornell.edu)
+ *                        Geert Uytterhoeven
+ *                        Jes Sorensen (jds@kom.auc.dk)
+ *                        Martin Apel
+ *           with work by Guenther Kelleter
+ *                        Martin Schaller
+ *                        Andreas Schwab
+ *                        Emmanuel Marty (core@ggi-project.org)
+ *                        Jakub Jelinek (jj@ultra.linux.cz)
+ *                        Martin Mares <mj@ucw.cz>
+ *
+ *  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.
+ */
+/*
+ *  TODO:
+ *   - call STI in virtual mode rather than in real mode
+ *   - support for PCI-only STI ROMs (which don't have a traditional region
+ *     list)
+ *   - safe detection (i.e. verify there is a graphics device at a given
+ *     address first, not just read a random device's io space)
+ *   - support for multiple STI devices in one machine
+ *   - support for byte-mode STI ROMs
+ *   - support for just using STI to switch to a colour fb (stifb ?)
+ *   - try to make it work on m68k hp workstations ;)
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/console_struct.h>
+#include <linux/errno.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+
+#include <asm/io.h>
+
+#include "sti.h"
+
+/* STICON */
+
+static const char * __init
+sticon_startup(void)
+{
+       return "STI console";
+}
+
+static int
+sticon_set_palette(struct vc_data *c, unsigned char *table)
+{
+       return -EINVAL;
+}
+static int
+sticon_font_op(struct vc_data *c, struct console_font_op *op)
+{
+       return -ENOSYS;
+}
+
+static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
+{
+       sti_putc(&default_sti, c, ypos, xpos);
+}
+
+static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
+       int count, int ypos, int xpos)
+{
+       while(count--) {
+               sti_putc(&default_sti, *s++, ypos, xpos++);
+       }
+}
+
+static void sticon_cursor(struct vc_data *conp, int mode)
+{
+}
+
+static int sticon_scroll(struct vc_data *conp, int t, int b, int dir,
+                       int count)
+{
+       struct sti_struct *sti = &default_sti;
+
+       if(console_blanked)
+               return 0;
+
+       sticon_cursor(conp, CM_ERASE);
+
+       switch(dir) {
+       case SM_UP:
+               sti_bmove(sti, t+count, 0, t, 0, b-t-count, conp->vc_cols);
+               sti_clear(sti, b-count, 0, count, conp->vc_cols);
+
+               break;
+
+       case SM_DOWN:
+               sti_bmove(sti, t, 0, t+count, 0, b-t-count, conp->vc_cols);
+               sti_clear(sti, t, 0, count, conp->vc_cols);
+
+               break;
+       }
+
+       return 0;
+}
+       
+static void sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+                        int height, int width)
+{
+       sti_bmove(&default_sti, sy, sx, dy, dx, height, width);
+}
+
+static void sticon_init(struct vc_data *c, int init)
+{
+       struct sti_struct *sti = &default_sti;
+       int vc_cols, vc_rows;
+
+       sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
+       c->vc_can_do_color = 1;
+       vc_cols = PTR_STI(sti->glob_cfg)->onscreen_x / sti_font_x(sti);
+       vc_rows = PTR_STI(sti->glob_cfg)->onscreen_y / sti_font_y(sti);
+
+       vc_resize_con(vc_rows, vc_cols, c->vc_num);
+}
+
+static void sticon_deinit(struct vc_data *c)
+{
+}
+
+static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
+                       int width)
+{
+       sti_clear(&default_sti, sy, sx, height, width);
+}
+
+static int sticon_switch(struct vc_data *conp)
+{
+       return 0;
+}
+
+static int sticon_blank(struct vc_data *conp, int blank)
+{
+       return 0;
+}
+
+static int sticon_scrolldelta(struct vc_data *conp, int lines)
+{
+       return 0;
+}
+
+static int sticon_set_origin(struct vc_data *conp)
+{
+       return 0;
+}
+
+static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
+{
+       return NULL;
+}
+
+static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, int *px, int *py)
+{
+       return 0;
+}
+
+static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse)
+{
+       u8 attr = ((color & 0x70) >> 1) | ((color & 7));
+
+       if(reverse) {
+               color = ((color>>3)&0x7) | ((color &0x7)<<3);
+       }
+
+
+       return attr;
+}
+
+struct consw sti_con = {
+       con_startup:            sticon_startup, 
+       con_init:               sticon_init,
+       con_deinit:             sticon_deinit,
+       con_clear:              sticon_clear,
+       con_putc:               sticon_putc,
+       con_putcs:              sticon_putcs,
+       con_cursor:             sticon_cursor,
+       con_scroll:             sticon_scroll,
+       con_bmove:              sticon_bmove,
+       con_switch:             sticon_switch,
+       con_blank:              sticon_blank,
+       con_font_op:            sticon_font_op,
+       con_set_palette:        sticon_set_palette,
+       con_scrolldelta:        sticon_scrolldelta,
+       con_set_origin:         sticon_set_origin,
+       con_save_screen:        NULL,
+       con_build_attr:         sticon_build_attr,
+       con_invert_region:      NULL,
+       con_screen_pos:         sticon_screen_pos,
+       con_getxy:              sticon_getxy,
+};
+
+static int __init sti_init(void)
+{
+       printk("searching for word mode STI ROMs\n");
+       if (sti_init_roms()) {
+               pdc_console_die();
+               take_over_console(&sti_con, 0, MAX_NR_CONSOLES-1, 1);
+               return 0;
+       } else
+               return -ENODEV;
+}
+
+module_init(sti_init)
diff --git a/drivers/video/sticore.c b/drivers/video/sticore.c
new file mode 100644 (file)
index 0000000..bc3bf85
--- /dev/null
@@ -0,0 +1,599 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+
+#include "sti.h"
+
+struct sti_struct default_sti = {
+       SPIN_LOCK_UNLOCKED,
+};
+
+static struct sti_font_flags default_font_flags = {
+       STI_WAIT, 0, 0, NULL
+};
+
+/* The colour indices used by STI are
+ *   0 - Black
+ *   1 - White
+ *   2 - Red
+ *   3 - Yellow/Brown
+ *   4 - Green
+ *   5 - Cyan
+ *   6 - Blue
+ *   7 - Magenta
+ *
+ * So we have the same colours as VGA (basically one bit each for R, G, B),
+ * but have to translate them, anyway. */
+
+static u8 col_trans[8] = {
+        0, 6, 4, 5,
+        2, 7, 3, 1
+};
+
+#define c_fg(sti, c) col_trans[((c>> 8) & 7)]
+#define c_bg(sti, c) col_trans[((c>>11) & 7)]
+#define c_index(sti, c) (c&0xff)
+
+static struct sti_init_flags default_init_flags = {
+       STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL
+};
+
+void
+sti_init_graph(struct sti_struct *sti) 
+{
+       struct sti_init_inptr_ext inptr_ext = {
+               0, { 0 }, 0, NULL
+       };
+       struct sti_init_inptr inptr = {
+               3, STI_PTR(&inptr_ext)
+       };
+       struct sti_init_outptr outptr = { 0 };
+       unsigned long flags;
+       s32 ret;
+
+       spin_lock_irqsave(&sti->lock, flags);
+
+       ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr,
+               &outptr, sti->glob_cfg);
+
+       spin_unlock_irqrestore(&sti->lock, flags);
+
+       sti->text_planes = outptr.text_planes;
+}
+
+static struct sti_conf_flags default_conf_flags = {
+       STI_WAIT, 0, NULL
+};
+
+void
+sti_inq_conf(struct sti_struct *sti)
+{
+       struct sti_conf_inptr inptr = { NULL };
+       struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL };
+       struct sti_conf_outptr outptr = {
+               ext_ptr: STI_PTR(&outptr_ext)
+       };
+       unsigned long flags;
+       s32 ret;
+       
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->inq_conf, &default_conf_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+
+void
+sti_putc(struct sti_struct *sti, int c, int y, int x)
+{
+       struct sti_font_inptr inptr = {
+               (u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
+               x * sti_font_x(sti), y * sti_font_y(sti), NULL
+       };
+       struct sti_font_outptr outptr = {
+               0, NULL
+       };
+       s32 ret;
+       unsigned long flags;
+
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->font_unpmv, &default_font_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+
+static struct sti_blkmv_flags clear_blkmv_flags = {
+       STI_WAIT, 1, 1, 0, 0, NULL
+};
+
+void
+sti_set(struct sti_struct *sti, int src_y, int src_x,
+       int height, int width, u8 color)
+{
+       struct sti_blkmv_inptr inptr = {
+               color, color,
+               src_x, src_y ,
+               src_x, src_y ,
+               width, height,
+               NULL
+       };
+       struct sti_blkmv_outptr outptr = { 0, NULL };
+       s32 ret = 0;
+       unsigned long flags;
+       
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+
+void
+sti_clear(struct sti_struct *sti, int src_y, int src_x,
+         int height, int width)
+{
+       struct sti_blkmv_inptr inptr = {
+               0, 0,
+               src_x * sti_font_x(sti), src_y * sti_font_y(sti),
+               src_x * sti_font_x(sti), src_y * sti_font_y(sti),
+               width * sti_font_x(sti), height* sti_font_y(sti),
+               NULL
+       };
+       struct sti_blkmv_outptr outptr = { 0, NULL };
+       s32 ret = 0;
+       unsigned long flags;
+
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+
+static struct sti_blkmv_flags default_blkmv_flags = {
+       STI_WAIT, 0, 0, 0, 0, NULL
+};
+
+void
+sti_bmove(struct sti_struct *sti, int src_y, int src_x,
+         int dst_y, int dst_x, int height, int width)
+{
+       struct sti_blkmv_inptr inptr = {
+               0, 0,
+               src_x * sti_font_x(sti), src_y * sti_font_y(sti),
+               dst_x * sti_font_x(sti), dst_y * sti_font_y(sti),
+               width * sti_font_x(sti), height* sti_font_y(sti),
+               NULL
+       };
+       struct sti_blkmv_outptr outptr = { 0, NULL };
+       s32 ret = 0;
+       unsigned long flags;
+
+       do {
+               spin_lock_irqsave(&sti->lock, flags);
+               ret = STI_CALL(sti->block_move, &default_blkmv_flags,
+                       &inptr, &outptr, sti->glob_cfg);
+               spin_unlock_irqrestore(&sti->lock, flags);
+       } while(ret == 1);
+}
+
+
+static void __init
+sti_rom_copy(unsigned long base, unsigned long offset,
+            unsigned long count, void *dest)
+{
+       void *savedest = dest;
+       int savecount = count;
+
+       while(count >= 4) {
+               count -= 4;
+               *(u32 *)dest = gsc_readl(base + offset);
+               offset += 4;
+               dest += 4;
+       }
+       while(count) {
+               count--;
+               *(u8 *)dest = gsc_readb(base + offset);
+               offset++;
+               dest++;
+       }
+       __flush_dcache_range((unsigned long) dest, count);
+       __flush_icache_range((unsigned long) dest, count);
+}
+
+static void dump_sti_rom(struct sti_rom *rom)
+{
+       printk("STI word mode ROM type %d\n", rom->type[3]);
+       printk(" supports %d monitors\n", rom->num_mons);
+       printk(" conforms to STI ROM spec revision %d.%02x\n",
+               rom->revno[0] >> 4, rom->revno[0] & 0x0f);
+       printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n",
+               rom->graphics_id[0], 
+               rom->graphics_id[1], 
+               rom->graphics_id[2], 
+               rom->graphics_id[3], 
+               rom->graphics_id[4], 
+               rom->graphics_id[5], 
+               rom->graphics_id[6], 
+               rom->graphics_id[7]);
+       printk(" font start %08x\n", rom->font_start);
+       printk(" region list %08x\n", rom->region_list);
+       printk(" init_graph %08x\n", rom->init_graph);
+       printk(" alternate code type %d\n", rom->alt_code_type);
+}
+
+static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
+                                 struct sti_rom *raw_rom)
+{
+       struct sti_rom_font *raw_font;
+       struct sti_cooked_font *cooked_font;
+       struct sti_rom_font *font_start;
+       
+       cooked_font =
+               kmalloc(sizeof *cooked_font, GFP_KERNEL);
+       if(!cooked_font)
+               return;
+
+       cooked_rom->font_start = cooked_font;
+
+       raw_font = ((void *)raw_rom) + (raw_rom->font_start);
+
+       font_start = raw_font;
+       cooked_font->raw = raw_font;
+
+       while(raw_font->next_font) {
+               raw_font = ((void *)font_start) + (raw_font->next_font);
+               
+               cooked_font->next_font =
+                       kmalloc(sizeof *cooked_font, GFP_KERNEL);
+               if(!cooked_font->next_font)
+                       return;
+
+               cooked_font = cooked_font->next_font;
+
+               cooked_font->raw = raw_font;
+       }
+
+       cooked_font->next_font = NULL;
+}
+
+static int font_index, font_height, font_width;
+
+static int __init sti_font_setup(char *str)
+{
+       char *x;
+
+       /* we accept sti_font=10x20, sti_font=10*20 or sti_font=7 style
+        * command lines. */
+
+       if((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
+               font_height = simple_strtoul(str, NULL, 0);
+               font_width = simple_strtoul(x+1, NULL, 0);
+       } else {
+               font_index = simple_strtoul(str, NULL, 0);
+       }
+
+       return 0;
+}
+
+__setup("sti_font=", sti_font_setup);
+
+static int __init sti_search_font(struct sti_cooked_rom *rom,
+                                 int height, int width)
+{
+       struct sti_cooked_font *font;
+       int i = 0;
+       
+       for(font = rom->font_start; font; font = font->next_font, i++) {
+               if((font->raw->width == width) && (font->raw->height == height))
+                       return i;
+       }
+
+       return 0;
+}
+
+static struct sti_cooked_font * __init
+sti_select_font(struct sti_cooked_rom *rom)
+{
+       struct sti_cooked_font *font;
+       int i;
+
+       if(font_width && font_height)
+               font_index = sti_search_font(rom, font_height, font_width);
+
+       for(font = rom->font_start, i = font_index;
+           font && (i > 0);
+           font = font->next_font, i--);
+
+       if(font)
+               return font;
+       else
+               return rom->font_start;
+}
+       
+static void __init
+sti_dump_globcfg_ext(struct sti_glob_cfg_ext *cfg)
+{
+       printk( "monitor %d\n"
+               "in friendly mode: %d\n"
+               "power consumption %d watts\n"
+               "freq ref %d\n"
+               "sti_mem_addr %p\n",
+               cfg->curr_mon,
+               cfg->friendly_boot,
+               cfg->power,
+               cfg->freq_ref,
+               cfg->sti_mem_addr);
+}
+
+void __init
+sti_dump_globcfg(struct sti_glob_cfg *glob_cfg)
+{
+       printk( "%d text planes\n"
+               "%4d x %4d screen resolution\n"
+               "%4d x %4d offscreen\n"
+               "%4d x %4d layout\n"
+               "regions at %08x %08x %08x %08x\n"
+               "regions at %08x %08x %08x %08x\n"
+               "reent_lvl %d\n"
+               "save_addr %p\n",
+               glob_cfg->text_planes,
+               glob_cfg->onscreen_x, glob_cfg->onscreen_y,
+               glob_cfg->offscreen_x, glob_cfg->offscreen_y,
+               glob_cfg->total_x, glob_cfg->total_y,
+               glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
+               glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
+               glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
+               glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
+               glob_cfg->reent_lvl,
+               glob_cfg->save_addr);
+       sti_dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr));
+}
+               
+static void __init
+sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa,
+                 unsigned long rom_address)
+{
+       struct sti_glob_cfg *glob_cfg;
+       struct sti_glob_cfg_ext *glob_cfg_ext;
+       void *save_addr;
+       void *sti_mem_addr;
+
+       glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL);
+       glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL);
+       save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL);
+       sti_mem_addr = kmalloc(1024, GFP_KERNEL);
+
+       if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr))
+               return;
+
+       memset(glob_cfg, 0, sizeof *glob_cfg);
+       memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext);
+       memset(save_addr, 0, 1024);
+       memset(sti_mem_addr, 0, 1024);
+
+       glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
+       glob_cfg->save_addr = STI_PTR(save_addr);
+       glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address;
+       glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa;
+       glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa;
+       
+       glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
+
+       sti->glob_cfg = STI_PTR(glob_cfg);
+}
+
+/* address is a pointer to a word mode or pci rom */
+static struct sti_struct * __init
+sti_read_rom(unsigned long address)
+{
+       struct sti_struct *ret = NULL;
+       struct sti_cooked_rom *cooked = NULL;
+       struct sti_rom *raw = NULL;
+       unsigned long size;
+
+       ret = &default_sti;
+
+       if(!ret)
+               goto out_err;
+
+       cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
+       raw = kmalloc(sizeof *raw, GFP_KERNEL);
+       
+       if(!(raw && cooked))
+               goto out_err;
+
+       /* reallocate raw */
+       sti_rom_copy(address, 0, sizeof *raw, raw);
+
+       dump_sti_rom(raw);
+
+       size = raw->last_addr;
+       /* kfree(raw); */
+       raw = kmalloc(size, GFP_KERNEL);
+       if(!raw)
+               goto out_err;
+       sti_rom_copy(address, 0, size, raw);
+
+       sti_cook_fonts(cooked, raw);
+#if 0
+       sti_cook_regions(cooked, raw);
+       sti_cook_functions(cooked, raw);
+#endif
+
+       if(raw->region_list) {
+               ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME */
+
+               memcpy(ret->regions, ((void *)raw)+raw->region_list, 32);
+       }
+
+       address = virt_to_phys(raw);
+
+       ret->font_unpmv = address+(raw->font_unpmv & 0x03ffffff);
+       ret->block_move = address+(raw->block_move & 0x03ffffff);
+       ret->init_graph = address+(raw->init_graph & 0x03ffffff);
+       ret->inq_conf = address+(raw->inq_conf     & 0x03ffffff);
+
+       ret->rom = cooked;
+       ret->rom->raw = raw;
+
+       ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw);
+
+       return ret;
+
+out_err:
+       if(raw)
+               kfree(raw);
+       if(cooked)
+               kfree(cooked);
+
+       return NULL;
+}
+
+static struct sti_struct * __init
+sti_try_rom(unsigned long address, unsigned long hpa)
+{
+       struct sti_struct *sti = NULL;
+       u16 sig;
+       
+test_rom:
+       /* if we can't read the ROM, bail out early.  Not being able
+        * to read the hpa is okay, for romless sti */
+       if(pdc_add_valid((void*)address))
+               return NULL;
+
+       printk("found potential STI ROM at %08lx\n", address);
+
+       sig = le16_to_cpu(gsc_readw(address));
+
+       if((sig==0x55aa) || (sig==0xaa55)) {
+               address += le32_to_cpu(gsc_readl(address+8));
+               printk("sig %04x, PCI STI ROM at %08lx\n",
+                      sig, address);
+
+               goto test_rom;
+       }
+
+       if((sig&0xff) == 0x01) {
+               printk("STI byte mode ROM at %08lx, ignored\n",
+                      address);
+
+               sti = NULL;
+       }
+
+       if(sig == 0x0303) {
+               printk("STI word mode ROM at %08lx\n",
+                      address);
+
+               sti = sti_read_rom(address);
+       }
+
+       if (!sti)
+               return NULL;
+
+       /* this is hacked.  We need a better way to find out the HPA for
+        * romless STI (eg search for the graphics devices we know about
+        * by sversion) */
+       if (!pdc_add_valid((void *)0xf5000000)) printk("f4000000 g\n");
+       if (!pdc_add_valid((void *)0xf7000000)) printk("f6000000 g\n");
+       if (!pdc_add_valid((void *)0xf9000000)) printk("f8000000 g\n");
+       if (!pdc_add_valid((void *)0xfb000000)) printk("fa000000 g\n");
+       sti_init_glob_cfg(sti, hpa, address);
+
+       sti_init_graph(sti);
+
+       sti_inq_conf(sti);
+       sti_dump_globcfg(PTR_STI(sti->glob_cfg));
+
+       return sti;
+}
+
+static unsigned long sti_address;
+static unsigned long sti_hpa;
+
+/* XXX: should build a list of STI ROMs */
+struct sti_struct * __init
+sti_init_roms(void)
+{
+       struct sti_struct *tmp = NULL, *sti = NULL;
+
+       /* handle the command line */
+       if (sti_address && sti_hpa) {
+               return sti_try_rom(sti_address, sti_hpa);
+       }
+
+       /* 712, 715, some other boxes don't have a separate STI ROM,
+        * but use part of the regular flash */
+       if (PAGE0->proc_sti) {
+               printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti);
+               if (!pdc_add_valid((void *)0xf9000000))
+                       sti = sti_try_rom(PAGE0->proc_sti, 0xf8000000);
+               else if (!pdc_add_valid((void *)0xf5000000))
+                       sti = sti_try_rom(PAGE0->proc_sti, 0xf4000000);
+               else if (!pdc_add_valid((void *)0xf7000000))
+                       sti = sti_try_rom(PAGE0->proc_sti, 0xf6000000);
+               else if (!pdc_add_valid((void *)0xfb000000))
+                       sti = sti_try_rom(PAGE0->proc_sti, 0xfa000000);
+
+       }
+
+       /* standard locations for GSC graphic devices */
+       if (!pdc_add_valid((void *)0xf4000000))
+               tmp = sti_try_rom(0xf4000000, 0xf4000000);
+       sti = tmp ? tmp : sti;
+       if (!pdc_add_valid((void *)0xf6000000))
+               tmp = sti_try_rom(0xf6000000, 0xf6000000);
+       sti = tmp ? tmp : sti;
+       if (!pdc_add_valid((void *)0xf8000000))
+               tmp = sti_try_rom(0xf8000000, 0xf8000000);
+       sti = tmp ? tmp : sti;
+       if (!pdc_add_valid((void *)0xfa000000))
+               tmp = sti_try_rom(0xfa000000, 0xfa000000);
+       sti = tmp ? tmp : sti;
+
+       return sti;
+}
+
+static int __init
+sti_setup(char *str)
+{
+       char *end;
+
+       if(strcmp(str, "pdc") == 0) {
+               sti_address = PAGE0->proc_sti;
+
+               return 1;
+       } else {
+               sti_address = simple_strtoul(str, &end, 16);
+
+               if((end == str) || (sti_address < 0xf0000000)) {
+                       sti_address = 0;
+                       return 0;
+               }
+
+               sti_hpa = sti_address;
+
+               return 1;
+       }
+
+       return 0;
+}
+
+__setup("sti=", sti_setup);
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
new file mode 100644 (file)
index 0000000..661ff29
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * linux/drivers/video/stifb.c - Generic frame buffer driver for HP
+ * workstations with STI (standard text interface) video firmware.
+ *
+ * Based on:
+ * linux/drivers/video/artistfb.c -- Artist frame buffer driver
+ *
+ *     Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ *  based on skeletonfb, which was
+ *     Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ * 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.  */
+
+/*
+ * Notes:
+ *
+ * This driver assumes that the video has been set up in 1bpp mode by
+ * the firmware.  Since HP video tends to be planar rather than
+ * packed-pixel this will probably work anyway even if it isn't.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include <video/fbcon.h>
+
+#include "sti.h"
+
+static struct fb_ops stifb_ops;
+
+struct stifb_info {
+       struct fb_info_gen gen;
+       struct sti_struct *sti;
+};
+
+struct stifb_par {
+};
+
+static struct stifb_info fb_info;
+static struct display disp;
+
+int stifb_init(void);
+int stifb_setup(char*);
+
+extern struct display_switch fbcon_sti;
+
+/* ------------------- chipset specific functions -------------------------- */
+
+static int
+sti_encode_fix(struct fb_fix_screeninfo *fix,
+              const void *par, struct fb_info_gen *info)
+{
+       /* XXX: what about smem_len? */
+       fix->smem_start = PTR_STI(fb_info.sti->glob_cfg)->region_ptrs[1];
+       fix->type = FB_TYPE_PLANES; /* well, sort of */
+
+       return 0;
+}
+
+static int
+sti_decode_var(const struct fb_var_screeninfo *var,
+       void *par, struct fb_info_gen *info)
+{
+       return 0;
+}
+
+static int
+sti_encode_var(struct fb_var_screeninfo *var,
+              const void *par, struct fb_info_gen *info)
+{
+       var->xres = PTR_STI(fb_info.sti->glob_cfg)->onscreen_x;
+       var->yres = PTR_STI(fb_info.sti->glob_cfg)->onscreen_y;
+       var->xres_virtual = PTR_STI(fb_info.sti->glob_cfg)->total_x;
+       var->yres_virtual = PTR_STI(fb_info.sti->glob_cfg)->total_y;
+       var->xoffset = var->yoffset = 0;
+
+       var->bits_per_pixel = 1;
+       var->grayscale = 0;
+
+       return 0;
+}
+
+static void
+sti_get_par(void *par, struct fb_info_gen *info)
+{
+}
+
+static void
+sti_set_par(const void *par, struct fb_info_gen *info)
+{
+}
+
+static int
+sti_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+             unsigned *blue, unsigned *transp, struct fb_info *info)
+{
+       return 0;
+}
+
+static int
+sti_setcolreg(unsigned regno, unsigned red, unsigned green,
+             unsigned blue, unsigned transp, struct fb_info *info)
+{
+       return 0;
+}
+
+static void
+sti_set_disp(const void *par, struct display *disp,
+            struct fb_info_gen *info)
+{
+       disp->screen_base =
+               (void *) PTR_STI(fb_info.sti->glob_cfg)->region_ptrs[1];
+       disp->dispsw = &fbcon_sti;
+}
+
+static void
+sti_detect(void)
+{
+}
+
+static int
+sti_blank(int blank_mode, const struct fb_info *info)
+{
+       return 0;
+}
+
+/* ------------ Interfaces to hardware functions ------------ */
+
+struct fbgen_hwswitch sti_switch = {
+       detect:         sti_detect,
+       encode_fix:     sti_encode_fix,
+       decode_var:     sti_decode_var,
+       encode_var:     sti_encode_var,
+       get_par:        sti_get_par,
+       set_par:        sti_set_par,
+       getcolreg:      sti_getcolreg,
+       setcolreg:      sti_setcolreg,
+       pan_display:    NULL,
+       blank:          sti_blank,
+       set_disp:       sti_set_disp
+};
+
+
+/* ------------ Hardware Independent Functions ------------ */
+
+    /*
+     *  Initialization
+     */
+
+int __init
+stifb_init(void)
+{
+       printk("searching for word mode STI ROMs\n");
+       /* XXX: in the future this will return a list of ROMs */
+       if ((fb_info.sti = sti_init_roms()) == NULL)
+               return -ENXIO;
+
+       fb_info.gen.info.node = -1;
+       fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+       fb_info.gen.info.fbops = &stifb_ops;
+       fb_info.gen.info.disp = &disp;
+       fb_info.gen.info.changevar = NULL;
+       fb_info.gen.info.switch_con = &fbgen_switch;
+       fb_info.gen.info.updatevar = &fbgen_update_var;
+       fb_info.gen.info.blank = &fbgen_blank;
+       strcpy(fb_info.gen.info.modename, "STI Generic");
+       fb_info.gen.fbhw = &sti_switch;
+       fb_info.gen.fbhw->detect();
+
+       /* This should give a reasonable default video mode */
+       fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+       fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+       fbgen_set_disp(-1, &fb_info.gen);
+       fbgen_install_cmap(0, &fb_info.gen);
+       pdc_console_die();
+       if (register_framebuffer(&fb_info.gen.info) < 0)
+               return -EINVAL;
+
+       printk(KERN_INFO "fb%d: %s frame buffer device\n",
+               GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);
+
+       return 0;
+}
+
+
+    /*
+     *  Cleanup
+     */
+
+void
+stifb_cleanup(struct fb_info *info)
+{
+       printk("stifb_cleanup: you're on crack\n");
+}
+
+
+int __init
+stifb_setup(char *options)
+{
+       /* XXX: we should take the resolution, bpp as command line arguments. */
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static struct fb_ops stifb_ops = {
+       owner:          THIS_MODULE,
+       fb_open:        NULL,
+       fb_release:     NULL,
+       fb_get_fix:     fbgen_get_fix,
+       fb_get_var:     fbgen_get_var,
+       fb_set_var:     fbgen_set_var,
+       fb_get_cmap:    fbgen_get_cmap,
+       fb_set_cmap:    fbgen_set_cmap,
+       fb_pan_display: fbgen_pan_display,
+       fb_ioctl:       NULL
+};
index 09b28574dc266581ca400716e2b46bcc4be835c3..7a935a739423ce784f2bb067097fa47ddf18d8f1 100644 (file)
@@ -40,13 +40,11 @@ struct file * get_empty_filp(void)
                list_del(&f->f_list);
                files_stat.nr_free_files--;
        new_one:
-               file_list_unlock();
                memset(f, 0, sizeof(*f));
                atomic_set(&f->f_count,1);
                f->f_version = ++event;
                f->f_uid = current->fsuid;
                f->f_gid = current->fsgid;
-               file_list_lock();
                list_add(&f->f_list, &anon_list);
                file_list_unlock();
                return f;
index 135e8707cc68a679b8dfdf6edda7717a855ad3db..f6c7a4112252173064d32444d1d6ab571ef2b26e 100644 (file)
@@ -82,7 +82,7 @@ io_error:
 }
 
 /*
- * We are called with the page locked and the caller unlocks.
+ * We are called with the page locked and we unlock it when done.
  */
 static int
 smb_readpage(struct file *file, struct page *page)
@@ -147,17 +147,33 @@ smb_writepage_sync(struct dentry *dentry, struct page *page,
  * Write a page to the server. This will be used for NFS swapping only
  * (for now), and we currently do this synchronously only.
  *
- * We are called with the page locked and the caller unlocks.
+ * We are called with the page locked and we unlock it when done.
  */
 static int
-smb_writepage(struct file *file, struct page *page)
+smb_writepage(struct page *page)
 {
-       struct dentry *dentry = file->f_dentry;
-       struct inode *inode = dentry->d_inode;
-       unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+       struct address_space *mapping = page->mapping;
+       struct dentry *dentry;
+       struct inode *inode;
+       struct list_head *head;
+       unsigned long end_index;
        unsigned offset = PAGE_CACHE_SIZE;
        int err;
 
+       if (!mapping)
+               BUG();
+       inode = (struct inode *)mapping->host;
+       if (!inode)
+               BUG();
+
+       /* Pick the first dentry for this inode. */
+       head = &inode->i_dentry;
+       if (list_empty(head))
+               BUG();  /* We need one, are we guaranteed to have one?  */
+       dentry = list_entry(head->next, struct dentry, d_alias);
+
+       end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
        /* easy case */
        if (page->index < end_index)
                goto do_it;
@@ -170,6 +186,7 @@ do_it:
        get_page(page);
        err = smb_writepage_sync(dentry, page, 0, offset);
        SetPageUptodate(page);
+       UnlockPage(page);
        put_page(page);
        return err;
 }
@@ -264,7 +281,7 @@ static int smb_commit_write(struct file *file, struct page *page,
 
 struct address_space_operations smb_file_aops = {
        readpage: smb_readpage,
-       writepage: smb_writepage,
+       /* writepage: smb_writepage, */
        prepare_write: smb_prepare_write,
        commit_write: smb_commit_write
 };
index e07b237e47fbc425df6da17135d84b6f6a838d83..3d7efa0ada0e95b8e74324f0e4ebbe94f08ff042 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -25,7 +25,7 @@ do_revalidate(struct dentry *dentry)
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -126,7 +126,7 @@ static int cp_new_stat(struct inode * inode, struct stat * statbuf)
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
 /*
  * For backward compatibility?  Maybe this should be moved
  * into arch/i386 instead?
@@ -162,7 +162,7 @@ asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
        return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -200,7 +200,7 @@ asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
        return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
index 45ca4dbbb61d1bf682e3ed9e874e7032eee6a9f6..3783b43fdd850d14331ef28f3795450204c73702 100644 (file)
@@ -202,7 +202,7 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
        mark_buffer_dirty(bh);
        udf_release_data(bh);
 
-       inode->i_data.a_ops->writepage(NULL, page);
+       inode->i_data.a_ops->writepage(page);
        UnlockPage(page);
        page_cache_release(page);
 
index ce0fdd07515564efce1b8f10c243415fb81e9648..4129be7011e6614fc9f05a163d83fac7596a960f 100644 (file)
@@ -13,6 +13,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <asm/machdep.h>
 
 #ifdef CONFIG_Q40
index 190f6bd9967e5ad4357244a80bbfd44022a5e041..7fea2e4ff2b6d0995031e667bb335b476c768e4e 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _MOTOROLA_PGTABLE_H
 #define _MOTOROLA_PGTABLE_H
 
+#include <linux/config.h>
+
 /*
  * Definitions for MMU descriptors
  */
index 8778ec6d5d94f3128816818eecf8c6eba722c9fe..9f307b3439d71cc0b9d2880e655bd64c680ec17e 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef M68K_PGALLOC_H
 #define M68K_PGALLOC_H
 
+#include <linux/config.h>
 #include <asm/setup.h>
 #include <asm/virtconvert.h>
 
diff --git a/include/asm-parisc/a.out.h b/include/asm-parisc/a.out.h
new file mode 100644 (file)
index 0000000..2a490cc
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __PARISC_A_OUT_H__
+#define __PARISC_A_OUT_H__
+
+struct exec
+{
+  unsigned int a_info;         /* Use macros N_MAGIC, etc for access */
+  unsigned a_text;             /* length of text, in bytes */
+  unsigned a_data;             /* length of data, in bytes */
+  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
+  unsigned a_syms;             /* length of symbol table data in file, in bytes */
+  unsigned a_entry;            /* start address */
+  unsigned a_trsize;           /* length of relocation info for text, in bytes */
+  unsigned a_drsize;           /* length of relocation info for data, in bytes */
+};
+
+#define N_TRSIZE(a)    ((a).a_trsize)
+#define N_DRSIZE(a)    ((a).a_drsize)
+#define N_SYMSIZE(a)   ((a).a_syms)
+
+#ifdef __KERNEL__
+
+/* XXX: STACK_TOP actually should be STACK_BOTTOM for parisc.
+ * prumpf */
+
+#define STACK_TOP      TASK_SIZE
+
+#endif
+
+#endif /* __A_OUT_GNU_H__ */
diff --git a/include/asm-parisc/asmregs.h b/include/asm-parisc/asmregs.h
new file mode 100644 (file)
index 0000000..d93c646
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
+ *
+ *     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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PARISC_ASMREGS_H
+#define _PARISC_ASMREGS_H
+
+;! General Registers
+
+rp:    .reg    %r2
+arg3:  .reg    %r23
+arg2:  .reg    %r24
+arg1:  .reg    %r25
+arg0:  .reg    %r26
+dp:    .reg    %r27
+ret0:  .reg    %r28
+ret1:  .reg    %r29
+sl:    .reg    %r29
+sp:    .reg    %r30
+
+#if 0
+/* PA20_REVISIT */
+arg7:  .reg    r19
+arg6:  .reg    r20
+arg5:  .reg    r21
+arg4:  .reg    r22
+gp:    .reg    r27
+ap:    .reg    r29
+#endif
+
+
+r0:    .reg    %r0
+r1:    .reg    %r1
+r2:    .reg    %r2
+r3:    .reg    %r3
+r4:    .reg    %r4
+r5:    .reg    %r5
+r6:    .reg    %r6
+r7:    .reg    %r7
+r8:    .reg    %r8
+r9:    .reg    %r9
+r10:   .reg    %r10
+r11:   .reg    %r11
+r12:   .reg    %r12
+r13:   .reg    %r13
+r14:   .reg    %r14
+r15:   .reg    %r15
+r16:   .reg    %r16
+r17:   .reg    %r17
+r18:   .reg    %r18
+r19:   .reg    %r19
+r20:   .reg    %r20
+r21:   .reg    %r21
+r22:   .reg    %r22
+r23:   .reg    %r23
+r24:   .reg    %r24
+r25:   .reg    %r25
+r26:   .reg    %r26
+r27:   .reg    %r27
+r28:   .reg    %r28
+r29:   .reg    %r29
+r30:   .reg    %r30
+r31:   .reg    %r31
+
+
+;! Space Registers
+
+sr0:   .reg    %sr0
+sr1:   .reg    %sr1
+sr2:   .reg    %sr2
+sr3:   .reg    %sr3
+sr4:   .reg    %sr4
+sr5:   .reg    %sr5
+sr6:   .reg    %sr6
+sr7:   .reg    %sr7
+
+
+;! Floating Point Registers
+
+fr0:   .reg    %fr0
+fr1:   .reg    %fr1
+fr2:   .reg    %fr2
+fr3:   .reg    %fr3
+fr4:   .reg    %fr4
+fr5:   .reg    %fr5
+fr6:   .reg    %fr6
+fr7:   .reg    %fr7
+fr8:   .reg    %fr8
+fr9:   .reg    %fr9
+fr10:  .reg    %fr10
+fr11:  .reg    %fr11
+fr12:  .reg    %fr12
+fr13:  .reg    %fr13
+fr14:  .reg    %fr14
+fr15:  .reg    %fr15
+fr16:  .reg    %fr16
+fr17:  .reg    %fr17
+fr18:  .reg    %fr18
+fr19:  .reg    %fr19
+fr20:  .reg    %fr20
+fr21:  .reg    %fr21
+fr22:  .reg    %fr22
+fr23:  .reg    %fr23
+fr24:  .reg    %fr24
+fr25:  .reg    %fr25
+fr26:  .reg    %fr26
+fr27:  .reg    %fr27
+fr28:  .reg    %fr28
+fr29:  .reg    %fr29
+fr30:  .reg    %fr30
+fr31:  .reg    %fr31
+
+
+;! Control Registers
+
+rctr:  .reg    %cr0
+pidr1: .reg    %cr8
+pidr2: .reg    %cr9
+ccr:   .reg    %cr10
+sar:   .reg    %cr11
+pidr3: .reg    %cr12
+pidr4: .reg    %cr13
+iva:   .reg    %cr14
+eiem:  .reg    %cr15
+itmr:  .reg    %cr16
+pcsq:  .reg    %cr17
+pcoq:  .reg    %cr18
+iir:   .reg    %cr19
+isr:   .reg    %cr20
+ior:   .reg    %cr21
+ipsw:  .reg    %cr22
+eirr:  .reg    %cr23
+tr0:   .reg    %cr24
+tr1:   .reg    %cr25
+tr2:   .reg    %cr26
+tr3:   .reg    %cr27
+tr4:   .reg    %cr28
+tr5:   .reg    %cr29
+tr6:   .reg    %cr30
+tr7:   .reg    %cr31
+
+
+cr0:   .reg    %cr0
+cr8:   .reg    %cr8
+cr9:   .reg    %cr9
+cr10:  .reg    %cr10
+cr11:  .reg    %cr11
+cr12:  .reg    %cr12
+cr13:  .reg    %cr13
+cr14:  .reg    %cr14
+cr15:  .reg    %cr15
+cr16:  .reg    %cr16
+cr17:  .reg    %cr17
+cr18:  .reg    %cr18
+cr19:  .reg    %cr19
+cr20:  .reg    %cr20
+cr21:  .reg    %cr21
+cr22:  .reg    %cr22
+cr23:  .reg    %cr23
+cr24:  .reg    %cr24
+cr25:  .reg    %cr25
+cr26:  .reg    %cr26
+cr27:  .reg    %cr27
+cr28:  .reg    %cr28
+cr29:  .reg    %cr29
+cr30:  .reg    %cr30
+cr31:  .reg    %cr31
+
+#endif
diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h
new file mode 100644 (file)
index 0000000..8d60681
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
+ * Copyright (C) 1999 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 1999 SuSE GmbH
+ *
+ *    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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PARISC_ASSEMBLY_H
+#define _PARISC_ASSEMBLY_H
+
+#if defined(__LP64__) && defined(__ASSEMBLY__)
+/* the 64-bit pa gnu assembler unfortunately defaults to .level 1.1 or 2.0 so
+ * work around that for now... */
+       .level 2.0w
+#endif
+
+#include <asm/offset.h>
+#include <asm/page.h>
+
+#include <asm/asmregs.h>
+
+       sp      =       30
+       gp      =       27
+       ipsw    =       22
+
+#if __PAGE_OFFSET == 0xc0000000
+       .macro  tophys  gr
+       zdep    \gr, 31, 30, \gr
+       .endm
+       
+       .macro  tovirt  gr
+       depi    3,1,2,\gr
+       .endm
+#else
+#error unknown __PAGE_OFFSET
+#endif
+
+       .macro delay value
+       ldil    L%\value, 1
+       ldo     R%\value(1), 1
+       addib,UV,n -1,1,.
+       addib,NUV,n -1,1,.+8
+       nop
+       .endm
+
+       .macro  debug value
+       .endm
+
+#ifdef __LP64__
+# define LDIL_FIXUP(reg) depdi 0,31,32,reg
+#else
+# define LDIL_FIXUP(reg)
+#endif
+
+       /* load 32-bit 'value' into 'reg' compensating for the ldil
+        * sign-extension when running in wide mode.
+        * WARNING!! neither 'value' nor 'reg' can be expressions
+        * containing '.'!!!! */
+       .macro  load32 value, reg
+       ldil    L%\value, \reg
+       ldo     R%\value(\reg), \reg
+       LDIL_FIXUP(\reg)
+       .endm
+
+#ifdef __LP64__
+#define LDREG   ldd
+#define STREG   std
+#define RP_OFFSET      16
+#else
+#define LDREG   ldw
+#define STREG   stw
+#define RP_OFFSET      20
+#endif
+
+       .macro loadgp
+#ifdef __LP64__
+       ldil            L%__gp, %r27
+       ldo             R%__gp(%r27), %r27
+       LDIL_FIXUP(%r27)
+#else
+       ldil            L%$global$, %r27
+       ldo             R%$global$(%r27), %r27
+#endif
+       .endm
+
+#define SAVE_SP(r, where) mfsp r, %r1 ! STREG %r1, where
+#define REST_SP(r, where) LDREG where, %r1 ! mtsp %r1, r
+#define SAVE_CR(r, where) mfctl r, %r1 ! STREG %r1, where
+#define REST_CR(r, where) LDREG where, %r1 ! mtctl %r1, r
+
+       .macro  save_general    regs
+       STREG %r2, PT_GR2 (\regs)
+       STREG %r3, PT_GR3 (\regs)
+       STREG %r4, PT_GR4 (\regs)
+       STREG %r5, PT_GR5 (\regs)
+       STREG %r6, PT_GR6 (\regs)
+       STREG %r7, PT_GR7 (\regs)
+       STREG %r8, PT_GR8 (\regs)
+       STREG %r9, PT_GR9 (\regs)
+       STREG %r10, PT_GR10(\regs)
+       STREG %r11, PT_GR11(\regs)
+       STREG %r12, PT_GR12(\regs)
+       STREG %r13, PT_GR13(\regs)
+       STREG %r14, PT_GR14(\regs)
+       STREG %r15, PT_GR15(\regs)
+       STREG %r16, PT_GR16(\regs)
+       STREG %r17, PT_GR17(\regs)
+       STREG %r18, PT_GR18(\regs)
+       STREG %r19, PT_GR19(\regs)
+       STREG %r20, PT_GR20(\regs)
+       STREG %r21, PT_GR21(\regs)
+       STREG %r22, PT_GR22(\regs)
+       STREG %r23, PT_GR23(\regs)
+       STREG %r24, PT_GR24(\regs)
+       STREG %r25, PT_GR25(\regs)
+       /* r26 is clobbered by cr19 and assumed to be saved before hand */
+       STREG %r27, PT_GR27(\regs)
+       STREG %r28, PT_GR28(\regs)
+       /* r29 is already saved and points to PT_xxx struct */
+       /* r30 stack pointer saved in get_stack */
+       STREG %r31, PT_GR31(\regs)
+       .endm
+
+       .macro  rest_general    regs
+       LDREG PT_GR2 (\regs), %r2
+       LDREG PT_GR3 (\regs), %r3
+       LDREG PT_GR4 (\regs), %r4
+       LDREG PT_GR5 (\regs), %r5
+       LDREG PT_GR6 (\regs), %r6
+       LDREG PT_GR7 (\regs), %r7
+       LDREG PT_GR8 (\regs), %r8
+       LDREG PT_GR9 (\regs), %r9
+       LDREG PT_GR10(\regs), %r10
+       LDREG PT_GR11(\regs), %r11
+       LDREG PT_GR12(\regs), %r12
+       LDREG PT_GR13(\regs), %r13
+       LDREG PT_GR14(\regs), %r14
+       LDREG PT_GR15(\regs), %r15
+       LDREG PT_GR16(\regs), %r16
+       LDREG PT_GR17(\regs), %r17
+       LDREG PT_GR18(\regs), %r18
+       LDREG PT_GR19(\regs), %r19
+       LDREG PT_GR20(\regs), %r20
+       LDREG PT_GR21(\regs), %r21
+       LDREG PT_GR22(\regs), %r22
+       LDREG PT_GR23(\regs), %r23
+       LDREG PT_GR24(\regs), %r24
+       LDREG PT_GR25(\regs), %r25
+       LDREG PT_GR26(\regs), %r26
+       LDREG PT_GR27(\regs), %r27
+       LDREG PT_GR28(\regs), %r28
+       /* r30 stack pointer restored in rest_stack */
+       LDREG PT_GR31(\regs), %r31
+       .endm
+
+       .macro  save_fp         regs
+       fstd,ma  %fr0, 8(\regs)
+       fstd,ma  %fr1, 8(\regs)
+       fstd,ma  %fr2, 8(\regs)
+       fstd,ma  %fr3, 8(\regs)
+       fstd,ma  %fr4, 8(\regs)
+       fstd,ma  %fr5, 8(\regs)
+       fstd,ma  %fr6, 8(\regs)
+       fstd,ma  %fr7, 8(\regs)
+       fstd,ma  %fr8, 8(\regs)
+       fstd,ma  %fr9, 8(\regs)
+       fstd,ma %fr10, 8(\regs)
+       fstd,ma %fr11, 8(\regs)
+       fstd,ma %fr12, 8(\regs)
+       fstd,ma %fr13, 8(\regs)
+       fstd,ma %fr14, 8(\regs)
+       fstd,ma %fr15, 8(\regs)
+       fstd,ma %fr16, 8(\regs)
+       fstd,ma %fr17, 8(\regs)
+       fstd,ma %fr18, 8(\regs)
+       fstd,ma %fr19, 8(\regs)
+       fstd,ma %fr20, 8(\regs)
+       fstd,ma %fr21, 8(\regs)
+       fstd,ma %fr22, 8(\regs)
+       fstd,ma %fr23, 8(\regs)
+       fstd,ma %fr24, 8(\regs)
+       fstd,ma %fr25, 8(\regs)
+       fstd,ma %fr26, 8(\regs)
+       fstd,ma %fr27, 8(\regs)
+       fstd,ma %fr28, 8(\regs)
+       fstd,ma %fr29, 8(\regs)
+       fstd,ma %fr30, 8(\regs)
+       fstd    %fr31, 0(\regs)
+       .endm
+
+       .macro  rest_fp         regs
+       fldd    0(\regs),        %fr31
+       fldd,mb -8(\regs),       %fr30
+       fldd,mb -8(\regs),       %fr29
+       fldd,mb -8(\regs),       %fr28
+       fldd,mb -8(\regs),       %fr27
+       fldd,mb -8(\regs),       %fr26
+       fldd,mb -8(\regs),       %fr25
+       fldd,mb -8(\regs),       %fr24
+       fldd,mb -8(\regs),       %fr23
+       fldd,mb -8(\regs),       %fr22
+       fldd,mb -8(\regs),       %fr21
+       fldd,mb -8(\regs),       %fr20
+       fldd,mb -8(\regs),       %fr19
+       fldd,mb -8(\regs),       %fr18
+       fldd,mb -8(\regs),       %fr17
+       fldd,mb -8(\regs),       %fr16
+       fldd,mb -8(\regs),       %fr15
+       fldd,mb -8(\regs),       %fr14
+       fldd,mb -8(\regs),       %fr13
+       fldd,mb -8(\regs),       %fr12
+       fldd,mb -8(\regs),       %fr11
+       fldd,mb -8(\regs),       %fr10
+       fldd,mb -8(\regs),       %fr9
+       fldd,mb -8(\regs),       %fr8
+       fldd,mb -8(\regs),       %fr7
+       fldd,mb -8(\regs),       %fr6
+       fldd,mb -8(\regs),       %fr5
+       fldd,mb -8(\regs),       %fr4
+       fldd,mb -8(\regs),       %fr3
+       fldd,mb -8(\regs),       %fr2
+       fldd,mb -8(\regs),       %fr1
+       fldd,mb -8(\regs),       %fr0
+       .endm
+
+#ifdef __LP64__
+       .macro  callee_save
+       ldo     144(%r30), %r30
+       std       %r3,  -144(%r30)
+       std       %r4,  -136(%r30)
+       std       %r5,  -128(%r30)
+       std       %r6,  -120(%r30)
+       std       %r7,  -112(%r30)
+       std       %r8,  -104(%r30)
+       std       %r9,   -96(%r30)
+       std      %r10,   -88(%r30)
+       std      %r11,   -80(%r30)
+       std      %r12,   -72(%r30)
+       std      %r13,   -64(%r30)
+       std      %r14,   -56(%r30)
+       std      %r15,   -48(%r30)
+       std      %r16,   -40(%r30)
+       std      %r17,   -32(%r30)
+       std      %r18,   -24(%r30)
+       .endm
+
+       .macro  callee_rest
+       ldd      -24(%r30),   %r18
+       ldd      -32(%r30),   %r17
+       ldd      -40(%r30),   %r16
+       ldd      -48(%r30),   %r15
+       ldd      -56(%r30),   %r14
+       ldd      -64(%r30),   %r13
+       ldd      -72(%r30),   %r12
+       ldd      -80(%r30),   %r11
+       ldd      -88(%r30),   %r10
+       ldd      -96(%r30),    %r9
+       ldd     -104(%r30),    %r8
+       ldd     -112(%r30),    %r7
+       ldd     -120(%r30),    %r6
+       ldd     -128(%r30),    %r5
+       ldd     -136(%r30),    %r4
+       ldd     -144(%r30),    %r3
+       ldo     -144(%r30),   %r30
+       .endm
+
+#else /* __LP64__ */
+
+       .macro  callee_save
+       ldo     128(30), 30
+       stw      3,     -128(30)
+       stw      4,     -124(30)
+       stw      5,     -120(30)
+       stw      6,     -116(30)
+       stw      7,     -112(30)
+       stw      8,     -108(30)
+       stw      9,     -104(30)
+       stw      10,    -100(30)
+       stw      11,     -96(30)
+       stw      12,     -92(30)
+       stw      13,     -88(30)
+       stw      14,     -84(30)
+       stw      15,     -80(30)
+       stw      16,     -76(30)
+       stw      17,     -72(30)
+       stw      18,     -68(30)
+       .endm
+
+       .macro  callee_rest
+       ldw      -68(30),   18
+       ldw      -72(30),   17
+       ldw      -76(30),   16
+       ldw      -80(30),   15
+       ldw      -84(30),   14
+       ldw      -88(30),   13
+       ldw      -92(30),   12
+       ldw      -96(30),   11
+       ldw     -100(30),   10
+       ldw     -104(30),    9
+       ldw     -108(30),    8
+       ldw     -112(30),    7
+       ldw     -116(30),    6
+       ldw     -120(30),    5
+       ldw     -124(30),    4
+       ldw     -128(30),    3
+       ldo     -128(30),   30
+       .endm
+#endif /* __LP64__ */
+
+       .macro  save_specials   regs
+
+       SAVE_SP  (%sr0, PT_SR0 (\regs))
+       SAVE_SP  (%sr1, PT_SR1 (\regs))
+       SAVE_SP  (%sr2, PT_SR2 (\regs))
+       SAVE_SP  (%sr3, PT_SR3 (\regs))
+       SAVE_SP  (%sr4, PT_SR4 (\regs))
+       SAVE_SP  (%sr5, PT_SR5 (\regs))
+       SAVE_SP  (%sr6, PT_SR6 (\regs))
+       SAVE_SP  (%sr7, PT_SR7 (\regs))
+
+       SAVE_CR  (%cr17, PT_IASQ0(\regs))
+       mtctl    %r0,   %cr17
+       SAVE_CR  (%cr17, PT_IASQ1(\regs))
+
+       SAVE_CR  (%cr18, PT_IAOQ0(\regs))
+       mtctl    %r0,   %cr18
+       SAVE_CR  (%cr18, PT_IAOQ1(\regs))
+
+       SAVE_CR  (%cr11, PT_SAR  (\regs))
+       SAVE_CR  (%cr22, PT_PSW  (\regs))
+       SAVE_CR  (%cr19, PT_IIR  (\regs))
+       SAVE_CR  (%cr28, PT_GR1  (\regs))
+       SAVE_CR  (%cr31, PT_GR29 (\regs))
+
+       STREG   %r26,   PT_GR26 (\regs)
+       mfctl   %cr29,  %r26
+       .endm
+
+       .macro  rest_specials   regs
+
+       REST_SP  (%sr0, PT_SR0 (\regs))
+       REST_SP  (%sr1, PT_SR1 (\regs))
+       REST_SP  (%sr2, PT_SR2 (\regs))
+       REST_SP  (%sr3, PT_SR3 (\regs))
+       REST_SP  (%sr4, PT_SR4 (\regs))
+       REST_SP  (%sr5, PT_SR5 (\regs))
+       REST_SP  (%sr6, PT_SR6 (\regs))
+       REST_SP  (%sr7, PT_SR7 (\regs))
+
+       REST_CR (%cr17, PT_IASQ0(\regs))
+       REST_CR (%cr17, PT_IASQ1(\regs))
+
+       REST_CR (%cr18, PT_IAOQ0(\regs))
+       REST_CR (%cr18, PT_IAOQ1(\regs))
+
+       REST_CR (%cr11, PT_SAR  (\regs))
+
+       REST_CR (%cr22, PT_PSW  (\regs))
+       .endm
+
+#endif
diff --git a/include/asm-parisc/atomic.h b/include/asm-parisc/atomic.h
new file mode 100644 (file)
index 0000000..82304cc
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _ASM_PARISC_ATOMIC_H_
+#define _ASM_PARISC_ATOMIC_H_
+
+#include <asm/system.h>
+
+/* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>.  */
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ *
+ * And probably incredibly slow on parisc.  OTOH, we don't
+ * have to write any serious assembly.   prumpf
+ */
+
+#ifdef CONFIG_SMP
+/* we have an array of spinlocks for our atomic_ts, and a hash function
+ * to get the right index */
+#  define ATOMIC_HASH_SIZE 1
+#  define ATOMIC_HASH(a) (&__atomic_hash[0])
+
+extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE];
+/* copied from <asm/spinlock.h> and modified */
+#  define SPIN_LOCK(x) \
+       do { while(__ldcw(&(x)->lock) == 0); } while(0)
+       
+#  define SPIN_UNLOCK(x) \
+       do { (x)->lock = 1; } while(0)
+#else
+#  define ATOMIC_HASH_SIZE 1
+#  define ATOMIC_HASH(a)       (0)
+
+/* copied from <linux/spinlock.h> and modified */
+#  define SPIN_LOCK(x) (void)(x)
+       
+#  define SPIN_UNLOCK(x) do { } while(0)
+#endif
+
+/* copied from <linux/spinlock.h> and modified */
+#define SPIN_LOCK_IRQSAVE(lock, flags)         do { local_irq_save(flags);       SPIN_LOCK(lock); } while (0)
+#define SPIN_UNLOCK_IRQRESTORE(lock, flags)    do { SPIN_UNLOCK(lock);  local_irq_restore(flags); } while (0)
+
+/* Note that we need not lock read accesses - aligned word writes/reads
+ * are atomic, so a reader never sees unconsistent values.
+ *
+ * Cache-line alignment would conflict with, for example, linux/module.h */
+
+typedef struct {
+       volatile int counter;
+} atomic_t;
+
+/* It's possible to reduce all atomic operations to either
+ * __atomic_add_return, __atomic_set and __atomic_ret (the latter
+ * is there only for consistency). */
+
+static __inline__ int __atomic_add_return(int i, atomic_t *v)
+{
+       int ret;
+       unsigned long flags;
+       SPIN_LOCK_IRQSAVE(ATOMIC_HASH(v), flags);
+
+       ret = (v->counter += i);
+
+       SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
+       return ret;
+}
+
+static __inline__ void __atomic_set(atomic_t *v, int i) 
+{
+       unsigned long flags;
+       SPIN_LOCK_IRQSAVE(ATOMIC_HASH(v), flags);
+
+       v->counter = i;
+
+       SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
+}
+       
+static __inline__ int __atomic_read(atomic_t *v)
+{
+       return v->counter;
+}
+
+/* exported interface */
+
+#define atomic_add(i,v)                ((void)(__atomic_add_return( (i),(v))))
+#define atomic_sub(i,v)                ((void)(__atomic_add_return(-(i),(v))))
+#define atomic_inc(v)          ((void)(__atomic_add_return(   1,(v))))
+#define atomic_dec(v)          ((void)(__atomic_add_return(  -1,(v))))
+
+#define atomic_add_return(i,v) (__atomic_add_return( (i),(v)))
+#define atomic_sub_return(i,v) (__atomic_add_return(-(i),(v)))
+#define atomic_inc_return(v)   (__atomic_add_return(   1,(v)))
+#define atomic_dec_return(v)   (__atomic_add_return(  -1,(v)))
+
+#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
+
+#define atomic_set(v,i)                (__atomic_set((v),i))
+#define atomic_read(v)         (__atomic_read(v))
+
+#define ATOMIC_INIT(i) { (i) }
+
+#endif
diff --git a/include/asm-parisc/bitops.h b/include/asm-parisc/bitops.h
new file mode 100644 (file)
index 0000000..f3f8e0e
--- /dev/null
@@ -0,0 +1,247 @@
+#ifndef _PARISC_BITOPS_H
+#define _PARISC_BITOPS_H
+
+#include <linux/spinlock.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+
+#ifdef __LP64__
+#   define SHIFT_PER_LONG 6
+#ifndef BITS_PER_LONG
+#   define BITS_PER_LONG 64
+#endif
+#else
+#   define SHIFT_PER_LONG 5
+#ifndef BITS_PER_LONG
+#   define BITS_PER_LONG 32
+#endif
+#endif
+
+#define CHOP_SHIFTCOUNT(x) ((x) & (BITS_PER_LONG - 1))
+
+static __inline__ int test_and_set_bit(int nr, void * address)
+{
+       unsigned long mask;
+       unsigned long *addr = (unsigned long *) address;
+       int oldbit;
+       unsigned long flags;
+
+       addr += (nr >> SHIFT_PER_LONG);
+       SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
+
+       mask = 1L << CHOP_SHIFTCOUNT(nr);
+       oldbit = (*addr & mask) ? 1 : 0;
+       *addr |= mask;
+
+       SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
+
+       return oldbit;
+}
+
+static __inline__ int test_and_clear_bit(int nr, void * address)
+{
+       unsigned long mask;
+       unsigned long *addr = (unsigned long *) address;
+       int oldbit;
+       unsigned long flags;
+
+       addr += (nr >> SHIFT_PER_LONG);
+       SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
+
+       mask = 1L << CHOP_SHIFTCOUNT(nr);
+       oldbit = (*addr & mask) ? 1 : 0;
+       *addr &= ~mask;
+
+       SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
+
+       return oldbit;
+}
+
+static __inline__ int test_and_change_bit(int nr, void * address)
+{
+       unsigned long mask;
+       unsigned long *addr = (unsigned long *) address;
+       int oldbit;
+       unsigned long flags;
+
+       addr += (nr >> SHIFT_PER_LONG);
+       SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
+
+       mask = 1L << CHOP_SHIFTCOUNT(nr);
+       oldbit = (*addr & mask) ? 1 : 0;
+       *addr ^= mask;
+
+       SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
+
+       return oldbit;
+}
+
+/* again, the read-only case doesn't have to do any locking */
+
+static __inline__ int test_bit(int nr, const volatile void *address)
+{
+       unsigned long mask;
+       unsigned long *addr = (unsigned long *) address;
+       
+       addr += (nr >> SHIFT_PER_LONG);
+       mask = 1L << CHOP_SHIFTCOUNT(nr);
+       
+       return !!(*addr & mask);
+}
+
+/* sparc does this, other arch's don't -- what's the right answer? XXX */
+#define smp_mb__before_clear_bit()     do { } while(0)
+#define smp_mb__after_clear_bit()      do { } while(0)
+#define set_bit(nr,addr)       ((void)test_and_set_bit(nr,addr))
+#define clear_bit(nr,addr)     ((void)test_and_clear_bit(nr,addr))
+#define change_bit(nr,addr)    ((void)test_and_change_bit(nr,addr))
+
+/* XXX We'd need some binary search here */
+
+extern __inline__ unsigned long ffz(unsigned long word)
+{
+       unsigned long result;
+
+       result = 0;
+       while(word & 1) {
+               result++;
+               word >>= 1;
+       }
+
+       return result;
+}
+
+#ifdef __KERNEL__
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+#endif /* __KERNEL__ */
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+#define find_first_zero_bit(addr, size) \
+       find_next_zero_bit((addr), (size), 0)
+
+static __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset)
+{
+       unsigned long * p = ((unsigned long *) addr) + (offset >> SHIFT_PER_LONG);
+       unsigned long result = offset & ~(BITS_PER_LONG-1);
+       unsigned long tmp;
+
+       if (offset >= size)
+               return size;
+       size -= result;
+       offset &= (BITS_PER_LONG-1);
+       if (offset) {
+               tmp = *(p++);
+               tmp |= ~0UL >> (BITS_PER_LONG-offset);
+               if (size < BITS_PER_LONG)
+                       goto found_first;
+               if (~tmp)
+                       goto found_middle;
+               size -= BITS_PER_LONG;
+               result += BITS_PER_LONG;
+       }
+       while (size & ~(BITS_PER_LONG -1)) {
+               if (~(tmp = *(p++)))
+                       goto found_middle;
+               result += BITS_PER_LONG;
+               size -= BITS_PER_LONG;
+       }
+       if (!size)
+               return result;
+       tmp = *p;
+found_first:
+       tmp |= ~0UL << size;
+found_middle:
+       return result + ffz(tmp);
+}
+
+#define _EXT2_HAVE_ASM_BITOPS_
+
+#ifdef __KERNEL__
+/*
+ * test_and_{set,clear}_bit guarantee atomicity without
+ * disabling interrupts.
+ */
+#define ext2_set_bit(nr, addr)         test_and_set_bit((nr) ^ 0x18, addr)
+#define ext2_clear_bit(nr, addr)       test_and_clear_bit((nr) ^ 0x18, addr)
+
+#endif /* __KERNEL__ */
+
+static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
+{
+       __const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
+
+       return (ADDR[nr >> 3] >> (nr & 7)) & 1;
+}
+
+/*
+ * This implementation of ext2_find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h and modified for a big-endian machine.
+ */
+
+#define ext2_find_first_zero_bit(addr, size) \
+        ext2_find_next_zero_bit((addr), (size), 0)
+
+extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr,
+       unsigned long size, unsigned long offset)
+{
+       unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
+       unsigned int result = offset & ~31UL;
+       unsigned int tmp;
+
+       if (offset >= size)
+               return size;
+       size -= result;
+       offset &= 31UL;
+       if (offset) {
+               tmp = cpu_to_le32p(p++);
+               tmp |= ~0UL >> (32-offset);
+               if (size < 32)
+                       goto found_first;
+               if (tmp != ~0U)
+                       goto found_middle;
+               size -= 32;
+               result += 32;
+       }
+       while (size >= 32) {
+               if ((tmp = cpu_to_le32p(p++)) != ~0U)
+                       goto found_middle;
+               result += 32;
+               size -= 32;
+       }
+       if (!size)
+               return result;
+       tmp = cpu_to_le32p(p);
+found_first:
+       tmp |= ~0U << size;
+found_middle:
+       return result + ffz(tmp);
+}
+
+/* Bitmap functions for the minix filesystem.  */
+#define minix_set_bit(nr,addr) ext2_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) ext2_test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
+
+#endif /* _PARISC_BITOPS_H */
diff --git a/include/asm-parisc/bootdata.h b/include/asm-parisc/bootdata.h
new file mode 100644 (file)
index 0000000..e4de299
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _PARISC_BOOTDATA_H
+#define _PARISC_BOOTDATA_H
+
+/* structure given from bootloader... */
+typedef struct {
+    unsigned   data_valid_signature,
+               initrd_start,
+               initrd_end;
+    char       commandline[1024];
+} bootdata_t;
+
+#define BOOTDATA_DATA_VALID_SIGNATURE 0xC0400000
+
+#define BOOTDATA_PTR ((bootdata_t*) 0xC0400000)
+
+#endif 
diff --git a/include/asm-parisc/bugs.h b/include/asm-parisc/bugs.h
new file mode 100644 (file)
index 0000000..6eda75d
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  include/asm-parisc/bugs.h
+ *
+ *  Copyright (C) 1999 Mike Shaver
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ *     void check_bugs(void);
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+
+static inline void check_bugs(void)
+{
+//     identify_cpu(&boot_cpu_data);
+}
diff --git a/include/asm-parisc/byteorder.h b/include/asm-parisc/byteorder.h
new file mode 100644 (file)
index 0000000..7b3a2ab
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef _PARISC_BYTEORDER_H
+#define _PARISC_BYTEORDER_H
+
+#include <asm/types.h>
+
+#ifdef __GNUC__
+
+static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+{
+       unsigned int temp;
+       __asm__("shd %0, %0, 16, %1\n\t"        /* shift abcdabcd -> cdab */
+               "dep %1, 15, 8, %1\n\t"         /* deposit cdab -> cbab */
+               "shd %0, %1, 8, %0"             /* shift abcdcbab -> dcba */
+               : "=r" (x), "=&r" (temp)
+               : "0" (x));
+       return x;
+}
+
+
+#if BITS_PER_LONG > 32
+/*
+** From "PA-RISC 2.0 Architecture", HP Professional Books.
+** See Appendix I page 8 , "Endian Byte Swapping".
+**
+** Pretty cool algorithm: (* == zero'd bits)
+**      PERMH   01234567 -> 67452301 into %0
+**      HSHL    67452301 -> 7*5*3*1* into %1
+**      HSHR    67452301 -> *6*4*2*0 into %0
+**      OR      %0 | %1  -> 76543210 into %0 (all done!)
+*/
+static __inline__ __const__ __u64 ___arch__swab64(__u64 x) {
+       __u64 temp;
+       __asm__("permh 3210, %0, %0\n\t"
+               "hshl %0, 8, %1\n\t"
+               "hshr u, %0, 8, %0\n\t"
+               "or %1, %0, %0"
+               : "=r" (x), "=&r" (temp)
+               : "0" (x));
+       return x;
+}
+#define __arch__swab64(x) ___arch__swab64(x)
+#else
+static __inline__ __const__ __u64 ___arch__swab64(__u64 x)
+{
+       __u32 t1 = (__u32) x;
+       __u32 t2 = (__u32) ((x) >> 32);
+       ___arch__swab32(t1);
+       ___arch__swab32(t2);
+       return (((__u64) t1 << 32) + ((__u64) t2));
+}
+#endif
+
+
+static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+{
+       __asm__("dep %0, 15, 8, %0\n\t"         /* deposit 00ab -> 0bab */
+               "shd %r0, %0, 8, %0"            /* shift 000000ab -> 00ba */
+               : "=r" (x)
+               : "0" (x));
+       return x;
+}
+
+#define __arch__swab32(x) ___arch__swab32(x)
+#define __arch__swab16(x) ___arch__swab16(x)
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#endif /* __GNUC__ */
+
+#include <linux/byteorder/big_endian.h>
+
+#endif /* _PARISC_BYTEORDER_H */
diff --git a/include/asm-parisc/cache.h b/include/asm-parisc/cache.h
new file mode 100644 (file)
index 0000000..d226210
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * include/asm-parisc/cache.h
+ */
+
+#ifndef __ARCH_PARISC_CACHE_H
+#define __ARCH_PARISC_CACHE_H
+
+#include <linux/config.h>
+
+/*
+** XXX FIXME : L1_CACHE_BYTES (cacheline size) should be a boot time thing.
+** 
+** 32-bit on PA2.0 is not covered well by the #ifdef __LP64__ below.
+** PA2.0 processors have 64-byte cachelines.
+**
+** The issue is mostly cacheline ping-ponging on SMP boxes.
+** To avoid this, code should define stuff to be per CPU on cacheline
+** aligned boundaries. This can make a 2x or more difference in perf
+** depending on how badly the thrashing is.
+**
+** We don't need to worry about I/O since all PA2.0 boxes (except T600)
+** are I/O coherent. That means flushing less than you needed to generally
+** doesn't matter - the I/O MMU will read/modify/write the cacheline.
+**
+** (Digression: it is possible to program I/O MMU's to not first read
+** a cacheline for inbound data - ie just grab ownership and start writing.
+** While it improves I/O throughput, you gotta know the device driver
+** is well behaved and can deal with the issues.)
+*/
+#if defined(__LP64__)
+#define L1_CACHE_BYTES 64
+#else
+#define L1_CACHE_BYTES 32
+#endif
+
+#define L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+
+#define SMP_CACHE_BYTES L1_CACHE_BYTES
+
+#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
+
+extern void init_cache(void);          /* initializes cache-flushing */
+extern void flush_data_cache(void);    /* flushes data-cache only */
+extern void flush_instruction_cache(void);/* flushes code-cache only */
+extern void flush_all_caches(void);    /* flushes code and data-cache */
+
+extern int get_cache_info(char *);
+
+extern struct pdc_cache_info cache_info;
+
+#define fdce(addr) asm volatile("fdce 0(%0)" : : "r" (addr))
+#define fice(addr) asm volatile("fice 0(%%sr1,%0)" : : "r" (addr))
+
+#define pdtlbe(addr) asm volatile("pdtlbe 0(%%sr1,%0)" : : "r" (addr))
+#define pdtlb_kernel(addr)  asm volatile("pdtlb 0(%0)" : : "r" (addr));
+#define pitlbe(addr) asm volatile("pitlbe 0(%%sr1,%0)" : : "r" (addr))
+
+#define kernel_fdc(addr) asm volatile("fdc 0(%%sr0, %0)" : : "r" (addr))
+
+#endif
diff --git a/include/asm-parisc/checksum.h b/include/asm-parisc/checksum.h
new file mode 100644 (file)
index 0000000..9088f97
--- /dev/null
@@ -0,0 +1,174 @@
+#ifndef _PARISC_CHECKSUM_H
+#define _PARISC_CHECKSUM_H
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern unsigned int csum_partial(const unsigned char *, int, unsigned int);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+extern unsigned int csum_partial_copy(const char *, char *, int, unsigned int);
+
+/*
+ * the same as csum_partial, but copies from user space
+ *
+ * this is obsolete and will go away.
+ */
+#define csum_partial_copy_fromuser csum_partial_copy
+
+/*
+ * this is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros the rest of the buffer.
+ */
+unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp);
+
+/*
+ *     Note: when you get a NULL pointer exception here this means someone
+ *     passed in an incorrect kernel address to one of these functions. 
+ *     
+ *     If you use these functions directly please don't forget the 
+ *     verify_area().
+ */
+extern __inline__
+unsigned int csum_partial_copy_nocheck (const char *src, char *dst,
+                                       int len, int sum)
+{
+       return csum_partial_copy (src, dst, len, sum);
+}
+
+/*
+ *     Optimized for IP headers, which always checksum on 4 octet boundaries.
+ *
+ *     Written by Randolph Chung <tausq@debian.org>
+ */
+static inline unsigned short ip_fast_csum(unsigned char * iph,
+                                         unsigned int ihl) {
+       unsigned int sum;
+
+
+       __asm__ __volatile__ ("
+       ldws,ma         4(%1), %0
+       addi            -4, %2, %2
+       comib,>=        0, %2, 2f
+       
+       ldws,ma         4(%1), %%r19
+       add             %0, %%r19, %0
+       ldws,ma         4(%1), %%r19
+       addc            %0, %%r19, %0
+       ldws,ma         4(%1), %%r19
+       addc            %0, %%r19, %0
+1:     ldws,ma         4(%1), %%r19
+       addib,<>        -1, %2, 1b
+       addc            %0, %%r19, %0
+       addc            %0, %%r0, %0
+
+       zdepi           -1, 31, 16, %%r19
+       and             %0, %%r19, %%r20
+       extru           %0, 15, 16, %%r21
+       add             %%r20, %%r21, %0
+       and             %0, %%r19, %%r20
+       extru           %0, 15, 16, %%r21
+       add             %%r20, %%r21, %0
+       subi            -1, %0, %0
+2:
+       "
+       : "=r" (sum), "=r" (iph), "=r" (ihl)
+       : "1" (iph), "2" (ihl)
+       : "r19", "r20", "r21" );
+
+       return(sum);
+}
+
+/*
+ *     Fold a partial checksum
+ */
+static inline unsigned int csum_fold(unsigned int sum)
+{
+       sum = (sum & 0xffff) + (sum >> 16);
+       sum = (sum & 0xffff) + (sum >> 16);
+       return ~sum;
+}
+static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
+                                              unsigned long daddr,
+                                              unsigned short len,
+                                              unsigned short proto,
+                                              unsigned int sum) 
+{
+       __asm__("
+               add  %1, %0, %0
+               addc %2, %0, %0
+               addc %3, %0, %0
+               addc %%r0, %0, %0 "
+               : "=r" (sum)
+               : "r" (daddr), "r"(saddr), "r"((proto<<16)+len), "0"(sum));
+    return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+                                                  unsigned long daddr,
+                                                  unsigned short len,
+                                                  unsigned short proto,
+                                                  unsigned int sum) 
+{
+       return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+static inline unsigned short ip_compute_csum(unsigned char * buf, int len) {
+        return csum_fold (csum_partial(buf, len, 0));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+                                                    struct in6_addr *daddr,
+                                                    __u16 len,
+                                                    unsigned short proto,
+                                                    unsigned int sum) 
+{
+       BUG();
+       return csum_fold(sum);
+}
+
+/* 
+ *     Copy and checksum to user
+ */
+#define HAVE_CSUM_COPY_USER
+static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst,
+                                   int len, int sum, int *err_ptr)
+{
+       /* code stolen from include/asm-mips64 */
+       sum = csum_partial(src, len, sum);
+        
+       if (copy_to_user(dst, src, len)) {
+               *err_ptr = -EFAULT;
+               return -1;
+       }
+
+       return sum;
+}
+
+#endif
+
diff --git a/include/asm-parisc/current.h b/include/asm-parisc/current.h
new file mode 100644 (file)
index 0000000..f3452d3
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _PARISC_CURRENT_H
+#define _PARISC_CURRENT_H
+
+#include <asm/processor.h>
+
+struct task_struct;
+
+static inline struct task_struct * get_current(void)
+{
+       struct task_struct *current;
+
+       asm("copy 30,%0" : "=r" (current));
+       
+       return (struct task_struct *)((long) current & ~(THREAD_SIZE-1));
+}
+#define current get_current()
+
+#endif /* !(_PARISC_CURRENT_H) */
diff --git a/include/asm-parisc/delay.h b/include/asm-parisc/delay.h
new file mode 100644 (file)
index 0000000..705c4a7
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _PARISC_DELAY_H
+#define _PARISC_DELAY_H
+
+#include <asm/system.h>    /* for mfctl() */
+#include <asm/processor.h> /* for boot_cpu_data */
+
+
+/*
+ * Copyright (C) 1993 Linus Torvalds
+ *
+ * Delay routines
+ */
+
+extern unsigned long loops_per_sec;
+
+static __inline__ void __delay(unsigned long loops) {
+       asm volatile(
+       "       .balignl        64,0x34000034
+               addib,UV -1,%0,.
+               nop"
+               : "=r" (loops) : "0" (loops));
+}
+
+static __inline__ void __cr16_delay(unsigned long clocks) {
+       unsigned long start;
+
+       /*
+        * Note: Due to unsigned math, cr16 rollovers shouldn't be
+        * a problem here. However, on 32 bit, we need to make sure
+        * we don't pass in too big a value. The current default
+        * value of MAX_UDELAY_MS should help prevent this.
+        */
+
+       start = mfctl(16);
+       while ((mfctl(16) - start) < clocks)
+           ;
+}
+
+static __inline__ void __udelay(unsigned long usecs) {
+       __cr16_delay(usecs * ((unsigned long)boot_cpu_data.cpu_hz / 1000000UL));
+}
+
+#define udelay(n) __udelay(n)
+
+#endif /* defined(_PARISC_DELAY_H) */
diff --git a/include/asm-parisc/div64.h b/include/asm-parisc/div64.h
new file mode 100644 (file)
index 0000000..e86e35e
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __ASM_PARISC_DIV64
+#define __ASM_PARISC_DIV64
+
+#ifdef __LP64__
+
+/*
+ * Copyright (C) 1999 Hewlett-Packard Co
+ * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * vsprintf uses this to divide a 64-bit integer N by a small integer BASE.
+ * This is incredibly hard on IA-64 and HPPA
+ */
+
+#define do_div(n,base)                                         \
+({                                                             \
+       int _res;                                               \
+       _res = ((unsigned long) (n)) % (unsigned) (base);       \
+       (n) = ((unsigned long) (n)) / (unsigned) (base);        \
+       _res;                                                   \
+})
+
+#else
+/*
+ * unsigned long long division.  Yuck Yuck!  What is Linux coming to?
+ * This is 100% disgusting
+ */
+#define do_div(n,base)                                                 \
+({                                                                     \
+       unsigned long __low, __low2, __high, __rem;                     \
+       __low  = (n) & 0xffffffff;                                      \
+       __high = (n) >> 32;                                             \
+       if (__high) {                                                   \
+               __rem   = __high % (unsigned long)base;                 \
+               __high  = __high / (unsigned long)base;                 \
+               __low2  = __low >> 16;                                  \
+               __low2 += __rem << 16;                                  \
+               __rem   = __low2 % (unsigned long)base;                 \
+               __low2  = __low2 / (unsigned long)base;                 \
+               __low   = __low & 0xffff;                               \
+               __low  += __rem << 16;                                  \
+               __rem   = __low  % (unsigned long)base;                 \
+               __low   = __low  / (unsigned long)base;                 \
+               n = __low  + ((long long)__low2 << 16) +                \
+                       ((long long) __high << 32);                     \
+       } else {                                                        \
+               __rem = __low % (unsigned long)base;                    \
+               n = (__low / (unsigned long)base);                      \
+       }                                                               \
+       __rem;                                                          \
+})
+#endif
+
+#endif
+
diff --git a/include/asm-parisc/elf.h b/include/asm-parisc/elf.h
new file mode 100644 (file)
index 0000000..c478db0
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef __ASMPARISC_ELF_H
+#define __ASMPARISC_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+
+#define EM_PARISC 15
+
+#define ELF_NGREG 32
+#define ELF_NFPREG 32
+
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+#define ELF_CORE_COPY_REGS(gregs, regs) \
+       memcpy(gregs, regs, \
+              sizeof(struct pt_regs) < sizeof(elf_gregset_t)? \
+              sizeof(struct pt_regs): sizeof(elf_gregset_t));
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ *
+ * Note that this header file is used by default in fs/binfmt_elf.c. So
+ * the following macros are for the default case. However, for the 64
+ * bit kernel we also support 32 bit parisc binaries. To do that
+ * arch/parisc64/kernel/binfmt_elf32.c defines its own set of these
+ * macros, and then if includes fs/binfmt_elf.c to provide an alternate
+ * elf binary handler for 32 bit binaries (on the 64 bit kernel).
+ */
+
+#ifdef __LP64__
+#define ELF_CLASS       ELFCLASS64
+#else
+#define ELF_CLASS      ELFCLASS32
+#endif
+
+#define elf_check_arch(x) ((x)->e_machine == EM_PARISC && (x)->e_ident[EI_CLASS] == ELF_CLASS)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_DATA       ELFDATA2MSB
+#define ELF_ARCH       EM_PARISC
+
+/* %r23 is set by ld.so to a pointer to a function which might be 
+   registered using atexit.  This provides a mean for the dynamic
+   linker to call DT_FINI functions for shared libraries that have
+   been loaded before the code runs.
+
+   So that we can use the same startup file with static executables,
+   we start programs with a value of 0 to indicate that there is no
+   such function.  */
+#define ELF_PLAT_INIT(_r)       _r->gr[23] = 0
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE      4096
+
+/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+   use of this is to invoke "./ld.so someprog" to test out a new version of
+   the loader.  We need to make sure that it is out of the way of the program
+   that it will "exec", and that there is sufficient room for the brk.
+
+   (2 * TASK_SIZE / 3) turns into something undefined when run through a
+   32 bit preprocessor and in some cases results in the kernel trying to map
+   ld.so to the kernel virtual base. Use a sane value instead. /Jes 
+  */
+
+#define ELF_ET_DYN_BASE         (TASK_UNMAPPED_BASE + 0x01000000)
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this CPU supports.  This could be done in user space,
+   but it's not easy, and we've already done it here.  */
+
+#define ELF_HWCAP      0
+/* (boot_cpu_data.x86_capability) */
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo.
+
+   For the moment, we have only optimizations for the Intel generations,
+   but that could change... */
+
+#define ELF_PLATFORM  ("PARISC\0" /*+((boot_cpu_data.x86-3)*5) */)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex, ibcs2) \
+       current->personality = PER_LINUX
+#endif
+
+#endif
diff --git a/include/asm-parisc/errno.h b/include/asm-parisc/errno.h
new file mode 100644 (file)
index 0000000..b7348c5
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef _PARISC_ERRNO_H
+#define _PARISC_ERRNO_H
+
+#define        EPERM            1      /* Operation not permitted */
+#define        ENOENT           2      /* No such file or directory */
+#define        ESRCH            3      /* No such process */
+#define        EINTR            4      /* Interrupted system call */
+#define        EIO              5      /* I/O error */
+#define        ENXIO            6      /* No such device or address */
+#define        E2BIG            7      /* Arg list too long */
+#define        ENOEXEC          8      /* Exec format error */
+#define        EBADF            9      /* Bad file number */
+#define        ECHILD          10      /* No child processes */
+#define        EAGAIN          11      /* Try again */
+#define        ENOMEM          12      /* Out of memory */
+#define        EACCES          13      /* Permission denied */
+#define        EFAULT          14      /* Bad address */
+#define        ENOTBLK         15      /* Block device required */
+#define        EBUSY           16      /* Device or resource busy */
+#define        EEXIST          17      /* File exists */
+#define        EXDEV           18      /* Cross-device link */
+#define        ENODEV          19      /* No such device */
+#define        ENOTDIR         20      /* Not a directory */
+#define        EISDIR          21      /* Is a directory */
+#define        EINVAL          22      /* Invalid argument */
+#define        ENFILE          23      /* File table overflow */
+#define        EMFILE          24      /* Too many open files */
+#define        ENOTTY          25      /* Not a typewriter */
+#define        ETXTBSY         26      /* Text file busy */
+#define        EFBIG           27      /* File too large */
+#define        ENOSPC          28      /* No space left on device */
+#define        ESPIPE          29      /* Illegal seek */
+#define        EROFS           30      /* Read-only file system */
+#define        EMLINK          31      /* Too many links */
+#define        EPIPE           32      /* Broken pipe */
+#define        EDOM            33      /* Math argument out of domain of func */
+#define        ERANGE          34      /* Math result not representable */
+#define        ENOMSG          35      /* No message of desired type */
+#define        EIDRM           36      /* Identifier removed */
+#define        ECHRNG          37      /* Channel number out of range */
+#define        EL2NSYNC        38      /* Level 2 not synchronized */
+#define        EL3HLT          39      /* Level 3 halted */
+#define        EL3RST          40      /* Level 3 reset */
+#define        ELNRNG          41      /* Link number out of range */
+#define        EUNATCH         42      /* Protocol driver not attached */
+#define        ENOCSI          43      /* No CSI structure available */
+#define        EL2HLT          44      /* Level 2 halted */
+#define        EDEADLK         45      /* Resource deadlock would occur */
+#define        EDEADLOCK       EDEADLK
+#define        ENOLCK          46      /* No record locks available */
+#define        EILSEQ          47      /* Illegal byte sequence */
+
+#define        ENONET          50      /* Machine is not on the network */
+#define        ENODATA         51      /* No data available */
+#define        ETIME           52      /* Timer expired */
+#define        ENOSR           53      /* Out of streams resources */
+#define        ENOSTR          54      /* Device not a stream */
+#define        ENOPKG          55      /* Package not installed */
+
+#define        ENOLINK         57      /* Link has been severed */
+#define        EADV            58      /* Advertise error */
+#define        ESRMNT          59      /* Srmount error */
+#define        ECOMM           60      /* Communication error on send */
+#define        EPROTO          61      /* Protocol error */
+
+#define        EMULTIHOP       64      /* Multihop attempted */
+
+#define        EDOTDOT         66      /* RFS specific error */
+#define        EBADMSG         67      /* Not a data message */
+#define        EUSERS          68      /* Too many users */
+#define        EDQUOT          69      /* Quota exceeded */
+#define        ESTALE          70      /* Stale NFS file handle */
+#define        EREMOTE         71      /* Object is remote */
+#define        EOVERFLOW       72      /* Value too large for defined data type */
+
+/* these errnos are defined by Linux but not HPUX. */
+
+#define        EBADE           160     /* Invalid exchange */
+#define        EBADR           161     /* Invalid request descriptor */
+#define        EXFULL          162     /* Exchange full */
+#define        ENOANO          163     /* No anode */
+#define        EBADRQC         164     /* Invalid request code */
+#define        EBADSLT         165     /* Invalid slot */
+#define        EBFONT          166     /* Bad font file format */
+#define        ENOTUNIQ        167     /* Name not unique on network */
+#define        EBADFD          168     /* File descriptor in bad state */
+#define        EREMCHG         169     /* Remote address changed */
+#define        ELIBACC         170     /* Can not access a needed shared library */
+#define        ELIBBAD         171     /* Accessing a corrupted shared library */
+#define        ELIBSCN         172     /* .lib section in a.out corrupted */
+#define        ELIBMAX         173     /* Attempting to link in too many shared libraries */
+#define        ELIBEXEC        174     /* Cannot exec a shared library directly */
+#define        ERESTART        175     /* Interrupted system call should be restarted */
+#define        ESTRPIPE        176     /* Streams pipe error */
+#define        EUCLEAN         177     /* Structure needs cleaning */
+#define        ENOTNAM         178     /* Not a XENIX named type file */
+#define        ENAVAIL         179     /* No XENIX semaphores available */
+#define        EISNAM          180     /* Is a named type file */
+#define        EREMOTEIO       181     /* Remote I/O error */
+#define        ENOMEDIUM       182     /* No medium found */
+#define        EMEDIUMTYPE     183     /* Wrong medium type */
+
+/* We now return you to your regularly scheduled HPUX. */
+
+#define ENOSYM         215     /* symbol does not exist in executable */
+#define        ENOTSOCK        216     /* Socket operation on non-socket */
+#define        EDESTADDRREQ    217     /* Destination address required */
+#define        EMSGSIZE        218     /* Message too long */
+#define        EPROTOTYPE      219     /* Protocol wrong type for socket */
+#define        ENOPROTOOPT     220     /* Protocol not available */
+#define        EPROTONOSUPPORT 221     /* Protocol not supported */
+#define        ESOCKTNOSUPPORT 222     /* Socket type not supported */
+#define        EOPNOTSUPP      223     /* Operation not supported on transport endpoint */
+#define        EPFNOSUPPORT    224     /* Protocol family not supported */
+#define        EAFNOSUPPORT    225     /* Address family not supported by protocol */
+#define        EADDRINUSE      226     /* Address already in use */
+#define        EADDRNOTAVAIL   227     /* Cannot assign requested address */
+#define        ENETDOWN        228     /* Network is down */
+#define        ENETUNREACH     229     /* Network is unreachable */
+#define        ENETRESET       230     /* Network dropped connection because of reset */
+#define        ECONNABORTED    231     /* Software caused connection abort */
+#define        ECONNRESET      232     /* Connection reset by peer */
+#define        ENOBUFS         233     /* No buffer space available */
+#define        EISCONN         234     /* Transport endpoint is already connected */
+#define        ENOTCONN        235     /* Transport endpoint is not connected */
+#define        ESHUTDOWN       236     /* Cannot send after transport endpoint shutdown */
+#define        ETOOMANYREFS    237     /* Too many references: cannot splice */
+#define EREFUSED       ECONNREFUSED    /* for HP's NFS apparently */
+#define        ETIMEDOUT       238     /* Connection timed out */
+#define        ECONNREFUSED    239     /* Connection refused */
+#define EREMOTERELEASE 240     /* Remote peer released connection */
+#define        EHOSTDOWN       241     /* Host is down */
+#define        EHOSTUNREACH    242     /* No route to host */
+
+#define        EALREADY        244     /* Operation already in progress */
+#define        EINPROGRESS     245     /* Operation now in progress */
+#define        EWOULDBLOCK     246     /* Operation would block (Linux returns EAGAIN) */
+#define        ENOTEMPTY       247     /* Directory not empty */
+#define        ENAMETOOLONG    248     /* File name too long */
+#define        ELOOP           249     /* Too many symbolic links encountered */
+#define        ENOSYS          251     /* Function not implemented */
+
+#define ENOTSUP                252     /* Function not implemented (POSIX.4 / HPUX) */
+#define ECANCELLED     253     /* aio request was canceled before complete (POSIX.4 / HPUX) */
+
+
+#endif
diff --git a/include/asm-parisc/fcntl.h b/include/asm-parisc/fcntl.h
new file mode 100644 (file)
index 0000000..94fa13f
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef _PARISC_FCNTL_H
+#define _PARISC_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_ACCMODE      00000003
+#define O_RDONLY       00000000
+#define O_WRONLY       00000001
+#define O_RDWR         00000002
+#define O_APPEND       00000010
+#define O_BLKSEEK      00000100 /* HPUX only */
+#define O_CREAT                00000400 /* not fcntl */
+#define O_TRUNC                00001000 /* not fcntl */
+#define O_EXCL         00002000 /* not fcntl */
+#define O_LARGEFILE    00004000
+#define O_SYNC         00100000
+#define O_NONBLOCK     00200004 /* HPUX has separate NDELAY & NONBLOCK */
+#define O_NDELAY       O_NONBLOCK
+#define O_NOCTTY       00400000 /* not fcntl */
+#define O_DSYNC                01000000 /* HPUX only */
+#define O_RSYNC                02000000 /* HPUX only */
+
+#define FASYNC         00020000 /* fcntl, for BSD compatibility */
+#define O_DIRECT       00040000 /* direct disk access hint - currently ignored */
+#define O_DIRECTORY    00010000 /* must be a directory */
+#define O_NOFOLLOW     00000200 /* don't follow links */
+
+#define F_DUPFD                0       /* dup */
+#define F_GETFD                1       /* get f_flags */
+#define F_SETFD                2       /* set f_flags */
+#define F_GETFL                3       /* more flags (cloexec) */
+#define F_SETFL                4
+#define F_GETLK                5
+#define F_SETLK                6
+#define F_SETLKW       7
+#define F_GETLK64      8
+#define F_SETLK64      9
+#define F_SETLKW64     10
+
+#define F_GETOWN       11      /*  for sockets. */
+#define F_SETOWN       12      /*  for sockets. */
+#define F_SETSIG       13      /*  for sockets. */
+#define F_GETSIG       14      /*  for sockets. */
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK                01
+#define F_WRLCK                02
+#define F_UNLCK                03
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK                4       /* or 3 */
+#define F_SHLCK                8       /* or 4 */
+
+/* for leases */
+#define F_INPROGRESS   16
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH                1       /* shared lock */
+#define LOCK_EX                2       /* exclusive lock */
+#define LOCK_NB                4       /* or'd with one of the above to prevent
+                                  blocking */
+#define LOCK_UN                8       /* remove lock */
+
+#define LOCK_MAND      32      /* This is a mandatory flock */
+#define LOCK_READ      64      /* ... Which allows concurrent read operations */
+#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
+#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
+
+struct flock {
+       short l_type;
+       short l_whence;
+       off_t l_start;
+       off_t l_len;
+       pid_t l_pid;
+};
+
+struct flock64 {
+       short l_type;
+       short l_whence;
+       loff_t l_start;
+       loff_t l_len;
+       pid_t l_pid;
+};
+
+#define F_LINUX_SPECIFIC_BASE  1024
+
+#endif
diff --git a/include/asm-parisc/fixmap.h b/include/asm-parisc/fixmap.h
new file mode 100644 (file)
index 0000000..013ea21
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+#define FIXADDR_TOP    (0xffffe000UL)
+#define FIXADDR_SIZE   (0 << PAGE_SHIFT)
+#define FIXADDR_START  (FIXADDR_TOP - FIXADDR_SIZE)
+
+#endif
diff --git a/include/asm-parisc/gsc.h b/include/asm-parisc/gsc.h
new file mode 100644 (file)
index 0000000..014bf1b
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef ASM_PARISC_GSC_H
+#define ASM_PARISC_GSC_H
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <asm/hardware.h>      /* for struct hp_device */
+
+/*
+ * The convention used for inb/outb etc. is that names starting with
+ * two underscores are the inline versions, names starting with a
+ * single underscore are proper functions, and names starting with a
+ * letter are macros that map in some way to inline or proper function
+ * versions.  Not all that pretty, but before you change it, be sure
+ * to convince yourself that it won't break anything (in particular
+ * module support).
+ */
+extern   u8 _gsc_readb(void *);
+extern  u16 _gsc_readw(void *);
+extern  u32 _gsc_readl(void *);
+extern  u64 _gsc_readq(void *);
+extern void _gsc_writeb(u8, void *);
+extern void _gsc_writew(u16,void *);
+extern void _gsc_writel(u32,void *);
+extern void _gsc_writeq(u64,void *);
+
+#define gsc_readb(a)   _gsc_readb((void *)(a))
+#define gsc_readw(a)   _gsc_readw((void *)(a))
+#define gsc_readl(a)   _gsc_readl((void *)(a))
+#define gsc_readq(a)   _gsc_readq((void *)(a))
+#define gsc_writeb(v,a)        _gsc_writeb((v),(void *)(a))
+#define gsc_writew(v,a)        _gsc_writew((v),(void *)(a))
+#define gsc_writel(v,a)        _gsc_writel((v),(void *)(a))
+#define gsc_writeq(v,a)        _gsc_writeq((v),(void *)(a))
+
+struct gsc_dev {
+       struct gsc_bus  *bus;           /* bus this device is on */
+       struct gsc_dev  *next;          /* chain of all devices */
+       struct gsc_dev  *next_bus;      /* chain of all devices on a bus */
+       struct gsc_dev  *next_submod;   /* chain of all devices on a module */
+
+       unsigned        irq;            /* irq generated by this device */
+       void            *hpa;           /* hard physical address */
+
+       u16             hversion;
+       u8              spa;            /* SPA requirements */
+       u8              type;
+       u32             sversion;
+};
+
+struct gsc_irq {
+       unsigned long txn_addr; /* IRQ "target" */
+       int txn_data;           /* HW "IRQ" */
+       int irq;                /* virtual IRQ */
+};
+
+/* PA I/O Architected devices support at least 5 bits in the EIM register. */
+#define GSC_EIM_WIDTH 5
+
+extern int gsc_alloc_irq(struct gsc_irq *dev); /* dev needs an irq */
+extern int gsc_claim_irq(struct gsc_irq *dev, int irq);        /* dev needs this irq */
+
+struct gsc_bus {
+       void            *hpa;           /* HPA of device 0, function 0 of this bus */
+};
+
+/*
+ * There is one gsc_dev structure for each slot-number/function-number
+ * combination:
+ */
+
+struct gsc_dev *gsc_find_device(u16 hversion, struct gsc_dev *from);
+
+extern void probe_serial_gsc(void);
+
+/* returns a virtual irq for device at dev->hpa (works for all LASI/ASP/WAX) */
+extern int busdevice_alloc_irq( struct hp_device *dev );
+
+#endif /* __KERNEL__ */
+#endif /* LINUX_GSC_H */
diff --git a/include/asm-parisc/hardirq.h b/include/asm-parisc/hardirq.h
new file mode 100644 (file)
index 0000000..2c717bf
--- /dev/null
@@ -0,0 +1,87 @@
+/* hardirq.h: 32-bit Sparc hard IRQ support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au)
+ */
+
+#ifndef __PARISC_HARDIRQ_H
+#define __PARISC_HARDIRQ_H
+
+#include <linux/config.h>
+#include <linux/threads.h>
+
+typedef struct {
+       unsigned int __softirq_active;
+       unsigned int __softirq_mask;
+       unsigned int __local_irq_count;
+       unsigned int __local_bh_count;
+       unsigned int __syscall_count;
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+       (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+
+#define in_irq() ({ int __cpu = smp_processor_id(); \
+       (local_irq_count(__cpu) != 0); })
+
+#ifndef CONFIG_SMP
+
+#define hardirq_trylock(cpu)   (local_irq_count(cpu) == 0)
+#define hardirq_endlock(cpu)   do { } while (0)
+
+#define irq_enter(cpu, irq)    (local_irq_count(cpu)++)
+#define irq_exit(cpu, irq)     (local_irq_count(cpu)--)
+
+#define synchronize_irq()      barrier()
+
+#else
+
+#include <asm/atomic.h>
+#include <linux/spinlock.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+
+extern unsigned char global_irq_holder;
+extern spinlock_t global_irq_lock;
+extern atomic_t global_irq_count;
+
+static inline void release_irqlock(int cpu)
+{
+       /* if we didn't own the irq lock, just ignore.. */
+       if (global_irq_holder == (unsigned char) cpu) {
+               global_irq_holder = NO_PROC_ID;
+               spin_unlock(&global_irq_lock);
+       }
+}
+
+static inline void irq_enter(int cpu)
+{
+       ++local_irq_count(cpu);
+       atomic_inc(&global_irq_count);
+}
+
+static inline void irq_exit(int cpu)
+{
+       atomic_dec(&global_irq_count);
+       --local_irq_count(cpu);
+}
+
+static inline int hardirq_trylock(int cpu)
+{
+       return (! atomic_read(&global_irq_count) &&
+               ! spin_is_locked (&global_irq_lock));
+}
+
+#define hardirq_endlock(cpu)   do { } while (0)
+
+extern void synchronize_irq(void);
+
+#endif /* CONFIG_SMP */
+
+#endif /* __PARISC_HARDIRQ_H */
diff --git a/include/asm-parisc/hardware.h b/include/asm-parisc/hardware.h
new file mode 100644 (file)
index 0000000..c44e941
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef _PARISC_HP_MACHINES_H_ 
+#define _PARISC_HP_MACHINES_H_ 
+
+struct hp_hardware {
+       unsigned short hw_type:5;               /* HPHW_xxx */
+       unsigned short hversion;
+       unsigned long  sversion:28;
+       unsigned short opt;
+       char *name; 
+};
+
+struct hp_device {
+       unsigned short hw_type:5;       /* HPHW_xxx */
+       unsigned short hversion;        /* HP-UX uses  hv_model:12 */
+       unsigned int   sversion;        /* HP-UX uses sv_model:20 sv_opt:8 */
+       unsigned short opt;
+       unsigned int hversion_rev;
+       unsigned int sversion_rev;
+       struct hp_hardware * reference;  /* This is a pointer to the
+                                            reference */
+       unsigned int managed; /* this is if the device has a driver for it */
+       void * hpa;
+
+#ifdef __LP64__
+       /* parms for pdc_pat_cell_module() call */
+       unsigned long  pcell_loc;       /* Physical Cell location */
+       unsigned long  mod_index;       /* PAT specific - Misc Module info */
+
+       /* generic info returned from pdc_pat_cell_module() */
+       unsigned long  mod_info;        /* PAT specific - Misc Module info */
+       unsigned long  pmod_loc;        /* physical Module location */
+       unsigned long  mod_path;        /* Module HW path */
+#endif
+};
+
+enum cpu_type {
+       pcx     = 0, /* pa7000          pa 1.0  */
+       pcxs    = 1, /* pa7000          pa 1.1a */
+       pcxt    = 2, /* pa7100          pa 1.1b */
+       pcxt_   = 3, /* pa7200  (t')    pa 1.1c */
+       pcxl    = 4, /* pa7100lc        pa 1.1d */
+       pcxl2   = 5, /* pa7300lc        pa 1.1e */
+       pcxu    = 6, /* pa8000          pa 2.0  */
+       pcxu_   = 7, /* pa8200  (u+)    pa 2.0  */
+       pcxw    = 8, /* pa8500          pa 2.0  */
+       pcxw_   = 9  /* pa8600  (w+)    pa 2.0  */
+};
+
+extern char *cpu_name_version[][2]; /* mapping from enum cpu_type to strings */
+
+struct pa_iodc_driver {
+       unsigned short hw_type:5;               /* HPHW_xxx */
+       unsigned short hversion;
+       unsigned short hversion_rev;
+       unsigned long  sversion:28;
+       unsigned short sversion_rev;
+       unsigned short opt;
+       unsigned int check;  /* Components that are significant */
+       char *name; 
+       char *version; 
+       int (* callback)(struct hp_device *d, struct pa_iodc_driver *dri);
+};
+
+#define DRIVER_CHECK_HWTYPE          1
+#define DRIVER_CHECK_HVERSION        2
+#define DRIVER_CHECK_SVERSION        4
+#define DRIVER_CHECK_OPT             8
+/* The following two are useless right now */
+#define DRIVER_CHECK_HVERSION_REV   16
+#define DRIVER_CHECK_SVERSION_REV   32
+#define DRIVER_CHECK_EVERYTHING     63
+
+
+#define HPHW_NPROC     0 
+#define HPHW_MEMORY    1       
+#define HPHW_B_DMA     2
+#define HPHW_OBSOLETE  3
+#define HPHW_A_DMA     4
+#define HPHW_A_DIRECT  5
+#define HPHW_OTHER     6
+#define HPHW_BCPORT    7
+#define HPHW_CIO       8
+#define HPHW_CONSOLE   9
+#define HPHW_FIO       10
+#define HPHW_BA        11
+#define HPHW_IOA       12
+#define HPHW_BRIDGE    13
+#define HPHW_FABRIC    14
+#define HPHW_FAULTY    31
+
+extern struct hp_hardware hp_hardware_list[];
+
+char *parisc_getHWtype(        unsigned short hw_type );
+
+/* Attention: first hversion, then sversion...! */
+char *parisc_getHWdescription( unsigned short hw_type,
+                                unsigned long hversion,  /* have to be long ! */
+                               unsigned long sversion );
+
+enum cpu_type parisc_get_cpu_type( unsigned long hversion );
+
+extern int register_driver(struct pa_iodc_driver *driver);
+#endif
diff --git a/include/asm-parisc/hdreg.h b/include/asm-parisc/hdreg.h
new file mode 100644 (file)
index 0000000..629b220
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASM_HDREG_H
+#define _ASM_HDREG_H
+
+typedef unsigned short ide_ioreg_t;
+
+#endif
diff --git a/include/asm-parisc/hil.h b/include/asm-parisc/hil.h
new file mode 100644 (file)
index 0000000..9112f9b
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _ASM_HIL_H
+#define _ASM_HIL_H
+
+/*
+ *     linux/asm-parisc/hil.h
+ *
+ *     (c) 1999 Matthew Wilcox
+ */
+
+extern unsigned long hil_base; /* declared in drivers/gsc/hil.c */
+extern unsigned int hil_irq;
+
+#define HILBASE                        hil_base /* 0xf0821000 (old) or 0xf0201000 (new) */
+#define HIL_DATA               0x800
+#define HIL_CMD                        0x801
+
+#define HIL_IRQ                        hil_irq
+
+#define hil_busy()             (gsc_readb(HILBASE + HIL_CMD) & HIL_BUSY)
+#define hil_data_available()   (gsc_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
+#define hil_status()           (gsc_readb(HILBASE + HIL_CMD))
+#define hil_command(x)         do { gsc_writeb((x), HILBASE + HIL_CMD); } while (0)
+#define hil_read_data()                (gsc_readb(HILBASE + HIL_DATA))
+#define hil_write_data(x)      do { gsc_writeb((x), HILBASE + HIL_DATA); } while (0)
+
+#endif
diff --git a/include/asm-parisc/hw_irq.h b/include/asm-parisc/hw_irq.h
new file mode 100644 (file)
index 0000000..f35c91d
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _ASM_HW_IRQ_H
+#define _ASM_HW_IRQ_H
+
+/*
+ *     linux/include/asm/hw_irq.h
+ *
+ *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
+ *
+ *     moved some of the old arch/i386/kernel/irq.h to here. VY
+ *
+ *     IRQ/IPI changes taken from work by Thomas Radke
+ *     <tomsoft@informatik.tu-chemnitz.de>
+ */
+
+#include <asm/irq.h>
+
+#endif
diff --git a/include/asm-parisc/ide.h b/include/asm-parisc/ide.h
new file mode 100644 (file)
index 0000000..08d1c94
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  linux/include/asm-parisc/ide.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+/*
+ *  This file contains the i386 architecture specific IDE code.
+ */
+
+#ifndef __ASMi386_IDE_H
+#define __ASMi386_IDE_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifndef MAX_HWIFS
+#define MAX_HWIFS      10
+#endif
+
+#define ide__sti()     __sti()
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
+{
+       switch (base) {
+               case 0x1f0: return 14;
+               case 0x170: return 15;
+               case 0x1e8: return 11;
+               case 0x168: return 10;
+               case 0x1e0: return 8;
+               case 0x160: return 12;
+               default:
+                       return 0;
+       }
+}
+
+static __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+       switch (index) {
+               case 0: return 0x1f0;
+               case 1: return 0x170;
+               case 2: return 0x1e8;
+               case 3: return 0x168;
+               case 4: return 0x1e0;
+               case 5: return 0x160;
+               default:
+                       return 0;
+       }
+}
+
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+       ide_ioreg_t reg = data_port;
+       int i;
+
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw->io_ports[i] = reg;
+               reg += 1;
+       }
+       if (ctrl_port) {
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+       } else {
+               hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+       }
+       if (irq != NULL)
+               *irq = 0;
+}
+
+static __inline__ void ide_init_default_hwifs(void)
+{
+#ifndef CONFIG_BLK_DEV_IDEPCI
+       hw_regs_t hw;
+       int index;
+
+       for(index = 0; index < MAX_HWIFS; index++) {
+               ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
+               hw.irq = ide_default_irq(ide_default_io_base(index));
+               ide_register_hw(&hw, NULL);
+       }
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+}
+
+typedef union {
+       unsigned all                    : 8;    /* all of the bits together */
+       struct {
+               unsigned head           : 4;    /* always zeros here */
+               unsigned unit           : 1;    /* drive select number, 0 or 1 */
+               unsigned bit5           : 1;    /* always 1 */
+               unsigned lba            : 1;    /* using LBA instead of CHS */
+               unsigned bit7           : 1;    /* always 1 */
+       } b;
+       } select_t;
+
+#define ide_request_irq(irq,hand,flg,dev,id)   request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)               free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)          check_region((from), (extent))
+#define ide_request_region(from,extent,name)   request_region((from), (extent), (name))
+#define ide_release_region(from,extent)                release_region((from), (extent))
+
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(hwif)             (1)
+#define ide_fix_driveid(id)            do {} while (0)
+#define ide_release_lock(lock)         do {} while (0)
+#define ide_get_lock(lock, hdlr, data) do {} while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMi386_IDE_H */
diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h
new file mode 100644 (file)
index 0000000..65f2a29
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _ASM_IO_H
+#define _ASM_IO_H
+
+#include <linux/types.h>
+#include <asm/gsc.h>
+
+#define virt_to_phys(a) ((unsigned long)__pa(a))
+#define phys_to_virt(a) __va(a)
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+#define inb_p inb
+#define inw_p inw
+#define inl_p inl
+#define outb_p outb
+#define outw_p outw
+#define outl_p outl
+
+#define readb gsc_readb
+#define readw gsc_readw
+#define readl gsc_readl
+#define writeb gsc_writeb
+#define writew gsc_writew
+#define writel gsc_writel
+
+
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+/*
+ *     So we get clear link errors 
+ */
+extern u8 inb(unsigned long addr);
+extern u16 inw(unsigned long addr);
+extern u32 inl(unsigned long addr);
+
+extern void outb(unsigned char b, unsigned long addr);
+extern void outw(unsigned short b, unsigned long addr);
+extern void outl(u32 b, unsigned long addr);
+
+static inline void memcpy_toio(void *dest, void *src, int count) 
+{
+       while(count--)
+               writeb(*((char *)src)++, (char *)dest++);
+}
+
+#endif
+
+/* IO Port space is :      BBiiii   where BB is HBA number. */
+#define IO_SPACE_LIMIT 0x00ffffff
+
+/* Right now we don't support Dino-on-a-card and V class which do PCI MMIO
+ * through address/data registers. */
+
+#define ioremap(__offset, __size)      ((void *)(__offset))
+#define iounmap(__addr)
+
+#define dma_cache_inv(_start,_size)            do { flush_kernel_dcache_range(_start,_size); } while(0)
+#define dma_cache_wback(_start,_size)          do { flush_kernel_dcache_range(_start,_size); } while (0)
+#define dma_cache_wback_inv(_start,_size)      do { flush_kernel_dcache_range(_start,_size); } while (0)
+
+#endif
diff --git a/include/asm-parisc/ioctl.h b/include/asm-parisc/ioctl.h
new file mode 100644 (file)
index 0000000..ff78546
--- /dev/null
@@ -0,0 +1,67 @@
+/* $Id: ioctl.h,v 1.2 1999/12/29 22:18:15 willy Exp $
+ *
+ * linux/ioctl.h for Linux by H.H. Bergman.
+ */
+
+#ifndef _ASM_PARISC_IOCTL_H
+#define _ASM_PARISC_IOCTL_H
+
+/* ioctl command encoding: 32 bits total, command in lower 16 bits,
+ * size of the parameter structure in the lower 14 bits of the
+ * upper 16 bits.
+ * Encoding the size of the parameter structure in the ioctl request
+ * is useful for catching programs compiled with old versions
+ * and to avoid overwriting user space outside the user buffer area.
+ * The highest 2 bits are reserved for indicating the ``access mode''.
+ * NOTE: This limits the max parameter size to 16kB -1 !
+ */
+
+#define _IOC_NRBITS    8
+#define _IOC_TYPEBITS  8
+#define _IOC_SIZEBITS  14
+#define _IOC_DIRBITS   2
+
+#define _IOC_NRMASK    ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK  ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK  ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK   ((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT   0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT  (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+/*
+ * Direction bits.
+ */
+#define _IOC_NONE      0U
+#define _IOC_WRITE     2U
+#define _IOC_READ      1U
+
+#define _IOC(dir,type,nr,size) \
+       (((dir)  << _IOC_DIRSHIFT) | \
+        ((type) << _IOC_TYPESHIFT) | \
+        ((nr)   << _IOC_NRSHIFT) | \
+        ((size) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr)           _IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size)     _IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW(type,nr,size)     _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+#define _IOWR(type,nr,size)    _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* used to decode ioctl numbers.. */
+#define _IOC_DIR(nr)           (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr)          (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr)            (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr)          (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the drivers/sound files... */
+
+#define IOC_IN         (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT                (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT      ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK   (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT  (_IOC_SIZESHIFT)
+
+#endif /* _ASM_PARISC_IOCTL_H */
diff --git a/include/asm-parisc/ioctls.h b/include/asm-parisc/ioctls.h
new file mode 100644 (file)
index 0000000..332027f
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __ARCH_PARISC_IOCTLS_H__
+#define __ARCH_PARISC_IOCTLS_H__
+
+#include <asm/ioctl.h>
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS         _IOR('T', 16, struct termios) /* TCGETATTR */
+#define TCSETS         _IOW('T', 17, struct termios) /* TCSETATTR */
+#define TCSETSW                _IOW('T', 18, struct termios) /* TCSETATTRD */
+#define TCSETSF                _IOW('T', 19, struct termios) /* TCSETATTRF */
+#define TCGETA         _IOR('T', 1, struct termio)
+#define TCSETA         _IOW('T', 2, struct termio)
+#define TCSETAW                _IOW('T', 3, struct termio)
+#define TCSETAF                _IOW('T', 4, struct termio)
+#define TCSBRK         _IO('T', 5)
+#define TCXONC         _IO('T', 6)
+#define TCFLSH         _IO('T', 7)
+#define TIOCEXCL       0x540C
+#define TIOCNXCL       0x540D
+#define TIOCSCTTY      0x540E
+#define TIOCGPGRP      _IOR('T', 30, int)
+#define TIOCSPGRP      _IOW('T', 29, int)
+#define TIOCOUTQ       0x5411
+#define TIOCSTI                0x5412
+#define TIOCGWINSZ     0x5413
+#define TIOCSWINSZ     0x5414
+#define TIOCMGET       0x5415
+#define TIOCMBIS       0x5416
+#define TIOCMBIC       0x5417
+#define TIOCMSET       0x5418
+#define TIOCGSOFTCAR   0x5419
+#define TIOCSSOFTCAR   0x541A
+#define FIONREAD       0x541B
+#define TIOCINQ                FIONREAD
+#define TIOCLINUX      0x541C
+#define TIOCCONS       0x541D
+#define TIOCGSERIAL    0x541E
+#define TIOCSSERIAL    0x541F
+#define TIOCPKT                0x5420
+#define FIONBIO                0x5421
+#define TIOCNOTTY      0x5422
+#define TIOCSETD       0x5423
+#define TIOCGETD       0x5424
+#define TCSBRKP                0x5425  /* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT 0x5426  /* For debugging only */
+#define TIOCSBRK       0x5427  /* BSD compatibility */
+#define TIOCCBRK       0x5428  /* BSD compatibility */
+#define TIOCGSID       _IOR('T', 20, int) /* Return the session ID of FD */
+#define TIOCGPTN       _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK     _IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define FIONCLEX       0x5450  /* these numbers need to be adjusted. */
+#define FIOCLEX                0x5451
+#define FIOASYNC       0x5452
+#define TIOCSERCONFIG  0x5453
+#define TIOCSERGWILD   0x5454
+#define TIOCSERSWILD   0x5455
+#define TIOCGLCKTRMIOS 0x5456
+#define TIOCSLCKTRMIOS 0x5457
+#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT     0x545C  /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT    0x545D  /* read serial port inline interrupt counts */
+#define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TIOCPKT_DATA            0
+#define TIOCPKT_FLUSHREAD       1
+#define TIOCPKT_FLUSHWRITE      2
+#define TIOCPKT_STOP            4
+#define TIOCPKT_START           8
+#define TIOCPKT_NOSTOP         16
+#define TIOCPKT_DOSTOP         32
+
+#define TIOCSER_TEMT    0x01   /* Transmitter physically empty */
+
+#endif /* _ASM_PARISC_IOCTLS_H */
diff --git a/include/asm-parisc/iosapic.h b/include/asm-parisc/iosapic.h
new file mode 100644 (file)
index 0000000..d22509f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+** This file is private to iosapic driver.
+** If stuff needs to be used by another driver, move it to a common file.
+**
+** WARNING: fields most data structures here are ordered to make sure
+**          they pack nicely for 64-bit compilation. (ie sizeof(long) == 8)
+*/
+
+
+/*
+** I/O SAPIC init function
+** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
+** Call setup as part of per instance initialization.
+** (ie *not* init_module() function unless only one is present.)
+** fixup_irq is to initialize PCI IRQ line support and
+** virtualize pcidev->irq value. To be called by pci_fixup_bus().
+*/
+extern void *iosapic_register(void *hpa);
+extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
+
+
+#ifdef __IA64__
+/*
+** PA: PIB (Processor Interrupt Block) is handled by Runway bus adapter.
+**     and is hardcoded to 0xfeeNNNN0 where NNNN is id_eid field.
+**
+** IA64: PIB is handled by "Local SAPIC" (integrated in the processor).
+*/
+struct local_sapic_info {
+       struct local_sapic_info *lsi_next;      /* point to next CPU info */
+       int                     *lsi_cpu_id;    /* point to logical CPU id */
+       unsigned long           *lsi_id_eid;    /* point to IA-64 CPU id */
+       int                     *lsi_status;    /* point to CPU status   */
+       void                    *lsi_private;   /* point to special info */
+};
+
+/*
+** "root" data structure which ties everything together.
+** Should always be able to start with sapic_root and locate
+** the desired information.
+*/
+struct sapic_info {
+       struct sapic_info       *si_next;       /* info is per cell */
+       int                     si_cellid;      /* cell id */
+       unsigned int            si_status;       /* status  */
+       char                    *si_pib_base;   /* intr blk base address */
+       local_sapic_info_t      *si_local_info;
+       io_sapic_info_t         *si_io_info;
+       extint_info_t           *si_extint_info;/* External Intr info      */
+};
+
+#endif /* IA64 */
+
diff --git a/include/asm-parisc/ipcbuf.h b/include/asm-parisc/ipcbuf.h
new file mode 100644 (file)
index 0000000..f576ce5
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __PARISC_IPCBUF_H__
+#define __PARISC_IPCBUF_H__
+
+/*
+ * The ipc64_perm structure for PA-RISC is identical to kern_ipc_perm
+ * as we have always had 32-bit UIDs and GIDs in the kernel.
+ */
+
+#define ipc64_perm     kern_ipc_perm
+
+#endif /* __PARISC_IPCBUF_H__ */
diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h
new file mode 100644 (file)
index 0000000..b52415f
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
+
+#include <linux/string.h>
+#include <asm/ptrace.h>
+#include <linux/interrupt.h>
+
+#include <asm/types.h>
+/*
+ *     linux/include/asm/irq.h
+ *
+ *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar,
+ *             Copyright 1999 SuSE GmbH
+ *
+ *     IRQ/IPI changes taken from work by Thomas Radke
+ *     <tomsoft@informatik.tu-chemnitz.de>
+ */
+
+#define CPU_IRQ_REGION  1
+#define TIMER_IRQ       (IRQ_FROM_REGION(CPU_IRQ_REGION) | 0)
+#define        IPI_IRQ          (IRQ_FROM_REGION(CPU_IRQ_REGION) | 1)
+
+/* This should be 31 for PA1.1 binaries and 63 for PA-2.0 wide mode) */
+#define MAX_CPU_IRQ    (BITS_PER_LONG - 1)
+
+#if 1    /* set to 1 to get the new irq offsets, or ...   */
+# if BITS_PER_LONG == 32
+#  define IRQ_REGION_SHIFT 5
+# else
+#  define IRQ_REGION_SHIFT 6
+# endif
+#else   /* 256 irq-entries per region (wastes memory, maybe gains speed? :-))*/
+# define IRQ_REGION_SHIFT 8
+#endif 
+
+#define IRQ_PER_REGION  (1 << IRQ_REGION_SHIFT)
+#define NR_IRQ_REGS    8
+#define NR_IRQS                (NR_IRQ_REGS * IRQ_PER_REGION)
+
+#define IRQ_REGION(irq)        ((irq) >> IRQ_REGION_SHIFT)
+#define IRQ_OFFSET(irq)                ((irq) & ((1<<IRQ_REGION_SHIFT)-1))
+#define        IRQ_FROM_REGION(reg)    ((reg) << IRQ_REGION_SHIFT)
+
+#define IRQ_REG_DIS       1    /* support disable_irq / enable_irq */
+#define IRQ_REG_MASK      2    /* require IRQs to be masked */
+
+struct irq_region_ops {
+       void (*disable_irq)(void *dev, int irq);
+       void (* enable_irq)(void *dev, int irq);
+       void (*   mask_irq)(void *dev, int irq);
+       void (* unmask_irq)(void *dev, int irq);
+};
+
+struct irq_region_data {
+       void *dev;
+       const char *name;
+       unsigned flags;
+       int irqbase;
+};
+
+struct irq_region {
+       struct irq_region_ops ops;
+       struct irq_region_data data;
+
+       struct irqaction *action;
+};
+
+extern struct irq_region *irq_region[NR_IRQ_REGS];
+
+static __inline__ int irq_cannonicalize(int irq)
+{
+       return irq;
+}
+
+extern void disable_irq(int);
+extern void enable_irq(int);
+
+extern void do_irq_mask(unsigned long mask, struct irq_region *region,
+       struct pt_regs *regs);
+
+extern struct irq_region *alloc_irq_region(int count, struct irq_region_ops *ops,
+       unsigned long flags, const char *name, void *dev);
+
+extern int txn_alloc_irq(void);
+extern int txn_claim_irq(int);
+extern unsigned int txn_alloc_data(int, unsigned int);
+extern unsigned long txn_alloc_addr(int);
+
+#endif /* _ASM_IRQ_H */
diff --git a/include/asm-parisc/keyboard.h b/include/asm-parisc/keyboard.h
new file mode 100644 (file)
index 0000000..e477610
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  linux/include/asm-parisc/keyboard.h
+ *
+ *  Original by Geert Uytterhoeven
+ *  updates by Alex deVries <adevries@thepuffingroup.com>
+ *  portions copyright (1999) The Puffin Group
+ *  mostly rewritten by Philipp Rumpf <prumpf@tux.org>,
+ *   Copyright 2000 Philipp Rumpf
+ */
+
+/*
+ *  We try to keep the amount of generic code as low as possible -
+ *  we want to support all HIL, PS/2, and untranslated USB keyboards
+ */
+
+#ifndef _PARISC_KEYBOARD_H
+#define _PARISC_KEYBOARD_H
+
+#include <linux/config.h>
+
+#ifdef __KERNEL__
+#ifdef CONFIG_VT
+
+/*  These are basically the generic functions / variables.  The only
+ *  unexpected detail is the initialization sequence for the keyboard
+ *  driver is something like this:
+ *
+ *  detect keyboard port
+ *  detect keyboard
+ *  call register_kbd_ops 
+ *  wait for init_hw
+ *
+ *  only after init_hw has been called you're allowed to call
+ *  handle_scancode.  This means you either have to be extremely
+ *  careful or use a global flag or something - I strongly suggest
+ *  the latter.    prumpf */
+
+extern struct kbd_ops {
+       int (*setkeycode)(unsigned int, unsigned int);
+       int (*getkeycode)(unsigned int);
+       int (*translate)(unsigned char, unsigned char *, char);
+       char (*unexpected_up)(unsigned char);
+       void (*leds)(unsigned char);
+       void (*init_hw)(void);
+
+       unsigned char sysrq_key;
+       unsigned char *sysrq_xlate;
+} *kbd_ops;
+
+#define kbd_setkeycode         (*kbd_ops->setkeycode)
+#define kbd_getkeycode         (*kbd_ops->getkeycode)
+#define kbd_translate          (*kbd_ops->translate)
+#define kbd_unexpected_up      (*kbd_ops->unexpected_up)
+#define kbd_leds               (*kbd_ops->leds)
+#define kbd_init_hw            (*kbd_ops->init_hw)
+
+#define SYSRQ_KEY              (kbd_ops->sysrq_key)
+#define        kbd_sysrq_xlate         (kbd_ops->sysrq_xlate)
+extern unsigned char hp_ps2kbd_sysrq_xlate[128];       /* from drivers/char/hp_keyb.c */
+
+extern void register_kbd_ops(struct kbd_ops *ops);
+
+#endif /* CONFIG_VT */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMPARISC_KEYBOARD_H */
diff --git a/include/asm-parisc/led.h b/include/asm-parisc/led.h
new file mode 100644 (file)
index 0000000..e4c9b2c
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef LED_H
+#define LED_H
+
+
+#define        LED7            0x80            /* top (or furthest right) LED */
+#define        LED6            0x40
+#define        LED5            0x20
+#define        LED4            0x10
+#define        LED3            0x08
+#define        LED2            0x04
+#define        LED1            0x02
+#define        LED0            0x01            /* bottom (or furthest left) LED */
+
+#define        LED_LAN_TX      LED0            /* for LAN transmit activity */
+#define        LED_LAN_RCV     LED1            /* for LAN receive activity */
+#define        LED_DISK_IO     LED2            /* for disk activity */
+#define        LED_HEARTBEAT   LED3            /* heartbeat */
+
+
+/* irq function */
+extern void led_interrupt_func(void);
+
+/* LASI & ASP specific LED initialization funcs */
+extern void __init lasi_led_init( unsigned long lasi_hpa );
+extern void __init asp_led_init( unsigned long led_ptr );
+
+/* registers the LED regions for procfs */
+extern void __init register_led_regions(void);
+
+/* main LED initialization function (uses the PDC) */ 
+extern int __init led_init(void);
+
+#endif /* LED_H */
diff --git a/include/asm-parisc/linux_logo.h b/include/asm-parisc/linux_logo.h
new file mode 100644 (file)
index 0000000..f431e42
--- /dev/null
@@ -0,0 +1,48 @@
+/* $Id: linux_logo.h,v 1.1.1.1 1999/03/15 19:41:01 pjlahaie Exp $
+ * include/asm-parisc/linux_logo.h: This is a linux logo
+ *                                to be displayed on boot.
+ *
+ * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * You can put anything here, but:
+ * LINUX_LOGO_COLORS has to be less than 224
+ * image size has to be 80x80
+ * values have to start from 0x20
+ * (i.e. RGB(linux_logo_red[0],
+ *          linux_logo_green[0],
+ *          linux_logo_blue[0]) is color 0x20)
+ * BW image has to be 80x80 as well, with MS bit
+ * on the left
+ * Serial_console ascii image can be any size,
+ * but should contain %s to display the version
+ */
+#include <linux/init.h>
+#include <linux/version.h>
+
+#define linux_logo_banner "Linux/PA-RISC version " UTS_RELEASE
+
+#define LINUX_LOGO_COLORS 214
+
+#ifdef INCLUDE_LINUX_LOGO_DATA
+
+#define INCLUDE_LINUX_LOGOBW
+#define INCLUDE_LINUX_LOGO16
+
+#include <linux/linux_logo.h>
+
+#else
+
+/* prototypes only */
+extern unsigned char linux_logo_red[];
+extern unsigned char linux_logo_green[];
+extern unsigned char linux_logo_blue[];
+extern unsigned char linux_logo[];
+extern unsigned char linux_logo_bw[];
+extern unsigned char linux_logo16_red[];
+extern unsigned char linux_logo16_green[];
+extern unsigned char linux_logo16_blue[];
+extern unsigned char linux_logo16[];
+
+#endif
diff --git a/include/asm-parisc/machdep.h b/include/asm-parisc/machdep.h
new file mode 100644 (file)
index 0000000..a231c97
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _PARISC_MACHDEP_H
+#define _PARISC_MACHDEP_H
+
+#include <linux/notifier.h>
+
+#define        MACH_RESTART    1
+#define        MACH_HALT       2
+#define MACH_POWER_ON  3
+#define        MACH_POWER_OFF  4
+
+extern struct notifier_block *mach_notifier;
+extern void pa7300lc_init(void);
+
+extern void (*cpu_lpmc)(int, struct pt_regs *);
+
+#endif
diff --git a/include/asm-parisc/mc146818rtc.h b/include/asm-parisc/mc146818rtc.h
new file mode 100644 (file)
index 0000000..adf4163
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+/* empty include file to satisfy the include in genrtc.c */
+
+#endif /* _ASM_MC146818RTC_H */
diff --git a/include/asm-parisc/md.h b/include/asm-parisc/md.h
new file mode 100644 (file)
index 0000000..67aace8
--- /dev/null
@@ -0,0 +1,13 @@
+/* $Id: md.h,v 1.1.1.1 1999/03/15 19:41:02 pjlahaie Exp $
+ * md.h: High speed xor_block operation for RAID4/5 
+ *
+ */
+#ifndef __ASM_MD_H
+#define __ASM_MD_H
+
+/* #define HAVE_ARCH_XORBLOCK */
+
+#define MD_XORBLOCK_ALIGNMENT  sizeof(long)
+
+#endif /* __ASM_MD_H */
diff --git a/include/asm-parisc/mman.h b/include/asm-parisc/mman.h
new file mode 100644 (file)
index 0000000..b040142
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef __PARISC_MMAN_H__
+#define __PARISC_MMAN_H__
+
+#define PROT_READ      0x1             /* page can be read */
+#define PROT_WRITE     0x2             /* page can be written */
+#define PROT_EXEC      0x4             /* page can be executed */
+#define PROT_NONE      0x0             /* page can not be accessed */
+
+#define MAP_SHARED     0x01            /* Share changes */
+#define MAP_PRIVATE    0x02            /* Changes are private */
+#define MAP_TYPE       0x03            /* Mask for type of mapping */
+#define MAP_FIXED      0x04            /* Interpret addr exactly */
+#define MAP_ANONYMOUS  0x10            /* don't use a file */
+
+#define MAP_DENYWRITE  0x0800          /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
+#define MAP_LOCKED     0x2000          /* pages are locked */
+#define MAP_NORESERVE  0x4000          /* don't check for reservations */
+#define MAP_GROWSDOWN  0x8000          /* stack-like segment */
+
+#define MS_SYNC                1               /* synchronous memory sync */
+#define MS_ASYNC       2               /* sync memory asynchronously */
+#define MS_INVALIDATE  4               /* invalidate the caches */
+
+#define MCL_CURRENT    1               /* lock all current mappings */
+#define MCL_FUTURE     2               /* lock all future mappings */
+
+#define MADV_NORMAL     0               /* no further special treatment */
+#define MADV_RANDOM     1               /* expect random page references */
+#define MADV_SEQUENTIAL 2               /* expect sequential page references */
+#define MADV_WILLNEED   3               /* will need these pages */
+#define MADV_DONTNEED   4               /* dont need these pages */
+#define MADV_SPACEAVAIL 5               /* insure that resources are reserved */
+#define MADV_VPS_PURGE  6               /* Purge pages from VM page cache */
+#define MADV_VPS_INHERIT 7              /* Inherit parents page size */
+
+/* The range 12-64 is reserved for page size specification. */
+#define MADV_4K_PAGES   12              /* Use 4K pages  */
+#define MADV_16K_PAGES  14              /* Use 16K pages */
+#define MADV_64K_PAGES  16              /* Use 64K pages */
+#define MADV_256K_PAGES 18              /* Use 256K pages */
+#define MADV_1M_PAGES   20              /* Use 1 Megabyte pages */
+#define MADV_4M_PAGES   22              /* Use 4 Megabyte pages */
+#define MADV_16M_PAGES  24              /* Use 16 Megabyte pages */
+#define MADV_64M_PAGES  26              /* Use 64 Megabyte pages */
+
+/* compatibility flags */
+#define MAP_ANON       MAP_ANONYMOUS
+#define MAP_FILE       0
+#define MAP_VARIABLE   0
+
+#endif /* __PARISC_MMAN_H__ */
diff --git a/include/asm-parisc/mmu.h b/include/asm-parisc/mmu.h
new file mode 100644 (file)
index 0000000..c311f8a
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * parisc mmu structures 
+ */
+
+#ifndef _PARISC_MMU_H_
+#define _PARISC_MMU_H_
+
+#ifndef __ASSEMBLY__
+/* Hardware Page Table Entry */
+typedef struct _PTE {
+       unsigned long v:1;      /* Entry is valid */
+       unsigned long tag:31;   /* Unique Tag */
+
+       unsigned long r:1;      /* referenced */
+       unsigned long os_1:1;   /*  */
+       unsigned long t:1;      /* page reference trap */
+       unsigned long d:1;      /* dirty */
+       unsigned long b:1;      /* break */
+       unsigned long type:3;   /* access type */
+       unsigned long pl1:2;    /* PL1 (execute) */
+       unsigned long pl2:2;    /* PL2 (write) */
+       unsigned long u:1;      /* uncacheable */
+       unsigned long id:1;     /* access id */
+       unsigned long os_2:1;   /*  */
+
+       unsigned long os_3:3;   /*  */
+       unsigned long res_1:4;  /*  */
+       unsigned long phys:20;  /* physical page number */
+       unsigned long os_4:2;   /*  */
+       unsigned long res_2:3;  /*  */
+
+       unsigned long next;     /* pointer to next page */
+} PTE; 
+
+/*
+ * Simulated two-level MMU.  This structure is used by the kernel
+ * to keep track of MMU mappings and is used to update/maintain
+ * the hardware HASH table which is really a cache of mappings.
+ *
+ * The simulated structures mimic the hardware available on other
+ * platforms, notably the 80x86 and 680x0.
+ */
+
+typedef struct _pte {
+       unsigned long page_num:20;
+       unsigned long flags:12;         /* Page flags (some unused bits) */
+} pte;
+
+#define PD_SHIFT (10+12)               /* Page directory */
+#define PD_MASK  0x02FF
+#define PT_SHIFT (12)                  /* Page Table */
+#define PT_MASK  0x02FF
+#define PG_SHIFT (12)                  /* Page Entry */
+
+/* MMU context */
+
+typedef struct _MMU_context {
+       long    pid[4];
+       pte     **pmap;         /* Two-level page-map structure */
+} MMU_context;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _PARISC_MMU_H_ */
diff --git a/include/asm-parisc/mmu_context.h b/include/asm-parisc/mmu_context.h
new file mode 100644 (file)
index 0000000..64531f9
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __PARISC_MMU_CONTEXT_H
+#define __PARISC_MMU_CONTEXT_H
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+}
+
+/* on PA-RISC, we actually have enough contexts to justify an allocator
+ * for them.  prumpf */
+
+extern unsigned long alloc_sid(void);
+extern void free_sid(unsigned long);
+
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+       /*
+        * Init_new_context can be called for a cloned mm, so we
+        * only allocate a space id if one hasn't been allocated
+        * yet AND mm != &init_mm (cloned kernel thread which
+        * will run in the kernel space with spaceid 0).
+        */
+
+       if ((mm != &init_mm) && (mm->context == 0)) {
+               mm->context = alloc_sid();
+       }
+
+       return 0;
+}
+
+static inline void
+destroy_context(struct mm_struct *mm)
+{
+       free_sid(mm->context);
+       mm->context = 0;
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
+{
+
+       if (prev != next) {
+               /* Re-load page tables */
+               tsk->thread.pg_tables = __pa(next->pgd);
+
+               mtctl(tsk->thread.pg_tables, 25);
+               mtsp(next->context,3);
+       }
+}
+
+static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+       /*
+        * Activate_mm is our one chance to allocate a space id
+        * for a new mm created in the exec path. There's also
+        * some lazy tlb stuff, which is currently dead code, but
+        * we only allocate a space id if one hasn't been allocated
+        * already, so we should be OK.
+        */
+
+       if (next == &init_mm) BUG(); /* Should never happen */
+
+       if (next->context == 0)
+           next->context = alloc_sid();
+
+       switch_mm(prev,next,current,0);
+}
+#endif
diff --git a/include/asm-parisc/msgbuf.h b/include/asm-parisc/msgbuf.h
new file mode 100644 (file)
index 0000000..9dd868a
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _PARISC_MSGBUF_H
+#define _PARISC_MSGBUF_H
+
+/* 
+ * The msqid64_ds structure for parisc architecture, copied from sparc.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+       struct ipc64_perm msg_perm;
+       unsigned int   __pad1;
+       __kernel_time_t msg_stime;      /* last msgsnd time */
+       unsigned int   __pad2;
+       __kernel_time_t msg_rtime;      /* last msgrcv time */
+       unsigned int   __pad3;
+       __kernel_time_t msg_ctime;      /* last change time */
+       unsigned int  msg_cbytes;       /* current number of bytes on queue */
+       unsigned int  msg_qnum; /* number of messages in queue */
+       unsigned int  msg_qbytes;       /* max number of bytes on queue */
+       __kernel_pid_t msg_lspid;       /* pid of last msgsnd */
+       __kernel_pid_t msg_lrpid;       /* last receive pid */
+       unsigned int  __unused1;
+       unsigned int  __unused2;
+};
+
+#endif /* _PARISC_MSGBUF_H */
diff --git a/include/asm-parisc/namei.h b/include/asm-parisc/namei.h
new file mode 100644 (file)
index 0000000..2b8132d
--- /dev/null
@@ -0,0 +1,17 @@
+/* $Id: namei.h,v 1.1.1.1 1999/03/15 19:41:02 pjlahaie Exp $
+ * linux/include/asm-parisc/namei.h
+ *
+ * Included from linux/fs/namei.c
+ */
+
+#ifndef __PARISC_NAMEI_H
+#define __PARISC_NAMEI_H
+
+/* This dummy routine maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define __emul_prefix() NULL
+
+#endif /* __PARISC_NAMEI_H */
diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h
new file mode 100644 (file)
index 0000000..39f19f6
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef _PARISC_PAGE_H
+#define _PARISC_PAGE_H
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT     12
+#define PAGE_SIZE      (1UL << PAGE_SHIFT)
+#define PAGE_MASK      (~(PAGE_SIZE-1))
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#define clear_page(page)       memset((void *)(page), 0, PAGE_SIZE)
+#define copy_page(to,from)     memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+
+#define clear_user_page(page, vaddr) clear_page(page)
+#define copy_user_page(to, from, vaddr) copy_page(to, from)
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)     ((x).pte)
+#define pmd_val(x)     ((x).pmd)
+#define pgd_val(x)     ((x).pgd)
+#define pgprot_val(x)  ((x).pgprot)
+
+#define __pte(x)       ((pte_t) { (x) } )
+#define __pmd(x)       ((pmd_t) { (x) } )
+#define __pgd(x)       ((pgd_t) { (x) } )
+#define __pgprot(x)    ((pgprot_t) { (x) } )
+
+/* Pure 2^n version of get_order */
+extern __inline__ int get_order(unsigned long size)
+{
+       int order;
+
+       size = (size-1) >> (PAGE_SHIFT-1);
+       order = -1;
+       do {
+               size >>= 1;
+               order++;
+       } while (size);
+       return order;
+}
+
+#endif /* !__ASSEMBLY__ */
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+/*
+ * Tell the user there is some problem. Beep too, so we can
+ * see^H^H^Hhear bugs in early bootup as well!
+ *
+ * We don't beep yet.  prumpf
+ */
+#define BUG() do { \
+       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+} while (0)
+
+#define PAGE_BUG(page) do { \
+       BUG(); \
+} while (0)
+
+
+#define LINUX_GATEWAY_SPACE     0
+#define __PAGE_OFFSET          (0xc0000000)
+
+#define PAGE_OFFSET            ((unsigned long)__PAGE_OFFSET)
+/* These macros don't work for 64-bit C code -- don't allow in C at all */
+#ifdef __ASSEMBLY__
+#   define PA(x)       ((x)-__PAGE_OFFSET)
+#   define VA(x)       ((x)+__PAGE_OFFSET)
+#endif
+#define __pa(x)                        ((unsigned long)(x)-PAGE_OFFSET)
+#define __va(x)                        ((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define        virt_to_page(kaddr)     (mem_map + (__pa(kaddr) >> PAGE_SHIFT))
+#define VALID_PAGE(page)       ((page - mem_map) < max_mapnr)
+
+#endif /* __KERNEL__ */
+
+#endif /* _PARISC_PAGE_H */
diff --git a/include/asm-parisc/param.h b/include/asm-parisc/param.h
new file mode 100644 (file)
index 0000000..d6ee56c
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _ASMPARISC_PARAM_H
+#define _ASMPARISC_PARAM_H
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#define EXEC_PAGESIZE  4096
+
+#ifndef NGROUPS
+#define NGROUPS                32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP                (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64      /* max length of hostname */
+
+#ifdef __KERNEL__
+# define CLOCKS_PER_SEC        HZ      /* frequency at which times() counts */
+#endif
+
+#endif
diff --git a/include/asm-parisc/parport.h b/include/asm-parisc/parport.h
new file mode 100644 (file)
index 0000000..00d9cc3
--- /dev/null
@@ -0,0 +1,18 @@
+/* 
+ *
+ * parport.h: ia32-compatible parport initialisation
+ *
+ * This file should only be included by drivers/parport/parport_pc.c.
+ */
+#ifndef _ASM_PARPORT_H
+#define _ASM_PARPORT_H 1
+
+
+static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
+{
+       /* nothing ! */
+       return 0;
+}
+
+
+#endif /* !(_ASM_PARPORT_H) */
diff --git a/include/asm-parisc/parport_gsc.h b/include/asm-parisc/parport_gsc.h
new file mode 100644 (file)
index 0000000..686d4f1
--- /dev/null
@@ -0,0 +1,193 @@
+#ifndef __LINUX_PARPORT_GSC_H
+#define __LINUX_PARPORT_GSC_H
+
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#undef DEBUG_PARPORT   /* undefine for production */
+#define DELAY_TIME     0
+
+#if DELAY_TIME == 0
+#define parport_readb  gsc_readb
+#define parport_writeb gsc_writeb
+#else
+static __inline__ unsigned char parport_readb( unsigned long port )
+{
+    udelay(DELAY_TIME);
+    return gsc_readb(port);
+}
+
+static __inline__ void parport_writeb( unsigned char value, unsigned long port )
+{
+    gsc_writeb(value,port);
+    udelay(DELAY_TIME);
+}
+#endif
+
+/* --- register definitions ------------------------------- */
+
+#define EPPDATA(p)  ((p)->base    + 0x4)
+#define EPPADDR(p)  ((p)->base    + 0x3)
+#define CONTROL(p)  ((p)->base    + 0x2)
+#define STATUS(p)   ((p)->base    + 0x1)
+#define DATA(p)     ((p)->base    + 0x0)
+
+struct parport_gsc_private {
+       /* Contents of CTR. */
+       unsigned char ctr;
+
+       /* Bitmask of writable CTR bits. */
+       unsigned char ctr_writable;
+
+       /* Number of bytes per portword. */
+       int pword;
+
+       /* Not used yet. */
+       int readIntrThreshold;
+       int writeIntrThreshold;
+
+       /* buffer suitable for DMA, if DMA enabled */
+       char *dma_buf;
+       dma_addr_t dma_handle;
+       struct pci_dev *dev;
+};
+
+extern __inline__ void parport_gsc_write_data(struct parport *p, unsigned char d)
+{
+#ifdef DEBUG_PARPORT
+       printk (KERN_DEBUG "parport_gsc_write_data(%p,0x%02x)\n", p, d);
+#endif
+       parport_writeb(d, DATA(p));
+}
+
+extern __inline__ unsigned char parport_gsc_read_data(struct parport *p)
+{
+       unsigned char val = parport_readb (DATA (p));
+#ifdef DEBUG_PARPORT
+       printk (KERN_DEBUG "parport_gsc_read_data(%p) = 0x%02x\n",
+               p, val);
+#endif
+       return val;
+}
+
+/* __parport_gsc_frob_control differs from parport_gsc_frob_control in that
+ * it doesn't do any extra masking. */
+static __inline__ unsigned char __parport_gsc_frob_control (struct parport *p,
+                                                          unsigned char mask,
+                                                          unsigned char val)
+{
+       struct parport_gsc_private *priv = p->physport->private_data;
+       unsigned char ctr = priv->ctr;
+#ifdef DEBUG_PARPORT
+       printk (KERN_DEBUG
+               "__parport_gsc_frob_control(%02x,%02x): %02x -> %02x\n",
+               mask, val, ctr, ((ctr & ~mask) ^ val) & priv->ctr_writable);
+#endif
+       ctr = (ctr & ~mask) ^ val;
+       ctr &= priv->ctr_writable; /* only write writable bits. */
+       parport_writeb (ctr, CONTROL (p));
+       priv->ctr = ctr;        /* Update soft copy */
+       return ctr;
+}
+
+extern __inline__ void parport_gsc_data_reverse (struct parport *p)
+{
+       __parport_gsc_frob_control (p, 0x20, 0x20);
+}
+
+extern __inline__ void parport_gsc_data_forward (struct parport *p)
+{
+       __parport_gsc_frob_control (p, 0x20, 0x00);
+}
+
+extern __inline__ void parport_gsc_write_control (struct parport *p,
+                                                unsigned char d)
+{
+       const unsigned char wm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
+
+       /* Take this out when drivers have adapted to newer interface. */
+       if (d & 0x20) {
+               printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+                       p->name, p->cad->name);
+               parport_gsc_data_reverse (p);
+       }
+
+       __parport_gsc_frob_control (p, wm, d & wm);
+}
+
+extern __inline__ unsigned char parport_gsc_read_control(struct parport *p)
+{
+       const unsigned char rm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
+       const struct parport_gsc_private *priv = p->physport->private_data;
+       return priv->ctr & rm; /* Use soft copy */
+}
+
+extern __inline__ unsigned char parport_gsc_frob_control (struct parport *p,
+                                                        unsigned char mask,
+                                                        unsigned char val)
+{
+       const unsigned char wm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
+
+       /* Take this out when drivers have adapted to newer interface. */
+       if (mask & 0x20) {
+               printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
+                       p->name, p->cad->name,
+                       (val & 0x20) ? "reverse" : "forward");
+               if (val & 0x20)
+                       parport_gsc_data_reverse (p);
+               else
+                       parport_gsc_data_forward (p);
+       }
+
+       /* Restrict mask and val to control lines. */
+       mask &= wm;
+       val &= wm;
+
+       return __parport_gsc_frob_control (p, mask, val);
+}
+
+extern __inline__ unsigned char parport_gsc_read_status(struct parport *p)
+{
+       return parport_readb (STATUS(p));
+}
+
+
+extern __inline__ void parport_gsc_disable_irq(struct parport *p)
+{
+       __parport_gsc_frob_control (p, 0x10, 0x00);
+}
+
+extern __inline__ void parport_gsc_enable_irq(struct parport *p)
+{
+       __parport_gsc_frob_control (p, 0x10, 0x10);
+}
+
+extern void parport_gsc_release_resources(struct parport *p);
+
+extern int parport_gsc_claim_resources(struct parport *p);
+
+extern void parport_gsc_init_state(struct pardevice *, struct parport_state *s);
+
+extern void parport_gsc_save_state(struct parport *p, struct parport_state *s);
+
+extern void parport_gsc_restore_state(struct parport *p, struct parport_state *s);
+
+extern void parport_gsc_inc_use_count(void);
+
+extern void parport_gsc_dec_use_count(void);
+
+extern struct parport *parport_gsc_probe_port (unsigned long base,
+                                             unsigned long base_hi,
+                                             int irq, int dma,
+                                             struct pci_dev *dev);
+
+#endif
diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
new file mode 100644 (file)
index 0000000..89ea370
--- /dev/null
@@ -0,0 +1,215 @@
+#ifndef __ASM_PARISC_PCI_H
+#define __ASM_PARISC_PCI_H
+
+#include <asm/scatterlist.h>
+
+#define MIN_PCI_PORT 0x000000
+#define MAX_PCI_PORT 0xffffff
+
+/*
+** HP PCI platforms generally support multiple bus adapters.
+**    (workstations 1-~4, servers 2-~32)
+**
+** Newer platforms number the busses across PCI bus adapters *sparsely*.
+** E.g. 0, 8, 16, ...
+**
+** Under a PCI bus, most HP platforms support PPBs up to two or three
+** levels deep. See "Bit3" product line. 
+*/
+#define PCI_MAX_BUSSES 256
+
+/* [soapbox on]
+** Who the hell can develope stuff without ASSERT or VASSERT?
+** No one understands all the modules across all platforms.
+** For linux add another dimension - processor architectures.
+**
+** This should be a standard/global macro used liberally
+** in all code. Every respectable engineer I know in HP
+** would support this argument. - grant
+** [soapbox off]
+*/
+#ifdef PCI_DEBUG
+#define ASSERT(expr) \
+       if(!(expr)) { \
+               printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
+               panic(#expr); \
+       }
+#else
+#define ASSERT(expr)
+#endif
+
+
+/*
+** pci_hba_data (aka H2P_OBJECT in HP/UX)
+**
+** This is the "common" or "base" data structure which HBA drivers
+** (eg Dino or LBA) are required to place at the top of their own
+** dev->sysdata structure.  I've heard this called "C inheritance" too.
+**
+** Data needed by pcibios layer belongs here.
+*/
+struct pci_hba_data {
+       struct pci_hba_data *next;      /* global chain of HBAs */
+       char           *base_addr;      /* aka Host Physical Address */
+       struct hp_device *iodc_info;    /* Info from PA bus walk */
+       struct pci_bus *hba_bus;        /* primary PCI bus below HBA */
+       int             hba_num;        /* I/O port space access "key" */
+       struct resource bus_num;        /* PCI bus numbers */
+       struct resource io_space;       /* PIOP */
+       struct resource mem_space;      /* LMMIO */
+       unsigned long   mem_space_offset;  /* VCLASS support */
+       /* REVISIT - spinlock to protect resources? */
+};
+
+
+/*
+** KLUGE: linux/pci.h include asm/pci.h BEFORE declaring struct pci_bus
+** (This eliminates some of the warnings).
+*/
+struct pci_bus;
+struct pci_dev;
+
+/*
+** Most PCI devices (eg Tulip, NCR720) also export the same registers
+** to both MMIO and I/O port space.  Due to poor performance of I/O Port
+** access under HP PCI bus adapters, strongly reccomend use of MMIO
+** address space.
+**
+** While I'm at it more PA programming notes:
+**
+** 1) MMIO stores (writes) are posted operations. This means the processor
+**    gets an "ACK" before the write actually gets to the device. A read
+**    to the same device (or typically the bus adapter above it) will
+**    force in-flight write transaction(s) out to the targeted device
+**    before the read can complete.
+**
+** 2) The Programmed I/O (PIO) data may not always be strongly ordered with
+**    respect to DMA on all platforms. Ie PIO data can reach the processor
+**    before in-flight DMA reaches memory. Since most SMP PA platforms
+**    are I/O coherent, it generally doesn't matter...but sometimes
+**    it does.
+**
+** I've helped device driver writers debug both types of problems.
+*/
+struct pci_port_ops {
+         u8 (*inb)  (struct pci_hba_data *hba, u16 port);
+        u16 (*inw)  (struct pci_hba_data *hba, u16 port);
+        u32 (*inl)  (struct pci_hba_data *hba, u16 port);
+       void (*outb) (struct pci_hba_data *hba, u16 port,  u8 data);
+       void (*outw) (struct pci_hba_data *hba, u16 port, u16 data);
+       void (*outl) (struct pci_hba_data *hba, u16 port, u32 data);
+};
+
+
+struct pci_bios_ops {
+       void (*init)(void);
+       void (*fixup_bus)(struct pci_bus *bus);
+};
+
+extern void pcibios_size_bridge(struct pci_bus *, struct pbus_set_ranges_data *);
+
+
+/*
+** See Documentation/DMA-mapping.txt
+*/
+struct pci_dma_ops {
+       int  (*dma_supported)(struct pci_dev *dev, dma_addr_t mask);
+       void *(*alloc_consistent)(struct pci_dev *dev, size_t size, dma_addr_t *iova);
+       void (*free_consistent)(struct pci_dev *dev, size_t size, void *vaddr, dma_addr_t iova);
+       dma_addr_t (*map_single)(struct pci_dev *dev, void *addr, size_t size, int direction);
+       void (*unmap_single)(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction);
+       int  (*map_sg)(struct pci_dev *dev, struct scatterlist *sg, int nents, int direction);
+       void (*unmap_sg)(struct pci_dev *dev, struct scatterlist *sg, int nhwents, int direction);
+       void (*dma_sync_single)(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction);
+       void (*dma_sync_sg)(struct pci_dev *dev, struct scatterlist *sg, int nelems, int direction);
+};
+
+
+/*
+** We could live without the hppa_dma_ops indirection if we didn't want
+** to support 4 different dma models with one binary or they were
+** all loadable modules:
+**     I/O MMU        consistent method           dma_sync behavior
+**  =============   ======================       =======================
+**  a) PA-7x00LC    uncachable host memory          flush/purge
+**  b) U2/Uturn      cachable host memory              NOP
+**  c) Ike/Astro     cachable host memory              NOP
+**  d) EPIC/SAGA     memory on EPIC/SAGA         flush/reset DMA channel
+**
+** PA-7[13]00LC processors have a GSC bus interface and no I/O MMU.
+**
+** Systems (eg PCX-T workstations) that don't fall into the above
+** categories will need to modify the needed drivers to perform
+** flush/purge and allocate "regular" cacheable pages for everything.
+*/
+
+extern struct pci_dma_ops *hppa_dma_ops;
+extern struct pci_dma_ops pcxl_dma_ops;
+extern struct pci_dma_ops pcx_dma_ops;
+
+/*
+** Oops hard if we haven't setup hppa_dma_ops by the time the first driver
+** attempts to initialize.
+** Since panic() is a (void)(), pci_dma_panic() is needed to satisfy
+** the (int)() required by pci_dma_supported() interface.
+*/
+static inline int pci_dma_panic(char *msg)
+{
+       panic(msg);
+       return -1;
+}
+
+#define pci_dma_supported(p, m)        ( \
+       (NULL == hppa_dma_ops) \
+       ?  pci_dma_panic("Dynamic DMA support missing...OOPS!\n(Hint: was Astro/Ike/U2/Uturn not claimed?)\n") \
+       : hppa_dma_ops->dma_supported(p,m) \
+)
+
+#define pci_alloc_consistent(p, s, a)  hppa_dma_ops->alloc_consistent(p,s,a)
+#define pci_free_consistent(p, s, v, a)        hppa_dma_ops->free_consistent(p,s,v,a)
+#define pci_map_single(p, v, s, d)     hppa_dma_ops->map_single(p, v, s, d)
+#define pci_unmap_single(p, a, s, d)   hppa_dma_ops->unmap_single(p, a, s, d)
+#define pci_map_sg(p, sg, n, d)                hppa_dma_ops->map_sg(p, sg, n, d)
+#define pci_unmap_sg(p, sg, n, d)      hppa_dma_ops->unmap_sg(p, sg, n, d)
+
+/* For U2/Astro/Ike based platforms (which are fully I/O coherent)
+** dma_sync is a NOP. Let's keep the performance path short here.
+*/
+#define pci_dma_sync_single(p, a, s, d)        { if (hppa_dma_ops->dma_sync_single) \
+       hppa_dma_ops->dma_sync_single(p, a, s, d); \
+       }
+#define pci_dma_sync_sg(p, sg, n, d)   { if (hppa_dma_ops->dma_sync_sg) \
+       hppa_dma_ops->dma_sync_sg(p, sg, n, d); \
+       }
+
+/*
+** Stuff declared in arch/parisc/kernel/pci.c
+*/
+extern struct pci_port_ops *pci_port;
+extern struct pci_bios_ops *pci_bios;
+extern int pci_post_reset_delay;       /* delay after de-asserting #RESET */
+
+extern void pcibios_register_hba(struct pci_hba_data *);
+extern void pcibios_assign_unassigned_resources(struct pci_bus *);
+
+
+/*
+** used by drivers/pci/pci.c:pci_do_scan_bus()
+**   0 == check if bridge is numbered before re-numbering.
+**   1 == pci_do_scan_bus() should automatically number all PCI-PCI bridges.
+**
+** REVISIT:
+**   To date, only alpha sets this to one. We'll need to set this
+**   to zero for legacy platforms and one for PAT platforms.
+*/
+#ifdef __LP64__
+extern int pdc_pat;  /* arch/parisc/kernel/inventory.c */
+#define pcibios_assign_all_busses()    pdc_pat
+#else
+#define pcibios_assign_all_busses()    0
+#endif
+
+#define PCIBIOS_MIN_IO          0x10
+#define PCIBIOS_MIN_MEM         0x1000 /* NBPG - but pci/setup-res.c dies */
+
+#endif /* __ASM_PARISC_PCI_H */
diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h
new file mode 100644 (file)
index 0000000..debd3f5
--- /dev/null
@@ -0,0 +1,629 @@
+#ifndef _PARISC_PDC_H
+#define _PARISC_PDC_H
+
+/*
+    PDC entry points...
+*/
+
+#define PDC_POW_FAIL   1               /* perform a power-fail         */
+#define PDC_POW_FAIL_PREPARE   0       /* prepare for powerfail        */
+
+#define PDC_CHASSIS    2               /* PDC-chassis functions        */
+#define PDC_CHASSIS_DISP       0       /* update chassis display       */
+#define PDC_CHASSIS_WARN       1       /* return chassis warnings      */
+#define PDC_CHASSIS_DISPWARN   2       /* update&return chassis status */
+#define PDC_RETURN_CHASSIS_INFO 128    /* HVERSION dependend: return chassis LED/LCD info  */
+
+#define PDC_PIM         3               /* Get PIM data                 */
+#define PDC_PIM_HPMC            0       /* Transfer HPMC data           */
+#define PDC_PIM_RETURN_SIZE     1       /* Get Max buffer needed for PIM*/
+#define PDC_PIM_LPMC            2       /* Transfer HPMC data           */
+#define PDC_PIM_SOFT_BOOT       3       /* Transfer Soft Boot data      */
+#define PDC_PIM_TOC             4       /* Transfer TOC data            */
+
+#define PDC_MODEL      4               /* PDC model information call   */
+#define PDC_MODEL_INFO         0       /* returns information          */
+#define PDC_MODEL_BOOTID       1       /* set the BOOT_ID              */
+#define PDC_MODEL_VERSIONS     2       /* returns cpu-internal versions*/
+#define PDC_MODEL_SYSMODEL     3       /* return system model info     */
+#define PDC_MODEL_ENSPEC       4       /* ??? */
+#define PDC_MODEL_DISPEC       5       /* ??? */
+#define PDC_MODEL_CPU_ID       6       /* returns cpu-id (only newer machines!) */
+#define PDC_MODEL_CAPABILITIES 7       /* returns OS32/OS64-flags      */
+#define PDC_MODEL_GET_BOOT__OP 8       /* returns boot test options    */
+#define PDC_MODEL_SET_BOOT__OP 9       /* set boot test options        */
+
+#define PDC_CACHE      5               /* return/set cache (& TLB) info*/
+#define PDC_CACHE_INFO         0       /* returns information          */
+#define PDC_CACHE_SET_COH      1       /* set coherence state          */
+#define PDC_CACHE_RET_SPID     2       /* returns space-ID bits        */
+
+#define PDC_HPA         6              /* return HPA of processor */
+#define PDC_HPA_PROCESSOR       0
+#define PDC_HPA_MODULES         1
+
+#define PDC_IODC       8       /* talk to IODC */
+#define PDC_IODC_READ     0       /* read IODC entry point */
+/*      PDC_IODC_RI_*                INDEX parameter of PDC_IODC_READ   */
+#define PDC_IODC_RI_DATA_BYTES 0       /* IODC Data Bytes                  */
+/*                             1, 2       obsolete - HVERSION dependent      */
+#define PDC_IODC_RI_INIT       3       /* Initialize module              */
+#define PDC_IODC_RI_IO         4       /* Module input/output          */
+#define PDC_IODC_RI_SPA                5       /* Module input/output          */
+#define PDC_IODC_RI_CONFIG     6       /* Module input/output          */
+/*                             7         obsolete - HVERSION dependent      */
+#define PDC_IODC_RI_TEST       8       /* Module input/output          */
+#define PDC_IODC_RI_TLB                9       /* Module input/output          */
+#define PDC_IODC_NINIT   2       /* non-destructive init */
+#define PDC_IODC_DINIT   3       /* destructive init */
+#define PDC_IODC_MEMERR         4       /* check for memory errors */
+#define PDC_IODC_INDEX_DATA     0       /* get first 16 bytes from mod IODC */
+#define PDC_IODC_BUS_ERROR      -4      /* bus error return value */
+#define PDC_IODC_INVALID_INDEX  -5      /* invalid index return value */
+#define PDC_IODC_COUNT   -6      /* count is too small */
+
+#define        PDC_TOD         9               /* time-of-day clock (TOD) */
+#define        PDC_TOD_READ            0       /* read TOD  */
+#define        PDC_TOD_WRITE           1       /* write TOD */
+#define        PDC_TOD_ITIMER          2       /* calibrate Interval Timer (CR16) */
+
+#define PDC_ADD_VALID  12              /* Memory validation PDC call */
+#define PDC_ADD_VALID_VERIFY  0        /* Make PDC_ADD_VALID verify region */
+
+#define PDC_INSTR      15              /* get instr to invoke PDCE_CHECK() */
+
+#define PDC_BLOCK_TLB  18              /* manage hardware block-TLB    */
+#define PDC_BTLB_INFO          0       /* returns parameter            */
+#define PDC_BTLB_INSERT                1       /* insert BTLB entry            */
+#define PDC_BTLB_PURGE         2       /* purge BTLB entries           */
+#define PDC_BTLB_PURGE_ALL     3       /* purge all BTLB entries       */
+
+#define PDC_TLB                19              /* manage hardware TLB miss handling */
+#define PDC_TLB_INFO           0       /* returns parameter            */
+#define PDC_TLB_SETUP          1       /* set up miss handling         */
+
+#define PDC_SYSTEM_MAP 22              /* find system modules */
+#define PDC_FIND_MODULE        0
+
+
+/* HVERSION dependent */
+
+#define PDC_IO                 135     /* log error info, reset IO system  */
+
+#define PDC_BROADCAST_RESET    136     /* reset all processors      */
+#define PDC_DO_RESET            0UL    /* option: perform a broadcast reset */
+#define PDC_DO_FIRM_TEST_RESET  1UL    /* Do broadcast reset with bitmap */
+#define PDC_BR_RECONFIGURATION  2UL    /* reset w/reconfiguration */
+#define PDC_FIRM_TEST_MAGIC    0xab9ec36fUL    /* for this reboot only */
+
+#define PDC_LAN_STATION_ID      138     /* Hversion dependent mechanism for */
+#define PDC_LAN_STATION_ID_READ 0       /* getting the lan station address  */
+
+#define        PDC_LAN_STATION_ID_SIZE 6
+
+/* Legacy PDC definitions for same stuff */
+#define PDC_PCI_INDEX             147UL
+#define PDC_PCI_GET_INT_TBL_SIZE       13UL
+#define PDC_PCI_GET_INT_TBL         14UL
+
+/* generic error codes returned by all PDC-functions */
+
+#define PDC_WARN           3  /* Call completed with a warning */
+#define PDC_REQ_ERR_1       2  /* See above */
+#define PDC_REQ_ERR_0       1  /* Call would generate a requestor error */
+#define PDC_OK       0  /* Call completed successfully */
+#define PDC_BAD_PROC      -1  /* Called non-existant procedure */
+#define PDC_BAD_OPTION     -2  /* Called with non-existant option */
+#define PDC_ERROR        -3  /* Call could not complete without an error */
+#define PDC_INVALID_ARG   -10  /* Called with an invalid argument */
+#define PDC_BUS_POW_WARN  -12  /* Call could not complete in allowed power budget */
+
+
+/* The following are from the HPUX .h files, and are just for
+compatibility */
+
+#define PDC_RET_OK       0L    /* Call completed successfully */
+#define PDC_RET_NE_PROC -1L    /* Non-existent procedure */
+#define PDC_RET_NE_OPT  -2L    /* non-existant option - arg1 */
+#define PDC_RET_NE_MOD  -5L    /* Module not found */
+#define PDC_RET_NE_CELL_MOD -7L        /* Cell module not found */
+#define PDC_RET_INV_ARG        -10L    /* Invalid argument */
+#define PDC_RET_NOT_NARROW -17L /* Narrow mode not supported */
+
+
+/* Error codes for PDC_ADD_VALID */
+
+#define PDC_ADD_VALID_WARN         3  /* Call completed with a warning */
+#define PDC_ADD_VALID_REQ_ERR_1       2  /* See above */
+#define PDC_ADD_VALID_REQ_ERR_0       1  /* Call would generate a requestor error */
+#define PDC_ADD_VALID_OK             0  /* Call completed successfully */
+#define PDC_ADD_VALID_BAD_OPTION     -2  /* Called with non-existant option */
+#define PDC_ADD_VALID_ERROR      -3  /* Call could not complete without an error */
+#define PDC_ADD_VALID_INVALID_ARG   -10  /* Called with an invalid argument */
+#define PDC_ADD_VALID_BUS_POW_WARN  -12  /* Call could not complete in allowed power budget */
+
+/* The PDC_MEM_MAP calls */
+
+#define PDC_MEM_MAP        128
+#define PDC_MEM_MAP_HPA                0
+
+/* constants for OS (NVM...) */
+#define OS_ID_NONE     0
+#define OS_ID_HPUX     1
+#define OS_ID_MPEXL    2
+#define OS_ID_OSF      3
+#define OS_ID_LINUX    OS_ID_HPUX
+
+/* constants for PDC_CHASSIS */
+#define OSTAT_OFF                    0
+#define OSTAT_FLT                    1 
+#define OSTAT_TEST                  2
+#define OSTAT_INIT                  3
+#define OSTAT_SHUT                  4
+#define OSTAT_WARN                  5
+#define OSTAT_RUN                    6
+#define OSTAT_ON                      7
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+struct pdc_model {             /* for PDC_MODEL */
+       unsigned long hversion;
+       unsigned long sversion;
+       unsigned long hw_id;
+       unsigned long boot_id;
+       unsigned long sw_id;
+       unsigned long sw_cap;
+       unsigned long arch_rev;
+       unsigned long pot_key;
+       unsigned long curr_key;
+       unsigned long pad[32-9];
+} __attribute__((aligned(8))) ;
+
+
+#if 0
+struct pdc_chassis_warn {              /* for PDC_CHASSIS */
+       unsigned long warn;
+       unsigned long pad[32-1];
+} __attribute__((aligned(8))) ;
+#endif
+
+struct pdc_model_sysmodel {    /* for PDC_MODEL_SYSMODEL */
+       unsigned long mod_len;
+       unsigned long pad[32-1];
+} __attribute__((aligned(8))) ;
+
+struct pdc_model_cpuid  {      /* for PDC_MODEL_CPU_ID */
+       unsigned long cpuid;
+       unsigned long pad[32-1];
+} __attribute__((aligned(8))) ;
+
+struct pdc_cache_cf {          /* for PDC_CACHE  (I/D-caches) */
+    unsigned long
+#ifdef __LP64__
+               cc_padW:32,
+#endif
+               cc_alias:4,     /* alias boundaries for virtual adresses   */
+               cc_block: 4,    /* to determine most efficient stride */
+               cc_line : 3,    /* maximum amount written back as a result of store (multiple of 16 bytes) */
+               cc_pad0 : 2,    /* reserved */
+               cc_wt   : 1,    /* 0 = WT-Dcache, 1 = WB-Dcache */
+               cc_sh   : 2,    /* 0 = separate I/D-cache, else shared I/D-cache */
+               cc_cst  : 3,    /* 0 = incoherent D-cache, 1=coherent D-cache */
+               cc_pad1 : 5,    /* reserved */
+               cc_assoc: 8;    /* associativity of I/D-cache */
+};
+
+struct pdc_tlb_cf {            /* for PDC_CACHE (I/D-TLB's) */
+    unsigned long tc_pad0:12,  /* reserved */
+#ifdef __LP64__
+               tc_padW:32,
+#endif
+               tc_sh   : 2,    /* 0 = separate I/D-TLB, else shared I/D-TLB */
+               tc_hv   : 1,    /* HV */
+               tc_page : 1,    /* 0 = 2K page-size-machine, 1 = 4k page size */
+               tc_cst  : 3,    /* 0 = incoherent operations, else coherent operations */
+               tc_aid  : 5,    /* ITLB: width of access ids of processor (encoded!) */
+               tc_pad1 : 8;    /* ITLB: width of space-registers (encoded) */
+};
+
+struct pdc_cache_info {                /* main-PDC_CACHE-structure (caches & TLB's) */
+       /* I-cache */
+       unsigned long   ic_size;        /* size in bytes */
+       struct pdc_cache_cf ic_conf;    /* configuration */
+       unsigned long   ic_base;        /* base-addr */
+       unsigned long   ic_stride;
+       unsigned long   ic_count;
+       unsigned long   ic_loop;
+       /* D-cache */
+       unsigned long   dc_size;        /* size in bytes */
+       struct pdc_cache_cf dc_conf;    /* configuration */
+       unsigned long   dc_base;        /* base-addr */
+       unsigned long   dc_stride;
+       unsigned long   dc_count;
+       unsigned long   dc_loop;
+       /* Instruction-TLB */
+       unsigned long   it_size;        /* number of entries in I-TLB */
+       struct pdc_tlb_cf it_conf;      /* I-TLB-configuration */
+       unsigned long   it_sp_base;
+       unsigned long   it_sp_stride;
+       unsigned long   it_sp_count;
+       unsigned long   it_off_base;
+       unsigned long   it_off_stride;
+       unsigned long   it_off_count;
+       unsigned long   it_loop;
+       /* data-TLB */
+       unsigned long   dt_size;        /* number of entries in D-TLB */
+       struct pdc_tlb_cf dt_conf;      /* D-TLB-configuration */
+       unsigned long   dt_sp_base;
+       unsigned long   dt_sp_stride;
+       unsigned long   dt_sp_count;
+       unsigned long   dt_off_base;
+       unsigned long   dt_off_stride;
+       unsigned long   dt_off_count;
+       unsigned long   dt_loop;
+       /* padded to 32 entries... */
+       unsigned long   pad[32-30];
+} __attribute__((aligned(8))) ;
+
+struct pdc_hpa {      /* PDC_HPA */
+       unsigned long   hpa;
+       unsigned long   filler[31];
+} __attribute__((aligned(8))) ;
+
+#if 0
+/* If you start using the next struct, you'll have to adjust it to
+ * work with 64-bit firmware I think -PB
+ */
+struct pdc_iodc {     /* PDC_IODC */
+       unsigned char   hversion_model;
+       unsigned char   hversion;
+       unsigned char   spa;
+       unsigned char   type;
+       unsigned int    sversion_rev:4;
+       unsigned int    sversion_model:19;
+       unsigned int    sversion_opt:8;
+       unsigned char   rev;
+       unsigned char   dep;
+       unsigned char   features;
+       unsigned char   filler1;
+       unsigned int    checksum:16;
+       unsigned int    length:16;
+       unsigned int    filler[15];
+} __attribute__((aligned(8))) ;
+#endif
+
+#ifndef __LP64__
+/* no BLTBs in pa2.0 processors */
+struct pdc_btlb_info_range {
+       __u8 res00;
+       __u8 num_i;
+       __u8 num_d;
+       __u8 num_comb;
+};
+
+struct pdc_btlb_info { /* PDC_BLOCK_TLB, return of PDC_BTLB_INFO */
+       unsigned int min_size;  /* minimum size of BTLB in pages */
+       unsigned int max_size;  /* maximum size of BTLB in pages */
+       struct pdc_btlb_info_range fixed_range_info;
+       struct pdc_btlb_info_range variable_range_info;
+       unsigned int pad[32-4];
+} __attribute__((aligned(8))) ;
+#endif
+
+struct pdc_tlb {               /* for PDC_TLB */
+       unsigned long min_size;
+       unsigned long max_size;
+       unsigned long pad[32-2];
+} __attribute__((aligned(8))) ;
+
+struct pdc_system_map { /* PDC_SYTEM_MAP/FIND_MODULE */
+       void * mod_addr;
+       unsigned long mod_pgs;
+       unsigned long add_addrs;
+       unsigned long filler[29];
+} __attribute__((aligned(8))) ;
+
+/*
+ * Device path specifications used by PDC.
+ */
+struct pdc_module_path {
+       char  flags;    /* see bit definitions below */
+       char  bc[6];    /* Bus Converter routing info to a specific */
+                       /* I/O adaptor (< 0 means none, > 63 resvd) */
+       char  mod;      /* fixed field of specified module */
+       unsigned int layers[6]; /* device-specific info (ctlr #, unit # ...) */
+} __attribute__((aligned(8))) ;
+
+#ifndef __LP64__
+/* Probably needs 64-bit porting -PB */
+struct pdc_memory_map {        /* PDC_MEMORY_MAP */
+       unsigned int hpa;       /* mod's register set address */
+       unsigned int more_pgs;  /* number of additional I/O pgs */
+} __attribute__((aligned(8))) ;
+
+struct pdc_lan_station_id {    /* PDC_LAN_STATION_ID */
+       unsigned char addr[PDC_LAN_STATION_ID_SIZE];
+       unsigned char pad0[2];
+       int pad1[30];
+};
+#endif
+
+struct pdc_tod {
+       unsigned long tod_sec; 
+       unsigned long tod_usec;
+       long pad[30];
+} __attribute__((aligned(8))) ;
+
+/* architected results from PDC_PIM/transfer hpmc on a PA1.1 machine */
+
+struct pdc_hpmc_pim_11 { /* PDC_PIM */
+       __u32 gr[32];
+       __u32 cr[32];
+       __u32 sr[8];
+       __u32 iasq_back;
+       __u32 iaoq_back;
+       __u32 check_type;
+       __u32 cpu_state;
+       __u32 rsvd1;
+       __u32 cache_check;
+       __u32 tlb_check;
+       __u32 bus_check;
+       __u32 assists_check;
+       __u32 rsvd2;
+       __u32 assist_state;
+       __u32 responder_addr;
+       __u32 requestor_addr;
+       __u32 path_info;
+       __u64 fr[32];
+};
+
+/*
+ * architected results from PDC_PIM/transfer hpmc on a PA2.0 machine
+ *
+ * Note that PDC_PIM doesn't care whether or not wide mode was enabled
+ * so the results are different on  PA1.1 vs. PA2.0 when in narrow mode.
+ *
+ * Note also that there are unarchitected results available, which
+ * are hversion dependent. Do a "ser pim 0 hpmc" after rebooting, since
+ * the firmware is probably the best way of printing hversion dependent
+ * data.
+ */
+
+struct pdc_hpmc_pim_20 { /* PDC_PIM */
+       __u64 gr[32];
+       __u64 cr[32];
+       __u64 sr[8];
+       __u64 iasq_back;
+       __u64 iaoq_back;
+       __u32 check_type;
+       __u32 cpu_state;
+       __u32 cache_check;
+       __u32 tlb_check;
+       __u32 bus_check;
+       __u32 assists_check;
+       __u32 assist_state;
+       __u32 path_info;
+       __u64 responder_addr;
+       __u64 requestor_addr;
+       __u64 fr[32];
+};
+
+#endif /* __ASSEMBLY__ */
+
+/* flags of the device_path (see below) */
+#define        PF_AUTOBOOT     0x80
+#define        PF_AUTOSEARCH   0x40
+#define        PF_TIMER        0x0F
+
+#ifndef __ASSEMBLY__
+
+struct device_path {           /* page 1-69 */
+       unsigned char flags;    /* flags see above! */
+       unsigned char bc[6];    /* bus converter routing info */
+       unsigned char mod;
+       unsigned int  layers[6];/* device-specific layer-info */
+} __attribute__((aligned(8))) ;
+
+struct pz_device {
+       struct  device_path dp; /* see above */
+       /* struct       iomod *hpa; */
+       unsigned int hpa;       /* HPA base address */
+       /* char *spa; */
+       unsigned int spa;       /* SPA base address */
+       /* int  (*iodc_io)(struct iomod*, ...); */
+       unsigned int iodc_io;   /* device entry point */
+       short   pad;            /* reserved */
+       unsigned short cl_class;/* see below */
+} __attribute__((aligned(8))) ;
+
+#endif /* __ASSEMBLY__ */
+
+/* cl_class
+ * page 3-33 of IO-Firmware ARS
+ * IODC ENTRY_INIT(Search first) RET[1]
+ */
+#define        CL_NULL         0       /* invalid */
+#define        CL_RANDOM       1       /* random access (as disk) */
+#define        CL_SEQU         2       /* sequential access (as tape) */
+#define        CL_DUPLEX       7       /* full-duplex point-to-point (RS-232, Net) */
+#define        CL_KEYBD        8       /* half-duplex console (HIL Keyboard) */
+#define        CL_DISPL        9       /* half-duplex console (display) */
+#define        CL_FC           10      /* FiberChannel access media */
+
+#if 0
+/* FIXME: DEVCLASS_* duplicates CL_* (above).  Delete DEVCLASS_*? */
+#define DEVCLASS_RANDOM                1
+#define DEVCLASS_SEQU          2
+#define DEVCLASS_DUPLEX                7
+#define DEVCLASS_KEYBD         8
+#define DEVCLASS_DISP          9
+#endif
+
+/* IODC ENTRY_INIT() */
+#define ENTRY_INIT_SRCH_FRST   2
+#define ENTRY_INIT_SRCH_NEXT   3
+#define ENTRY_INIT_MOD_DEV     4
+#define ENTRY_INIT_DEV         5
+#define ENTRY_INIT_MOD         6
+#define ENTRY_INIT_MSG         9
+
+/* IODC ENTRY_IO() */
+#define ENTRY_IO_BOOTIN                0
+#define ENTRY_IO_CIN           2
+#define ENTRY_IO_COUT          3
+#define ENTRY_IO_CLOSE         4
+#define ENTRY_IO_GETMSG                9
+
+/* IODC ENTRY_SPA() */
+
+/* IODC ENTRY_CONFIG() */
+
+/* IODC ENTRY_TEST() */
+
+/* IODC ENTRY_TLB() */
+
+
+/* DEFINITION OF THE ZERO-PAGE (PAG0) */
+/* based on work by Jason Eckhardt (jason@equator.com) */
+
+#ifndef __ASSEMBLY__
+
+#define        PAGE0   ((struct zeropage *)0xc0000000)
+
+struct zeropage {
+       /* [0x000] initialize vectors (VEC) */
+       unsigned int    vec_special;            /* must be zero */
+       /* int  (*vec_pow_fail)(void);*/
+       unsigned int    vec_pow_fail; /* power failure handler */
+       /* int  (*vec_toc)(void); */
+       unsigned int    vec_toc;
+       unsigned int    vec_toclen;
+       /* int  (*vec_rendz)(void); */
+       unsigned int vec_rendz;
+       int     vec_pow_fail_flen;
+       int     vec_pad[10];            
+       
+       /* [0x040] reserved processor dependent */
+       int     pad0[112];
+
+       /* [0x200] reserved */
+       int     pad1[84];
+
+       /* [0x350] memory configuration (MC) */
+       int     memc_cont;              /* contiguous mem size (bytes) */
+       int     memc_phsize;            /* physical memory size */
+       int     memc_adsize;            /* additional mem size, bytes of SPA space used by PDC */
+       unsigned int mem_pdc_hi;        /* used for 64-bit */
+
+       /* [0x360] various parameters for the boot-CPU */
+       /* unsigned int *mem_booterr[8]; */
+       unsigned int mem_booterr[8];    /* ptr to boot errors */
+       unsigned int mem_free;          /* first location, where OS can be loaded */
+       /* struct iomod *mem_hpa; */
+       unsigned int mem_hpa;           /* HPA of the boot-CPU */
+       /* int (*mem_pdc)(int, ...); */
+       unsigned int mem_pdc;           /* PDC entry point */
+       unsigned int mem_10msec;        /* number of clock ticks in 10msec */
+
+       /* [0x390] initial memory module (IMM) */
+       /* struct iomod *imm_hpa; */
+       unsigned int imm_hpa;           /* HPA of the IMM */
+       int     imm_soft_boot;          /* 0 = was hard boot, 1 = was soft boot */
+       unsigned int    imm_spa_size;           /* SPA size of the IMM in bytes */
+       unsigned int    imm_max_mem;            /* bytes of mem in IMM */
+
+       /* [0x3A0] boot console, display device and keyboard */
+       struct pz_device mem_cons;      /* description of console device */
+       struct pz_device mem_boot;      /* description of boot device */
+       struct pz_device mem_kbd;       /* description of keyboard device */
+
+       /* [0x430] reserved */
+       int     pad430[116];
+
+       /* [0x600] processor dependent */
+       __u32   pad600[1];
+       __u32   proc_sti;               /* pointer to STI ROM */
+       __u32   pad608[126];
+};
+
+#endif /* __ASSEMBLY__ */
+
+/* Page Zero constant offsets used by the HPMC handler */
+
+#define BOOT_CONSOLE_HPA_OFFSET  0x3c0
+#define BOOT_CONSOLE_SPA_OFFSET  0x3c4
+#define BOOT_CONSOLE_PATH_OFFSET 0x3a8
+
+#ifndef __ASSEMBLY__
+
+struct pdc_pat_io_num {
+       unsigned long num;
+       unsigned long reserved[31];
+};
+
+
+
+extern void pdc_console_init(void);
+extern int  pdc_getc(void);    /* wait for char */
+extern void pdc_putc(unsigned char);   /* print char */
+
+
+/* wrapper-functions from pdc.c */
+
+int pdc_add_valid(void *address);
+int pdc_hpa_processor(void *address);
+#if 0
+int pdc_hpa_modules(void *address);
+#endif
+int pdc_iodc_read(void *address, void *hpa, unsigned int index,
+                 void *iodc_data, unsigned int iodc_data_size);
+int pdc_system_map_find_mods(void *pdc_mod_info, void *mod_path, int index);
+int pdc_model_info(struct pdc_model *model);
+int pdc_model_sysmodel(char  *name);
+int pdc_model_cpuid(struct pdc_model_cpuid *cpu_id);
+int pdc_model_versions(struct pdc_model_cpuid *cpu_id, int id);
+int pdc_cache_info(struct pdc_cache_info *cache);
+#ifndef __LP64__
+int pdc_btlb_info( struct pdc_btlb_info *btlb);
+int pdc_lan_station_id( char *lan_addr, void *net_hpa);
+#endif
+int pdc_mem_map_hpa(void *r_addr, void *mod_path);
+
+extern int pdc_chassis_disp(unsigned long disp);
+extern int pdc_chassis_info(void *pdc_result, void *chassis_info, unsigned long len);
+
+#ifdef __LP64__
+int pdc_pat_get_irt_size(void *r_addr, unsigned long cell_num);
+int pdc_pat_get_irt(void *r_addr, unsigned long cell_num);
+#else
+/* No PAT support for 32-bit kernels...sorry */
+#define pdc_pat_get_irt_size(r_addr, cell_numn)        PDC_RET_NE_PROC
+#define pdc_pat_get_irt(r_addr, cell_num)      PDC_RET_NE_PROC
+#endif
+int pdc_pci_irt_size(void *r_addr, void *hpa);
+int pdc_pci_irt(void *r_addr, void *hpa, void *tbl);
+
+int pdc_tod_read(struct pdc_tod *tod);
+int pdc_tod_set(unsigned long sec, unsigned long usec);
+
+/* on all currently-supported platforms, IODC I/O calls are always
+ * 32-bit calls, and MEM_PDC calls are always the same width as the OS.
+ * This means Cxxx boxes can't run wide kernels right now. -PB
+ *
+ * Note that some PAT boxes may have 64-bit IODC I/O...
+ */
+#ifdef __LP64__
+#   define mem_pdc_call(args...) real64_call(0L, ##args)
+#else
+#   define mem_pdc_call(args...) real32_call(0L, ##args)
+#endif
+/* yes 'int', not 'long' -- IODC I/O is always 32-bit stuff */
+extern long real64_call(unsigned long function, ...);
+extern long real32_call(unsigned long function, ...);
+extern void pdc_init(void);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _PARISC_PDC_H */
diff --git a/include/asm-parisc/pdcpat.h b/include/asm-parisc/pdcpat.h
new file mode 100644 (file)
index 0000000..38fb259
--- /dev/null
@@ -0,0 +1,247 @@
+#ifndef __PARISC_PATPDC_H
+#define __PARISC_PATPDC_H
+
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) Hewlett Packard (Paul Bame <bame@puffin.external.hp.com>)
+ * Copyright 2000 (c) Grant Grundler <grundler@puffin.external.hp.com>
+ */
+
+
+/* PDC PAT CELL */
+#define PDC_PAT_CELL                   64L   /* Interface for gaining and 
+                                         * manipulatin g cell state within PD */
+#define PDC_PAT_CELL_GET_NUMBER    0L   /* Return Cell number */
+#define PDC_PAT_CELL_GET_INFO      1L   /* Returns info about Cell */
+#define PDC_PAT_CELL_MODULE        2L   /* Returns info about Module */
+#define PDC_PAT_CELL_SET_ATTENTION 9L   /* Set Cell Attention indicator */
+#define PDC_PAT_CELL_NUMBER_TO_LOC 10L   /* Cell Number -> Location */
+#define PDC_PAT_CELL_WALK_FABRIC   11L   /* Walk the Fabric */
+#define PDC_PAT_CELL_GET_RDT_SIZE  12L   /* Return Route Distance Table Sizes */
+#define PDC_PAT_CELL_GET_RDT       13L   /* Return Route Distance Tables */
+#define PDC_PAT_CELL_GET_LOCAL_PDH_SZ 14L /* Read Local PDH Buffer Size */
+#define PDC_PAT_CELL_SET_LOCAL_PDH    15L  /* Write Local PDH Buffer */
+#define PDC_PAT_CELL_GET_REMOTE_PDH_SZ 16L /* Return Remote PDH Buffer Size */
+#define PDC_PAT_CELL_GET_REMOTE_PDH 17L /* Read Remote PDH Buffer */
+#define PDC_PAT_CELL_GET_DBG_INFO   128L  /* Return DBG Buffer Info */
+#define PDC_PAT_CELL_CHANGE_ALIAS   129L  /* Change Non-Equivalent Alias Chacking */
+
+
+/*
+** Arg to PDC_PAT_CELL_MODULE memaddr[4]
+**
+** Addresses on the Merced Bus != all Runway Bus addresses.
+** This is intended for programming SBA/LBA chips range registers.
+*/
+#define IO_VIEW      0UL
+#define PA_VIEW      1UL
+
+/* PDC_PAT_CELL_MODULE entity type values */
+#define        PAT_ENTITY_CA   0       /* central agent */
+#define        PAT_ENTITY_PROC 1       /* processor */
+#define        PAT_ENTITY_MEM  2       /* memory controller */
+#define        PAT_ENTITY_SBA  3       /* system bus adapter */
+#define        PAT_ENTITY_LBA  4       /* local bus adapter */
+#define        PAT_ENTITY_PBC  5       /* processor bus converter */
+#define        PAT_ENTITY_XBC  6       /* crossbar fabric connect */
+#define        PAT_ENTITY_RC   7       /* fabric interconnect */
+
+/* PDC_PAT_CELL_MODULE address range type values */
+#define PAT_PBNUM           0         /* PCI Bus Number */
+#define PAT_LMMIO           1         /* < 4G MMIO Space */
+#define PAT_GMMIO           2         /* > 4G MMIO Space */
+#define PAT_NPIOP           3         /* Non Postable I/O Port Space */
+#define PAT_PIOP            4         /* Postable I/O Port Space */
+#define PAT_AHPA            5         /* Addional HPA Space */
+#define PAT_UFO             6         /* HPA Space (UFO for Mariposa) */
+#define PAT_GNIP            7         /* GNI Reserved Space */
+
+
+/* PDC PAT CHASSIS LOG */
+
+#define PDC_PAT_CHASSIS_LOG            65L /* Platform logging & forward
+                                           ** progress functions */
+#define PDC_PAT_CHASSIS_WRITE_LOG      0L /* Write Log Entry */
+#define PDC_PAT_CHASSIS_READ_LOG       1L /* Read  Log Entry */
+
+/* PDC PAT CPU  */
+
+#define PDC_PAT_CPU                    67L /* Interface to CPU configuration
+                                               * within the protection domain */
+#define PDC_PAT_CPU_INFO               0L /* Return CPU config info */
+#define PDC_PAT_CPU_DELETE             1L /* Delete CPU */
+#define PDC_PAT_CPU_ADD                2L /* Add    CPU */
+#define PDC_PAT_CPU_GET_NUMBER         3L /* Return CPU Number */
+#define PDC_PAT_CPU_GET_HPA            4L /* Return CPU HPA */
+#define PDC_PAT_CPU_STOP               5L /* Stop   CPU */
+#define PDC_PAT_CPU_RENDEZVOUS         6L /* Rendezvous CPU */
+#define PDC_PAT_CPU_GET_CLOCK_INFO     7L /* Return CPU Clock info */
+#define PDC_PAT_CPU_GET_RENDEZVOUS_STATE 8L /* Return Rendezvous State */
+#define PDC_PAT_CPU_PLUNGE_FABRIC      128L /* Plunge Fabric */
+#define PDC_PAT_CPU_UPDATE_CACHE_CLEANSING 129L /* Manipulate Cache 
+                                                 * Cleansing Mode */
+/*  PDC PAT EVENT */
+
+#define PDC_PAT_EVENT                  68L /* Interface to Platform Events */
+#define PDC_PAT_EVENT_GET_CAPS         0L /* Get Capabilities */
+#define PDC_PAT_EVENT_SET_MODE         1L /* Set Notification Mode */
+#define PDC_PAT_EVENT_SCAN             2L /* Scan Event */
+#define PDC_PAT_EVENT_HANDLE           3L /* Handle Event */
+#define PDC_PAT_EVENT_GET_NB_CALL      4L /* Get Non-Blocking call Args */
+
+/*  PDC PAT HPMC */
+
+#define PDC_PAT_HPMC               70L /* Cause processor to go into spin
+                                      ** loop, and wait for wake up from
+                                      ** Monarch Processor */
+#define PDC_PAT_HPMC_RENDEZ_CPU     0L /* go into spin loop */
+#define PDC_PAT_HPMC_SET_PARAMS     1L /* Allows OS to specify intr which PDC 
+                                        * will use to interupt OS during machine
+                                        * check rendezvous */
+
+/* parameters for PDC_PAT_HPMC_SET_PARAMS: */
+#define HPMC_SET_PARAMS_INTR       1L /* Rendezvous Interrupt */
+#define HPMC_SET_PARAMS_WAKE       2L /* Wake up processor */
+
+/*  PDC PAT IO */
+
+#define PDC_PAT_IO                  71L /* On-line services for I/O modules */
+#define PDC_PAT_IO_GET_SLOT_STATUS     5L /* Get Slot Status Info*/
+#define PDC_PAT_IO_GET_LOC_FROM_HARDWARE 6L /* Get Physical Location from */
+                                            /* Hardware Path */
+#define PDC_PAT_IO_GET_HARDWARE_FROM_LOC 7L /* Get Hardware Path from 
+                                             * Physical Location */
+#define PDC_PAT_IO_GET_PCI_CONFIG_FROM_HW 11L /* Get PCI Configuration
+                                               * Address from Hardware Path */
+#define PDC_PAT_IO_GET_HW_FROM_PCI_CONFIG 12L /* Get Hardware Path 
+                                               * from PCI Configuration Address */
+#define PDC_PAT_IO_READ_HOST_BRIDGE_INFO 13L  /* Read Host Bridge State Info */
+#define PDC_PAT_IO_CLEAR_HOST_BRIDGE_INFO 14L /* Clear Host Bridge State Info*/
+#define PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE 15L /* Get PCI INT Routing Table 
+                                                   * Size */
+#define PDC_PAT_IO_GET_PCI_ROUTING_TABLE  16L /* Get PCI INT Routing Table */
+#define PDC_PAT_IO_GET_HINT_TABLE_SIZE         17L /* Get Hint Table Size */
+#define PDC_PAT_IO_GET_HINT_TABLE      18L /* Get Hint Table */
+#define PDC_PAT_IO_PCI_CONFIG_READ     19L /* PCI Config Read */
+#define PDC_PAT_IO_PCI_CONFIG_WRITE    20L /* PCI Config Write */
+#define PDC_PAT_IO_GET_NUM_IO_SLOTS    21L /* Get Number of I/O Bay Slots in 
+                                                         * Cabinet */
+#define PDC_PAT_IO_GET_LOC_IO_SLOTS    22L /* Get Physical Location of I/O */
+                                                    /* Bay Slots in Cabinet */
+#define PDC_PAT_IO_BAY_STATUS_INFO     28L /* Get I/O Bay Slot Status Info */
+#define PDC_PAT_IO_GET_PROC_VIEW        29L /* Get Processor view of IO address */
+#define PDC_PAT_IO_PROG_SBA_DIR_RANGE   30L /* Program directed range */
+
+/* PDC PAT MEM */
+
+#define PDC_PAT_MEM                    72L /* Manage memory page deallocation */
+#define PDC_PAT_MEM_PD_INFO            0L /* Return PDT info for PD       */
+#define PDC_PAT_MEM_PD_CLEAR           1L /* Clear PDT for PD             */
+#define PDC_PAT_MEM_PD_READ            2L /* Read PDT entries for PD      */
+#define PDC_PAT_MEM_PD_RESET           3L /* Reset clear bit for PD       */
+#define PDC_PAT_MEM_CELL_INFO          5L /* Return PDT info For Cell     */
+#define PDC_PAT_MEM_CELL_CLEAR         6L /* Clear PDT For Cell           */
+#define PDC_PAT_MEM_CELL_READ          7L /* Read PDT entries For Cell    */
+#define PDC_PAT_MEM_CELL_RESET         8L /* Reset clear bit For Cell     */
+#define PDC_PAT_MEM_SETGM              9L /* Set Golden Memory value      */
+#define PDC_PAT_MEM_ADD_PAGE           10L /* ADDs a page to the cell      */
+#define PDC_PAT_MEM_ADDRESS            11L /* Get Physical Location From   */
+                                                /* Memory Address               */
+#define PDC_PAT_MEM_GET_TXT_SIZE       12L /* Get Formatted Text Size   */
+#define PDC_PAT_MEM_GET_PD_TXT         13L /* Get PD Formatted Text     */
+#define PDC_PAT_MEM_GET_CELL_TXT       14L /* Get Cell Formatted Text   */
+#define PDC_PAT_MEM_RD_STATE_INFO      15L /* Read Mem Module State Info*/
+#define PDC_PAT_MEM_CLR_STATE_INFO     16L /*Clear Mem Module State Info*/
+#define PDC_PAT_MEM_CLEAN_RANGE        128L /*Clean Mem in specific range*/
+#define PDC_PAT_MEM_GET_TBL_SIZE       131L /* Get Memory Table Size     */
+#define PDC_PAT_MEM_GET_TBL            132L /* Get Memory Table          */
+
+/* PDC PAT NVOLATILE */
+
+#define PDC_PAT_NVOLATILE              73L /* Access Non-Volatile Memory */
+#define PDC_PAT_NVOLATILE_READ         0L /* Read Non-Volatile Memory   */
+#define PDC_PAT_NVOLATILE_WRITE        1L /* Write Non-Volatile Memory  */
+#define PDC_PAT_NVOLATILE_GET_SIZE     2L /* Return size of NVM         */
+#define PDC_PAT_NVOLATILE_VERIFY       3L /* Verify contents of NVM     */
+#define PDC_PAT_NVOLATILE_INIT         4L /* Initialize NVM             */
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+
+/*
+** PDC_PAT_CELL_GET_INFO return block
+*/
+typedef struct pdc_pat_cell_info_rtn_block {
+       unsigned long cpu_info;
+       unsigned long cell_info;
+       unsigned long cell_location;
+       unsigned long reo_location;
+       unsigned long mem_size;
+       unsigned long dimm_status;
+       unsigned long pdc_rev;
+       unsigned long fabric_info0;
+       unsigned long fabric_info1;
+       unsigned long fabric_info2;
+       unsigned long fabric_info3;
+       unsigned long reserved[21];
+} pdc_pat_cell_info_rtn_block_t;
+
+
+/* FIXME: mod[508] should really be a union of the various mod components */
+struct pdc_pat_cell_mod_maddr_block {  /* PDC_PAT_CELL_MODULE */
+       unsigned long cba;              /* function 0 configuration space address */
+       unsigned long mod_info;         /* module information */
+       unsigned long mod_location;     /* physical location of the module */
+       unsigned long mod_path;         /* module path (device path - layers) */
+       unsigned long mod[508];         /* PAT cell module components */
+} __attribute__((aligned(8))) ;
+
+typedef struct pdc_pat_cell_mod_maddr_block pdc_pat_cell_mod_maddr_block_t;
+
+
+extern int pdc_pat_cell_get_number(void *);
+extern int pdc_pat_cell_module(void *, unsigned long, unsigned long, unsigned long, void *);
+extern int pdc_pat_cell_num_to_loc(void *, unsigned long);
+
+/* Flag to indicate this is a PAT box...don't use this unless you
+** really have to...it might go away some day.
+*/
+#ifdef __LP64__
+extern int pdc_pat;     /* arch/parisc/kernel/inventory.c */
+#endif
+
+/********************************************************************
+* PDC_PAT_CELL[Return Cell Module] memaddr[0] conf_base_addr
+* ----------------------------------------------------------
+* Bit  0 to 51 - conf_base_addr
+* Bit 52 to 62 - reserved
+* Bit       63 - endianess bit
+********************************************************************/
+#define PAT_GET_CBA(value) ((value) & 0xfffffffffffff000UL)
+
+/********************************************************************
+* PDC_PAT_CELL[Return Cell Module] memaddr[1] mod_info
+* ----------------------------------------------------
+* Bit  0 to  7 - entity type
+*    0 = central agent,            1 = processor,
+*    2 = memory controller,        3 = system bus adapter,
+*    4 = local bus adapter,        5 = processor bus converter,
+*    6 = crossbar fabric connect,  7 = fabric interconnect,
+*    8 to 254 reserved,            255 = unknown.
+* Bit  8 to 15 - DVI
+* Bit 16 to 23 - IOC functions
+* Bit 24 to 39 - reserved
+* Bit 40 to 63 - mod_pages
+*    number of 4K pages a module occupies starting at conf_base_addr
+********************************************************************/
+#define PAT_GET_ENTITY(value)  (((value) >> 56) & 0xffUL)
+#define PAT_GET_DVI(value)     (((value) >> 48) & 0xffUL)
+#define PAT_GET_IOC(value)     (((value) >> 40) & 0xffUL)
+#define PAT_GET_MOD_PAGES(value)(((value) & 0xffffffUL)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* ! __PARISC_PATPDC_H */
diff --git a/include/asm-parisc/pgalloc.h b/include/asm-parisc/pgalloc.h
new file mode 100644 (file)
index 0000000..1d93652
--- /dev/null
@@ -0,0 +1,404 @@
+#ifndef _ASM_PGALLOC_H
+#define _ASM_PGALLOC_H
+
+/* The usual comment is "Caches aren't brain-dead on the <architecture>".
+ * Unfortunately, that doesn't apply to PA-RISC. */
+
+#include <asm/processor.h>
+#include <asm/fixmap.h>
+#include <linux/threads.h>
+
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+
+
+/* Internal use D/I cache flushing routines... */
+/* XXX: these functions must not access memory between f[di]ce instructions. */
+
+static inline void __flush_dcache_range(unsigned long start, unsigned long size)
+{
+#if 0
+       register unsigned long count = (size / L1_CACHE_BYTES);
+       register unsigned long loop = cache_info.dc_loop;
+       register unsigned long i, j;
+
+       if (size > 64 * 1024) {
+               /* Just punt and clear the whole damn thing */
+               flush_data_cache();
+               return;
+       }
+
+       for(i = 0; i <= count; i++, start += L1_CACHE_BYTES)
+               for(j = 0; j < loop; j++)
+                       fdce(start);
+#else
+       flush_data_cache();
+#endif
+}
+
+
+static inline void __flush_icache_range(unsigned long start, unsigned long size)
+{
+#if 0
+       register unsigned long count = (size / L1_CACHE_BYTES);
+       register unsigned long loop = cache_info.ic_loop;
+       register unsigned long i, j;
+
+       if (size > 64 * 1024) {
+               /* Just punt and clear the whole damn thing */
+               flush_instruction_cache();
+               return;
+       }
+
+       for(i = 0; i <= count; i++, start += L1_CACHE_BYTES)
+               for(j = 0; j < loop; j++)
+                       fice(start);
+#else
+       flush_instruction_cache();
+#endif
+}
+
+static inline void
+flush_kernel_dcache_range(unsigned long start, unsigned long size)
+{
+       register unsigned long end = start + size;
+       register unsigned long i;
+
+       start &= ~(L1_CACHE_BYTES - 1);
+       for (i = start; i < end; i += L1_CACHE_BYTES) {
+               kernel_fdc(i);
+       }
+       asm volatile("sync" : : );
+       asm volatile("syncdma" : : );
+}
+
+extern void __flush_page_to_ram(unsigned long address);
+
+#define flush_cache_all()                      flush_all_caches()
+#define flush_cache_mm(foo)                    flush_all_caches()
+
+#if 0
+/* This is how I think the cache flushing should be done -- mrw */
+extern inline void flush_cache_mm(struct mm_struct *mm) {
+       if (mm == current->mm) {
+               flush_user_dcache_range(mm->start_data, mm->end_data);
+               flush_user_icache_range(mm->start_code, mm->end_code);
+       } else {
+               flush_other_dcache_range(mm->context, mm->start_data, mm->end_data);
+               flush_other_icache_range(mm->context, mm->start_code, mm->end_code);
+       }
+}
+#endif
+
+#define flush_cache_range(mm, start, end) do { \
+                __flush_dcache_range(start, (unsigned long)end - (unsigned long)start); \
+                __flush_icache_range(start, (unsigned long)end - (unsigned long)start); \
+} while(0)
+
+#define flush_cache_page(vma, vmaddr) do { \
+                __flush_dcache_range(vmaddr, PAGE_SIZE); \
+                __flush_icache_range(vmaddr, PAGE_SIZE); \
+} while(0)
+
+#define flush_page_to_ram(page)        \
+        __flush_page_to_ram((unsigned long)page_address(page))
+
+#define flush_icache_range(start, end) \
+        __flush_icache_range(start, end - start)
+
+#define flush_icache_page(vma, page) \
+       __flush_icache_range(page_address(page), PAGE_SIZE)
+
+#define flush_dcache_page(page) \
+       __flush_dcache_range(page_address(page), PAGE_SIZE)
+
+/* TLB flushing routines.... */
+
+extern void flush_data_tlb(void);
+extern void flush_instruction_tlb(void);
+
+#define flush_tlb() do { \
+        flush_data_tlb(); \
+       flush_instruction_tlb(); \
+} while(0);
+
+#define flush_tlb_all()        flush_tlb()     /* XXX p[id]tlb */
+
+extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+}
+static inline void flush_instruction_tlb_range(unsigned long start,
+                                       unsigned long size)
+{
+#if 0
+       register unsigned long count = (size / PAGE_SIZE);
+       register unsigned long loop = cache_info.it_loop;
+       register unsigned long i, j;
+       
+       for(i = 0; i <= count; i++, start += PAGE_SIZE)
+               for(j = 0; j < loop; j++)
+                       pitlbe(start);
+#else
+       flush_instruction_tlb();
+#endif
+}
+
+static inline void flush_data_tlb_range(unsigned long start,
+                                       unsigned long size)
+{
+#if 0
+       register unsigned long count = (size / PAGE_SIZE);
+       register unsigned long loop = cache_info.dt_loop;
+       register unsigned long i, j;
+       
+       for(i = 0; i <= count; i++, start += PAGE_SIZE)
+               for(j = 0; j < loop; j++)
+                       pdtlbe(start);
+#else
+       flush_data_tlb();
+#endif
+}
+
+
+
+static inline void __flush_tlb_range(unsigned long space, unsigned long start,
+                      unsigned long size)
+{
+       unsigned long old_sr1;
+
+       if(!size)
+               return;
+
+       old_sr1 = mfsp(1);
+       mtsp(space, 1);
+       
+       flush_data_tlb_range(start, size);
+       flush_instruction_tlb_range(start, size);
+
+       mtsp(old_sr1, 1);
+}
+
+extern void __flush_tlb_space(unsigned long space);
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+#if 0
+       __flush_tlb_space(mm->context);
+#else
+       flush_tlb();
+#endif
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+       unsigned long addr)
+{
+       __flush_tlb_range(vma->vm_mm->context, addr, PAGE_SIZE);
+               
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+       unsigned long start, unsigned long end)
+{
+       __flush_tlb_range(mm->context, start, end - start);
+}
+
+/*
+ * NOTE: Many of the below macros use PT_NLEVELS because
+ *       it is convenient that PT_NLEVELS == LOG2(pte size in bytes),
+ *       i.e. we use 3 level page tables when we use 8 byte pte's
+ *       (for 64 bit) and 2 level page tables when we use 4 byte pte's
+ */
+
+#ifdef __LP64__
+#define PT_NLEVELS 3
+#define PT_INITIAL 4 /* Number of initial page tables */
+#else
+#define PT_NLEVELS 2
+#define PT_INITIAL 2 /* Number of initial page tables */
+#endif
+
+/* Definitions for 1st level */
+
+#define PGDIR_SHIFT  (PAGE_SHIFT + (PT_NLEVELS - 1)*(PAGE_SHIFT - PT_NLEVELS))
+#define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK     (~(PGDIR_SIZE-1))
+#define PTRS_PER_PGD    (1UL << (PAGE_SHIFT - PT_NLEVELS))
+#define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
+
+/* Definitions for 2nd level */
+
+#define PMD_SHIFT       (PAGE_SHIFT + (PAGE_SHIFT - PT_NLEVELS))
+#define PMD_SIZE       (1UL << PMD_SHIFT)
+#define PMD_MASK       (~(PMD_SIZE-1))
+#if PT_NLEVELS == 3
+#define PTRS_PER_PMD    (1UL << (PAGE_SHIFT - PT_NLEVELS))
+#else
+#define PTRS_PER_PMD    1
+#endif
+
+/* Definitions for 3rd level */
+
+#define PTRS_PER_PTE    (1UL << (PAGE_SHIFT - PT_NLEVELS))
+
+
+#define get_pgd_fast get_pgd_slow
+#define free_pgd_fast free_pgd_slow
+
+extern __inline__ pgd_t *get_pgd_slow(void)
+{
+       extern unsigned long gateway_pgd_offset;
+       extern unsigned long gateway_pgd_entry;
+       pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
+
+       if (ret) {
+           memset (ret, 0, PTRS_PER_PGD * sizeof(pgd_t));
+
+           /* Install HP-UX and Linux gateway page translations */
+
+           pgd_val(*(ret + gateway_pgd_offset)) = gateway_pgd_entry;
+       }
+       return ret;
+}
+
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+       free_page((unsigned long)pgd);
+}
+
+#if PT_NLEVELS == 3
+
+/* Three Level Page Table Support for pmd's */
+
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+       return NULL; /* la la */
+}
+
+#if 0
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+}
+#else
+#define free_pmd_fast free_pmd_slow
+#endif
+
+extern __inline__ pmd_t *get_pmd_slow(void)
+{
+       pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+
+       if (pmd)
+               clear_page(pmd);
+       return pmd;
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+       free_page((unsigned long)pmd);
+}
+
+extern void __bad_pgd(pgd_t *pgd);
+
+extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
+{
+       address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+
+       if (pgd_none(*pgd))
+               goto getnew;
+       if (pgd_bad(*pgd))
+               goto fix;
+       return (pmd_t *) pgd_page(*pgd) + address;
+getnew:
+{
+       pmd_t *page = get_pmd_fast();
+       
+       if (!page)
+               page = get_pmd_slow();
+       if (page) {
+               if (pgd_none(*pgd)) {
+                   pgd_val(*pgd) = _PAGE_TABLE + __pa((unsigned long)page);
+                   return page + address;
+               }
+               else
+                   free_pmd_fast(page);
+       }
+       else {
+               return NULL;
+       }
+}
+fix:
+       __bad_pgd(pgd);
+       return NULL;
+}
+
+#else
+
+/* Two Level Page Table Support for pmd's */
+
+extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+       return (pmd_t *) pgd;
+}
+
+extern inline void free_pmd_fast(pmd_t * pmd)
+{
+}
+
+#endif
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+       return NULL; /* la la */
+}
+
+#if 0
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+}
+#else
+#define free_pte_fast free_pte_slow
+#endif
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+       free_page((unsigned long)pte);
+}
+
+#define pmd_alloc_kernel       pmd_alloc
+#define pte_alloc_kernel       pte_alloc
+
+#define pte_free(pte)          free_pte_fast(pte)
+#define pmd_free(pmd)           free_pmd_fast(pmd)
+#define pgd_free(pgd)          free_pgd_fast(pgd)
+#define pgd_alloc()            get_pgd_fast()
+
+extern void __bad_pmd(pmd_t *pmd);
+
+extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+{
+       address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+
+       if (pmd_none(*pmd))
+               goto getnew;
+       if (pmd_bad(*pmd))
+               goto fix;
+       return (pte_t *) pmd_page(*pmd) + address;
+getnew:
+{
+       pte_t *page = get_pte_fast();
+       
+       if (!page)
+               return get_pte_slow(pmd, address);
+       pmd_val(*pmd) = _PAGE_TABLE + __pa((unsigned long)page);
+       return page + address;
+}
+fix:
+       __bad_pmd(pmd);
+       return NULL;
+}
+
+extern int do_check_pgt_cache(int, int);
+
+#endif
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
new file mode 100644 (file)
index 0000000..f4887a9
--- /dev/null
@@ -0,0 +1,338 @@
+#ifndef _PARISC_PGTABLE_H
+#define _PARISC_PGTABLE_H
+
+#ifndef __ASSEMBLY__
+#include <linux/config.h>
+/*
+ * we simulate an x86-style page table for the linux mm code
+ */
+
+#include <asm/processor.h>
+#include <asm/fixmap.h>
+#include <asm/cache.h>
+
+/* To make 53c7xx.c happy */
+
+#define IOMAP_FULL_CACHING     2               /* used for 'what' below */
+#define IOMAP_NOCACHE_SER      3
+
+extern void kernel_set_cachemode(unsigned long addr,
+                                   unsigned long size, int what);
+
+/*
+ * cache_clear() semantics: Clear any cache entries for the area in question,
+ * without writing back dirty entries first. This is useful if the data will
+ * be overwritten anyway, e.g. by DMA to memory. The range is defined by a
+ * _physical_ address.
+ */
+#define cache_clear(paddr, len)                        do { } while (0)
+/*
+ * cache_push() semantics: Write back any dirty cache data in the given area,
+ * and invalidate the range in the instruction cache. It needs not (but may)
+ * invalidate those entries also in the data cache. The range is defined by a
+ * _physical_ address.
+ */
+#define cache_push(paddr, len) \
+       do { \
+               unsigned long vaddr = phys_to_virt(paddr); \
+               flush_cache_range(&init_mm, vaddr, vaddr + len); \
+       } while(0)
+#define cache_push_v(vaddr, len) \
+                       flush_cache_range(&init_mm, vaddr, vaddr + len)
+
+/*
+ * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
+ * memory.  For the return value to be meaningful, ADDR must be >=
+ * PAGE_OFFSET.  This operation can be relatively expensive (e.g.,
+ * require a hash-, or multi-level tree-lookup or something of that
+ * sort) but it guarantees to return TRUE only if accessing the page
+ * at that address does not cause an error.  Note that there may be
+ * addresses for which kern_addr_valid() returns FALSE even though an
+ * access would not cause an error (e.g., this is typically true for
+ * memory mapped I/O regions.
+ *
+ * XXX Need to implement this for parisc.
+ */
+#define kern_addr_valid(addr)  (1)
+
+/* Certain architectures need to do special things when PTEs
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+#define set_pte(pteptr, pteval)                                 \
+        do{                                                     \
+                *(pteptr) = (pteval);                           \
+        } while(0)
+
+
+
+#endif /* !__ASSEMBLY__ */
+
+#define pte_ERROR(e) \
+       printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+       printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+       printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * pgd entries used up by user/kernel:
+ */
+
+#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+#define FIRST_USER_PGD_NR      0
+
+#ifndef __ASSEMBLY__
+extern  void *vmalloc_start;
+#define PCXL_DMA_MAP_SIZE   (8*1024*1024)
+#define VMALLOC_START   ((unsigned long)vmalloc_start)
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END    (FIXADDR_START)
+#endif
+
+#define _PAGE_READ     0x001   /* read access allowed */
+#define _PAGE_WRITE    0x002   /* write access allowed */
+#define _PAGE_EXEC     0x004   /* execute access allowed */
+#define _PAGE_GATEWAY  0x008   /* privilege promotion allowed */
+#define _PAGE_GATEWAY_BIT 28   /* _PAGE_GATEWAY & _PAGE_GATEWAY_BIT need */
+                               /* to agree. One could be defined in relation */
+                               /* to the other, but that's kind of ugly. */
+
+                               /* 0x010 reserved (B bit) */
+#define _PAGE_DIRTY    0x020   /* D: dirty */
+                               /* 0x040 reserved (T bit) */
+#define _PAGE_NO_CACHE  0x080   /* Software: Uncacheable */
+#define _PAGE_NO_CACHE_BIT 24   /* Needs to agree with _PAGE_NO_CACHE above */
+#define _PAGE_ACCESSED 0x100   /* R: page cache referenced */
+#define _PAGE_PRESENT   0x200   /* Software: pte contains a translation */
+#define _PAGE_PRESENT_BIT  22   /* Needs to agree with _PAGE_PRESENT above */
+#define _PAGE_USER      0x400   /* Software: User accessable page */
+#define _PAGE_USER_BIT     21   /* Needs to agree with _PAGE_USER above */
+                               /* 0x800 still available */
+
+#ifdef __ASSEMBLY__
+#define _PGB_(x)       (1 << (63 - (x)))
+#define __PAGE_O       _PGB_(13)
+#define __PAGE_U       _PGB_(12)
+#define __PAGE_T       _PGB_(2)
+#define __PAGE_D       _PGB_(3)
+#define __PAGE_B       _PGB_(4)
+#define __PAGE_P       _PGB_(14)
+#endif
+#define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE |  _PAGE_DIRTY | _PAGE_ACCESSED)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_KERNEL   (_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
+
+#ifndef __ASSEMBLY__
+
+#define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_ACCESSED)
+/* Others seem to make this executable, I don't know if that's correct
+   or not.  The stack is mapped this way though so this is necessary
+   in the short term - dhd@linuxcare.com, 2000-08-08 */
+#define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_ACCESSED)
+#define PAGE_WRITEONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITE | _PAGE_ACCESSED)
+#define PAGE_EXECREAD   __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_EXEC |_PAGE_ACCESSED)
+#define PAGE_COPY       PAGE_EXECREAD
+#define PAGE_RWX        __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC |_PAGE_ACCESSED)
+#define PAGE_KERNEL    __pgprot(_PAGE_KERNEL)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL_UNC        __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
+#define PAGE_GATEWAY    __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_GATEWAY| _PAGE_READ)
+
+
+/*
+ * We could have an execute only page using "gateway - promote to priv
+ * level 3", but that is kind of silly. So, the way things are defined
+ * now, we must always have read permission for pages with execute
+ * permission. For the fun of it we'll go ahead and support write only
+ * pages.
+ */
+
+        /*xwr*/
+#define __P000  PAGE_NONE
+#define __P001  PAGE_READONLY
+#define __P010  __P000 /* copy on write */
+#define __P011  __P001 /* copy on write */
+#define __P100  PAGE_EXECREAD
+#define __P101  PAGE_EXECREAD
+#define __P110  __P100 /* copy on write */
+#define __P111  __P101 /* copy on write */
+
+#define __S000  PAGE_NONE
+#define __S001  PAGE_READONLY
+#define __S010  PAGE_WRITEONLY
+#define __S011  PAGE_SHARED
+#define __S100  PAGE_EXECREAD
+#define __S101  PAGE_EXECREAD
+#define __S110  PAGE_RWX
+#define __S111  PAGE_RWX
+
+extern unsigned long swapper_pg_dir[]; /* declared in init_task.c */
+
+/* initial page tables for 0-8MB for kernel */
+
+extern unsigned long pg0[];
+
+/* zero page used for uninitialized stuff */
+
+extern unsigned long *empty_zero_page;
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#define pte_none(x)    (!pte_val(x))
+#define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
+#define pte_clear(xp)  do { pte_val(*(xp)) = 0; } while (0)
+#define pte_pagenr(x)  ((unsigned long)((pte_val(x) >> PAGE_SHIFT)))
+
+#define pmd_none(x)    (!pmd_val(x))
+#define pmd_bad(x)     ((pmd_val(x) & ~PAGE_MASK) != _PAGE_TABLE)
+#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
+#define pmd_clear(xp)  do { pmd_val(*(xp)) = 0; } while (0)
+
+
+
+#ifdef __LP64__
+#define pgd_page(pgd) ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
+/* For 64 bit we have three level tables */
+
+#define pgd_none(x)     (!pgd_val(x))
+#define pgd_bad(x)      ((pgd_val(x) & ~PAGE_MASK) != _PAGE_TABLE)
+#define pgd_present(x)  (pgd_val(x) & _PAGE_PRESENT)
+#define pgd_clear(xp)   do { pgd_val(*(xp)) = 0; } while (0)
+#else
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+extern inline int pgd_none(pgd_t pgd)          { return 0; }
+extern inline int pgd_bad(pgd_t pgd)           { return 0; }
+extern inline int pgd_present(pgd_t pgd)       { return 1; }
+extern inline void pgd_clear(pgd_t * pgdp)     { }
+#endif
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+extern inline int pte_read(pte_t pte)          { return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
+extern inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
+extern inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_WRITE; }
+
+extern inline pte_t pte_rdprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_READ; return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkold(pte_t pte)       { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_WRITE; return pte; }
+extern inline pte_t pte_mkread(pte_t pte)      { pte_val(pte) |= _PAGE_READ; return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) |= _PAGE_WRITE; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define __mk_pte(addr,pgprot) \
+({                                                                     \
+       pte_t __pte;                                                    \
+                                                                       \
+       pte_val(__pte) = ((addr)+pgprot_val(pgprot));                   \
+                                                                       \
+       __pte;                                                          \
+})
+
+#define mk_pte(page,pgprot) \
+({                                                                     \
+       pte_t __pte;                                                    \
+                                                                       \
+       pte_val(__pte) = ((page)-mem_map)*PAGE_SIZE +                   \
+                               pgprot_val(pgprot);                     \
+       __pte;                                                          \
+})
+
+/* This takes a physical page address that is used by the remapping functions */
+#define mk_pte_phys(physpage, pgprot) \
+({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+/*
+ * Permanent address of a page. Obviously must never be
+ * called on a highmem page.
+ */
+#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; })
+#define __page_address(page) ({ if (PageHighMem(page)) BUG(); PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT); })
+#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
+#define pte_page(x) (mem_map+pte_pagenr(x))
+
+#define pmd_page(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+
+/* to find an entry in a page-table-directory */
+#define pgd_offset(mm, address) \
+((mm)->pgd + ((address) >> PGDIR_SHIFT))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* Find an entry in the second-level page table.. */
+
+#ifdef __LP64__
+#define pmd_offset(dir,address) \
+((pmd_t *) pgd_page(*(dir)) + (((address)>>PMD_SHIFT) & (PTRS_PER_PMD-1)))
+#else
+#define pmd_offset(dir,addr) ((pmd_t *) dir)
+#endif
+
+/* Find an entry in the third-level page table.. */ 
+#define pte_offset(pmd, address) \
+((pte_t *) pmd_page(*(pmd)) + (((address)>>PAGE_SHIFT) & (PTRS_PER_PTE-1)))
+
+extern void paging_init (void);
+
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
+       unsigned long address, pte_t pte)
+{
+}
+
+/* Encode and de-code a swap entry */
+
+#define SWP_TYPE(x)                     ((x).val & 0x3f)
+#define SWP_OFFSET(x)                   ( (((x).val >> 6) &  0x7) | \
+                                         (((x).val >> 7) & ~0x7) )
+#define SWP_ENTRY(type, offset)         ((swp_entry_t) { (type) | \
+                                           ((offset &  0x7) << 6) | \
+                                           ((offset & ~0x7) << 7) })
+#define pte_to_swp_entry(pte)          ((swp_entry_t) { pte_val(pte) })
+#define swp_entry_to_pte(x)            ((pte_t) { (x).val })
+
+#define module_map     vmalloc
+#define module_unmap   vfree
+
+#include <asm-generic/pgtable.h>
+
+#endif /* !__ASSEMBLY__ */
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define PageSkip(page)         (0)
+
+#define io_remap_page_range remap_page_range
+
+#endif /* _PARISC_PAGE_H */
diff --git a/include/asm-parisc/poll.h b/include/asm-parisc/poll.h
new file mode 100644 (file)
index 0000000..55ebfcc
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __PARISC_POLL_H
+#define __PARISC_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN         0x0001
+#define POLLPRI                0x0002
+#define POLLOUT                0x0004
+#define POLLERR                0x0008
+#define POLLHUP                0x0010
+#define POLLNVAL       0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM     0x0040
+#define POLLRDBAND     0x0080
+#define POLLWRNORM     0x0100
+#define POLLWRBAND     0x0200
+#define POLLMSG                0x0400
+
+struct pollfd {
+       int fd;
+       short events;
+       short revents;
+};
+
+#endif
diff --git a/include/asm-parisc/posix_types.h b/include/asm-parisc/posix_types.h
new file mode 100644 (file)
index 0000000..58f2085
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef __ARCH_PARISC_POSIX_TYPES_H
+#define __ARCH_PARISC_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+typedef unsigned int           __kernel_dev_t;
+typedef unsigned long          __kernel_ino_t;
+typedef unsigned short         __kernel_mode_t;
+typedef unsigned short         __kernel_nlink_t;
+typedef long                   __kernel_off_t;
+typedef int                    __kernel_pid_t;
+typedef unsigned short         __kernel_ipc_pid_t;
+typedef unsigned int           __kernel_uid_t;
+typedef unsigned int           __kernel_gid_t;
+typedef int                    __kernel_suseconds_t;
+typedef int                    __kernel_clock_t;
+typedef int                    __kernel_daddr_t;
+/* Note these change from narrow to wide kernels */
+typedef unsigned long          __kernel_size_t;
+typedef long                   __kernel_ssize_t;
+typedef long                   __kernel_ptrdiff_t;
+typedef long                   __kernel_time_t;
+typedef char *                 __kernel_caddr_t;
+
+typedef unsigned short         __kernel_uid16_t;
+typedef unsigned short         __kernel_gid16_t;
+typedef unsigned int           __kernel_uid32_t;
+typedef unsigned int           __kernel_gid32_t;
+
+#ifdef __GNUC__
+typedef long long              __kernel_loff_t;
+typedef long long              __kernel_off64_t;
+typedef unsigned long long     __kernel_ino64_t;
+#endif
+
+typedef struct {
+#if defined(__KERNEL__) || defined(__USE_ALL)
+       int     val[2];
+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+       int     __val[2];
+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+} __kernel_fsid_t;
+
+#if defined(__KERNEL__) && defined(__LP64__)
+/* Now 32bit compatibility types */
+typedef unsigned int           __kernel_dev_t32;
+typedef unsigned int           __kernel_ino_t32;
+typedef unsigned short         __kernel_mode_t32;
+typedef unsigned short         __kernel_nlink_t32;
+typedef int                    __kernel_off_t32;
+typedef int                    __kernel_pid_t32;
+typedef unsigned short         __kernel_ipc_pid_t32;
+typedef unsigned int           __kernel_uid_t32;
+typedef unsigned int           __kernel_gid_t32;
+typedef unsigned int           __kernel_size_t32;
+typedef int                    __kernel_ssize_t32;
+typedef int                    __kernel_ptrdiff_t32;
+typedef int                    __kernel_time_t32;
+typedef int                    __kernel_suseconds_t32;
+typedef int                    __kernel_clock_t32;
+typedef int                    __kernel_daddr_t32;
+typedef unsigned int           __kernel_caddr_t32;
+#endif
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#undef __FD_SET
+static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
+{
+       unsigned long __tmp = __fd / __NFDBITS;
+       unsigned long __rem = __fd % __NFDBITS;
+       __fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
+}
+
+#undef __FD_CLR
+static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
+{
+       unsigned long __tmp = __fd / __NFDBITS;
+       unsigned long __rem = __fd % __NFDBITS;
+       __fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
+}
+
+#undef __FD_ISSET
+static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
+{ 
+       unsigned long __tmp = __fd / __NFDBITS;
+       unsigned long __rem = __fd % __NFDBITS;
+       return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
+}
+
+/*
+ * This will unroll the loop for the normal constant case (8 ints,
+ * for a 256-bit fd_set)
+ */
+#undef __FD_ZERO
+static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
+{
+       unsigned long *__tmp = __p->fds_bits;
+       int __i;
+
+       if (__builtin_constant_p(__FDSET_LONGS)) {
+               switch (__FDSET_LONGS) {
+               case 16:
+                       __tmp[ 0] = 0; __tmp[ 1] = 0;
+                       __tmp[ 2] = 0; __tmp[ 3] = 0;
+                       __tmp[ 4] = 0; __tmp[ 5] = 0;
+                       __tmp[ 6] = 0; __tmp[ 7] = 0;
+                       __tmp[ 8] = 0; __tmp[ 9] = 0;
+                       __tmp[10] = 0; __tmp[11] = 0;
+                       __tmp[12] = 0; __tmp[13] = 0;
+                       __tmp[14] = 0; __tmp[15] = 0;
+                       return;
+
+               case 8:
+                       __tmp[ 0] = 0; __tmp[ 1] = 0;
+                       __tmp[ 2] = 0; __tmp[ 3] = 0;
+                       __tmp[ 4] = 0; __tmp[ 5] = 0;
+                       __tmp[ 6] = 0; __tmp[ 7] = 0;
+                       return;
+
+               case 4:
+                       __tmp[ 0] = 0; __tmp[ 1] = 0;
+                       __tmp[ 2] = 0; __tmp[ 3] = 0;
+                       return;
+               }
+       }
+       __i = __FDSET_LONGS;
+       while (__i) {
+               __i--;
+               *__tmp = 0;
+               __tmp++;
+       }
+}
+
+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+
+#endif
diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h
new file mode 100644 (file)
index 0000000..4063662
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * include/asm-parisc/processor.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+#ifndef __ASM_PARISC_PROCESSOR_H
+#define __ASM_PARISC_PROCESSOR_H
+
+#ifndef __ASSEMBLY__
+#include <linux/threads.h>
+
+#include <asm/hardware.h>
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/ptrace.h>
+#include <asm/types.h>
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+
+/* We cannot use MFIA as it was added for PA2.0 - prumpf
+
+   At one point there were no "0f/0b" type local symbols in gas for
+   PA-RISC.  This is no longer true, but this still seems like the
+   nicest way to implement this. */
+
+#define current_text_addr() ({ void *pc; __asm__("\n\tblr 0,%0\n\tnop":"=r" (pc)); pc; })
+
+#define TASK_SIZE          (PAGE_OFFSET)
+#define TASK_UNMAPPED_BASE  (TASK_SIZE / 3)
+
+#ifndef __ASSEMBLY__
+
+/*
+** Data detected about CPUs at boot time which is the same for all CPU's.
+** HP boxes are SMP - ie identical processors.
+**
+** FIXME: some CPU rev info may be processor specific...
+*/
+struct system_cpuinfo_parisc {
+       unsigned int    cpu_count;
+       unsigned int    cpu_hz;
+       unsigned int    hversion;
+       unsigned int    sversion;
+       enum cpu_type   cpu_type;
+
+       struct {
+               struct pdc_model model;
+               struct pdc_model_cpuid /* ARGH */ versions;
+               struct pdc_model_cpuid cpuid;
+#if 0
+               struct pdc_model_caps caps;
+#endif
+               char   sys_model_name[81]; /* PDC-ROM returnes this model name */
+       } pdc;
+
+       char            *model_name;
+       char            *cpu_name;
+       char            *family_name;
+};
+
+
+/*
+** Per CPU data structure - ie varies per CPU.
+*/
+struct cpuinfo_parisc {
+       unsigned cpuid;
+
+       struct irq_region *region;
+
+       unsigned long it_value; /* Interval Timer value at last timer interrupt */
+       unsigned long it_delta; /* Interval Timer delta (tic_10ms / HZ * 100) */
+
+       unsigned long hpa;      /* Host Physical address */
+       unsigned long txn_addr; /* External Interrupt Register or id_eid */
+
+       unsigned long bh_count;         /* number of times bh was invoked */
+       unsigned long irq_count;        /* number of IRQ's since boot */
+       unsigned long irq_max_cr16;     /* longest time to handle a single IRQ */
+};
+
+extern struct system_cpuinfo_parisc boot_cpu_data;
+extern struct cpuinfo_parisc cpu_data[NR_CPUS];
+#define current_cpu_data cpu_data[smp_processor_id()]
+
+extern void identify_cpu(struct cpuinfo_parisc *);
+
+#define EISA_bus 0 /* we don't have ISA support yet */
+#define EISA_bus__is_a_macro /* for versions in ksyms.c */
+#define MCA_bus 0
+#define MCA_bus__is_a_macro /* for versions in ksyms.c */
+
+typedef struct {
+       int seg;  
+} mm_segment_t;
+
+struct thread_struct {
+       struct pt_regs regs;
+       unsigned long  pg_tables;
+       unsigned long  flags;
+}; 
+
+/* Thread struct flags. */
+#define PARISC_KERNEL_DEATH    (1UL << 31)     /* see die_if_kernel()... */
+
+#define INIT_MMAP { &init_mm, 0, 0, NULL, PAGE_SHARED, \
+                   VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
+
+#define INIT_THREAD { {                        \
+       { 0, 0, 0, 0, 0, 0, 0, 0,       \
+         0, 0, 0, 0, 0, 0, 0, 0,       \
+         0, 0, 0, 0, 0, 0, 0, 0,       \
+         0, 0, 0, 0, 0, 0, 0, 0 },     \
+       { 0, 0, 0, 0, 0, 0, 0, 0,       \
+         0, 0, 0, 0, 0, 0, 0, 0,       \
+         0, 0, 0, 0, 0, 0, 0, 0,       \
+         0, 0, 0, 0, 0, 0, 0, 0 },     \
+       { 0, 0, 0, 0, 0, 0, 0, 0 },     \
+       { 0, 0}, { 0, 0}, 0, 0, 0, 0    \
+       }, __pa((unsigned long) swapper_pg_dir) }
+
+/*
+ * Return saved PC of a blocked thread.  This is used by ps mostly.
+ */
+
+extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+{
+       return 0xabcdef;
+}
+
+/*
+ * Start user thread in another space.
+ *
+ * Note that we set both the iaoq and r31 to the new pc. When
+ * the kernel initially calls execve it will return through an
+ * rfi path that will use the values in the iaoq. The execve
+ * syscall path will return through the gateway page, and
+ * that uses r31 to branch to.
+ *
+ * For ELF we clear r23, because the dynamic linker uses it to pass
+ * the address of the finalizer function.
+ *
+ * We also initialize sr3 to an illegal value (illegal for our
+ * implementation, not for the architecture).
+ */
+
+/* The ELF abi wants things done a "wee bit" differently than
+ * som does.  Supporting this behavior here avoids
+ * having our own version of create_elf_tables.
+ *
+ * Oh, and yes, that is not a typo, we are really passing argc in r25
+ * and argv in r24 (rather than r26 and r25).  This is because that's
+ * where __libc_start_main wants them.
+ *
+ * Duplicated from dl-machine.h for the benefit of readers:
+ *
+ *  Our initial stack layout is rather different from everyone else's
+ *  due to the unique PA-RISC ABI.  As far as I know it looks like
+ *  this:
+
+   -----------------------------------  (user startup code creates this frame)
+   |         32 bytes of magic       |
+   |---------------------------------|
+   | 32 bytes argument/sp save area  |
+   |---------------------------------|  ((current->mm->env_end) + 63 & ~63)
+   |         N bytes of slack        |
+   |---------------------------------|
+   |      envvar and arg strings     |
+   |---------------------------------|
+   |       ELF auxiliary info       |
+   |         (up to 28 words)        |
+   |---------------------------------|
+   |  Environment variable pointers  |
+   |         upwards to NULL        |
+   |---------------------------------|
+   |        Argument pointers        |
+   |         upwards to NULL        |
+   |---------------------------------|
+   |          argc (1 word)          |
+   -----------------------------------
+
+ *  The pleasant part of this is that if we need to skip arguments we
+ *  can just decrement argc and move argv, because the stack pointer
+ *  is utterly unrelated to the location of the environment and
+ *  argument vectors.
+ *
+ * Note that the S/390 people took the easy way out and hacked their
+ * GCC to make the stack grow downwards.  */
+
+#define start_thread_som(regs, new_pc, new_sp) do {            \
+       unsigned long *sp = (unsigned long *)new_sp;    \
+       __u32 spaceid = (__u32)current->mm->context;    \
+       unsigned long pc = (unsigned long)new_pc;       \
+       /* offset pc for priv. level */                 \
+       pc |= 3;                                        \
+                                                       \
+       set_fs(USER_DS);                                \
+       regs->iasq[0] = spaceid;                        \
+       regs->iasq[1] = spaceid;                        \
+       regs->iaoq[0] = pc;                             \
+       regs->iaoq[1] = pc;                             \
+       regs->sr[2] = LINUX_GATEWAY_SPACE;              \
+       regs->sr[3] = 0xffff;                           \
+       regs->sr[4] = spaceid;                          \
+       regs->sr[5] = spaceid;                          \
+       regs->sr[6] = spaceid;                          \
+       regs->sr[7] = spaceid;                          \
+       regs->gr[ 0] = USER_INIT_PSW;                   \
+       regs->gr[30] = ((new_sp)+63)&~63;               \
+       regs->gr[31] = pc;                              \
+                                                       \
+       get_user(regs->gr[26],&sp[0]);                  \
+       get_user(regs->gr[25],&sp[-1]);                 \
+       get_user(regs->gr[24],&sp[-2]);                 \
+       get_user(regs->gr[23],&sp[-3]);                 \
+                                                       \
+       regs->cr30 = (u32) current;                     \
+} while(0)
+
+
+#define start_thread(regs, new_pc, new_sp) do {                \
+       unsigned long *sp = (unsigned long *)new_sp;    \
+       __u32 spaceid = (__u32)current->mm->context;    \
+        unsigned long pc = (unsigned long)new_pc;       \
+        /* offset pc for priv. level */                 \
+        pc |= 3;                                        \
+                                                       \
+                                                       \
+       set_fs(USER_DS);                                \
+       regs->iasq[0] = spaceid;                        \
+       regs->iasq[1] = spaceid;                        \
+       regs->iaoq[0] = pc;                             \
+       regs->iaoq[1] = pc;                             \
+       regs->sr[2] = LINUX_GATEWAY_SPACE;              \
+       regs->sr[3] = 0xffff;                           \
+       regs->sr[4] = spaceid;                          \
+       regs->sr[5] = spaceid;                          \
+       regs->sr[6] = spaceid;                          \
+       regs->sr[7] = spaceid;                          \
+       regs->gr[ 0] = USER_INIT_PSW;                   \
+       regs->fr[ 0] = 0LL;                             \
+       regs->fr[ 1] = 0LL;                             \
+       regs->fr[ 2] = 0LL;                             \
+       regs->fr[ 3] = 0LL;                             \
+       regs->gr[30] = ((current->mm->env_end)+63)&~63; \
+       regs->gr[31] = pc;                              \
+                                                       \
+       get_user(regs->gr[25],&sp[0]);                  \
+       regs->gr[24] = (unsigned long) &sp[1];          \
+       regs->gr[23] = 0;                               \
+                                                       \
+       regs->cr30 = (u32) current;                     \
+} while(0)
+
+#ifdef __LP64__
+
+/*
+ * For 64 bit kernels we need a version of start thread for 32 bit
+ * elf files.
+ *
+ * FIXME: It should be possible to not duplicate the above code
+ *        by playing games with concatenation to form both
+ *        macros at compile time. The only difference between
+ *        this macro and the above is the name and the types
+ *        for sp and pc.
+ */
+
+#define start_thread32(regs, new_pc, new_sp) do {         \
+       __u32 *sp = (__u32 *)new_sp;                    \
+       __u32 spaceid = (__u32)current->mm->context;    \
+       __u32 pc = (__u32)new_pc;                       \
+        /* offset pc for priv. level */                 \
+        pc |= 3;                                        \
+                                                       \
+       set_fs(USER_DS);                                \
+       regs->iasq[0] = spaceid;                        \
+       regs->iasq[1] = spaceid;                        \
+       regs->iaoq[0] = pc;                             \
+       regs->iaoq[1] = pc;                             \
+       regs->sr[2] = LINUX_GATEWAY_SPACE;              \
+       regs->sr[3] = 0xffff;                           \
+       regs->sr[4] = spaceid;                          \
+       regs->sr[5] = spaceid;                          \
+       regs->sr[6] = spaceid;                          \
+       regs->sr[7] = spaceid;                          \
+       regs->gr[ 0] = USER_INIT_PSW;                   \
+       regs->fr[ 0] = 0LL;                             \
+       regs->fr[ 1] = 0LL;                             \
+       regs->fr[ 2] = 0LL;                             \
+       regs->fr[ 3] = 0LL;                             \
+       regs->gr[30] = ((current->mm->env_end)+63)&~63; \
+       regs->gr[31] = pc;                              \
+                                                       \
+       get_user(regs->gr[25],&sp[0]);                  \
+       regs->gr[24] = (unsigned long) &sp[1];          \
+       regs->gr[23] = 0;                               \
+                                                       \
+       regs->cr30 = (u32) current;                     \
+} while(0)
+
+#endif
+
+struct task_struct;
+
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+#define copy_segments(tsk, mm) do { } while (0)
+#define release_segments(mm)   do { } while (0)
+#define forget_segments()      do { } while (0)
+
+extern inline unsigned long get_wchan(struct task_struct *p)
+{
+       return 0xdeadbeef; /* XXX */
+}
+
+#define KSTK_EIP(tsk)  (0xdeadbeef)
+#define KSTK_ESP(tsk)  (0xdeadbeef)
+
+/* Be sure to hunt all references to this down when you change the size of
+ * the kernel stack */
+
+#endif /* __ASSEMBLY__ */
+
+#define THREAD_SIZE    (4*PAGE_SIZE)
+
+#define alloc_task_struct() \
+       ((struct task_struct *) __get_free_pages(GFP_KERNEL,2))
+#define free_task_struct(p)     free_pages((unsigned long)(p),2)
+#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
+
+#define init_task (init_task_union.task) 
+#define init_stack (init_task_union.stack)
+
+
+#endif /* __ASM_PARISC_PROCESSOR_H */
diff --git a/include/asm-parisc/psw.h b/include/asm-parisc/psw.h
new file mode 100644 (file)
index 0000000..5d425e4
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _PARISC_PSW_H
+#define        PSW_I   0x00000001
+#define        PSW_D   0x00000002
+#define        PSW_P   0x00000004
+#define        PSW_Q   0x00000008
+
+#define        PSW_R   0x00000010
+#define        PSW_F   0x00000020
+#define        PSW_G   0x00000040      /* PA1.x only */
+#define PSW_O  0x00000080      /* PA2.0 only */
+
+#define        PSW_M   0x00010000
+#define        PSW_V   0x00020000
+#define        PSW_C   0x00040000
+#define        PSW_B   0x00080000
+
+#define        PSW_X   0x00100000
+#define        PSW_N   0x00200000
+#define        PSW_L   0x00400000
+#define        PSW_H   0x00800000
+
+#define        PSW_T   0x01000000
+#define        PSW_S   0x02000000
+#define        PSW_E   0x04000000
+#define PSW_W  0x08000000      /* PA2.0 only */
+
+#define        PSW_Z   0x40000000      /* PA1.x only */
+#define        PSW_Y   0x80000000      /* PA1.x only */
+
+/* PSW bits to be used with ssm/rsm */
+#define PSW_SM_I        0x1
+#define PSW_SM_D        0x2
+#define PSW_SM_P        0x4
+#define PSW_SM_Q        0x8
+#define PSW_SM_R        0x10
+#define PSW_SM_F        0x20
+#define PSW_SM_G        0x40
+#define PSW_SM_O        0x80
+#define PSW_SM_E        0x100
+#define PSW_SM_W        0x200
+
+#ifdef __LP64__
+#  define USER_PSW     (PSW_C | PSW_D | PSW_Q | PSW_I)
+#  define USER_INIT_PSW        (PSW_C | PSW_D | PSW_Q | PSW_I | PSW_N)
+#  define KERNEL_PSW   (PSW_C | PSW_D | PSW_Q | PSW_W)
+#  define PDC_PSW      (PSW_Q | PSW_W)
+#else
+#  define USER_PSW     (PSW_C | PSW_D | PSW_Q | PSW_I | PSW_P)
+#  define USER_INIT_PSW        (PSW_C | PSW_D | PSW_Q | PSW_I | PSW_N)
+#  define KERNEL_PSW   (PSW_C | PSW_D | PSW_Q)
+#  define PDC_PSW      (PSW_Q)
+#endif
+
+#endif
diff --git a/include/asm-parisc/ptrace.h b/include/asm-parisc/ptrace.h
new file mode 100644 (file)
index 0000000..81ea038
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _PARISC_PTRACE_H
+#define _PARISC_PTRACE_H
+
+/* written by Philipp Rumpf, Copyright (C) 1999 SuSE GmbH Nuernberg
+** Copyright (C) 2000 Grant Grundler, Hewlett-Packard
+*/
+
+#include <linux/types.h>
+
+/* This struct defines the way the registers are stored on the 
+   stack during a system call. */
+
+struct pt_regs {
+       unsigned long gr[32];   /* PSW is in gr[0] */
+       __u64 fr[32];
+       unsigned long sr[ 8];
+       unsigned long iasq[2];
+       unsigned long iaoq[2];
+       unsigned long cr24;
+       unsigned long cr25;
+       unsigned long cr26;
+       unsigned long cr27;
+       unsigned long cr30;
+       unsigned long orig_r28;
+       unsigned long ksp;
+       unsigned long kpc;
+       unsigned long sar;      /* CR11 */
+       unsigned long iir;      /* CR19 */
+       unsigned long isr;      /* CR20 */
+       unsigned long ior;      /* CR21 */
+       unsigned long ipsw;     /* CR22 */
+       unsigned long cr_pid[4]; /* CR8,9,12,13 */
+};
+
+#define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS))
+/*
+ * The numbers chosen here are somewhat arbitrary but absolutely MUST
+ * not overlap with any of the number assigned in <linux/ptrace.h>.
+ *
+ * These ones are taken from IA-64 on the assumption that theirs are
+ * the most correct (and we also want to support PTRACE_SINGLEBLOCK
+ * since we have taken branch traps too)
+ */
+#define PTRACE_SINGLEBLOCK     12      /* resume execution until next branch */
+#define PTRACE_GETSIGINFO      13      /* get child's siginfo structure */
+#define PTRACE_SETSIGINFO      14      /* set child's siginfo structure */
+
+#ifdef __KERNEL__
+
+/* XXX should we use iaoq[1] or iaoq[0] ? */
+#define user_mode(regs)                        (((regs)->iaoq[0] &  3) ? 1 : 0)
+#define instruction_pointer(regs)      ((regs)->iaoq[0] & ~3)
+extern void show_regs(struct pt_regs *);
+#endif
+
+#endif
diff --git a/include/asm-parisc/real.h b/include/asm-parisc/real.h
new file mode 100644 (file)
index 0000000..82acb25
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef _PARISC_REAL_H
+#define _PARISC_REAL_H
+
+
+#endif
diff --git a/include/asm-parisc/resource.h b/include/asm-parisc/resource.h
new file mode 100644 (file)
index 0000000..f908884
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _ASM_PARISC_RESOURCE_H
+#define _ASM_PARISC_RESOURCE_H
+
+/*
+ * Resource limits
+ */
+
+#define RLIMIT_CPU     0               /* CPU time in ms */
+#define RLIMIT_FSIZE   1               /* Maximum filesize */
+#define RLIMIT_DATA    2               /* max data size */
+#define RLIMIT_STACK   3               /* max stack size */
+#define RLIMIT_CORE    4               /* max core file size */
+#define RLIMIT_RSS     5               /* max resident set size */
+#define RLIMIT_NPROC   6               /* max number of processes */
+#define RLIMIT_NOFILE  7               /* max number of open files */
+#define RLIMIT_MEMLOCK 8               /* max locked-in-memory address space */
+#define RLIMIT_AS      9               /* address space limit */
+#define RLIMIT_LOCKS   10              /* maximum file locks held */
+
+#define RLIM_NLIMITS   11
+
+/*
+ * SuS says limits have to be unsigned.
+ * Which makes a ton more sense anyway.
+ */
+#define RLIM_INFINITY   (~0UL)
+
+#ifdef __KERNEL__
+
+#define INIT_RLIMITS                                   \
+{                                                      \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       {      _STK_LIM, 10 * _STK_LIM },               \
+       {             0, RLIM_INFINITY },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       {             0,             0 },               \
+       {      INR_OPEN,     INR_OPEN  },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+}
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/include/asm-parisc/runway.h b/include/asm-parisc/runway.h
new file mode 100644 (file)
index 0000000..a1dea78
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef ASM_PARISC_RUNWAY_H
+#define ASM_PARISC_RUNWAY_H
+#ifdef __KERNEL__
+
+/* declared in arch/parisc/kernel/setup.c */
+extern struct proc_dir_entry * proc_runway_root;
+
+#endif /* __KERNEL__ */
+#endif /* ASM_PARISC_RUNWAY_H */
diff --git a/include/asm-parisc/scatterlist.h b/include/asm-parisc/scatterlist.h
new file mode 100644 (file)
index 0000000..3ef9a11
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _ASM_PARISC_SCATTERLIST_H
+#define _ASM_PARISC_SCATTERLIST_H
+
+struct scatterlist {
+       char *  address;    /* Location data is to be transferred to */
+       char * alt_address; /* Location of actual if address is a 
+                            * dma indirect buffer.  NULL otherwise */
+       unsigned int length;
+
+       /* an IOVA can be 64-bits on some PA-Risc platforms. */
+       dma_addr_t iova;        /* I/O Virtual Address */
+       __u32      iova_length; /* bytes mapped */
+};
+
+#define sg_dma_address(sg) ((sg)->iova)
+#define sg_dma_len(sg)     ((sg)->iova_length)
+
+#define ISA_DMA_THRESHOLD (~0UL)
+
+#endif /* _ASM_PARISC_SCATTERLIST_H */
diff --git a/include/asm-parisc/segment.h b/include/asm-parisc/segment.h
new file mode 100644 (file)
index 0000000..26794dd
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __PARISC_SEGMENT_H
+#define __PARISC_SEGMENT_H
+
+/* Only here because we have some old header files that expect it.. */
+
+#endif
diff --git a/include/asm-parisc/semaphore-helper.h b/include/asm-parisc/semaphore-helper.h
new file mode 100644 (file)
index 0000000..387f7c1
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef _ASM_PARISC_SEMAPHORE_HELPER_H
+#define _ASM_PARISC_SEMAPHORE_HELPER_H
+
+/*
+ * SMP- and interrupt-safe semaphores helper functions.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ * (C) Copyright 1999 Andrea Arcangeli
+ */
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ *
+ * This is trivially done with load_locked/store_cond,
+ * which we have.  Let the rest of the losers suck eggs.
+ */
+static __inline__ void wake_one_more(struct semaphore * sem)
+{
+       atomic_inc((atomic_t *)&sem->waking);
+}
+
+static __inline__ int waking_non_zero(struct semaphore *sem)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       if (sem->waking > 0) {
+               sem->waking--;
+               ret = 1;
+       }
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+       return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ *     1       got the lock
+ *     0       go to sleep
+ *     -EINTR  interrupted
+ *
+ * We must undo the sem->count down_interruptible() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+static __inline__ int waking_non_zero_interruptible(struct semaphore *sem,
+                                               struct task_struct *tsk)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       if (sem->waking > 0) {
+               sem->waking--;
+               ret = 1;
+       } else if (signal_pending(tsk)) {
+               atomic_inc(&sem->count);
+               ret = -EINTR;
+       }
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+       return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ *     1       failed to lock
+ *     0       got the lock
+ *
+ * We must undo the sem->count down_trylock() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
+{
+       unsigned long flags;
+       int ret = 1;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       if (sem->waking <= 0)
+               atomic_inc(&sem->count);
+       else {
+               sem->waking--;
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+       return ret;
+}
+
+#endif /* _ASM_PARISC_SEMAPHORE_HELPER_H */
diff --git a/include/asm-parisc/semaphore.h b/include/asm-parisc/semaphore.h
new file mode 100644 (file)
index 0000000..12deca8
--- /dev/null
@@ -0,0 +1,301 @@
+#ifndef _ASM_PARISC_SEMAPHORE_H
+#define _ASM_PARISC_SEMAPHORE_H
+
+#include <linux/linkage.h>
+
+/*
+ * SMP- and interrupt-safe semaphores.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * SuperH verison by Niibe Yutaka
+ *
+ */
+
+/* if you're going to use out-of-line slowpaths, use .section .lock.text,
+ * not .text.lock or the -ffunction-sections monster will eat you alive
+ */
+
+#include <linux/spinlock.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+
+struct semaphore {
+       atomic_t count;
+       int waking;
+       wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+       long __magic;
+#endif
+};
+
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+               , (long)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+       __SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+       __SEMAPHORE_INITIALIZER(name,1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+       struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+extern inline void sema_init (struct semaphore *sem, int val)
+{
+/*
+ *     *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
+ *
+ * i'd rather use the more flexible initialization above, but sadly
+ * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
+ */
+       atomic_set(&sem->count, val);
+       sem->waking = 0;
+       init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+       sem->__magic = (long)&sem->__magic;
+#endif
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+       sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+       sema_init(sem, 0);
+}
+
+asmlinkage void __down_failed(void /* special register calling convention */);
+asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
+asmlinkage void __up_wakeup(void /* special register calling convention */);
+
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int  __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
+
+extern spinlock_t semaphore_wake_lock;
+
+extern __inline__ void down(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+
+       if (atomic_dec_return(&sem->count) < 0)
+               __down(sem);
+}
+
+extern __inline__ int down_interruptible(struct semaphore * sem)
+{
+       int ret = 0;
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+
+       if (atomic_dec_return(&sem->count) < 0)
+               ret = __down_interruptible(sem);
+       return ret;
+}
+
+extern __inline__ int down_trylock(struct semaphore * sem)
+{
+       int ret = 0;
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+
+       if (atomic_dec_return(&sem->count) < 0)
+               ret = __down_trylock(sem);
+       return ret;
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ */
+extern __inline__ void up(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+       if (atomic_inc_return(&sem->count) <= 0)
+               __up(sem);
+}
+
+/* rw mutexes (should that be mutices? =) -- throw rw
+ * spinlocks and semaphores together, and this is what we
+ * end up with...
+ *
+ * The lock is initialized to BIAS.  This way, a writer
+ * subtracts BIAS ands gets 0 for the case of an uncontended
+ * lock.  Readers decrement by 1 and see a positive value
+ * when uncontended, negative if there are writers waiting
+ * (in which case it goes to sleep).
+ *
+ * The value 0x01000000 supports up to 128 processors and
+ * lots of processes.  BIAS must be chosen such that subl'ing
+ * BIAS once per CPU will result in the long remaining
+ * negative.
+ *
+ * In terms of fairness, this should result in the lock
+ * flopping back and forth between readers and writers
+ * under heavy use.
+ *
+ *              -ben
+ */
+struct rw_semaphore {
+        atomic_t                count;
+        volatile unsigned char  write_bias_granted;
+        volatile unsigned char  read_bias_granted;
+        volatile unsigned char  pad1;
+        volatile unsigned char  pad2;
+        wait_queue_head_t       wait;
+        wait_queue_head_t       write_bias_wait;
+#if WAITQUEUE_DEBUG
+        long                    __magic;
+        atomic_t                readers;
+        atomic_t                writers;
+#endif
+};
+
+#if WAITQUEUE_DEBUG
+#define __RWSEM_DEBUG_INIT      , ATOMIC_INIT(0), ATOMIC_INIT(0)
+#else
+#define __RWSEM_DEBUG_INIT      /* */
+#endif
+
+#define RW_LOCK_BIAS 0x01000000
+
+#define __RWSEM_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
+        __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
+        __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
+
+#define __DECLARE_RWSEM_GENERIC(name,count) \
+        struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
+
+#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
+#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
+
+extern inline void init_rwsem(struct rw_semaphore *sem)
+{
+        atomic_set(&sem->count, RW_LOCK_BIAS);
+        sem->read_bias_granted = 0;
+        sem->write_bias_granted = 0;
+        init_waitqueue_head(&sem->wait);
+        init_waitqueue_head(&sem->write_bias_wait);
+#if WAITQUEUE_DEBUG
+        sem->__magic = (long)&sem->__magic;
+        atomic_set(&sem->readers, 0);
+        atomic_set(&sem->writers, 0);
+#endif
+}
+
+#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME
+extern struct rw_semaphore *__build_read_lock(struct rw_semaphore *sem, const char *what);
+extern struct rw_semaphore *__build_write_lock(struct rw_semaphore *sem, const char *what);
+#endif
+
+/* we use FASTCALL convention for the helpers */
+extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem));
+
+extern inline void down_read(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+        if (sem->__magic != (long)&sem->__magic)
+                BUG();
+#endif
+#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME
+        __build_read_lock(sem, "__down_read_failed");
+#endif
+#if WAITQUEUE_DEBUG
+        if (sem->write_bias_granted)
+                BUG();
+        if (atomic_read(&sem->writers))
+                BUG();
+        atomic_inc(&sem->readers);
+#endif
+}
+
+extern inline void down_write(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+        if (sem->__magic != (long)&sem->__magic)
+                BUG();
+#endif
+#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME
+        __build_write_lock(sem, "__down_write_failed");
+#endif
+#if WAITQUEUE_DEBUG
+        if (atomic_read(&sem->writers))
+                BUG();
+        if (atomic_read(&sem->readers))
+                BUG();
+        if (sem->read_bias_granted)
+                BUG();
+        if (sem->write_bias_granted)
+                BUG();
+        atomic_inc(&sem->writers);
+#endif
+}
+
+/* When a reader does a release, the only significant
+ * case is when there was a writer waiting, and we've
+ * bumped the count to 0: we must wake the writer up.
+ */
+extern inline void __up_read(struct rw_semaphore *sem)
+{
+}
+
+/* releasing the writer is easy -- just release it and
+ * wake up any sleepers.
+ */
+extern inline void __up_write(struct rw_semaphore *sem)
+{
+}
+
+extern inline void up_read(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+        if (sem->write_bias_granted)
+                BUG();
+        if (atomic_read(&sem->writers))
+                BUG();
+        atomic_dec(&sem->readers);
+#endif
+        __up_read(sem);
+}
+
+extern inline void up_write(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+        if (sem->read_bias_granted)
+                BUG();
+        if (sem->write_bias_granted)
+                BUG();
+        if (atomic_read(&sem->readers))
+                BUG();
+        if (atomic_read(&sem->writers) != 1)
+                BUG();
+        atomic_dec(&sem->writers);
+#endif
+        __up_write(sem);
+}
+
+#endif /* _ASM_PARISC_SEMAPHORE_H */
diff --git a/include/asm-parisc/sembuf.h b/include/asm-parisc/sembuf.h
new file mode 100644 (file)
index 0000000..25f3ef8
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _PARISC_SEMBUF_H
+#define _PARISC_SEMBUF_H
+
+/* 
+ * The semid64_ds structure for parisc architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+       struct ipc64_perm sem_perm;             /* permissions .. see ipc.h */
+       unsigned int    __pad1;
+       __kernel_time_t sem_otime;              /* last semop time */
+       unsigned int    __pad2;
+       __kernel_time_t sem_ctime;              /* last change time */
+       unsigned int    sem_nsems;              /* no. of semaphores in array */
+       unsigned int    __unused1;
+       unsigned int    __unused2;
+};
+
+#endif /* _PARISC_SEMBUF_H */
diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h
new file mode 100644 (file)
index 0000000..a9cef8e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * include/asm-parisc/serial.h
+ */
+
+#include <linux/config.h>
+#include <asm/gsc.h>
+
+/*
+ * This assumes you have a 7.272727 MHz clock for your UART.
+ * The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock
+ * Clarified: 7.2727MHz on LASI. Not yet clarified for DINO
+ */
+
+#define LASI_BASE_BAUD ( 7272727 / 16 )
+#define BASE_BAUD  LASI_BASE_BAUD
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#endif
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define FOURPORT_FLAGS ASYNC_FOURPORT
+#define ACCENT_FLAGS 0
+#define BOCA_FLAGS 0
+#define HUB6_FLAGS 0
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  4
+#endif
+       
+/*
+ *     The base is relative to the LASI base. We can fix that
+ *     up later. We could also virtually map LASI so that we get
+ *     nice constants all over our kernel...
+ */
+#define STD_SERIAL_PORT_DEFNS                  \
+       /* UART CLK   PORT IRQ     FLAGS        */                      \
+       { 0, LASI_BASE_BAUD, -1, 4, ASYNC_SKIP_TEST, 0, PORT_UNKNOWN,}, /* ttyS0 */
+
+#define SERIAL_PORT_DFNS               \
+       STD_SERIAL_PORT_DEFNS
+
diff --git a/include/asm-parisc/setup.h b/include/asm-parisc/setup.h
new file mode 100644 (file)
index 0000000..ae25cc4
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ *     Just a place holder. We don't want to have to test x86 before
+ *     we include stuff
+ */
+
+#ifndef _i386_SETUP_H
+#define _i386_SETUP_H
+
+
+#endif /* _i386_SETUP_H */
diff --git a/include/asm-parisc/shmbuf.h b/include/asm-parisc/shmbuf.h
new file mode 100644 (file)
index 0000000..ea45e96
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _PARISC_SHMBUF_H
+#define _PARISC_SHMBUF_H
+
+/* 
+ * The shmid64_ds structure for parisc architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+       struct ipc64_perm       shm_perm;       /* operation perms */
+       unsigned int            __pad1;
+       __kernel_time_t         shm_atime;      /* last attach time */
+       unsigned int            __pad2;
+       __kernel_time_t         shm_dtime;      /* last detach time */
+       unsigned int            __pad3;
+       __kernel_time_t         shm_ctime;      /* last change time */
+       size_t                  shm_segsz;      /* size of segment (bytes) */
+       __kernel_pid_t          shm_cpid;       /* pid of creator */
+       __kernel_pid_t          shm_lpid;       /* pid of last operator */
+       unsigned int            shm_nattch;     /* no. of current attaches */
+       unsigned int            __unused1;
+       unsigned int            __unused2;
+};
+
+#ifdef __LP64__
+#warning shminfo64 is an undocumented struct
+/* The 'unsigned int' (formerly 'unsigned long') data types below will
+ * ensure that a 32-bit app calling shmctl(*,IPC_INFO,*) will work on
+ * a wide kernel, but if some of these values are meant to contain pointers
+ * they may need to be 'long long' instead. -PB
+ */
+#endif
+struct shminfo64 {
+       unsigned int    shmmax;
+       unsigned int    shmmin;
+       unsigned int    shmmni;
+       unsigned int    shmseg;
+       unsigned int    shmall;
+       unsigned int    __unused1;
+       unsigned int    __unused2;
+       unsigned int    __unused3;
+       unsigned int    __unused4;
+};
+
+#endif /* _PARISC_SHMBUF_H */
diff --git a/include/asm-parisc/shmparam.h b/include/asm-parisc/shmparam.h
new file mode 100644 (file)
index 0000000..bbc52f0
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASMPARISC_SHMPARAM_H
+#define _ASMPARISC_SHMPARAM_H
+
+#define        SHMLBA PAGE_SIZE                 /* attach addr a multiple of this */
+
+#endif /* _ASMPARISC_SHMPARAM_H */
diff --git a/include/asm-parisc/sigcontext.h b/include/asm-parisc/sigcontext.h
new file mode 100644 (file)
index 0000000..27ef31b
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _ASMPARISC_SIGCONTEXT_H
+#define _ASMPARISC_SIGCONTEXT_H
+
+#define PARISC_SC_FLAG_ONSTACK 1<<0
+#define PARISC_SC_FLAG_IN_SYSCALL 1<<1
+
+/* We will add more stuff here as it becomes necessary, until we know
+   it works. */
+struct sigcontext {
+       unsigned long sc_flags;
+
+       unsigned long sc_gr[32]; /* PSW in sc_gr[0] */
+       unsigned long long sc_fr[32]; /* FIXME, do we need other state info? */
+       unsigned long sc_iasq[2];
+       unsigned long sc_iaoq[2];
+       unsigned long sc_sar; /* cr11 */
+};
+
+
+#endif
diff --git a/include/asm-parisc/siginfo.h b/include/asm-parisc/siginfo.h
new file mode 100644 (file)
index 0000000..143fe7e
--- /dev/null
@@ -0,0 +1,234 @@
+#ifndef _PARISC_SIGINFO_H
+#define _PARISC_SIGINFO_H
+
+#include <linux/types.h>
+
+/* XXX: This structure was copied from the Alpha; is there an iBCS version?  */
+
+typedef union sigval {
+       int sival_int;
+       void *sival_ptr;
+} sigval_t;
+
+#define SI_MAX_SIZE    128
+#define SI_PAD_SIZE    ((SI_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct siginfo {
+       int si_signo;
+       int si_errno;
+       int si_code;
+
+       union {
+               int _pad[SI_PAD_SIZE];
+
+               /* kill() */
+               struct {
+                       pid_t _pid;             /* sender's pid */
+                       uid_t _uid;             /* sender's uid */
+               } _kill;
+
+               /* POSIX.1b timers */
+               struct {
+                       unsigned int _timer1;
+                       unsigned int _timer2;
+               } _timer;
+
+               /* POSIX.1b signals */
+               struct {
+                       pid_t _pid;             /* sender's pid */
+                       uid_t _uid;             /* sender's uid */
+                       sigval_t _sigval;
+               } _rt;
+
+               /* SIGCHLD */
+               struct {
+                       pid_t _pid;             /* which child */
+                       uid_t _uid;             /* sender's uid */
+                       int _status;            /* exit code */
+                       clock_t _utime;
+                       clock_t _stime;
+               } _sigchld;
+
+               /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+               struct {
+                       void *_addr; /* faulting insn/memory ref. */
+               } _sigfault;
+
+               /* SIGPOLL */
+               struct {
+                       int _band;      /* POLL_IN, POLL_OUT, POLL_MSG */
+                       int _fd;
+               } _sigpoll;
+       } _sifields;
+} siginfo_t;
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid         _sifields._kill._pid
+#define si_uid         _sifields._kill._uid
+#define si_status      _sifields._sigchld._status
+#define si_utime       _sifields._sigchld._utime
+#define si_stime       _sifields._sigchld._stime
+#define si_value       _sifields._rt._sigval
+#define si_int         _sifields._rt._sigval.sival_int
+#define si_ptr         _sifields._rt._sigval.sival_ptr
+#define si_addr                _sifields._sigfault._addr
+#define si_band                _sifields._sigpoll._band
+#define si_fd          _sifields._sigpoll._fd
+
+#ifdef __KERNEL__
+#define __SI_MASK      0xffff0000
+#define __SI_KILL      (0 << 16)
+#define __SI_TIMER     (1 << 16)
+#define __SI_POLL      (2 << 16)
+#define __SI_FAULT     (3 << 16)
+#define __SI_CHLD      (4 << 16)
+#define __SI_RT                (5 << 16)
+#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff))
+#else
+#define __SI_KILL      0
+#define __SI_TIMER     0
+#define __SI_POLL      0
+#define __SI_FAULT     0
+#define __SI_CHLD      0
+#define __SI_RT                0
+#define __SI_CODE(T,N) (N)
+#endif
+
+/*
+ * si_code values
+ * Digital reserves positive values for kernel-generated signals.
+ */
+#define SI_USER                0               /* sent by kill, sigsend, raise */
+#define SI_KERNEL      0x80            /* sent by the kernel from somewhere */
+#define SI_QUEUE       -1              /* sent by sigqueue */
+#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
+#define SI_MESGQ       -3              /* sent by real time mesq state change */
+#define SI_ASYNCIO     -4              /* sent by AIO completion */
+#define SI_SIGIO       -5              /* sent by queued SIGIO */
+
+#define SI_FROMUSER(siptr)     ((siptr)->si_code <= 0)
+#define SI_FROMKERNEL(siptr)   ((siptr)->si_code > 0)
+
+/*
+ * SIGILL si_codes
+ */
+#define ILL_ILLOPC     (__SI_FAULT|1)  /* illegal opcode */
+#define ILL_ILLOPN     (__SI_FAULT|2)  /* illegal operand */
+#define ILL_ILLADR     (__SI_FAULT|3)  /* illegal addressing mode */
+#define ILL_ILLTRP     (__SI_FAULT|4)  /* illegal trap */
+#define ILL_PRVOPC     (__SI_FAULT|5)  /* privileged opcode */
+#define ILL_PRVREG     (__SI_FAULT|6)  /* privileged register */
+#define ILL_COPROC     (__SI_FAULT|7)  /* coprocessor error */
+#define ILL_BADSTK     (__SI_FAULT|8)  /* internal stack error */
+#define NSIGILL                8
+
+/*
+ * SIGFPE si_codes
+ */
+#define FPE_INTDIV     (__SI_FAULT|1)  /* integer divide by zero */
+#define FPE_INTOVF     (__SI_FAULT|2)  /* integer overflow */
+#define FPE_FLTDIV     (__SI_FAULT|3)  /* floating point divide by zero */
+#define FPE_FLTOVF     (__SI_FAULT|4)  /* floating point overflow */
+#define FPE_FLTUND     (__SI_FAULT|5)  /* floating point underflow */
+#define FPE_FLTRES     (__SI_FAULT|6)  /* floating point inexact result */
+#define FPE_FLTINV     (__SI_FAULT|7)  /* floating point invalid operation */
+#define FPE_FLTSUB     (__SI_FAULT|8)  /* subscript out of range */
+#define NSIGFPE                8
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_MAPERR    (__SI_FAULT|1)  /* address not mapped to object */
+#define SEGV_ACCERR    (__SI_FAULT|2)  /* invalid permissions for mapped object */
+#define NSIGSEGV       2
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_ADRALN     (__SI_FAULT|1)  /* invalid address alignment */
+#define BUS_ADRERR     (__SI_FAULT|2)  /* non-existant physical address */
+#define BUS_OBJERR     (__SI_FAULT|3)  /* object specific hardware error */
+#define NSIGBUS                3
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_BRKPT     (__SI_FAULT|1)  /* process breakpoint */
+#define TRAP_TRACE     (__SI_FAULT|2)  /* process trace trap */
+#define TRAP_BRANCH    (__SI_FAULT|3)  /* process taken branch trap */
+#define TRAP_HWBKPT    (__SI_FAULT|4)  /* hardware breakpoint or watchpoint */
+#define NSIGTRAP       4
+
+/*
+ * SIGCHLD si_codes
+ */
+#define CLD_EXITED     (__SI_CHLD|1)   /* child has exited */
+#define CLD_KILLED     (__SI_CHLD|2)   /* child was killed */
+#define CLD_DUMPED     (__SI_CHLD|3)   /* child terminated abnormally */
+#define CLD_TRAPPED    (__SI_CHLD|4)   /* traced child has trapped */
+#define CLD_STOPPED    (__SI_CHLD|5)   /* child has stopped */
+#define CLD_CONTINUED  (__SI_CHLD|6)   /* stopped child has continued */
+#define NSIGCHLD       6
+
+/*
+ * SIGPOLL si_codes
+ */
+#define POLL_IN                (__SI_POLL|1)   /* data input available */
+#define POLL_OUT       (__SI_POLL|2)   /* output buffers available */
+#define POLL_MSG       (__SI_POLL|3)   /* input message available */
+#define POLL_ERR       (__SI_POLL|4)   /* i/o error */
+#define POLL_PRI       (__SI_POLL|5)   /* high priority input available */
+#define POLL_HUP       (__SI_POLL|6)   /* device disconnected */
+#define NSIGPOLL       6
+
+/*
+ * sigevent definitions
+ * 
+ * It seems likely that SIGEV_THREAD will have to be handled from 
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+#define SIGEV_SIGNAL   0       /* notify via signal */
+#define SIGEV_NONE     1       /* other notification: meaningless */
+#define SIGEV_THREAD   2       /* deliver via thread creation */
+
+#define SIGEV_MAX_SIZE 64
+#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct sigevent {
+       sigval_t sigev_value;
+       int sigev_signo;
+       int sigev_notify;
+       union {
+               int _pad[SIGEV_PAD_SIZE];
+
+               struct {
+                       void (*_function)(sigval_t);
+                       void *_attribute;       /* really pthread_attr_t */
+               } _sigev_thread;
+       } _sigev_un;
+} sigevent_t;
+
+#define sigev_notify_function  _sigev_un._sigev_thread._function
+#define sigev_notify_attributes        _sigev_un._sigev_thread._attribute
+
+#ifdef __KERNEL__
+#include <linux/string.h>
+
+extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
+{
+       if (from->si_code < 0)
+               memcpy(to, from, sizeof(siginfo_t));
+       else
+               /* _sigchld is currently the largest know union member */
+               memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
+}
+
+extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/include/asm-parisc/signal.h b/include/asm-parisc/signal.h
new file mode 100644 (file)
index 0000000..9295c21
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef _ASM_PARISC_SIGNAL_H
+#define _ASM_PARISC_SIGNAL_H
+
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGEMT          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGBUS         10
+#define SIGSEGV                11
+#define SIGSYS         12 /* Linux doesn't use this */
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGUSR1                16
+#define SIGUSR2                17
+#define SIGCHLD                18
+#define SIGPWR         19
+#define SIGVTALRM      20
+#define SIGPROF                21
+#define SIGIO          22
+#define SIGPOLL                SIGIO
+#define SIGWINCH       23
+#define SIGSTOP                24
+#define SIGTSTP                25
+#define SIGCONT                26
+#define SIGTTIN                27
+#define SIGTTOU                28
+#define SIGURG         29
+#define SIGLOST                30 /* Linux doesn't use this either */
+#define        SIGUNUSED       31
+#define SIGRESERVE     SIGUNUSED
+
+#define SIGXCPU                33
+#define SIGXFSZ                34
+#define SIGSTKFLT      36
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN       37
+#define SIGRTMAX       (_NSIG-1) /* it's 44 under HP/UX */
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_ONSTACK     0x00000001
+#define SA_RESETHAND   0x00000004
+#define SA_NOCLDSTOP   0x00000008
+#define SA_SIGINFO     0x00000010
+#define SA_NODEFER     0x00000020
+#define SA_RESTART     0x00000040
+#define SA_NOCLDWAIT   0x00000080 /* not supported yet */
+#define _SA_SIGGFAULT  0x00000100 /* HPUX */
+
+#define SA_NOMASK      SA_NODEFER
+#define SA_ONESHOT     SA_RESETHAND
+#define SA_INTERRUPT   0x20000000 /* dummy -- ignored */
+
+#define SA_RESTORER    0x04000000 /* obsolete -- ignored */
+
+/* 
+ * sigaltstack controls
+ */
+#define SS_ONSTACK     1
+#define SS_DISABLE     2
+
+#define MINSIGSTKSZ    2048
+#define SIGSTKSZ       8192
+
+#ifdef __KERNEL__
+
+#define _NSIG          64
+/* bits-per-word, where word apparently means 'long' not 'int' */
+#define _NSIG_BPW      BITS_PER_LONG
+#define _NSIG_WORDS    (_NSIG / _NSIG_BPW)
+
+/*
+ * These values of sa_flags are used only by the kernel as part of the
+ * irq handling routines.
+ *
+ * SA_INTERRUPT is also used by the irq handling routines.
+ * SA_SHIRQ is for shared interrupt support on PCI and EISA.
+ */
+#define SA_PROBE               SA_ONESHOT
+#define SA_SAMPLE_RANDOM       SA_RESTART
+#define SA_SHIRQ               0x04000000
+
+#endif /* __KERNEL__ */
+
+#define SIG_BLOCK          0   /* for blocking signals */
+#define SIG_UNBLOCK        1   /* for unblocking signals */
+#define SIG_SETMASK        2   /* for setting the signal mask */
+
+#define SIG_DFL        ((__sighandler_t)0)     /* default signal handling */
+#define SIG_IGN        ((__sighandler_t)1)     /* ignore signal */
+#define SIG_ERR        ((__sighandler_t)-1)    /* error return from signal */
+
+# ifndef __ASSEMBLY__
+
+#  include <linux/types.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+/* Type of a signal handler.  */
+#ifdef __LP64__
+/* function pointers on 64-bit parisc are pointers to little structs and the
+ * compiler doesn't support code which changes or tests the address of
+ * the function in the little struct.  This is really ugly -PB
+ */
+typedef __kernel_caddr_t __sighandler_t;
+#else
+typedef void (*__sighandler_t)(int);
+#endif
+
+typedef struct sigaltstack {
+       void *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
+typedef unsigned long old_sigset_t;            /* at least 32 bits */
+
+typedef struct {
+       /* next_signal() assumes this is a long - no choice */
+       unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+struct sigaction {
+       __sighandler_t sa_handler;
+       unsigned long sa_flags;
+       sigset_t sa_mask;               /* mask last for extensibility */
+};
+
+struct k_sigaction {
+       struct sigaction sa;
+};
+
+#include <asm/sigcontext.h>
+
+#endif /* __KERNEL__ */
+#endif /* !__ASSEMBLY */
+#endif /* _ASM_PARISC_SIGNAL_H */
diff --git a/include/asm-parisc/smp.h b/include/asm-parisc/smp.h
new file mode 100644 (file)
index 0000000..24c418d
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __ASM_SMP_H
+#define __ASM_SMP_H
+
+#ifdef CONFIG_SMP
+extern volatile unsigned long cpu_online_map;  /* Bitmap of available cpu's */
+#endif
+
+#endif
diff --git a/include/asm-parisc/smplock.h b/include/asm-parisc/smplock.h
new file mode 100644 (file)
index 0000000..1590faf
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * <asm/smplock.h>
+ *
+ * Default SMP lock implementation
+ */
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+extern spinlock_t kernel_flag;
+
+/*
+ * Release global kernel lock and global interrupt lock
+ */
+#define release_kernel_lock(task, cpu) \
+do { \
+       if (task->lock_depth >= 0) \
+               spin_unlock(&kernel_flag); \
+       release_irqlock(cpu); \
+       __sti(); \
+} while (0)
+
+/*
+ * Re-acquire the kernel lock
+ */
+#define reacquire_kernel_lock(task) \
+do { \
+       if (task->lock_depth >= 0) \
+               spin_lock(&kernel_flag); \
+} while (0)
+
+
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously,
+ * so we only need to worry about other
+ * CPU's.
+ */
+extern __inline__ void lock_kernel(void)
+{
+       if (!++current->lock_depth)
+               spin_lock(&kernel_flag);
+}
+
+extern __inline__ void unlock_kernel(void)
+{
+       if (--current->lock_depth < 0)
+               spin_unlock(&kernel_flag);
+}
diff --git a/include/asm-parisc/socket.h b/include/asm-parisc/socket.h
new file mode 100644 (file)
index 0000000..6ce5534
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef _ASM_SOCKET_H
+#define _ASM_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockoptions(2) */
+#define SOL_SOCKET     0xffff
+
+#define SO_DEBUG       0x0001
+#define SO_REUSEADDR   0x0004
+#define SO_KEEPALIVE   0x0008
+#define SO_DONTROUTE   0x0010
+#define SO_BROADCAST   0x0020
+#define SO_LINGER      0x0080
+#define SO_OOBINLINE   0x0100
+/* To add :#define SO_REUSEPORT 0x0200 */
+#define SO_SNDBUF      0x1001
+#define SO_RCVBUF      0x1002
+#define SO_SNDLOWAT    0x1003
+#define SO_RCVLOWAT    0x1004
+#define SO_SNDTIMEO    0x1005
+#define SO_RCVTIMEO    0x1006
+#define SO_ERROR       0x1007
+#define SO_TYPE                0x1008
+#define SO_PEERNAME    0x2000
+
+#define SO_NO_CHECK    0x400b
+#define SO_PRIORITY    0x400c
+#define SO_BSDCOMPAT   0x400e
+#define SO_PASSCRED    0x4010
+#define SO_PEERCRED    0x4011
+#define SO_TIMESTAMP   0x4012
+#define SCM_TIMESTAMP  SO_TIMESTAMP
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             0x4016
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       0x4017
+#define SO_SECURITY_ENCRYPTION_NETWORK         0x4018
+
+#define SO_BINDTODEVICE        0x4019
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER        0x401a
+#define SO_DETACH_FILTER        0x401b
+
+#if defined(__KERNEL__)
+#define SOCK_STREAM    1       /* stream (connection) socket   */
+#define SOCK_DGRAM     2       /* datagram (conn.less) socket  */
+#define SOCK_RAW       3       /* raw socket                   */
+#define SOCK_RDM       4       /* reliably-delivered message   */
+#define SOCK_SEQPACKET 5       /* sequential packet socket     */
+#define SOCK_PACKET    10      /* linux specific way of        */
+                               /* getting packets at the dev   */
+                               /* level.  For writing rarp and */
+                               /* other similar things on the  */
+                               /* user level.                  */
+#endif
+
+#endif /* _ASM_SOCKET_H */
diff --git a/include/asm-parisc/sockios.h b/include/asm-parisc/sockios.h
new file mode 100644 (file)
index 0000000..aace496
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __ARCH_PARISC_SOCKIOS__
+#define __ARCH_PARISC_SOCKIOS__
+
+/* Socket-level I/O control calls. */
+#define FIOSETOWN      0x8901
+#define SIOCSPGRP      0x8902
+#define FIOGETOWN      0x8903
+#define SIOCGPGRP      0x8904
+#define SIOCATMARK     0x8905
+#define SIOCGSTAMP     0x8906          /* Get stamp */
+
+#endif
diff --git a/include/asm-parisc/softirq.h b/include/asm-parisc/softirq.h
new file mode 100644 (file)
index 0000000..4fe26b2
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __ASM_SOFTIRQ_H
+#define __ASM_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
+#define cpu_bh_disable(cpu)    do { local_bh_count(cpu)++; barrier(); } while (0)
+#define cpu_bh_enable(cpu)     do { barrier(); local_bh_count(cpu)--; } while (0)
+
+#define local_bh_disable()     cpu_bh_disable(smp_processor_id())
+#define local_bh_enable()      cpu_bh_enable(smp_processor_id())
+
+#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
+
+#endif /* __ASM_SOFTIRQ_H */
diff --git a/include/asm-parisc/som.h b/include/asm-parisc/som.h
new file mode 100644 (file)
index 0000000..5f90baa
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _ASM_PARISC_SOM_H
+#define _ASM_PARISC_SOM_H
+
+/* File format definition for SOM executables / shared libraries */
+#include <linux/som.h>
+
+
+#endif /* _ASM_PARISC_SOM_H
diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h
new file mode 100644 (file)
index 0000000..7a59ed6
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#include <asm/system.h>
+
+/* if you're going to use out-of-line slowpaths, use .section .lock.text,
+ * not .text.lock or the -ffunction-sections monster will eat you alive
+ */
+
+/* we seem to be the only architecture that uses 0 to mean locked - but we
+ * have to.  prumpf */
+
+#undef SPIN_LOCK_UNLOCKED
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
+
+#define spin_lock_init(x)      do { (x)->lock = 1; } while(0)
+
+#define spin_unlock_wait(x)    do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 1)
+
+#define spin_lock(x) \
+       do { while(__ldcw(&(x)->lock) == 0); } while(0)
+       
+#define spin_unlock(x) \
+       do { (x)->lock = 1; } while(0)
+
+#define spin_trylock(x) (__ldcw(&(x)->lock) == 1)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ */
+typedef struct {
+       spinlock_t lock;
+       volatile int counter;
+} rwlock_t;
+
+#define RW_LOCK_UNLOCKED (rwlock_t) { SPIN_LOCK_UNLOCKED, 0 }
+
+/* read_lock, read_unlock are pretty straightforward.  Of course it somehow
+ * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */
+
+static inline void read_lock(rwlock_t *rw)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&rw->lock, flags);
+
+       rw->counter++;
+
+       spin_unlock_irqrestore(&rw->lock, flags);
+}
+
+static inline void read_unlock(rwlock_t *rw)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&rw->lock, flags);
+
+       rw->counter--;
+
+       spin_unlock_irqrestore(&rw->lock, flags);
+}
+
+/* write_lock is less trivial.  We optimistically grab the lock and check
+ * if we surprised any readers.  If so we release the lock and wait till
+ * they're all gone before trying again
+ *
+ * Also note that we don't use the _irqsave / _irqrestore suffixes here.
+ * If we're called with interrupts enabled and we've got readers (or other
+ * writers) in interrupt handlers someone fucked up and we'd dead-lock
+ * sooner or later anyway.   prumpf */
+
+static inline void write_lock(rwlock_t *rw)
+{
+retry:
+       spin_lock(&rw->lock);
+
+       if(rw->counter != 0) {
+               /* this basically never happens */
+               spin_unlock(&rw->lock);
+
+               while(rw->counter != 0);
+
+               goto retry;
+       }
+
+       /* got it.  now leave without unlocking */
+}
+
+/* write_unlock is absolutely trivial - we don't have to wait for anything */
+
+static inline void write_unlock(rwlock_t *rw)
+{
+       spin_unlock(&rw->lock);
+}
+
+#endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-parisc/stat.h b/include/asm-parisc/stat.h
new file mode 100644 (file)
index 0000000..9d09e95
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef _PARISC_STAT_H
+#define _PARISC_STAT_H
+
+#include <linux/types.h>
+
+struct stat {
+       dev_t           st_dev;         /* dev_t is 32 bits on parisc */
+       ino_t           st_ino;         /* 32 bits */
+       mode_t          st_mode;        /* 16 bits */
+       nlink_t         st_nlink;       /* 16 bits */
+       unsigned short  st_reserved1;   /* old st_uid */
+       unsigned short  st_reserved2;   /* old st_gid */
+       dev_t           st_rdev;
+       off_t           st_size;
+       time_t          st_atime;
+       unsigned int    st_spare1;
+       time_t          st_mtime;
+       unsigned int    st_spare2;
+       time_t          st_ctime;
+       unsigned int    st_spare3;
+       int             st_blksize;
+       int             st_blocks;
+       unsigned int    __unused1;      /* ACL stuff */
+       dev_t           __unused2;      /* network */
+       ino_t           __unused3;      /* network */
+       unsigned int    __unused4;      /* cnodes */
+       unsigned short  __unused5;      /* netsite */
+       short           st_fstype;
+       dev_t           st_realdev;
+       unsigned short  st_basemode;
+       unsigned short  st_spareshort;
+       uid_t           st_uid;
+       gid_t           st_gid;
+       unsigned int    st_spare4[3];
+};
+
+typedef __kernel_off64_t       off64_t;
+
+struct hpux_stat64 {
+       dev_t           st_dev;         /* dev_t is 32 bits on parisc */
+       ino_t           st_ino;         /* 32 bits */
+       mode_t          st_mode;        /* 16 bits */
+       nlink_t         st_nlink;       /* 16 bits */
+       unsigned short  st_reserved1;   /* old st_uid */
+       unsigned short  st_reserved2;   /* old st_gid */
+       dev_t           st_rdev;
+       off64_t         st_size;
+       time_t          st_atime;
+       unsigned int    st_spare1;
+       time_t          st_mtime;
+       unsigned int    st_spare2;
+       time_t          st_ctime;
+       unsigned int    st_spare3;
+       int             st_blksize;
+       __u64           st_blocks;
+       unsigned int    __unused1;      /* ACL stuff */
+       dev_t           __unused2;      /* network */
+       ino_t           __unused3;      /* network */
+       unsigned int    __unused4;      /* cnodes */
+       unsigned short  __unused5;      /* netsite */
+       short           st_fstype;
+       dev_t           st_realdev;
+       unsigned short  st_basemode;
+       unsigned short  st_spareshort;
+       uid_t           st_uid;
+       gid_t           st_gid;
+       unsigned int    st_spare4[3];
+};
+#define stat64 hpux_stat64
+
+#endif
diff --git a/include/asm-parisc/statfs.h b/include/asm-parisc/statfs.h
new file mode 100644 (file)
index 0000000..db72e85
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _PARISC_STATFS_H
+#define _PARISC_STATFS_H
+
+#ifndef __KERNEL_STRICT_NAMES
+
+#include <linux/types.h>
+
+typedef __kernel_fsid_t        fsid_t;
+
+#endif
+
+struct statfs {
+       long f_type;
+       long f_bsize;
+       long f_blocks;
+       long f_bfree;
+       long f_bavail;
+       long f_files;
+       long f_ffree;
+       __kernel_fsid_t f_fsid;
+       long f_namelen;
+       long f_spare[6];
+};
+
+#endif
diff --git a/include/asm-parisc/string.h b/include/asm-parisc/string.h
new file mode 100644 (file)
index 0000000..beede57
--- /dev/null
@@ -0,0 +1,2 @@
+
+/* This left blank until we do parisc optimizations */
diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h
new file mode 100644 (file)
index 0000000..3cdbde9
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef __PARISC_SYSTEM_H
+#define __PARISC_SYSTEM_H
+
+#include <asm/psw.h>
+
+/* The program status word as bitfields.  */
+struct pa_psw {
+       unsigned int y:1;
+       unsigned int z:1;
+       unsigned int rv:2;
+       unsigned int w:1;
+       unsigned int e:1;
+       unsigned int s:1;
+       unsigned int t:1;
+
+       unsigned int h:1;
+       unsigned int l:1;
+       unsigned int n:1;
+       unsigned int x:1;
+       unsigned int b:1;
+       unsigned int c:1;
+       unsigned int v:1;
+       unsigned int m:1;
+
+       unsigned int cb:8;
+
+       unsigned int o:1;
+       unsigned int g:1;
+       unsigned int f:1;
+       unsigned int r:1;
+       unsigned int q:1;
+       unsigned int p:1;
+       unsigned int d:1;
+       unsigned int i:1;
+};
+
+#define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW))
+
+struct task_struct;
+
+extern struct task_struct *_switch_to(struct task_struct *, struct task_struct *);
+
+#define prepare_to_switch()    do { } while(0)
+#define switch_to(prev, next, last) do {                       \
+       (last) = _switch_to(prev, next);                        \
+} while(0)
+
+/* borrowed this from sparc64 -- probably the SMP case is hosed for us */
+#ifdef CONFIG_SMP
+#define smp_mb()       mb()
+#define smp_rmb()      rmb()
+#define smp_wmb()      wmb()
+#else
+/* This is simply the barrier() macro from linux/kernel.h but when serial.c
+ * uses tqueue.h uses smp_mb() defined using barrier(), linux/kernel.h
+ * hasn't yet been included yet so it fails, thus repeating the macro here.
+ */
+#define smp_mb()       __asm__ __volatile__("":::"memory");
+#define smp_rmb()      __asm__ __volatile__("":::"memory");
+#define smp_wmb()      __asm__ __volatile__("":::"memory");
+#endif
+
+/* interrupt control */
+#define __save_flags(x)        __asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
+#define __restore_flags(x) __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory")
+#define __cli()        __asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
+#define __sti()        __asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
+
+#define local_irq_save(x) \
+       __asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
+#define local_irq_restore(x) \
+       __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" )
+#define local_irq_disable() __cli()
+#define local_irq_enable()  __sti()
+
+#ifdef CONFIG_SMP
+#else
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(x) __save_flags(x)
+#define restore_flags(x) __restore_flags(x)
+#endif
+
+
+#define mfctl(reg)     ({              \
+       unsigned long cr;               \
+       __asm__ __volatile__(           \
+               "mfctl " #reg ",%0" :   \
+                "=r" (cr)              \
+       );                              \
+       cr;                             \
+})
+
+#define mtctl(gr, cr) \
+       __asm__ __volatile__("mtctl %0,%1" \
+               : /* no outputs */ \
+               : "r" (gr), "i" (cr))
+
+/* these are here to de-mystefy the calling code, and to provide hooks */
+/* which I needed for debugging EIEM problems -PB */
+#define get_eiem() mfctl(15)
+static inline void set_eiem(unsigned long val)
+{
+       mtctl(val, 15);
+}
+
+#define mfsp(reg)      ({              \
+       unsigned long cr;               \
+       __asm__ __volatile__(           \
+               "mfsp " #reg ",%0" :    \
+                "=r" (cr)              \
+       );                              \
+       cr;                             \
+})
+
+#define mtsp(gr, cr) \
+       __asm__ __volatile__("mtsp %0,%1" \
+               : /* no outputs */ \
+               : "r" (gr), "i" (cr))
+
+
+#define mb()  __asm__ __volatile__ ("sync" : : :"memory")
+#define wmb() mb()
+
+extern unsigned long __xchg(unsigned long, unsigned long *, int);
+
+#define xchg(ptr,x) \
+ (__typeof__(*(ptr)))__xchg((unsigned long)(x),(unsigned long*)(ptr),sizeof(*(ptr)))
+
+/* LDCW, the only atomic read-write operation PA-RISC has.  Sigh. */
+#define __ldcw(a) ({ \
+       unsigned __ret; \
+       __asm__ __volatile__("ldcw 0(%1),%0" : "=r" (__ret) : "r" (a)); \
+       __ret; \
+})
+
+#ifdef CONFIG_SMP
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+       volatile unsigned int __attribute__((aligned(16))) lock;
+} spinlock_t;
+#endif
+
+#endif
diff --git a/include/asm-parisc/termbits.h b/include/asm-parisc/termbits.h
new file mode 100644 (file)
index 0000000..4cff593
--- /dev/null
@@ -0,0 +1,174 @@
+#ifndef __ARCH_PARISC_TERMBITS_H__
+#define __ARCH_PARISC_TERMBITS_H__
+
+#include <linux/posix_types.h>
+
+typedef unsigned char  cc_t;
+typedef unsigned int   speed_t;
+typedef unsigned int   tcflag_t;
+
+#define NCCS 19
+struct termios {
+       tcflag_t c_iflag;               /* input mode flags */
+       tcflag_t c_oflag;               /* output mode flags */
+       tcflag_t c_cflag;               /* control mode flags */
+       tcflag_t c_lflag;               /* local mode flags */
+       cc_t c_line;                    /* line discipline */
+       cc_t c_cc[NCCS];                /* control characters */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+
+/* c_iflag bits */
+#define IGNBRK 0000001
+#define BRKINT 0000002
+#define IGNPAR 0000004
+#define PARMRK 0000010
+#define INPCK  0000020
+#define ISTRIP 0000040
+#define INLCR  0000100
+#define IGNCR  0000200
+#define ICRNL  0000400
+#define IUCLC  0001000
+#define IXON   0002000
+#define IXANY  0004000
+#define IXOFF  0010000
+#define IMAXBEL        0040000
+
+/* c_oflag bits */
+#define OPOST  0000001
+#define OLCUC  0000002
+#define ONLCR  0000004
+#define OCRNL  0000010
+#define ONOCR  0000020
+#define ONLRET 0000040
+#define OFILL  0000100
+#define OFDEL  0000200
+#define NLDLY  0000400
+#define   NL0  0000000
+#define   NL1  0000400
+#define CRDLY  0003000
+#define   CR0  0000000
+#define   CR1  0001000
+#define   CR2  0002000
+#define   CR3  0003000
+#define TABDLY 0014000
+#define   TAB0 0000000
+#define   TAB1 0004000
+#define   TAB2 0010000
+#define   TAB3 0014000
+#define   XTABS        0014000
+#define BSDLY  0020000
+#define   BS0  0000000
+#define   BS1  0020000
+#define VTDLY  0040000
+#define   VT0  0000000
+#define   VT1  0040000
+#define FFDLY  0100000
+#define   FF0  0000000
+#define   FF1  0100000
+
+/* c_cflag bit meaning */
+#define CBAUD   0010017
+#define  B0     0000000         /* hang up */
+#define  B50    0000001
+#define  B75    0000002
+#define  B110   0000003
+#define  B134   0000004
+#define  B150   0000005
+#define  B200   0000006
+#define  B300   0000007
+#define  B600   0000010
+#define  B1200  0000011
+#define  B1800  0000012
+#define  B2400  0000013
+#define  B4800  0000014
+#define  B9600  0000015
+#define  B19200 0000016
+#define  B38400 0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE   0000060
+#define   CS5   0000000
+#define   CS6   0000020
+#define   CS7   0000040
+#define   CS8   0000060
+#define CSTOPB  0000100
+#define CREAD   0000200
+#define PARENB  0000400
+#define PARODD  0001000
+#define HUPCL   0002000
+#define CLOCAL  0004000
+#define CBAUDEX 0010000
+#define    B57600 0010001
+#define   B115200 0010002
+#define   B230400 0010003
+#define   B460800 0010004
+#define   B500000 0010005
+#define   B576000 0010006
+#define   B921600 0010007
+#define  B1000000 0010010
+#define  B1152000 0010011
+#define  B1500000 0010012
+#define  B2000000 0010013
+#define  B2500000 0010014
+#define  B3000000 0010015
+#define  B3500000 0010016
+#define  B4000000 0010017
+#define CIBAUD    002003600000  /* input baud rate (not used) */
+#define CMSPAR    010000000000          /* mark or space (stick) parity */
+#define CRTSCTS   020000000000          /* flow control */
+
+
+/* c_lflag bits */
+#define ISIG    0000001
+#define ICANON  0000002
+#define XCASE   0000004
+#define ECHO    0000010
+#define ECHOE   0000020
+#define ECHOK   0000040
+#define ECHONL  0000100
+#define NOFLSH  0000200
+#define TOSTOP  0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE  0004000
+#define FLUSHO  0010000
+#define PENDIN  0040000
+#define IEXTEN  0100000
+
+/* tcflow() and TCXONC use these */
+#define        TCOOFF          0
+#define        TCOON           1
+#define        TCIOFF          2
+#define        TCION           3
+
+/* tcflush() and TCFLSH use these */
+#define        TCIFLUSH        0
+#define        TCOFLUSH        1
+#define        TCIOFLUSH       2
+
+/* tcsetattr uses these */
+#define        TCSANOW         0
+#define        TCSADRAIN       1
+#define        TCSAFLUSH       2
+
+#endif
diff --git a/include/asm-parisc/termios.h b/include/asm-parisc/termios.h
new file mode 100644 (file)
index 0000000..6aa0f8f
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef _PARISC_TERMIOS_H
+#define _PARISC_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+       unsigned short ws_row;
+       unsigned short ws_col;
+       unsigned short ws_xpixel;
+       unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+       unsigned short c_iflag;         /* input mode flags */
+       unsigned short c_oflag;         /* output mode flags */
+       unsigned short c_cflag;         /* control mode flags */
+       unsigned short c_lflag;         /* local mode flags */
+       unsigned char c_line;           /* line discipline */
+       unsigned char c_cc[NCC];        /* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE       0x001
+#define TIOCM_DTR      0x002
+#define TIOCM_RTS      0x004
+#define TIOCM_ST       0x008
+#define TIOCM_SR       0x010
+#define TIOCM_CTS      0x020
+#define TIOCM_CAR      0x040
+#define TIOCM_RNG      0x080
+#define TIOCM_DSR      0x100
+#define TIOCM_CD       TIOCM_CAR
+#define TIOCM_RI       TIOCM_RNG
+#define TIOCM_OUT1     0x2000
+#define TIOCM_OUT2     0x4000
+#define TIOCM_LOOP     0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+/* line disciplines */
+#define N_TTY          0
+#define N_SLIP         1
+#define N_MOUSE                2
+#define N_PPP          3
+#define N_STRIP                4
+#define N_AX25         5
+#define N_X25          6       /* X.25 async */
+#define N_6PACK                7
+#define N_MASC         8       /* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964                9       /* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL 10      /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA         11      /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK     12      /* SMS block mode - for talking to GSM data cards about SMS messages */
+
+#ifdef __KERNEL__
+
+/*     intr=^C         quit=^\         erase=del       kill=^U
+       eof=^D          vtime=\0        vmin=\1         sxtc=\0
+       start=^Q        stop=^S         susp=^Z         eol=\0
+       reprint=^R      discard=^U      werase=^W       lnext=^V
+       eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+       unsigned short __tmp; \
+       get_user(__tmp,&(termio)->x); \
+       *(unsigned short *) &(termios)->x = __tmp; \
+}
+
+#define user_termio_to_kernel_termios(termios, termio) \
+({ \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+       copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+#define kernel_termios_to_user_termio(termio, termios) \
+({ \
+       put_user((termios)->c_iflag, &(termio)->c_iflag); \
+       put_user((termios)->c_oflag, &(termio)->c_oflag); \
+       put_user((termios)->c_cflag, &(termio)->c_cflag); \
+       put_user((termios)->c_lflag, &(termio)->c_lflag); \
+       put_user((termios)->c_line,  &(termio)->c_line); \
+       copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
+
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif /* __KERNEL__ */
+
+#endif /* _PARISC_TERMIOS_H */
diff --git a/include/asm-parisc/timex.h b/include/asm-parisc/timex.h
new file mode 100644 (file)
index 0000000..13fab4b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * linux/include/asm-parisc/timex.h
+ *
+ * PARISC architecture timex specifications
+ */
+#ifndef _ASMPARISC_TIMEX_H
+#define _ASMPARISC_TIMEX_H
+
+#include <asm/system.h>
+#include <linux/config.h>
+#include <linux/time.h>
+
+typedef unsigned long cycles_t;
+
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles (void)
+{
+       return mfctl(16);
+}
+
+#endif
diff --git a/include/asm-parisc/traps.h b/include/asm-parisc/traps.h
new file mode 100644 (file)
index 0000000..6ebc4e6
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASM_TRAPS_H
+#define __ASM_TRAPS_H
+
+#endif
diff --git a/include/asm-parisc/types.h b/include/asm-parisc/types.h
new file mode 100644 (file)
index 0000000..6d46986
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _PARISC_TYPES_H
+#define _PARISC_TYPES_H
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+#endif
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#ifdef __LP64__
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif
+
+/* Dma addresses are 32-bits wide.  */
+
+typedef u32 dma_addr_t;
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/include/asm-parisc/uaccess.h b/include/asm-parisc/uaccess.h
new file mode 100644 (file)
index 0000000..0d825d0
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef __PARISC_UACCESS_H
+#define __PARISC_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/cache.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+#define KERNEL_DS      ((mm_segment_t){0})
+#define USER_DS        ((mm_segment_t){1})
+
+#define segment_eq(a,b)        ((a).seg == (b).seg)
+
+#define get_ds()       (KERNEL_DS)
+#define get_fs()       (current->addr_limit)
+#define set_fs(x)      (current->addr_limit = (x))
+
+/*
+ * Note that since kernel addresses are in a separate address space on
+ * parisc, we don't need to do anything for access_ok() or verify_area().
+ * We just let the page fault handler do the right thing. This also means
+ * that put_user is the same as __put_user, etc.
+ */
+
+#define access_ok(type,addr,size)   (1)
+#define verify_area(type,addr,size) (0)
+
+#define put_user __put_user
+#define get_user __get_user
+
+/*
+ * The exception table contains two values: the first is an address
+ * for an instruction that is allowed to fault, and the second is
+ * the number of bytes to skip if a fault occurs. We also support in
+ * two bit flags: 0x2 tells the exception handler to clear register
+ * r9 and 0x1 tells the exception handler to put -EFAULT in r8.
+ * This allows us to handle the simple cases for put_user and
+ * get_user without having to have .fixup sections.
+ */
+
+struct exception_table_entry {
+       unsigned long addr;  /* address of insn that is allowed to fault.   */
+       int skip;            /* pcoq skip | r9 clear flag | r8 -EFAULT flag */
+};
+
+extern const struct exception_table_entry 
+    *search_exception_table(unsigned long addr);
+
+#define __get_user(x,ptr)                               \
+({                                                      \
+       register long __gu_err __asm__ ("r8") = 0;      \
+       register long __gu_val __asm__ ("r9") = 0;      \
+                                                       \
+       if (segment_eq(get_fs(),KERNEL_DS)) {           \
+           switch (sizeof(*(ptr))) {                   \
+           case 1: __get_kernel_asm("ldb",ptr); break; \
+           case 2: __get_kernel_asm("ldh",ptr); break; \
+           case 4: __get_kernel_asm("ldw",ptr); break; \
+           case 8: __get_kernel_asm("ldd",ptr); break; \
+           default: BUG(); break;                      \
+           }                                           \
+       }                                               \
+       else {                                          \
+           switch (sizeof(*(ptr))) {                   \
+           case 1: __get_user_asm("ldb",ptr); break;   \
+           case 2: __get_user_asm("ldh",ptr); break;   \
+           case 4: __get_user_asm("ldw",ptr); break;   \
+           case 8: __get_user_asm("ldd",ptr); break;   \
+           default: BUG(); break;                      \
+           }                                           \
+       }                                               \
+                                                       \
+       (x) = (__typeof__(*(ptr))) __gu_val;            \
+       __gu_err;                                       \
+})
+
+#define __get_kernel_asm(ldx,ptr)                       \
+       __asm__("\n1:\t" ldx "\t0(%2),%0\n"             \
+               "2:\n"                                  \
+               "\t.section __ex_table,\"a\"\n"         \
+                "\t.word\t1b\n"                        \
+                "\t.word\t(2b-1b)+3\n"                 \
+                "\t.previous"                          \
+               : "=r"(__gu_val), "=r"(__gu_err)        \
+               : "r"(ptr), "1"(__gu_err));
+
+#define __get_user_asm(ldx,ptr)                         \
+       __asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n"       \
+               "2:\n"                                  \
+               "\t.section __ex_table,\"a\"\n"         \
+                "\t.word\t1b\n"                        \
+                "\t.word\t(2b-1b)+3\n"                 \
+                "\t.previous"                          \
+               : "=r"(__gu_val), "=r"(__gu_err)        \
+               : "r"(ptr), "1"(__gu_err));
+
+
+#define __put_user(x,ptr)                                       \
+({                                                             \
+       register long __pu_err __asm__ ("r8") = 0;              \
+                                                               \
+       if (segment_eq(get_fs(),KERNEL_DS)) {                   \
+           switch (sizeof(*(ptr))) {                           \
+           case 1: __put_kernel_asm("stb",x,ptr); break;       \
+           case 2: __put_kernel_asm("sth",x,ptr); break;       \
+           case 4: __put_kernel_asm("stw",x,ptr); break;       \
+           case 8: __put_kernel_asm("std",x,ptr); break;       \
+           default: BUG(); break;                              \
+           }                                                   \
+       }                                                       \
+       else {                                                  \
+           switch (sizeof(*(ptr))) {                           \
+           case 1: __put_user_asm("stb",x,ptr); break;         \
+           case 2: __put_user_asm("sth",x,ptr); break;         \
+           case 4: __put_user_asm("stw",x,ptr); break;         \
+           case 8: __put_user_asm("std",x,ptr); break;         \
+           default: BUG(); break;                              \
+           }                                                   \
+       }                                                       \
+                                                               \
+       __pu_err;                                               \
+})
+
+/*
+ * The "__put_user/kernel_asm()" macros tell gcc they read from memory
+ * instead of writing. This is because they do not write to any memory
+ * gcc knows about, so there are no aliasing issues.
+ */
+
+#define __put_kernel_asm(stx,x,ptr)                         \
+       __asm__ __volatile__ (                              \
+               "\n1:\t" stx "\t%2,0(%1)\n"                 \
+               "2:\n"                                      \
+               "\t.section __ex_table,\"a\"\n"             \
+                "\t.word\t1b\n"                            \
+                "\t.word\t(2b-1b)+1\n"                     \
+                "\t.previous"                              \
+               : "=r"(__pu_err)                            \
+               : "r"(ptr), "r"(x), "0"(__pu_err))
+
+#define __put_user_asm(stx,x,ptr)                           \
+       __asm__ __volatile__ (                              \
+               "\n1:\t" stx "\t%2,0(%%sr3,%1)\n"           \
+               "2:\n"                                      \
+               "\t.section __ex_table,\"a\"\n"             \
+                "\t.word\t1b\n"                            \
+                "\t.word\t(2b-1b)+1\n"                     \
+                "\t.previous"                              \
+               : "=r"(__pu_err)                            \
+               : "r"(ptr), "r"(x), "0"(__pu_err))
+
+
+/*
+ * Complex access routines -- external declarations
+ */
+
+extern unsigned long lcopy_to_user(void *, const void *, unsigned long);
+extern unsigned long lcopy_from_user(void *, const void *, unsigned long);
+extern long lstrncpy_from_user(char *, const char *, long);
+extern unsigned lclear_user(void *,unsigned long);
+extern long lstrnlen_user(const char *,long);
+
+/*
+ * Complex access routines -- macros
+ */
+
+#define strncpy_from_user lstrncpy_from_user
+#define strnlen_user lstrnlen_user
+#define strlen_user(str) lstrnlen_user(str, 0x7fffffffL)
+#define clear_user lclear_user
+
+#define copy_from_user lcopy_from_user
+#define __copy_from_user lcopy_from_user
+#define copy_to_user lcopy_to_user
+#define __copy_to_user lcopy_to_user
+
+#define copy_to_user_ret(to,from,n,retval) \
+    ({ if (lcopy_to_user(to,from,n)) return retval; })
+
+#define copy_from_user_ret(to,from,n,retval) \
+    ({ if (lcopy_from_user(to,from,n)) return retval; })
+
+#endif /* __PARISC_UACCESS_H */
diff --git a/include/asm-parisc/ucontext.h b/include/asm-parisc/ucontext.h
new file mode 100644 (file)
index 0000000..f2e5904
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _ASMPARISC_UCONTEXT_H
+#define _ASMPARISC_UCONTEXT_H
+
+struct ucontext {
+       unsigned long     uc_flags;
+       struct ucontext  *uc_link;
+       stack_t           uc_stack;
+       struct sigcontext uc_mcontext;
+       sigset_t          uc_sigmask;   /* mask last for extensibility */
+};
+
+#endif /* !_ASMPARISC_UCONTEXT_H */
diff --git a/include/asm-parisc/unaligned.h b/include/asm-parisc/unaligned.h
new file mode 100644 (file)
index 0000000..531f538
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _ASM_PARISC_UNALIGNED_H_
+#define _ASM_PARISC_UNALIGNED_H_
+
+/* parisc can't handle unaligned accesses. */
+/* copied from asm-sparc/unaligned.h */
+
+#include <linux/string.h>
+
+
+/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
+
+#define get_unaligned(ptr) \
+  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+
+#define put_unaligned(val, ptr)                                \
+  ({ __typeof__(*(ptr)) __tmp = (val);                 \
+     memmove((ptr), &__tmp, sizeof(*(ptr)));           \
+     (void)0; })
+
+#endif /* _ASM_PARISC_UNALIGNED_H */
diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h
new file mode 100644 (file)
index 0000000..ea0542a
--- /dev/null
@@ -0,0 +1,901 @@
+#ifndef _ASM_PARISC_UNISTD_H_
+#define _ASM_PARISC_UNISTD_H_
+
+/*
+ * This file contains the system call numbers.
+ */
+
+/*
+ *   HP-UX system calls get their native numbers for binary compatibility.
+ */
+
+#define __NR_HPUX_exit                    1
+#define __NR_HPUX_fork                    2
+#define __NR_HPUX_read                    3
+#define __NR_HPUX_write                   4
+#define __NR_HPUX_open                    5
+#define __NR_HPUX_close                   6
+#define __NR_HPUX_wait                    7
+#define __NR_HPUX_creat                   8
+#define __NR_HPUX_link                    9
+#define __NR_HPUX_unlink                 10
+#define __NR_HPUX_execv                  11
+#define __NR_HPUX_chdir                  12
+#define __NR_HPUX_time                   13
+#define __NR_HPUX_mknod                  14
+#define __NR_HPUX_chmod                  15
+#define __NR_HPUX_chown                  16
+#define __NR_HPUX_break                  17
+#define __NR_HPUX_lchmod                 18
+#define __NR_HPUX_lseek                  19
+#define __NR_HPUX_getpid                 20
+#define __NR_HPUX_mount                  21
+#define __NR_HPUX_umount                 22
+#define __NR_HPUX_setuid                 23
+#define __NR_HPUX_getuid                 24
+#define __NR_HPUX_stime                  25
+#define __NR_HPUX_ptrace                 26
+#define __NR_HPUX_alarm                  27
+#define __NR_HPUX_oldfstat               28
+#define __NR_HPUX_pause                  29
+#define __NR_HPUX_utime                  30
+#define __NR_HPUX_stty                   31
+#define __NR_HPUX_gtty                   32
+#define __NR_HPUX_access                 33
+#define __NR_HPUX_nice                   34
+#define __NR_HPUX_ftime                  35
+#define __NR_HPUX_sync                   36
+#define __NR_HPUX_kill                   37
+#define __NR_HPUX_stat                   38
+#define __NR_HPUX_setpgrp3               39
+#define __NR_HPUX_lstat                  40
+#define __NR_HPUX_dup                    41
+#define __NR_HPUX_pipe                   42
+#define __NR_HPUX_times                  43
+#define __NR_HPUX_profil                 44
+#define __NR_HPUX_ki_call                45
+#define __NR_HPUX_setgid                 46
+#define __NR_HPUX_getgid                 47
+#define __NR_HPUX_sigsys                 48
+#define __NR_HPUX_reserved1              49
+#define __NR_HPUX_reserved2              50
+#define __NR_HPUX_acct                   51
+#define __NR_HPUX_set_userthreadid       52
+#define __NR_HPUX_oldlock                53
+#define __NR_HPUX_ioctl                  54
+#define __NR_HPUX_reboot                 55
+#define __NR_HPUX_symlink                56
+#define __NR_HPUX_utssys                 57
+#define __NR_HPUX_readlink               58
+#define __NR_HPUX_execve                 59
+#define __NR_HPUX_umask                  60
+#define __NR_HPUX_chroot                 61
+#define __NR_HPUX_fcntl                  62
+#define __NR_HPUX_ulimit                 63
+#define __NR_HPUX_getpagesize            64
+#define __NR_HPUX_mremap                 65
+#define __NR_HPUX_vfork                  66
+#define __NR_HPUX_vread                  67
+#define __NR_HPUX_vwrite                 68
+#define __NR_HPUX_sbrk                   69
+#define __NR_HPUX_sstk                   70
+#define __NR_HPUX_mmap                   71
+#define __NR_HPUX_vadvise                72
+#define __NR_HPUX_munmap                 73
+#define __NR_HPUX_mprotect               74
+#define __NR_HPUX_madvise                75
+#define __NR_HPUX_vhangup                76
+#define __NR_HPUX_swapoff                77
+#define __NR_HPUX_mincore                78
+#define __NR_HPUX_getgroups              79
+#define __NR_HPUX_setgroups              80
+#define __NR_HPUX_getpgrp2               81
+#define __NR_HPUX_setpgrp2               82
+#define __NR_HPUX_setitimer              83
+#define __NR_HPUX_wait3                  84
+#define __NR_HPUX_swapon                 85
+#define __NR_HPUX_getitimer              86
+#define __NR_HPUX_gethostname42          87
+#define __NR_HPUX_sethostname42          88
+#define __NR_HPUX_getdtablesize          89
+#define __NR_HPUX_dup2                   90
+#define __NR_HPUX_getdopt                91
+#define __NR_HPUX_fstat                  92
+#define __NR_HPUX_select                 93
+#define __NR_HPUX_setdopt                94
+#define __NR_HPUX_fsync                  95
+#define __NR_HPUX_setpriority            96
+#define __NR_HPUX_socket_old             97
+#define __NR_HPUX_connect_old            98
+#define __NR_HPUX_accept_old             99
+#define __NR_HPUX_getpriority           100
+#define __NR_HPUX_send_old              101
+#define __NR_HPUX_recv_old              102
+#define __NR_HPUX_socketaddr_old        103
+#define __NR_HPUX_bind_old              104
+#define __NR_HPUX_setsockopt_old        105
+#define __NR_HPUX_listen_old            106
+#define __NR_HPUX_vtimes_old            107
+#define __NR_HPUX_sigvector             108
+#define __NR_HPUX_sigblock              109
+#define __NR_HPUX_siggetmask            110
+#define __NR_HPUX_sigpause              111
+#define __NR_HPUX_sigstack              112
+#define __NR_HPUX_recvmsg_old           113
+#define __NR_HPUX_sendmsg_old           114
+#define __NR_HPUX_vtrace_old            115
+#define __NR_HPUX_gettimeofday          116
+#define __NR_HPUX_getrusage             117
+#define __NR_HPUX_getsockopt_old        118
+#define __NR_HPUX_resuba_old            119
+#define __NR_HPUX_readv                 120
+#define __NR_HPUX_writev                121
+#define __NR_HPUX_settimeofday          122
+#define __NR_HPUX_fchown                123
+#define __NR_HPUX_fchmod                124
+#define __NR_HPUX_recvfrom_old          125
+#define __NR_HPUX_setresuid             126
+#define __NR_HPUX_setresgid             127
+#define __NR_HPUX_rename                128
+#define __NR_HPUX_truncate              129
+#define __NR_HPUX_ftruncate             130
+#define __NR_HPUX_flock_old             131
+#define __NR_HPUX_sysconf               132
+#define __NR_HPUX_sendto_old            133
+#define __NR_HPUX_shutdown_old          134
+#define __NR_HPUX_socketpair_old        135
+#define __NR_HPUX_mkdir                 136
+#define __NR_HPUX_rmdir                 137
+#define __NR_HPUX_utimes_old            138
+#define __NR_HPUX_sigcleanup_old        139
+#define __NR_HPUX_setcore               140
+#define __NR_HPUX_getpeername_old       141
+#define __NR_HPUX_gethostid             142
+#define __NR_HPUX_sethostid             143
+#define __NR_HPUX_getrlimit             144
+#define __NR_HPUX_setrlimit             145
+#define __NR_HPUX_killpg_old            146
+#define __NR_HPUX_cachectl              147
+#define __NR_HPUX_quotactl              148
+#define __NR_HPUX_get_sysinfo           149
+#define __NR_HPUX_getsockname_old       150
+#define __NR_HPUX_privgrp               151
+#define __NR_HPUX_rtprio                152
+#define __NR_HPUX_plock                 153
+#define __NR_HPUX_reserved3             154
+#define __NR_HPUX_lockf                 155
+#define __NR_HPUX_semget                156
+#define __NR_HPUX_osemctl               157
+#define __NR_HPUX_semop                 158
+#define __NR_HPUX_msgget                159
+#define __NR_HPUX_omsgctl               160
+#define __NR_HPUX_msgsnd                161
+#define __NR_HPUX_msgrecv               162
+#define __NR_HPUX_shmget                163
+#define __NR_HPUX_oshmctl               164
+#define __NR_HPUX_shmat                 165
+#define __NR_HPUX_shmdt                 166
+#define __NR_HPUX_m68020_advise         167
+/* [168,189] are for Discless/DUX */
+#define __NR_HPUX_csp                   168
+#define __NR_HPUX_cluster               169
+#define __NR_HPUX_mkrnod                170
+#define __NR_HPUX_test                  171
+#define __NR_HPUX_unsp_open             172
+#define __NR_HPUX_reserved4             173
+#define __NR_HPUX_getcontext_old        174
+#define __NR_HPUX_osetcontext           175
+#define __NR_HPUX_bigio                 176
+#define __NR_HPUX_pipenode              177
+#define __NR_HPUX_lsync                 178
+#define __NR_HPUX_getmachineid          179
+#define __NR_HPUX_cnodeid               180
+#define __NR_HPUX_cnodes                181
+#define __NR_HPUX_swapclients           182
+#define __NR_HPUX_rmt_process           183
+#define __NR_HPUX_dskless_stats         184
+#define __NR_HPUX_sigprocmask           185
+#define __NR_HPUX_sigpending            186
+#define __NR_HPUX_sigsuspend            187
+#define __NR_HPUX_sigaction             188
+#define __NR_HPUX_reserved5             189
+#define __NR_HPUX_nfssvc                190
+#define __NR_HPUX_getfh                 191
+#define __NR_HPUX_getdomainname         192
+#define __NR_HPUX_setdomainname         193
+#define __NR_HPUX_async_daemon          194
+#define __NR_HPUX_getdirentries         195
+#define __NR_HPUX_statfs                196
+#define __NR_HPUX_fstatfs               197
+#define __NR_HPUX_vfsmount              198
+#define __NR_HPUX_reserved6             199
+#define __NR_HPUX_waitpid               200
+/* 201 - 223 missing */
+#define __NR_HPUX_sigsetreturn          224
+#define __NR_HPUX_sigsetstatemask       225
+/* 226 missing */
+#define __NR_HPUX_cs                    227
+#define __NR_HPUX_cds                   228
+#define __NR_HPUX_set_no_trunc          229
+#define __NR_HPUX_pathconf              230
+#define __NR_HPUX_fpathconf             231
+/* 232, 233 missing */
+#define __NR_HPUX_nfs_fcntl             234
+#define __NR_HPUX_ogetacl               235
+#define __NR_HPUX_ofgetacl              236
+#define __NR_HPUX_osetacl               237
+#define __NR_HPUX_ofsetacl              238
+#define __NR_HPUX_pstat                 239
+#define __NR_HPUX_getaudid              240
+#define __NR_HPUX_setaudid              241
+#define __NR_HPUX_getaudproc            242
+#define __NR_HPUX_setaudproc            243
+#define __NR_HPUX_getevent              244
+#define __NR_HPUX_setevent              245
+#define __NR_HPUX_audwrite              246
+#define __NR_HPUX_audswitch             247
+#define __NR_HPUX_audctl                248
+#define __NR_HPUX_ogetaccess            249
+#define __NR_HPUX_fsctl                 250
+/* 251 - 258 missing */
+#define __NR_HPUX_swapfs                259
+#define __NR_HPUX_fss                   260
+/* 261 - 266 missing */
+#define __NR_HPUX_tsync                 267
+#define __NR_HPUX_getnumfds             268
+#define __NR_HPUX_poll                  269
+#define __NR_HPUX_getmsg                270
+#define __NR_HPUX_putmsg                271
+#define __NR_HPUX_fchdir                272
+#define __NR_HPUX_getmount_cnt          273
+#define __NR_HPUX_getmount_entry        274
+#define __NR_HPUX_accept                275
+#define __NR_HPUX_bind                  276
+#define __NR_HPUX_connect               277
+#define __NR_HPUX_getpeername           278
+#define __NR_HPUX_getsockname           279
+#define __NR_HPUX_getsockopt            280
+#define __NR_HPUX_listen                281
+#define __NR_HPUX_recv                  282
+#define __NR_HPUX_recvfrom              283
+#define __NR_HPUX_recvmsg               284
+#define __NR_HPUX_send                  285
+#define __NR_HPUX_sendmsg               286
+#define __NR_HPUX_sendto                287
+#define __NR_HPUX_setsockopt            288
+#define __NR_HPUX_shutdown              289
+#define __NR_HPUX_socket                290
+#define __NR_HPUX_socketpair            291
+#define __NR_HPUX_proc_open             292
+#define __NR_HPUX_proc_close            293
+#define __NR_HPUX_proc_send             294
+#define __NR_HPUX_proc_recv             295
+#define __NR_HPUX_proc_sendrecv         296
+#define __NR_HPUX_proc_syscall          297
+/* 298 - 311 missing */
+#define __NR_HPUX_semctl                312
+#define __NR_HPUX_msgctl                313
+#define __NR_HPUX_shmctl                314
+#define __NR_HPUX_mpctl                 315
+#define __NR_HPUX_exportfs              316
+#define __NR_HPUX_getpmsg               317
+#define __NR_HPUX_putpmsg               318
+/* 319 missing */
+#define __NR_HPUX_msync                 320
+#define __NR_HPUX_msleep                321
+#define __NR_HPUX_mwakeup               322
+#define __NR_HPUX_msem_init             323
+#define __NR_HPUX_msem_remove           324
+#define __NR_HPUX_adjtime               325
+#define __NR_HPUX_kload                 326
+#define __NR_HPUX_fattach               327
+#define __NR_HPUX_fdetach               328
+#define __NR_HPUX_serialize             329
+#define __NR_HPUX_statvfs               330
+#define __NR_HPUX_fstatvfs              331
+#define __NR_HPUX_lchown                332
+#define __NR_HPUX_getsid                333
+#define __NR_HPUX_sysfs                 334
+/* 335, 336 missing */
+#define __NR_HPUX_sched_setparam        337
+#define __NR_HPUX_sched_getparam        338
+#define __NR_HPUX_sched_setscheduler    339
+#define __NR_HPUX_sched_getscheduler    340
+#define __NR_HPUX_sched_yield           341
+#define __NR_HPUX_sched_get_priority_max 342
+#define __NR_HPUX_sched_get_priority_min 343
+#define __NR_HPUX_sched_rr_get_interval 344
+#define __NR_HPUX_clock_settime         345
+#define __NR_HPUX_clock_gettime         346
+#define __NR_HPUX_clock_getres          347
+#define __NR_HPUX_timer_create          348
+#define __NR_HPUX_timer_delete          349
+#define __NR_HPUX_timer_settime         350
+#define __NR_HPUX_timer_gettime         351
+#define __NR_HPUX_timer_getoverrun      352
+#define __NR_HPUX_nanosleep             353
+#define __NR_HPUX_toolbox               354
+/* 355 missing */
+#define __NR_HPUX_getdents              356
+#define __NR_HPUX_getcontext            357
+#define __NR_HPUX_sysinfo               358
+#define __NR_HPUX_fcntl64               359
+#define __NR_HPUX_ftruncate64           360
+#define __NR_HPUX_fstat64               361
+#define __NR_HPUX_getdirentries64       362
+#define __NR_HPUX_getrlimit64           363
+#define __NR_HPUX_lockf64               364
+#define __NR_HPUX_lseek64               365
+#define __NR_HPUX_lstat64               366
+#define __NR_HPUX_mmap64                367
+#define __NR_HPUX_setrlimit64           368
+#define __NR_HPUX_stat64                369
+#define __NR_HPUX_truncate64            370
+#define __NR_HPUX_ulimit64              371
+#define __NR_HPUX_pread                 372
+#define __NR_HPUX_preadv                373
+#define __NR_HPUX_pwrite                374
+#define __NR_HPUX_pwritev               375
+#define __NR_HPUX_pread64               376
+#define __NR_HPUX_preadv64              377
+#define __NR_HPUX_pwrite64              378
+#define __NR_HPUX_pwritev64             379
+#define __NR_HPUX_setcontext            380
+#define __NR_HPUX_sigaltstack           381
+#define __NR_HPUX_waitid                382
+#define __NR_HPUX_setpgrp               383
+#define __NR_HPUX_recvmsg2              384
+#define __NR_HPUX_sendmsg2              385
+#define __NR_HPUX_socket2               386
+#define __NR_HPUX_socketpair2           387
+#define __NR_HPUX_setregid              388
+#define __NR_HPUX_lwp_create            389
+#define __NR_HPUX_lwp_terminate         390
+#define __NR_HPUX_lwp_wait              391
+#define __NR_HPUX_lwp_suspend           392
+#define __NR_HPUX_lwp_resume            393
+/* 394 missing */
+#define __NR_HPUX_lwp_abort_syscall     395
+#define __NR_HPUX_lwp_info              396
+#define __NR_HPUX_lwp_kill              397
+#define __NR_HPUX_ksleep                398
+#define __NR_HPUX_kwakeup               399
+/* 400 missing */
+#define __NR_HPUX_pstat_getlwp          401
+#define __NR_HPUX_lwp_exit              402
+#define __NR_HPUX_lwp_continue          403
+#define __NR_HPUX_getacl                404
+#define __NR_HPUX_fgetacl               405
+#define __NR_HPUX_setacl                406
+#define __NR_HPUX_fsetacl               407
+#define __NR_HPUX_getaccess             408
+#define __NR_HPUX_lwp_mutex_init        409
+#define __NR_HPUX_lwp_mutex_lock_sys    410
+#define __NR_HPUX_lwp_mutex_unlock      411
+#define __NR_HPUX_lwp_cond_init         412
+#define __NR_HPUX_lwp_cond_signal       413
+#define __NR_HPUX_lwp_cond_broadcast    414
+#define __NR_HPUX_lwp_cond_wait_sys     415
+#define __NR_HPUX_lwp_getscheduler      416
+#define __NR_HPUX_lwp_setscheduler      417
+#define __NR_HPUX_lwp_getstate          418
+#define __NR_HPUX_lwp_setstate          419
+#define __NR_HPUX_lwp_detach            420
+#define __NR_HPUX_mlock                 421
+#define __NR_HPUX_munlock               422
+#define __NR_HPUX_mlockall              423
+#define __NR_HPUX_munlockall            424
+#define __NR_HPUX_shm_open              425
+#define __NR_HPUX_shm_unlink            426
+#define __NR_HPUX_sigqueue              427
+#define __NR_HPUX_sigwaitinfo           428
+#define __NR_HPUX_sigtimedwait          429
+#define __NR_HPUX_sigwait               430
+#define __NR_HPUX_aio_read              431
+#define __NR_HPUX_aio_write             432
+#define __NR_HPUX_lio_listio            433
+#define __NR_HPUX_aio_error             434
+#define __NR_HPUX_aio_return            435
+#define __NR_HPUX_aio_cancel            436
+#define __NR_HPUX_aio_suspend           437
+#define __NR_HPUX_aio_fsync             438
+#define __NR_HPUX_mq_open               439
+#define __NR_HPUX_mq_close              440
+#define __NR_HPUX_mq_unlink             441
+#define __NR_HPUX_mq_send               442
+#define __NR_HPUX_mq_receive            443
+#define __NR_HPUX_mq_notify             444
+#define __NR_HPUX_mq_setattr            445
+#define __NR_HPUX_mq_getattr            446
+#define __NR_HPUX_ksem_open             447
+#define __NR_HPUX_ksem_unlink           448
+#define __NR_HPUX_ksem_close            449
+#define __NR_HPUX_ksem_post             450
+#define __NR_HPUX_ksem_wait             451
+#define __NR_HPUX_ksem_read             452
+#define __NR_HPUX_ksem_trywait          453
+#define __NR_HPUX_lwp_rwlock_init       454
+#define __NR_HPUX_lwp_rwlock_destroy    455
+#define __NR_HPUX_lwp_rwlock_rdlock_sys 456
+#define __NR_HPUX_lwp_rwlock_wrlock_sys 457
+#define __NR_HPUX_lwp_rwlock_tryrdlock  458
+#define __NR_HPUX_lwp_rwlock_trywrlock  459
+#define __NR_HPUX_lwp_rwlock_unlock     460
+#define __NR_HPUX_ttrace                461
+#define __NR_HPUX_ttrace_wait           462
+#define __NR_HPUX_lf_wire_mem           463
+#define __NR_HPUX_lf_unwire_mem         464
+#define __NR_HPUX_lf_send_pin_map       465
+#define __NR_HPUX_lf_free_buf           466
+#define __NR_HPUX_lf_wait_nq            467
+#define __NR_HPUX_lf_wakeup_conn_q      468
+#define __NR_HPUX_lf_unused             469
+#define __NR_HPUX_lwp_sema_init         470
+#define __NR_HPUX_lwp_sema_post         471
+#define __NR_HPUX_lwp_sema_wait         472
+#define __NR_HPUX_lwp_sema_trywait      473
+#define __NR_HPUX_lwp_sema_destroy      474
+#define __NR_HPUX_statvfs64             475
+#define __NR_HPUX_fstatvfs64            476
+#define __NR_HPUX_msh_register          477
+#define __NR_HPUX_ptrace64              478
+#define __NR_HPUX_sendfile              479
+#define __NR_HPUX_sendpath              480
+#define __NR_HPUX_sendfile64            481
+#define __NR_HPUX_sendpath64            482
+#define __NR_HPUX_modload               483
+#define __NR_HPUX_moduload              484
+#define __NR_HPUX_modpath               485
+#define __NR_HPUX_getksym               486
+#define __NR_HPUX_modadm                487
+#define __NR_HPUX_modstat               488
+#define __NR_HPUX_lwp_detached_exit     489
+#define __NR_HPUX_crashconf             490
+#define __NR_HPUX_siginhibit            491
+#define __NR_HPUX_sigenable             492
+#define __NR_HPUX_spuctl                493
+#define __NR_HPUX_zerokernelsum         494
+#define __NR_HPUX_nfs_kstat             495
+#define __NR_HPUX_aio_read64            496
+#define __NR_HPUX_aio_write64           497
+#define __NR_HPUX_aio_error64           498
+#define __NR_HPUX_aio_return64          499
+#define __NR_HPUX_aio_cancel64          500
+#define __NR_HPUX_aio_suspend64         501
+#define __NR_HPUX_aio_fsync64           502
+#define __NR_HPUX_lio_listio64          503
+#define __NR_HPUX_recv2                 504
+#define __NR_HPUX_recvfrom2             505
+#define __NR_HPUX_send2                 506
+#define __NR_HPUX_sendto2               507
+#define __NR_HPUX_acl                   508
+#define __NR_HPUX___cnx_p2p_ctl         509
+#define __NR_HPUX___cnx_gsched_ctl      510
+#define __NR_HPUX___cnx_pmon_ctl        511
+
+#define __NR_HPUX_syscalls             512
+
+/*
+ * Linux system call numbers.
+ *
+ * Cary Coutant says that we should just use another syscall gateway
+ * page to avoid clashing with the HPUX space, and I think he's right:
+ * it will would keep a branch out of our syscall entry path, at the
+ * very least.  If we decide to change it later, we can ``just'' tweak
+ * the LINUX_GATEWAY_ADDR define at the bottom and make __NR_Linux be
+ * 1024 or something.  Oh, and recompile libc. =)
+ *
+ * 64-bit HPUX binaries get the syscall gateway address passed in a register
+ * from the kernel at startup, which seems a sane strategy.
+ */
+
+#define __NR_Linux                0
+#define __NR_syscall              (__NR_Linux + 0)
+#define __NR_exit                 (__NR_Linux + 1)
+#define __NR_fork                 (__NR_Linux + 2)
+#define __NR_read                 (__NR_Linux + 3)
+#define __NR_write                (__NR_Linux + 4)
+#define __NR_open                 (__NR_Linux + 5)
+#define __NR_close                (__NR_Linux + 6)
+#define __NR_waitpid              (__NR_Linux + 7)
+#define __NR_creat                (__NR_Linux + 8)
+#define __NR_link                 (__NR_Linux + 9)
+#define __NR_unlink              (__NR_Linux + 10)
+#define __NR_execve              (__NR_Linux + 11)
+#define __NR_chdir               (__NR_Linux + 12)
+#define __NR_time                (__NR_Linux + 13)
+#define __NR_mknod               (__NR_Linux + 14)
+#define __NR_chmod               (__NR_Linux + 15)
+#define __NR_lchown              (__NR_Linux + 16)
+#define __NR_socket              (__NR_Linux + 17)
+#define __NR_stat                (__NR_Linux + 18)
+#define __NR_lseek               (__NR_Linux + 19)
+#define __NR_getpid              (__NR_Linux + 20)
+#define __NR_mount               (__NR_Linux + 21)
+#define __NR_bind                (__NR_Linux + 22)
+#define __NR_setuid              (__NR_Linux + 23)
+#define __NR_getuid              (__NR_Linux + 24)
+#define __NR_stime               (__NR_Linux + 25)
+#define __NR_ptrace              (__NR_Linux + 26)
+#define __NR_alarm               (__NR_Linux + 27)
+#define __NR_fstat               (__NR_Linux + 28)
+#define __NR_pause               (__NR_Linux + 29)
+#define __NR_utime               (__NR_Linux + 30)
+#define __NR_connect             (__NR_Linux + 31)
+#define __NR_listen              (__NR_Linux + 32)
+#define __NR_access              (__NR_Linux + 33)
+#define __NR_nice                (__NR_Linux + 34)
+#define __NR_accept              (__NR_Linux + 35)
+#define __NR_sync                (__NR_Linux + 36)
+#define __NR_kill                (__NR_Linux + 37)
+#define __NR_rename              (__NR_Linux + 38)
+#define __NR_mkdir               (__NR_Linux + 39)
+#define __NR_rmdir               (__NR_Linux + 40)
+#define __NR_dup                 (__NR_Linux + 41)
+#define __NR_pipe                (__NR_Linux + 42)
+#define __NR_times               (__NR_Linux + 43)
+#define __NR_getsockname         (__NR_Linux + 44)
+#define __NR_brk                 (__NR_Linux + 45)
+#define __NR_setgid              (__NR_Linux + 46)
+#define __NR_getgid              (__NR_Linux + 47)
+#define __NR_signal              (__NR_Linux + 48)
+#define __NR_geteuid             (__NR_Linux + 49)
+#define __NR_getegid             (__NR_Linux + 50)
+#define __NR_acct                (__NR_Linux + 51)
+#define __NR_umount2             (__NR_Linux + 52)
+#define __NR_getpeername         (__NR_Linux + 53)
+#define __NR_ioctl               (__NR_Linux + 54)
+#define __NR_fcntl               (__NR_Linux + 55)
+#define __NR_socketpair          (__NR_Linux + 56)
+#define __NR_setpgid             (__NR_Linux + 57)
+#define __NR_send                (__NR_Linux + 58)
+#define __NR_uname               (__NR_Linux + 59)
+#define __NR_umask               (__NR_Linux + 60)
+#define __NR_chroot              (__NR_Linux + 61)
+#define __NR_ustat               (__NR_Linux + 62)
+#define __NR_dup2                (__NR_Linux + 63)
+#define __NR_getppid             (__NR_Linux + 64)
+#define __NR_getpgrp             (__NR_Linux + 65)
+#define __NR_setsid              (__NR_Linux + 66)
+#define __NR_pivot_root          (__NR_Linux + 67)
+#define __NR_sgetmask            (__NR_Linux + 68)
+#define __NR_ssetmask            (__NR_Linux + 69)
+#define __NR_setreuid            (__NR_Linux + 70)
+#define __NR_setregid            (__NR_Linux + 71)
+#define __NR_mincore             (__NR_Linux + 72)
+#define __NR_sigpending          (__NR_Linux + 73)
+#define __NR_sethostname         (__NR_Linux + 74)
+#define __NR_setrlimit           (__NR_Linux + 75)
+#define __NR_getrlimit           (__NR_Linux + 76)
+#define __NR_getrusage           (__NR_Linux + 77)
+#define __NR_gettimeofday        (__NR_Linux + 78)
+#define __NR_settimeofday        (__NR_Linux + 79)
+#define __NR_getgroups           (__NR_Linux + 80)
+#define __NR_setgroups           (__NR_Linux + 81)
+#define __NR_sendto              (__NR_Linux + 82)
+#define __NR_symlink             (__NR_Linux + 83)
+#define __NR_lstat               (__NR_Linux + 84)
+#define __NR_readlink            (__NR_Linux + 85)
+#define __NR_uselib              (__NR_Linux + 86)
+#define __NR_swapon              (__NR_Linux + 87)
+#define __NR_reboot              (__NR_Linux + 88)
+#define __NR_readdir             (__NR_Linux + 89)
+#define __NR_mmap                (__NR_Linux + 90)
+#define __NR_munmap              (__NR_Linux + 91)
+#define __NR_truncate            (__NR_Linux + 92)
+#define __NR_ftruncate           (__NR_Linux + 93)
+#define __NR_fchmod              (__NR_Linux + 94)
+#define __NR_fchown              (__NR_Linux + 95)
+#define __NR_getpriority         (__NR_Linux + 96)
+#define __NR_setpriority         (__NR_Linux + 97)
+#define __NR_recv                (__NR_Linux + 98)
+#define __NR_statfs              (__NR_Linux + 99)
+#define __NR_fstatfs            (__NR_Linux + 100)
+#define __NR_ioperm             (__NR_Linux + 101)
+#define __NR_socketcall         (__NR_Linux + 102)
+#define __NR_syslog             (__NR_Linux + 103)
+#define __NR_setitimer          (__NR_Linux + 104)
+#define __NR_getitimer          (__NR_Linux + 105)
+#define __NR_capget             (__NR_Linux + 106)
+#define __NR_capset             (__NR_Linux + 107)
+#define __NR_pread              (__NR_Linux + 108)
+#define __NR_pwrite             (__NR_Linux + 109)
+#define __NR_getcwd             (__NR_Linux + 110)
+#define __NR_vhangup            (__NR_Linux + 111)
+#define __NR_idle               (__NR_Linux + 112)
+#define __NR_vfork              (__NR_Linux + 113)
+#define __NR_wait4              (__NR_Linux + 114)
+#define __NR_swapoff            (__NR_Linux + 115)
+#define __NR_sysinfo            (__NR_Linux + 116)
+#define __NR_shutdown           (__NR_Linux + 117)
+#define __NR_fsync              (__NR_Linux + 118)
+#define __NR_madvise            (__NR_Linux + 119)
+#define __NR_clone              (__NR_Linux + 120)
+#define __NR_setdomainname      (__NR_Linux + 121)
+#define __NR_sendfile           (__NR_Linux + 122)
+#define __NR_recvfrom           (__NR_Linux + 123)
+#define __NR_adjtimex           (__NR_Linux + 124)
+#define __NR_mprotect           (__NR_Linux + 125)
+#define __NR_sigprocmask        (__NR_Linux + 126)
+#define __NR_create_module      (__NR_Linux + 127)
+#define __NR_init_module        (__NR_Linux + 128)
+#define __NR_delete_module      (__NR_Linux + 129)
+#define __NR_get_kernel_syms    (__NR_Linux + 130)
+#define __NR_quotactl           (__NR_Linux + 131)
+#define __NR_getpgid            (__NR_Linux + 132)
+#define __NR_fchdir             (__NR_Linux + 133)
+#define __NR_bdflush            (__NR_Linux + 134)
+#define __NR_sysfs              (__NR_Linux + 135)
+#define __NR_personality        (__NR_Linux + 136)
+#define __NR_afs_syscall        (__NR_Linux + 137) /* Syscall for Andrew File System */
+#define __NR_setfsuid           (__NR_Linux + 138)
+#define __NR_setfsgid           (__NR_Linux + 139)
+#define __NR__llseek            (__NR_Linux + 140)
+#define __NR_getdents           (__NR_Linux + 141)
+#define __NR__newselect         (__NR_Linux + 142)
+#define __NR_flock              (__NR_Linux + 143)
+#define __NR_msync              (__NR_Linux + 144)
+#define __NR_readv              (__NR_Linux + 145)
+#define __NR_writev             (__NR_Linux + 146)
+#define __NR_getsid             (__NR_Linux + 147)
+#define __NR_fdatasync          (__NR_Linux + 148)
+#define __NR__sysctl            (__NR_Linux + 149)
+#define __NR_mlock              (__NR_Linux + 150)
+#define __NR_munlock            (__NR_Linux + 151)
+#define __NR_mlockall           (__NR_Linux + 152)
+#define __NR_munlockall         (__NR_Linux + 153)
+#define __NR_sched_setparam             (__NR_Linux + 154)
+#define __NR_sched_getparam             (__NR_Linux + 155)
+#define __NR_sched_setscheduler         (__NR_Linux + 156)
+#define __NR_sched_getscheduler         (__NR_Linux + 157)
+#define __NR_sched_yield                (__NR_Linux + 158)
+#define __NR_sched_get_priority_max     (__NR_Linux + 159)
+#define __NR_sched_get_priority_min     (__NR_Linux + 160)
+#define __NR_sched_rr_get_interval      (__NR_Linux + 161)
+#define __NR_nanosleep          (__NR_Linux + 162)
+#define __NR_mremap             (__NR_Linux + 163)
+#define __NR_setresuid          (__NR_Linux + 164)
+#define __NR_getresuid          (__NR_Linux + 165)
+#define __NR_sigaltstack        (__NR_Linux + 166)
+#define __NR_query_module       (__NR_Linux + 167)
+#define __NR_poll               (__NR_Linux + 168)
+#define __NR_nfsservctl         (__NR_Linux + 169)
+#define __NR_setresgid          (__NR_Linux + 170)
+#define __NR_getresgid          (__NR_Linux + 171)
+#define __NR_prctl              (__NR_Linux + 172)
+#define __NR_rt_sigreturn       (__NR_Linux + 173)
+#define __NR_rt_sigaction       (__NR_Linux + 174)
+#define __NR_rt_sigprocmask     (__NR_Linux + 175)
+#define __NR_rt_sigpending      (__NR_Linux + 176)
+#define __NR_rt_sigtimedwait    (__NR_Linux + 177)
+#define __NR_rt_sigqueueinfo    (__NR_Linux + 178)
+#define __NR_rt_sigsuspend      (__NR_Linux + 179)
+#define __NR_chown              (__NR_Linux + 180)
+#define __NR_setsockopt         (__NR_Linux + 181)
+#define __NR_getsockopt         (__NR_Linux + 182)
+#define __NR_sendmsg            (__NR_Linux + 183)
+#define __NR_recvmsg            (__NR_Linux + 184)
+#define __NR_semop              (__NR_Linux + 185)
+#define __NR_semget             (__NR_Linux + 186)
+#define __NR_semctl             (__NR_Linux + 187)
+#define __NR_msgsnd             (__NR_Linux + 188)
+#define __NR_msgrcv             (__NR_Linux + 189)
+#define __NR_msgget             (__NR_Linux + 190)
+#define __NR_msgctl             (__NR_Linux + 191)
+#define __NR_shmat              (__NR_Linux + 192)
+#define __NR_shmdt              (__NR_Linux + 193)
+#define __NR_shmget             (__NR_Linux + 194)
+#define __NR_shmctl             (__NR_Linux + 195)
+
+#define __NR_getpmsg            (__NR_Linux + 196)      /* some people actually want streams */
+#define __NR_putpmsg            (__NR_Linux + 197)      /* some people actually want streams */
+
+#define __NR_Linux_syscalls     197
+
+#define HPUX_GATEWAY_ADDR       0xC0000004
+#define LINUX_GATEWAY_ADDR      0x100
+#define LINUX_GATEWAY_STR       "0x100"
+
+/* The old syscall code here didn't work, and it looks like it's only used
+ * by applications such as fdisk which for some reason need to produce
+ * their own syscall instead of using same from libc.  The code below
+ * is leveraged from glibc/sysdeps/unix/sysv/linux/hppa/sysdep.h where
+ * it is essentially duplicated -- which sucks.  -PB
+ */
+
+#define SYS_ify(syscall_name)   __NR_##syscall_name
+
+/* The system call number MUST ALWAYS be loaded in the delay slot of
+   the ble instruction, or restarting system calls WILL NOT WORK.  See
+   arch/parisc/kernel/signal.c - dhd, 2000-07-26 */
+#define K_INLINE_SYSCALL(name, nr, args...)       ({              \
+        unsigned long __sys_res;                                \
+        {                                                       \
+                register unsigned long __res asm("r28");        \
+                K_LOAD_ARGS_##nr(args)                            \
+                asm volatile(                                   \
+                       "ble  0x100(%%sr2, %%r0)\n\t"           \
+                        " ldi %1, %%r20"                        \
+                        : "=r" (__res)                          \
+                        : "i" (SYS_ify(name)) K_ASM_ARGS_##nr   \
+                         );                                    \
+                __sys_res = __res;                              \
+        }                                                       \
+        if (__sys_res >= (unsigned long)-4095) {                \
+               errno = -__sys_res;                             \
+                __sys_res == (unsigned long)-1;                 \
+        }                                                       \
+        __sys_res;                                              \
+})
+
+#define K_LOAD_ARGS_0()
+#define K_LOAD_ARGS_1(r26)                                        \
+        register unsigned long __r26 __asm__("r26") = (unsigned long)r26;       \
+        K_LOAD_ARGS_0()
+#define K_LOAD_ARGS_2(r26,r25)                                    \
+        register unsigned long __r25 __asm__("r25") = (unsigned long)r25;       \
+        K_LOAD_ARGS_1(r26)
+#define K_LOAD_ARGS_3(r26,r25,r24)                                \
+        register unsigned long __r24 __asm__("r24") = (unsigned long)r24;       \
+        K_LOAD_ARGS_2(r26,r25)
+#define K_LOAD_ARGS_4(r26,r25,r24,r23)                            \
+        register unsigned long __r23 __asm__("r23") = (unsigned long)r23;       \
+        K_LOAD_ARGS_3(r26,r25,r24)
+#define K_LOAD_ARGS_5(r26,r25,r24,r23,r22)                        \
+        register unsigned long __r22 __asm__("r22") = (unsigned long)r22;       \
+        K_LOAD_ARGS_4(r26,r25,r24,r23)
+#define K_LOAD_ARGS_6(r26,r25,r24,r23,r22,r21)                    \
+        register unsigned long __r21 __asm__("r21") = (unsigned long)r21;       \
+        K_LOAD_ARGS_5(r26,r25,r24,r23,r22)
+
+#define K_ASM_ARGS_0
+#define K_ASM_ARGS_1 , "r" (__r26)
+#define K_ASM_ARGS_2 , "r" (__r26), "r" (__r25)
+#define K_ASM_ARGS_3 , "r" (__r26), "r" (__r25), "r" (__r24)
+#define K_ASM_ARGS_4 , "r" (__r26), "r" (__r25), "r" (__r24), "r" (__r23)
+#define K_ASM_ARGS_5 , "r" (__r26), "r" (__r25), "r" (__r24), "r" (__r23), "r" (__r22)
+#define K_ASM_ARGS_6 , "r" (__r26), "r" (__r25), "r" (__r24), "r" (__r23), "r" (__r22), "r" (__r21)
+
+#define _syscall0(type,name)                                                 \
+type name(void)                                                                      \
+{                                                                            \
+    return K_INLINE_SYSCALL(name, 0);  \
+}
+
+#define _syscall1(type,name,type1,arg1)                                              \
+type name(type1 arg1)                                                        \
+{                                                                            \
+    return K_INLINE_SYSCALL(name, 1, arg1);    \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)                           \
+type name(type1 arg1, type2 arg2)                                            \
+{                                                                            \
+    return K_INLINE_SYSCALL(name, 2, arg1, arg2);      \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)                \
+type name(type1 arg1, type2 arg2, type3 arg3)                                \
+{                                                                            \
+    return K_INLINE_SYSCALL(name, 3, arg1, arg2, arg3);        \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)      \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4)                    \
+{                                                                            \
+    return K_INLINE_SYSCALL(name, 4, arg1, arg2, arg3, arg4);  \
+}
+
+/* select takes 5 arguments */
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)  \
+{                                                                      \
+    return K_INLINE_SYSCALL(name, 5, arg1, arg2, arg3, arg4, arg5);    \
+}
+
+
+/* mmap takes 6 arguments */
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \
+{                                                                      \
+    return K_INLINE_SYSCALL(name, 6, arg1, arg2, arg3, arg4, arg5, arg6);      \
+}
+
+#ifdef __KERNEL_SYSCALLS__
+
+static inline int idle(void)
+{
+       extern int sys_idle(void);
+       return sys_idle();
+}
+
+static inline int pause(void)
+{
+       extern int sys_pause(void);
+       return sys_pause();
+}
+
+static inline int sync(void)
+{
+       extern int sys_sync(void);
+       return sys_sync();
+}
+
+static inline pid_t setsid(void)
+{
+       extern int sys_setsid(void);
+       return sys_setsid();
+}
+
+static inline int write(int fd, const char *buf, off_t count)
+{
+       extern int sys_write(int, const char *, int);
+       return sys_write(fd, buf, count);
+}
+
+static inline int read(int fd, char *buf, off_t count)
+{
+       extern int sys_read(int, char *, int);
+       return sys_read(fd, buf, count);
+}
+
+static inline off_t lseek(int fd, off_t offset, int count)
+{
+       extern off_t sys_lseek(int, off_t, int);
+       return sys_lseek(fd, offset, count);
+}
+
+static inline int dup(int fd)
+{
+       extern int sys_dup(int);
+       return sys_dup(fd);
+}
+
+static inline int open(const char *file, int flag, int mode)
+{
+       extern long sys_open(const char *, int, int);
+       return sys_open(file, flag, mode);
+}
+
+static inline int close(int fd)
+{
+       return sys_close(fd);
+}
+
+static inline int _exit(int exitcode)
+{
+       extern int sys_exit(int) __attribute__((noreturn));
+       return sys_exit(exitcode);
+}
+
+static inline pid_t waitpid(pid_t pid, int *wait_stat, int options)
+{
+       extern int sys_wait4(int, int *, int, struct rusage *);
+       return sys_wait4((int)pid, wait_stat, options, NULL);
+}
+
+static inline int delete_module(const char *name)
+{
+       extern int sys_delete_module(const char *name);
+       return sys_delete_module(name);
+}
+
+static inline pid_t wait(int * wait_stat)
+{
+       extern int sys_wait4(int, int *, int, struct rusage *);
+       return sys_wait4(-1, wait_stat, 0, NULL);
+}
+
+static inline int execve(char *filename, char * argv [],
+       char * envp[])
+{
+       extern int __execve(char *, char **, char **, struct task_struct *);
+       return __execve(filename, argv, envp, current);
+}
+
+#endif
+
+#undef STR
+
+#endif /* _ASM_PARISC_UNISTD_H_ */
diff --git a/include/asm-parisc/user.h b/include/asm-parisc/user.h
new file mode 100644 (file)
index 0000000..8022475
--- /dev/null
@@ -0,0 +1,5 @@
+/* This file should not exist, but lots of generic code still includes
+   it. It's a hangover from old a.out days and the traditional core
+   dump format.  We are ELF-only, and so are our core dumps.  If we
+   need to support HP/UX core format then we'll do it here
+   eventually. */
index 2a55e6018b7ffd463577d7a8e12056f969c35d71..99a5444daab26dc595932d87bb8209073be8ddf8 100644 (file)
@@ -199,7 +199,7 @@ struct hdlcdrv_state {
 
        struct hdlcdrv_hdlcrx {
                struct hdlcdrv_hdlcbuffer hbuf;
-               int in_hdlc_rx;
+               long in_hdlc_rx;
                /* 0 = sync hunt, != 0 receiving */
                int rx_state;   
                unsigned int bitstream;
index 5d287bbb3315b69fcbb0165839b166818f167617..d5a9ff5d09e4af914e92ea935dcd70084f86a641 100644 (file)
@@ -41,14 +41,14 @@ extern int overflowgid;
 #ifdef CONFIG_UID16
 
 /* prevent uid mod 65536 effect by returning a default value for high UIDs */
-#define high2lowuid(uid) ((uid) > 65535) ? (old_uid_t)overflowuid : (old_uid_t)(uid)
-#define high2lowgid(gid) ((gid) > 65535) ? (old_gid_t)overflowgid : (old_gid_t)(gid)
+#define high2lowuid(uid) ((uid) > 65535 ? (old_uid_t)overflowuid : (old_uid_t)(uid))
+#define high2lowgid(gid) ((gid) > 65535 ? (old_gid_t)overflowgid : (old_gid_t)(gid))
 /*
  * -1 is different in 16 bits than it is in 32 bits
  * these macros are used by chown(), setreuid(), ...,
  */
-#define low2highuid(uid) ((uid) == (old_uid_t)-1) ? (uid_t)-1 : (uid_t)(uid)
-#define low2highgid(gid) ((gid) == (old_gid_t)-1) ? (gid_t)-1 : (gid_t)(gid)
+#define low2highuid(uid) ((uid) == (old_uid_t)-1 ? (uid_t)-1 : (uid_t)(uid))
+#define low2highgid(gid) ((gid) == (old_gid_t)-1 ? (gid_t)-1 : (gid_t)(gid))
 
 /* Avoid extra ifdefs with these macros */
 
@@ -67,13 +67,13 @@ extern int overflowgid;
 
 #define SET_UID16(var, uid)    do { ; } while (0)
 #define SET_GID16(var, gid)    do { ; } while (0)
-#define NEW_TO_OLD_UID(uid)    uid
-#define NEW_TO_OLD_GID(gid)    gid
+#define NEW_TO_OLD_UID(uid)    (uid)
+#define NEW_TO_OLD_GID(gid)    (gid)
 
-#define SET_OLDSTAT_UID(stat, uid)     (stat).st_uid = uid
-#define SET_OLDSTAT_GID(stat, gid)     (stat).st_gid = gid
-#define SET_STAT_UID(stat, uid)                (stat).st_uid = uid
-#define SET_STAT_GID(stat, gid)                (stat).st_gid = gid
+#define SET_OLDSTAT_UID(stat, uid)     (stat).st_uid = (uid)
+#define SET_OLDSTAT_GID(stat, gid)     (stat).st_gid = (gid)
+#define SET_STAT_UID(stat, uid)                (stat).st_uid = (uid)
+#define SET_STAT_GID(stat, gid)                (stat).st_gid = (gid)
 
 #endif /* CONFIG_UID16 */
 
@@ -97,10 +97,10 @@ extern int fs_overflowgid;
  * Since these macros are used in architectures that only need limited
  * 16-bit UID back compatibility, we won't use old_uid_t and old_gid_t
  */
-#define fs_high2lowuid(uid) (uid > 65535) ? (uid16_t)fs_overflowuid : (uid16_t)uid
-#define fs_high2lowgid(gid) (gid > 65535) ? (gid16_t)fs_overflowgid : (gid16_t)gid
+#define fs_high2lowuid(uid) ((uid) > 65535 ? (uid16_t)fs_overflowuid : (uid16_t)(uid))
+#define fs_high2lowgid(gid) ((gid) > 65535 ? (gid16_t)fs_overflowgid : (gid16_t)(gid))
 
-#define low_16_bits(x) x & 0xFFFF
-#define high_16_bits(x)        (x & 0xFFFF0000) >> 16
+#define low_16_bits(x) ((x) & 0xFFFF)
+#define high_16_bits(x)        (((x) & 0xFFFF0000) >> 16)
 
 #endif /* _LINUX_HIGHUID_H */
index 249cb01637df5a7a3411848d7ad7136cb8985873..61cbe14d80e5b858100f137d34e78f1e39473507 100644 (file)
@@ -345,7 +345,7 @@ __attribute__((section("__ksymtab"))) =                     \
 #endif /* MODULE */
 
 #ifdef CONFIG_MODULES
-#define SET_MODULE_OWNER(some_struct) do { some_struct->owner = THIS_MODULE; } while (0)
+#define SET_MODULE_OWNER(some_struct) do { (some_struct)->owner = THIS_MODULE; } while (0)
 #else
 #define SET_MODULE_OWNER(some_struct) do { } while (0)
 #endif
index 44bee2c1720635119c01f41a22c862d95947de06..757121a5ded6188aab4bc44bf8257fd715736bc3 100644 (file)
@@ -150,6 +150,7 @@ extern signed long FASTCALL(schedule_timeout(signed long timeout));
 asmlinkage void schedule(void);
 
 extern void schedule_task(struct tq_struct *task);
+extern int start_context_thread(void);
 
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
index a4f6e22781c1a778f9d3467eb46a30a57a76926e..072f89508a13fd51c19f4494a313fd27865ff537 100644 (file)
@@ -75,7 +75,7 @@ typedef struct stlport {
        int                     ioaddr;
        int                     uartaddr;
        int                     pagenr;
-       int                     istate;
+       long                    istate;
        int                     flags;
        int                     baud_base;
        int                     custom_divisor;
index bb5bebde0be1741a74ca0f0d1f6a9c30b7ac4c08..642c8bd7e29c9a18ca50db1e32d44b652bb1f364 100644 (file)
@@ -360,7 +360,6 @@ extern int rp_init(void);
 extern int cy_init(void);
 extern int stl_init(void);
 extern int stli_init(void);
-extern int riscom8_init(void);
 extern int specialix_init(void);
 extern int espserial_init(void);
 extern int macserial_init(void);
index 2828238ac04de9ec43059c63b51f2b7c0031349a..42f0011cdc6e8fd9f1f665f4282da05455c3ec63 100644 (file)
@@ -412,7 +412,7 @@ typedef struct urb
        struct usb_device *dev;         // pointer to associated USB device
        unsigned int pipe;              // pipe information
        int status;                     // returned status
-       unsigned int transfer_flags;    // USB_DISABLE_SPD | USB_ISO_ASAP | USB_URB_EARLY_COMPLETE
+       unsigned int transfer_flags;    // USB_DISABLE_SPD | USB_ISO_ASAP | etc.
        void *transfer_buffer;          // associated data buffer
        int transfer_buffer_length;     // data buffer length
        int actual_length;              // actual data buffer length    
@@ -428,7 +428,7 @@ typedef struct urb
        void *context;                  // context for completion routine
        usb_complete_t complete;        // pointer to completion routine
        //
-       iso_packet_descriptor_t  iso_frame_desc[0];
+       iso_packet_descriptor_t iso_frame_desc[0];
 } urb_t, *purb_t;
 
 #define FILL_CONTROL_URB(a,aa,b,c,d,e,f,g) \
index 736493d1da0ef88589671c262807b94c9d1f7572..415454f5f2b601d898fd387b55f44c5ae6508585 100644 (file)
@@ -442,7 +442,7 @@ typedef struct wan_device
        char api_status;                /* device api status */
        struct net_device_stats stats;  /* interface statistics */
        unsigned reserved[16];          /* reserved for future use */
-       unsigned critical;              /* critical section flag */
+       unsigned long critical;         /* critical section flag */
                                        /****** device management methods ***/
        int (*setup) (struct wan_device *wandev, wandev_conf_t *conf);
        int (*shutdown) (struct wan_device *wandev);
index d7d56607515e199a8032de084be96c6cac0d1469..c1e83578b4c525b5de46e95c1998f40110184200 100644 (file)
@@ -700,6 +700,7 @@ static void __init do_basic_setup(void)
        else mount_initrd =0;
 #endif
 
+       start_context_thread();
        do_initcalls();
 
        /* .. filesystems .. */
@@ -712,7 +713,10 @@ static void __init do_basic_setup(void)
        init_pcmcia_ds();               /* Do this last */
 #endif
 
-#ifdef CONFIG_HOTPLUG
+       /* Mount the root filesystem.. */
+       mount_root();
+
+#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
        /* do this after other 'do this last' stuff, because we want
         * to minimize spurious executions of /sbin/hotplug
         * during boot-up
@@ -720,9 +724,6 @@ static void __init do_basic_setup(void)
        net_notifier_init();
 #endif
 
-       /* Mount the root filesystem.. */
-       mount_root();
-
        mount_devfs_fs ();
 
 #ifdef CONFIG_BLK_DEV_INITRD
index b5219786af50ee8569ebf8b955047f64ff96c364..8ea9f5b9900a6e13d720d31ad68ec80dee82b5fd 100644 (file)
@@ -6,16 +6,23 @@
  * dwmw2@redhat.com
  */
 
+#define __KERNEL_SYSCALLS__
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/unistd.h>
+#include <linux/signal.h>
 
 static DECLARE_TASK_QUEUE(tq_context);
 static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
+static int keventd_running;
 
 void schedule_task(struct tq_struct *task)
 {
+       if (keventd_running == 0)
+               printk(KERN_ERR "schedule_task(): keventd has not started\n");
        queue_task(task, &tq_context);
        wake_up(&context_task_wq);
 }
@@ -24,18 +31,27 @@ EXPORT_SYMBOL(schedule_task);
 
 static int context_thread(void *dummy)
 {
-       DECLARE_WAITQUEUE(wait, current);
+       struct task_struct *curtask = current;
+       DECLARE_WAITQUEUE(wait, curtask);
+       struct k_sigaction sa;
 
        daemonize();
-       strcpy(current->comm, "eventd");
+       strcpy(curtask->comm, "keventd");
+       keventd_running = 1;
+
+       spin_lock_irq(&curtask->sigmask_lock);
+       siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
+       recalc_sigpending(curtask);
+       spin_unlock_irq(&curtask->sigmask_lock);
 
-        spin_lock_irq(&current->sigmask_lock);
-        sigfillset(&current->blocked);
-        recalc_sigpending(current);
-        spin_unlock_irq(&current->sigmask_lock);
+       /* Install a handler so SIGCLD is delivered */
+       sa.sa.sa_handler = SIG_IGN;
+       sa.sa.sa_flags = 0;
+       siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
+       do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
 
        for (;;) {
-               current->state = TASK_INTERRUPTIBLE;
+               __set_task_state(curtask, TASK_INTERRUPTIBLE);
                add_wait_queue(&context_task_wq, &wait);
 
                /*
@@ -46,15 +62,19 @@ static int context_thread(void *dummy)
                        schedule();
 
                remove_wait_queue(&context_task_wq, &wait);
-               current->state = TASK_RUNNING;
+               __set_task_state(curtask, TASK_RUNNING);
                run_task_queue(&tq_context);
+               if (signal_pending(curtask)) {
+                       while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)
+                               ;
+                       flush_signals(curtask);
+                       recalc_sigpending(curtask);
+               }
        }
 }
 
-static int __init start_context_thread(void)
+int start_context_thread(void)
 {
        kernel_thread(context_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
        return 0;
 }
-
-module_init(start_context_thread);
index 983dedb605afd9ffcbe6cf6a3d4145a22c2647c9..3ee09759fda19b8c777256d2de13ebdf9e9fcc7e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/spinlock.h>
+#include <linux/string.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 
index a21507eecfd714f70f1e653087f4a7c23ec115ab..0239b8b0c190717e62f0837992c9be3d2d506467 100644 (file)
@@ -165,7 +165,7 @@ static int exec_modprobe(void * module_name)
  
 int request_module(const char * module_name)
 {
-       int pid;
+       pid_t pid;
        int waitpid_result;
        sigset_t tmpsig;
        int i;
@@ -259,40 +259,121 @@ EXPORT_SYMBOL(hotplug_path);
 
 static int exec_helper (void *arg)
 {
+       long ret;
        void **params = (void **) arg;
        char *path = (char *) params [0];
        char **argv = (char **) params [1];
        char **envp = (char **) params [2];
-       return exec_usermodehelper (path, argv, envp);
+
+       ret = exec_usermodehelper (path, argv, envp);
+       if (ret < 0)
+               ret = -ret;
+       do_exit(ret);
 }
 
+struct subprocess_info {
+       struct semaphore *sem;
+       char *path;
+       char **argv;
+       char **envp;
+       int retval;
+};
 
-int call_usermodehelper (char *path, char **argv, char **envp)
+/*
+ * This is a standalone child of keventd.  It forks off another thread which
+ * is the desired usermode helper and then waits for the child to exit.
+ * We return the usermode process's exit code, or some -ve error code.
+ */
+static int ____call_usermodehelper(void *data)
 {
-       void *params [3] = { path, argv, envp };
-       int pid, pid2, retval;
+       struct subprocess_info *sub_info = data;
+       struct task_struct *curtask = current;
+       void *params [3] = { sub_info->path, sub_info->argv, sub_info->envp };
+       pid_t pid, pid2;
        mm_segment_t fs;
+       int retval = 0;
 
-       if ( ! current->fs->root ) {
-               printk(KERN_ERR "call_usermodehelper[%s]: no root fs\n",
-                       path);
-               return -EPERM;
+       if (!curtask->fs->root) {
+               printk(KERN_ERR "call_usermodehelper[%s]: no root fs\n", sub_info->path);
+               retval = -EPERM;
+               goto up_and_out;
        }
-       if ((pid = kernel_thread (exec_helper, (void *) params, 0)) < 0) {
-               printk(KERN_ERR "failed fork %s, errno = %d", argv [0], -pid);
-               return -1;
+       if ((pid = kernel_thread(exec_helper, (void *) params, 0)) < 0) {
+               printk(KERN_ERR "failed fork2 %s, errno = %d", sub_info->argv[0], -pid);
+               retval = pid;
+               goto up_and_out;
        }
 
-       fs = get_fs ();
-       set_fs (KERNEL_DS);
-       pid2 = waitpid (pid, &retval, __WCLONE);
-       set_fs (fs);
+       if (retval >= 0) {
+               /* Block everything but SIGKILL/SIGSTOP */
+               spin_lock_irq(&curtask->sigmask_lock);
+               siginitsetinv(&curtask->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
+               recalc_sigpending(curtask);
+               spin_unlock_irq(&curtask->sigmask_lock);
+
+               /* Allow the system call to access kernel memory */
+               fs = get_fs();
+               set_fs(KERNEL_DS);
+               pid2 = waitpid(pid, &retval, __WCLONE);
+               if (pid2 == -1 && errno < 0)
+                       pid2 = errno;
+               set_fs(fs);
+
+               if (pid2 != pid) {
+                       printk(KERN_ERR "waitpid(%d) failed, %d\n", pid, pid2);
+                       retval = (pid2 < 0) ? pid2 : -1;
+               }
+       }
 
-       if (pid2 != pid) {
-               printk(KERN_ERR "waitpid(%d) failed, %d\n", pid, pid2);
-                       return -1;
+up_and_out:
+       sub_info->retval = retval;
+       curtask->exit_signal = SIGCHLD;         /* Wake up parent */
+       up_and_exit(sub_info->sem, retval);
+}
+
+/*
+ * This is a schedule_task function, so we must not sleep for very long at all.
+ * But the exec'ed process could do anything at all.  So we launch another
+ * kernel thread.
+ */
+static void __call_usermodehelper(void *data)
+{
+       struct subprocess_info *sub_info = data;
+       pid_t pid;
+
+       if ((pid = kernel_thread (____call_usermodehelper, (void *)sub_info, 0)) < 0) {
+               printk(KERN_ERR "failed fork1 %s, errno = %d", sub_info->argv[0], -pid);
+               sub_info->retval = pid;
+               up(sub_info->sem);
        }
-       return retval;
+}
+
+/*
+ * This function can be called via do_exit->__exit_files, which means that
+ * we're partway through exitting and things break if we fork children.
+ * So we use keventd to parent the usermode helper.
+ * We return the usermode application's exit code or some -ve error.
+ */
+int call_usermodehelper (char *path, char **argv, char **envp)
+{
+       DECLARE_MUTEX_LOCKED(sem);
+       struct subprocess_info sub_info = {
+               sem:    &sem,
+               path:   path,
+               argv:   argv,
+               envp:   envp,
+               retval: 0,
+       };
+       struct tq_struct tqs = {
+               next:           0,
+               sync:           0,
+               routine:        __call_usermodehelper,
+               data:           &sub_info,
+       };
+
+       schedule_task(&tqs);
+       down(&sem);             /* Wait for an error or completion */
+       return sub_info.retval;
 }
 
 EXPORT_SYMBOL(exec_usermodehelper);
index 64c178b312c25b1b4dabe9231aeb98caa9d50bfe..e47987f1e4c401a3497bb524989a1c3e8f651f94 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
+#include <asm/pgtable.h>
 
 static inline void change_pte_range(pmd_t * pmd, unsigned long address,
        unsigned long size, pgprot_t newprot)
index 9eee6afe219692ae6dfd4efcebe2516bc81397a9..b229ee3e1018931e26ac8dbb36c7183fc2b3b4ef 100644 (file)
@@ -82,7 +82,7 @@ spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED;
  * This is the last-ditch buffer for NFS swap requests
  */
 static u32                     swap_buffer[PAGE_SIZE >> 2];
-static int                     swap_buffer_used;
+static long                    swap_buffer_used;
 
 /*
  * Make allocation of the swap_buffer SMP-safe