S: Germany
N: Richard Henderson
-E: rth@tamu.edu
+E: richard@gnu.ai.mit.edu
+E: rth@cygnus.com
D: Alpha/ELF, gcc, binutils, and glibc
-S: 304 E. North Ave.
-S: Bryan, Texas 77801-3431
-S: USA
N: Sebastian Hetze
E: she@lunetix.de
S: Canberra ACT 0200
S: AUSTRALIA
+N: Pavel Machek
+E: pavel@atrey.karlin.mff.cuni.cz
+D: Softcursor for vga, hypertech cdrom support, vcsa bugfix
+S: Volkova 1131
+S: 198 00 Praha 9
+S: Czech Republic
+
N: James B. MacLean
E: macleajb@ednet.ns.ca
W: http://www.ednet.ns.ca/~macleajb/dosemu.html
D: improved memory detection code.
N: Avery Pennarun
-E: apenwarr@foxnet.net
+E: apenwarr@bond.net
D: ARCnet driver
D: "make xconfig" improvements
D: Various minor hacking
S: 2611 TT Delft
S: The Netherlands
+N: David Woodhouse
+E: dwmw2@cam.ac.uk
+D: Extensive ARCnet rewrite
+D: ARCnet COM20020, COM90xx IO-MAP drivers
+S: Robinson College, Grange Road
+S: Cambridge. CB3 9AN
+S: England
+
N: Frank Xia
E: qx@math.columbia.edu
D: Xiafs filesystem [defunct]
L: linux-net@vger.rutgers.edu
S: Maintained
+NI5010 NETWORK DRIVER
+P: Jan-Pascal van Best and Andreas Mohr
+M: jvbest@qv3pluto.leidenuniv.nl (Best)
+M: 100.30936@germany.net (Mohr)
+L: linux-net@vger.rutgers.edu
+S: Maintained
+
TLAN NETWORK DRIVER
P: James Banks
M: james.banks@caldera.com
S: Maintained
MODULE SUPPORT [GENERAL], KERNELD
-P: Bjorn Ekwall
-M: bj0rn@blox.se
-W: http://www.pi.se/blox/modules/
+P: Richard Henderson
+M: richard@gnu.ai.mit.edu
L: linux-kernel@vger.rutgers.edu
S: Maintained
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 50
+SUBLEVEL = 51
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
DRIVERS := $(DRIVERS) drivers/sbus/sbus.a
endif
+ifdef CONFIG_PPC
+DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a
+endif
+
ifdef CONFIG_PNP
DRIVERS := $(DRIVERS) drivers/pnp/pnp.a
endif
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
#
# Network device support
# CONFIG_ROMFS_FS is not set
CONFIG_AUTOFS_FS=y
# CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
#
# Character devices
#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
EXPORT_SYMBOL_NOVERS(active_kernel_processor);
EXPORT_SYMBOL(smp_invalidate_needed);
EXPORT_SYMBOL_NOVERS(__lock_kernel);
+EXPORT_SYMBOL(lk_lockmsg);
/* Global SMP irq stuff */
EXPORT_SYMBOL(synchronize_irq);
all: kernel.o head.o
O_TARGET := kernel.o
O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \
- setup.o bios32.o sys_m68k.o time.o
+ setup.o sys_m68k.o time.o
ifdef CONFIG_VT
O_OBJS += console.o
endif
+++ /dev/null
-/*
- * bios 32 replacement
- */
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
- return memory_start;
-}
current->priority = -100;
current->counter = -100;
for (;;){
- if (!need_resched)
+ if (!resched_needed())
#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
/* block out HSYNC on the atari (falcon) */
__asm__("stop #0x2200" : : : "cc");
goto out;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
regs->pc -= 2;
}
}
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code)) {
discard_frame:
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
# Copyright (C) 1994, 1995, 1996 by Ralf Baechle
# DECStation modifications by Paul M. Antoine, 1996
#
-# $Id: Makefile,v 1.7 1997/06/30 15:52:03 ralf Exp $
+# $Id: Makefile,v 1.8 1997/08/08 18:11:35 miguel Exp $
#
#
# Select the object file format to substitute into the linker script.
#
ifdef CONFIG_CPU_LITTLE_ENDIAN
-CROSS_COMPILE = mipsel-linux-
+CROSS_COMPILE = mipsel-linux-
ifdef CONFIG_MIPS_ECOFF
-oformat = ecoff-littlemips
+oformat = ecoff-littlemips
else
-oformat = elf32-littlemips
+oformat = elf32-littlemips
endif
else
-CROSS_COMPILE = mips-linux-
+CROSS_COMPILE = mips-linux-
ifdef CONFIG_MIPS_ECOFF
-oformat = ecoff-bigmips
+oformat = ecoff-bigmips
else
-oformat = elf32-bigmips
+oformat = elf32-bigmips
endif
endif
LINKFLAGS = -static -N
+MODFLAGS += -mlong-calls
#
# The new ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC
fi
dep:
- $(CPP) -M *.[cS] > .depend
clean:
rm -f zImage zImage.tmp mkboot
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'Support for SGI workstations' CONFIG_SGI
+ if [ "$CONFIG_SGI" = "y" ]; then
+ bool 'Support for SGI graphic devices' CONFIG_SGI_GRAPHICS
+ fi
fi
bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
if [ "$CONFIG_DESKSTATION_RPC44" = "y" -o \
fi
if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
define_bool CONFIG_BINFMT_IRIX y
+ define_bool CONFIG_FORWARD_KEYBOARD y
fi
define_bool CONFIG_BINFMT_ELF y
define_bool CONFIG_BINFMT_AOUT n
bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
fi
-#
-# All SGI block devices are SCSI based AFAIK. -davem
-#
-if [ "$CONFIG_SGI" != "y" ]; then
- source drivers/block/Config.in
-fi
+source drivers/block/Config.in
if [ "$CONFIG_NET" = "y" ]; then
source net/Config.in
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
endmenu
+
+define_bool CONFIG_VGA_CONSOLE y
CONFIG_NET=y
CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
-# CONFIG_PNP_PARPORT is not set
+# CONFIG_PARPORT is not set
#
# Loadable module support
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_NET_RADIO is not set
# CONFIG_SLIP is not set
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_FAT_FS is not set
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+# CONFIG_JOYSTICK is not set
#
# Sound
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: hw-access.c,v 1.2 1997/08/08 18:11:57 miguel Exp $
*/
#include <linux/config.h>
#include <linux/delay.h>
+#include <linux/kbdcntrlr.h>
#include <linux/kernel.h>
#include <linux/linkage.h>
#include <linux/types.h>
rtc_write_data
};
#endif
+
+static unsigned char dtc_read_input(void)
+{
+ return inb(KBD_DATA_REG);
+}
+
+static void dtc_write_output(unsigned char val)
+{
+ outb(val, KBD_DATA_REG);
+}
+
+static void dtc_write_command(unsigned char val)
+{
+ outb(val, KBD_CNTL_REG);
+}
+
+static unsigned char dtc_read_status(void)
+{
+ return inb(KBD_STATUS_REG);
+}
+
+static void dtc_rm200_keyboard_setup(void)
+{
+ kbd_read_input = dtc_read_input;
+ kbd_write_output = dtc_write_output;
+ kbd_write_command = dtc_write_command;
+ kbd_read_status = dtc_read_status;
+ request_region(0x60, 16, "keyboard");
+}
* for more details.
*
* Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: setup.c,v 1.2 1997/08/08 18:11:59 miguel Exp $
*/
#include <linux/config.h>
#include <linux/init.h>
#endif
}
fd_cacheflush = deskstation_fd_cacheflush;
+ keyboard_setup = dtc_keyboard_setup;
request_region(0x00,0x20,"dma1");
request_region(0x40,0x20,"timer");
request_region(0x70,0x10,"rtc");
/*
* Various defines for the G364
*/
-#define G364_MEM_BASE 0xe0800000
-#define G364_PORT_BASE 0xe0200000
-#define ID_REG 0xe0200000 /* Read only */
-#define BOOT_REG 0xe0280000
-#define TIMING_REG 0xe0280108 /* to 0x080170 - DON'T TOUCH! */
-#define MASK_REG 0xe0280200
-#define CTLA_REG 0xe0280300
+#define G364_MEM_BASE 0xe4400000
+#define G364_PORT_BASE 0xe4000000
+#define ID_REG 0xe4000000 /* Read only */
+#define BOOT_REG 0xe4080000
+#define TIMING_REG 0xe4080108 /* to 0x080170 - DON'T TOUCH! */
+#define MASK_REG 0xe4080200
+#define CTLA_REG 0xe4080300
#define CURS_TOGGLE 0x800000
#define BIT_PER_PIX 0x700000 /* bits 22 to 20 of Control A */
#define DELAY_SAMPLE 0x080000
#define INTL_STAND 0x000004
#define SCRN_FORM 0x000002
#define ENABLE_VTG 0x000001
-#define TOP_REG 0xe0280400
-#define CURS_PAL_REG 0xe0280508 /* to 0x080518 */
-#define CHKSUM_REG 0xe0280600 /* to 0x080610 - unused */
-#define CURS_POS_REG 0xe0280638
-#define CLR_PAL_REG 0xe0280800 /* to 0x080ff8 */
-#define CURS_PAT_REG 0xe0281000 /* to 0x081ff8 */
-#define MON_ID_REG 0xe0300000 /* unused */
-#define RESET_REG 0xe0380000 /* Write only */
+#define TOP_REG 0xe4080400
+#define CURS_PAL_REG 0xe4080508 /* to 0x080518 */
+#define CHKSUM_REG 0xe4080600 /* to 0x080610 - unused */
+#define CURS_POS_REG 0xe4080638
+#define CLR_PAL_REG 0xe4080800 /* to 0x080ff8 */
+#define CURS_PAT_REG 0xe4081000 /* to 0x081ff8 */
+#define MON_ID_REG 0xe4100000 /* unused */
+#define RESET_REG 0xe4180000 /* Write only */
/*
* built-in font management constants
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
*/
#include <linux/delay.h>
#include <linux/linkage.h>
#include <asm/vector.h>
#include <asm/jazz.h>
#include <asm/jazzdma.h>
+#include <asm/keyboard.h>
#include <asm/pgtable.h>
#include <asm/mc146818rtc.h>
rtc_read_data,
rtc_write_data
};
+
+static volatile keyboard_hardware *jazz_kh = (keyboard_hardware *)JAZZ_KEYBOARD_ADDRESS;
+
+static unsigned char jazz_read_input(void)
+{
+ return jazz_kh->data;
+}
+
+static void jazz_write_output(unsigned char val)
+{
+ jazz_kh->data = val;
+}
+
+static void jazz_write_command(unsigned char val)
+{
+ jazz_kh->command = val;
+}
+
+static unsigned char jazz_read_status(void)
+{
+ return jazz_kh->command;
+}
+
+void jazz_keyboard_setup(void)
+{
+ kbd_read_input = jazz_read_input;
+ kbd_write_output = jazz_write_output;
+ kbd_write_command = jazz_write_command;
+ kbd_read_status = jazz_read_status;
+ request_region(0x60, 16, "keyboard");
+ r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | JAZZ_IE_KEYBOARD);
+}
return residual;
}
+
+/*
+ * Get DMA channel enable register
+ */
+int vdma_get_enable(int channel)
+{
+ int enable;
+
+ enable = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5));
+
+ if (vdma_debug)
+ printk("vdma_get_enable: channel %d: enable=%d\n",channel,enable);
+
+ return enable;
+}
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/mm.h>
#include <asm/bootinfo.h>
+#include <asm/keyboard.h>
#include <asm/irq.h>
#include <asm/jazz.h>
#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/vector.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
/*
* Initial irq handlers.
extern asmlinkage void jazz_handle_int(void);
extern asmlinkage void jazz_fd_cacheflush(const void *addr, size_t size);
extern struct feature jazz_feature;
+extern void jazz_keyboard_setup(void);
extern void jazz_machine_restart(char *command);
extern void jazz_machine_halt(void);
}
}
+ add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K);
+ add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M);
+ add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M);
+
irq_setup = jazz_irq_setup;
fd_cacheflush = jazz_fd_cacheflush;
+ keyboard_setup = jazz_keyboard_setup;
feature = &jazz_feature; // Will go away
port_base = JAZZ_PORT_BASE;
isa_slot_offset = 0xe3000000;
*
* Copyright (C) 1995 Andreas Busse
*
- * $Id: gdb-stub.c,v 1.4 1997/06/30 15:52:25 ralf Exp $
+ * $Id: gdb-stub.c,v 1.5 1997/08/08 18:12:15 miguel Exp $
*/
/*
*/
#include <linux/string.h>
-#include <linux/signal.h>
#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
-#include <asm/cachectl.h>
+#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/gdb-stub.h>
static void getpacket(char *buffer);
static void putpacket(char *buffer);
-static void set_mem_fault_trap(int enable);
static int computeSignal(int tt);
static int hex(unsigned char ch);
static int hexToInt(char **ptr, int *intValue);
static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
void handle_exception(struct gdb_regs *regs);
-static void show_gdbregs(struct gdb_regs *regs);
/*
* BUFMAX defines the maximum number of characters in inbound/outbound buffers
*/
static volatile int mem_err = 0;
+
+#if 0
+static void set_mem_fault_trap(int enable)
+{
+ mem_err = 0;
+
+#if 0
+ if (enable)
+ exceptionHandler(9, fltr_set_mem_err);
+ else
+ exceptionHandler(9, trap_low);
+#endif
+}
+#endif /* dead code */
+
/*
* Convert the memory pointed to by mem into hex, placing result in buf.
* Return a pointer to the last char put in buf (null), in case of mem fault,
/* FIXME: Needs to be written... */
}
-
-static void set_mem_fault_trap(int enable)
-{
- mem_err = 0;
-
-#if 0
- if (enable)
- exceptionHandler(9, fltr_set_mem_err);
- else
- exceptionHandler(9, trap_low);
-#endif
-}
-
/*
* Convert the MIPS hardware trap type code to a unix signal number.
*/
return (numChars);
}
+
+#if 0
+/*
+ * Print registers (on target console)
+ * Used only to debug the stub...
+ */
+void show_gdbregs(struct gdb_regs * regs)
+{
+ /*
+ * Saved main processor registers
+ */
+ printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg0, regs->reg1, regs->reg2, regs->reg3,
+ regs->reg4, regs->reg5, regs->reg6, regs->reg7);
+ printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg8, regs->reg9, regs->reg10, regs->reg11,
+ regs->reg12, regs->reg13, regs->reg14, regs->reg15);
+ printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg16, regs->reg17, regs->reg18, regs->reg19,
+ regs->reg20, regs->reg21, regs->reg22, regs->reg23);
+ printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg24, regs->reg25, regs->reg26, regs->reg27,
+ regs->reg28, regs->reg29, regs->reg30, regs->reg31);
+
+ /*
+ * Saved cp0 registers
+ */
+ printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n",
+ regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
+}
+#endif /* dead code */
+
/*
* This function does all command processing for interfacing to gdb. It
* returns 1 if you should skip the instruction at the trap address, 0
lw $9,0($8)
");
}
-
-/*
- * Print registers (on target console)
- * Used only to debug the stub...
- */
-void show_gdbregs(struct gdb_regs * regs)
-{
- /*
- * Saved main processor registers
- */
- printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg0, regs->reg1, regs->reg2, regs->reg3,
- regs->reg4, regs->reg5, regs->reg6, regs->reg7);
- printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg8, regs->reg9, regs->reg10, regs->reg11,
- regs->reg12, regs->reg13, regs->reg14, regs->reg15);
- printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg16, regs->reg17, regs->reg18, regs->reg19,
- regs->reg20, regs->reg21, regs->reg22, regs->reg23);
- printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg24, regs->reg25, regs->reg26, regs->reg27,
- regs->reg28, regs->reg29, regs->reg30, regs->reg31);
-
- /*
- * Saved cp0 registers
- */
- printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n",
- regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
-}
-/* $Id: irix5sys.h,v 1.1 1997/06/06 09:32:29 ralf Exp $
+/* $Id: irix5sys.h,v 1.2 1997/08/08 18:12:17 miguel Exp $
* irix5sys.h: 32-bit IRIX5 ABI system call table.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
-/* $Id: irixioctl.c,v 1.1 1997/06/06 09:32:33 ralf Exp $
+/* $Id: irixioctl.c,v 1.2 1997/08/08 18:12:19 miguel Exp $
* irixioctl.c: A fucking mess...
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
-/* $Id: irixsig.c,v 1.2 1997/06/13 10:11:22 ralf Exp $
+/* $Id: irixsig.c,v 1.4 1997/08/08 18:12:21 miguel Exp $
* irixsig.c: WHEEE, IRIX signals! YOW, am I compatable or what?!?!
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
#define P_ALL 7
extern int getrusage(struct task_struct *, int, struct rusage *);
-extern void release(struct task_struct * p);
#define W_EXITED 1
#define W_TRAPPED 2
REMOVE_LINKS(p);
p->p_pptr = p->p_opptr;
SET_LINKS(p);
- notify_parent(p);
+ notify_parent(p, SIGCHLD);
} else
release(p);
goto end_waitsys;
*
* Mips support by Ralf Baechle and Andreas Busse
*
- * $Id: irq.c,v 1.6 1997/06/30 15:52:34 ralf Exp $
+ * $Id: irq.c,v 1.7 1997/08/08 18:12:24 miguel Exp $
*/
#include <linux/config.h>
#include <linux/errno.h>
static inline void mask_irq(unsigned int irq_nr)
{
unsigned char mask;
+
+ if (irq_nr >= 16)
+ return;
mask = 1 << (irq_nr & 7);
if (irq_nr < 8) {
{
unsigned char mask;
+ if (irq_nr >= 16)
+ return;
+
mask = ~(1 << (irq_nr & 7));
if (irq_nr < 8) {
cache_21 &= mask;
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: mips_ksyms.c,v 1.2 1997/08/08 18:12:26 miguel Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
+#include <linux/in6.h>
+
+#include <asm/checksum.h>
#include <asm/dma.h>
#include <asm/floppy.h>
#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sgihpc.h>
#include <asm/softirq.h>
+#include <asm/uaccess.h>
EXPORT_SYMBOL(EISA_bus);
/*
* String functions
*/
+EXPORT_SYMBOL_NOVERS(bcopy);
+EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memmove);
-EXPORT_SYMBOL_NOVERS(bcopy);
+EXPORT_SYMBOL_NOVERS(strcat);
+EXPORT_SYMBOL_NOVERS(strchr);
+EXPORT_SYMBOL_NOVERS(strlen);
+EXPORT_SYMBOL_NOVERS(strncat);
+EXPORT_SYMBOL_NOVERS(strnlen);
+EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(__mips_bh_counter);
EXPORT_SYMBOL(local_irq_count);
+/*
+ * Userspace access stuff.
+ */
+EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(active_ds);
+
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
/*
* Functions to control caches.
*/
+EXPORT_SYMBOL(flush_page_to_ram);
EXPORT_SYMBOL(fd_cacheflush);
/*
* Base address of ports for Intel style I/O.
*/
EXPORT_SYMBOL(port_base);
+
+#ifdef CONFIG_SGI
+EXPORT_SYMBOL(hpc3c0);
+#endif
return;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994, 1995, 1996 Ralf Baechle
*
- * $Id: signal.c,v 1.7 1997/06/25 19:25:08 ralf Exp $
+ * $Id: signal.c,v 1.8 1997/08/08 18:12:30 miguel Exp $
*/
#include <linux/config.h>
#include <linux/sched.h>
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
* possible. Should help alot for battery powered
* R4200/4300i systems.
*/
- if (wait_available && !need_resched)
+ if (wait_available && !resched_needed())
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0\n\t");
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
*
- * $Id: syscalls.h,v 1.6 1997/07/20 15:32:25 ralf Exp $
+ * $Id: syscalls.h,v 1.7 1997/08/08 18:12:32 miguel Exp $
*/
/*
SYS(sys_nfsservctl, 3)
SYS(sys_setresgid, 3) /* 4190 */
SYS(sys_getresgid, 3)
+SYS(sys_setresgid, 3) /* 4190 */
+SYS(sys_getresgid, 3)
-/* $Id: sysirix.c,v 1.3 1997/07/20 15:32:25 ralf Exp $
+/* $Id: sysirix.c,v 1.4 1997/08/08 18:12:35 miguel Exp $
* sysirix.c: IRIX system call emulation.
*
* Copyright (C) 1996 David S. Miller
}
error = 0;
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
error = 0;
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
error = 0;
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
*
* Copyright (C) 1995, 1996, 1997 by Ralf Baechle
*
- * $Id: sysmips.c,v 1.5 1997/07/20 15:32:27 ralf Exp $
+ * $Id: sysmips.c,v 1.6 1997/08/08 18:12:38 miguel Exp $
*/
#include <linux/errno.h>
#include <linux/linkage.h>
* This file contains the time handling details for PC-style clocks as
* found in some MIPS systems.
*
- * $Id: time.c,v 1.4 1997/06/30 15:52:40 ralf Exp $
+ * $Id: time.c,v 1.5 1997/08/08 18:12:39 miguel Exp $
*/
#include <linux/errno.h>
#include <linux/init.h>
/*
* Assume it would be too dangerous to continue ...
*/
+ printk ("BE HANDLER\n");
+ show_regs (regs);
force_sig(SIGBUS, current);
}
#
# Makefile for MIPS-specific library files..
#
+# Many of these routines are just left over debugging trash of ancient
+# times when I just make my Tyne beep and so ...
+#
+# ...and for when I need to get the DECStation to use the boot prom to
+# do things... Paul M. Antoine.
+#
.S.s:
$(CPP) $(CFLAGS) $< -o $*.s
$(CC) $(CFLAGS) -c $< -o $*.o
L_TARGET = lib.a
-L_OBJS = checksum.o copy_user.o csum.o dump_tlb.o io.o \
- memset.o memcpy.o strlen_user.o strncpy_user.o tags.o watch.o
+L_OBJS = beep.o checksum.o copy_user.o csum.o dump_tlb.o io.o memset.o \
+ memcpy.o strlen_user.o strncpy_user.o tags.o watch.o
ifdef CONFIG_DECSTATION
L_OBJS += pmaxcon.o pmaxio.o
*
* MIPS specific IP/TCP/UDP checksumming routines
*
- * Authors: Ralf Baechle, <ralf@waldorf-gmbh.de>
+ * Authors: Ralf Baechle, <ralf@gnu.ai.mit.edu>
* Lots of code moved from tcp.c and ip.c; see those files
* for more names.
*
* 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.4 1997/07/03 09:43:16 ralf Exp $
+ * $Id: checksum.c,v 1.5 1997/08/08 18:12:51 miguel Exp $
*/
#include <net/checksum.h>
#include <linux/types.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+static char *region_map [] = {
+ "u", "s", "k", "!"
+};
+
+static char *cache_map [] = {
+ "c/nc/wt/nwa,",
+ "c/nc/wt/wa, ",
+ "uncached, ",
+ "c/nc/wb, "
+ "unknown, ",
+ "unknown, ",
+ "unknown, ",
+ "unknown, "
+};
+
void
dump_tlb(int first, int last)
{
int i;
int wired;
- unsigned int pagemask;
+ unsigned int pagemask, c0, c1, r;
unsigned long long entryhi, entrylo0, entrylo1;
wired = read_32bit_cp0_register(CP0_WIRED);
/*
* Only print entries in use
*/
- printk("\nIndex: %2d %08x", i, pagemask);
-
- printk(" %08x %08x", (unsigned int)(entryhi >> 32),
- (unsigned int) entryhi);
- printk(" %08x %08x", (unsigned int)(entrylo0 >> 32),
- (unsigned int) entrylo0);
- printk(" %08x %08x", (unsigned int)(entrylo1 >> 32),
- (unsigned int) entrylo1);
+ printk("\nIndex: %2d pgmask=%08x ", i, pagemask);
+
+ r = entryhi >> 62;
+ c0 = (entrylo0 >> 3) & 7;
+ c1 = (entrylo1 >> 3) & 7;
+
+ printk("%s vpn2=%08x "
+ "[pfn=%06x c=%d d=%d v=%d g=%d]"
+ "[pfn=%06x c=%d d=%d v=%d g=%d]",
+ region_map [r], (entryhi >> 13) & 0xffffffff,
+ (entrylo0 >> 6) & 0xffffff, c0,
+ (entrylo0 & 4) ? 1 : 0,
+ (entrylo0 & 2) ? 1 : 0,
+ (entrylo0 & 1),
+ (entrylo1 >> 6) & 0xffffff, c1,
+ (entrylo1 & 4) ? 1 : 0,
+ (entrylo1 & 2) ? 1 : 0,
+ (entrylo1 & 1));
+
}
}
printk("\n");
O_OBJS := extable.o init.o fault.o r4xx0.o r2300.o r6000.o tfp.o \
andes.o loadmmu.o
+ifdef CONFIG_SGI
+O_OBJS += umap.o
+endif
+
include $(TOPDIR)/Rules.make
-/* $Id: andes.c,v 1.1 1997/06/06 09:34:31 ralf Exp $
+/* $Id: andes.c,v 1.2 1997/08/08 18:13:01 miguel Exp $
* andes.c: MMU and cache operations for the R10000 (ANDES).
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
{
}
+static void andes_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ /* XXX */
+}
+
void ld_mmu_andes(void)
{
flush_cache_all = andes_flush_cache_all;
flush_tlb_mm = andes_flush_tlb_mm;
flush_tlb_range = andes_flush_tlb_range;
flush_tlb_page = andes_flush_tlb_page;
+
+ add_wired_entry = andes_add_wired_entry;
load_pgd = andes_load_pgd;
pgd_init = andes_pgd_init;
* terminate things with extreme prejudice.
*/
printk(KERN_ALERT "Unable to handle kernel paging request at virtual "
- "address %08lx, epc == %08lx\n", address, regs->cp0_epc);
+ "address %08lx, epc == %08lx, ra == %08lx\n",
+ address, regs->cp0_epc, regs->regs[31]);
die_if_kernel("Oops", regs, writeaccess);
do_exit(SIGKILL);
out:
-/* $Id: loadmmu.c,v 1.1 1997/06/06 09:34:51 ralf Exp $
+/* $Id: loadmmu.c,v 1.2 1997/08/08 18:13:05 miguel Exp $
* loadmmu.c: Setup cpu/cache specific function ptrs at boot time.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
unsigned long address, pte_t pte);
void (*show_regs)(struct pt_regs *);
+
+void (*add_wired_entry)(unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask);
+
asmlinkage void (*resume)(void *tsk);
extern void ld_mmu_r2300(void);
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: r2300.c,v 1.2 1997/06/30 15:52:51 ralf Exp $
+ * $Id: r2300.c,v 1.3 1997/08/08 18:13:06 miguel Exp $
*/
#include <linux/kernel.h>
(unsigned int) regs->cp0_cause);
}
+static void r2300_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ /*
+ * FIXME, to be done
+ */
+}
+
void ld_mmu_r2300(void)
{
clear_page = r2300_clear_page;
update_mmu_cache = r2300_update_mmu_cache;
show_regs = r2300_show_regs;
+
+ add_wired_entry = r2300_add_wired_entry;
flush_tlb_all();
}
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: r4xx0.c,v 1.4 1997/06/30 15:52:53 ralf Exp $
+ * $Id: r4xx0.c,v 1.5 1997/08/08 18:13:07 miguel Exp $
*/
#include <linux/config.h>
set_entrylo1(0);
BARRIER;
- entry = 0;
+ entry = get_wired();
/* Blast 'em all away. */
while(entry < NTLB_ENTRIES) {
int oldpid, newpid, idx;
#ifdef DEBUG_TLB
- printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+ printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
#endif
newpid = (vma->vm_mm->context & 0xff);
page &= (PAGE_MASK << 1);
printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n",
regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
}
+
+static void r4k_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ unsigned long flags;
+ unsigned long wired;
+ unsigned long old_pagemask;
+ unsigned long old_ctx;
+
+ save_and_cli(flags);
+ /* Save old context and create impossible VPN2 value */
+ old_ctx = (get_entryhi() & 0xff);
+ old_pagemask = get_pagemask();
+ wired = get_wired();
+ set_wired (wired + 1);
+ set_index (wired);
+ BARRIER;
+ set_pagemask (pagemask);
+ set_entryhi(entryhi);
+ set_entrylo0(entrylo0);
+ set_entrylo1(entrylo1);
+ BARRIER;
+ tlb_write_indexed();
+ BARRIER;
+
+ set_entryhi(old_ctx);
+ BARRIER;
+ set_pagemask (old_pagemask);
+ flush_tlb_all();
+ restore_flags(flags);
+}
/* Detect and size the various r4k caches. */
static void probe_icache(unsigned long config)
update_mmu_cache = r4k_update_mmu_cache;
show_regs = r4k_show_regs;
+
+ add_wired_entry = r4k_add_wired_entry;
flush_cache_all();
write_32bit_cp0_register(CP0_WIRED, 0);
-/* $Id: r6000.c,v 1.1 1997/06/06 09:35:31 ralf Exp $
+/* $Id: r6000.c,v 1.2 1997/08/08 18:13:11 miguel Exp $
* r6000.c: MMU and cache routines for the R6000 processors.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
(unsigned int) regs->cp0_cause);
}
+static void r6000_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ /* XXX */
+}
+
void ld_mmu_r6000(void)
{
flush_cache_all = r6000_flush_cache_all;
update_mmu_cache = r6000_update_mmu_cache;
show_regs = r6000_show_regs;
+
+ add_wired_entry = r6000_add_wired_entry;
flush_cache_all();
flush_tlb_all();
-/* $Id: tfp.c,v 1.1 1997/06/06 09:35:39 ralf Exp $
+/* $Id: tfp.c,v 1.2 1997/08/08 18:13:13 miguel Exp $
* tfp.c: MMU and cache routines specific to the r8000 (TFP).
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
{
}
+static void tfp_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ /* XXX */
+}
+
void ld_mmu_tfp(void)
{
flush_cache_all = tfp_flush_cache_all;
flush_tlb_range = tfp_flush_tlb_range;
flush_tlb_page = tfp_flush_tlb_page;
+ add_wired_entry = tfp_add_wired_entry;
+
load_pgd = tfp_load_pgd;
pgd_init = tfp_pgd_init;
-
+
flush_cache_all();
flush_tlb_all();
}
--- /dev/null
+/*
+ * arch/mips/mm/umap.c
+ *
+ * (C) Copyright 1994 Linus Torvalds
+ *
+ * Changes:
+ *
+ * Modified from Linus source to removing active mappings from any
+ * task. This is required for implementing the virtual graphics
+ * interface for direct rendering on the SGI - miguel.
+ *
+ * Added a routine to map a vmalloc()ed area into user space, this one
+ * is required by the /dev/shmiq driver - miguel.
+ */
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <linux/mman.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/swap.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+static inline void
+remove_mapping_pte_range (pmd_t *pmd, unsigned long address, unsigned long size)
+{
+ pte_t *pte;
+ unsigned long end;
+
+ if (pmd_none (*pmd))
+ return;
+ if (pmd_bad (*pmd)){
+ printk ("remove_graphics_pte_range: bad pmd (%08lx)\n", pmd_val (*pmd));
+ pmd_clear (pmd);
+ return;
+ }
+ pte = pte_offset (pmd, address);
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ pte_t entry = *pte;
+ if (pte_present (entry))
+ set_pte (pte, pte_modify (entry, PAGE_NONE));
+ address += PAGE_SIZE;
+ pte++;
+ } while (address < end);
+
+}
+
+static inline void
+remove_mapping_pmd_range (pgd_t *pgd, unsigned long address, unsigned long size)
+{
+ pmd_t *pmd;
+ unsigned long end;
+
+ if (pgd_none (*pgd))
+ return;
+
+ if (pgd_bad (*pgd)){
+ printk ("remove_graphics_pmd_range: bad pgd (%08lx)\n", pgd_val (*pgd));
+ pgd_clear (pgd);
+ return;
+ }
+ pmd = pmd_offset (pgd, address);
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ do {
+ remove_mapping_pte_range (pmd, address, end - address);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+
+}
+
+/*
+ * This routine is called from the page fault handler to remove a
+ * range of active mappings at this point
+ */
+void
+remove_mapping (struct task_struct *task, unsigned long start, unsigned long end)
+{
+ unsigned long beg = start;
+ pgd_t *dir;
+
+ down (&task->mm->mmap_sem);
+ dir = pgd_offset (task->mm, start);
+ flush_cache_range (task->mm, beg, end);
+ while (start < end){
+ remove_mapping_pmd_range (dir, start, end - start);
+ start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ }
+ flush_tlb_range (task->mm, beg, end);
+ up (&task->mm->mmap_sem);
+}
+
+void *vmalloc_uncached (unsigned long size)
+{
+ return vmalloc_prot (size, PAGE_KERNEL_UNCACHED);
+}
+
+static inline void free_pte(pte_t page)
+{
+ if (pte_present(page)) {
+ unsigned long addr = pte_page(page);
+ if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
+ return;
+ free_page(addr);
+ if (current->mm->rss <= 0)
+ return;
+ current->mm->rss--;
+ return;
+ }
+ swap_free(pte_val(page));
+}
+
+static inline void forget_pte(pte_t page)
+{
+ if (!pte_none(page)) {
+ printk("forget_pte: old mapping existed!\n");
+ free_pte(page);
+ }
+}
+
+/*
+ * maps a range of vmalloc()ed memory into the requested pages. the old
+ * mappings are removed.
+ */
+static inline void
+vmap_pte_range (pte_t *pte, unsigned long address, unsigned long size, unsigned long vaddr)
+{
+ unsigned long end;
+ pgd_t *vdir;
+ pmd_t *vpmd;
+ pte_t *vpte;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ pte_t oldpage = *pte;
+ unsigned long page;
+ pte_clear(pte);
+
+ vdir = pgd_offset_k (vaddr);
+ vpmd = pmd_offset (vdir, vaddr);
+ vpte = pte_offset (vpmd, vaddr);
+ page = pte_page (*vpte);
+
+ set_pte(pte, mk_pte_phys(page, PAGE_USERIO));
+ forget_pte(oldpage);
+ address += PAGE_SIZE;
+ vaddr += PAGE_SIZE;
+ pte++;
+ } while (address < end);
+}
+
+static inline int
+vmap_pmd_range (pmd_t *pmd, unsigned long address, unsigned long size, unsigned long vaddr)
+{
+ unsigned long end;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ vaddr -= address;
+ do {
+ pte_t * pte = pte_alloc(pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ vmap_pte_range(pte, address, end - address, address + vaddr);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+ return 0;
+}
+
+int
+vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr)
+{
+ int error = 0;
+ pgd_t * dir;
+ unsigned long beg = from;
+ unsigned long end = from + size;
+
+ vaddr -= from;
+ dir = pgd_offset(current->mm, from);
+ flush_cache_range(current->mm, beg, end);
+ while (from < end) {
+ pmd_t *pmd = pmd_alloc(dir, from);
+ error = -ENOMEM;
+ if (!pmd)
+ break;
+ error = vmap_pmd_range(pmd, from, end - from, vaddr + from);
+ if (error)
+ break;
+ from = (from + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ }
+ flush_tlb_range(current->mm, beg, end);
+ return error;
+}
-/* $Id: setup.c,v 1.2 1997/06/30 15:26:24 ralf Exp $
+/*
* setup.c: SGI specific setup, including init of the feature struct.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: setup.c,v 1.3 1997/08/08 18:13:22 miguel Exp $
*/
#ifndef __GOGOGO__
#error "... about to fuckup your Indy?"
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <asm/addrspace.h>
+#include <asm/keyboard.h>
#include <asm/reboot.h>
#include <asm/vector.h>
#include <asm/sgialib.h>
struct feature sgi_feature = {
};
+static volatile struct hpc_keyb *sgi_kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
+
+static unsigned char sgi_read_input(void)
+{
+ return sgi_kh->data;
+}
+
+static void sgi_write_output(unsigned char val)
+{
+ sgi_kh->data = val;
+}
+
+static void sgi_write_command(unsigned char val)
+{
+ sgi_kh->command = val;
+}
+
+static unsigned char sgi_read_status(void)
+{
+ return sgi_kh->command;
+}
+
+static void sgi_keyboard_setup(void)
+{
+ kbd_read_input = sgi_read_input;
+ kbd_write_output = sgi_write_output;
+ kbd_write_command = sgi_write_command;
+ kbd_read_status = sgi_read_status;
+}
+
static void sgi_irq_setup(void)
{
sgint_init();
irq_setup = sgi_irq_setup;
feature = &sgi_feature;
+ keyboard_setup = sgi_keyboard_setup;
_machine_restart = sgi_machine_restart;
_machine_halt = sgi_machine_halt;
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: hw-access.c,v 1.2 1997/08/08 18:13:27 miguel Exp $
*/
#include <linux/delay.h>
+#include <linux/kbdcntrlr.h>
#include <linux/kernel.h>
#include <linux/linkage.h>
#include <linux/types.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
#include <asm/dma.h>
+#include <asm/keyboard.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mc146818rtc.h>
rtc_read_data,
rtc_write_data
};
+
+static unsigned char sni_read_input(void)
+{
+ return inb(KBD_DATA_REG);
+}
+
+static void sni_write_output(unsigned char val)
+{
+ outb(val, KBD_DATA_REG);
+}
+
+static void sni_write_command(unsigned char val)
+{
+ outb(val, KBD_CNTL_REG);
+}
+
+static unsigned char sni_read_status(void)
+{
+ return inb(KBD_STATUS_REG);
+}
+
+void sni_rm200_keyboard_setup(void)
+{
+ kbd_read_input = sni_read_input;
+ kbd_write_output = sni_write_output;
+ kbd_write_command = sni_write_command;
+ kbd_read_status = sni_read_status;
+ request_region(0x60, 16, "keyboard");
+}
#include <linux/timex.h>
#include <linux/pci.h>
#include <asm/bootinfo.h>
+#include <asm/keyboard.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
extern asmlinkage void sni_rm200_pci_handle_int(void);
extern asmlinkage void sni_fd_cacheflush(const void *addr, size_t size);
extern struct feature sni_rm200_pci_feature;
+extern void sni_rm200_keyboard_setup(void);
extern void sni_machine_restart(char *command);
extern void sni_machine_halt(void);
fd_cacheflush = sni_fd_cacheflush; // Will go away
feature = &sni_rm200_pci_feature;
port_base = SNI_PORT_BASE;
+ keyboard_setup = sni_rm200_keyboard_setup;
/*
* Setup (E)ISA I/O memory access stuff
#
# Copyright (C) 1994 by Linus Torvalds
# Changes for PPC by Gary Thomas
-# Modified by Cort Dougan
+# Modified by Cort Dougan and Paul Mackerras
#
+ifeq ($(CONFIG_PMAC),y)
+KERNELBASE =0xc0000000
+else
+KERNELBASE =0x90000000
+endif
+
# PowerPC (cross) tools
-SUFFIX =
-AS = as$(SUFFIX)
-ASFLAGS =
-LD = ld$(SUFFIX)
-LINKFLAGS = -T arch/ppc/ld.script -Ttext 0x90000000
-HOSTCC = gcc
-CC = gcc$(SUFFIX)
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE =powerpc-eabi-
+endif
+
+ASFLAGS =
+LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELBASE) -Bstatic
CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
CFLAGS = $(CFLAGSINC) \
- -Wstrict-prototypes -fomit-frame-pointer \
+ -Wall -Wstrict-prototypes -Wno-uninitialized \
-fno-builtin \
- -finhibit-size-directive \
- -O2 -fsigned-char -pipe -ffixed-r2 -mstring -mmultiple -msoft-float
-# -fverbose-asm
+ -fsigned-char \
+ -msoft-float \
+ -O2 -pipe
CPP = $(CC) -E $(CFLAGS)
-AR = ar$(SUFFIX)
-RANLIB = ranlib$(SUFFIX)
-STRIP = strip$(SUFFIX)
-NM = nm$(SUFFIX)
ifdef CONFIG_601
CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
+ifdef CONFIG_XMON
+SUBDIRS += arch/ppc/xmon
+CORE_FILES += arch/ppc/xmon/x.o
+endif
+
+ifdef CONFIG_PMAC
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/coffboot
+else
+# PReP systems
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+endif
checks:
@$(MAKE) -C arch/$(ARCH)/kernel checks
-netboot: checks vmlinux
- @$(MAKEBOOT) netboot
-
-znetboot: checks vmlinux
- @$(MAKEBOOT) znetboot
-
-#rcpboot: checks vmlinux
-# @$(MAKEBOOT) rcpboot
+BOOT_TARGETS = netboot znetboot zImage floppy install \
+ vmlinux.coff znetboot.initrd zImage.initrd
-zImage: checks vmlinux
- @$(MAKEBOOT) zImage
+$(BOOT_TARGETS): checks vmlinux
+ @$(MAKEBOOT) $@
-floppy: checks vmlinux
- @$(MAKEBOOT) floppy
-
-install: checks vmlinux
- @$(MAKEBOOT) install
-
-vmlinux.coff : checks vmlinux
- $(MAKE) -C arch/ppc/coffboot/ vmlinux.coff
-
-arch/ppc/kernel: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
-
-arch/ppc/mm: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/mm
-
-arch/ppc/lib: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib
-
-diffs:
- arch/ppc/mkdiff
-
-tar:
- arch/ppc/mktar
+tags:
+ etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
archclean:
- rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h arch/ppc/kernel/checks TAGS
- rm -f `find arch/ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
- rm -f `find include/asm-ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
+ rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h
+ rm -f arch/ppc/kernel/checks
+ find arch/ppc/ -name '*.o' -exec /bin/rm -f '{}' \;
+ find arch/ppc/ -name '*~' -exec /bin/rm -f '{}' \;
+ find arch/ppc/ -name '*.a' -exec /bin/rm -f '{}' \;
@$(MAKEBOOT) clean
archdep:
- $(MAKE) -C arch/ppc/boot fastdep
- $(MAKE) -C arch/ppc/kernel fastdep
- $(MAKE) -C arch/ppc/mm fastdep
- $(MAKE) -C arch/ppc/lib fastdep
-
-tags :
- etags arch/ppc/*/*.c arch/ppc/*/*.S include/asm/* */*.c
+ $(MAKEBOOT) fastdep
$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
-ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
GZIP_FLAGS = -v9
SYSTEM = $(TOPDIR)/vmlinux
-
-OBJECTS = head.o inflate.o unzip.o misc.o vreset.o
-
+OBJECTS = head.o inflate.o unzip.o misc.o vreset.o #kbd.o
CFLAGS = -O2 -DSTDC_HEADERS -I$(TOPDIR)/include
+OBJCOPY = objcopy
+OBJCOPY_ARGS = -O elf32-powerpc
+
all: $(TOPDIR)/zImage
find_name : find_name.c
$(HOSTCC) $(CFLAGSINC) -o find_name find_name.c
-mk_type41: mk_type41.c
- $(HOSTCC) $(CFLAGSINC) -o mk_type41 mk_type41.c
-
-piggyback: piggyback.c
- $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
-
floppy: $(TOPDIR)/vmlinux zImage
dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
-netboot : $(TOPDIR)/vmlinux mkprep
- mkprep $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+floppy.initrd: $(TOPDIR)/vmlinux zImage
+ dd if=$(TOPDIR)/zImage.initrd of=/dev/fd0H1440 bs=64b
-znetboot : zvmlinux mkprep
- mkprep zvmlinux $(TOPDIR)/znetboot
- cp $(TOPDIR)/znetboot /usr/local/tftpboot/vmlinux
+znetboot : zImage mkprep
+ cp $(TOPDIR)/zImage /usr/local/tftpboot/vmlinux
-rcpboot : znetboot
- rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
+znetboot.initrd : zImage.initrd mkprep
+ cp $(TOPDIR)/zImage.initrd /usr/local/tftpboot/vmlinux
zImage: zvmlinux mkprep
mkprep -pbp zvmlinux $(TOPDIR)/zImage
-install: zImage
- dd if=$(TOPDIR)/zImage of=/dev/sda4
- ln -s /dev/sda4 $(INSTALL_PATH)/vmlinuz
- cp $(TOPDIR)/System.map $(INSTALL_PATH)/
+zImage.initrd: zvmlinux.initrd mkprep
+ mkprep -pbp zvmlinux.initrd $(TOPDIR)/zImage.initrd
+
+zvmlinux: $(OBJECTS) $(SYSTEM) mkprep find_name vmlinux.gz
+ $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
+ zvmlinux.tmp $@
+ rm zvmlinux.tmp
+
+vmlinux.gz: $(TOPDIR)/vmlinux
+ dd bs=64k skip=1 if=$(TOPDIR)/vmlinux | gzip -vf9 - > vmlinux.gz
-zvmlinux: $(OBJECTS) $(SYSTEM) mkprep find_name
- mkprep $(TOPDIR)/vmlinux -|gzip ${GZIP_FLAGS}|mkprep -asm - -|$(AS) -o piggy.o
- $(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
- rm -f piggy.o
+zvmlinux.initrd: zvmlinux
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+ zvmlinux $@
clean:
- rm -f piggyback zvmlinux mk_type41 mkprep mkboot find_name
- rm -f $(TOPDIR)/{zImage,znetboot,netboot}
+ rm -f vmlinux* znetboot* zImage* zvmlinux* mkprep find_name
+ rm -f $(TOPDIR)/{zImage*,znetboot*,zvmlinux*,vmlinux*}
fastdep:
$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
start:
bl start_
start_:
-/* TEMP - No residual data on BeBox (yet) */
-#if 0
-#define IS_BE_BOX 0x42654278 /* 'BeBx' */
- lis r2,IS_BE_BOX>>16
- ori r2,r2,IS_BE_BOX&0xFFFF
- cmp 0,r30,r2
- bne notBeBox
- li r3,0
-#endif
-notBeBox:
-/* TEMP */
mr r11,r3 /* Save pointer to residual data */
mfmsr r3 /* Turn off interrupts */
li r4,0
mtlr r21
mtctr r22
bctr /* Jump to code */
-/* Relocate code to final resting spot */
+/*
+ * no matter where we're loaded, move ourselves to -Ttext address
+ */
relocate:
mflr r3 /* Compute code bias */
subi r3,r3,4
mr r5,r6 /* Checksum */
mr r6,r11 /* Residual data */
bl decompress_kernel
- /*mr r29,r3*/ /* R3 = TotalMemory */
- /*lis r28,hold_residual@h
- ori r28,r28,hold_residual@l*/
+
/* changed to use r3 (as firmware does) for kernel
as ptr to residual -- Cort*/
- li r5,0x100 /* Kernel code starts here */
- mtlr r5
+ lis r6,cmd_line@h
+ ori r6,r6,cmd_line@l
+ subi r7,r7,1
+00: lbzu r2,1(r12)
+ cmpi 0,r2,0
+ bne 00b
+
+ /* r4,r5 have initrd_start, size */
+ lis r2,initrd_start@h
+ ori r2,r2,initrd_start@l
+ lwz r4,0(r2)
+ lis r2,initrd_end@h
+ ori r2,r2,initrd_end@l
+ lwz r5,0(r2)
+
+ li r9,0x00c /* Kernel code starts here */
+ mtlr r9
blr
hang:
b hang
mtspr HID0,r3
blr
+/*
+ * Delay for a number of microseconds
+ * -- Use the BUS timer (assumes 66MHz)
+ */
+ .globl udelay
+udelay:
+ mfspr r4,PVR
+ srwi r4,r4,16
+ cmpi 0,r4,1 /* 601 ? */
+ bne .udelay_not_601
+00: li r0,86 /* Instructions / microsecond? */
+ mtctr r0
+10: addi r0,r0,0 /* NOP */
+ bdnz 10b
+ subic. r3,r3,1
+ bne 00b
+ blr
+
+.udelay_not_601:
+ mulli r4,r3,1000 /* nanoseconds */
+ addi r4,r4,59
+ li r5,60
+ divw r4,r4,r5 /* BUS ticks */
+1: mftbu r5
+ mftb r6
+ mftbu r7
+ cmp 0,r5,r7
+ bne 1b /* Get [synced] base time */
+ addc r9,r6,r4 /* Compute end time */
+ addze r8,r5
+2: mftbu r5
+ cmp 0,r5,r8
+ blt 2b
+ bgt 3f
+ mftb r6
+ cmp 0,r6,r9
+ blt 2b
+3: blr
+
/*
* This space [buffer] is used to forceably flush the data cache when
* running in copyback mode. This is necessary IFF the data cache could
* puts by Nick Holloway 1993
*
* Adapted for PowerPC by Gary Thomas
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu)
*/
#include "gzip.h"
#include "lzw.h"
#include "asm/residual.h"
+#include <elf.h>
RESIDUAL hold_residual;
+unsigned long initrd_start = 0, initrd_end = 0;
+char *zimage_start;
+int zimage_size;
+extern char input_data[];
+extern int input_len;
+void cksum_text(void);
+void verify_data(unsigned long load_addr);
+
void dump_buf(unsigned char *p, int s);
#define EOF -1
unsigned insize;
unsigned inptr;
-extern char input_data[];
-extern int input_len;
+char cmd_line[256];
int input_ptr;
int orig_x, orig_y;
void puts(const char *);
+void putc(const char c);
+void puthex(unsigned long val);
+void _bcopy(char *src, char *dst, int len);
void *malloc(int size)
{
*/
if (free_mem_ptr < (long)&end) {
- if (free_mem_ptr > (long)&input_data[input_ptr])
+ if (free_mem_ptr > (long)&zimage_start[input_ptr])
error("\nOut of memory\n");
return p;
#endif
return p;
puts("large kernel, low 1M tight...");
- free_mem_ptr = (long)input_data;
+ free_mem_ptr = (long)zimage_start;
}
}
for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
vidmem[i] = ' ';
}
+#if 0
+tstc(void)
+{
+ return (CRT_tstc() );
+}
+
+getc(void)
+{
+ while (1) {
+ if (CRT_tstc()) return (CRT_getc());
+ }
+}
+#endif
+void
+putc(const char c)
+{
+ int x,y;
+
+ x = orig_x;
+ y = orig_y;
+
+ if ( c == '\n' ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ scroll();
+ y--;
+ }
+ } else if (c == '\b') {
+ if (x > 0) {
+ x--;
+ }
+ } else {
+ vidmem [ ( x + cols * y ) * 2 ] = c;
+ if ( ++x >= cols ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ scroll();
+ y--;
+ }
+ }
+ }
+
+ cursor(x, y);
+
+ orig_x = x;
+ orig_y = y;
+}
void puts(const char *s)
{
insize = 0;
do {
len = INBUFSIZ-insize;
- if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
+ if (len > (zimage_size-input_ptr+1)) len=zimage_size-input_ptr+1;
if (len == 0 || len == EOF) break;
- for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
+ for (i=0;i<len;i++) inbuf[insize+i] = zimage_start[input_ptr+i];
insize += len;
input_ptr += len;
} while (insize < INBUFSIZ);
unsigned long
decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
{
- unsigned long TotalMemory;
+ int timer;
+ char *cp, ch;
+ Elf32_Ehdr *eh;
+ Elf32_Shdr *sh, *strtab_shdr;
+ char *strtab;
+ unsigned long i;
+
+
output_data = (char *)0x0; /* Points to 0 */
lines = 25;
cols = 80;
clear_bufs();
makecrc();
- puts("Loaded at "); puthex(load_addr); puts(", "); puthex(num_words); puts(" words");
- puts(", cksum = "); puthex(cksum); puts("\n");
+ puts("Loaded at: "); puthex(load_addr); puts(" "); puthex(num_words+load_addr);
+ puts("\n");
+ /*puts("Relocated to start: "); puthex(start); puts(" ");
+ puthex(num_words+start);
+ puts("\n");*/
+ puts("Cksum: "); puthex(cksum); puts("\n");
if (residual) {
- _bcopy(residual, &hold_residual, sizeof(hold_residual));
- puts("Residual data at "); puthex(residual); puts("\n");
- show_residual_data(residual);
- TotalMemory = residual->TotalMemory;
- } else {
- TotalMemory = 0x01000000;
+ _bcopy((char *)residual, (char *)&hold_residual, sizeof(hold_residual));
+ puts("Residual data at: "); puthex((unsigned long)residual); puts(" ");
+ puthex((unsigned long)(residual->ResidualLength + residual)); puts("\n");
}
- puts("Uncompressing Linux...");
+ /*
+ * Take care of initrd if we have one
+ */
+ /*
+ * the _actual_ load addr is 64k (elf hdr size) lower but the
+ * firmware gives us the starting exec point not the load ptr
+ * -- Cort
+ */
+ eh = (Elf32_Ehdr *)(load_addr - 65536);
+ sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+ /*puts("Entry point: "); puthex(eh->e_entry); puts("\n");*/
+
+ /* find string table */
+ for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+ {
+ /*puts("Section: "); puthex(i);
+ puts(" type: "); puthex(sh->sh_type);
+ puts(" offset: "); puthex(sh->sh_offset);
+ puts("\n");*/
+
+ if ( sh->sh_type == SHT_STRTAB )
+ {
+ strtab_shdr = sh;
+ strtab = (char *)(sh->sh_offset + (unsigned long)eh);
+ /*puts("Found strtab at: "); puthex((unsigned long)strtab);
+ puts("\n");*/
+ break;
+ }
+ }
- method = get_method(0);
+ /* find the initrd and image sections */
+ if ( strtab_shdr )
+ {
+ sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+ for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+ {
+ if ( !memcmp("initrd", (char *)(strtab+sh->sh_name), 6 ) )
+ {
+ initrd_start = (unsigned long)eh + sh->sh_offset;
+ initrd_end = initrd_start + sh->sh_size;
+ puts("Found initrd at: "); puthex(initrd_start);
+ puts(" "); puthex(initrd_end);
+ puts("\n");
+ }
+ if ( !memcmp("image", (char *)(strtab+sh->sh_name), 5 ) )
+ {
+ zimage_start = (char *)((unsigned long)eh + sh->sh_offset);
+ zimage_size = sh->sh_size;
+ puts("Found zimage at: "); puthex((unsigned long)zimage_start);
+ puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
+ puts("\n");
+ }
+ }
+ }
+ else
+ {
+ puts("Couldn't find string table for boot image!\n");
+ }
+
+ /* relocate initrd */
+ if ( initrd_start )
+ {
+ memcpy ((void *)0x00D00000,(void *)initrd_start,
+ initrd_end - initrd_start );
+ initrd_end = 0x00D00000 + initrd_end - initrd_start;
+ initrd_start = 0x00D00000;
+ puts("Moved initrd to: "); puthex(initrd_start);
+ puts(" "); puthex(initrd_end); puts("\n");
+ }
+ /* make the moto firmware print something */
+
+ puts("Uncompressing Linux...");
+ method = get_method(0);
work(0, 0);
-
puts("done.\n");
+
puts("Now booting the kernel\n");
- /*return (TotalMemory);*/ /* Later this can be a pointer to saved residual data */
- return &hold_residual;
+ return (unsigned long)&hold_residual;
}
show_residual_data(RESIDUAL *res)
{
puts("Residual data: "); puthex(res->ResidualLength); puts(" bytes\n");
- puts("Total memory: "); puthex(res->TotalMemory); puts("\n");
#if 0
puts("Residual structure = "); puthex(sizeof(*res)); puts(" bytes\n");
dump_buf(&hold_residual, 32);
{
unsigned int *ptr, len, cksum, cnt;
cksum = cnt = 0;
- ptr = input_data;
+ ptr = (unsigned int *)zimage_start;
puts("Checksums: ");
- for (len = 0; len < input_len; len += 4) {
+ for (len = 0; len < zimage_size; len += 4) {
cksum ^= *ptr++;
if (len && ((len & 0x0FFF) == 0)) {
if (cnt == 0) {
puts("\n [");
- puthex(ptr-1);
+ puthex((unsigned long)ptr-1);
puts("] ");
}
puthex(cksum);
puts("Data cksum = "); puthex(cksum); puts("\n");
}
-cksum_text()
+void cksum_text(void)
{
extern int start, etext;
unsigned int *ptr, len, text_len, cksum, cnt;
if (len && ((len & 0x0FFF) == 0)) {
if (cnt == 0) {
puts("\n [");
- puthex(ptr-1);
+ puthex((unsigned long)ptr-1);
puts("] ");
}
puthex(cksum);
puts("TEXT cksum = "); puthex(cksum); puts("\n");
}
-verify_data(unsigned long load_addr)
+void verify_data(unsigned long load_addr)
{
extern int start, etext;
unsigned int *orig_ptr, *copy_ptr, len, errors;
errors = 0;
- copy_ptr = input_data;
- orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
- for (len = 0; len < input_len; len += 4) {
+ copy_ptr = (unsigned int *)zimage_start;
+ orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+ for (len = 0; len < zimage_size; len += 4) {
if (*copy_ptr++ != *orig_ptr++) {
errors++;
}
}
- copy_ptr = input_data;
- orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
- for (len = 0; len < input_len; len += 4) {
+ copy_ptr = (unsigned int *)zimage_start;
+ orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+ for (len = 0; len < zimage_size; len += 4) {
if (*copy_ptr++ != *orig_ptr++) {
- dump_buf(copy_ptr-1, 128);
- dump_buf(orig_ptr-1, 128);
+ dump_buf((unsigned char *) (copy_ptr-1), 128);
+ dump_buf((unsigned char *) (orig_ptr-1), 128);
puts("Total errors = "); puthex(errors*4); puts("\n");
while (1) ;
}
extern int start, etext;
unsigned int *orig_ptr, *copy_ptr, len, errors;
errors = 0;
- copy_ptr = input_data;
- orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
- for (len = 0; len < input_len; len += 4) {
+ copy_ptr = (unsigned int *)zimage_start;
+ orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+ for (len = 0; len < zimage_size; len += 4) {
if (*copy_ptr++ != *orig_ptr++) {
errors++;
}
}
while (s > 0)
{
- puthex(p); puts(": ");
+ puthex((unsigned long)p); puts(": ");
for (i = 0; i < 16; i++)
{
if (i < s)
argptr++;
/* skip elf header in input file */
- lseek(in_fd, elfhdr_size, SEEK_SET);
+ if ( !prep )
+ lseek(in_fd, elfhdr_size, SEEK_SET);
/* write prep partition if necessary */
if ( prep )
- write_prep_partition( in_fd, out_fd );
+ write_prep_partition( in_fd, out_fd );
/* write input image to bootimage */
if ( asmoutput )
- write_asm_data( in_fd, out_fd );
+ write_asm_data( in_fd, out_fd );
else
- copy_image(in_fd, out_fd);
+ copy_image(in_fd, out_fd);
return 0;
}
}
bzero( block, sizeof block );
-
- /* set entry point and boot image size */
- *entry = cpu_to_le32(0x400);
- /* need use size - elfheader? */
+ /* set entry point and boot image size skipping over elf header */
+ *entry = cpu_to_le32(0x400+65536);
*length = cpu_to_le32(info.st_size+0x400);
- /*
- * Writes the "boot record", which contains the partition table, to the
- * diskette, followed by the dummy PC boot block and load image descriptor
- * block. It returns the number of bytes it has written to the load
- * image.
- *
- * The boot record is the first block of the diskette and identifies the
- * "PReP" partition. The "PReP" partition contains the "load image" starting
- * at offset zero within the partition. The first block of the load image is
- * a dummy PC boot block. The second block is the "load image descriptor"
- * which contains the size of the load image and the entry point into the
- * image. The actual boot image starts at offset 1024 bytes (third sector)
- * in the partition.
- */
-
/* sets magic number for msdos partition (used by linux) */
block[510] = 0x55;
block[511] = 0xAA;
/* This has to be 0 on the PowerStack? */
pe->beginning_sector = cpu_to_le32(0);
#endif
-/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/
+ pe->number_of_sectors = cpu_to_le32(2*18*80-1);
write( out, block, sizeof(block) );
write( out, entry, sizeof(*entry) );
--- /dev/null
+# Makefile for making XCOFF bootable images for booting on PowerMacs
+# using Open Firmware.
+#
+# Paul Mackerras January 1997
+
+# PowerPC (cross) tools
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE =powerpc-eabi-
+endif
+
+HOSTCC = gcc
+HOSTCFLAGS = -O -I$(TOPDIR)/include
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+CFLAGS = -O -fno-builtin -I$(TOPDIR)/include
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \
+ --add-section=image=zImage
+LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+GZIP = gzip -9
+
+OBJS = crt0.o start.o main.o misc.o string.o zlib.o
+LIBS = $(TOPDIR)/lib/lib.a
+
+vmlinux.coff: coffboot hack-coff zImage
+ $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
+ ./hack-coff $@
+
+vmlinux.coff.initrd: coffboot hack-coff zImage ramdisk.image.gz
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+ coffboot $@
+ ./hack-coff $@
+
+coffboot: $(OBJS) ld.script
+ $(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
+
+zImage: $(TOPDIR)/vmlinux elfextract
+ ./elfextract $(TOPDIR)/vmlinux | $(GZIP) >zImage
+
+hack-coff: hack-coff.c
+ $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
+
+elfextract: elfextract.c
+ $(HOSTCC) $(HOSTCFLAGS) -o elfextract elfextract.c
+
+clean:
+ rm -f elfextract hack-coff coffboot zImage vmlinux.coff
+
+fastdep:
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+ .text
+ .globl _start
+_start:
+ .long __start,0,0
+
+ .globl __start
+__start:
+ lis 9,_start@h
+ lis 8,_etext@ha
+ addi 8,8,_etext@l
+1: dcbf 0,9
+ icbi 0,9
+ addi 9,9,0x20
+ cmplwi 0,9,8
+ blt 1b
+ b start
--- /dev/null
+/*
+ * Extract the loadable program segment from an elf file.
+ *
+ * Copyright 1996 Paul Mackerras.
+ *
+ * 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 <stdio.h>
+#include <linux/elf.h>
+
+FILE *fi, *fo;
+char *ni, *no;
+char buf[65536];
+
+void
+rd(void *buf, int len)
+{
+ int nr;
+
+ nr = fread(buf, 1, len, fi);
+ if (nr == len)
+ return;
+ if (ferror(fi))
+ fprintf(stderr, "%s: read error\n", ni);
+ else
+ fprintf(stderr, "%s: short file\n", ni);
+ exit(1);
+}
+
+main(int ac, char **av)
+{
+ unsigned nb, len;
+ Elf32_Ehdr eh;
+ Elf32_Phdr ph;
+
+ if (ac > 3 || ac > 1 && av[1][0] == '-') {
+ fprintf(stderr, "Usage: %s [elf-file [image-file]]\n", av[0]);
+ exit(0);
+ }
+
+ fi = stdin;
+ ni = "(stdin)";
+ fo = stdout;
+ no = "(stdout)";
+
+ if (ac > 1) {
+ ni = av[1];
+ fi = fopen(ni, "rb");
+ if (fi == NULL) {
+ perror(ni);
+ exit(1);
+ }
+ }
+
+ rd(&eh, sizeof(eh));
+ if (eh.e_ident[EI_MAG0] != ELFMAG0
+ || eh.e_ident[EI_MAG1] != ELFMAG1
+ || eh.e_ident[EI_MAG2] != ELFMAG2
+ || eh.e_ident[EI_MAG3] != ELFMAG3) {
+ fprintf(stderr, "%s: not an ELF file\n", ni);
+ exit(1);
+ }
+
+ fseek(fi, eh.e_phoff + (eh.e_phnum - 1) * sizeof(ph), 0);
+ rd(&ph, sizeof(ph));
+ if (ph.p_type != PT_LOAD) {
+ fprintf(stderr, "%s: doesn't have a loadable segment\n", ni);
+ exit(1);
+ }
+
+ if (ac > 2) {
+ no = av[2];
+ fo = fopen(no, "wb");
+ if (fo == NULL) {
+ perror(no);
+ exit(1);
+ }
+ }
+
+ fseek(fi, ph.p_offset, 0);
+ for (len = ph.p_filesz; len != 0; len -= nb) {
+ nb = len;
+ if (nb > sizeof(buf))
+ nb = sizeof(buf);
+ rd(buf, nb);
+ if (fwrite(buf, 1, nb, fo) != nb) {
+ fprintf(stderr, "%s: write error\n", no);
+ exit(1);
+ }
+ }
+
+ fclose(fo);
+ fclose(fi);
+ exit(0);
+}
--- /dev/null
+/*
+ * hack-coff.c - hack the header of an xcoff file to fill in
+ * a few fields needed by the Open Firmware xcoff loader on
+ * Power Macs but not initialized by objcopy.
+ *
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 <stdio.h>
+#include "rs6000.h"
+
+#define AOUT_MAGIC 0x010b
+
+#define get_16be(x) ((((unsigned char *)(x))[0] << 8) \
+ + ((unsigned char *)(x))[1])
+#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \
+ ((unsigned char *)(x))[1] = (v) & 0xff)
+#define get_32be(x) ((((unsigned char *)(x))[0] << 24) \
+ + (((unsigned char *)(x))[1] << 16) \
+ + (((unsigned char *)(x))[2] << 8) \
+ + ((unsigned char *)(x))[3])
+
+main(int ac, char **av)
+{
+ int fd;
+ int i, nsect;
+ int aoutsz;
+ struct external_filehdr fhdr;
+ AOUTHDR aout;
+ struct external_scnhdr shdr;
+
+ if (ac != 2) {
+ fprintf(stderr, "Usage: hack-coff coff-file\n");
+ exit(1);
+ }
+ if ((fd = open(av[1], 2)) == -1) {
+ perror(av[2]);
+ exit(1);
+ }
+ if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
+ goto readerr;
+ i = get_16be(fhdr.f_magic);
+ if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
+ fprintf(stderr, "%s: not an xcoff file\n", av[1]);
+ exit(1);
+ }
+ aoutsz = get_16be(fhdr.f_opthdr);
+ if (read(fd, &aout, aoutsz) != aoutsz)
+ goto readerr;
+ nsect = get_16be(fhdr.f_nscns);
+ for (i = 0; i < nsect; ++i) {
+ if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
+ goto readerr;
+ if (strcmp(shdr.s_name, ".text") == 0) {
+ put_16be(aout.o_snentry, i+1);
+ put_16be(aout.o_sntext, i+1);
+ } else if (strcmp(shdr.s_name, ".data") == 0) {
+ put_16be(aout.o_sndata, i+1);
+ } else if (strcmp(shdr.s_name, ".bss") == 0) {
+ put_16be(aout.o_snbss, i+1);
+ }
+ }
+ put_16be(aout.magic, AOUT_MAGIC);
+ if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
+ || write(fd, &aout, aoutsz) != aoutsz) {
+ fprintf(stderr, "%s: write error\n", av[1]);
+ exit(1);
+ }
+ close(fd);
+ exit(0);
+
+readerr:
+ fprintf(stderr, "%s: read error or file too short\n", av[1]);
+ exit(1);
+}
--- /dev/null
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) } =0
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text)
+ *(.rodata)
+ *(.rodata1)
+ *(.got1)
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ _etext = .;
+ PROVIDE (etext = .);
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt) *(.got)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
+
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 "nonstdio.h"
+#include "rs6000.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+void gunzip(void *, int, unsigned char *, int *);
+
+#define get_16be(x) (*(unsigned short *)(x))
+#define get_32be(x) (*(unsigned *)(x))
+
+#define RAM_START 0xc0000000
+#define RAM_END 0xc0800000 /* only 8M mapped with BATs */
+
+#define RAM_FREE 0xc0540000 /* after image of coffboot */
+
+char *avail_ram;
+char *end_avail;
+
+coffboot(int a1, int a2, void *prom)
+{
+ void *options;
+ unsigned loadbase;
+ struct external_filehdr *eh;
+ struct external_scnhdr *sp;
+ struct external_scnhdr *isect, *rsect;
+ int ns, oh, i;
+ unsigned sa, len;
+ void *dst;
+ unsigned char *im;
+ unsigned initrd_start, initrd_size;
+
+ printf("coffboot starting\n");
+ options = finddevice("/options");
+ if (options == (void *) -1)
+ exit();
+ if (getprop(options, "load-base", &loadbase, sizeof(loadbase))
+ != sizeof(loadbase)) {
+ printf("error getting load-base\n");
+ exit();
+ }
+ setup_bats();
+
+ eh = (struct external_filehdr *) loadbase;
+ ns = get_16be(eh->f_nscns);
+ oh = get_16be(eh->f_opthdr);
+
+ sp = (struct external_scnhdr *) (loadbase + sizeof(struct external_filehdr) + oh);
+ isect = rsect = NULL;
+ for (i = 0; i < ns; ++i, ++sp) {
+ if (strcmp(sp->s_name, "image") == 0)
+ isect = sp;
+ else if (strcmp(sp->s_name, "initrd") == 0)
+ rsect = sp;
+ }
+ if (isect == NULL) {
+ printf("image section not found\n");
+ exit();
+ }
+
+ if (rsect != NULL && (initrd_size = get_32be(rsect->s_size)) != 0) {
+ initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+ a1 = initrd_start;
+ a2 = initrd_size;
+ printf("initial ramdisk at %x (%u bytes)\n",
+ initrd_start, initrd_size);
+ memcpy((char *) initrd_start,
+ (char *) (loadbase + get_32be(rsect->s_scnptr)),
+ initrd_size);
+ end_avail = (char *) initrd_start;
+ } else {
+ end_avail = (char *) RAM_END;
+ }
+
+ im = (unsigned char *)(loadbase + get_32be(isect->s_scnptr));
+ len = get_32be(isect->s_size);
+ dst = (void *) RAM_START;
+
+ if (im[0] == 0x1f && im[1] == 0x8b) {
+ void *cp = (void *) RAM_FREE;
+ avail_ram = (void *) (RAM_FREE + ((len + 7) & -8));
+ memcpy(cp, im, len);
+ printf("gunzipping... ");
+ gunzip(dst, 0x400000, cp, &len);
+ printf("done\n");
+
+ } else {
+ memmove(dst, im, len);
+ }
+
+ flush_cache(dst, len);
+
+ sa = *(unsigned *)dst + RAM_START;
+ printf("start address = 0x%x\n", sa);
+
+#if 0
+ pause();
+#endif
+ (*(void (*)())sa)(a1, a2, prom);
+
+ printf("returned?\n");
+
+ pause();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p = avail_ram;
+
+ size *= items;
+ size = (size + 7) & -8;
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ printf("oops... out of memory\n");
+ pause();
+ }
+ return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+ z_stream s;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ printf("bad gzipped data\n");
+ exit();
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= *lenp) {
+ printf("gunzip: ran out of data in header\n");
+ exit();
+ }
+
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ printf("inflateInit2 returned %d\n", r);
+ exit();
+ }
+ s.next_in = src + i;
+ s.avail_in = *lenp - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ r = inflate(&s, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END) {
+ printf("inflate returned %d\n", r);
+ exit();
+ }
+ *lenp = s.next_out - (unsigned char *) dst;
+ inflateEnd(&s);
+}
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+ .text
+
+/*
+ * Use the BAT0 registers to map the 1st 8MB of RAM to 0xc0000000.
+ */
+ .globl setup_bats
+setup_bats:
+ mfpvr 3
+ rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */
+ cmpi 0,3,1
+ lis 4,0xc000
+ bne 4f
+ ori 4,4,4 /* set up BAT registers for 601 */
+ li 5,0x7f
+ b 5f
+4: ori 4,4,0xff /* set up BAT registers for 604 */
+ li 5,2
+ mtdbatu 0,4
+ mtdbatl 0,5
+5: mtibatu 0,4
+ mtibatl 0,5
+ isync
+ blr
+
+/*
+ * Flush the dcache and invalidate the icache for a range of addresses.
+ *
+ * flush_cache(addr, len)
+ */
+ .global flush_cache
+flush_cache:
+ addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */
+ rlwinm. 4,4,27,5,31
+ mtctr 4
+ beqlr
+1: dcbf 0,3
+ icbi 0,3
+ addi 3,3,0x20
+ bdnz 1b
+ sync
+ isync
+ blr
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+typedef int FILE;
+extern FILE *stdin, *stdout;
+#define NULL ((void *)0)
+#define EOF (-1)
+#define fopen(n, m) NULL
+#define fflush(f) 0
+#define fclose(f) 0
+extern char *fgets();
+
+#define perror(s) printf("%s: no files!\n", (s))
--- /dev/null
+/* IBM RS/6000 "XCOFF" file definitions for BFD.
+ Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+ FIXME: Can someone provide a transliteration of this name into ASCII?
+ Using the following chars caused a compiler warning on HIUX (so I replaced
+ them with octal escapes), and isn't useful without an understanding of what
+ character set it is.
+ Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM
+ and John Gilmore of Cygnus Support. */
+
+/********************** FILE HEADER **********************/
+
+struct external_filehdr {
+ char f_magic[2]; /* magic number */
+ char f_nscns[2]; /* number of sections */
+ char f_timdat[4]; /* time & date stamp */
+ char f_symptr[4]; /* file pointer to symtab */
+ char f_nsyms[4]; /* number of symtab entries */
+ char f_opthdr[2]; /* sizeof(optional hdr) */
+ char f_flags[2]; /* flags */
+};
+
+ /* IBM RS/6000 */
+#define U802WRMAGIC 0730 /* writeable text segments **chh** */
+#define U802ROMAGIC 0735 /* readonly sharable text segments */
+#define U802TOCMAGIC 0737 /* readonly text segments and TOC */
+
+#define BADMAG(x) \
+ ((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
+ (x).f_magic != U802TOCMAGIC)
+
+#define FILHDR struct external_filehdr
+#define FILHSZ 20
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+
+typedef struct
+{
+ unsigned char magic[2]; /* type of file */
+ unsigned char vstamp[2]; /* version stamp */
+ unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */
+ unsigned char dsize[4]; /* initialized data " " */
+ unsigned char bsize[4]; /* uninitialized data " " */
+ unsigned char entry[4]; /* entry pt. */
+ unsigned char text_start[4]; /* base of text used for this file */
+ unsigned char data_start[4]; /* base of data used for this file */
+ unsigned char o_toc[4]; /* address of TOC */
+ unsigned char o_snentry[2]; /* section number of entry point */
+ unsigned char o_sntext[2]; /* section number of .text section */
+ unsigned char o_sndata[2]; /* section number of .data section */
+ unsigned char o_sntoc[2]; /* section number of TOC */
+ unsigned char o_snloader[2]; /* section number of .loader section */
+ unsigned char o_snbss[2]; /* section number of .bss section */
+ unsigned char o_algntext[2]; /* .text alignment */
+ unsigned char o_algndata[2]; /* .data alignment */
+ unsigned char o_modtype[2]; /* module type (??) */
+ unsigned char o_cputype[2]; /* cpu type */
+ unsigned char o_maxstack[4]; /* max stack size (??) */
+ unsigned char o_maxdata[4]; /* max data size (??) */
+ unsigned char o_resv2[12]; /* reserved */
+}
+AOUTHDR;
+
+#define AOUTSZ 72
+#define SMALL_AOUTSZ (28)
+#define AOUTHDRSZ 72
+
+#define RS6K_AOUTHDR_OMAGIC 0x0107 /* old: text & data writeable */
+#define RS6K_AOUTHDR_NMAGIC 0x0108 /* new: text r/o, data r/w */
+#define RS6K_AOUTHDR_ZMAGIC 0x010B /* paged: text r/o, both page-aligned */
+
+
+/********************** SECTION HEADER **********************/
+
+
+struct external_scnhdr {
+ char s_name[8]; /* section name */
+ char s_paddr[4]; /* physical address, aliased s_nlib */
+ char s_vaddr[4]; /* virtual address */
+ char s_size[4]; /* section size */
+ char s_scnptr[4]; /* file ptr to raw data for section */
+ char s_relptr[4]; /* file ptr to relocation */
+ char s_lnnoptr[4]; /* file ptr to line numbers */
+ char s_nreloc[2]; /* number of relocation entries */
+ char s_nlnno[2]; /* number of line number entries*/
+ char s_flags[4]; /* flags */
+};
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT ".text"
+#define _DATA ".data"
+#define _BSS ".bss"
+#define _PAD ".pad"
+#define _LOADER ".loader"
+
+#define SCNHDR struct external_scnhdr
+#define SCNHSZ 40
+
+/* XCOFF uses a special .loader section with type STYP_LOADER. */
+#define STYP_LOADER 0x1000
+
+/* XCOFF uses a special .debug section with type STYP_DEBUG. */
+#define STYP_DEBUG 0x2000
+
+/* XCOFF handles line number or relocation overflow by creating
+ another section header with STYP_OVRFLO set. */
+#define STYP_OVRFLO 0x8000
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct external_lineno {
+ union {
+ char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
+ char l_paddr[4]; /* (physical) address of line number */
+ } l_addr;
+ char l_lnno[2]; /* line number */
+};
+
+
+#define LINENO struct external_lineno
+#define LINESZ 6
+
+
+/********************** SYMBOLS **********************/
+
+#define E_SYMNMLEN 8 /* # characters in a symbol name */
+#define E_FILNMLEN 14 /* # characters in a file name */
+#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
+
+struct external_syment
+{
+ union {
+ char e_name[E_SYMNMLEN];
+ struct {
+ char e_zeroes[4];
+ char e_offset[4];
+ } e;
+ } e;
+ char e_value[4];
+ char e_scnum[2];
+ char e_type[2];
+ char e_sclass[1];
+ char e_numaux[1];
+};
+
+
+
+#define N_BTMASK (017)
+#define N_TMASK (060)
+#define N_BTSHFT (4)
+#define N_TSHIFT (2)
+
+
+union external_auxent {
+ struct {
+ char x_tagndx[4]; /* str, un, or enum tag indx */
+ union {
+ struct {
+ char x_lnno[2]; /* declaration line number */
+ char x_size[2]; /* str/union/array size */
+ } x_lnsz;
+ char x_fsize[4]; /* size of function */
+ } x_misc;
+ union {
+ struct { /* if ISFCN, tag, or .bb */
+ char x_lnnoptr[4]; /* ptr to fcn line # */
+ char x_endndx[4]; /* entry ndx past block end */
+ } x_fcn;
+ struct { /* if ISARY, up to 4 dimen. */
+ char x_dimen[E_DIMNUM][2];
+ } x_ary;
+ } x_fcnary;
+ char x_tvndx[2]; /* tv index */
+ } x_sym;
+
+ union {
+ char x_fname[E_FILNMLEN];
+ struct {
+ char x_zeroes[4];
+ char x_offset[4];
+ } x_n;
+ } x_file;
+
+ struct {
+ char x_scnlen[4]; /* section length */
+ char x_nreloc[2]; /* # relocation entries */
+ char x_nlinno[2]; /* # line numbers */
+ } x_scn;
+
+ struct {
+ char x_tvfill[4]; /* tv fill value */
+ char x_tvlen[2]; /* length of .tv */
+ char x_tvran[2][2]; /* tv range */
+ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
+
+ struct {
+ unsigned char x_scnlen[4];
+ unsigned char x_parmhash[4];
+ unsigned char x_snhash[2];
+ unsigned char x_smtyp[1];
+ unsigned char x_smclas[1];
+ unsigned char x_stab[4];
+ unsigned char x_snstab[2];
+ } x_csect;
+
+};
+
+#define SYMENT struct external_syment
+#define SYMESZ 18
+#define AUXENT union external_auxent
+#define AUXESZ 18
+#define DBXMASK 0x80 /* for dbx storage mask */
+#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK)
+
+
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+
+struct external_reloc {
+ char r_vaddr[4];
+ char r_symndx[4];
+ char r_size[1];
+ char r_type[1];
+};
+
+
+#define RELOC struct external_reloc
+#define RELSZ 10
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 4
+/* For new sections we havn't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 <stdarg.h>
+
+int (*prom)();
+
+void *chosen_handle;
+void *stdin;
+void *stdout;
+void *stderr;
+
+void exit(void);
+void *finddevice(const char *name);
+int getprop(void *phandle, const char *name, void *buf, int buflen);
+
+void
+start(int a1, int a2, void *promptr)
+{
+ prom = (int (*)()) promptr;
+ chosen_handle = finddevice("/chosen");
+ if (chosen_handle == (void *) -1)
+ exit();
+ if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
+ exit();
+ stderr = stdout;
+ if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
+ exit();
+
+ coffboot(a1, a2, promptr);
+ for (;;)
+ exit();
+}
+
+int
+write(void *handle, void *ptr, int nb)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ void *ihandle;
+ void *addr;
+ int len;
+ int actual;
+ } args;
+
+ args.service = "write";
+ args.nargs = 3;
+ args.nret = 1;
+ args.ihandle = handle;
+ args.addr = ptr;
+ args.len = nb;
+ args.actual = -1;
+ (*prom)(&args);
+ return args.actual;
+}
+
+int
+read(void *handle, void *ptr, int nb)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ void *ihandle;
+ void *addr;
+ int len;
+ int actual;
+ } args;
+
+ args.service = "read";
+ args.nargs = 3;
+ args.nret = 1;
+ args.ihandle = handle;
+ args.addr = ptr;
+ args.len = nb;
+ args.actual = -1;
+ (*prom)(&args);
+ return args.actual;
+}
+
+void
+exit()
+{
+ struct prom_args {
+ char *service;
+ } args;
+
+ for (;;) {
+ args.service = "exit";
+ (*prom)(&args);
+ }
+}
+
+void
+pause()
+{
+ struct prom_args {
+ char *service;
+ } args;
+
+ args.service = "enter";
+ (*prom)(&args);
+}
+
+void *
+finddevice(const char *name)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ const char *devspec;
+ void *phandle;
+ } args;
+
+ args.service = "finddevice";
+ args.nargs = 1;
+ args.nret = 1;
+ args.devspec = name;
+ args.phandle = (void *) -1;
+ (*prom)(&args);
+ return args.phandle;
+}
+
+int
+getprop(void *phandle, const char *name, void *buf, int buflen)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ void *phandle;
+ const char *name;
+ void *buf;
+ int buflen;
+ int size;
+ } args;
+
+ args.service = "getprop";
+ args.nargs = 4;
+ args.nret = 1;
+ args.phandle = phandle;
+ args.name = name;
+ args.buf = buf;
+ args.buflen = buflen;
+ args.size = -1;
+ (*prom)(&args);
+ return args.size;
+}
+
+int
+putc(int c, void *f)
+{
+ char ch = c;
+
+ if (c == '\n')
+ putc('\r', f);
+ return write(f, &ch, 1) == 1? c: -1;
+}
+
+int
+putchar(int c)
+{
+ return putc(c, stdout);
+}
+
+int
+fputs(char *str, void *f)
+{
+ int n = strlen(str);
+
+ return write(f, str, n) == n? 0: -1;
+}
+
+int
+readchar()
+{
+ char ch;
+
+ for (;;) {
+ switch (read(stdin, &ch, 1)) {
+ case 1:
+ return ch;
+ case -1:
+ printk("read(stdin) returned -1\r\n");
+ return -1;
+ }
+ }
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int
+getchar()
+{
+ int c;
+
+ if (lineleft == 0) {
+ lineptr = line;
+ for (;;) {
+ c = readchar();
+ if (c == -1 || c == 4)
+ break;
+ if (c == '\r' || c == '\n') {
+ *lineptr++ = '\n';
+ putchar('\n');
+ break;
+ }
+ switch (c) {
+ case 0177:
+ case '\b':
+ if (lineptr > line) {
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ --lineptr;
+ }
+ break;
+ case 'U' & 0x1F:
+ while (lineptr > line) {
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ --lineptr;
+ }
+ break;
+ default:
+ if (lineptr >= &line[sizeof(line) - 1])
+ putchar('\a');
+ else {
+ putchar(c);
+ *lineptr++ = c;
+ }
+ }
+ }
+ lineleft = lineptr - line;
+ lineptr = line;
+ }
+ if (lineleft == 0)
+ return -1;
+ --lineleft;
+ return *lineptr++;
+}
+
+extern int vsprintf(char *buf, const char *fmt, va_list args);
+static char sprint_buf[1024];
+
+void
+printk(char *fmt, ...)
+{
+ va_list args;
+ int n;
+
+ va_start(args, fmt);
+ n = vsprintf(sprint_buf, fmt, args);
+ va_end(args);
+ write(stdout, sprint_buf, n);
+}
+
+int
+printf(char *fmt, ...)
+{
+ va_list args;
+ int n;
+
+ va_start(args, fmt);
+ n = vsprintf(sprint_buf, fmt, args);
+ va_end(args);
+ write(stdout, sprint_buf, n);
+ return n;
+}
--- /dev/null
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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.
+ */
+#define r0 0
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+
+ .globl strcpy
+strcpy:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strncpy
+strncpy:
+ cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ blr
+
+ .globl strcat
+strcat:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r5)
+ cmpwi 0,r0,0
+ bne 1b
+ addi r5,r5,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strcmp
+strcmp:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r5)
+ cmpwi 1,r3,0
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ beqlr 1
+ beq 1b
+ blr
+
+ .globl strlen
+strlen:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ blr
+
+ .globl memset
+memset:
+ rlwimi r4,r4,8,16,23
+ rlwimi r4,r4,16,0,15
+ addi r6,r3,-4
+ cmplwi 0,r5,4
+ blt 7f
+ stwu r4,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r5,r0,r5
+ subf r6,r0,r6
+ rlwinm r0,r5,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r4,4(r6)
+ bdnz 1b
+6: andi. r5,r5,3
+7: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r6,3
+8: stbu r4,1(r6)
+ bdnz 8b
+ blr
+
+ .globl bcopy
+bcopy:
+ mr r6,r3
+ mr r3,r4
+ mr r4,r6
+ b memcpy
+
+ .globl memmove
+memmove:
+ cmplw 0,r3,r4
+ bgt backwards_memcpy
+ /* fall through */
+
+ .globl memcpy
+memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ addi r6,r3,-4
+ addi r4,r4,-4
+ beq 2f /* if less than 8 bytes to do */
+ andi. r0,r6,3 /* get dest word aligned */
+ mtctr r7
+ bne 5f
+1: lwz r7,4(r4)
+ lwzu r8,8(r4)
+ stw r7,4(r6)
+ stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,4(r4)
+ addi r5,r5,-4
+ stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+ stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+6: lbz r7,4(r4)
+ addi r4,r4,1
+ stb r7,4(r6)
+ addi r6,r6,1
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl backwards_memcpy
+backwards_memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ add r6,r3,r5
+ add r4,r4,r5
+ beq 2f
+ andi. r0,r6,3
+ mtctr r7
+ bne 5f
+1: lwz r7,-4(r4)
+ lwzu r8,-8(r4)
+ stw r7,-4(r6)
+ stwu r8,-8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,-4(r4)
+ subi r5,r5,4
+ stwu r0,-4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+4: lbzu r0,-1(r4)
+ stbu r0,-1(r6)
+ bdnz 4b
+ blr
+5: mtctr r0
+6: lbzu r7,-1(r4)
+ stbu r7,-1(r6)
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl memcmp
+memcmp:
+ cmpwi 0,r5,0
+ blelr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r6)
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ bdnzt 2,1b
+ blr
--- /dev/null
+/*
+ * This file is derived from various .h and .c files from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets. See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - changed functions not used outside this file to "local"
+ * - added minCompression parameter to deflateInit2
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp
+ *
+ * $Id: zlib.c,v 1.1 1997/07/31 07:16:14 paulus Exp $
+ */
+
+/*+++++*/
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */
+
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#define FAR
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern char *z_errmsg[]; /* indexed by 1-zlib_error */
+
+#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err)
+/* To be used only when the state is known to be valid */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+ /* common constants */
+
+#define DEFLATED 8
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+ /* functions */
+
+#include <string.h>
+#define zmemcpy memcpy
+#define zmemzero(dest, len) memset(dest, 0, len)
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+# include <stdio.h>
+# ifndef verbose
+# define verbose 0
+# endif
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len));
+
+/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */
+/* void zcfree OF((voidpf opaque, voidpf ptr)); */
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr, size) \
+ (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size))
+#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);}
+
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/*+++++*/
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+local inflate_blocks_statef * inflate_blocks_new OF((
+ z_stream *z,
+ check_func c, /* check function */
+ uInt w)); /* window size */
+
+local int inflate_blocks OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ int)); /* initial return code */
+
+local void inflate_blocks_reset OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ uLongf *)); /* check value on output */
+
+local int inflate_blocks_free OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ uLongf *)); /* check value on output */
+
+local int inflate_addhistory OF((
+ inflate_blocks_statef *,
+ z_stream *));
+
+local int inflate_packet_flush OF((
+ inflate_blocks_statef *));
+
+/*+++++*/
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ uInt Nalloc; /* number of these allocated here */
+ Bytef *pad; /* pad structure to a power of 2 (4 bytes for */
+ } word; /* 16-bit, 8 bytes for 32-bit machines) */
+ union {
+ uInt Base; /* literal, length base, or distance base */
+ inflate_huft *Next; /* pointer to next level of table */
+ } more;
+};
+
+#ifdef DEBUG_ZLIB
+ local uInt inflate_hufts;
+#endif
+
+local int inflate_trees_bits OF((
+ uIntf *, /* 19 code lengths */
+ uIntf *, /* bits tree desired/actual depth */
+ inflate_huft * FAR *, /* bits tree result */
+ z_stream *)); /* for zalloc, zfree functions */
+
+local int inflate_trees_dynamic OF((
+ uInt, /* number of literal/length codes */
+ uInt, /* number of distance codes */
+ uIntf *, /* that many (total) code lengths */
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ z_stream *)); /* for zalloc, zfree functions */
+
+local int inflate_trees_fixed OF((
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *)); /* distance tree result */
+
+local int inflate_trees_free OF((
+ inflate_huft *, /* tables to free */
+ z_stream *)); /* for zfree function */
+
+
+/*+++++*/
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+local inflate_codes_statef *inflate_codes_new OF((
+ uInt, uInt,
+ inflate_huft *, inflate_huft *,
+ z_stream *));
+
+local int inflate_codes OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ int));
+
+local void inflate_codes_free OF((
+ inflate_codes_statef *,
+ z_stream *));
+
+
+/*+++++*/
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+ mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_stream *z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, &c);
+ Trace((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_stream *z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z, &c);
+ ZFREE(z, z->state, sizeof(struct internal_state));
+ z->state = Z_NULL;
+ Trace((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int inflateInit2(z, w)
+z_stream *z;
+int w;
+{
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */
+/* if (z->zfree == Z_NULL) z->zfree = zcfree; */
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Trace((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+int inflateInit(z)
+z_stream *z;
+{
+ return inflateInit2(z, DEF_WBITS);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_stream *z;
+int f;
+{
+ int r;
+ uInt b;
+
+ if (z == Z_NULL || z->next_in == Z_NULL)
+ return Z_STREAM_ERROR;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = "unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = "invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ if ((b = NEXTBYTE) & 0x20)
+ {
+ z->state->mode = BAD;
+ z->msg = "invalid reserved bit";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = "incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib header ok\n"));
+ z->state->mode = BLOCKS;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+ r = inflate_packet_flush(z->state->blocks);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r != Z_STREAM_END)
+ return r;
+ r = Z_OK;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = "incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ empty:
+ if (f != Z_PACKET_FLUSH)
+ return r;
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_DATA_ERROR;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output. The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS). On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+ if (z->state->mode != BLOCKS)
+ return Z_DATA_ERROR;
+ return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_stream *z;
+{
+ uInt n; /* number of bytes to look at */
+ Bytef *p; /* pointer to bytes */
+ uInt m; /* number of marker bytes found in a row */
+ uLong r, w; /* temporaries to save total_in and total_out */
+
+ /* set up */
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->mode != BAD)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0;
+ }
+ if ((n = z->avail_in) == 0)
+ return Z_BUF_ERROR;
+ p = z->next_in;
+ m = z->state->sub.marker;
+
+ /* search */
+ while (n && m < 4)
+ {
+ if (*p == (Byte)(m < 2 ? 0 : 0xff))
+ m++;
+ else if (*p)
+ m = 0;
+ else
+ m = 4 - m;
+ p++, n--;
+ }
+
+ /* restore */
+ z->total_in += p - z->next_in;
+ z->next_in = p;
+ z->avail_in = n;
+ z->state->sub.marker = m;
+
+ /* return no joy or set up to restart on a new block */
+ if (m != 4)
+ return Z_DATA_ERROR;
+ r = z->total_in; w = z->total_out;
+ inflateReset(z);
+ z->total_in = r; z->total_out = w;
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+
+/*+++++*/
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+ /* mode */
+ enum {
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONEB, /* finished last block, done */
+ BADB} /* got a data error--stuck here */
+ mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf *blens; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ int nblens; /* # elements allocated at blens */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_huft *tl, *td; /* trees to free */
+ inflate_codes_statef
+ *codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+ uInt last; /* true if this block is the last block */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ Bytef *window; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ check_func checkfn; /* check function */
+ uLong check; /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/* update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/* get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/* output bytes */
+#define WAVAIL (q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/* load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* And'ing with mask[n] masks the lower n bits */
+local uInt inflate_mask[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ int));
+
+/*+++++*/
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+local int inflate_fast OF((
+ uInt,
+ uInt,
+ inflate_huft *,
+ inflate_huft *,
+ inflate_blocks_statef *,
+ z_stream *));
+
+
+/*+++++*/
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+local void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+ if (s->checkfn != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+ if (s->mode == CODES)
+ {
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ }
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(0L, Z_NULL, 0);
+ Trace((stderr, "inflate: blocks reset\n"));
+}
+
+
+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_stream *z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s, sizeof(struct inflate_blocks_state));
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Trace((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, &s->check);
+ return s;
+}
+
+
+local int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Trace((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Trace((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.tl = Z_NULL; /* don't try to free these */
+ s->sub.decode.td = Z_NULL;
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Trace((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BADB;
+ z->msg = "invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if (((~b) >> 16) != (b & 0xffff))
+ {
+ s->mode = BADB;
+ z->msg = "invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : TYPE;
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BADB;
+ z->msg = "too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if (t < 19)
+ t = 19;
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.trees.nblens = t;
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, z);
+ if (t != Z_OK)
+ {
+ r = t;
+ if (r == Z_DATA_ERROR)
+ s->mode = BADB;
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->word.what.Bits;
+ c = h->more.Base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ s->mode = BADB;
+ z->msg = "invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ inflate_trees_free(s->sub.trees.tb, z);
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ s->mode = BADB;
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok\n"));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ inflate_trees_free(td, z);
+ inflate_trees_free(tl, z);
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+ s->sub.decode.codes = c;
+ s->sub.decode.tl = tl;
+ s->sub.decode.td = td;
+ }
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONEB;
+ case DONEB:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADB:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+local int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+ inflate_blocks_reset(s, z, c);
+ ZFREE(z, s->window, s->end - s->window);
+ ZFREE(z, s, sizeof(struct inflate_blocks_state));
+ Trace((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output. The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS). On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+local int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+ uLong b; /* bit buffer */ /* NOT USED HERE */
+ uInt k; /* bits in bit buffer */ /* NOT USED HERE */
+ uInt t; /* temporary storage */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ if (s->read != s->write)
+ return Z_STREAM_ERROR;
+ if (s->mode != TYPE)
+ return Z_DATA_ERROR;
+
+ /* we're ready to rock */
+ LOAD
+ /* while there is input ready, copy to output buffer, moving
+ * pointers as needed.
+ */
+ while (n) {
+ t = n; /* how many to do */
+ /* is there room until end of buffer? */
+ if (t > m) t = m;
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, t);
+ zmemcpy(q, p, t);
+ q += t;
+ p += t;
+ n -= t;
+ z->total_out += t;
+ s->read = q; /* drag read pointer forward */
+/* WRAP */ /* expand WRAP macro by hand to handle s->read */
+ if (q == s->end) {
+ s->read = q = s->window;
+ m = WAVAIL;
+ }
+ }
+ UPDATE
+ return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+local int inflate_packet_flush(s)
+ inflate_blocks_statef *s;
+{
+ if (s->mode != LENS)
+ return Z_DATA_ERROR;
+ s->mode = TYPE;
+ return Z_OK;
+}
+
+
+/*+++++*/
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ uIntf *, /* list of base values for non-simple codes */
+ uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ z_stream *)); /* for zalloc function */
+
+local voidpf falloc OF((
+ voidpf, /* opaque pointer (not used) */
+ uInt, /* number of items */
+ uInt)); /* size of item */
+
+local void ffree OF((
+ voidpf q, /* opaque pointer (not used) */
+ voidpf p, /* what to free (not used) */
+ uInt n)); /* number of bytes (not used) */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* actually lengths - 2; also see note #13 above about 258 */
+local uInt cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */
+local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+local uInt cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+ uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= N_MAX) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+uIntf *d; /* list of base values for non-simple codes */
+uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+z_stream *zs; /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
+ over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ uInt v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (inflate_huft *)ZALLOC
+ (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+ {
+ if (h)
+ inflate_trees_free(u[0], zs);
+ return Z_MEM_ERROR; /* not enough memory */
+ }
+ q->word.Nalloc = z + 1;
+#ifdef DEBUG_ZLIB
+ inflate_hufts += z + 1;
+#endif
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->next)) = Z_NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ r.next = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+local int inflate_trees_bits(c, bb, tb, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_stream *z; /* for zfree function */
+{
+ int r;
+
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+ if (r == Z_DATA_ERROR)
+ z->msg = "oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR)
+ {
+ inflate_trees_free(*tb, z);
+ z->msg = "incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+}
+
+
+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_stream *z; /* for zfree function */
+{
+ int r;
+
+ /* build literal/length tree */
+ if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = "oversubscribed literal/length tree";
+ else if (r == Z_BUF_ERROR)
+ {
+ inflate_trees_free(*tl, z);
+ z->msg = "incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+ }
+
+ /* build distance tree */
+ if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = "oversubscribed literal/length tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ inflate_trees_free(*td, z);
+ z->msg = "incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ inflate_trees_free(*tl, z);
+ return r;
+#endif
+ }
+
+ /* done */
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_lock = 0;
+local int fixed_built = 0;
+#define FIXEDH 530 /* number of hufts used by fixed tables */
+local uInt fixed_left = FIXEDH;
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q; /* opaque pointer (not used) */
+uInt n; /* number of items */
+uInt s; /* size of item */
+{
+ Assert(s == sizeof(inflate_huft) && n <= fixed_left,
+ "inflate_trees falloc overflow");
+ if (q) s++; /* to make some compilers happy */
+ fixed_left -= n;
+ return (voidpf)(fixed_mem + fixed_left);
+}
+
+
+local void ffree(q, p, n)
+voidpf q;
+voidpf p;
+uInt n;
+{
+ Assert(0, "inflate_trees ffree called!");
+ if (q) q = p; /* to make some compilers happy */
+}
+
+
+local int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+{
+ /* build fixed tables if not built already--lock out other instances */
+ while (++fixed_lock > 1)
+ fixed_lock--;
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ unsigned c[288]; /* length list for huft_build */
+ z_stream z; /* for falloc function */
+
+ /* set up fake z_stream for memory routines */
+ z.zalloc = falloc;
+ z.zfree = ffree;
+ z.opaque = Z_NULL;
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 7;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+ /* done */
+ fixed_built = 1;
+ }
+ fixed_lock--;
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
+
+
+local int inflate_trees_free(t, z)
+inflate_huft *t; /* table to free */
+z_stream *z; /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register inflate_huft *p, *q;
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != Z_NULL)
+ {
+ q = (--p)->next;
+ ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft));
+ p = q;
+ }
+ return Z_OK;
+}
+
+/*+++++*/
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+ mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+z_stream *z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+local int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = "invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = "invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+ f = (uInt)(q - s->window) < c->sub.copy.dist ?
+ s->end - (c->sub.copy.dist - (q - s->window)) :
+ q - c->sub.copy.dist;
+#else
+ f = q - c->sub.copy.dist;
+ if ((uInt)(q - s->window) < c->sub.copy.dist)
+ f = s->end - (c->sub.copy.dist - (q - s->window));
+#endif
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+local void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_stream *z;
+{
+ ZFREE(z, c, sizeof(struct inflate_codes_state));
+ Tracev((stderr, "inflate: codes free\n"));
+}
+
+/*+++++*/
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+ uInt n;
+ Bytef *p, *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
+
+
+/*+++++*/
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. */
+
+local int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+inflate_blocks_statef *s;
+z_stream *z;
+{
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ uInt ml; /* mask for literal/length tree */
+ uInt md; /* mask for distance tree */
+ uInt c; /* bytes to copy */
+ uInt d; /* distance back to copy from */
+ Bytef *r; /* copy source pointer */
+
+ /* load input, output, bit values */
+ LOAD
+
+ /* initialize masks */
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ /* do until not enough input or output space for fast loop */
+ do { /* assume called with m >= 258 && n >= 10 */
+ /* get literal/length code */
+ GRABBITS(20) /* max bits for literal/length code */
+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ continue;
+ }
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits for length */
+ e &= 15;
+ c = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * length %u\n", c));
+
+ /* decode distance base of block to copy */
+ GRABBITS(15); /* max bits for distance code */
+ e = (t = td + ((uInt)b & md))->exop;
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits to add to distance base */
+ e &= 15;
+ GRABBITS(e) /* get extra bits (up to 13) */
+ d = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * distance %u\n", d));
+
+ /* do the copy */
+ m -= c;
+ if ((uInt)(q - s->window) >= d) /* offset before dest */
+ { /* just copy */
+ r = q - d;
+ *q++ = *r++; c--; /* minimum count is three, */
+ *q++ = *r++; c--; /* so unroll loop a little */
+ }
+ else /* else offset after destination */
+ {
+ e = d - (q - s->window); /* bytes from offset to end */
+ r = s->end - e; /* pointer to offset */
+ if (c > e) /* if source crosses, */
+ {
+ c -= e; /* copy to end of window */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window; /* copy rest from start of window */
+ }
+ }
+ do { /* copy all or what's left */
+ *q++ = *r++;
+ } while (--c);
+ break;
+ }
+ else if ((e & 64) == 0)
+ e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+ else
+ {
+ z->msg = "invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ Tracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ z->msg = "invalid literal/length code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ } while (m >= 258 && n >= 10);
+
+ /* not enough input or output--restore pointers and return */
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
+
+
+/*+++++*/
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */
+
+char *zlib_version = ZLIB_VERSION;
+
+char *z_errmsg[] = {
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+""};
+
+
+/*+++++*/
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf) {s1 += *buf++; s2 += s1;}
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+#define DO16(buf) DO8(buf); DO8(buf);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+ uLong adler;
+ Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ k -= 16;
+ }
+ if (k != 0) do {
+ DO1(buf);
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
--- /dev/null
+/* $Id: zlib.h,v 1.1 1997/07/31 07:16:15 paulus Exp $ */
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/*
+ * ==FILEVERSION 960122==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 0.95, Aug 16th, 1995.
+
+ Copyright (C) 1995 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ gzip@prep.ai.mit.edu madler@alumni.caltech.edu
+ */
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+/* #include "zconf.h" */ /* included directly here */
+
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
+
+/*
+ The library does not install any signal handler. It is recommended to
+ add at least a handler for SIGSEGV when decompressing; the library checks
+ the consistency of the input data whenever possible but may go nuts
+ for some forms of corrupted input.
+ */
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
+ * at addresses which are not a multiple of their size.
+ * Under DOS, -DFAR=far or -DFAR=__far may be needed.
+ */
+
+#ifndef STDC
+# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
+# define STDC
+# endif
+#endif
+
+#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
+# include <unix.h>
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ 1 << (windowBits+2) + 1 << (memLevel+9)
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+typedef unsigned char Byte; /* 8 bits */
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+typedef Byte FAR Bytef;
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+/* end of original zconf.h */
+
+#define ZLIB_VERSION "0.95P"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms may be added later and will have the same
+ stream interface.
+
+ For compression the application must provide the output buffer and
+ may optionally provide the input buffer for optimization. For decompression,
+ the application must provide the input buffer and may optionally provide
+ the output buffer for optimization.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidp opaque; /* private data object passed to zalloc and zfree */
+
+ Byte data_type; /* best guess about the data type: ascii or binary */
+
+} z_stream;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_FULL_FLUSH 2
+#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */
+#define Z_FINISH 4
+#define Z_PACKET_FLUSH 5
+/* See deflate() below for the usage of these constants */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+/* error codes for the compression/decompression functions */
+
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Used to set the data_type field */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+extern char *zlib_version;
+/* The application can compare zlib_version and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ */
+
+ /* basic functions */
+
+extern int inflateInit OF((z_stream *strm));
+/*
+ Initializes the internal stream state for decompression. The fields
+ zalloc and zfree must be initialized before by the caller. If zalloc and
+ zfree are set to Z_NULL, inflateInit updates them to use default allocation
+ functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory. msg is set to null if there is no error message.
+ inflateInit does not perform any decompression: this will be done by
+ inflate().
+*/
+
+
+extern int inflate OF((z_stream *strm, int flush));
+/*
+ Performs one or both of the following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() always provides as much output as possible
+ (until there is no more input data or no more space in the output buffer).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate().
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+ inflate flushes as much output as possible to the output buffer. The
+ flushing behavior of inflate is not specified for values of the flush
+ parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+ current implementation actually flushes as much output as possible
+ anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
+ has been consumed, it is expecting to see the length field of a stored
+ block; if not, it returns Z_DATA_ERROR.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ inflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if the end of the
+ compressed data has been reached and all uncompressed output has been
+ produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
+ the stream structure was inconsistent (for example if next_in or next_out
+ was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
+ progress is possible or if there was not enough room in the output buffer
+ when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
+ call inflateSync to look for a good compression block. */
+
+
+extern int inflateEnd OF((z_stream *strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* advanced functions */
+
+extern int inflateInit2 OF((z_stream *strm,
+ int windowBits));
+/*
+ This is another version of inflateInit with more compression options. The
+ fields next_out, zalloc and zfree must be initialized before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library (the value 16 will be allowed soon). The
+ default value is 15 if inflateInit is used instead. If a compressed stream
+ with a larger window size is given as input, inflate() will return with
+ the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ If next_out is not null, the library will use this buffer for the history
+ buffer; the buffer must either be large enough to hold the entire output
+ data, or have at least 1<<windowBits bytes. If next_out is null, the
+ library will allocate its own buffer (and leave next_out null). next_in
+ need not be provided here but must be provided by the application for the
+ next call of inflate().
+
+ If the history buffer is provided by the application, next_out must
+ never be changed by the application since the decompressor maintains
+ history information inside this buffer from call to call; the application
+ can only reset next_out to the beginning of the history buffer when
+ avail_out is zero and all output has been consumed.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ windowBits < 8). msg is set to null if there is no error message.
+ inflateInit2 does not perform any decompression: this will be done by
+ inflate().
+*/
+
+extern int inflateSync OF((z_stream *strm));
+/*
+ Skips invalid compressed data until the special marker (see deflate()
+ above) can be found, or until all available input is skipped. No output
+ is provided.
+
+ inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no marker has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+extern int inflateReset OF((z_stream *strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+ This function adds the data at next_in (avail_in bytes) to the output
+ history without performing any output. There must be no pending output,
+ and the decompressor must be expecting to see the start of a block.
+ Calling this function is equivalent to decompressing a stored block
+ containing the data at next_in (except that the data is not output).
+*/
+
+ /* checksum functions */
+
+/*
+ This function is not related to compression but is exported
+ anyway because it might be useful in applications using the
+ compression library.
+*/
+
+extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+#ifndef _Z_UTIL_H
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+#endif /* _ZLIB_H */
-#
+# $Id: config.in,v 1.16 1997/08/11 08:37:49 cort Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
mainmenu_name "Linux/PowerPC Kernel Configuration"
+mainmenu_option next_comment
+comment 'Platform support'
+define_bool CONFIG_PPC y
+
if [ "`uname`" != "Linux" ]; then
define_bool CONFIG_CROSSCOMPILE y
else
bool 'Build PowerMac Kernel (not PReP)?' CONFIG_PMAC
bool 'Build PReP Kernel (not PowerMac)?' CONFIG_PREP
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-bool 'Used Harddrive LED on IBM 83x workstations as heartbeat?' CONFIG_HEARTBEAT
-bool 'Used PowerPC specific powersaving?' CONFIG_POWERSAVING
+
choice 'Processor type' \
"Common CONFIG_MCOMMON \
601 CONFIG_M601 \
603 CONFIG_M603 \
604 CONFIG_M604" Common
+endmenu
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
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 daemon support (e.g. autoload of modules)' CONFIG_KERNELD
fi
-
-mainmenu_option next_comment
define_bool CONFIG_PCI y
-bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+if [ "$CONFIG_PREP" = "y" ]; then
+ bool 'PCI bridge optimization' CONFIG_PCI_OPTIMIZE
+fi
bool 'Networking support' CONFIG_NET
bool 'Sysctl support' CONFIG_SYSCTL
bool 'System V IPC' CONFIG_SYSVIPC
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+if [ "$CONFIG_PMAC" = "y" ]; then
+ define_bool CONFIG_PMAC_CONSOLE y
+ define_bool CONFIG_MAC_KEYBOARD y
+ define_bool CONFIG_MAC_FLOPPY y
+ bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+ bool 'Include xmon kernel debugger' CONFIG_XMON
+fi
+
+if [ "$CONFIG_PMAC_CONSOLE" = "y" ]; then
+ bool 'Support for ATI Mach64 display cards' CONFIG_ATY_VIDEO
+ bool 'Support for IMS Twin Turbo display card' CONFIG_IMSTT_VIDEO
+else
+ define_bool CONFIG_VGA_CONSOLE y
+fi
+
+endmenu
source drivers/pnp/Config.in
source drivers/block/Config.in
endmenu
source fs/Config.in
+
source drivers/char/Config.in
mainmenu_option next_comment
fi
endmenu
-mainmenu_option next_comment
+#mainmenu_option next_comment
#comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
#bool 'Kernel profiling support' CONFIG_PROFILE
#if [ "$CONFIG_PROFILE" = "y" ]; then
# int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
#fi
-endmenu
+#endmenu
#
# Automatically generated by make menuconfig: don't edit
#
+
+#
+# Platform support
+#
CONFIG_NATIVE=y
# CONFIG_PMAC is not set
CONFIG_PREP=y
-# CONFIG_HEARTBEAT is not set
-# CONFIG_POWERSAVING is not set
CONFIG_MCOMMON=y
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
CONFIG_PCI=y
CONFIG_PCI_OPTIMIZE=y
CONFIG_NET=y
CONFIG_SYSCTL=y
CONFIG_SYSVIPC=y
-# CONFIG_BINFMT_JAVA is not set
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
#
# Plug and Play support
# CONFIG_BLK_DEV_RZ1000 is not set
# CONFIG_BLK_DEV_TRITON is not set
# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_INITRD=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_BLK_DEV_EZ is not set
# CONFIG_BLK_DEV_HD is not set
# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_MESH is not set
# CONFIG_SCSI_MAC53C94 is not set
-# CONFIG_SCSI_QLOGIC_PMAC is not set
#
# Network device support
# CONFIG_IP_ACCT is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_PCTCP is not set
# CONFIG_INET_RARP is not set
CONFIG_PATH_MTU_DISCOVERY=y
# CONFIG_DEC_ELCP is not set
# CONFIG_DGRS is not set
# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
# CONFIG_ES3210 is not set
# CONFIG_ZNET is not set
# CONFIG_NET_POCKET is not set
# CONFIG_QUOTA is not set
# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
-CONFIG_BEXT2_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_RNFS_BOOTP is not set
-# CONFIG_RNFS_RARP is not set
+# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
CONFIG_MAC_PARTITION=y
-CONFIG_HFS_FS=y
#
# Character devices
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
-# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_PRINTER is not set
CONFIG_MOUSE=y
# CONFIG_MS_BUSMOUSE is not set
CONFIG_PSMOUSE=y
# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_FTAPE is not set
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
#
# Sound
#
-# CONFIG_SOUND is not set
+#CONFIG_SOUND=y
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+CONFIG_CS4232=y
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CS4232_BASE=830
+CS4232_IRQ=10
+CS4232_DMA=6
+CS4232_DMA2=7
+CS4232_MPU_BASE=330
+CS4232_MPU_IRQ=9
+# CONFIG_LOWLEVEL_SOUND is not set
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.S.s:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
.S.o:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
- $(AS) $(ASFLAGS) -o $*.o $*.s
- rm $*.s
+ $(CC) -D__ASSEMBLY__ -c $< -o $*.o
-HOST_CC = gcc
-
-OBJS = misc.o port_io.o pci.o traps.o process.o \
- signal.o syscalls.o ptrace.o ksyms.o irq.o bitops.o strcase.o ppc_htab.o
+O_TARGET := kernel.o
+O_OBJS := misc.o traps.o process.o signal.o syscalls.o \
+ align.o ptrace.o irq.o bitops.o ppc_htab.o idle.o prom.o \
+ time.o prep_time.o pmac_time.o \
+ setup.o pmac_setup.o pmac_support.o \
+ pci.o prep_pci.o pmac_pci.o
+OX_OBJS := ppc_ksyms.o
all: head.o kernel.o
+
head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
ifeq ($(CONFIG_PREP),y)
-OBJS += prep_setup.o prep_time.o
-endif
-
-ifeq ($(CONFIG_PMAC),y)
-OBJS += pmac_setup.o pmac_support.o align.o pmac_time.o
+O_OBJS += prep_setup.o #prep_time.o
endif
-ifeq ($(CONFIG_MODULES),y)
-OBJS = ksyms.o
-endif
-
-
ppc_defs.h: mk_defs.c ppc_defs.head \
$(TOPDIR)/include/asm/mmu.h \
$(TOPDIR)/include/asm/processor.h \
checks: checks.c
$(HOSTCC) ${CFLAGS} -o checks checks.c
- checks
-
-kernel.o: $(OBJS)
- $(LD) -r -o kernel.o $(OBJS)
+ ./checks
-fastdep:
- $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
- $(CPP) -M *.S *.c > .depend
-
-modules:
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
int main(void)
{
int ret = 0;
-
+#if 0
if ( sizeof(struct thread_struct) % 16 )
{
printf("Thread struct is not modulo 16 bytes: "
sizeof(struct thread_struct)%16);
ret = -1;
}
+#endif
if ( sizeof(struct pt_regs) % 16 )
{
#define TOPHYS(x) (x - KERNELBASE)
-
/* this is a very kludgey way of loading up the BATs on the
prep system. I'll kill this horrible macro and write
something clean when I have a chance -- Cort
*/
#define LOAD_BATS(RA,RB) \
mfspr RA,PVR ; \
- srwi r5,r5,16 ; \
+ srwi RA,RA,16 ; \
cmpi 0,RA,1 ; \
beq 199f ; \
/* load bats for 60x */ ; \
mtspr DBAT3L,RB ; \
200:
-
-
-
.text
.globl _stext
_stext:
-#ifdef CONFIG_PREP
- . = 0x100
-_GLOBAL(HardReset)
- b _start
-
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_PMAC
/*
* _start is defined this way because the XCOFF loader in the OpenFirmware
* on the powermac expects the entry point to be a procedure descriptor.
_start:
.long TOPHYS(__start),0,0
-/*
+/* PMAC
* Enter here with the kernel text, data and bss loaded starting at
* 0, running with virtual == physical mapping.
* r5 points to the prom entry point (the client interface handler
* pointer (r1) points to just below the end of the half-meg region
* from 0x380000 - 0x400000, which is mapped in already.
*/
+/* PREP
+ * This is jumped to on prep systems right after the kernel is relocated
+ * to its proper place in memory by the boot loader. The expected layout
+ * of the regs is:
+ * r3: ptr to residual data
+ * r4: initrd_start or if no initrd then 0
+ * r5: initrd_end - unused if r4 is 0
+ * r6: Start of command line string
+ * r7: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort
+ */
+
.globl __start
__start:
/*
- * Use the first pair of BAT registers to map the 1st 8MB
+ * Use the first pair of BAT registers to map the 1st 16MB
* of RAM to KERNELBASE.
*/
mfspr r9,PVR
rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
cmpi 0,r9,1
- lis r7,KERNELBASE@h
+ lis r11,KERNELBASE@h
bne 4f
- ori r7,r7,4 /* set up BAT registers for 601 */
+ ori r11,r11,4 /* set up BAT registers for 601 */
li r8,0x7f
+ oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */
+ oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */
+ mtspr IBAT1U,r9
+ mtspr IBAT1L,r10
b 5f
-4: ori r7,r7,0xff /* set up BAT registers for 604 */
+4: ori r11,r11,0x1ff /* set up BAT registers for 604 */
li r8,2
- mtspr DBAT0U,r7
+ mtspr DBAT0U,r11
mtspr DBAT0L,r8
-5: mtspr IBAT0U,r7
+5: mtspr IBAT0U,r11
mtspr IBAT0L,r8
isync
+#if 0
/*
* Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
* refer to addresses of data items, procedures, etc. normally.
*/
- lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
- addi r7,r7,start_here@l
- mtlr r7
+ lis r10,start_here@ha /* jump up to our copy at KERNELBASE */
+ addi r10,r10,start_here@l
+ mtlr r10
blr
-#endif /* CONFIG_PMAC */
-
-
+#endif
+/*
+ * we now have the 1st 16M of ram mapped with the bats.
+ * prep needs the mmu to be turned on here, but pmac already has it on.
+ * this shouldn't bother the pmac since it just gets turned on again
+ * as we jump to our code at KERNELBASE. -- Cort
+ */
+ mfmsr r0
+ ori r0,r0,MSR_DR|MSR_IR
+ mtspr SRR1,r0
+ lis r0,start_here@h
+ ori r0,r0,start_here@l
+ mtspr SRR0,r0
+ SYNC
+ rfi /* enables MMU */
+
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't. To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
+ */
+#define STACK_UNDERHEAD 64
/*
* Macros for storing registers into and loading registers from
.long hdlr; \
.long int_return
-#ifndef CONFIG_PREP
/* System reset */
STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif /* ndef CONFIG_PREP */
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
/* Instruction access exception */
. = 0x400
-InstructionAccess:
+InstructionAccess:
EXCEPTION_PROLOG
andis. r0,r23,0x4000 /* no pte found? */
beq 1f /* if so, try to put a PTE */
.long int_return
/* External interrupt */
- STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+ STD_EXCEPTION(0x500, HardwareInterrupt, do_IRQ)
/* Alignment exception */
. = 0x600
.long KernelFP
.long int_return
-/* Decrementer */
-#ifdef CONFIG_PREP
-/* - ignored for now... */
-_ORG(0x0900)
- mtspr SPRG0,r1
- lis r1,0x7FFF
- ori r1,r1,0xFFFF
- mtspr DEC,r1
- mfspr r1,SPRG0
- rfi
-#endif /* CONFIG_PREP */
-#ifdef CONFIG_PMAC
STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
-#endif /* CONFIG_PMAC */
-
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
andi. r23,r23,MSR_PR
mfspr r23,SPRG3 /* if from user, fix up tss */
beq 2f
-#ifdef CONFIG_PMAC
- lwz r24,GPR1(r21)
- stw r22,LAST_PC(r23)
- stw r24,USER_STACK(r23)
-#endif /* CONFIG_PMAC */
addi r24,r1,STACK_FRAME_OVERHEAD
stw r24,PT_REGS(r23)
2: addi r2,r23,-TSS /* set r2 to current */
REST_32FPRS(0, r5)
/* use last_task_used_math instead of fpu_tss */
- lis r3,last_task_used_math@h/*a*/
+ lis r3,last_task_used_math@ha
addis r3,r3,-KERNELBASE@h
subi r4,r5,TSS
addis r4,r4,KERNELBASE@h
REST_GPR(20, r21)
REST_2GPRS(22, r21)
lwz r21,GPR21(r21)
- SYNC
+ SYNC
rfi
/*
.globl hash_page
hash_page:
/* Get PTE (linux-style) and check access */
- lwz r5,PG_TABLES(r5) /* task's page tables */
- lis r2,-KERNELBASE@h
- add r5,r5,r2 /* convert to phys addr */
+ lwz r5,MM-TSS(r5)
+ addis r5,r5,-KERNELBASE@h /* get physical current->mm */
+ lwz r5,PGD(r5) /* get current->mm->pgd */
+ addis r5,r5,-KERNELBASE@h /* convert to phys addr */
rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
lwz r5,0(r5) /* get pmd entry */
rlwinm. r5,r5,0,0,19 /* extract address of pte page */
beqlr- /* return if no mapping */
- add r2,r5,r2
+ addis r2,r5,-KERNELBASE@h
rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */
lwz r6,0(r2) /* get linux-style pte */
ori r4,r4,1 /* set _PAGE_PRESENT bit in access */
rlwinm r9,r9,16,16,31
cmpi 0,r9,1
beq 4f /* not needed for 601 */
- mfspr r7,HID0
- andi. r0,r7,HID0_DCE
- ori r7,r7,HID0_ICE|HID0_DCE
- ori r8,r7,HID0_ICFI
+ mfspr r11,HID0
+ andi. r0,r11,HID0_DCE
+ ori r11,r11,HID0_ICE|HID0_DCE
+ ori r8,r11,HID0_ICFI
bne 3f /* don't invalidate the D-cache */
ori r8,r8,HID0_DCI /* unless it wasn't enabled */
-3: sync
+3:
+ /* I haven't tested this yet so it's off now - Cort */
+ /* turn on dpm for 603 */
+ cmpi 0,r9,3
+ bne 10f
+ oris r11,r11,HID0_DPM@h
+10:
+ sync
mtspr HID0,r8 /* enable and invalidate caches */
sync
- mtspr HID0,r7 /* enable caches */
+ mtspr HID0,r11 /* enable caches */
sync
isync
cmpi 0,r9,4 /* check for 604 */
cmpi 1,r9,9 /* or 604e */
cror 2,2,6
bne 4f
- ori r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
- mtspr HID0,r7 /* superscalar exec & br history tbl */
+ ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+ mtspr HID0,r11 /* superscalar exec & br history tbl */
4:
/* ptr to current */
lis r2,init_task_union@h
ori r2,r2,init_task_union@l
/* ptr to phys current tss */
- addis r3,r2,-KERNELBASE@h
- addi r3,r3,TSS /* init task's TSS */
- mtspr SPRG3,r3
+ addis r11,r2,-KERNELBASE@h
+ addi r11,r11,TSS /* init task's TSS */
+ mtspr SPRG3,r11
/* stack */
addi r1,r2,TASK_UNION_SIZE
li r0,0
stwu r0,-STACK_FRAME_OVERHEAD(r1)
/* Clear out the BSS */
- lis r7,_end@ha
- addi r7,r7,_end@l
+ lis r11,_end@ha
+ addi r11,r11,_end@l
lis r8,__bss_start@ha
addi r8,r8,__bss_start@l
- subf r7,r8,r7
- addi r7,r7,3
- rlwinm. r7,r7,30,2,31
+ subf r11,r8,r11
+ addi r11,r11,3
+ rlwinm. r11,r11,30,2,31
beq 2f
addi r8,r8,-4
- mtctr r7
+ mtctr r11
li r0,0
3: stwu r0,4(r8)
bdnz 3b
2:
/*
- * Initialize the prom stuff (powermacs only) and the MMU.
+ * Initialize the prom stuff and the MMU.
*/
-#ifdef CONFIG_PMAC
+ bl identify_machine
bl prom_init
-#endif /* CONFIG_PMAC */
bl MMU_init
/*
rfi
/* Load up the kernel context */
2:
-#ifdef CONFIG_PREP
- /* reload the bats now that MMU_init() has setup them up -- Cort */
- LOAD_BATS(r3,r0)
-#endif
-
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
mtspr SDR1,r6
addi r3,r3,1 /* increment VSID */
addis r4,r4,0x1000 /* address of next segment */
bdnz 3b
-#ifdef CONFIG_PMAC
- li r0,0 /* zot the BATs */
+
+ lis r3,_machine@ha
+ addis r3,r3,-KERNELBASE@h
+ lwz r0,_machine@l(r3)
+ cmpi 0,r0,_MACH_Pmac
+ beq 99f
+
+/* on prep reload the bats now that MMU_init() has setup them up -- Cort */
+ LOAD_BATS(r3,r14)
+ b 100f
+
+/* on pmac clear the bats out */
+99: li r0,0 /* zot the BATs */
#if 1
mtspr IBAT0U,r0
mtspr IBAT0L,r0
mtspr IBAT3L,r0
mtspr DBAT3U,r0
mtspr DBAT3L,r0
-#endif
+100:
/* Now turn on the MMU for real! */
li r4,MSR_KERNEL
lis r3,start_kernel@h
mtspr SRR1,r4
rfi /* enable MMU and jump to start_kernel */
-#ifdef CONFIG_PREP
-/*
- * This is jumped to on prep systems right after the kernel is relocated
- * to its proper place in memory by the boot loader. The expected layout
- * of the regs is:
- * R3: End of image
- * R4: Start of image - 0x400
- * R11: Start of command line string
- * R12: End of command line string
- *
- * This just gets a minimal mmu environment setup so we can call
- * start_here() to do the real work.
- * -- Cort
- */
- .globl __start
-__start:
- .globl _start
-_start:
- lis r7,0xF000 /* To mask upper 4 bits */
-/* save pointer to residual data */
- lis r1,resptr@h
- ori r1,r1,resptr@l
- addis r1,r1,-KERNELBASE@h
- stw r3,0(r1)
-/* save argument string */
- li r0,0 /* Null terminate string */
- stb r0,0(r12)
- lis r1,cmd_line@h
- ori r1,r1,cmd_line@l
- addis r1,r1,-KERNELBASE@h
- subi r1,r1,1
- subi r11,r11,1
-00: lbzu r0,1(r11)
- cmpi 0,r0,0
- stbu r0,1(r1)
- bne 00b
-/* setup the msr with sane values */
- li r0,MSR_
- mtmsr r0
-/* turn on the mmu with bats covering kernel enough to get started */
- LOAD_BATS(r3,r0)
- mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
- mtspr SRR1,r3
- lis r3,10f@h
- ori r3,r3,10f@l
- mtspr SRR0,r3
- SYNC
- rfi /* enables MMU */
-10: lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
- addi r7,r7,start_here@l
- mtlr r7
- blr
-#endif /* CONFIG_PREP */
-
/*
* FP unavailable trap from kernel - print a message, but let
* the task use FP in the kernel until it returns to user mode.
giveup_fpu:
li r6,0
1:
- addis r3,r6,last_task_used_math@h/*a*/
+ addis r3,r6,last_task_used_math@ha
lwz r4,last_task_used_math@l(r3)
-#if 0
- addis r3,r6,fpu_tss@ha
- lwz r4,fpu_tss@l(r3)
-#endif
mfmsr r5
ori r5,r5,MSR_FP
SYNC
mtmsr r5 /* enable use of fpu now */
SYNC
cmpi 0,r4,0
+ beqlr- /* if no previous owner, done */
add r4,r4,r6
- beqlr /* if no previous owner, done */
addi r4,r4,TSS /* want TSS of last_task_used_math */
li r5,0
stw r5,last_task_used_math@l(r3)
-#if 0
- stw r5,fpu_tss@l(r3)
-#endif
SAVE_32FPRS(0, r4)
mffs fr0
stfd fr0,TSS_FPSCR-4(r4)
lwz r5,PT_REGS(r4)
- lwz r5,PT_REGS(r4)
add r5,r5,r6
lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5)
li r4,MSR_FP
cmpi 0,r4,0
beq+ 1f
addi r3,r1,STACK_FRAME_OVERHEAD
- bl handle_IRQ
+ bl do_IRQ
b 3b
1: lis r4,bh_mask@ha
lwz r4,bh_mask@l(r4)
li r0,0x0fac
stw r0,TRAP(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
- bl handle_IRQ
+ bl do_IRQ
addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
lwz r0,4(r1)
mtlr r0
* and invalidate the corresponding instruction cache blocks.
* This is a no-op on the 601.
*
- * store_cache_range(unsigned long start, unsigned long stop)
+ * flush_icache_range(unsigned long start, unsigned long stop)
*/
CACHE_LINE_SIZE = 32
LG_CACHE_LINE_SIZE = 5
-_GLOBAL(store_cache_range)
+_GLOBAL(flush_icache_range)
mfspr r5,PVR
rlwinm r5,r5,16,16,31
cmpi 0,r5,1
_GLOBAL(__main)
blr
-#ifdef CONFIG_PMAC
/*
* These exception handlers are used when we have called a prom
* routine after we have taken over the exception vectors and MMU.
lwz r31,28(r1)
lwz r1,0(r1)
blr
-#endif
/*
* We put a few things here that have to be page-aligned.
.data
.globl sdata
sdata:
- .space 2*4096
.globl empty_zero_page
empty_zero_page:
.space 4096
swapper_pg_dir:
.space 4096
-#ifdef CONFIG_PREP
/*
* This space gets a copy of optional info passed to us by the bootstrap
* Used to pass parameters into the kernel like root=/dev/sda1, etc.
.globl cmd_line
cmd_line:
.space 512
-#endif /* CONFIG_PREP */
--- /dev/null
+/*
+ * $Id: idle.c,v 1.3 1997/08/10 04:49:08 davem Exp $
+ *
+ * Idle daemon for PowerPC. Idle daemon will handle any action
+ * that needs to be taken when the system becomes idle.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * 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.
+ */
+#define __KERNEL_SYSCALLS__
+
+#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/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+#include <asm/processor.h>
+
+int zero_paged(void *unused);
+int power_saved(void *unused);
+
+asmlinkage int sys_idle(void)
+{
+ int ret = -EPERM;
+
+ if (current->pid != 0)
+ goto out;
+
+ /*
+ * want one per cpu since it would be nice to have all
+ * processors who aren't doing anything
+ * zero-ing pages since this daemon is lock-free
+ * -- Cort
+ */
+ kernel_thread(zero_paged, NULL, 0);
+ /* no powersaving modes on 601 */
+ /*if( (_get_PVR()>>16) != 1 )
+ kernel_thread(power_saved, NULL, 0);*/
+
+ /* endless loop with no priority at all */
+ current->priority = -100;
+ current->counter = -100;
+ for (;;)
+ {
+ schedule();
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
+/*
+ * vars for idle task zero'ing out pages
+ */
+unsigned long zero_list = 0; /* head linked list of pre-zero'd pages */
+unsigned long bytecount = 0; /* pointer into the currently being zero'd page */
+unsigned long zerocount = 0; /* # currently pre-zero'd pages */
+unsigned long zerototal = 0; /* # pages zero'd over time -- for ooh's and ahhh's */
+unsigned long pageptr = 0; /* current page being zero'd */
+unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
+unsigned long zeropage_calls = 0;/* # zero'd pages request that've been made */
+static struct wait_queue * page_zerod_wait = NULL;
+#define PAGE_THRESHOLD 96 /* how many pages to keep pre-zero'd */
+
+/*
+ * Returns a pre-zero'd page from the list otherwise returns
+ * NULL.
+ */
+unsigned long get_prezerod_page(void)
+{
+ unsigned long page;
+
+ atomic_inc((atomic_t *)&zeropage_calls);
+ if ( zero_list )
+ {
+ /* atomically remove this page from the list */
+ asm ( "101:lwarx %1,0,%2\n" /* reserve zero_list */
+ " lwz %0,0(%1)\n" /* get next -- new zero_list */
+ " stwcx. %0,0,%2\n" /* update zero_list */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list), "=&r" (page)
+ : "r" (&zero_list)
+ : "cc" );
+ /* we can update zerocount after the fact since it is not
+ * used for anything but control of a loop which doesn't
+ * matter since it won't effect anything if it zero's one
+ * less page -- Cort
+ */
+ atomic_inc((atomic_t *)&zeropage_hits);
+ atomic_dec((atomic_t *)&zerocount);
+ wake_up(&page_zerod_wait);
+ resched_force();
+
+ /* zero out the pointer to next in the page */
+ *(unsigned long *)page = 0;
+ return page;
+ }
+ return 0;
+}
+
+/*
+ * Experimental stuff to zero out pages in the idle task
+ * to speed up get_free_pages() -- Cort
+ * Zero's out pages until we need to resched or
+ * we've reached the limit of zero'd pages.
+ */
+
+int zero_paged(void *unused)
+{
+ extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
+ pgd_t *dir;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ sprintf(current->comm, "zero_paged (idle)");
+ current->blocked = ~0UL;
+
+ printk("Started zero_paged\n");
+
+ __sti();
+ while ( 1 )
+ {
+ /* don't want to be pre-empted by swapper or power_saved */
+ current->priority = -98;
+ current->counter = -98;
+ /* we don't want to run until we have something to do */
+ while ( zerocount >= PAGE_THRESHOLD )
+ sleep_on(&page_zerod_wait);
+ /*
+ * Mark a page as reserved so we can mess with it
+ * If we're interrupted we keep this page and our place in it
+ * since we validly hold it and it's reserved for us.
+ */
+ pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+ if ( !pageptr )
+ {
+ printk("!pageptr in zero_paged\n");
+ goto retry;
+ }
+
+ if ( resched_needed() )
+ schedule();
+
+ /*
+ * Make the page no cache so we don't blow our cache with 0's
+ */
+ dir = pgd_offset( init_task.mm, pageptr );
+ if (dir)
+ {
+ pmd = pmd_offset(dir, pageptr & PAGE_MASK);
+ if (pmd && pmd_present(*pmd))
+ {
+ pte = pte_offset(pmd, pageptr & PAGE_MASK);
+ if (pte && pte_present(*pte))
+ {
+ pte_uncache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+ }
+ }
+ }
+
+ /*
+ * Important here to not take time away from real processes.
+ */
+ for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
+ {
+ if ( resched_needed() )
+ schedule();
+ *(unsigned long *)(bytecount + pageptr) = 0;
+ }
+
+ /*
+ * If we finished zero-ing out a page add this page to
+ * the zero_list atomically -- we can't use
+ * down/up since we can't sleep in idle.
+ * Disabling interrupts is also a bad idea since we would
+ * steal time away from real processes.
+ * We can also have several zero_paged's running
+ * on different processors so we can't interfere with them.
+ * So we update the list atomically without locking it.
+ * -- Cort
+ */
+ /* turn cache on for this page */
+ pte_cache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+
+ /* atomically add this page to the list */
+ asm ( "101:lwarx %0,0,%1\n" /* reserve zero_list */
+ " stw %0,0(%2)\n" /* update *pageptr */
+#ifdef __SMP__
+ " sync\n" /* let store settle */
+#endif
+ " mr %0,%2\n" /* update zero_list in reg */
+ " stwcx. %2,0,%1\n" /* update zero_list in mem */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list)
+ : "r" (&zero_list), "r" (pageptr)
+ : "cc" );
+ /*
+ * This variable is used in the above loop and nowhere
+ * else so the worst that could happen is we would
+ * zero out one more or one less page than we want
+ * per processor on the machine. This is because
+ * we could add our page to the list but not have
+ * zerocount updated yet when another processor
+ * reads it. -- Cort
+ */
+ atomic_inc((atomic_t *)&zerocount);
+ atomic_inc((atomic_t *)&zerototal);
+retry:
+ schedule();
+ }
+}
+
+int power_saved(void *unused)
+{
+ unsigned long msr, hid0;
+ sprintf(current->comm, "power_saved (idle)");
+ current->blocked = ~0UL;
+
+ printk("Power saving daemon started\n");
+
+ __sti();
+ while (1)
+ {
+ /* don't want to be pre-empted by swapper */
+ current->priority = -99;
+ current->counter = -99;
+ /* go ahead and wakeup page_zerod() */
+ wake_up(&page_zerod_wait);
+ schedule();
+ asm volatile(
+ /* clear powersaving modes and set nap mode */
+ "mfspr %3,1008 \n\t"
+ "andc %3,%3,%4 \n\t"
+ "or %3,%3,%5 \n\t"
+ "mtspr 1008,%3 \n\t"
+ /* enter the mode */
+ "mfmsr %0 \n\t"
+ "oris %0,%0,%2 \n\t"
+ "sync \n\t"
+ "mtmsr %0 \n\t"
+ "isync \n\t"
+ : "=&r" (msr)
+ : "0" (msr), "i" (MSR_POW>>16),
+ "r" (hid0),
+ "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+ "r" (HID0_NAP));
+ /*
+ * The ibm carolina spec says that the eagle memory
+ * controller will detect the need for a snoop
+ * and wake up the processor so we don't need to
+ * check for cache operations that need to be
+ * snooped. The ppc book says the run signal
+ * must be asserted while napping for this though.
+ *
+ * Paul, what do you know about the pmac here?
+ * -- Cort
+ */
+ schedule();
+ }
+}
/*
* arch/ppc/kernel/irq.c
*
- * Power Macintosh version
- * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *
* Derived from arch/i386/kernel/irq.c
* Copyright (C) 1992 Linus Torvalds
* Adapted from arch/i386 by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu)
+ * Adapted for Power Macintosh by Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
*
* This file contains the code used by various IRQ handling routines:
* asking for different IRQ's should be done through these routines
* shouldn't result in any weird surprises, and installing new handlers
* should be easier.
*/
-
-/*
- * IRQ's are in fact implemented a bit like signal handlers for the kernel.
- * Naturally it's not a 1:1 relation, but there are similarities.
- */
+
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
-#define IRQ_FLAG ((unsigned *)0xf3000020)
-#define IRQ_ENABLE ((unsigned *)0xf3000024)
-#define IRQ_ACK ((unsigned *)0xf3000028)
-#define IRQ_LEVEL ((unsigned *)0xf300002c)
-
-#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
-
-#undef SHOW_IRQ 1
+#undef SHOW_IRQ
unsigned lost_interrupts = 0;
static struct irqaction irq_action[32];
/*
- * This contains the irq mask for both irq controllers
+ * These are set to the appropriate functions by init_IRQ()
*/
-static unsigned int cached_irq_mask = 0xffff;
-
-#define cached_21 (((char *)(&cached_irq_mask))[0])
-#define cached_A1 (((char *)(&cached_irq_mask))[1])
-
+void (*mask_and_ack_irq)(int irq_nr);
+void (*set_irq_mask)(int irq_nr);
+static unsigned int cached_irq_mask = 0xffffffff;
+#define cached_21 (((char *)(&cached_irq_mask))[3])
+#define cached_A1 (((char *)(&cached_irq_mask))[2])
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
int __ppc_bh_counter;
-void *null_handler(int,void *,struct pt_regs *);
+/* prep */
+#define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21
+extern unsigned long route_pci_interrupts(void);
-/*
- * disable and enable intrs in software. This is used
- * from the non-realtime parts of Linux to disable interrupts.
- * The realtime part disables/enables intrs in the hardware.
- * -- Cort
- */
-unsigned long soft_intr_enable = 1;
-void _soft_cli(void)
-{
- soft_intr_enable = 0;
-}
+/* pmac */
+#define IRQ_FLAG ((unsigned *)0xf3000020)
+#define IRQ_ENABLE ((unsigned *)0xf3000024)
+#define IRQ_ACK ((unsigned *)0xf3000028)
+#define IRQ_LEVEL ((unsigned *)0xf300002c)
+#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
+#define PMAC_IRQ_MASK (~ld_le32(IRQ_ENABLE))
-void _soft_sti(void)
+void prep_mask_and_ack_irq(int irq_nr)
{
- soft_intr_enable = 1;
- if ( lost_interrupts )
- {
- printk("lost_interrupts from _soft_sti() %x\n",lost_interrupts);
- fake_interrupt();
+ spin_lock(&irq_controller_lock);
+ cached_irq_mask |= 1 << irq_nr;
+ if (irq_nr > 7) {
+ inb(0xA1); /* DUMMY */
+ outb(cached_A1,0xA1);
+ outb(0x62,0x20); /* Specific EOI to cascade */
+ /*outb(0x20,0xA0);*/
+ outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */
+ } else {
+ inb(0x21); /* DUMMY */
+ outb(cached_21,0x21);
+ /*outb(0x20,0x20);*/
+ outb(0x60|irq_nr,0x20); /* specific eoi */
+
}
+ spin_unlock(&irq_controller_lock);
}
-void *
-null_handler(int a, void *b, struct pt_regs *regs)
+void pmac_mask_and_ack_irq(int irq_nr)
{
- /*printk("irq.c: null_handler() called. Should not have happened.\n");*/
+ spin_lock(&irq_controller_lock);
+ cached_irq_mask |= 1 << irq_nr;
+ out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+ out_le32(IRQ_ACK, 1U << irq_nr);
+ spin_unlock(&irq_controller_lock);
}
-void
-disable_irq(unsigned int irq_nr)
+void prep_set_irq_mask(int irq_nr)
{
- int s = _disable_interrupts();
- unsigned char mask;
-
-#ifdef CONFIG_PMAC
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
-#else /* CONFIG_PMAC */
- mask = 1 << (irq_nr & 7);
- if (irq_nr < 8)
- {
- cached_21 |= mask;
- outb(cached_21,0x21);
- } else
- {
- cached_A1 |= mask;
+ if (irq_nr > 7) {
outb(cached_A1,0xA1);
- }
-#endif /* CONFIG_PMAC */
- _enable_interrupts(s);
+ } else {
+ outb(cached_21,0x21);
+ }
}
-void
-enable_irq(unsigned int irq_nr)
+void pmac_set_irq_mask(int irq_nr)
{
- int s = _disable_interrupts();
-#ifdef CONFIG_PMAC
- unsigned bit = 1U << irq_nr;
-
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) | bit);
-
+ /* this could be being enabled or disabled - so use cached_irq_mask */
+ out_le32(IRQ_ENABLE, ~cached_irq_mask /* enable all unmasked */ );
/*
* Unfortunately, setting the bit in the enable register
* when the device interrupt is already on *doesn't* set
* the bit in the flag register or request another interrupt.
*/
- if ((ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
- lost_interrupts |= bit;
-#else /* CONFIG_PMAC */
- if (irq_nr < 8) {
- cached_21 &= ~(1 << (irq_nr & 7));
- outb(cached_21,0x21);
- } else
- {
- cached_A1 &= ~(1 << (irq_nr-8 & 7));
- outb(cached_A1,0xA1);
- }
-#endif /* CONFIG_PMAC */
+ if ((ld_le32(IRQ_LEVEL) & (1UL<<irq_nr)) && !(ld_le32(IRQ_FLAG) & (1UL<<irq_nr)))
+ lost_interrupts |= (1UL<<irq_nr);
+}
- _enable_interrupts(s);
+/*
+ * These have to be protected by the spinlock
+ * before being called.
+ */
+static inline void mask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask |= 1 << irq_nr;
+ set_irq_mask(irq_nr);
}
+static inline void unmask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask &= ~(1 << irq_nr);
+ set_irq_mask(irq_nr);
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_controller_lock, flags);
+ mask_irq(irq_nr);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
+ synchronize_irq();
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_controller_lock, flags);
+ unmask_irq(irq_nr);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
int get_irq_list(char *buf)
{
for (i = 0 ; i < NR_IRQS ; i++) {
action = irq_action + i;
- if (!action || !action->handler)
+ if (!action || !action->handler)
continue;
len += sprintf(buf+len, "%2d: %10u %s",
i, kstat.interrupts[i], action->name);
}
len += sprintf(buf+len, "\n");
}
-/*
- * Linus - should you add NMI counts here ?????
- */
#ifdef __SMP_PROF__
len+=sprintf(buf+len, "IPI: %8lu received\n",
ipi_count);
-#endif
+#endif
return len;
}
-asmlinkage void handle_IRQ(struct pt_regs *regs)
+asmlinkage void do_IRQ(struct pt_regs *regs)
{
int irq;
- unsigned bits;
+ unsigned long bits;
struct irqaction *action;
int cpu = smp_processor_id();
+ int status;
hardirq_enter(cpu);
-#ifdef CONFIG_PMAC
- bits = ld_le32(IRQ_FLAG) | lost_interrupts;
- lost_interrupts = 0;
-
- for (irq = NR_IRQS; irq >= 0; --irq)
- if (bits & (1U << irq))
- break;
-#else /* CONFIG_PMAC */
-#if 1
- if ( lost_interrupts )
+ if ( _machine == _MACH_Pmac )
{
- irq = ffz(~lost_interrupts);
- lost_interrupts &= ~irq;
- goto retry;
+ bits = ld_le32(IRQ_FLAG) | lost_interrupts;
+ lost_interrupts = 0;
}
- outb(0x0C, 0x20);
- irq = inb(0x20) & 7;
- if (irq == 2)
+ else /* prep */
{
-retry_cascade:
- outb(0x0C, 0xA0);
- irq = inb(0xA0);
- /* if no intr left */
- if ( !(irq & 128 ) )
- goto out;
- irq = (irq&7) + 8;
- }
-retry:
+#if 1
+ outb(0x0C, 0x20);
+ irq = inb(0x20) & 7;
+ if (irq == 2)
+ {
+retry_cascade:
+ outb(0x0C, 0xA0);
+ irq = inb(0xA0);
+ /* if no intr left */
+ if ( !(irq & 128 ) )
+ goto out;
+ irq = (irq&7) + 8;
+ }
+ bits = 1UL << irq;
#else
- /* get the irr from the intr controller */
- outb(0x0A, 0x20);
- bits = inb(0x20);
- /* handle cascade */
- if ( bits )
- {
- bits &= 4;
- outb(0x0A, 0xA0);
- bits = inb(0xA0)<<8;
+ /*
+ * get the isr from the intr controller since
+ * the bit in the irr has been cleared
+ */
+ outb(0x0a, 0x20);
+ bits = inb(0x20)&0xff;
+ /* handle cascade */
+ if ( bits & 4 )
+ {
+ bits &= ~4UL;
+ outb(0x0a, 0xA0);
+ bits |= inb(0xA0)<<8;
+ }
+ /* ignore masked irqs */
+ bits &= ~cached_irq_mask;
+#endif
}
- /* get lost interrupts */
- bits |= lost_interrupts;
- /* save intrs that are masked out */
- lost_interrupts = bits & cached_irq_mask;
- /* get rid of intrs being masked */
- bits &= ~cached_irq_mask;
- /* non-specifc eoi */
- outb(0x20,0x20);
- if ( bits & 0xff00 )
- outb(0x20,0xA0);
- printk("bits %04X lost %04X mask %04x\n",
- bits, lost_interrupts,cached_irq_mask);
-
- for (irq = NR_IRQS; irq >= 0; --irq)
+ for (irq = NR_IRQS - 1; irq >= 0; --irq)
if (bits & (1U << irq))
break;
-#endif
-#endif /* CONFIG_PMAC */
-
+
if (irq < 0) {
- printk("Bogus interrupt from PC = %lx, irq %d\n",regs->nip,irq);
+ printk("Bogus interrupt from PC = %lx\n", regs->nip);
goto out;
}
-#ifdef CONFIG_PMAC
- out_le32(IRQ_ACK, 1U << irq);
-#else /* CONFIG_PMAC */
- /* mask out the irq while handling it */
- disable_irq(irq);
- /*
- * send eoi to interrupt controller right away or lower
- * priority intrs would be ignored even if with intrs enabled
- */
- if (irq > 7)
- {
- outb(0xE0|(irq-8), 0xA0);
- outb(0xE2, 0x20);
- } else
- {
- outb(0xE0|irq, 0x20);
- }
-#endif /* !CONFIG_PMAC */
+ mask_and_ack_irq(irq);
- /*
- * now that we've acked the irq, if intrs are disabled in software
- * we're in the real-time system and non-rt linux has disabled them
- * so we just queue it up and return -- Cort
- */
- if ( ! soft_intr_enable )
- {
- lost_interrupts |= 1UL << irq;
- /* can't printk - kernel expects intrs off! */
- /*printk("irq %d while intrs soft disabled\n", irq);*/
- goto out;
- }
-
- action = irq + irq_action;
+ status = 0;
+ action = irq_action + irq;
kstat.interrupts[irq]++;
- if (action->handler) {
+ if ( action )
+ {
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ status |= action->flags;
action->handler(irq, action->dev_id, regs);
- _disable_interrupts(); /* in case the handler turned them on */
+ /*if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);*/
+ __cli(); /* in case the handler turned them on */
+ spin_lock(&irq_controller_lock);
+ unmask_irq(irq);
+ spin_unlock(&irq_controller_lock);
} else {
disable_irq( irq );
}
-#ifdef CONFIG_PREP
- /* re-enable if the interrupt was good and isn't one-shot */
- if ( action->handler && !(action->flags & SA_ONESHOT) )
- enable_irq(irq);
+
/* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
- if ( irq > 7 )
+ if ( (_machine != _MACH_Pmac)/*prep*/ && (irq > 7) )
goto retry_cascade;
-#endif
-
- hardirq_exit(cpu);
- /*
- * This should be conditional: we should really get
- * a return code from the irq handler to tell us
- * whether the handler wants us to do software bottom
- * half handling or not..
- */
- if (1)
- if (bh_active & bh_mask)
- do_bottom_half();
- return;
+ /* do_bottom_half is called if necessary from int_return in head.S */
out:
hardirq_exit(cpu);
-
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
{
struct irqaction * action;
unsigned long flags;
-
-#ifdef SHOW_IRQ
+
+#ifdef SHOW_IRQ
printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
irq,handler,devname,dev_id);
#endif /* SHOW_IRQ */
-
- if (irq > NR_IRQS)
+
+ if (irq >= NR_IRQS)
return -EINVAL;
action = irq + irq_action;
if (action->handler)
restore_flags(flags);
return 0;
}
-
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction * action = irq + irq_action;
unsigned long flags;
-#ifdef SHOW_IRQ
+#ifdef SHOW_IRQ
printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
#endif /* SHOW_IRQ */
-
- if (irq > NR_IRQS) {
+
+ if (irq >= NR_IRQS) {
printk("Trying to free IRQ%d\n",irq);
return;
}
unsigned long probe_irq_on (void)
{
- unsigned int i, irqs = 0, irqmask;
- unsigned long delay;
-
- /* first, snaffle up any unassigned irqs */
- for (i = 15; i > 0; i--) {
- if (!request_irq(i, null_handler, SA_ONESHOT, "probe", NULL)) {
- enable_irq(i);
- irqs |= (1 << i);
- }
- }
-
- /* wait for spurious interrupts to mask themselves out again */
- for (delay = jiffies + 2; delay > jiffies; ); /* min 10ms delay */
-
- /* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
- for (i = 15; i > 0; i--) {
- if (irqs & (1 << i) & irqmask) {
- irqs ^= (1 << i);
- free_irq(i, NULL);
- }
- }
-#ifdef DEBUG
- printk("probe_irq_on: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
- return irqs;
+ return 0;
}
int probe_irq_off (unsigned long irqs)
{
- unsigned int i, irqmask;
-
- irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
- for (i = 15; i > 0; i--) {
- if (irqs & (1 << i)) {
- free_irq(i, NULL);
- }
- }
-#ifdef SHOW_IRQ
- printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
- irqs &= irqmask;
- if (!irqs)
- return 0;
- i = ffz(~irqs);
- if (irqs != (irqs & (1 << i)))
- i = -i;
- return i;
+ return 0;
}
-void init_IRQ(void)
+__initfunc(void init_IRQ(void))
{
-#ifdef CONFIG_PMAC
extern void xmon_irq(int, void *, struct pt_regs *);
- *IRQ_ENABLE = 0;
- request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
-#else /* CONFIG_PMAC */
- /* Initialize interrupt controllers */
- outb(0x11, 0x20); /* Start init sequence */
- outb(0x40, 0x21); /* Vector base */
-#if 1
- outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
-#else
- outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif
-
- outb(0x01, 0x21); /* Select 8086 mode */
- outb(0xFF, 0x21); /* Mask all */
-
- outb(0x11, 0xA0); /* Start init sequence */
- outb(0x48, 0xA1); /* Vector base */
-#if 1
- outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
-#else
- outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif
- outb(0x01, 0xA1); /* Select 8086 mode */
- outb(0xFF, 0xA1); /* Mask all */
+ if ( _machine == _MACH_Pmac )
+ {
+ mask_and_ack_irq = pmac_mask_and_ack_irq;
+ set_irq_mask = pmac_set_irq_mask;
+
+ *IRQ_ENABLE = 0;
+#ifdef CONFIG_XMON
+ request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
+#endif /* CONFIG_XMON */
+ }
+ else /* prep */
+ {
+ mask_and_ack_irq = prep_mask_and_ack_irq;
+ set_irq_mask = prep_set_irq_mask;
+
+ /* init master interrupt controller */
+ outb(0x11, 0x20); /* Start init sequence */
+ outb(0x40, 0x21); /* Vector base */
+ /*outb(0x04, 0x21);*/ /* edge tiggered, Cascade (slave) on IRQ2 */
+ outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+ outb(0x01, 0x21); /* Select 8086 mode */
+ outb(0xFF, 0x21); /* Mask all */
+
+ /* init slave interrupt controller */
+ outb(0x11, 0xA0); /* Start init sequence */
+ outb(0x48, 0xA1); /* Vector base */
+ /*outb(0x02, 0xA1);*/ /* edge triggered, Cascade (slave) on IRQ2 */
+ outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+ outb(0x01, 0xA1); /* Select 8086 mode */
+ outb(0xFF, 0xA1); /* Mask all */
+
+ /*
+ * According to the Carolina spec from ibm irq's 0,1,2, and 8
+ * must be edge triggered. Also, the pci intrs must be level
+ * triggered and _only_ isa intrs can be level sensitive
+ * which are 3-7,9-12,14-15. 13 is special - it can be level.
+ *
+ * power on default is 0's in both regs - all edge.
+ *
+ * These edge/level control regs allow edge/level status
+ * to be decided on a irq basis instead of on a PIC basis.
+ * It's still pretty ugly.
+ * - Cort
+ */
+ {
+ unsigned char irq_mode1 = 0, irq_mode2 = 0;
+ irq_mode1 = 0; /* to get rid of compiler warnings */
+ /*
+ * On Carolina, irq 15 and 13 must be level (scsi/ide/net).
+ */
+ if ( _machine == _MACH_IBM )
+ irq_mode2 |= 0xa0;
+ /*
+ * Sound on the Powerstack reportedly needs to be edge triggered
+ */
+ if ( _machine == _MACH_Motorola )
+ {}
+
+ /*outb( irq_mode1 , 0x4d0 );
+ outb( irq_mode2 , 0x4d1 );*/
+ }
+ outb(cached_A1, 0xA1);
+ outb(cached_21, 0x21);
+ if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
+ panic("Could not allocate cascade IRQ!");
+ enable_irq(2); /* Enable cascade interrupt */
- /*
- * Program level mode for irq's that 'can' be level triggered.
- * This does not effect irq's 0,1,2 and 8 since they must be
- * edge triggered. This is not the PIC controller. The default
- * here is for edge trigger mode. -- Cort
- */
-#if 0
- outb(0xf8, 0x4d0); /* level triggered */
- outb(0xff, 0x4d1);
-#endif
-#if 0
- outb(0x00, 0x4D0); /* All edge triggered */
- outb(0xCF, 0x4D1); /* Trigger mode */
-#endif
- outb(cached_A1, 0xA1);
- outb(cached_21, 0x21);
- if (request_irq(2, null_handler, SA_INTERRUPT, "cascade", NULL))
- printk("Unable to get IRQ2 for cascade\n");
- enable_irq(2); /* Enable cascade interrupt */
-
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
- /* set timer to periodic mode */
- outb_p(0x34,TIMER_CONTROL); /* binary, mode 2, LSB/MSB, ch 0 */
- /* set the clock to ~100 Hz */
- outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
- outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
-
- route_pci_interrupts();
-#endif /* CONFIG_PMAC */
+ route_pci_interrupts();
+ }
}
+++ /dev/null
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/elfcore.h>
-#include <linux/sched.h>
-
-#include <asm/semaphore.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-void transfer_to_handler();
-void int_return();
-void syscall_trace();
-void handle_IRQ();
-void MachineCheckException();
-void AlignmentException();
-void ProgramCheckException();
-void SingleStepException();
-void FloatingPointCheckException();
-void sys_sigreturn();
-unsigned long sys_call_table[];
-
-extern struct task_struct *current_set[1];
-
-/* platform dependent support */
-EXPORT_SYMBOL(current_set);
-EXPORT_SYMBOL(do_signal);
-EXPORT_SYMBOL(syscall_trace);
-EXPORT_SYMBOL(transfer_to_handler);
-EXPORT_SYMBOL(int_return);
-EXPORT_SYMBOL(handle_IRQ);
-EXPORT_SYMBOL(init_task_union);
-EXPORT_SYMBOL(MachineCheckException);
-EXPORT_SYMBOL(AlignmentException);
-EXPORT_SYMBOL(ProgramCheckException);
-EXPORT_SYMBOL(SingleStepException);
-EXPORT_SYMBOL(FloatingPointCheckException);
-EXPORT_SYMBOL(sys_sigreturn);
-EXPORT_SYMBOL(sys_call_table);
mtmsr r3 /* Update machine state */
blr
+#if 0
/*
* Restore 'flags'
* __restore_flags(long val)
mtmsr r3
isync
blr
-
+#endif
+
/*
* We were about to enable interrupts but we have to simulate
* some interrupts that were lost by enable_irq first.
*/
+ .globl do_lost_interrupts
do_lost_interrupts:
stwu r1,-16(r1)
mflr r0
bdnz 00b
blr
-#ifdef CONFIG_PMAC
_GLOBAL(ide_insw)
mtctr r5
subi r4,r4,2
sthx r5,0,r3
bdnz 00b
blr
-#endif
/*
* Extended precision shifts
_GLOBAL(_get_SP)
mr r3,r1 /* Close enough */
blr
-
+
_GLOBAL(_get_PVR)
mfspr r3,PVR
blr
lfs 0,0(r3)
stfd 0,0(r4)
blr
+
/*
* Fetch the current SR register
* get_SR(int index)
mr r3,r4
blr
-
_GLOBAL(cvt_df)
cvt_df:
lfd 0,0(r3)
void
main(void)
{
- /*DEFINE(KERNELBASE, KERNELBASE);*/
DEFINE(STATE, offsetof(struct task_struct, state));
DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
DEFINE(COUNTER, offsetof(struct task_struct, counter));
DEFINE(SIGNAL, offsetof(struct task_struct, signal));
DEFINE(TSS, offsetof(struct task_struct, tss));
DEFINE(KSP, offsetof(struct thread_struct, ksp));
- DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));
-#ifdef CONFIG_PMAC
- DEFINE(LAST_PC, offsetof(struct thread_struct, last_pc));
- DEFINE(USER_STACK, offsetof(struct thread_struct, user_stack));
-#endif
+ /*DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));*/
+ DEFINE(MM, offsetof(struct task_struct, mm));
+ DEFINE(PGD, offsetof(struct mm_struct, pgd));
DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
DEFINE(PF_TRACESYS, PF_TRACESYS);
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
-#if 0
- DEFINE(TSS_FPR1, offsetof(struct thread_struct, fpr[1]));
- DEFINE(TSS_FPR2, offsetof(struct thread_struct, fpr[2]));
- DEFINE(TSS_FPR3, offsetof(struct thread_struct, fpr[3]));
- DEFINE(TSS_FPR4, offsetof(struct thread_struct, fpr[4]));
- DEFINE(TSS_FPR5, offsetof(struct thread_struct, fpr[5]));
- DEFINE(TSS_FPR6, offsetof(struct thread_struct, fpr[6]));
- DEFINE(TSS_FPR7, offsetof(struct thread_struct, fpr[7]));
- DEFINE(TSS_FPR8, offsetof(struct thread_struct, fpr[8]));
- DEFINE(TSS_FPR9, offsetof(struct thread_struct, fpr[9]));
- DEFINE(TSS_FPR10, offsetof(struct thread_struct, fpr[10]));
- DEFINE(TSS_FPR11, offsetof(struct thread_struct, fpr[11]));
- DEFINE(TSS_FPR12, offsetof(struct thread_struct, fpr[12]));
- DEFINE(TSS_FPR13, offsetof(struct thread_struct, fpr[13]));
- DEFINE(TSS_FPR14, offsetof(struct thread_struct, fpr[14]));
- DEFINE(TSS_FPR15, offsetof(struct thread_struct, fpr[15]));
- DEFINE(TSS_FPR16, offsetof(struct thread_struct, fpr[16]));
- DEFINE(TSS_FPR17, offsetof(struct thread_struct, fpr[17]));
- DEFINE(TSS_FPR18, offsetof(struct thread_struct, fpr[18]));
- DEFINE(TSS_FPR19, offsetof(struct thread_struct, fpr[19]));
- DEFINE(TSS_FPR20, offsetof(struct thread_struct, fpr[20]));
- DEFINE(TSS_FPR21, offsetof(struct thread_struct, fpr[21]));
- DEFINE(TSS_FPR22, offsetof(struct thread_struct, fpr[22]));
- DEFINE(TSS_FPR23, offsetof(struct thread_struct, fpr[23]));
- DEFINE(TSS_FPR24, offsetof(struct thread_struct, fpr[24]));
- DEFINE(TSS_FPR25, offsetof(struct thread_struct, fpr[25]));
- DEFINE(TSS_FPR26, offsetof(struct thread_struct, fpr[26]));
- DEFINE(TSS_FPR27, offsetof(struct thread_struct, fpr[27]));
- DEFINE(TSS_FPR28, offsetof(struct thread_struct, fpr[28]));
- DEFINE(TSS_FPR29, offsetof(struct thread_struct, fpr[29]));
- DEFINE(TSS_FPR30, offsetof(struct thread_struct, fpr[30]));
- DEFINE(TSS_FPR31, offsetof(struct thread_struct, fpr[31]));
-#endif
DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
/* Interrupt register frame */
DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+ /* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */
DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
--- /dev/null
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+struct bridge_data {
+ volatile unsigned int *cfg_addr;
+ volatile unsigned char *cfg_data;
+ void *io_base;
+ int bus_number;
+ int max_bus;
+ struct bridge_data *next;
+ struct device_node *node;
+};
+
+static struct bridge_data **bridges, *bridge_list;
+static int max_bus;
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define APPLE_VENDID 0x106b
+#define BANDIT_DEVID 1
+#define BANDIT_REVID 3
+
+#define BANDIT_DEVNUM 11
+#define BANDIT_MAGIC 0x50
+#define BANDIT_COHERENT 0x40
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we can't use pcibios_*_config_* here because bridges[]
+ * is not initialized yet.
+ */
+static void init_bandit(struct bridge_data *bp)
+{
+ unsigned int vendev, magic;
+ int rev;
+
+ /* read the word at offset 0 in config space for device 11 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+ udelay(2);
+ vendev = in_le32((volatile unsigned int *)bp->cfg_data);
+ if (vendev != (BANDIT_DEVID << 16) + APPLE_VENDID) {
+ printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+ return;
+ }
+
+ /* read the revision id */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+ udelay(2);
+ rev = in_8(bp->cfg_data);
+ if (rev != BANDIT_REVID)
+ printk(KERN_WARNING "Unknown revision %d for bandit at %p\n",
+ rev, bp->io_base);
+
+ /* read the word at offset 0x50 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+ udelay(2);
+ magic = in_le32((volatile unsigned int *)bp->cfg_data);
+ if ((magic & BANDIT_COHERENT) != 0)
+ return;
+ magic |= BANDIT_COHERENT;
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, magic);
+ printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %p\n",
+ bp->io_base);
+}
+
+unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)
+{
+ int bus;
+ struct bridge_data *bridge;
+
+ bridge_list = 0;
+ max_bus = 0;
+ add_bridges(find_devices("bandit"), &mem_start);
+ add_bridges(find_devices("chaos"), &mem_start);
+ bridges = (struct bridge_data **) mem_start;
+ mem_start += (max_bus + 1) * sizeof(struct bridge_data *);
+ memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *));
+ for (bridge = bridge_list; bridge != NULL; bridge = bridge->next)
+ for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus)
+ bridges[bus] = bridge;
+
+ return mem_start;
+}
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
+{
+ int *bus_range;
+ int len;
+ struct bridge_data *bp;
+
+ for (; dev != NULL; dev = dev->next) {
+ if (dev->n_addrs < 1) {
+ printk(KERN_WARNING "Can't use %s: no address\n",
+ dev->full_name);
+ continue;
+ }
+ bus_range = (int *) get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ dev->full_name);
+ continue;
+ }
+ if (bus_range[1] == bus_range[0])
+ printk(KERN_INFO "PCI bus %d", bus_range[0]);
+ else
+ printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
+ bus_range[1]);
+ printk(" controlled by %s at %x\n",
+ dev->name, dev->addrs[0].address);
+ bp = (struct bridge_data *) *mem_ptr;
+ *mem_ptr += sizeof(struct bridge_data);
+ bp->cfg_addr = (volatile unsigned int *)
+ (dev->addrs[0].address + 0x800000);
+ bp->cfg_data = (volatile unsigned char *)
+ (dev->addrs[0].address + 0xc00000);
+ bp->io_base = (void *) dev->addrs[0].address;
+ ioremap(dev->addrs[0].address, 0x800000);
+ bp->bus_number = bus_range[0];
+ bp->max_bus = bus_range[1];
+ bp->next = bridge_list;
+ bp->node = dev;
+ bridge_list = bp;
+ if (bp->max_bus > max_bus)
+ max_bus = bp->max_bus;
+
+ if (strcmp(dev->name, "bandit") == 0)
+ init_bandit(bp);
+ }
+}
+
+void *pci_io_base(unsigned int bus)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return 0;
+ return bp->io_base;
+}
+
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+ unsigned char *devfn_ptr)
+{
+ unsigned int *reg;
+ int len;
+
+ reg = (unsigned int *) get_property(dev, "reg", &len);
+ if (reg == 0 || len < 5 * sizeof(unsigned int)) {
+ /* doesn't look like a PCI device */
+ *bus_ptr = 0xff;
+ *devfn_ptr = 0xff;
+ return -1;
+ }
+ *bus_ptr = reg[0] >> 16;
+ *devfn_ptr = reg[0] >> 8;
+ return 0;
+}
+
+int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_8(bp->cfg_data + (offset & 3));
+
+ if (offset == PCI_INTERRUPT_LINE) {
+ /*
+ * Open Firmware often doesn't initialize this
+ * register properly, so we find the node and see
+ * if it has an AAPL,interrupts property.
+ */
+ struct device_node *node;
+ unsigned int *reg;
+
+ for (node = bp->node->child; node != 0; node = node->sibling) {
+ reg = (unsigned int *) get_property(node, "reg", 0);
+ if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
+ continue;
+ /* this is the node, see if it has interrupts */
+ if (node->n_intrs > 0)
+ *val = node->intrs[0];
+ break;
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffffffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ *val = in_le32((volatile unsigned int *)bp->cfg_data);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_8(bp->cfg_data + (offset & 3), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x, vendev;
+ unsigned char h;
+
+ if (vendor == 0xffff)
+ return PCIBIOS_BAD_VENDOR_ID;
+ vendev = (dev_id << 16) + vendor;
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_VENDOR_ID, &x)
+ == PCIBIOS_SUCCESSFUL && x == vendev) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x;
+ unsigned char h;
+
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_CLASS_REVISION, &x)
+ == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+__initfunc(unsigned long route_pci_interrupts(void))
+{
+ return 0;
+}
/*
- * PCI support
- * -- rough emulation of "PCI BIOS" functions
- *
- * Note: these are very motherboard specific! Some way needs to
- * be worked out to handle the differences.
+ * $Id: pci.c,v 1.11 1997/08/13 03:06:14 cort Exp $
+ * Common pmac/prep pci routines. -- Cort
*/
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/bios32.h>
+#include <linux/kernel.h>
#include <linux/pci.h>
+/*#include <linux/bios32.h>*/
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/ptrace.h>
#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
-/*
- * PCI interrupt configuration. This is motherboard specific.
- */
-/* Which PCI interrupt line does a given device [slot] use? */
-/* Note: This really should be two dimensional based in slot/pin used */
-unsigned char *Motherboard_map;
-unsigned char *Motherboard_map_name;
-
-/* How is the 82378 PIRQ mapping setup? */
-unsigned char *Motherboard_routes;
-
-/* Tables for known hardware */
-
-/* Motorola PowerStack */
-static char Blackhawk_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 1, /* Slot 14 - Ethernet */
- 0, /* Slot 15 - unused */
-};
-
-static char Blackhawk_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 9, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* Motorola MVME16xx */
-static char Genesis_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 1, /* Slot 14 - Ethernet */
- 0, /* Slot 15 - unused */
-};
-
-static char Genesis_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 10, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* Motorola Series-E */
-static char Comet_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 1, /* Slot 14 - Ethernet */
- 0, /* Slot 15 - unused */
-};
-
-static char Comet_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 10, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* BeBox */
-static char BeBox_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 16, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 0, /* Slot 14 - unused */
- 0, /* Slot 15 - unused */
-};
-
-static char BeBox_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 9, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* IBM Nobis */
-static char Nobis_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 0, /* Slot 14 - unused */
- 0, /* Slot 15 - unused */
-};
-
-static char Nobis_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 13, /* Line 1 */
- 13, /* Line 2 */
- 13, /* Line 3 */
- 13 /* Line 4 */
-};
-
+unsigned long io_base;
/*
- * ibm 830 (and 850?).
- * This is actually based on the Carolina motherboard
- * -- Cort
+ * It would be nice if we could create a include/asm/pci.h and have just
+ * function ptrs for all these in there, but that isn't the case.
+ * We have a function, pcibios_*() which calls the function ptr ptr_pcibios_*()
+ * which has been setup by pcibios_init(). This is all to avoid a check
+ * for pmac/prep every time we call one of these. It should also make the move
+ * to a include/asm/pcibios.h easier, we can drop the ptr_ on these functions
+ * and create pci.h
+ * -- Cort
*/
-static char ibm8xx_pci_IRQ_map[23] = {
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - FireCoral */
- 4, /* Slot 12 - Ethernet PCIINTD# */
- 2, /* Slot 13 - PCI Slot #2 */
- 2, /* Slot 14 - S3 Video PCIINTD# */
- 0, /* Slot 15 - onboard SCSI (INDI) [1] */
- 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
- 0, /* Slot 17 - unused */
- 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
- 0, /* Slot 19 - unused */
- 0, /* Slot 20 - unused */
- 0, /* Slot 21 - unused */
- 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
-};
-static char ibm8xx_pci_IRQ_routes[] = {
- 0, /* Line 0 - unused */
- 13, /* Line 1 */
- 10, /* Line 2 */
- 15, /* Line 3 */
- 15, /* Line 4 */
-};
-/* This just changes the PCI slots & onboard SCSI + S3 to IRQ10, but
- * it really needs some logic to set them to unique IRQ's, or even
- * add some logic to the drivers to ask an irq.c routine to re-map
- * the IRQ if it needs one to itself...
- */
-static char Carolina_PIRQ_routes[] = {
- 0xad, /* INTB# = 10, INTA# = 13 */
- 0xff /* INTD# = 15, INTC# = 15 */
-};
-/* We have to turn on LEVEL mode for changed IRQ's */
-/* All PCI IRQ's need to be level mode, so this should be something
- * other than hard-coded as well... IRQ's are individually mappable
- * to either edge or level.
- */
-#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
-#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
-#define PCI_DEVICE_ID_IBM_CORAL 0x000a
-
-#undef PCI_DEBUG
-
-#ifdef PCI_STATS
-int PCI_conversions[2];
-#endif
-
-
-unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
-{
- return mem_start;
+int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+int (*ptr_pcibios_find_device)(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+int (*ptr_pcibios_find_class)(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+extern int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+extern int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+extern int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+extern int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+extern int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int prep_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+extern int prep_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+extern int prep_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+extern int prep_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+extern int prep_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+extern int prep_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+extern int prep_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+extern int prep_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ return ptr_pcibios_read_config_byte(bus,dev_fn,offset,val);
}
-
-int
-pcibios_present (void)
+int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
{
-#ifdef PCI_DEBUG
- printk("PCI [BIOS] present?\n");
-#endif
- return (1);
+ return ptr_pcibios_read_config_word(bus,dev_fn,offset,val);
}
-
-int
-pcibios_read_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int *val)
+int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
{
- unsigned long _val;
- unsigned long *ptr;
- dev >>= 3;
-#ifdef PCI_DEBUG
- printk("PCI Read config dword[%d.%d.%x] = ", bus, dev, offset);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- *val = 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
- printk("[%x] ", ptr);
-#endif
- _val = le32_to_cpu(*ptr);
- }
-#ifdef PCI_DEBUG
- printk("%x\n", _val);
-#endif
- *val = _val;
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_read_config_dword(bus,dev_fn,offset,val);
}
-
-int
-pcibios_read_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short *val)
+int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
{
- unsigned short _val;
- unsigned short *ptr;
- dev >>= 3;
-#ifdef PCI_DEBUG
- printk("PCI Read config word[%d.%d.%x] = ", bus, dev, offset);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- *val = (unsigned short)0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
- printk("[%x] ", ptr);
-#endif
- _val = le16_to_cpu(*ptr);
- }
-#ifdef PCI_DEBUG
- printk("%x\n", _val);
-#endif
- *val = _val;
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_write_config_byte(bus,dev_fn,offset,val);
}
-
-int
-pcibios_read_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char *val)
+int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
{
- unsigned char _val;
- volatile unsigned char *ptr;
- dev >>= 3;
- /* Note: the configuration registers don't always have this right! */
- if (offset == PCI_INTERRUPT_LINE)
- {
- if (Motherboard_map[dev] <= 4)
- {
- *val = Motherboard_routes[Motherboard_map[dev]];
- /*printk("dev %d map %d route %d\n",
- dev,Motherboard_map[dev],
- Motherboard_routes[Motherboard_map[dev]]);*/
- } else
- { /* Pseudo interrupts [for BeBox] */
- *val = Motherboard_map[dev];
- }
-#ifdef PCI_DEBUG
- printk("PCI Read Interrupt Line[%d.%d] = %d\n", bus, dev, *val);
-#endif
- return PCIBIOS_SUCCESSFUL;
- }
-#ifdef PCI_DEBUG
- printk("PCI Read config byte[%d.%d.%x] = ", bus, dev, offset);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- *val = 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
-#ifdef PCI_DEBUG
- printk("[%x] ", ptr);
-#endif
- _val = *ptr;
- }
-#ifdef PCI_DEBUG
- printk("%x\n", _val);
-#endif
- *val = _val;
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_write_config_word(bus,dev_fn,offset,val);
}
-
-int
-pcibios_write_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int val)
+int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
{
- unsigned long _val;
- unsigned long *ptr;
- dev >>= 3;
- _val = le32_to_cpu(val);
-#ifdef PCI_DEBUG
- printk("PCI Write config dword[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
- *ptr = _val;
- }
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val);
}
-
-int
-pcibios_write_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short val)
+int pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
{
- unsigned short _val;
- unsigned short *ptr;
- dev >>= 3;
- _val = le16_to_cpu(val);
-#ifdef PCI_DEBUG
- printk("PCI Write config word[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
- *ptr = _val;
- }
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_find_device(vendor,dev_id,index,bus_ptr,dev_fn_ptr);
}
-
-int
-pcibios_write_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char val)
+int pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
{
- unsigned char _val;
- unsigned char *ptr;
- dev >>= 3;
- _val = val;
-#ifdef PCI_DEBUG
- printk("PCI Write config byte[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
- *ptr = _val;
- }
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_find_class(class_code,index,bus_ptr,dev_fn_ptr);
}
-int
-pcibios_find_device (unsigned short vendor, unsigned short device_id,
- unsigned short index, unsigned char *bus,
- unsigned char *dev)
+int pcibios_present(void)
{
- unsigned long w, desired = (device_id << 16) | vendor;
- int devnr;
-
- if (vendor == 0xffff) {
- return PCIBIOS_BAD_VENDOR_ID;
- }
-
- for (devnr = 11; devnr < 16; devnr++)
- {
- pcibios_read_config_dword(0, devnr<<3, PCI_VENDOR_ID, &w);
- if (w == desired) {
- if (index == 0) {
- *bus = 0;
- *dev = devnr<<3;
- return PCIBIOS_SUCCESSFUL;
- }
- --index;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
+ return 1;
}
-int
-pcibios_find_class (unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *dev)
+__initfunc(unsigned long
+pcibios_init(unsigned long mem_start,unsigned long mem_end))
{
- int dev_nr, class, indx;
- indx = 0;
-#ifdef PCI_DEBUG
- printk("pcibios_find_class - class: %x, index: %x", class_code, index);
-#endif
- for (dev_nr = 11; dev_nr < 16; dev_nr++)
+ if ( _machine == _MACH_Pmac )
{
- pcibios_read_config_dword(0, dev_nr<<3, PCI_CLASS_REVISION, &class);
- if ((class>>8) == class_code)
- {
- if (index == indx)
- {
- *bus = 0;
- *dev = dev_nr<<3;
-#ifdef PCI_DEBUG
- printk(" - device: %x\n", dev_nr);
-#endif
- return (0);
- }
- indx++;
- }
+ ptr_pcibios_read_config_byte = pmac_pcibios_read_config_byte;
+ ptr_pcibios_read_config_word = pmac_pcibios_read_config_word;
+ ptr_pcibios_read_config_dword = pmac_pcibios_read_config_dword;
+ ptr_pcibios_write_config_byte = pmac_pcibios_write_config_byte;
+ ptr_pcibios_write_config_word = pmac_pcibios_write_config_word;
+ ptr_pcibios_write_config_dword = pmac_pcibios_write_config_dword;
+ ptr_pcibios_find_device = pmac_pcibios_find_device;
+ ptr_pcibios_find_class = pmac_pcibios_find_class;
}
-#ifdef PCI_DEBUG
- printk(" - not found\n");
-#endif
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-const char *pcibios_strerror(int error)
-{
- static char buf[32];
- switch (error)
- { case PCIBIOS_SUCCESSFUL:
- return ("PCI BIOS: no error");
- case PCIBIOS_FUNC_NOT_SUPPORTED:
- return ("PCI BIOS: function not supported");
- case PCIBIOS_BAD_VENDOR_ID:
- return ("PCI BIOS: bad vendor ID");
- case PCIBIOS_DEVICE_NOT_FOUND:
- return ("PCI BIOS: device not found");
- case PCIBIOS_BAD_REGISTER_NUMBER:
- return ("PCI BIOS: bad register number");
- case PCIBIOS_SET_FAILED:
- return ("PCI BIOS: set failed");
- case PCIBIOS_BUFFER_TOO_SMALL:
- return ("PCI BIOS: buffer too small");
- default:
- sprintf(buf, "PCI BIOS: invalid error #%d", error);
- return(buf);
+ else /* prep */
+ {
+ ptr_pcibios_read_config_byte = prep_pcibios_read_config_byte;
+ ptr_pcibios_read_config_word = prep_pcibios_read_config_word;
+ ptr_pcibios_read_config_dword = prep_pcibios_read_config_dword;
+ ptr_pcibios_write_config_byte = prep_pcibios_write_config_byte;
+ ptr_pcibios_write_config_word = prep_pcibios_write_config_word;
+ ptr_pcibios_write_config_dword = prep_pcibios_write_config_dword;
+ ptr_pcibios_find_device = prep_pcibios_find_device;
+ ptr_pcibios_find_class = prep_pcibios_find_class;
}
-}
-
-/*
- * Note: This routine has to access the PCI configuration space
- * for the PCI bridge chip (Intel 82378).
- */
-unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)
-{
return mem_start;
}
-unsigned long route_pci_interrupts(void)
+__initfunc(unsigned long
+pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
{
- unsigned char *ibc_pirq = (unsigned char *)0x80800860;
- unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
- extern unsigned long isBeBox[];
- int i;
-
- if ( _machine == _MACH_Motorola)
- {
- switch (inb(0x800) & 0xF0)
- {
- case 0x10: /* MVME16xx */
- Motherboard_map_name = "Genesis";
- Motherboard_map = Genesis_pci_IRQ_map;
- Motherboard_routes = Genesis_pci_IRQ_routes;
- break;
- case 0x20: /* Series E */
- Motherboard_map_name = "Series E";
- Motherboard_map = Comet_pci_IRQ_map;
- Motherboard_routes = Comet_pci_IRQ_routes;
- break;
- case 0x40: /* PowerStack */
- default: /* Can't hurt, can it? */
- Motherboard_map_name = "Blackhawk (Powerstack)";
- Motherboard_map = Blackhawk_pci_IRQ_map;
- Motherboard_routes = Blackhawk_pci_IRQ_routes;
- break;
- }
- } else
- {
- if ( _machine == _MACH_IBM )
- {
- unsigned char pl_id;
- unsigned long flags;
- unsigned index;
- unsigned char fn, bus;
- unsigned int addr;
- unsigned char dma_mode, ide_mode;
- int i;
-
- Motherboard_map_name = "IBM 8xx (Carolina)";
- Motherboard_map = ibm8xx_pci_IRQ_map;
- Motherboard_routes = ibm8xx_pci_IRQ_routes;
-ll_printk("before loop\n");
-
- for (index = 0;
- !pcibios_find_device (PCI_VENDOR_ID_IBM,
- PCI_DEVICE_ID_IBM_CORAL,
- index, &bus, &fn); ++index)
- {
- pcibios_read_config_dword(bus, fn, 0x10, &addr);
- addr &= ~0x3;
- outb(0x26, addr);
- dma_mode = inb(addr+4);
- outb(0x25, addr);
- ide_mode = inb(addr+4);
- /*printk("CORAL I/O at 0x%x, DMA mode: %x, IDE mode: %x",
- addr, dma_mode, ide_mode);*/
- /* Make CDROM non-DMA */
- ide_mode = (ide_mode & 0x0F) | 0x20;
- outb(0x25, addr);
- outb(ide_mode, addr+4);
- dma_mode = dma_mode & ~0x80;
- outb(0x26, addr);
- outb(dma_mode, addr+4);
- outb(0x26, addr);
- dma_mode = inb(addr+4);
- outb(0x25, addr);
- ide_mode = inb(addr+4);
- /*printk("=> DMA mode: %x, IDE mode: %x\n",
- dma_mode, ide_mode);*/
- }
-
- /* Setup the PCI INT mappings for the Carolina */
- /* These are PCI Interrupt Route Control [1|2] Register */
- outb(Carolina_PIRQ_routes[0], 0x0890);
- outb(Carolina_PIRQ_routes[1], 0x0891);
-
- pl_id=inb(0x0852);
- /*printk("CPU Planar ID is %#0x\n", pl_id);*/
-
- if (pl_id == 0x0C) {
- /* INDI */
- Motherboard_map[12] = 1;
- }
-ll_printk("before edge/level\n");
-#if 0
- /*printk("Changing IRQ mode\n");*/
- pl_id=inb(0x04d0);
- /*printk("Low mask is %#0x\n", pl_id);*/
- outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
-
- pl_id=inb(0x04d1);
- /*printk("Hi mask is %#0x\n", pl_id);*/
- outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
- pl_id=inb(0x04d1);
- /*printk("Hi mask now %#0x\n", pl_id);*/
-#endif
- }
- }
-
- /* Set up mapping from slots */
- for (i = 1; i <= 4; i++)
- {
- ibc_pirq[i-1] = Motherboard_routes[i];
- }
- /* Enable PCI interrupts */
- *ibc_pcicon |= 0x20;
+ return mem_start;
}
* bootup setup stuff..
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/ioport.h>
+#include <linux/major.h>
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/ide.h>
+#include <asm/pci-bridge.h>
+#include "time.h"
+
+/*
+ * A magic address and value to put into it on machines with the
+ * "ohare" I/O controller. This makes the IDE CD work on Starmaxes.
+ * Contributed by Harry Eaton.
+ */
+#define OMAGICPLACE ((volatile unsigned *) 0xf3000038)
+#define OMAGICCONT 0xbeff7a
extern int root_mountflags;
extern char command_line[];
-char saved_command_line[256];
+extern char saved_command_line[256];
-unsigned char aux_device_present; /* XXX */
-unsigned char kbd_read_mask;
unsigned char drive_info;
#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
extern unsigned long find_available_memory(void);
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
- return memory_start;
-}
-
-void setup_arch(char **cmdline_p,
+void pmac_setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p)
{
extern unsigned long *end_of_DRAM;
if (fp != 0) {
switch (_get_PVR() >> 16) {
case 4: /* 604 */
+ case 9: /* 604e */
+ case 20: /* 620 */
loops_per_sec = *fp;
break;
default: /* 601, 603, etc. */
kdev_t boot_dev;
unsigned long
-pmac_find_devices(unsigned long mem_start, unsigned long mem_end)
+powermac_init(unsigned long mem_start, unsigned long mem_end)
{
- struct device_node *chosen_np;
+ struct device_node *chosen_np, *ohare_np;
- nvram_init();
+ mem_start = pmac_find_bridges(mem_start, mem_end);
+ ohare_np = find_devices("ohare");
+ if (ohare_np != NULL) {
+ printk(KERN_INFO "Twiddling the magic ohare bits\n");
+ out_le32(OMAGICPLACE, OMAGICCONT);
+ }
+ pmac_nvram_init();
via_cuda_init();
- read_rtc_time();
+ pmac_read_rtc_time();
pmac_find_display();
bootpath = NULL;
chosen_np = find_devices("chosen");
}
}
-void find_scsi_boot()
+void find_boot_device(void)
{
int dev;
ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
if (boot_host == NULL)
return;
+#ifdef CONFIG_SCSI
dev = sd_find_target(boot_host, boot_target);
if (dev == 0)
return;
boot_dev = to_kdev_t(dev + boot_part);
+#endif
+ /* XXX should cope with booting from IDE also */
+}
+
+void note_bootable_part(kdev_t dev, int part)
+{
+ static int found_boot = 0;
+
+ if (!found_boot) {
+ find_boot_device();
+ found_boot = 1;
+ }
+ if (dev == boot_dev) {
+ ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
+ boot_dev = NODEV;
+ printk(" (root)");
+ }
}
void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
if (np->n_intrs == 0) {
printk("ide: no intrs for device %s, using 13\n",
np->full_name);
- np->intrs[0] = 13;
+ *irq = 13;
+ } else {
+ *irq = np->intrs[0];
}
base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
for (i = 0; i < 8; ++i)
*p++ = base + i * 0x10;
*p = base + 0x160;
- *irq = np->intrs[0];
-}
-
-int sys_ioperm(unsigned long from, unsigned long num, int on)
-{
- return -EIO;
-}
-
-#if 0
-extern char builtin_ramdisk_image;
-extern long builtin_ramdisk_size;
-#endif
-
-void
-builtin_ramdisk_init(void)
-{
-#if 0
- if ((ROOT_DEV == to_kdev_t(DEFAULT_ROOT_DEVICE)) && (builtin_ramdisk_size != 0))
- {
- rd_preloaded_init(&builtin_ramdisk_image, builtin_ramdisk_size);
- } else
-#endif
- { /* Not ramdisk - assume root needs to be mounted read only */
- root_mountflags |= MS_RDONLY;
- }
}
int
-get_cpuinfo(char *buffer)
+pmac_get_cpuinfo(char *buffer)
{
int pvr = _get_PVR();
char *model;
case 7:
model = "603ev";
break;
+ case 9:
+ model = "604e";
+ break;
default:
model = "unknown";
break;
}
return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model,
- (pvr & 0xff) >> 8, pvr & 0xff);
+ (pvr & 0xff00) >> 8, pvr & 0xff);
}
*/
#include <linux/kernel.h>
#include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/cuda.h>
#include <asm/system.h>
#include <asm/prom.h>
-void hard_reset_now(void)
-{
- struct cuda_request req;
-
- cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
- for (;;)
- cuda_poll();
-}
-
-void poweroff_now(void)
-{
- struct cuda_request req;
-
- cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
- for (;;)
- cuda_poll();
-}
-
/*
* Read and write the non-volatile RAM on PowerMacs.
*/
static volatile unsigned char *nvram_addr;
static volatile unsigned char *nvram_data;
-void nvram_init(void)
+void pmac_nvram_init(void)
{
struct device_node *dp;
dp = find_devices("nvram");
- if (dp == NULL)
- panic("Can't find NVRAM device");
+ if (dp == NULL) {
+ printk(KERN_ERR "Can't find NVRAM device\n");
+ nvram_naddrs = 0;
+ return;
+ }
nvram_naddrs = dp->n_addrs;
- if (nvram_naddrs == 1)
+ if (nvram_naddrs == 1) {
nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
- else if (nvram_naddrs == 2) {
+ } else if (nvram_naddrs == 2) {
nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
} else {
- printk("Found %d addresses for NVRAM\n", nvram_naddrs);
- panic("don't understand NVRAM");
+ printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
+ nvram_naddrs);
}
}
-int nvram_readb(int addr)
+unsigned char nvram_read_byte(int addr)
{
switch (nvram_naddrs) {
case 1:
eieio();
return nvram_data[(addr & 0x1f) << 4];
}
- return -1;
+ return 0;
}
-void nvram_writeb(int addr, int val)
+void nvram_write_byte(unsigned char val, int addr)
{
switch (nvram_naddrs) {
case 1:
#include <asm/prom.h>
#include <asm/system.h>
-static int get_dec(void);
-static void set_dec(int);
-static unsigned long get_rtc_time(void);
+#include "time.h"
+
/* Apparently the RTC stores seconds since 1 Jan 1904 */
#define RTC_OFFSET 2082844800
-/* Accessor functions for the decrementer register. */
-static inline int
-get_dec()
-{
- int ret;
-
- asm volatile("mfspr %0,22" : "=r" (ret) :);
- return ret;
-}
-
-static inline void
-set_dec(int val)
-{
- asm volatile("mtspr 22,%0" : : "r" (val));
-}
-
-/* The decrementer counts down by 128 every 128ns on a 601. */
-#define DECREMENTER_COUNT_601 (1000000000 / HZ)
-#define COUNT_PERIOD_NUM_601 1
-#define COUNT_PERIOD_DEN_601 1000
-
-unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
-unsigned count_period_num; /* 1 decrementer count equals */
-unsigned count_period_den; /* count_period_num / count_period_den us */
-
/*
- * This version of gettimeofday has microsecond resolution.
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
*/
-void do_gettimeofday(struct timeval *tv)
+void pmac_calibrate_decr(void)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- *tv = xtime;
- tv->tv_usec += (decrementer_count - get_dec())
- * count_period_num / count_period_den;
- if (tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
- }
- restore_flags(flags);
-}
-
-void do_settimeofday(struct timeval *tv)
-{
- unsigned long flags;
- int frac_tick;
+ struct device_node *cpu;
+ int freq, *fp, divisor;
- frac_tick = tv->tv_usec % (1000000 / HZ);
- save_flags(flags);
- cli();
- xtime.tv_sec = tv->tv_sec;
- xtime.tv_usec = tv->tv_usec - frac_tick;
- set_dec(frac_tick * count_period_den / count_period_num);
- restore_flags(flags);
+ /*
+ * The cpu node should have a timebase-frequency property
+ * to tell us the rate at which the decrementer counts.
+ */
+ cpu = find_type_devices("cpu");
+ if (cpu == 0)
+ panic("can't find cpu node in time_init");
+ fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+ if (fp == 0)
+ panic("can't get cpu timebase frequency");
+ freq = *fp * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n",
+ freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
}
-/*
- * timer_interrupt - gets called when the decrementer overflows,
- * with interrupts disabled.
- * We set it up to overflow again in 1/HZ seconds.
- */
-void timer_interrupt(struct pt_regs * regs)
+unsigned long
+pmac_get_rtc_time(void)
{
- int dval, d;
-
- while ((dval = get_dec()) < 0) {
- /*
- * Wait for the decrementer to change, then jump
- * in and add decrementer_count to its value
- * (quickly, before it changes again!)
- */
- while ((d = get_dec()) == dval)
- ;
- set_dec(d + decrementer_count);
- do_timer(regs);
- }
+ struct cuda_request req;
+ /* Get the time from the RTC */
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
+ while (!req.got_reply)
+ cuda_poll();
+ if (req.reply_len != 7)
+ printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return (req.reply[3] << 24) + (req.reply[4] << 16)
+ + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
}
-void
-time_init(void)
+int pmac_set_rtc_time(unsigned long nowtime)
{
- struct device_node *cpu;
- int freq, *fp, divisor;
-
- if ((_get_PVR() >> 16) == 1) {
- /* 601 processor: dec counts down by 128 every 128ns */
- decrementer_count = DECREMENTER_COUNT_601;
- count_period_num = COUNT_PERIOD_NUM_601;
- count_period_den = COUNT_PERIOD_DEN_601;
- } else {
- /*
- * The cpu node should have a timebase-frequency property
- * to tell us the rate at which the decrementer counts.
- */
- cpu = find_type_devices("cpu");
- if (cpu == 0)
- panic("can't find cpu node in time_init");
- fp = (int *) get_property(cpu, "timebase-frequency", NULL);
- if (fp == 0)
- panic("can't get cpu timebase frequency");
- freq = *fp * 60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %d/%d\n",
- freq, divisor);
- decrementer_count = freq / HZ / divisor;
- count_period_num = divisor;
- count_period_den = freq / 1000000;
- }
- set_dec(decrementer_count);
+ return 0;
}
/*
* been called at that stage.
*/
void
-read_rtc_time(void)
+pmac_read_rtc_time(void)
{
- xtime.tv_sec = get_rtc_time();
+ xtime.tv_sec = pmac_get_rtc_time();
xtime.tv_usec = 0;
}
-
-static unsigned long
-get_rtc_time()
-{
- struct cuda_request req;
-
- /* Get the time from the RTC */
- cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
- while (!req.got_reply)
- cuda_poll();
- if (req.reply_len != 7)
- panic("get_rtc_time: didn't expect %d byte reply",
- req.reply_len);
- return (req.reply[3] << 24) + (req.reply[4] << 16)
- + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
-}
+++ /dev/null
-/*
- * I/O 'port' access routines
- */
-#include <asm/byteorder.h>
-#include <asm/io.h>
-
-#define inb_asm(port) {( \
- unsigned char ret; \
- asm ( "lbz %0,0(%1)\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" : "=r" (ret) : "r" (port+_IO_BASE)); \
- return ret; \
-})
-
-inline unsigned char
-inb(int port)
-{
- unsigned char ret;
- asm("/*inb*/\n");
- asm ( "lbz %0,0(%1)" : "=r" (ret) : "r" (port+_IO_BASE));
- return ret;
-}
-
-inline unsigned short
-inw(int port)
-{
- unsigned short ret;
- asm("/*inw*/\n");
- asm ( "lhbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
- return ret;
-}
-
-inline unsigned long
-inl(int port)
-{
- unsigned long ret;
- asm("/*inl*/\n");
- asm ( "lwbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
- return ret;
-}
-
-inline unsigned char
-outb(unsigned char val,int port)
-{
- asm("/*outb*/\n");
- asm ( "stb %0,0(%1)" :: "r" (val), "r" (port+_IO_BASE));
- return (val);
-}
-
-inline unsigned short
-outw(unsigned short val,int port)
-{
- asm("/*outw*/\n");
- asm ( "sthbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
- return (val);
-}
-
-inline unsigned long
-outl(unsigned long val,int port)
-{
- asm("/*outl*/\n");
- asm ( "stwbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
- return (val);
-}
-
-void insb(int port, char *ptr, int len)
-{
- memcpy( (void *)ptr, (void *)(port+_IO_BASE), len);
-}
-
-void insw(int port, short *ptr, int len)
-{
- asm ("mtctr %2 \n\t"
- "subi %1,%1,2 \n\t"
- "00:\n\t"
- "lhbrx %2,0,%0 \n\t"
- "sthu %2,2(%1) \n\t"
- "bdnz 00b \n\t"
- :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void insw_unswapped(int port, short *ptr, int len)
-{
- memcpy( (void *)ptr, (void *)(port+_IO_BASE), (len*sizeof(short)) );
-}
-
-void insl(int port, long *ptr, int len)
-{
- asm ("mtctr %2 \n\t"
- "subi %1,%1,4 \n\t"
- "00:\n\t"
- "lhbrx %2,0,%0 \n\t"
- "sthu %2,4(%1) \n\t"
- "bdnz 00b \n\t"
- :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void outsb(int port, char *ptr, int len)
-{
- memcpy( (void *)ptr, (void *)(port+_IO_BASE), len );
-}
-
-void outsw(int port, short *ptr, int len)
-{
- asm ("mtctr %2\n\t"
- "subi %1,%1,2\n\t"
- "00:lhzu %2,2(%1)\n\t"
- "sthbrx %2,0,%0\n\t"
- "bdnz 00b\n\t"
- :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void outsw_unswapped(int port, short *ptr, int len)
-{
- memcpy( (void *)ptr, (void *)(port+_IO_BASE), len*sizeof(short) );
-}
-
-void outsl(int port, long *ptr, int len)
-{
- asm ("mtctr %2\n\t"
- "subi %1,%1,4\n\t"
- "00:lwzu %2,4(%1)\n\t"
- "sthbrx %2,0,%0\n\t"
- "bdnz 00b\n\t"
- :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void insl_unswapped(int port, long *ptr, int len)
-{
- unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
- /* Ensure I/O operations complete */
- __asm__ volatile("eieio");
- while (len-- > 0)
- {
- *ptr++ = (*io_ptr);
- }
-}
-
-void outsl_unswapped(int port, long *ptr, int len)
-{
- unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
- /* Ensure I/O operations complete */
- __asm__ volatile("eieio");
- while (len-- > 0)
- {
- *io_ptr = (*ptr++);
- }
-}
#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base)
#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
-
-/* Missing instructions */
-#define bdne bc 0,2,
-
+++ /dev/null
-/*
- * WARNING! This file is automatically generated - DO NOT EDIT!
- */
-#define STATE 0
-#define NEXT_TASK 68
-#define COUNTER 4
-#define BLOCKED 16
-#define SIGNAL 12
-#define TSS 544
-#define KSP 0
-#define PG_TABLES 4
-#define LAST_SYSCALL 288
-#define PT_REGS 280
-#define PF_TRACESYS 32
-#define TASK_FLAGS 20
-#define TSS_FPR0 16
-#define TSS_FPSCR 12
-#define TASK_UNION_SIZE 8192
-#define STACK_FRAME_OVERHEAD 16
-#define INT_FRAME_SIZE 192
-#define GPR0 16
-#define GPR1 20
-#define GPR2 24
-#define GPR3 28
-#define GPR4 32
-#define GPR5 36
-#define GPR6 40
-#define GPR7 44
-#define GPR8 48
-#define GPR9 52
-#define GPR10 56
-#define GPR11 60
-#define GPR12 64
-#define GPR13 68
-#define GPR14 72
-#define GPR15 76
-#define GPR16 80
-#define GPR17 84
-#define GPR18 88
-#define GPR19 92
-#define GPR20 96
-#define GPR21 100
-#define GPR22 104
-#define GPR23 108
-#define GPR24 112
-#define GPR25 116
-#define GPR26 120
-#define GPR27 124
-#define GPR28 128
-#define GPR29 132
-#define GPR30 136
-#define GPR31 140
-#define _NIP 144
-#define _MSR 148
-#define _CTR 152
-#define _LINK 156
-#define _CCR 160
-#define _XER 164
-#define _DAR 168
-#define _DSISR 172
-#define ORIG_GPR3 176
-#define RESULT 180
-#define TRAP 184
--- /dev/null
+/*
+ * $Id: ppc_htab.c,v 1.4 1997/08/12 04:24:54 cort Exp $
+ * PowerPC hash table management proc entry. Will show information
+ * about the current hash table and will allow changes to it.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * 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/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+static long ppc_htab_read(struct inode * inode, struct file * file,
+ char * buf, unsigned long nbytes);
+static long ppc_htab_write(struct inode * inode, struct file * file,
+ const char * buffer, unsigned long count);
+static long long ppc_htab_lseek(struct inode * inode, struct file * file,
+ long long offset, int orig);
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+
+static struct file_operations ppc_htab_operations = {
+ ppc_htab_lseek, /* lseek */
+ ppc_htab_read, /* read */
+ ppc_htab_write, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+/*
+ * proc files can do almost nothing..
+ */
+struct inode_operations proc_ppc_htab_inode_operations = {
+ &ppc_htab_operations, /* default proc file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+
+/*
+ * print some useful info about the hash table. This function
+ * is _REALLY_ slow (see the nested for loops below) but nothing
+ * in here should be really timing critical. -- Cort
+ */
+static long ppc_htab_read(struct inode * inode, struct file * file,
+ char * buf, unsigned long nbytes)
+{
+ int n = 0, valid;
+ unsigned int kptes = 0, overflow = 0, uptes = 0;
+ PTE *ptr;
+ struct task_struct *p;
+
+ if (nbytes < 0)
+ return -EINVAL;
+
+ /*
+ * compute user/kernel pte's table this info can be
+ * misleading since there can be valid (v bit set) entries
+ * in the table but their vsid is used by no process (mm->context)
+ * due to the way tlb invalidation is handled on the ppc
+ * -- Cort
+ */
+ for ( ptr = Hash ; ptr < (PTE *)(Hash+Hash_size) ; ptr+=sizeof(PTE))
+ {
+ if (ptr->v)
+ {
+ /* make sure someone is using this context/vsid */
+ for_each_task(p)
+ {
+ if ( (ptr->vsid >> 4) == p->mm->context )
+ {
+ valid = 1;
+ break;
+ }
+ }
+ if ( !valid )
+ continue;
+ /* user not allowed read or write */
+ if (ptr->pp == PP_RWXX)
+ kptes++;
+ else
+ uptes++;
+ if (ptr->h == 1)
+ overflow++;
+ }
+ }
+ n += sprintf( buf,
+ "Size\t\t: %luKb\n"
+ "Buckets\t\t: %lu\n"
+ "Address\t\t: %08lx\n"
+ "Entries\t\t: %lu\n"
+ "User ptes\t: %u\n"
+ "Kernel ptes\t: %u\n"
+ "Overflows\t: %u\n"
+ "Percent full\t: %%%lu\n",
+ (unsigned long)(Hash_size>>10),
+ (Hash_size/(sizeof(PTE)*8)),
+ (unsigned long)Hash,
+ Hash_size/sizeof(PTE),
+ uptes,
+ kptes,
+ overflow,
+ ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
+ );
+ /* if we're trying to read part of the file that isn't there */
+ if ( file->f_pos > n )
+ return -ENOMEM;
+ file->f_pos += n;
+ return n;
+}
+
+/*
+ * Can't _yet_ adjust the hash table size while running. -- Cort
+ */
+static long
+ppc_htab_write(struct inode * inode, struct file * file,
+ const char * buffer, unsigned long count)
+{
+ if ( current->uid != 0 )
+ return -EACCES;
+ else
+ return -ENOSYS;
+ return 0;
+}
+
+
+static long long
+ppc_htab_lseek(struct inode * inode, struct file * file,
+ long long offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return(file->f_pos);
+ case 1:
+ file->f_pos += offset;
+ return(file->f_pos);
+ case 2:
+ return(-EINVAL);
+ default:
+ return(-EINVAL);
+ }
+}
+
+
+#if 0
+/*
+ for root.c
+ */
+static struct proc_dir_entry proc_root_ppc_htab = {
+ PROC_PPC_HTAB, 8, "ppc_htab",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_ppc_htab_inode_operations
+};
+#ifdef __powerpc__
+ proc_register(&proc_root, &proc_root_ppc_htab);
+#endif
+
+
+/* add to proc_fs.h
+ PROC_PPC_HTAB,*/
+#endif
--- /dev/null
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/bios32.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/checksum.h>
+#include <asm/pgtable.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+
+void transfer_to_handler();
+void int_return();
+void syscall_trace();
+void do_IRQ();
+void MachineCheckException();
+void AlignmentException();
+void ProgramCheckException();
+void SingleStepException();
+void FloatingPointCheckException();
+void sys_sigreturn();
+extern unsigned lost_interrupts;
+extern void do_lost_interrupts(unsigned long);
+
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(transfer_to_handler);
+EXPORT_SYMBOL(int_return);
+EXPORT_SYMBOL(do_IRQ);
+EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(lost_interrupts);
+EXPORT_SYMBOL(do_lost_interrupts);
+
+EXPORT_SYMBOL(atomic_add);
+EXPORT_SYMBOL(atomic_sub);
+EXPORT_SYMBOL(atomic_inc);
+EXPORT_SYMBOL(atomic_inc_return);
+EXPORT_SYMBOL(atomic_dec);
+EXPORT_SYMBOL(atomic_dec_return);
+EXPORT_SYMBOL(atomic_dec_and_test);
+
+EXPORT_SYMBOL(set_bit);
+EXPORT_SYMBOL(clear_bit);
+EXPORT_SYMBOL(change_bit);
+EXPORT_SYMBOL(test_and_set_bit);
+EXPORT_SYMBOL(test_and_clear_bit);
+EXPORT_SYMBOL(test_and_change_bit);
+#if 0
+EXPORT_SYMBOL(ffz);
+EXPORT_SYMBOL(find_first_zero_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
+#endif
+
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strspn);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(memcmp);
+
+/* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(csum_tcpudp_magic);
+
+EXPORT_SYMBOL(__copy_tofrom_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(strlen_user);
+
+/*
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+EXPORT_SYMBOL(outsl);*/
+
+EXPORT_SYMBOL(_insw);
+EXPORT_SYMBOL(_outsw);
+EXPORT_SYMBOL(_insl);
+EXPORT_SYMBOL(_outsl);
+EXPORT_SYMBOL(ioremap);
+
+EXPORT_SYMBOL(start_thread);
+
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(__cli);
+EXPORT_SYMBOL(__sti);
+/*EXPORT_SYMBOL(__restore_flags);*/
+EXPORT_SYMBOL(_disable_interrupts);
+EXPORT_SYMBOL(_enable_interrupts);
+EXPORT_SYMBOL(flush_instruction_cache);
+EXPORT_SYMBOL(_get_PVR);
+EXPORT_SYMBOL(giveup_fpu);
+EXPORT_SYMBOL(flush_icache_range);
+EXPORT_SYMBOL(xchg_u32);
+
+EXPORT_SYMBOL(cuda_request);
+EXPORT_SYMBOL(cuda_send_request);
+EXPORT_SYMBOL(adb_register);
+EXPORT_SYMBOL(abort);
+EXPORT_SYMBOL(call_prom);
+EXPORT_SYMBOL(find_devices);
+EXPORT_SYMBOL(find_type_devices);
+EXPORT_SYMBOL(find_path_device);
+EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(pci_io_base);
+EXPORT_SYMBOL(pci_device_loc);
+EXPORT_SYMBOL(note_scsi_host);
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
#include <asm/mmu.h>
#include <asm/processor.h>
extern unsigned long loops_per_sec;
unsigned long empty_zero_page[1024];
-unsigned char aux_device_present;
+extern unsigned char aux_device_present;
#ifdef CONFIG_BLK_DEV_RAM
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
extern int rd_image_start; /* starting block # of image */
#endif
-/* copy of the residual data */
-RESIDUAL res;
-/* ptr to residual data from hw, must be initialized so not in bss (gets cleared )*/
-unsigned long resptr = 0;
-int _machine;
-extern unsigned long _TotalMemory;
-#define COMMAND_LINE_SIZE 256
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
-char saved_command_line[COMMAND_LINE_SIZE];
-#ifdef HASHSTATS
-unsigned long evicts;
-#endif
+extern char saved_command_line[256];
struct screen_info screen_info = {
0, 25, /* orig-x, orig-y */
16 /* orig-video-points */
};
-void machine_halt(void)
+
+/*
+ * these are here to get by until the pmac/prep merge is done
+ */
+int pmac_display_supported(char *name)
{
- machine_restart(NULL);
+ return 0;
}
-
-void machine_power_off(void)
+int sd_find_target(void *a, int b)
{
- machine_restart(NULL);
+ return 0;
}
-
-void machine_restart(char *cmd)
+void pmac_find_display(void)
{
- unsigned char ctl;
- unsigned long flags;
- unsigned long i = 10000;
-
- _disable_interrupts();
-
- /* set exception prefix high - to the prom */
- save_flags( flags );
- restore_flags( flags|MSR_IP );
-
- /* make sure bit 0 (reset) is a 0 */
- outb( inb(0x92) & ~1L , 0x92 );
- /* signal a reset to system control port A - soft reset */
- outb( inb(0x92) | 1 , 0x92 );
-
- while ( i != 0 ) i++;
- panic("restart failed\n");
}
int
-get_cpuinfo(char *buffer)
+prep_get_cpuinfo(char *buffer)
{
extern char *Motherboard_map_name;
+ extern RESIDUAL res;
int i;
int pvr = _get_PVR();
int len;
char *model;
- PTE *ptr;
- unsigned long kptes = 0, uptes = 0, overflow = 0;
- unsigned int ti;
-
switch (pvr>>16)
{
/* L2 */
if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
{
- int size;
-
len += sprintf(buffer+len,"l2\t\t: %dkB %s\n",
((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
(inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
* Ooh's and aah's info about zero'd pages in idle task
*/
{
- extern unsigned int zerocount, zerototal, zeropage_hits;
+ extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
- "current: %u (%uKb) hits: %u\n",
+ "current: %u (%uKb) hits: %u/%u (%lu%%)\n",
zerototal, (zerototal*PAGE_SIZE)>>10,
zerocount, (zerocount*PAGE_SIZE)>>10,
- zeropage_hits);
+ zeropage_hits,zeropage_calls,
+ /* : 1 below is so we don't div by zero */
+ (zeropage_hits*100) /
+ ((zeropage_calls)?zeropage_calls:1));
}
-
-
- /* ram/hash table info */
- len += sprintf(buffer+len,"hash table\t: %dkB (%dk buckets)\n",
- Hash_size>>10,(Hash_size/(sizeof(PTE)*8)) >> 10);
-
- /* if booted print info about hash table use (overflows, etc) */
-#ifdef HASHSTATS
- for ( ptr = Hash ; ptr < (PTE *)(Hash+Hash_size) ; ptr++)
- {
- if (ptr->v)
- {
- /* user not allowed read or write */
- if (ptr->pp == PP_RWXX)
- kptes++;
- else
- uptes++;
- if (ptr->h == 1)
- overflow++;
- }
- }
- /*len+=sprintf(buffer+len,"Hash %x Hash+Hash_size %x MemEnd %x\n",
- Hash,Hash+Hash_size,KERNELBASE+_TotalMemory);*/
- /*len += sprintf(buffer+len,"PTEs: (user/kernel/max) %d (%d%%)/%d "
- "(%d%%)/%d (%d%% full)\n",
- uptes,(uptes*100)/(Hash_size/sizeof(PTE)),
- kptes,(kptes*100)/(Hash_size/sizeof(PTE)),
- Hash_size/sizeof(PTE),
- ((uptes+kptes)*100)/(Hash_size/sizeof(PTE)));
- len += sprintf(buffer+len,"Current Ovflw PTE's: %d Total Evicts: %u\n",
- overflow,evicts);*/
-#endif /* HASHSTATS */
return len;
}
-__initfunc(unsigned long
-bios32_init(unsigned long memory_start, unsigned long memory_end))
-{
- return memory_start;
-}
-
__initfunc(void
-setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+prep_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
unsigned long * memory_end_p))
{
extern char cmd_line[];
extern char _etext[], _edata[], _end[];
- unsigned char reg;
extern int panic_timeout;
/* Save unparsed command line copy for /proc/cmdline */
*cmdline_p = cmd_line;
*memory_start_p = (unsigned long) Hash+Hash_size;
- (unsigned long *)*memory_end_p = (unsigned long *)(_TotalMemory+KERNELBASE);
+ (unsigned long *)*memory_end_p = (unsigned long *)(res.TotalMemory+KERNELBASE);
/* init to some ~sane value until calibrate_delay() runs */
loops_per_sec = 50000000;
/* reboot on panic */
- /*panic_timeout = 180;*/
+ panic_timeout = 180;
init_task.mm->start_code = PAGE_OFFSET;
init_task.mm->end_code = (unsigned long) _etext;
ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
break;
}
- /*ROOT_DEV = to_kdev_t(0x0811);*/ /* sdb1 */
-#if 0
- strcpy(cmd_line+strlen(cmd_line),"console=1,9600,n8");
-#endif
-#if 0
- if ( _machine == _MACH_Motorola )
- {
- /* get root via nfs from gordito -- only used for testing */
- ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255); /* nfs */
- /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
- strcpy(cmd_line+strlen(cmd_line),
- "nfsaddrs=129.138.6.13:129.138.6.101:129.138.6.1:255.255.255.0:"
- "pandora nfsroot=/usr/src/root/");
- }
-#endif
-
#ifdef CONFIG_BLK_DEV_RAM
#if 0
ROOT_DEV = to_kdev_t(0x0200); /* floppy */
rd_doload = 1;
rd_image_start = 0;
#endif
+ /* initrd_start and size are setup by boot/head.S and kernel/head.S */
+ if ( initrd_start )
+ {
+ if (initrd_end > *memory_end_p)
+ {
+ printk("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ initrd_end,*memory_end_p);
+ initrd_start = 0;
+ }
+ }
#endif
+
+ printk("Boot arguments: %s\n", cmd_line);
request_region(0x20,0x20,"pic1");
request_region(0xa0,0x20,"pic2");
request_region(0x80,0x10,"dma page reg");
request_region(0xc0,0x20,"dma2");
}
-
#include <asm/segment.h>
#include <asm/io.h>
#include <asm/processor.h>
+#include <asm/nvram.h>
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
-static int set_rtc_mmss(unsigned long nowtime);
-unsigned long get_cmos_time(void);
-static inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
+#include "time.h"
+
+inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
unsigned int, unsigned int, unsigned int);
-#define TIMER_IRQ 0
-/* Cycle counter value at the previous timer interrupt.. */
-static unsigned long long last_timer_cc = 0;
-static unsigned long long init_timer_cc = 0;
+/*
+ * The motorola uses the m48t18 rtc (includes DS1643) whose registers
+ * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
+ * rtc (ds1386) which has regs at addr 0-d). The intel gets
+ * past this because the bios emulates the mc146818.
+ *
+ * Why in the world did they have to use different clocks?
+ *
+ * Right now things are hacked to check which machine we're on then
+ * use the appropriate macro. This is very very ugly and I should
+ * probably have a function that checks which machine we're on then
+ * does things correctly transparently or a function pointer which
+ * is setup at boot time to use the correct addresses.
+ * -- Cort
+ */
+/*
+ * translate from mc146818 to m48t18 addresses
+ */
+unsigned int clock_transl[] = { MOTO_RTC_SECONDS,0 /* alarm */,
+ MOTO_RTC_MINUTES,0 /* alarm */,
+ MOTO_RTC_HOURS,0 /* alarm */, /* 4,5 */
+ MOTO_RTC_DAY_OF_WEEK,
+ MOTO_RTC_DAY_OF_MONTH,
+ MOTO_RTC_MONTH,
+ MOTO_RTC_YEAR, /* 9 */
+ MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */
+};
+
+int prep_cmos_clock_read(int addr)
+{
+ if ( _machine == _MACH_IBM )
+ return CMOS_READ(addr);
+ else if ( _machine == _MACH_Motorola )
+ {
+ outb(clock_transl[addr]>>8, NVRAM_AS1);
+ outb(clock_transl[addr], NVRAM_AS0);
+ return (inb(NVRAM_DATA));
+ }
+
+ printk("Unknown machine in prep_cmos_clock_read()!\n");
+ return -1;
+}
+
+void prep_cmos_clock_write(unsigned long val, int addr)
+{
+ if ( _machine == _MACH_IBM )
+ {
+ CMOS_WRITE(val,addr);
+ return;
+ }
+ else if ( _machine == _MACH_Motorola )
+ {
+ outb(clock_transl[addr]>>8, NVRAM_AS1);
+ outb(clock_transl[addr], NVRAM_AS0);
+ outb(val,NVRAM_DATA);
+ return;
+ }
+ printk("Unknown machine in prep_cmos_clock_write()!\n");
+}
#define TICK_SIZE tick
#define FEBRUARY 2
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
+#if 0
static unsigned long do_slow_gettimeoffset(void)
{
int count;
count = (count + LATCH/2) / LATCH;
return offset + count;
}
-
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
/*
sti();
}
+#endif
+
void to_tm(int tim, struct rtc_time * tm)
{
register int i;
/*
* Set the hardware clock. -- Cort
*/
-static int set_rtc_mmss(unsigned long nowtime)
+int prep_set_rtc_time(unsigned long nowtime)
{
- int retval = 0;
- int real_seconds, real_minutes, cmos_minutes;
unsigned char save_control, save_freq_select;
struct rtc_time tm;
to_tm(nowtime, &tm);
- save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
- CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+ save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
- save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
- CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+ prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+
+ prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
tm.tm_year -= 1900;
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BIN_TO_BCD(tm.tm_mday);
BIN_TO_BCD(tm.tm_year);
}
- CMOS_WRITE(tm.tm_sec,RTC_SECONDS);
- CMOS_WRITE(tm.tm_min,RTC_MINUTES);
- CMOS_WRITE(tm.tm_hour,RTC_HOURS);
- CMOS_WRITE(tm.tm_mon,RTC_MONTH);
- CMOS_WRITE(tm.tm_mday,RTC_DAY_OF_MONTH);
- CMOS_WRITE(tm.tm_year,RTC_YEAR);
+ prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+ prep_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+ prep_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+ prep_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+ prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+ prep_cmos_clock_write(tm.tm_year,RTC_YEAR);
/* The following flags have to be released exactly in this order,
* otherwise the DS12887 (popular MC146818A clone with integrated
* the Dallas Semiconductor data sheets, but who believes data
* sheets anyway ... -- Markus Kuhn
*/
- CMOS_WRITE(save_control, RTC_CONTROL);
- CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ prep_cmos_clock_write(save_control, RTC_CONTROL);
+ prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
time_state = TIME_OK;
return 0;
}
-unsigned long get_cmos_time(void)
+unsigned long prep_get_rtc_time(void)
{
unsigned int year, mon, day, hour, min, sec;
int i;
*/
/* read RTC exactly on falling edge of update flag */
for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
- if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+ if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
break;
for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
- if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+ if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
break;
do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = CMOS_READ(RTC_SECONDS);
- min = CMOS_READ(RTC_MINUTES);
- hour = CMOS_READ(RTC_HOURS);
- day = CMOS_READ(RTC_DAY_OF_MONTH);
- mon = CMOS_READ(RTC_MONTH);
- year = CMOS_READ(RTC_YEAR);
- } while (sec != CMOS_READ(RTC_SECONDS));
- if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ sec = prep_cmos_clock_read(RTC_SECONDS);
+ min = prep_cmos_clock_read(RTC_MINUTES);
+ hour = prep_cmos_clock_read(RTC_HOURS);
+ day = prep_cmos_clock_read(RTC_DAY_OF_MONTH);
+ mon = prep_cmos_clock_read(RTC_MONTH);
+ year = prep_cmos_clock_read(RTC_YEAR);
+ } while (sec != prep_cmos_clock_read(RTC_SECONDS));
+ if (!(prep_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
BCD_TO_BIN(sec);
BCD_TO_BIN(min);
return mktime(year, mon, day, hour, min, sec);
}
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+inline unsigned long mktime(unsigned int year, unsigned int mon,
+ unsigned int day, unsigned int hour,
+ unsigned int min, unsigned int sec)
+{
+
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (((
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
+#if 0
+void time_init(void)
+{
+ void (*irq_handler)(int, void *,struct pt_regs *);
+
+ xtime.tv_sec = prep_get_rtc_time();
+ xtime.tv_usec = 0;
+
+ prep_calibrate_decr();
+
+ /* If we have the CPU hardware time counters, use them */
+ irq_handler = timer_interrupt;
+ if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+}
+
/*
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
{
+ prep_calibrate_decr_handler(irq,dev,regs);
do_timer(regs);
/* update the hw clock if:
* the time is marked out of sync (TIME_ERROR)
* or ~11 minutes have expired since the last update -- Cort
* If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * CMOS clock accordingly every ~11 minutes. prep_set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
if ( time_state == TIME_BAD ||
/*if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
xtime.tv_usec > 500000 - (tick >> 1) &&
xtime.tv_usec < 500000 + (tick >> 1))*/
- if (set_rtc_mmss(xtime.tv_sec) == 0)
+ if (prep_set_rtc_time(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
#endif
}
-
-
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static inline unsigned long mktime(unsigned int year, unsigned int mon,
- unsigned int day, unsigned int hour,
- unsigned int min, unsigned int sec)
-{
- if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
- mon += 12; /* Puts Feb last since it has leap day */
- year -= 1;
- }
- return (((
- (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
- year*365 - 719499
- )*24 + hour /* now have hours */
- )*60 + min /* now have minutes */
- )*60 + sec; /* finally seconds */
-}
-
-void time_init(void)
-{
- void (*irq_handler)(int, void *,struct pt_regs *);
- xtime.tv_sec = get_cmos_time();
- xtime.tv_usec = 0;
-
- /* If we have the CPU hardware time counters, use them */
- irq_handler = timer_interrupt;
- if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
- panic("Could not allocate timer IRQ!");
-}
+#endif
* Derived from "arch/i386/kernel/process.c"
* Copyright (C) 1995 Linus Torvalds
*
- * Modified by Cort Dougan (cort@cs.nmt.edu) and
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
* Paul Mackerras (paulus@cs.anu.edu.au)
*
* This program is free software; you can redistribute it and/or
#include <linux/ptrace.h>
#include <linux/malloc.h>
#include <linux/user.h>
-#include <linux/a.out.h>
+#include <linux/elf.h>
#include <linux/config.h>
+#include <linux/elf.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/smp_lock.h>
+#include <asm/processor.h>
-int dump_fpu(void);
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
void switch_to(struct task_struct *, struct task_struct *);
-void print_backtrace(unsigned long *);
-void show_regs(struct pt_regs * regs);
-void inline zero_paged(void);
extern unsigned long _get_SP(void);
+
#undef SHOW_TASK_SWITCHES 1
#undef CHECK_STACK 1
#undef IDLE_ZERO 1
{
return ((unsigned long)tsk) + sizeof(struct task_struct);
}
-
+
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;
union task_union init_task_union = { INIT_TASK };
int
-dump_fpu(void)
+dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
{
- return (1);
+ if (last_task_used_math == current)
+ giveup_fpu();
+ memcpy(fpregs, ¤t->tss.fpr[0], sizeof(*fpregs));
+ return 1;
}
/* check to make sure the kernel stack is healthy */
unsigned long stack_top = kernel_stack_top(tsk);
unsigned long tsk_top = task_top(tsk);
int ret = 0;
- unsigned long *i;
#if 0
/* check tss magic */
if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
{
printk("stack out of bounds: %s/%d\n"
- " tsk_top %08x ksp %08x stack_top %08x\n",
+ " tsk_top %08lx ksp %08lx stack_top %08lx\n",
tsk->comm,tsk->pid,
tsk_top, tsk->tss.ksp, stack_top);
ret |= 2;
if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
{
printk("current stack ptr out of bounds: %s/%d\n"
- " tsk_top %08x sp %08x stack_top %08x\n",
+ " tsk_top %08lx sp %08lx stack_top %08lx\n",
current->comm,current->pid,
tsk_top, _get_SP(), stack_top);
ret |= 4;
{
struct thread_struct *new_tss, *old_tss;
int s = _disable_interrupts();
- struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
#if CHECK_STACK
check_stack(prev);
check_stack(new);
#endif
- /* turn off fpu for task last to run */
- /*prev->tss.regs->msr &= ~MSR_FP;*/
-
+
#ifdef SHOW_TASK_SWITCHES
printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
prev->comm,prev->pid,prev->tss.regs->nip,
new_tss = &new->tss;
old_tss = ¤t->tss;
_switch(old_tss, new_tss, new->mm->context);
- /* turn off fpu for task last to run */
_enable_interrupts(s);
}
-
-#include <linux/mc146818rtc.h>
-asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
-{
-#if 1
- struct task_struct *p;
- printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
- printk("last %x\n", last_task_used_math);
- printk("cur %x regs %x/%x tss %x/%x\n",
- current, current->tss.regs,regs,¤t->tss,current->tss);
- for_each_task(p)
- {
- if ((long)p < KERNELBASE)
- {
- printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
- print_mm_info();
- __cli();
- while(1);
- }
- }
- return regs->gpr[3];
-#endif
-#if 0
- /* set the time in the cmos clock */
- unsigned long hwtime, nowtime;
- struct rtc_time tm;
-
- hwtime = get_cmos_time();
- to_tm(hwtime, &tm);
- printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n",
- tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
- tm.tm_mday, tm.tm_year);
- return;
-#endif
-}
-/*
- * vars for idle task zero'ing out pages
- */
-unsigned long zero_list = 0; /* head linked list of pre-zero'd pages */
-unsigned long bytecount = 0; /* pointer into the currently being zero'd page */
-unsigned long zerocount = 0; /* # currently pre-zero'd pages */
-unsigned long zerototal = 0; /* # pages zero'd over time -- for ooh's and ahhh's */
-unsigned long pageptr = 0; /* current page being zero'd */
-unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
-
-/*
- * Returns a pre-zero'd page from the list otherwise returns
- * NULL.
- */
-unsigned long get_prezerod_page(void)
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
{
- unsigned long page;
- unsigned long s;
-
- if ( zero_list )
- {
- /* atomically remove this page from the list */
- asm ( "101:lwarx %1,0,%2\n" /* reserve zero_list */
- " lwz %0,0(%1)\n" /* get next -- new zero_list */
- " stwcx. %0,0,%2\n" /* update zero_list */
- " bne- 101b\n" /* if lost reservation try again */
- : "=&r" (zero_list), "=&r" (page)
- : "r" (&zero_list)
- : "cc" );
- /* we can update zerocount after the fact since it is not
- * used for anything but control of a loop which doesn't
- * matter since it won't effect anything if it zero's one
- * less page -- Cort
- */
- atomic_inc((atomic_t *)&zeropage_hits);
- atomic_dec((atomic_t *)&zerocount);
- /* zero out the pointer to next in the page */
- *(unsigned long *)page = 0;
- return page;
- }
return 0;
}
-/*
- * Experimental stuff to zero out pages in the idle task
- * to speed up get_free_pages() -- Cort
- * Zero's out pages until we need to resched or
- * we've reached the limit of zero'd pages.
- */
-void inline zero_paged(void)
-{
- extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
- unsigned long tmp;
- pte_t ptep;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- sprintf(current->comm, "zero_paged");
- printk("Started zero_paged\n");
- /* want priority over idle task and powerd */
- current->priority = -98;
- current->counter = -98;
- __sti();
-
- while ( zerocount < 128 )
- {
- /*
- * Mark a page as reserved so we can mess with it
- * If we're interrupted we keep this page and our place in it
- * since we validly hold it and it's reserved for us.
- */
- pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
- if ( !pageptr )
- {
- printk("!pageptr in zero_paged\n");
- goto retry;
- }
-
- if ( need_resched )
- schedule();
-
- /*
- * Make the page no cache so we don't blow our cache with 0's
- */
- dir = pgd_offset( init_task.mm, pageptr );
- if (dir)
- {
- pmd = pmd_offset(dir, pageptr & PAGE_MASK);
- if (pmd && pmd_present(*pmd))
- {
- pte = pte_offset(pmd, pageptr & PAGE_MASK);
- if (pte && pte_present(*pte))
- {
- pte_uncache(*pte);
- flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
- }
- }
- }
-
- /*
- * Important here to not take time away from real processes.
- */
- for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
- {
- if ( need_resched )
- schedule();
- *(unsigned long *)(bytecount + pageptr) = 0;
- }
-
- /*
- * If we finished zero-ing out a page add this page to
- * the zero_list atomically -- we can't use
- * down/up since we can't sleep in idle.
- * Disabling interrupts is also a bad idea since we would
- * steal time away from real processes.
- * We can also have several zero_paged's running
- * on different processors so we can't interfere with them.
- * So we update the list atomically without locking it.
- * -- Cort
- */
- /* turn cache on for this page */
- pte_cache(*pte);
- flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
-
- /* atomically add this page to the list */
- asm ( "101:lwarx %0,0,%1\n" /* reserve zero_list */
- " stw %0,0(%2)\n" /* update *pageptr */
-#ifdef __SMP__
- " sync\n" /* let store settle */
-#endif
- " mr %0,%2\n" /* update zero_list in reg */
- " stwcx. %2,0,%1\n" /* update zero_list in mem */
- " bne- 101b\n" /* if lost reservation try again */
- : "=&r" (zero_list)
- : "r" (&zero_list), "r" (pageptr)
- : "cc" );
- /*
- * This variable is used in the above loop and nowhere
- * else so the worst that could happen is we would
- * zero out one more or one less page than we want
- * per processor on the machine. This is because
- * we could add our page to the list but not have
- * zerocount updated yet when another processor
- * reads it. -- Cort
- */
- atomic_inc((atomic_t *)&zerocount);
- atomic_inc((atomic_t *)&zerototal);
-retry:
- schedule();
- }
-}
-
-void powerd(void)
-{
- unsigned long msr, hid0;
-
- sprintf(current->comm, "powerd");
- __sti();
- while (1)
- {
- /* want priority over idle task 'swapper' -- Cort */
- current->priority = -99;
- current->counter = -99;
- asm volatile(
- /* clear powersaving modes and set nap mode */
- "mfspr %3,1008 \n\t"
- "andc %3,%3,%4 \n\t"
- "or %3,%3,%5 \n\t"
- "mtspr 1008,%3 \n\t"
- /* enter the mode */
- "mfmsr %0 \n\t"
- "oris %0,%0,%2 \n\t"
- "sync \n\t"
- "mtmsr %0 \n\t"
- "isync \n\t"
- : "=&r" (msr)
- : "0" (msr), "i" (MSR_POW>>16),
- "r" (hid0),
- "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
- "r" (HID0_NAP));
- if ( need_resched )
- schedule();
- /*
- * The ibm carolina spec says that the eagle memory
- * controller will detect the need for a snoop
- * and wake up the processor so we don't need to
- * check for cache operations that need to be
- * snooped. The ppc book says the run signal
- * must be asserted while napping for this though.
- * -- Cort
- */
- }
-}
-
-asmlinkage int sys_idle(void)
-{
- int ret = -EPERM;
- if (current->pid != 0)
- goto out;
-
-#ifdef IDLE_ZERO
- /*
- * want one per cpu since it would be nice to have all
- * processors who aren't doing anything
- * zero-ing pages since this daemon is lock-free
- * -- Cort
- */
- kernel_thread(zero_paged, NULL, 0);
-#endif /* IDLE_ZERO */
-
-#ifdef CONFIG_POWERSAVING
- /* no powersaving modes on 601 - one per processor */
- if( (_get_PVR()>>16) != 1 )
- kernel_thread(powerd, NULL, 0);
-#endif /* CONFIG_POWERSAVING */
-
- /* endless loop with no priority at all */
- current->priority = -100;
- current->counter = -100;
- for (;;)
- {
- schedule();
- }
- ret = 0;
-out:
- return ret;
-}
-
void show_regs(struct pt_regs * regs)
{
int i;
- printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+ printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
regs->nip, regs->xer, regs->link, regs,regs->trap);
- printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
regs->msr&MSR_IR ? 1 : 0,
regs->msr&MSR_DR ? 1 : 0);
- printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+ printk("TASK = %p[%d] '%s' mm->pgd %p ",
current, current->pid, current->comm, current->mm->pgd);
- printk("Last syscall: %d ", current->tss.last_syscall);
- printk("\nlast math %08X\n", last_task_used_math);
+ printk("Last syscall: %ld ", current->tss.last_syscall);
+ printk("\nlast math %p\n", last_task_used_math);
for (i = 0; i < 32; i++)
{
long r;
printk("GPR%02d: ", i);
}
- if ( get_user(r, &(regs->gpr[i])) )
+ if ( __get_user(r, &(regs->gpr[i])) )
goto out;
- printk("%08X ", r);
+ printk("%08lX ", r);
if ((i % 8) == 7)
{
printk("\n");
}
/*
- * Copy a thread..
- */
+ * Copy a thread..
+ */
int
copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
- int i;
struct pt_regs * childregs;
+
/* Copy registers */
childregs = ((struct pt_regs *)
((unsigned long)p + sizeof(union task_union)
if ((childregs->msr & MSR_PR) == 0)
childregs->gpr[2] = (unsigned long) p; /* `current' in new task */
childregs->gpr[3] = 0; /* Result from fork() */
- p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
- p->tss.regs = (struct pt_regs *)(childregs);
- if (usp >= (unsigned long)regs)
- { /* Stack is in kernel space - must adjust */
- childregs->gpr[1] = (long)(childregs+1);
- } else
- { /* Provided stack is in user space */
+ p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
+ p->tss.regs = childregs;
+ if (usp >= (unsigned long) regs) {
+ /* Stack is in kernel space - must adjust */
+ childregs->gpr[1] = (unsigned long)(childregs + 1);
+ } else {
+ /* Provided stack is in user space */
childregs->gpr[1] = usp;
}
/*
* copy fpu info - assume lazy fpu switch now always
- * this should really be conditional on whether or
- * not the process has used the fpu
* -- Cort
*/
if ( last_task_used_math == current )
giveup_fpu();
-
+
memcpy(&p->tss.fpr, ¤t->tss.fpr, sizeof(p->tss.fpr));
p->tss.fpscr = current->tss.fpscr;
childregs->msr &= ~MSR_FP;
-
+
return 0;
}
+/*
+ * XXX ld.so expects the auxiliary table to start on
+ * a 16-byte boundary, so we have to find it and
+ * move it up. :-(
+ */
+static inline void shove_aux_table(unsigned long sp)
+{
+ int argc;
+ char *p;
+ unsigned long e;
+ unsigned long aux_start, offset;
+
+ if (__get_user(argc, (int *)sp))
+ return;
+ sp += sizeof(int) + (argc + 1) * sizeof(char *);
+ /* skip over the environment pointers */
+ do {
+ if (__get_user(p, (char **)sp))
+ return;
+ sp += sizeof(char *);
+ } while (p != NULL);
+ aux_start = sp;
+ /* skip to the end of the auxiliary table */
+ do {
+ if (__get_user(e, (unsigned long *)sp))
+ return;
+ sp += 2 * sizeof(unsigned long);
+ } while (e != AT_NULL);
+ offset = ((aux_start + 15) & ~15) - aux_start;
+ if (offset != 0) {
+ do {
+ sp -= sizeof(unsigned long);
+ if (__get_user(e, (unsigned long *)sp)
+ || __put_user(e, (unsigned long *)(sp + offset)))
+ return;
+ } while (sp > aux_start);
+ }
+}
+
+/*
+ * Set up a thread for executing a new program
+ */
+void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
+{
+ set_fs(USER_DS);
+ regs->nip = nip;
+ regs->gpr[1] = sp;
+ regs->msr = MSR_USER;
+ shove_aux_table(sp);
+}
+
+
asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
int ret;
+
lock_kernel();
ret = do_fork(SIGCHLD, regs->gpr[1], regs);
unlock_kernel();
{
int error;
char * filename;
- filename = (int) getname((char *) a0);
+
+ filename = getname((char *) a0);
error = PTR_ERR(filename);
- if(IS_ERR(filename))
+ if (IS_ERR(filename))
goto out;
if ( last_task_used_math == current )
last_task_used_math = NULL;
error = do_execve(filename, (char **) a1, (char **) a2, regs);
-
putname(filename);
-
out:
unlock_kernel();
return error;
}
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+ struct pt_regs *regs)
{
unsigned long clone_flags = p1;
int res;
-
+
lock_kernel();
res = do_fork(clone_flags, regs->gpr[1], regs);
unlock_kernel();
print_backtrace(unsigned long *sp)
{
int cnt = 0;
- int i;
+ unsigned long i;
+
printk("Call backtrace: ");
- while ( !get_user(i, sp) && i)
- {
- if ( get_user( i, &sp[1] ) )
- return;
- printk("%08X ", i);
- if ( get_user( (ulong)sp, sp) )
- return;
- if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
- if (++cnt == 8)
- {
+ while (sp) {
+ if (__get_user( i, &sp[1] ))
+ break;
+ if (cnt++ % 7 == 0)
printk("\n");
- }
+ printk("%08lX ", i);
if (cnt > 32) break;
+ if (__get_user(sp, (unsigned long **)sp))
+ break;
}
printk("\n");
}
-inline void start_thread(struct pt_regs * regs,
- unsigned long eip, unsigned long esp)
-{
- set_fs(USER_DS);
- regs->nip = eip;
- regs->gpr[1] = esp;
- regs->msr = MSR_USER;
-}
-
+#if 0
/*
* Low level print for debugging - Cort
*/
orig_x = x;
orig_y = y;
}
+#endif /* CONFIG_PREP */
--- /dev/null
+/*
+ * Procedures for interfacing to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * In particular, we are interested in the device tree
+ * and in using some of its services (exit, write to stdout).
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+
+#define getpromprop(node, name, buf, len) \
+ ((int)call_prom("getprop", 4, 1, (node), (name), (buf), (len)))
+
+ihandle prom_stdout;
+ihandle prom_chosen;
+
+char command_line[256];
+int screen_initialized = 0;
+
+char prom_display_path[128];
+
+struct prom_args {
+ const char *service;
+ int nargs;
+ int nret;
+ void *args[10];
+} prom_args;
+
+struct pci_address {
+ unsigned a_hi;
+ unsigned a_mid;
+ unsigned a_lo;
+};
+
+struct pci_reg_property {
+ struct pci_address addr;
+ unsigned size_hi;
+ unsigned size_lo;
+};
+
+struct pci_range {
+ struct pci_address addr;
+ unsigned phys;
+ unsigned size_hi;
+ unsigned size_lo;
+};
+
+void (*prom_entry)(void *);
+extern int prom_trashed;
+
+static int prom_callback(struct prom_args *);
+static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
+ unsigned long, unsigned long);
+static void check_display(void);
+static int prom_next_node(phandle *);
+
+extern int pmac_display_supported(const char *);
+extern void enter_prom(void *);
+
+void
+prom_exit()
+{
+ struct prom_args args;
+
+ args.service = "exit";
+ args.nargs = 0;
+ args.nret = 0;
+ enter_prom(&args);
+ for (;;) /* should never get here */
+ ;
+}
+
+void *
+call_prom(const char *service, int nargs, int nret, ...)
+{
+ va_list list;
+ int i;
+
+ if (prom_trashed)
+ panic("prom called after its memory was reclaimed");
+ prom_args.service = service;
+ prom_args.nargs = nargs;
+ prom_args.nret = nret;
+ va_start(list, nret);
+ for (i = 0; i < nargs; ++i)
+ prom_args.args[i] = va_arg(list, void *);
+ va_end(list);
+ for (i = 0; i < nret; ++i)
+ prom_args.args[i + nargs] = 0;
+ enter_prom(&prom_args);
+ return prom_args.args[nargs];
+}
+
+void
+prom_print(const char *msg)
+{
+ const char *p, *q;
+ const char *crlf = "\r\n";
+
+ if (screen_initialized)
+ return;
+ for (p = msg; *p != 0; p = q) {
+ for (q = p; *q != 0 && *q != '\n'; ++q)
+ ;
+ if (q > p)
+ call_prom("write", 3, 1, prom_stdout, p, q - p);
+ if (*q != 0) {
+ ++q;
+ call_prom("write", 3, 1, prom_stdout, crlf, 2);
+ }
+ }
+}
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+void
+prom_init(char *params, int unused, void (*pp)(void *))
+{
+ /* First get a handle for the stdout device */
+ if ( _machine != _MACH_Pmac ) /* prep */
+ return;
+ prom_entry = pp;
+ prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
+ if (prom_chosen == (void *)-1)
+ prom_exit();
+ call_prom("getprop", 4, 1, prom_chosen, "stdout", &prom_stdout,
+ (void *) sizeof(prom_stdout));
+
+ /*
+ * If we were booted via quik, params points to the physical address
+ * of the command-line parameters.
+ * If we were booted from an xcoff image (i.e. netbooted or
+ * booted from floppy), we get the command line from the bootargs
+ * property of the /chosen node. If an initial ramdisk is present,
+ * params and unused are used for initrd_start and initrd_size,
+ * otherwise they contain 0xdeadbeef.
+ */
+ command_line[0] = 0;
+ if ((unsigned long) params >= 0x4000
+ && (unsigned long) params < 0x800000
+ && unused == 0) {
+ strncpy(command_line, params+KERNELBASE, sizeof(command_line));
+ } else {
+#ifdef CONFIG_BLK_DEV_INITRD
+ if ((unsigned long) params - KERNELBASE < 0x800000
+ && unused != 0 && unused != 0xdeadbeef) {
+ initrd_start = (unsigned long) params;
+ initrd_end = initrd_start + unused;
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ }
+#endif
+ call_prom("getprop", 4, 1, prom_chosen, "bootargs",
+ command_line, sizeof(command_line));
+ }
+ command_line[sizeof(command_line) - 1] = 0;
+
+ check_display();
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later. However, OF may fall over if we do that after
+ * we've taken over the MMU and done set_prom_callback.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static void
+check_display()
+{
+ phandle node;
+ ihandle ih;
+ char type[16], name[64], path[128];
+
+ for (node = 0; prom_next_node(&node); ) {
+ type[0] = 0;
+ getpromprop(node, "device_type", type, sizeof(type));
+ if (strcmp(type, "display") != 0)
+ continue;
+ name[0] = 0;
+ getpromprop(node, "name", name, sizeof(name));
+ if (pmac_display_supported(name))
+ /* we have a supported display */
+ return;
+ }
+ printk(KERN_INFO "No supported display found\n");
+ for (node = 0; prom_next_node(&node); ) {
+ type[0] = 0;
+ getpromprop(node, "device_type", type, sizeof(type));
+ if (strcmp(type, "display") != 0)
+ continue;
+ /* It seems OF doesn't null-terminate the path :-( */
+ memset(path, 0, sizeof(path));
+ if ((int) call_prom("package-to-path", 3, 1,
+ node, path, sizeof(path) - 1) < 0) {
+ printk(KERN_WARNING "can't get path for display %p\n",
+ node);
+ continue;
+ }
+ ih = call_prom("open", 1, 1, path);
+ if (ih == 0 || ih == (ihandle) -1) {
+ printk(KERN_WARNING "couldn't open display %s\n",
+ path);
+ continue;
+ }
+ printk(KERN_INFO "Opened display device %s using "
+ "Open Firmware\n", path);
+ strcpy(prom_display_path, path);
+ break;
+ }
+}
+
+static int
+prom_next_node(phandle *nodep)
+{
+ phandle node;
+
+ if ((node = *nodep) != 0
+ && (*nodep = call_prom("child", 1, 1, node)) != 0)
+ return 1;
+ if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+ return 1;
+ for (;;) {
+ if ((node = call_prom("parent", 1, 1, node)) == 0)
+ return 0;
+ if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+ return 1;
+ }
+}
+
+/*
+ * Callback routine for the PROM to call us.
+ * No services are implemented yet :-)
+ */
+static int
+prom_callback(struct prom_args *argv)
+{
+ printk("uh oh, prom callback '%s' (%d/%d)\n", argv->service,
+ argv->nargs, argv->nret);
+ return -1;
+}
+
+/*
+ * Register a callback with the Open Firmware PROM so it can ask
+ * us to map/unmap memory, etc.
+ */
+void
+set_prom_callback()
+{
+ call_prom("set-callback", 1, 1, prom_callback);
+}
+
+void
+abort()
+{
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ prom_exit();
+}
+
+/*
+ * Make a copy of the device tree from the PROM.
+ */
+
+static struct device_node *allnodes;
+static struct device_node **allnextp;
+
+#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
+
+unsigned long
+copy_device_tree(unsigned long mem_start, unsigned long mem_end)
+{
+ phandle root;
+
+ root = call_prom("peer", 1, 1, (phandle)0);
+ if (root == (phandle)0)
+ panic("couldn't get device tree root\n");
+ allnextp = &allnodes;
+ mem_start = inspect_node(root, 0, 0, mem_start, mem_end);
+ *allnextp = 0;
+ return mem_start;
+}
+
+static unsigned long
+inspect_node(phandle node, struct device_node *dad, unsigned long base_address,
+ unsigned long mem_start, unsigned long mem_end)
+{
+ struct reg_property *reg, *rp;
+ struct pci_reg_property *pci_addrs;
+ int l, i;
+ phandle child;
+ struct device_node *np;
+ struct property *pp, **prev_propp;
+ char *prev_name;
+
+ np = (struct device_node *) mem_start;
+ mem_start += sizeof(struct device_node);
+ memset(np, 0, sizeof(*np));
+ np->node = node;
+ *allnextp = np;
+ allnextp = &np->allnext;
+ np->parent = dad;
+ if (dad != 0) {
+ /* we temporarily use the `next' field as `last_child'. */
+ if (dad->next == 0)
+ dad->child = np;
+ else
+ dad->next->sibling = np;
+ dad->next = np;
+ }
+
+ /* get and store all properties */
+ prev_propp = &np->properties;
+ prev_name = 0;
+ for (;;) {
+ pp = (struct property *) mem_start;
+ pp->name = (char *) (pp + 1);
+ if ((int) call_prom("nextprop", 3, 1, node, prev_name,
+ pp->name) <= 0)
+ break;
+ mem_start = ALIGN((unsigned long)pp->name
+ + strlen(pp->name) + 1);
+ pp->value = (unsigned char *) mem_start;
+ pp->length = (int)
+ call_prom("getprop", 4, 1, node, pp->name, pp->value,
+ mem_end - mem_start);
+ if (pp->length < 0)
+ panic("hey, where did property %s go?", pp->name);
+ mem_start = ALIGN(mem_start + pp->length);
+ prev_name = pp->name;
+ *prev_propp = pp;
+ prev_propp = &pp->next;
+ }
+ *prev_propp = 0;
+
+ np->name = get_property(np, "name", 0);
+ np->type = get_property(np, "device_type", 0);
+
+ /* get all the device addresses and interrupts */
+ reg = (struct reg_property *) mem_start;
+ pci_addrs = (struct pci_reg_property *)
+ get_property(np, "assigned-addresses", &l);
+ i = 0;
+ if (pci_addrs != 0) {
+ while ((l -= sizeof(struct pci_reg_property)) >= 0) {
+ /* XXX assumes PCI addresses mapped 1-1 to physical */
+ reg[i].address = pci_addrs[i].addr.a_lo;
+ reg[i].size = pci_addrs[i].size_lo;
+ ++i;
+ }
+ } else {
+ rp = (struct reg_property *) get_property(np, "reg", &l);
+ if (rp != 0) {
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ reg[i].address = rp[i].address + base_address;
+ reg[i].size = rp[i].size;
+ ++i;
+ }
+ }
+ }
+ if (i > 0) {
+ np->addrs = reg;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct reg_property);
+ }
+
+ np->intrs = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (np->intrs != 0)
+ np->n_intrs = l / sizeof(int);
+
+ /* get the node's full name */
+ l = (int) call_prom("package-to-path", 3, 1, node,
+ (char *) mem_start, mem_end - mem_start);
+ if (l >= 0) {
+ np->full_name = (char *) mem_start;
+ np->full_name[l] = 0;
+ mem_start = ALIGN(mem_start + l + 1);
+ }
+
+ if (np->type != 0 && strcmp(np->type, "dbdma") == 0 && np->n_addrs > 0)
+ base_address = np->addrs[0].address;
+
+ child = call_prom("child", 1, 1, node);
+ while (child != (void *)0) {
+ mem_start = inspect_node(child, np, base_address,
+ mem_start, mem_end);
+ child = call_prom("peer", 1, 1, child);
+ }
+
+ return mem_start;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given name.
+ */
+struct device_node *
+find_devices(const char *name)
+{
+ struct device_node *head, **prevp, *np;
+
+ prevp = &head;
+ for (np = allnodes; np != 0; np = np->allnext) {
+ if (np->name != 0 && strcasecmp(np->name, name) == 0) {
+ *prevp = np;
+ prevp = &np->next;
+ }
+ }
+ *prevp = 0;
+ return head;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given type.
+ */
+struct device_node *
+find_type_devices(const char *type)
+{
+ struct device_node *head, **prevp, *np;
+
+ prevp = &head;
+ for (np = allnodes; np != 0; np = np->allnext) {
+ if (np->type != 0 && strcasecmp(np->type, type) == 0) {
+ *prevp = np;
+ prevp = &np->next;
+ }
+ }
+ *prevp = 0;
+ return head;
+}
+
+/*
+ * Find the device_node with a given full_name.
+ */
+struct device_node *
+find_path_device(const char *path)
+{
+ struct device_node *np;
+
+ for (np = allnodes; np != 0; np = np->allnext)
+ if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
+ return np;
+ return NULL;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+unsigned char *
+get_property(struct device_node *np, const char *name, int *lenp)
+{
+ struct property *pp;
+
+ for (pp = np->properties; pp != 0; pp = pp->next)
+ if (strcmp(pp->name, name) == 0) {
+ if (lenp != 0)
+ *lenp = pp->length;
+ return pp->value;
+ }
+ return 0;
+}
+
+void
+print_properties(struct device_node *np)
+{
+ struct property *pp;
+ char *cp;
+ int i, n;
+
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ printk(KERN_INFO "%s", pp->name);
+ for (i = strlen(pp->name); i < 16; ++i)
+ printk(" ");
+ cp = (char *) pp->value;
+ for (i = pp->length; i > 0; --i, ++cp)
+ if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
+ || (i == 1 && *cp != 0))
+ break;
+ if (i == 0 && pp->length > 1) {
+ /* looks like a string */
+ printk(" %s\n", (char *) pp->value);
+ } else {
+ /* dump it in hex */
+ n = pp->length;
+ if (n > 64)
+ n = 64;
+ if (pp->length % 4 == 0) {
+ unsigned int *p = (unsigned int *) pp->value;
+
+ n /= 4;
+ for (i = 0; i < n; ++i) {
+ if (i != 0 && (i % 4) == 0)
+ printk("\n ");
+ printk(" %08x", *p++);
+ }
+ } else {
+ unsigned char *bp = pp->value;
+
+ for (i = 0; i < n; ++i) {
+ if (i != 0 && (i % 16) == 0)
+ printk("\n ");
+ printk(" %02x", *bp++);
+ }
+ }
+ printk("\n");
+ if (pp->length > 64)
+ printk(" ... (length = %d)\n",
+ pp->length);
+ }
+ }
+}
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (MAP_NR(page) < max_mapnr)
- *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+ if (MAP_NR(page) < max_mapnr) {
+ unsigned long phys_addr = page + (addr & ~PAGE_MASK);
+ *(unsigned long *) phys_addr = data;
+ flush_icache_range(phys_addr, phys_addr+4);
+ }
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
/* this should also re-instate whatever read-only mode there was before */
set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
case PTRACE_PEEKUSR: {
unsigned long tmp;
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+ if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2)) {
ret = -EIO;
goto out;
}
if (addr < PT_FPR0) {
tmp = get_reg(child, addr);
}
-#if 1
- else if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+ else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
if (last_task_used_math == child)
giveup_fpu();
tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
}
-#endif
else
ret = -EIO;
if (!ret)
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+ if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2))
goto out;
addr = addr >> 2; /* temporary hack. */
goto out;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
--- /dev/null
+/*
+ * $Id: setup.c,v 1.12 1997/08/13 03:06:17 cort Exp $
+ * Common prep/pmac boot and setup code.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+
+#include <asm/cuda.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+
+char saved_command_line[256];
+unsigned char aux_device_present;
+
+/* copy of the residual data */
+RESIDUAL res;
+int _machine;
+
+/*
+ * Find out what kind of machine we're on and save any data we need
+ * from the early boot process (devtree is copied on pmac by prom_init() )
+ */
+unsigned long identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ extern unsigned long initrd_start, initrd_end;
+ extern char cmd_line[256];
+#ifdef CONFIG_PMAC /* cheat for now - perhaps a check for OF could tell us */
+ _machine = _MACH_Pmac;
+#endif /* CONFIG_PMAC */
+#ifdef CONFIG_PREP
+ if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
+ _machine = _MACH_IBM;
+ else
+ _machine = _MACH_Motorola;
+#endif /* CONFIG_PREP */
+
+ if ( _machine == _MACH_Pmac )
+ {
+ io_base = 0;
+ }
+ else if ( is_prep ) /* prep */
+ {
+ io_base = 0x80000000;
+ /* make a copy of residual data */
+ if ( r3 )
+ memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(RESIDUAL) );
+ /* take care of initrd if we have one */
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+ /* take care of cmd line */
+ if ( r6 )
+ {
+
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+ }
+ else
+ {
+ printk("Unknown machine type in identify_machine!\n");
+ }
+ return 0;
+}
+
+/* cmd is ignored for now... */
+void machine_restart(char *cmd)
+{
+ struct cuda_request req;
+ unsigned long flags;
+ unsigned long i = 10000;
+
+ if ( _machine == _MACH_Pmac )
+ {
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
+ for (;;)
+ cuda_poll();
+ }
+ else /* prep */
+ {
+ _disable_interrupts();
+
+ /* set exception prefix high - to the prom */
+ save_flags( flags );
+ restore_flags( flags|MSR_IP );
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb( inb(0x92) & ~1L , 0x92 );
+ /* signal a reset to system control port A - soft reset */
+ outb( inb(0x92) | 1 , 0x92 );
+
+ while ( i != 0 ) i++;
+ panic("restart failed\n");
+ }
+
+}
+
+void machine_power_off(void)
+{
+ struct cuda_request req;
+
+ if ( _machine == _MACH_Pmac )
+ {
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
+ for (;;)
+ cuda_poll();
+ }
+ else /* prep */
+ {
+ machine_restart(NULL);
+ }
+}
+
+void machine_halt(void)
+{
+ if ( _machine == _MACH_Pmac )
+ {
+#if 0
+ prom_exit(); /* doesn't work because prom is trashed */
+#else
+ machine_power_off(); /* for now */
+#endif
+ }
+ else /* prep */
+ machine_restart(NULL);
+
+}
+
+
+__initfunc(unsigned long
+bios32_init(unsigned long memory_start, unsigned long memory_end))
+{
+ return memory_start;
+}
+
+/*
+ * Will merge more into here later -- Cort
+ */
+int get_cpuinfo(char *buffer)
+{
+ extern int pmac_get_cpuinfo(char *);
+ extern int prep_get_cpuinfo(char *);
+
+ if ( _machine == _MACH_Pmac )
+ return pmac_get_cpuinfo(buffer);
+#ifdef CONFIG_PREP
+ else /* prep */
+ return prep_get_cpuinfo(buffer);
+#endif /* CONFIG_PREP */
+}
+
+__initfunc(void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+ extern void pmac_setup_arch(char **, unsigned long *, unsigned long *);
+ extern void prep_setup_arch(char **, unsigned long *, unsigned long *);
+
+ if ( _machine == _MACH_Pmac )
+ pmac_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+#ifdef CONFIG_PREP
+ else /* prep */
+ prep_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+#endif /* CONFIG_PREP */
+}
+
+
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
+#include <linux/elf.h>
#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
#define PAUSE_AFTER_SIGNAL
#undef PAUSE_AFTER_SIGNAL
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
/*
}
}
+/*
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack. SE and BE
+ * should not be in this list since gdb may want to change these. I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
+
/*
* This sets regs->esp even though we don't actually use sigstacks yet..
*/
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
- struct sigcontext_struct *sc;
- struct pt_regs *int_regs;
- int signo, ret;
+ struct sigcontext_struct *sc, sigctx;
+ int ret;
+ elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */
-#if 1
- if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
- || (regs->gpr[1] >= KERNELBASE))
+ sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
goto badframe;
-#endif
- sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
- get_user(current->blocked, &sc->oldmask);
- current->blocked &= _BLOCKABLE;
- get_user(int_regs, &sc->regs);
- get_user(signo, &sc->signal);
+ current->blocked = sigctx.oldmask & _BLOCKABLE;
sc++; /* Pop signal 'context' */
#ifdef DEBUG_SIGNALS
-printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+ printk("Sig return - Regs: %p, sc: %p, sig: %d\n", sigctx.regs, sc,
+ sigctx.signal);
#endif
- if (sc == (struct sigcontext_struct *)(int_regs)) {
- /* Last stacked signal */
- memcpy(regs, int_regs, sizeof(*regs));
+ if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
+ /* Last stacked signal - restore registers */
+ if (last_task_used_math == current)
+ giveup_fpu();
+ if (copy_from_user(saved_regs, sigctx.regs, sizeof(saved_regs)))
+ goto badframe;
+ saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+ | (saved_regs[PT_MSR] & MSR_USERCHANGE);
+ memcpy(regs, saved_regs,
+ MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)));
+
+ if (copy_from_user(current->tss.fpr,
+ (unsigned long *)sigctx.regs + ELF_NGREG,
+ ELF_NFPREG * sizeof(double)))
+ goto badframe;
+
if (regs->trap == 0x0C00 /* System Call! */ &&
((int)regs->result == -ERESTARTNOHAND ||
(int)regs->result == -ERESTARTSYS ||
regs->result = 0;
}
ret = regs->result;
+
} else {
/* More signals to go */
- regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
- get_user(regs->gpr[3], &sc->signal);
- get_user(int_regs, (struct pt_regs **) &sc->regs);
- regs->gpr[4] = (unsigned long) int_regs;
- regs->link = (unsigned long) (int_regs+1);
- get_user(regs->nip, &sc->handler);
- ret = regs->gpr[3];
+ regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
+ if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+ goto badframe;
+ regs->gpr[3] = ret = sigctx.signal;
+ regs->gpr[4] = (unsigned long) sigctx.regs;
+ regs->link = regs->gpr[4] + ELF_NGREG * sizeof(unsigned long)
+ + ELF_NFPREG * sizeof(double);
+ regs->nip = sigctx.handler;
}
return ret;
unsigned long *frame = NULL;
unsigned long *trampoline;
unsigned long *regs_ptr;
+ double *fpregs_ptr;
unsigned long nip = 0;
unsigned long signr;
struct sigcontext_struct *sc;
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
nip = regs->nip;
frame = (unsigned long *) regs->gpr[1];
- /* Build trampoline code on stack */
- frame -= 2;
+ /*
+ * Build trampoline code on stack, and save gp and fp regs.
+ * The 56 word hole is because programs using the rs6000/xcoff
+ * style calling sequence can save up to 19 gp regs and 18 fp regs
+ * on the stack before decrementing sp.
+ */
+ frame -= 2 + 56;
trampoline = frame;
- /* verify stack is valid for writing regs struct */
- if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
- || ((unsigned long) frame >= KERNELBASE ))
- goto badframe;
- put_user(0x38007777UL, trampoline); /* li r0,0x7777 */
- put_user(0x44000002UL, trampoline+1); /* sc */
- frame -= sizeof(*regs) / sizeof(long);
+ frame -= ELF_NFPREG * sizeof(double) / sizeof(unsigned long);
+ fpregs_ptr = (double *) frame;
+ frame -= ELF_NGREG;
regs_ptr = frame;
- copy_to_user(regs_ptr, regs, sizeof(*regs));
+ /* verify stack is valid for writing to */
+ if (verify_area(VERIFY_WRITE, frame,
+ (ELF_NGREG + 2) * sizeof(long)
+ + ELF_NFPREG * sizeof(double)))
+ goto badframe;
+ if (last_task_used_math == current)
+ giveup_fpu();
+ if (__copy_to_user(regs_ptr, regs,
+ MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)))
+ || __copy_to_user(fpregs_ptr, current->tss.fpr,
+ ELF_NFPREG * sizeof(double))
+ || __put_user(0x38007777UL, trampoline) /* li r0,0x7777 */
+ || __put_user(0x44000002UL, trampoline+1)) /* sc */
+ goto badframe;
+
signr = 1;
sa = current->sig->action;
continue;
frame -= sizeof(struct sigcontext_struct) / sizeof(long);
- if (verify_area(VERIFY_WRITE,(void *)frame,
- sizeof(struct sigcontext_struct)/sizeof(long)))
+ if (verify_area(VERIFY_WRITE, frame,
+ sizeof(struct sigcontext_struct)))
goto badframe;
sc = (struct sigcontext_struct *)frame;
nip = (unsigned long) sa->sa_handler;
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
- put_user(nip, &sc->handler);
- put_user(oldmask, &sc->oldmask); /* was current->blocked */
- put_user(regs_ptr, &sc->regs);
- put_user(signr, &sc->signal);
+ if (__put_user(nip, &sc->handler)
+ || __put_user(oldmask, &sc->oldmask)
+ || __put_user(regs_ptr, &sc->regs)
+ || __put_user(signr, &sc->signal))
+ goto badframe;
current->blocked |= sa->sa_mask;
regs->gpr[3] = signr;
- regs->gpr[4] = (unsigned long)regs_ptr;
+ regs->gpr[4] = (unsigned long) regs_ptr;
}
+
+ frame -= __SIGNAL_FRAMESIZE / sizeof(unsigned long);
+ if (put_user(regs->gpr[1], frame))
+ goto badframe;
regs->link = (unsigned long)trampoline;
regs->nip = nip;
- regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+ regs->gpr[1] = (unsigned long) frame;
/* The DATA cache must be flushed here to insure coherency */
/* between the DATA & INSTRUCTION caches. Since we just */
/* cache for new data, we have to force the data to go on to */
/* memory and flush the instruction cache to force it to look */
/* there. The following function performs this magic */
- store_cache_range((unsigned long) trampoline,
- (unsigned long) (trampoline + 2));
+ flush_icache_range((unsigned long) trampoline,
+ (unsigned long) (trampoline + 2));
return 1;
badframe:
+++ /dev/null
-#include <linux/ctype.h>
-
-int strcasecmp(const char *s1, const char *s2)
-{
- int c1, c2;
-
- do {
- c1 = tolower(*s1++);
- c2 = tolower(*s2++);
- } while (c1 == c2 && c1 != 0);
- return c1 - c2;
-}
/*
* linux/arch/ppc/kernel/sys_ppc.c
*
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/sys_i386.c"
* Adapted from the i386 version by Gary Thomas
* Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au).
*
* This file contains various random system calls that
* have a non-standard calling sequence on the Linux/PPC
* platform.
+ *
+ * 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/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/mman.h>
+#include <linux/sys.h>
#include <linux/ipc.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
-
void
check_bugs(void)
{
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
{
- printk("sys_ioperm()\n");
+ printk(KERN_ERR "sys_ioperm()\n");
return -EIO;
}
int sys_iopl(int a1, int a2, int a3, int a4)
{
lock_kernel();
- printk( "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+ printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return (ENOSYS);
+ return (-ENOSYS);
}
int sys_vm86(int a1, int a2, int a3, int a4)
{
lock_kernel();
- printk( "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+ printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return (ENOSYS);
+ return (-ENOSYS);
}
int sys_modify_ldt(int a1, int a2, int a3, int a4)
{
lock_kernel();
- printk( "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+ printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return (ENOSYS);
+ return (-ENOSYS);
}
/*
*
* This is really horribly ugly.
*/
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+asmlinkage int
+sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
{
int version, ret;
version = call >> 16; /* hack for backward compatibility */
call &= 0xffff;
- if (call <= SEMCTL)
- switch (call) {
- case SEMOP:
- ret = sys_semop (first, (struct sembuf *)ptr, second);
- goto out;
- case SEMGET:
- ret = sys_semget (first, second, third);
- goto out;
- case SEMCTL: {
- union semun fourth;
- ret = -EINVAL;
- if (!ptr)
- goto out;
- ret = -EFAULT;
- if (get_user(fourth.__pad, (void **) ptr))
- goto out;
- ret = sys_semctl (first, second, third, fourth);
- goto out;
- }
- default:
- ret = -EINVAL;
- goto out;
+ ret = -EINVAL;
+ switch (call) {
+ case SEMOP:
+ ret = sys_semop (first, (struct sembuf *)ptr, second);
+ break;
+ case SEMGET:
+ ret = sys_semget (first, second, third);
+ break;
+ case SEMCTL: {
+ union semun fourth;
+
+ if (!ptr)
+ break;
+ if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
+ || (ret = get_user(fourth.__pad, (void **)ptr)))
+ break;
+ ret = sys_semctl (first, second, third, fourth);
+ break;
}
- if (call <= MSGCTL)
- switch (call) {
- case MSGSND:
- ret = sys_msgsnd (first, (struct msgbuf *) ptr,
- second, third);
- goto out;
- case MSGRCV:
- switch (version) {
- case 0: {
- struct ipc_kludge tmp;
- ret = -EINVAL;
- if (!ptr)
- goto out;
- ret = -EFAULT;
- if (copy_from_user(&tmp,(struct ipc_kludge *) ptr,
- sizeof (tmp)))
- goto out;
- ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
- goto out;
- }
- case 1: default:
- ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
- goto out;
+ case MSGSND:
+ ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third);
+ break;
+ case MSGRCV:
+ switch (version) {
+ case 0: {
+ struct ipc_kludge tmp;
+
+ if (!ptr)
+ break;
+ if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
+ || (ret = copy_from_user(&tmp,
+ (struct ipc_kludge *) ptr,
+ sizeof (tmp))))
+ break;
+ ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
+ third);
+ break;
}
- case MSGGET:
- ret = sys_msgget ((key_t) first, second);
- goto out;
- case MSGCTL:
- ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
- goto out;
default:
- ret = -EINVAL;
- goto out;
+ ret = sys_msgrcv (first, (struct msgbuf *) ptr,
+ second, fifth, third);
+ break;
}
- if (call <= SHMCTL)
- switch (call) {
- case SHMAT:
- switch (version) {
- case 0: default: {
- ulong raddr;
- ret = sys_shmat (first, (char *) ptr, second, &raddr);
- if (ret)
- goto out;
- ret = put_user (raddr, (ulong *) third);
- goto out;
+ break;
+ case MSGGET:
+ ret = sys_msgget ((key_t) first, second);
+ break;
+ case MSGCTL:
+ ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+ break;
+ case SHMAT:
+ switch (version) {
+ default: {
+ ulong raddr;
+
+ if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
+ sizeof(ulong))))
+ break;
+ ret = sys_shmat (first, (char *) ptr, second, &raddr);
+ if (ret)
+ break;
+ ret = put_user (raddr, (ulong *) third);
+ break;
}
- case 1: /* iBCS2 emulator entry point */
- ret = -EINVAL;
- if (get_fs() != get_ds())
- goto out;
- ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
- goto out;
- }
- case SHMDT:
- ret = sys_shmdt ((char *)ptr);
- goto out;
- case SHMGET:
- ret = sys_shmget (first, second, third);
- goto out;
- case SHMCTL:
- ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
- goto out;
- default:
- ret = -EINVAL;
- goto out;
+ case 1: /* iBCS2 emulator entry point */
+ if (get_fs() != get_ds())
+ break;
+ ret = sys_shmat (first, (char *) ptr, second,
+ (ulong *) third);
+ break;
}
- else
- ret = -EINVAL;
-out:
- unlock_kernel();
- return ret;
-}
-
+ break;
+ case SHMDT:
+ ret = sys_shmdt ((char *)ptr);
+ break;
+ case SHMGET:
+ ret = sys_shmget (first, second, third);
+ break;
+ case SHMCTL:
+ ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+ break;
+ }
-#ifndef CONFIG_MODULES
-void
-scsi_register_module(void)
-{
- lock_kernel();
- panic("scsi_register_module");
- unlock_kernel();
-}
-
-void
-scsi_unregister_module(void)
-{
- lock_kernel();
- panic("scsi_unregister_module");
unlock_kernel();
+ return ret;
}
-#endif
/*
* sys_pipe() is the normal C calling standard for creating
* a pipe. It's not the way unix traditionally does this, though.
*/
-asmlinkage int sys_pipe(unsigned long * fildes)
+asmlinkage int sys_pipe(int *fildes)
{
int fd[2];
int error;
- error = verify_area(VERIFY_WRITE,fildes,8);
+ error = verify_area(VERIFY_WRITE, fildes, 8);
if (error)
return error;
+ lock_kernel();
error = do_pipe(fd);
+ unlock_kernel();
if (error)
return error;
- put_user(fd[0],0+fildes);
- put_user(fd[1],1+fildes);
+ if (__put_user(fd[0],0+fildes)
+ || __put_user(fd[1],1+fildes))
+ return -EFAULT; /* should we close the fds? */
return 0;
}
unsigned long fd, off_t offset)
{
struct file * file = NULL;
+ int ret = -EBADF;
+
+ lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- return -EBADF;
+ goto out;
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
- return do_mmap(file, addr, len, prot, flags, offset);
+ ret = do_mmap(file, addr, len, prot, flags, offset);
+out:
+ unlock_kernel();
+ return ret;
}
extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
asmlinkage int
ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{
- int err;
if ( (unsigned long)n >= 4096 )
{
unsigned long *buffer = (unsigned long *)n;
- if ( get_user(n, buffer) ||
- get_user(inp,buffer+1) ||
- get_user(outp,buffer+2) ||
- get_user(exp,buffer+3) ||
- get_user(tvp,buffer+4) )
+ if (verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long))
+ || __get_user(n, buffer)
+ || __get_user(inp, ((fd_set **)(buffer+1)))
+ || __get_user(outp, ((fd_set **)(buffer+2)))
+ || __get_user(exp, ((fd_set **)(buffer+3)))
+ || __get_user(tvp, ((struct timeval **)(buffer+4))))
return -EFAULT;
}
return sys_select(n, inp, outp, exp, tvp);
--- /dev/null
+/*
+ * $Id: time.c,v 1.8 1997/08/11 08:37:51 cort Exp $
+ * Common time routines among all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+#include <linux/config.h>
+#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/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/time.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+
+#include "time.h"
+
+/* this is set to the appropriate pmac/prep func in init_IRQ() */
+int (*set_rtc_time)(unsigned long);
+
+/* keep track of when we need to update the rtc */
+unsigned long last_rtc_update = 0;
+
+/* The decrementer counts down by 128 every 128ns on a 601. */
+#define DECREMENTER_COUNT_601 (1000000000 / HZ)
+#define COUNT_PERIOD_NUM_601 1
+#define COUNT_PERIOD_DEN_601 1000
+
+unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
+unsigned count_period_num; /* 1 decrementer count equals */
+unsigned count_period_den; /* count_period_num / count_period_den us */
+
+/* Accessor functions for the decrementer register. */
+inline unsigned long
+get_dec(void)
+{
+ int ret;
+
+ asm volatile("mfspr %0,22" : "=r" (ret) :);
+ return ret;
+}
+
+inline void
+set_dec(int val)
+{
+ asm volatile("mtspr 22,%0" : : "r" (val));
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * We set it up to overflow again in 1/HZ seconds.
+ */
+void timer_interrupt(struct pt_regs * regs)
+{
+ int dval, d;
+ while ((dval = get_dec()) < 0) {
+ /*
+ * Wait for the decrementer to change, then jump
+ * in and add decrementer_count to its value
+ * (quickly, before it changes again!)
+ */
+ while ((d = get_dec()) == dval)
+ ;
+ set_dec(d + decrementer_count);
+ do_timer(regs);
+ /*
+ * update the rtc when needed
+ */
+ if ( xtime.tv_sec > last_rtc_update + 660 )
+ if (set_rtc_time(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
+}
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ *tv = xtime;
+ tv->tv_usec += (decrementer_count - get_dec())
+ * count_period_num / count_period_den;
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ int frac_tick;
+
+ last_rtc_update = 0; /* so the rtc gets updated soon */
+
+ frac_tick = tv->tv_usec % (1000000 / HZ);
+ save_flags(flags);
+ cli();
+ xtime.tv_sec = tv->tv_sec;
+ xtime.tv_usec = tv->tv_usec - frac_tick;
+ set_dec(frac_tick * count_period_den / count_period_num);
+ restore_flags(flags);
+}
+
+
+void
+time_init(void)
+{
+#ifdef CONFIG_PREP
+ /* pmac hasn't yet called via_cuda_init() */
+ if ( _machine != _MACH_Pmac ) /* prep */
+ {
+ xtime.tv_sec = prep_get_rtc_time();
+ xtime.tv_usec = 0;
+ /*
+ * mark the rtc/on-chip timer as in sync
+ * so we don't update right away
+ */
+ last_rtc_update = xtime.tv_sec;
+ }
+#endif /* CONFIG_PREP */
+ if ((_get_PVR() >> 16) == 1) {
+ /* 601 processor: dec counts down by 128 every 128ns */
+ decrementer_count = DECREMENTER_COUNT_601;
+ count_period_num = COUNT_PERIOD_NUM_601;
+ count_period_den = COUNT_PERIOD_DEN_601;
+ } else {
+ /*
+ * These should setup decrementer_count
+ */
+ if ( _machine == _MACH_Pmac )
+ pmac_calibrate_decr();
+#ifdef CONFIG_PREP
+ else /* PReP */
+ prep_calibrate_decr();
+#endif /* CONFIG_PREP */
+ }
+
+ if ( _machine == _MACH_Pmac )
+ set_rtc_time = pmac_set_rtc_time;
+#ifdef CONFIG_PREP
+ else /* prep */
+ set_rtc_time = prep_set_rtc_time;
+#endif /* CONFIG_PREP */
+
+ set_dec(decrementer_count);
+}
+
+#ifdef CONFIG_PREP
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems. On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+int calibrate_done = 0;
+volatile int *done_ptr = &calibrate_done;
+void prep_calibrate_decr(void)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+ /* set timer to periodic mode */
+ outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+ /* set the clock to ~100 Hz */
+ outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
+ outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
+
+ if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+ __sti();
+ while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
+ restore_flags(flags);
+ free_irq( 0, NULL);
+}
+
+void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
+{
+ int freq, divisor;
+ static unsigned long t1 = 0, t2 = 0;
+
+ if ( !t1 )
+ t1 = get_dec();
+ else if (!t2)
+ {
+ t2 = get_dec();
+ t2 = t1-t2; /* decr's in 1/HZ */
+ t2 = t2*HZ; /* # decrs in 1s - thus in Hz */
+ freq = t2 * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d (%luMHz)\n",
+ freq, divisor,t2>>20);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+ *done_ptr = 1;
+ }
+}
+#endif /* CONFIG_PREP */
--- /dev/null
+/*
+ * $Id: time.h,v 1.3 1997/08/12 08:22:14 cort Exp $
+ * Common time prototypes and such for all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+/* time.c */
+__inline__ unsigned long get_dec(void);
+__inline__ void set_dec(int val);
+void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
+void prep_calibrate_decr(void);
+void pmac_calibrate_decr(void);
+extern unsigned decrementer_count;
+extern unsigned count_period_num;
+extern unsigned count_period_den;
+
+/* pmac/prep_time.c */
+unsigned long prep_get_rtc_time(void);
+unsigned long pmac_get_rtc_time(void);
+int prep_set_rtc_time(unsigned long nowtime);
+int pmac_set_rtc_time(unsigned long nowtime);
+void pmac_read_rtc_time(void);
+
/*
* linux/arch/ppc/kernel/traps.c
*
- * Copyright (C) 1995 Gary Thomas
- * Adapted for PowerPC by Gary Thomas
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * 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.
+ *
* Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
*/
/*
#include <linux/config.h>
#include <asm/pgtable.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/processor.h>
+
+extern int fix_alignment(struct pt_regs *);
+extern void bad_page_fault(struct pt_regs *, unsigned long);
+
+#ifdef CONFIG_XMON
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern void xmon(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#endif
/*
* Trap & Exception support
if (!user_mode(regs))
{
show_regs(regs);
- print_backtrace(regs->gpr[1]);
- panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
}
force_sig(signr, current);
}
+void
MachineCheckException(struct pt_regs *regs)
{
if ( !user_mode(regs) )
{
+#ifdef CONFIG_XMON
+ if (xmon_fault_handler) {
+ xmon_fault_handler(regs);
+ return;
+ }
+#endif
printk("Machine check in kernel mode.\n");
printk("Caused by (from msr): ");
- printk("regs %08x ",regs);
+ printk("regs %p ",regs);
switch( regs->msr & 0x0000F000)
{
case (1<<12) :
printk("Machine check signal - probably due to mm fault\n"
"with mmu off\n");
- break;
+ break;
case (1<<13) :
printk("Transfer error ack signal\n");
- break;
+ break;
case (1<<14) :
printk("Data parity signal\n");
- break;
+ break;
case (1<<15) :
printk("Address parity signal\n");
- break;
+ break;
default:
printk("Unknown values in msr\n");
}
show_regs(regs);
- print_backtrace(regs->gpr[1]);
- panic("");
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ panic("machine check");
}
_exception(SIGSEGV, regs);
}
_exception(SIGTRAP, regs);
}
+void
ProgramCheckException(struct pt_regs *regs)
{
- if (current->flags & PF_PTRACED)
+ if (regs->msr & 0x100000) {
+ /* IEEE FP exception */
+ _exception(SIGFPE, regs);
+ } else if (regs->msr & 0x20000) {
+ /* trap exception */
+#ifdef CONFIG_XMON
+ if (xmon_bpt(regs))
+ return;
+#endif
_exception(SIGTRAP, regs);
- else
+ } else {
_exception(SIGILL, regs);
+ }
}
+void
SingleStepException(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
+#ifdef CONFIG_XMON
+ if (xmon_sstep(regs))
+ return;
+#endif
_exception(SIGTRAP, regs);
}
+void
AlignmentException(struct pt_regs *regs)
{
+ int fixed;
+
+ if (last_task_used_math == current)
+ giveup_fpu();
+ fixed = fix_alignment(regs);
+ if (fixed == 1) {
+ regs->nip += 4; /* skip over emulated instruction */
+ return;
+ }
+ if (fixed == -EFAULT) {
+ /* fixed == -EFAULT means the operand address was bad */
+ bad_page_fault(regs, regs->dar);
+ return;
+ }
_exception(SIGBUS, regs);
}
+void
+PromException(struct pt_regs *regs, int trap)
+{
+ regs->trap = trap;
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ printk("Exception %lx in prom at PC: %lx, SR: %lx\n",
+ regs->trap, regs->nip, regs->msr);
+ /* probably should turn up the toes here */
+}
+
+void
trace_syscall(struct pt_regs *regs)
{
- static int count;
- printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+ printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld\n",
current, current->pid, regs->nip, regs->link, regs->gpr[0],
regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
- if (++count == 20)
- {
- count = 0;
- }
}
+++ /dev/null
-OUTPUT_ARCH(powerpc)
-SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
-/* Do we need any of these for elf?
- __DYNAMIC = 0; */
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .rel.text : { *(.rel.text) }
- .rela.text : { *(.rela.text) }
- .rel.data : { *(.rel.data) }
- .rela.data : { *(.rela.data) }
- .rel.rodata : { *(.rel.rodata) }
- .rela.rodata : { *(.rela.rodata) }
- .rel.got : { *(.rel.got) }
- .rela.got : { *(.rela.got) }
- .rel.ctors : { *(.rel.ctors) }
- .rela.ctors : { *(.rela.ctors) }
- .rel.dtors : { *(.rel.dtors) }
- .rela.dtors : { *(.rela.dtors) }
- .rel.bss : { *(.rel.bss) }
- .rela.bss : { *(.rela.bss) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init : { *(.init) } =0
- .plt : { *(.plt) }
- .text :
- {
- *(.text)
- *(.fixup)
- *(.got1)
- }
- _etext = .;
- PROVIDE (etext = .);
- .rodata :
- {
- *(.rodata)
- *(.rodata1)
- }
- .fini : { *(.fini) } =0
- .ctors : { *(.ctors) }
- .dtors : { *(.dtors) }
- /* Read-write section, merged into data segment: */
- . = (. + 0x0FFF) & 0xFFFFF000;
- .data :
- {
- *(.data)
- *(.data1)
- *(.sdata)
- *(.sdata2)
- *(.got.plt) *(.got)
- *(.dynamic)
- CONSTRUCTORS
- }
- _edata = .;
-/*
- . = ALIGN(4096);
- __init_begin = .;
- .text.init : { *(.text.init) }
- .data.init : { *(.data.init) }
- . = ALIGN(4096);
- __init_end = .;
-*/
- __bss_start = .; /* BSS */
- PROVIDE (edata = .);
- __bss_start = .;
- .bss :
- {
- *(.sbss) *(.scommon)
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
- _end = . ;
- PROVIDE (end = .);
-}
-
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.S.s:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
-.S.o:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
- $(AS) $(ASFLAGS) -o $*.o $*.s
- rm $*.s
-
-HOST_CC = gcc
-
-L_TARGET = lib.o
-L_OBJS = checksum.o cksum_support.o string.o
-
-${L_TARGET}: $(L_OBJS)
- $(LD) -r -o ${L_TARGET} $(L_OBJS)
-
-
-fastdep:
- $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
- $(CPP) -M *.S *.c > .depend
+#
+# Makefile for ppc-specific library files..
+#
-modules:
+.S.o:
+ $(CC) -D__ASSEMBLY__ -c $< -o $*.o
-dummy:
+O_TARGET = lib.o
+O_OBJS = checksum.o string.o strcase.o
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * This file contains assembly-language implementations
+ * of IP-style 1's complement checksum routines.
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * 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.
+ *
+ * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+#include <linux/sys.h>
+#include <asm/errno.h>
+#include "../kernel/ppc_asm.tmpl"
+
+_TEXT()
+
+/*
+ * ip_fast_csum(buf, len) -- Optimized for IP header
+ * len is in words and is always >= 5.
+ */
+_GLOBAL(ip_fast_csum)
+ lwz r0,0(r3)
+ lwzu r5,4(r3)
+ addi r4,r4,-2
+ addc r0,r0,r5
+ mtctr r4
+1: lwzu r4,4(r3)
+ adde r0,r0,r4
+ bdnz 1b
+ addze r0,r0 /* add in final carry */
+ rlwinm r3,r0,16,0,31 /* fold two halves together */
+ add r3,r0,r3
+ not r3,r3
+ srwi r3,r3,16
+ blr
+
+/*
+ * Compute checksum of TCP or UDP pseudo-header:
+ * csum_tcpudp_magic(saddr, daddr, len, proto, sum)
+ */
+_GLOBAL(csum_tcpudp_magic)
+ rlwimi r5,r6,16,0,15 /* put proto in upper half of len */
+ addc r0,r3,r4 /* add 4 32-bit words together */
+ adde r0,r0,r5
+ adde r0,r0,r7
+ addze r0,r0 /* add in final carry */
+ rlwinm r3,r0,16,0,31 /* fold two halves together */
+ add r3,r0,r3
+ not r3,r3
+ srwi r3,r3,16
+ blr
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * csum_partial(buff, len, sum)
+ */
+_GLOBAL(csum_partial)
+ addic r0,r5,0
+ subi r3,r3,4
+ srwi. r6,r4,2
+ beq 3f /* if we're doing < 4 bytes */
+ andi. r5,r3,2 /* Align buffer to longword boundary */
+ beq+ 1f
+ lhz r5,4(r3) /* do 2 bytes to get aligned */
+ addi r3,r3,2
+ subi r4,r4,2
+ addc r0,r0,r5
+ srwi. r6,r4,2 /* # words to do */
+ beq 3f
+1: mtctr r6
+2: lwzu r5,4(r3) /* the bdnz has zero overhead, so it should */
+ adde r0,r0,r5 /* be unnecessary to unroll this loop */
+ bdnz 2b
+ andi. r4,r4,3
+3: cmpi 0,r4,2
+ blt+ 4f
+ lhz r5,4(r3)
+ addi r3,r3,2
+ subi r4,r4,2
+ adde r0,r0,r5
+4: cmpi 0,r4,1
+ bne+ 5f
+ lbz r5,4(r3)
+ slwi r5,r5,8 /* Upper byte of word */
+ adde r0,r0,r5
+5: addze r3,r0 /* add in final carry */
+ blr
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively, and (for an error on
+ * src) zeroes the rest of dst.
+ *
+ * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
+ */
+_GLOBAL(csum_partial_copy_generic)
+ addic r0,r6,0
+ subi r3,r3,4
+ subi r4,r4,4
+ srwi. r6,r5,2
+ beq 3f /* if we're doing < 4 bytes */
+ andi. r9,r4,2 /* Align dst to longword boundary */
+ beq+ 1f
+81: lhz r6,4(r3) /* do 2 bytes to get aligned */
+ addi r3,r3,2
+ subi r5,r5,2
+91: sth r6,4(r4)
+ addi r4,r4,2
+ addc r0,r0,r6
+ srwi. r6,r5,2 /* # words to do */
+ beq 3f
+1: mtctr r6
+82: lwzu r6,4(r3) /* the bdnz has zero overhead, so it should */
+92: stwu r6,4(r4) /* be unnecessary to unroll this loop */
+ adde r0,r0,r6
+ bdnz 82b
+ andi. r5,r5,3
+3: cmpi 0,r5,2
+ blt+ 4f
+83: lhz r6,4(r3)
+ addi r3,r3,2
+ subi r5,r5,2
+93: sth r6,4(r4)
+ addi r4,r4,2
+ adde r0,r0,r6
+4: cmpi 0,r5,1
+ bne+ 5f
+84: lbz r6,4(r3)
+94: stb r6,4(r4)
+ slwi r6,r6,8 /* Upper byte of word */
+ adde r0,r0,r6
+5: addze r3,r0 /* add in final carry */
+ blr
+
+.section .fixup,"ax"
+
+src_error_1:
+ li r6,0
+ subi r5,r5,2
+95: sth r6,4(r4)
+ addi r4,r4,2
+ srwi. r6,r5,2
+ beq 3f
+ mtctr r6
+src_error_2:
+ li r6,0
+96: stwu r6,4(r4)
+ bdnz 96b
+3: andi. r5,r5,3
+ beq src_error
+src_error_3:
+ li r6,0
+ mtctr r5
+ addi r4,r4,3
+97: stbu r6,1(r4)
+ bdnz 97b
+src_error:
+ cmpi 0,r7,0
+ beq 1f
+ li r6,-EFAULT
+ stw r6,0(r7)
+1: addze r3,r0
+ blr
+
+dst_error:
+ cmpi 0,r8,0
+ beq 1f
+ li r6,-EFAULT
+ stw r6,0(r8)
+1: addze r3,r0
+ blr
+
+.section __ex_table,"a"
+ .long 81b,src_error_1
+ .long 91b,dst_error
+ .long 82b,src_error_2
+ .long 92b,dst_error
+ .long 83b,src_error_3
+ .long 93b,dst_error
+ .long 84b,src_error_3
+ .long 94b,dst_error
+ .long 95b,dst_error
+ .long 96b,dst_error
+ .long 97b,dst_error
+++ /dev/null
-/*
- * 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.
- *
- * IP/TCP/UDP checksumming routines
- *
- * Authors: Jorge Cwik, <jorge@laser.satlink.net>
- * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- * Tom May, <ftom@netcom.com>
- * Lots of code moved from tcp.c and ip.c; see those files
- * for more names.
- *
- * Adapted for PowerPC by Gary Thomas <gdt@mc.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 <net/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
- */
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
-{
- unsigned long result = ~_csum_partial(buff, len, sum);
-#if 0
-printk("Csum partial(%x, %d, %x) = %x\n", buff, len, sum, result);
-dump_buf(buff, len);
-#endif
- return result;
-}
-
-/*
- * 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 boundary
- */
-
-unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum)
-{
- /*
- * The whole idea is to do the copy and the checksum at
- * the same time, but we do it the easy way now.
- *
- * At least csum on the source, not destination, for cache
- * reasons..
- */
- sum = csum_partial(src, len, sum);
- memcpy(dst, src, len);
- return sum;
-}
-
-extern unsigned short _ip_fast_csum(unsigned char *buf);
-
-unsigned short
-ip_fast_csum(unsigned char *buf, unsigned int len)
-{
- unsigned short _val;
- _val = _ip_fast_csum(buf);
-#if 0
- printk("IP CKSUM(%x, %d) = %x\n", buf, len, _val);
- dump_buf(buf, len*4);
-#endif
- return (_val);
-}
-
-extern unsigned short _ip_compute_csum(unsigned char *buf, int len);
-
-unsigned short
-ip_compute_csum(unsigned char *buf, int len)
-{
- unsigned short _val;
- _val = _ip_compute_csum(buf, len);
-#if 0
- printk("Compute IP CKSUM(%x, %d) = %x\n", buf, len, _val);
- dump_buf(buf, len);
-#endif
- return (_val);
-}
-
-unsigned short
-_udp_check(unsigned char *buf, int len, int saddr, int daddr, int hdr);
-
-unsigned short
-udp_check(unsigned char *buf, int len, int saddr, int daddr)
-{
- unsigned short _val;
- int hdr;
- hdr = (len << 16) + IPPROTO_UDP;
- _val = _udp_check(buf, len, saddr, daddr, hdr);
-#if 0
- printk("UDP CSUM(%x,%d,%x,%x) = %x\n", buf, len, saddr, daddr, _val);
- dump_buf(buf, len);
-#endif
- return (_val);
-}
-
-unsigned short
-_tcp_check(unsigned char *buf, int len, int saddr, int daddr, int hdr);
-
-unsigned short
-csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, unsigned short proto, unsigned int sum)
-{
- unsigned short _val;
- _val = _csum_tcpudp_magic(saddr, daddr, sum, (len<<16)+proto);
-#if 0
- printk("TCP Magic(%x, %x, %x, %x) = %x\n", saddr, daddr, (len<<16)+proto, sum, _val);
-#endif
- return (_val);
-}
-
-/*
- * Fold a partial checksum without adding pseudo headers
- */
-
-unsigned int csum_fold(unsigned int sum)
-{
- sum = (sum & 0xffff) + (sum >> 16);
- sum = (sum & 0xffff) + (sum >> 16);
- return ~sum;
-}
-
+++ /dev/null
-/*
- * This module contains the PowerPC interrupt fielders
- * set of code at specific locations, based on function
- */
-
-#include <linux/sys.h>
-#include "../kernel/ppc_asm.tmpl"
-
-_TEXT()
-
-/*
- * Compute IP checksums
- * _ip_fast_csum(buf, len) -- Optimized for IP header
- * _ip_compute_csum(buf, len)
- */
-
-_GLOBAL(_ip_fast_csum)
- li r0,0
- addic r0,r0,0 /* Clear initial carry */
- lwz r4,0(r3)
- lwz r5,4(r3)
- adde r0,r0,r4
- lwz r4,8(r3)
- adde r0,r0,r5
- lwz r5,12(r3)
- adde r0,r0,r4
- lwz r4,16(r3)
- adde r0,r0,r5
- adde r0,r0,r4
- mr r3,r0
- andi. r3,r3,0xFFFF
- srwi r0,r0,16
- adde r3,r3,r0
- andis. r0,r3,1
- beq 10f
- addi r3,r3,1
-10: not r3,r3
- andi. r3,r3,0xFFFF
- blr
-
-_GLOBAL(_ip_compute_csum)
- li r0,0
- addic r0,r0,0
-finish_ip_csum:
- subi r3,r3,4
- andi. r5,r3,2 /* Align buffer to longword boundary */
- beq 10f
- lhz r5,4(r3)
- adde r0,r0,r5
- addi r3,r3,2
- subi r4,r4,2
-10: cmpi 0,r4,16 /* unrolled loop - 16 bytes at a time */
- blt 20f
- lwz r5,4(r3)
- lwz r6,8(r3)
- adde r0,r0,r5
- lwz r5,12(r3)
- adde r0,r0,r6
- lwzu r6,16(r3)
- adde r0,r0,r5
- adde r0,r0,r6
- subi r4,r4,16
- b 10b
-20: cmpi 0,r4,4
- blt 30f
- lwzu r5,4(r3)
- adde r0,r0,r5
- subi r4,r4,4
- b 20b
-30: cmpi 0,r4,2
- blt 40f
- lhz r5,4(r3)
- addi r3,r3,2
- adde r0,r0,r5
- subi r4,r4,2
-40: cmpi 0,r4,1
- bne 50f
- lbz r5,4(r3)
- slwi r5,r5,8 /* Upper byte of word */
- adde r0,r0,r5
-50: mr r3,r0
- andi. r3,r3,0xFFFF
- srwi r0,r0,16
- adde r3,r3,r0
- andis. r0,r3,1
- beq 60f
- addi r3,r3,1
-60: not r3,r3
- andi. r3,r3,0xFFFF
- blr
-
-_GLOBAL(_udp_check)
- addc r0,r5,r6 /* Add in header fields */
- adde r0,r0,r7
- b finish_ip_csum
-
-_GLOBAL(_tcp_check)
- addc r0,r5,r6 /* Add in header fields */
- adde r0,r0,r7
- b finish_ip_csum
-
-_GLOBAL(_csum_partial)
- li r0,0
- addc r0,r5,r0
- b finish_ip_csum
-
-/*
- * Compute 16 bit sum:
- * _csum_tcpudp_magic(int saddr, int daddr, int sum, int proto)
- */
-_GLOBAL(_csum_tcpudp_magic)
- addc r0,r3,r4
- adde r0,r0,r5
- adde r0,r0,r6
- mr r3,r0
- andi. r3,r3,0xFFFF
- srwi r0,r0,16
- adde r3,r3,r0
- andis. r0,r3,1 /* Carry out of 16 bits? */
- beq 10f
- addi r3,r3,1
-10: not r3,r3
- andi. r3,r3,0xFFFF
- blr
-
--- /dev/null
+#include <linux/ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ int c1, c2;
+
+ do {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ } while (c1 == c2 && c1 != 0);
+ return c1 - c2;
+}
8: stbu r4,1(r6)
bdnz 8b
blr
+
.globl bcopy
bcopy:
mr r6,r3
.globl memcmp
memcmp:
cmpwi 0,r5,0
- blelr
+ ble- 2f
mtctr r5
addi r6,r3,-1
addi r4,r4,-1
subf. r3,r0,r3
bdnzt 2,1b
blr
+2: li r3,0
+ blr
+
+ .global memchr
+memchr:
+ cmpwi 0,r5,0
+ ble- 2f
+ mtctr r5
+ addi r3,r3,-1
+1: lbzu r0,1(r3)
+ cmpw 0,r0,r4
+ bdnzf 2,1b
+ beqlr
+2: li r3,0
+ blr
+
.globl __copy_tofrom_user
__copy_tofrom_user:
rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
#!/bin/bash
-N=`basename $PWD`
-V=`echo $N | sed 's/linux-//'`
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
date=`date +'%y%m%d'`
-mkdir -p ../dist
-mv zImage ../dist/zImage-$V-$date
-mv System.map ../dist/System.map-$V-$date
+
+echo zImage-$V.$P.$S-$date
+echo System.map-$V.$P.$S-$date
+
+rcp zImage charon:ppc/dist/kernel-images/zImage-$V.$P.$S-$date
+rcp System.map charon:ppc/dist/kernel-images/System.map-$V.$P.$S-$date
#!/bin/bash
-N=`basename $PWD`
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
date=`date +'%y%m%d'`
cd ../
mkdir -p dist
-tar -zcf dist/ppc$N-$date.tar.gz -X $N/arch/ppc/ignore $N
+tar -vzcf ppclinux-$V.$P.$S-$date.tar.gz -X linux/arch/ppc/ignore linux
#
# Note 2! The CFLAGS definition is now in the main makefile...
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.s.o:
- $(AS) -o $*.o $<
-.c.s:
- $(CC) $(CFLAGS) -S $<
+O_TARGET := mm.o
+O_OBJS = fault.o init.o extable.o
-OBJS = fault.o init.o extable.o
-
-mm.o: $(OBJS)
- $(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-
-fastdep:
- $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
/*
* arch/ppc/mm/fault.c
*
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- * Ported to PPC by Gary Thomas
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/mm/fault.c"
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ *
* Modified by Cort Dougan and Paul Mackerras.
*
* This program is free software; you can redistribute it and/or
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/mmu.h>
#include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *);
extern void (*xmon_fault_handler)(void);
-#endif
-
-/* the linux norm for the function name is show_regs() so
- make it call dump_regs() on the mac -- Cort */
-#ifdef CONFIG_PMAC
-#define show_regs dump_regs
+extern int xmon_dabr_match(struct pt_regs *);
+int xmon_kernel_faults;
#endif
extern void die_if_kernel(char *, struct pt_regs *, long);
void bad_page_fault(struct pt_regs *, unsigned long);
void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void print_pte(struct _PTE);
-void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
+/*
+ * The error_code parameter is DSISR for a data fault, SRR1 for
+ * an instruction fault.
+ */
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code)
{
- struct task_struct *tsk = current;
- extern unsigned _end[];
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- /*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
- current->comm,current->pid,address,regs->nip,regs,error_code);*/
-#ifdef CONFIG_PMAC
+
+#ifdef CONFIG_XMON
if (xmon_fault_handler && regs->trap == 0x300) {
xmon_fault_handler();
return;
}
+ if (error_code & 0x00400000) {
+ /* DABR match */
+ if (xmon_dabr_match(regs))
+ return;
+ }
#endif
if (in_interrupt()) {
static int complained;
printk("page fault in interrupt handler, addr=%lx\n",
address);
show_regs(regs);
+#ifdef CONFIG_XMON
+ if (xmon_kernel_faults)
+ xmon(regs);
+#endif
}
}
- if (current == NULL)
- goto bad_area;
-
-do_page:
+ if (current == NULL) {
+ bad_page_fault(regs, address);
+ return;
+ }
down(&mm->mmap_sem);
- vma = find_vma(tsk->mm, address);
+ vma = find_vma(mm, address);
if (!vma)
goto bad_area;
if (vma->vm_start <= address)
goto bad_area;
if (expand_stack(vma, address))
goto bad_area;
-
+
good_area:
if (error_code & 0xb5700000)
/* an error such as lwarx to I/O controller space,
/* a read */
} else {
/* protection fault */
- if ( error_code & 0x08000000 )
+ if (error_code & 0x08000000)
goto bad_area;
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
handle_mm_fault(current, vma, address, error_code & 0x02000000);
- up(&mm->mmap_sem);
- /*printk("do_page_fault() return %s/%d addr %x msr %x\n",
- current->comm,current->pid,address,regs->msr);*/
- /* not needed since flush_page_to_ram() works */
-#if 0
- flush_page(address);
-#endif
+ up(&mm->mmap_sem);
return;
-
+
bad_area:
- up(¤t->mm->mmap_sem);
+ up(&mm->mmap_sem);
bad_page_fault(regs, address);
}
-
void
bad_page_fault(struct pt_regs *regs, unsigned long address)
{
- extern unsigned int probingmem;
- struct task_struct *tsk = current;
unsigned long fixup;
-
+
+ if (user_mode(regs)) {
+ force_sig(SIGSEGV, current);
+ return;
+ }
/* Are we prepared to handle this fault? */
if ((fixup = search_exception_table(regs->nip)) != 0) {
- if ( user_mode(regs) )
- printk("Exception from user mode\n");
-#if 0
- printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
-#endif
regs->nip = fixup;
return;
}
- if ( user_mode(regs) )
- {
- force_sig(SIGSEGV, tsk);
- return;
- }
-
-bad_kernel_access:
- /* make sure it's not a bootup probe test */
- if ( probingmem )
- {
- probingmem = 0;
- return;
- }
/* kernel has accessed a bad area */
show_regs(regs);
- print_backtrace( regs->gpr[1] );
-#ifdef CONFIG_PMAC
- xmon(regs);
+ print_backtrace( (unsigned long *)regs->gpr[1] );
+#ifdef CONFIG_XMON
+ if (xmon_kernel_faults)
+ xmon(regs);
#endif
- panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
- regs->nip,address,tsk->comm,tsk->pid);
+ panic("kernel access of bad area\n pc %lx address %lX tsk %s/%d",
+ regs->nip,address,current->comm,current->pid);
}
unsigned long va_to_phys(unsigned long address)
return (0);
}
+#if 0
+/*
+ * Misc debugging functions. Please leave them here. -- Cort
+ */
void print_pte(struct _PTE p)
{
printk(
for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
{
if ( ptr->rpn == (address>>12) )
- printk("phys %08X -> va ???\n",
+ printk("phys %08lX -> va ???\n",
address);
}
}
+#endif
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/stddef.h>
-#ifdef CONFIG_PMAC
#include <asm/prom.h>
-#endif
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
-#ifdef CONFIG_PREP
#include <asm/residual.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h> /* for initrd_* */
#endif
+int prom_trashed;
int next_mmu_context;
+unsigned long _SDR1;
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
+unsigned long *end_of_DRAM;
+int mem_init_done;
extern pgd_t swapper_pg_dir[];
extern char _start[], _end[];
extern char etext[], _stext[];
-/* References to section boundaries */
extern char __init_begin, __init_end;
+extern RESIDUAL res;
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void show_net_buffers(void);
-extern unsigned long *find_end_of_memory(void);
-#undef MAP_RAM_WITH_SEGREGS 1
-
-#ifdef CONFIG_PMAC
void *find_mem_piece(unsigned, unsigned);
static void mapin_ram(void);
static void inherit_prom_translations(void);
-#endif
-#ifdef CONFIG_PREP
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va);
-int inline MMU_hash_page(struct task_struct *,unsigned long,pte *);
-#endif
-
static void hash_init(void);
static void *MMU_get_page(void);
-void map_page(struct thread_struct *, unsigned long va,
+void map_page(struct task_struct *, unsigned long va,
unsigned long pa, int flags);
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void show_net_buffers(void);
+extern unsigned long *find_end_of_memory(void);
-PTE *Hash, *Hash_end;
-unsigned long Hash_size, Hash_mask;
-unsigned long *end_of_DRAM;
-int mem_init_done;
+/*
+ * this tells the prep system to map all of ram with the segregs
+ * instead of the bats. I'd like to get this to apply to the
+ * pmac as well then have everything use the bats -- Cort
+ */
+#undef MAP_RAM_WITH_SEGREGS 1
-#ifdef CONFIG_PREP
-#ifdef HASHSTATS
-extern unsigned long evicts;
-#endif /* HASHSTATS */
/*
* these are used to setup the initial page tables
* They can waste up to an entire page since the
unsigned int probingmem = 0;
unsigned int mmu_pages_count = 0;
char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
-unsigned long _TotalMemory;
-#endif /* CONFIG_PREP */
/*
* BAD_PAGE is the page that is used for page faults when linux
return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
}
-#ifdef CONFIG_PMAC
#define MAX_MEM_REGIONS 32
phandle memory_pkg;
int n_regions;
struct reg_property regions[MAX_MEM_REGIONS];
};
-
struct mem_pieces phys_mem;
struct mem_pieces phys_avail;
struct mem_pieces prom_mem;
static void print_mem_pieces(struct mem_pieces *);
unsigned long avail_start;
-int prom_trashed;
/*
* Read in a property describing some pieces of memory.
* Our text, data, bss use something over 1MB, starting at 0.
* Open Firmware may be using 1MB at the 4MB point.
*/
-unsigned long *find_end_of_memory(void)
+unsigned long *pmac_find_end_of_memory(void)
{
unsigned long a, total;
unsigned long h, kstart, ksize;
int i;
unsigned long a, free;
unsigned long start, end;
+
+ if ( _machine != _MACH_Pmac )
+ return 0;
free = 0;
for (i = 0; i < phys_avail.n_regions - 1; ++i) {
avail_start = (unsigned long) __va(a);
return avail_start;
}
-#endif /* CONFIG_PMAC */
void show_mem(void)
{
"Ctx", "Ctx<<4", "Last Sys", "pc", "task");
for_each_task(p)
{
- printk("%-8.8s %3d %3d %8d %8d %8d %c%08x %08x",
+ printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ",
p->comm,p->pid,
p->mm->count,p->mm->context,
p->mm->context<<4, p->tss.last_syscall,
user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
- p);
+ (ulong)p);
if ( p == current )
- printk(" current");
+ printk("current");
+ if ( p == last_task_used_math )
+ {
+ if ( p == current )
+ printk(",");
+ printk("last math");
+ }
+
printk("\n");
}
}
void mem_init(unsigned long start_mem, unsigned long end_mem)
{
unsigned long addr;
-#ifdef CONFIG_PMAC
int i;
- unsigned long lim;
-#endif
+ unsigned long a, lim;
int codepages = 0;
int datapages = 0;
int initpages = 0;
end_mem &= PAGE_MASK;
high_memory = (void *) end_mem;
- num_physpages = max_mapnr = MAP_NR(high_memory);
-
- /* clear the zero-page */
- memset(empty_zero_page, 0, PAGE_SIZE);
-
+ max_mapnr = MAP_NR(high_memory);
+ num_physpages = max_mapnr; /* RAM is assumed contiguous */
+
/* mark usable pages in the mem_map[] */
start_mem = PAGE_ALIGN(start_mem);
-
-#ifdef CONFIG_PMAC
- remove_mem_piece(&phys_avail, __pa(avail_start),
- start_mem - avail_start, 1);
-
- for (a = KERNELBASE ; a < end_mem; a += PAGE_SIZE)
- set_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-
- for (i = 0; i < phys_avail.n_regions; ++i) {
- a = (unsigned long) __va(phys_avail.regions[i].address);
- lim = a + phys_avail.regions[i].size;
- a = PAGE_ALIGN(a);
- for (; a < lim; a += PAGE_SIZE) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
- mem_map[MAP_NR(a)].count = 1;
- free_page(a);
+
+ if ( _machine == _MACH_Pmac )
+ {
+ remove_mem_piece(&phys_avail, __pa(avail_start),
+ start_mem - avail_start, 1);
+
+ for (addr = KERNELBASE ; addr < end_mem; addr += PAGE_SIZE)
+ set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+
+ for (i = 0; i < phys_avail.n_regions; ++i) {
+ a = (unsigned long) __va(phys_avail.regions[i].address);
+ lim = a + phys_avail.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE)
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
}
- }
- phys_avail.n_regions = 0;
-
- /* free the prom's memory */
- for (i = 0; i < prom_mem.n_regions; ++i) {
- a = (unsigned long) __va(prom_mem.regions[i].address);
- lim = a + prom_mem.regions[i].size;
- a = PAGE_ALIGN(a);
- for (; a < lim; a += PAGE_SIZE) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
- mem_map[MAP_NR(a)].count = 1;
- free_page(a);
+ phys_avail.n_regions = 0;
+
+ /* free the prom's memory */
+ for (i = 0; i < prom_mem.n_regions; ++i) {
+ a = (unsigned long) __va(prom_mem.regions[i].address);
+ lim = a + prom_mem.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE)
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
}
+ prom_trashed = 1;
}
- prom_trashed = 1;
-#endif /* CONFIG_PMAC */
-
-#ifdef CONFIG_PREP
- /* mark mem used by kernel as reserved, mark other unreserved */
- for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+ else /* prep */
{
- /* skip hash table gap */
- if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
- continue;
- if ( addr < (ulong) /*Hash_end*/ start_mem )
- set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
- else
- clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ /* mark mem used by kernel as reserved, mark other unreserved */
+ for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+ {
+ /* skip hash table gap */
+ if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
+ continue;
+ if ( addr < (ulong) /*Hash_end*/ start_mem )
+ set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ else
+ clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ }
}
for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
- if(PageReserved(mem_map + MAP_NR(addr))) {
+ if (PageReserved(mem_map + MAP_NR(addr))) {
if (addr < (ulong) etext)
codepages++;
- /*else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
- initpages++;*/
+ else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+ initpages++;
else if (addr < (ulong) start_mem)
datapages++;
continue;
#endif /* CONFIG_BLK_DEV_INITRD */
free_page(addr);
}
-
-#endif /* CONFIG_PREP */
- printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+
+ printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
*/
void free_initmem(void)
{
- unsigned long addr;
unsigned long a;
unsigned long num_freed_pages = 0;
num_freed_pages++;
}
-#if 0
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- num_freed_pages++;
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- mem_map[MAP_NR(addr)].count = 1;
- free_page(addr);
+ a = (unsigned long)(&__init_begin);
+ for (; a < (unsigned long)(&__init_end); a += PAGE_SIZE) {
+ mem_map[MAP_NR(a)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(a)].count, 1);
+ free_page(a);
}
-#endif
- printk ("Freeing unused kernel memory: %dk freed\n",
+
+ printk ("Freeing unused kernel memory: %ldk freed\n",
(num_freed_pages * PAGE_SIZE) >> 10);
}
val->totalram++;
if (!atomic_read(&mem_map[i].count))
continue;
- val->sharedram += atomic_read(&mem_map[i].count)-1;
+ val->sharedram += atomic_read(&mem_map[i].count) - 1;
}
val->totalram <<= PAGE_SHIFT;
val->sharedram <<= PAGE_SHIFT;
return;
}
-/* Kernel MMU setup & lowest level hardware support */
-
-unsigned long _SDR1; /* Hardware SDR1 image */
-
-#ifdef CONFIG_PREP
-
BAT BAT0 =
{
{
0x00000000>>17, /* brpn */
0, /* w */
0, /* i */
+#ifdef __SMP__
1, /* m */
+#else
+ 0, /* m */
+#endif
0, /* g */
BPP_RW /* pp */
}
* this will likely stay seperate from the pmac.
* -- Cort
*/
-unsigned long *find_end_of_memory(void)
+unsigned long *prep_find_end_of_memory(void)
{
- extern RESIDUAL res;
- extern unsigned long resptr;
- int i, p;
+ int i;
unsigned long h;
-
- /* copy residual data */
- if ( resptr )
- memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
- else
- /* clearing bss probably clears this but... */
- memset( &res, sizeof(RESIDUAL), 0 );
- _TotalMemory = res.TotalMemory;
-
- /* this really has nothing to do with the mmu_init() but is
- necessary for early setup -- Cort */
- if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
- {
- _machine = _MACH_IBM;
- }
- else
- _machine = _MACH_Motorola;
-
/* setup the hash table */
- if (_TotalMemory == 0 )
+ if (res.TotalMemory == 0 )
{
/*
* I need a way to probe the amount of memory if the residual
* data doesn't contain it. -- Cort
*/
printk("Ramsize from residual data was 0 -- Probing for value\n");
- _TotalMemory = 0x03000000;
- printk("Ramsize default to be %dM\n", _TotalMemory>>20);
+ res.TotalMemory = 0x03000000;
+ printk("Ramsize default to be %ldM\n", res.TotalMemory>>20);
}
#if 0
/* linux has trouble with > 64M ram -- Cort */
- if ( _TotalMemory > 0x04000000 /* 64M */ )
+ if ( res.TotalMemory > 0x04000000 /* 64M */ )
{
printk("Only using first 64M of ram.\n");
- _TotalMemory = 0x04000000;
+ res.TotalMemory = 0x04000000;
}
#endif
/* setup the bat2 mapping to cover physical ram */
BAT2.batu.bl = 0x1; /* 256k mapping */
- for ( h = 256*1024 /* 256k */ ; (h <= _TotalMemory) && (h <= 256*1024*1024);
+ for ( h = 256*1024 /* 256k */ ; (h <= res.TotalMemory) && (h <= 256*1024*1024);
h *= 2 )
BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
/*
* Allow 64k of hash table for every 16MB of memory,
* up to a maximum of 2MB.
*/
- for (h = 64<<10; h < _TotalMemory / 256 && h < 2<<20; h *= 2)
+ for (h = 64<<10; h < res.TotalMemory / 256 && h < 2<<20; h *= 2)
;
Hash_size = h;
Hash_mask = (h >> 6) - 1;
if ( _get_PVR() == 1 )
{
/* map in rest of ram with seg regs */
- if ( _TotalMemory > 0x01000000 /* 16M */)
+ if ( res.TotalMemory > 0x01000000 /* 16M */)
{
for (i = KERNELBASE+0x01000000;
- i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
- map_page(&init_task.tss, i, __pa(i),
+ i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE)
+ map_page(&init_task, i, __pa(i),
_PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
}
}
memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
memset(&BAT3_601, sizeof(BAT2), 0);
/* map all of ram for kernel with segregs */
- for (i = KERNELBASE; i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
+ for (i = KERNELBASE; i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE)
{
if ( i < (unsigned long)etext )
- map_page(&init_task.tss, i, __pa(i),
+ map_page(&init_task, i, __pa(i),
_PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
else
- map_page(&init_task.tss, i, __pa(i),
+ map_page(&init_task, i, __pa(i),
_PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
}
#endif /* MAP_RAM_WITH_SEGREGS */
printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
- _TotalMemory >> 20, Hash_size >> 10, Hash);
- return ((unsigned long *)_TotalMemory);
+ res.TotalMemory >> 20, Hash_size >> 10, Hash);
+ return ((unsigned long *)res.TotalMemory);
}
-#endif /* CONFIG_PREP */
-#ifdef CONFIG_PMAC
/*
* Map in all of physical memory starting at KERNELBASE.
*/
f = _PAGE_PRESENT | _PAGE_ACCESSED;
if ((char *) v < _stext || (char *) v >= etext)
f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
- map_page(&init_task.tss, v, p, f);
+ else
+ /* On the powerpc, no user access forces R/W kernel access */
+ f |= _PAGE_USER;
+ map_page(&init_task, v, p, f);
v += PAGE_SIZE;
p += PAGE_SIZE;
}
for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
/* ignore stuff mapped down low */
- if (tp->virt < 0x10000000)
+ if (tp->virt < 0x10000000 && tp->phys < 0x10000000)
continue;
/* map PPC mmu flags to linux mm flags */
f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
p = tp->phys;
n = tp->size;
for (; n != 0; n -= PAGE_SIZE) {
- map_page(&init_task.tss, v, p, f);
+ map_page(&init_task, v, p, f);
v += PAGE_SIZE;
p += PAGE_SIZE;
}
}
}
-#endif
/*
* Initialize the hash table and patch the instructions in head.S.
* out from the data cache and invalidated in the instruction
* cache, on those machines with split caches.
*/
- store_cache_range((unsigned long) hash_page_patch_A,
- (unsigned long) (hash_page_patch_C + 1));
+ flush_icache_range((unsigned long) hash_page_patch_A,
+ (unsigned long) (hash_page_patch_C + 1));
}
void
MMU_init(void)
{
- end_of_DRAM = find_end_of_memory();
+ if ( _machine == _MACH_Pmac )
+ end_of_DRAM = pmac_find_end_of_memory();
+ else /* prep */
+ end_of_DRAM = prep_find_end_of_memory();
+
hash_init();
_SDR1 = __pa(Hash) | (Hash_mask >> 10);
-#ifdef CONFIG_PMAC
- /* Force initial page tables */
- /* this done by INIT_TSS in processor.h on prep -- Cort */
- init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
-
- /* Map in all of RAM starting at KERNELBASE */
- mapin_ram();
- /* Copy mappings from the prom */
- inherit_prom_translations();
-#endif /* CONFIG_PMAC */
+
+ if ( _machine == _MACH_Pmac )
+ {
+ /* Map in all of RAM starting at KERNELBASE */
+ mapin_ram();
+ /* Copy mappings from the prom */
+ inherit_prom_translations();
+ }
}
static void *
MMU_get_page()
{
- void *p;
-
- if (mem_init_done) {
- p = (void *) __get_free_page(GFP_KERNEL);
- if (p == 0)
- panic("couldn't get a page in MMU_get_page");
- } else {
-#ifdef CONFIG_PREP
- mmu_pages_count++;
- if ( mmu_pages_count > MAX_MMU_PAGES )
- printk("out of mmu pages!\n");
- p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
- (mmu_pages_count+PAGE_SIZE));
-#endif
-#ifdef CONFIG_PMAC
- p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
-#endif
- }
- memset(p, 0, PAGE_SIZE);
- return p;
+ void *p;
+
+ if (mem_init_done) {
+ p = (void *) __get_free_page(GFP_KERNEL);
+ if (p == 0)
+ panic("couldn't get a page in MMU_get_page");
+ } else {
+ if ( is_prep )
+ {
+ mmu_pages_count++;
+ if ( mmu_pages_count > MAX_MMU_PAGES )
+ printk("out of mmu pages!\n");
+ p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
+ (mmu_pages_count+PAGE_SIZE));
+ }
+ else /* pmac */
+ {
+ p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+ }
+ }
+ memset(p, 0, PAGE_SIZE);
+ return p;
}
-#ifdef CONFIG_PMAC
void *
ioremap(unsigned long addr, unsigned long size)
{
unsigned long p, end = addr + size;
for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
- map_page(&init_task.tss, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+ map_page(&init_task, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
return (void *) addr;
}
-#endif
void
-map_page(struct thread_struct *tss, unsigned long va,
+map_page(struct task_struct *tsk, unsigned long va,
unsigned long pa, int flags)
{
pmd_t *pd;
pte_t *pg;
+
- if (tss->pg_tables == NULL) {
+ if (tsk->mm->pgd == NULL) {
/* Allocate upper level page map */
- tss->pg_tables = (unsigned long *) MMU_get_page();
+ tsk->mm->pgd = (pgd_t *) MMU_get_page();
}
/* Use upper 10 bits of VA to index the first level map */
- pd = (pmd_t *) (tss->pg_tables + (va >> PGDIR_SHIFT));
+ pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
if (pmd_none(*pd)) {
/* Need to allocate second-level table */
pg = (pte_t *) MMU_get_page();
}
}
-
-void
-flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
- unsigned vsid;
-
- if ( vmaddr < TASK_SIZE) {
- /*vsid = (vma->vm_mm->context << 4) | (vmaddr >> 28);*/
- flush_hash_page(vma->vm_mm->context/*vsid*/, vmaddr);
- /* this is needed on prep at the moment -- don't know why
- -- Cort*/
- MMU_invalidate_page(vma->vm_mm,vmaddr);
- }
- else
- {
- /*printk("flush_tlb_page() vmaddr > TASK_SIZE %08x\n", vmaddr);*/
- }
-}
-
-
/* for each page addr in the range, call MMU_invalidate_page()
if the range is very large and the hash table is small it might be faster to
do a search of the hash table and just invalidate pages that are in the range
void
flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
{
- start &= PAGE_MASK;
+ start &= PAGE_MASK;
for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
{
- /*flush_hash_page(VSID_FROM_CONTEXT( start>>28, mm->context),
- start );*/
flush_hash_page(mm->context, start);
- /* this is needed on prep at the moment -- don't know why
- -- Cort*/
- MMU_invalidate_page(mm,start);
}
}
mmu_context_overflow(void)
{
struct task_struct *tsk;
- int nr;
- printk(KERN_INFO "mmu_context_overflow\n");
- for (nr = 0; nr < NR_TASKS; ++nr) {
- tsk = task[nr];
- if (tsk && tsk->mm)
+ printk(KERN_DEBUG "mmu_context_overflow\n");
+ read_lock(&tasklist_lock);
+ for_each_task(tsk) {
+ if (tsk->mm)
tsk->mm->context = NO_CONTEXT;
}
+ read_unlock(&tasklist_lock);
flush_hash_segments(0x10, 0xffffff);
- _tlbia();
next_mmu_context = 0;
-}
-
-#ifdef CONFIG_PREP
-/*
- * it's not a simple matter to get rid of these and switch to the
- * ones paul is using. it will take some time and thought -- Cort
- */
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
-{
- int hash, page_index, segment, i, h, _h, api, vsid, perms;
- PTE *_pte, *slot;
- int flags = 0;
- page_index = ((int)va & 0x0FFFF000) >> 12;
- segment = (unsigned int)va >> 28;
- api = page_index >> 10;
- vsid = VSID_FROM_CONTEXT(segment,mm->context);
- for (_h = 0; _h < 2; _h++)
- {
- hash = page_index ^ vsid;
- if (_h)
- {
- hash = ~hash; /* Secondary hash uses ones-complement */
- }
- hash &= 0x3FF | (Hash_mask /*<< 10*/);
- hash *= 8; /* Eight entries / hash bucket */
- _pte = &Hash[hash];
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
- { /* Found it! */
- _tlbie(va); /* Clear TLB */
- if (_pte->r) flags |= _PAGE_ACCESSED;
- if (_pte->c) flags |= _PAGE_DIRTY;
- _pte->v = 0;
- return /*(flags)*/;
- }
- }
- }
- _tlbie(va);
- return /*(flags)*/;
-}
-#endif
-
-#include <asm/mmu.h>
-void print_mm_info(void)
-{
- struct _SEGREG s;
- long a;
- struct _BATU bu;
- struct _BATL bl;
- unsigned long i;
-
- for ( i = 0x70000000 ; i <= 0x90000000 ; i+= 0x10000000 )
- {
- a = get_SR(i);
- memcpy(&s,&a,4);
- printk("sr %2d t:%1d ks:%d kp:%d n:%d vsid:%x %x\n",
- i>>28, s.t, s.ks, s.kp, s.n, s.vsid, a);
- }
-
- asm("mfspr %0,532; mfspr %1, 533\n" : "=r" (bu), "=r" (bl));
- printk("bat2 bepi: %0x vs: %1x vp: %1x wimg: %x%x%x%x pp: %1x\n",
- bu.bepi<<17, bu.vs, bu.vp, bl.w, bl.i, bl.m, bl.g, bl.pp);
+ /* make sure current always has a context */
+ current->mm->context = MUNGE_CONTEXT(++next_mmu_context);
+ set_context(current->mm->context);
}
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_NATIVE=y
+CONFIG_PMAC=y
+# CONFIG_PREP is not set
+CONFIG_MCOMMON=y
+# CONFIG_M601 is not set
+# CONFIG_M603 is not set
+# CONFIG_M604 is not set
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BINFMT_JAVA=m
+CONFIG_PMAC_CONSOLE=y
+CONFIG_MAC_KEYBOARD=y
+CONFIG_MAC_FLOPPY=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_XMON=y
+CONFIG_ATY_VIDEO=y
+CONFIG_IMSTT_VIDEO=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=10
+CONFIG_SCSI_MAC53C94=y
+CONFIG_SCSI_QLOGIC_PMAC=m
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+CONFIG_NET_ALIAS=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+CONFIG_NET_IPIP=m
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_PCTCP is not set
+CONFIG_INET_RARP=y
+CONFIG_PATH_MTU_DISCOVERY=y
+CONFIG_IP_NOSR=y
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MACE=y
+CONFIG_DEC_ELCP=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+CONFIG_MINIX_FS=m
+CONFIG_EXT2_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+CONFIG_NVRAM=y
+# CONFIG_JOYSTICK is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+# CONFIG_CS4232 is not set
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CONFIG_LOWLEVEL_SOUND=y
+# CONFIG_ACI_MIXER is not set
+# CONFIG_AWE32_SYNTH is not set
+# CONFIG_AEDSP16 is not set
+CONFIG_AWACS=y
#
# Automatically generated by make menuconfig: don't edit
#
+
+#
+# Platform support
+#
CONFIG_NATIVE=y
# CONFIG_PMAC is not set
CONFIG_PREP=y
-# CONFIG_HEARTBEAT is not set
-# CONFIG_POWERSAVING is not set
CONFIG_MCOMMON=y
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
CONFIG_PCI=y
CONFIG_PCI_OPTIMIZE=y
CONFIG_NET=y
CONFIG_SYSCTL=y
CONFIG_SYSVIPC=y
-# CONFIG_BINFMT_JAVA is not set
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
#
# Plug and Play support
# CONFIG_BLK_DEV_RZ1000 is not set
# CONFIG_BLK_DEV_TRITON is not set
# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_INITRD=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_BLK_DEV_EZ is not set
# CONFIG_BLK_DEV_HD is not set
# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_MESH is not set
# CONFIG_SCSI_MAC53C94 is not set
-# CONFIG_SCSI_QLOGIC_PMAC is not set
#
# Network device support
# CONFIG_IP_ACCT is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_PCTCP is not set
# CONFIG_INET_RARP is not set
CONFIG_PATH_MTU_DISCOVERY=y
# CONFIG_DEC_ELCP is not set
# CONFIG_DGRS is not set
# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
# CONFIG_ES3210 is not set
# CONFIG_ZNET is not set
# CONFIG_NET_POCKET is not set
# CONFIG_QUOTA is not set
# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
-CONFIG_BEXT2_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_RNFS_BOOTP is not set
-# CONFIG_RNFS_RARP is not set
+# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
CONFIG_MAC_PARTITION=y
-CONFIG_HFS_FS=y
#
# Character devices
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
-# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_PRINTER is not set
CONFIG_MOUSE=y
# CONFIG_MS_BUSMOUSE is not set
CONFIG_PSMOUSE=y
# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_FTAPE is not set
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
#
# Sound
#
-# CONFIG_SOUND is not set
+#CONFIG_SOUND=y
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+CONFIG_CS4232=y
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CS4232_BASE=830
+CS4232_IRQ=10
+CS4232_DMA=6
+CS4232_DMA2=7
+CS4232_MPU_BASE=330
+CS4232_MPU_IRQ=9
+# CONFIG_LOWLEVEL_SOUND is not set
--- /dev/null
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+/* .init : { *(.init) } =0*/
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text)
+ *(.fixup)
+ *(.got1)
+ }
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata1)
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt) *(.got)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
+
while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) {
tnet_check_completion();
- if (need_resched) break;
+ if (resched_needed())
+ break;
if (current->signal & ~current->blocked) break;
}
return 0;
void mpp_schedule(struct cap_request *req)
{
mpp_current_task = req->data[0];
- need_resched = 1;
+ resched_force();
mark_bh(TQUEUE_BH);
}
#endif
MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH);
intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH);
- need_resched = 1;
+ resched_force();
block_parallel_tasks = 1;
mark_bh(TQUEUE_BH);
}
static void reschedule(void)
{
- need_resched = 1;
+ resched_force();
mark_bh(TQUEUE_BH);
}
#
CONFIG_SUN_OPENPROMIO=m
CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SAB82532 is not set
# CONFIG_SUN_BPP is not set
# CONFIG_SUN_VIDEOPIX is not set
CONFIG_IP_ALIAS=m
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
#
# (it is safe to leave these untouched)
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
CONFIG_UFS_FS=y
CONFIG_BSD_DISKLABEL=y
CONFIG_SMD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
#
# Kernel hacking
/* This is being executed in task 0 'user space'. */
int cpu_idle(void *unused)
{
+ extern volatile int smp_commenced;
+
current->priority = -100;
while(1) {
/*
}
/* endless idle loop with no priority at all */
current->counter = -100;
- schedule();
+ if(!smp_commenced || resched_needed())
+ schedule();
}
}
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
current->tss.flags ^= MAGIC_CONSTANT;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
-/* $Id: rtrap.S,v 1.46 1997/04/01 02:21:48 davem Exp $
+/* $Id: rtrap.S,v 1.47 1997/08/10 04:49:24 davem Exp $
* rtrap.S: Return from Sparc trap low-level code.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
wr %t_psr, 0x0, %psr
b ret_trap_kernel
- nop
+ mov 1, %o0
1:
+ ld [%curptr + AOFF_task_processor], %o1
ld [%twin_tmp1 + %lo(C_LABEL(need_resched))], %g2
+ sll %o0, %o1, %o0
- cmp %g2, 0
+ andcc %g2, %o0, %g0
be signal_p
nop
-/* $Id: signal.c,v 1.74 1997/05/15 19:57:09 davem Exp $
+/* $Id: signal.c,v 1.75 1997/08/05 19:19:26 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
/* This happens to be SMP safe so no need to
* grab master kernel lock even in this case.
*/
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
/* notify_parent() is SMP safe */
if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
#define SMP_PRINTK(x)
#endif
-static volatile int smp_commenced = 0;
+volatile int smp_commenced = 0;
static char smp_buf[512];
/* Reschedule call back. */
void smp_reschedule_irq(void)
{
- need_resched=1;
+ resched_force();
}
/* Running cross calls. */
if(--current->counter < 0) {
current->counter = 0;
- need_resched = 1;
+ resched_force();
}
spin_lock(&ticker_lock);
-/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $
+/* $Id: sys_sunos.c,v 1.80 1997/07/17 02:20:22 davem Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
-/* $Id: srmmu.c,v 1.149 1997/07/20 05:59:34 davem Exp $
+/* $Id: srmmu.c,v 1.150 1997/07/25 23:06:17 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
}
/* turbosparc.S */
-extern void turbosparc_flush_cache_all();
+extern void turbosparc_flush_cache_all(void);
extern void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
static void poke_turbosparc(void)
-# $Id: config.in,v 1.9 1997/07/04 11:33:05 davem Exp $
+# $Id: config.in,v 1.10 1997/08/11 14:35:45 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
define_bool CONFIG_SUN_CONSOLE y
define_bool CONFIG_SUN_AUXIO y
define_bool CONFIG_SUN_IO y
+ define_bool CONFIG_PCI y
source drivers/sbus/char/Config.in
fi
CONFIG_SUN_CONSOLE=y
CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
+CONFIG_PCI=y
#
# SBUS Frame Buffer support
#
CONFIG_SUN_OPENPROMIO=m
CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SAB82532 is not set
# CONFIG_SUN_BPP is not set
# CONFIG_SUN_VIDEOPIX is not set
CONFIG_SUN_OPENPROMFS=m
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
#
# (it is safe to leave these untouched)
CONFIG_UFS_FS=m
CONFIG_BSD_DISKLABEL=y
CONFIG_SMD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
#
# Kernel hacking
-# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
+# $Id: Makefile,v 1.34 1997/08/12 04:12:36 ecd Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
O_TARGET := kernel.o
O_OBJS := process.o setup.o cpu.o idprom.o \
- systbls.o traps.o devices.o auxio.o ioport.o \
+ traps.o devices.o auxio.o ioport.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
- unaligned.o sys_sunos32.o sunos_ioctl32.o
+ unaligned.o sys_sunos32.o sunos_ioctl32.o \
+ central.o psycho.o ebus.o
OX_OBJS := sparc64_ksyms.o
ifdef SMP
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/init.h>
+#include <linux/delay.h>
+
#include <asm/oplib.h>
#include <asm/io.h>
#include <asm/auxio.h>
#include <asm/sbus.h>
+#include <asm/ebus.h>
+#include <asm/fhc.h>
/* Probe and map in the Auxiliary I/O register */
unsigned char *auxio_register;
}
if (!sdev) {
+#ifdef CONFIG_PCI
+ struct linux_ebus *ebus;
+ struct linux_ebus_device *edev = 0;
+
+ for_all_ebusdev(edev, ebus)
+ if (!strcmp(edev->prom_name, "auxio"))
+ break;
+
+ if (edev) {
+ auxio_register = (unsigned char *)
+ sparc_alloc_io(edev->regs[0].phys_addr, 0,
+ edev->regs[0].reg_size,
+ "auxiliaryIO",
+ edev->regs[0].which_io, 0x0);
+ *(auxio_register) = 0x01;
+ return;
+ }
+#endif
+ if(central_bus) {
+ auxio_register = NULL;
+ return;
+ }
prom_printf("Cannot find auxio node, cannot continue...\n");
prom_halt();
}
+
prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs));
prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev);
/* Map the register both read and write */
--- /dev/null
+/* $Id: central.c,v 1.3 1997/08/12 14:51:55 davem Exp $
+ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+#include <asm/fhc.h>
+
+struct linux_central *central_bus = NULL;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+ return ((addr + (sizeof(unsigned long) - 1)) &
+ ~(sizeof(unsigned long) - 1));
+}
+
+extern void prom_central_ranges_init(int cnode, struct linux_central *central);
+extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc);
+
+unsigned long central_probe(unsigned long memory_start)
+{
+ struct linux_prom_registers fpregs[6];
+ struct linux_fhc *fhc;
+ char namebuf[128];
+ int cnode, fnode, err;
+
+ prom_printf("CENTRAL: ");
+ printk("CENTRAL: ");
+ cnode = prom_finddevice("/central");
+ if(cnode == 0 || cnode == -1) {
+ prom_printf("no central found.\n");
+ printk("no central found.\n");
+ return memory_start;
+ }
+ prom_printf("found central PROM node.\n");
+ printk("found central PROM node.\n");
+
+ /* Ok we got one, grab some memory for software state. */
+ memory_start = long_align(memory_start);
+ central_bus = (struct linux_central *) (memory_start);
+
+ prom_printf("CENTRAL: central_bus[%p] ", central_bus);
+ memory_start += sizeof(struct linux_central);
+ memory_start = long_align(memory_start);
+ fhc = (struct linux_fhc *)(memory_start);
+ memory_start += sizeof(struct linux_fhc);
+ memory_start = long_align(memory_start);
+
+ prom_printf("fhc[%p] ", fhc);
+
+ /* First init central. */
+ central_bus->child = fhc;
+ central_bus->prom_node = cnode;
+
+ prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
+ strcpy(central_bus->prom_name, namebuf);
+
+ prom_printf("init_central_ranges ");
+ prom_central_ranges_init(cnode, central_bus);
+
+ /* And then central's FHC. */
+ fhc->next = NULL;
+ fhc->parent = central_bus;
+ fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
+ if(fnode == 0 || fnode == -1) {
+ prom_printf("Critical error, central board lacks fhc.\n");
+ prom_halt();
+ }
+ fhc->prom_node = fnode;
+ prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
+ strcpy(fhc->prom_name, namebuf);
+
+ prom_printf("cnode[%x] fnode[%x] init_fhc_ranges\n", cnode, fnode);
+ prom_fhc_ranges_init(fnode, fhc);
+
+ /* Finally, map in FHC register set. (From the prtconf dumps
+ * I have seen on Ex000 boxes only the central ranges need to
+ * be applied to the fhc internal register set) -DaveM
+ */
+ err = prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs));
+ if(err == -1) {
+ prom_printf("CENTRAL: fatal error, cannot get fhc regs.\n");
+ prom_halt();
+ }
+ prom_apply_central_ranges(central_bus, &fpregs[0], 6);
+ prom_printf("CENTRAL: FHC_REGS[(%08x,%08x) (%08x,%08x) "
+ "(%08x,%08x) (%08x,%08x) (%08x,%08x) (%08x,%08x)]\n",
+ fpregs[0].which_io, fpregs[0].phys_addr,
+ fpregs[1].which_io, fpregs[1].phys_addr,
+ fpregs[2].which_io, fpregs[2].phys_addr,
+ fpregs[3].which_io, fpregs[3].phys_addr,
+ fpregs[4].which_io, fpregs[4].phys_addr,
+ fpregs[5].which_io, fpregs[5].phys_addr);
+ fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
+ __va((((unsigned long)fpregs[0].which_io)<<32) |
+ (((unsigned long)fpregs[0].phys_addr)));
+ fhc->fhc_regs.ireg = (struct fhc_ign_reg *)
+ __va((((unsigned long)fpregs[1].which_io)<<32) |
+ (((unsigned long)fpregs[1].phys_addr)));
+ fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *)
+ __va((((unsigned long)fpregs[2].which_io)<<32) |
+ (((unsigned long)fpregs[2].phys_addr)));
+ fhc->fhc_regs.sregs = (struct fhc_system_regs *)
+ __va((((unsigned long)fpregs[3].which_io)<<32) |
+ (((unsigned long)fpregs[3].phys_addr)));
+ fhc->fhc_regs.uregs = (struct fhc_uart_regs *)
+ __va((((unsigned long)fpregs[4].which_io)<<32) |
+ (((unsigned long)fpregs[4].phys_addr)));
+ fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
+ __va((((unsigned long)fpregs[5].which_io)<<32) |
+ (((unsigned long)fpregs[5].phys_addr)));
+ prom_printf("CENTRAL: FHC_REGS[%p %p %p %p %p %p]\n",
+ fhc->fhc_regs.pregs, fhc->fhc_regs.ireg,
+ fhc->fhc_regs.ffregs, fhc->fhc_regs.sregs,
+ fhc->fhc_regs.uregs, fhc->fhc_regs.tregs);
+
+ prom_printf("CENTRAL: reading FHC_ID register... ");
+ err = fhc->fhc_regs.pregs->fhc_id;
+ prom_printf("VALUE[%x]\n", err);
+ printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n",
+ ((err & FHC_ID_VERS) >> 28),
+ ((err & FHC_ID_PARTID) >> 12),
+ ((err & FHC_ID_MANUF) >> 1));
+
+ return memory_start;
+}
#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
-char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
-char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#ifdef __SMP__
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#else
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", };
+#endif
unsigned int fsr_storage;
int linux_num_cpus = 0;
extern void cpu_probe(void);
+extern unsigned long central_probe(unsigned long);
__initfunc(unsigned long
device_scan(unsigned long mem_start))
{
char node_str[128];
int nd, prom_node_cpu, thismid;
- int cpu_nds[NCPUS]; /* One node for each cpu */
+ int cpu_nds[NR_CPUS]; /* One node for each cpu */
int cpu_ctr = 0;
prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
if(strcmp(node_str, "cpu") == 0) {
cpu_nds[cpu_ctr] = scan;
linux_cpus[cpu_ctr].prom_node = scan;
- prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+ prom_getproperty(scan, "upa-portid",
+ (char *) &thismid, sizeof(thismid));
linux_cpus[cpu_ctr].mid = thismid;
prom_printf("Found CPU %d <node=%08x,mid=%d>\n",
cpu_ctr, (unsigned) scan,
thismid);
+ printk("Found CPU %d <node=%08x,mid=%d>\n",
+ cpu_ctr, (unsigned) scan, thismid);
cpu_ctr++;
}
};
linux_num_cpus = cpu_ctr;
cpu_probe();
- return mem_start;
+ return central_probe(mem_start);
}
-/* $Id: dtlb_miss.S,v 1.12 1997/06/26 12:47:08 jj Exp $
+/* $Id: dtlb_miss.S,v 1.13 1997/08/14 19:27:15 davem Exp $
* dtlb_miss.S: Data TLB miss code, this is included directly
* into the trap table.
*
/*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET
/*0x44*/ brgez,pn %g5, 4f ! If >= 0, then walk down page tables
/*0x48*/ sethi %uhi(KERN_HIGHBITS), %g1 ! Construct PTE ^ PAGE_OFFSET
- /*0x4c*/ andcc %g3, 0x80, %g0 ! Slick trick...
+ /*0x4c*/ andcc %g3, 0x400, %g0 ! Slick trick...
/*0x50*/ sllx %g1, 32, %g1 ! Move high bits up
/*0x54*/ or %g1, (KERN_LOWBITS), %g1 ! Assume not IO
/*0x58*/ bne,a,pn %icc, 5f ! Is it an IO page?
-/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $
+/* $Id: dtlb_prot.S,v 1.14 1997/08/03 09:07:00 davem Exp $
* dtlb_prot.S: Data TLB protection code, this is included directly
* into the trap table.
*
/* ICACHE line 3 */
/*0x40*/ add %g2, 7, %g5 ! Compute mask
/*0x44*/ andn %g4, %g5, %g4 ! Mask page
- /*0x48*/ or %g4, 0x10, %g4 ! 2ndary Context
- /*0x4c*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
- /*0x50*/ membar #Sync ! Synchronize
- /*0x54*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE
- /*0x58*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
- /*0x5c*/ retry ! Trap return
+ /*0x48*/ mov TLB_SFSR, %g5 ! read SFSR
+ /*0x4c*/ ldxa [%g5] ASI_DMMU, %g5 ! from DMMU for
+ /*0x50*/ and %g5, 0x10, %g5 ! context bit
+ /*0x54*/ or %g4, %g5, %g4 ! for prot trap
+1:/*0x58*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
+ /*0x5c*/ membar #Sync ! Synchronize
/* ICACHE line 4 */
- /*0x60*/ nop
- /*0x64*/ nop
- /*0x68*/ nop
+ /*0x60*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE
+ /*0x64*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x68*/ retry ! Trap return
/*0x6c*/ nop
/*0x70*/ nop
/*0x74*/ nop
--- /dev/null
+/* $Id: ebus.c,v 1.2 1997/08/15 06:44:13 davem Exp $
+ * ebus.c: PCI to EBus bridge device.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/system.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#include <asm/oplib.h>
+#include <asm/bpp.h>
+
+struct linux_ebus *ebus_chain = 0;
+
+static char lbuf[128];
+
+extern void prom_ebus_ranges_init(struct linux_ebus *);
+
+#ifdef CONFIG_SUN_OPENPROMIO
+extern int openprom_init(void);
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+extern int rtc_init(void);
+#endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
+#ifdef CONFIG_SUN_AUXIO
+extern void auxio_probe(void);
+#endif
+
+__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
+{
+ int irqs[PROMINTR_MAX];
+ int i, len;
+
+ dev->prom_node = node;
+ prom_getstring(node, "name", lbuf, sizeof(lbuf));
+ strcpy(dev->prom_name, lbuf);
+
+ len = prom_getproperty(node, "reg", (void *)dev->regs,
+ sizeof(dev->regs));
+ if (len % sizeof(struct linux_prom_registers)) {
+ prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
+ dev->prom_name, len,
+ (int)sizeof(struct linux_prom_registers));
+ panic(__FUNCTION__);
+ }
+ dev->num_registers = len / sizeof(struct linux_prom_registers);
+
+ prom_apply_ebus_ranges(dev->parent, dev->regs, dev->num_registers);
+#if 0 /* XXX No longer exists/needed in new framework... */
+ prom_apply_pbm_ranges(dev->parent->parent, dev->regs,
+ dev->num_registers);
+#endif
+
+ len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+ if ((len == -1) || (len == 0)) {
+ dev->irqs[0].pri = 0;
+ dev->num_irqs = 0;
+ } else {
+ dev->num_irqs = len / sizeof(irqs[0]);
+ for (i = 0; i < dev->num_irqs; i++)
+ dev->irqs[i].pri = irqs[i];
+ }
+
+ printk("Found '%s' at %x.%08x", dev->prom_name,
+ dev->regs[0].which_io, dev->regs[0].phys_addr);
+ if (dev->num_irqs) {
+ printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ for (i = 0; i < dev->num_irqs; i++)
+ printk(" %03x", dev->irqs[i].pri);
+ }
+ printk("\n");
+}
+
+__initfunc(unsigned long ebus_init(unsigned long memory_start,
+ unsigned long memory_end))
+{
+ struct linux_ebus_device *dev;
+ struct linux_ebus *ebus;
+ int nd, ebusnd, topnd;
+ int num_ebus = 0;
+
+#ifndef CONFIG_PCI
+ return memory_start;
+#endif
+
+ memory_start = ((memory_start + 7) & (~7));
+
+ topnd = psycho_root->pbm_B.prom_node;
+ if (!topnd)
+ return memory_start;
+
+ ebusnd = prom_searchsiblings(prom_getchild(topnd), "ebus");
+ if (ebusnd == 0) {
+ printk("EBUS: No EBUS's found.\n");
+ return memory_start;
+ }
+
+ ebus_chain = ebus = (struct linux_ebus *)memory_start;
+ memory_start += sizeof(struct linux_ebus);
+ ebus->next = 0;
+
+ while (ebusnd) {
+ printk("ebus%d: ", num_ebus);
+
+ prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
+ ebus->prom_node = ebusnd;
+ strcpy(ebus->prom_name, lbuf);
+ ebus->parent = &psycho_root->pbm_B;
+
+ prom_ebus_ranges_init(ebus);
+
+ nd = prom_getchild(ebusnd);
+ ebus->devices = (struct linux_ebus_device *)memory_start;
+ memory_start += sizeof(struct linux_ebus_device);
+
+ dev = ebus->devices;
+ dev->next = 0;
+ dev->parent = ebus;
+ fill_ebus_device(nd, dev);
+
+ while ((nd = prom_getsibling(nd))) {
+ dev->next = (struct linux_ebus_device *)memory_start;
+ memory_start += sizeof(struct linux_ebus_device);
+
+ dev = dev->next;
+ dev->next = 0;
+ dev->parent = ebus;
+ fill_ebus_device(nd, dev);
+ }
+
+ ebusnd = prom_searchsiblings(prom_getsibling(ebusnd), "ebus");
+ ++num_ebus;
+ }
+
+#ifdef CONFIG_SUN_OPENPROMIO
+ openprom_init();
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+ rtc_init();
+#endif
+#ifdef CONFIG_SPARCAUDIO
+ sparcaudio_init();
+#endif
+#ifdef CONFIG_SUN_BPP
+ bpp_init();
+#endif
+#ifdef CONFIG_SUN_AUXIO
+ if (sparc_cpu_model == sun4u)
+ auxio_probe();
+#endif
+#ifdef __sparc_v9__
+ if (sparc_cpu_model == sun4u) {
+ extern void sun4u_start_timers(void);
+ extern void clock_probe(void);
+
+ sun4u_start_timers();
+ clock_probe();
+ }
+#endif
+ return memory_start;
+}
-/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
+/* $Id: entry.S,v 1.61 1997/08/15 06:44:16 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
bgu,a,pn %icc, winfix_trampoline
rdpr %tpc, %g3
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
b,pt %xcc, 1f
mov 1, %o2
+ .align 32
sparc64_dtlb_refbit_catch:
srlx %g5, 9, %g4
and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
-
cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
be,a,pt %xcc, 2f
mov 1, %g4
wr %g0, ASI_DMMU, %asi
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+
rdpr %tl, %g3
ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
-
cmp %g3, 1
bgu,pn %icc, winfix_trampoline
rdpr %tpc, %g3
+ sethi %hi(109f), %g7
b,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
+
clr %o2
1: srlx %l5, PAGE_SHIFT, %o1
add %sp, STACK_BIAS + REGWIN_SZ, %o0
-
call do_sparc64_fault
sllx %o1, PAGE_SHIFT, %o1
b,pt %xcc, rtrap
clr %l6
- nop
- nop
- nop
- nop
-
+ .align 32
sparc64_itlb_refbit_catch:
srlx %g5, 9, %g4
and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
rdpr %tpc, %g5
+ sethi %hi(109f), %g7
b,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
b,pt %xcc, 1b
clr %o2
+
+ .align 32
2: sllx %g4, 63, %g4 ! _PAGE_VALID
or %g5, _PAGE_ACCESSED, %g5
or %g5, %g4, %g5
stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE
-
stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
retry
+
+ .align 32
3: sllx %g4, 63, %g4 ! _PAGE_VALID
or %g5, _PAGE_ACCESSED, %g5
or %g5, %g4, %g5
or %g2, %lo((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2
add %g6, %g2, %g2
mov SECONDARY_CONTEXT, %g3
+ ldxa [%g3] ASI_DMMU, %g7
stxa %g0, [%g3] ASI_DMMU
flush %g2
wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
ldda [%g2 + 0x080] %asi, %f32
ldda [%g2 + 0x0c0] %asi, %f48
ldx [%g2 + 0x100], %fsr
- ldx [%g2 + 0x108], %g2
+ ldx [%g2 + 0x108], %g4
membar #Sync
- wr %g2, 0, %gsr
+ wr %g4, 0, %gsr
+
+ stxa %g7, [%g3] ASI_DMMU
+ flush %g2
fpdis_exit:
rdpr %tstate, %g3
sethi %hi(TSTATE_PEF), %g4
wrpr %g3, %tstate
retry
-#ifdef __SMP__
- /* Note check out head.h, this code isn't even used for UP,
- * for SMP things will be different. In particular the data
- * registers for cross calls will be:
+ /* The registers for cross calls will be:
*
* DATA 0: [low 32-bits] Address of function to call, jmp to this
* [high 32-bits] MMU Context Argument 0, place in %g5
* With this method we can do most of the cross-call tlb/cache
* flushing very quickly.
*/
+ .data
+ .align 8
+ .globl ivec_spurious_cookie
+ivec_spurious_cookie: .xword 0
+
+ .text
.align 32
- .globl do_ivec, do_ivec_return
+ .globl do_ivec
do_ivec:
- ldxa [%g0] ASI_INTR_RECEIVE, %g1
- andcc %g1, 0x20, %g0
+ ldxa [%g0] ASI_INTR_RECEIVE, %g5
+ andcc %g5, 0x20, %g0
be,pn %xcc, do_ivec_return
mov 0x40, %g2
* which is completely harmless.
*/
wr %g2, 0x0, %set_softint
-
do_ivec_return:
- /* Acknowledge the UPA */
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
retry
do_ivec_xcall:
srlx %g3, 32, %g5
add %g2, 0x10, %g2
- sra %g3, 0, %g3
+ srl %g3, 0, %g3
ldxa [%g2] ASI_UDB_INTR_R, %g6
add %g2, 0x10, %g2
+ ldxa [%g2] ASI_UDB_INTR_R, %g7
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
jmpl %g3, %g0
- ldxa [%g2] ASI_UDB_INTR_R, %g7
+ membar #Sync
do_ivec_spurious:
+ srl %g3, 3, %g3
+ sethi %hi(ivec_spurious_cookie), %g2
+ stx %g3, [%g2 + %lo(ivec_spurious_cookie)]
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pstate, %g5
+ wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
call report_spurious_ivec
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
clr %l6
-#endif /* __SMP__ */
.globl getcc, setcc
getcc:
floppy_dosoftint:
rdpr %pil, %g2
wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
b,pt %xcc, etrap_irq
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
mov 11, %o0
mov 0, %o1
cmp %g3, 1
bgu,a,pn %icc, winfix_mna
rdpr %tpc, %g3
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
call mem_address_unaligned
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
sys_vfork: mov SIGCHLD, %o0
clr %o1
sys_clone: mov %o7, %l5
-/*???*/ save %sp, -REGWIN_SZ, %sp
- flushw
-/*???*/ restore %g0, %g0, %g0
- rdpr %cwp, %o4
add %sp, STACK_BIAS + REGWIN_SZ, %o2
-
movrz %o1, %fp, %o1
- stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
call do_fork
mov %l5, %o7
#ifdef __SMP__
cmp %g1, NR_SYSCALLS ! IEU1 Group
bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
mov %i0, %o0 ! IEU0
- sll %g1, 3, %l4 ! IEU0 Group
+ sll %g1, 2, %l4 ! IEU0 Group
mov %i1, %o1 ! IEU1
- ldx [%l7 + %l4], %l7 ! Load
+ lduw [%l7 + %l4], %l7 ! Load
syscall_is_too_hard:
mov %i2, %o2 ! IEU0 Group
ldx [%curptr + AOFF_task_flags], %l5 ! Load
-/* $Id: etrap.S,v 1.30 1997/06/30 10:31:37 jj Exp $
+/* $Id: etrap.S,v 1.34 1997/08/08 08:33:40 jj Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
* Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
#define TASK_REGOFF ((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \
TRACEREG_SZ-REGWIN_SZ)
+/*
+ * On entry, %g7 is return address - 0x4.
+ * %g4 and %g5 will be preserved %l4 and %l5 respectively.
+ */
+
.text
.align 32
.globl etrap, etrap_irq, etraptl1
membar #Sync
sub %g2, (TRACEREG_SZ + REGWIN_SZ), %g2
-2: b,pt %xcc, etrap_after_fpu
+2: bne,pn %xcc, etrap_after_fpu
wr %g0, 0, %fprs
-3: /* Because Ultra lacks ASI_BLK_NUCLEUS a hack has to take place. */
- mov SECONDARY_CONTEXT, %g3
+ ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %g3
+ wr %g0, ASI_DMMU, %asi
+ nop
+ stxa %g3, [%g0 + SECONDARY_CONTEXT] %asi
+ flush %g2
+
+ b,pt %xcc, etrap_after_fpu
+ nop
+3: mov SECONDARY_CONTEXT, %g3
stxa %g0, [%g3] ASI_DMMU
flush %g2
wr %g0, ASI_BLK_S, %asi
- nop
-
b,pt %xcc, 1b
mov FPRS_FEF, %g3
- nop
+
etraptl1: rdpr %tstate, %g1
sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
ba,pt %xcc, etrap_maybe_fpu
-/* $Id: head.S,v 1.43 1997/07/07 03:05:25 davem Exp $
+/* $Id: head.S,v 1.46 1997/08/08 08:33:30 jj Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
#include <asm/processor.h>
#include <asm/lsu.h>
#include <asm/head.h>
+#include <asm/ttable.h>
/* This section from from _start to sparc64_boot_end should fit into
* 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
*/
wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
+#ifdef __SMP__
+ /* Ugly but necessary... */
+ sethi %hi(KERNBASE), %g7
+ sethi %hi(sparc64_cpu_startup), %g5
+ or %g5, %lo(sparc64_cpu_startup), %g5
+ sub %g5, %g7, %g5
+ sethi %hi(sparc64_cpu_startup_end), %g6
+ or %g6, %lo(sparc64_cpu_startup_end), %g6
+ sub %g6, %g7, %g6
+ sethi %hi(smp_trampoline), %g3
+ or %g3, %lo(smp_trampoline), %g3
+ sub %g3, %g7, %g3
+1: ldx [%g5], %g1
+ stx %g1, [%g3]
+ membar #StoreStore
+ flush %g3
+ add %g5, 8, %g5
+ cmp %g5, %g6
+ blu,pt %xcc, 1b
+ add %g3, 8, %g3
+#endif
+
create_mappings:
/* %g5 holds the tlb data */
sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
mov 0x40, %g2 /* INTR data 0 register */
/* Ok, we're done setting up all the state our trap mechanims needs,
- * now get back into normal globals and let the PROM know what it up.
+ * now get back into normal globals and let the PROM know what is up.
*/
wrpr %g0, %g0, %wstate
wrpr %o1, PSTATE_IE, %pstate
! 0x0000000000408000
#include "ttable.S"
+#include "systbls.S"
#include "etrap.S"
#include "rtrap.S"
#include "winfixup.S"
-/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
+/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
-/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
+/* $Id: ioport.c,v 1.12 1997/08/08 05:07:02 davem Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
u32 bus_type, int rdonly)
{
unsigned long vaddr, base_address;
- unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32);
+ unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32);
unsigned long offset = (addr & (~PAGE_MASK));
if (virtual) {
/* Tell Linux resource manager about the mapping */
request_region ((vaddr | offset), len, name);
} else {
- return __va(addr);
+ unsigned long vaddr = (unsigned long) __va(addr);
+
+ if(!check_region(vaddr, len))
+ request_region(vaddr, len, name);
+
+ return (void *) vaddr;
}
base_address = vaddr;
-/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
+/* $Id: irq.c,v 1.34 1997/08/15 06:44:18 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
#include <asm/hardirq.h>
#include <asm/softirq.h>
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#include <asm/pbm.h>
+#endif
+
/* Internal flag, should not be visible elsewhere at all. */
-#define SA_SYSIO_MASKED 0x100
+#define SA_IMAP_MASKED 0x100
+
+#ifdef __SMP__
+void distribute_irqs(void);
+static int irqs_have_been_distributed = 0;
+#endif
/* UPA nodes send interrupt packet to UltraSparc with first data reg value
* low 5 bits holding the IRQ identifier being delivered. We must translate
* make things even more swift we store the complete mask here.
*/
-#define NUM_IVECS 2048 /* XXX may need more on sunfire/wildfire */
+#define NUM_HARD_IVECS 2048
+#define NUM_IVECS (NUM_HARD_IVECS + 64) /* For SMP IRQ distribution alg. */
unsigned long ivector_to_mask[NUM_IVECS];
+struct ino_bucket {
+ struct ino_bucket *next;
+ unsigned int ino;
+ unsigned int *imap;
+ unsigned int *iclr;
+};
+
+#define INO_HASHSZ (NUM_HARD_IVECS >> 2)
+#define NUM_INO_STATIC 4
+static struct ino_bucket *ino_hash[INO_HASHSZ] = { NULL, };
+static struct ino_bucket static_ino_buckets[NUM_INO_STATIC];
+static int static_ino_bucket_count = 0;
+
+static inline struct ino_bucket *__ino_lookup(unsigned int hash, unsigned int ino)
+{
+ struct ino_bucket *ret = ino_hash[hash];
+
+ for(ret = ino_hash[hash]; ret && ret->ino != ino; ret = ret->next)
+ ;
+
+ return ret;
+}
+
+static inline struct ino_bucket *ino_lookup(unsigned int ino)
+{
+ return __ino_lookup((ino & (INO_HASHSZ - 1)), ino);
+}
+
/* This is based upon code in the 32-bit Sparc kernel written mostly by
* David Redman (djhr@tadpole.co.uk).
*/
return len;
}
-/* INO number to Sparc PIL level. */
-unsigned char ino_to_pil[] = {
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 0 */
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 1 */
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 2 */
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 3 */
+/* SBUS SYSIO INO number to Sparc PIL level. */
+unsigned char sysio_ino_to_pil[] = {
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */
3, /* Onboard SCSI */
5, /* Onboard Ethernet */
/*XXX*/ 8, /* Onboard BPP */
*/
#define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x)))
#define bogon ((unsigned long) -1)
-static unsigned long irq_offsets[] = {
+static unsigned long sysio_irq_offsets[] = {
/* SBUS Slot 0 --> 3, level 1 --> 7 */
offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
#undef bogon
-#define NUM_IRQ_ENTRIES (sizeof(irq_offsets) / sizeof(irq_offsets[0]))
+#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
-/* Convert an "interrupts" property IRQ level to an SBUS/SYSIO
- * Interrupt Mapping register pointer, or NULL if none exists.
+/* XXX Old compatability cruft, get rid of me when all drivers have been
+ * XXX converted to dcookie registry calls... -DaveM
*/
-static unsigned int *irq_to_imap(unsigned int irq)
+static unsigned int *sysio_irq_to_imap(unsigned int irq)
{
unsigned long offset;
struct sysio_regs *sregs;
if((irq == 14) ||
- (irq >= NUM_IRQ_ENTRIES) ||
- ((offset = irq_offsets[irq]) == ((unsigned long)-1)))
+ (irq >= NUM_SYSIO_OFFSETS) ||
+ ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1)))
return NULL;
sregs = SBus_chain->iommu->sysio_regs;
offset += ((unsigned long) sregs);
- return ((unsigned int *)offset) + 1;
+ return ((unsigned int *)offset);
}
/* Convert Interrupt Mapping register pointer to assosciated
- * Interrupt Clear register pointer.
+ * Interrupt Clear register pointer, SYSIO specific version.
*/
-static unsigned int *imap_to_iclr(unsigned int *imap)
+static unsigned int *sysio_imap_to_iclr(unsigned int *imap)
{
unsigned long diff;
#undef offset
-/* For non-SBUS IRQ's we do nothing, else we must enable them in the
- * appropriate SYSIO interrupt map registers.
+#ifdef CONFIG_PCI
+/* PCI PSYCHO INO number to Sparc PIL level. */
+unsigned char psycho_ino_to_pil[] = {
+ 7, 5, 5, 2, /* PCI A slot 0 Int A, B, C, D */
+ 7, 5, 5, 2, /* PCI A slot 1 Int A, B, C, D */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 6, 4, 3, 1, /* PCI B slot 0 Int A, B, C, D */
+ 6, 4, 3, 1, /* PCI B slot 1 Int A, B, C, D */
+ 6, 4, 3, 1, /* PCI B slot 2 Int A, B, C, D */
+ 6, 4, 3, 1, /* PCI B slot 3 Int A, B, C, D */
+ 3, /* SCSI */
+ 3, /* Ethernet */
+ 2, /* Parallel Port */
+ 8, /* Audio Record */
+ 7, /* Audio Playback */
+ 8, /* PowerFail */
+ 7, /* Keyboard/Mouse/Serial */
+ 8, /* Floppy */
+ 2, /* Spare Hardware */
+ 4, /* Keyboard */
+ 4, /* Mouse */
+ 7, /* Serial */
+ 6, /* Timer 0 */
+ 6, /* Timer 1 */
+ 8, /* Uncorrectable ECC */
+ 8, /* Correctable ECC */
+ 8, /* PCI Bus A Error */
+ 7, /* PCI Bus B Error */
+ 1, /* Power Management */
+};
+
+/* INO number to IMAP register offset for PSYCHO external IRQ's.
*/
-void enable_irq(unsigned int irq)
+#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x)))
+
+#define psycho_imap_offset(ino) \
+ ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \
+ (psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1)))
+
+#define psycho_iclr_offset(ino) \
+ ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \
+ (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f) << 3)))
+
+#endif
+
+/* Now these are always passed a true fully specified sun4u INO. */
+void enable_irq(unsigned int ino)
{
+ struct ino_bucket *bucket = ino_lookup(ino);
unsigned long tid;
unsigned int *imap;
- /* If this is for the tick interrupt, just ignore, note
- * that this is the one and only locally generated interrupt
- * source, all others come from external sources (essentially
- * any UPA device which is an interruptor). (actually, on
- * second thought Ultra can generate local interrupts for
- * async memory errors and we may setup handlers for those
- * at some point as well)
- *
- * XXX See commentary below in request_irq() this assumption
- * XXX is broken and needs to be fixed.
- */
- if(irq == 14)
+ if(!bucket)
return;
- /* Check for bogons. */
- imap = irq_to_imap(irq);
- if(imap == NULL)
- goto do_the_stb_watoosi;
+ imap = bucket->imap;
/* We send it to our UPA MID, for SMP this will be different. */
__asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
* Register, the hardware just mirrors that value here.
* However for Graphics and UPA Slave devices the full
* SYSIO_IMAP_INR field can be set by the programmer here.
- * (XXX we will have to handle those for FFB etc. XXX)
+ *
+ * Things like FFB can now be handled via the dcookie mechanism.
*/
*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
- return;
-
-do_the_stb_watoosi:
- printk("Cannot enable irq(%d), doing the \"STB Watoosi\" instead.", irq);
- panic("Trying to enable bogon IRQ");
}
-void disable_irq(unsigned int irq)
+/* This now gets passed true ino's as well. */
+void disable_irq(unsigned int ino)
{
+ struct ino_bucket *bucket = ino_lookup(ino);
unsigned int *imap;
- /* XXX Grrr, I know this is broken... */
- if(irq == 14)
+ if(!bucket)
return;
- /* Check for bogons. */
- imap = irq_to_imap(irq);
- if(imap == NULL)
- goto do_the_stb_watoosi;
+ imap = bucket->imap;
/* NOTE: We do not want to futz with the IRQ clear registers
* and move the state to IDLE, the SCSI code does call
* SCSI adapter driver code. Thus we'd lose interrupts.
*/
*imap &= ~(SYSIO_IMAP_VALID);
- return;
+}
+
+static void get_irq_translations(int *cpu_irq, int *ivindex_fixup,
+ unsigned int **imap, unsigned int **iclr,
+ void *busp, unsigned long flags,
+ unsigned int irq)
+{
+ if(*cpu_irq != -1 && *imap != NULL && *iclr != NULL)
+ return;
-do_the_stb_watoosi:
- printk("Cannot disable irq(%d), doing the \"STB Watoosi\" instead.", irq);
- panic("Trying to enable bogon IRQ");
+ if(*cpu_irq != -1 || *imap != NULL || *iclr != NULL || busp == NULL) {
+ printk("get_irq_translations: Partial specification, this is bad.\n");
+ printk("get_irq_translations: cpu_irq[%d] imap[%p] iclr[%p] busp[%p]\n",
+ *cpu_irq, *imap, *iclr, busp);
+ panic("Bad IRQ translations...");
+ }
+
+ if(SA_BUS(flags) == SA_SBUS) {
+ struct linux_sbus *sbusp = busp;
+ struct sysio_regs *sregs = sbusp->iommu->sysio_regs;
+ unsigned long offset;
+
+ *cpu_irq = sysio_ino_to_pil[irq];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: Bad SYSIO INO[%x]\n", irq);
+ panic("Bad SYSIO IRQ translations...");
+ }
+ offset = sysio_irq_offsets[irq];
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
+ irq, *cpu_irq);
+ panic("BAD SYSIO IRQ offset...");
+ }
+ offset += ((unsigned long)sregs);
+ *imap = ((unsigned int *)offset);
+
+ /* SYSIO inconsistancy. For external SLOTS, we have to select
+ * the right ICLR register based upon the lower SBUS irq level
+ * bits.
+ */
+ if(irq >= 0x20) {
+ *iclr = sysio_imap_to_iclr(*imap);
+ } else {
+ unsigned long iclraddr;
+ int sbus_slot = (irq & 0x18)>>3;
+ int sbus_level = irq & 0x7;
+
+ switch(sbus_slot) {
+ case 0:
+ *iclr = &sregs->iclr_slot0;
+ break;
+ case 1:
+ *iclr = &sregs->iclr_slot1;
+ break;
+ case 2:
+ *iclr = &sregs->iclr_slot2;
+ break;
+ case 3:
+ *iclr = &sregs->iclr_slot3;
+ break;
+ };
+
+ iclraddr = (unsigned long) *iclr;
+ iclraddr += ((sbus_level - 1) * 8);
+ *iclr = (unsigned int *) iclraddr;
+
+#if 0 /* DEBUGGING */
+ printk("SYSIO_FIXUP: slot[%x] level[%x] iclr[%p] ",
+ sbus_slot, sbus_level, *iclr);
+#endif
+
+ /* Also, make sure this is accounted for in ivindex
+ * computations done by the caller.
+ */
+ *ivindex_fixup = sbus_level;
+ }
+ return;
+ }
+#ifdef CONFIG_PCI
+ if(SA_BUS(flags) == SA_PCI) {
+ struct pci_bus *pbusp = busp;
+ struct linux_pbm_info *pbm = pbusp->sysdata;
+ struct psycho_regs *pregs = pbm->parent->psycho_regs;
+ unsigned long offset;
+
+ *cpu_irq = psycho_ino_to_pil[irq & 0x3f];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: Bad PSYCHO INO[%x]\n", irq);
+ panic("Bad PSYCHO IRQ translations...");
+ }
+ offset = psycho_imap_offset(irq);
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad PSYCHO INO[%x] cpu[%d]\n",
+ irq, *cpu_irq);
+ panic("Bad PSYCHO IRQ offset...");
+ }
+ offset += ((unsigned long)pregs);
+ *imap = ((unsigned int *)offset) + 1;
+ *iclr = (unsigned int *)
+ (((unsigned long)pregs) + psycho_imap_offset(irq));
+ return;
+ }
+#endif
+#if 0 /* XXX More to do before we can use this. -DaveM */
+ if(SA_BUS(flags) == SA_FHC) {
+ struct fhc_bus *fbusp = busp;
+ struct fhc_regs *fregs = fbusp->regs;
+ unsigned long offset;
+
+ *cpu_irq = fhc_ino_to_pil[irq];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: Bad FHC INO[%x]\n", irq);
+ panic("Bad FHC IRQ translations...");
+ }
+ offset = fhc_irq_offset[*cpu_irq];
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad FHC INO[%x] cpu[%d]\n",
+ irq, *cpu_irq);
+ panic("Bad FHC IRQ offset...");
+ }
+ offset += ((unsigned long)pregs);
+ *imap = (((unsigned int *)offset)+1);
+ *iclr = fhc_imap_to_iclr(*imap);
+ return;
+ }
+#endif
+ printk("get_irq_translations: IRQ register for unknown bus type.\n");
+ printk("get_irq_translations: BUS[%lx] IRQ[%x]\n",
+ SA_BUS(flags), irq);
+ panic("Bad IRQ bus type...");
+}
+
+/* Once added, they are never removed. */
+static struct ino_bucket *add_ino_hash(unsigned int ivindex,
+ unsigned int *imap, unsigned int *iclr,
+ unsigned long flags)
+{
+ struct ino_bucket *new = NULL, **hashp;
+ unsigned int hash = (ivindex & (INO_HASHSZ - 1));
+
+ new = __ino_lookup(hash, ivindex);
+ if(new)
+ return new;
+ if(flags & SA_STATIC_ALLOC) {
+ if(static_ino_bucket_count < NUM_INO_STATIC)
+ new = &static_ino_buckets[static_ino_bucket_count++];
+ else
+ printk("Request for ino bucket SA_STATIC_ALLOC failed "
+ "using kmalloc\n");
+ }
+ if(new == NULL)
+ new = kmalloc(sizeof(struct ino_bucket), GFP_KERNEL);
+ if(new) {
+ hashp = &ino_hash[hash];
+ new->imap = imap;
+ new->iclr = iclr;
+ new->ino = ivindex;
+ new->next = *hashp;
+ *hashp = new;
+ }
+ return new;
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char *name, void *dev_cookie)
+ unsigned long irqflags, const char *name, void *dev_id)
{
struct irqaction *action, *tmp = NULL;
+ struct devid_cookie *dcookie = NULL;
+ struct ino_bucket *bucket = NULL;
unsigned long flags;
- unsigned int cpu_irq, *imap, *iclr;
+ unsigned int *imap, *iclr;
+ void *bus_id = NULL;
+ int ivindex, ivindex_fixup, cpu_irq = -1;
- /* XXX This really is not the way to do it, the "right way"
- * XXX is to have drivers set SA_SBUS or something like that
- * XXX in irqflags and we base our decision here on whether
- * XXX that flag bit is set or not.
- */
- if(irq == 14)
- cpu_irq = irq;
- else
- cpu_irq = ino_to_pil[irq];
-
if(!handler)
return -EINVAL;
- imap = irq_to_imap(irq);
+ imap = iclr = NULL;
+
+ ivindex_fixup = 0;
+ if(irqflags & SA_DCOOKIE) {
+ if(!dev_id) {
+ printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
+ panic("Bogus irq registry.");
+ }
+ dcookie = dev_id;
+ dev_id = dcookie->real_dev_id;
+ cpu_irq = dcookie->pil;
+ imap = dcookie->imap;
+ iclr = dcookie->iclr;
+ bus_id = dcookie->bus_cookie;
+ get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
+ &iclr, bus_id, irqflags, irq);
+ } else {
+ /* XXX NOTE: This code is maintained for compatability until I can
+ * XXX verify that all drivers sparc64 will use are updated
+ * XXX to use the new IRQ registry dcookie interface. -DaveM
+ */
+ if(irq == 14)
+ cpu_irq = irq;
+ else
+ cpu_irq = sysio_ino_to_pil[irq];
+ imap = sysio_irq_to_imap(irq);
+ if(!imap) {
+ printk("request_irq: BAD, null imap for old style "
+ "irq registry IRQ[%x].\n", irq);
+ panic("Bad IRQ registery...");
+ }
+ iclr = sysio_imap_to_iclr(imap);
+ }
+ ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+ ivindex += ivindex_fixup;
action = *(cpu_irq + irq_action);
if(action) {
return -ENOMEM;
}
- if(imap) {
- int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+ bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
+ if(!bucket) {
+ kfree(action);
+ restore_flags(flags);
+ return -ENOMEM;
+ }
- ivector_to_mask[ivindex] = (1<<cpu_irq);
- iclr = imap_to_iclr(imap);
- action->mask = (unsigned long) iclr;
- irqflags |= SA_SYSIO_MASKED;
- } else {
- action->mask = 0;
+ ivector_to_mask[ivindex] = (1 << cpu_irq);
+
+ if(dcookie) {
+ dcookie->ret_ino = ivindex;
+ dcookie->ret_pil = cpu_irq;
}
+ action->mask = (unsigned long) bucket;
action->handler = handler;
- action->flags = irqflags;
+ action->flags = irqflags | SA_IMAP_MASKED;
action->name = name;
action->next = NULL;
- action->dev_id = dev_cookie;
+ action->dev_id = dev_id;
if(tmp)
tmp->next = action;
else
*(cpu_irq + irq_action) = action;
- enable_irq(irq);
+ enable_irq(ivindex);
restore_flags(flags);
+#ifdef __SMP__
+ if(irqs_have_been_distributed)
+ distribute_irqs();
+#endif
return 0;
}
-void free_irq(unsigned int irq, void *dev_cookie)
+void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction *action;
struct irqaction *tmp = NULL;
unsigned long flags;
unsigned int cpu_irq;
+ int ivindex = -1;
if(irq == 14)
cpu_irq = irq;
else
- cpu_irq = ino_to_pil[irq];
+ cpu_irq = sysio_ino_to_pil[irq];
action = *(cpu_irq + irq_action);
if(!action->handler) {
printk("Freeing free IRQ %d\n", irq);
return;
}
- if(dev_cookie) {
+ if(dev_id) {
for( ; action; action = action->next) {
- if(action->dev_id == dev_cookie)
+ if(action->dev_id == dev_id)
break;
tmp = action;
}
return;
}
} else if(action->flags & SA_SHIRQ) {
- printk("Trying to free shared IRQ %d with NULL device cookie\n", irq);
+ printk("Trying to free shared IRQ %d with NULL device ID\n", irq);
return;
}
else
*(cpu_irq + irq_action) = action->next;
- if(action->flags & SA_SYSIO_MASKED) {
- unsigned int *imap = irq_to_imap(irq);
- if(imap != NULL)
- ivector_to_mask[*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)] = 0;
+ if(action->flags & SA_IMAP_MASKED) {
+ struct ino_bucket *bucket = (struct ino_bucket *)action->mask;
+ unsigned int *imap = bucket->imap;
+
+ if(imap != NULL) {
+ ivindex = bucket->ino;
+ ivector_to_mask[ivindex] = 0;
+ }
else
printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n");
}
kfree(action);
- if(!*(cpu_irq + irq_action))
- disable_irq(irq);
+ if(ivindex != -1)
+ disable_irq(ivindex);
restore_flags(flags);
}
-/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
-unsigned int local_irq_count[NR_CPUS];
+/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu
+ * structure for cache reasons.
+ */
+#ifndef __SMP__
+unsigned int local_irq_count;
+#endif
#ifndef __SMP__
int __sparc64_bh_counter = 0;
-#define irq_enter(cpu, irq) (local_irq_count[cpu]++)
-#define irq_exit(cpu, irq) (local_irq_count[cpu]--)
+#define irq_enter(cpu, irq) (local_irq_count++)
+#define irq_exit(cpu, irq) (local_irq_count--)
#else
/* Global IRQ locking depth. */
atomic_t global_irq_count = ATOMIC_INIT(0);
-static inline void wait_on_irq(int cpu)
+static unsigned long previous_irqholder;
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+
+static inline void wait_on_irq(int cpu, unsigned long where)
{
- int local_count = local_irq_count[cpu];
+ int stuck = INIT_STUCK;
+ int local_count = local_irq_count;
while(local_count != atomic_read(&global_irq_count)) {
atomic_sub(local_count, &global_irq_count);
spin_unlock(&global_irq_lock);
for(;;) {
+ STUCK;
+ membar("#StoreLoad | #LoadLoad");
if (atomic_read(&global_irq_count))
continue;
- if (*((unsigned char *)&global_irq_lock))
+ if (*((volatile unsigned char *)&global_irq_lock))
continue;
+ membar("#LoadLoad | #LoadStore");
if (spin_trylock(&global_irq_lock))
break;
}
}
}
-static inline void get_irqlock(int cpu)
+#undef INIT_STUCK
+#define INIT_STUCK 10000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+
+static inline void get_irqlock(int cpu, unsigned long where)
{
+ int stuck = INIT_STUCK;
+
if (!spin_trylock(&global_irq_lock)) {
+ membar("#StoreLoad | #LoadLoad");
if ((unsigned char) cpu == global_irq_holder)
return;
do {
- barrier();
+ do {
+ STUCK;
+ membar("#LoadLoad");
+ } while(*((volatile unsigned char *)&global_irq_lock));
} while (!spin_trylock(&global_irq_lock));
}
- wait_on_irq(cpu);
+ wait_on_irq(cpu, where);
global_irq_holder = cpu;
+ previous_irqholder = where;
}
void __global_cli(void)
{
int cpu = smp_processor_id();
+ unsigned long where;
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (where));
__cli();
- get_irqlock(cpu);
+ get_irqlock(cpu, where);
}
void __global_sti(void)
__sti();
}
-unsigned long __global_save_flags(void)
-{
- return global_irq_holder == (unsigned char) smp_processor_id();
-}
-
void __global_restore_flags(unsigned long flags)
{
if (flags & 1) {
}
}
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
+
void irq_enter(int cpu, int irq)
{
+ int stuck = INIT_STUCK;
+
hardirq_enter(cpu);
- barrier();
- while (*((unsigned char *)&global_irq_lock)) {
+ while (*((volatile unsigned char *)&global_irq_lock)) {
if ((unsigned char) cpu == global_irq_holder)
printk("irq_enter: Frosted Lucky Charms, "
"they're magically delicious!\n");
- barrier();
+ STUCK;
+ membar("#LoadLoad");
}
}
void synchronize_irq(void)
{
- int cpu = smp_processor_id();
- int local_count = local_irq_count[cpu];
+ int local_count = local_irq_count;
unsigned long flags;
if (local_count != atomic_read(&global_irq_count)) {
void report_spurious_ivec(struct pt_regs *regs)
{
- printk("IVEC: Spurious interrupt vector received at (%016lx)\n",
- regs->tpc);
+ extern unsigned long ivec_spurious_cookie;
+
+ printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n",
+ ivec_spurious_cookie, regs->tpc);
return;
}
irq_enter(cpu, irq);
action = *(irq + irq_action);
kstat.interrupts[irq]++;
- do {
- if(!action || !action->handler)
- unexpected_irq(irq, 0, regs);
- action->handler(irq, action->dev_id, regs);
- if(action->flags & SA_SYSIO_MASKED)
- *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
- } while((action = action->next) != NULL);
+ if(!action) {
+ unexpected_irq(irq, 0, regs);
+ } else {
+ do {
+ action->handler(irq, action->dev_id, regs);
+ if(action->flags & SA_IMAP_MASKED) {
+ struct ino_bucket *bucket =
+ (struct ino_bucket *)action->mask;
+
+ *(bucket->iclr) = SYSIO_ICLR_IDLE;
+ membar("#MemIssue");
+ }
+ } while((action = action->next) != NULL);
+ }
irq_exit(cpu, irq);
}
irq_enter(cpu, irq);
floppy_interrupt(irq, dev_cookie, regs);
- if(action->flags & SA_SYSIO_MASKED)
+ if(action->flags & SA_IMAP_MASKED)
*((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
irq_exit(cpu, irq);
}
insns[0] = SPARC_BRANCH(((unsigned long) handler),
((unsigned long)&insns[0]));
insns[1] = SPARC_NOP;
- __asm__ __volatile__("flush %0" : : "r" (ttent));
+ __asm__ __volatile__("membar #StoreStore; flush %0" : : "r" (ttent));
}
int request_fast_irq(unsigned int irq,
struct irqaction *action;
unsigned long flags;
unsigned int cpu_irq, *imap, *iclr;
+ int ivindex = -1;
/* XXX This really is not the way to do it, the "right way"
* XXX is to have drivers set SA_SBUS or something like that
*/
if(irq == 14)
return -EINVAL;
- cpu_irq = ino_to_pil[irq];
+ cpu_irq = sysio_ino_to_pil[irq];
if(!handler)
return -EINVAL;
- imap = irq_to_imap(irq);
+ imap = sysio_irq_to_imap(irq);
action = *(cpu_irq + irq_action);
if(action) {
if(action->flags & SA_SHIRQ)
install_fast_irq(cpu_irq, handler);
if(imap) {
- int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
-
+ ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
ivector_to_mask[ivindex] = (1 << cpu_irq);
- iclr = imap_to_iclr(imap);
+ iclr = sysio_imap_to_iclr(imap);
action->mask = (unsigned long) iclr;
- irqflags |= SA_SYSIO_MASKED;
+ irqflags |= SA_IMAP_MASKED;
+ add_ino_hash(ivindex, imap, iclr, irqflags);
} else
action->mask = 0;
*(cpu_irq + irq_action) = action;
- enable_irq(irq);
+ if(ivindex != -1)
+ enable_irq(ivindex);
+
restore_flags(flags);
return 0;
}
*/
unsigned long probe_irq_on(void)
{
- return 0;
+ return 0;
}
int probe_irq_off(unsigned long mask)
{
- return 0;
+ return 0;
}
struct sun5_timer *linux_timers = NULL;
-/* This is called from sbus_init() to get the jiffies timer going.
- * We need to call this after there exists a valid SBus_chain so
- * that the IMAP/ICLR registers can be accessed.
- *
- * XXX That is because the whole startup sequence is broken. I will
- * XXX fix it all up very soon. -DaveM
- */
+/* This is gets the master level10 timer going. */
void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
{
struct linux_prom64_registers pregs[3];
+ struct devid_cookie dcookie;
+ unsigned int *imap, *iclr;
u32 pirqs[2];
int node, err;
node = prom_finddevice("/counter-timer");
- if(node == 0) {
+ if(node == 0 || node == -1) {
prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
prom_halt();
}
prom_halt();
}
linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
+ iclr = (((unsigned int *)__va(pregs[1].phys_addr))+1);
+ imap = (((unsigned int *)__va(pregs[2].phys_addr))+1);
/* Shut it up first. */
linux_timers->limit0 = 0;
/* Register IRQ handler. */
- err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
- cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
+ dcookie.real_dev_id = NULL;
+ dcookie.imap = imap;
+ dcookie.iclr = iclr;
+ dcookie.pil = 10;
+ dcookie.bus_cookie = NULL;
+
+ err = request_irq(pirqs[0], cfunc,
+ (SA_DCOOKIE | SA_INTERRUPT | SA_STATIC_ALLOC),
+ "timer", &dcookie);
if(err) {
prom_printf("Serious problem, cannot register timer interrupt\n");
prom_timers->count0 = 0;
}
+#ifdef __SMP__
+/* Called from smp_commence, when we know how many cpus are in the system
+ * and can have device IRQ's directed at them.
+ */
+void distribute_irqs(void)
+{
+ unsigned long flags;
+ int cpu, level;
+
+ printk("SMP: redistributing interrupts...\n");
+ save_and_cli(flags);
+ cpu = 0;
+ for(level = 0; level < NR_IRQS; level++) {
+ struct irqaction *p = irq_action[level];
+
+ while(p) {
+ if(p->flags & SA_IMAP_MASKED) {
+ struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
+ unsigned int *imap = bucket->imap;
+ unsigned int val;
+ unsigned long tid = linux_cpus[cpu].mid << 9;
+
+ val = *imap;
+ *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+
+ printk("SMP: Redirecting IGN[%x] INO[%x] "
+ "to cpu %d [%s]\n",
+ (val & SYSIO_IMAP_IGN) >> 6,
+ (val & SYSIO_IMAP_INO), cpu,
+ p->name);
+
+ cpu += 1;
+ while(!(cpu_present_map & (1UL << cpu))) {
+ cpu += 1;
+ if(cpu >= smp_num_cpus)
+ cpu = 0;
+ }
+ }
+ p = p->next;
+ }
+ }
+ restore_flags(flags);
+ irqs_have_been_distributed = 1;
+}
+#endif
+
__initfunc(void init_IRQ(void))
{
int i;
-/* $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
+/* $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
#include <linux/a.out.h>
#include <linux/config.h>
#include <linux/reboot.h>
+#include <linux/delay.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/delay.h>
#include <asm/processor.h>
#include <asm/pstate.h>
#include <asm/elf.h>
#include <asm/fpumacro.h>
+#define PGTCACHE_HIGH_WATER 50
+#define PGTCACHE_LOW_WATER 25
+
#ifndef __SMP__
/*
current->priority = -100;
current->counter = -100;
for (;;) {
+ if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+ do {
+ if(pgd_quicklist)
+ free_page((unsigned long) get_pgd_fast());
+ if(pmd_quicklist)
+ free_page((unsigned long) get_pmd_fast());
+ if(pte_quicklist)
+ free_page((unsigned long) get_pte_fast());
+ } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+ }
run_task_queue(&tq_scheduler);
schedule();
}
{
current->priority = -100;
while(1) {
+ if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+ do {
+ if(pgd_quicklist)
+ free_page((unsigned long) get_pgd_fast());
+ if(pmd_quicklist)
+ free_page((unsigned long) get_pmd_fast());
+ if(pte_quicklist)
+ free_page((unsigned long) get_pte_fast());
+ } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+ }
if(tq_scheduler) {
lock_kernel();
run_task_queue(&tq_scheduler);
unlock_kernel();
}
+ barrier();
current->counter = -100;
- schedule();
+ if(resched_needed())
+ schedule();
+ barrier();
}
}
} while ((size -= sizeof(unsigned)));
}
-void show_regs(struct pt_regs * regs)
+#ifdef __SMP__
+static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+void __show_regs(struct pt_regs * regs)
{
+#ifdef __SMP__
+ unsigned long flags;
+
+ spin_lock_irqsave(®dump_lock, flags);
+ printk("CPU[%d]: local_irq_count[%ld] global_irq_count[%d]\n",
+ smp_processor_id(), local_irq_count,
+ atomic_read(&global_irq_count));
+#endif
printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
regs->tpc, regs->tnpc, regs->y);
printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
regs->u_regs[15]);
show_regwindow(regs);
+#ifdef __SMP__
+ spin_unlock_irqrestore(®dump_lock, flags);
+#endif
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ __show_regs(regs);
+#ifdef __SMP__
+ {
+ extern void smp_report_regs(void);
+
+ smp_report_regs();
+ }
+#endif
}
void show_regs32(struct pt_regs32 *regs)
/* Now, this task is no longer a kernel thread. */
current->tss.current_ds = USER_DS;
if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+ extern spinlock_t scheduler_lock;
+
current->tss.flags &= ~SPARC_FLAG_KTHREAD;
/* exec_mmap() set context to NO_CONTEXT, here is
* where we grab a new one.
*/
+ spin_lock(&scheduler_lock);
get_mmu_context(current);
+ spin_unlock(&scheduler_lock);
}
current->tss.ctx = current->mm->context & 0x1fff;
spitfire_set_secondary_context (current->tss.ctx);
struct reg_window *rwin = &tp->reg_window[window];
if(copy_to_user((char *)sp, rwin, winsize))
- do_exit(SIGILL);
+ goto barf;
} while(window--);
}
current->tss.w_saved = 0;
+ return;
+barf:
+ lock_kernel();
+ do_exit(SIGILL);
}
/* Copy a Sparc thread. The fork() return value conventions
p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
#endif
p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
- p->tss.cwp = regs->u_regs[UREG_G0];
+ p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
if(regs->tstate & TSTATE_PRIV) {
p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
p->tss.flags |= SPARC_FLAG_KTHREAD;
--- /dev/null
+/* $Id: psycho.c,v 1.5 1997/08/15 06:44:18 davem Exp $
+ * psycho.c: Ultra/AX U2P PCI controller support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/ebus.h>
+#include <asm/sbus.h> /* for sanity check... */
+
+#ifndef CONFIG_PCI
+
+int pcibios_present(void)
+{
+ return 0;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ return 0;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ return 0;
+}
+
+#else
+
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/oplib.h>
+#include <asm/pbm.h>
+#include <asm/uaccess.h>
+
+struct linux_psycho *psycho_root = NULL;
+
+/* This is used to make the scan_bus in the generic PCI code be
+ * a nop, as we need to control the actual bus probing sequence.
+ * After that we leave it on of course.
+ */
+static int pci_probe_enable = 0;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+ return ((addr + (sizeof(unsigned long) - 1)) &
+ ~(sizeof(unsigned long) - 1));
+}
+
+extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
+
+unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+{
+ struct linux_prom64_registers pr_regs[3];
+ char namebuf[128];
+ u32 portid;
+ int node;
+
+ /* prom_printf("PSYCHO: Probing for controllers.\n"); */
+ printk("PSYCHO: Probing for controllers.\n");
+
+ memory_start = long_align(memory_start);
+ node = prom_getchild(prom_root_node);
+ while((node = prom_searchsiblings(node, "pci")) != 0) {
+ struct linux_psycho *psycho = (struct linux_psycho *)memory_start;
+ struct linux_psycho *search;
+ struct linux_pbm_info *pbm = NULL;
+ u32 busrange[2];
+ int err, is_pbm_a;
+
+ portid = prom_getintdefault(node, "upa-portid", 0xff);
+ for(search = psycho_root; search; search = search->next) {
+ if(search->upa_portid == portid) {
+ psycho = search;
+
+ /* This represents _this_ instance, so it's
+ * which ever one does _not_ have the prom node
+ * info filled in yet.
+ */
+ is_pbm_a = (psycho->pbm_A.prom_node == 0);
+ goto other_pbm;
+ }
+ }
+
+ memory_start = long_align(memory_start + sizeof(struct linux_psycho));
+
+ memset(psycho, 0, sizeof(*psycho));
+
+ psycho->next = psycho_root;
+ psycho_root = psycho;
+
+ psycho->upa_portid = portid;
+
+ /* Map in PSYCHO register set and report the presence of this PSYCHO. */
+ err = prom_getproperty(node, "reg",
+ (char *)&pr_regs[0], sizeof(pr_regs));
+ if(err == 0 || err == -1) {
+ prom_printf("PSYCHO: Error, cannot get U2P registers "
+ "from PROM.\n");
+ prom_halt();
+ }
+
+ /* Third REG in property is base of entire PSYCHO register space. */
+ psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
+ NULL, sizeof(struct psycho_regs),
+ "PSYCHO Registers",
+ (pr_regs[2].phys_addr >> 32), 0);
+ if(psycho->psycho_regs == NULL) {
+ prom_printf("PSYCHO: Error, cannot map PSYCHO "
+ "main registers.\n");
+ prom_halt();
+ }
+
+ prom_printf("PSYCHO: Found controller, main regs at %p\n",
+ psycho->psycho_regs);
+ printk("PSYCHO: Found controller, main regs at %p\n",
+ psycho->psycho_regs);
+
+ /* Now map in PCI config space for entire PSYCHO. */
+ psycho->pci_config_space =
+ sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000),
+ NULL, 0x01000000,
+ "PCI Config Space",
+ (pr_regs[2].phys_addr >> 32), 0);
+ if(psycho->pci_config_space == NULL) {
+ prom_printf("PSYCHO: Error, cannot map PCI config space.\n");
+ prom_halt();
+ }
+
+ /* Finally map in I/O space for both PBM's. This is essentially
+ * backwards compatability for non-conformant PCI cards which
+ * do not map themselves into the PCI memory space.
+ */
+ psycho->pbm_B.pbm_IO = __va(pr_regs[2].phys_addr + 0x02000000UL);
+ psycho->pbm_A.pbm_IO = __va(pr_regs[2].phys_addr + 0x02010000UL);
+
+ /* Now record MEM space for both PBM's.
+ *
+ * XXX Eddie, these can be reversed if BOOT_BUS pin is clear, is
+ * XXX there some way to find out what value of BOOT_BUS pin is?
+ */
+ psycho->pbm_B.pbm_mem = __va(pr_regs[2].phys_addr + 0x180000000UL);
+ psycho->pbm_A.pbm_mem = __va(pr_regs[2].phys_addr + 0x100000000UL);
+
+ /* Report some more info. */
+ prom_printf("PSYCHO: PCI config space at %p\n",
+ psycho->pci_config_space);
+ prom_printf("PSYCHO: PBM A I/O space at %p, PBM B I/O at %p\n",
+ psycho->pbm_A.pbm_IO, psycho->pbm_B.pbm_IO);
+ prom_printf("PSYCHO: PBM A MEM at %p, PBM B MEM at %p\n");
+
+ printk("PSYCHO: PCI config space at %p\n", psycho->pci_config_space);
+ printk("PSYCHO: PBM A I/O space at %p, PBM B I/O at %p\n",
+ psycho->pbm_A.pbm_IO, psycho->pbm_B.pbm_IO);
+
+ is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
+
+ other_pbm:
+ if(is_pbm_a)
+ pbm = &psycho->pbm_A;
+ else
+ pbm = &psycho->pbm_B;
+
+ pbm->parent = psycho;
+ pbm->prom_node = node;
+
+ prom_getstring(node, "name", namebuf, sizeof(namebuf));
+ strcpy(pbm->prom_name, namebuf);
+
+ /* Now the ranges. */
+ prom_pbm_ranges_init(node, pbm);
+
+ /* Finally grab the pci bus root array for this pbm after
+ * having found the bus range existing under it.
+ */
+ err = prom_getproperty(node, "bus-range",
+ (char *)&busrange[0], sizeof(busrange));
+ if(err == 0 || err == -1) {
+ prom_printf("PSYCHO: Error, cannot get PCI bus range.\n");
+ prom_halt();
+ }
+ pbm->pci_first_busno = busrange[0];
+ pbm->pci_last_busno = busrange[1];
+ memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
+
+ node = prom_getsibling(node);
+ if(!node)
+ break;
+ }
+
+ /* Last minute sanity check. */
+ if(psycho_root == NULL && SBus_chain == NULL) {
+ prom_printf("Fatal error, neither SBUS nor PCI bus found.\n");
+ prom_halt();
+ }
+
+ return memory_start;
+}
+
+int pcibios_present(void)
+{
+ return psycho_root != NULL;
+}
+
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->vendor == vendor && dev->device == device_id) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pcibios_find_class (unsigned int class_code, unsigned short index,
+ unsigned char *bus, unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->class == class_code) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
+{
+ struct pci_bus *pbus = &pbm->pci_bus;
+
+ /* PSYCHO PBM's include child PCI bridges in bus-range property,
+ * but we don't scan each of those ourselves, Linux generic PCI
+ * probing code will find child bridges and link them into this
+ * pbm's root PCI device hierarchy.
+ */
+ pbus->number = pbm->pci_first_busno;
+ pbus->sysdata = pbm;
+ pbus->subordinate = pci_scan_bus(pbus, mstart);
+}
+
+static void fill_in_pbm_cookies(struct linux_pbm_info *pbm)
+{
+ struct pci_bus *pbtmp, *pbus = &pbm->pci_bus;
+ struct pci_dev *pdev;
+
+ for(pbtmp = pbus->children; pbtmp; pbtmp = pbtmp->children)
+ pbtmp->sysdata = pbm;
+
+ for( ; pbus; pbus = pbus->children)
+ for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ pdev->sysdata = pbm;
+}
+
+static void fixup_pci_dev(struct pci_dev *pdev,
+ struct pci_bus *pbus,
+ struct linux_pbm_info *pbm)
+{
+ struct linux_prom_pci_registers pregs[PROMREG_MAX];
+ int node;
+#if 0
+ int nregs, busno = pbus->number;
+#endif
+
+ node = prom_getchild(pbm->prom_node);
+ while(node) {
+ u32 devfn;
+ int err, nregs;
+
+ err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+ if(err == 0 || err == -1) {
+ prom_printf("fixup_pci_dev: No PCI device reg property?!?!\n");
+ prom_halt();
+ }
+ nregs = (err / sizeof(struct linux_prom_pci_registers));
+
+ devfn = (pregs[0].phys_hi >> 8) & 0xff;
+ if(devfn == pdev->devfn) {
+
+ return;
+ }
+
+ node = prom_getsibling(node);
+ }
+
+ prom_printf("fixup_pci_dev: Cannot find prom node for PCI device\n");
+ prom_halt();
+}
+
+static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
+{
+ struct pci_dev *pdev;
+
+ for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ fixup_pci_dev(pdev, pbus, pbm);
+
+ for(pbus = pbus->children; pbus; pbus = pbus->children)
+ fixup_pci_bus(pbus, pbm);
+}
+
+static void fixup_addr_irq(struct linux_pbm_info *pbm)
+{
+ struct pci_bus *pbus = &pbm->pci_bus;
+
+ /* Work through top level devices (not bridges, those and their
+ * devices are handled specially in the next loop).
+ */
+ fixup_pci_bus(pbus, pbm);
+}
+
+/* Walk all PCI devices probes, fixing up base registers and IRQ registers.
+ * We use OBP for most of this work.
+ */
+static void psycho_final_fixup(struct linux_psycho *psycho)
+{
+ /* First, walk all PCI devices found. For each device, and
+ * PCI bridge which is not one of the PSYCHO PBM's, fill in the
+ * sysdata with a pointer to the PBM.
+ */
+ fill_in_pbm_cookies(&psycho->pbm_A);
+ fill_in_pbm_cookies(&psycho->pbm_B);
+
+ /* Second, fixup base address registers and IRQ lines... */
+ fixup_addr_irq(&psycho->pbm_A);
+ fixup_addr_irq(&psycho->pbm_B);
+}
+
+unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end)
+{
+ struct linux_psycho *psycho = psycho_root;
+
+ pci_probe_enable = 1;
+
+ /* XXX Really this should be per-PSYCHO, but the config space
+ * XXX reads and writes give us no way to know which PSYCHO
+ * XXX in which the config space reads should occur.
+ * XXX
+ * XXX Further thought says that we cannot change this generic
+ * XXX interface, else we'd break xfree86 and other parts of the
+ * XXX kernel (but whats more important is breaking userland for
+ * XXX the ix86/Alpha/etc. people). So we should define our own
+ * XXX internal extension initially, we can compile our own user
+ * XXX apps that need to get at PCI configuration space.
+ */
+
+ /* Probe busses under PBM A. */
+ pbm_probe(&psycho->pbm_A, &memory_start);
+
+ /* Probe busses under PBM B. */
+ pbm_probe(&psycho->pbm_B, &memory_start);
+
+
+ psycho_final_fixup(psycho);
+
+ return ebus_init(memory_start, memory_end);
+}
+
+/* "PCI: The emerging standard..." 8-( */
+volatile int pci_poke_in_progress = 0;
+volatile int pci_poke_faulted = 0;
+
+/* XXX Current PCI support code is broken, it assumes one master PCI config
+ * XXX space exists, on Ultra we can have many of them, especially with
+ * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire.
+ */
+static char *pci_mkaddr(unsigned char bus, unsigned char device_fn,
+ unsigned char where)
+{
+ unsigned long ret = (unsigned long) psycho_root->pci_config_space;
+
+ ret |= (1 << 24);
+ ret |= ((bus & 0xff) << 16);
+ ret |= ((device_fn & 0xff) << 8);
+ ret |= (where & 0xfc);
+ return (unsigned char *)ret;
+}
+
+static inline int out_of_range(unsigned char bus, unsigned char device_fn)
+{
+ return ((bus == 0 && PCI_SLOT(device_fn) > 4) ||
+ (bus == 1 && PCI_SLOT(device_fn) > 6) ||
+ (pci_probe_enable == 0));
+}
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char *value)
+{
+ unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+ unsigned int word, trapped;
+
+ *value = 0xff;
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ trapped = pci_poke_faulted;
+ pci_poke_faulted = 0;
+ if(!trapped) {
+ switch(where & 3) {
+ case 0:
+ *value = word & 0xff;
+ break;
+ case 1:
+ *value = (word >> 8) & 0xff;
+ break;
+ case 2:
+ *value = (word >> 16) & 0xff;
+ break;
+ case 3:
+ *value = (word >> 24) & 0xff;
+ break;
+ };
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short *value)
+{
+ unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+ unsigned int word, trapped;
+
+ *value = 0xffff;
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ /* XXX Check no-probe-list conflicts here. XXX */
+
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ trapped = pci_poke_faulted;
+ pci_poke_faulted = 0;
+ if(!trapped) {
+ switch(where & 3) {
+ case 0:
+ *value = word & 0xffff;
+ break;
+ case 2:
+ *value = (word >> 16) & 0xffff;
+ break;
+ default:
+ prom_printf("pcibios_read_config_word: misaligned "
+ "reg [%x]\n", where);
+ prom_halt();
+ };
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int *value)
+{
+ unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+ unsigned int word, trapped;
+
+ *value = 0xffffffff;
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ /* XXX Check no-probe-list conflicts here. XXX */
+
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ trapped = pci_poke_faulted;
+ pci_poke_faulted = 0;
+ if(!trapped)
+ *value = word;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char value)
+{
+ unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ /* XXX Check no-probe-list conflicts here. XXX */
+
+ pci_poke_in_progress = 1;
+
+ /* Endianness doesn't matter but we have to get the memory
+ * barriers in there so...
+ */
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stba %0, [%1] %2\n\t"
+ "membar #Sync\n\t"
+ : /* no outputs */
+ : "r" (value), "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short value)
+{
+ unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ /* XXX Check no-probe-list conflicts here. XXX */
+
+ pci_poke_in_progress = 1;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stha %0, [%1] %2\n\t"
+ "membar #Sync\n\t"
+ : /* no outputs */
+ : "r" (value), "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int value)
+{
+ unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ /* XXX Check no-probe-list conflicts here. XXX */
+
+ pci_poke_in_progress = 1;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stwa %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (value), "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ int err = 0;
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ pcibios_read_config_byte(bus, dfn, off, &ubyte);
+ put_user(ubyte, buf);
+ break;
+ case 2:
+ pcibios_read_config_word(bus, dfn, off, &ushort);
+ put_user(ushort, buf);
+ break;
+ case 4:
+ pcibios_read_config_dword(bus, dfn, off, &uint);
+ put_user(uint, buf);
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+ };
+ unlock_kernel();
+
+ return err;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ int err = 0;
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ err = get_user(ubyte, (unsigned char *)buf);
+ if(err)
+ break;
+ pcibios_write_config_byte(bus, dfn, off, ubyte);
+ break;
+
+ case 2:
+ err = get_user(ushort, (unsigned short *)buf);
+ if(err)
+ break;
+ pcibios_write_config_byte(bus, dfn, off, ushort);
+ break;
+
+ case 4:
+ err = get_user(uint, (unsigned int *)buf);
+ if(err)
+ break;
+ pcibios_write_config_byte(bus, dfn, off, uint);
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+
+ };
+ unlock_kernel();
+
+ return err;
+}
+
+#endif
unsigned long tmp;
int res;
-#if 0
- /* XXX Find out what is really going on. */
- flush_cache_all();
-#endif
/* Non-word alignment _not_ allowed on Sparc. */
if (current->tss.flags & SPARC_FLAG_32BIT) {
unsigned int x;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
current->tss.flags ^= MAGIC_CONSTANT;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
current->pid, current->exit_code);
#endif
if (current->exit_code) {
- /* spin_lock_irq(¤t->sigmask_lock); */
+ spin_lock_irq(¤t->sigmask_lock);
current->signal |= (1 << (current->exit_code - 1));
- /* spin_unlock_irq(¤t->sigmask_lock); */
+ spin_unlock_irq(¤t->sigmask_lock);
}
current->exit_code = 0;
-/* $Id: rtrap.S,v 1.28 1997/06/30 10:31:39 jj Exp $
+/* $Id: rtrap.S,v 1.30 1997/08/10 04:49:33 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
sethi %hi(bh_mask), %l1
ldx [%l2 + %lo(bh_active)], %l4
ldx [%l1 + %lo(bh_mask)], %l7
-
andcc %l4, %l7, %g0
be,pt %xcc, 2f
+
nop
call do_bottom_half
nop
2: ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
sethi %hi(0xf << 20), %l4
andcc %l1, TSTATE_PRIV, %l3
-
and %l1, %l4, %l4
rdpr %pstate, %l7
+
andn %l1, %l4, %l1
be,pt %icc, to_user
andn %l7, PSTATE_IE, %l7
rt_continue: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
-
brnz,pn %l2, rt_fpu_restore
ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2
+
rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
mov %g6, %l6
ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4
ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5
ldx [%sp + PTREGS_OFF + PT_V9_G6], %g6
ldx [%sp + PTREGS_OFF + PT_V9_G7], %g7
-
wrpr %l7, PSTATE_AG, %pstate
ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0
+
ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1
ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2
ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3
ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4
ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5
ldx [%sp + PTREGS_OFF + PT_V9_I6], %i6
-
ldx [%sp + PTREGS_OFF + PT_V9_I7], %i7
ld [%sp + PTREGS_OFF + PT_V9_Y], %o3
+
ldx [%sp + PTREGS_OFF + PT_V9_TPC], %l2
ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %o2
wr %o3, %g0, %y
srl %l4, 20, %l4
wrpr %l4, 0x0, %pil
wrpr %g0, 0x1, %tl
-
wrpr %l1, %g0, %tstate
wrpr %l2, %g0, %tpc
- mov PRIMARY_CONTEXT, %l7
+
+ wr %g0, ASI_DMMU, %asi
brnz,pn %l3, kern_rtt
wrpr %o2, %g0, %tnpc
- stxa %l0, [%l7] ASI_DMMU
+ stxa %l0, [%g0 + SECONDARY_CONTEXT] %asi
+ flush %l6
+ stxa %l0, [%g0 + PRIMARY_CONTEXT] %asi
flush %l6
rdpr %wstate, %l1
retry
kern_rtt: restore
retry
-to_user: sethi %hi(need_resched), %l0
- ld [%l0 + %lo(need_resched)], %l0
+to_user: lduw [%g6 + AOFF_task_processor], %o0
+ mov 1, %o1
+ sethi %hi(need_resched), %l0
+ ldx [%l0 + %lo(need_resched)], %l0
+ sllx %o1, %o0, %o1
+
wrpr %l7, PSTATE_IE, %pstate
- brz,pt %l0, check_signal
+ andcc %o1, %l0, %g0
+ be,pt %xcc, check_signal
ldx [%g6 + AOFF_task_signal], %l0
-
call schedule
nop
ldx [%g6 + AOFF_task_signal], %l0
nop
+
check_signal: ldx [%g6 + AOFF_task_blocked], %o0
andncc %l0, %o0, %g0
be,pt %xcc, check_user_wins
ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
-
mov %l5, %o2
mov %l6, %o3
call do_signal
add %sp, STACK_BIAS + REGWIN_SZ, %o1
+
ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
clr %l6
-check_user_wins:
- brz,pt %o2, rt_continue
+check_user_wins:brz,pt %o2, rt_continue
nop
-
call fault_in_user_windows
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,a,pt %xcc, rt_continue
rt_fpu_restore: wr %g0, FPRS_FEF, %fprs
+
add %sp, PTREGS_OFF + TRACEREG_SZ, %g4
wr %g0, ASI_BLK_P, %asi
-
membar #StoreLoad | #LoadLoad
ldda [%g4 + 0x000] %asi, %f0
ldda [%g4 + 0x040] %asi, %f16
ldda [%g4 + 0x080] %asi, %f32
ldda [%g4 + 0x0c0] %asi, %f48
ldx [%g4 + 0x100], %fsr
+
ldx [%g4 + 0x108], %g3
membar #Sync
-
b,pt %xcc, rt_after_fpu
wr %g3, 0, %gsr
+ nop
+ nop
+ nop
+ nop
#undef PTREGS_OFF
-/* $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $
+/* $Id: signal.c,v 1.22 1997/08/05 19:19:36 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
if(tp->w_saved ||
(((unsigned long)ucp) & (sizeof(unsigned long)-1)) ||
(!__access_ok((unsigned long)ucp, sizeof(*ucp))))
- do_exit(SIGSEGV);
+ goto do_sigsegv;
grp = &ucp->uc_mcontext.mc_gregs;
__get_user(pc, &((*grp)[MC_PC]));
__get_user(npc, &((*grp)[MC_NPC]));
if((pc | npc) & 3)
- do_exit(SIGSEGV);
+ goto do_sigsegv;
if(regs->u_regs[UREG_I1]) {
__get_user(current->blocked, &ucp->uc_sigmask);
current->blocked &= _BLOCKABLE;
__get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
regs->fprs = FPRS_FEF;
}
+ return;
+do_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
asmlinkage void sparc64_get_context(struct pt_regs *regs)
synchronize_user_stack();
if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
- do_exit(SIGSEGV);
+ goto do_sigsegv;
mcp = &ucp->uc_mcontext;
grp = &mcp->mc_gregs;
__put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr));
__put_user(FPRS_FEF, &(mcp->mc_fpregs.mcfpu_fprs));
}
+ return;
+do_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
/*
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
current->exit_code = signr;
if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
-/* $Id: signal32.c,v 1.26 1997/07/14 03:10:31 davem Exp $
+/* $Id: signal32.c,v 1.28 1997/08/05 19:19:40 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
synchronize_user_stack();
if (current->tss.w_saved){
printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved);
+ lock_kernel();
do_exit (SIGSEGV);
}
if(clear_user(uc, sizeof (*uc)))
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
current->exit_code = signr;
if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <asm/head.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
-#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
unsigned long cpu_present_map = 0;
int smp_num_cpus = 1;
int smp_threads_ready = 0;
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-struct cpuinfo_sparc cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
+
static unsigned char boot_cpu_id = 0;
static int smp_activated = 0;
struct klock_info klock_info = { KLOCK_CLEAR, 0 };
-static volatile int smp_commenced = 0;
-
void smp_setup(char *str, int *ints)
{
/* XXX implement me XXX */
void smp_store_cpu_info(int id)
{
- cpu_data[id].udelay_val = loops_per_sec;
+ cpu_data[id].udelay_val = loops_per_sec;
+ cpu_data[id].irq_count = 0;
+ cpu_data[id].last_tlbversion_seen = tlb_context_cache & CTX_VERSION_MASK;
+ cpu_data[id].pgcache_size = 0;
+ cpu_data[id].pgd_cache = NULL;
+ cpu_data[id].pmd_cache = NULL;
+ cpu_data[id].pte_cache = NULL;
}
+extern void distribute_irqs(void);
+
void smp_commence(void)
{
- flush_cache_all();
- flush_tlb_all();
- smp_commenced = 1;
- flush_cache_all();
- flush_tlb_all();
+ distribute_irqs();
}
static void smp_setup_percpu_timer(void);
static volatile unsigned long callin_flag = 0;
+extern void inherit_locked_prom_mappings(int save_p);
+extern void cpu_probe(void);
+
void smp_callin(void)
{
int cpuid = hard_smp_processor_id();
- flush_cache_all();
- flush_tlb_all();
+ inherit_locked_prom_mappings(0);
+
+ __flush_cache_all();
+ __flush_tlb_all();
+
+ cpu_probe();
+
+ /* Master did this already, now is the time for us to do it. */
+ __asm__ __volatile__("
+ sethi %%hi(0x80000000), %%g1
+ sllx %%g1, 32, %%g1
+ rd %%tick, %%g2
+ add %%g2, 6, %%g2
+ andn %%g2, %%g1, %%g2
+ wrpr %%g2, 0, %%tick
+" : /* no outputs */
+ : /* no inputs */
+ : "g1", "g2");
smp_setup_percpu_timer();
+ __sti();
+
calibrate_delay();
smp_store_cpu_info(cpuid);
callin_flag = 1;
__asm__ __volatile__("membar #Sync\n\t"
"flush %%g6" : : : "memory");
- while(!task[cpuid])
- barrier();
- current = task[cpuid];
-
- while(!smp_commenced)
- barrier();
-
- __sti();
+ while(!smp_processors_ready)
+ membar("#LoadLoad");
}
extern int cpu_idle(void *unused);
panic("SMP bolixed\n");
}
+static void smp_tickoffset_init(void);
+
extern struct prom_cpuinfo linux_cpus[NR_CPUS];
-extern unsigned long sparc64_cpu_startup;
+
+extern unsigned long smp_trampoline;
void smp_boot_cpus(void)
{
int cpucount = 0, i;
printk("Entering UltraSMPenguin Mode...\n");
+ smp_tickoffset_init();
__sti();
cpu_present_map = 0;
for(i = 0; i < linux_num_cpus; i++)
- cpu_present_map |= (1 << i);
+ cpu_present_map |= (1UL << i);
for(i = 0; i < NR_CPUS; i++) {
cpu_number_map[i] = -1;
cpu_logical_map[i] = -1;
if(i == boot_cpu_id)
continue;
- if(cpu_present_map & (1 << i)) {
+ if(cpu_present_map & (1UL << i)) {
+ unsigned long entry = (unsigned long)(&smp_trampoline);
struct task_struct *p;
int timeout;
+ entry -= KERNBASE;
kernel_thread(start_secondary, NULL, CLONE_PID);
p = task[++cpucount];
p->processor = i;
+ callin_flag = 0;
prom_startcpu(linux_cpus[i].prom_node,
- ((unsigned long)&sparc64_cpu_startup),
- ((unsigned long)p));
+ entry, ((unsigned long)p));
for(timeout = 0; timeout < 5000000; timeout++) {
- if(cpu_callin_map[i])
+ if(callin_flag)
break;
udelay(100);
}
- if(cpu_callin_map[i]) {
- /* XXX fix this */
+ if(callin_flag) {
cpu_number_map[i] = i;
cpu_logical_map[i] = i;
} else {
printk("Processor %d is stuck.\n", i);
}
}
- if(!(cpu_callin_map[i])) {
- cpu_present_map &= ~(1 << i);
+ if(!callin_flag) {
+ cpu_present_map &= ~(1UL << i);
cpu_number_map[i] = -1;
}
}
if(cpucount == 0) {
printk("Error: only one processor found.\n");
- cpu_present_map = (1 << smp_processor_id());
+ cpu_present_map = (1UL << smp_processor_id());
} else {
unsigned long bogosum = 0;
for(i = 0; i < NR_CPUS; i++) {
- if(cpu_present_map & (1 << i))
+ if(cpu_present_map & (1UL << i))
bogosum += cpu_data[i].udelay_val;
}
printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
smp_num_cpus = cpucount + 1;
}
smp_processors_ready = 1;
+ membar("#StoreStore | #StoreLoad");
}
-/* XXX deprecated interface... */
+/* We don't even need to do anything, the only generic message pass done
+ * anymore is to stop all cpus during a panic(). When the user drops to
+ * the PROM prompt, the firmware will send the other cpu's it's MONDO
+ * vector anyways, so doing anything special here is pointless.
+ *
+ * This whole thing should go away anyways...
+ */
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
- printk("smp_message_pass() called, this is bad, spinning.\n");
- __sti();
- while(1)
- barrier();
}
+/* #define XCALL_DEBUG */
+
static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
{
- u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
-
+ u64 result, target = (((unsigned long)linux_cpus[cpu].mid) << 14) | 0x70;
+ int stuck;
+
+#ifdef XCALL_DEBUG
+ printk("CPU[%d]: xcall(data[%016lx:%016lx:%016lx],tgt[%016lx])\n",
+ smp_processor_id(), data0, data1, data2, target);
+#endif
+again:
__asm__ __volatile__("
wrpr %0, %1, %%pstate
wr %%g0, %2, %%asi
stxa %3, [0x40] %%asi
stxa %4, [0x50] %%asi
stxa %5, [0x60] %%asi
+ membar #Sync
stxa %%g0, [%6] %%asi
membar #Sync"
: /* No outputs */
"r" (data0), "r" (data1), "r" (data2), "r" (target));
/* NOTE: PSTATE_IE is still clear. */
+ stuck = 100000;
do {
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (result)
: "i" (ASI_INTR_DISPATCH_STAT));
+ if(result == 0) {
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+ : : "r" (pstate));
+ return;
+ }
+ stuck -= 1;
+ if(stuck == 0)
+ break;
} while(result & 0x1);
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate));
- if(result & 0x2)
- panic("Penguin NACK's master!");
+ if(stuck == 0) {
+#ifdef XCALL_DEBUG
+ printk("CPU[%d]: mondo stuckage result[%016lx]\n",
+ smp_processor_id(), result);
+#endif
+ } else {
+#ifdef XCALL_DEBUG
+ printk("CPU[%d]: Penguin %d NACK's master.\n", smp_processor_id(), cpu);
+#endif
+ udelay(2);
+ goto again;
+ }
}
void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
{
if(smp_processors_ready) {
- unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+ unsigned long mask = (cpu_present_map & ~(1UL<<smp_processor_id()));
u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
int i, ncpus = smp_num_cpus;
__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
for(i = 0; i < ncpus; i++) {
- if(mask & (1 << i))
+ if(mask & (1UL << i))
xcall_deliver(data0, data1, data2, pstate, i);
}
/* NOTE: Caller runs local copy on master. */
extern unsigned long xcall_flush_tlb_mm;
extern unsigned long xcall_flush_tlb_range;
extern unsigned long xcall_flush_tlb_all;
+extern unsigned long xcall_tlbcachesync;
extern unsigned long xcall_flush_cache_all;
+extern unsigned long xcall_report_regs;
+
+void smp_report_regs(void)
+{
+ smp_cross_call(&xcall_report_regs, 0, 0, 0);
+}
void smp_flush_cache_all(void)
{
__flush_tlb_all();
}
+static void smp_cross_call_avoidance(struct mm_struct *mm)
+{
+ spin_lock(&scheduler_lock);
+ get_new_mmu_context(mm, &tlb_context_cache);
+ mm->cpu_vm_mask = (1UL << smp_processor_id());
+ if(current->tss.current_ds) {
+ u32 ctx = mm->context & 0x1fff;
+
+ current->tss.ctx = ctx;
+ spitfire_set_secondary_context(ctx);
+ __asm__ __volatile__("flush %g6");
+ }
+ spin_unlock(&scheduler_lock);
+}
+
void smp_flush_tlb_mm(struct mm_struct *mm)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+ if(mm == current->mm && mm->count == 1) {
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ return smp_cross_call_avoidance(mm);
+ }
+ smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+local_flush_and_out:
__flush_tlb_mm(ctx);
}
unsigned long end)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+ if(mm == current->mm && mm->count == 1) {
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ return smp_cross_call_avoidance(mm);
+ }
+ smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+local_flush_and_out:
__flush_tlb_range(ctx, start, end);
}
-void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
{
- struct mm_struct *mm = vma->vm_mm;
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+ if(mm == current->mm && mm->count == 1) {
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ return smp_cross_call_avoidance(mm);
+ } else if(mm != current->mm && mm->count == 1) {
+ /* Try to handle two special cases to avoid cross calls
+ * in common scenerios where we are swapping process
+ * pages out.
+ */
+ if((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK)
+ return; /* It's dead, nothing to do. */
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ }
+ smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+
+local_flush_and_out:
__flush_tlb_page(ctx, page);
}
-static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+/* CPU capture. */
+#define CAPTURE_DEBUG
+extern unsigned long xcall_capture;
+
+static atomic_t smp_capture_depth = ATOMIC_INIT(0);
+static atomic_t smp_capture_registry = ATOMIC_INIT(0);
+static unsigned long penguins_are_doing_time = 0;
+
+void smp_capture(void)
+{
+ int result = atomic_add_return(1, &smp_capture_depth);
+
+ membar("#StoreStore | #LoadStore");
+ if(result == 1) {
+ int ncpus = smp_num_cpus;
+
+#ifdef CAPTURE_DEBUG
+ printk("CPU[%d]: Sending penguins to jail...", smp_processor_id());
+#endif
+ penguins_are_doing_time = 1;
+ membar("#StoreStore | #LoadStore");
+ atomic_inc(&smp_capture_registry);
+ smp_cross_call(&xcall_capture, 0, 0, 0);
+ while(atomic_read(&smp_capture_registry) != ncpus)
+ membar("#LoadLoad");
+#ifdef CAPTURE_DEBUG
+ printk("done\n");
+#endif
+ }
+}
+
+void smp_release(void)
+{
+ if(atomic_dec_and_test(&smp_capture_depth)) {
+#ifdef CAPTURE_DEBUG
+ printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
+ smp_processor_id());
+#endif
+ penguins_are_doing_time = 0;
+ membar("#StoreStore | #StoreLoad");
+ atomic_dec(&smp_capture_registry);
+ }
+}
+
+/* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
+ * can service tlb flush xcalls...
+ */
+void smp_penguin_jailcell(void)
+{
+ flushw_user();
+ atomic_inc(&smp_capture_registry);
+ membar("#StoreLoad | #StoreStore");
+ while(penguins_are_doing_time)
+ membar("#LoadLoad");
+ atomic_dec(&smp_capture_registry);
+}
static inline void sparc64_do_profile(unsigned long pc)
{
pc -= (unsigned long) &_stext;
pc >>= prof_shift;
- spin_lock(&ticker_lock);
- if(pc < prof_len)
- prof_buffer[pc]++;
- else
- prof_buffer[prof_len - 1]++;
- spin_unlock(&ticker_lock);
+ if(pc >= prof_len)
+ pc = prof_len - 1;
+ atomic_inc((atomic_t *)&prof_buffer[pc]);
}
}
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
+static unsigned long real_tick_offset, current_tick_offset;
+
+#define prof_multiplier(__cpu) cpu_data[(__cpu)].multiplier
+#define prof_counter(__cpu) cpu_data[(__cpu)].counter
extern void update_one_process(struct task_struct *p, unsigned long ticks,
unsigned long user, unsigned long system);
void smp_percpu_timer_interrupt(struct pt_regs *regs)
{
+ unsigned long compare, tick;
int cpu = smp_processor_id();
int user = user_mode(regs);
- /* XXX clear_profile_irq(cpu); */
- if(!user)
- sparc64_do_profile(regs->tpc);
- if(!--prof_counter[cpu]) {
- if(current->pid) {
- update_one_process(current, 1, user, !user);
- if(--current->counter < 0) {
- current->counter = 0;
- need_resched = 1;
- }
-
- spin_lock(&ticker_lock);
- if(user) {
- if(current->priority < DEF_PRIORITY)
- kstat.cpu_nice++;
- else
- kstat.cpu_user++;
- } else {
- kstat.cpu_system++;
+ clear_softint((1UL << 0));
+ do {
+ if(!user)
+ sparc64_do_profile(regs->tpc);
+ if(!--prof_counter(cpu)) {
+ if(current->pid) {
+ unsigned int *inc_me;
+
+ update_one_process(current, 1, user, !user);
+ if(--current->counter < 0) {
+ current->counter = 0;
+ resched_force();
+ }
+
+ if(user) {
+ if(current->priority < DEF_PRIORITY)
+ inc_me = &kstat.cpu_nice;
+ else
+ inc_me = &kstat.cpu_user;
+ } else {
+ inc_me = &kstat.cpu_system;
+ }
+ atomic_inc((atomic_t *)inc_me);
}
- spin_unlock(&ticker_lock);
+ prof_counter(cpu) = prof_multiplier(cpu);
}
- prof_counter[cpu] = prof_multiplier[cpu];
- }
+ __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
+ "add %0, %2, %0\n\t"
+ "wr %0, 0x0, %%tick_cmpr\n\t"
+ "rd %%tick, %1"
+ : "=&r" (compare), "=r" (tick)
+ : "r" (current_tick_offset));
+ } while (tick >= compare);
}
static void smp_setup_percpu_timer(void)
{
- /* XXX implement me */
+ int cpu = smp_processor_id();
+
+ prof_counter(cpu) = prof_multiplier(cpu) = 1;
+
+ __asm__ __volatile__("rd %%tick, %%g1\n\t"
+ "add %%g1, %0, %%g1\n\t"
+ "wr %%g1, 0x0, %%tick_cmpr"
+ : /* no outputs */
+ : "r" (current_tick_offset)
+ : "g1");
+}
+
+static void smp_tickoffset_init(void)
+{
+ int node;
+
+ node = linux_cpus[0].prom_node;
+ real_tick_offset = prom_getint(node, "clock-frequency");
+ real_tick_offset = real_tick_offset / HZ;
+ current_tick_offset = real_tick_offset;
}
int setup_profiling_timer(unsigned int multiplier)
{
- /* XXX implement me */
+ unsigned long flags;
+ int i;
+
+ if((!multiplier) || (real_tick_offset / multiplier) < 1000)
+ return -EINVAL;
+
+ save_and_cli(flags);
+ for(i = 0; i < NR_CPUS; i++) {
+ if(cpu_present_map & (1UL << i))
+ prof_multiplier(i) = multiplier;
+ }
+ current_tick_offset = (real_tick_offset / multiplier);
+ restore_flags(flags);
+
return 0;
}
-/* $Id: sparc64_ksyms.c,v 1.11 1997/07/14 23:58:20 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.17 1997/08/10 01:51:01 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
extern void *__memscan_generic(void *, int, size_t);
extern int __memcmp(const void *, const void *, __kernel_size_t);
extern int __strncmp(const char *, const char *, __kernel_size_t);
-extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
+extern unsigned int csum_partial_copy_sparc64(const char *src, char *dst,
+ int len, unsigned int sum);
extern char saved_command_line[];
extern void bcopy (const char *, char *, int);
extern void dump_thread(struct pt_regs *, struct user *);
+#ifdef __SMP__
+extern spinlock_t scheduler_lock;
+#endif
+
/* One thing to note is that the way the symbols of the mul/div
* support routines are named is a mess, they all start with
* a '.' which makes it a bitch to export, here is the trick:
/* used by various drivers */
#ifdef __SMP__
+EXPORT_SYMBOL(scheduler_lock);
+EXPORT_SYMBOL(global_bh_lock);
EXPORT_SYMBOL(klock_info);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL_PRIVATE(global_cli);
+EXPORT_SYMBOL_PRIVATE(global_sti);
+EXPORT_SYMBOL_PRIVATE(global_restore_flags);
+#else
+EXPORT_SYMBOL(local_irq_count);
#endif
EXPORT_SYMBOL_PRIVATE(_lock_kernel);
EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
EXPORT_SYMBOL(request_fast_irq);
EXPORT_SYMBOL(sparc_alloc_io);
EXPORT_SYMBOL(sparc_free_io);
-EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(__sparc64_bh_counter);
EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
EXPORT_SYMBOL(mmu_get_scsi_sgl);
EXPORT_SYMBOL(mmu_get_scsi_one);
EXPORT_SYMBOL(sparc_dvma_malloc);
+EXPORT_SYMBOL(mmu_release_scsi_one);
+EXPORT_SYMBOL(mmu_release_scsi_sgl);
#if CONFIG_SBUS
EXPORT_SYMBOL(SBus_chain);
EXPORT_SYMBOL(dma_chain);
EXPORT_SYMBOL(__strncmp);
EXPORT_SYMBOL(__memmove);
-EXPORT_SYMBOL(__csum_partial_copy_sparc_generic);
+EXPORT_SYMBOL(csum_partial_copy_sparc64);
/* Moving data to/from userspace. */
EXPORT_SYMBOL(__copy_to_user);
-/* $Id: sys_sparc.c,v 1.2 1997/07/05 09:52:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.3 1997/07/29 09:35:10 davem Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
{
struct sigaction new_sa, *p;
- int err = -EINVAL;
- lock_kernel();
if(signum < 0) {
current->tss.new_signal = 1;
signum = -signum;
}
-
if (signum<1 || signum>32)
- goto out;
+ return -EINVAL;
p = signum - 1 + current->sig->action;
if (action) {
- err = -EINVAL;
if (signum==SIGKILL || signum==SIGSTOP)
- goto out;
- err = -EFAULT;
+ return -EINVAL;
if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
- goto out;
+ return -EFAULT;
if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
- err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
+ int err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
if (err)
- goto out;
+ return err;
}
}
-
if (oldaction) {
- err = -EFAULT;
if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
- goto out;
+ return -EFAULT;
}
-
if (action) {
+ spin_lock_irq(¤t->sig->siglock);
*p = new_sa;
check_pending(signum);
+ spin_unlock_irq(¤t->sig->siglock);
}
-
- err = 0;
-out:
- unlock_kernel();
- return err;
+ return 0;
}
/* only AP+ systems have sys_aplib */
-/* $Id: sys_sparc32.c,v 1.44 1997/07/20 09:18:47 davem Exp $
+/* $Id: sys_sparc32.c,v 1.43 1997/07/17 02:20:45 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
void putname32(char * name)
{
- if (name_page_cache32 == 0)
- name_page_cache32 = (unsigned long) name;
- else
- free_page((unsigned long) name);
+ unsigned long page;
+
+ page = xchg(&name_page_cache32, ((unsigned long)name));
+ if(page)
+ free_page(page);
}
int getname32(u32 filename, char **result)
unsigned long page;
int retval;
- page = name_page_cache32;
- name_page_cache32 = 0;
+ page = xchg(&name_page_cache32, NULL);
if (!page) {
page = __get_free_page(GFP_KERNEL);
if (!page)
lock_kernel ();
p = (char *)__get_free_page (GFP_KERNEL);
if (!p)
- goto out;
+ goto out_nofree;
q = (u32 *)p;
Inp = (u32 *)A(inp);
}
out:
free_page ((unsigned long)p);
+out_nofree:
unlock_kernel();
return ret;
}
{
struct sigaction32 new_sa, old_sa;
struct sigaction *p;
- int err = -EINVAL;
- lock_kernel();
if(signum < 0) {
current->tss.new_signal = 1;
signum = -signum;
}
-
if (signum<1 || signum>32)
- goto out;
+ return -EINVAL;
p = signum - 1 + current->sig->action;
if (action) {
- err = -EINVAL;
if (signum==SIGKILL || signum==SIGSTOP)
- goto out;
- err = -EFAULT;
+ return -EINVAL;
if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32)))
- goto out;
+ return -EFAULT;
if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL &&
((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) {
- err = verify_area(VERIFY_READ, (__sighandler_t)A(new_sa.sa_handler), 1);
+ int err = verify_area(VERIFY_READ,
+ (__sighandler_t)A(new_sa.sa_handler), 1);
if (err)
- goto out;
+ return err;
}
}
-
if (oldaction) {
- err = -EFAULT;
old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
old_sa.sa_mask = (sigset_t32)(p->sa_mask);
old_sa.sa_flags = (unsigned)(p->sa_flags);
old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer);
if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32)))
- goto out;
+ return -EFAULT;
}
-
if (action) {
+ spin_lock_irq(¤t->sig->siglock);
p->sa_handler = (__sighandler_t)A(new_sa.sa_handler);
p->sa_mask = (sigset_t)(new_sa.sa_mask);
p->sa_flags = new_sa.sa_flags;
p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer);
check_pending(signum);
+ spin_unlock_irq(¤t->sig->siglock);
}
-
- err = 0;
-out:
- unlock_kernel();
- return err;
+ return 0;
}
/*
base = 1;
lock_kernel();
- filename = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0]);
+ filename = getname((char *)A((u32)regs->u_regs[base + UREG_I0]));
error = PTR_ERR(filename);
if(IS_ERR(filename))
goto out;
return 0;
}
-extern asmlinkage int sys_nfsservctl(int cmd,
- struct nfsctl_arg *arg,
- union nfsctl_res *resp);
+extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp);
int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp)
{
-/* $Id: systbls.S,v 1.21 1997/07/05 07:09:17 davem Exp $
+/* $Id: systbls.S,v 1.23 1997/08/09 18:33:17 jj Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
* Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
*/
- .data
- .align 8
+ .text
+ .align 1024
/* First, the 32-bit Linux native syscall table. */
.globl sys_call_table32
sys_call_table32:
-/*0*/ .xword sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
-/*5*/ .xword sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
-/*10*/ .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
-/*15*/ .xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
-/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .xword sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
- .xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
-/*40*/ .xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
- .xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
-/*50*/ .xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
- .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
-/*60*/ .xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
- .xword sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/ .xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
- .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
-/*80*/ .xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
- .xword sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
-/*90*/ .xword sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
- .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*100*/ .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
-/*120*/ .xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
- .xword sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
-/*130*/ .xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
- .xword sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
-/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
- .xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
-/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
- .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
- .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/ .xword sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
- .xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
-/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
- .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
-/*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
- .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
-/*220*/ .xword sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
- .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
- .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
-/*240*/ .xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
-/*250*/ .xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
- .xword sys_aplib, sys_nis_syscall
+/*0*/ .word sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
+/*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
+/*10*/ .word sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
+/*15*/ .word sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
+/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .word sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .word sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
+ .word sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
+/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
+ .word sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
+/*50*/ .word sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
+ .word sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
+/*60*/ .word sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
+ .word sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
+ .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
+/*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
+ .word sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
+/*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
+ .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/ .word sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
+ .word sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
+/*130*/ .word sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
+ .word sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
+/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
+ .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
+/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
+ .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
+ .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
+/*190*/ .word sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
+ .word sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
+/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
+ .word sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
+/*210*/ .word sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
+ .word sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+/*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
+ .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/ .word sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ .word sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
+/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
+/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+ .word sys_aplib
/* Now the 64-bit native Linux syscall table. */
+ .align 1024
.globl sys_call_table64, sys_call_table
sys_call_table64:
sys_call_table:
-/*0*/ .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
-/*5*/ .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/ .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
-/*15*/ .xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
-/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
- .xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
-/*40*/ .xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
- .xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
-/*50*/ .xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
- .xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
-/*60*/ .xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
- .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/ .xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
- .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
-/*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
- .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
-/*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
- .xword sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
-/*100*/ .xword sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
- .xword sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
- .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
-/*120*/ .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
- .xword sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/ .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
- .xword sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/ .xword sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
- .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/ .xword sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
-/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
- .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
- .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
- .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
-/*190*/ .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
- .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
-/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
-/*210*/ .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
- .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
-/*220*/ .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
- .xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/ .xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
- .xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
-/*240*/ .xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/ .xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
- .xword sys_aplib, sys_nis_syscall
+/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .word sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
+ .word sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
+ .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+ .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+ .word sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+ .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+ .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+ .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
+/*100*/ .word sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
+ .word sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
+ .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
+/*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+ .word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
+ .word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+ .word sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
+ .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
+/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+ .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
+ .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/ .word sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
+ .word sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+ .word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/ .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+ .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/ .word sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+ .word sys_aplib
/* Now the 32-bit SunOS syscall table. */
- .align 8
+ .align 1024
.globl sunos_sys_table
sunos_sys_table:
-/*0*/ .xword sunos_indir, sys_exit, sys_fork
- .xword sunos_read, sunos_write, sunos_open
- .xword sys_close, sunos_wait4, sys32_creat
- .xword sys32_link, sys32_unlink, sunos_execv
- .xword sys32_chdir, sunos_nosys, sys32_mknod
- .xword sys32_chmod, sys32_chown, sunos_brk
- .xword sunos_nosys, sys32_lseek, sunos_getpid
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_getuid, sunos_nosys, sys_ptrace
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sys32_access, sunos_nosys, sunos_nosys
- .xword sys_sync, sys_kill, sys32_newstat
- .xword sunos_nosys, sys32_newlstat, sys_dup
- .xword sys_pipe, sunos_nosys, sys_profil
- .xword sunos_nosys, sunos_nosys, sunos_getgid
- .xword sunos_nosys, sunos_nosys
-/*50*/ .xword sunos_nosys, sys32_acct, sunos_nosys
- .xword sunos_mctl, sunos_ioctl, sys32_reboot
- .xword sunos_nosys, sys32_symlink, sys32_readlink
- .xword sys32_execve, sys_umask, sys32_chroot
- .xword sys32_newfstat, sunos_nosys, sys_getpagesize
- .xword sys32_msync, sys_vfork, sunos_nosys
- .xword sunos_nosys, sunos_sbrk, sunos_sstk
- .xword sunos_mmap, sunos_vadvise, sys32_munmap
- .xword sys32_mprotect, sunos_madvise, sys_vhangup
- .xword sunos_nosys, sunos_mincore, sys32_getgroups
- .xword sys32_setgroups, sys_getpgrp, sunos_setpgrp
- .xword sys32_setitimer, sunos_nosys, sys32_swapon
- .xword sys32_getitimer, sys32_gethostname, sys32_sethostname
- .xword sunos_getdtablesize, sys_dup2, sunos_nop
- .xword sys32_fcntl, sunos_select, sunos_nop
- .xword sys_fsync, sys_setpriority, sys_socket
- .xword sys32_connect, sunos_accept
-/*100*/ .xword sys_getpriority, sunos_send, sunos_recv
- .xword sunos_nosys, sys32_bind, sunos_setsockopt
- .xword sys_listen, sunos_nosys, sunos_sigaction
- .xword sunos_sigblock, sunos_sigsetmask, sys_sigpause
- .xword sys32_sigstack, sys32_recvmsg, sys32_sendmsg
- .xword sunos_nosys, sys_gettimeofday, sys32_getrusage
- .xword sunos_getsockopt, sunos_nosys, sunos_readv
- .xword sunos_writev, sys_settimeofday, sys_fchown
- .xword sys_fchmod, sys32_recvfrom, sys32_setreuid
- .xword sys_setregid, sys32_rename, sys32_truncate
- .xword sys32_ftruncate, sys_flock, sunos_nosys
- .xword sys32_sendto, sys_shutdown, sys_socketpair
- .xword sys32_mkdir, sys32_rmdir, sys32_utimes
- .xword sys_sigreturn, sunos_nosys, sys32_getpeername
- .xword sunos_gethostid, sunos_nosys, sys32_getrlimit
- .xword sys32_setrlimit, sunos_killpg, sunos_nosys
- .xword sunos_nosys, sunos_nosys
-/*150*/ .xword sys32_getsockname, sunos_nosys, sunos_nosys
- .xword sys32_poll, sunos_nosys, sunos_nosys
- .xword sunos_getdirentries, sys32_statfs, sys32_fstatfs
- .xword sys32_umount, sunos_nosys, sunos_nosys
- .xword sunos_getdomainname, sys32_setdomainname
- .xword sunos_nosys, sys32_quotactl, sunos_nosys
- .xword sunos_mount, sys32_ustat, sunos_semsys
- .xword sunos_nosys, sunos_shmsys, sunos_audit
- .xword sunos_nosys, sunos_getdents, sys_setsid
- .xword sys_fchdir, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sys32_sigpending, sunos_nosys
- .xword sys_setpgid, sunos_pathconf, sunos_fpathconf
- .xword sunos_sysconf, sunos_uname, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
-/*200*/ .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys
-/*250*/ .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sys_aplib
+/*0*/ .word sunos_indir, sys_exit, sys_fork
+ .word sunos_read, sunos_write, sunos_open
+ .word sys_close, sunos_wait4, sys32_creat
+ .word sys32_link, sys32_unlink, sunos_execv
+ .word sys32_chdir, sunos_nosys, sys32_mknod
+ .word sys32_chmod, sys32_chown, sunos_brk
+ .word sunos_nosys, sys32_lseek, sunos_getpid
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_getuid, sunos_nosys, sys_ptrace
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sys32_access, sunos_nosys, sunos_nosys
+ .word sys_sync, sys_kill, sys32_newstat
+ .word sunos_nosys, sys32_newlstat, sys_dup
+ .word sys_pipe, sunos_nosys, sys_profil
+ .word sunos_nosys, sunos_nosys, sunos_getgid
+ .word sunos_nosys, sunos_nosys
+/*50*/ .word sunos_nosys, sys32_acct, sunos_nosys
+ .word sunos_mctl, sunos_ioctl, sys32_reboot
+ .word sunos_nosys, sys32_symlink, sys32_readlink
+ .word sys32_execve, sys_umask, sys32_chroot
+ .word sys32_newfstat, sunos_nosys, sys_getpagesize
+ .word sys32_msync, sys_vfork, sunos_nosys
+ .word sunos_nosys, sunos_sbrk, sunos_sstk
+ .word sunos_mmap, sunos_vadvise, sys32_munmap
+ .word sys32_mprotect, sunos_madvise, sys_vhangup
+ .word sunos_nosys, sunos_mincore, sys32_getgroups
+ .word sys32_setgroups, sys_getpgrp, sunos_setpgrp
+ .word sys32_setitimer, sunos_nosys, sys32_swapon
+ .word sys32_getitimer, sys32_gethostname, sys32_sethostname
+ .word sunos_getdtablesize, sys_dup2, sunos_nop
+ .word sys32_fcntl, sunos_select, sunos_nop
+ .word sys_fsync, sys_setpriority, sys_socket
+ .word sys32_connect, sunos_accept
+/*100*/ .word sys_getpriority, sunos_send, sunos_recv
+ .word sunos_nosys, sys32_bind, sunos_setsockopt
+ .word sys_listen, sunos_nosys, sunos_sigaction
+ .word sunos_sigblock, sunos_sigsetmask, sys_sigpause
+ .word sys32_sigstack, sys32_recvmsg, sys32_sendmsg
+ .word sunos_nosys, sys_gettimeofday, sys32_getrusage
+ .word sunos_getsockopt, sunos_nosys, sunos_readv
+ .word sunos_writev, sys_settimeofday, sys_fchown
+ .word sys_fchmod, sys32_recvfrom, sys32_setreuid
+ .word sys_setregid, sys32_rename, sys32_truncate
+ .word sys32_ftruncate, sys_flock, sunos_nosys
+ .word sys32_sendto, sys_shutdown, sys_socketpair
+ .word sys32_mkdir, sys32_rmdir, sys32_utimes
+ .word sys_sigreturn, sunos_nosys, sys32_getpeername
+ .word sunos_gethostid, sunos_nosys, sys32_getrlimit
+ .word sys32_setrlimit, sunos_killpg, sunos_nosys
+ .word sunos_nosys, sunos_nosys
+/*150*/ .word sys32_getsockname, sunos_nosys, sunos_nosys
+ .word sys32_poll, sunos_nosys, sunos_nosys
+ .word sunos_getdirentries, sys32_statfs, sys32_fstatfs
+ .word sys32_umount, sunos_nosys, sunos_nosys
+ .word sunos_getdomainname, sys32_setdomainname
+ .word sunos_nosys, sys32_quotactl, sunos_nosys
+ .word sunos_mount, sys32_ustat, sunos_semsys
+ .word sunos_nosys, sunos_shmsys, sunos_audit
+ .word sunos_nosys, sunos_getdents, sys_setsid
+ .word sys_fchdir, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sys32_sigpending, sunos_nosys
+ .word sys_setpgid, sunos_pathconf, sunos_fpathconf
+ .word sunos_sysconf, sunos_uname, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+/*200*/ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys
+/*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sys_aplib
-/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
+/* $Id: time.c,v 1.9 1997/08/12 04:12:40 ecd Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/fhc.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
struct mostek48t02 *mstk48t02_regs = 0;
struct mostek48t08 *mstk48t08_regs = 0;
/* Probe for the real time clock chip. */
-__initfunc(static void clock_probe(void))
+__initfunc(static void set_system_time(void))
{
- struct linux_prom_registers clk_reg[2];
- char model[128];
- int node, sbusnd, err;
-
- /* XXX HACK HACK HACK, delete me soon */
- struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX];
- int XXX_sbus_nranges;
+ unsigned int year, mon, day, hour, min, sec;
+ struct mostek48t02 *mregs;
- node = prom_getchild(prom_root_node);
- sbusnd = prom_searchsiblings(node, "sbus");
- node = prom_getchild(sbusnd);
+ do_get_fast_time = do_gettimeofday;
- if(node == 0 || node == -1) {
- prom_printf("clock_probe: Serious problem can't find sbus PROM node.\n");
+ mregs = mstk48t02_regs;
+ if(!mregs) {
+ prom_printf("Something wrong, clock regs not mapped yet.\n");
prom_halt();
+ }
+
+ mregs->creg |= MSTK_CREG_READ;
+ sec = MSTK_REG_SEC(mregs);
+ min = MSTK_REG_MIN(mregs);
+ hour = MSTK_REG_HOUR(mregs);
+ day = MSTK_REG_DOM(mregs);
+ mon = MSTK_REG_MONTH(mregs);
+ year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
+ xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+ xtime.tv_usec = 0;
+ mregs->creg &= ~MSTK_CREG_READ;
+}
+
+__initfunc(void clock_probe(void))
+{
+ struct linux_prom_registers clk_reg[2];
+ char model[128];
+ int node, busnd = -1, err;
+
+ if(central_bus != NULL) {
+ busnd = central_bus->child->prom_node;
+ }
+#ifdef CONFIG_PCI
+ else if (ebus_chain != NULL) {
+ busnd = ebus_chain->prom_node;
+ }
+#endif
+ else {
+ busnd = SBus_chain->prom_node;
}
- /* XXX FIX ME */
- err = prom_getproperty(sbusnd, "ranges", (char *) XXX_sbus_ranges,
- sizeof(XXX_sbus_ranges));
- if(err == -1) {
- prom_printf("clock_probe: Cannot get XXX sbus ranges\n");
+ if(busnd == -1) {
+ prom_printf("clock_probe: problem, cannot find bus to search.\n");
prom_halt();
}
- XXX_sbus_nranges = (err / sizeof(struct linux_prom_ranges));
+
+ node = prom_getchild(busnd);
while(1) {
prom_getstring(node, "model", model, sizeof(model));
err = prom_getproperty(node, "reg", (char *)clk_reg,
sizeof(clk_reg));
if(err == -1) {
- prom_printf("clock_probe: Cannot make Mostek\n");
+ prom_printf("clock_probe: Cannot get Mostek reg property\n");
prom_halt();
}
- /* XXX fix me badly */
- prom_adjust_regs(clk_reg, 1, XXX_sbus_ranges, XXX_sbus_nranges);
+ if(central_bus) {
+ prom_apply_fhc_ranges(central_bus->child, clk_reg, 1);
+ prom_apply_central_ranges(central_bus, clk_reg, 1);
+ }
+#ifdef CONFIG_PCI
+ else if (ebus_chain) {
+ struct linux_ebus_device *edev;
+
+ for_each_ebusdev(edev, ebus_chain)
+ if (edev->prom_node == node)
+ break;
+ if (!edev) {
+ prom_printf("%s: Mostek not probed by EBUS\n");
+ prom_halt();
+ }
+
+ clk_reg[0] = edev->regs[0];
+ }
+#endif
+ else {
+ prom_adjust_regs(clk_reg, 1,
+ SBus_chain->sbus_ranges,
+ SBus_chain->num_sbus_ranges);
+ }
if(model[5] == '0' && model[6] == '2') {
mstk48t02_regs = (struct mostek48t02 *)
/* Kick start the clock if it is completely stopped. */
if (mstk48t02_regs->sec & MSTK_STOP)
kick_start_clock();
+
+ set_system_time();
}
#ifndef BCD_TO_BIN
__initfunc(void time_init(void))
{
- unsigned int year, mon, day, hour, min, sec;
- struct mostek48t02 *mregs;
-
- do_get_fast_time = do_gettimeofday;
-
- clock_probe();
-
- mregs = mstk48t02_regs;
- if(!mregs) {
- prom_printf("Something wrong, clock regs not mapped yet.\n");
- prom_halt();
- }
-
- mregs->creg |= MSTK_CREG_READ;
- sec = MSTK_REG_SEC(mregs);
- min = MSTK_REG_MIN(mregs);
- hour = MSTK_REG_HOUR(mregs);
- day = MSTK_REG_DOM(mregs);
- mon = MSTK_REG_MONTH(mregs);
- year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
- xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
- xtime.tv_usec = 0;
- mregs->creg &= ~MSTK_CREG_READ;
+ /* clock_probe() is now done at end of sbus_init on sparc64
+ * so that both sbus and fhc bus information is probed and
+ * available.
+ */
}
extern void init_timers(void (*func)(int, void *, struct pt_regs *));
sethi %hi(xtime), %g2
ldx [%o1 + %lo(linux_timers)], %g3
1: ldd [%g2 + %lo(xtime)], %o4
+ membar #LoadLoad | #MemIssue
ldx [%g3], %o1
+ membar #LoadLoad | #MemIssue
ldd [%g2 + %lo(xtime)], %o2
+ membar #LoadLoad
xor %o4, %o2, %o2
xor %o5, %o3, %o3
orcc %o2, %o3, %g0
-/* $Id: trampoline.S,v 1.1 1997/07/24 14:47:53 davem Exp $
+/* $Id: trampoline.S,v 1.2 1997/07/28 02:57:32 davem Exp $
* trampoline.S: Jump start slave processors on sparc64.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
#include <asm/spitfire.h>
#include <asm/asm_offsets.h>
+ .data
+ .align 8
+ .globl smp_trampoline
+smp_trampoline: .skip 0x300
+
.text
- .globl sparc64_cpu_startup
+ .align 8
+ .globl sparc64_cpu_startup, sparc64_cpu_startup_end
sparc64_cpu_startup:
flushw
mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
stxa %g1, [%g0] ASI_LSU_CONTROL
+ membar #Sync
wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
wrpr %g0, 15, %pil
- mov %o0, %g6
+ sethi %uhi(PAGE_OFFSET), %g4
+ sllx %g4, 32, %g4
+
+ /* XXX Buggy PROM... */
+ srl %o0, 0, %g6
+ add %g6, %g4, %g6
sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
sllx %g5, 32, %g5
sllx %g3, 32, %g3
sethi %hi(_PAGE_PADDR), %g7
or %g7, %lo(_PAGE_PADDR), %g7
- or %g3, %g7, %g7
+ or %g3, %g7, %g3
- /* Find TLB entry we are executing out of. */
clr %l0
set 0x1fff, %l2
rd %pc, %l3
andn %g1, %l2, %g1
cmp %g1, %g3
blu,pn %xcc, 2f
- cmp %g1, %g7
+ cmp %g1, %g7
bgeu,pn %xcc, 2f
nop
stxa %g0, [%l7] ASI_IMMU
stxa %g3, [%l7] ASI_IMMU
stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS
membar #Sync
- flush %g6
+ flush %g3
membar #Sync
b,pt %xcc, 1f
nop
stxa %g0, [%g7] ASI_DMMU
membar #Sync
- sethi %uhi(PAGE_OFFSET), %g4
- sllx %g4, 32, %g4
-
mov TLB_TAG_ACCESS, %g2
stxa %g3, [%g2] ASI_IMMU
stxa %g3, [%g2] ASI_DMMU
stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS
membar #Sync
- flush %g6
+ flush %g3
membar #Sync
mov 1, %g5
stxa %o5, [%o4] ASI_IMMU
membar #Sync
- wrpr %g0, 0, %pil
or %o1, PSTATE_IE, %o1
wrpr %o1, 0, %pstate
call cpu_panic
nop
1: b,a,pt %xcc, 1b
+
+ .align 8
+sparc64_cpu_startup_end:
-/* $Id: traps.c,v 1.29 1997/07/05 09:52:38 davem Exp $
+/* $Id: traps.c,v 1.31 1997/08/11 14:35:33 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
+#include <asm/lsu.h>
/* #define SYSCALL_TRACING */
/* #define VERBOSE_SYSCALL_TRACING */
send_sig(SIGSEGV, current, 1);
}
+#ifdef CONFIG_PCI
+/* This is really pathetic... */
+/* #define DEBUG_PCI_POKES */
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_faulted;
+#endif
+
void do_dae(struct pt_regs *regs)
{
+#ifdef CONFIG_PCI
+#ifdef DEBUG_PCI_POKES
+ prom_printf(" (POKE ");
+#endif
+ if(pci_poke_in_progress) {
+ unsigned long va;
+#ifdef DEBUG_PCI_POKES
+ prom_printf("tpc[%016lx] tnpc[%016lx] ",
+ regs->tpc, regs->tnpc);
+#endif
+ pci_poke_faulted = 1;
+ regs->tnpc = regs->tpc + 4;
+
+
+#ifdef DEBUG_PCI_POKES
+ prom_printf("PCI) ");
+ /* prom_halt(); */
+#endif
+ /* Re-enable I/D caches, Ultra turned them off. */
+ for(va = 0; va < (PAGE_SIZE << 1); va += 32) {
+ spitfire_put_icache_tag(va, 0x0);
+ spitfire_put_dcache_tag(va, 0x0);
+ }
+ __asm__ __volatile__("flush %%g6\n\t"
+ "membar #Sync\n\t"
+ "stxa %0, [%%g0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
+ LSU_CONTROL_IM | LSU_CONTROL_DM),
+ "i" (ASI_LSU_CONTROL)
+ : "memory");
+ return;
+ }
+#ifdef DEBUG_PCI_POKES
+ prom_printf("USER) ");
+ prom_printf("tpc[%016lx] tnpc[%016lx]\n");
+ prom_halt();
+#endif
+#endif
send_sig(SIGSEGV, current, 1);
}
regs->tpc = regs->tnpc;
regs->tnpc += 4;
} else {
- lock_kernel();
current->tss.sig_address = regs->tpc;
current->tss.sig_desc = SUBSIG_FPERROR;
send_sig(SIGFPE, current, 1);
- unlock_kernel();
}
}
}
printk("Instruction DUMP:");
instruction_dump ((unsigned int *) regs->tpc);
+ lock_kernel(); /* Or else! */
if(regs->tstate & TSTATE_PRIV)
do_exit(SIGKILL);
do_exit(SIGSEGV);
unsigned long pc = regs->tpc;
unsigned long tstate = regs->tstate;
- lock_kernel();
if(tstate & TSTATE_PRIV)
die_if_kernel("Kernel illegal instruction", regs);
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
void mem_address_unaligned(struct pt_regs *regs)
current->tss.sig_address = regs->tpc;
current->tss.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long tstate)
{
- lock_kernel();
if(tstate & TSTATE_PRIV)
die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
/* XXX User may want to be allowed to do this. XXX */
void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long tstate)
{
- lock_kernel();
if(regs->tstate & TSTATE_PRIV) {
printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc,
regs->u_regs[UREG_RETPC]);
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGBUS, current, 1);
- unlock_kernel();
}
void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long psr)
{
- lock_kernel();
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
/* Trap level 1 stuff or other traps we should never see... */
-/* $Id: ttable.S,v 1.18 1997/07/05 09:52:41 davem Exp $
+/* $Id: ttable.S,v 1.19 1997/07/26 18:38:56 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8)
tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10)
tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
-tl0_irq13: TRAP_IRQ(handler_irq, 13) TRAP_IRQ(handler_irq, 14)
+tl0_irq13: TRAP_IRQ(handler_irq, 13)
+tl0_itick: TRAP_TICK
tl0_irq15: TRAP_IRQ(handler_irq, 15)
tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
-/* $Id: winfixup.S,v 1.16 1997/07/13 20:02:42 davem Exp $
+/* $Id: winfixup.S,v 1.19 1997/08/08 08:33:37 jj Exp $
*
* winfixup.S: Handle cases where user stack pointer is found to be bogus.
*
retry
window_scheisse_from_user_common:
wrpr %g1, %cwp
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
window_scheisse_merge:
srlx %l5, PAGE_SHIFT, %o1
retry
window_mna_from_user_common:
wrpr %g1, %cwp
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
window_mna_merge:
call mem_address_unaligned
add %sp, STACK_BIAS + REGWIN_SZ, %o0
OBJS = blockops.o locks.o strlen.o strncmp.o \
memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
- VIScopy.o VISbzero.o VISmemset.o VIScsum.o
+ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
-/* $Id: VISbzero.S,v 1.4 1997/06/28 17:21:21 jj Exp $
+/* $Id: VISbzero.S,v 1.6 1997/08/08 08:34:00 jj Exp $
* VISbzero.S: High speed clear operations utilizing the UltraSparc
* Visual Instruction Set.
*
#else
wr %g0, ASI_BLK_P, %asi
#endif
- membar #StoreStore | #LoadStore
+ membar #StoreLoad | #StoreStore | #LoadStore
fzero %f0
andcc %o3, 0xc0, %o2
and %o1, 0x3f, %o1
wr %g0, 0, %fprs
wr %g7, 0x0, %asi
#endif
- membar #Sync
+ membar #StoreLoad | #StoreStore
9: andcc %o1, 0xf8, %o2
be,pn %xcc, 13f
andcc %o1, 7, %o1
+#ifdef __KERNEL__
+14: sethi %hi(13f), %o4
+ srl %o2, 1, %o3
+ sub %o4, %o3, %o4
+ jmpl %o4 + %lo(13f), %g0
+ add %o0, %o2, %o0
+#else
14: rd %pc, %o4
srl %o2, 1, %o3
sub %o4, %o3, %o4
jmpl %o4 + (13f - 14b), %g0
add %o0, %o2, %o0
+#endif
12: ZERO_BLOCKS(%o0, 0xc8, %g0)
ZERO_BLOCKS(%o0, 0x88, %g0)
ZERO_BLOCKS(%o0, 0x48, %g0)
-/* $Id: VIScopy.S,v 1.9 1997/07/13 18:23:39 davem Exp $
+/* $Id: VIScopy.S,v 1.11 1997/08/08 08:34:02 jj Exp $
* VIScopy.S: High speed copy operations utilizing the UltraSparc
* Visual Instruction Set.
*
sethi %hi(8192), %o2 ! IEU0 Group
mov ASI_BLK_P, asi_src ! IEU1
b,pt %xcc, dest_is_64byte_aligned ! CTI
- mov ASI_BLK_COMMIT_P, asi_dest ! IEU0 Group
+ mov ASI_BLK_P, asi_dest ! IEU0 Group
.align 32
.globl __copy_from_user
EXVIS1(LDBLK [%o1 + 0x40] ASIBLK, %f16) ! LSU Group
sub %g7, 0x80, %g7 ! IEU0
EXVIS(LDBLK [%o1 + 0x80] ASIBLK, %f32) ! LSU Group
+#ifdef __KERNEL__
+vispc: sll %g2, 9, %g2 ! IEU0 Group
+ sethi %hi(vis00), %g5 ! IEU1
+ or %g5, %lo(vis00), %g5 ! IEU0 Group
+ jmpl %g5 + %g2, %g0 ! CTI Group brk forced
+ addcc %o1, 0xc0, %o1 ! IEU1 Group
+#else
! Clk1 Group 8-(
! Clk2 Group 8-(
! Clk3 Group 8-(
sll %g2, 9, %g2 ! IEU0
jmpl %g5 + %g2, %g0 ! CTI Group brk forced
addcc %o1, 0xc0, %o1 ! IEU1 Group
+#endif
.align 512 /* OK, here comes the fun part... */
vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis01)
FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) LOOP_CHUNK2(o1, o0, g7, vis02)
3: andcc %o2, 0x70, %g7 ! IEU1 Group
41: be,pn %xcc, 80f ! CTI
andcc %o2, 8, %g0 ! IEU1 Group
- ! Clk1 8-(
- ! Clk2 8-(
- ! Clk3 8-(
- ! Clk4 8-(
-79: rd %pc, %o5 ! PDU Group
#ifdef __KERNEL__
+79: sethi %hi(80f), %o5 ! IEU0
sll %g7, 1, %g5 ! IEU0 Group
add %o1, %g7, %o1 ! IEU1
srl %g7, 1, %g2 ! IEU0 Group
sub %o5, %g5, %o5 ! IEU1
sub %o5, %g2, %o5 ! IEU0 Group
- jmpl %o5 + %lo(80f - 79b), %g0 ! CTI Group brk forced
+ jmpl %o5 + %lo(80f), %g0 ! CTI Group brk forced
add %o0, %g7, %o0 ! IEU0 Group
#else
+ ! Clk1 8-(
+ ! Clk2 8-(
+ ! Clk3 8-(
+ ! Clk4 8-(
+79: rd %pc, %o5 ! PDU Group
sll %g7, 1, %g5 ! IEU0 Group
add %o1, %g7, %o1 ! IEU1
sub %o5, %g5, %o5 ! IEU0 Group
andcc %o2, 0x70, %g7 ! IEU1
be,pn %xcc, 84f ! CTI
andcc %o2, 8, %g0 ! IEU1 Group
+#ifdef __KERNEL__
+83: srl %g7, 1, %g5 ! IEU0
+ sethi %hi(84f), %o5 ! IEU0 Group
+ add %g7, %g5, %g5 ! IEU1
+ add %o1, %g7, %o1 ! IEU0 Group
+ sub %o5, %g5, %o5 ! IEU1
+ jmpl %o5 + %lo(84f), %g0 ! CTI Group brk forced
+ add %o0, %g7, %o0 ! IEU0 Group
+#else
! Clk1 8-(
! Clk2 8-(
! Clk3 8-(
! Clk4 8-(
83: rd %pc, %o5 ! PDU Group
-#ifdef __KERNEL__
- srl %g7, 1, %g5 ! IEU0 Group
- add %g7, %g5, %g5 ! IEU0 Group
- add %o1, %g7, %o1 ! IEU1
- sub %o5, %g5, %o5 ! IEU0 Group
- jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced
- add %o0, %g7, %o0 ! IEU0 Group
-#else
add %o1, %g7, %o1 ! IEU0 Group
sub %o5, %g7, %o5 ! IEU1
jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced
add %o2, 1, %o2 /* IEU0 */
1: ba,pt %xcc, 25b /* CTI Group */
sllx %o2, 32, %g1 /* IEU0 */
+/* $Id: VIScsum.S,v 1.2 1997/08/08 08:34:05 jj Exp $
+ * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
+ * Visual Instruction Set.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on older sparc32/sparc64 checksum.S, which is:
+ *
+ * Copyright(C) 1995 Linus Torvalds
+ * Copyright(C) 1995 Miguel de Icaza
+ * Copyright(C) 1996,1997 David S. Miller
+ * derived from:
+ * Linux/Alpha checksum c-code
+ * Linux/ix86 inline checksum assembly
+ * RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ * David Mosberger-Tang for optimized reference c-code
+ * BSD4.4 portable checksum routine
+ */
+
+#ifdef __sparc_v9__
+#define STACKOFF 2175
+#else
+#define STACKOFF 64
+#endif
+
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#else
+#define ASI_BLK_P 0xf0
+#define FRPS_FEF 0x04
+#endif
+
+/* Dobrou noc, SunSoft engineers. Spete sladce.
+ * This has a couple of tricks in and those
+ * tricks are UltraLinux trade secrets :))
+ */
+
+#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10) \
+ fcmpgt32 %fz, %f0, %g1 /* FPM Group */; \
+ fcmpgt32 %fz, %f2, %g2 /* FPM Group */; \
+ fcmpgt32 %fz, %f4, %g3 /* FPM Group */; \
+ fcmpgt32 %fz, %f6, %g5 /* FPM Group */; \
+ inc %g1 /* IEU0 */; \
+ fcmpgt32 %fz, %f8, %g7 /* FPM Group */; \
+ srl %g1, 1, %g1 /* IEU0 */; \
+ inc %g2 /* IEU1 */; \
+ fcmpgt32 %fz, %f10, %o3 /* FPM Group */; \
+ srl %g2, 1, %g2 /* IEU0 */; \
+ add %o2, %g1, %o2 /* IEU1 */; \
+ add %g3, 1, %g3 /* IEU0 Group */; \
+ srl %g3, 1, %g3 /* IEU0 Group */; \
+ add %o2, %g2, %o2 /* IEU1 */; \
+ inc %g5 /* IEU0 Group */; \
+ add %o2, %g3, %o2 /* IEU1 */;
+
+#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14) \
+ fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \
+ srl %g5, 1, %g5 /* IEU0 */; \
+ inc %g7 /* IEU1 */; \
+ fpadd32 %F0, %f0, %F0 /* FPA */; \
+ fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \
+ srl %g7, 1, %g7 /* IEU0 */; \
+ add %o2, %g5, %o2 /* IEU1 */; \
+ fpadd32 %F2, %f2, %F2 /* FPA */; \
+ inc %o3 /* IEU0 Group */; \
+ add %o2, %g7, %o2 /* IEU1 */; \
+ fcmpgt32 %f0, %F0, %g1 /* FPM Group */; \
+ srl %o3, 1, %o3 /* IEU0 */; \
+ inc %o4 /* IEU1 */; \
+ fpadd32 %F4, %f4, %F4 /* FPA */; \
+ fcmpgt32 %f2, %F2, %g2 /* FPM Group */; \
+ srl %o4, 1, %o4 /* IEU0 */; \
+ add %o2, %o3, %o2 /* IEU1 */; \
+ fpadd32 %F6, %f6, %F6 /* FPA */; \
+ inc %o5 /* IEU0 Group */; \
+ add %o2, %o4, %o2 /* IEU1 */; \
+ fcmpgt32 %f4, %F4, %g3 /* FPM Group */; \
+ srl %o5, 1, %o5 /* IEU0 */; \
+ inc %g1 /* IEU1 */; \
+ fpadd32 %F8, %f8, %F8 /* FPA */; \
+ fcmpgt32 %f6, %F6, %g5 /* FPM Group */; \
+ srl %g1, 1, %g1 /* IEU0 */; \
+ add %o2, %o5, %o2 /* IEU1 */; \
+ fpadd32 %F10, %f10, %F10 /* FPA */; \
+ inc %g2 /* IEU0 Group */; \
+ add %o2, %g1, %o2 /* IEU1 */; \
+ fcmpgt32 %f8, %F8, %g7 /* FPM Group */; \
+ srl %g2, 1, %g2 /* IEU0 */; \
+ inc %g3 /* IEU1 */; \
+ fpadd32 %F12, %f12, %F12 /* FPA */; \
+ fcmpgt32 %f10, %F10, %o3 /* FPM Group */; \
+ srl %g3, 1, %g3 /* IEU0 */; \
+ add %o2, %g2, %o2 /* IEU1 */; \
+ fpadd32 %F14, %f14, %F14 /* FPA */; \
+ inc %g5 /* IEU0 Group */; \
+ add %o2, %g3, %o2 /* IEU1 */;
+
+#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz) \
+ fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \
+ srl %g5, 1, %g5 /* IEU0 */; \
+ inc %g7 /* IEU1 */; \
+ fpadd32 %f2, %f0, %S0 /* FPA */; \
+ fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \
+ srl %g7, 1, %g7 /* IEU0 */; \
+ add %o2, %g5, %o2 /* IEU1 */; \
+ fpadd32 %f6, %f4, %S1 /* FPA */; \
+ inc %o3 /* IEU0 Group */; \
+ add %o2, %g7, %o2 /* IEU1 */; \
+ fcmpgt32 %f0, %S0, %g1 /* FPM Group */; \
+ srl %o3, 1, %o3 /* IEU0 */; \
+ inc %o4 /* IEU1 */; \
+ fpadd32 %f10, %f8, %S2 /* FPA */; \
+ fcmpgt32 %f4, %S1, %g2 /* FPM Group */; \
+ srl %o4, 1, %o4 /* IEU0 */; \
+ add %o2, %o3, %o2 /* IEU1 */; \
+ fpadd32 %f14, %f12, %S3 /* FPA */; \
+ inc %o5 /* IEU0 Group */; \
+ add %o2, %o4, %o2 /* IEU1 */; \
+ fzero %fz /* FPA */; \
+ fcmpgt32 %f8, %S2, %g3 /* FPM Group */; \
+ srl %o5, 1, %o5 /* IEU0 */; \
+ inc %g1 /* IEU1 */; \
+ fpadd32 %S0, %S1, %T0 /* FPA */; \
+ fcmpgt32 %f12, %S3, %g5 /* FPM Group */; \
+ srl %g1, 1, %g1 /* IEU0 */; \
+ add %o2, %o5, %o2 /* IEU1 */; \
+ fpadd32 %S2, %S3, %T1 /* FPA */; \
+ inc %g2 /* IEU0 Group */; \
+ add %o2, %g1, %o2 /* IEU1 */; \
+ fcmpgt32 %S0, %T0, %g7 /* FPM Group */; \
+ srl %g2, 1, %g2 /* IEU0 */; \
+ inc %g3 /* IEU1 */; \
+ fcmpgt32 %S2, %T1, %o3 /* FPM Group */; \
+ srl %g3, 1, %g3 /* IEU0 */; \
+ add %o2, %g2, %o2 /* IEU1 */; \
+ inc %g5 /* IEU0 Group */; \
+ add %o2, %g3, %o2 /* IEU1 */; \
+ fcmpgt32 %fz, %f2, %o4 /* FPM Group */; \
+ srl %g5, 1, %g5 /* IEU0 */; \
+ inc %g7 /* IEU1 */; \
+ fpadd32 %T0, %T1, %U0 /* FPA */; \
+ fcmpgt32 %fz, %f6, %o5 /* FPM Group */; \
+ srl %g7, 1, %g7 /* IEU0 */; \
+ add %o2, %g5, %o2 /* IEU1 */; \
+ inc %o3 /* IEU0 Group */; \
+ add %o2, %g7, %o2 /* IEU1 */; \
+ fcmpgt32 %fz, %f10, %g1 /* FPM Group */; \
+ srl %o3, 1, %o3 /* IEU0 */; \
+ inc %o4 /* IEU1 */; \
+ fcmpgt32 %fz, %f14, %g2 /* FPM Group */; \
+ srl %o4, 1, %o4 /* IEU0 */; \
+ add %o2, %o3, %o2 /* IEU1 */; \
+ std %U0, [%sp + STACKOFF] /* Store Group */; \
+ inc %o5 /* IEU0 */; \
+ sub %o2, %o4, %o2 /* IEU1 */; \
+ fcmpgt32 %fz, %S1, %g3 /* FPM Group */; \
+ srl %o5, 1, %o5 /* IEU0 */; \
+ inc %g1 /* IEU1 */; \
+ fcmpgt32 %fz, %S3, %g5 /* FPM Group */; \
+ srl %g1, 1, %g1 /* IEU0 */; \
+ sub %o2, %o5, %o2 /* IEU1 */; \
+ ldx [%sp + STACKOFF], %o5 /* Load Group */; \
+ inc %g2 /* IEU0 */; \
+ sub %o2, %g1, %o2 /* IEU1 */; \
+ fcmpgt32 %fz, %T1, %g7 /* FPM Group */; \
+ srl %g2, 1, %g2 /* IEU0 */; \
+ inc %g3 /* IEU1 */; \
+ fcmpgt32 %T0, %U0, %o3 /* FPM Group */; \
+ srl %g3, 1, %g3 /* IEU0 */; \
+ sub %o2, %g2, %o2 /* IEU1 */; \
+ inc %g5 /* IEU0 Group */; \
+ sub %o2, %g3, %o2 /* IEU1 */; \
+ fcmpgt32 %fz, %U0, %o4 /* FPM Group */; \
+ srl %g5, 1, %g5 /* IEU0 */; \
+ inc %g7 /* IEU1 */; \
+ srl %g7, 1, %g7 /* IEU0 Group */; \
+ sub %o2, %g5, %o2 /* IEU1 */; \
+ inc %o3 /* IEU0 Group */; \
+ sub %o2, %g7, %o2 /* IEU1 */; \
+ srl %o3, 1, %o3 /* IEU0 Group */; \
+ inc %o4 /* IEU1 */; \
+ srl %o4, 1, %o4 /* IEU0 Group */; \
+ add %o2, %o3, %o2 /* IEU1 */; \
+ sub %o2, %o4, %o2 /* IEU0 Group */; \
+ addcc %o2, %o5, %o2 /* IEU1 Group */; \
+ bcs,a,pn %xcc, 33f /* CTI */; \
+ add %o2, 1, %o2 /* IEU0 */; \
+33: /* That's it */;
+
+#define CSUM_LASTCHUNK(offset) \
+ ldx [%o0 - offset - 0x10], %g2; \
+ ldx [%o0 - offset - 0x08], %g3; \
+ addcc %g2, %o2, %o2; \
+ bcs,a,pn %xcc, 31f; \
+ add %o2, 1, %o2; \
+31: addcc %g3, %o2, %o2; \
+ bcs,a,pn %xcc, 32f; \
+ add %o2, 1, %o2; \
+32:
+
+ .text
+ .globl csum_partial
+ .align 32
+csum_partial:
+ andcc %o0, 7, %g0 /* IEU1 Group */
+ be,pt %icc, 4f /* CTI */
+ andcc %o0, 0x38, %g3 /* IEU1 */
+ mov 1, %g5 /* IEU0 Group */
+ cmp %o1, 6 /* IEU1 */
+ bl,pn %icc, 21f /* CTI */
+ andcc %o0, 2, %g0 /* IEU1 Group */
+ be,pt %icc, 1f /* CTI */
+ and %o0, 4, %g7 /* IEU0 */
+ lduh [%o0], %g2 /* Load */
+ sub %o1, 2, %o1 /* IEU0 Group */
+ add %o0, 2, %o0 /* IEU1 */
+ andcc %o0, 4, %g7 /* IEU1 Group */
+ sll %g5, 16, %g5 /* IEU0 */
+ sll %g2, 16, %g2 /* IEU0 Group */
+ addcc %g2, %o2, %o2 /* IEU1 Group (regdep) */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %o2, %g5, %o2 /* IEU0 */
+1: ld [%o0], %g2 /* Load */
+ brz,a,pn %g7, 4f /* CTI+IEU1 Group */
+ and %o0, 0x38, %g3 /* IEU0 */
+ add %o0, 4, %o0 /* IEU0 Group */
+ sub %o1, 4, %o1 /* IEU1 */
+ addcc %g2, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: and %o0, 0x38, %g3 /* IEU1 Group */
+4: srl %o2, 0, %o2 /* IEU0 Group */
+ mov 0x40, %g1 /* IEU1 */
+ brz,pn %g3, 3f /* CTI+IEU1 Group */
+ sub %g1, %g3, %g1 /* IEU0 */
+ cmp %o1, 56 /* IEU1 Group */
+ blu,pn %icc, 20f /* CTI */
+ andcc %o0, 8, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ ldx [%o0], %g2 /* Load */
+ add %o0, 8, %o0 /* IEU0 Group */
+ sub %o1, 8, %o1 /* IEU1 */
+ addcc %g2, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: andcc %g1, 0x10, %g0 /* IEU1 Group */
+ be,pn %icc, 2f /* CTI */
+ and %g1, 0x20, %g1 /* IEU0 */
+ ldx [%o0], %g2 /* Load */
+ ldx [%o0+8], %g3 /* Load Group */
+ add %o0, 16, %o0 /* IEU0 */
+ sub %o1, 16, %o1 /* IEU1 */
+ addcc %g2, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: addcc %g3, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 2f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+2: brz,pn %g1, 3f /* CTI+IEU1 Group */
+ ldx [%o0], %g2 /* Load */
+ ldx [%o0+8], %g3 /* Load Group */
+ ldx [%o0+16], %g5 /* Load Group */
+ ldx [%o0+24], %g7 /* Load Group */
+ add %o0, 32, %o0 /* IEU0 */
+ sub %o1, 32, %o1 /* IEU1 */
+ addcc %g2, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: addcc %g3, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: addcc %g5, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: addcc %g7, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 3f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+3: cmp %o1, 0xc0 /* IEU1 Group */
+ blu,pn %icc, 20f /* CTI */
+ sllx %o2, 32, %g1 /* IEU0 */
+ addcc %o2, %g1, %o2 /* IEU1 Group */
+ sub %o1, 0xc0, %o1 /* IEU0 */
+ wr %g0, ASI_BLK_P, %asi /* LSU Group */
+#ifdef __KERNEL__
+ wr %g0, FPRS_FEF, %fprs /* LSU Group */
+#endif
+ membar #StoreLoad /* LSU Group */
+ srlx %o2, 32, %o2 /* IEU0 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU1 */
+1: andcc %o1, 0x80, %g0 /* IEU1 Group */
+ bne,pn %icc, 7f /* CTI */
+ andcc %o1, 0x40, %g0 /* IEU1 Group */
+ be,pn %icc, 6f /* CTI */
+ fzero %f12 /* FPA */
+ fzero %f14 /* FPA Group */
+ ldda [%o0 + 0x000] %asi, %f16
+ ldda [%o0 + 0x040] %asi, %f32
+ ldda [%o0 + 0x080] %asi, %f48
+ START_THE_TRICK(f12,f16,f18,f20,f22,f24,f26)
+ ba,a,pt %xcc, 3f
+6: sub %o0, 0x40, %o0 /* IEU0 Group */
+ fzero %f28 /* FPA */
+ fzero %f30 /* FPA Group */
+ ldda [%o0 + 0x040] %asi, %f32
+ ldda [%o0 + 0x080] %asi, %f48
+ ldda [%o0 + 0x0c0] %asi, %f0
+ START_THE_TRICK(f28,f32,f34,f36,f38,f40,f42)
+ ba,a,pt %xcc, 4f
+7: bne,pt %icc, 8f /* CTI */
+ fzero %f44 /* FPA */
+ add %o0, 0x40, %o0 /* IEU0 Group */
+ fzero %f60 /* FPA */
+ fzero %f62 /* FPA Group */
+ ldda [%o0 - 0x040] %asi, %f0
+ ldda [%o0 + 0x000] %asi, %f16
+ ldda [%o0 + 0x040] %asi, %f32
+ START_THE_TRICK(f60,f0,f2,f4,f6,f8,f10)
+ ba,a,pt %xcc, 2f
+8: add %o0, 0x80, %o0 /* IEU0 Group */
+ fzero %f46 /* FPA */
+ ldda [%o0 - 0x080] %asi, %f48
+ ldda [%o0 - 0x040] %asi, %f0
+ ldda [%o0 + 0x000] %asi, %f16
+ START_THE_TRICK(f44,f48,f50,f52,f54,f56,f58)
+1: DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
+ ldda [%o0 + 0x040] %asi, %f32
+2: DO_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
+ ldda [%o0 + 0x080] %asi, %f48
+3: DO_THE_TRICK(f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46)
+ ldda [%o0 + 0x0c0] %asi, %f0
+4: DO_THE_TRICK(f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,f48,f50,f52,f54,f56,f58,f60,f62)
+ add %o0, 0x100, %o0 /* IEU0 Group */
+ subcc %o1, 0x100, %o1 /* IEU1 */
+ bgeu,a,pt %icc, 1b /* CTI */
+ ldda [%o0 + 0x000] %asi, %f16
+ membar #Sync /* LSU Group */
+ DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
+ END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
+ and %o1, 0x3f, %o1 /* IEU0 Group */
+#ifdef __KERNEL__
+ wr %g0, 0, %fprs /* LSU Group */
+#endif
+20: andcc %o1, 0xf0, %g1 /* IEU1 Group */
+ be,pn %icc, 23f /* CTI */
+ and %o1, 0xf, %o3 /* IEU0 */
+#ifdef __KERNEL__
+22: sll %g1, 1, %o4 /* IEU0 Group */
+ sethi %hi(23f), %g7 /* IEU1 */
+ sub %g7, %o4, %g7 /* IEU0 Group */
+ jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced */
+ add %o0, %g1, %o0 /* IEU0 */
+#else
+22: rd %pc, %g7 /* LSU Group+4bubbles */
+ sll %g1, 1, %o4 /* IEU0 Group */
+ sub %g7, %o4, %g7 /* IEU0 Group (regdep) */
+ jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced */
+ add %o0, %g1, %o0 /* IEU0 */
+#endif
+ CSUM_LASTCHUNK(0xe0)
+ CSUM_LASTCHUNK(0xd0)
+ CSUM_LASTCHUNK(0xc0)
+ CSUM_LASTCHUNK(0xb0)
+ CSUM_LASTCHUNK(0xa0)
+ CSUM_LASTCHUNK(0x90)
+ CSUM_LASTCHUNK(0x80)
+ CSUM_LASTCHUNK(0x70)
+ CSUM_LASTCHUNK(0x60)
+ CSUM_LASTCHUNK(0x50)
+ CSUM_LASTCHUNK(0x40)
+ CSUM_LASTCHUNK(0x30)
+ CSUM_LASTCHUNK(0x20)
+ CSUM_LASTCHUNK(0x10)
+ CSUM_LASTCHUNK(0x00)
+23: brnz,pn %o3, 26f /* CTI+IEU1 Group */
+24: sllx %o2, 32, %g1 /* IEU0 */
+25: addcc %o2, %g1, %o0 /* IEU1 Group */
+ srlx %o0, 32, %o0 /* IEU0 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o0, 1, %o0 /* IEU1 */
+1: retl /* CTI Group brk forced */
+ srl %o0, 0, %o0 /* IEU0 */
+26: andcc %o1, 8, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ ldx [%o0], %g3 /* Load */
+ add %o0, 8, %o0 /* IEU0 Group */
+ addcc %g3, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: andcc %o1, 4, %g0 /* IEU1 Group */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g2 /* IEU0 */
+ ld [%o0], %g2 /* Load */
+ add %o0, 4, %o0 /* IEU0 Group */
+ sllx %g2, 32, %g2 /* IEU0 Group */
+1: andcc %o1, 2, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o4 /* IEU0 Group */
+ lduh [%o0], %o4 /* Load */
+ add %o0, 2, %o0 /* IEU1 */
+ sll %o4, 16, %o4 /* IEU0 Group */
+1: andcc %o1, 1, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o5 /* IEU0 Group */
+ ldub [%o0], %o5 /* Load */
+ sll %o5, 8, %o5 /* IEU0 Group */
+1: or %g2, %o4, %o4 /* IEU1 */
+ or %o5, %o4, %o4 /* IEU0 Group (regdep) */
+ addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: ba,pt %xcc, 25b /* CTI Group */
+ sllx %o2, 32, %g1 /* IEU0 */
+21: srl %o2, 0, %o2 /* IEU0 Group */
+ cmp %o1, 0 /* IEU1 */
+ be,pn %icc, 24b /* CTI */
+ andcc %o1, 4, %g0 /* IEU1 Group */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g2 /* IEU0 */
+ lduh [%o0], %g3 /* Load */
+ lduh [%o0+2], %g2 /* Load Group */
+ add %o0, 4, %o0 /* IEU0 Group */
+ sllx %g3, 48, %g3 /* IEU0 Group */
+ sllx %g2, 32, %g2 /* IEU0 Group */
+ or %g3, %g2, %g2 /* IEU0 Group */
+1: andcc %o1, 2, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o4 /* IEU0 Group */
+ lduh [%o0], %o4 /* Load */
+ add %o0, 2, %o0 /* IEU1 */
+ sll %o4, 16, %o4 /* IEU0 Group */
+1: andcc %o1, 1, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o5 /* IEU0 Group */
+ ldub [%o0], %o5 /* Load */
+ sll %o5, 8, %o5 /* IEU0 Group */
+1: or %g2, %o4, %o4 /* IEU1 */
+ or %o5, %o4, %o4 /* IEU0 Group (regdep) */
+ addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: ba,pt %xcc, 25b /* CTI Group */
+ sllx %o2, 32, %g1 /* IEU0 */
--- /dev/null
+/* $Id: VIScsumcopy.S,v 1.1 1997/08/09 18:14:29 jj Exp $
+ * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous
+ * copying utilizing the UltraSparc Visual Instruction Set.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on older sparc32/sparc64 checksum.S, which is:
+ *
+ * Copyright(C) 1995 Linus Torvalds
+ * Copyright(C) 1995 Miguel de Icaza
+ * Copyright(C) 1996,1997 David S. Miller
+ * derived from:
+ * Linux/Alpha checksum c-code
+ * Linux/ix86 inline checksum assembly
+ * RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ * David Mosberger-Tang for optimized reference c-code
+ * BSD4.4 portable checksum routine
+ */
+
+#ifdef __sparc_v9__
+#define STACKOFF 0x7ff+128
+#else
+#define STACKOFF 64
+#endif
+
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#else
+#define ASI_P 0x80
+#define ASI_BLK_P 0xf0
+#define FRPS_FEF 0x04
+#define FPRS_DU 0x02
+#define FPRS_DL 0x01
+#endif
+#define ASI_BLK_XOR (ASI_BLK_P ^ ASI_P)
+
+#define src o0
+#define dst o1
+#define len o2
+#define sum o3
+#define x1 g1
+#define x2 g2
+#define x3 g3
+#define x4 g4
+#define x5 g5
+#define x6 g7
+#define x7 o4
+#define x8 o5
+
+/* Dobrou noc, SunSoft engineers. Spete sladce.
+ * This has a couple of tricks in and those
+ * tricks are UltraLinux trade secrets :))
+ * Once AGAIN, the SunSoft engineers are caught
+ * asleep at the keyboard :)).
+ * The main loop does about 20 superscalar cycles
+ * per 64bytes checksummed/copied.
+ */
+
+#define LDBLK(O0) \
+ ldda [%src] %asi, %O0 /* Load Group */
+
+#define STBLK \
+ stda %f48, [%dst] ASI_BLK_P /* Store */
+
+#define ST(fx,off) \
+ std %fx, [%dst + off] /* Store */
+
+#define SYNC \
+ membar #Sync
+
+
+#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DYMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \
+ LOAD /* Load Group */; \
+ faligndata %A14, %F0, %A14 /* FPA Group */; \
+ inc %x5 /* IEU0 */; \
+ STORE1 /* Store (optional) */; \
+ faligndata %F0, %F2, %A0 /* FPA Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ fpadd32 %F0, %f0, %F0 /* FPA Group */; \
+ inc %x6 /* IEU0 */; \
+ STORE2 /* Store (optional) */; \
+ faligndata %F2, %F4, %A2 /* FPA Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fpadd32 %F2, %f2, %F2 /* FPA Group */; \
+ add %src, 64, %src /* IEU0 */; \
+ add %dst, 64, %dst /* IEU1 */; \
+ fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \
+ inc %x7 /* IEU0 */; \
+ STORE3 /* Store (optional) */; \
+ faligndata %F4, %F6, %A4 /* FPA */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ fpadd32 %F4, %f4, %F4 /* FPA */; \
+ fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \
+ inc %x8 /* IEU0 */; \
+ STORE4 /* Store (optional) */; \
+ faligndata %F6, %F8, %A6 /* FPA */; \
+ srl %x8, 1, %x8 /* IEU0 Group */; \
+ add %sum, %x7, %sum /* IEU1 */; \
+ fpadd32 %F6, %f6, %F6 /* FPA */; \
+ fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \
+ inc %x1 /* IEU0 */; \
+ STORE5 /* Store (optional) */; \
+ faligndata %F8, %F10, %A8 /* FPA */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ add %sum, %x8, %sum /* IEU1 */; \
+ fpadd32 %F8, %f8, %F8 /* FPA */; \
+ fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \
+ inc %x2 /* IEU0 */; \
+ STORE6 /* Store (optional) */; \
+ faligndata %F10, %F12, %A10 /* FPA */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ fpadd32 %F10, %f10, %F10 /* FPA */; \
+ fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \
+ inc %x3 /* IEU0 */; \
+ STORE7 /* Store (optional) */; \
+ faligndata %F12, %F14, %A12 /* FPA */; \
+ srl %x3, 1, %x3 /* IEU0 Group */; \
+ add %sum, %x2, %sum /* IEU1 */; \
+ fpadd32 %F12, %f12, %F12 /* FPA */; \
+ fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \
+ inc %x4 /* IEU0 */; \
+ STORE8 /* Store (optional) */; \
+ fmovd %F14, %B14 /* FPA */; \
+ srl %x4, 1, %x4 /* IEU0 Group */; \
+ add %sum, %x3, %sum /* IEU1 */; \
+ fpadd32 %F14, %f14, %F14 /* FPA */; \
+ fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \
+ subcc %len, 64, %len /* IEU1 */; \
+ BRANCH /* CTI */; \
+ fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \
+
+#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \
+ inc %x5 /* IEU0 Group */; \
+ fpadd32 %f2, %f0, %S0 /* FPA */; \
+ srl %x5, 1, %x5 /* IEU0 Group */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ fpadd32 %f6, %f4, %S1 /* FPA */; \
+ inc %x6 /* IEU0 Group */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ inc %x7 /* IEU1 */; \
+ fpadd32 %f10, %f8, %S2 /* FPA */; \
+ fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \
+ srl %x7, 1, %x7 /* IEU0 */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ fpadd32 %f14, %f12, %S3 /* FPA */; \
+ inc %x8 /* IEU0 Group */; \
+ add %sum, %x7, %sum /* IEU1 */; \
+ fzero %fz /* FPA */; \
+ fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \
+ srl %x8, 1, %x8 /* IEU0 */; \
+ inc %x1 /* IEU1 */; \
+ fpadd32 %S0, %S1, %T0 /* FPA */; \
+ fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \
+ srl %x1, 1, %x1 /* IEU0 */; \
+ add %sum, %x8, %sum /* IEU1 */; \
+ fpadd32 %S2, %S3, %T1 /* FPA */; \
+ inc %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \
+ srl %x2, 1, %x2 /* IEU0 */; \
+ inc %x3 /* IEU1 */; \
+ fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \
+ srl %x3, 1, %x3 /* IEU0 */; \
+ add %sum, %x2, %sum /* IEU1 */; \
+ inc %x4 /* IEU0 Group */; \
+ add %sum, %x3, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \
+ srl %x4, 1, %x4 /* IEU0 */; \
+ inc %x5 /* IEU1 */; \
+ fpadd32 %T0, %T1, %U0 /* FPA */; \
+ fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ inc %x6 /* IEU0 Group */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ inc %x7 /* IEU1 */; \
+ fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \
+ ba,pt %xcc, ett /* CTI */; \
+ fmovd %FA, %FB /* FPA */; \
+
+#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \
+ END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62)
+
+#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \
+ fpadd32 %U0, %U1, %V0 /* FPA Group */; \
+ srl %x7, 1, %x7 /* IEU0 */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ std %V0, [%sp + STACKOFF] /* Store Group */; \
+ inc %x8 /* IEU0 */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \
+ srl %x8, 1, %x8 /* IEU0 */; \
+ inc %x1 /* IEU1 */; \
+ fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \
+ srl %x1, 1, %x1 /* IEU0 */; \
+ sub %sum, %x8, %sum /* IEU1 */; \
+ ldx [%sp + STACKOFF], %x8 /* Load Group */; \
+ inc %x2 /* IEU0 */; \
+ sub %sum, %x1, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \
+ srl %x2, 1, %x2 /* IEU0 */; \
+ inc %x3 /* IEU1 */; \
+ fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \
+ srl %x3, 1, %x3 /* IEU0 */; \
+ sub %sum, %x2, %sum /* IEU1 */; \
+ inc %x4 /* IEU0 Group */; \
+ sub %sum, %x3, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \
+ srl %x4, 1, %x4 /* IEU0 */; \
+ inc %x5 /* IEU1 */; \
+ fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ sub %sum, %x4, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \
+ inc %x6 /* IEU0 */; \
+ sub %sum, %x5, %sum /* IEU1 */; \
+ srl %x6, 1, %x6 /* IEU0 Group */; \
+ inc %x7 /* IEU1 */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ inc %x1 /* IEU0 Group */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ inc %x2 /* IEU1 */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ sub %sum, %x2, %sum /* IEU0 Group */; \
+ addcc %sum, %x8, %sum /* IEU Group */; \
+ bcs,a,pn %xcc, 33f /* CTI */; \
+ add %sum, 1, %sum /* IEU0 */; \
+33: /* That's it */;
+
+ .text
+ .globl csum_partial_copy_vis
+ .align 32
+/* %asi should be either ASI_P or ASI_S for csum_partial_copy resp. csum_partial_copy_from_user */
+/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */
+csum_partial_copy_vis:
+ andcc %dst, 7, %g0 /* IEU1 Group */
+ be,pt %icc, 4f /* CTI */
+ and %dst, 0x38, %g3 /* IEU0 */
+ mov 1, %g5 /* IEU0 Group */
+ andcc %dst, 2, %g0 /* IEU1 */
+ be,pt %icc, 1f /* CTI */
+ and %dst, 4, %g7 /* IEU0 Group */
+ lduha [%src] %asi, %g2 /* Load */
+ sub %len, 2, %len /* IEU0 Group */
+ add %dst, 2, %dst /* IEU1 */
+ andcc %dst, 4, %g7 /* IEU1 Group */
+ sll %g5, 16, %g5 /* IEU0 */
+ sth %g2, [%dst - 2] /* Store Group */
+ sll %g2, 16, %g2 /* IEU0 */
+ add %src, 2, %src /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, %g5, %sum /* IEU0 */
+1: lduwa [%src] %asi, %g2 /* Load */
+ brz,a,pn %g7, 4f /* CTI+IEU1 Group */
+ and %dst, 0x38, %g3 /* IEU0 */
+ add %dst, 4, %dst /* IEU0 Group */
+ sub %len, 4, %len /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: and %dst, 0x38, %g3 /* IEU0 Group */
+ stw %g2, [%dst - 4] /* Store */
+ add %src, 4, %src /* IEU1 */
+4:
+#ifdef __KERNEL__
+ wr %g0, FPRS_FEF, %fprs /* LSU Group */
+#endif
+ mov %src, %g7 /* IEU1 Group */
+ fzero %f48 /* FPA */
+ alignaddr %src, %g0, %src /* Single Group */
+ subcc %g7, %src, %g7 /* IEU1 Group */
+ be,pt %xcc, 1f /* CTI */
+ mov 0x40, %g1 /* IEU0 */
+ lduwa [%src] %asi, %g2 /* Load Group */
+ subcc %sum, %g2, %sum /* IEU1 Group+load stall */
+ bcs,a,pn %icc, 1f /* CTI */
+ sub %sum, 1, %sum /* IEU0 */
+1: srl %sum, 0, %sum /* IEU0 Group */
+ clr %g5 /* IEU1 */
+ brz,pn %g3, 3f /* CTI+IEU1 Group */
+ sub %g1, %g3, %g1 /* IEU0 */
+ ldda [%src] %asi, %f0 /* Load */
+ clr %g3 /* IEU0 Group */
+ andcc %dst, 8, %g0 /* IEU1 */
+ be,pn %icc, 1f /* CTI */
+ ldda [%src + 8] %asi, %f2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ sub %len, 8, %len /* IEU1 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ addcc %dst, 8, %dst /* IEU1 Group */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %g3 /* FPM Group */
+ fmovd %f2, %f0 /* FPA Group */
+ ldda [%src + 8] %asi, %f2 /* Load */
+ std %f16, [%dst - 8] /* Store */
+ fmovd %f50, %f48 /* FPA */
+1: andcc %g1, 0x10, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ and %g1, 0x20, %g1 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldda [%src + 16] %asi, %f4 /* Load Group */
+ add %src, 16, %src /* IEU0 */
+ add %dst, 16, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ sub %len, 16, %len /* IEU0 */
+ inc %g3 /* IEU1 */
+ std %f16, [%dst - 16] /* Store Group */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ srl %g3, 1, %o5 /* IEU0 */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ std %f18, [%dst - 8] /* Store */
+ fcmpgt32 %f50, %f48, %g3 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ ldda [%src + 8] %asi, %f2 /* Load */
+ fmovd %f4, %f0 /* FPA */
+1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */
+ rd %asi, %g2 /* LSU Group + 4 bubbles */
+ inc %g5 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldda [%src + 16] %asi, %f4 /* Load Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ add %dst, 32, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %o5 /* FPM Group */
+ inc %g3 /* IEU0 */
+ ldda [%src + 24] %asi, %f6 /* Load */
+ srl %g3, 1, %g3 /* IEU0 Group */
+ add %g5, %sum, %sum /* IEU1 */
+ ldda [%src + 32] %asi, %f8 /* Load */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ sub %len, 32, %len /* IEU0 */
+ std %f16, [%dst - 32] /* Store */
+ fcmpgt32 %f50, %f48, %o4 /* FPM Group */
+ inc %o5 /* IEU0 */
+ add %g3, %sum, %sum /* IEU1 */
+ fpadd32 %f4, %f48, %f50 /* FPA */
+ faligndata %f4, %f6, %f20 /* FPA Group */
+ srl %o5, 1, %o5 /* IEU0 */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ std %f18, [%dst - 24] /* Store */
+ fpadd32 %f6, %f50, %f48 /* FPA */
+ inc %o4 /* IEU0 Group */
+ std %f20, [%dst - 16] /* Store */
+ add %src, 32, %src /* IEU1 */
+ faligndata %f6, %f8, %f22 /* FPA */
+ fcmpgt32 %f50, %f48, %g3 /* FPM Group */
+ srl %o4, 1, %o4 /* IEU0 */
+ std %f22, [%dst - 8] /* Store */
+ add %o4, %sum, %sum /* IEU0 Group */
+3: rd %asi, %g2 /* LSU Group + 4 bubbles */
+#ifdef __KERNEL__
+4: sethi %hi(vis0s), %g7 /* IEU0 Group */
+#else
+4: rd %pc, %g7 /* LSU Group + 4 bubbles */
+#endif
+ inc %g5 /* IEU0 Group */
+ and %src, 0x38, %o4 /* IEU1 */
+ membar #StoreLoad /* LSU Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ inc %g3 /* IEU1 */
+ sll %o4, 8, %o4 /* IEU0 Group */
+ sub %len, 0xc0, %len /* IEU1 */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ srl %g3, 1, %g3 /* IEU0 */
+ add %g7, %o4, %g7 /* IEU0 Group */
+ add %g3, %sum, %sum /* IEU1 */
+#ifdef __KERNEL__
+ jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */
+#else
+ jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */
+#endif
+ fzero %f32 /* FPA */
+
+ .align 2048
+vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f62 /* FPA Group */
+ faligndata %f0, %f2, %f48 /* FPA Group */
+ fcmpgt32 %f32, %f2, %x1 /* FPM Group */
+ fpadd32 %f0, %f62, %f0 /* FPA */
+ fcmpgt32 %f32, %f4, %x2 /* FPM Group */
+ faligndata %f2, %f4, %f50 /* FPA */
+ fcmpgt32 %f62, %f0, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f52 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ inc %x1 /* IEU0 */
+ faligndata %f6, %f8, %f54 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ srl %x1, 1, %x1 /* IEU0 */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f56 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ srl %x2, 1, %x2 /* IEU0 */
+ add %sum, %x1, %sum /* IEU1 */
+ faligndata %f10, %f12, %f58 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f60 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f62 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
+vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f32), STBLK,,,,,,,,
+ ,bcs,pn %icc, vis0e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f0), STBLK,,,,,,,,
+ ,bcs,pn %icc, vis0e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f16), STBLK,,,,,,,,
+ ,bcc,pt %icc, vis0)
+vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f32,
+ ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+ ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2)
+vis0e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f0,
+ ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+ ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3)
+vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f16,
+ ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+ ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 8, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fcmpgt32 %f32, %f2, %x2 /* FPM Group */
+ faligndata %f2, %f4, %f48 /* FPA */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f50 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f52 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f54 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ srl %x2, 1, %x2 /* IEU0 */
+ faligndata %f10, %f12, %f56 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f58 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f60 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
+vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+ ,LDBLK(f32), ,STBLK,,,,,,,
+ ,bcs,pn %icc, vis1e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+ ,LDBLK(f0), ,STBLK,,,,,,,
+ ,bcs,pn %icc, vis1e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+ ,LDBLK(f16), ,STBLK,,,,,,,
+ ,bcc,pt %icc, vis1)
+vis1e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f32,
+ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+ ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e2)
+vis1e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f0,
+ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+ ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e3)
+vis1e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f16,
+ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+ ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 16, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fzero %f2 /* FPA Group */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f48 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f50 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f52 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f54 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ faligndata %f12, %f14, %f56 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f58 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
+vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+ ,LDBLK(f32), ,,STBLK,,,,,,
+ ,bcs,pn %icc, vis2e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+ ,LDBLK(f0), ,,STBLK,,,,,,
+ ,bcs,pn %icc, vis2e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+ ,LDBLK(f16), ,,STBLK,,,,,,
+ ,bcc,pt %icc, vis2)
+vis2e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f32,
+ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+ ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e2)
+vis2e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f0,
+ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+ ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e3)
+vis2e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f16,
+ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+ ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 24, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fzero %f2 /* FPA Group */
+ fzero %f4 /* FPA Group */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f48 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f50 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f52 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f54 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f56 /* FPA */
+ inc %x4 /* IEU0 */
+ srl %x4, 1, %x4 /* IEU0 Group */
+vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+ ,LDBLK(f32), ,,,STBLK,,,,,
+ ,bcs,pn %icc, vis3e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+ ,LDBLK(f0), ,,,STBLK,,,,,
+ ,bcs,pn %icc, vis3e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+ ,LDBLK(f16), ,,,STBLK,,,,,
+ ,bcc,pt %icc, vis3)
+vis3e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f32,
+ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+ ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e2)
+vis3e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f0,
+ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+ ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e3)
+vis3e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f16,
+ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+ ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 32, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fzero %f2 /* FPA Group */
+ fzero %f4 /* FPA Group */
+ fzero %f6 /* FPA Group */
+ clr %x4 /* IEU0 */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f48 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f50 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f52 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f54 /* FPA */
+vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+ ,LDBLK(f32), ,,,,STBLK,,,,
+ ,bcs,pn %icc, vis4e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+ ,LDBLK(f0), ,,,,STBLK,,,,
+ ,bcs,pn %icc, vis4e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+ ,LDBLK(f16), ,,,,STBLK,,,,
+ ,bcc,pt %icc, vis4)
+vis4e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f32,
+ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+ ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e2)
+vis4e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f0,
+ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+ ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e3)
+vis4e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f16,
+ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+ ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis5s: add %src, 128 - 40, %src /* IEU0 Group */
+ ldda [%src-88] %asi, %f10 /* Load Group */
+ ldda [%src-80] %asi, %f12 /* Load Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ faligndata %f10, %f12, %f48 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f50 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f52 /* FPA */
+vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+ ,LDBLK(f32), ,,,,,STBLK,,,
+ ,bcs,pn %icc, vis5e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+ ,LDBLK(f0), ,,,,,STBLK,,,
+ ,bcs,pn %icc, vis5e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+ ,LDBLK(f16), ,,,,,STBLK,,,
+ ,bcc,pt %icc, vis5)
+vis5e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f32,
+ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
+ ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e2)
+vis5e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f0,
+ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
+ ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e3)
+vis5e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f16,
+ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
+ ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis6s: add %src, 128 - 48, %src /* IEU0 Group */
+ ldda [%src-80] %asi, %f12 /* Load Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ faligndata %f12, %f14, %f48 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f50 /* FPA */
+vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+ ,LDBLK(f32), ,,,,,,STBLK,,
+ ,bcs,pn %icc, vis6e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+ ,LDBLK(f0), ,,,,,,STBLK,,
+ ,bcs,pn %icc, vis6e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+ ,LDBLK(f16), ,,,,,,STBLK,,
+ ,bcc,pt %icc, vis6)
+vis6e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f32,
+ ,SYNC, ,,,,,,STBLK,ST(f48,64),
+ ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e2)
+vis6e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f0,
+ ,SYNC, ,,,,,,STBLK,ST(f48,64),
+ ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e3)
+vis6e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f16,
+ ,SYNC, ,,,,,,STBLK,ST(f48,64),
+ ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis7s: add %src, 128 - 56, %src /* IEU0 Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ faddd %f32, %f32, %f12 /* FPA Group */
+ clr %x7 /* IEU0 */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fmovd %f14, %f48 /* FPA */
+vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+ ,LDBLK(f32), ,,,,,,,STBLK,
+ ,bcs,pn %icc, vis7e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+ ,LDBLK(f0), ,,,,,,,STBLK,
+ ,bcs,pn %icc, vis7e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+ ,LDBLK(f16), ,,,,,,,STBLK,
+ ,bcc,pt %icc, vis7)
+vis7e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f32,
+ ,SYNC, ,,,,,,,STBLK,
+ ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e2)
+vis7e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f0,
+ ,SYNC, ,,,,,,,STBLK,
+ ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e3)
+vis7e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f16,
+ ,SYNC, ,,,,,,,STBLK,
+ ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e1)
+e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6)
+e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6)
+e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6)
+ett: rd %gsr, %x3 /* LSU Group+4bubbles */
+ andcc %x3, 7, %x3 /* IEU1 Group */
+ add %dst, 8, %dst /* IEU0 Group */
+ bne,pn %icc, 1f /* CTI */
+ fzero %f10 /* FPA */
+ brz,a,pn %len, 2f /* CTI+IEU1 Group */
+ std %f6, [%dst - 8] /* Store */
+1: rd %asi, %x4 /* LSU Group+4bubbles */
+ sub %src, 64, %src /* IEU0 Group */
+ cmp %len, 8 /* IEU1 */
+ blu,pn %icc, 3f /* CTI */
+ wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */
+1: ldda [%src] %asi, %f2 /* Load Group */
+ fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ faligndata %f6, %f2, %f14 /* FPA Group */
+ fcmpgt32 %f10, %f12, %x5 /* FPM Group */
+ std %f14, [%dst - 16] /* Store */
+ fmovd %f2, %f6 /* FPA */
+ fmovd %f12, %f10 /* FPA Group */
+ sub %len, 8, %len /* IEU1 */
+ fzero %f16 /* FPA Group - FPU nop */
+ fzero %f18 /* FPA Group - FPU nop */
+ inc %x5 /* IEU0 */
+ srl %x5, 1, %x5 /* IEU0 Group (regdep) */
+ cmp %len, 8 /* IEU1 */
+ bgeu,pt %icc, 1b /* CTI */
+ add %x5, %sum, %sum /* IEU0 Group */
+3: brz,a,pt %x3, 2f /* CTI+IEU1 */
+ std %f6, [%dst - 8] /* Store Group */
+ st %f7, [%dst - 8] /* Store Group */
+ sub %dst, 4, %dst /* IEU0 */
+ add %len, 4, %len /* IEU1 */
+2:
+#ifdef __KERNEL__
+ sub %sp, 8, %sp /* IEU0 Group */
+#endif
+ END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
+ membar #Sync /* LSU Group */
+#ifdef __KERNEL__
+ wr %g0, 0, %fprs /* LSU Group */
+ add %sp, 8, %sp /* IEU0 Group */
+#endif
+23: brnz,pn %len, 26f /* CTI+IEU1 Group */
+24: sllx %sum, 32, %g1 /* IEU0 */
+25: addcc %sum, %g1, %src /* IEU1 Group */
+ srlx %src, 32, %src /* IEU0 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %src, 1, %src /* IEU1 */
+#ifndef __KERNEL__
+1: retl /* CTI Group brk forced */
+ srl %src, 0, %src /* IEU0 */
+#else
+1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */
+ retl /* CTI Group brk forced */
+ sllx %g4, 32, %g4 /* IEU0 */
+#endif
+26: andcc %len, 8, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ lduwa [%src] %asi, %g3 /* Load */
+ lduwa [%src+4] %asi, %g2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ sllx %g3, 32, %g5 /* IEU0 Group */
+ stw %g3, [%dst - 8] /* Store */
+ or %g5, %g2, %g5 /* IEU0 Group */
+ stw %g2, [%dst - 4] /* Store */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: andcc %len, 4, %g0 /* IEU1 Group */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g2 /* IEU0 */
+ lduwa [%src] %asi, %g7 /* Load */
+ add %src, 4, %src /* IEU0 Group */
+ add %dst, 4, %dst /* IEU1 */
+ sllx %g7, 32, %g2 /* IEU0 Group */
+ stw %g7, [%dst - 4] /* Store */
+1: andcc %len, 2, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o4 /* IEU0 Group */
+ lduha [%src] %asi, %g7 /* Load */
+ add %src, 2, %src /* IEU1 */
+ add %dst, 2, %dst /* IEU0 Group */
+ sll %g7, 16, %o4 /* IEU0 Group */
+ sth %g7, [%dst - 2] /* Store */
+1: andcc %len, 1, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o5 /* IEU0 Group */
+ lduba [%src] %asi, %g7 /* Load */
+ sll %g7, 8, %o5 /* IEU0 Group */
+ stb %g7, [%dst] /* Store */
+1: or %g2, %o4, %o4 /* IEU1 */
+ or %o5, %o4, %o4 /* IEU0 Group (regdep) */
+ addcc %o4, %sum, %sum /* IEU1 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: ba,pt %xcc, 25b /* CTI Group */
+ sllx %sum, 32, %g1 /* IEU0 */
+
+#ifdef __KERNEL__
+end:
+
+ .section __ex_table
+ .align 8
+ .xword csum_partial_copy_vis, 0, end, cpc_handler
+#endif
-/* $Id: VISmemset.S,v 1.4 1997/07/02 19:00:39 jj Exp $
+/* $Id: VISmemset.S,v 1.6 1997/08/08 08:34:13 jj Exp $
* VISmemset.S: High speed memset operations utilizing the UltraSparc
* Visual Instruction Set.
*
#ifdef __KERNEL__
wr %g0, 0, %fprs
#endif
- membar #Sync
+ membar #StoreLoad | #StoreStore
9: andcc %o2, 0x78, %g5
be,pn %xcc, 13f
andcc %o2, 7, %o2
+#ifdef __KERNEL__
+14: srl %g5, 1, %o3
+ sethi %hi(13f), %o4
+ sub %o4, %o3, %o4
+ jmpl %o4 + %lo(13f), %g0
+ add %o0, %g5, %o0
+#else
14: rd %pc, %o4
#ifdef REGS_64BIT
srl %g5, 1, %o3
#endif
jmpl %o4 + (13f - 14b), %g0
add %o0, %g5, %o0
+#endif
12: SET_BLOCKS(%o0, 0x68, %o1)
SET_BLOCKS(%o0, 0x48, %o1)
SET_BLOCKS(%o0, 0x28, %o1)
-/* $Id: blockops.S,v 1.10 1997/06/24 17:29:10 jj Exp $
+/* $Id: blockops.S,v 1.11 1997/07/29 09:35:36 davem Exp $
* arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
wr %g0, FPRS_FEF, %fprs ! FPU Group
ldd [%o1], %f48 ! Load Group
wr %g0, ASI_BLK_P, %asi ! LSU Group
- membar #StoreStore | #LoadStore ! LSU Group
+ membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
mov 32, %g2 ! IEU0 Group
/* Cannot perform real arithmatic on the pattern, that can
subcc %g2, 1, %g2 ! IEU1 Group
bne,pt %icc, 1b ! CTI
add %o0, 0x100, %o0 ! IEU0
- membar #Sync ! LSU Group
+ membar #StoreLoad | #StoreStore ! LSU Group
jmpl %o7 + 0x8, %g0 ! CTI Group brk forced
wr %g0, 0, %fprs ! FPU Group
faddd %f0, %f2, %f12 ! FPA Group
fmuld %f0, %f2, %f14 ! FPM
wr %g0, ASI_BLK_P, %asi ! LSU Group
- membar #StoreStore | #LoadStore ! LSU Group
+ membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
1: stda %f0, [%o0 + 0x00] %asi ! Store Group
stda %f0, [%o0 + 0x40] %asi ! Store Group
stda %f0, [%o0 + 0x80] %asi ! Store Group
subcc %g1, 1, %g1 ! IEU1
bne,pt %icc, 1b ! CTI
add %o0, 0x100, %o0 ! IEU0 Group
- membar #Sync ! LSU Group
+ membar #StoreLoad | #StoreStore ! LSU Group
jmpl %o7 + 0x8, %g0 ! CTI Group brk forced
wr %g0, 0, %fprs ! FPU Group
* are two fold. Firstly, they cannot pair with jack shit,
* and also they only add in the 32-bit carry condition bit
* into the accumulated sum. The following is much better.
- *
- * This should run at max bandwidth for ecache hits, a better
- * technique is to use VIS and fpu operations. This is already
- * done for csum_partial, needs to be written for the copy stuff
- * still.
+ * For larger chunks we use VIS code, which is faster ;)
*/
- .text
- .globl __csum_partial_copy_start, __csum_partial_copy_end
-__csum_partial_copy_start:
+#define src o0
+#define dst o1
+#define len o2
+#define sum o3
+ .text
/* I think I have an erection... Once _AGAIN_ the SunSoft
* engineers are caught asleep at the keyboard, tsk tsk...
*/
-#define CSUMCOPY_ECACHE_LOAD(src, off, t0, t1, t2, t3, t4, t5, t6, t7) \
- ldxa [src + off + 0x00] %asi, t0; \
- ldxa [src + off + 0x08] %asi, t1; \
- ldxa [src + off + 0x10] %asi, t2; \
- ldxa [src + off + 0x18] %asi, t3; \
- ldxa [src + off + 0x20] %asi, t4; \
- ldxa [src + off + 0x28] %asi, t5; \
- ldxa [src + off + 0x30] %asi, t6; \
- ldxa [src + off + 0x38] %asi, t7; \
+#define CSUMCOPY_ECACHE_LOAD(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ ldxa [%src + off + 0x00] %asi, t0; \
+ ldxa [%src + off + 0x08] %asi, t1; \
+ ldxa [%src + off + 0x10] %asi, t2; \
+ ldxa [%src + off + 0x18] %asi, t3; \
+ ldxa [%src + off + 0x20] %asi, t4; \
+ ldxa [%src + off + 0x28] %asi, t5; \
+ ldxa [%src + off + 0x30] %asi, t6; \
+ ldxa [%src + off + 0x38] %asi, t7; \
nop; nop; /* DO NOT TOUCH THIS!!!!! */
-#define CSUMCOPY_EC_STALIGNED_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
- stx t0, [dest + off - 0x40]; \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STALIGNED_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ stx t0, [%dst + off - 0x40]; \
+ addcc %sum, t0, %sum; \
bcc,pt %xcc, 11f; \
- ldxa [src + off + 0x00] %asi, t0; \
- add sum, 1, sum; \
-11: stx t1, [dest + off - 0x38]; \
- addcc sum, t1, sum; \
+ ldxa [%src + off + 0x00] %asi, t0; \
+ add %sum, 1, %sum; \
+11: stx t1, [%dst + off - 0x38]; \
+ addcc %sum, t1, %sum; \
bcc,pt %xcc, 12f; \
- ldxa [src + off + 0x08] %asi, t1; \
- add sum, 1, sum; \
-12: stx t2, [dest + off - 0x30]; \
- addcc sum, t2, sum; \
+ ldxa [%src + off + 0x08] %asi, t1; \
+ add %sum, 1, %sum; \
+12: stx t2, [%dst + off - 0x30]; \
+ addcc %sum, t2, %sum; \
bcc,pt %xcc, 13f; \
- ldxa [src + off + 0x10] %asi, t2; \
- add sum, 1, sum; \
-13: stx t3, [dest + off - 0x28]; \
- addcc sum, t3, sum; \
+ ldxa [%src + off + 0x10] %asi, t2; \
+ add %sum, 1, %sum; \
+13: stx t3, [%dst + off - 0x28]; \
+ addcc %sum, t3, %sum; \
bcc,pt %xcc, 14f; \
- ldxa [src + off + 0x18] %asi, t3; \
- add sum, 1, sum; \
-14: stx t4, [dest + off - 0x20]; \
- addcc sum, t4, sum; \
+ ldxa [%src + off + 0x18] %asi, t3; \
+ add %sum, 1, %sum; \
+14: stx t4, [%dst + off - 0x20]; \
+ addcc %sum, t4, %sum; \
bcc,pt %xcc, 15f; \
- ldxa [src + off + 0x20] %asi, t4; \
- add sum, 1, sum; \
-15: stx t5, [dest + off - 0x18]; \
- addcc sum, t5, sum; \
+ ldxa [%src + off + 0x20] %asi, t4; \
+ add %sum, 1, %sum; \
+15: stx t5, [%dst + off - 0x18]; \
+ addcc %sum, t5, %sum; \
bcc,pt %xcc, 16f; \
- ldxa [src + off + 0x28] %asi, t5; \
- add sum, 1, sum; \
-16: stx t6, [dest + off - 0x10]; \
- addcc sum, t6, sum; \
+ ldxa [%src + off + 0x28] %asi, t5; \
+ add %sum, 1, %sum; \
+16: stx t6, [%dst + off - 0x10]; \
+ addcc %sum, t6, %sum; \
bcc,pt %xcc, 17f; \
- ldxa [src + off + 0x30] %asi, t6; \
- add sum, 1, sum; \
-17: stx t7, [dest + off - 0x08]; \
- addcc sum, t7, sum; \
+ ldxa [%src + off + 0x30] %asi, t6; \
+ add %sum, 1, %sum; \
+17: stx t7, [%dst + off - 0x08]; \
+ addcc %sum, t7, %sum; \
bcc,pt %xcc, 18f; \
- ldxa [src + off + 0x38] %asi, t7; \
- add sum, 1, sum; \
+ ldxa [%src + off + 0x38] %asi, t7; \
+ add %sum, 1, %sum; \
18:
-#define CSUMCOPY_EC_STUNALIGN_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
- stw t0, [dest + off - 0x3c]; \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STUNALIGN_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ stw t0, [%dst + off - 0x3c]; \
+ addcc %sum, t0, %sum; \
srlx t0, 32, t0; \
- stw t0, [dest + off - 0x40]; \
+ stw t0, [%dst + off - 0x40]; \
bcc,pt %xcc, 21f; \
- ldxa [src + off + 0x00] %asi, t0; \
- add sum, 1, sum; \
-21: stw t1, [dest + off - 0x34]; \
- addcc sum, t1, sum; \
+ ldxa [%src + off + 0x00] %asi, t0; \
+ add %sum, 1, %sum; \
+21: stw t1, [%dst + off - 0x34]; \
+ addcc %sum, t1, %sum; \
srlx t1, 32, t1; \
- stw t1, [dest + off - 0x38]; \
+ stw t1, [%dst + off - 0x38]; \
bcc,pt %xcc, 22f; \
- ldxa [src + off + 0x08] %asi, t1; \
- add sum, 1, sum; \
-22: stw t2, [dest + off - 0x2c]; \
- addcc sum, t2, sum; \
+ ldxa [%src + off + 0x08] %asi, t1; \
+ add %sum, 1, %sum; \
+22: stw t2, [%dst + off - 0x2c]; \
+ addcc %sum, t2, %sum; \
srlx t2, 32, t2; \
- stw t2, [dest + off - 0x30]; \
+ stw t2, [%dst + off - 0x30]; \
bcc,pt %xcc, 23f; \
- ldxa [src + off + 0x10] %asi, t2; \
- add sum, 1, sum; \
-23: stw t3, [dest + off - 0x24]; \
- addcc sum, t3, sum; \
+ ldxa [%src + off + 0x10] %asi, t2; \
+ add %sum, 1, %sum; \
+23: stw t3, [%dst + off - 0x24]; \
+ addcc %sum, t3, %sum; \
srlx t3, 32, t3; \
- stw t3, [dest + off - 0x28]; \
+ stw t3, [%dst + off - 0x28]; \
bcc,pt %xcc, 24f; \
- ldxa [src + off + 0x18] %asi, t3; \
- add sum, 1, sum; \
-24: stw t4, [dest + off - 0x1c]; \
- addcc sum, t4, sum; \
+ ldxa [%src + off + 0x18] %asi, t3; \
+ add %sum, 1, %sum; \
+24: stw t4, [%dst + off - 0x1c]; \
+ addcc %sum, t4, %sum; \
srlx t4, 32, t4; \
- stw t4, [dest + off - 0x20]; \
+ stw t4, [%dst + off - 0x20]; \
bcc,pt %xcc, 25f; \
- ldxa [src + off + 0x20] %asi, t4; \
- add sum, 1, sum; \
-25: stw t5, [dest + off - 0x14]; \
- addcc sum, t5, sum; \
+ ldxa [%src + off + 0x20] %asi, t4; \
+ add %sum, 1, %sum; \
+25: stw t5, [%dst + off - 0x14]; \
+ addcc %sum, t5, %sum; \
srlx t5, 32, t5; \
- stw t5, [dest + off - 0x18]; \
+ stw t5, [%dst + off - 0x18]; \
bcc,pt %xcc, 26f; \
- ldxa [src + off + 0x28] %asi, t5; \
- add sum, 1, sum; \
-26: stw t6, [dest + off - 0x0c]; \
- addcc sum, t6, sum; \
+ ldxa [%src + off + 0x28] %asi, t5; \
+ add %sum, 1, %sum; \
+26: stw t6, [%dst + off - 0x0c]; \
+ addcc %sum, t6, %sum; \
srlx t6, 32, t6; \
- stw t6, [dest + off - 0x10]; \
+ stw t6, [%dst + off - 0x10]; \
bcc,pt %xcc, 27f; \
- ldxa [src + off + 0x30] %asi, t6; \
- add sum, 1, sum; \
-27: stw t7, [dest + off - 0x04]; \
- addcc sum, t7, sum; \
+ ldxa [%src + off + 0x30] %asi, t6; \
+ add %sum, 1, %sum; \
+27: stw t7, [%dst + off - 0x04]; \
+ addcc %sum, t7, %sum; \
srlx t7, 32, t7; \
- stw t7, [dest + off - 0x08]; \
+ stw t7, [%dst + off - 0x08]; \
bcc,pt %xcc, 28f; \
- ldxa [src + off + 0x38] %asi, t7; \
- add sum, 1, sum; \
+ ldxa [%src + off + 0x38] %asi, t7; \
+ add %sum, 1, %sum; \
28:
-#define CSUMCOPY_EC_STALIGNED(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7) \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STALIGNED(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ addcc %sum, t0, %sum; \
bcc,pt %xcc, 31f; \
- stx t0, [dest + off + 0x00]; \
- add sum, 1, sum; \
-31: addcc sum, t1, sum; \
+ stx t0, [%dst + off + 0x00]; \
+ add %sum, 1, %sum; \
+31: addcc %sum, t1, %sum; \
bcc,pt %xcc, 32f; \
- stx t1, [dest + off + 0x08]; \
- add sum, 1, sum; \
-32: addcc sum, t2, sum; \
+ stx t1, [%dst + off + 0x08]; \
+ add %sum, 1, %sum; \
+32: addcc %sum, t2, %sum; \
bcc,pt %xcc, 33f; \
- stx t2, [dest + off + 0x10]; \
- add sum, 1, sum; \
-33: addcc sum, t3, sum; \
+ stx t2, [%dst + off + 0x10]; \
+ add %sum, 1, %sum; \
+33: addcc %sum, t3, %sum; \
bcc,pt %xcc, 34f; \
- stx t3, [dest + off + 0x18]; \
- add sum, 1, sum; \
-34: addcc sum, t4, sum; \
+ stx t3, [%dst + off + 0x18]; \
+ add %sum, 1, %sum; \
+34: addcc %sum, t4, %sum; \
bcc,pt %xcc, 35f; \
- stx t4, [dest + off + 0x20]; \
- add sum, 1, sum; \
-35: addcc sum, t5, sum; \
+ stx t4, [%dst + off + 0x20]; \
+ add %sum, 1, %sum; \
+35: addcc %sum, t5, %sum; \
bcc,pt %xcc, 36f; \
- stx t5, [dest + off + 0x28]; \
- add sum, 1, sum; \
-36: addcc sum, t6, sum; \
+ stx t5, [%dst + off + 0x28]; \
+ add %sum, 1, %sum; \
+36: addcc %sum, t6, %sum; \
bcc,pt %xcc, 37f; \
- stx t6, [dest + off + 0x30]; \
- add sum, 1, sum; \
-37: addcc sum, t7, sum; \
+ stx t6, [%dst + off + 0x30]; \
+ add %sum, 1, %sum; \
+37: addcc %sum, t7, %sum; \
bcc,pt %xcc, 38f; \
- stx t7, [dest + off + 0x38]; \
- add sum, 1, sum; \
+ stx t7, [%dst + off + 0x38]; \
+ add %sum, 1, %sum; \
38:
-#define CSUMCOPY_EC_STUNALIGN(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7) \
- stw t0, [dest + off + 0x04]; \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STUNALIGN(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ stw t0, [%dst + off + 0x04]; \
+ addcc %sum, t0, %sum; \
srlx t0, 32, t0; \
bcc,pt %xcc, 41f; \
- stw t0, [dest + off + 0x00]; \
- add sum, 1, sum; \
-41: stw t1, [dest + off + 0x0c]; \
- addcc sum, t1, sum; \
+ stw t0, [%dst + off + 0x00]; \
+ add %sum, 1, %sum; \
+41: stw t1, [%dst + off + 0x0c]; \
+ addcc %sum, t1, %sum; \
srlx t1, 32, t1; \
bcc,pt %xcc, 42f; \
- stw t1, [dest + off + 0x08]; \
- add sum, 1, sum; \
-42: stw t2, [dest + off + 0x14]; \
- addcc sum, t2, sum; \
+ stw t1, [%dst + off + 0x08]; \
+ add %sum, 1, %sum; \
+42: stw t2, [%dst + off + 0x14]; \
+ addcc %sum, t2, %sum; \
srlx t2, 32, t2; \
bcc,pt %xcc, 43f; \
- stw t2, [dest + off + 0x10]; \
- add sum, 1, sum; \
-43: stw t3, [dest + off + 0x1c]; \
- addcc sum, t3, sum; \
+ stw t2, [%dst + off + 0x10]; \
+ add %sum, 1, %sum; \
+43: stw t3, [%dst + off + 0x1c]; \
+ addcc %sum, t3, %sum; \
srlx t3, 32, t3; \
bcc,pt %xcc, 44f; \
- stw t3, [dest + off + 0x18]; \
- add sum, 1, sum; \
-44: stw t4, [dest + off + 0x24]; \
- addcc sum, t4, sum; \
+ stw t3, [%dst + off + 0x18]; \
+ add %sum, 1, %sum; \
+44: stw t4, [%dst + off + 0x24]; \
+ addcc %sum, t4, %sum; \
srlx t4, 32, t4; \
bcc,pt %xcc, 45f; \
- stw t4, [dest + off + 0x20]; \
- add sum, 1, sum; \
-45: stw t5, [dest + off + 0x2c]; \
- addcc sum, t5, sum; \
+ stw t4, [%dst + off + 0x20]; \
+ add %sum, 1, %sum; \
+45: stw t5, [%dst + off + 0x2c]; \
+ addcc %sum, t5, %sum; \
srlx t5, 32, t5; \
bcc,pt %xcc, 46f; \
- stw t5, [dest + off + 0x28]; \
- add sum, 1, sum; \
-46: stw t6, [dest + off + 0x34]; \
- addcc sum, t6, sum; \
+ stw t5, [%dst + off + 0x28]; \
+ add %sum, 1, %sum; \
+46: stw t6, [%dst + off + 0x34]; \
+ addcc %sum, t6, %sum; \
srlx t6, 32, t6; \
bcc,pt %xcc, 47f; \
- stw t6, [dest + off + 0x30]; \
- add sum, 1, sum; \
-47: stw t7, [dest + off + 0x3c]; \
- addcc sum, t7, sum; \
+ stw t6, [%dst + off + 0x30]; \
+ add %sum, 1, %sum; \
+47: stw t7, [%dst + off + 0x3c]; \
+ addcc %sum, t7, %sum; \
srlx t7, 32, t7; \
bcc,pt %xcc, 48f; \
- stw t7, [dest + off + 0x38]; \
- add sum, 1, sum; \
+ stw t7, [%dst + off + 0x38]; \
+ add %sum, 1, %sum; \
48:
-#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1) \
- ldxa [src - off - 0x08] %asi, t0; \
- ldxa [src - off - 0x00] %asi, t1; \
+#define CSUMCOPY_LASTCHUNK(off, t0, t1) \
+ ldxa [%src - off - 0x08] %asi, t0; \
+ ldxa [%src - off - 0x00] %asi, t1; \
nop; nop; \
- addcc t0, sum, sum; \
- stw t0, [dst - off - 0x04]; \
+ addcc t0, %sum, %sum; \
+ stw t0, [%dst - off - 0x04]; \
srlx t0, 32, t0; \
bcc,pt %xcc, 51f; \
- stw t0, [dst - off - 0x08]; \
- add sum, 1, sum; \
-51: addcc t1, sum, sum; \
- stw t1, [dst - off + 0x04]; \
+ stw t0, [%dst - off - 0x08]; \
+ add %sum, 1, %sum; \
+51: addcc t1, %sum, %sum; \
+ stw t1, [%dst - off + 0x04]; \
srlx t1, 32, t1; \
bcc,pt %xcc, 52f; \
- stw t1, [dst - off - 0x00]; \
- add sum, 1, sum; \
+ stw t1, [%dst - off - 0x00]; \
+ add %sum, 1, %sum; \
52:
+cpc_start:
cc_end_cruft:
- andcc %o3, 8, %g0 ! IEU1 Group
+ andcc %g7, 8, %g0 ! IEU1 Group
be,pn %icc, 1f ! CTI
- and %o3, 4, %g5 ! IEU0
- ldxa [%o0 + 0x00] %asi, %g2 ! Load Group
- add %o1, 8, %o1 ! IEU0
- add %o0, 8, %o0 ! IEU1
- addcc %g2, %g7, %g7 ! IEU1 Group + 2 bubbles
- stw %g2, [%o1 - 0x04] ! Store
+ and %g7, 4, %g5 ! IEU0
+ ldxa [%src + 0x00] %asi, %g2 ! Load Group
+ add %dst, 8, %dst ! IEU0
+ add %src, 8, %src ! IEU1
+ addcc %g2, %sum, %sum ! IEU1 Group + 2 bubbles
+ stw %g2, [%dst - 0x04] ! Store
srlx %g2, 32, %g2 ! IEU0
bcc,pt %xcc, 1f ! CTI Group
- stw %g2, [%o1 - 0x08] ! Store
- add %g7, 1, %g7 ! IEU0
+ stw %g2, [%dst - 0x08] ! Store
+ add %sum, 1, %sum ! IEU0
1: brz,pt %g5, 1f ! CTI Group
clr %g2 ! IEU0
- lduwa [%o0 + 0x00] %asi, %g2 ! Load
- add %o1, 4, %o1 ! IEU0 Group
- add %o0, 4, %o0 ! IEU1
- stw %g2, [%o1 - 0x04] ! Store Group + 2 bubbles
+ lduwa [%src + 0x00] %asi, %g2 ! Load
+ add %dst, 4, %dst ! IEU0 Group
+ add %src, 4, %src ! IEU1
+ stw %g2, [%dst - 0x04] ! Store Group + 2 bubbles
sllx %g2, 32, %g2 ! IEU0
-1: andcc %o3, 2, %g0 ! IEU1
+1: andcc %g7, 2, %g0 ! IEU1
be,pn %icc, 1f ! CTI Group
clr %o4 ! IEU1
- lduha [%o0 + 0x00] %asi, %o4 ! Load
- add %o0, 2, %o0 ! IEU0 Group
- add %o1, 2, %o1 ! IEU1
- sth %o4, [%o1 - 0x2] ! Store Group + 2 bubbles
+ lduha [%src + 0x00] %asi, %o4 ! Load
+ add %src, 2, %src ! IEU0 Group
+ add %dst, 2, %dst ! IEU1
+ sth %o4, [%dst - 0x2] ! Store Group + 2 bubbles
sll %o4, 16, %o4 ! IEU0
-1: andcc %o3, 1, %g0 ! IEU1
+1: andcc %g7, 1, %g0 ! IEU1
be,pn %icc, 1f ! CTI Group
clr %o5 ! IEU0
- lduba [%o0 + 0x00] %asi, %o5 ! Load
- stb %o5, [%o1 + 0x00] ! Store Group + 2 bubbles
+ lduba [%src + 0x00] %asi, %o5 ! Load
+ stb %o5, [%dst + 0x00] ! Store Group + 2 bubbles
sll %o5, 8, %o5 ! IEU0
1: or %g2, %o4, %o4 ! IEU1
or %o5, %o4, %o4 ! IEU0 Group
- addcc %o4, %g7, %g7 ! IEU1
+ addcc %o4, %sum, %sum ! IEU1
bcc,pt %xcc, ccfold ! CTI
sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 Group
b,pt %xcc, ccfold ! CTI
- add %g7, 1, %g7 ! IEU1
+ add %sum, 1, %sum ! IEU1
cc_fixit:
bl,a,pn %icc, ccte ! CTI
- andcc %g1, 0xf, %o3 ! IEU1 Group
- andcc %o0, 1, %g0 ! IEU1 Group
- bne,pn %icc, ccslow ! CTI
- andcc %o0, 2, %g0 ! IEU1 Group
+ andcc %len, 0xf, %g7 ! IEU1 Group
+ andcc %src, 2, %g0 ! IEU1 Group
be,pn %icc, 1f ! CTI
- andcc %o0, 0x4, %g0 ! IEU1 Group
- lduha [%o0 + 0x00] %asi, %g4 ! Load
- sub %g1, 2, %g1 ! IEU0
- add %o0, 2, %o0 ! IEU0 Group
- add %o1, 2, %o1 ! IEU1
+ andcc %src, 0x4, %g0 ! IEU1 Group
+ lduha [%src + 0x00] %asi, %g4 ! Load
+ sub %len, 2, %len ! IEU0
+ add %src, 2, %src ! IEU0 Group
+ add %dst, 2, %dst ! IEU1
sll %g4, 16, %g3 ! IEU0 Group + 1 bubble
- addcc %g3, %g7, %g7 ! IEU1
+ addcc %g3, %sum, %sum ! IEU1
bcc,pt %xcc, 0f ! CTI
- srl %g7, 16, %g3 ! IEU0 Group
+ srl %sum, 16, %g3 ! IEU0 Group
add %g3, 1, %g3 ! IEU0 4 clocks (mispredict)
-0: andcc %o0, 0x4, %g0 ! IEU1 Group
- sth %g4, [%o1 - 0x2] ! Store
- sll %g7, 16, %g7 ! IEU0
+0: andcc %src, 0x4, %g0 ! IEU1 Group
+ sth %g4, [%dst - 0x2] ! Store
+ sll %sum, 16, %sum ! IEU0
sll %g3, 16, %g3 ! IEU0 Group
- srl %g7, 16, %g7 ! IEU0 Group
- or %g3, %g7, %g7 ! IEU0 Group (regdep)
+ srl %sum, 16, %sum ! IEU0 Group
+ or %g3, %sum, %sum ! IEU0 Group (regdep)
1: be,pt %icc, cc_dword_aligned ! CTI
- andn %g1, 0xff, %g2 ! IEU1
- lduwa [%o0 + 0x00] %asi, %g4 ! Load Group
- sub %g1, 4, %g1 ! IEU0
- add %o0, 4, %o0 ! IEU1
- add %o1, 4, %o1 ! IEU0 Group
- addcc %g4, %g7, %g7 ! IEU1 Group + 1 bubble
- stw %g4, [%o1 - 0x4] ! Store
+ andn %len, 0xff, %g2 ! IEU1
+ lduwa [%src + 0x00] %asi, %g4 ! Load Group
+ sub %len, 4, %len ! IEU0
+ add %src, 4, %src ! IEU1
+ add %dst, 4, %dst ! IEU0 Group
+ addcc %g4, %sum, %sum ! IEU1 Group + 1 bubble
+ stw %g4, [%dst - 0x4] ! Store
bcc,pt %xcc, cc_dword_aligned ! CTI
- andn %g1, 0xff, %g2 ! IEU0 Group
+ andn %len, 0xff, %g2 ! IEU0 Group
b,pt %xcc, cc_dword_aligned ! CTI 4 clocks (mispredict)
- add %g7, 1, %g7 ! IEU0
+ add %sum, 1, %sum ! IEU0
.align 32
- .globl __csum_partial_copy_sparc_generic, csum_partial_copy
-csum_partial_copy:
-__csum_partial_copy_sparc_generic: /* %o0=src, %o1=dest, %g1=len, %g7=sum */
- xorcc %o0, %o1, %o4 ! IEU1 Group
- srl %g7, 0, %g7 ! IEU0
+ .globl csum_partial_copy_sparc64
+csum_partial_copy_sparc64: /* %o0=src, %o1=dest, %o2=len, %o3=sum */
+ xorcc %src, %dst, %o4 ! IEU1 Group
+ srl %sum, 0, %sum ! IEU0
andcc %o4, 3, %g0 ! IEU1 Group
- srl %g1, 0, %g1 ! IEU0
+ srl %len, 0, %len ! IEU0
+ bne,pn %icc, ccslow ! CTI
+ andcc %src, 1, %g0 ! IEU1 Group
bne,pn %icc, ccslow ! CTI
- andcc %o0, 7, %g0 ! IEU1 Group
+ cmp %len, 256 ! IEU1 Group
+ bgeu,pt %icc, csum_partial_copy_vis ! CTI
+ andcc %src, 7, %g0 ! IEU1 Group
be,pt %icc, cc_dword_aligned ! CTI
- andn %g1, 0xff, %g2 ! IEU0
+ andn %len, 0xff, %g2 ! IEU0
b,pt %xcc, cc_fixit ! CTI Group
- cmp %g1, 6 ! IEU1
+ cmp %len, 6 ! IEU1
cc_dword_aligned:
brz,pn %g2, 3f ! CTI Group
- andcc %o1, 4, %g0 ! IEU1 Group (brz uses IEU1)
+ andcc %dst, 4, %g0 ! IEU1 Group (brz uses IEU1)
be,pn %icc, ccdbl + 4 ! CTI
-5: CSUMCOPY_ECACHE_LOAD( %o0, 0x00, %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN( %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+5: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
10:
- sub %g1, 256, %g1 ! IEU0 Group
- add %o0, 256, %o0 ! IEU1
- andncc %g1, 0xff, %g0 ! IEU1 Group
+ sub %len, 256, %len ! IEU0 Group
+ add %src, 256, %src ! IEU1
+ andncc %len, 0xff, %g0 ! IEU1 Group
bne,pt %icc, 5b ! CTI
- add %o1, 256, %o1 ! IEU0
-3: andcc %g1, 0xf0, %o2 ! IEU1 Group
+ add %dst, 256, %dst ! IEU0
+3: andcc %len, 0xf0, %g1 ! IEU1 Group
ccmerge:be,pn %icc, ccte ! CTI
- andcc %g1, 0xf, %o3 ! IEU1 Group
- sll %o2, 2, %o4 ! IEU0
-13: rd %pc, %o5 ! LSU Group + 4 clocks
- add %o0, %o2, %o0 ! IEU0 Group
- sub %o5, %o4, %o5 ! IEU1 Group
- jmpl %o5 + (12f - 13b), %g0 ! CTI Group brk forced
- add %o1, %o2, %o1 ! IEU0 Group
-cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xe8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xd8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xc8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xb8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xa8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x98,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x88,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x78,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x48,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x38,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3)
+ andcc %len, 0xf, %g7 ! IEU1 Group
+ sll %g1, 2, %o4 ! IEU0
+13: sethi %hi(12f), %o5 ! IEU0 Group
+ add %src, %g1, %src ! IEU1
+ sub %o5, %o4, %o5 ! IEU0 Group
+ jmpl %o5 + %lo(12f), %g0 ! CTI Group brk forced
+ add %dst, %g1, %dst ! IEU0 Group
+cctbl: CSUMCOPY_LASTCHUNK(0xe8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xd8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xc8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xb8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xa8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x98,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x88,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x78,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x68,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x58,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x48,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x38,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x28,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x18,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x08,%g2,%g3)
12:
- andcc %g1, 0xf, %o3 ! IEU1 Group
+ andcc %len, 0xf, %g7 ! IEU1 Group
ccte: bne,pn %icc, cc_end_cruft ! CTI
sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
-ccfold: sllx %g7, 32, %o0 ! IEU0 Group
- addcc %g7, %o0, %o0 ! IEU1 Group (regdep)
+ccfold: sllx %sum, 32, %o0 ! IEU0 Group
+ addcc %sum, %o0, %o0 ! IEU1 Group (regdep)
srlx %o0, 32, %o0 ! IEU0 Group (regdep)
bcs,a,pn %xcc, 1f ! CTI
add %o0, 1, %o0 ! IEU1 4 clocks (mispredict)
1: retl ! CTI Group brk forced
sllx %g4, 32,%g4 ! IEU0 Group
-ccdbl: CSUMCOPY_ECACHE_LOAD( %o0, 0x00, %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED( %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ccdbl: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
11:
- sub %g1, 256, %g1 ! IEU0 Group
- add %o0, 256, %o0 ! IEU1
- andncc %g1, 0xff, %g0 ! IEU1 Group
+ sub %len, 256, %len ! IEU0 Group
+ add %src, 256, %src ! IEU1
+ andncc %len, 0xff, %g0 ! IEU1 Group
bne,pt %icc, ccdbl ! CTI
- add %o1, 256, %o1 ! IEU0
+ add %dst, 256, %dst ! IEU0
b,pt %xcc, ccmerge ! CTI Group
- andcc %g1, 0xf0, %o2 ! IEU1
+ andcc %len, 0xf0, %g1 ! IEU1
ccslow: mov 0, %g5
- brlez,pn %g1, 4f
- andcc %o0, 1, %o5
+ brlez,pn %len, 4f
+ andcc %src, 1, %o5
be,a,pt %icc, 1f
- srl %g1, 1, %o3
- sub %g1, 1, %g1
- lduba [%o0] %asi, %g5
- add %o0, 1, %o0
- stb %g5, [%o1]
- srl %g1, 1, %o3
- add %o1, 1, %o1
-1: brz,a,pn %o3, 3f
- andcc %g1, 1, %g0
- andcc %o0, 2, %g0
+ srl %len, 1, %g7
+ sub %len, 1, %len
+ lduba [%src] %asi, %g5
+ add %src, 1, %src
+ stb %g5, [%dst]
+ srl %len, 1, %g7
+ add %dst, 1, %dst
+1: brz,a,pn %g7, 3f
+ andcc %len, 1, %g0
+ andcc %src, 2, %g0
be,a,pt %icc, 1f
- srl %o3, 1, %o3
- lduha [%o0] %asi, %o4
- sub %g1, 2, %g1
+ srl %g7, 1, %g7
+ lduha [%src] %asi, %o4
+ sub %len, 2, %len
srl %o4, 8, %g2
- sub %o3, 1, %o3
- stb %g2, [%o1]
+ sub %g7, 1, %g7
+ stb %g2, [%dst]
add %o4, %g5, %g5
- stb %o4, [%o1 + 1]
- add %o0, 2, %o0
- srl %o3, 1, %o3
- add %o1, 2, %o1
-1: brz,a,pn %o3, 2f
- andcc %g1, 2, %g0
- lda [%o0] %asi, %o4
+ stb %o4, [%dst + 1]
+ add %src, 2, %src
+ srl %g7, 1, %g7
+ add %dst, 2, %dst
+1: brz,a,pn %g7, 2f
+ andcc %len, 2, %g0
+ lduwa [%src] %asi, %o4
5: srl %o4, 24, %g2
srl %o4, 16, %g3
- stb %g2, [%o1]
+ stb %g2, [%dst]
srl %o4, 8, %g2
- stb %g3, [%o1 + 1]
- add %o0, 4, %o0
- stb %g2, [%o1 + 2]
+ stb %g3, [%dst + 1]
+ add %src, 4, %src
+ stb %g2, [%dst + 2]
addcc %o4, %g5, %g5
- stb %o4, [%o1 + 3]
- addc %g5, %g0, %g5 ! I am now to lazy to optimize this (question is if it
- add %o1, 4, %o1 ! is worthy). Maybe some day - with the sll/srl
- subcc %o3, 1, %o3 ! tricks
+ stb %o4, [%dst + 3]
+ addc %g5, %g0, %g5
+ add %dst, 4, %dst
+ subcc %g7, 1, %g7
bne,a,pt %icc, 5b
- lda [%o0] %asi, %o4
+ lduwa [%src] %asi, %o4
sll %g5, 16, %g2
srl %g5, 16, %g5
srl %g2, 16, %g2
- andcc %g1, 2, %g0
+ andcc %len, 2, %g0
add %g2, %g5, %g5
2: be,a,pt %icc, 3f
- andcc %g1, 1, %g0
- lduha [%o0] %asi, %o4
- andcc %g1, 1, %g0
+ andcc %len, 1, %g0
+ lduha [%src] %asi, %o4
+ andcc %len, 1, %g0
srl %o4, 8, %g2
- add %o0, 2, %o0
- stb %g2, [%o1]
+ add %src, 2, %src
+ stb %g2, [%dst]
add %g5, %o4, %g5
- stb %o4, [%o1 + 1]
- add %o1, 2, %o1
+ stb %o4, [%dst + 1]
+ add %dst, 2, %dst
3: be,a,pt %icc, 1f
sll %g5, 16, %o4
- lduba [%o0] %asi, %g2
+ lduba [%src] %asi, %g2
sll %g2, 8, %o4
- stb %g2, [%o1]
+ stb %g2, [%dst]
add %g5, %o4, %g5
sll %g5, 16, %o4
1: addcc %o4, %g5, %g5
and %o4, 0xff, %o4
sll %g2, 8, %g2
or %g2, %o4, %g5
-4: addcc %g7, %g5, %g7
- addc %g0, %g7, %o0
+4: addcc %sum, %g5, %sum
+ addc %g0, %sum, %o0
retl
srl %o0, 0, %o0
-__csum_partial_copy_end:
+cpc_end:
+
+ .globl cpc_handler
+cpc_handler:
+ ldx [%sp + 0x7ff + 128], %g1
+ sub %g0, EFAULT, %g2
+ brnz,a,pt %g1, 1f
+ st %g2, [%g1]
+1: retl
+ nop
+
+ .section __ex_table
+ .align 8
+ .xword cpc_start, 0, cpc_end, cpc_handler
+
-/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $
+/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $
* locks.S: SMP low-level lock primitives on Sparc64.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
.align 32
___lk_busy_spin:
- orcc %g2, 0, %g0
- bne,pt %icc, ___lk_busy_spin
- ldub [%g1 + 0], %g2
+ ldub [%g1 + 0], %g2
+ brnz,pt %g2, ___lk_busy_spin
+ membar #LoadLoad
b,pt %xcc, 1f
ldstub [%g1 + 0], %g2
addcc %g2, -1, %g2
rdpr %pil, %g3
bcs,a,pn %icc, 9f
- st %g2, [%g6 + AOFF_task_lock_depth]
+ stw %g2, [%g6 + AOFF_task_lock_depth]
wrpr %g0, 15, %pil
ldstub [%g1 + 0], %g2
-1: brnz,a,pn %g2, ___lk_busy_spin
- ldub [%g1 + 0], %g2
+1: brnz,pn %g2, ___lk_busy_spin
+ membar #StoreLoad | #StoreStore
lduw [%g6 + AOFF_task_processor], %g2
- membar #LoadLoad | #LoadStore
stb %g2, [%g1 + 1]
2: mov -1, %g2
- st %g2, [%g6 + AOFF_task_lock_depth]
+ stw %g2, [%g6 + AOFF_task_lock_depth]
wrpr %g3, 0, %pil
9: jmpl %o7 + 0x8, %g0
mov %g5, %o7
___lock_reacquire_kernel:
rdpr %pil, %g3
wrpr %g0, 15, %pil
- st %g2, [%g6 + AOFF_task_lock_depth]
+ stw %g2, [%g6 + AOFF_task_lock_depth]
ldstub [%g1 + 0], %g2
1: brz,pt %g2, 3f
- ldub [%g1 + 0], %g2
-2: brnz,a,pt %g2, 2b
- ldub [%g1 + 0], %g2
+ membar #StoreLoad | #StoreStore
+2: ldub [%g1 + 0], %g2
+ brnz,pt %g2, 2b
+ membar #LoadLoad
b,pt %xcc, 1b
ldstub [%g1 + 0], %g2
3: lduw [%g6 + AOFF_task_processor], %g2
- membar #LoadLoad | #LoadStore
stb %g2, [%g1 + 1]
wrpr %g3, 0, %pil
jmpl %o7 + 0x8, %g0
out:
unlock_kernel();
}
-
-void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
- struct vm_area_struct *vmaring;
- struct inode *inode;
- unsigned long vaddr, offset, start;
- pgd_t *pgdp;
- pmd_t *pmdp;
- pte_t *ptep;
- int alias_found = 0;
-
- inode = vma->vm_dentry->d_inode;
- if(!inode)
- return;
-
- offset = (address & PAGE_MASK) - vma->vm_start;
- vmaring = inode->i_mmap;
- do {
- vaddr = vmaring->vm_start + offset;
-
- /* This conditional is misleading... */
- if((vaddr ^ address) & PAGE_SIZE) {
- alias_found++;
- start = vmaring->vm_start;
- while(start < vmaring->vm_end) {
- pgdp = pgd_offset(vmaring->vm_mm, start);
- if(!pgdp) goto next;
- pmdp = pmd_offset(pgdp, start);
- if(!pmdp) goto next;
- ptep = pte_offset(pmdp, start);
- if(!ptep) goto next;
-
- if(pte_val(*ptep) & _PAGE_PRESENT) {
- flush_cache_page(vmaring, start);
- *ptep = __pte(pte_val(*ptep) &
- ~(_PAGE_CV));
- flush_tlb_page(vmaring, start);
- }
- next:
- start += PAGE_SIZE;
- }
- }
- } while((vmaring = vmaring->vm_next_share) != NULL);
-
- if(alias_found && (pte_val(pte) & _PAGE_CV)) {
- pgdp = pgd_offset(vma->vm_mm, address);
- pmdp = pmd_offset(pgdp, address);
- ptep = pte_offset(pmdp, address);
- flush_cache_page(vma, address);
- *ptep = __pte(pte_val(*ptep) & ~(_PAGE_CV));
- flush_tlb_page(vma, address);
- }
-}
-/* $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $
+/* $Id: init.c,v 1.54 1997/08/15 06:44:23 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
/* References to section boundaries */
extern char __init_begin, __init_end, etext, __bss_start;
+extern void __bfill64(void *, unsigned long *);
+
+static __inline__ void __init_pmd(pmd_t *pmdp)
+{
+ __bfill64((void *)pmdp, &null_pte_table);
+}
+
+static __inline__ void __init_pgd(pgd_t *pgdp)
+{
+ __bfill64((void *)pgdp, &null_pmd_table);
+}
+
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
/* IOMMU support, the ideas are right, the code should be cleaned a bit still... */
-/* XXX Also, play with the streaming buffers at some point, both
- * XXX Fusion and Sunfire both have them aparently... -DaveM
- */
-
/* This keeps track of pages used in sparc_alloc_dvma() invocations. */
static unsigned long dvma_map_pages[0x10000000 >> 16] = { 0, };
static unsigned long dvma_pages_current_offset = 0;
static int dvma_pages_current_index = 0;
+/* #define E3000_DEBUG */
+
__initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
unsigned long memory_end, struct linux_sbus *sbus))
{
struct iommu_struct *iommu;
struct sysio_regs *sregs;
- struct linux_prom_registers rprop[2];
+ struct linux_prom64_registers rprop;
unsigned long impl, vers;
unsigned long control, tsbbase;
unsigned long *iopte;
+ u32 rlow, rhigh;
int err, i;
- err = prom_getproperty(iommu_node, "reg", (char *)rprop,
+#ifdef E3000_DEBUG
+ prom_printf("\niommu_init: [%x:%016lx:%016lx:%p] ",
+ iommu_node, memory_start, memory_end, sbus);
+#endif
+ err = prom_getproperty(iommu_node, "reg", (char *)&rprop,
sizeof(rprop));
if(err == -1) {
prom_printf("iommu_init: Cannot map SYSIO control registers.\n");
prom_halt();
}
- sregs = (struct sysio_regs *) sparc_alloc_io(rprop[0].phys_addr,
- (void *)0,
+ rlow = (rprop.phys_addr & 0xffffffff);
+ rhigh = (rprop.phys_addr >> 32);
+#ifdef E3000_DEBUG
+ prom_printf("rlow[%08x] rhigh[%08x] ", rlow, rhigh);
+#endif
+ sregs = (struct sysio_regs *) sparc_alloc_io(rlow, (void *)0,
sizeof(struct sysio_regs),
- "SYSIO Regs",
- rprop[0].which_io, 0x0);
+ "SYSIO Regs", rhigh, 0x0);
+#ifdef E3000_DEBUG
+ prom_printf("sregs[%p]\n");
+#endif
+ if(!sregs) {
+ prom_printf("iommu_init: Fatal error, sysio regs not mapped\n");
+ prom_halt();
+ }
memory_start = (memory_start + 7) & ~7;
iommu = (struct iommu_struct *) memory_start;
memory_start += sizeof(struct iommu_struct);
+
+#ifdef E3000_DEBUG
+ prom_printf("iommu_init: iommu[%p] ", iommu);
+#endif
+
+ spin_lock_init(&iommu->iommu_lock);
iommu->sysio_regs = sregs;
sbus->iommu = iommu;
control = sregs->iommu_control;
impl = (control & IOMMU_CTRL_IMPL) >> 60;
vers = (control & IOMMU_CTRL_VERS) >> 56;
+#ifdef E3000_DEBUG
+ prom_printf("sreg_control[%08x]\n", control);
+ prom_printf("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
+ (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
+#endif
printk("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
(unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
/* Setup aliased mappings... */
for(i = 0; i < (65536 - 4096); i++) {
- *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+ *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF |
+ IOPTE_CACHE | IOPTE_WRITE);
*iopte |= (i << 16);
iopte++;
}
for( ; i < 65536; i++)
*iopte++ = 0;
+#ifdef E3000_DEBUG
+ prom_printf("IOMMU: pte's mapped, enabling IOMMU... ");
+#endif
sregs->iommu_tsbbase = __pa(tsbbase);
sregs->iommu_control = control;
+#ifdef E3000_DEBUG
+ prom_printf("done\n");
+#endif
+ /* Get the streaming buffer going. */
+ control = sregs->sbuf_control;
+ impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60;
+ vers = (control & SYSIO_SBUFCTRL_REV) >> 56;
+#ifdef E3000_DEBUG
+ prom_printf("IOMMU: enabling streaming buffer, control[%08x]... ",
+ control);
+#endif
+ printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ",
+ (unsigned int)impl, (unsigned int)vers);
+ printk("FlushFLAG[%p,%016lx] ... ",
+ (iommu->sbuf_flushflag_va = (unsigned int *)memory_start),
+ (iommu->sbuf_flushflag_pa = __pa(memory_start)));
+ *(iommu->sbuf_flushflag_va) = 0;
+ memory_start += sizeof(unsigned long); /* yes, unsigned long, for alignment */
+
+ sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN);
+
+#ifdef E3000_DEBUG
+ prom_printf("done, returning %016lx\n", memory_start);
+#endif
+ printk("ENABLED\n");
+
+ /* Finally enable DVMA arbitration for all devices, just in case. */
+ sregs->sbus_control |= SYSIO_SBCNTRL_AEN;
+
return memory_start;
}
-void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
+void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
+ struct linux_sbus *sbus)
{
- struct iommu_struct *iommu = SBus_chain->iommu; /* GROSS ME OUT! */
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
/* Find out if we need to grab some pages. */
if(!dvma_map_pages[dvma_pages_current_index] ||
((dvma_pages_current_offset + len) > (1 << 16))) {
+ struct linux_sbus *sbus;
unsigned long *iopte;
unsigned long newpages = __get_free_pages(GFP_KERNEL, 3, 0);
int i;
/* Stick it in the IOMMU. */
i = (65536 - 4096) + i;
- iopte = (unsigned long *)(iommu->page_table + i);
- *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
- *iopte |= __pa(newpages);
+ for_each_sbus(sbus) {
+ struct iommu_struct *iommu = sbus->iommu;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+ iopte = (unsigned long *)(iommu->page_table + i);
+ *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+ *iopte |= __pa(newpages);
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+ }
}
/* Get this out of the way. */
return (__u32)0;
}
+void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+ struct iommu_struct *iommu = sbus->iommu;
+ struct sysio_regs *sregs = iommu->sysio_regs;
+ unsigned long start = (unsigned long) vaddr;
+ unsigned long end = PAGE_ALIGN(start + len);
+ unsigned long flags;
+ unsigned int *sync_word;
+
+ start &= PAGE_MASK;
+
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+ sync_word = iommu->sbuf_flushflag_va;
+ sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+ membar("#StoreLoad | #MemIssue");
+ while((*sync_word & 0x1) == 0)
+ membar("#LoadLoad");
+ *sync_word = 0;
+
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
{
while(sz >= 0) {
}
}
+void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+ struct iommu_struct *iommu = sbus->iommu;
+ struct sysio_regs *sregs = iommu->sysio_regs;
+ unsigned long flags;
+ unsigned int *sync_word;
+
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+ while(sz >= 0) {
+ unsigned long start = sg[sz].dvma_addr;
+ unsigned long end = PAGE_ALIGN(start + sg[sz].len);
+
+ start &= PAGE_MASK;
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+ sz--;
+ }
+ sync_word = iommu->sbuf_flushflag_va;
+ sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+ membar("#StoreLoad | #MemIssue");
+ while((*sync_word & 0x1) == 0)
+ membar("#LoadLoad");
+ *sync_word = 0;
+
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
static char sfmmuinfo[512];
char *mmu_info(void)
unsigned long prom_itlb_tag, prom_itlb_data;
unsigned long prom_dtlb_tag, prom_dtlb_data;
-static inline void inherit_locked_prom_mappings(void)
+void inherit_locked_prom_mappings(int save_p)
{
int i;
int dtlb_seen = 0;
data = spitfire_get_dtlb_data(i);
if(!dtlb_seen && (data & _PAGE_L)) {
unsigned long tag = spitfire_get_dtlb_tag(i);
- prom_dtlb_ent = i;
- prom_dtlb_tag = tag;
- prom_dtlb_data = data;
+
+ if(save_p) {
+ prom_dtlb_ent = i;
+ prom_dtlb_tag = tag;
+ prom_dtlb_data = data;
+ }
__asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
membar("#Sync");
data = spitfire_get_itlb_data(i);
if(!itlb_seen && (data & _PAGE_L)) {
unsigned long tag = spitfire_get_itlb_tag(i);
- prom_itlb_ent = i;
- prom_itlb_tag = tag;
- prom_itlb_data = data;
+
+ if(save_p) {
+ prom_itlb_ent = i;
+ prom_itlb_tag = tag;
+ prom_itlb_data = data;
+ }
__asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
membar("#Sync");
/* If not locked, zap it. */
void __flush_tlb_all(void)
{
- unsigned long flags;
+ unsigned long pstate;
int i;
- save_flags(flags); cli();
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate\n\t"
+ "flushw"
+ : "=r" (pstate)
+ : "i" (PSTATE_IE));
for(i = 0; i < 64; i++) {
if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
__asm__ __volatile__("stxa %%g0, [%0] %1"
membar("#Sync");
}
}
- restore_flags(flags);
+ __asm__ __volatile__("wrpr %0, 0, %%pstate"
+ : : "r" (pstate));
}
-void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx)
+/* We are always protected by scheduler_lock under SMP. */
+void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx)
{
- if((ctx & ~(CTX_VERSION_MASK)) == 0) {
- flush_tlb_all();
- ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
- if(ctx == 1)
- ctx = CTX_FIRST_VERSION;
+ unsigned int new_ctx = *ctx;
+
+ if((new_ctx & ~(CTX_VERSION_MASK)) == 0) {
+ new_ctx += CTX_FIRST_VERSION;
+ if(new_ctx == 1)
+ new_ctx = CTX_FIRST_VERSION;
+ *ctx = new_ctx;
+ DO_LOCAL_FLUSH(smp_processor_id());
}
- tlb_context_cache = ctx + 1;
- mm->context = ctx;
+ mm->context = new_ctx;
+ mm->cpu_vm_mask = 0; /* Callers sets it properly. */
+ (*ctx)++;
+}
+
+#ifndef __SMP__
+unsigned long *pgd_quicklist = NULL;
+unsigned long *pmd_quicklist = NULL;
+unsigned long *pte_quicklist = NULL;
+unsigned long pgtable_cache_size = 0;
+#endif
+
+pgd_t *get_pgd_slow(void)
+{
+ pgd_t *pgd;
+
+ pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
+ if(pgd)
+ __init_pgd(pgd);
+ return pgd;
+}
+
+pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+ pmd_t *pmd;
+
+ pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+ if(pmd) {
+ __init_pmd(pmd);
+ pgd_set(pgd, pmd);
+ return pmd + offset;
+ }
+ return NULL;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) get_free_page(GFP_KERNEL);
+ if(pte) {
+ pmd_set(pmd, pte);
+ return pte + offset;
+ }
+ return NULL;
}
__initfunc(static void
*/
pt = phys_base | _PAGE_VALID | _PAGE_SZ4MB;
pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W;
- save_flags(flags); cli();
+ __save_and_cli(flags);
__asm__ __volatile__("
stxa %1, [%0] %3
stxa %2, [%5] %4
: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
: "memory");
- restore_flags(flags);
+ __restore_flags(flags);
/* Now set kernel pgd to upper alias so physical page computations
* work.
*/
init_mm.pgd += ((shift) / (sizeof(pgd_t *)));
- null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + shift);
- null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + shift);
+ /* The funny offsets are to make page table operations much quicker and
+ * requite less state, see pgtable.h for gory details.
+ */
+ null_pmd_table=__pa(((unsigned long)&empty_null_pmd_table)+shift);
+ null_pte_table=__pa(((unsigned long)&empty_null_pte_table)+shift);
pmdp = (pmd_t *) &empty_null_pmd_table;
for(i = 0; i < 1024; i++)
flushi((long)&empty_zero_page);
membar("#Sync");
- inherit_locked_prom_mappings();
+ inherit_locked_prom_mappings(1);
flush_tlb_all();
-/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $
+/* $Id: ultra.S,v 1.18 1997/08/08 08:34:23 jj Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
.align 32
.globl __flush_tlb_mm, __flush_tlb_range, __flush_tlb_page
__flush_tlb_mm: /* %o0 == (mm->context & 0x1fff) */
- rdpr %otherwin, %g1
- brz,pt %g1, 1f
- mov %o7, %g3
- call __flushw_user
- clr %g2
-1: rdpr %pil, %g1
-9: mov SECONDARY_CONTEXT, %g7
- wrpr %g0, 15, %pil
-
- ldxa [%g7] ASI_DMMU, %g2
+ mov SECONDARY_CONTEXT, %g7
+9: ldxa [%g7] ASI_DMMU, %g2
cmp %g2, %o0
- be,pt %icc, 1f
+ bne,pn %icc, 1f
mov 0x50, %g3
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ retl
+ flush %g6
+1: rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%g7] ASI_DMMU
-1: stxa %g0, [%g3] ASI_DMMU_DEMAP
- be,pt %icc, 1f
- stxa %g0, [%g3] ASI_IMMU_DEMAP
-
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ flush %g6
stxa %g2, [%g7] ASI_DMMU
-1: wrpr %g1, 0x0, %pil
+ flush %g6
retl
- flush %g6
+ wrpr %g1, 0, %pstate
+ nop
__flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
sethi %hi(8192 - 1), %g5
or %g5, %lo(8192 - 1), %g5
sub %o2, %o1, %o3
add %g5, 1, %g5
- orcc %o1, 0x50, %o1
+ orcc %o1, 0x10, %o1
srlx %o3, 13, %o4
- rdpr %otherwin, %g1
- brz,pt %g1, 1f
- mov %o7, %g3
- call __flushw_user
-
- clr %g2
-1: cmp %o4, 96
+ cmp %o4, 96
bgu,pn %icc, 9b
- rdpr %pil, %g1
- mov SECONDARY_CONTEXT, %g7
- wrpr %g0, 15, %pil
+ mov SECONDARY_CONTEXT, %g7
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
ldxa [%g7] ASI_DMMU, %g2
cmp %g2, %o0
stxa %g0, [%o1 + %o3] ASI_IMMU_DEMAP
brnz,pt %o3, 1b
sub %o3, %g5, %o3
- nop
+ flush %g6
- be,pt %icc, 1f
- wrpr %g1, 0x0, %pil
+ be,a,pt %icc, 1f
+ nop
stxa %g2, [%g7] ASI_DMMU
-1: retl
- flush %g6
+1: flush %g6
+ wrpr %g1, 0, %pstate
+ retl
+ nop
.align 32
__flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
- rdpr %otherwin, %g1
- brz,pt %g1, 1f
- mov %o7, %g3
- call __flushw_user
- clr %g2
-1: rdpr %pil, %g1
mov SECONDARY_CONTEXT, %g7
- wrpr %g0, 15, %pil
-
ldxa [%g7] ASI_DMMU, %g2
cmp %g2, %o0
be,pt %icc, 1f
or %o1, 0x10, %g3
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ retl
+ flush %g6
+1: rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%g7] ASI_DMMU
-1: stxa %g0, [%g3] ASI_DMMU_DEMAP
- be,pt %icc, 1f
- stxa %g0, [%g3] ASI_IMMU_DEMAP
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ flush %g6
stxa %g2, [%g7] ASI_DMMU
-1: wrpr %g1, 0x0, %pil
+ flush %g6
retl
- flush %g6
+ wrpr %g1, 0, %pstate
#ifdef __SMP__
/* These are all called by the slaves of a cross call, at
* %g2 scratch 1
* %g3 scratch 2
* %g4 scratch 3
- *
- * NOTE: We do not acknowledge the UPA until we are done
- * with the service. This is what tells the master
- * that he can consider the effects of the flush
- * "complete" on this cpu.
*/
.align 32
- .globl xcall_flush_tlb_page
+ .globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
xcall_flush_tlb_page:
mov SECONDARY_CONTEXT, %g2
- nop
+ or %g6, 0x10, %g4
ldxa [%g2] ASI_DMMU, %g3
- cmp %g3, %g5
- be,pt %icc, 1f
- or %g6, 0x10, %g4
stxa %g5, [%g2] ASI_DMMU
-1: stxa %g0, [%g4] ASI_DMMU_DEMAP
-
- be,pt %icc, 1f
- stxa %g0, [%g4] ASI_IMMU_DEMAP
+ stxa %g0, [%g4] ASI_DMMU_DEMAP
+ stxa %g0, [%g4] ASI_IMMU_DEMAP
stxa %g3, [%g2] ASI_DMMU
-1: b,pt %xcc, do_ivec_return
- flush %g1
+ retry
- .align 32
- .globl xcall_flush_tlb_mm
xcall_flush_tlb_mm:
mov SECONDARY_CONTEXT, %g2
- nop
+ mov 0x50, %g4
ldxa [%g2] ASI_DMMU, %g3
- cmp %g3, %g5
- be,pt %icc, 1f
- mov 0x50, %g4
stxa %g5, [%g2] ASI_DMMU
-1: stxa %g0, [%g4] ASI_DMMU_DEMAP
-
- be,pt %icc, 1f
- stxa %g0, [%g4] ASI_IMMU_DEMAP
+ stxa %g0, [%g4] ASI_DMMU_DEMAP
+ stxa %g0, [%g4] ASI_IMMU_DEMAP
stxa %g3, [%g2] ASI_DMMU
-1: b,pt %xcc, do_ivec_return
- flush %g1
+ retry
- .align 32
- .globl xcall_flush_tlb_range
xcall_flush_tlb_range:
sethi %hi(8192 - 1), %g2
or %g2, %lo(8192 - 1), %g2
andn %g7, %g2, %g7
sub %g7, %g6, %g3
add %g2, 1, %g2
- orcc %g6, 0x50, %g6
+ orcc %g6, 0x10, %g6
srlx %g3, 13, %g4
cmp %g4, 96
bgu,pn %icc, xcall_flush_tlb_mm
mov SECONDARY_CONTEXT, %g4
ldxa [%g4] ASI_DMMU, %g7
- cmp %g7, %g5
- be,pt %icc, 1f
- sub %g3, %g2, %g3
+ sub %g3, %g2, %g3
stxa %g5, [%g4] ASI_DMMU
+ nop
+ nop
1: stxa %g0, [%g6 + %g3] ASI_DMMU_DEMAP
stxa %g0, [%g6 + %g3] ASI_IMMU_DEMAP
brnz,pt %g3, 1b
sub %g3, %g2, %g3
- bne,a,pn %icc, 1f
- stxa %g7, [%g4] ASI_DMMU
-1: b,pt %xcc, do_ivec_return
- flush %g1
+ stxa %g7, [%g4] ASI_DMMU
+ retry
+ nop
+ nop
+
+ .globl xcall_report_regs
+xcall_report_regs:
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
+ b,pt %xcc, etrap_irq
+109: or %g7, %lo(109b), %g7
+ call __show_regs
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ b,pt %xcc, rtrap
+ clr %l6
+
+ .globl xcall_capture
+xcall_capture:
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
+ b,pt %xcc, etrap_irq
+109: or %g7, %lo(109b), %g7
+ call smp_penguin_jailcell
+ nop
+ b,pt %xcc, rtrap
+ clr %l6
/* These two are not performance critical... */
.globl xcall_flush_tlb_all
cmp %g2, 63
ble,pt %icc, 1b
sll %g2, 3, %g3
- b,pt %xcc, do_ivec_return
- flush %g1
+ flush %g1
+ retry
.globl xcall_flush_cache_all
xcall_flush_cache_all:
cmp %g3, %g2
bleu,pt %xcc, 1b
nop
- b,pt %xcc, do_ivec_return
- flush %g1
+ flush %g1
+ retry
#endif /* __SMP__ */
-/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $
+/* $Id: p1275.c,v 1.12 1997/07/26 18:39:01 davem Exp $
* p1275.c: Sun IEEE 1275 PROM low level interface routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
long ctx = 0;
p = p1275buf.prom_buffer;
- save_and_cli(flags);
+ __save_and_cli(flags);
ctx = spitfire_get_primary_context ();
if (ctx) {
flushw_user ();
if (ctx)
spitfire_set_primary_context (ctx);
- restore_flags(flags);
+ __restore_flags(flags);
return x;
}
-/* $Id: ranges.c,v 1.3 1997/03/21 12:33:36 jj Exp $
+/* $Id: ranges.c,v 1.7 1997/08/15 06:44:29 davem Exp $
* ranges.c: Handle ranges in newer proms for obio/sbus.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
+#include <linux/config.h>
#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/sbus.h>
+#include <asm/fhc.h>
#include <asm/system.h>
+#ifdef CONFIG_PCI
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#endif
struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
int num_obio_ranges;
}
}
+/* Apply probed fhc ranges to registers passed, if no ranges return. */
+void prom_apply_fhc_ranges(struct linux_fhc *fhc,
+ struct linux_prom_registers *regs,
+ int nregs)
+{
+ if(fhc->num_fhc_ranges)
+ prom_adjust_regs(regs, nregs, fhc->fhc_ranges,
+ fhc->num_fhc_ranges);
+}
+
+/* Apply probed central ranges to registers passed, if no ranges return. */
+void prom_apply_central_ranges(struct linux_central *central,
+ struct linux_prom_registers *regs, int nregs)
+{
+ if(central->num_central_ranges)
+ prom_adjust_regs(regs, nregs, central->central_ranges,
+ central->num_central_ranges);
+}
+
+#ifdef CONFIG_PCI
+void prom_apply_ebus_ranges(struct linux_ebus *ebus,
+ struct linux_prom_registers *regs, int nregs)
+{
+ if (ebus->num_ebus_ranges)
+ prom_adjust_regs(regs, nregs, ebus->ebus_ranges,
+ ebus->num_ebus_ranges);
+}
+#endif
+
__initfunc(void prom_ranges_init(void))
{
}
sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges));
}
+__initfunc(void prom_central_ranges_init(int cnode, struct linux_central *central))
+{
+ int success;
+
+ central->num_central_ranges = 0;
+ success = prom_getproperty(central->prom_node, "ranges",
+ (char *) central->central_ranges,
+ sizeof (central->central_ranges));
+ if (success != -1)
+ central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+__initfunc(void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc))
+{
+ int success;
+
+ fhc->num_fhc_ranges = 0;
+ success = prom_getproperty(fhc->prom_node, "ranges",
+ (char *) fhc->fhc_ranges,
+ sizeof (fhc->fhc_ranges));
+ if (success != -1)
+ fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+#ifdef CONFIG_PCI
+__initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus))
+{
+ struct ebus_range {
+ unsigned int cld_space;
+ unsigned int cld_base;
+ unsigned int prn_space;
+ unsigned int prn_base_hi;
+ unsigned int prn_base_lo;
+ unsigned int size;
+ } ranges[PROMREG_MAX];
+ int i, success;
+
+ ebus->num_ebus_ranges = 0;
+ success = prom_getproperty(ebus->prom_node, "ranges",
+ (char *)ranges, sizeof (ranges));
+ if (success != -1)
+ ebus->num_ebus_ranges = (success/sizeof(struct ebus_range));
+
+ for (i = 0; i < ebus->num_ebus_ranges; i++) {
+ ebus->ebus_ranges[i].ot_child_space = ranges[i].cld_space;
+ ebus->ebus_ranges[i].ot_child_base = ranges[i].cld_base;
+ ebus->ebus_ranges[i].ot_parent_space =
+ ranges[i].prn_space & 0x0f000000;
+ if (ranges[i].prn_base_hi)
+ prom_printf("WARNING: %s: ot_parent_base high lost\n");
+ ebus->ebus_ranges[i].ot_parent_base = ranges[i].prn_base_lo;
+ ebus->ebus_ranges[i].or_size = ranges[i].size;
+ }
+}
+
+__initfunc(void prom_pbm_ranges_init(int pnode, struct linux_pbm_info *pbm))
+{
+ int success;
+
+ pbm->num_pbm_ranges = 0;
+ success = prom_getproperty(pbm->prom_node, "ranges",
+ (char *)&pbm->pbm_ranges,
+ sizeof(pbm->pbm_ranges));
+ if(success != -1)
+ pbm->num_pbm_ranges = (success/sizeof(struct linux_prom_pci_ranges));
+}
+#endif
+
void
prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
{
-/* $Id: tree.c,v 1.5 1997/03/24 17:44:01 jj Exp $
+/* $Id: tree.c,v 1.6 1997/08/12 16:32:48 davem Exp $
* tree.c: Basic device tree traversal/scanning for the Linux
* prom library.
*
__inline__ int
prom_getchild(int node)
{
- long cnode;
+ int cnode;
if(node == -1) return 0;
cnode = __prom_getchild(node);
__inline__ int
prom_getparent(int node)
{
- long cnode;
+ int cnode;
if(node == -1) return 0;
cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
__inline__ int
prom_getsibling(int node)
{
- long sibnode;
+ int sibnode;
if(node == -1) return 0;
sibnode = __prom_getsibling(node);
if(sibnode == -1) return 0;
- return (int)sibnode;
+ return sibnode;
}
/* Return the length in bytes of property 'prop' at node 'node'.
. += 8192;
empty_bad_pte_table = .;
. += 8192;
+ empty_bad_page = .;
+ . += 8192;
+ . += 0x40;
empty_null_pmd_table = .;
. += 8192;
+ . += 0x40;
empty_null_pte_table = .;
. += 8192;
- empty_bad_page = .;
- . += 8192;
}
_end = . ;
PROVIDE (end = .);
SUB_DIRS := block char net misc #streams
MOD_SUB_DIRS := $(SUB_DIRS) sbus
-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn pnp
+ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn pnp macintosh
ifdef CONFIG_PCI
SUB_DIRS += pci
SUB_DIRS += sbus
endif
+ifdef CONFIG_PPC
+SUB_DIRS += macintosh
+MOD_SUB_DIRS += macintosh
+endif
+
# If CONFIG_SCSI is set, the core of scsi support will be added to the kernel,
# but some of the low-level things may also be modules.
ifeq ($(CONFIG_SCSI),y)
LX_OBJS :=
MX_OBJS :=
+ifeq ($(CONFIG_MAC_FLOPPY),y)
+L_OBJS += swim3.o
+endif
+
ifeq ($(CONFIG_BLK_DEV_FD),y)
L_OBJS += floppy.o
else
}
fdc_state[0].address = FDC1;
+ if (fdc_state[0].address == -1) {
+ unregister_blkdev(MAJOR_NR,"fd");
+ return -ENODEV;
+ }
#if N_FDC > 1
fdc_state[1].address = FDC2;
#endif
}
#endif /* CONFIG_AMIGA_PARTITION */
+#ifdef CONFIG_MAC_PARTITION
+#include <linux/ctype.h>
+
+/*
+ * Code to understand MacOS partition tables.
+ */
+
+#define MAC_PARTITION_MAGIC 0x504d
+
+/* type field value for A/UX or other Unix partitions */
+#define APPLE_AUX_TYPE "Apple_UNIX_SVR2"
+
+struct mac_partition {
+ __u16 signature; /* expected to be MAC_PARTITION_MAGIC */
+ __u16 res1;
+ __u32 map_count; /* # blocks in partition map */
+ __u32 start_block; /* absolute starting block # of partition */
+ __u32 block_count; /* number of blocks in partition */
+ char name[32]; /* partition name */
+ char type[32]; /* string type description */
+ __u32 data_start; /* rel block # of first data block */
+ __u32 data_count; /* number of data blocks */
+ __u32 status; /* partition status bits */
+ __u32 boot_start;
+ __u32 boot_size;
+ __u32 boot_load;
+ __u32 boot_load2;
+ __u32 boot_entry;
+ __u32 boot_entry2;
+ __u32 boot_cksum;
+ char processor[16]; /* identifies ISA of boot */
+ /* there is more stuff after this that we don't need */
+};
+
+#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */
+
+#define MAC_DRIVER_MAGIC 0x4552
+
+/* Driver descriptor structure, in block 0 */
+struct mac_driver_desc {
+ __u16 signature; /* expected to be MAC_DRIVER_MAGIC */
+ __u16 block_size;
+ __u32 block_count;
+ /* ... more stuff */
+};
+
+static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec)
+{
+ struct buffer_head *bh;
+ int blk, blocks_in_map;
+ int dev_bsize, dev_pos, pos;
+ unsigned secsize;
+ int first_bootable = 1;
+ struct mac_partition *part;
+ struct mac_driver_desc *md;
+
+ dev_bsize = get_ptable_blocksize(dev);
+ dev_pos = 0;
+ /* Get 0th block and look at the first partition map entry. */
+ if ((bh = bread(dev, 0, dev_bsize)) == 0) {
+ printk("%s: error reading partition table\n",
+ kdevname(dev));
+ return -1;
+ }
+ md = (struct mac_driver_desc *) bh->b_data;
+ if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
+ brelse(bh);
+ return 0;
+ }
+ secsize = be16_to_cpu(md->block_size);
+ if (secsize >= dev_bsize) {
+ brelse(bh);
+ dev_pos = secsize;
+ if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) {
+ printk("%s: error reading partition table\n",
+ kdevname(dev));
+ return -1;
+ }
+ }
+ part = (struct mac_partition *) (bh->b_data + secsize - dev_pos);
+ if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
+ brelse(bh);
+ return 0; /* not a MacOS disk */
+ }
+ blocks_in_map = be32_to_cpu(part->map_count);
+ for (blk = 1; blk <= blocks_in_map; ++blk) {
+ pos = blk * secsize;
+ if (pos >= dev_pos + dev_bsize) {
+ brelse(bh);
+ dev_pos = pos;
+ if ((bh = bread(dev, pos/dev_bsize, dev_bsize)) == 0) {
+ printk("%s: error reading partition table\n",
+ kdevname(dev));
+ return -1;
+ }
+ }
+ part = (struct mac_partition *) (bh->b_data + pos - dev_pos);
+ if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+ break;
+ blocks_in_map = be32_to_cpu(part->map_count);
+ add_partition(hd, current_minor,
+ fsec + be32_to_cpu(part->start_block) * (secsize/512),
+ be32_to_cpu(part->block_count) * (secsize/512));
+
+#ifdef CONFIG_PMAC
+ /*
+ * If this is the first bootable partition, tell the
+ * setup code, in case it wants to make this the root.
+ */
+ if (first_bootable
+ && (be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
+ && strcasecmp(part->processor, "powerpc") == 0) {
+ note_bootable_part(dev, blk);
+ first_bootable = 0;
+ }
+#endif /* CONFIG_PMAC */
+
+ ++current_minor;
+ }
+ brelse(bh);
+ printk("\n");
+ return 1;
+}
+
+#endif /* CONFIG_MAC_PARTITION */
+
#ifdef CONFIG_ATARI_PARTITION
#include <asm/atari_rootsec.h>
#ifdef CONFIG_ATARI_PARTITION
if(atari_partition(hd, dev, first_sector))
return;
+#endif
+#ifdef CONFIG_MAC_PARTITION
+ if (mac_partition(hd, dev, first_sector))
+ return;
#endif
printk(" unknown partition table\n");
}
#ifdef CONFIG_BLK_DEV_EZ
ez_init();
#endif
+#ifdef CONFIG_MAC_FLOPPY
+ swim3_init();
+#endif
#ifdef CONFIG_BLK_DEV_FD
floppy_init();
#else
-#if !defined (__mc68000__)
+#if !defined (__mc68000__) && !defined(CONFIG_PMAC) && !defined(__sparc__)
outb_p(0xc, 0x3f2);
#endif
#endif
--- /dev/null
+/*
+ * Driver for the SWIM3 (Super Woz Integrated Machine 3)
+ * floppy controller found on Power Macintoshes.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/fd.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/prom.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR FLOPPY_MAJOR
+#include <linux/blk.h>
+
+static int floppy_blocksizes[2] = {512};
+static int floppy_sizes[2] = {2880};
+
+enum swim_state {
+ idle,
+ locating,
+ seeking,
+ settling,
+ do_transfer,
+ jogging,
+ available,
+ revalidating,
+ ejecting
+};
+
+#define REG(x) unsigned char x; char x ## _pad[15];
+
+/*
+ * The names for these registers mostly represent speculation on my part.
+ * It will be interesting to see how close they are to the names Apple uses.
+ */
+struct swim3 {
+ REG(data);
+ REG(usecs); /* counts down at 1MHz */
+ REG(error);
+ REG(mode);
+ REG(select); /* controls CA0, CA1, CA2 and LSTRB signals */
+ REG(reg5);
+ REG(control); /* writing bits clears them */
+ REG(status); /* writing bits sets them in control */
+ REG(intr);
+ REG(nseek); /* # tracks to seek */
+ REG(ctrack); /* current track number */
+ REG(csect); /* current sector number */
+ REG(ssize); /* sector size code?? */
+ REG(sector); /* sector # to read or write */
+ REG(nsect); /* # sectors to read or write */
+ REG(intr_enable);
+};
+
+#define control_bic control
+#define control_bis status
+
+/* Bits in select register */
+#define CA_MASK 7
+#define LSTRB 8
+
+/* Bits in control register */
+#define DO_SEEK 0x80
+#define SELECT 0x20
+#define WRITE_SECTORS 0x10
+#define SCAN_TRACK 0x08
+#define DRIVE_ENABLE 0x02
+#define INTR_ENABLE 0x01
+
+/* Bits in status register */
+#define DATA 0x08
+
+/* Bits in intr and intr_enable registers */
+#define ERROR 0x20
+#define DATA_CHANGED 0x10
+#define TRANSFER_DONE 0x08
+#define SEEN_SECTOR 0x04
+#define SEEK_DONE 0x02
+
+/* Select values for swim3_action */
+#define SEEK_POSITIVE 0
+#define SEEK_NEGATIVE 4
+#define STEP 1
+#define MOTOR_ON 2
+#define MOTOR_OFF 6
+#define EJECT 7
+
+/* Select values for swim3_select and swim3_readbit */
+#define STEP_DIR 0
+#define STEPPING 1
+#define MOTOR_ON 2
+#define RELAX 3
+#define READ_DATA_0 4
+#define SINGLE_SIDED 6
+#define DRIVE_PRESENT 7
+#define DISK_IN 8
+#define WRITE_PROT 9
+#define TRACK_ZERO 10
+#define TACHO 11
+#define READ_DATA_1 12
+#define SEEK_COMPLETE 14
+
+struct floppy_state {
+ enum swim_state state;
+ volatile struct swim3 *swim3; /* hardware registers */
+ struct dbdma_regs *dma; /* DMA controller registers */
+ int swim3_intr; /* interrupt number for SWIM3 */
+ int dma_intr; /* interrupt number for DMA channel */
+ int cur_cyl; /* cylinder head is on, or -1 */
+ int cur_sector; /* last sector we saw go past */
+ int req_cyl; /* the cylinder for the current r/w request */
+ int head; /* head number ditto */
+ int req_sector; /* sector number ditto */
+ int scount; /* # sectors we're transferring at present */
+ int retries;
+ int secpercyl; /* disk geometry information */
+ int secpertrack;
+ int total_secs;
+ int write_prot; /* 1 if write-protected, 0 if not, -1 dunno */
+ struct dbdma_cmd *dma_cmd;
+ int ref_count;
+ int expect_cyl;
+ struct timer_list timeout;
+ int ejected;
+ struct wait_queue *wait;
+ int wanted;
+ char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)];
+};
+
+static struct floppy_state floppy_states[1];
+
+static unsigned short write_preamble[] = {
+ 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, /* gap field */
+ 0, 0, 0, 0, 0, 0, /* sync field */
+ 0x99a1, 0x99a1, 0x99a1, 0x99fb, /* data address mark */
+ 0x990f /* init CRC generator */
+};
+
+static unsigned short write_postamble[] = {
+ 0x9904, /* insert CRC */
+ 0x4e4e, 0x4e4e,
+ 0x9908, /* stop writing */
+ 0, 0, 0, 0, 0, 0
+};
+
+static void swim3_select(struct floppy_state *fs, int sel);
+static void swim3_action(struct floppy_state *fs, int action);
+static int swim3_readbit(struct floppy_state *fs, int bit);
+static void do_fd_request(void);
+static void start_request(struct floppy_state *fs);
+static void scan_track(struct floppy_state *fs);
+static void seek_track(struct floppy_state *fs, int n);
+static void init_dma(struct dbdma_cmd *cp, int cmd, void *buf, int count);
+static void setup_transfer(struct floppy_state *fs);
+static void act(struct floppy_state *fs);
+static void scan_timeout(unsigned long data);
+static void seek_timeout(unsigned long data);
+static void xfer_timeout(unsigned long data);
+static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int grab_drive(struct floppy_state *fs, enum swim_state state,
+ int interruptible);
+static void release_drive(struct floppy_state *fs);
+static int fd_eject(struct floppy_state *fs);
+static int floppy_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long param);
+static int floppy_open(struct inode *inode, struct file *filp);
+static int floppy_release(struct inode *inode, struct file *filp);
+static long floppy_read(struct inode *inode, struct file *filp,
+ char *buf, unsigned long count);
+static long floppy_write(struct inode *inode, struct file *filp,
+ const char *buf, unsigned long count);
+static int floppy_check_change(kdev_t dev);
+static int floppy_revalidate(kdev_t dev);
+int swim3_init(void);
+
+#define IOCTL_MODE_BIT 8
+#define OPEN_WRITE_BIT 16
+
+static void swim3_select(struct floppy_state *fs, int sel)
+{
+ volatile struct swim3 *sw = fs->swim3;
+
+ out_8(&sw->select, RELAX);
+ if (sel & 8)
+ out_8(&sw->control_bis, SELECT);
+ else
+ out_8(&sw->control_bic, SELECT);
+ out_8(&sw->select, sel & CA_MASK);
+}
+
+static void swim3_action(struct floppy_state *fs, int action)
+{
+ volatile struct swim3 *sw = fs->swim3;
+
+ swim3_select(fs, action);
+ udelay(1);
+ sw->select |= LSTRB; eieio();
+ udelay(2);
+ sw->select &= ~LSTRB; eieio();
+ udelay(1);
+ out_8(&sw->select, RELAX);
+}
+
+static int swim3_readbit(struct floppy_state *fs, int bit)
+{
+ volatile struct swim3 *sw = fs->swim3;
+ int stat;
+
+ swim3_select(fs, bit);
+ udelay(1);
+ stat = in_8(&sw->status);
+ out_8(&sw->select, RELAX);
+ return (stat & DATA) == 0;
+}
+
+static void do_fd_request(void)
+{
+ start_request(&floppy_states[0]);
+ sti();
+}
+
+static void start_request(struct floppy_state *fs)
+{
+ int drive;
+ unsigned long x;
+
+ if (fs->state == idle && fs->wanted) {
+ fs->state = available;
+ wake_up(&fs->wait);
+ return;
+ }
+ while (CURRENT && fs->state == idle) {
+ if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+ panic(DEVICE_NAME ": request list destroyed");
+ if (CURRENT->bh && !buffer_locked(CURRENT->bh))
+ panic(DEVICE_NAME ": block not locked");
+#if 0
+ printk("do_fd_req: dev=%x cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
+ kdev_t_to_nr(CURRENT->rq_dev), CURRENT->cmd,
+ CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer);
+ printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n",
+ CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors);
+#endif
+
+ drive = MINOR(CURRENT->rq_dev);
+ if (drive != 0) {
+ end_request(0);
+ continue;
+ }
+ if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) {
+ end_request(0);
+ continue;
+ }
+ if (CURRENT->current_nr_sectors == 0) {
+ end_request(1);
+ continue;
+ }
+ if (fs->ejected) {
+ end_request(0);
+ continue;
+ }
+
+ if (CURRENT->cmd == WRITE) {
+ if (fs->write_prot < 0)
+ fs->write_prot = swim3_readbit(fs, WRITE_PROT);
+ if (fs->write_prot) {
+ end_request(0);
+ continue;
+ }
+ }
+
+ fs->req_cyl = CURRENT->sector / fs->secpercyl;
+ x = CURRENT->sector % fs->secpercyl;
+ fs->head = x / fs->secpertrack;
+ fs->req_sector = x % fs->secpertrack + 1;
+ fs->state = do_transfer;
+ fs->retries = 0;
+
+ act(fs);
+ }
+}
+
+static inline void scan_track(struct floppy_state *fs)
+{
+ volatile struct swim3 *sw = fs->swim3;
+ int xx;
+
+ swim3_select(fs, READ_DATA_0);
+ xx = sw->intr; /* clear SEEN_SECTOR bit */
+ out_8(&sw->control_bis, SCAN_TRACK);
+ /* enable intr when track found */
+ out_8(&sw->intr_enable, ERROR | SEEN_SECTOR);
+ /* enable timeout */
+ fs->timeout.expires = jiffies + HZ;
+ fs->timeout.function = scan_timeout;
+ fs->timeout.data = (unsigned long) fs;
+ add_timer(&fs->timeout);
+}
+
+static inline void seek_track(struct floppy_state *fs, int n)
+{
+ volatile struct swim3 *sw = fs->swim3;
+
+ if (n >= 0) {
+ swim3_action(fs, SEEK_POSITIVE);
+ sw->nseek = n;
+ } else {
+ swim3_action(fs, SEEK_NEGATIVE);
+ sw->nseek = -n;
+ }
+ fs->expect_cyl = (fs->cur_cyl > 0)? fs->cur_cyl + n: -1;
+ swim3_select(fs, STEP);
+ out_8(&sw->control_bis, DO_SEEK);
+ /* enable intr when seek finished */
+ out_8(&sw->intr_enable, ERROR | SEEK_DONE);
+ /* enable timeout */
+ fs->timeout.expires = jiffies + HZ/2;
+ fs->timeout.function = seek_timeout;
+ fs->timeout.data = (unsigned long) fs;
+ add_timer(&fs->timeout);
+}
+
+static inline void init_dma(struct dbdma_cmd *cp, int cmd,
+ void *buf, int count)
+{
+ st_le16(&cp->req_count, count);
+ st_le16(&cp->command, cmd);
+ st_le32(&cp->phy_addr, virt_to_bus(buf));
+ cp->xfer_status = 0;
+}
+
+static inline void setup_transfer(struct floppy_state *fs)
+{
+ int n;
+ volatile struct swim3 *sw = fs->swim3;
+ struct dbdma_cmd *cp = fs->dma_cmd;
+ struct dbdma_regs *dr = fs->dma;
+
+ if (CURRENT->current_nr_sectors <= 0) {
+ printk(KERN_ERR "swim3: transfer 0 sectors?\n");
+ return;
+ }
+ if (CURRENT->cmd == WRITE)
+ n = 1;
+ else {
+ n = fs->secpertrack - fs->req_sector + 1;
+ if (n > CURRENT->current_nr_sectors)
+ n = CURRENT->current_nr_sectors;
+ }
+ fs->scount = n;
+ swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0);
+ out_8(&sw->sector, fs->req_sector);
+ out_8(&sw->nsect, n);
+ out_8(&sw->ssize, 0);
+ st_le32(&dr->cmdptr, virt_to_bus(cp));
+ if (CURRENT->cmd == WRITE) {
+ /* Set up 3 dma commands: write preamble, data, postamble */
+ init_dma(cp, OUTPUT_MORE, write_preamble, sizeof(write_preamble));
+ ++cp;
+ init_dma(cp, OUTPUT_MORE, CURRENT->buffer, 512);
+ ++cp;
+ init_dma(cp, OUTPUT_MORE, write_postamble, sizeof(write_postamble));
+ } else {
+ init_dma(cp, INPUT_MORE, CURRENT->buffer, n * 512);
+ }
+ ++cp;
+ out_le16(&cp->command, DBDMA_STOP);
+ out_le32(&dr->control, (RUN << 16) | RUN);
+ out_8(&sw->control_bis,
+ (CURRENT->cmd == WRITE? WRITE_SECTORS: 0) | SCAN_TRACK);
+ /* enable intr when transfer complete */
+ out_8(&sw->intr_enable, ERROR | TRANSFER_DONE);
+ /* enable timeout */
+ fs->timeout.expires = jiffies + 2*HZ;
+ fs->timeout.function = xfer_timeout;
+ fs->timeout.data = (unsigned long) fs;
+ add_timer(&fs->timeout);
+}
+
+static void act(struct floppy_state *fs)
+{
+ volatile struct swim3 *sw = fs->swim3;
+
+ for (;;) {
+ switch (fs->state) {
+ case idle:
+ return; /* XXX shouldn't get here */
+
+ case locating:
+ if (swim3_readbit(fs, TRACK_ZERO)) {
+ fs->cur_cyl = 0;
+ if (fs->req_cyl == 0)
+ fs->state = do_transfer;
+ else
+ fs->state = seeking;
+ break;
+ }
+ scan_track(fs);
+ return;
+
+ case seeking:
+ if (fs->cur_cyl < 0) {
+ fs->expect_cyl = -1;
+ fs->state = locating;
+ break;
+ }
+ if (fs->req_cyl == fs->cur_cyl) {
+ printk("whoops, seeking 0\n");
+ fs->state = do_transfer;
+ break;
+ }
+ seek_track(fs, fs->req_cyl - fs->cur_cyl);
+ return;
+
+ case settling:
+ /* wait for SEEK_COMPLETE to become true */
+ swim3_select(fs, SEEK_COMPLETE);
+ udelay(1);
+ out_8(&sw->intr_enable, ERROR | DATA_CHANGED);
+ in_8(&sw->intr); /* clear DATA_CHANGED */
+ if (in_8(&sw->status) & DATA) {
+ /* seek_complete is not yet true */
+ fs->timeout.expires = jiffies + HZ/2;
+ fs->timeout.function = seek_timeout;
+ fs->timeout.data = (unsigned long) fs;
+ add_timer(&fs->timeout);
+ return;
+ }
+ out_8(&sw->intr_enable, 0);
+ in_8(&sw->intr);
+ fs->state = locating;
+ break;
+
+ case do_transfer:
+ if (fs->cur_cyl != fs->req_cyl) {
+ if (fs->retries > 5) {
+ end_request(0);
+ fs->state = idle;
+ return;
+ }
+ fs->state = seeking;
+ break;
+ }
+ setup_transfer(fs);
+ return;
+
+ case jogging:
+ seek_track(fs, -5);
+ return;
+
+ default:
+ printk(KERN_ERR"swim3: unknown state %d\n", fs->state);
+ return;
+ }
+ }
+}
+
+static void scan_timeout(unsigned long data)
+{
+ struct floppy_state *fs = (struct floppy_state *) data;
+ volatile struct swim3 *sw = fs->swim3;
+
+ out_8(&sw->control_bic, SCAN_TRACK);
+ out_8(&sw->select, RELAX);
+ out_8(&sw->intr_enable, 0);
+ fs->cur_cyl = -1;
+ if (fs->retries > 5) {
+ end_request(0);
+ fs->state = idle;
+ start_request(fs);
+ } else {
+ fs->state = jogging;
+ act(fs);
+ }
+}
+
+static void seek_timeout(unsigned long data)
+{
+ struct floppy_state *fs = (struct floppy_state *) data;
+ volatile struct swim3 *sw = fs->swim3;
+
+ if (fs->state == settling) {
+ printk(KERN_ERR "swim3: MSI sel=%x ctrl=%x stat=%x intr=%x ie=%x\n",
+ sw->select, sw->control, sw->status, sw->intr, sw->intr_enable);
+ }
+ out_8(&sw->control_bic, DO_SEEK);
+ out_8(&sw->select, RELAX);
+ out_8(&sw->intr_enable, 0);
+ if (fs->state == settling && swim3_readbit(fs, SEEK_COMPLETE)) {
+ /* printk(KERN_DEBUG "swim3: missed settling interrupt\n"); */
+ fs->state = locating;
+ act(fs);
+ return;
+ }
+ printk(KERN_ERR "swim3: seek timeout\n");
+ end_request(0);
+ fs->state = idle;
+ start_request(fs);
+}
+
+static void xfer_timeout(unsigned long data)
+{
+ struct floppy_state *fs = (struct floppy_state *) data;
+ volatile struct swim3 *sw = fs->swim3;
+ struct dbdma_regs *dr = fs->dma;
+ struct dbdma_cmd *cp = fs->dma_cmd;
+ unsigned long s;
+
+ st_le32(&dr->control, RUN << 16);
+ out_8(&sw->intr_enable, 0);
+ out_8(&sw->control_bic, WRITE_SECTORS | SCAN_TRACK);
+ out_8(&sw->select, RELAX);
+ if (CURRENT->cmd == WRITE)
+ ++cp;
+ if (ld_le16(&cp->xfer_status) != 0)
+ s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9);
+ else
+ s = 0;
+ CURRENT->sector += s;
+ CURRENT->current_nr_sectors -= s;
+ printk(KERN_ERR "swim3: timeout %sing sector %ld\n",
+ (CURRENT->cmd==WRITE? "writ": "read"), CURRENT->sector);
+ end_request(0);
+ fs->state = idle;
+ start_request(fs);
+}
+
+static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct floppy_state *fs = (struct floppy_state *) dev_id;
+ volatile struct swim3 *sw = fs->swim3;
+ int intr, err, n;
+ int stat, resid;
+ struct dbdma_regs *dr;
+ struct dbdma_cmd *cp;
+
+ err = in_8(&sw->error);
+ intr = in_8(&sw->intr);
+ if ((intr & ERROR) && fs->state != do_transfer)
+ printk(KERN_ERR "swim3_interrupt, state=%d, cmd=%x, intr=%x, err=%x\n",
+ fs->state, CURRENT->cmd, intr, err);
+ switch (fs->state) {
+ case locating:
+ if (intr & SEEN_SECTOR) {
+ out_8(&sw->control_bic, SCAN_TRACK);
+ out_8(&sw->select, RELAX);
+ out_8(&sw->intr_enable, 0);
+ del_timer(&fs->timeout);
+ if (sw->ctrack == 0xff) {
+ printk(KERN_ERR "swim3: seen sector but cyl=ff?\n");
+ fs->cur_cyl = -1;
+ if (fs->retries > 5) {
+ end_request(0);
+ fs->state = idle;
+ start_request(fs);
+ } else {
+ fs->state = jogging;
+ act(fs);
+ }
+ break;
+ }
+ fs->cur_cyl = sw->ctrack;
+ fs->cur_sector = sw->csect;
+ if (fs->expect_cyl != -1 && fs->expect_cyl != fs->cur_cyl)
+ printk(KERN_ERR "swim3: expected cyl %d, got %d\n",
+ fs->expect_cyl, fs->cur_cyl);
+ fs->state = do_transfer;
+ act(fs);
+ }
+ break;
+ case seeking:
+ case jogging:
+ if (sw->nseek == 0) {
+ out_8(&sw->control_bic, DO_SEEK);
+ out_8(&sw->select, RELAX);
+ out_8(&sw->intr_enable, 0);
+ del_timer(&fs->timeout);
+ if (fs->state == seeking)
+ ++fs->retries;
+ fs->state = settling;
+ act(fs);
+ }
+ break;
+ case settling:
+ out_8(&sw->intr_enable, 0);
+ del_timer(&fs->timeout);
+ act(fs);
+ break;
+ case do_transfer:
+ if ((intr & (ERROR | TRANSFER_DONE)) == 0)
+ break;
+ dr = fs->dma;
+ cp = fs->dma_cmd;
+ st_le32(&dr->control, RUN << 16);
+ out_8(&sw->intr_enable, 0);
+ out_8(&sw->control_bic, WRITE_SECTORS | SCAN_TRACK);
+ out_8(&sw->select, RELAX);
+ del_timer(&fs->timeout);
+ if (CURRENT->cmd == WRITE)
+ ++cp;
+ stat = ld_le16(&cp->xfer_status);
+ resid = ld_le16(&cp->res_count);
+ if (intr & ERROR) {
+ n = fs->scount - 1 - resid / 512;
+ if (n > 0) {
+ CURRENT->sector += n;
+ CURRENT->current_nr_sectors -= n;
+ CURRENT->buffer += n * 512;
+ fs->req_sector += n;
+ }
+ if (fs->retries < 5) {
+ ++fs->retries;
+ act(fs);
+ } else {
+ printk("swim3: error %sing block %ld (err=%x)\n",
+ CURRENT->cmd == WRITE? "writ": "read",
+ CURRENT->sector, err);
+ end_request(0);
+ fs->state = idle;
+ }
+ } else {
+ if ((stat & ACTIVE) == 0 || resid != 0) {
+ /* musta been an error */
+ printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
+ printk(KERN_ERR " state=%d, cmd=%x, intr=%x, err=%x\n",
+ fs->state, CURRENT->cmd, intr, err);
+ end_request(0);
+ fs->state = idle;
+ start_request(fs);
+ break;
+ }
+ CURRENT->sector += fs->scount;
+ CURRENT->current_nr_sectors -= fs->scount;
+ CURRENT->buffer += fs->scount * 512;
+ if (CURRENT->current_nr_sectors <= 0) {
+ end_request(1);
+ fs->state = idle;
+ } else {
+ fs->req_sector += fs->scount;
+ if (fs->req_sector > fs->secpertrack) {
+ fs->req_sector -= fs->secpertrack;
+ if (++fs->head > 1) {
+ fs->head = 0;
+ ++fs->req_cyl;
+ }
+ }
+ act(fs);
+ }
+ }
+ if (fs->state == idle)
+ start_request(fs);
+ break;
+ default:
+ printk(KERN_ERR "swim3: don't know what to do in state %d\n", fs->state);
+ }
+}
+
+static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int grab_drive(struct floppy_state *fs, enum swim_state state,
+ int interruptible)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (fs->state != idle) {
+ ++fs->wanted;
+ while (fs->state != available) {
+ if (interruptible
+ && (current->signal & ~current->blocked)) {
+ --fs->wanted;
+ restore_flags(flags);
+ return -EINTR;
+ }
+ interruptible_sleep_on(&fs->wait);
+ }
+ --fs->wanted;
+ }
+ fs->state = state;
+ restore_flags(flags);
+ return 0;
+}
+
+static void release_drive(struct floppy_state *fs)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ fs->state = idle;
+ start_request(fs);
+ restore_flags(flags);
+}
+
+static int fd_eject(struct floppy_state *fs)
+{
+ int err, n;
+
+ err = grab_drive(fs, ejecting, 1);
+ if (err)
+ return err;
+ swim3_action(fs, EJECT);
+ for (n = 2*HZ; n > 0; --n) {
+ if (swim3_readbit(fs, RELAX))
+ break;
+ if ((current->signal & ~current->blocked) != 0) {
+ err = -EINTR;
+ break;
+ }
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ }
+ fs->ejected = 1;
+ release_drive(fs);
+ return err;
+}
+
+static struct floppy_struct floppy_type =
+ { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */
+
+static int floppy_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long param)
+{
+ struct floppy_state *fs;
+ int err;
+
+ if (((cmd & 0x80) && !suser())
+ || ((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))))
+ return -EPERM;
+
+ fs = &floppy_states[0];
+ switch (cmd) {
+ case FDEJECT:
+ if (fs->ref_count != 1)
+ return -EBUSY;
+ err = fd_eject(fs);
+ return err;
+ case FDGETPRM:
+ err = copy_to_user((void *) param, (void *) &floppy_type,
+ sizeof(struct floppy_struct));
+ return err;
+ }
+ return -ENOIOCTLCMD;
+}
+
+static int floppy_open(struct inode *inode, struct file *filp)
+{
+ struct floppy_state *fs;
+ volatile struct swim3 *sw;
+ int n, err;
+
+ if (MINOR(inode->i_rdev) != 0)
+ return -ENODEV;
+ fs = &floppy_states[0];
+ sw = fs->swim3;
+ err = 0;
+ if (fs->ref_count == 0) {
+ out_8(&sw->intr_enable, 0);
+ out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
+ swim3_action(fs, MOTOR_ON);
+ fs->write_prot = -1;
+ fs->cur_cyl = -1;
+ for (n = HZ; n > 0; --n) {
+ if (swim3_readbit(fs, SEEK_COMPLETE))
+ break;
+ if ((current->signal & ~current->blocked) != 0) {
+ err = -EINTR;
+ break;
+ }
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ }
+ if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0
+ || swim3_readbit(fs, DISK_IN) == 0))
+ err = -ENXIO;
+ swim3_action(fs, 9);
+
+ } else if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
+ return -EBUSY;
+
+ if (err == 0 && filp && (filp->f_flags & O_NDELAY) == 0
+ && (filp->f_mode & 3)) {
+ check_disk_change(inode->i_rdev);
+ if (fs->ejected)
+ err = -ENXIO;
+ }
+
+ if (err == 0 && filp && (filp->f_flags & (O_WRONLY | O_RDWR))) {
+ if (fs->write_prot < 0)
+ fs->write_prot = swim3_readbit(fs, WRITE_PROT);
+ if (fs->write_prot)
+ err = -EROFS;
+ }
+
+ if (err) {
+ if (fs->ref_count == 0) {
+ swim3_action(fs, MOTOR_OFF);
+ out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE);
+ }
+ return err;
+ }
+
+ if (filp->f_flags & O_EXCL)
+ fs->ref_count = -1;
+ else
+ ++fs->ref_count;
+
+ /* Allow ioctls if we have write-permissions even if read-only open */
+ if ((filp->f_mode & 2) || (permission(inode, 2) == 0))
+ filp->f_mode |= IOCTL_MODE_BIT;
+ if (filp->f_mode & 2)
+ filp->f_mode |= OPEN_WRITE_BIT;
+
+ return 0;
+}
+
+static int floppy_release(struct inode *inode, struct file *filp)
+{
+ struct floppy_state *fs;
+ volatile struct swim3 *sw;
+
+ if (MINOR(inode->i_rdev) != 0)
+ return -ENXIO;
+ fs = &floppy_states[0];
+ if (filp == 0 || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
+ block_fsync(inode, filp);
+ sw = fs->swim3;
+ if (fs->ref_count > 0 && --fs->ref_count == 0) {
+ swim3_action(fs, MOTOR_OFF);
+ out_8(&sw->control_bic, 0xff);
+ }
+ return 0;
+}
+
+static int floppy_check_change(kdev_t dev)
+{
+ struct floppy_state *fs;
+
+ if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0)
+ return 0;
+ fs = &floppy_states[0];
+ return fs->ejected;
+}
+
+static int floppy_revalidate(kdev_t dev)
+{
+ struct floppy_state *fs;
+ volatile struct swim3 *sw;
+ int ret, n;
+
+ if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0)
+ return 0;
+ fs = &floppy_states[0];
+ sw = fs->swim3;
+ grab_drive(fs, revalidating, 0);
+ out_8(&sw->intr_enable, 0);
+ out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
+ swim3_action(fs, MOTOR_ON);
+ fs->write_prot = -1;
+ fs->cur_cyl = -1;
+ for (n = HZ; n > 0; --n) {
+ if (swim3_readbit(fs, SEEK_COMPLETE))
+ break;
+ if ((current->signal & ~current->blocked) != 0)
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ }
+ ret = swim3_readbit(fs, SEEK_COMPLETE) == 0
+ || swim3_readbit(fs, DISK_IN) == 0;
+ if (ret)
+ swim3_action(fs, MOTOR_OFF);
+ else {
+ fs->ejected = 0;
+ swim3_action(fs, 9);
+ }
+
+ release_drive(fs);
+ return ret;
+}
+
+static long floppy_read(struct inode *inode, struct file *filp,
+ char *buf, unsigned long count)
+{
+ struct floppy_state *fs;
+
+ if (MINOR(inode->i_rdev) != 0)
+ return -ENODEV;
+ fs = &floppy_states[0];
+ if (fs->ejected)
+ return -ENXIO;
+ return block_read(inode, filp, buf, count);
+}
+
+static long floppy_write(struct inode *inode, struct file *filp,
+ const char *buf, unsigned long count)
+{
+ struct floppy_state *fs;
+
+ if (MINOR(inode->i_rdev) != 0)
+ return -ENODEV;
+ fs = &floppy_states[0];
+ if (fs->ejected)
+ return -ENXIO;
+ return block_write(inode, filp, buf, count);
+}
+
+static void floppy_off(unsigned int nr)
+{
+}
+
+static struct file_operations floppy_fops = {
+ NULL, /* lseek */
+ floppy_read, /* read */
+ floppy_write, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ floppy_ioctl, /* ioctl */
+ NULL, /* mmap */
+ floppy_open, /* open */
+ floppy_release, /* release */
+ block_fsync, /* fsync */
+ NULL, /* fasync */
+ floppy_check_change, /* check_media_change */
+ floppy_revalidate, /* revalidate */
+};
+
+int swim3_init(void)
+{
+ struct device_node *swims;
+ struct floppy_state *fs = &floppy_states[0];
+ volatile struct swim3 *sw;
+
+ swims = find_devices("swim3");
+ if (swims == NULL)
+ return 0;
+
+ if (swims->next != NULL)
+ printk(KERN_ERR "Warning: only using first SWIM3 floppy controller\n");
+ if (swims->n_addrs != 2 || swims->n_intrs != 2) {
+ printk(KERN_ERR "swim3: expecting 2 addrs and 2 intrs! (%d, %d)\n",
+ swims->n_addrs, swims->n_intrs);
+ return -EINVAL;
+ }
+
+ if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
+ printk(KERN_ERR "Unable to get major %d for floppy\n",
+ MAJOR_NR);
+ return -EBUSY;
+ }
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ blksize_size[MAJOR_NR] = floppy_blocksizes;
+ blk_size[MAJOR_NR] = floppy_sizes;
+
+ memset(fs, 0, sizeof(*fs));
+ fs->state = idle;
+ fs->swim3 = (volatile struct swim3 *) swims->addrs[0].address;
+ fs->dma = (struct dbdma_regs *) swims->addrs[1].address;
+ fs->swim3_intr = swims->intrs[0];
+ fs->dma_intr = swims->intrs[1];
+ fs->cur_cyl = -1;
+ fs->cur_sector = -1;
+ fs->secpercyl = 36;
+ fs->secpertrack = 18;
+ fs->total_secs = 2880;
+
+ fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space);
+ memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd));
+ st_le16(&fs->dma_cmd[1].command, DBDMA_STOP);
+
+ if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) {
+ printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr);
+ return -EBUSY;
+ }
+ if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) {
+ printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA",
+ fs->dma_intr);
+ return -EBUSY;
+ }
+
+ sw = fs->swim3;
+ out_8(&sw->mode, 0x95);
+ out_8(&sw->control_bic, 0xff);
+ out_8(&sw->reg5, 0x28);
+
+ do_floppy = NULL;
+
+ printk(KERN_INFO "fd0: SWIM3 floppy controller\n");
+
+ return 0;
+}
--- /dev/null
+#
+# Makefile for the Macintosh-specific device drivers.
+#
+# 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 inherited from the
+# parent makes..
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := macintosh.a
+M_OBJS :=
+L_OBJS := via-cuda.o adb.o nvram.o
+
+ifeq ($(CONFIG_SERIAL),y)
+ LX_OBJS += macserial.o
+else
+ ifeq ($(CONFIG_SERIAL),m)
+ MX_OBJS += macserial.o
+ endif
+endif
+
+ifdef CONFIG_MAC_KEYBOARD
+L_OBJS += mac_keyb.o mackeymap.o
+endif
+
+ifdef CONFIG_VT
+ ifdef CONFIG_PMAC_CONSOLE
+ L_OBJS += pmac-cons.o control.o platinum.o valkyrie.o
+ ifdef CONFIG_ATY_VIDEO
+ L_OBJS += aty.o
+ endif
+ ifdef CONFIG_IMSTT_VIDEO
+ L_OBJS += imstt.o
+ endif
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+mackeymap.c: mackeymap.map
+ loadkeys --mktable mackeymap.map > mackeymap.c
--- /dev/null
+/*
+ * Device driver for the /dev/adb device on macintoshes.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <asm/prom.h>
+#include <asm/cuda.h>
+#include <asm/uaccess.h>
+
+#define ADB_MAJOR 56 /* major number for /dev/adb */
+
+extern void adbdev_init(void);
+
+struct adbdev_state {
+ struct cuda_request req;
+};
+
+static struct wait_queue *adb_wait;
+
+static int adb_wait_reply(struct adbdev_state *state, struct file *file)
+{
+ int ret = 0;
+ struct wait_queue wait = { current, NULL };
+
+ add_wait_queue(&adb_wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ while (!state->req.got_reply) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (current->signal & ~current->blocked) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&adb_wait, &wait);
+
+ return ret;
+}
+
+static void adb_write_done(struct cuda_request *req)
+{
+ if (!req->got_reply) {
+ req->reply_len = 0;
+ req->got_reply = 1;
+ }
+ wake_up_interruptible(&adb_wait);
+}
+
+static int adb_open(struct inode *inode, struct file *file)
+{
+ struct adbdev_state *state;
+
+ if (MINOR(inode->i_rdev) > 0)
+ return -ENXIO;
+ state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
+ if (state == 0)
+ return -ENOMEM;
+ file->private_data = state;
+ state->req.reply_expected = 0;
+ return 0;
+}
+
+static int adb_release(struct inode *inode, struct file *file)
+{
+ struct adbdev_state *state = file->private_data;
+
+ if (state) {
+ file->private_data = NULL;
+ if (state->req.reply_expected && !state->req.got_reply)
+ if (adb_wait_reply(state, file))
+ return 0;
+ kfree(state);
+ }
+ return 0;
+}
+
+static long long adb_lseek(struct inode *inode, struct file *file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static long adb_read(struct inode *inode, struct file *file,
+ char *buf, unsigned long count)
+{
+ int ret;
+ struct adbdev_state *state = file->private_data;
+
+ if (count < 2)
+ return -EINVAL;
+ if (count > sizeof(state->req.reply))
+ count = sizeof(state->req.reply);
+ ret = verify_area(VERIFY_WRITE, buf, count);
+ if (ret)
+ return ret;
+
+ if (!state->req.reply_expected)
+ return 0;
+
+ ret = adb_wait_reply(state, file);
+ if (ret)
+ return ret;
+
+ ret = state->req.reply_len;
+ copy_to_user(buf, state->req.reply, ret);
+ state->req.reply_expected = 0;
+
+ return ret;
+}
+
+static long adb_write(struct inode *inode, struct file *file,
+ const char *buf, unsigned long count)
+{
+ int ret;
+ struct adbdev_state *state = file->private_data;
+
+ if (count < 2 || count > sizeof(state->req.data))
+ return -EINVAL;
+ ret = verify_area(VERIFY_READ, buf, count);
+ if (ret)
+ return ret;
+
+ if (state->req.reply_expected && !state->req.got_reply) {
+ /* A previous request is still being processed.
+ Wait for it to finish. */
+ ret = adb_wait_reply(state, file);
+ if (ret)
+ return ret;
+ }
+
+ state->req.nbytes = count;
+ state->req.done = adb_write_done;
+ copy_from_user(state->req.data, buf, count);
+ state->req.reply_expected = 1;
+ state->req.got_reply = 0;
+ cuda_send_request(&state->req);
+
+ return count;
+}
+
+static struct file_operations adb_fops = {
+ adb_lseek,
+ adb_read,
+ adb_write,
+ NULL, /* no readdir */
+ NULL, /* no poll yet */
+ NULL, /* no ioctl yet */
+ NULL, /* no mmap */
+ adb_open,
+ adb_release
+};
+
+void adbdev_init()
+{
+ if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
+ printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
+}
--- /dev/null
+#if 0 /* not filled inaty_gt_reg_init yet */
+/* Register values for 1280x1024, 75Hz mode (20) */
+static struct aty_regvals aty_gt_reg_init_20 = {
+ { 0x10, 0x28, 0x3c },
+ { },
+ { } /* pixel clock = 134.61MHz for V=74.81Hz */
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct aty_regvals aty_gt_reg_init_19 = {
+ { 0x10, 0x28, 0x3c },
+ { },
+ { } /* pixel clock = 126.01MHz for V=75.01 Hz */
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct aty_regvals aty_gt_reg_init_18 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 100.33MHz for V=75.31Hz */
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_gt_reg_init_17 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 79.55MHz for V=74.50Hz */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_gt_reg_init_15 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 78.12MHz for V=72.12Hz */
+};
+
+#endif
+
+
+/* Register values for 1280x1024, 60Hz mode (20) */
+static struct aty_regvals aty_gt_reg_init_20 = {
+ { 0, 0, 0 },
+
+ { 0x310086, 0x310084, 0x310084 },
+ { 0x3070200, 0x30e0300, 0x30e0300 },
+ { 0x2002312, 0x3002312, 0x3002312 },
+
+ 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000,
+ { 0x88, 0x7 }
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_gt_reg_init_17 = {
+ { 0, 0, 0 },
+
+ { 0xc0085, 0xc0083, 0xc0083 },
+ { 0x3070200, 0x30e0300, 0x30e0300 },
+ { 0x2002312, 0x3002312, 0x3002312 },
+
+ 0x7f00a3, 0x2ff031f, 0x30300, 0x20100000,
+ { 0x41, 0x3 }
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_gt_reg_init_15 = {
+ { 0, 0, 0 },
+
+ { 0x310086, 0x310084, 0x310084 },
+ { 0x3070200, 0x30e0300, 0x30e0300 },
+ { 0x2002312, 0x3002312, 0x3002312 },
+
+ 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000,
+ { 0x88, 0x7 }
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct aty_regvals aty_gt_reg_init_14 = {
+ { 0, 0, 0 },
+
+ { 0x310086, 0x310084, 0x310084 },
+ { 0x3060200, 0x30d0300, 0x30d0300 },
+ { 0x2002312, 0x3002312, 0x3002312 },
+
+ 0x7f00a7, 0x2ff0325, 0x260302, 0x20100000,
+ { 0x6c, 0x6 }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct aty_regvals aty_gt_reg_init_13 = {
+ { 0x200, 0x200, 0x200 },
+
+ { 0x28006f, 0x28006d, 0x28006c },
+ { 0x3050200, 0x30b0300, 0x30e0600 },
+ { 0x2002312, 0x3002312, 0x6002312 },
+
+ 0x67008f, 0x26f029a, 0x230270, 0x1a100040,
+ { 0x4f, 0x05 }
+};
+
+#if 0 /* not filled in yet */
+/* Register values for 800x600, 75Hz mode (12) */
+static struct aty_regvals aty_gt_reg_init_12 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct aty_regvals aty_gt_reg_init_11 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct aty_regvals aty_gt_reg_init_10 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct aty_regvals aty_gt_reg_init_7 = {
+ { 0x10, 0x30, 0x68 },
+ { },
+ { } /* pixel clock = 57.29MHz for V=75.01Hz */
+};
+#endif
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct aty_regvals aty_gt_reg_init_6 = {
+ { 0x200, 0x200, 0x200 },
+
+ { 0x28005b, 0x280059, 0x280058 },
+ { 0x3040200, 0x3060300, 0x30c0600 },
+ { 0x2002312, 0x3002312, 0x6002312 },
+
+ 0x4f006b, 0x1df020c, 0x2301e2, 0x14100040,
+ { 0x35, 0x07 }
+};
+
+#if 0 /* not filled in yet */
+/* Register values for 640x480, 60Hz mode (5) */
+static struct aty_regvals aty_gt_reg_init_5 = {
+ { 0x200, 0x200, 0x200 },
+ { },
+ { 0x35, 0x07 }
+};
+#endif
--- /dev/null
+#if 0 /* not filled inaty_vt_reg_init yet */
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct aty_regvals aty_vt_reg_init_7 = {
+ { 0x10, 0x30, 0x68 },
+ { },
+ { } /* pixel clock = 57.29MHz for V=75.01Hz */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_vt_reg_init_15 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 78.12MHz for V=72.12Hz */
+};
+
+#endif
+
+/* Register values for 1280x1024, 60Hz mode (20) */
+static struct aty_regvals aty_vt_reg_init_20 = {
+ { 0, 0, 0 },
+ { 0x2e02a7, 0x2e02a7, 0x2e02a7},
+ { 0x3070200, 0x3070200, 0x3070200},
+ { 0xa00cb22, 0xb00cb23, 0xe00cb24 },
+
+ 0x9f00d2, 0x3ff0429, 0x30400, 0x28000000,
+ { 0x00, 0xaa }
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct aty_regvals aty_vt_reg_init_18 = {
+ { 0, 0, 0 },
+ { 0x300295, 0x300194, 0x300194 },
+ { 0x3060200, 0x30e0300, 0x30e0300 },
+ { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+
+ 0x8f00b5, 0x3650392, 0x230368, 0x24000000,
+ { 0x00, 0x9d }
+ /* pixel clock = 100.33MHz for V=75.31Hz */
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_vt_reg_init_17 = {
+ { 0, 0, 0 },
+
+ { 0x2c0283, 0x2c0182, 0x2c0182 },
+ { 0x3060200, 0x30a0300, 0x30a0300 },
+ { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+
+ 0x7f00a3, 0x2ff031f, 0x30300, 0x20000000,
+ { 0x01, 0xf7 }
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_vt_reg_init_15 = {
+ { 0, 0, 0 },
+
+ { 0x310284, 0x310183, 0x310183 },
+ { 0x3060200, 0x3090300, 0x3090600 },
+ { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+
+ 0x7f00a5, 0x2ff0325, 0x260302, 0x20000000,
+ { 0x01, 0xeb }
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct aty_regvals aty_vt_reg_init_14 = {
+ { 0, 0, 0 },
+ { 0x310284, 0x310183, 0x310183 },
+ { 0x3060200, 0x3080300, 0x30f0600 },
+ { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+
+ 0x7f00a7, 0x2ff0325, 0x260302, 0x20000000,
+ { 0x01, 0xcc }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct aty_regvals aty_vt_reg_init_13 = {
+ { 0, 0, 0 },
+
+ { 0x28026d, 0x28016c, 0x28016c },
+ { 0x3060200, 0x3080300, 0x30f0600 },
+ { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+
+ 0x67008f, 0x26f029a, 0x230270, 0x1a000000,
+ { 0x01, 0xb4 }
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct aty_regvals aty_vt_reg_init_12 = {
+ { 0, 0, 0 },
+ { 0x2a0267, 0x2a0166, 0x2a0565 },
+ { 0x3040200, 0x3060300, 0x30d0600 },
+ { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+
+ 0x630083, 0x2570270, 0x30258, 0x19000000,
+ { 0x01, 0x9c }
+ /* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct aty_regvals aty_vt_reg_init_11 = {
+ { 0, 0, 0 },
+
+ { 0x2f026c, 0x2f016b, 0x2f056a },
+ { 0x3040200, 0x3060300, 0x30d0600 },
+ { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+
+ 0x630081, 0x257029b, 0x6027c, 0x19000000,
+ { 0x01, 0x9d }
+ /* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct aty_regvals aty_vt_reg_init_10 = {
+ { 0, 0, 0 },
+ { 0x30026a, 0x300169, 0x300568 },
+ { 0x3030200, 0x3050300, 0x30b0600 },
+ { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+
+ 0x630083, 0x2570273, 0x40258, 0x19000000,
+ { 0x02, 0xfb }
+/* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct aty_regvals aty_vt_reg_init_6 = {
+ { 0, 0, 0 },
+
+ { 0x280259, 0x280158, 0x280557 },
+ { 0x3030200, 0x3040300, 0x3080600 },
+ { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+
+ 0x4f006b, 0x1df020c, 0x2301e2, 0x14000000,
+ { 0x02, 0xbe }
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct aty_regvals aty_vt_reg_init_5 = {
+ { 0, 0, 0 },
+
+ { 0x2c0253, 0x2c0152, 0x2c0551 },
+ { 0x3030200, 0x3040300, 0x3060600 },
+ { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+
+ 0x4f0063, 0x1df020c, 0x2201e9, 0x14000000,
+ { 0x02, 0x9e }
+};
--- /dev/null
+/*
+ * aty.c: Console support for ATI/mach64 display adaptor cards.
+ *
+ * Copyright (C) 1997 Michael AK Tesch
+ * written with much help from Jon Howell
+ * changes to support the vt chip set by harry ac eaton
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include "pmac-cons.h"
+#include "aty.h"
+
+struct aty_cmap_regs {
+ unsigned char windex;
+ unsigned char lut;
+ unsigned char mask;
+ unsigned char rindex;
+ unsigned char cntl;
+};
+
+struct aty_regvals {
+ int offset[3]; /* first pixel address */
+
+ int crtc_h_sync_strt_wid[3]; /* depth dependant */
+ int crtc_gen_cntl[3];
+ int mem_cntl[3];
+
+ int crtc_h_tot_disp; /* mode dependant */
+ int crtc_v_tot_disp;
+ int crtc_v_sync_strt_wid;
+ int crtc_off_pitch;
+
+ unsigned char clock_val[2]; /* vals for 20 and 21 */
+};
+
+/*static void set_aty_clock(unsigned char *params);*/
+static int aty_vram_reqd(int vmode, int cmode);
+
+static unsigned char *frame_buffer;
+static int total_vram; /* total amount of video memory, bytes */
+static int is_vt_chip; /* whether a vt chip type was detected */
+
+static unsigned long aty_regbase;
+static struct aty_cmap_regs *aty_cmap_regs;
+
+/* this array contains the number of bytes/line for each mode and color depth */
+static int pitch[20][3] = {
+ {0,0,0}, /* mode 1?? */
+ {0,0,0}, /* mode 2?? */
+ {0,0,0}, /* mode 3??*/
+ {0,0,0}, /* mode 4?? */
+ {640, 1280, 2560}, /* mode 5 */
+ {640, 1280, 2560}, /* mode 6 */
+ {640, 1280, 2560}, /* mode 7 */
+ {800, 1600, 3200}, /* mode 8 */
+ {0,0,0}, /* mode 9 ??*/
+ {800, 1600, 3200}, /* mode 10 */
+ {800, 1600, 3200}, /* mode 11 */
+ {800, 1600, 3200}, /* mode 12 */
+ {832, 1664, 3328}, /* mode 13 */
+ {1024, 2048, 4096}, /* mode 14 */
+ {1024, 2048, 4096}, /* mode 15 */
+ {1024, 2048, 4096}, /* mode 16 */
+ {1024, 2048, 4096}, /* mode 17 */
+ {1152, 2304, 4608}, /* mode 18 */
+ {1280, 2560, 5120}, /* mode 19 */
+ {1280, 2560, 5120} /* mode 20 */
+};
+
+#include "ati-gt.h"
+#include "ati-vt.h"
+
+static struct aty_regvals *aty_gt_reg_init[20] = {
+ NULL, NULL, NULL, NULL,
+ &aty_gt_reg_init_6,
+ &aty_gt_reg_init_6,
+ NULL,
+ NULL, NULL,
+ NULL,
+ NULL,NULL,
+ &aty_gt_reg_init_13,
+ &aty_gt_reg_init_14,
+ &aty_gt_reg_init_15,
+ NULL,
+ &aty_gt_reg_init_17,
+ NULL,
+ NULL,
+ &aty_gt_reg_init_20
+};
+
+static struct aty_regvals *aty_vt_reg_init[20] = {
+ NULL, NULL, NULL, NULL,
+ &aty_vt_reg_init_5,
+ &aty_vt_reg_init_6,
+ NULL,
+ NULL, NULL,
+ &aty_vt_reg_init_10,
+ &aty_vt_reg_init_11,
+ &aty_vt_reg_init_12,
+ &aty_vt_reg_init_13,
+ &aty_vt_reg_init_14,
+ &aty_vt_reg_init_15,
+ NULL,
+ &aty_vt_reg_init_17,
+ &aty_vt_reg_init_18,
+ NULL,
+ &aty_vt_reg_init_20
+};
+
+static inline int aty_vram_reqd(int vmode, int cmode)
+{
+ return vmode_attrs[vmode-1].vres
+ * pitch[vmode-1][cmode];
+}
+
+extern inline unsigned aty_ld_rev(volatile unsigned long addr)
+{
+ unsigned val;
+
+ (long)addr += (long)aty_regbase;
+ asm volatile("lwbrx %0,0,%1" : "=r" (val) : "r" (addr));
+ return val;
+}
+
+extern inline void aty_st_rev(volatile unsigned long addr, unsigned val)
+{
+ (long)addr += (long)aty_regbase;
+ asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+extern inline unsigned char aty_ld_byte(volatile unsigned long addr)
+{
+ unsigned char val;
+
+ val = *(char*)((long)addr+(long)aty_regbase);
+ return val;
+}
+
+extern inline void aty_st_byte(volatile unsigned long addr, unsigned char val)
+{
+ *(unsigned char*)(addr+(unsigned long)aty_regbase) = val;
+}
+
+void
+aty_st_514( int offset, char val )
+{
+ aty_WaitQueue(5);
+ aty_st_byte( DAC_CNTL, 1);
+ aty_st_byte( DAC_W_INDEX, offset & 0xff ); /* right addr byte */
+ aty_st_byte( DAC_DATA, (offset>>8) & 0xff ); /* left addr byte */
+ aty_st_byte( DAC_MASK, val );
+ aty_st_byte( DAC_CNTL, 0 );
+}
+
+void
+aty_st_pll( int offset, char val )
+{
+ aty_WaitQueue(3);
+ aty_st_byte( CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN ); /* write addr byte */
+ aty_st_byte( CLOCK_CNTL + 2, val); /* write the register value */
+ aty_st_byte( CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN);
+}
+
+#if 0
+unsigned char
+aty_ld_514( int offset )
+{
+/* do the same thing as aty_st_514, just read the DAC_MASK instead of writing*/
+}
+#endif
+
+void
+aty_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors)
+{
+ int i,scale;
+
+ aty_WaitQueue(2);
+ aty_st_byte(DAC_CNTL, aty_ld_byte(DAC_CNTL) & 0xfc);
+ aty_st_byte(DAC_REGS + DAC_MASK, 0xff);
+ eieio();
+ scale = (is_vt_chip) ? ((color_mode == CMODE_16) ? 3 : 0) : 0;
+ for (i = 0; i < ncolors; ++i) {
+ aty_WaitQueue(4);
+ aty_cmap_regs->windex = (index + i) << scale; eieio();
+ aty_cmap_regs->lut = red[i]; eieio();
+ aty_cmap_regs->lut = green[i]; eieio();
+ aty_cmap_regs->lut = blue[i]; eieio();
+ }
+
+}
+
+void
+map_aty_display(struct device_node *dp)
+{
+ int i, sense;
+ unsigned long addr;
+ unsigned char bus, devfn;
+ unsigned short cmd;
+
+ if (dp->next != 0)
+ printk("Warning: only using first ATI card detected\n");
+ if (dp->n_addrs != 1)
+ panic("expecting 1 addresses for ATY (got %d)", dp->n_addrs);
+
+ aty_regbase = (int)ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
+ aty_cmap_regs = (struct aty_cmap_regs *)(aty_regbase+0xC0);
+
+ /* enable memory-space accesses using config-space command register */
+ if (pci_device_loc(dp, &bus, &devfn) == 0) {
+ pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+ if (cmd != 0xffff) {
+ cmd |= PCI_COMMAND_MEMORY;
+ pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+ }
+ }
+
+ switch( aty_ld_rev(MEM_CNTL)&MEM_SIZE_ALIAS ) {
+ case MEM_SIZE_512K:
+ total_vram = 0x80000;
+ break;
+ case MEM_SIZE_1M:
+ total_vram = 0x100000;
+ break;
+ case MEM_SIZE_2M:
+ total_vram = 0x200000;
+ break;
+ case MEM_SIZE_4M:
+ total_vram = 0x400000;
+ break;
+ case MEM_SIZE_6M:
+ total_vram = 0x600000;
+ break;
+ case MEM_SIZE_8M:
+ total_vram = 0x800000;
+ break;
+ default:
+ total_vram = 0x80000;
+ }
+#if 1
+ printk("aty_display_init: node = %p, addrs = ", dp->node);
+ printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
+ printk(", intrs =");
+ for (i = 0; i < dp->n_intrs; ++i)
+ printk(" %x", dp->intrs[i]);
+ printk( "\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int)aty_regbase,
+ bus, devfn, total_vram, (int)aty_cmap_regs );
+#endif
+ is_vt_chip = ((aty_ld_rev(CONFIG_CHIP_ID) & CFG_CHIP_TYPE) == MACH64_VT_ID);
+ /* Map in frame buffer */
+ addr = dp->addrs[0].address;
+
+ /* use the big-endian aperture (??) */
+ addr += 0x800000;
+ frame_buffer = ioremap(addr, 0x800000);
+
+
+ /* sense = read_aty_sense(); XXX not yet, just give it mine */
+ sense = 0x62b;
+ if (video_mode == VMODE_NVRAM) {
+ video_mode = nvram_read_byte(NV_VMODE);
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0)
+ video_mode = VMODE_CHOOSE;
+ }
+ if (video_mode == VMODE_CHOOSE)
+ video_mode = map_monitor_sense(sense);
+ if (((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0)
+ video_mode = VMODE_640_480_60;
+
+ /*
+ * Reduce the pixel size if we don't have enough VRAM.
+ */
+
+ if (color_mode == CMODE_NVRAM)
+ color_mode = nvram_read_byte(NV_CMODE);
+ if (color_mode < CMODE_8 || color_mode > CMODE_32)
+ color_mode = CMODE_8;
+ while (aty_vram_reqd(video_mode, color_mode) > total_vram) {
+ while (color_mode > CMODE_8
+ && aty_vram_reqd(video_mode, color_mode) > total_vram)
+ --color_mode;
+ /*
+ * adjust the video mode smaller if there still is not enough VRAM
+ */
+ if (aty_vram_reqd(video_mode, color_mode) > total_vram)
+ while ((((is_vt_chip) ? aty_vt_reg_init[--video_mode - 1]
+ : aty_gt_reg_init[--video_mode -1 ]) == 0) && (video_mode > VMODE_640_480_60)) ;
+ }
+}
+
+#if 0
+static void
+set_aty_clock(unsigned char *params)
+{
+ /* done in aty_init...probably need to change for different modes */
+ printk("tried to set ATY clock\n");
+}
+#endif
+
+void
+RGB514_Program(int cmode)
+{
+ typedef struct {
+ char pixel_dly;
+ char misc2_cntl;
+ char pixel_rep;
+ char pixel_cntl_index;
+ char pixel_cntl_v1;
+ } RGB514_DAC_Table;
+
+ static RGB514_DAC_Table RGB514DAC_Tab[8] = {
+ { 0, 0x41, 0x03, 0x71, 0x45 }, // 8bpp
+ { 0, 0x45, 0x04, 0x0c, 0x01 }, // 555
+ { 0, 0x45, 0x06, 0x0e, 0x00 }, // XRGB
+ };
+ RGB514_DAC_Table *pDacProgTab;
+
+ pDacProgTab = &RGB514DAC_Tab[cmode];
+
+ aty_st_514(0x90, 0x00);
+ aty_st_514(0x04, pDacProgTab->pixel_dly);
+ aty_st_514(0x05, 0x00);
+
+ aty_st_514(0x2, 0x1);
+ aty_st_514(0x71, pDacProgTab->misc2_cntl);
+ aty_st_514(0x0a, pDacProgTab->pixel_rep);
+
+ aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1);
+}
+
+/* The vt chipset seems to need a specialized color table for 15 bit mode */
+void
+VT_Program(int cmode)
+{
+#if 0
+ int i;
+ if (cmode != CMODE_8) {
+ aty_WaitQueue(2);
+ aty_cmap_regs->mask = 0xff; eieio();
+ aty_cmap_regs->windex = 0; eieio();
+ for (i = 0; i < 0x100; i++) {
+ aty_WaitQueue(3);
+ aty_cmap_regs->lut = i;
+ aty_cmap_regs->lut = i;
+ aty_cmap_regs->lut = i; eieio();
+ }
+ }
+#endif
+}
+
+void
+aty_init()
+{
+ int i, yoff, hres;
+ unsigned *p;
+ struct aty_regvals *init;
+
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || (init = ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1])) == 0)
+ panic("aty: display mode %d not supported", video_mode);
+ n_scanlines = vmode_attrs[video_mode-1].vres;
+ hres = vmode_attrs[video_mode-1].hres;
+ pixel_size = 1 << color_mode;
+ line_pitch = pitch[video_mode-1][color_mode];
+ row_pitch = line_pitch * 16;
+
+ aty_st_rev(BUS_CNTL, aty_ld_rev(BUS_CNTL) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK);
+
+ /* Reset engine */
+ i = aty_ld_rev(GEN_TEST_CNTL);
+ aty_st_rev(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE);
+ eieio();
+ aty_WaitIdleEmpty();
+ aty_st_rev(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE);
+ aty_WaitIdleEmpty();
+
+ i = aty_ld_byte(CRTC_GEN_CNTL+3);
+ aty_st_byte(CRTC_GEN_CNTL+3, i | (CRTC_EXT_DISP_EN >> 24));
+
+ i = aty_ld_byte(GEN_TEST_CNTL);
+ aty_st_byte(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN );
+
+ if (!is_vt_chip) {
+ RGB514_Program(color_mode);
+
+ aty_WaitIdleEmpty();
+
+ aty_st_514(0x06, 0x02);
+ aty_st_514(0x10, 0x01);
+ aty_st_514(0x70, 0x01);
+ aty_st_514(0x8f, 0x1f);
+ aty_st_514(0x03, 0x00);
+ aty_st_514(0x05, 0x00);
+
+ aty_st_514(0x20, init->clock_val[0]);
+ aty_st_514(0x21, init->clock_val[1]);
+ } else {
+ VT_Program(color_mode);
+ aty_st_pll(PLL_MACRO_CNTL, 0xb5);
+ aty_st_pll(PLL_REF_DIV, 0x2d);
+ aty_st_pll(PLL_GEN_CNTL, 0x14);
+ aty_st_pll(MCLK_FB_DIV, 0xbd);
+ aty_st_pll(PLL_VCLK_CNTL, 0x0b);
+ aty_st_pll(VCLK_POST_DIV, init->clock_val[0]);
+ aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]);
+ aty_st_pll(VCLK1_FB_DIV, 0xd6);
+ aty_st_pll(VCLK2_FB_DIV, 0xee);
+ aty_st_pll(VCLK3_FB_DIV, 0xf8);
+ aty_st_pll(PLL_XCLK_CNTL, 0x0);
+ aty_st_pll(PLL_TEST_CTRL, 0x0);
+ aty_st_pll(PLL_TEST_COUNT, 0x0);
+ }
+
+ aty_ld_byte( DAC_REGS ); /* clear counter */
+
+ aty_WaitIdleEmpty();
+
+ aty_st_rev(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp);
+ aty_st_rev(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[color_mode]);
+ aty_st_rev(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp);
+ aty_st_rev(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid);
+
+ aty_st_byte(CLOCK_CNTL, 0);
+ aty_st_byte(CLOCK_CNTL, CLOCK_STROBE);
+
+ aty_st_rev(CRTC_OFF_PITCH, init->crtc_off_pitch);
+
+ aty_st_rev(CRTC_VLINE_CRNT_VLINE, 0x14e01d0);
+/* The magic constant below translates into:
+ * 5 = No RDY delay, 1 wait st for mem write, increment during burst transfer
+ * 9 = DAC access delayed, 1 wait state for DAC
+ * 0 = Disables interupts for FIFO errors
+ * e = Allows FIFO to generate 14 wait states before generating error
+ * 1 = DAC snooping disabled, ROM disabled
+ * 0 = ROM page at 0 (disabled so doesn't matter)
+ * f = 15 ROM wait states (disabled so doesn't matter)
+ * f = 15 BUS wait states (I'm not sure this applies to PCI bus types)
+ * at some point it would be good to experiment with bench marks to see if
+ * we can gain some speed by fooling with the wait states etc.
+ */
+ aty_st_rev(BUS_CNTL, 0x590e10ff);
+ i = aty_ld_rev(MEM_CNTL) & MEM_SIZE_ALIAS;
+ if (total_vram >= 0x400000)
+ aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] &0xffff0000) | 0x0538 | i);
+ else
+ aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] & ~MEM_SIZE_ALIAS) | i );
+ aty_st_rev(CRTC_INT_CNTL, 0x2);
+ aty_WaitIdleEmpty();
+/* These magic constants are harder to figure out
+ * on the vt chipset bit 3 set makes the screen brighter
+ * and bit 15 makes the screen black! But nothing else
+ * seems to matter for the vt DAC_CNTL
+ */
+ if (is_vt_chip)
+ aty_st_rev(DAC_CNTL, 0x47012104);
+ else
+ aty_st_rev(DAC_CNTL, 0x47012100);
+
+ aty_st_byte(DAC_MASK, 0xff);
+
+ aty_st_rev(CRTC_INT_CNTL, 0x00000002);
+
+ aty_st_byte(CRTC_FIFO, ((char*)&init->crtc_gen_cntl[color_mode])[1] );
+ aty_st_byte(CRTC_PIX_WIDTH, ((char*)&init->crtc_gen_cntl[color_mode])[2] );
+ aty_st_byte(CRTC_EXT_DISP, ((char*)&init->crtc_gen_cntl[color_mode])[0] );
+
+ aty_st_rev(GEN_TEST_CNTL, 0x300); /* gui_en block_en*/
+
+ pmac_init_palette(); /* Initialize colormap */
+ yoff = (n_scanlines % 16) / 2;
+ fb_start = frame_buffer + yoff * line_pitch + init->offset[color_mode];
+
+ /* Clear screen */
+ p = (unsigned *) fb_start;
+
+ for (i = n_scanlines * line_pitch * pixel_size / sizeof(unsigned); i != 0; --i)
+ *p++ = 0;
+ display_info.height = n_scanlines;
+ display_info.width = hres;
+ display_info.depth = pixel_size * 8;
+ display_info.pitch = line_pitch;
+ display_info.mode = video_mode;
+ strncpy(display_info.name, "ATY Mach64", sizeof(display_info.name));
+ display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
+ display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex;
+ display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut;
+ display_info.disp_reg_address = aty_regbase;
+}
+
+int
+aty_setmode(struct vc_mode *mode, int doit)
+{
+ int cmode;
+#if 0
+ if (mode->mode == 21) {
+ printk("hace: about to set 0x%x to 0x%x\n",mode->depth, mode->pitch & 0xff);
+ aty_st_byte(mode->depth, mode->pitch & 0xff);
+ return 0;
+ }
+
+ if (mode->mode == 0) {
+ printk("hace: 0x%x contains 0x%x\n",mode->depth, aty_ld_byte(mode->depth));
+ return 0;
+ }
+#endif
+
+ if (mode->mode <= 0 || mode->mode > VMODE_MAX
+ || ((is_vt_chip) ? aty_vt_reg_init[mode->mode-1] : aty_gt_reg_init[mode->mode-1]) == NULL)
+ return -EINVAL;
+ switch (mode->depth) {
+ case 24:
+ case 32:
+ cmode = CMODE_32;
+ break;
+ case 16:
+ cmode = CMODE_16;
+ break;
+ case 8:
+ case 0: /* (default) */
+ cmode = CMODE_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (aty_vram_reqd(mode->mode, cmode) > total_vram) {
+ return -EINVAL;
+ }
+ if (doit) {
+ video_mode = mode->mode;
+ color_mode = cmode;
+ aty_init();
+ }
+ return 0;
+}
+
+void
+aty_set_blanking(int blank_mode)
+{
+ char gen_cntl;
+
+ gen_cntl = aty_ld_byte(CRTC_GEN_CNTL);
+ if (blank_mode & VESA_VSYNC_SUSPEND)
+ gen_cntl |= 0x8;
+ if (blank_mode & VESA_HSYNC_SUSPEND)
+ gen_cntl |= 0x4;
+ if ((blank_mode & VESA_POWERDOWN) == VESA_POWERDOWN)
+ gen_cntl |= 0x40;
+ if (blank_mode == VESA_NO_BLANKING)
+ gen_cntl &= ~(0x4c);
+ aty_st_byte(CRTC_GEN_CNTL, gen_cntl);
+}
--- /dev/null
+/*
+ * Exported procedures for the ATI/mach64 display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Michael AK Tesch
+ * written with much help from Jon Howell
+ *
+ * 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.
+ */
+
+extern void map_aty_display(struct device_node *);
+extern void aty_init(void);
+extern int aty_setmode(struct vc_mode *mode, int doit);
+extern void aty_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors);
+extern void aty_set_blanking(int blank_mode);
+
+/*
+ * most of the rest of this file comes from ATI sample code
+ */
+#ifndef REGMACH64_H
+#define REGMACH64_H
+
+/* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */
+
+#define CRTC_H_TOTAL_DISP 0x0000 /* Dword offset 00 */
+#define CRTC_H_SYNC_STRT_WID 0x0004 /* Dword offset 01 */
+#define CRTC_H_SYNC_STRT 0x0004
+#define CRTC_H_SYNC_DLY 0x0005
+#define CRTC_H_SYNC_WID 0x0006
+
+#define CRTC_V_TOTAL_DISP 0x0008 /* Dword offset 02 */
+#define CRTC_V_TOTAL 0x0008
+#define CRTC_V_DISP 0x000a
+#define CRTC_V_SYNC_STRT_WID 0x000C /* Dword offset 03 */
+#define CRTC_V_SYNC_STRT 0x000c
+#define CRTC_V_SYNC_WID 0x000e
+
+#define CRTC_VLINE_CRNT_VLINE 0x0010 /* Dword offset 04 */
+#define CRTC_OFF_PITCH 0x0014 /* Dword offset 05 */
+#define CRTC_OFFSET 0x0014
+#define CRTC_PITCH 0x0016
+
+#define CRTC_INT_CNTL 0x0018 /* Dword offset 06 */
+#define CRTC_GEN_CNTL 0x001C /* Dword offset 07 */
+#define CRTC_PIX_WIDTH 0x001d
+#define CRTC_FIFO 0x001e
+#define CRTC_EXT_DISP 0x001f
+
+#define OVR_CLR 0x0040 /* Dword offset 10 */
+#define OVR_WID_LEFT_RIGHT 0x0044 /* Dword offset 11 */
+#define OVR_WID_TOP_BOTTOM 0x0048 /* Dword offset 12 */
+
+#define CUR_CLR0 0x0060 /* Dword offset 18 */
+#define CUR_CLR1 0x0064 /* Dword offset 19 */
+#define CUR_OFFSET 0x0068 /* Dword offset 1A */
+#define CUR_HORZ_VERT_POSN 0x006C /* Dword offset 1B */
+#define CUR_HORZ_VERT_OFF 0x0070 /* Dword offset 1C */
+
+#define SCRATCH_REG0 0x0080 /* Dword offset 20 */
+#define SCRATCH_REG1 0x0084 /* Dword offset 21 */
+
+#define CLOCK_CNTL 0x0090 /* Dword offset 24 */
+#define CLOCK_SEL_CNTL 0x0090 // Dword offset 24
+
+#define BUS_CNTL 0x00A0 /* Dword offset 28 */
+
+#define MEM_CNTL 0x00B0 /* Dword offset 2C */
+
+#define MEM_VGA_WP_SEL 0x00B4 /* Dword offset 2D */
+#define MEM_VGA_RP_SEL 0x00B8 /* Dword offset 2E */
+
+#define DAC_REGS 0x00C0 /* Dword offset 30 */
+#define DAC_W_INDEX 0x00C0 /* Dword offset 30 */
+#define DAC_DATA 0x00C1 /* Dword offset 30 */
+#define DAC_MASK 0x00C2 /* Dword offset 30 */
+#define DAC_R_INDEX 0x00C3 /* Dword offset 30 */
+#define DAC_CNTL 0x00C4 /* Dword offset 31 */
+
+#define GEN_TEST_CNTL 0x00D0 /* Dword offset 34 */
+
+#define CONFIG_CNTL 0x00DC /* Dword offset 37 (CT, ET, VT) */
+#define CONFIG_CHIP_ID 0x00E0 /* Dword offset 38 */
+#define CONFIG_STAT0 0x00E4 /* Dword offset 39 */
+#define CONFIG_STAT1 0x00E8 /* Dword offset 3A */
+
+
+/* GUI MEMORY MAPPED Registers */
+
+#define DST_OFF_PITCH 0x0100 /* Dword offset 40 */
+#define DST_X 0x0104 /* Dword offset 41 */
+#define DST_Y 0x0108 /* Dword offset 42 */
+#define DST_Y_X 0x010C /* Dword offset 43 */
+#define DST_WIDTH 0x0110 /* Dword offset 44 */
+#define DST_HEIGHT 0x0114 /* Dword offset 45 */
+#define DST_HEIGHT_WIDTH 0x0118 /* Dword offset 46 */
+#define DST_X_WIDTH 0x011C /* Dword offset 47 */
+#define DST_BRES_LNTH 0x0120 /* Dword offset 48 */
+#define DST_BRES_ERR 0x0124 /* Dword offset 49 */
+#define DST_BRES_INC 0x0128 /* Dword offset 4A */
+#define DST_BRES_DEC 0x012C /* Dword offset 4B */
+#define DST_CNTL 0x0130 /* Dword offset 4C */
+
+#define SRC_OFF_PITCH 0x0180 /* Dword offset 60 */
+#define SRC_X 0x0184 /* Dword offset 61 */
+#define SRC_Y 0x0188 /* Dword offset 62 */
+#define SRC_Y_X 0x018C /* Dword offset 63 */
+#define SRC_WIDTH1 0x0190 /* Dword offset 64 */
+#define SRC_HEIGHT1 0x0194 /* Dword offset 65 */
+#define SRC_HEIGHT1_WIDTH1 0x0198 /* Dword offset 66 */
+#define SRC_X_START 0x019C /* Dword offset 67 */
+#define SRC_Y_START 0x01A0 /* Dword offset 68 */
+#define SRC_Y_X_START 0x01A4 /* Dword offset 69 */
+#define SRC_WIDTH2 0x01A8 /* Dword offset 6A */
+#define SRC_HEIGHT2 0x01AC /* Dword offset 6B */
+#define SRC_HEIGHT2_WIDTH2 0x01B0 /* Dword offset 6C */
+#define SRC_CNTL 0x01B4 /* Dword offset 6D */
+
+#define HOST_DATA0 0x0200 /* Dword offset 80 */
+#define HOST_DATA1 0x0204 /* Dword offset 81 */
+#define HOST_DATA2 0x0208 /* Dword offset 82 */
+#define HOST_DATA3 0x020C /* Dword offset 83 */
+#define HOST_DATA4 0x0210 /* Dword offset 84 */
+#define HOST_DATA5 0x0214 /* Dword offset 85 */
+#define HOST_DATA6 0x0218 /* Dword offset 86 */
+#define HOST_DATA7 0x021C /* Dword offset 87 */
+#define HOST_DATA8 0x0220 /* Dword offset 88 */
+#define HOST_DATA9 0x0224 /* Dword offset 89 */
+#define HOST_DATAA 0x0228 /* Dword offset 8A */
+#define HOST_DATAB 0x022C /* Dword offset 8B */
+#define HOST_DATAC 0x0230 /* Dword offset 8C */
+#define HOST_DATAD 0x0234 /* Dword offset 8D */
+#define HOST_DATAE 0x0238 /* Dword offset 8E */
+#define HOST_DATAF 0x023C /* Dword offset 8F */
+#define HOST_CNTL 0x0240 /* Dword offset 90 */
+
+#define PAT_REG0 0x0280 /* Dword offset A0 */
+#define PAT_REG1 0x0284 /* Dword offset A1 */
+#define PAT_CNTL 0x0288 /* Dword offset A2 */
+
+#define SC_LEFT 0x02A0 /* Dword offset A8 */
+#define SC_RIGHT 0x02A4 /* Dword offset A9 */
+#define SC_LEFT_RIGHT 0x02A8 /* Dword offset AA */
+#define SC_TOP 0x02AC /* Dword offset AB */
+#define SC_BOTTOM 0x02B0 /* Dword offset AC */
+#define SC_TOP_BOTTOM 0x02B4 /* Dword offset AD */
+
+#define DP_BKGD_CLR 0x02C0 /* Dword offset B0 */
+#define DP_FRGD_CLR 0x02C4 /* Dword offset B1 */
+#define DP_WRITE_MASK 0x02C8 /* Dword offset B2 */
+#define DP_CHAIN_MASK 0x02CC /* Dword offset B3 */
+#define DP_PIX_WIDTH 0x02D0 /* Dword offset B4 */
+#define DP_MIX 0x02D4 /* Dword offset B5 */
+#define DP_SRC 0x02D8 /* Dword offset B6 */
+
+#define CLR_CMP_CLR 0x0300 /* Dword offset C0 */
+#define CLR_CMP_MASK 0x0304 /* Dword offset C1 */
+#define CLR_CMP_CNTL 0x0308 /* Dword offset C2 */
+
+#define FIFO_STAT 0x0310 /* Dword offset C4 */
+
+#define CONTEXT_MASK 0x0320 /* Dword offset C8 */
+#define CONTEXT_LOAD_CNTL 0x032C /* Dword offset CB */
+
+#define GUI_TRAJ_CNTL 0x0330 /* Dword offset CC */
+#define GUI_STAT 0x0338 /* Dword offset CE */
+
+
+/* CRTC control values (mostly CRTC_GEN_CNTL) */
+
+#define CRTC_H_SYNC_NEG 0x00200000
+#define CRTC_V_SYNC_NEG 0x00200000
+
+#define CRTC_DBL_SCAN_EN 0x00000001
+#define CRTC_INTERLACE_EN 0x00000002
+#define CRTC_HSYNC_DIS 0x00000004
+#define CRTC_VSYNC_DIS 0x00000008
+#define CRTC_CSYNC_EN 0x00000010
+#define CRTC_PIX_BY_2_EN 0x00000020
+#define CRTC_BLANK 0x00000040
+
+#define CRTC_PIX_WIDTH_MASK 0x00000700
+#define CRTC_PIX_WIDTH_4BPP 0x00000100
+#define CRTC_PIX_WIDTH_8BPP 0x00000200
+#define CRTC_PIX_WIDTH_15BPP 0x00000300
+#define CRTC_PIX_WIDTH_16BPP 0x00000400
+#define CRTC_PIX_WIDTH_24BPP 0x00000500
+#define CRTC_PIX_WIDTH_32BPP 0x00000600
+
+#define CRTC_BYTE_PIX_ORDER 0x00000800
+#define CRTC_PIX_ORDER_MSN_LSN 0x00000000
+#define CRTC_PIX_ORDER_LSN_MSN 0x00000800
+
+#define CRTC_FIFO_LWM 0x000f0000
+#define CRTC_EXT_DISP_EN 0x01000000
+#define CRTC_EXT_EN 0x02000000
+
+#define CRTC_CRNT_VLINE 0x07f00000
+#define CRTC_VBLANK 0x00000001
+
+/* DAC control values */
+
+#define DAC_EXT_SEL_RS2 0x01
+#define DAC_EXT_SEL_RS3 0x02
+#define DAC_8BIT_EN 0x00000100
+#define DAC_PIX_DLY_MASK 0x00000600
+#define DAC_PIX_DLY_0NS 0x00000000
+#define DAC_PIX_DLY_2NS 0x00000200
+#define DAC_PIX_DLY_4NS 0x00000400
+#define DAC_BLANK_ADJ_MASK 0x00001800
+#define DAC_BLANK_ADJ_0 0x00000000
+#define DAC_BLANK_ADJ_1 0x00000800
+#define DAC_BLANK_ADJ_2 0x00001000
+
+
+/* Mix control values */
+
+#define MIX_NOT_DST 0x0000
+#define MIX_0 0x0001
+#define MIX_1 0x0002
+#define MIX_DST 0x0003
+#define MIX_NOT_SRC 0x0004
+#define MIX_XOR 0x0005
+#define MIX_XNOR 0x0006
+#define MIX_SRC 0x0007
+#define MIX_NAND 0x0008
+#define MIX_NOT_SRC_OR_DST 0x0009
+#define MIX_SRC_OR_NOT_DST 0x000a
+#define MIX_OR 0x000b
+#define MIX_AND 0x000c
+#define MIX_SRC_AND_NOT_DST 0x000d
+#define MIX_NOT_SRC_AND_DST 0x000e
+#define MIX_NOR 0x000f
+
+/* Maximum engine dimensions */
+#define ENGINE_MIN_X 0
+#define ENGINE_MIN_Y 0
+#define ENGINE_MAX_X 4095
+#define ENGINE_MAX_Y 16383
+
+/* Mach64 engine bit constants - these are typically ORed together */
+
+/* BUS_CNTL register constants */
+#define BUS_FIFO_ERR_ACK 0x00200000
+#define BUS_HOST_ERR_ACK 0x00800000
+
+/* GEN_TEST_CNTL register constants */
+#define GEN_OVR_OUTPUT_EN 0x20
+#define HWCURSOR_ENABLE 0x80
+#define GUI_ENGINE_ENABLE 0x100
+#define BLOCK_WRITE_ENABLE 0x200
+
+/* CLOCK_CNTL register constants */
+#define CLOCK_SEL 0x0f
+#define CLOCK_DIV 0x30
+#define CLOCK_DIV1 0x00
+#define CLOCK_DIV2 0x10
+#define CLOCK_DIV4 0x20
+#define CLOCK_STROBE 0x40
+#define PLL_WR_EN 0x02
+
+/* PLL registers */
+#define PLL_MACRO_CNTL 0x01
+#define PLL_REF_DIV 0x02
+#define PLL_GEN_CNTL 0x03
+#define MCLK_FB_DIV 0x04
+#define PLL_VCLK_CNTL 0x05
+#define VCLK_POST_DIV 0x06
+#define VCLK0_FB_DIV 0x07
+#define VCLK1_FB_DIV 0x08
+#define VCLK2_FB_DIV 0x09
+#define VCLK3_FB_DIV 0x0A
+#define PLL_XCLK_CNTL 0x0B
+#define PLL_TEST_CTRL 0x0E
+#define PLL_TEST_COUNT 0x0F
+
+/* Fields in PLL registers */
+#define PLL_PC_GAIN 0x07
+#define PLL_VC_GAIN 0x18
+#define PLL_DUTY_CYC 0xE0
+#define PLL_OVERRIDE 0x01
+#define PLL_MCLK_RST 0x02
+#define OSC_EN 0x04
+#define EXT_CLK_EN 0x08
+#define MCLK_SRC_SEL 0x70
+#define EXT_CLK_CNTL 0x80
+#define VCLK_SRC_SEL 0x03
+#define PLL_VCLK_RST 0x04
+#define VCLK_INVERT 0x08
+#define VCLK0_POST 0x03
+#define VCLK1_POST 0x0C
+#define VCLK2_POST 0x30
+#define VCLK3_POST 0xC0
+
+/* CONFIG_CNTL register constants */
+#define APERTURE_4M_ENABLE 1
+#define APERTURE_8M_ENABLE 2
+#define VGA_APERTURE_ENABLE 4
+
+/* CONFIG_STAT0 register constants (GX, CX) */
+#define CFG_BUS_TYPE 0x00000007
+#define CFG_MEM_TYPE 0x00000038
+#define CFG_INIT_DAC_TYPE 0x00000e00
+
+/* CONFIG_STAT0 register constants (CT, ET, VT) */
+#define CFG_MEM_TYPE_xT 0x00000007
+
+#define ISA 0
+#define EISA 1
+#define LOCAL_BUS 6
+#define PCI 7
+
+/* Memory types for GX, CX */
+#define DRAMx4 0
+#define VRAMx16 1
+#define VRAMx16ssr 2
+#define DRAMx16 3
+#define GraphicsDRAMx16 4
+#define EnhancedVRAMx16 5
+#define EnhancedVRAMx16ssr 6
+
+/* Memory types for CT, ET, VT, GT */
+#define DRAM 0
+#define EDO_DRAM 1
+#define PSEUDO_EDO 2
+#define SDRAM 3
+
+#define DAC_INTERNAL 0x00
+#define DAC_IBMRGB514 0x01
+#define DAC_ATI68875 0x02
+#define DAC_TVP3026_A 0x72
+#define DAC_BT476 0x03
+#define DAC_BT481 0x04
+#define DAC_ATT20C491 0x14
+#define DAC_SC15026 0x24
+#define DAC_MU9C1880 0x34
+#define DAC_IMSG174 0x44
+#define DAC_ATI68860_B 0x05
+#define DAC_ATI68860_C 0x15
+#define DAC_TVP3026_B 0x75
+#define DAC_STG1700 0x06
+#define DAC_ATT498 0x16
+#define DAC_STG1702 0x07
+#define DAC_SC15021 0x17
+#define DAC_ATT21C498 0x27
+#define DAC_STG1703 0x37
+#define DAC_CH8398 0x47
+#define DAC_ATT20C408 0x57
+
+#define CLK_ATI18818_0 0
+#define CLK_ATI18818_1 1
+#define CLK_STG1703 2
+#define CLK_CH8398 3
+#define CLK_INTERNAL 4
+#define CLK_ATT20C408 5
+#define CLK_IBMRGB514 6
+
+/* MEM_CNTL register constants */
+#define MEM_SIZE_ALIAS 0x00000007
+#define MEM_SIZE_512K 0x00000000
+#define MEM_SIZE_1M 0x00000001
+#define MEM_SIZE_2M 0x00000002
+#define MEM_SIZE_4M 0x00000003
+#define MEM_SIZE_6M 0x00000004
+#define MEM_SIZE_8M 0x00000005
+#define MEM_SIZE_ALIAS_GTB 0x0000000F
+#define MEM_SIZE_2M_GTB 0x00000003
+#define MEM_SIZE_4M_GTB 0x00000007
+#define MEM_SIZE_6M_GTB 0x00000009
+#define MEM_SIZE_8M_GTB 0x0000000B
+#define MEM_BNDRY 0x00030000
+#define MEM_BNDRY_0K 0x00000000
+#define MEM_BNDRY_256K 0x00010000
+#define MEM_BNDRY_512K 0x00020000
+#define MEM_BNDRY_1M 0x00030000
+#define MEM_BNDRY_EN 0x00040000
+
+/* ATI PCI constants */
+#define PCI_ATI_VENDOR_ID 0x1002
+#define PCI_MACH64_GX 0x4758
+#define PCI_MACH64_CX 0x4358
+#define PCI_MACH64_CT 0x4354
+#define PCI_MACH64_ET 0x4554
+#define PCI_MACH64_VT 0x5654
+#define PCI_MACH64_GT 0x4754
+
+/* CONFIG_CHIP_ID register constants */
+#define CFG_CHIP_TYPE 0x0000FFFF
+#define CFG_CHIP_CLASS 0x00FF0000
+#define CFG_CHIP_REV 0xFF000000
+#define CFG_CHIP_VERSION 0x07000000
+#define CFG_CHIP_FOUNDRY 0x38000000
+#define CFG_CHIP_REVISION 0xC0000000
+
+/* Chip IDs read from CONFIG_CHIP_ID */
+#define MACH64_GX_ID 0xD7
+#define MACH64_CX_ID 0x57
+#define MACH64_CT_ID 0x4354
+#define MACH64_ET_ID 0x4554
+#define MACH64_VT_ID 0x5654
+#define MACH64_GT_ID 0x4754
+
+/* Mach64 chip types */
+#define MACH64_UNKNOWN 0
+#define MACH64_GX 1
+#define MACH64_CX 2
+#define MACH64_CT 3
+#define MACH64_ET 4
+#define MACH64_VT 5
+#define MACH64_GT 6
+
+/* DST_CNTL register constants */
+#define DST_X_RIGHT_TO_LEFT 0
+#define DST_X_LEFT_TO_RIGHT 1
+#define DST_Y_BOTTOM_TO_TOP 0
+#define DST_Y_TOP_TO_BOTTOM 2
+#define DST_X_MAJOR 0
+#define DST_Y_MAJOR 4
+#define DST_X_TILE 8
+#define DST_Y_TILE 0x10
+#define DST_LAST_PEL 0x20
+#define DST_POLYGON_ENABLE 0x40
+#define DST_24_ROTATION_ENABLE 0x80
+
+/* SRC_CNTL register constants */
+#define SRC_PATTERN_ENABLE 1
+#define SRC_ROTATION_ENABLE 2
+#define SRC_LINEAR_ENABLE 4
+#define SRC_BYTE_ALIGN 8
+#define SRC_LINE_X_RIGHT_TO_LEFT 0
+#define SRC_LINE_X_LEFT_TO_RIGHT 0x10
+
+/* HOST_CNTL register constants */
+#define HOST_BYTE_ALIGN 1
+
+/* GUI_TRAJ_CNTL register constants */
+#define PAT_MONO_8x8_ENABLE 0x01000000
+#define PAT_CLR_4x2_ENABLE 0x02000000
+#define PAT_CLR_8x1_ENABLE 0x04000000
+
+/* DP_CHAIN_MASK register constants */
+#define DP_CHAIN_4BPP 0x8888
+#define DP_CHAIN_7BPP 0xD2D2
+#define DP_CHAIN_8BPP 0x8080
+#define DP_CHAIN_8BPP_RGB 0x9292
+#define DP_CHAIN_15BPP 0x4210
+#define DP_CHAIN_16BPP 0x8410
+#define DP_CHAIN_24BPP 0x8080
+#define DP_CHAIN_32BPP 0x8080
+
+/* DP_PIX_WIDTH register constants */
+#define DST_1BPP 0
+#define DST_4BPP 1
+#define DST_8BPP 2
+#define DST_15BPP 3
+#define DST_16BPP 4
+#define DST_32BPP 6
+#define SRC_1BPP 0
+#define SRC_4BPP 0x100
+#define SRC_8BPP 0x200
+#define SRC_15BPP 0x300
+#define SRC_16BPP 0x400
+#define SRC_32BPP 0x600
+#define HOST_1BPP 0
+#define HOST_4BPP 0x10000
+#define HOST_8BPP 0x20000
+#define HOST_15BPP 0x30000
+#define HOST_16BPP 0x40000
+#define HOST_32BPP 0x60000
+#define BYTE_ORDER_MSB_TO_LSB 0
+#define BYTE_ORDER_LSB_TO_MSB 0x1000000
+
+/* DP_MIX register constants */
+#define BKGD_MIX_NOT_D 0
+#define BKGD_MIX_ZERO 1
+#define BKGD_MIX_ONE 2
+#define BKGD_MIX_D 3
+#define BKGD_MIX_NOT_S 4
+#define BKGD_MIX_D_XOR_S 5
+#define BKGD_MIX_NOT_D_XOR_S 6
+#define BKGD_MIX_S 7
+#define BKGD_MIX_NOT_D_OR_NOT_S 8
+#define BKGD_MIX_D_OR_NOT_S 9
+#define BKGD_MIX_NOT_D_OR_S 10
+#define BKGD_MIX_D_OR_S 11
+#define BKGD_MIX_D_AND_S 12
+#define BKGD_MIX_NOT_D_AND_S 13
+#define BKGD_MIX_D_AND_NOT_S 14
+#define BKGD_MIX_NOT_D_AND_NOT_S 15
+#define BKGD_MIX_D_PLUS_S_DIV2 0x17
+#define FRGD_MIX_NOT_D 0
+#define FRGD_MIX_ZERO 0x10000
+#define FRGD_MIX_ONE 0x20000
+#define FRGD_MIX_D 0x30000
+#define FRGD_MIX_NOT_S 0x40000
+#define FRGD_MIX_D_XOR_S 0x50000
+#define FRGD_MIX_NOT_D_XOR_S 0x60000
+#define FRGD_MIX_S 0x70000
+#define FRGD_MIX_NOT_D_OR_NOT_S 0x80000
+#define FRGD_MIX_D_OR_NOT_S 0x90000
+#define FRGD_MIX_NOT_D_OR_S 0xa0000
+#define FRGD_MIX_D_OR_S 0xb0000
+#define FRGD_MIX_D_AND_S 0xc0000
+#define FRGD_MIX_NOT_D_AND_S 0xd0000
+#define FRGD_MIX_D_AND_NOT_S 0xe0000
+#define FRGD_MIX_NOT_D_AND_NOT_S 0xf0000
+#define FRGD_MIX_D_PLUS_S_DIV2 0x170000
+
+/* DP_SRC register constants */
+#define BKGD_SRC_BKGD_CLR 0
+#define BKGD_SRC_FRGD_CLR 1
+#define BKGD_SRC_HOST 2
+#define BKGD_SRC_BLIT 3
+#define BKGD_SRC_PATTERN 4
+#define FRGD_SRC_BKGD_CLR 0
+#define FRGD_SRC_FRGD_CLR 0x100
+#define FRGD_SRC_HOST 0x200
+#define FRGD_SRC_BLIT 0x300
+#define FRGD_SRC_PATTERN 0x400
+#define MONO_SRC_ONE 0
+#define MONO_SRC_PATTERN 0x10000
+#define MONO_SRC_HOST 0x20000
+#define MONO_SRC_BLIT 0x30000
+
+/* CLR_CMP_CNTL register constants */
+#define COMPARE_FALSE 0
+#define COMPARE_TRUE 1
+#define COMPARE_NOT_EQUAL 4
+#define COMPARE_EQUAL 5
+#define COMPARE_DESTINATION 0
+#define COMPARE_SOURCE 0x1000000
+
+/* FIFO_STAT register constants */
+#define FIFO_ERR 0x80000000
+
+/* CONTEXT_LOAD_CNTL constants */
+#define CONTEXT_NO_LOAD 0
+#define CONTEXT_LOAD 0x10000
+#define CONTEXT_LOAD_AND_DO_FILL 0x20000
+#define CONTEXT_LOAD_AND_DO_LINE 0x30000
+#define CONTEXT_EXECUTE 0
+#define CONTEXT_CMD_DISABLE 0x80000000
+
+/* GUI_STAT register constants */
+#define ENGINE_IDLE 0
+#define ENGINE_BUSY 1
+#define SCISSOR_LEFT_FLAG 0x10
+#define SCISSOR_RIGHT_FLAG 0x20
+#define SCISSOR_TOP_FLAG 0x40
+#define SCISSOR_BOTTOM_FLAG 0x80
+
+/* ATI VGA Extended Regsiters */
+#define sioATIEXT 0x1ce
+#define bioATIEXT 0x3ce
+
+#define ATI2E 0xae
+#define ATI32 0xb2
+#define ATI36 0xb6
+
+/* VGA Graphics Controller Registers */
+#define VGAGRA 0x3ce
+#define GRA06 0x06
+
+/* VGA Seququencer Registers */
+#define VGASEQ 0x3c4
+#define SEQ02 0x02
+#define SEQ04 0x04
+
+#define MACH64_MAX_X ENGINE_MAX_X
+#define MACH64_MAX_Y ENGINE_MAX_Y
+
+#define INC_X 0x0020
+#define INC_Y 0x0080
+
+#define RGB16_555 0x0000
+#define RGB16_565 0x0040
+#define RGB16_655 0x0080
+#define RGB16_664 0x00c0
+
+#define POLY_TEXT_TYPE 0x0001
+#define IMAGE_TEXT_TYPE 0x0002
+#define TEXT_TYPE_8_BIT 0x0004
+#define TEXT_TYPE_16_BIT 0x0008
+#define POLY_TEXT_TYPE_8 (POLY_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define IMAGE_TEXT_TYPE_8 (IMAGE_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define POLY_TEXT_TYPE_16 (POLY_TEXT_TYPE | TEXT_TYPE_16_BIT)
+#define IMAGE_TEXT_TYPE_16 (IMAGE_TEXT_TYPE | TEXT_TYPE_16_BIT)
+
+#define MACH64_NUM_CLOCKS 16
+#define MACH64_NUM_FREQS 50
+
+/* Wait until "v" queue entries are free */
+#define aty_WaitQueue(v) { while ((aty_ld_rev(FIFO_STAT) & 0xffff) > \
+ ((unsigned short)(0x8000 >> (v)))); }
+
+/* Wait until GP is idle and queue is empty */
+#define aty_WaitIdleEmpty() { aty_WaitQueue(16); \
+ while ((aty_ld_rev(GUI_STAT) & 1) != 0); }
+
+#define SKIP_2(_v) ((((_v)<<1)&0xfff8)|((_v)&0x3)|(((_v)&0x80)>>5))
+
+#define MACH64_BIT_BLT(_srcx, _srcy, _dstx, _dsty, _w, _h, _dir) \
+{ \
+ aty_WaitQueue(5); \
+ aty_st_rev(SRC_Y_X, (((_srcx) << 16) | ((_srcy) & 0x0000ffff))); \
+ aty_st_rev(SRC_WIDTH1, (_w)); \
+ aty_st_rev(DST_CNTL, (_dir)); \
+ aty_st_rev(DST_Y_X, (((_dstx) << 16) | ((_dsty) & 0x0000ffff))); \
+ aty_st_rev(DST_HEIGHT_WIDTH, (((_w) << 16) | ((_h) & 0x0000ffff))); \
+}
+#endif /* REGMACH64_H */
+
--- /dev/null
+/*
+ * control.c: Console support for PowerMac "control" display adaptor.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <linux/selection.h>
+#include "pmac-cons.h"
+#include "control.h"
+
+/*
+ * Structure of the registers for the RADACAL colormap device.
+ */
+struct cmap_regs {
+ unsigned char addr;
+ char pad1[15];
+ unsigned char d1;
+ char pad2[15];
+ unsigned char d2;
+ char pad3[15];
+ unsigned char lut;
+ char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "control" display adaptor".
+ */
+#define PAD(x) char x[12]
+
+struct preg { /* padded register */
+ unsigned r;
+ char pad[12];
+};
+
+struct control_regs {
+ struct preg vcount; /* vertical counter */
+ /* Vertical parameters are in units of 1/2 scan line */
+ struct preg vswin; /* between vsblank and vssync */
+ struct preg vsblank; /* vert start blank */
+ struct preg veblank; /* vert end blank (display start) */
+ struct preg vewin; /* between vesync and veblank */
+ struct preg vesync; /* vert end sync */
+ struct preg vssync; /* vert start sync */
+ struct preg vperiod; /* vert period */
+ struct preg reg8;
+ /* Horizontal params are in units of 2 pixels */
+ struct preg hperiod; /* horiz period - 2 */
+ struct preg hsblank; /* horiz start blank */
+ struct preg heblank; /* horiz end blank */
+ struct preg hesync; /* horiz end sync */
+ struct preg hssync; /* horiz start sync */
+ struct preg rege;
+ struct preg regf;
+ struct preg reg10;
+ struct preg reg11;
+ struct preg ctrl; /* display control */
+ struct preg start_addr; /* start address: 5 lsbs zero */
+ struct preg pitch; /* addrs diff between scan lines */
+ struct preg mon_sense; /* monitor sense bits */
+ struct preg flags;
+ struct preg mode;
+ struct preg reg18;
+ struct preg reg19;
+ struct preg res[6];
+};
+
+static void set_control_clock(unsigned char *params);
+static int read_control_sense(void);
+static int control_vram_reqd(int vmode, int cmode);
+
+static int total_vram; /* total amount of video memory, bytes */
+static unsigned char *frame_buffer;
+static struct cmap_regs *cmap_regs;
+static struct control_regs *disp_regs;
+static int control_use_bank2;
+
+/*
+ * Register initialization tables for the control display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ *
+ * The values for vertical frequency (V) in the comments below
+ * are the values measured using the modes under MacOS.
+ */
+struct control_regvals {
+ int pitch[3]; /* bytes/line, indexed by color_mode */
+ int offset[3]; /* first pixel address */
+ unsigned regs[16]; /* for vswin .. reg10 */
+ unsigned char mode[3]; /* indexed by color_mode */
+ unsigned char radacal_ctrl[3];
+ unsigned char clock_params[3];
+};
+
+/* Register values for 1280x1024, 75Hz mode (20) */
+static struct control_regvals control_reg_init_20 = {
+ { 1280, 2560, 0 },
+ { 0x10, 0x20, 0 },
+ { 2129, 2128, 80, 42, 4, 2130, 2132, 88,
+ 420, 411, 91, 35, 421, 18, 211, 386, },
+ { 1, 1, 1},
+ { 0x50, 0x64, 0x64 },
+ { 13, 56, 3 } /* pixel clock = 134.61MHz for V=74.81Hz */
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct control_regvals control_reg_init_19 = {
+ { 1280, 2560, 0 },
+ { 0x10, 0x20, 0 },
+ { 1997, 1996, 76, 40, 4, 1998, 2000, 86,
+ 418, 409, 89, 35, 419, 18, 210, 384, },
+ { 1, 1, 1 },
+ { 0x50, 0x64, 0x64 },
+ { 31, 125, 3 } /* pixel clock = 126.01MHz for V=75.01 Hz */
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct control_regvals control_reg_init_18 = {
+ { 1152, 2304, 4608 },
+ { 0x10, 0x28, 0x50 },
+ { 1825, 1822, 82, 43, 4, 1828, 1830, 120,
+ 726, 705, 129, 63, 727, 32, 364, 664 },
+ { 2, 1, 1 },
+ { 0x10, 0x14, 0x28 },
+ { 19, 61, 3 } /* pixel clock = 100.33MHz for V=75.31Hz */
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct control_regvals control_reg_init_17 = {
+ { 1024, 2048, 4096 },
+ { 0x10, 0x28, 0x50 },
+ { 1603, 1600, 64, 34, 4, 1606, 1608, 120,
+ 662, 641, 129, 47, 663, 24, 332, 616 },
+ { 2, 1, 1 },
+ { 0x10, 0x14, 0x28 },
+ { 11, 28, 3 } /* pixel clock = 79.55MHz for V=74.50Hz */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct control_regvals control_reg_init_15 = {
+ { 1024, 2048, 4096 },
+ { 0x10, 0x28, 0x50 },
+ { 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+ 670, 653, 141, 67, 671, 34, 336, 604, },
+ { 2, 1, 1 },
+ { 0x10, 0x14, 0x28 },
+ { 12, 30, 3 } /* pixel clock = 78.12MHz for V=72.12Hz */
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct control_regvals control_reg_init_14 = {
+ { 1024, 2048, 4096 },
+ { 0x10, 0x28, 0x50 },
+ { 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+ 670, 653, 141, 67, 671, 34, 336, 604, },
+ { 2, 1, 1 },
+ { 0x10, 0x14, 0x28 },
+ { 15, 31, 3 } /* pixel clock = 64.58MHz for V=59.62Hz */
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct control_regvals control_reg_init_13 = {
+ { 832, 1664, 3328 },
+ { 0x10, 0x28, 0x50 },
+ { 1331, 1330, 82, 43, 4, 1332, 1334, 128,
+ 574, 553, 137, 31, 575, 16, 288, 544 },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 23, 42, 3 } /* pixel clock = 57.07MHz for V=74.27Hz */
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct control_regvals control_reg_init_12 = {
+ { 800, 1600, 3200 },
+ { 0x10, 0x28, 0x50 },
+ { 1247, 1246, 46, 25, 4, 1248, 1250, 104,
+ 526, 513, 113, 39, 527, 20, 264, 488, },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 7, 11, 3 } /* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct control_regvals control_reg_init_11 = {
+ { 800, 1600, 3200 },
+ { 0x10, 0x28, 0x50 },
+ { 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+ 518, 485, 85, 59, 519, 30, 260, 460, },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 17, 27, 3 } /* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct control_regvals control_reg_init_10 = {
+ { 800, 1600, 3200 },
+ { 0x10, 0x28, 0x50 },
+ { 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+ 518, 485, 85, 59, 519, 30, 260, 460, },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 20, 53, 2 } /* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct control_regvals control_reg_init_7 = {
+ { 640, 1280, 2560 },
+ { 0x10, 0x30, 0x68 },
+ { 0x727, 0x724, 0x58, 0x2e, 0x4, 0x72a, 0x72c, 0x40,
+ 0x19e, 0x18c, 0x4c, 0x27, 0x19f, 0x14, 0xd0, 0x178 },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 9, 33, 2 } /* pixel clock = 57.29MHz for V=75.01Hz */
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct control_regvals control_reg_init_6 = {
+ { 640, 1280, 2560 },
+ { 0, 8, 0x10 },
+ { 1045, 1042, 82, 43, 4, 1048, 1050, 72,
+ 430, 393, 73, 31, 431, 16, 216, 400 },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 14, 27, 2 } /* pixel clock = 30.13MHz for V=66.43Hz */
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct control_regvals control_reg_init_5 = {
+ { 640, 1280, 2560 },
+ { 0x10, 0x28, 0x50 },
+ { 1037, 1026, 66, 34, 2, 1048, 1050, 56,
+ 398, 385, 65, 47, 399, 24, 200, 352, },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 23, 37, 2 } /* pixel clock = 25.14MHz for V=59.85Hz */
+};
+
+static struct control_regvals *control_reg_init[20] = {
+ NULL, NULL, NULL, NULL,
+ &control_reg_init_5,
+ &control_reg_init_6,
+ &control_reg_init_7,
+ NULL, NULL,
+ &control_reg_init_10,
+ &control_reg_init_11,
+ &control_reg_init_12,
+ &control_reg_init_13,
+ &control_reg_init_14,
+ &control_reg_init_15,
+ NULL,
+ &control_reg_init_17,
+ &control_reg_init_18,
+ &control_reg_init_19,
+ &control_reg_init_20
+};
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int
+read_control_sense()
+{
+ int sense;
+
+ out_le32(&disp_regs->mon_sense.r, 7); /* drive all lines high */
+ __delay(200);
+ out_le32(&disp_regs->mon_sense.r, 077); /* turn off drivers */
+ __delay(2000);
+ sense = (in_le32(&disp_regs->mon_sense.r) & 0x1c0) << 2;
+
+ /* drive each sense line low in turn and collect the other 2 */
+ out_le32(&disp_regs->mon_sense.r, 033); /* drive A low */
+ __delay(2000);
+ sense |= (in_le32(&disp_regs->mon_sense.r) & 0xc0) >> 2;
+ out_le32(&disp_regs->mon_sense.r, 055); /* drive B low */
+ __delay(2000);
+ sense |= ((in_le32(&disp_regs->mon_sense.r) & 0x100) >> 5)
+ | ((in_le32(&disp_regs->mon_sense.r) & 0x40) >> 4);
+ out_le32(&disp_regs->mon_sense.r, 066); /* drive C low */
+ __delay(2000);
+ sense |= (in_le32(&disp_regs->mon_sense.r) & 0x180) >> 7;
+
+ out_le32(&disp_regs->mon_sense.r, 077); /* turn off drivers */
+ return sense;
+}
+
+static inline int control_vram_reqd(int vmode, int cmode)
+{
+ return vmode_attrs[vmode-1].vres
+ * control_reg_init[vmode-1]->pitch[cmode];
+}
+
+void
+map_control_display(struct device_node *dp)
+{
+ int i, sense;
+ unsigned long addr, size;
+ int bank1, bank2;
+
+ if (dp->next != 0)
+ printk("Warning: only using first control display device\n");
+ if (dp->n_addrs != 2)
+ panic("expecting 2 addresses for control (got %d)", dp->n_addrs);
+
+#if 0
+ printk("pmac_display_init: node = %p, addrs =", dp->node);
+ for (i = 0; i < dp->n_addrs; ++i)
+ printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
+ printk(", intrs =");
+ for (i = 0; i < dp->n_intrs; ++i)
+ printk(" %x", dp->intrs[i]);
+ printk("\n");
+#endif
+
+ /* Map in frame buffer and registers */
+ for (i = 0; i < dp->n_addrs; ++i) {
+ addr = dp->addrs[i].address;
+ size = dp->addrs[i].size;
+ if (size >= 0x800000) {
+ /* use the big-endian aperture (??) */
+ addr += 0x800000;
+ /* map at most 8MB for the frame buffer */
+ frame_buffer = ioremap(addr, 0x800000);
+ } else {
+ disp_regs = ioremap(addr, size);
+ }
+ }
+ cmap_regs = ioremap(0xf301b000, 0x1000); /* XXX not in prom? */
+
+ /* Work out which banks of VRAM we have installed. */
+ frame_buffer[0] = 0x5a;
+ frame_buffer[1] = 0xc7;
+ bank1 = frame_buffer[0] == 0x5a && frame_buffer[1] == 0xc7;
+ frame_buffer[0x600000] = 0xa5;
+ frame_buffer[0x600001] = 0x38;
+ bank2 = frame_buffer[0x600000] == 0xa5 && frame_buffer[0x600001] == 0x38;
+ total_vram = (bank1 + bank2) * 0x200000;
+ /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
+ control_use_bank2 = !bank1;
+ if (control_use_bank2)
+ frame_buffer += 0x600000;
+
+ sense = read_control_sense();
+ if (video_mode == VMODE_NVRAM) {
+ video_mode = nvram_read_byte(NV_VMODE);
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || control_reg_init[video_mode-1] == 0)
+ video_mode = VMODE_CHOOSE;
+ }
+ if (video_mode == VMODE_CHOOSE)
+ video_mode = map_monitor_sense(sense);
+ if (control_reg_init[video_mode-1] == 0)
+ video_mode = VMODE_640_480_60;
+
+ /*
+ * Reduce the pixel size if we don't have enough VRAM.
+ */
+ if (color_mode == CMODE_NVRAM)
+ color_mode = nvram_read_byte(NV_CMODE);
+ if (color_mode < CMODE_8 || color_mode > CMODE_32)
+ color_mode = CMODE_8;
+ while (color_mode > CMODE_8
+ && control_vram_reqd(video_mode, color_mode) > total_vram)
+ --color_mode;
+
+ printk("Monitor sense value = 0x%x, ", sense);
+}
+
+static void
+set_control_clock(unsigned char *params)
+{
+ struct cuda_request req;
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x50, i + 1, params[i]);
+ while (!req.got_reply)
+ cuda_poll();
+ }
+}
+
+void
+control_init()
+{
+ struct preg *rp;
+ int i, yoff, hres;
+ int ctrl, flags;
+ unsigned *p;
+ struct control_regvals *init;
+
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || (init = control_reg_init[video_mode-1]) == 0)
+ panic("control: display mode %d not supported", video_mode);
+ n_scanlines = vmode_attrs[video_mode-1].vres;
+ hres = vmode_attrs[video_mode-1].hres;
+ pixel_size = 1 << color_mode;
+ line_pitch = init->pitch[color_mode];
+ row_pitch = line_pitch * 16;
+
+ if (control_vram_reqd(video_mode, color_mode) > 0x200000)
+ flags = 0x51;
+ else if (control_use_bank2)
+ flags = 0x39;
+ else
+ flags = 0x31;
+ if (video_mode >= VMODE_1280_960_75 && color_mode >= CMODE_16)
+ ctrl = 0x7f;
+ else
+ ctrl = 0x3b;
+
+ /* Initialize display timing registers */
+ out_le32(&disp_regs->ctrl.r, 0x43b);
+ set_control_clock(init->clock_params);
+ cmap_regs->addr = 0x20; cmap_regs->d2 = init->radacal_ctrl[color_mode];
+ cmap_regs->addr = 0x21; cmap_regs->d2 = control_use_bank2? 0: 1;
+ cmap_regs->addr = 0x10; cmap_regs->d2 = 0;
+ cmap_regs->addr = 0x11; cmap_regs->d2 = 0;
+ rp = &disp_regs->vswin;
+ for (i = 0; i < 16; ++i, ++rp)
+ out_le32(&rp->r, init->regs[i]);
+ out_le32(&disp_regs->pitch.r, line_pitch);
+ out_le32(&disp_regs->mode.r, init->mode[color_mode]);
+ out_le32(&disp_regs->flags.r, flags);
+ out_le32(&disp_regs->start_addr.r, 0);
+ out_le32(&disp_regs->reg18.r, 0x1e5);
+ out_le32(&disp_regs->reg19.r, 0);
+
+ pmac_init_palette(); /* Initialize colormap */
+
+ /* Turn on display */
+ out_le32(&disp_regs->ctrl.r, ctrl);
+
+ yoff = (n_scanlines % 16) / 2;
+ fb_start = frame_buffer + yoff * line_pitch + init->offset[color_mode];
+
+ /* Clear screen */
+ p = (unsigned *) (frame_buffer + init->offset[color_mode]);
+ for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+ *p++ = 0;
+
+ display_info.height = n_scanlines;
+ display_info.width = hres;
+ display_info.depth = pixel_size * 8;
+ display_info.pitch = line_pitch;
+ display_info.mode = video_mode;
+ strncpy(display_info.name, "control", sizeof(display_info.name));
+ display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
+ display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
+ display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
+ display_info.disp_reg_address = (unsigned long) &disp_regs;
+}
+
+int
+control_setmode(struct vc_mode *mode, int doit)
+{
+ int cmode;
+
+ if (mode->mode <= 0 || mode->mode > VMODE_MAX
+ || control_reg_init[mode->mode-1] == 0)
+ return -EINVAL;
+ switch (mode->depth) {
+ case 24:
+ case 32:
+ cmode = CMODE_32;
+ break;
+ case 16:
+ cmode = CMODE_16;
+ break;
+ case 8:
+ case 0: /* (default) */
+ cmode = CMODE_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (control_vram_reqd(mode->mode, cmode) > total_vram)
+ return -EINVAL;
+ if (doit) {
+ video_mode = mode->mode;
+ color_mode = cmode;
+ control_init();
+ }
+ return 0;
+}
+
+void
+control_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors)
+{
+ int i;
+
+ for (i = 0; i < ncolors; ++i) {
+ cmap_regs->addr = index + i; eieio();
+ cmap_regs->lut = red[i]; eieio();
+ cmap_regs->lut = green[i]; eieio();
+ cmap_regs->lut = blue[i]; eieio();
+ }
+}
+
+void
+control_set_blanking(int blank_mode)
+{
+ int ctrl;
+
+ ctrl = ld_le32(&disp_regs->ctrl.r) | 0x33;
+ if (blank_mode & VESA_VSYNC_SUSPEND)
+ ctrl &= ~3;
+ if (blank_mode & VESA_HSYNC_SUSPEND)
+ ctrl &= ~0x30;
+ out_le32(&disp_regs->ctrl.r, ctrl);
+}
--- /dev/null
+/*
+ * Exported procedures for the "control" display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *
+ * 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.
+ */
+
+extern void map_control_display(struct device_node *);
+extern void control_init(void);
+extern int control_setmode(struct vc_mode *mode, int doit);
+extern void control_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors);
+extern void control_set_blanking(int blank_mode);
--- /dev/null
+/*
+ * imstt.c: Console support for PowerMac "imstt" display adaptor.
+ *
+ * Copyright (C) 1997 Sigurdur Asgeirsson
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include "pmac-cons.h"
+#include "imstt.h"
+
+enum
+{
+ S1SA = 0, /* 0x00 */
+ S2SA = 1, /* 0x04 */
+ SP = 2, /* 0x08 */
+ DSA = 3, /* 0x0C */
+ CNT = 4, /* 0x10 */
+ DP_OCTRL = 5, /* 0x14 */
+ BLTCTL = 10, /* 0x28 */
+
+ // Scan Timing Generator Registers
+ HES = 12, /* 0x30 */
+ HEB = 13, /* 0x34 */
+ HSB = 14, /* 0x38 */
+ HT = 15, /* 0x3C */
+ VES = 16, /* 0x40 */
+ VEB = 17, /* 0x44 */
+ VSB = 18, /* 0x48 */
+ VT = 19, /* 0x4C */
+ HCIV = 20, /* 0x50 */
+ VCIV = 21, /* 0x54 */
+ TCDR = 22, /* 0x58 */
+ VIL = 23, /* 0x5C */
+ STGCTL = 24, /* 0x60 */
+
+ // Screen Refresh Generator Registers
+ SSR = 25, /* 0x64 */
+ HRIR = 26, /* 0x68 */
+ SPR = 27, /* 0x6C */
+ CMR = 28, /* 0x70 */
+ SRGCTL = 29, /* 0x74 */
+
+ // RAM Refresh Generator Registers
+ RRCIV = 30, /* 0x78 */
+ RRSC = 31, /* 0x7C */
+ RRCR = 34, /* 0x88 */
+
+ // System Registers
+ GIOE = 32, /* 0x80 */
+ GIO = 33, /* 0x84 */
+ SCR = 35, /* 0x8C */
+ SSTATUS = 36, /* 0x90 */
+ PRC = 37, /* 0x94 */
+
+#if 0
+ // PCI Registers
+ DVID = 0x00000000L,
+ SC = 0x00000004L,
+ CCR = 0x00000008L,
+ OG = 0x0000000CL,
+ BARM = 0x00000010L,
+ BARER = 0x00000030L,
+#endif
+};
+
+enum
+{
+ PADDRW = 0x00,
+ PDATA = 0x04,
+ PPMASK = 0x08,
+ PADDRR = 0x0C,
+ PIDXLO = 0x10,
+ PIDXHI = 0x14,
+ PIDXDATA = 0x18,
+ PIDXCTL = 0x1C,
+
+ PPIXREP = 0x0A,
+ PM0 = 0x20,
+ PN0 = 0x21,
+ PP0 = 0x22,
+ PC0 = 0x23
+};
+
+struct initvalues
+{
+ unsigned char addr, value;
+};
+
+static struct initvalues initregs[] =
+{
+ { 0x02, 0x21 }, /* (0x01) Miscellaneous Clock Control */
+ { 0x03, 0x00 }, /* (0x00) Sync Control */
+ { 0x04, 0x00 }, /* (0x00) Horizontal Sync Position */
+ { 0x05, 0x00 }, /* (0x00) Power Management */
+ { 0x06, 0x0B }, /* (0x02) DAC Operation */
+ { 0x07, 0x00 }, /* (0x00) Palette Control */
+ { 0x08, 0x01 }, /* (0x01) System Clock Control */
+ { 0x0B, 0x00 }, /* (U) 8 BPP Control */
+ { 0x0C, 0xC4 }, /* (U) 16 BPP Control */
+ { 0x0D, 0x00 }, /* (U) 24 BPP Packed Control */
+ { 0x0E, 0x03 }, /* (U) 32 BPP Control */
+ { 0x10, 0x05 }, /* (0x00) Pixel PLL Control 1 */
+ { 0x11, 0x00 }, /* (0x00) Pixel PLL Control 2 */
+ { 0x15, 0x08 }, /* (0x08) SYSCLK N (System PLL Reference Divider) */
+ { 0x16, 0x57 }, /* (0x41) SYSCLK M (System PLL VCO Divider) */
+ { 0x17, 0x00 }, /* (U) SYSCLK P */
+ { 0x18, 0x00 }, /* (U) SYSCLK C */
+ { 0x30, 0x00 }, /* (0x00) Cursor Control */
+ { 0x60, 0xFF }, /* (U) Border Color Red */
+ { 0x61, 0xFF }, /* (U) Border Color Green */
+ { 0x62, 0xFF }, /* (U) Border Color Blue */
+ { 0x70, 0x01 }, /* (0x00) Miscellaneous Control 1 */
+ { 0x71, 0x45 }, /* (0x00) Miscellaneous Control 2 */
+ { 0x72, 0x00 }, /* (0x00) Miscellaneous Control 3 */
+ { 0x78, 0x00 }, /* (0x00) Key Control/DB Operation */
+};
+
+static void set_imstt_clock(unsigned char *params);
+static int read_imstt_sense(void);
+static int imstt_vram_reqd(int vmode, int cmode);
+
+static int total_vram = 2 * 1024 * 1024; /* total amount of video memory, bytes */
+static unsigned char *frame_buffer;
+static unsigned char *cmap_regs;
+static unsigned *dc_regs;
+
+
+/*
+ * Register initialization tables for the imstt display.
+ *
+ * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
+ * where m = clk[0], n = clk[1], p = clk[2]
+ * clk[3] is c, charge pump bias which depends on the VCO frequency
+ */
+struct imstt_regvals {
+ unsigned short cfg[8];
+ unsigned char clk[4];
+ unsigned long pitch[3];
+} imsttmode;
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct imstt_regvals imstt_reg_init_17 = {
+ { 0x0A, 0x1C, 0x9C, 0xA6, 0x0003, 0x0020, 0x0320, 0x0323 },
+ { 0x07, 0x00, 0x01, 0x02 },
+ { 0x0400, 0x0800, 0x1000 }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct imstt_regvals imstt_reg_init_13 = {
+ { 0x05, 0x20, 0x88, 0x90, 0x0003, 0x0028, 0x0298, 0x029B },
+ { 0x3E, 0x0A, 0x01, 0x02 },
+ { 832, 832 * 2, 832 * 4 }
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct imstt_regvals imstt_reg_init_6 = {
+ { 0x08, 0x12, 0x62, 0x6C, 0x0003, 0x002A, 0x020A, 0x020C },
+ { 0x78, 0x13, 0x02, 0x02 },
+ { 640, 640 * 2, 640 * 4 }
+};
+
+static struct imstt_regvals *imstt_reg_init[20] = {
+ NULL, NULL, NULL, NULL,
+ &imstt_reg_init_6, // fake'm out
+ &imstt_reg_init_6,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ &imstt_reg_init_13,
+ NULL, NULL, NULL,
+ &imstt_reg_init_17,
+ NULL, NULL, NULL
+};
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int
+read_imstt_sense()
+{
+#if 0
+ int sense;
+ unsigned gio, gioe;
+
+ gio = ld_le32(dc_regs + GIO) & ~0x0038;
+ gioe = ld_le32(dc_
+
+ out_le32(dc_regs + GIOE, reg); /* drive all lines high */
+ __delay(200);
+ out_le32(dc_regs + GIOE, 077); /* turn off drivers */
+ __delay(2000);
+ sense = (in_le32(dc_regs + GIOE) & 0x1c0) << 2;
+
+ /* drive each sense line low in turn and collect the other 2 */
+ out_le32(dc_regs + GIOE, 033); /* drive A low */
+ __delay(2000);
+ sense |= (in_le32(dc_regs + GIOE) & 0xc0) >> 2;
+ out_le32(dc_regs + GIOE, 055); /* drive B low */
+ __delay(2000);
+ sense |= ((in_le32(dc_regs + GIOE) & 0x100) >> 5)
+ | ((in_le32(dc_regs + GIOE) & 0x40) >> 4);
+ out_le32(dc_regs + GIOE, 066); /* drive C low */
+ __delay(2000);
+ sense |= (in_le32(dc_regs + GIOE) & 0x180) >> 7;
+
+ out_le32(dc_regs + GIOE, 077); /* turn off drivers */
+ return sense;
+#else
+ return 0;
+#endif
+}
+
+static inline int imstt_vram_reqd(int vmode, int cmode)
+{
+ return vmode_attrs[vmode-1].vres
+ * imstt_reg_init[vmode-1]->pitch[cmode];
+}
+
+void
+map_imstt_display(struct device_node *dp)
+{
+ int i, sense;
+ unsigned long addr, size, tmp;
+ unsigned char bus, devfn;
+ unsigned short cmd;
+
+ if (dp->next != 0)
+ printk("Warning: only using first imstt display device\n");
+
+#if 1
+ printk("pmac_display_init: node = %p, addrs =", dp->node);
+ for (i = 0; i < dp->n_addrs; ++i)
+ printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
+ printk(", intrs =");
+ for (i = 0; i < dp->n_intrs; ++i)
+ printk(" %x", dp->intrs[i]);
+ printk("\n");
+#endif
+
+ /* Map in frame buffer and registers */
+ for (i = 0; i < dp->n_addrs; ++i) {
+ addr = dp->addrs[i].address;
+ size = dp->addrs[i].size;
+ if (size >= 0x02000000) {
+ frame_buffer = ioremap(addr, size);
+ dc_regs = (unsigned*)(frame_buffer + 0x00800000);
+ cmap_regs = (unsigned char*)(frame_buffer + 0x00840000);
+
+ printk("mapped frame_buffer=%x(%x)", (unsigned)frame_buffer, (unsigned)size);
+ printk(" dc_regs=%x, cmap_regs=%x\n", (unsigned)dc_regs, (unsigned)cmap_regs);
+ }
+ }
+
+ /* enable memory-space accesses using config-space command register */
+ if (pci_device_loc(dp, &bus, &devfn) == 0) {
+ pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+
+ printk("command word 0x%04X\n", cmd);
+
+ if (cmd != 0xffff) {
+ cmd |= PCI_COMMAND_MEMORY;
+ pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+ }
+ }
+ else
+ printk("unable to find pci device\n");
+
+ tmp = in_le32(dc_regs + SSTATUS);
+ printk("chip version %ld, ", (tmp & 0x0F00) >> 8);
+
+ tmp = in_le32(dc_regs + PRC);
+ total_vram = (tmp & 0x0004) ? 0x000400000L : 0x000200000L;
+ printk("VRAM size %ldM\n", total_vram / 0x000100000L);
+
+ sense = read_imstt_sense();
+ printk("Monitor sense value = 0x%x, ", sense);
+#if 0
+ if (video_mode == VMODE_NVRAM) {
+ video_mode = nvram_read_byte(NV_VMODE);
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || imstt_reg_init[video_mode-1] == 0)
+ video_mode = VMODE_CHOOSE;
+ }
+ if (video_mode == VMODE_CHOOSE)
+ video_mode = map_monitor_sense(sense);
+ if (imstt_reg_init[video_mode-1] == 0)
+ video_mode = VMODE_640_480_67;
+
+ /*
+ * Reduce the pixel size if we don't have enough VRAM.
+ */
+ if (color_mode == CMODE_NVRAM)
+ color_mode = nvram_read_byte(NV_CMODE);
+ if (color_mode < CMODE_8 || color_mode > CMODE_32)
+ color_mode = CMODE_8;
+ while (color_mode > CMODE_8
+ && imstt_vram_reqd(video_mode, color_mode) > total_vram)
+ --color_mode;
+
+#endif
+
+ video_mode = VMODE_640_480_67;
+ color_mode = CMODE_8;
+}
+
+static void
+set_imstt_clock(unsigned char *params)
+{
+ cmap_regs[PIDXHI] = 0; eieio();
+ cmap_regs[PIDXLO] = PM0; eieio();
+ cmap_regs[PIDXDATA] = params[0]; eieio();
+
+ cmap_regs[PIDXLO] = PN0; eieio();
+ cmap_regs[PIDXDATA] = params[1]; eieio();
+
+ cmap_regs[PIDXLO] = PP0; eieio();
+ cmap_regs[PIDXDATA] = params[2]; eieio();
+
+ cmap_regs[PIDXLO] = PC0; eieio();
+ cmap_regs[PIDXDATA] = params[3]; eieio();
+}
+
+void
+imstt_init()
+{
+ int i, yoff, hres;
+ unsigned long ctl, pitch, tmp;
+ unsigned char pformat;
+ unsigned *p;
+ struct imstt_regvals *init;
+
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || (init = imstt_reg_init[video_mode-1]) == 0)
+ panic("imstt: display mode %d not supported", video_mode);
+
+ n_scanlines = vmode_attrs[video_mode-1].vres;
+ hres = vmode_attrs[video_mode-1].hres;
+ pixel_size = 1 << color_mode;
+ line_pitch = init->pitch[color_mode];
+ row_pitch = line_pitch * 16;
+
+ /* initialize the card */
+ tmp = in_le32(dc_regs + STGCTL);
+ out_le32(dc_regs + STGCTL, tmp & ~0x1);
+#if 0
+ out_le32(dc_regs + SCR, 0);
+#endif
+
+ cmap_regs[PPMASK] = 0xFF;
+ /* set default values for DAC registers */
+ cmap_regs[PIDXHI] = 0; eieio();
+ for(i = 0; i < sizeof(initregs) / sizeof(*initregs); i++) {
+ cmap_regs[PIDXLO] = initregs[i].addr; eieio();
+ cmap_regs[PIDXDATA] = initregs[i].value; eieio();
+ }
+ set_imstt_clock(init->clk);
+
+ switch(color_mode) {
+ case CMODE_32:
+ ctl = 0x17b5;
+ pitch = init->pitch[2] / 4;
+ pformat = 0x06;
+ break;
+ case CMODE_16:
+ ctl = 0x17b3;
+ pitch = init->pitch[1] / 4;
+ pformat = 0x04;
+ break;
+ case CMODE_8:
+ default:
+ ctl = 0x17b1;
+ pitch = init->pitch[0] / 4;
+ pformat = 0x03;
+ break;
+ }
+
+ out_le32(&dc_regs[HES], init->cfg[0]);
+ out_le32(&dc_regs[HEB], init->cfg[1]);
+ out_le32(&dc_regs[HSB], init->cfg[2]);
+ out_le32(&dc_regs[HT], init->cfg[3]);
+ out_le32(&dc_regs[VES], init->cfg[4]);
+ out_le32(&dc_regs[VEB], init->cfg[5]);
+ out_le32(&dc_regs[VSB], init->cfg[6]);
+ out_le32(&dc_regs[VT], init->cfg[7]);
+ out_le32(&dc_regs[HCIV], 1);
+ out_le32(&dc_regs[VCIV], 1);
+ out_le32(&dc_regs[TCDR], 4);
+ out_le32(&dc_regs[VIL], 0);
+
+ out_le32(&dc_regs[SSR], 0);
+ out_le32(&dc_regs[HRIR], 0x0200);
+ out_le32(&dc_regs[CMR], 0x01FF);
+ out_le32(&dc_regs[SRGCTL], 0x0003);
+ if(total_vram == 0x000200000)
+ out_le32(&dc_regs[SCR], 0x0059D);
+ else {
+ pitch /= 2;
+ out_le32(&dc_regs[SCR], 0x00D0DC);
+ }
+
+ out_le32(&dc_regs[SPR], pitch);
+
+ cmap_regs[PIDXLO] = PPIXREP; eieio();
+ cmap_regs[PIDXDATA] = pformat; eieio();
+
+
+ pmac_init_palette(); /* Initialize colormap */
+
+ out_le32(&dc_regs[STGCTL], ctl);
+
+ yoff = (n_scanlines % 16) / 2;
+ fb_start = frame_buffer + yoff * line_pitch;
+
+ /* Clear screen */
+ p = (unsigned *)frame_buffer;
+ for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+ *p++ = 0;
+
+ display_info.height = n_scanlines;
+ display_info.width = hres;
+ display_info.depth = pixel_size * 8;
+ display_info.pitch = line_pitch;
+ display_info.mode = video_mode;
+ strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
+ display_info.fb_address = (unsigned long) frame_buffer;
+ display_info.cmap_adr_address = (unsigned long) &cmap_regs[PADDRW];
+ display_info.cmap_data_address = (unsigned long) &cmap_regs[PDATA];
+ display_info.disp_reg_address = (unsigned long) NULL;
+}
+
+int
+imstt_setmode(struct vc_mode *mode, int doit)
+{
+ int cmode;
+
+ if (mode->mode <= 0 || mode->mode > VMODE_MAX
+ || imstt_reg_init[mode->mode-1] == 0)
+ return -EINVAL;
+ switch (mode->depth) {
+ case 24:
+ case 32:
+ cmode = CMODE_32;
+ break;
+ case 16:
+ cmode = CMODE_16;
+ break;
+ case 8:
+ case 0: /* (default) */
+ cmode = CMODE_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (imstt_vram_reqd(mode->mode, cmode) > total_vram)
+ return -EINVAL;
+ if (doit) {
+ video_mode = mode->mode;
+ color_mode = cmode;
+ imstt_init();
+ }
+ return 0;
+}
+
+void
+imstt_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors)
+{
+ int i;
+
+ for (i = 0; i < ncolors; ++i) {
+ cmap_regs[PADDRW] = index + i; eieio();
+ cmap_regs[PDATA] = red[i]; eieio();
+ cmap_regs[PDATA] = green[i]; eieio();
+ cmap_regs[PDATA] = blue[i]; eieio();
+ }
+}
+
+void
+imstt_set_blanking(int blank_mode)
+{
+ long ctrl;
+
+ ctrl = ld_le32(dc_regs + STGCTL) | 0x0030;
+ if (blank_mode & VESA_VSYNC_SUSPEND)
+ ctrl &= ~0x0020;
+ if (blank_mode & VESA_HSYNC_SUSPEND)
+ ctrl &= ~0x0010;
+ out_le32(dc_regs + STGCTL, ctrl);
+}
--- /dev/null
+/*
+ * Exported procedures for the "control" display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *
+ * 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.
+ */
+
+extern void map_imstt_display(struct device_node *);
+extern void imstt_init(void);
+extern int imstt_setmode(struct vc_mode *mode, int doit);
+extern void imstt_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors);
+extern void imstt_set_blanking(int blank_mode);
+
--- /dev/null
+/*
+ * drivers/char/mac_keyb.c
+ *
+ * Keyboard driver for Power Macintosh computers.
+ *
+ * Adapted from drivers/char/keyboard.c by Paul Mackerras
+ * (see that file for its authors and contributors).
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/cuda.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/kbd_ll.h>
+
+#define KEYB_KEYREG 0 /* register # for key up/down data */
+#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */
+#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
+
+unsigned char kbd_read_mask = 0; /* XXX */
+
+static void kbd_repeat(unsigned long);
+static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
+static int last_keycode;
+
+static void keyboard_input(unsigned char *, int, struct pt_regs *);
+static void input_keycode(int, int);
+static void leds_done(struct cuda_request *);
+
+extern struct kbd_struct kbd_table[];
+
+extern void handle_scancode(unsigned char);
+extern void put_queue(int);
+
+/* this map indicates which keys shouldn't autorepeat. */
+static unsigned char dont_repeat[128] = {
+ 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, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */
+ 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, 1, 0, 0, 0, 0, /* scroll lock */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+int mackbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+ return -EINVAL;
+}
+
+int mackbd_getkeycode(unsigned int scancode)
+{
+ return -EINVAL;
+}
+
+int mackbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+ return 1;
+}
+
+int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
+ char raw_mode)
+{
+ if (!raw_mode) {
+ /*
+ * Convert R-shift/control/option to L version.
+ * Remap keycode 0 (A) to the unused keycode 0x5a.
+ * Other parts of the system assume 0 is not a valid keycode.
+ */
+ switch (keycode) {
+ case 0x7b: keycode = 0x38; break; /* R-shift */
+ case 0x7c: keycode = 0x3a; break; /* R-option */
+ case 0x7d: keycode = 0x36; break; /* R-control */
+ case 0: keycode = 0x5a; break; /* A */
+ }
+ }
+ *keycodep = keycode;
+ return 1;
+}
+
+int mackbd_unexpected_up(unsigned char keycode)
+{
+ return 0x80;
+}
+
+static void
+keyboard_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+ /* first check this is from register 0 */
+ if (nb != 5 || (data[2] & 3) != KEYB_KEYREG)
+ return; /* ignore it */
+ kbd_pt_regs = regs;
+ input_keycode(data[3], 0);
+ if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f)))
+ input_keycode(data[4], 0);
+}
+
+static void
+input_keycode(int keycode, int repeat)
+{
+ struct kbd_struct *kbd;
+ int up_flag;
+
+ kbd = kbd_table + fg_console;
+ up_flag = (keycode & 0x80);
+ keycode &= 0x7f;
+ if (!repeat)
+ del_timer(&repeat_timer);
+
+ if (kbd->kbdmode != VC_RAW) {
+ if (!up_flag && !dont_repeat[keycode]) {
+ last_keycode = keycode;
+ repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2);
+ add_timer(&repeat_timer);
+ }
+
+ /*
+ * XXX fix caps-lock behaviour by turning the key-up
+ * transition into a key-down transition.
+ */
+ if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK))
+ up_flag = 0;
+ }
+
+ handle_scancode(keycode + up_flag);
+}
+
+static void
+kbd_repeat(unsigned long xxx)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ input_keycode(last_keycode, 1);
+ restore_flags(flags);
+}
+
+static void
+mouse_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+ /* [ACA:23-Mar-97] Three button mouse support. This is designed to
+ function with MkLinux DR-2.1 style X servers. It only works with
+ three-button mice that conform to Apple's multi-button mouse
+ protocol. */
+
+ /*
+ The X server for MkLinux DR2.1 uses the following unused keycodes to
+ read the mouse:
+
+ 0x7e This indicates that the next two keycodes should be interpreted
+ as mouse information. The first following byte's high bit
+ represents the state of the left button. The lower seven bits
+ represent the x-axis acceleration. The lower seven bits of the
+ second byte represent y-axis acceleration.
+
+ 0x3f The x server interprets this keycode as a middle button
+ release.
+
+ 0xbf The x server interprets this keycode as a middle button
+ depress.
+
+ 0x40 The x server interprets this keycode as a right button
+ release.
+
+ 0xc0 The x server interprets this keycode as a right button
+ depress.
+
+ NOTES: There should be a better way of handling mice in the X server.
+ The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead
+ of two. The three mouse buttons should then, in the X server, be read
+ as the high-bits of all three bytes. The x and y motions can still be
+ in the first two bytes. Maybe I'll do this...
+ */
+
+ /*
+ Handler 4 -- Apple Extended mouse protocol.
+
+ For Apple's 3-button mouse protocol the data array will contain the
+ following values:
+
+ BITS COMMENTS
+ data[0] = 0000 0000 ADB packet identifer.
+ data[1] = 0100 0000 Extended protocol register.
+ Bits 6-7 are the device id, which should be 1.
+ Bits 4-5 are resolution which is in "units/inch".
+ The Logitech MouseMan returns these bits clear but it has
+ 200/300cpi resolution.
+ Bits 0-3 are unique vendor id.
+ data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
+ Bits 2-3 should be 8 + 4.
+ Bits 4-7 should be 3 for a mouse device.
+ data[3] = bxxx xxxx Left button and x-axis motion.
+ data[4] = byyy yyyy Second button and y-axis motion.
+ data[5] = byyy bxxx Third button and fourth button. Y is additional
+ high bits of y-axis motion. XY is additional
+ high bits of x-axis motion.
+
+ NOTE: data[0] and data[2] are confirmed by the parent function and
+ need not be checked here.
+ */
+
+ /*
+ Handler 1 -- 100cpi original Apple mouse protocol.
+ Handler 2 -- 200cpi original Apple mouse protocol.
+
+ For Apple's standard one-button mouse protocol the data array will
+ contain the following values:
+
+ BITS COMMENTS
+ data[0] = 0000 0000 ADB packet identifer.
+ data[1] = ???? ???? (?)
+ data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
+ data[3] = bxxx xxxx First button and x-axis motion.
+ data[4] = byyy yyyy Second button and y-axis motion.
+
+ NOTE: data[0] is confirmed by the parent function and need not be
+ checked here.
+ */
+ struct kbd_struct *kbd;
+
+ kbd = kbd_table + fg_console;
+
+ /* Only send mouse codes when keyboard is in raw mode. */
+ if (kbd->kbdmode == VC_RAW) {
+ static unsigned char uch_ButtonStateSecond = 0;
+ unsigned char uchButtonSecond;
+
+ /* Send first button, second button and movement. */
+ put_queue( 0x7e );
+ put_queue( data[3] );
+ put_queue( data[4] );
+
+ /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */
+
+ /* Store the button state. */
+ uchButtonSecond = (data[4] & 0x80);
+
+ /* Send second button. */
+ if (uchButtonSecond != uch_ButtonStateSecond) {
+ put_queue( 0x3f | uchButtonSecond );
+ uch_ButtonStateSecond = uchButtonSecond;
+ }
+
+ /* Macintosh 3-button mouse (handler 4). */
+ if ((nb == 6) && (data[1] & 0x40)) {
+ static unsigned char uch_ButtonStateThird = 0;
+ unsigned char uchButtonThird;
+
+ /* Store the button state for speed. */
+ uchButtonThird = (data[5] & 0x80);
+
+ /* Send third button. */
+ if (uchButtonThird != uch_ButtonStateThird) {
+ put_queue( 0x40 | uchButtonThird );
+ uch_ButtonStateThird = uchButtonThird;
+ }
+ }
+ }
+}
+
+/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
+static unsigned char mac_ledmap[8] = {
+ 0, /* none */
+ 4, /* scroll lock */
+ 1, /* num lock */
+ 5, /* scroll + num lock */
+ 2, /* caps lock */
+ 6, /* caps + scroll lock */
+ 3, /* caps + num lock */
+ 7, /* caps + num + scroll lock */
+};
+
+static struct cuda_request led_request;
+static int leds_pending;
+
+void mackbd_leds(unsigned char leds)
+{
+ if (led_request.got_reply) {
+ cuda_request(&led_request, leds_done, 4, ADB_PACKET,
+ ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG),
+ 0xff, ~mac_ledmap[leds]);
+ } else
+ leds_pending = leds | 0x100;
+}
+
+static void leds_done(struct cuda_request *req)
+{
+ int leds;
+
+ if (leds_pending) {
+ leds = leds_pending & 0xff;
+ leds_pending = 0;
+ mackbd_leds(leds);
+ }
+}
+
+void mackbd_init_hw(void)
+{
+ struct cuda_request req;
+
+ adb_register(ADB_KEYBOARD, keyboard_input);
+ adb_register(ADB_MOUSE, mouse_input);
+
+ /* turn on ADB auto-polling in the CUDA */
+ cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
+ while (!req.got_reply)
+ cuda_poll();
+
+ /* turn off all leds */
+ cuda_request(&req, NULL, 4, ADB_PACKET,
+ ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, 0xff);
+ while (!req.got_reply)
+ cuda_poll();
+
+ /* get the keyboard to send separate codes for
+ left and right shift, control, option keys. */
+ cuda_request(&req, NULL, 4, ADB_PACKET,
+ ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3);
+ while (!req.got_reply)
+ cuda_poll();
+
+ led_request.got_reply = 1;
+
+ /* Try to switch the mouse (id 3) to handler 4, for three-button
+ mode. (0x20 is Service Request Enable, 0x03 is Device ID). */
+ cuda_request(&req, NULL, 4, ADB_PACKET,
+ ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 );
+ while (!req.got_reply)
+ cuda_poll();
+}
+
--- /dev/null
+/* Do not edit this file! It was automatically generated by */
+/* loadkeys --mktable defkeymap.map > defkeymap.c */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+ 0xf200, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+ 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72,
+ 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035,
+ 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f,
+ 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027,
+ 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e,
+ 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xfb61, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+ 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+ 0xf200, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58,
+ 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52,
+ 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025,
+ 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f,
+ 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022,
+ 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e,
+ 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xfb41, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117,
+ 0xf10b, 0xf20a, 0xf10a, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+ 0xf200, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+ 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72,
+ 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+ 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f,
+ 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200,
+ 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f,
+ 0xf910, 0xf911, 0xf914, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200,
+ 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516,
+ 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117,
+ 0xf50d, 0xf119, 0xf50c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+ 0xf200, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+ 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d,
+ 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f,
+ 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007,
+ 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e,
+ 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+ 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+ 0xf200, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+ 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f,
+ 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200,
+ 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117,
+ 0xf200, 0xf119, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c,
+};
+
+u_short alt_map[NR_KEYS] = {
+ 0xf200, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878,
+ 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872,
+ 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835,
+ 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f,
+ 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827,
+ 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e,
+ 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905,
+ 0xf906, 0xf907, 0xf861, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200,
+ 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+ 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+ 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+ 0xf200, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818,
+ 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812,
+ 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f,
+ 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200,
+ 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf801, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+ 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+ 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+ plain_map, shift_map, altgr_map, 0,
+ ctrl_map, shift_ctrl_map, 0, 0,
+ alt_map, 0, 0, 0,
+ ctrl_alt_map, 0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+ '\033', '[', '[', 'A', 0,
+ '\033', '[', '[', 'B', 0,
+ '\033', '[', '[', 'C', 0,
+ '\033', '[', '[', 'D', 0,
+ '\033', '[', '[', 'E', 0,
+ '\033', '[', '1', '7', '~', 0,
+ '\033', '[', '1', '8', '~', 0,
+ '\033', '[', '1', '9', '~', 0,
+ '\033', '[', '2', '0', '~', 0,
+ '\033', '[', '2', '1', '~', 0,
+ '\033', '[', '2', '3', '~', 0,
+ '\033', '[', '2', '4', '~', 0,
+ '\033', '[', '2', '5', '~', 0,
+ '\033', '[', '2', '6', '~', 0,
+ '\033', '[', '2', '8', '~', 0,
+ '\033', '[', '2', '9', '~', 0,
+ '\033', '[', '3', '1', '~', 0,
+ '\033', '[', '3', '2', '~', 0,
+ '\033', '[', '3', '3', '~', 0,
+ '\033', '[', '3', '4', '~', 0,
+ '\033', '[', '1', '~', 0,
+ '\033', '[', '2', '~', 0,
+ '\033', '[', '3', '~', 0,
+ '\033', '[', '4', '~', 0,
+ '\033', '[', '5', '~', 0,
+ '\033', '[', '6', '~', 0,
+ '\033', '[', 'M', 0,
+ '\033', '[', 'P', 0,
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0; /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+ func_buf + 0,
+ func_buf + 5,
+ func_buf + 10,
+ func_buf + 15,
+ func_buf + 20,
+ func_buf + 25,
+ func_buf + 31,
+ func_buf + 37,
+ func_buf + 43,
+ func_buf + 49,
+ func_buf + 55,
+ func_buf + 61,
+ func_buf + 67,
+ func_buf + 73,
+ func_buf + 79,
+ func_buf + 85,
+ func_buf + 91,
+ func_buf + 97,
+ func_buf + 103,
+ func_buf + 109,
+ func_buf + 115,
+ func_buf + 120,
+ func_buf + 125,
+ func_buf + 130,
+ func_buf + 135,
+ func_buf + 140,
+ func_buf + 145,
+ 0,
+ 0,
+ func_buf + 149,
+ 0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+ {'`', 'A', '\300'}, {'`', 'a', '\340'},
+ {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
+ {'^', 'A', '\302'}, {'^', 'a', '\342'},
+ {'~', 'A', '\303'}, {'~', 'a', '\343'},
+ {'"', 'A', '\304'}, {'"', 'a', '\344'},
+ {'O', 'A', '\305'}, {'o', 'a', '\345'},
+ {'0', 'A', '\305'}, {'0', 'a', '\345'},
+ {'A', 'A', '\305'}, {'a', 'a', '\345'},
+ {'A', 'E', '\306'}, {'a', 'e', '\346'},
+ {',', 'C', '\307'}, {',', 'c', '\347'},
+ {'`', 'E', '\310'}, {'`', 'e', '\350'},
+ {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
+ {'^', 'E', '\312'}, {'^', 'e', '\352'},
+ {'"', 'E', '\313'}, {'"', 'e', '\353'},
+ {'`', 'I', '\314'}, {'`', 'i', '\354'},
+ {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
+ {'^', 'I', '\316'}, {'^', 'i', '\356'},
+ {'"', 'I', '\317'}, {'"', 'i', '\357'},
+ {'-', 'D', '\320'}, {'-', 'd', '\360'},
+ {'~', 'N', '\321'}, {'~', 'n', '\361'},
+ {'`', 'O', '\322'}, {'`', 'o', '\362'},
+ {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
+ {'^', 'O', '\324'}, {'^', 'o', '\364'},
+ {'~', 'O', '\325'}, {'~', 'o', '\365'},
+ {'"', 'O', '\326'}, {'"', 'o', '\366'},
+ {'/', 'O', '\330'}, {'/', 'o', '\370'},
+ {'`', 'U', '\331'}, {'`', 'u', '\371'},
+ {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
+ {'^', 'U', '\333'}, {'^', 'u', '\373'},
+ {'"', 'U', '\334'}, {'"', 'u', '\374'},
+ {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
+ {'T', 'H', '\336'}, {'t', 'h', '\376'},
+ {'s', 's', '\337'}, {'"', 'y', '\377'},
+ {'s', 'z', '\337'}, {'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
--- /dev/null
+# Kernel keymap for Macintoshes. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# We use the Command (pretzel) key as Alt, and the Option key as AltGr.
+#
+keycode 0x00 =
+keycode 0x01 = s
+keycode 0x02 = d
+ altgr keycode 0x02 = Hex_D
+keycode 0x03 = f
+ altgr keycode 0x03 = Hex_F
+keycode 0x04 = h
+keycode 0x05 = g
+keycode 0x06 = z
+keycode 0x07 = x
+keycode 0x08 = c
+ altgr keycode 0x08 = Hex_C
+keycode 0x09 = v
+keycode 0x0a =
+keycode 0x0b = b
+ altgr keycode 0x0b = Hex_B
+keycode 0x0c = q
+keycode 0x0d = w
+keycode 0x0e = e
+ altgr keycode 0x0e = Hex_E
+keycode 0x0f = r
+keycode 0x10 = y
+keycode 0x11 = t
+keycode 0x12 = one exclam
+ alt keycode 0x12 = Meta_one
+keycode 0x13 = two at at
+ control keycode 0x13 = nul
+ shift control keycode 0x13 = nul
+ alt keycode 0x13 = Meta_two
+keycode 0x14 = three numbersign
+ control keycode 0x14 = Escape
+ alt keycode 0x14 = Meta_three
+keycode 0x15 = four dollar dollar
+ control keycode 0x15 = Control_backslash
+ alt keycode 0x15 = Meta_four
+keycode 0x16 = six asciicircum
+ control keycode 0x16 = Control_asciicircum
+ alt keycode 0x16 = Meta_six
+keycode 0x17 = five percent
+ control keycode 0x17 = Control_bracketright
+ alt keycode 0x17 = Meta_five
+keycode 0x18 = equal plus
+ alt keycode 0x18 = Meta_equal
+keycode 0x19 = nine parenleft bracketright
+ alt keycode 0x19 = Meta_nine
+keycode 0x1a = seven ampersand braceleft
+ control keycode 0x1a = Control_underscore
+ alt keycode 0x1a = Meta_seven
+keycode 0x1b = minus underscore backslash
+ control keycode 0x1b = Control_underscore
+ shift control keycode 0x1b = Control_underscore
+ alt keycode 0x1b = Meta_minus
+keycode 0x1c = eight asterisk bracketleft
+ control keycode 0x1c = Delete
+ alt keycode 0x1c = Meta_eight
+keycode 0x1d = zero parenright braceright
+ alt keycode 0x1d = Meta_zero
+keycode 0x1e = bracketright braceright asciitilde
+ control keycode 0x1e = Control_bracketright
+ alt keycode 0x1e = Meta_bracketright
+keycode 0x1f = o
+keycode 0x20 = u
+keycode 0x21 = bracketleft braceleft
+ control keycode 0x21 = Escape
+ alt keycode 0x21 = Meta_bracketleft
+keycode 0x22 = i
+keycode 0x23 = p
+keycode 0x24 = Return
+ alt keycode 0x24 = Meta_Control_m
+keycode 0x25 = l
+keycode 0x26 = j
+keycode 0x27 = apostrophe quotedbl
+ control keycode 0x27 = Control_g
+ alt keycode 0x27 = Meta_apostrophe
+keycode 0x28 = k
+keycode 0x29 = semicolon colon
+ alt keycode 0x29 = Meta_semicolon
+keycode 0x2a = backslash bar
+ control keycode 0x2a = Control_backslash
+ alt keycode 0x2a = Meta_backslash
+keycode 0x2b = comma less
+ alt keycode 0x2b = Meta_comma
+keycode 0x2c = slash question
+ control keycode 0x2c = Delete
+ alt keycode 0x2c = Meta_slash
+keycode 0x2d = n
+keycode 0x2e = m
+keycode 0x2f = period greater
+ control keycode 0x2f = Compose
+ alt keycode 0x2f = Meta_period
+keycode 0x30 = Tab Tab
+ alt keycode 0x30 = Meta_Tab
+keycode 0x31 = space space
+ control keycode 0x31 = nul
+ alt keycode 0x31 = Meta_space
+keycode 0x32 = grave asciitilde
+ control keycode 0x32 = nul
+ alt keycode 0x32 = Meta_grave
+keycode 0x33 = Delete Delete
+ control keycode 0x33 = BackSpace
+ alt keycode 0x33 = Meta_Delete
+keycode 0x34 =
+keycode 0x35 = Escape Escape
+ alt keycode 0x35 = Meta_Escape
+keycode 0x36 = Control
+keycode 0x37 = Alt
+keycode 0x38 = Shift
+keycode 0x39 = Caps_Lock
+keycode 0x3a = AltGr
+keycode 0x3b = Left
+ alt keycode 0x3b = Decr_Console
+keycode 0x3c = Right
+ alt keycode 0x3c = Incr_Console
+keycode 0x3d = Down
+keycode 0x3e = Up
+keycode 0x3f =
+keycode 0x40 =
+keycode 0x41 = KP_Period
+keycode 0x42 =
+keycode 0x43 = KP_Multiply
+keycode 0x44 =
+keycode 0x45 = KP_Add
+keycode 0x46 =
+keycode 0x47 = Num_Lock
+# shift keycode 0x47 = Bare_Num_Lock
+keycode 0x48 =
+keycode 0x49 =
+keycode 0x4a =
+keycode 0x4b = KP_Divide
+keycode 0x4c = KP_Enter
+keycode 0x4d =
+keycode 0x4e = KP_Subtract
+keycode 0x4f =
+keycode 0x50 =
+keycode 0x51 =
+#keycode 0x51 = KP_Equals
+keycode 0x52 = KP_0
+ alt keycode 0x52 = Ascii_0
+ altgr keycode 0x52 = Hex_0
+keycode 0x53 = KP_1
+ alt keycode 0x53 = Ascii_1
+ altgr keycode 0x53 = Hex_1
+keycode 0x54 = KP_2
+ alt keycode 0x54 = Ascii_2
+ altgr keycode 0x54 = Hex_2
+keycode 0x55 = KP_3
+ alt keycode 0x55 = Ascii_3
+ altgr keycode 0x55 = Hex_3
+keycode 0x56 = KP_4
+ alt keycode 0x56 = Ascii_4
+ altgr keycode 0x56 = Hex_4
+keycode 0x57 = KP_5
+ alt keycode 0x57 = Ascii_5
+ altgr keycode 0x57 = Hex_5
+keycode 0x58 = KP_6
+ alt keycode 0x58 = Ascii_6
+ altgr keycode 0x58 = Hex_6
+keycode 0x59 = KP_7
+ alt keycode 0x59 = Ascii_7
+ altgr keycode 0x59 = Hex_7
+# keycode 0 (A) is remapped to here
+keycode 0x5a = a
+ altgr keycode 0x00 = Hex_A
+keycode 0x5b = KP_8
+ alt keycode 0x5b = Ascii_8
+ altgr keycode 0x5b = Hex_8
+keycode 0x5c = KP_9
+ alt keycode 0x5c = Ascii_9
+ altgr keycode 0x5c = Hex_9
+keycode 0x5d =
+keycode 0x5e =
+keycode 0x5f =
+keycode 0x60 = F5 F15 Console_17
+ control keycode 0x60 = F5
+ alt keycode 0x60 = Console_5
+ control alt keycode 0x60 = Console_5
+keycode 0x61 = F6 F16 Console_18
+ control keycode 0x61 = F6
+ alt keycode 0x61 = Console_6
+ control alt keycode 0x61 = Console_6
+keycode 0x62 = F7 F17 Console_19
+ control keycode 0x62 = F7
+ alt keycode 0x62 = Console_7
+ control alt keycode 0x62 = Console_7
+keycode 0x63 = F3 F13 Console_15
+ control keycode 0x63 = F3
+ alt keycode 0x63 = Console_3
+ control alt keycode 0x63 = Console_3
+keycode 0x64 = F8 F18 Console_20
+ control keycode 0x64 = F8
+ alt keycode 0x64 = Console_8
+ control alt keycode 0x64 = Console_8
+keycode 0x65 = F9 F19 Console_21
+ control keycode 0x65 = F9
+ alt keycode 0x65 = Console_9
+ control alt keycode 0x65 = Console_9
+keycode 0x66 =
+keycode 0x67 = F11 F11 Console_23
+ control keycode 0x67 = F11
+ alt keycode 0x67 = Console_11
+ control alt keycode 0x67 = Console_11
+keycode 0x68 =
+keycode 0x69 = F13
+keycode 0x6a =
+keycode 0x6b = Scroll_Lock Show_Memory Show_Registers
+ control keycode 0x6b = Show_State
+ alt keycode 0x6b = Scroll_Lock
+keycode 0x6c =
+keycode 0x6d = F10 F20 Console_22
+ control keycode 0x6d = F10
+ alt keycode 0x6d = Console_10
+ control alt keycode 0x6d = Console_10
+keycode 0x6e =
+keycode 0x6f = F12 F12 Console_24
+ control keycode 0x6f = F12
+ alt keycode 0x6f = Console_12
+ control alt keycode 0x6f = Console_12
+keycode 0x70 =
+keycode 0x71 = Pause
+keycode 0x72 = Insert
+keycode 0x73 = Home
+keycode 0x74 = Prior
+ shift keycode 0x74 = Scroll_Backward
+keycode 0x75 = Remove
+keycode 0x76 = F4 F14 Console_16
+ control keycode 0x76 = F4
+ alt keycode 0x76 = Console_4
+ control alt keycode 0x76 = Console_4
+keycode 0x77 = End
+keycode 0x78 = F2 F12 Console_14
+ control keycode 0x78 = F2
+ alt keycode 0x78 = Console_2
+ control alt keycode 0x78 = Console_2
+keycode 0x79 = Next
+ shift keycode 0x79 = Scroll_Forward
+keycode 0x7a = F1 F11 Console_13
+ control keycode 0x7a = F1
+ alt keycode 0x7a = Console_1
+ control alt keycode 0x7a = Console_1
+keycode 0x7b = Shift
+keycode 0x7c = AltGr
+keycode 0x7d = Control
+keycode 0x7e =
+keycode 0x7f =
+#keycode 0x7f = Power
+ control shift keycode 0x7f = Boot
+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 'ÿ'
--- /dev/null
+/*
+ * macserial.c: Serial port driver for Power Macintoshes.
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+
+#include "macserial.h"
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on NUM_SERIAL, so we could support any number of
+ * Z8530s, but for now...
+ */
+#define NUM_SERIAL 2 /* Max number of ZS chips supported */
+#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
+
+/* On PowerMacs, the hardware takes care of the SCC recovery time,
+ but we need the eieio to make sure that the accesses occur
+ in the order we want. */
+#define RECOVERY_DELAY eieio()
+
+struct mac_zschannel *zs_kgdbchan;
+struct mac_zschannel zs_channels[NUM_CHANNELS];
+
+struct mac_serial zs_soft[NUM_CHANNELS];
+int zs_channels_found;
+struct mac_serial *zs_chain; /* list of all channels */
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chan = 0;
+struct mac_serial *zs_consinfo = 0;
+struct mac_zschannel *zs_conschan;
+
+/*
+ * Initialization values for when a channel is used for
+ * kernel gdb support.
+ */
+static unsigned char kgdb_regs[16] = {
+ 0, 0, 0, /* write 0, 1, 2 */
+ (Rx8 | RxENABLE), /* write 3 */
+ (X16CLK | SB1), /* write 4 */
+ (Tx8 | TxENAB | RTS), /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ (NV), /* write 9 */
+ (NRZ), /* write 10 */
+ (TCBR | RCBR), /* write 11 */
+ 1, 0, /* 38400 baud divisor, write 12 + 13 */
+ (BRENABL), /* write 14 */
+ (DCDIE) /* write 15 */
+};
+
+#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
+
+DECLARE_TASK_QUEUE(tq_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void probe_sccs(void);
+static void change_speed(struct mac_serial *info);
+
+static struct tty_struct *serial_table[NUM_CHANNELS];
+static struct termios *serial_termios[NUM_CHANNELS];
+static struct termios *serial_termios_locked[NUM_CHANNELS];
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write. We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct mac_serial *info,
+ dev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+ static const char *badmagic =
+ "Warning: bad magic number for serial struct (%d, %d) in %s\n";
+ static const char *badinfo =
+ "Warning: null mac_serial for (%d, %d) in %s\n";
+
+ if (!info) {
+ printk(badinfo, MAJOR(device), MINOR(device), routine);
+ return 1;
+ }
+ if (info->magic != SERIAL_MAGIC) {
+ printk(badmagic, MAJOR(device), MINOR(device), routine);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 230400, 0 };
+
+/*
+ * Reading and writing Z8530 registers.
+ */
+static inline unsigned char read_zsreg(struct mac_zschannel *channel,
+ unsigned char reg)
+{
+ unsigned char retval;
+
+ if (reg != 0) {
+ *channel->control = reg;
+ RECOVERY_DELAY;
+ }
+ retval = *channel->control;
+ RECOVERY_DELAY;
+ return retval;
+}
+
+static inline void write_zsreg(struct mac_zschannel *channel,
+ unsigned char reg, unsigned char value)
+{
+ if (reg != 0) {
+ *channel->control = reg;
+ RECOVERY_DELAY;
+ }
+ *channel->control = value;
+ RECOVERY_DELAY;
+ return;
+}
+
+static inline unsigned char read_zsdata(struct mac_zschannel *channel)
+{
+ unsigned char retval;
+
+ retval = *channel->data;
+ RECOVERY_DELAY;
+ return retval;
+}
+
+static inline void write_zsdata(struct mac_zschannel *channel,
+ unsigned char value)
+{
+ *channel->data = value;
+ RECOVERY_DELAY;
+ return;
+}
+
+static inline void load_zsregs(struct mac_zschannel *channel,
+ unsigned char *regs)
+{
+ ZS_CLEARERR(channel);
+ ZS_CLEARFIFO(channel);
+ /* Load 'em up */
+ write_zsreg(channel, R4, regs[R4]);
+ write_zsreg(channel, R10, regs[R10]);
+ write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+ write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+ write_zsreg(channel, R1, regs[R1]);
+ write_zsreg(channel, R9, regs[R9]);
+ write_zsreg(channel, R11, regs[R11]);
+ write_zsreg(channel, R12, regs[R12]);
+ write_zsreg(channel, R13, regs[R13]);
+ write_zsreg(channel, R14, regs[R14]);
+ write_zsreg(channel, R15, regs[R15]);
+ write_zsreg(channel, R3, regs[R3]);
+ write_zsreg(channel, R5, regs[R5]);
+ return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct mac_serial *ss, int set)
+{
+ if (set)
+ ss->curregs[5] |= (RTS | DTR);
+ else
+ ss->curregs[5] &= ~(RTS | DTR);
+ write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+ return;
+}
+
+static inline void kgdb_chaninit(struct mac_serial *ss, int intson, int bps)
+{
+ int brg;
+
+ if (intson) {
+ kgdb_regs[R1] = INT_ALL_Rx;
+ kgdb_regs[R9] |= MIE;
+ } else {
+ kgdb_regs[R1] = 0;
+ kgdb_regs[R9] &= ~MIE;
+ }
+ brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+ kgdb_regs[R12] = brg;
+ kgdb_regs[R13] = brg >> 8;
+ load_zsregs(ss->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct mac_serial *ss)
+{
+ struct mac_zschannel *channel = ss->zs_channel;
+ int brg;
+
+ if ((ss->curregs[R11] & TCBR) == 0) {
+ /* higher rates don't use the baud rate generator */
+ return (ss->curregs[R4] & X32CLK)? ZS_CLOCK/32: ZS_CLOCK/16;
+ }
+ /* The baud rate is split up between two 8-bit registers in
+ * what is termed 'BRG time constant' format in my docs for
+ * the chip, it is a function of the clk rate the chip is
+ * receiving which happens to be constant.
+ */
+ brg = (read_zsreg(channel, 13) << 8);
+ brg |= read_zsreg(channel, 12);
+ return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void rs_recv_clear(struct mac_zschannel *zsc)
+{
+ write_zsreg(zsc, 0, ERR_RES);
+ write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines. All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt(). They were separated out for readability's sake.
+ *
+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct mac_serial *info,
+ int event)
+{
+ info->event |= 1 << event;
+ queue_task(&info->tqueue, &tq_serial);
+ mark_bh(SERIAL_BH);
+}
+
+extern void breakpoint(void); /* For the KGDB frame character */
+
+static _INLINE_ void receive_chars(struct mac_serial *info,
+ struct pt_regs *regs)
+{
+ struct tty_struct *tty = info->tty;
+ unsigned char ch, stat, flag;
+
+ while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
+
+ stat = read_zsreg(info->zs_channel, R1);
+ ch = read_zsdata(info->zs_channel);
+
+#if 0 /* KGDB not yet supported */
+ /* Look for kgdb 'stop' character, consult the gdb documentation
+ * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+ * to see how all this works.
+ */
+ if ((info->kgdb_channel) && (ch =='\003')) {
+ breakpoint();
+ continue;
+ }
+#endif
+
+ if (!tty)
+ continue;
+ queue_task(&tty->flip.tqueue, &tq_timer);
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ static int flip_buf_ovf;
+ ++flip_buf_ovf;
+ continue;
+ }
+ tty->flip.count++;
+ {
+ static int flip_max_cnt;
+ if (flip_max_cnt < tty->flip.count)
+ flip_max_cnt = tty->flip.count;
+ }
+ if (stat & Rx_OVR) {
+ flag = TTY_OVERRUN;
+ /* reset the error indication */
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ } else if (stat & FRM_ERR) {
+ /* this error is not sticky */
+ flag = TTY_FRAME;
+ } else if (stat & PAR_ERR) {
+ flag = TTY_PARITY;
+ /* reset the error indication */
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ } else
+ flag = 0;
+ *tty->flip.flag_buf_ptr++ = flag;
+ *tty->flip.char_buf_ptr++ = ch;
+ }
+}
+
+static void transmit_chars(struct mac_serial *info)
+{
+ if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
+ return;
+ info->tx_active = 0;
+
+ if (info->x_char) {
+ /* Send next char */
+ write_zsdata(info->zs_channel, info->x_char);
+ info->x_char = 0;
+ info->tx_active = 1;
+ return;
+ }
+
+ if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
+ write_zsreg(info->zs_channel, 0, RES_Tx_P);
+ return;
+ }
+
+ /* Send char */
+ write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+ info->tx_active = 1;
+
+ if (info->xmit_cnt < WAKEUP_CHARS)
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+}
+
+static _INLINE_ void status_handle(struct mac_serial *info)
+{
+ unsigned char status;
+
+ /* Get status from Read Register 0 */
+ status = read_zsreg(info->zs_channel, 0);
+
+ /* Check for DCD transitions */
+ if (((status ^ info->read_reg_zero) & DCD) != 0
+ && info->tty && !C_CLOCAL(info->tty)) {
+ if (status & DCD) {
+ wake_up_interruptible(&info->open_wait);
+ } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+ queue_task(&info->tqueue_hangup, &tq_scheduler);
+ }
+ }
+
+ /* Check for CTS transitions */
+ if (info->tty && C_CRTSCTS(info->tty)) {
+ /*
+ * For some reason, on the Power Macintosh,
+ * it seems that the CTS bit is 1 when CTS is
+ * *negated* and 0 when it is asserted.
+ * The DCD bit doesn't seem to be inverted
+ * like this.
+ */
+ if ((status & CTS) == 0) {
+ if (info->tx_stopped) {
+ info->tx_stopped = 0;
+ if (!info->tx_active)
+ transmit_chars(info);
+ }
+ } else {
+ info->tx_stopped = 1;
+ }
+ }
+
+ /* Clear status condition... */
+ write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+ info->read_reg_zero = status;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct mac_serial *info = (struct mac_serial *) dev_id;
+ unsigned char zs_intreg;
+ int shift;
+
+ /* NOTE: The read register 3, which holds the irq status,
+ * does so for both channels on each chip. Although
+ * the status value itself must be read from the A
+ * channel and is only valid when read from channel A.
+ * Yes... broken hardware...
+ */
+#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+ if (info->zs_chan_a == info->zs_channel)
+ shift = 3; /* Channel A */
+ else
+ shift = 0; /* Channel B */
+
+ for (;;) {
+ zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
+ if ((zs_intreg & CHAN_IRQMASK) == 0)
+ break;
+
+ if (zs_intreg & CHBRxIP)
+ receive_chars(info, regs);
+ if (zs_intreg & CHBTxIP)
+ transmit_chars(info);
+ if (zs_intreg & CHBEXT)
+ status_handle(info);
+ }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_stop"))
+ return;
+
+#if 0
+ save_flags(flags); cli();
+ if (info->curregs[5] & TxENAB) {
+ info->curregs[5] &= ~TxENAB;
+ info->pendregs[5] &= ~TxENAB;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ }
+ restore_flags(flags);
+#endif
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_start"))
+ return;
+
+ save_flags(flags); cli();
+#if 0
+ if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
+ info->curregs[5] |= TxENAB;
+ info->pendregs[5] = info->curregs[5];
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ }
+#else
+ if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
+ transmit_chars(info);
+ }
+#endif
+ restore_flags(flags);
+}
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+ run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+ struct mac_serial *info = (struct mac_serial *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred. The path of
+ * hangup processing is:
+ *
+ * serial interrupt routine -> (scheduler tqueue) ->
+ * do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ *
+ */
+static void do_serial_hangup(void *private_)
+{
+ struct mac_serial *info = (struct mac_serial *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ tty_hangup(tty);
+}
+
+static void rs_timer(void)
+{
+}
+
+static int startup(struct mac_serial * info)
+{
+ unsigned long flags;
+
+ if (info->flags & ZILOG_INITIALIZED)
+ return 0;
+
+ if (!info->xmit_buf) {
+ info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+ if (!info->xmit_buf)
+ return -ENOMEM;
+ }
+
+ save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+#endif
+
+ /*
+ * Clear the receive FIFO.
+ */
+ ZS_CLEARFIFO(info->zs_channel);
+ info->xmit_fifo_size = 1;
+
+ /*
+ * Clear the interrupt registers.
+ */
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+ /*
+ * Turn on RTS and DTR.
+ */
+ zs_rtsdtr(info, 1);
+
+ /*
+ * Finally, enable sequencing and interrupts
+ */
+ info->curregs[1] = (info->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+ info->pendregs[1] = info->curregs[1];
+ info->curregs[3] |= (RxENABLE | Rx8);
+ info->pendregs[3] = info->curregs[3];
+ info->curregs[5] |= (TxENAB | Tx8);
+ info->pendregs[5] = info->curregs[5];
+ info->curregs[9] |= (NV | MIE);
+ info->pendregs[9] = info->curregs[9];
+ write_zsreg(info->zs_channel, 3, info->curregs[3]);
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ write_zsreg(info->zs_channel, 9, info->curregs[9]);
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /*
+ * Set the speed of the serial port
+ */
+ change_speed(info);
+
+ /* Save the current value of RR0 */
+ info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+
+ info->flags |= ZILOG_INITIALIZED;
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct mac_serial * info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ZILOG_INITIALIZED))
+ return;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("Shutting down serial port %d (irq %d)....", info->line,
+ info->irq);
+#endif
+
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ if (info->xmit_buf) {
+ free_page((unsigned long) info->xmit_buf);
+ info->xmit_buf = 0;
+ }
+
+ info->pendregs[1] = info->curregs[1] = 0;
+ write_zsreg(info->zs_channel, 1, 0); /* no interrupts */
+
+ info->curregs[3] &= ~RxENABLE;
+ info->pendregs[3] = info->curregs[3];
+ write_zsreg(info->zs_channel, 3, info->curregs[3]);
+
+ info->curregs[5] &= ~TxENAB;
+ if (!info->tty || C_HUPCL(info->tty))
+ info->curregs[5] &= ~(DTR | RTS);
+ info->pendregs[5] = info->curregs[5];
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ZILOG_INITIALIZED;
+ restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct mac_serial *info)
+{
+ unsigned short port;
+ unsigned cflag;
+ int i;
+ int brg;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return;
+ cflag = info->tty->termios->c_cflag;
+ if (!(port = info->port))
+ return;
+ i = cflag & CBAUD;
+
+ save_flags(flags); cli();
+ info->zs_baud = baud_table[i];
+ info->clk_divisor = 16;
+
+ switch (info->zs_baud) {
+ case ZS_CLOCK/16: /* 230400 */
+ info->curregs[4] = X16CLK;
+ info->curregs[11] = 0;
+ break;
+ case ZS_CLOCK/32: /* 115200 */
+ info->curregs[4] = X32CLK;
+ info->curregs[11] = 0;
+ break;
+ default:
+ info->curregs[4] = X16CLK;
+ info->curregs[11] = TCBR | RCBR;
+ brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+ info->curregs[12] = (brg & 255);
+ info->curregs[13] = ((brg >> 8) & 255);
+ info->curregs[14] = BRENABL;
+ }
+
+ /* byte size and parity */
+ info->curregs[3] &= ~RxNBITS_MASK;
+ info->curregs[5] &= ~TxNBITS_MASK;
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->curregs[3] |= Rx5;
+ info->curregs[5] |= Tx5;
+ break;
+ case CS6:
+ info->curregs[3] |= Rx6;
+ info->curregs[5] |= Tx6;
+ break;
+ case CS7:
+ info->curregs[3] |= Rx7;
+ info->curregs[5] |= Tx7;
+ break;
+ case CS8:
+ default: /* defaults to 8 bits */
+ info->curregs[3] |= Rx8;
+ info->curregs[5] |= Tx8;
+ break;
+ }
+ info->pendregs[3] = info->curregs[3];
+ info->pendregs[5] = info->curregs[5];
+
+ info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+ if (cflag & CSTOPB) {
+ info->curregs[4] |= SB2;
+ } else {
+ info->curregs[4] |= SB1;
+ }
+ if (cflag & PARENB) {
+ info->curregs[4] |= PAR_ENA;
+ }
+ if (!(cflag & PARODD)) {
+ info->curregs[4] |= PAR_EVEN;
+ }
+ info->pendregs[4] = info->curregs[4];
+
+ if (!(cflag & CLOCAL)) {
+ if (!(info->curregs[15] & DCDIE))
+ info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+ info->curregs[15] |= DCDIE;
+ } else
+ info->curregs[15] &= ~DCDIE;
+ if (cflag & CRTSCTS) {
+ info->curregs[15] |= CTSIE;
+ if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
+ info->tx_stopped = 1;
+ } else {
+ info->curregs[15] &= ~CTSIE;
+ info->tx_stopped = 0;
+ }
+ info->pendregs[15] = info->curregs[15];
+
+ /* Load up the new values */
+ load_zsregs(info->zs_channel, info->curregs);
+
+ restore_flags(flags);
+}
+
+/* This is for console output over ttya/ttyb */
+static void rs_put_char(char ch)
+{
+ struct mac_zschannel *chan = zs_conschan;
+ int loops = 0;
+ unsigned long flags;
+
+ if(!chan)
+ return;
+
+ save_flags(flags); cli();
+ while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+ if (++loops >= 1000000)
+ break;
+ write_zsdata(chan, ch);
+ restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+
+ while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+ udelay(5);
+ write_zsdata(chan, kgdb_char);
+}
+
+char getDebugChar(void)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+
+ while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+ udelay(5);
+ return read_zsdata(chan);
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+ int left; /* Output no more than that */
+ unsigned long flags;
+ struct mac_serial *info = zs_consinfo;
+ char c;
+
+ if (info == 0) return;
+ if (info->xmit_buf == 0) return;
+
+ save_flags(flags); cli();
+ left = info->xmit_cnt;
+ while (left != 0) {
+ c = info->xmit_buf[info->xmit_tail];
+ info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+ restore_flags(flags);
+
+ rs_put_char(c);
+
+ save_flags(flags); cli();
+ left = MIN(info->xmit_cnt, left-1);
+ }
+
+ restore_flags(flags);
+ return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+ char c;
+
+ while ((c = *(p++)) != 0) {
+ if (c == '\n')
+ rs_put_char('\r');
+ rs_put_char(c);
+ }
+
+ /* Comment this if you want to have a strict interrupt-driven output */
+ rs_fair_output();
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+ return;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
+ !info->xmit_buf)
+ return;
+
+ /* Enable transmitter */
+ save_flags(flags); cli();
+ transmit_chars(info);
+ restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, total = 0;
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write"))
+ return 0;
+
+ if (!tty || !info->xmit_buf)
+ return 0;
+
+ save_flags(flags);
+ while (1) {
+ cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ if (from_user) {
+ down(&tmp_buf_sem);
+ copy_from_user(tmp_buf, buf, c);
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ up(&tmp_buf_sem);
+ } else
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
+ && !info->tx_active)
+ transmit_chars(info);
+ restore_flags(flags);
+ return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+ int ret;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+ return 0;
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+ return 0;
+ return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+ return;
+ cli();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ sti();
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+ unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("throttle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+ return;
+
+ if (I_IXOFF(tty)) {
+ save_flags(flags); cli();
+ info->x_char = STOP_CHAR(tty);
+ if (!info->tx_active)
+ transmit_chars(info);
+ restore_flags(flags);
+ }
+
+ if (C_CRTSCTS(tty)) {
+ /*
+ * Here we want to turn off the RTS line. On Macintoshes,
+ * we only get the DTR line, which goes to both DTR and
+ * RTS on the modem. RTS doesn't go out to the serial
+ * port socket. So you should make sure your modem is
+ * set to ignore DTR if you're using CRTSCTS.
+ */
+ save_flags(flags); cli();
+ info->curregs[5] &= ~(DTR | RTS);
+ info->pendregs[5] &= ~(DTR | RTS);
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ restore_flags(flags);
+ }
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+ unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+ return;
+
+ if (I_IXOFF(tty)) {
+ save_flags(flags); cli();
+ if (info->x_char)
+ info->x_char = 0;
+ else {
+ info->x_char = START_CHAR(tty);
+ if (!info->tx_active)
+ transmit_chars(info);
+ }
+ restore_flags(flags);
+ }
+
+ if (C_CRTSCTS(tty)) {
+ /* Assert RTS and DTR lines */
+ save_flags(flags); cli();
+ info->curregs[5] |= DTR | RTS;
+ info->pendregs[5] |= DTR | RTS;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ restore_flags(flags);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct mac_serial * info,
+ struct serial_struct * retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->line;
+ tmp.port = info->port;
+ tmp.irq = info->irq;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ tmp.custom_divisor = info->custom_divisor;
+ return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+}
+
+static int set_serial_info(struct mac_serial * info,
+ struct serial_struct * new_info)
+{
+ struct serial_struct new_serial;
+ struct mac_serial old_info;
+ int retval = 0;
+
+ if (!new_info)
+ return -EFAULT;
+ copy_from_user(&new_serial,new_info,sizeof(new_serial));
+ old_info = *info;
+
+ if (!suser()) {
+ if ((new_serial.baud_base != info->baud_base) ||
+ (new_serial.type != info->type) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ZILOG_USR_MASK) !=
+ (info->flags & ~ZILOG_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ZILOG_USR_MASK) |
+ (new_serial.flags & ZILOG_USR_MASK));
+ info->custom_divisor = new_serial.custom_divisor;
+ goto check_and_exit;
+ }
+
+ if (info->count > 1)
+ return -EBUSY;
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+
+ info->baud_base = new_serial.baud_base;
+ info->flags = ((info->flags & ~ZILOG_FLAGS) |
+ (new_serial.flags & ZILOG_FLAGS));
+ info->type = new_serial.type;
+ info->close_delay = new_serial.close_delay;
+ info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+ retval = startup(info);
+ return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info(struct mac_serial * info, unsigned int *value)
+{
+ unsigned char status;
+
+ cli();
+ status = read_zsreg(info->zs_channel, 0);
+ sti();
+ put_user(status,value);
+ return 0;
+}
+
+static int get_modem_info(struct mac_serial *info, unsigned int *value)
+{
+ unsigned char control, status;
+ unsigned int result;
+
+ cli();
+ control = info->curregs[5];
+ status = read_zsreg(info->zs_channel, 0);
+ sti();
+ result = ((control & RTS) ? TIOCM_RTS: 0)
+ | ((control & DTR) ? TIOCM_DTR: 0)
+ | ((status & DCD) ? TIOCM_CAR: 0)
+ | ((status & CTS) ? 0: TIOCM_CTS);
+ put_user(result,value);
+ return 0;
+}
+
+static int set_modem_info(struct mac_serial *info, unsigned int cmd,
+ unsigned int *value)
+{
+ int error;
+ unsigned int arg, bits;
+
+ error = verify_area(VERIFY_READ, value, sizeof(int));
+ if (error)
+ return error;
+ get_user(arg, value);
+ bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
+ cli();
+ switch (cmd) {
+ case TIOCMBIS:
+ info->curregs[5] |= bits;
+ break;
+ case TIOCMBIC:
+ info->curregs[5] &= ~bits;
+ break;
+ case TIOCMSET:
+ info->curregs[5] = (info->curregs[5] & ~(DTR | RTS)) | bits;
+ break;
+ default:
+ sti();
+ return -EINVAL;
+ }
+ info->pendregs[5] = info->curregs[5];
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ sti();
+ return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break( struct mac_serial * info, int duration)
+{
+ if (!info->port)
+ return;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + duration;
+ cli();
+ info->curregs[5] |= SND_BRK;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ schedule();
+ info->curregs[5] &= ~SND_BRK;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ sti();
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ int error;
+ struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+ int retval;
+
+ if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+ return -ENODEV;
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
+ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ send_break(info, HZ/4); /* 1/4 second */
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ return 0;
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
+ case TIOCSSOFTCAR:
+ error = get_user(arg, (int *) arg);
+ if (error)
+ return error;
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ return 0;
+ case TIOCMGET:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int));
+ if (error)
+ return error;
+ return get_modem_info(info, (unsigned int *) arg);
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return set_modem_info(info, cmd, (unsigned int *) arg);
+ case TIOCGSERIAL:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct serial_struct));
+ if (error)
+ return error;
+ return get_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSERGETLSR: /* Get line status register */
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int));
+ if (error)
+ return error;
+ else
+ return get_lsr_info(info, (unsigned int *) arg);
+
+ case TIOCSERGSTRUCT:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct mac_serial));
+ if (error)
+ return error;
+ copy_from_user((struct mac_serial *) arg,
+ info, sizeof(struct mac_serial));
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+ int was_stopped;
+
+ if (tty->termios->c_cflag == old_termios->c_cflag)
+ return;
+ was_stopped = info->tx_stopped;
+
+ change_speed(info);
+
+ if (was_stopped && !info->tx_stopped)
+ rs_start(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed.
+ * Wait for the last remaining data to be sent.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+ struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+ unsigned long flags;
+ unsigned long timeout;
+
+ if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+ return;
+
+ save_flags(flags); cli();
+
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ return;
+ }
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("rs_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
+ if (--info->count < 0) {
+ printk("rs_close: bad serial port count for ttys%d: %d\n",
+ info->line, info->count);
+ info->count = 0;
+ }
+ if (info->count) {
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ZILOG_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ZILOG_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ if (info->flags & ZILOG_CALLOUT_ACTIVE)
+ info->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receiver and receive interrupts.
+ */
+ /** if (!info->iscons) ... **/
+ info->curregs[3] &= ~RxENABLE;
+ info->pendregs[3] = info->curregs[3];
+ write_zsreg(info->zs_channel, 3, info->curregs[3]);
+ info->curregs[1] &= ~(0x18); /* disable any rx ints */
+ info->pendregs[1] = info->curregs[1];
+ write_zsreg(info->zs_channel, 1, info->curregs[1]);
+ ZS_CLEARFIFO(info->zs_channel);
+ if (info->flags & ZILOG_INITIALIZED) {
+ /*
+ * Before we drop DTR, make sure the SCC transmitter
+ * has completely drained.
+ */
+ timeout = jiffies+HZ;
+ while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + info->timeout;
+ schedule();
+ if (jiffies > timeout)
+ break;
+ }
+ }
+
+ shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+ if (tty->ldisc.num != ldiscs[N_TTY].num) {
+ if (tty->ldisc.close)
+ (tty->ldisc.close)(tty);
+ tty->ldisc = ldiscs[N_TTY];
+ tty->termios->c_line = N_TTY;
+ if (tty->ldisc.open)
+ (tty->ldisc.open)(tty);
+ }
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + info->close_delay;
+ schedule();
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
+ ZILOG_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+ restore_flags(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+ struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+ return;
+
+ rs_flush_buffer(tty);
+ shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct mac_serial *info)
+{
+ struct wait_queue wait = { current, NULL };
+ int retval;
+ int do_clocal = 0;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (info->flags & ZILOG_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ZILOG_HUP_NOTIFY)
+ return -EAGAIN;
+ else
+ return -ERESTARTSYS;
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ZILOG_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ (info->flags & ZILOG_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return -EBUSY;
+ if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ (info->flags & ZILOG_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return -EBUSY;
+ info->flags |= ZILOG_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (info->flags & ZILOG_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= ZILOG_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (info->flags & ZILOG_CALLOUT_ACTIVE) {
+ if (info->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready before block: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ cli();
+ if (!tty_hung_up_p(filp))
+ info->count--;
+ sti();
+ info->blocked_open++;
+ while (1) {
+ cli();
+ if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ (tty->termios->c_cflag & CBAUD))
+ zs_rtsdtr(info, 1);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ZILOG_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ !(info->flags & ZILOG_CLOSING) &&
+ (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
+ break;
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready blocking: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ info->count++;
+ info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ if (retval)
+ return retval;
+ info->flags |= ZILOG_NORMAL_ACTIVE;
+ return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its ZILOG structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+ struct mac_serial *info;
+ int retval, line;
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if ((line < 0) || (line >= zs_channels_found))
+ return -ENODEV;
+ info = zs_soft + line;
+
+ /* Is the kgdb running over this line? */
+ if (info->kgdb_channel)
+ return -ENODEV;
+ if (serial_paranoia_check(info, tty->device, "rs_open"))
+ return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+ info->count);
+#endif
+
+ info->count++;
+ tty->driver_data = info;
+ info->tty = tty;
+
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval)
+ return retval;
+
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open returning after block_til_ready with %d\n",
+ retval);
+#endif
+ return retval;
+ }
+
+ if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ change_speed(info);
+ }
+
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open ttys%d successful...", info->line);
+#endif
+ return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+ printk("PowerMac Z8530 serial driver version 1.00\n");
+}
+
+/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
+static void
+probe_sccs()
+{
+ struct device_node *dev, *ch;
+ struct mac_serial **pp;
+ int n;
+
+ n = 0;
+ pp = &zs_chain;
+ for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+ if (n >= NUM_CHANNELS) {
+ printk("Sorry, can't use %s: no more channels\n",
+ dev->full_name);
+ continue;
+ }
+ for (ch = dev->child; ch != 0; ch = ch->sibling) {
+ if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
+ printk("Can't use %s: %d addrs %d intrs\n",
+ ch->full_name, ch->n_addrs, ch->n_intrs);
+ continue;
+ }
+ zs_channels[n].control = (volatile unsigned char *)
+ ch->addrs[0].address;
+ zs_channels[n].data = zs_channels[n].control
+ + ch->addrs[0].size / 2;
+ zs_soft[n].zs_channel = &zs_channels[n];
+ zs_soft[n].irq = ch->intrs[0];
+ if (request_irq(ch->intrs[0], rs_interrupt, 0,
+ "SCC", &zs_soft[n]))
+ panic("macserial: can't get irq %d",
+ ch->intrs[0]);
+ /* XXX this assumes the prom puts chan A before B */
+ if (n & 1)
+ zs_soft[n].zs_chan_a = &zs_channels[n-1];
+ else
+ zs_soft[n].zs_chan_a = &zs_channels[n];
+
+ *pp = &zs_soft[n];
+ pp = &zs_soft[n].zs_next;
+ ++n;
+ }
+ }
+ *pp = 0;
+ zs_channels_found = n;
+}
+
+/* rs_init inits the driver */
+int rs_init(void)
+{
+ int channel, i;
+ unsigned long flags;
+ struct mac_serial *info;
+
+ /* Setup base handler, and timer table. */
+ init_bh(SERIAL_BH, do_serial_bh);
+ timer_table[RS_TIMER].fn = rs_timer;
+ timer_table[RS_TIMER].expires = 0;
+
+ /* Find out how many Z8530 SCCs we have */
+ if (zs_chain == 0)
+ probe_sccs();
+
+ show_serial_version();
+
+ /* Initialize the tty_driver structure */
+ /* Not all of this is exactly right for us. */
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+ serial_driver.name = "ttyS";
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = zs_channels_found;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+
+ serial_driver.init_termios.c_cflag =
+ B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = rs_open;
+ serial_driver.close = rs_close;
+ serial_driver.write = rs_write;
+ serial_driver.flush_chars = rs_flush_chars;
+ serial_driver.write_room = rs_write_room;
+ serial_driver.chars_in_buffer = rs_chars_in_buffer;
+ serial_driver.flush_buffer = rs_flush_buffer;
+ serial_driver.ioctl = rs_ioctl;
+ serial_driver.throttle = rs_throttle;
+ serial_driver.unthrottle = rs_unthrottle;
+ serial_driver.set_termios = rs_set_termios;
+ serial_driver.stop = rs_stop;
+ serial_driver.start = rs_start;
+ serial_driver.hangup = rs_hangup;
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+ callout_driver.name = "cua";
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+ if (tty_register_driver(&serial_driver))
+ panic("Couldn't register serial driver\n");
+ if (tty_register_driver(&callout_driver))
+ panic("Couldn't register callout driver\n");
+
+ save_flags(flags); cli();
+
+ for (channel = 0; channel < zs_channels_found; ++channel) {
+ zs_soft[channel].clk_divisor = 16;
+ zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+
+ /* If console serial line, then enable interrupts. */
+ if (zs_soft[channel].is_cons) {
+ write_zsreg(zs_soft[channel].zs_channel, R1,
+ (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
+ write_zsreg(zs_soft[channel].zs_channel, R9,
+ (NV | MIE));
+ }
+ /* If this is the kgdb line, enable interrupts because we
+ * now want to receive the 'control-c' character from the
+ * client attached to us asynchronously.
+ */
+ if (zs_soft[channel].kgdb_channel)
+ kgdb_chaninit(&zs_soft[channel], 1,
+ zs_soft[channel].zs_baud);
+ }
+
+ for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
+ {
+ info->magic = SERIAL_MAGIC;
+ info->port = (int) info->zs_channel->control;
+ info->line = i;
+ info->tty = 0;
+ info->custom_divisor = 16;
+ info->close_delay = 50;
+ info->closing_wait = 3000;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->tqueue_hangup.routine = do_serial_hangup;
+ info->tqueue_hangup.data = info;
+ info->callout_termios =callout_driver.init_termios;
+ info->normal_termios = serial_driver.init_termios;
+ info->open_wait = 0;
+ info->close_wait = 0;
+ printk("tty%02d at 0x%08x (irq = %d)", info->line,
+ info->port, info->irq);
+ printk(" is a Z8530 ESCC\n");
+ }
+
+ restore_flags(flags);
+
+ return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* PowerMac: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+ return -1;
+}
+
+void unregister_serial(int line)
+{
+ return;
+}
+
+extern void register_console(void (*proc)(const char *));
+
+/*
+ * Initialization values for when a channel is used for
+ * a serial console.
+ */
+static unsigned char cons_init_regs[16] = {
+ 0, 0, 0, /* write 0, 1, 2 */
+ (Rx8 | RxENABLE), /* write 3 */
+ (X16CLK | SB1), /* write 4 */
+ (Tx8 | TxENAB | RTS), /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ 0, /* write 9 */
+ (NRZ), /* write 10 */
+ (TCBR | RCBR), /* write 11 */
+ 1, 0, /* 38400 baud divisor, write 12 + 13 */
+ (BRENABL), /* write 14 */
+ 0 /* write 15 */
+};
+
+/*
+ * Hooks for running a serial console. con_init() calls this if the
+ * console is being run over one of the serial ports.
+ * 'channel' is decoded as 1=modem, 2=printer.
+ */
+void
+rs_cons_hook(int chip, int out, int channel)
+{
+ int brg;
+
+ if (!out)
+ return;
+ if (zs_consinfo != 0) {
+ printk("rs_cons_hook called twice?\n");
+ return;
+ }
+ if (zs_chain == 0)
+ probe_sccs();
+ --channel;
+ if (channel < 0 || channel >= zs_channels_found) {
+ printk("rs_cons_hook: channel = %d?\n", channel);
+ return;
+ }
+
+ zs_cons_chan = channel;
+ zs_consinfo = &zs_soft[channel];
+ zs_conschan = zs_consinfo->zs_channel;
+ zs_consinfo->clk_divisor = 16;
+ zs_consinfo->zs_baud = 38400;
+ zs_consinfo->is_cons = 1;
+
+ memcpy(zs_consinfo->curregs, cons_init_regs, sizeof(cons_init_regs));
+ brg = BPS_TO_BRG(zs_consinfo->zs_baud, ZS_CLOCK/16);
+ zs_consinfo->curregs[R12] = brg;
+ zs_consinfo->curregs[R13] = brg >> 8;
+ load_zsregs(zs_conschan, zs_consinfo->curregs);
+
+ register_console(zs_console_print);
+ printk("zs%d: console I/O\n", channel);
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line. The 'tty_num' argument is 0 for /dev/ttyS0 and 1
+ * for /dev/ttyS1 which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+ if (zs_chain == 0)
+ probe_sccs();
+ zs_kgdbchan = zs_soft[tty_num].zs_channel;
+ zs_soft[tty_num].clk_divisor = 16;
+ zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+ zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */
+ zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+ /* Turn on transmitter/receiver at 8-bits/char */
+ kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+ ZS_CLEARERR(zs_kgdbchan);
+ ZS_CLEARFIFO(zs_kgdbchan);
+}
--- /dev/null
+/*
+ * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _MACSERIAL_H
+#define _MACSERIAL_H
+
+#define NUM_ZSREGS 16
+
+struct serial_struct {
+ int type;
+ int line;
+ int port;
+ int irq;
+ int flags;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int baud_base;
+ unsigned short close_delay;
+ char reserved_char[2];
+ int hub6;
+ unsigned short closing_wait; /* time to wait before closing */
+ unsigned short closing_wait2; /* no longer used... */
+ int reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output. 65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF 0
+#define ZILOG_CLOSING_WAIT_NONE 65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
+ on the callout port */
+#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK 0x0030
+#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
+ * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct mac_zschannel {
+ volatile unsigned char *control;
+ volatile unsigned char *data;
+};
+
+struct mac_serial {
+ struct mac_serial *zs_next; /* For IRQ servicing chain */
+ struct mac_zschannel *zs_channel; /* Channel registers */
+ struct mac_zschannel *zs_chan_a; /* A side registers */
+ unsigned char read_reg_zero;
+
+ char soft_carrier; /* Use soft carrier on this channel */
+ char break_abort; /* Is serial console in, so process brk/abrt */
+ char kgdb_channel; /* Kgdb is running on this channel */
+ char is_cons; /* Is this our console. */
+ unsigned char tx_active; /* character is being xmitted */
+ unsigned char tx_stopped; /* output is suspended */
+
+ /* We need to know the current clock divisor
+ * to read the bps rate the chip has currently
+ * loaded.
+ */
+ unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
+ int zs_baud;
+
+ /* Current write register values */
+ unsigned char curregs[NUM_ZSREGS];
+
+ /* Values we need to set next opportunity */
+ unsigned char pendregs[NUM_ZSREGS];
+
+ char change_needed;
+
+ int magic;
+ int baud_base;
+ int port;
+ int irq;
+ int flags; /* defined in tty.h */
+ int type; /* UART type */
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int timeout;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int x_char; /* xon/xoff character */
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ unsigned long event;
+ unsigned long last_active;
+ int line;
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ struct tq_struct tqueue;
+ struct tq_struct tqueue_hangup;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP 0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define FLAG 0x7e
+
+/* Write Register 0 */
+#define R0 0 /* Register selects */
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+#define NULLCODE 0 /* Null Code */
+#define POINT_HIGH 0x8 /* Select upper half of registers */
+#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
+#define SEND_ABORT 0x18 /* HDLC Abort */
+#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
+#define RES_Tx_P 0x28 /* Reset TxINT Pending */
+#define ERR_RES 0x30 /* Error Reset */
+#define RES_H_IUS 0x38 /* Reset highest IUS */
+
+#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
+#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
+#define RES_EOM_L 0xC0 /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
+#define TxINT_ENAB 0x2 /* Tx Int Enable */
+#define PAR_SPEC 0x4 /* Parity is special condition */
+
+#define RxINT_DISAB 0 /* Rx Int Disable */
+#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
+#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
+#define INT_ERR_Rx 0x18 /* Int on error only */
+
+#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
+#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define RxENABLE 0x1 /* Rx Enable */
+#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
+#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
+#define ENT_HM 0x10 /* Enter Hunt Mode */
+#define AUTO_ENAB 0x20 /* Auto Enables */
+#define Rx5 0x0 /* Rx 5 Bits/Character */
+#define Rx7 0x40 /* Rx 7 Bits/Character */
+#define Rx6 0x80 /* Rx 6 Bits/Character */
+#define Rx8 0xc0 /* Rx 8 Bits/Character */
+#define RxNBITS_MASK 0xc0
+
+/* Write Register 4 */
+
+#define PAR_ENA 0x1 /* Parity Enable */
+#define PAR_EVEN 0x2 /* Parity Even/Odd* */
+
+#define SYNC_ENAB 0 /* Sync Modes Enable */
+#define SB1 0x4 /* 1 stop bit/char */
+#define SB15 0x8 /* 1.5 stop bits/char */
+#define SB2 0xc /* 2 stop bits/char */
+#define SB_MASK 0xc
+
+#define MONSYNC 0 /* 8 Bit Sync character */
+#define BISYNC 0x10 /* 16 bit sync character */
+#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC 0x30 /* External Sync Mode */
+
+#define X1CLK 0x0 /* x1 clock mode */
+#define X16CLK 0x40 /* x16 clock mode */
+#define X32CLK 0x80 /* x32 clock mode */
+#define X64CLK 0xC0 /* x64 clock mode */
+#define XCLK_MASK 0xC0
+
+/* Write Register 5 */
+
+#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
+#define RTS 0x2 /* RTS */
+#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
+#define TxENAB 0x8 /* Tx Enable */
+#define SND_BRK 0x10 /* Send Break */
+#define Tx5 0x0 /* Tx 5 bits (or less)/character */
+#define Tx7 0x20 /* Tx 7 bits/character */
+#define Tx6 0x40 /* Tx 6 bits/character */
+#define Tx8 0x60 /* Tx 8 bits/character */
+#define TxNBITS_MASK 0x60
+#define DTR 0x80 /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define VIS 1 /* Vector Includes Status */
+#define NV 2 /* No Vector */
+#define DLC 4 /* Disable Lower Chain */
+#define MIE 8 /* Master Interrupt Enable */
+#define STATHI 0x10 /* Status high */
+#define NORESET 0 /* No reset on write to R9 */
+#define CHRB 0x40 /* Reset channel B */
+#define CHRA 0x80 /* Reset channel A */
+#define FHWRES 0xc0 /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define BIT6 1 /* 6 bit/8bit sync */
+#define LOOPMODE 2 /* SDLC Loop mode */
+#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE 8 /* Mark/flag on idle */
+#define GAOP 0x10 /* Go active on poll */
+#define NRZ 0 /* NRZ mode */
+#define NRZI 0x20 /* NRZI mode */
+#define FM1 0x40 /* FM1 (transition = 1) */
+#define FM0 0x60 /* FM0 (transition = 0) */
+#define CRCPS 0x80 /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define TRxCXT 0 /* TRxC = Xtal output */
+#define TRxCTC 1 /* TRxC = Transmit clock */
+#define TRxCBR 2 /* TRxC = BR Generator Output */
+#define TRxCDP 3 /* TRxC = DPLL output */
+#define TRxCOI 4 /* TRxC O/I */
+#define TCRTxCP 0 /* Transmit clock = RTxC pin */
+#define TCTRxCP 8 /* Transmit clock = TRxC pin */
+#define TCBR 0x10 /* Transmit clock = BR Generator output */
+#define TCDPLL 0x18 /* Transmit clock = DPLL output */
+#define RCRTxCP 0 /* Receive clock = RTxC pin */
+#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
+#define RCBR 0x40 /* Receive clock = BR Generator output */
+#define RCDPLL 0x60 /* Receive clock = DPLL output */
+#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define BRENABL 1 /* Baud rate generator enable */
+#define BRSRC 2 /* Baud rate generator source */
+#define DTRREQ 4 /* DTR/Request function */
+#define AUTOECHO 8 /* Auto Echo */
+#define LOOPBAK 0x10 /* Local loopback */
+#define SEARCH 0x20 /* Enter search mode */
+#define RMC 0x40 /* Reset missing clock */
+#define DISDPLL 0x60 /* Disable DPLL */
+#define SSBR 0x80 /* Set DPLL source = BR generator */
+#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
+#define SFMM 0xc0 /* Set FM mode */
+#define SNRZI 0xe0 /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define ZCIE 2 /* Zero count IE */
+#define DCDIE 8 /* DCD IE */
+#define SYNCIE 0x10 /* Sync/hunt IE */
+#define CTSIE 0x20 /* CTS IE */
+#define TxUIE 0x40 /* Tx Underrun/EOM IE */
+#define BRKIE 0x80 /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define Rx_CH_AV 0x1 /* Rx Character Available */
+#define ZCOUNT 0x2 /* Zero count */
+#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
+#define DCD 0x8 /* DCD */
+#define SYNC_HUNT 0x10 /* Sync/hunt */
+#define CTS 0x20 /* CTS */
+#define TxEOM 0x40 /* Tx underrun */
+#define BRK_ABRT 0x80 /* Break/Abort */
+
+/* Read Register 1 */
+#define ALL_SNT 0x1 /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3 0x8 /* 0/3 */
+#define RES4 0x4 /* 0/4 */
+#define RES5 0xc /* 0/5 */
+#define RES6 0x2 /* 0/6 */
+#define RES7 0xa /* 0/7 */
+#define RES8 0x6 /* 0/8 */
+#define RES18 0xe /* 1/8 */
+#define RES28 0x0 /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR 0x10 /* Parity error */
+#define Rx_OVR 0x20 /* Rx Overrun Error */
+#define FRM_ERR 0x40 /* CRC/Framing Error */
+#define END_FR 0x80 /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
+#define CHBTxIP 0x2 /* Channel B Tx IP */
+#define CHBRxIP 0x4 /* Channel B Rx IP */
+#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
+#define CHATxIP 0x10 /* Channel A Tx IP */
+#define CHARxIP 0x20 /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10 (misc status bits) */
+#define ONLOOP 2 /* On loop */
+#define LOOPSEND 0x10 /* Loop sending */
+#define CLK2MIS 0x40 /* Two clocks missing */
+#define CLK1MIS 0x80 /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES))
+#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
+ garbage = read_zsdata(channel); \
+ garbage = read_zsdata(channel); \
+ garbage = read_zsdata(channel); \
+ } while(0)
+
+#endif /* !(_MACSERIAL_H) */
--- /dev/null
+/*
+ * /dev/nvram driver for Power Macintosh.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#define NVRAM_SIZE 8192
+
+static long long nvram_llseek(struct inode *inode, struct file *file,
+ loff_t offset, int origin)
+{
+ switch (origin) {
+ case 1:
+ offset += file->f_pos;
+ break;
+ case 2:
+ offset += NVRAM_SIZE;
+ break;
+ }
+ if (offset < 0)
+ return -EINVAL;
+ file->f_pos = offset;
+ return file->f_pos;
+}
+
+static long read_nvram(struct inode *inode, struct file *file,
+ char *buf, unsigned long count)
+{
+ unsigned int i = file->f_pos;
+ char *p = buf;
+
+ for (; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count)
+ put_user(nvram_read_byte(i), p);
+ file->f_pos = i;
+ return p - buf;
+}
+
+static long write_nvram(struct inode *inode, struct file *file,
+ const char *buf, unsigned long count)
+{
+ unsigned int i = file->f_pos;
+ const char *p = buf;
+ char c;
+
+ for (; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) {
+ get_user(c, p);
+ nvram_write_byte(i, c);
+ }
+ file->f_pos = i;
+ return p - buf;
+}
+
+static int nvram_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+struct file_operations nvram_fops = {
+ nvram_llseek,
+ read_nvram,
+ write_nvram,
+ NULL, /* nvram_readdir */
+ NULL, /* nvram_select */
+ NULL, /* nvram_ioctl */
+ NULL, /* nvram_mmap */
+ nvram_open,
+ NULL, /* no special release code */
+ NULL /* fsync */
+};
+
+static struct miscdevice nvram_dev = {
+ NVRAM_MINOR,
+ "nvram",
+ &nvram_fops
+};
+
+__initfunc(int nvram_init(void))
+{
+ misc_register(&nvram_dev);
+ return 0;
+}
--- /dev/null
+/*
+ * platinum.c: Console support for PowerMac "platinum" display adaptor.
+ *
+ * Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <linux/selection.h>
+#include "pmac-cons.h"
+#include "platinum.h"
+
+/*
+ * Structure of the registers for the DACula colormap device.
+ */
+struct cmap_regs {
+ unsigned char addr;
+ char pad1[15];
+ unsigned char d1;
+ char pad2[15];
+ unsigned char d2;
+ char pad3[15];
+ unsigned char lut;
+ char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "platinum" display adaptor".
+ */
+#define PAD(x) char x[12]
+
+struct preg { /* padded register */
+ unsigned r;
+ char pad[12];
+};
+
+struct platinum_regs {
+ struct preg reg[128];
+};
+
+static void set_platinum_clock(unsigned char *clksel);
+static int read_platinum_sense(void);
+static int platinum_vram_reqd(int vmode, int cmode);
+
+static int total_vram; /* total amount of video memory, bytes */
+static unsigned char *frame_buffer;
+static unsigned char *base_frame_buffer;
+static struct cmap_regs *cmap_regs;
+static volatile struct platinum_regs *plat_regs;
+
+/*
+ * Register initialization tables for the platinum display.
+ *
+ * It seems that there are two different types of platinum display
+ * out there. Older ones use the values in clocksel[1], for which
+ * the formula for the clock frequency seems to be
+ * F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5))
+ * Newer ones use the values in clocksel[0], for which the formula
+ * seems to be
+ * F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5))
+ */
+struct plat_regvals {
+ int fb_offset;
+ int pitch[3];
+ unsigned regs[26];
+ unsigned char plat_offset[3];
+ unsigned char mode[3];
+ unsigned char dacula_ctrl[3];
+ unsigned char clocksel[2][2];
+};
+
+#define DIV2 0x20
+#define DIV4 0x40
+#define DIV8 0x60
+#define DIV16 0x80
+
+/* 1280x1024, 75Hz (20) */
+static struct plat_regvals platinum_reg_init_20 = {
+ 0x5c00,
+ { 1312, 2592, 2592 },
+ { 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+ 0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d,
+ 0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50,
+ 0x850, 0x851 }, { 0x58, 0x5d, 0x5d },
+ { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+ {{ 45, 3 }, { 66, 7 }}
+};
+
+/* 1280x960, 75Hz (19) */
+static struct plat_regvals platinum_reg_init_19 = {
+ 0x5c00,
+ { 1312, 2592, 2592 },
+ { 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+ 0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d,
+ 0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c,
+ 0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b },
+ { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+ {{ 42, 3 }, { 44, 5 }}
+};
+
+/* 1152x870, 75Hz (18) */
+static struct plat_regvals platinum_reg_init_18 = {
+ 0x11b0,
+ { 1184, 2336, 4640 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x38f, 0,
+ 0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53,
+ 0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52,
+ 0x71e, 0x722 }, { 0x74, 0x7c, 0x81 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 26, 0 + DIV2 }, { 42, 6 }}
+};
+
+/* 1024x768, 75Hz (17) */
+static struct plat_regvals platinum_reg_init_17 = {
+ 0x10b0,
+ { 1056, 2080, 4128 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b,
+ 0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40,
+ 0x640, 0x644 }, { 0x72, 0x7a, 0x7f },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 54, 3 + DIV2 }, { 67, 12 }}
+};
+
+/* 1024x768, 75Hz (16) */
+static struct plat_regvals platinum_reg_init_16 = {
+ 0x10b0,
+ { 1056, 2080, 4128 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47,
+ 0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c,
+ 0x63c, 0x63d }, { 0x74, 0x7c, 0x81 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 20, 0 + DIV2 }, { 11, 2 }}
+};
+
+/* 1024x768, 70Hz (15) */
+static struct plat_regvals platinum_reg_init_15 = {
+ 0x10b0,
+ { 1056, 2080, 4128 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b,
+ 0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+ 0x644, 0x646 }, { 0x78, 0x80, 0x85 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 19, 0 + DIV2 }, { 110, 21 }}
+};
+
+/* 1024x768, 60Hz (14) */
+static struct plat_regvals platinum_reg_init_14 = {
+ 0x10b0,
+ { 1056, 2080, 4128 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b,
+ 0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+ 0x644, 0x646 }, { 0x80, 0x88, 0x8d },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }}
+};
+
+/* 832x624, 75Hz (13) */
+static struct plat_regvals platinum_reg_init_13 = {
+ 0x70,
+ { 864, 1680, 3360 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+ { 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
+ 0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
+ 0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
+ 0x532, 0x533 }, { 0x7c, 0x84, 0x89 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 800x600, 75Hz (12) */
+static struct plat_regvals platinum_reg_init_12 = {
+ 0x1010,
+ { 832, 1632, 3232 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39,
+ 0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e,
+ 0x4de, 0x4df }, { 0x64, 0x6c, 0x71 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }}
+};
+
+/* 800x600, 72Hz (11) */
+static struct plat_regvals platinum_reg_init_11 = {
+ 0x1010,
+ { 832, 1632, 3232 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d,
+ 0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38,
+ 0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }}
+};
+
+/* 800x600, 60Hz (10) */
+static struct plat_regvals platinum_reg_init_10 = {
+ 0x1010,
+ { 832, 1632, 3232 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+ 0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+ 0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }}
+};
+
+/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */
+static struct plat_regvals platinum_reg_init_9 = {
+ 0x1010,
+ { 832, 1632, 3232 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+ 0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+ 0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }}
+};
+
+/* 768x576, 50Hz Interlaced-PAL (8) */
+static struct plat_regvals platinum_reg_init_8 = {
+ 0x1010,
+ { 800, 1568, 3104 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+ 0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27,
+ 0x267, 0x26b }, { 0x39, 0x41, 0x46 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 640x870, 75Hz Portrait (7) */
+static struct plat_regvals platinum_reg_init_7 = {
+ 0xb10,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f,
+ 0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58,
+ 0x724, 0x72a }, { 0x3c, 0x44, 0x49 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 640x480, 67Hz (6) */
+static struct plat_regvals platinum_reg_init_6 = {
+ 0x1010,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x209, 0,
+ 0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37,
+ 0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52,
+ 0x412, 0x416 }, { 0x3c, 0x44, 0x49 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }}
+};
+
+/* 640x480, 60Hz (5) */
+static struct plat_regvals platinum_reg_init_5 = {
+ 0x1010,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e,
+ 0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44,
+ 0x404, 0x408 }, { 0x34, 0x3c, 0x41 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }}
+};
+
+/* 640x480, 60Hz Interlaced-NTSC (4) */
+static struct plat_regvals platinum_reg_init_4 = {
+ 0x1010,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+ 0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23,
+ 0x203, 0x206 }, { 0x29, 0x31, 0x36 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+/* 640x480, 50Hz Interlaced-PAL (3) */
+static struct plat_regvals platinum_reg_init_3 = {
+ 0x1010,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+ 0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57,
+ 0x237, 0x26b }, { 0x59, 0x61, 0x66 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz (2) */
+static struct plat_regvals platinum_reg_init_2 = {
+ 0x1010,
+ { 544, 1056, 2080 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f,
+ 0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a,
+ 0x32a, 0x32b }, { 0x5a, 0x62, 0x67 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz Interlaced-NTSC (1) */
+static struct plat_regvals platinum_reg_init_1 = {
+ 0x1010,
+ { 544, 1056, 2080 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+ 0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53,
+ 0x1d3, 0x206 }, { 0x49, 0x51, 0x56 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+static struct plat_regvals *platinum_reg_init[VMODE_MAX] = {
+ &platinum_reg_init_1,
+ &platinum_reg_init_2,
+ &platinum_reg_init_3,
+ &platinum_reg_init_4,
+ &platinum_reg_init_5,
+ &platinum_reg_init_6,
+ &platinum_reg_init_7,
+ &platinum_reg_init_8,
+ &platinum_reg_init_9,
+ &platinum_reg_init_10,
+ &platinum_reg_init_11,
+ &platinum_reg_init_12,
+ &platinum_reg_init_13,
+ &platinum_reg_init_14,
+ &platinum_reg_init_15,
+ &platinum_reg_init_16,
+ &platinum_reg_init_17,
+ &platinum_reg_init_18,
+ &platinum_reg_init_19,
+ &platinum_reg_init_20
+};
+
+/*
+ * Get the monitor sense value.
+ */
+static int
+read_platinum_sense()
+{
+ int sense;
+
+ plat_regs->reg[23].r = 7; /* turn off drivers */
+ eieio(); __delay(2000);
+ sense = (~plat_regs->reg[23].r & 7) << 8;
+
+ /* drive each sense line low in turn and collect the other 2 */
+ plat_regs->reg[23].r = 3; /* drive A low */
+ eieio(); __delay(2000);
+ sense |= (~plat_regs->reg[23].r & 3) << 4;
+ eieio();
+ plat_regs->reg[23].r = 5; /* drive B low */
+ eieio(); __delay(2000);
+ sense |= (~plat_regs->reg[23].r & 4) << 1;
+ sense |= (~plat_regs->reg[23].r & 1) << 2;
+ eieio();
+ plat_regs->reg[23].r = 6; /* drive C low */
+ eieio(); __delay(2000);
+ sense |= (~plat_regs->reg[23].r & 6) >> 1;
+ eieio();
+
+ plat_regs->reg[23].r = 7; /* turn off drivers */
+ return sense;
+}
+
+static inline int platinum_vram_reqd(int vmode, int cmode)
+{
+ return vmode_attrs[vmode-1].vres
+ * platinum_reg_init[vmode-1]->pitch[cmode];
+}
+
+void
+map_platinum(struct device_node *dp)
+{
+ int i, sense;
+ unsigned long addr, size;
+ int bank0, bank1, bank2, bank3;
+
+ if (dp->next != 0)
+ printk("Warning: only using first platinum display device\n");
+ if (dp->n_addrs != 2)
+ panic("expecting 2 addresses for platinum (got %d)",
+ dp->n_addrs);
+
+ /* Map in frame buffer and registers */
+ for (i = 0; i < dp->n_addrs; ++i) {
+ addr = dp->addrs[i].address;
+ size = dp->addrs[i].size;
+ if (size >= 0x400000) {
+ /* frame buffer - map only 4MB */
+ frame_buffer = ioremap(addr, 0x400000);
+ base_frame_buffer = frame_buffer;
+ } else {
+ /* registers */
+ plat_regs = ioremap(addr, size);
+ }
+ }
+ cmap_regs = ioremap(0xf301b000, 0x1000); /* XXX not in prom? */
+
+ /* Grok total video ram */
+ plat_regs->reg[16].r = (unsigned)frame_buffer;
+ plat_regs->reg[20].r = 0x1011; /* select max vram */
+ plat_regs->reg[24].r = 0; /* switch in vram */
+ eieio();
+ frame_buffer[0x100000] = 0x34;
+ frame_buffer[0x200000] = 0x56;
+ frame_buffer[0x300000] = 0x78;
+ eieio();
+ bank0 = 1; /* builtin 1MB vram, always there */
+ bank1 = frame_buffer[0x100000] == 0x34;
+ bank2 = frame_buffer[0x200000] == 0x56;
+ bank3 = frame_buffer[0x300000] == 0x78;
+ total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
+ printk("Total VRAM = %dMB\n", total_vram / 1024 / 1024);
+
+ sense = read_platinum_sense();
+ if (video_mode == VMODE_NVRAM) {
+ video_mode = nvram_read_byte(NV_VMODE);
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || platinum_reg_init[video_mode-1] == 0)
+ video_mode = VMODE_CHOOSE;
+ }
+ if (video_mode == VMODE_CHOOSE)
+ video_mode = map_monitor_sense(sense);
+ if (platinum_reg_init[video_mode-1] == 0)
+ video_mode = VMODE_640_480_60;
+ printk("Monitor sense value = 0x%x, ", sense);
+
+ if (color_mode == CMODE_NVRAM)
+ color_mode = nvram_read_byte(NV_CMODE);
+ if (color_mode < CMODE_8 || color_mode > CMODE_32)
+ color_mode = CMODE_8;
+ /*
+ * Reduce the pixel size if we don't have enough VRAM.
+ */
+ while (color_mode > CMODE_8
+ && platinum_vram_reqd(video_mode, color_mode) > total_vram)
+ --color_mode;
+ /*
+ * Reduce the video mode if we don't have enough VRAM.
+ */
+ while (platinum_vram_reqd(video_mode, color_mode) > total_vram)
+ --video_mode;
+}
+
+#define STORE_D2(a, v) { \
+ out_8(&cmap_regs->addr, (a+32)); \
+ out_8(&cmap_regs->d2, (v)); \
+}
+
+static void
+set_platinum_clock(unsigned char *clksel)
+{
+ STORE_D2(6, 0xc6);
+ out_8(&cmap_regs->addr, 3+32);
+ if (cmap_regs->d2 == 2) {
+ STORE_D2(7, clksel[0]);
+ STORE_D2(8, clksel[1]);
+ STORE_D2(3, 3);
+ } else {
+ STORE_D2(4, clksel[0]);
+ STORE_D2(5, clksel[1]);
+ STORE_D2(3, 2);
+ }
+ __delay(5000);
+ STORE_D2(9, 0xa6);
+}
+
+void
+platinum_init()
+{
+ int i, yoff, width, clkmode, dtype;
+ struct plat_regvals *init;
+ unsigned *p;
+ int one_mb = 0;
+
+ if (total_vram == 0x100000) one_mb=1;
+
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || (init = platinum_reg_init[video_mode-1]) == 0)
+ panic("platinum: video mode %d not supported", video_mode);
+
+ frame_buffer = base_frame_buffer + init->fb_offset;
+ /* printk("Frame buffer start address is %p\n", frame_buffer); */
+
+ pixel_size = 1 << color_mode;
+ line_pitch = init->pitch[color_mode];
+ width = vmode_attrs[video_mode-1].hres;
+ n_scanlines = vmode_attrs[video_mode-1].vres;
+ row_pitch = line_pitch * 16;
+
+ /* Initialize display timing registers */
+ out_be32(&plat_regs->reg[24].r, 7); /* turn display off */
+
+ for (i = 0; i < 26; ++i)
+ plat_regs->reg[i+32].r = init->regs[i];
+ plat_regs->reg[26+32].r = (one_mb ? init->plat_offset[color_mode] + 4 - color_mode : init->plat_offset[color_mode]);
+ plat_regs->reg[16].r = (unsigned) frame_buffer;
+ plat_regs->reg[18].r = line_pitch;
+ plat_regs->reg[19].r = (one_mb ? init->mode[color_mode+1] : init->mode[color_mode]);
+ plat_regs->reg[20].r = (one_mb ? 0x11 : 0x1011);
+ plat_regs->reg[21].r = 0x100;
+ plat_regs->reg[22].r = 1;
+ plat_regs->reg[23].r = 1;
+ plat_regs->reg[26].r = 0xc00;
+ plat_regs->reg[27].r = 0x235;
+ /* plat_regs->reg[27].r = 0x2aa; */
+
+ STORE_D2(0, (one_mb ? init->dacula_ctrl[color_mode] & 0xf : init->dacula_ctrl[color_mode]));
+ STORE_D2(1, 4);
+ STORE_D2(2, 0);
+ /*
+ * Try to determine whether we have an old or a new DACula.
+ */
+ out_8(&cmap_regs->addr, 0x40);
+ dtype = cmap_regs->d2;
+ switch (dtype) {
+ case 0x3c:
+ clkmode = 1;
+ break;
+ case 0x84:
+ clkmode = 0;
+ break;
+ default:
+ clkmode = 0;
+ printk("Unknown DACula type: %x\n", cmap_regs->d2);
+ }
+ set_platinum_clock(init->clocksel[clkmode]);
+
+ out_be32(&plat_regs->reg[24].r, 0); /* turn display on */
+
+ pmac_init_palette();
+
+ yoff = (n_scanlines % 16) / 2;
+ fb_start = frame_buffer + yoff * line_pitch + 0x10;
+
+ /* Clear screen */
+ p = (unsigned *) (frame_buffer + 0x10);
+ for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+ *p++ = 0;
+
+ display_info.height = n_scanlines;
+ display_info.width = width;
+ display_info.depth = 8 * pixel_size;
+ display_info.pitch = line_pitch;
+ display_info.mode = video_mode;
+ strncpy(display_info.name, "platinum", sizeof(display_info.name));
+ display_info.fb_address = (unsigned long) frame_buffer + 0x10;
+ display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
+ display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
+ display_info.disp_reg_address = (unsigned long) &plat_regs;
+}
+
+int
+platinum_setmode(struct vc_mode *mode, int doit)
+{
+ int cmode;
+
+ if (mode->mode <= 0 || mode->mode > VMODE_MAX
+ || platinum_reg_init[mode->mode-1] == 0)
+ return -EINVAL;
+ if (mode->depth != 8 && mode->depth != 16 && mode->depth != 24 && mode->depth != 32)
+ return -EINVAL;
+
+ switch (mode->depth) {
+ case 24:
+ case 32:
+ cmode = CMODE_32;
+ break;
+ case 16:
+ cmode = CMODE_16;
+ break;
+ case 8:
+ cmode = CMODE_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (platinum_vram_reqd(mode->mode, cmode) > total_vram)
+ return -EINVAL;
+
+ if (doit) {
+ video_mode = mode->mode;
+ color_mode = cmode;
+ platinum_init();
+ }
+ return 0;
+}
+
+void
+platinum_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors)
+{
+ int i;
+
+ for (i = 0; i < ncolors; ++i) {
+ cmap_regs->addr = index + i; eieio();
+ cmap_regs->lut = red[i]; eieio();
+ cmap_regs->lut = green[i]; eieio();
+ cmap_regs->lut = blue[i]; eieio();
+ }
+}
+
+void
+platinum_set_blanking(int blank_mode)
+{
+}
--- /dev/null
+/*
+ * Exported procedures for the PowerMac "platinum" display adaptor.
+ *
+ * Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *
+ * 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.
+ */
+
+extern void map_platinum(struct device_node *);
+extern void platinum_init(void);
+extern int platinum_setmode(struct vc_mode *mode, int doit);
+extern void platinum_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors);
+extern void platinum_set_blanking(int blank_mode);
--- /dev/null
+/*
+ * pmac-cons.c: Console support for PowerMac (PCI-based).
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ * 7200/Platinum code hacked by Mark Abene.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/kd.h>
+#include <linux/version.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/cuda.h>
+#include <asm/linux_logo.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+#include <linux/vt_kern.h>
+#include "pmac-cons.h"
+#include "control.h"
+#include "platinum.h"
+#include "valkyrie.h"
+#ifdef CONFIG_ATY_VIDEO
+#include "aty.h"
+#endif
+#ifdef CONFIG_IMSTT_VIDEO
+#include "imstt.h"
+#endif
+
+int video_mode = VMODE_NVRAM;
+int color_mode = CMODE_NVRAM;
+
+/*
+ * The format of "screen_info" is strange, and due to early
+ * i386-setup code. This is just enough to make the console
+ * code think we're on a EGA+ colour display.
+ */
+struct screen_info screen_info = {
+ 0, 0, /* orig-x, orig-y */
+ {0, 0}, /* unused1 */
+ 0, /* orig-video-page */
+ 0, /* orig-video-mode */
+ 80, /* orig-video-cols */
+ 0, /* unused [short] */
+ 0, /* ega_bx */
+ 0, /* unused [short] */
+ 25, /* orig-video-lines */
+ 0, /* isVGA */
+ 16 /* video points */
+};
+
+/*
+ * We allocate enough character+attribute memory for the largest
+ * screen resolution supported.
+ */
+#define MAX_TEXT_COLS (1280/8)
+#define MAX_TEXT_ROWS (1024/16)
+
+/*
+ * We get a sense value from the monitor and use it to choose
+ * what resolution to use. This structure maps sense values
+ * to display mode values (which determine the resolution and
+ * frequencies).
+ */
+struct mon_map {
+ int sense;
+ int vmode;
+} monitor_map [] = {
+ {0x000, VMODE_1280_1024_75}, /* 21" RGB */
+ {0x114, VMODE_640_870_75P}, /* Portrait Monochrome */
+ {0x221, VMODE_512_384_60}, /* 12" RGB*/
+ {0x331, VMODE_1280_1024_75}, /* 21" RGB (Radius) */
+ {0x334, VMODE_1280_1024_75}, /* 21" mono (Radius) */
+ {0x335, VMODE_1280_1024_75}, /* 21" mono */
+ {0x40A, VMODE_640_480_60I}, /* NTSC */
+ {0x51E, VMODE_640_870_75P}, /* Portrait RGB */
+ {0x603, VMODE_832_624_75}, /* 12"-16" multiscan */
+ {0x60b, VMODE_1024_768_70}, /* 13"-19" multiscan */
+ {0x623, VMODE_1152_870_75}, /* 13"-21" multiscan */
+ {0x62b, VMODE_640_480_67}, /* 13"/14" RGB */
+ {0x700, VMODE_640_480_50I}, /* PAL */
+ {0x714, VMODE_640_480_60I}, /* NTSC */
+ {0x717, VMODE_800_600_75}, /* VGA */
+ {0x72d, VMODE_832_624_75}, /* 16" RGB (Goldfish) */
+ {0x730, VMODE_768_576_50I}, /* PAL (Alternate) */
+ {0x73a, VMODE_1152_870_75}, /* 3rd party 19" */
+ {-1, VMODE_640_480_60}, /* catch-all, must be last */
+};
+
+int
+map_monitor_sense(int sense)
+{
+ struct mon_map *map;
+
+ for (map = monitor_map; map->sense >= 0; ++map)
+ if (map->sense == sense)
+ break;
+ return map->vmode;
+}
+
+/*
+ * Horizontal and vertical resolution for each mode.
+ */
+struct vmode_attr vmode_attrs[VMODE_MAX] = {
+ {512, 384, 60, 1},
+ {512, 384, 60},
+ {640, 480, 50, 1},
+ {640, 480, 60, 1},
+ {640, 480, 60},
+ {640, 480, 67},
+ {640, 870, 75},
+ {768, 576, 50, 1},
+ {800, 600, 56},
+ {800, 600, 60},
+ {800, 600, 72},
+ {800, 600, 75},
+ {832, 624, 75},
+ {1024, 768, 60},
+ {1024, 768, 72},
+ {1024, 768, 75},
+ {1024, 768, 75},
+ {1152, 870, 75},
+ {1280, 960, 75},
+ {1280, 1024, 75}
+};
+
+static void invert_cursor(int);
+static int map_unknown(struct device_node *);
+static void unknown_init(void);
+
+struct display_interface {
+ char *name;
+ void (*map_interface)(struct device_node *);
+ void (*init_interface)(void);
+ int (*setmode)(struct vc_mode *, int);
+ void (*set_palette)(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors);
+ void (*set_blanking)(int blank_mode);
+} displays[] = {
+ { "control", map_control_display, control_init,
+ control_setmode, control_set_palette, control_set_blanking },
+ { "platinum", map_platinum, platinum_init,
+ platinum_setmode, platinum_set_palette, platinum_set_blanking },
+ { "valkyrie", map_valkyrie_display, valkyrie_init,
+ valkyrie_setmode, valkyrie_set_palette, valkyrie_set_blanking },
+#ifdef CONFIG_ATY_VIDEO
+ { "ATY,mach64", map_aty_display, aty_init,
+ aty_setmode, aty_set_palette, aty_set_blanking },
+ { "ATY,XCLAIM", map_aty_display, aty_init,
+ aty_setmode, aty_set_palette, aty_set_blanking },
+ { "ATY,264VT", map_aty_display, aty_init,
+ aty_setmode, aty_set_palette, aty_set_blanking },
+ { "ATY,mach64ii", map_aty_display, aty_init,
+ aty_setmode, aty_set_palette, aty_set_blanking },
+#if 0 /* not right for 3D mach64 yet */
+ { "ATY,264GT-B", map_aty_display, aty_init,
+ aty_setmode, aty_set_palette, aty_set_blanking },
+ { "ATY,mach64_3D_pcc", map_aty_display, aty_init,
+ aty_setmode, aty_set_palette },
+#endif
+#endif
+#ifdef CONFIG_IMSTT_VIDEO
+ { "IMS,tt128mb", map_imstt_display, imstt_init,
+ imstt_setmode, imstt_set_palette, imstt_set_blanking },
+#endif
+ { NULL }
+};
+
+struct display_interface unknown_display = {
+ "unknown", NULL, unknown_init, NULL, NULL
+};
+
+static struct display_interface *current_display;
+
+static int cursor_pos = -1;
+static unsigned *cursor_fb; /* address of cursor pos in frame buffer */
+static unsigned cursor_bits; /* bits changed to turn cursor on */
+
+int pixel_size; /* in bytes */
+int n_scanlines; /* # of scan lines */
+int line_pitch; /* # bytes in 1 scan line */
+int row_pitch; /* # bytes in 1 row of characters */
+unsigned char *fb_start; /* addr of top left pixel of top left char */
+struct vc_mode display_info;
+
+extern int screen_initialized; /* in arch/ppc/pmac/prom.c */
+
+#define cmapsz (16*256)
+extern unsigned char vga_font[cmapsz];
+
+static inline unsigned pixel32(int currcons, int cidx)
+{
+ cidx *= 3;
+ return (palette[cidx] << 16) | (palette[cidx + 1] << 8)
+ | palette[cidx + 2];
+}
+
+static inline unsigned pixel16(int currcons, int cidx)
+{
+ unsigned p;
+
+ p = ((cidx << 10) & 0x7c00) + ((cidx << 5) & 0x03e0)
+ + (cidx & 0x1f);
+ return (p << 16) | p;
+}
+
+void
+__set_origin(unsigned short offset)
+{
+}
+
+static void
+invert_cursor(int cpos)
+{
+ int row, col;
+ int l, c, nw;
+ unsigned *fb, mask;
+ int currcons = fg_console; /* for `color', which is a macro */
+
+ if (cpos == -1) {
+ /* turning cursor off */
+ fb = cursor_fb;
+ mask = cursor_bits;
+ } else {
+ row = cpos / video_num_columns;
+ col = cpos - row * video_num_columns;
+ fb = (unsigned *) (fb_start + row * row_pitch
+ + col * pixel_size * 8);
+ switch (color_mode) {
+ case CMODE_16:
+ mask = pixel16(currcons, foreground)
+ ^ pixel16(currcons, background >> 4);
+ break;
+ default:
+ mask = (color ^ (color >> 4)) & 0xf;
+ mask |= mask << 8;
+ mask |= mask << 16;
+ break;
+ }
+ cursor_fb = fb;
+ cursor_bits = mask;
+ }
+ nw = pixel_size * 2; /* pixel_size * 8 (char width) / 4 */
+ for (l = 0; l < 16; ++l) {
+ for (c = 0; c < nw; ++c)
+ fb[c] ^= mask;
+ fb = (unsigned *) ((char *)fb + line_pitch);
+ }
+}
+
+void
+hide_cursor()
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (cursor_pos != -1) {
+ invert_cursor(-1);
+ cursor_pos = -1;
+ }
+ restore_flags(flags);
+}
+
+void
+set_cursor(int currcons)
+{
+ unsigned long flags;
+ int old_cursor;
+
+ if (currcons != fg_console || console_blanked)
+ return;
+
+ save_flags(flags);
+ cli();
+ if (!deccm) {
+ hide_cursor();
+ } else {
+ old_cursor = cursor_pos;
+ cursor_pos = (pos - video_mem_base) >> 1;
+ if (old_cursor != -1)
+ invert_cursor(-1);
+ invert_cursor(cursor_pos);
+ }
+ restore_flags(flags);
+}
+
+/*
+ * NOTE: get_scrmem() and set_scrmem() are here only because
+ * the VGA version of set_scrmem() has some direct VGA references.
+ */
+void
+get_scrmem(int currcons)
+{
+ memcpyw((unsigned short *)vc_scrbuf[currcons],
+ (unsigned short *)origin, video_screen_size);
+ origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
+ scr_end = video_mem_end = video_mem_start + video_screen_size;
+ pos = origin + y*video_size_row + (x<<1);
+}
+
+void
+set_scrmem(int currcons, long offset)
+{
+ if (video_mem_term - video_mem_base < offset + video_screen_size)
+ offset = 0;
+ memcpyw((unsigned short *)(video_mem_base + offset),
+ (unsigned short *) origin, video_screen_size);
+ video_mem_start = video_mem_base;
+ video_mem_end = video_mem_term;
+ origin = video_mem_base + offset;
+ scr_end = origin + video_screen_size;
+ pos = origin + y*video_size_row + (x<<1);
+}
+
+int
+set_get_cmap(unsigned char *p, int set)
+{
+ int i, j, err;
+
+ err = verify_area(set? VERIFY_READ: VERIFY_WRITE, p, 48);
+ if (err)
+ return err;
+
+ for (i = 0; i < 16; ++i) {
+ if (set) {
+ get_user(default_red[i], p++);
+ get_user(default_grn[i], p++);
+ get_user(default_blu[i], p++);
+ } else {
+ put_user(default_red[i], p++);
+ put_user(default_grn[i], p++);
+ put_user(default_blu[i], p++);
+ }
+ }
+
+ if (set) {
+ for (j = 0; j < MAX_NR_CONSOLES; ++j) {
+ if (!vc_cons_allocated(j))
+ continue;
+ for (i = 0; i < 16; ++i) {
+ vc_cons[j].d->vc_palette[3*i+0] = default_red[i];
+ vc_cons[j].d->vc_palette[3*i+1] = default_grn[i];
+ vc_cons[j].d->vc_palette[3*i+2] = default_blu[i];
+ }
+ }
+ set_palette();
+ }
+
+ return 0;
+}
+
+int
+set_get_font(char *p, int set, int ch512)
+{
+ return 0;
+}
+
+void
+set_palette()
+{
+ int i, j, n;
+ unsigned char red[16], green[16], blue[16];
+
+ if (console_blanked || current_display == NULL
+ || current_display->set_palette == NULL
+ || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+ return;
+
+ for (i = j = 0; i < 16; ++i) {
+ n = color_table[i] & 0xf;
+ red[n] = vc_cons[fg_console].d->vc_palette[j++];
+ green[n] = vc_cons[fg_console].d->vc_palette[j++];
+ blue[n] = vc_cons[fg_console].d->vc_palette[j++];
+ }
+ (*current_display->set_palette)(red, green, blue, 0, 16);
+}
+
+void
+pmac_init_palette()
+{
+ int i, n;
+ unsigned char red[16], green[16], blue[16];
+
+ for (i = 0; i < 16; ++i) {
+ n = color_table[i] & 0xf;
+ red[n] = default_red[i];
+ green[n] = default_grn[i];
+ blue[n] = default_blu[i];
+ }
+ (*current_display->set_palette)(red, green, blue, 0, 16);
+}
+
+static int vesa_blanking_mode;
+static int vesa_blanked;
+
+void
+vesa_blank()
+{
+ if (vesa_blanking_mode == 0 || vesa_blanked
+ || current_display == NULL
+ || current_display->set_blanking == NULL)
+ return;
+ (*current_display->set_blanking)(vesa_blanking_mode);
+ vesa_blanked = vesa_blanking_mode;
+}
+
+void
+vesa_unblank()
+{
+ if (vesa_blanked == 0
+ || current_display == NULL
+ || current_display->set_blanking == NULL)
+ return;
+ (*current_display->set_blanking)(VESA_NO_BLANKING);
+ vesa_blanked = VESA_NO_BLANKING;
+}
+
+void
+set_vesa_blanking(const unsigned long arg)
+{
+ unsigned char *argp = (unsigned char *)(arg + 1);
+ unsigned int mode;
+
+ if (verify_area(VERIFY_READ, argp, 1))
+ return;
+
+ get_user(mode, argp);
+ vesa_blanking_mode = (mode <= VESA_POWERDOWN)? mode: \
+ DEFAULT_VESA_BLANKING_MODE;
+}
+
+void
+vesa_powerdown()
+{
+ if (vesa_blanked == 0 || vesa_blanked == VESA_POWERDOWN
+ || current_display == NULL
+ || current_display->set_blanking == NULL)
+ return;
+ (*current_display->set_blanking)(VESA_POWERDOWN);
+ vesa_blanked = VESA_POWERDOWN;
+}
+
+void
+memsetw(unsigned short *p, unsigned short c, unsigned count)
+{
+ count /= 2;
+ if ((unsigned long)(p + count) > video_mem_base
+ && (unsigned long)p < video_mem_term) {
+ for (; p < (unsigned short *) video_mem_base && count != 0; --count)
+ *p++ = c;
+ for (; p < (unsigned short *) video_mem_term && count != 0; --count) {
+ if (*p != c) {
+ *p = c;
+ pmac_blitc(c, (unsigned long)p);
+ }
+ ++p;
+ }
+ }
+ for (; count != 0; --count)
+ *p++ = c;
+}
+
+void
+memcpyw(unsigned short *to, unsigned short *from, unsigned count)
+{
+ unsigned short c;
+
+ count /= 2;
+ if ((unsigned long)(to + count) > video_mem_base
+ && (unsigned long)to < video_mem_term) {
+ for (; to < (unsigned short *) video_mem_base && count != 0; --count)
+ *to++ = *from++;
+ for (; to < (unsigned short *) video_mem_term && count != 0; --count) {
+ c = *from++;
+ if (*to != c) {
+ *to = c;
+ pmac_blitc(c, (unsigned long)to);
+ }
+ ++to;
+ }
+ }
+ for (; count != 0; --count)
+ *to++ = *from++;
+}
+
+void
+pmac_find_display()
+{
+ struct display_interface *disp;
+ struct device_node *dp;
+ struct vmode_attr *ap;
+
+ current_display = NULL;
+ if (serial_console)
+ return;
+ for (disp = displays; disp->name != NULL; ++disp) {
+ dp = find_devices(disp->name);
+ if (dp == 0)
+ continue;
+ current_display = disp;
+ disp->map_interface(dp);
+ break;
+ }
+
+ if (current_display == NULL) {
+ /*
+ * We haven't found a display that we know about,
+ * but if there is a display with sufficient prom support,
+ * we may be able to use it in a limited fashion.
+ * If there is, it has already been opened in prom_init().
+ */
+ if (prom_display_path[0] != 0) {
+ dp = find_path_device(prom_display_path);
+ if (dp != 0 && map_unknown(dp))
+ current_display = &unknown_display;
+ else
+ printk(KERN_INFO "Can't use %s for display\n",
+ prom_display_path);
+ }
+ }
+
+ if (current_display == NULL
+ || video_mode <= 0 || video_mode > VMODE_MAX) {
+ printk(KERN_INFO "No usable display device found"
+ "- using serial console\n");
+ serial_console = 1; /* no screen - fall back to serial */
+ return;
+ }
+ ap = &vmode_attrs[video_mode - 1];
+ screen_info.orig_video_cols = ap->hres / 8;
+ screen_info.orig_video_lines = ap->vres / 16;
+ printk("using video mode %d (%dx%d at %dHz%s), %d bits/pixel\n",
+ video_mode, ap->hres, ap->vres, ap->vfreq,
+ ap->interlaced? " interlaced": "",
+ (color_mode + 1) * 8);
+}
+
+int
+pmac_display_supported(const char *name)
+{
+ struct display_interface *disp;
+
+ for (disp = displays; disp->name != NULL; ++disp)
+ if (strcmp(name, disp->name) == 0)
+ return 1;
+ return 0;
+}
+
+int
+console_getmode(struct vc_mode *mode)
+{
+ *mode = display_info;
+ return 0;
+}
+
+int
+console_setmode(struct vc_mode *mode, int doit)
+{
+ int err;
+
+ if (current_display == NULL || current_display->setmode == NULL)
+ return -EINVAL;
+ err = (*current_display->setmode)(mode, doit);
+ if (doit && err == 0)
+ memset((void *)video_mem_base, 0, video_screen_size);
+ return err;
+}
+
+int
+console_powermode(int mode)
+{
+ if (mode == VC_POWERMODE_INQUIRY)
+ return vesa_blanked;
+ if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
+ return -EINVAL;
+ if (current_display == NULL || current_display->set_blanking == NULL)
+ return -ENXIO;
+ (*current_display->set_blanking)(mode);
+ vesa_blanked = mode;
+ return 0;
+}
+
+void
+pmac_cons_setup(char *str, int *ints)
+{
+ if (strcmp(str, "ttya") == 0 || strcmp(str, "modem") == 0)
+ serial_console = 1;
+ else if (strcmp(str, "ttyb") == 0 || strcmp(str, "printer") == 0)
+ serial_console = 2;
+}
+
+void
+pmac_vmode_setup(char *str, int *ints)
+{
+ if (ints[0] >= 1)
+ video_mode = ints[1];
+ if (ints[0] >= 2)
+ color_mode = ints[2];
+}
+
+unsigned long
+con_type_init(unsigned long mem_start, const char **type_p)
+{
+ if (current_display == NULL)
+ panic("no display available");
+ current_display->init_interface();
+ screen_initialized = 1; /* inhibits prom_print */
+ can_do_color = 1;
+ video_type = VIDEO_TYPE_PMAC;
+ *type_p = display_info.name;
+ video_mem_base = mem_start;
+ mem_start += MAX_TEXT_COLS * MAX_TEXT_ROWS * 2;
+ video_mem_term = mem_start;
+ memset((char *) video_mem_base, 0, video_screen_size);
+ return mem_start;
+}
+
+static __inline__ void
+draw_logo_8(void)
+{
+ unsigned char *fb = fb_start;
+ unsigned char *p = linux_logo;
+ int yy;
+
+ (*current_display->set_palette)
+ (linux_logo_red, linux_logo_green, linux_logo_blue,
+ 32, LINUX_LOGO_COLORS);
+
+ for (yy = 0; yy < LINUX_LOGO_HEIGHT; ++yy) {
+ memcpy(fb, p, LINUX_LOGO_WIDTH);
+ fb += line_pitch;
+ p += LINUX_LOGO_WIDTH;
+ }
+}
+
+static __inline__ void
+draw_logo_15(void)
+{
+ unsigned short *fb;
+ unsigned char *row = fb_start;
+ unsigned char *p = linux_logo;
+ int i, xx, yy;
+ unsigned char grey[16];
+
+ /*
+ * For 15-bit mode, treat the screen as a 4/4/4 TrueColor.
+ */
+ for (i = 0; i < 16; ++i)
+ grey[i] = i << 4;
+ (*current_display->set_palette)(grey, grey, grey, 16, 16);
+
+ for (yy = 0; yy < LINUX_LOGO_HEIGHT; ++yy) {
+ fb = (unsigned short *) row;
+ for (xx = 0; xx < LINUX_LOGO_WIDTH; ++xx) {
+ i = *p++ - 32;
+ *fb++ = 0x4210
+ + ((linux_logo_red[i] & 0xf0) << 6)
+ + ((linux_logo_green[i] & 0xf0) << 1)
+ + (linux_logo_blue[i] >> 4);
+ }
+ row += line_pitch;
+ }
+}
+
+static __inline__ void
+draw_logo_24(void)
+{
+ unsigned long *fb;
+ unsigned char *row = fb_start;
+ unsigned char *p = linux_logo;
+ int xx, yy, v;
+
+ (*current_display->set_palette)
+ (linux_logo_red, linux_logo_green, linux_logo_blue,
+ 32, LINUX_LOGO_COLORS);
+
+ for (yy = 0; yy < LINUX_LOGO_HEIGHT; ++yy) {
+ fb = (unsigned long *) row;
+ for (xx = 0; xx < LINUX_LOGO_WIDTH; ++xx) {
+ v = *p++;
+ v |= v << 8;
+ v |= v << 16;
+ *fb++ = v;
+ }
+ row += line_pitch;
+ }
+}
+
+void
+con_type_init_finish(void)
+{
+ char *p;
+ int c;
+ unsigned short *addr;
+ char xy[2];
+ int currcons = 0; /* for `attr', which is a macro */
+
+ if (current_display == NULL
+ || current_display->set_palette == NULL)
+ return;
+
+ switch (color_mode) {
+ case CMODE_8:
+ draw_logo_8();
+ break;
+
+ case CMODE_16:
+ draw_logo_15();
+ break;
+
+ case CMODE_32:
+ draw_logo_24();
+ break;
+ }
+ xy[0] = 0;
+ xy[1] = (LINUX_LOGO_HEIGHT + 16) / 16;
+ putconsxy(0, xy);
+
+ p = "PowerMac/Linux " UTS_RELEASE;
+ addr = (unsigned short *) video_mem_base + 2 * video_num_columns
+ + LINUX_LOGO_WIDTH / 8 + 8;
+ for (; *p; ++p) {
+ c = (attr << 8) + *p;
+ scr_writew(c, addr);
+ ++addr;
+ }
+}
+
+int
+con_adjust_height(unsigned long height)
+{
+ return -EINVAL;
+}
+
+static unsigned long expand_bits_8[16] = {
+ 0x00000000,
+ 0x000000ff,
+ 0x0000ff00,
+ 0x0000ffff,
+ 0x00ff0000,
+ 0x00ff00ff,
+ 0x00ffff00,
+ 0x00ffffff,
+ 0xff000000,
+ 0xff0000ff,
+ 0xff00ff00,
+ 0xff00ffff,
+ 0xffff0000,
+ 0xffff00ff,
+ 0xffffff00,
+ 0xffffffff
+};
+
+static unsigned long expand_bits_16[4] = {
+ 0x00000000,
+ 0x0000ffff,
+ 0xffff0000,
+ 0xffffffff
+};
+
+void
+pmac_blitc(unsigned charattr, unsigned long addr)
+{
+ int col, row, fg, bg, l, bits;
+ unsigned char *fp;
+ unsigned long *fb;
+ static int cached_row_start, cached_row_end = -1;
+ static unsigned char *cached_fb;
+ static int cached_attr = -1;
+ static unsigned long cached_fg, cached_bg;
+
+ col = (addr - video_mem_base) / 2;
+ if (cursor_pos == col)
+ cursor_pos = -1;
+ if (!(col >= cached_row_start && col < cached_row_end)) {
+ row = col / video_num_columns;
+ cached_row_start = row * video_num_columns;
+ cached_row_end = cached_row_start + video_num_columns;
+ cached_fb = fb_start + row * row_pitch;
+ }
+ fb = (unsigned long *)
+ (cached_fb + (col - cached_row_start) * pixel_size * 8);
+
+ if ((charattr & 0xff00) != cached_attr) {
+ fg = (charattr >> 8) & 0xf;
+ bg = (charattr >> 12) & 0xf;
+ switch (color_mode) {
+ case CMODE_16:
+ fg = pixel16(fg_console, fg);
+ bg = pixel16(fg_console, bg);
+ break;
+ default:
+ fg += fg << 8;
+ fg += fg << 16;
+ bg += bg << 8;
+ bg += bg << 16;
+ }
+ fg ^= bg;
+ cached_fg = fg;
+ cached_bg = bg;
+ } else {
+ fg = cached_fg;
+ bg = cached_bg;
+ }
+
+ fp = &vga_font[(charattr & 0xff) * 16];
+ switch (color_mode) {
+ case CMODE_32:
+ for (l = 0; l < 16; ++l) {
+ bits = *fp++;
+ fb[0] = (-(bits >> 7) & fg) ^ bg;
+ fb[1] = (-((bits >> 6) & 1) & fg) ^ bg;
+ fb[2] = (-((bits >> 5) & 1) & fg) ^ bg;
+ fb[3] = (-((bits >> 4) & 1) & fg) ^ bg;
+ fb[4] = (-((bits >> 3) & 1) & fg) ^ bg;
+ fb[5] = (-((bits >> 2) & 1) & fg) ^ bg;
+ fb[6] = (-((bits >> 1) & 1) & fg) ^ bg;
+ fb[7] = (-(bits & 1) & fg) ^ bg;
+ fb = (unsigned long *) ((char *)fb + line_pitch);
+ }
+ break;
+ case CMODE_16:
+ for (l = 0; l < 16; ++l) {
+ bits = *fp++;
+ fb[0] = (expand_bits_16[bits >> 6] & fg) ^ bg;
+ fb[1] = (expand_bits_16[(bits >> 4) & 3] & fg) ^ bg;
+ fb[2] = (expand_bits_16[(bits >> 2) & 3] & fg) ^ bg;
+ fb[3] = (expand_bits_16[bits & 3] & fg) ^ bg;
+ fb = (unsigned long *) ((char *)fb + line_pitch);
+ }
+ break;
+ default:
+ for (l = 0; l < 16; ++l) {
+ bits = *fp++;
+ fb[0] = (expand_bits_8[bits >> 4] & fg) ^ bg;
+ fb[1] = (expand_bits_8[bits & 0xf] & fg) ^ bg;
+ fb = (unsigned long *) ((char *)fb + line_pitch);
+ }
+ }
+}
+
+
+/*
+ * The following provides a very basic screen driver for displays
+ * that we basically don't know anything about, but which we can
+ * initialize by using their Open Firmware "open" method.
+ */
+
+static int unknown_modes[] = {
+ VMODE_512_384_60,
+ VMODE_640_480_60,
+ VMODE_800_600_60,
+ VMODE_832_624_75,
+ VMODE_1024_768_60,
+ VMODE_1152_870_75,
+ VMODE_1280_960_75,
+ VMODE_1280_1024_75,
+ 0
+};
+
+static unsigned char *frame_buffer;
+
+static int map_unknown(struct device_node *dp)
+{
+ int i, mode;
+ int width;
+ int *pp, len;
+ unsigned *up, address;
+
+ printk("map_unknown(%p), name = %s\n", dp, dp->full_name);
+
+ /* check the depth */
+ if ((pp = (int *) get_property(dp, "depth", &len)) != NULL
+ && len == sizeof(int) && *pp != 8) {
+ printk("%s: can't use depth = %d\n", dp->full_name, *pp);
+ return 0;
+ }
+
+ width = 640; /* default values */
+ n_scanlines = 480;
+ if ((pp = (int *) get_property(dp, "width", &len)) != NULL
+ && len == sizeof(int))
+ width = *pp;
+ if ((pp = (int *) get_property(dp, "height", &len)) != NULL
+ && len == sizeof(int))
+ n_scanlines = *pp;
+ line_pitch = width;
+ if ((pp = (int *) get_property(dp, "linebytes", &len)) != NULL
+ && len == sizeof(int))
+ line_pitch = *pp;
+ printk(KERN_INFO "width=%d height=%d pitch=%d\n",
+ width, n_scanlines, line_pitch);
+
+ len = n_scanlines * line_pitch;
+ if ((up = (unsigned *) get_property(dp, "address", &len)) != NULL
+ && len == sizeof(unsigned)) {
+ address = *up;
+ } else {
+ for (i = 0; i < dp->n_addrs; ++i)
+ if (dp->addrs[i].size >= len)
+ break;
+ if (i >= dp->n_addrs) {
+ printk("no framebuffer address found for %s\n",
+ dp->full_name);
+ return 0;
+ }
+ address = dp->addrs[i].address;
+ /* temporary kludge for valkyrie */
+ if (strcmp(dp->name, "valkyrie") == 0)
+ address += 0x1000;
+ }
+ printk(KERN_INFO "%s: using address %x\n", dp->full_name, address);
+ frame_buffer = ioremap(address, len);
+
+ video_mode = 0;
+ color_mode = CMODE_8;
+ pixel_size = 1;
+
+ for (i = 0; (mode = unknown_modes[i]) != 0; ++i) {
+ if (vmode_attrs[mode-1].hres <= width
+ && vmode_attrs[mode-1].vres <= n_scanlines)
+ video_mode = mode;
+ }
+ if (video_mode == 0) {
+ printk(KERN_INFO "%s: no mode found for %d x %d\n",
+ dp->full_name, width, n_scanlines);
+ return 0;
+ }
+
+ display_info.height = n_scanlines;
+ display_info.width = width;
+ display_info.depth = 8;
+ display_info.pitch = line_pitch;
+ display_info.mode = video_mode;
+ strncpy(display_info.name, dp->name, sizeof(display_info.name));
+ display_info.fb_address = (unsigned long) frame_buffer;
+ display_info.cmap_adr_address = 0;
+ display_info.cmap_data_address = 0;
+ display_info.disp_reg_address = 0;
+
+ return 1;
+}
+
+static void
+unknown_init()
+{
+ unsigned *p;
+ int i;
+
+ row_pitch = line_pitch * 16;
+ fb_start = frame_buffer;
+
+ /* Clear screen */
+ p = (unsigned *) frame_buffer;
+ for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+ *p++ = 0;
+}
+
+
+unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd,
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe,
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e,
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8,
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e,
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6,
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c,
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18,
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c,
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18,
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06,
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb,
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6,
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe,
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06,
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe,
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66,
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b,
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c,
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66,
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc,
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06,
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8,
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66,
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60,
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00,
+};
--- /dev/null
+/*
+ * Definitions for display drivers for console use on PowerMacs.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *
+ * 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.
+ */
+
+extern int serial_console; /* set to use serial port as console */
+
+/*
+ * Video mode values.
+ * These are supposed to be the same as the values that
+ * Apple uses in MacOS.
+ */
+#define VMODE_NVRAM 0 /* use value stored in nvram */
+#define VMODE_512_384_60I 1 /* 512x384, 60Hz interlaced (NTSC) */
+#define VMODE_512_384_60 2 /* 512x384, 60Hz */
+#define VMODE_640_480_50I 3 /* 640x480, 50Hz interlaced (PAL) */
+#define VMODE_640_480_60I 4 /* 640x480, 60Hz interlaced (NTSC) */
+#define VMODE_640_480_60 5 /* 640x480, 60Hz (VGA) */
+#define VMODE_640_480_67 6 /* 640x480, 67Hz */
+#define VMODE_640_870_75P 7 /* 640x870, 75Hz (portrait) */
+#define VMODE_768_576_50I 8 /* 768x576, 50Hz (PAL full frame) */
+#define VMODE_800_600_56 9 /* 800x600, 56Hz */
+#define VMODE_800_600_60 10 /* 800x600, 60Hz */
+#define VMODE_800_600_72 11 /* 800x600, 72Hz */
+#define VMODE_800_600_75 12 /* 800x600, 75Hz */
+#define VMODE_832_624_75 13 /* 832x624, 75Hz */
+#define VMODE_1024_768_60 14 /* 1024x768, 60Hz */
+#define VMODE_1024_768_70 15 /* 1024x768, 70Hz (or 72Hz?) */
+#define VMODE_1024_768_75V 16 /* 1024x768, 75Hz (VESA) */
+#define VMODE_1024_768_75 17 /* 1024x768, 75Hz */
+#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */
+#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */
+#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */
+#define VMODE_MAX 20
+#define VMODE_CHOOSE 99 /* choose based on monitor sense */
+
+/*
+ * Color mode values, used to select number of bits/pixel.
+ */
+#define CMODE_NVRAM -1 /* use value stored in nvram */
+#define CMODE_8 0 /* 8 bits/pixel */
+#define CMODE_16 1 /* 16 (actually 15) bits/pixel */
+#define CMODE_32 2 /* 32 (actually 24) bits/pixel */
+
+extern int video_mode;
+extern int color_mode;
+
+/*
+ * Addresses in NVRAM where video mode and pixel size are stored.
+ */
+#define NV_VMODE 0x140f
+#define NV_CMODE 0x1410
+
+/*
+ * Horizontal and vertical resolution information.
+ */
+extern struct vmode_attr {
+ int hres;
+ int vres;
+ int vfreq;
+ int interlaced;
+} vmode_attrs[VMODE_MAX];
+
+extern struct vc_mode display_info;
+
+#define DEFAULT_VESA_BLANKING_MODE VESA_NO_BLANKING
+
+extern int pixel_size; /* in bytes */
+extern int n_scanlines; /* # of scan lines */
+extern int line_pitch; /* # bytes in 1 scan line */
+extern int row_pitch; /* # bytes in 1 row of characters */
+extern unsigned char *fb_start; /* addr of top left pixel of top left char */
+
+/* map monitor sense value to video mode */
+extern int map_monitor_sense(int sense);
+
+void set_palette(void);
+void pmac_find_display(void);
+void vesa_blank(void);
+void vesa_unblank(void);
+void set_vesa_blanking(const unsigned long);
+void vesa_powerdown(void);
+void hide_cursor(void);
+void pmac_init_palette(void);
--- /dev/null
+/*
+ * valkyrie.c: Console support for PowerMac "valkyrie" display adaptor.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <linux/selection.h>
+#include "pmac-cons.h"
+#include "valkyrie.h"
+
+/*
+ * Structure of the registers for the Valkyrie colormap registers.
+ */
+struct cmap_regs {
+ unsigned char addr;
+ char pad1[7];
+ unsigned char lut;
+};
+
+/*
+ * Structure of the registers for the "valkyrie" display adaptor.
+ */
+#define PAD(x) char x[7]
+
+struct valkyrie_regs {
+ unsigned char mode;
+ PAD(pad0);
+ unsigned char depth;
+ PAD(pad1);
+ unsigned char status;
+ PAD(pad2);
+ unsigned char reg3;
+ PAD(pad3);
+ unsigned char intr;
+ PAD(pad4);
+ unsigned char reg5;
+ PAD(pad5);
+ unsigned char intr_enb;
+ PAD(pad6);
+ unsigned char msense;
+ PAD(pad7);
+};
+
+static void set_valkyrie_clock(unsigned char *params);
+static int read_valkyrie_sense(void);
+
+static unsigned char *frame_buffer;
+static struct cmap_regs *cmap_regs;
+static struct valkyrie_regs *disp_regs;
+
+/*
+ * Register initialization tables for the valkyrie display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ */
+struct valkyrie_regvals {
+ unsigned char mode;
+ unsigned char clock_params[3];
+ int pitch[2]; /* bytes/line, indexed by color_mode */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct valkyrie_regvals valkyrie_reg_init_15 = {
+ 15,
+ { 12, 30, 3 }, /* pixel clock = 78.12MHz for V=72.12Hz */
+ { 1024, 0 }
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct valkyrie_regvals valkyrie_reg_init_14 = {
+ 14,
+ { 15, 31, 3 }, /* pixel clock = 64.58MHz for V=59.62Hz */
+ { 1024, 0 }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct valkyrie_regvals valkyrie_reg_init_13 = {
+ 9,
+ { 23, 42, 3 }, /* pixel clock = 57.07MHz for V=74.27Hz */
+ { 832, 0 }
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct valkyrie_regvals valkyrie_reg_init_11 = {
+ 13,
+ { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */
+ { 800, 0 }
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct valkyrie_regvals valkyrie_reg_init_10 = {
+ 12,
+ { 20, 53, 2 }, /* pixel clock = 41.41MHz for V=59.78Hz */
+ { 800, 0 }
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct valkyrie_regvals valkyrie_reg_init_6 = {
+ 6,
+ { 14, 27, 2 }, /* pixel clock = 30.13MHz for V=66.43Hz */
+ { 640, 1280 }
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct valkyrie_regvals valkyrie_reg_init_5 = {
+ 11,
+ { 23, 37, 2 }, /* pixel clock = 25.14MHz for V=59.85Hz */
+ { 640, 1280 }
+};
+
+static struct valkyrie_regvals *valkyrie_reg_init[20] = {
+ NULL, NULL, NULL, NULL,
+ &valkyrie_reg_init_5,
+ &valkyrie_reg_init_6,
+ NULL, NULL, NULL,
+ &valkyrie_reg_init_10,
+ &valkyrie_reg_init_11,
+ NULL,
+ &valkyrie_reg_init_13,
+ &valkyrie_reg_init_14,
+ &valkyrie_reg_init_15,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+/*
+ * Get the monitor sense value.
+ */
+static int
+read_valkyrie_sense()
+{
+ int sense;
+
+ out_8(&disp_regs->msense, 0); /* release all lines */
+ __delay(20000);
+ sense = (in_8(&disp_regs->msense) & 0x70) << 4;
+
+ /* drive each sense line low in turn and collect the other 2 */
+ out_8(&disp_regs->msense, 4); /* drive A low */
+ __delay(20000);
+ sense |= in_8(&disp_regs->msense) & 0x30;
+ out_8(&disp_regs->msense, 2); /* drive B low */
+ __delay(20000);
+ sense |= ((in_8(&disp_regs->msense) & 0x40) >> 3)
+ | ((in_8(&disp_regs->msense) & 0x10) >> 2);
+ out_8(&disp_regs->msense, 1); /* drive C low */
+ __delay(20000);
+ sense |= (in_8(&disp_regs->msense) & 0x60) >> 5;
+
+ out_8(&disp_regs->msense, 7);
+ return sense;
+}
+
+void
+map_valkyrie_display(struct device_node *dp)
+{
+ int sense;
+ unsigned long addr;
+
+ if (dp->next != 0)
+ printk("Warning: only using first valkyrie display device\n");
+ if (dp->n_addrs != 1)
+ panic("expecting 1 address for valkyrie (got %d)", dp->n_addrs);
+
+ /* Map in frame buffer and registers */
+ addr = dp->addrs[0].address;
+ frame_buffer = ioremap(addr, 0x100000);
+ disp_regs = ioremap(addr + 0x30a000, 4096);
+ cmap_regs = ioremap(addr + 0x304000, 4096);
+
+ /* Read the monitor sense value and choose the video mode */
+ sense = read_valkyrie_sense();
+ if (video_mode == VMODE_NVRAM) {
+ video_mode = nvram_read_byte(NV_VMODE);
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || valkyrie_reg_init[video_mode-1] == 0)
+ video_mode = VMODE_CHOOSE;
+ }
+ if (video_mode == VMODE_CHOOSE)
+ video_mode = map_monitor_sense(sense);
+ if (valkyrie_reg_init[video_mode-1] == 0)
+ video_mode = VMODE_640_480_60;
+
+ /*
+ * Reduce the pixel size if we don't have enough VRAM.
+ */
+ if (color_mode == CMODE_NVRAM)
+ color_mode = nvram_read_byte(NV_CMODE);
+ if (color_mode < CMODE_8 || color_mode > CMODE_16
+ || valkyrie_reg_init[video_mode-1]->pitch[color_mode] == 0)
+ color_mode = CMODE_8;
+
+ printk("Monitor sense value = 0x%x, ", sense);
+}
+
+static void
+set_valkyrie_clock(unsigned char *params)
+{
+ struct cuda_request req;
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x50, i + 1, params[i]);
+ while (!req.got_reply)
+ cuda_poll();
+ }
+}
+
+void
+valkyrie_init()
+{
+ int i, yoff, hres;
+ unsigned *p;
+ struct valkyrie_regvals *init;
+
+ if (video_mode <= 0 || video_mode > VMODE_MAX
+ || (init = valkyrie_reg_init[video_mode-1]) == 0)
+ panic("valkyrie: display mode %d not supported", video_mode);
+ n_scanlines = vmode_attrs[video_mode-1].vres;
+ hres = vmode_attrs[video_mode-1].hres;
+ pixel_size = 1 << color_mode;
+ line_pitch = init->pitch[color_mode];
+ row_pitch = line_pitch * 16;
+
+ /* Reset the valkyrie */
+ out_8(&disp_regs->status, 0);
+ udelay(100);
+
+ /* Initialize display timing registers */
+ out_8(&disp_regs->mode, init->mode | 0x80);
+ out_8(&disp_regs->depth, color_mode + 3);
+ set_valkyrie_clock(init->clock_params);
+ udelay(100);
+
+ pmac_init_palette(); /* Initialize colormap */
+
+ /* Turn on display */
+ out_8(&disp_regs->mode, init->mode);
+
+ yoff = (n_scanlines % 16) / 2;
+ fb_start = frame_buffer + yoff * line_pitch + 0x1000;
+
+ /* Clear screen */
+ p = (unsigned *) (frame_buffer + 0x1000);
+ for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+ *p++ = 0;
+
+ display_info.height = n_scanlines;
+ display_info.width = hres;
+ display_info.depth = pixel_size * 8;
+ display_info.pitch = line_pitch;
+ display_info.mode = video_mode;
+ strncpy(display_info.name, "valkyrie", sizeof(display_info.name));
+ display_info.fb_address = (unsigned long) frame_buffer + 0x1000;
+ display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
+ display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
+ display_info.disp_reg_address = (unsigned long) &disp_regs;
+}
+
+int
+valkyrie_setmode(struct vc_mode *mode, int doit)
+{
+ int cmode;
+
+ switch (mode->depth) {
+ case 16:
+ cmode = CMODE_16;
+ break;
+ case 8:
+ case 0: /* (default) */
+ cmode = CMODE_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (mode->mode <= 0 || mode->mode > VMODE_MAX
+ || valkyrie_reg_init[mode->mode-1] == 0
+ || valkyrie_reg_init[mode->mode-1]->pitch[cmode] == 0)
+ return -EINVAL;
+ if (doit) {
+ video_mode = mode->mode;
+ color_mode = cmode;
+ valkyrie_init();
+ }
+ return 0;
+}
+
+void
+valkyrie_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors)
+{
+ int i;
+
+ for (i = 0; i < ncolors; ++i) {
+ out_8(&cmap_regs->addr, index + i);
+ udelay(1);
+ out_8(&cmap_regs->lut, red[i]);
+ out_8(&cmap_regs->lut, green[i]);
+ out_8(&cmap_regs->lut, blue[i]);
+ }
+}
+
+void
+valkyrie_set_blanking(int blank_mode)
+{
+ /* don't know how to do this yet */
+}
--- /dev/null
+/*
+ * Exported procedures for the "valkyrie" display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *
+ * 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.
+ */
+
+extern void map_valkyrie_display(struct device_node *);
+extern void valkyrie_init(void);
+extern int valkyrie_setmode(struct vc_mode *mode, int doit);
+extern void valkyrie_set_palette(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors);
+extern void valkyrie_set_blanking(int blank_mode);
--- /dev/null
+/*
+ * Device driver for the via-cuda on Apple Powermacs.
+ *
+ * The VIA (versatile interface adapter) interfaces to the CUDA,
+ * a 6805 microprocessor core which controls the ADB (Apple Desktop
+ * Bus) which connects to the keyboard and mouse. The CUDA also
+ * controls system power and the RTC (real time clock) chip.
+ *
+ * This file also contains routines to support access to ADB
+ * devices via the /dev/adb interface.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/prom.h>
+#include <asm/cuda.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+static volatile unsigned char *via;
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS 0x200 /* skip between registers */
+#define B 0 /* B-side data */
+#define A RS /* A-side data */
+#define DIRB (2*RS) /* B-side direction (1=output) */
+#define DIRA (3*RS) /* A-side direction (1=output) */
+#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
+#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
+#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
+#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
+#define SR (10*RS) /* Shift register */
+#define ACR (11*RS) /* Auxiliary control register */
+#define PCR (12*RS) /* Peripheral control register */
+#define IFR (13*RS) /* Interrupt flag register */
+#define IER (14*RS) /* Interrupt enable register */
+#define ANH (15*RS) /* A-side data, no handshake */
+
+/* Bits in B data register: all active low */
+#define TREQ 0x08 /* Transfer request (input) */
+#define TACK 0x10 /* Transfer acknowledge (output) */
+#define TIP 0x20 /* Transfer in progress (output) */
+
+/* Bits in ACR */
+#define SR_CTRL 0x1c /* Shift register control bits */
+#define SR_EXT 0x0c /* Shift on external clock */
+#define SR_OUT 0x10 /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET 0x80 /* set bits in IER */
+#define IER_CLR 0 /* clear bits in IER */
+#define SR_INT 0x04 /* Shift register full/empty */
+
+static struct adb_handler {
+ void (*handler)(unsigned char *, int, struct pt_regs *);
+} adb_handler[16];
+
+static enum cuda_state {
+ idle,
+ sent_first_byte,
+ sending,
+ reading,
+ read_done,
+ awaiting_reply
+} cuda_state;
+
+static struct cuda_request *current_req;
+static struct cuda_request *last_req;
+static unsigned char cuda_rbuf[16];
+static unsigned char *reply_ptr;
+static int reading_reply;
+static int data_index;
+
+static int init_via(void);
+static void cuda_start(void);
+static void via_interrupt(int irq, void *arg, struct pt_regs *regs);
+static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
+
+void
+via_cuda_init()
+{
+ struct device_node *vias;
+
+ vias = find_devices("via-cuda");
+ if (vias == 0) {
+ printk(KERN_WARNING "Warning: no via-cuda\n");
+ vias = find_devices("via-pmu");
+ if (vias == 0)
+ return;
+ printk(KERN_WARNING "Found via-pmu, using it as via-cuda\n");
+ }
+ if (vias->next != 0)
+ printk("Warning: only using 1st via-cuda\n");
+
+#if 0
+ { int i;
+
+ printk("via_cuda_init: node = %p, addrs =", vias->node);
+ for (i = 0; i < vias->n_addrs; ++i)
+ printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
+ printk(", intrs =");
+ for (i = 0; i < vias->n_intrs; ++i)
+ printk(" %x", vias->intrs[i]);
+ printk("\n"); }
+#endif
+
+ if (vias->n_addrs != 1 || vias->n_intrs != 1)
+ panic("via-cuda: expecting 1 address and 1 interrupt");
+ via = (volatile unsigned char *) vias->addrs->address;
+
+ if (!init_via())
+ panic("init_via failed");
+
+ cuda_state = idle;
+
+ if (request_irq(vias->intrs[0], via_interrupt, 0, "VIA", (void *)0))
+ panic("VIA: can't get irq %d\n", vias->intrs[0]);
+
+ /* Clear and enable interrupts */
+ via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */
+ via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */
+}
+
+#define WAIT_FOR(cond, what) \
+ do { \
+ for (x = 1000; !(cond); --x) { \
+ if (x == 0) { \
+ printk("Timeout waiting for " what); \
+ return 0; \
+ } \
+ udelay(100); \
+ } \
+ } while (0)
+
+static int
+init_via()
+{
+ int x;
+
+ via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; /* TACK & TIP out */
+ via[B] |= TACK | TIP; /* negate them */
+ via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; /* SR data in */
+ eieio();
+ x = via[SR]; eieio(); /* clear any left-over data */
+ via[IER] = 0x7f; eieio(); /* disable interrupts from VIA */
+ eieio();
+
+ /* delay 4ms and then clear any pending interrupt */
+ udelay(4000);
+ x = via[SR]; eieio();
+
+ /* sync with the CUDA - assert TACK without TIP */
+ via[B] &= ~TACK; eieio();
+
+ /* wait for the CUDA to assert TREQ in response */
+ WAIT_FOR((via[B] & TREQ) == 0, "CUDA response to sync");
+
+ /* wait for the interrupt and then clear it */
+ WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (2)");
+ x = via[SR]; eieio();
+
+ /* finish the sync by negating TACK */
+ via[B] |= TACK; eieio();
+
+ /* wait for the CUDA to negate TREQ and the corresponding interrupt */
+ WAIT_FOR(via[B] & TREQ, "CUDA response to sync (3)");
+ WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (4)");
+ x = via[SR]; eieio();
+ via[B] |= TIP; eieio(); /* should be unnecessary */
+
+ return 1;
+}
+
+/* Construct and send a cuda request */
+int
+cuda_request(struct cuda_request *req, void (*done)(struct cuda_request *),
+ int nbytes, ...)
+{
+ va_list list;
+ int i;
+
+ req->nbytes = nbytes;
+ req->done = done;
+ va_start(list, nbytes);
+ for (i = 0; i < nbytes; ++i)
+ req->data[i] = va_arg(list, int);
+ va_end(list);
+ req->reply_expected = 1;
+ return cuda_send_request(req);
+}
+
+int
+cuda_send_request(struct cuda_request *req)
+{
+ unsigned long flags;
+
+ req->next = 0;
+ req->sent = 0;
+ req->got_reply = 0;
+ req->reply_len = 0;
+ save_flags(flags); cli();
+
+ if (current_req != 0) {
+ last_req->next = req;
+ last_req = req;
+ } else {
+ current_req = req;
+ last_req = req;
+ if (cuda_state == idle)
+ cuda_start();
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+static void
+cuda_start()
+{
+ unsigned long flags;
+ struct cuda_request *req;
+
+ /* assert cuda_state == idle */
+ /* get the packet to send */
+ req = current_req;
+ if (req == 0)
+ return;
+ save_flags(flags); cli();
+ if ((via[B] & TREQ) == 0) {
+ restore_flags(flags);
+ return; /* a byte is coming in from the CUDA */
+ }
+
+ /* set the shift register to shift out and send a byte */
+ via[ACR] |= SR_OUT; eieio();
+ via[SR] = req->data[0]; eieio();
+ via[B] &= ~TIP;
+ cuda_state = sent_first_byte;
+ restore_flags(flags);
+}
+
+void
+cuda_poll()
+{
+ int ie;
+
+ ie = _disable_interrupts();
+ if (via[IFR] & SR_INT)
+ via_interrupt(0, 0, 0);
+ _enable_interrupts(ie);
+}
+
+static void
+via_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+ int x, status;
+ struct cuda_request *req;
+
+ if ((via[IFR] & SR_INT) == 0)
+ return;
+
+ status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio();
+ /* printk("via_interrupt: state=%d status=%x\n", cuda_state, status); */
+ switch (cuda_state) {
+ case idle:
+ /* CUDA has sent us the first byte of data - unsolicited */
+ if (status != TREQ)
+ printk("cuda: state=idle, status=%x\n", status);
+ x = via[SR]; eieio();
+ via[B] &= ~TIP; eieio();
+ cuda_state = reading;
+ reply_ptr = cuda_rbuf;
+ reading_reply = 0;
+ break;
+
+ case awaiting_reply:
+ /* CUDA has sent us the first byte of data of a reply */
+ if (status != TREQ)
+ printk("cuda: state=awaiting_reply, status=%x\n", status);
+ x = via[SR]; eieio();
+ via[B] &= ~TIP; eieio();
+ cuda_state = reading;
+ reply_ptr = current_req->reply;
+ reading_reply = 1;
+ break;
+
+ case sent_first_byte:
+ if (status == TREQ + TIP + SR_OUT) {
+ /* collision */
+ via[ACR] &= ~SR_OUT; eieio();
+ x = via[SR]; eieio();
+ via[B] |= TIP | TACK; eieio();
+ cuda_state = idle;
+ } else {
+ /* assert status == TIP + SR_OUT */
+ if (status != TIP + SR_OUT)
+ printk("cuda: state=sent_first_byte status=%x\n", status);
+ via[SR] = current_req->data[1]; eieio();
+ via[B] ^= TACK; eieio();
+ data_index = 2;
+ cuda_state = sending;
+ }
+ break;
+
+ case sending:
+ req = current_req;
+ if (data_index >= req->nbytes) {
+ via[ACR] &= ~SR_OUT; eieio();
+ x = via[SR]; eieio();
+ via[B] |= TACK | TIP; eieio();
+ req->sent = 1;
+ if (req->reply_expected) {
+ cuda_state = awaiting_reply;
+ } else {
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ /* not sure about this */
+ cuda_state = idle;
+ cuda_start();
+ }
+ } else {
+ via[SR] = req->data[data_index++]; eieio();
+ via[B] ^= TACK; eieio();
+ }
+ break;
+
+ case reading:
+ *reply_ptr++ = via[SR]; eieio();
+ if (status == TIP) {
+ /* that's all folks */
+ via[B] |= TACK | TIP; eieio();
+ cuda_state = read_done;
+ } else {
+ /* assert status == TIP | TREQ */
+ if (status != TIP + TREQ)
+ printk("cuda: state=reading status=%x\n", status);
+ via[B] ^= TACK; eieio();
+ }
+ break;
+
+ case read_done:
+ x = via[SR]; eieio();
+ if (reading_reply) {
+ req = current_req;
+ req->reply_len = reply_ptr - req->reply;
+ req->got_reply = 1;
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ } else {
+ cuda_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+ }
+ if (status == TREQ) {
+ via[B] &= ~TIP; eieio();
+ cuda_state = reading;
+ reply_ptr = cuda_rbuf;
+ reading_reply = 0;
+ } else {
+ cuda_state = idle;
+ cuda_start();
+ }
+ break;
+
+ default:
+ printk("via_interrupt: unknown cuda_state %d?\n", cuda_state);
+ }
+}
+
+static void
+cuda_input(unsigned char *buf, int nb, struct pt_regs *regs)
+{
+ int i, id;
+ static int dump_cuda_input = 0;
+
+ switch (buf[0]) {
+ case ADB_PACKET:
+ id = buf[2] >> 4;
+ if (dump_cuda_input) {
+ printk(KERN_INFO "adb packet: ");
+ for (i = 0; i < nb; ++i)
+ printk(" %x", buf[i]);
+ printk(", id = %d\n", id);
+ }
+ if (adb_handler[id].handler != 0) {
+ (*adb_handler[id].handler)(buf, nb, regs);
+ }
+ break;
+
+ default:
+ printk("data from cuda (%d bytes):", nb);
+ for (i = 0; i < nb; ++i)
+ printk(" %.2x", buf[i]);
+ printk("\n");
+ }
+}
+
+/* Ultimately this should return the number of devices with
+ the given default id. */
+int
+adb_register(int default_id,
+ void (*handler)(unsigned char *, int, struct pt_regs *))
+{
+ if (adb_handler[default_id].handler != 0)
+ panic("Two handlers for ADB device %d\n", default_id);
+ adb_handler[default_id].handler = handler;
+ return 1;
+}
--- /dev/null
+/*
+ * Network device driver for the MACE ethernet controller on
+ * Apple Powermacs. Assumes it's under a DBDMA controller.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include "mace.h"
+
+#define N_RX_RING 8
+#define N_TX_RING 6
+#define MAX_TX_ACTIVE 1
+#define NCMDS_TX 1 /* dma commands per element in tx ring */
+#define RX_BUFLEN (ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT HZ /* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR 0x80
+
+struct mace_data {
+ volatile struct mace *mace;
+ volatile struct dbdma_regs *tx_dma;
+ int tx_dma_intr;
+ volatile struct dbdma_regs *rx_dma;
+ int rx_dma_intr;
+ volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */
+ volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */
+ struct sk_buff *rx_bufs[N_RX_RING];
+ int rx_fill;
+ int rx_empty;
+ struct sk_buff *tx_bufs[N_TX_RING];
+ int tx_fill;
+ int tx_empty;
+ unsigned char maccc;
+ unsigned char tx_fullup;
+ unsigned char tx_active;
+ unsigned char tx_bad_runt;
+ struct net_device_stats stats;
+ struct timer_list tx_timeout;
+};
+
+/*
+ * Number of bytes of private data per MACE: allow enough for
+ * the rx and tx dma commands plus a branch dma command each,
+ * and another 16 bytes to allow us to align the dma command
+ * buffers on a 16 byte boundary.
+ */
+#define PRIV_BYTES (sizeof(struct mace_data) \
+ + (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
+
+static int bitrev(int);
+static int mace_open(struct device *dev);
+static int mace_close(struct device *dev);
+static int mace_xmit_start(struct sk_buff *skb, struct device *dev);
+static struct net_device_stats *mace_stats(struct device *dev);
+static void mace_set_multicast(struct device *dev);
+static void mace_reset(struct device *dev);
+static int mace_set_address(struct device *dev, void *addr);
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void mace_set_timeout(struct device *dev);
+static void mace_tx_timeout(unsigned long data);
+
+/*
+ * If we can't get a skbuff when we need it, we use this area for DMA.
+ */
+static unsigned char dummy_buf[RX_BUFLEN+2];
+
+/* Bit-reverse one byte of an ethernet hardware address. */
+static int
+bitrev(int b)
+{
+ int d = 0, i;
+
+ for (i = 0; i < 8; ++i, b >>= 1)
+ d = (d << 1) | (b & 1);
+ return d;
+}
+
+int
+mace_probe(struct device *dev)
+{
+ int j, rev;
+ struct mace_data *mp;
+ struct device_node *maces;
+ unsigned char *addr;
+
+ maces = find_devices("mace");
+ if (maces == 0)
+ return ENODEV;
+
+ do {
+ if (maces->n_addrs != 3 || maces->n_intrs != 3) {
+ printk(KERN_ERR "can't use MACE %s: expect 3 addrs and 3 intrs\n",
+ maces->full_name);
+ continue;
+ }
+
+ if (dev == NULL)
+ dev = init_etherdev(0, PRIV_BYTES);
+ else {
+ /* XXX this doesn't look right (but it's never used :-) */
+ dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL);
+ if (dev->priv == 0)
+ return -ENOMEM;
+ }
+
+ mp = (struct mace_data *) dev->priv;
+ dev->base_addr = maces->addrs[0].address;
+ mp->mace = (volatile struct mace *) maces->addrs[0].address;
+ dev->irq = maces->intrs[0];
+
+ if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) {
+ printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
+ return -EAGAIN;
+ }
+ if (request_irq(maces->intrs[1], mace_txdma_intr, 0, "MACE-txdma",
+ dev)) {
+ printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[1]);
+ return -EAGAIN;
+ }
+ if (request_irq(maces->intrs[2], mace_rxdma_intr, 0, "MACE-rxdma",
+ dev)) {
+ printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[2]);
+ return -EAGAIN;
+ }
+
+ addr = get_property(maces, "mac-address", NULL);
+ if (addr == NULL) {
+ addr = get_property(maces, "local-mac-address", NULL);
+ if (addr == NULL) {
+ printk(KERN_ERR "Can't get mac-address for MACE at %lx\n",
+ dev->base_addr);
+ return -EAGAIN;
+ }
+ }
+
+ printk(KERN_INFO "%s: MACE at", dev->name);
+ rev = addr[0] == 0 && addr[1] == 0xA0;
+ for (j = 0; j < 6; ++j) {
+ dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+ printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+ }
+ printk("\n");
+
+ mp = (struct mace_data *) dev->priv;
+ mp->maccc = ENXMT | ENRCV;
+ mp->tx_dma = (volatile struct dbdma_regs *) maces->addrs[1].address;
+ mp->tx_dma_intr = maces->intrs[1];
+ mp->rx_dma = (volatile struct dbdma_regs *) maces->addrs[2].address;
+ mp->rx_dma_intr = maces->intrs[2];
+
+ mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
+ mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
+
+ memset(&mp->stats, 0, sizeof(mp->stats));
+ memset((char *) mp->tx_cmds, 0,
+ (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
+
+ mace_reset(dev);
+
+ dev->open = mace_open;
+ dev->stop = mace_close;
+ dev->hard_start_xmit = mace_xmit_start;
+ dev->get_stats = mace_stats;
+ dev->set_multicast_list = mace_set_multicast;
+ dev->set_mac_address = mace_set_address;
+
+ ether_setup(dev);
+
+ } while ((maces = maces->next) != 0);
+
+ return 0;
+}
+
+static void mace_reset(struct device *dev)
+{
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ int i;
+
+ /* soft-reset the chip */
+ mb->biucc = SWRST; eieio();
+ udelay(100);
+
+ mb->biucc = XMTSP_64;
+ mb->imr = 0xff; /* disable all intrs for now */
+ i = mb->ir;
+ mb->maccc = 0; /* turn off tx, rx */
+ mb->utr = RTRD;
+ mb->fifocc = RCVFW_64;
+ mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
+
+ /* load up the hardware address */
+ mb->iac = ADDRCHG | PHYADDR; eieio();
+ while ((mb->iac & ADDRCHG) != 0)
+ eieio();
+ for (i = 0; i < 6; ++i) {
+ mb->padr = dev->dev_addr[i];
+ eieio();
+ }
+
+ /* clear the multicast filter */
+ mb->iac = ADDRCHG | LOGADDR; eieio();
+ while ((mb->iac & ADDRCHG) != 0)
+ eieio();
+ for (i = 0; i < 8; ++i) {
+ mb->ladrf = 0;
+ eieio();
+ }
+
+ mb->plscc = PORTSEL_GPSI + ENPLSIO;
+}
+
+static int mace_set_address(struct device *dev, void *addr)
+{
+ unsigned char *p = addr;
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ int i;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ /* load up the hardware address */
+ mb->iac = ADDRCHG | PHYADDR; eieio();
+ while ((mb->iac & ADDRCHG) != 0)
+ eieio();
+ for (i = 0; i < 6; ++i) {
+ mb->padr = dev->dev_addr[i] = p[i];
+ eieio();
+ }
+ /* note: setting ADDRCHG clears ENRCV */
+ mb->maccc = mp->maccc; eieio();
+
+ restore_flags(flags);
+ return 0;
+}
+
+static int mace_open(struct device *dev)
+{
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ volatile struct dbdma_regs *rd = mp->rx_dma;
+ volatile struct dbdma_regs *td = mp->tx_dma;
+ volatile struct dbdma_cmd *cp;
+ int i;
+ struct sk_buff *skb;
+ unsigned char *data;
+
+ /* initialize list of sk_buffs for receiving and set up recv dma */
+ memset((char *)mp->rx_cmds, 0, N_RX_RING * sizeof(struct dbdma_cmd));
+ cp = mp->rx_cmds;
+ for (i = 0; i < N_RX_RING - 1; ++i) {
+ skb = dev_alloc_skb(RX_BUFLEN + 2);
+ if (skb == 0) {
+ data = dummy_buf;
+ } else {
+ skb_reserve(skb, 2); /* so IP header lands on 4-byte bdry */
+ data = skb->data;
+ }
+ mp->rx_bufs[i] = skb;
+ st_le16(&cp->req_count, RX_BUFLEN);
+ st_le16(&cp->command, INPUT_LAST + INTR_ALWAYS);
+ st_le32(&cp->phy_addr, virt_to_bus(data));
+ cp->xfer_status = 0;
+ ++cp;
+ }
+ mp->rx_bufs[i] = 0;
+ st_le16(&cp->command, DBDMA_STOP);
+ mp->rx_fill = i;
+ mp->rx_empty = 0;
+
+ /* Put a branch back to the beginning of the receive command list */
+ ++cp;
+ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+ st_le32(&cp->cmd_dep, virt_to_bus(mp->rx_cmds));
+
+ /* start rx dma */
+ out_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+ out_le32(&rd->cmdptr, virt_to_bus(mp->rx_cmds));
+ out_le32(&rd->control, (RUN << 16) | RUN);
+
+ /* put a branch at the end of the tx command list */
+ cp = mp->tx_cmds + NCMDS_TX * N_TX_RING;
+ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+ st_le32(&cp->cmd_dep, virt_to_bus(mp->tx_cmds));
+
+ /* reset tx dma */
+ out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&td->cmdptr, virt_to_bus(mp->tx_cmds));
+ mp->tx_fill = 0;
+ mp->tx_empty = 0;
+ mp->tx_fullup = 0;
+ mp->tx_active = 0;
+ mp->tx_bad_runt = 0;
+
+ /* turn it on! */
+ mb->maccc = mp->maccc; eieio();
+ /* enable all interrupts except receive interrupts */
+ mb->imr = RCVINT; eieio();
+ return 0;
+}
+
+static int mace_close(struct device *dev)
+{
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ volatile struct dbdma_regs *rd = mp->rx_dma;
+ volatile struct dbdma_regs *td = mp->tx_dma;
+ int i;
+
+ /* disable rx and tx */
+ mb->maccc = 0;
+ mb->imr = 0xff; /* disable all intrs */
+
+ /* disable rx and tx dma */
+ st_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+ st_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+
+ /* free some skb's */
+ for (i = 0; i < N_RX_RING; ++i) {
+ if (mp->rx_bufs[i] != 0) {
+ dev_kfree_skb(mp->rx_bufs[i], FREE_READ);
+ mp->rx_bufs[i] = 0;
+ }
+ }
+ for (i = mp->tx_empty; i != mp->tx_fill; ) {
+ dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+ if (++i >= N_TX_RING)
+ i = 0;
+ }
+
+ return 0;
+}
+
+static inline void mace_set_timeout(struct device *dev)
+{
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+
+ mp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+ mp->tx_timeout.function = mace_tx_timeout;
+ mp->tx_timeout.data = (unsigned long) dev;
+ add_timer(&mp->tx_timeout);
+}
+
+static int mace_xmit_start(struct sk_buff *skb, struct device *dev)
+{
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct dbdma_regs *td = mp->tx_dma;
+ volatile struct dbdma_cmd *cp, *np;
+ unsigned long flags;
+ int fill, next, len;
+
+ /* see if there's a free slot in the tx ring */
+ save_flags(flags); cli();
+ fill = mp->tx_fill;
+ next = fill + 1;
+ if (next >= N_TX_RING)
+ next = 0;
+ if (next == mp->tx_empty) {
+ dev->tbusy = 1;
+ mp->tx_fullup = 1;
+ restore_flags(flags);
+ return -1; /* can't take it at the moment */
+ }
+ restore_flags(flags);
+
+ /* partially fill in the dma command block */
+ len = skb->len;
+ if (len > ETH_FRAME_LEN) {
+ printk(KERN_DEBUG "mace: xmit frame too long (%d)\n", len);
+ len = ETH_FRAME_LEN;
+ }
+ mp->tx_bufs[fill] = skb;
+ cp = mp->tx_cmds + NCMDS_TX * fill;
+ st_le16(&cp->req_count, len);
+ st_le32(&cp->phy_addr, virt_to_bus(skb->data));
+
+ np = mp->tx_cmds + NCMDS_TX * next;
+ out_le16(&np->command, DBDMA_STOP);
+
+ /* poke the tx dma channel */
+ save_flags(flags);
+ cli();
+ mp->tx_fill = next;
+ if (!mp->tx_bad_runt && mp->tx_active < MAX_TX_ACTIVE) {
+ out_le16(&cp->xfer_status, 0);
+ out_le16(&cp->command, OUTPUT_LAST);
+ out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+ ++mp->tx_active;
+ mace_set_timeout(dev);
+ }
+ restore_flags(flags);
+
+ return 0;
+}
+
+static struct net_device_stats *mace_stats(struct device *dev)
+{
+ struct mace_data *p = (struct mace_data *) dev->priv;
+
+ return &p->stats;
+}
+
+/*
+ * CRC polynomial - used in working out multicast filter bits.
+ */
+#define CRC_POLY 0xedb88320
+
+static void mace_set_multicast(struct device *dev)
+{
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ int i, j, k, b;
+ unsigned long crc;
+
+ mp->maccc &= ~PROM;
+ if (dev->flags & IFF_PROMISC) {
+ mp->maccc |= PROM;
+ } else {
+ unsigned char multicast_filter[8];
+ struct dev_mc_list *dmi = dev->mc_list;
+
+ if (dev->flags & IFF_ALLMULTI) {
+ for (i = 0; i < 8; i++)
+ multicast_filter[i] = 0xff;
+ } else {
+ for (i = 0; i < 8; i++)
+ multicast_filter[i] = 0;
+ for (i = 0; i < dev->mc_count; i++) {
+ crc = ~0;
+ for (j = 0; j < 6; ++j) {
+ b = dmi->dmi_addr[j];
+ for (k = 0; k < 8; ++k) {
+ if ((crc ^ b) & 1)
+ crc = (crc >> 1) ^ CRC_POLY;
+ else
+ crc >>= 1;
+ b >>= 1;
+ }
+ }
+ j = crc >> 26; /* bit number in multicast_filter */
+ multicast_filter[j >> 3] |= 1 << (j & 7);
+ dmi = dmi->next;
+ }
+ }
+#if 0
+ printk("Multicast filter :");
+ for (i = 0; i < 8; i++)
+ printk("%02x ", multicast_filter[i]);
+ printk("\n");
+#endif
+
+ mb->iac = ADDRCHG | LOGADDR; eieio();
+ while ((mb->iac & ADDRCHG) != 0)
+ eieio();
+ for (i = 0; i < 8; ++i) {
+ mb->ladrf = multicast_filter[i];
+ eieio();
+ }
+ }
+ /* reset maccc */
+ mb->maccc = mp->maccc; eieio();
+}
+
+static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+{
+ volatile struct mace *mb = mp->mace;
+ static int mace_babbles, mace_jabbers;
+
+ if (intr & MPCO)
+ mp->stats.rx_missed_errors += 256;
+ mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */
+ if (intr & RNTPCO)
+ mp->stats.rx_length_errors += 256;
+ mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+ if (intr & CERR)
+ ++mp->stats.tx_heartbeat_errors;
+ if (intr & BABBLE)
+ if (mace_babbles++ < 4)
+ printk(KERN_DEBUG "mace: babbling transmitter\n");
+ if (intr & JABBER)
+ if (mace_jabbers++ < 4)
+ printk(KERN_DEBUG "mace: jabbering transceiver\n");
+}
+
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *) dev_id;
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ volatile struct dbdma_regs *td = mp->tx_dma;
+ volatile struct dbdma_cmd *cp;
+ int intr, fs, i, stat, x;
+ int xcount, dstat;
+ static int mace_last_fs, mace_last_xcount;
+
+ intr = mb->ir; /* read interrupt register */
+ mace_handle_misc_intrs(mp, intr);
+
+ i = mp->tx_empty;
+ while (mb->pr & XMTSV) {
+ /*
+ * Clear any interrupt indication associated with this status
+ * word. This appears to unlatch any error indication from
+ * the DMA controller.
+ */
+ intr = mb->ir;
+ if (intr != 0)
+ mace_handle_misc_intrs(mp, intr);
+ if (mp->tx_bad_runt) {
+ fs = mb->xmtfs;
+ eieio();
+ mp->tx_bad_runt = 0;
+ mb->xmtfc = AUTO_PAD_XMIT;
+ del_timer(&mp->tx_timeout);
+ continue;
+ }
+ dstat = ld_le32(&td->status);
+ /* stop DMA controller */
+ out_le32(&td->control, RUN << 16);
+ /*
+ * xcount is the number of complete frames which have been
+ * written to the fifo but for which status has not been read.
+ */
+ xcount = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK;
+ if (xcount == 0 || (dstat & DEAD)) {
+ /*
+ * If a packet was aborted before the DMA controller has
+ * finished transferring it, it seems that there are 2 bytes
+ * which are stuck in some buffer somewhere. These will get
+ * transmitted as soon as we read the frame status (which
+ * reenables the transmit data transfer request). Turning
+ * off the DMA controller and/or resetting the MACE doesn't
+ * help. So we disable auto-padding and FCS transmission
+ * so the two bytes will only be a runt packet which should
+ * be ignored by other stations.
+ */
+ mb->xmtfc = DXMTFCS;
+ eieio();
+ }
+ fs = mb->xmtfs;
+ if ((fs & XMTSV) == 0) {
+ printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat);
+ }
+ cp = mp->tx_cmds + NCMDS_TX * i;
+ stat = ld_le16(&cp->xfer_status);
+ if ((fs & (UFLO|LCOL|LCAR|RTRY)) || (dstat & DEAD) || xcount == 0) {
+ /*
+ * Check whether there were in fact 2 bytes written to
+ * the transmit FIFO.
+ */
+ x = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK;
+ if (x != 0) {
+ /* there were two bytes with an end-of-packet indication */
+ mp->tx_bad_runt = 1;
+ mace_set_timeout(dev);
+ } else {
+ /*
+ * Either there weren't the two bytes buffered up, or they
+ * didn't have an end-of-packet indication. Maybe we ought
+ * to flush the transmit FIFO just in case (by setting the
+ * XMTFWU bit with the transmitter disabled).
+ */
+ mb->xmtfc = AUTO_PAD_XMIT;
+ eieio();
+ }
+ }
+ /* dma should have finished */
+ if (i == mp->tx_fill) {
+ printk(KERN_DEBUG "mace: tx ring ran out? (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat);
+ continue;
+ }
+ /* Update stats */
+ if (fs & (UFLO|LCOL|LCAR|RTRY)) {
+ ++mp->stats.tx_errors;
+ if (fs & LCAR)
+ ++mp->stats.tx_carrier_errors;
+ if (fs & (UFLO|LCOL|RTRY))
+ ++mp->stats.tx_aborted_errors;
+ } else
+ ++mp->stats.tx_packets;
+ dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+ --mp->tx_active;
+ if (++i >= N_TX_RING)
+ i = 0;
+ mace_last_fs = fs;
+ mace_last_xcount = xcount;
+ del_timer(&mp->tx_timeout);
+ }
+
+ mp->tx_empty = i;
+ i += mp->tx_active;
+ if (i >= N_TX_RING)
+ i -= N_TX_RING;
+ if (i != mp->tx_fill && mp->tx_fullup) {
+ mp->tx_fullup = 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+ if (!mp->tx_bad_runt && i != mp->tx_fill && mp->tx_active < MAX_TX_ACTIVE) {
+ do {
+ /* set up the next one */
+ cp = mp->tx_cmds + NCMDS_TX * i;
+ out_le16(&cp->xfer_status, 0);
+ out_le16(&cp->command, OUTPUT_LAST);
+ ++mp->tx_active;
+ if (++i >= N_TX_RING)
+ i = 0;
+ } while (i != mp->tx_fill && mp->tx_active < MAX_TX_ACTIVE);
+ out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+ mace_set_timeout(dev);
+ }
+}
+
+static void mace_tx_timeout(unsigned long data)
+{
+ struct device *dev = (struct device *) data;
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ volatile struct dbdma_regs *td = mp->tx_dma;
+ volatile struct dbdma_regs *rd = mp->rx_dma;
+ volatile struct dbdma_cmd *cp;
+ unsigned long flags;
+ int i;
+
+ save_flags(flags);
+ cli();
+ if (mp->tx_active == 0 && !mp->tx_bad_runt)
+ goto out;
+
+ /* update various counters */
+ mace_handle_misc_intrs(mp, mb->ir);
+
+ cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
+ printk(KERN_DEBUG "mace: tx dmastat=%x %x bad_runt=%d pr=%x fs=%x fc=%x\n",
+ ld_le32(&td->status), ld_le16(&cp->xfer_status), mp->tx_bad_runt,
+ mb->pr, mb->xmtfs, mb->fifofc);
+
+ /* turn off both tx and rx and reset the chip */
+ mb->maccc = 0;
+ out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ printk(KERN_ERR "mace: transmit timeout - resetting\n");
+ mace_reset(dev);
+
+ /* restart rx dma */
+ cp = bus_to_virt(ld_le32(&rd->cmdptr));
+ out_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le16(&cp->xfer_status, 0);
+ out_le32(&rd->cmdptr, virt_to_bus(cp));
+ out_le32(&rd->control, (RUN << 16) | RUN);
+
+ /* fix up the transmit side */
+ i = mp->tx_empty;
+ mp->tx_active = 0;
+ ++mp->stats.tx_errors;
+ if (mp->tx_bad_runt) {
+ mp->tx_bad_runt = 0;
+ } else if (i != mp->tx_fill) {
+ dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+ if (++i >= N_TX_RING)
+ i = 0;
+ mp->tx_empty = i;
+ }
+ if (mp->tx_fullup) {
+ mp->tx_fullup = 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+ if (i != mp->tx_fill) {
+ cp = mp->tx_cmds + NCMDS_TX * i;
+ out_le16(&cp->xfer_status, 0);
+ out_le16(&cp->command, OUTPUT_LAST);
+ out_le32(&td->cmdptr, virt_to_bus(cp));
+ out_le32(&td->control, (RUN << 16) | RUN);
+ ++mp->tx_active;
+ mace_set_timeout(dev);
+ }
+
+ /* turn it back on */
+ out_8(&mb->imr, RCVINT);
+ out_8(&mb->maccc, mp->maccc);
+
+out:
+ restore_flags(flags);
+}
+
+static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *) dev_id;
+ struct mace_data *mp = (struct mace_data *) dev->priv;
+ volatile struct dbdma_regs *rd = mp->rx_dma;
+ volatile struct dbdma_cmd *cp, *np;
+ int i, nb, stat, next;
+ struct sk_buff *skb;
+ unsigned frame_status;
+ static int mace_lost_status;
+ unsigned char *data;
+
+ for (i = mp->rx_empty; i != mp->rx_fill; ) {
+ cp = mp->rx_cmds + i;
+ stat = ld_le16(&cp->xfer_status);
+ if ((stat & ACTIVE) == 0) {
+ next = i + 1;
+ if (next >= N_RX_RING)
+ next = 0;
+ np = mp->rx_cmds + next;
+ if (next != mp->rx_fill
+ && (ld_le16(&np->xfer_status) & ACTIVE) != 0) {
+ printk(KERN_DEBUG "mace: lost a status word\n");
+ ++mace_lost_status;
+ } else
+ break;
+ }
+ nb = ld_le16(&cp->req_count) - ld_le16(&cp->res_count);
+ out_le16(&cp->command, DBDMA_STOP);
+ /* got a packet, have a look at it */
+ skb = mp->rx_bufs[i];
+ if (skb == 0) {
+ ++mp->stats.rx_dropped;
+ } else if (nb > 8) {
+ data = skb->data;
+ frame_status = (data[nb-3] << 8) + data[nb-4];
+ if (frame_status & (RS_OFLO|RS_CLSN|RS_FRAMERR|RS_FCSERR)) {
+ ++mp->stats.rx_errors;
+ if (frame_status & RS_OFLO)
+ ++mp->stats.rx_over_errors;
+ if (frame_status & RS_FRAMERR)
+ ++mp->stats.rx_frame_errors;
+ if (frame_status & RS_FCSERR)
+ ++mp->stats.rx_crc_errors;
+ } else {
+ nb -= 8;
+ skb_put(skb, nb);
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ mp->rx_bufs[i] = 0;
+ ++mp->stats.rx_packets;
+ }
+ } else {
+ ++mp->stats.rx_errors;
+ ++mp->stats.rx_length_errors;
+ }
+
+ /* advance to next */
+ if (++i >= N_RX_RING)
+ i = 0;
+ }
+ mp->rx_empty = i;
+
+ i = mp->rx_fill;
+ for (;;) {
+ next = i + 1;
+ if (next >= N_RX_RING)
+ next = 0;
+ if (next == mp->rx_empty)
+ break;
+ cp = mp->rx_cmds + i;
+ skb = mp->rx_bufs[i];
+ if (skb == 0) {
+ skb = dev_alloc_skb(RX_BUFLEN + 2);
+ if (skb != 0) {
+ skb_reserve(skb, 2);
+ mp->rx_bufs[i] = skb;
+ }
+ }
+ st_le16(&cp->req_count, RX_BUFLEN);
+ data = skb? skb->data: dummy_buf;
+ st_le32(&cp->phy_addr, virt_to_bus(data));
+ out_le16(&cp->xfer_status, 0);
+ out_le16(&cp->command, INPUT_LAST + INTR_ALWAYS);
+#if 0
+ if ((ld_le32(&rd->status) & ACTIVE) != 0) {
+ out_le32(&rd->control, (PAUSE << 16) | PAUSE);
+ while ((in_le32(&rd->status) & ACTIVE) != 0)
+ ;
+ }
+#endif
+ i = next;
+ }
+ if (i != mp->rx_fill) {
+ out_le32(&rd->control, ((RUN|WAKE) << 16) | (RUN|WAKE));
+ mp->rx_fill = i;
+ }
+}
--- /dev/null
+/*
+ * mace.h - definitions for the registers in the Am79C940 MACE
+ * (Medium Access Control for Ethernet) controller.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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.
+ */
+
+#define REG(x) volatile unsigned char x; char x ## _pad[15]
+
+struct mace {
+ REG(rcvfifo); /* receive FIFO */
+ REG(xmtfifo); /* transmit FIFO */
+ REG(xmtfc); /* transmit frame control */
+ REG(xmtfs); /* transmit frame status */
+ REG(xmtrc); /* transmit retry count */
+ REG(rcvfc); /* receive frame control */
+ REG(rcvfs); /* receive frame status (4 bytes) */
+ REG(fifofc); /* FIFO frame count */
+ REG(ir); /* interrupt register */
+ REG(imr); /* interrupt mask register */
+ REG(pr); /* poll register */
+ REG(biucc); /* bus interface unit config control */
+ REG(fifocc); /* FIFO configuration control */
+ REG(maccc); /* medium access control config control */
+ REG(plscc); /* phys layer signalling config control */
+ REG(phycc); /* physical configuration control */
+ REG(chipid_lo); /* chip ID, lsb */
+ REG(chipid_hi); /* chip ID, msb */
+ REG(iac); /* internal address config */
+ REG(reg19);
+ REG(ladrf); /* logical address filter (8 bytes) */
+ REG(padr); /* physical address (6 bytes) */
+ REG(reg22);
+ REG(reg23);
+ REG(mpc); /* missed packet count (clears when read) */
+ REG(reg25);
+ REG(rntpc); /* runt packet count (clears when read) */
+ REG(rcvcc); /* recv collision count (clears when read) */
+ REG(reg28);
+ REG(utr); /* user test reg */
+ REG(reg30);
+ REG(reg31);
+};
+
+/* Bits in XMTFC */
+#define DRTRY 0x80 /* don't retry transmission after collision */
+#define DXMTFCS 0x08 /* don't append FCS to transmitted frame */
+#define AUTO_PAD_XMIT 0x01 /* auto-pad short packets on transmission */
+
+/* Bits in XMTFS: only valid when XMTSV is set in PR and XMTFS */
+#define XMTSV 0x80 /* transmit status (i.e. XMTFS) valid */
+#define UFLO 0x40 /* underflow - xmit fifo ran dry */
+#define LCOL 0x20 /* late collision (transmission aborted) */
+#define MORE 0x10 /* 2 or more retries needed to xmit frame */
+#define ONE 0x08 /* 1 retry needed to xmit frame */
+#define DEFER 0x04 /* MACE had to defer xmission (enet busy) */
+#define LCAR 0x02 /* loss of carrier (transmission aborted) */
+#define RTRY 0x01 /* too many retries (transmission aborted) */
+
+/* Bits in XMTRC: only valid when XMTSV is set in PR (and XMTFS) */
+#define EXDEF 0x80 /* had to defer for excessive time */
+#define RETRY_MASK 0x0f /* number of retries (0 - 15) */
+
+/* Bits in RCVFC */
+#define LLRCV 0x08 /* low latency receive: early DMA request */
+#define M_RBAR 0x04 /* sets function of EAM/R pin */
+#define AUTO_STRIP_RCV 0x01 /* auto-strip short LLC frames on recv */
+
+/*
+ * Bits in RCVFS. After a frame is received, four bytes of status
+ * are automatically read from this register and appended to the frame
+ * data in memory. These are:
+ * Byte 0 and 1: message byte count and frame status
+ * Byte 2: runt packet count
+ * Byte 3: receive collision count
+ */
+#define RS_OFLO 0x8000 /* receive FIFO overflowed */
+#define RS_CLSN 0x4000 /* received frame suffered (late) collision */
+#define RS_FRAMERR 0x2000 /* framing error flag */
+#define RS_FCSERR 0x1000 /* frame had FCS error */
+#define RS_COUNT 0x0fff /* mask for byte count field */
+
+/* Bits (fields) in FIFOFC */
+#define RCVFC_SH 4 /* receive frame count in FIFO */
+#define RCVFC_MASK 0x0f
+#define XMTFC_SH 0 /* transmit frame count in FIFO */
+#define XMTFC_MASK 0x0f
+
+/*
+ * Bits in IR and IMR. The IR clears itself when read.
+ * Setting a bit in the IMR will disable the corresponding interrupt.
+ */
+#define JABBER 0x80 /* jabber error - 10baseT xmission too long */
+#define BABBLE 0x40 /* babble - xmitter xmitting for too long */
+#define CERR 0x20 /* collision err - no SQE test (heartbeat) */
+#define RCVCCO 0x10 /* RCVCC overflow */
+#define RNTPCO 0x08 /* RNTPC overflow */
+#define MPCO 0x04 /* MPC overflow */
+#define RCVINT 0x02 /* receive interrupt */
+#define XMTINT 0x01 /* transmitter interrupt */
+
+/* Bits in PR */
+#define XMTSV 0x80 /* XMTFS valid (same as in XMTFS) */
+#define TDTREQ 0x40 /* set when xmit fifo is requesting data */
+#define RDTREQ 0x20 /* set when recv fifo requests data xfer */
+
+/* Bits in BIUCC */
+#define BSWP 0x40 /* byte swap, i.e. big-endian bus */
+#define XMTSP_4 0x00 /* start xmitting when 4 bytes in FIFO */
+#define XMTSP_16 0x10 /* start xmitting when 16 bytes in FIFO */
+#define XMTSP_64 0x20 /* start xmitting when 64 bytes in FIFO */
+#define XMTSP_112 0x30 /* start xmitting when 112 bytes in FIFO */
+#define SWRST 0x01 /* software reset */
+
+/* Bits in FIFOCC */
+#define XMTFW_8 0x00 /* xmit fifo watermark = 8 words free */
+#define XMTFW_16 0x40 /* 16 words free */
+#define XMTFW_32 0x80 /* 32 words free */
+#define RCVFW_16 0x00 /* recv fifo watermark = 16 bytes avail */
+#define RCVFW_32 0x10 /* 32 bytes avail */
+#define RCVFW_64 0x20 /* 64 bytes avail */
+#define XMTFWU 0x08 /* xmit fifo watermark update enable */
+#define RCVFWU 0x04 /* recv fifo watermark update enable */
+#define XMTBRST 0x02 /* enable transmit burst mode */
+#define RCVBRST 0x01 /* enable receive burst mode */
+
+/* Bits in MACCC */
+#define PROM 0x80 /* promiscuous mode */
+#define DXMT2PD 0x40 /* disable xmit two-part deferral algorithm */
+#define EMBA 0x20 /* enable modified backoff algorithm */
+#define DRCVPA 0x08 /* disable receiving physical address */
+#define DRCVBC 0x04 /* disable receiving broadcasts */
+#define ENXMT 0x02 /* enable transmitter */
+#define ENRCV 0x01 /* enable receiver */
+
+/* Bits in PLSCC */
+#define XMTSEL 0x08 /* select DO+/DO- state when idle */
+#define PORTSEL_AUI 0x00 /* select AUI port */
+#define PORTSEL_10T 0x02 /* select 10Base-T port */
+#define PORTSEL_DAI 0x04 /* select DAI port */
+#define PORTSEL_GPSI 0x06 /* select GPSI port */
+#define ENPLSIO 0x01 /* enable optional PLS I/O pins */
+
+/* Bits in PHYCC */
+#define LNKFL 0x80 /* reports 10Base-T link failure */
+#define DLNKTST 0x40 /* disable 10Base-T link test */
+#define REVPOL 0x20 /* 10Base-T receiver polarity reversed */
+#define DAPC 0x10 /* disable auto receiver polarity correction */
+#define LRT 0x08 /* low receive threshold for long links */
+#define ASEL 0x04 /* auto-select AUI or 10Base-T port */
+#define RWAKE 0x02 /* remote wake function */
+#define AWAKE 0x01 /* auto wake function */
+
+/* Bits in IAC */
+#define ADDRCHG 0x80 /* request address change */
+#define PHYADDR 0x04 /* access physical address */
+#define LOGADDR 0x02 /* access multicast filter */
+
+/* Bits in UTR */
+#define RTRE 0x80 /* reserved test register enable. DON'T SET. */
+#define RTRD 0x40 /* reserved test register disable. Sticky */
+#define RPA 0x20 /* accept runt packets */
+#define FCOLL 0x10 /* force collision */
+#define RCVFCSE 0x08 /* receive FCS enable */
+#define LOOP_NONE 0x00 /* no loopback */
+#define LOOP_EXT 0x02 /* external loopback */
+#define LOOP_INT 0x04 /* internal loopback, excludes MENDEC */
+#define LOOP_MENDEC 0x06 /* internal loopback, includes MENDEC */
-/* $Id: creator.c,v 1.8 1997/07/22 06:14:12 davem Exp $
+/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $
* creator.c: Creator/Creator3D frame buffer driver
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
-/* $Id: tcx.c,v 1.18 1997/07/22 06:14:09 davem Exp $
+/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $
* tcx.c: SUNW,tcx 24/8bit frame buffer driver
*
* Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
-/* $Id: weitek.c,v 1.15 1997/07/22 06:14:11 davem Exp $
+/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $
* weitek.c: Tadpole P9100/P9000 console driver
*
* Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
fi
dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI
+if [ "$CONFIG_SCSI_MESH" != "n" ]; then
+ int ' maximum synchronous transfer rate (MB/s) (0 = async)' CONFIG_SCSI_MESH_SYNC_RATE 5
+fi
+dep_tristate '53C94 (Power Mac external SCSI) support' CONFIG_SCSI_MAC53C94 $CONFIG_SCSI
endmenu
endif
endif
+ifeq ($(CONFIG_SCSI_MESH),y)
+L_OBJS += mesh.o
+else
+ ifeq ($(CONFIG_SCSI_MESH),m)
+ M_OBJS += mesh.o
+ endif
+endif
+
+ifeq ($(CONFIG_SCSI_MAC53C94),y)
+L_OBJS += mac53c94.o
+else
+ ifeq ($(CONFIG_SCSI_MAC53C94),m)
+ M_OBJS += mac53c94.o
+ endif
+endif
+
ifeq ($(CONFIG_SCSI_DEBUG),y)
L_OBJS += scsi_debug.o
else
#include "ide-scsi.h"
#endif
+#ifdef CONFIG_SCSI_MESH
+#include "mesh.h"
+#endif
+
+#ifdef CONFIG_SCSI_MAC53C94
+#include "mac53c94.h"
+#endif
+
#ifdef CONFIG_SCSI_DEBUG
#include "scsi_debug.h"
#endif
#ifdef CONFIG_BLK_DEV_IDESCSI
IDESCSI,
#endif
+#ifdef CONFIG_SCSI_MESH
+ SCSI_MESH,
+#endif
+#ifdef CONFIG_SCSI_MAC53C94
+ SCSI_MAC53C94,
+#endif
#ifdef CONFIG_SCSI_DEBUG
SCSI_DEBUG,
#endif
--- /dev/null
+/*
+ * SCSI low-level driver for the 53c94 SCSI bus adaptor found
+ * on Power Macintosh computers, controlling the external SCSI chain.
+ * We assume the 53c94 is connected to a DBDMA (descriptor-based DMA)
+ * controller.
+ *
+ * Paul Mackerras, August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "mac53c94.h"
+
+struct proc_dir_entry proc_scsi_mac53c94 = {
+ PROC_SCSI_53C94, 5, "53c94",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+enum fsc_phase {
+ idle,
+ selecting,
+ dataing,
+ completing,
+ busfreeing,
+};
+
+struct fsc_state {
+ volatile struct mac53c94_regs *regs;
+ int intr;
+ volatile struct dbdma_regs *dma;
+ int dmaintr;
+ int clk_freq;
+ struct Scsi_Host *host;
+ struct fsc_state *next;
+ Scsi_Cmnd *request_q;
+ Scsi_Cmnd *request_qtail;
+ Scsi_Cmnd *current_req; /* req we're currently working on */
+ enum fsc_phase phase; /* what we're currently trying to do */
+ struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */
+};
+
+static struct fsc_state *all_53c94s;
+
+static void mac53c94_init(struct fsc_state *);
+static void mac53c94_start(struct fsc_state *);
+static void mac53c94_interrupt(int, void *, struct pt_regs *);
+static void cmd_done(struct fsc_state *, int result);
+static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *);
+static int data_goes_out(Scsi_Cmnd *);
+
+int
+mac53c94_detect(Scsi_Host_Template *tp)
+{
+ struct device_node *node;
+ int nfscs;
+ struct fsc_state *state, **prev_statep;
+ struct Scsi_Host *host;
+ void *dma_cmd_space;
+ unsigned char *clkprop;
+ int proplen;
+
+ nfscs = 0;
+ prev_statep = &all_53c94s;
+ for (node = find_devices("53c94"); node != 0; node = node->next) {
+ if (node->n_addrs != 2 || node->n_intrs != 2)
+ panic("53c94: expected 2 addrs and intrs (got %d/%d)",
+ node->n_addrs, node->n_intrs);
+ host = scsi_register(tp, sizeof(struct fsc_state));
+ if (host == 0)
+ panic("couldn't register 53c94 host");
+ host->unique_id = nfscs;
+ note_scsi_host(node, host);
+
+ state = (struct fsc_state *) host->hostdata;
+ if (state == 0)
+ panic("no 53c94 state");
+ state->host = host;
+ state->regs = (volatile struct mac53c94_regs *)
+ node->addrs[0].address;
+ state->intr = node->intrs[0];
+ state->dma = (volatile struct dbdma_regs *)
+ node->addrs[1].address;
+ state->dmaintr = node->intrs[1];
+
+ clkprop = get_property(node, "clock-frequency", &proplen);
+ if (clkprop == NULL || proplen != sizeof(int)) {
+ printk(KERN_ERR "%s: can't get clock frequency\n",
+ node->full_name);
+ state->clk_freq = 25000000;
+ } else
+ state->clk_freq = *(int *)clkprop;
+
+ /* Space for dma command list: +1 for stop command,
+ +1 to allow for aligning. */
+ dma_cmd_space = kmalloc((host->sg_tablesize + 2) *
+ sizeof(struct dbdma_cmd), GFP_KERNEL);
+ if (dma_cmd_space == 0)
+ panic("53c94: couldn't allocate dma command space");
+ state->dma_cmds = (struct dbdma_cmd *)
+ DBDMA_ALIGN(dma_cmd_space);
+ memset(state->dma_cmds, 0, (host->sg_tablesize + 1)
+ * sizeof(struct dbdma_cmd));
+
+ *prev_statep = state;
+ prev_statep = &state->next;
+
+ if (request_irq(state->intr, mac53c94_interrupt, 0,
+ "53C94", state)) {
+ printk(KERN_ERR "mac53C94: can't get irq %d\n", state->intr);
+ }
+
+ mac53c94_init(state);
+
+ ++nfscs;
+ }
+ return nfscs;
+}
+
+int
+mac53c94_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+ unsigned long flags;
+ struct fsc_state *state;
+
+#if 0
+ if (data_goes_out(cmd)) {
+ int i;
+ printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd);
+ for (i = 0; i < cmd->cmd_len; ++i)
+ printk(" %.2x", cmd->cmnd[i]);
+ printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
+ cmd->use_sg, cmd->request_bufflen, cmd->request_buffer);
+ }
+#endif
+
+ cmd->scsi_done = done;
+ cmd->host_scribble = NULL;
+
+ state = (struct fsc_state *) cmd->host->hostdata;
+
+ save_flags(flags);
+ cli();
+ if (state->request_q == NULL)
+ state->request_q = cmd;
+ else
+ state->request_qtail->host_scribble = (void *) cmd;
+ state->request_qtail = cmd;
+
+ if (state->phase == idle)
+ mac53c94_start(state);
+
+ restore_flags(flags);
+ return 0;
+}
+
+int
+mac53c94_abort(Scsi_Cmnd *cmd)
+{
+ return SCSI_ABORT_SNOOZE;
+}
+
+int
+mac53c94_reset(Scsi_Cmnd *cmd, unsigned how)
+{
+ struct fsc_state *state = (struct fsc_state *) cmd->host->hostdata;
+ volatile struct mac53c94_regs *regs = state->regs;
+ volatile struct dbdma_regs *dma = state->dma;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ st_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ regs->command = CMD_SCSI_RESET; /* assert RST */
+ eieio();
+ udelay(100); /* leave it on for a while (>= 25us) */
+ regs->command = CMD_RESET;
+ eieio();
+ udelay(20);
+ mac53c94_init(state);
+ regs->command = CMD_NOP;
+ eieio();
+ restore_flags(flags);
+ return SCSI_RESET_PENDING;
+}
+
+int
+mac53c94_command(Scsi_Cmnd *cmd)
+{
+ printk(KERN_DEBUG "whoops... mac53c94_command called\n");
+ return -1;
+}
+
+static void
+mac53c94_init(struct fsc_state *state)
+{
+ volatile struct mac53c94_regs *regs = state->regs;
+ volatile struct dbdma_regs *dma = state->dma;
+ int x;
+
+ regs->config1 = state->host->this_id | CF1_PAR_ENABLE;
+ regs->sel_timeout = TIMO_VAL(250); /* 250ms */
+ regs->clk_factor = CLKF_VAL(state->clk_freq);
+ regs->config2 = CF2_FEATURE_EN;
+ regs->config3 = 0;
+ regs->sync_period = 0;
+ regs->sync_offset = 0;
+ eieio();
+ x = regs->interrupt;
+ st_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+}
+
+/*
+ * Start the next command for a 53C94.
+ * Should be called with interrupts disabled.
+ */
+static void
+mac53c94_start(struct fsc_state *state)
+{
+ Scsi_Cmnd *cmd;
+ volatile struct mac53c94_regs *regs = state->regs;
+ int i;
+
+ if (state->phase != idle || state->current_req != NULL)
+ panic("inappropriate mac53c94_start (state=%p)", state);
+ if (state->request_q == NULL)
+ return;
+ state->current_req = cmd = state->request_q;
+ state->request_q = (Scsi_Cmnd *) cmd->host_scribble;
+
+ /* Off we go */
+ regs->count_lo = 0;
+ regs->count_mid = 0;
+ regs->count_hi = 0;
+ eieio();
+ regs->command = CMD_NOP + CMD_DMA_MODE;
+ udelay(1);
+ eieio();
+ regs->command = CMD_FLUSH;
+ udelay(1);
+ eieio();
+ regs->dest_id = cmd->target;
+ regs->sync_period = 0;
+ regs->sync_offset = 0;
+ eieio();
+
+ /* load the command into the FIFO */
+ for (i = 0; i < cmd->cmd_len; ++i) {
+ regs->fifo = cmd->cmnd[i];
+ eieio();
+ }
+
+ /* do select without ATN XXX */
+ regs->command = CMD_SELECT;
+ state->phase = selecting;
+
+ if (cmd->use_sg > 0 || cmd->request_bufflen != 0)
+ set_dma_cmds(state, cmd);
+}
+
+static void
+mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ struct fsc_state *state = (struct fsc_state *) dev_id;
+ volatile struct mac53c94_regs *regs = state->regs;
+ volatile struct dbdma_regs *dma = state->dma;
+ Scsi_Cmnd *cmd = state->current_req;
+ int nb, stat, seq, intr;
+ static int mac53c94_errors;
+
+ /*
+ * Apparently, reading the interrupt register unlatches
+ * the status and sequence step registers.
+ */
+ seq = regs->seqstep;
+ stat = regs->status;
+ intr = regs->interrupt;
+
+#if 0
+ printk(KERN_DEBUG "mac53c94_intr, intr=%x stat=%x seq=%x phase=%d\n",
+ intr, stat, seq, state->phase);
+#endif
+
+ if (intr & INTR_RESET) {
+ /* SCSI bus was reset */
+ printk(KERN_INFO "external SCSI bus reset detected\n");
+ regs->command = CMD_NOP;
+ st_le32(&dma->control, RUN << 16); /* stop dma */
+ cmd_done(state, DID_RESET << 16);
+ return;
+ }
+ if (intr & INTR_ILL_CMD) {
+ printk(KERN_ERR "53c94: illegal cmd, intr=%x stat=%x seq=%x phase=%d\n",
+ intr, stat, seq, state->phase);
+ cmd_done(state, DID_ERROR << 16);
+ return;
+ }
+ if (stat & STAT_ERROR) {
+#if 0
+ /* XXX these seem to be harmless? */
+ printk("53c94: bad error, intr=%x stat=%x seq=%x phase=%d\n",
+ intr, stat, seq, state->phase);
+#endif
+ ++mac53c94_errors;
+ regs->command = CMD_NOP + CMD_DMA_MODE;
+ eieio();
+ }
+ if (cmd == 0) {
+ printk(KERN_DEBUG "53c94: interrupt with no command active?\n");
+ return;
+ }
+ if (stat & STAT_PARITY) {
+ printk(KERN_ERR "mac53c94: parity error\n");
+ cmd_done(state, DID_PARITY << 16);
+ return;
+ }
+ switch (state->phase) {
+ case selecting:
+ if (intr & INTR_DISCONNECT) {
+ /* selection timed out */
+ cmd_done(state, DID_BAD_TARGET << 16);
+ return;
+ }
+ if (intr != INTR_BUS_SERV + INTR_DONE) {
+ printk(KERN_DEBUG "got intr %x during selection\n", intr);
+ cmd_done(state, DID_ERROR << 16);
+ return;
+ }
+ if ((seq & SS_MASK) != SS_DONE) {
+ printk(KERN_DEBUG "seq step %x after command\n", seq);
+ cmd_done(state, DID_ERROR << 16);
+ return;
+ }
+ regs->command = CMD_NOP;
+ /* set DMA controller going if any data to transfer */
+ if ((stat & (STAT_MSG|STAT_CD)) == 0
+ && (cmd->use_sg > 0 || cmd->request_bufflen != 0)) {
+ nb = cmd->SCp.this_residual;
+ if (nb > 0xfff0)
+ nb = 0xfff0;
+ cmd->SCp.this_residual -= nb;
+ regs->count_lo = nb;
+ regs->count_mid = nb >> 8;
+ eieio();
+ regs->command = CMD_DMA_MODE + CMD_NOP;
+ eieio();
+ st_le32(&dma->cmdptr, virt_to_phys(state->dma_cmds));
+ st_le32(&dma->control, (RUN << 16) | RUN);
+ eieio();
+ regs->command = CMD_DMA_MODE + CMD_XFER_DATA;
+ state->phase = dataing;
+ break;
+ } else if ((stat & STAT_PHASE) == STAT_CD + STAT_IO) {
+ /* up to status phase already */
+ regs->command = CMD_I_COMPLETE;
+ state->phase = completing;
+ } else {
+ printk(KERN_DEBUG "in unexpected phase %x after cmd\n",
+ stat & STAT_PHASE);
+ cmd_done(state, DID_ERROR << 16);
+ return;
+ }
+ break;
+
+ case dataing:
+ if (intr != INTR_BUS_SERV) {
+ printk(KERN_DEBUG "got intr %x before status\n", intr);
+ cmd_done(state, DID_ERROR << 16);
+ return;
+ }
+ if (cmd->SCp.this_residual != 0
+ && (stat & (STAT_MSG|STAT_CD)) == 0) {
+ /* Set up the count regs to transfer more */
+ nb = cmd->SCp.this_residual;
+ if (nb > 0xfff0)
+ nb = 0xfff0;
+ cmd->SCp.this_residual -= nb;
+ regs->count_lo = nb;
+ regs->count_mid = nb >> 8;
+ eieio();
+ regs->command = CMD_DMA_MODE + CMD_NOP;
+ eieio();
+ regs->command = CMD_DMA_MODE + CMD_XFER_DATA;
+ break;
+ }
+ if ((stat & STAT_PHASE) != STAT_CD + STAT_IO) {
+ printk(KERN_DEBUG "intr %x before data xfer complete\n", intr);
+ }
+ st_le32(&dma->control, RUN << 16); /* stop dma */
+ /* should check dma status */
+ regs->command = CMD_I_COMPLETE;
+ state->phase = completing;
+ break;
+ case completing:
+ if (intr != INTR_DONE) {
+ printk(KERN_DEBUG "got intr %x on completion\n", intr);
+ cmd_done(state, DID_ERROR << 16);
+ return;
+ }
+ cmd->SCp.Status = regs->fifo; eieio();
+ cmd->SCp.Message = regs->fifo; eieio();
+ cmd->result =
+ regs->command = CMD_ACCEPT_MSG;
+ state->phase = busfreeing;
+ break;
+ case busfreeing:
+ if (intr != INTR_DISCONNECT) {
+ printk(KERN_DEBUG "got intr %x when expected disconnect\n", intr);
+ }
+ cmd_done(state, (DID_OK << 16) + (cmd->SCp.Message << 8)
+ + cmd->SCp.Status);
+ break;
+ default:
+ printk(KERN_DEBUG "don't know about phase %d\n", state->phase);
+ }
+}
+
+static void
+cmd_done(struct fsc_state *state, int result)
+{
+ Scsi_Cmnd *cmd;
+
+ cmd = state->current_req;
+ if (cmd != 0) {
+ cmd->result = result;
+ (*cmd->scsi_done)(cmd);
+ state->current_req = NULL;
+ }
+ state->phase = idle;
+ mac53c94_start(state);
+}
+
+/*
+ * Set up DMA commands for transferring data.
+ */
+static void
+set_dma_cmds(struct fsc_state *state, Scsi_Cmnd *cmd)
+{
+ int i, dma_cmd, total;
+ struct scatterlist *scl;
+ struct dbdma_cmd *dcmds;
+
+ dma_cmd = data_goes_out(cmd)? OUTPUT_MORE: INPUT_MORE;
+ dcmds = state->dma_cmds;
+ if (cmd->use_sg > 0) {
+ total = 0;
+ scl = (struct scatterlist *) cmd->buffer;
+ for (i = 0; i < cmd->use_sg; ++i) {
+ if (scl->length > 0xffff)
+ panic("mac53c94: scatterlist element >= 64k");
+ total += scl->length;
+ st_le16(&dcmds->req_count, scl->length);
+ st_le16(&dcmds->command, dma_cmd);
+ st_le32(&dcmds->phy_addr, virt_to_phys(scl->address));
+ dcmds->xfer_status = 0;
+ ++scl;
+ ++dcmds;
+ }
+ } else {
+ total = cmd->request_bufflen;
+ if (total > 0xffff)
+ panic("mac53c94: transfer size >= 64k");
+ st_le16(&dcmds->req_count, total);
+ st_le32(&dcmds->phy_addr, virt_to_phys(cmd->request_buffer));
+ dcmds->xfer_status = 0;
+ ++dcmds;
+ }
+ dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
+ st_le16(&dcmds[-1].command, dma_cmd);
+ st_le16(&dcmds->command, DBDMA_STOP);
+ cmd->SCp.this_residual = total;
+}
+
+/*
+ * Work out whether data will be going out from the host adaptor or into it.
+ * (If this information is available from somewhere else in the scsi
+ * code, somebody please let me know :-)
+ */
+static int
+data_goes_out(Scsi_Cmnd *cmd)
+{
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12: /* any others? */
+ return 1;
+ default:
+ return 0;
+ }
+}
--- /dev/null
+/*
+ * mac53c94.h: definitions for the driver for the 53c94 SCSI bus adaptor
+ * found on Power Macintosh computers, controlling the external SCSI chain.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#ifndef _MAC53C94_H
+#define _MAC53C94_H
+
+extern struct proc_dir_entry proc_scsi_mac53c94;
+
+int mac53c94_detect(Scsi_Host_Template *);
+int mac53c94_command(Scsi_Cmnd *);
+int mac53c94_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int mac53c94_abort(Scsi_Cmnd *);
+int mac53c94_reset(Scsi_Cmnd *, unsigned int);
+
+#define SCSI_MAC53C94 { \
+ NULL, /* next */ \
+ NULL, /* usage_count */ \
+ &proc_scsi_mac53c94, /* proc_dir */ \
+ NULL, /* proc_info */ \
+ "53C94", /* name */ \
+ mac53c94_detect, /* detect */ \
+ NULL, /* release */ \
+ NULL, /* info */ \
+ mac53c94_command, /* command */ \
+ mac53c94_queue, /* queuecommand */ \
+ mac53c94_abort, /* abort */ \
+ mac53c94_reset, /* reset */ \
+ NULL, /* slave_attach */ \
+ NULL, /* bios_param */ \
+ 1, /* can_queue */ \
+ 7, /* this_id */ \
+ SG_ALL, /* sg_tablesize */ \
+ 1, /* cmd_per_lun */ \
+ 0, /* present */ \
+ 0, /* unchecked_isa_dma */ \
+ DISABLE_CLUSTERING, /* use_clustering */ \
+}
+
+/*
+ * Registers in the 53C94 controller.
+ */
+
+struct mac53c94_regs {
+ unsigned char count_lo;
+ char pad0[15];
+ unsigned char count_mid;
+ char pad1[15];
+ unsigned char fifo;
+ char pad2[15];
+ unsigned char command;
+ char pad3[15];
+ unsigned char status;
+ char pad4[15];
+ unsigned char interrupt;
+ char pad5[15];
+ unsigned char seqstep;
+ char pad6[15];
+ unsigned char flags;
+ char pad7[15];
+ unsigned char config1;
+ char pad8[15];
+ unsigned char clk_factor;
+ char pad9[15];
+ unsigned char test;
+ char pad10[15];
+ unsigned char config2;
+ char pad11[15];
+ unsigned char config3;
+ char pad12[15];
+ unsigned char config4;
+ char pad13[15];
+ unsigned char count_hi;
+ char pad14[15];
+ unsigned char fifo_res;
+ char pad15[15];
+};
+
+/*
+ * Alternate functions for some registers.
+ */
+#define dest_id status
+#define sel_timeout interrupt
+#define sync_period seqstep
+#define sync_offset flags
+
+/*
+ * Bits in command register.
+ */
+#define CMD_DMA_MODE 0x80
+#define CMD_MODE_MASK 0x70
+#define CMD_MODE_INIT 0x10
+#define CMD_MODE_TARG 0x20
+#define CMD_MODE_DISC 0x40
+
+#define CMD_NOP 0
+#define CMD_FLUSH 1
+#define CMD_RESET 2
+#define CMD_SCSI_RESET 3
+
+#define CMD_XFER_DATA 0x10
+#define CMD_I_COMPLETE 0x11
+#define CMD_ACCEPT_MSG 0x12
+#define CMD_XFER_PAD 0x18
+#define CMD_SET_ATN 0x1a
+#define CMD_CLR_ATN 0x1b
+
+#define CMD_SEND_MSG 0x20
+#define CMD_SEND_STATUS 0x21
+#define CMD_SEND_DATA 0x22
+#define CMD_DISC_SEQ 0x23
+#define CMD_TERMINATE 0x24
+#define CMD_T_COMPLETE 0x25
+#define CMD_DISCONNECT 0x27
+#define CMD_RECV_MSG 0x28
+#define CMD_RECV_CDB 0x29
+#define CMD_RECV_DATA 0x2a
+#define CMD_RECV_CMD 0x2b
+#define CMD_ABORT_DMA 0x04
+
+#define CMD_RESELECT 0x40
+#define CMD_SELECT 0x41
+#define CMD_SELECT_ATN 0x42
+#define CMD_SELATN_STOP 0x43
+#define CMD_ENABLE_SEL 0x44
+#define CMD_DISABLE_SEL 0x45
+#define CMD_SEL_ATN3 0x46
+#define CMD_RESEL_ATN3 0x47
+
+/*
+ * Bits in status register.
+ */
+#define STAT_IRQ 0x80
+#define STAT_ERROR 0x40
+#define STAT_PARITY 0x20
+#define STAT_TC_ZERO 0x10
+#define STAT_DONE 0x08
+#define STAT_PHASE 0x07
+#define STAT_MSG 0x04
+#define STAT_CD 0x02
+#define STAT_IO 0x01
+
+/*
+ * Bits in interrupt register.
+ */
+#define INTR_RESET 0x80 /* SCSI bus was reset */
+#define INTR_ILL_CMD 0x40 /* illegal command */
+#define INTR_DISCONNECT 0x20 /* we got disconnected */
+#define INTR_BUS_SERV 0x10 /* bus service requested */
+#define INTR_DONE 0x08 /* function completed */
+#define INTR_RESELECTED 0x04 /* we were reselected */
+#define INTR_SEL_ATN 0x02 /* we were selected, ATN asserted */
+#define INTR_SELECT 0x01 /* we were selected, ATN negated */
+
+/*
+ * Encoding for the select timeout.
+ */
+#define TIMO_VAL(x) ((x) * 5000 / 7682)
+
+/*
+ * Bits in sequence step register.
+ */
+#define SS_MASK 7
+#define SS_ARB_SEL 0 /* Selection & arbitration complete */
+#define SS_MSG_SENT 1 /* One message byte sent */
+#define SS_NOT_CMD 2 /* Not in command phase */
+#define SS_PHASE_CHG 3 /* Early phase change, cmd bytes lost */
+#define SS_DONE 4 /* Command was sent OK */
+
+/*
+ * Encoding for sync transfer period.
+ */
+#define SYNCP_MASK 0x1f
+#define SYNCP_MIN 4
+#define SYNCP_MAX 31
+
+/*
+ * Bits in flags register.
+ */
+#define FLAGS_FIFO_LEV 0x1f
+#define FLAGS_SEQ_STEP 0xe0
+
+/*
+ * Encoding for sync offset.
+ */
+#define SYNCO_MASK 0x0f
+#define SYNCO_ASS_CTRL 0x30 /* REQ/ACK assertion control */
+#define SYNCO_NEG_CTRL 0xc0 /* REQ/ACK negation control */
+
+/*
+ * Bits in config1 register.
+ */
+#define CF1_SLOW_CABLE 0x80 /* Slow cable mode */
+#define CF1_NO_RES_REP 0x40 /* Disable SCSI reset reports */
+#define CF1_PAR_TEST 0x20 /* Parity test mode enable */
+#define CF1_PAR_ENABLE 0x10 /* Enable parity checks */
+#define CF1_TEST 0x08 /* Chip tests */
+#define CF1_MY_ID 0x07 /* Controller's address on bus */
+
+/*
+ * Encoding for clk_factor register.
+ */
+#define CLKF_MASK 7
+#define CLKF_VAL(freq) ((((freq) + 4999999) / 5000000) & CLKF_MASK)
+
+/*
+ * Bits in test mode register.
+ */
+#define TEST_TARGET 1 /* target test mode */
+#define TEST_INITIATOR 2 /* initiator test mode */
+#define TEST_TRISTATE 4 /* tristate (hi-z) test mode */
+
+/*
+ * Bits in config2 register.
+ */
+#define CF2_RFB 0x80
+#define CF2_FEATURE_EN 0x40 /* enable features / phase latch */
+#define CF2_BYTECTRL 0x20
+#define CF2_DREQ_HIZ 0x10
+#define CF2_SCSI2 0x08
+#define CF2_PAR_ABORT 0x04 /* bad parity target abort */
+#define CF2_REG_PARERR 0x02 /* register parity error */
+#define CF2_DMA_PARERR 0x01 /* DMA parity error */
+
+/*
+ * Bits in the config3 register.
+ */
+#define CF3_ID_MSG_CHK 0x80
+#define CF3_3B_MSGS 0x40
+#define CF3_CDB10 0x20
+#define CF3_FASTSCSI 0x10 /* enable fast SCSI support */
+#define CF3_FASTCLOCK 0x08
+#define CF3_SAVERESID 0x04
+#define CF3_ALT_DMA 0x02
+#define CF3_THRESH_8 0x01
+
+/*
+ * Bits in the config4 register.
+ */
+#define CF4_EAN 0x04
+#define CF4_TEST 0x02
+#define CF4_BBTE 0x01
+
+#endif /* _MAC53C94_H */
--- /dev/null
+/*
+ * SCSI low-level driver for the MESH (Macintosh Enhanced SCSI Hardware)
+ * bus adaptor found on Power Macintosh computers.
+ * We assume the MESH is connected to a DBDMA (descriptor-based DMA)
+ * controller.
+ *
+ * Paul Mackerras, August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/config.h>
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "mesh.h"
+
+#if 0
+#undef KERN_DEBUG
+#define KERN_DEBUG KERN_WARNING
+#endif
+
+#if CONFIG_SCSI_MESH_SYNC_RATE == 0
+int mesh_sync_period = 100;
+int mesh_sync_offset = 0;
+#else
+int mesh_sync_period = 1000 / CONFIG_SCSI_MESH_SYNC_RATE; /* ns */
+int mesh_sync_offset = 15;
+#endif
+
+int mesh_sync_targets = 0xff; /* targets to set synchronous (bitmap) */
+int mesh_resel_targets = 0xff; /* targets that we let disconnect (bitmap) */
+int mesh_debug_targets = 0; /* print debug for these targets */
+
+#define ALLOW_SYNC(tgt) ((mesh_sync_targets >> (tgt)) & 1)
+#define ALLOW_RESEL(tgt) ((mesh_resel_targets >> (tgt)) & 1)
+#define ALLOW_DEBUG(tgt) ((mesh_debug_targets >> (tgt)) & 1)
+#define DEBUG_TARGET(cmd) ((cmd) && ALLOW_DEBUG((cmd)->target))
+
+struct proc_dir_entry proc_scsi_mesh = {
+ PROC_SCSI_MESH, 4, "mesh",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+enum mesh_phase {
+ idle,
+ arbitrating,
+ selecting,
+ commanding,
+ dataing,
+ statusing,
+ busfreeing,
+ disconnecting,
+ reselecting
+};
+
+enum msg_phase {
+ msg_none,
+ msg_out,
+ msg_out_xxx,
+ msg_out_last,
+ msg_in,
+};
+
+enum sdtr_phase {
+ do_sdtr,
+ sdtr_sent,
+ sdtr_done
+};
+
+struct mesh_target {
+ enum sdtr_phase sdtr_state;
+ enum mesh_phase phase;
+ int sync_params;
+ int data_goes_out;
+ Scsi_Cmnd *current_req;
+ u32 saved_ptr;
+};
+
+struct mesh_state {
+ volatile struct mesh_regs *mesh;
+ int meshintr;
+ volatile struct dbdma_regs *dma;
+ int dmaintr;
+ struct Scsi_Host *host;
+ struct mesh_state *next;
+ Scsi_Cmnd *request_q;
+ Scsi_Cmnd *request_qtail;
+ enum mesh_phase phase; /* what we're currently trying to do */
+ enum msg_phase msgphase;
+ int conn_tgt; /* target we're connected to */
+ Scsi_Cmnd *current_req; /* req we're currently working on */
+ int data_ptr;
+ int data_goes_out; /* guess as to data direction */
+ int dma_started;
+ int dma_count;
+ int expect_reply;
+ int n_msgin;
+ u8 msgin[16];
+ int n_msgout;
+ int last_n_msgout;
+ u8 msgout[16];
+ struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */
+ int clk_freq;
+ struct mesh_target tgts[8];
+ struct tq_struct tqueue;
+ Scsi_Cmnd *completed_q;
+ Scsi_Cmnd *completed_qtail;
+};
+
+static struct mesh_state *all_meshes;
+
+static void mesh_init(struct mesh_state *);
+static int mesh_notify_reboot(struct notifier_block *, unsigned long, void *);
+static void mesh_dump_regs(struct mesh_state *);
+static void mesh_start(struct mesh_state *);
+static void finish_cmds(void *);
+static void add_sdtr_msg(struct mesh_state *);
+static void set_sdtr(struct mesh_state *, int, int);
+static void start_phase(struct mesh_state *);
+static void get_msgin(struct mesh_state *);
+static int msgin_length(struct mesh_state *);
+static void cmd_complete(struct mesh_state *);
+static void phase_mismatch(struct mesh_state *);
+static void reselected(struct mesh_state *);
+static void handle_reset(struct mesh_state *);
+static void mesh_interrupt(int, void *, struct pt_regs *);
+static void handle_msgin(struct mesh_state *);
+static void mesh_done(struct mesh_state *);
+static void mesh_completed(struct mesh_state *, Scsi_Cmnd *);
+static void set_dma_cmds(struct mesh_state *, Scsi_Cmnd *);
+static void halt_dma(struct mesh_state *);
+static int data_goes_out(Scsi_Cmnd *);
+
+static struct notifier_block mesh_notifier = {
+ mesh_notify_reboot,
+ NULL,
+ 0
+};
+
+int
+mesh_detect(Scsi_Host_Template *tp)
+{
+ struct device_node *mesh;
+ int nmeshes, tgt, *cfp, minper;
+ struct mesh_state *ms, **prev_statep;
+ struct Scsi_Host *mesh_host;
+ void *dma_cmd_space;
+
+ nmeshes = 0;
+ prev_statep = &all_meshes;
+ for (mesh = find_devices("mesh"); mesh != 0; mesh = mesh->next) {
+ if (mesh->n_addrs != 2 || mesh->n_intrs != 2)
+ panic("mesh: expected 2 addrs and intrs (got %d/%d)",
+ mesh->n_addrs, mesh->n_intrs);
+ mesh_host = scsi_register(tp, sizeof(struct mesh_state));
+ if (mesh_host == 0)
+ panic("couldn't register mesh host");
+ mesh_host->unique_id = nmeshes;
+ note_scsi_host(mesh, mesh_host);
+
+ ms = (struct mesh_state *) mesh_host->hostdata;
+ if (ms == 0)
+ panic("no mesh state");
+ memset(ms, 0, sizeof(*ms));
+ ms->host = mesh_host;
+ ms->mesh = (volatile struct mesh_regs *)
+ mesh->addrs[0].address;
+ ms->meshintr = mesh->intrs[0];
+ ms->dma = (volatile struct dbdma_regs *)
+ mesh->addrs[1].address;
+ ms->dmaintr = mesh->intrs[1];
+
+ /* Space for dma command list: +1 for stop command,
+ +1 to allow for aligning. */
+ dma_cmd_space = kmalloc((mesh_host->sg_tablesize + 2) *
+ sizeof(struct dbdma_cmd), GFP_KERNEL);
+ if (dma_cmd_space == 0)
+ panic("mesh: couldn't allocate dma command space");
+ ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space);
+ memset(ms->dma_cmds, 0, (mesh_host->sg_tablesize + 1)
+ * sizeof(struct dbdma_cmd));
+
+ ms->current_req = 0;
+ for (tgt = 0; tgt < 8; ++tgt) {
+ ms->tgts[tgt].sdtr_state = do_sdtr;
+ ms->tgts[tgt].sync_params = ASYNC_PARAMS;
+ ms->tgts[tgt].current_req = 0;
+ }
+
+ ms->tqueue.routine = finish_cmds;
+ ms->tqueue.data = ms;
+
+ *prev_statep = ms;
+ prev_statep = &ms->next;
+
+ if (request_irq(ms->meshintr, mesh_interrupt, 0, "MESH", ms)) {
+ printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
+ }
+
+ cfp = (int *) get_property(mesh, "clock-frequency", NULL);
+ if (cfp) {
+ ms->clk_freq = *cfp;
+ } else {
+ printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
+ ms->clk_freq = 50000000;
+ }
+ /* The maximum sync rate is clock / 5; increase
+ mesh_sync_period if necessary. */
+ minper = 1000000000 / (ms->clk_freq / 5); /* ns */
+ if (mesh_sync_period < minper)
+ mesh_sync_period = minper;
+
+ mesh_init(ms);
+
+ ++nmeshes;
+ }
+ if (nmeshes > 0)
+ register_reboot_notifier(&mesh_notifier);
+
+ return nmeshes;
+}
+
+int
+mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+ unsigned long flags;
+ struct mesh_state *ms;
+
+#if 0
+ if (data_goes_out(cmd)) {
+ printk(KERN_DEBUG "mesh_queue %p: command is", cmd);
+ for (i = 0; i < cmd->cmd_len; ++i)
+ printk(" %.2x", cmd->cmnd[i]);
+ printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
+ cmd->use_sg, cmd->request_bufflen, cmd->request_buffer);
+ }
+#endif
+
+ cmd->scsi_done = done;
+ cmd->host_scribble = NULL;
+
+ ms = (struct mesh_state *) cmd->host->hostdata;
+
+ save_flags(flags);
+ cli();
+ if (ms->request_q == NULL)
+ ms->request_q = cmd;
+ else
+ ms->request_qtail->host_scribble = (void *) cmd;
+ ms->request_qtail = cmd;
+
+ if (ms->phase == idle)
+ mesh_start(ms);
+
+ restore_flags(flags);
+ return 0;
+}
+
+int
+mesh_abort(Scsi_Cmnd *cmd)
+{
+ printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);
+ mesh_dump_regs((struct mesh_state *)(cmd->host->hostdata));
+ return SCSI_ABORT_SNOOZE;
+}
+
+static void
+mesh_dump_regs(struct mesh_state *ms)
+{
+ volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct dbdma_regs *md = ms->dma;
+ int t;
+ struct mesh_target *tp;
+
+ printk(KERN_DEBUG "mesh: state at %p, regs at %p, dma at %p\n",
+ ms, mr, md);
+ printk(KERN_DEBUG " ct=%4x seq=%2x bs=%4x fc=%2x exc=%2x err=%2x sp=%2x\n",
+ (mr->count_hi << 8) + mr->count_lo, mr->sequence,
+ (mr->bus_status1 << 8) + mr->bus_status0, mr->fifo_count,
+ mr->exception, mr->error, mr->sync_params);
+ printk(KERN_DEBUG " dma stat=%x cmdptr=%x\n",
+ in_le32(&md->status), in_le32(&md->cmdptr));
+ printk(KERN_DEBUG " phase=%d msgphase=%d conn_tgt=%d data_ptr=%d\n",
+ ms->phase, ms->msgphase, ms->conn_tgt, ms->data_ptr);
+ printk(KERN_DEBUG " goes_out=%d dma_st=%d dma_ct=%d n_msgout=%d\n",
+ ms->data_goes_out, ms->dma_started, ms->dma_count, ms->n_msgout);
+ for (t = 0; t < 8; ++t) {
+ tp = &ms->tgts[t];
+ if (tp->current_req == NULL)
+ continue;
+ printk(KERN_DEBUG " target %d: req=%p phase=%d saved_ptr=%d\n",
+ t, tp->current_req, tp->phase, tp->saved_ptr);
+ }
+}
+
+int
+mesh_reset(Scsi_Cmnd *cmd, unsigned how)
+{
+ struct mesh_state *ms = (struct mesh_state *) cmd->host->hostdata;
+ volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct dbdma_regs *md = ms->dma;
+ unsigned long flags;
+ int ret;
+
+ printk(KERN_DEBUG "mesh_reset %x\n", how);
+ ret = SCSI_RESET_BUS_RESET;
+ save_flags(flags);
+ cli();
+ out_8(&mr->exception, 0xff); /* clear all exception bits */
+ out_8(&mr->error, 0xff); /* clear all error bits */
+ out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ if (how & SCSI_RESET_SUGGEST_HOST_RESET) {
+ out_8(&mr->sequence, SEQ_RESETMESH);
+ ret |= SCSI_RESET_HOST_RESET;
+ udelay(1);
+ out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+ }
+ out_8(&mr->bus_status1, BS1_RST); /* assert RST */
+ udelay(30); /* leave it on for >= 25us */
+ out_8(&mr->bus_status1, 0); /* negate RST */
+#ifdef DO_ASYNC_RESET
+ if (how & SCSI_RESET_ASYNCHRONOUS) {
+ restore_flags(flags);
+ ret |= SCSI_RESET_PENDING;
+ } else
+#endif
+ {
+ out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+ handle_reset(ms);
+ restore_flags(flags);
+ finish_cmds(ms);
+ ret |= SCSI_RESET_SUCCESS;
+ }
+ return ret;
+}
+
+/*
+ * If we leave drives set for synchronous transfers (especially
+ * CDROMs), and reboot to MacOS, it gets confused, poor thing.
+ * So, on reboot we reset the SCSI bus.
+ */
+static int
+mesh_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+ struct mesh_state *ms;
+ volatile struct mesh_regs *mr;
+
+ if (code == SYS_DOWN || code == SYS_HALT) {
+ printk(KERN_INFO "resetting MESH scsi bus(es)\n");
+ for (ms = all_meshes; ms != 0; ms = ms->next) {
+ mr = ms->mesh;
+ out_8(&mr->intr_mask, 0);
+ out_8(&mr->interrupt,
+ INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+ out_8(&mr->bus_status1, BS1_RST);
+ udelay(30);
+ out_8(&mr->bus_status1, 0);
+ }
+ }
+ return NOTIFY_DONE;
+}
+
+int
+mesh_command(Scsi_Cmnd *cmd)
+{
+ printk(KERN_WARNING "whoops... mesh_command called\n");
+ return -1;
+}
+
+static void
+mesh_init(struct mesh_state *ms)
+{
+ volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct dbdma_regs *md = ms->dma;
+
+ out_8(&mr->interrupt, 0xff); /* clear all interrupt bits */
+ out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+ out_8(&mr->source_id, ms->host->this_id);
+ out_8(&mr->sel_timeout, 25); /* 250ms */
+ out_8(&mr->sync_params, ASYNC_PARAMS); /* asynchronous initially */
+ out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+}
+
+/*
+ * Start the next command for a MESH.
+ * Should be called with interrupts disabled.
+ */
+static void
+mesh_start(struct mesh_state *ms)
+{
+ Scsi_Cmnd *cmd, *prev, *next;
+ volatile struct mesh_regs *mr = ms->mesh;
+
+ if (ms->phase != idle || ms->current_req != NULL)
+ panic("inappropriate mesh_start (ms=%p)", ms);
+
+ prev = NULL;
+ for (cmd = ms->request_q; ; cmd = (Scsi_Cmnd *) cmd->host_scribble) {
+ if (cmd == NULL)
+ return;
+ if (ms->tgts[cmd->target].current_req == NULL)
+ break;
+ prev = cmd;
+ }
+ next = (Scsi_Cmnd *) cmd->host_scribble;
+ if (prev == NULL)
+ ms->request_q = next;
+ else
+ prev->host_scribble = (void *) next;
+ if (next == NULL)
+ ms->request_qtail = prev;
+
+ ms->current_req = cmd;
+ ms->data_goes_out = data_goes_out(cmd);
+ ms->tgts[cmd->target].current_req = cmd;
+
+#if 1
+ if (DEBUG_TARGET(cmd)) {
+ int i;
+ printk(KERN_DEBUG "mesh_start: %p ser=%lu tgt=%d cmd=",
+ cmd, cmd->serial_number, cmd->target);
+ for (i = 0; i < cmd->cmd_len; ++i)
+ printk(" %x", cmd->cmnd[i]);
+ printk(" use_sg=%d buffer=%p bufflen=%u\n",
+ cmd->use_sg, cmd->request_buffer, cmd->request_bufflen);
+ }
+#endif
+
+ /* Off we go */
+ out_8(&mr->sequence, SEQ_ARBITRATE);
+
+ ms->phase = arbitrating;
+ ms->msgphase = msg_none;
+ ms->data_ptr = 0;
+ ms->dma_started = 0;
+ ms->n_msgout = 0;
+ ms->last_n_msgout = 0;
+ ms->expect_reply = 0;
+ ms->conn_tgt = cmd->target;
+ ms->tgts[cmd->target].saved_ptr = 0;
+}
+
+static void
+finish_cmds(void *data)
+{
+ struct mesh_state *ms = data;
+ Scsi_Cmnd *cmd;
+ unsigned long flags;
+
+ for (;;) {
+ save_flags(flags);
+ cli();
+ cmd = ms->completed_q;
+ if (cmd == NULL) {
+ restore_flags(flags);
+ break;
+ }
+ ms->completed_q = (Scsi_Cmnd *) cmd->host_scribble;
+ restore_flags(flags);
+ (*cmd->scsi_done)(cmd);
+ }
+}
+
+static inline void
+add_sdtr_msg(struct mesh_state *ms)
+{
+ int i = ms->n_msgout;
+
+ ms->msgout[i] = EXTENDED_MESSAGE;
+ ms->msgout[i+1] = 3;
+ ms->msgout[i+2] = EXTENDED_SDTR;
+ ms->msgout[i+3] = mesh_sync_period/4;
+ ms->msgout[i+4] = (ALLOW_SYNC(ms->conn_tgt)? mesh_sync_offset: 0);
+ ms->n_msgout = i + 5;
+}
+
+static void
+set_sdtr(struct mesh_state *ms, int period, int offset)
+{
+ struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+ volatile struct mesh_regs *mr = ms->mesh;
+ int v, tr;
+
+ tp->sdtr_state = sdtr_done;
+ if (offset == 0) {
+ /* asynchronous */
+ if (SYNC_OFF(tp->sync_params))
+ printk(KERN_INFO "mesh: target %d now asynchronous\n",
+ ms->conn_tgt);
+ tp->sync_params = ASYNC_PARAMS;
+ out_8(&mr->sync_params, ASYNC_PARAMS);
+ return;
+ }
+ /*
+ * We need to compute ceil(clk_freq * period / 500e6) - 2
+ * without incurring overflow.
+ */
+ v = (ms->clk_freq / 5000) * period;
+ if (v <= 250000) {
+ /* special case: sync_period == 5 * clk_period */
+ v = 0;
+ /* units of tr are 100kB/s */
+ tr = (ms->clk_freq + 250000) / 500000;
+ } else {
+ /* sync_period == (v + 2) * 2 * clk_period */
+ v = (v + 99999) / 100000 - 2;
+ if (v > 15)
+ v = 15; /* oops */
+ tr = ((ms->clk_freq / (v + 2)) + 199999) / 200000;
+ }
+ if (offset > 15)
+ offset = 15; /* can't happen */
+ tp->sync_params = SYNC_PARAMS(offset, v);
+ out_8(&mr->sync_params, tp->sync_params);
+ printk(KERN_INFO "mesh: target %d synchronous at %d.%d MB/s\n",
+ ms->conn_tgt, tr/10, tr%10);
+}
+
+static void
+start_phase(struct mesh_state *ms)
+{
+ int i, seq, nb;
+ volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct dbdma_regs *md = ms->dma;
+ Scsi_Cmnd *cmd = ms->current_req;
+ struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+ if (cmd == 0) {
+ printk(KERN_ERR "mesh: start_phase but no cmd?\n");
+ return;
+ }
+ seq = SEQ_ACTIVE_NEG + (ms->n_msgout? SEQ_ATN: 0);
+ switch (ms->msgphase) {
+ case msg_none:
+ break;
+
+ case msg_in:
+ out_8(&mr->count_hi, 0);
+ out_8(&mr->count_lo, 1);
+ out_8(&mr->sequence, SEQ_MSGIN + seq);
+ ms->n_msgin = 0;
+ return;
+
+ case msg_out:
+ /*
+ * To make sure ATN drops before we assert ACK for
+ * the last byte of the message, we have to do the
+ * last byte specially.
+ */
+ if (DEBUG_TARGET(cmd)) {
+ printk(KERN_DEBUG "mesh: sending %d msg bytes:",
+ ms->n_msgout);
+ for (i = 0; i < ms->n_msgout; ++i)
+ printk(" %x", ms->msgout[i]);
+ printk("\n");
+ }
+ out_8(&mr->count_hi, 0);
+ if (ms->n_msgout == 1) {
+ out_8(&mr->count_lo, 1);
+ out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG);
+ udelay(1);
+ out_8(&mr->fifo, ms->msgout[0]);
+ ms->msgphase = msg_out_last;
+ } else {
+ out_8(&mr->count_lo, ms->n_msgout - 1);
+ out_8(&mr->sequence, SEQ_MSGOUT + seq);
+ for (i = 0; i < ms->n_msgout - 1; ++i)
+ out_8(&mr->fifo, ms->msgout[i]);
+ }
+ return;
+
+ default:
+ printk(KERN_ERR "mesh bug: start_phase msgphase=%d\n",
+ ms->msgphase);
+ }
+
+ switch (ms->phase) {
+ case selecting:
+ out_8(&mr->dest_id, cmd->target);
+ out_8(&mr->sequence, SEQ_SELECT + SEQ_ATN);
+ break;
+ case commanding:
+ out_8(&mr->sync_params, tp->sync_params);
+ out_8(&mr->count_hi, 0);
+ out_8(&mr->count_lo, cmd->cmd_len);
+ out_8(&mr->sequence, SEQ_COMMAND + seq);
+ for (i = 0; i < cmd->cmd_len; ++i)
+ out_8(&mr->fifo, cmd->cmnd[i]);
+ break;
+ case dataing:
+ /* transfer data, if any */
+ if (!ms->dma_started) {
+ set_dma_cmds(ms, cmd);
+ out_le32(&md->cmdptr, virt_to_phys(ms->dma_cmds));
+ out_le32(&md->control, (RUN << 16) | RUN);
+ ms->dma_started = 1;
+ }
+ nb = ms->dma_count;
+ if (nb > 0xfff0)
+ nb = 0xfff0;
+ ms->dma_count -= nb;
+ ms->data_ptr += nb;
+ out_8(&mr->count_lo, nb);
+ out_8(&mr->count_hi, nb >> 8);
+ out_8(&mr->sequence, (ms->data_goes_out?
+ SEQ_DATAOUT: SEQ_DATAIN) + SEQ_DMA_MODE + seq);
+ break;
+ case statusing:
+ out_8(&mr->count_hi, 0);
+ out_8(&mr->count_lo, 1);
+ out_8(&mr->sequence, SEQ_STATUS + seq);
+ break;
+ case busfreeing:
+ case disconnecting:
+ out_8(&mr->sequence, SEQ_ENBRESEL);
+ udelay(1);
+ out_8(&mr->sequence, SEQ_BUSFREE);
+ break;
+ default:
+ printk(KERN_ERR "mesh: start_phase called with phase=%d\n",
+ ms->phase);
+ }
+
+}
+
+static inline void
+get_msgin(struct mesh_state *ms)
+{
+ volatile struct mesh_regs *mr = ms->mesh;
+ int i, n;
+
+ n = mr->fifo_count;
+ if (n != 0) {
+ i = ms->n_msgin;
+ ms->n_msgin = i + n;
+ for (; n > 0; --n)
+ ms->msgin[i++] = in_8(&mr->fifo);
+ }
+}
+
+static inline int
+msgin_length(struct mesh_state *ms)
+{
+ int b, n;
+
+ n = 1;
+ if (ms->n_msgin > 0) {
+ b = ms->msgin[0];
+ if (b == 1) {
+ /* extended message */
+ n = ms->n_msgin < 2? 2: ms->msgin[1] + 2;
+ } else if (0x20 <= b && b <= 0x2f) {
+ /* 2-byte message */
+ n = 2;
+ }
+ }
+ return n;
+}
+
+static void
+cmd_complete(struct mesh_state *ms)
+{
+ volatile struct mesh_regs *mr = ms->mesh;
+ Scsi_Cmnd *cmd = ms->current_req;
+ struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+ int seq, n, t;
+
+ seq = SEQ_ACTIVE_NEG + (ms->n_msgout? SEQ_ATN: 0);
+ switch (ms->msgphase) {
+ case msg_out_xxx:
+ /* huh? we expected a phase mismatch */
+ ms->n_msgin = 0;
+ ms->msgphase = msg_in;
+ /* fall through */
+
+ case msg_in:
+ /* should have some message bytes in fifo */
+ get_msgin(ms);
+ n = msgin_length(ms);
+ if (ms->n_msgin < n) {
+ out_8(&mr->count_lo, n - ms->n_msgin);
+ out_8(&mr->sequence, SEQ_MSGIN + seq);
+ } else {
+ ms->msgphase = msg_none;
+ handle_msgin(ms);
+ start_phase(ms);
+ }
+ break;
+
+ case msg_out:
+ /*
+ * To get the right timing on ATN wrt ACK, we have
+ * to get the MESH to drop ACK, wait until REQ gets
+ * asserted, then drop ATN. To do this we first
+ * issue a SEQ_MSGOUT with ATN and wait for REQ,
+ * then change the command to a SEQ_MSGOUT w/o ATN.
+ * If we don't see REQ in a reasonable time, we
+ * change the command to SEQ_MSGIN with ATN,
+ * wait for the phase mismatch interrupt, then
+ * issue the SEQ_MSGOUT without ATN.
+ */
+ out_8(&mr->count_lo, 1);
+ out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG + SEQ_ATN);
+ t = 30; /* wait up to 30us */
+ while ((mr->bus_status0 & BS0_REQ) == 0 && --t >= 0)
+ udelay(1);
+ if (mr->bus_status0 & BS0_REQ) {
+ out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG);
+ udelay(1);
+ out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+ ms->msgphase = msg_out_last;
+ } else {
+ out_8(&mr->sequence, SEQ_MSGIN + SEQ_ACTIVE_NEG + SEQ_ATN);
+ ms->msgphase = msg_out_xxx;
+ }
+ break;
+
+ case msg_out_last:
+ ms->last_n_msgout = ms->n_msgout;
+ ms->n_msgout = 0;
+ ms->msgphase = ms->expect_reply? msg_in: msg_none;
+ start_phase(ms);
+ break;
+
+ case msg_none:
+ switch (ms->phase) {
+ case selecting:
+ ms->msgout[0] = IDENTIFY(ALLOW_RESEL(cmd->target), cmd->lun);
+ ms->n_msgout = 1;
+ ms->expect_reply = 0;
+ if (tp->sdtr_state == do_sdtr) {
+ /* add SDTR message */
+ add_sdtr_msg(ms);
+ ms->expect_reply = 1;
+ tp->sdtr_state = sdtr_sent;
+ }
+ ms->msgphase = msg_out;
+ /*
+ * We need to wait for REQ before dropping ATN.
+ * We wait for at most 30us, then fall back to
+ * a scheme where we issue a SEQ_COMMAND with ATN,
+ * which will give us a phase mismatch interrupt
+ * when REQ does come, and then we send the message.
+ */
+ t = 30; /* wait up to 30us */
+ while ((mr->bus_status0 & BS0_REQ) == 0) {
+ if (--t < 0) {
+ ms->msgphase = msg_none;
+ break;
+ }
+ udelay(1);
+ }
+ break;
+ case dataing:
+ if (ms->dma_count != 0) {
+ start_phase(ms);
+ return;
+ }
+ halt_dma(ms);
+ break;
+ case statusing:
+ cmd->SCp.Status = mr->fifo;
+ cmd->result = (DID_OK << 16) + cmd->SCp.Status;
+ ms->msgphase = msg_in;
+ if (DEBUG_TARGET(cmd))
+ printk(KERN_DEBUG "mesh: status is %x\n",
+ cmd->SCp.Status);
+ break;
+ case busfreeing:
+ mesh_done(ms);
+ return;
+ case disconnecting:
+ ms->current_req = 0;
+ ms->phase = idle;
+ mesh_start(ms);
+ return;
+ default:
+ break;
+ }
+ ++ms->phase;
+ start_phase(ms);
+ break;
+ }
+}
+
+static void phase_mismatch(struct mesh_state *ms)
+{
+ volatile struct mesh_regs *mr = ms->mesh;
+ int phase;
+
+ phase = mr->bus_status0 & BS0_PHASE;
+ if (ms->msgphase == msg_out_xxx && phase == BP_MSGOUT) {
+ /* output the last byte of the message, without ATN */
+ out_8(&mr->count_lo, 1);
+ out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG);
+ udelay(1);
+ out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+ ms->msgphase = msg_out_last;
+ return;
+ }
+
+ if (ms->msgphase == msg_in) {
+ get_msgin(ms);
+ if (ms->n_msgin)
+ handle_msgin(ms);
+ }
+
+ if (ms->dma_started)
+ halt_dma(ms);
+ if (mr->fifo_count) {
+ out_8(&mr->sequence, SEQ_FLUSHFIFO);
+ udelay(1);
+ }
+
+ ms->msgphase = msg_none;
+ switch (phase) {
+ case BP_DATAIN:
+ ms->data_goes_out = 0;
+ ms->phase = dataing;
+ break;
+ case BP_DATAOUT:
+ ms->data_goes_out = 1;
+ ms->phase = dataing;
+ break;
+ case BP_COMMAND:
+ ms->phase = commanding;
+ break;
+ case BP_STATUS:
+ ms->phase = statusing;
+ break;
+ case BP_MSGIN:
+ ms->msgphase = msg_in;
+ ms->n_msgin = 0;
+ break;
+ case BP_MSGOUT:
+ ms->msgphase = msg_out;
+ if (ms->n_msgout == 0) {
+ if (ms->last_n_msgout == 0) {
+ printk(KERN_DEBUG "mesh: no msg to repeat\n");
+ ms->msgout[0] = NOP;
+ ms->last_n_msgout = 1;
+ }
+ ms->n_msgout = ms->last_n_msgout;
+ }
+ break;
+ default:
+ printk(KERN_DEBUG "mesh: unknown scsi phase %x\n", phase);
+ ms->current_req->result = DID_ERROR << 16;
+ mesh_done(ms);
+ return;
+ }
+
+ start_phase(ms);
+}
+
+static void
+reselected(struct mesh_state *ms)
+{
+ volatile struct mesh_regs *mr = ms->mesh;
+ Scsi_Cmnd *cmd = ms->current_req;
+ struct mesh_target *tp;
+ int b, t;
+
+ switch (ms->phase) {
+ case idle:
+ case arbitrating:
+ break;
+ case busfreeing:
+ ms->phase = reselecting;
+ mesh_done(ms);
+ cmd = NULL;
+ break;
+ case disconnecting:
+ cmd = NULL;
+ break;
+ default:
+ printk(KERN_ERR "mesh: reselected in phase %d/%d\n",
+ ms->msgphase, ms->phase);
+ }
+ if (cmd) {
+ /* put the command back on the queue */
+ cmd->host_scribble = (void *) ms->request_q;
+ if (ms->request_q == NULL)
+ ms->request_qtail = cmd;
+ ms->request_q = cmd;
+ tp = &ms->tgts[cmd->target];
+ tp->current_req = NULL;
+ ms->current_req = NULL;
+ }
+
+ /*
+ * Find out who reselected us.
+ */
+ if (mr->fifo_count == 0) {
+ printk(KERN_ERR "mesh: reselection but nothing in fifo?\n");
+ return;
+ }
+ /* get the last byte in the fifo */
+ do {
+ b = in_8(&mr->fifo);
+ } while (in_8(&mr->fifo_count));
+ for (t = 0; t < 8; ++t)
+ if ((b & (1 << t)) != 0 && t != ms->host->this_id)
+ break;
+ if (b != (1 << t) + (1 << ms->host->this_id)) {
+ printk(KERN_ERR "mesh: bad reselection data %x\n", b);
+ return;
+ }
+
+ /*
+ * Set up to continue with that target's transfer.
+ */
+ tp = &ms->tgts[t];
+ if (ALLOW_DEBUG(t)) {
+ printk(KERN_DEBUG "mesh: reselected by target %d\n", t);
+ printk(KERN_DEBUG "mesh: saved_ptr=%x phase=%d cmd=%p\n",
+ tp->saved_ptr, tp->phase, tp->current_req);
+ }
+ if (tp->current_req == NULL) {
+ printk(KERN_ERR "mesh: reselected by tgt %d but no cmd!\n", t);
+ return;
+ }
+ ms->current_req = tp->current_req;
+ ms->phase = tp->phase;
+ ms->msgphase = msg_in;
+ ms->data_goes_out = tp->data_goes_out;
+ ms->data_ptr = tp->saved_ptr;
+ ms->conn_tgt = t;
+ ms->dma_started = 0;
+ ms->n_msgout = 0;
+ ms->last_n_msgout = 0;
+ out_8(&mr->sync_params, tp->sync_params);
+ start_phase(ms);
+}
+
+static void
+handle_reset(struct mesh_state *ms)
+{
+ int tgt;
+ struct mesh_target *tp;
+ Scsi_Cmnd *cmd;
+ volatile struct mesh_regs *mr = ms->mesh;
+
+ for (tgt = 0; tgt < 8; ++tgt) {
+ tp = &ms->tgts[tgt];
+ if ((cmd = tp->current_req) != NULL) {
+ cmd->result = DID_RESET << 16;
+ tp->current_req = NULL;
+ mesh_completed(ms, cmd);
+ }
+ ms->tgts[tgt].sdtr_state = do_sdtr;
+ ms->tgts[tgt].sync_params = ASYNC_PARAMS;
+ }
+ ms->current_req = NULL;
+ while ((cmd = ms->request_q) != NULL) {
+ ms->request_q = (Scsi_Cmnd *) cmd->host_scribble;
+ cmd->result = DID_RESET << 16;
+ mesh_completed(ms, cmd);
+ }
+ ms->phase = idle;
+ out_8(&mr->sync_params, ASYNC_PARAMS);
+}
+
+static void
+mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ struct mesh_state *ms = (struct mesh_state *) dev_id;
+ volatile struct mesh_regs *mr = ms->mesh;
+ Scsi_Cmnd *cmd = ms->current_req;
+ int stat, exc, err, intr;
+
+#if 0
+ if (DEBUG_TARGET(cmd))
+ printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x phase=%d msgphase=%d\n",
+ mr->bus_status0, mr->interrupt, mr->exception, mr->error, ms->phase, ms->msgphase);
+#endif
+ while ((intr = in_8(&mr->interrupt)) != 0) {
+ if (intr & INT_ERROR) {
+ stat = DID_BAD_INTR << 16;
+ err = in_8(&mr->error);
+ exc = in_8(&mr->exception);
+ out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+ if (err & ERR_SCSIRESET) {
+ /* SCSI bus was reset */
+ printk(KERN_INFO "mesh: SCSI bus reset detected: "
+ "waiting for end...");
+ while ((mr->bus_status1 & BS1_RST) != 0)
+ udelay(1);
+ printk("done\n");
+ handle_reset(ms);
+ /* request_q is empty, no point in mesh_start() */
+ continue;
+ } else if (err & ERR_UNEXPDISC) {
+ /* Unexpected disconnect */
+ printk(KERN_WARNING "mesh: target %d aborted\n",
+ ms->conn_tgt);
+ stat = DID_ABORT << 16;
+ } else if (err & ERR_PARITY) {
+ printk(KERN_ERR "mesh: parity error\n");
+ stat = DID_PARITY << 16;
+ } else if ((err & ERR_SEQERR) && (exc & EXC_RESELECTED)
+ && ms->phase == arbitrating) {
+ /* This can happen if we issue a command to
+ get the bus just after the target
+ reselects us. */
+ static int mesh_resel_seqerr;
+ mesh_resel_seqerr++;
+ reselected(ms);
+ continue;
+ } else {
+ printk(KERN_ERR "mesh: error %x (exc = %x)\n",
+ err, exc);
+ mesh_dump_regs(ms);
+ }
+ if (cmd != 0) {
+ cmd->result = stat;
+ mesh_done(ms);
+ }
+
+ } else if (intr & INT_EXCEPTION) {
+ exc = in_8(&mr->exception);
+ out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE);
+ if (exc & EXC_RESELECTED) {
+ static int mesh_resel_exc;
+ mesh_resel_exc++;
+ reselected(ms);
+ } else if (cmd && exc == EXC_ARBLOST
+ && ms->phase == arbitrating) {
+ printk(KERN_DEBUG "mesh: lost arbitration\n");
+ cmd->result = DID_BUS_BUSY << 16;
+ mesh_done(ms);
+ } else if (cmd && exc == EXC_SELTO && ms->phase == selecting) {
+ /* selection timed out */
+ cmd->result = DID_BAD_TARGET << 16;
+ mesh_done(ms);
+ } else if (cmd && exc == EXC_PHASEMM
+ && (mr->bus_status0 & BS0_REQ) != 0) {
+ /* target wants to do something different:
+ find out what it wants and do it. */
+ phase_mismatch(ms);
+ } else {
+ printk(KERN_ERR "mesh: can't cope with exception %x\n",
+ exc);
+ cmd->result = DID_ERROR << 16;
+ mesh_done(ms);
+ }
+
+ } else if (intr & INT_CMDDONE) {
+ out_8(&mr->interrupt, INT_CMDDONE);
+ cmd_complete(ms);
+ }
+ }
+}
+
+static void
+handle_msgin(struct mesh_state *ms)
+{
+ int i;
+ Scsi_Cmnd *cmd = ms->current_req;
+ struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+ if (ms->n_msgin == 0)
+ return;
+ if (DEBUG_TARGET(cmd)) {
+ printk(KERN_DEBUG "got %d message bytes:", ms->n_msgin);
+ for (i = 0; i < ms->n_msgin; ++i)
+ printk(" %x", ms->msgin[i]);
+ printk("\n");
+ }
+
+ ms->expect_reply = 0;
+ ms->n_msgout = 0;
+ if (ms->n_msgin < msgin_length(ms))
+ goto reject;
+ if (cmd)
+ cmd->SCp.Message = ms->msgin[0];
+ switch (ms->msgin[0]) {
+ case COMMAND_COMPLETE:
+ break;
+ case EXTENDED_MESSAGE:
+ switch (ms->msgin[2]) {
+ case EXTENDED_MODIFY_DATA_POINTER:
+ ms->data_ptr += (ms->msgin[3] << 24) + ms->msgin[6]
+ + (ms->msgin[4] << 16) + (ms->msgin[5] << 8);
+ break;
+ case EXTENDED_SDTR:
+ if (tp->sdtr_state != sdtr_sent) {
+ /* reply with an SDTR */
+ add_sdtr_msg(ms);
+ /* limit period to at least his value,
+ offset to no more than his */
+ if (ms->msgout[3] < ms->msgin[3])
+ ms->msgout[3] = ms->msgin[3];
+ if (ms->msgout[4] > ms->msgin[4])
+ ms->msgout[4] = ms->msgin[4];
+ set_sdtr(ms, ms->msgout[3], ms->msgout[4]);
+ ms->msgphase = msg_out;
+ } else {
+ set_sdtr(ms, ms->msgin[3], ms->msgin[4]);
+ }
+ break;
+ default:
+ goto reject;
+ }
+ break;
+ case SAVE_POINTERS:
+ tp->saved_ptr = ms->data_ptr;
+ break;
+ case RESTORE_POINTERS:
+ ms->data_ptr = tp->saved_ptr;
+ break;
+ case DISCONNECT:
+ tp->phase = ms->phase;
+ tp->data_goes_out = ms->data_goes_out;
+ ms->phase = disconnecting;
+ break;
+ case ABORT:
+ break;
+ case MESSAGE_REJECT:
+ if (tp->sdtr_state == sdtr_sent)
+ set_sdtr(ms, 0, 0);
+ break;
+ case NOP:
+ break;
+ default:
+ if (cmd && IDENTIFY_BASE <= ms->msgin[0]
+ && ms->msgin[0] <= IDENTIFY_BASE + 7) {
+ i = ms->msgin[0] - IDENTIFY_BASE;
+ if (i != cmd->lun)
+ printk(KERN_WARNING "mesh: lun mismatch "
+ "(%d != %d) on reselection from "
+ "target %d\n", i, cmd->lun,
+ ms->conn_tgt);
+ break;
+ }
+ goto reject;
+ }
+ return;
+
+ reject:
+ printk(KERN_WARNING "mesh: rejecting message %x from target %d\n",
+ ms->msgin[0], ms->conn_tgt);
+ ms->msgout[0] = MESSAGE_REJECT;
+ ms->n_msgout = 1;
+ ms->msgphase = msg_out;
+}
+
+static void
+mesh_done(struct mesh_state *ms)
+{
+ Scsi_Cmnd *cmd;
+ struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+ cmd = ms->current_req;
+ if (DEBUG_TARGET(cmd)) {
+ printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
+ cmd->result, ms->data_ptr, cmd->request_bufflen);
+ if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)
+ && cmd->request_buffer != 0) {
+ unsigned char *b = cmd->request_buffer;
+ printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",
+ b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+ }
+ }
+ tp->current_req = 0;
+ cmd->SCp.this_residual -= ms->data_ptr;
+ ms->current_req = NULL;
+ mesh_completed(ms, cmd);
+ if (ms->phase != reselecting) {
+ ms->phase = idle;
+ mesh_start(ms);
+ }
+}
+
+static void
+mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd)
+{
+ if (ms->completed_q == NULL)
+ ms->completed_q = cmd;
+ else
+ ms->completed_qtail->host_scribble = (void *) cmd;
+ ms->completed_qtail = cmd;
+ cmd->host_scribble = NULL;
+ queue_task(&ms->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * Set up DMA commands for transferring data.
+ */
+static void
+set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd)
+{
+ int i, dma_cmd, total, off, dtot;
+ struct scatterlist *scl;
+ struct dbdma_cmd *dcmds;
+
+ dma_cmd = ms->data_goes_out? OUTPUT_MORE: INPUT_MORE;
+ dcmds = ms->dma_cmds;
+ dtot = 0;
+ cmd->SCp.this_residual = cmd->request_bufflen;
+ if (cmd->use_sg > 0) {
+ total = 0;
+ scl = (struct scatterlist *) cmd->buffer;
+ off = ms->data_ptr;
+ for (i = 0; i < cmd->use_sg; ++i, ++scl) {
+ total += scl->length;
+ if (off >= scl->length) {
+ off -= scl->length;
+ continue;
+ }
+ if (scl->length > 0xffff)
+ panic("mesh: scatterlist element >= 64k");
+ st_le16(&dcmds->req_count, scl->length - off);
+ st_le16(&dcmds->command, dma_cmd);
+ st_le32(&dcmds->phy_addr,
+ virt_to_phys(scl->address) + off);
+ dcmds->xfer_status = 0;
+ ++dcmds;
+ dtot += scl->length - off;
+ off = 0;
+ }
+ } else if (ms->data_ptr < cmd->request_bufflen) {
+ dtot = cmd->request_bufflen - ms->data_ptr;
+ if (dtot > 0xffff)
+ panic("mesh: transfer size >= 64k");
+ st_le16(&dcmds->req_count, dtot);
+ st_le32(&dcmds->phy_addr,
+ virt_to_phys(cmd->request_buffer) + ms->data_ptr);
+ dcmds->xfer_status = 0;
+ ++dcmds;
+ }
+ if (dtot == 0) {
+ /* Either the target has overrun our buffer,
+ or the caller didn't provide a buffer. */
+ static char mesh_extra_buf[64];
+
+ if (cmd->request_bufflen != 0)
+ printk(KERN_DEBUG "mesh: target %d overrun, "
+ "data_ptr=%x total=%x goes_out=%d\n",
+ ms->conn_tgt, ms->data_ptr,
+ cmd->request_bufflen, ms->data_goes_out);
+ dtot = sizeof(mesh_extra_buf);
+ st_le16(&dcmds->req_count, dtot);
+ st_le32(&dcmds->phy_addr, virt_to_phys(mesh_extra_buf));
+ dcmds->xfer_status = 0;
+ ++dcmds;
+ }
+ dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
+ st_le16(&dcmds[-1].command, dma_cmd);
+ memset(dcmds, 0, sizeof(*dcmds));
+ st_le16(&dcmds->command, DBDMA_STOP);
+ ms->dma_count = dtot;
+}
+
+static void
+halt_dma(struct mesh_state *ms)
+{
+ volatile struct dbdma_regs *md = ms->dma;
+ volatile struct mesh_regs *mr = ms->mesh;
+ int t, nb;
+
+ if (!ms->data_goes_out) {
+ /* wait a little while until the fifo drains */
+ t = 50;
+ while (t > 0 && mr->fifo_count != 0
+ && (in_le32(&md->status) & ACTIVE) != 0) {
+ --t;
+ udelay(1);
+ }
+ }
+ out_le32(&md->control, RUN << 16); /* turn off RUN bit */
+ nb = (mr->count_hi << 8) + mr->count_lo;
+ if (ms->data_goes_out)
+ nb += mr->fifo_count;
+ /* nb is the number of bytes not yet transferred
+ to/from the target. */
+ ms->data_ptr -= nb;
+ if (ms->data_ptr < 0) {
+ printk(KERN_ERR "mesh: halt_dma: data_ptr=%d (nb=%d, ms=%p)\n",
+ ms->data_ptr, nb, ms);
+ ms->data_ptr = 0;
+ }
+ ms->dma_started = 0;
+}
+
+/*
+ * Work out whether we expect data to go out from the host adaptor or into it.
+ * (If this information is available from somewhere else in the scsi
+ * code, somebody please let me know :-)
+ */
+static int
+data_goes_out(Scsi_Cmnd *cmd)
+{
+ switch (cmd->cmnd[0]) {
+ case MODE_SELECT:
+ case MODE_SELECT_10:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12: /* any others? */
+ return 1;
+ default:
+ return 0;
+ }
+}
--- /dev/null
+/*
+ * mesh.h: definitions for the driver for the MESH SCSI bus adaptor
+ * (Macintosh Enhanced SCSI Hardware) found on Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#ifndef _MESH_H
+#define _MESH_H
+
+extern struct proc_dir_entry proc_scsi_mesh;
+
+int mesh_detect(Scsi_Host_Template *);
+int mesh_command(Scsi_Cmnd *);
+int mesh_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int mesh_abort(Scsi_Cmnd *);
+int mesh_reset(Scsi_Cmnd *, unsigned int);
+
+#define SCSI_MESH { \
+ NULL, /* next */ \
+ NULL, /* usage_count */ \
+ &proc_scsi_mesh, /* proc_dir */ \
+ NULL, /* proc_info */ \
+ "MESH", /* name */ \
+ mesh_detect, /* detect */ \
+ NULL, /* release */ \
+ NULL, /* info */ \
+ mesh_command, /* command */ \
+ mesh_queue, /* queuecommand */ \
+ mesh_abort, /* abort */ \
+ mesh_reset, /* reset */ \
+ NULL, /* slave_attach */ \
+ NULL, /* bios_param */ \
+ 20, /* can_queue */ \
+ 7, /* this_id */ \
+ SG_ALL, /* sg_tablesize */ \
+ 2, /* cmd_per_lun */ \
+ 0, /* present */ \
+ 0, /* unchecked_isa_dma */ \
+ DISABLE_CLUSTERING, /* use_clustering */ \
+}
+
+/*
+ * Registers in the MESH controller.
+ */
+
+struct mesh_regs {
+ unsigned char count_lo;
+ char pad0[15];
+ unsigned char count_hi;
+ char pad1[15];
+ unsigned char fifo;
+ char pad2[15];
+ unsigned char sequence;
+ char pad3[15];
+ unsigned char bus_status0;
+ char pad4[15];
+ unsigned char bus_status1;
+ char pad5[15];
+ unsigned char fifo_count;
+ char pad6[15];
+ unsigned char exception;
+ char pad7[15];
+ unsigned char error;
+ char pad8[15];
+ unsigned char intr_mask;
+ char pad9[15];
+ unsigned char interrupt;
+ char pad10[15];
+ unsigned char source_id;
+ char pad11[15];
+ unsigned char dest_id;
+ char pad12[15];
+ unsigned char sync_params;
+ char pad13[15];
+ unsigned char mesh_id;
+ char pad14[15];
+ unsigned char sel_timeout;
+ char pad15[15];
+};
+
+/* Bits in the sequence register. */
+#define SEQ_DMA_MODE 0x80 /* use DMA for data transfer */
+#define SEQ_TARGET 0x40 /* put the controller into target mode */
+#define SEQ_ATN 0x20 /* assert ATN signal */
+#define SEQ_ACTIVE_NEG 0x10 /* use active negation on REQ/ACK */
+#define SEQ_CMD 0x0f /* command bits: */
+#define SEQ_ARBITRATE 1 /* get the bus */
+#define SEQ_SELECT 2 /* select a target */
+#define SEQ_COMMAND 3 /* send a command */
+#define SEQ_STATUS 4 /* receive status */
+#define SEQ_DATAOUT 5 /* send data */
+#define SEQ_DATAIN 6 /* receive data */
+#define SEQ_MSGOUT 7 /* send a message */
+#define SEQ_MSGIN 8 /* receive a message */
+#define SEQ_BUSFREE 9 /* look for bus free */
+#define SEQ_ENBPARITY 0x0a /* enable parity checking */
+#define SEQ_DISPARITY 0x0b /* disable parity checking */
+#define SEQ_ENBRESEL 0x0c /* enable reselection */
+#define SEQ_DISRESEL 0x0d /* disable reselection */
+#define SEQ_RESETMESH 0x0e /* reset the controller */
+#define SEQ_FLUSHFIFO 0x0f /* clear out the FIFO */
+
+/* Bits in the bus_status0 and bus_status1 registers:
+ these correspond directly to the SCSI bus control signals. */
+#define BS0_REQ 0x20
+#define BS0_ACK 0x10
+#define BS0_ATN 0x08
+#define BS0_MSG 0x04
+#define BS0_CD 0x02
+#define BS0_IO 0x01
+#define BS1_RST 0x80
+#define BS1_BSY 0x40
+#define BS1_SEL 0x20
+
+/* Bus phases defined by the bits in bus_status0 */
+#define BS0_PHASE (BS0_MSG+BS0_CD+BS0_IO)
+#define BP_DATAOUT 0
+#define BP_DATAIN BS0_IO
+#define BP_COMMAND BS0_CD
+#define BP_STATUS (BS0_CD+BS0_IO)
+#define BP_MSGOUT (BS0_MSG+BS0_CD)
+#define BP_MSGIN (BS0_MSG+BS0_CD+BS0_IO)
+
+/* Bits in the exception register. */
+#define EXC_SELWATN 0x20 /* (as target) we were selected with ATN */
+#define EXC_SELECTED 0x10 /* (as target) we were selected w/o ATN */
+#define EXC_RESELECTED 0x08 /* (as initiator) we were reselected */
+#define EXC_ARBLOST 0x04 /* we lost arbitration */
+#define EXC_PHASEMM 0x02 /* SCSI phase mismatch */
+#define EXC_SELTO 0x01 /* selection timeout */
+
+/* Bits in the error register */
+#define ERR_UNEXPDISC 0x40 /* target unexpectedly disconnected */
+#define ERR_SCSIRESET 0x20 /* SCSI bus got reset on us */
+#define ERR_SEQERR 0x10 /* we did something the chip didn't like */
+#define ERR_PARITY 0x01 /* parity error was detected */
+
+/* Bits in the interrupt and intr_mask registers */
+#define INT_ERROR 0x04 /* error interrupt */
+#define INT_EXCEPTION 0x02 /* exception interrupt */
+#define INT_CMDDONE 0x01 /* command done interrupt */
+
+/* Fields in the sync_params register */
+#define SYNC_OFF(x) ((x) >> 4) /* offset field */
+#define SYNC_PER(x) ((x) & 0xf) /* period field */
+#define SYNC_PARAMS(o, p) (((o) << 4) | (p))
+#define ASYNC_PARAMS 2 /* sync_params value for async xfers */
+
+/*
+ * Assuming a clock frequency of 50MHz:
+ *
+ * The transfer period with SYNC_PER(sync_params) == x
+ * is (x + 2) * 40ns, except that x == 0 gives 100ns.
+ *
+ * The units of the sel_timeout register are 10ms.
+ */
+
+
+#endif /* _MESH_H */
for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
if(cpnt->device == SDp) {
kdev_t devi = MKDEV(MAJOR_NR, i);
+ struct super_block * sb = get_super(devi);
/*
* Since the cdrom is read-only, no need to sync the device.
* We should be kind to our buffer cache, however.
*/
- invalidate_inodes(devi);
+ if (sb) invalidate_inodes(sb);
invalidate_buffers(devi);
/*
bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL
bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
fi
+bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
endmenu
inode->i_size = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(ino);
return written;
}
inode->i_size = pos;
filp->f_pos = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(ino);
return written;
}
s->s_dev = dev;
s->s_op = &affs_sops;
- s->s_mounted = iget(s,root_block);
+ s->s_root = d_alloc_root(iget(s,root_block),NULL);
s->s_dirt = 1;
unlock_super(s);
- if (!(s->s_mounted)) {
+ if (!(s->s_root)) {
s->s_dev = 0;
printk(KERN_ERR "AFFS: get root inode failed\n");
MOD_DEC_USE_COUNT;
/* create data zones if the fs is mounted r/w */
if (!(s->s_flags & MS_RDONLY)) {
- ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_mounted)->bm_flag = 0;
+ ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_root->d_inode)->bm_flag = 0;
secs_to_datestamp(CURRENT_TIME,&ROOT_END(s->u.affs_sb.s_root_bh->b_data,
- s->s_mounted)->disk_altered);
+ s->s_root->d_inode)->disk_altered);
affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5);
mark_buffer_dirty(s->u.affs_sb.s_root_bh,1);
affs_make_zones(s);
pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
- inode->i_dirt = 0;
if (!inode->i_nlink)
return;
if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
inode->i_ino = block;
inode->i_op = NULL;
inode->i_blocks = 0;
FILE_END(link_bh->b_data,link)->link_chain = ntohl(inode->i_ino);
affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
link->i_version = ++event;
- link->i_dirt = 1;
+ mark_inode_dirty(link);
mark_buffer_dirty(link_bh,1);
}
affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
dir->i_mtime = dir->i_atime = dir->i_ctime = CURRENT_TIME;
unlock_super(inode->i_sb);
- dir->i_dirt = 1;
- inode->i_dirt = 1;
+ mark_inode_dirty(dir);
+ mark_inode_dirty(inode);
mark_buffer_dirty(dir_bh,1);
mark_buffer_dirty(inode_bh,1);
goto unlink_done;
inode->i_nlink=0;
- inode->i_dirt=1;
+ mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_version = ++event;
- dir->i_dirt=1;
+ mark_inode_dirty(dir);
unlink_done:
affs_brelse(bh);
iput(inode);
if (error) {
iput(dir);
inode->i_nlink = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -ENOSPC;
}
if (error) {
iput(dir);
inode->i_nlink = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return error;
}
goto rmdir_done;
inode->i_nlink=0;
- inode->i_dirt=1;
+ mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_version = ++event;
- dir->i_dirt=1;
+ mark_inode_dirty(dir);
rmdir_done:
iput(dir);
iput(inode);
if (!bh) {
iput(dir);
inode->i_nlink = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return -EIO;
}
*p = 0;
mark_buffer_dirty(bh,1);
affs_brelse(bh);
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
bh = affs_find_entry(dir,name,len,&tmp);
if (bh) {
inode->i_nlink = 0;
i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
if (i) {
inode->i_nlink = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
affs_brelse(bh);
iput(dir);
error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
if (error) {
inode->i_nlink = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
iput(dir);
iput(inode);
goto retry;
mark_buffer_dirty(new_bh,1);
new_dir->i_version = ++event;
- new_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
new_inode->i_nlink = 0;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
}
retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
AFFS_I2HSIZE(old_dir)) + 6,old_ino,
new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
new_dir->i_version = ++event;
old_dir->i_version = ++event;
- new_dir->i_dirt = 1;
- old_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
+ mark_inode_dirty(old_dir);
mark_buffer_dirty(old_bh,1);
end_rename:
ofinode->i_size = inode->i_size;
ofinode->i_uid = inode->i_uid;
ofinode->i_gid = inode->i_gid;
- ofinode->i_dirt = 1;
+ mark_inode_dirty(ofinode);
link_key = ofinode->i_ino;
/* Let all remaining links point to the new file */
"Inode %d in link chain is not a link",
key);
ofinode->u.affs_i.i_original = link_key;
- ofinode->i_dirt = 1;
+ mark_inode_dirty(ofinode);
FILE_END(nbh->b_data,inode)->original = htonl(link_key);
} else
affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
struct super_block *autofs_read_super(struct super_block *s, void *data,
int silent)
{
+ struct inode * root_inode;
+ struct dentry * root;
+ struct file * pipe;
int pipefd;
struct autofs_sb_info *sbi;
int minproto, maxproto;
MOD_INC_USE_COUNT;
lock_super(s);
+ /* Super block already completed? */
+ if (s->s_root)
+ goto out_unlock;
+
sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
- if ( !sbi ) {
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ if ( !sbi )
+ goto fail_unlock;
DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
s->u.generic_sbp = sbi;
s->s_blocksize_bits = 10;
s->s_magic = AUTOFS_SUPER_MAGIC;
s->s_op = &autofs_sops;
- unlock_super(s);
- s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
- if (!s->s_root) {
- printk("autofs: get root inode failed\n");
- kfree(sbi);
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ s->s_root = NULL;
+ unlock_super(s); /* shouldn't we keep it locked a while longer? */
+
+ /*
+ * Get the root inode and dentry, but defer checking for errors.
+ */
+ root_inode = iget(s, AUTOFS_ROOT_INO);
+ root = d_alloc_root(root_inode, NULL);
+ pipe = NULL;
- if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root)
+ goto out_dput;
+
+ if (!root)
+ goto fail_iput;
+
+ /* Can this call block? */
+ if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
printk("autofs: called with bogus options\n");
- dput(s->s_root);
- kfree(sbi);
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
+ goto fail_dput;
}
- if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
+ /* Couldn't this be tested earlier? */
+ if ( minproto > AUTOFS_PROTO_VERSION ||
+ maxproto < AUTOFS_PROTO_VERSION ) {
printk("autofs: kernel does not match daemon version\n");
- dput(s->s_root);
- kfree(sbi);
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
+ goto fail_dput;
}
DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
- sbi->pipe = fget(pipefd);
- if ( !sbi->pipe || !sbi->pipe->f_op || !sbi->pipe->f_op->write ) {
- if ( sbi->pipe ) {
- fput(sbi->pipe);
- printk("autofs: pipe file descriptor does not contain proper ops\n");
- } else {
- printk("autofs: could not open pipe file descriptor\n");
- }
- dput(s->s_root);
- kfree(sbi);
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
+ pipe = fget(pipefd);
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root)
+ goto out_fput;
+
+ if ( !pipe ) {
+ printk("autofs: could not open pipe file descriptor\n");
+ goto fail_dput;
}
+ if ( !pipe->f_op || !pipe->f_op->write )
+ goto fail_fput;
+ sbi->pipe = pipe;
+
+ /*
+ * Success! Install the root dentry now to indicate completion.
+ */
+ s->s_root = root;
+ return s;
+
+ /*
+ * Success ... somebody else completed the super block for us.
+ */
+out_unlock:
+ unlock_super(s);
+ goto out_dec;
+out_fput:
+ if (pipe)
+ fput(pipe);
+out_dput:
+ if (root)
+ dput(root);
+ else
+ iput(root_inode);
+out_dec:
+ MOD_DEC_USE_COUNT;
return s;
+
+ /*
+ * Failure ... clear the s_dev slot and clean up.
+ */
+fail_fput:
+ printk("autofs: pipe file descriptor does not contain proper ops\n");
+ /*
+ * fput() can block, so we clear the super block first.
+ */
+ s->s_dev = 0;
+ fput(pipe);
+ /* fall through */
+fail_dput:
+ /*
+ * dput() can block, so we clear the super block first.
+ */
+ s->s_dev = 0;
+ dput(root);
+ goto fail_free;
+fail_iput:
+ printk("autofs: get root dentry failed\n");
+ /*
+ * iput() can block, so we clear the super block first.
+ */
+ s->s_dev = 0;
+ iput(root_inode);
+fail_free:
+ kfree(sbi);
+ goto fail_dec;
+fail_unlock:
+ unlock_super(s);
+fail_dec:
+ s->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return NULL;
}
static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
/*
* Force 16 byte _final_ alignment here for generality.
+ * Leave an extra 16 bytes free so that on the PowerPC we
+ * can move the aux table up to start on a 16-byte boundary.
*/
- sp = (elf_addr_t *) (~15UL & (unsigned long) p);
+ sp = (elf_addr_t *) ((~15UL & (unsigned long) p) - 16UL);
csp = sp;
csp -= exec ? DLINFO_ITEMS*2 : 2;
csp -= envc+1;
csp -= argc+1;
csp -= (!ibcs ? 3 : 1); /* argc itself */
if ((unsigned long)csp & 15UL) {
- sp -= (16UL - ((unsigned long)csp & 15UL)) / sizeof(*sp);
+ sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
}
/*
static struct list_head dentry_hashtable[D_HASHSIZE];
static LIST_HEAD(dentry_unused);
-void d_free(struct dentry *dentry)
+static inline void d_free(struct dentry *dentry)
{
kfree(dentry->d_name.name);
kfree(dentry);
memcpy(str, name->name, name->len);
str[name->len] = 0;
- dentry->d_count = 0;
+ dentry->d_count = 1;
dentry->d_flags = 0;
dentry->d_inode = NULL;
- dentry->d_parent = parent;
+ dentry->d_parent = dget(parent);
dentry->d_mounts = dentry;
dentry->d_covers = dentry;
INIT_LIST_HEAD(&dentry->d_hash);
if (root_inode) {
res = d_alloc(NULL, &(const struct qstr) { "/", 1, 0 });
res->d_parent = res;
- res->d_count = 1;
d_instantiate(res, root_inode);
}
return res;
if (parent->d_op && parent->d_op->d_compare) {
if (parent->d_op->d_compare(parent, &dentry->d_name, name))
continue;
- return dentry;
+ } else {
+ if (dentry->d_name.len != len)
+ continue;
+ if (memcmp(dentry->d_name.name, str, len))
+ continue;
}
- if (dentry->d_name.len != len)
- continue;
- if (memcmp(dentry->d_name.name, str, len))
- continue;
- return dentry;
+ return dget(dentry->d_mounts);
}
return NULL;
}
void d_add(struct dentry * entry, struct inode * inode)
{
- struct dentry * parent = dget(entry->d_parent);
+ struct dentry * parent = entry->d_parent;
list_add(&entry->d_hash, d_hash(parent, entry->d_name.hash));
d_instantiate(entry, inode);
*mm = *current->mm;
init_new_context(mm);
mm->def_flags = 0; /* should future lockings be kept? */
- mm->cpu_vm_mask = (1 << smp_processor_id());
+ mm->cpu_vm_mask = (1UL << smp_processor_id());
mm->count = 1;
mm->mmap = mm->mmap_cache = NULL;
mm->total_vm = 0;
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
- unsigned int block, i, f_pos, offset, inode_number;
+ unsigned int block, i, f_pos, offset,
+ inode_number = 0; /* shut gcc up */
struct buffer_head * bh;
unsigned int old_offset;
int dlen, rrflag, match;
char * dpnt;
- struct iso_directory_record * de;
+ struct iso_directory_record * de = NULL; /* shut gcc up */
+ char de_not_in_buf = 0; /* true if de is in kmalloc'd memory */
char c;
*ino = 0;
if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
while (f_pos < dir->i_size) {
- de = (struct iso_directory_record *) (bh->b_data + offset);
- inode_number = (block << bufbits) + (offset & (bufsize - 1));
- /* If byte is zero, this is the end of file, or time to move to
- the next sector. Usually 2048 byte boundaries. */
+ /* if de is in kmalloc'd memory, do not point to the
+ next de, instead we will move to the next sector */
+ if(!de_not_in_buf) {
+ de = (struct iso_directory_record *)
+ (bh->b_data + offset);
+ inode_number = (block << bufbits)
+ + (offset & (bufsize - 1));
+ }
+
+ /* If byte is zero, or we had to fetch this de past
+ the end of the buffer, this is the end of file, or
+ time to move to the next sector. Usually 2048 byte
+ boundaries. */
- if (*((unsigned char *) de) == 0) {
+ if (*((unsigned char *) de) == 0 || de_not_in_buf) {
+ if(de_not_in_buf) {
+ /* james@bpgc.com: Since we slopped
+ past the end of the last buffer, we
+ must start some way into the new
+ one */
+ de_not_in_buf = 0;
+ kfree(de);
+ offset -= bufsize;
+ }
+ else
+ offset = 0;
brelse(bh);
- offset = 0;
f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
- + ISOFS_BLOCK_SIZE);
+ + ISOFS_BLOCK_SIZE) + offset;
if( f_pos >= dir->i_size )
{
offset += *((unsigned char *) de);
f_pos += *((unsigned char *) de);
- /* Handle case where the directory entry spans two blocks.
- Usually 1024 byte boundaries */
+ /* james@bpgc.com: new code to handle case where the
+ directory entry spans two blocks. Usually 1024
+ byte boundaries */
if (offset >= bufsize) {
- printk("Directory entry extends past end of iso9660 block\n");
- return 0;
+ struct buffer_head *bh_next;
+
+ /* james@bpgc.com: read the next block, and
+ copy the split de into a newly kmalloc'd
+ buffer */
+ block = isofs_bmap(dir,f_pos>>bufbits);
+ if (!block ||
+ !(bh_next = bread(dir->i_dev,block,bufsize)))
+ return NULL;
+
+ de = (struct iso_directory_record *)
+ kmalloc(offset - old_offset, GFP_KERNEL);
+ memcpy((char *)de, bh->b_data + old_offset,
+ bufsize - old_offset);
+ memcpy((char *)de + bufsize - old_offset,
+ bh_next->b_data, offset - bufsize);
+ brelse(bh_next);
+ de_not_in_buf = 1;
}
dlen = de->name_len[0];
find_rock_ridge_relocation(de,dir));
}
*ino = inode_number;
+ if(de_not_in_buf)
+ kfree(de);
return bh;
}
}
out:
brelse(bh);
+ if(de_not_in_buf)
+ kfree(de);
return NULL;
}
#include <asm/uaccess.h>
static int isofs_readlink(struct inode *, char *, int);
+static struct dentry * isofs_follow_link(struct inode * inode, struct dentry *base);
/*
* symlinks can't do much...
NULL, /* mknod */
NULL, /* rename */
isofs_readlink, /* readlink */
+ isofs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
buflen = 1023;
pnt = get_rock_ridge_symlink(inode);
- iput(inode);
if (!pnt)
return 0;
kfree(pnt);
return i;
}
+
+static struct dentry * isofs_follow_link(struct inode * inode, struct dentry *base)
+{
+ char * pnt;
+
+ pnt = get_rock_ridge_symlink(inode);
+
+ if(!pnt) {
+ dput(base);
+ return ERR_PTR(-ELOOP);
+ }
+
+ base = lookup_dentry(pnt, base, 1);
+
+ kfree(pnt);
+ return base;
+}
down(&dir->i_sem);
result = d_lookup(parent, name);
if (!result) {
- int error;
- result = d_alloc(parent, name);
- result->d_count++;
- error = dir->i_op->lookup(dir, result);
- result->d_count--;
- if (error) {
- d_free(result);
- result = ERR_PTR(error);
- }
+ struct dentry * dentry = d_alloc(parent, name);
+ int error = dir->i_op->lookup(dir, dentry);
+ result = ERR_PTR(error);
+ if (!error)
+ result = dget(dentry->d_mounts);
+ dput(dentry);
}
up(&dir->i_sem);
return result;
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
int validated, (*revalidate)(struct dentry *) = dentry->d_op->d_revalidate;
- dentry->d_count++;
validated = revalidate(dentry) || d_invalidate(dentry);
- dput(dentry);
- if (!validated)
+ if (!validated) {
+ dput(dentry);
dentry = NULL;
+ }
}
return dentry;
}
result = parent;
}
}
- return result;
+ return dget(result);
}
/* In difference to the former version, lookup() no longer eats the dir. */
-static struct dentry * lookup(struct dentry * dir, struct qstr * name)
+static inline struct dentry * lookup(struct dentry * dir, struct qstr * name)
{
struct dentry * result;
result = reserved_lookup(dir, name);
if (result)
- goto done_noerror;
+ goto done;
result = cached_lookup(dir, name);
if (result)
- goto done_noerror;
+ goto done;
result = real_lookup(dir, name);
- if (!IS_ERR(result)) {
-done_noerror:
- result = dget(result->d_mounts);
- }
+done:
return result;
}
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
error = dir->i_op->create(dir, dentry, mode);
- /* Don't check for write permission */
+ /* Don't check for write permission, don't truncate */
acc_mode = 0;
+ flag &= ~O_TRUNC;
}
up(&dir->i_sem);
if (error)
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
}
- inode->i_dirt = 1;
-
+ mark_inode_dirty(inode);
+
DPRINTK("ncp_file_read: exit %s\n", NCP_ISTRUCT(inode)->entryName);
return already_read;
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
-
+ mark_inode_dirty(inode);
+
file->f_pos = pos;
if (pos > inode->i_size) {
}
if ((data->ncp_fd >= NR_OPEN)
|| ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL)
- || (!S_ISSOCK(ncp_filp->f_inode->i_mode))) {
+ || (!S_ISSOCK(ncp_filp->f_dentry->d_inode->i_mode))) {
printk("ncp_read_super: invalid ncp socket\n");
sb->s_dev = 0;
return NULL;
ncp_init_root(server);
- if (!(sb->s_mounted = iget(sb, ncp_info_ino(server,
- &(server->root))))) {
+ if (!(sb->s_root = d_alloc_root(iget(sb,ncp_info_ino(server,
+ &(server->root))),NULL))) {
sb->s_dev = 0;
printk("ncp_read_super: get root inode failed\n");
goto disconnect;
static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
unsigned long address, int no_share)
{
- struct inode *inode = area->vm_inode;
+ struct inode *inode = area->vm_dentry->d_inode;
unsigned long page;
unsigned int clear;
unsigned long tmp;
return -EACCES;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
vma->vm_dentry = dget(file->f_dentry);
struct ncp_reply_header reply;
file = server->ncp_filp;
- inode = file->f_inode;
+ inode = file->f_dentry->d_inode;
sock = &inode->u.socket_i;
if (!sock) {
printk("ncp_rpc_call: socki_lookup failed\n");
static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
struct nfs_sattr sattr;
- struct nfs_fattr fattr;
- struct nfs_fh fhandle;
- struct inode * inode;
int error;
dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
if (error)
return error;
- inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
-
nfs_invalidate_dircache(dir);
- d_instantiate(dentry, inode);
+ /* this looks _funny_ doesn't it? But: nfs_proc_symlynk()
+ * only fills in sattr, not fattr. Thus nfs_fhget() cannot be
+ * called, it would be pointless, without a valid fattr
+ * argument. Other possibility: call nfs_proc_lookup()
+ * HERE. But why? If somebody wants to reference this
+ * symlink, the cached_lookup() will fail, and
+ * nfs_proc_symlink() will be called anyway.
+ */
+ d_drop(dentry);
return 0;
}
copy_to_user(buffer, res, len);
put_user('\0', buffer + len);
error = len;
+ kfree(mem);
}
- kfree(mem);
return error;
}
if (error) {
dput(base);
- kfree(mem);
return ERR_PTR(error);
}
path = kmalloc(len + 1, GFP_KERNEL);
int error;
lock_kernel();
- error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
- if (error)
- goto out;
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
error = -EBADF;
else if (!(dentry = file->f_dentry))
else if (!inode->i_sb->s_op->statfs)
error = -ENOSYS;
else
- inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
-out:
+ error = inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
unlock_kernel();
return error;
}
endif
endif
+ifeq ($(CONFIG_PROC_DEVICETREE),y)
+O_OBJS += proc_devtree.o
+endif
+
include $(TOPDIR)/Rules.make
-/* $Id: openpromfs.c,v 1.20 1997/07/22 06:40:07 davem Exp $
+/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
--- /dev/null
+/*
+ * proc_devtree.c - handles /proc/device-tree
+ *
+ * Copyright 1997 Paul Mackerras
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <asm/prom.h>
+#include <asm/uaccess.h>
+
+static struct proc_dir_entry *proc_device_tree;
+
+/*
+ * Supply data on a read from /proc/device-tree/node/property.
+ */
+static int property_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct property *pp = data;
+ int n;
+
+ if (off >= pp->length) {
+ *eof = 1;
+ return 0;
+ }
+ n = pp->length - off;
+ if (n > count)
+ n = count;
+ else
+ *eof = 1;
+ memcpy(page, pp->value + off, n);
+ *start = page;
+ return n;
+}
+
+/*
+ * For a node with a name like "gc@10", we make symlinks called "gc"
+ * and "@10" to it.
+ */
+
+static int devtree_readlink(struct inode *, char *, int);
+static struct dentry *devtree_follow_link(struct inode *, struct dentry *);
+
+struct inode_operations devtree_symlink_inode_operations = {
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ devtree_readlink, /* readlink */
+ devtree_follow_link, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
+
+static struct dentry *devtree_follow_link(struct inode *inode,
+ struct dentry *base)
+{
+ struct proc_dir_entry * de;
+ char *link;
+
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
+ link = (char *) de->data;
+ return lookup_dentry(link, base, 1);
+}
+
+static int devtree_readlink(struct inode *inode, char *buffer, int buflen)
+{
+ struct proc_dir_entry * de;
+ char *link;
+ int linklen;
+
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
+ link = (char *) de->data;
+ linklen = strlen(link);
+ if (linklen > buflen)
+ linklen = buflen;
+ if (copy_to_user(buffer, link, linklen))
+ return -EFAULT;
+ return linklen;
+}
+
+/*
+ * Process a node, adding entries for its children and its properties.
+ */
+static void add_node(struct device_node *np, struct proc_dir_entry *de)
+{
+ struct property *pp;
+ struct proc_dir_entry *ent;
+ struct device_node *child, *sib;
+ const char *p, *at;
+ int l;
+ struct proc_dir_entry *list, **lastp, *al;
+
+ lastp = &list;
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ /*
+ * Unfortunately proc_register puts each new entry
+ * at the beginning of the list. So we rearrange them.
+ */
+ ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+ if (ent == 0)
+ break;
+ memset(ent, 0, sizeof(struct proc_dir_entry));
+ ent->name = pp->name;
+ ent->namelen = strlen(pp->name);
+ ent->mode = S_IFREG | S_IRUGO;
+ ent->nlink = 1;
+ ent->data = pp;
+ ent->read_proc = property_read_proc;
+ ent->size = pp->length;
+ proc_register(de, ent);
+ *lastp = ent;
+ lastp = &ent->next;
+ }
+ for (child = np->child; child != 0; child = child->sibling) {
+ p = strrchr(child->full_name, '/');
+ if (p == 0)
+ p = child->full_name;
+ else
+ ++p;
+ /* chop off '@0' if the name ends with that */
+ l = strlen(p);
+ if (l > 2 && p[l-2] == '@' && p[l-1] == '0')
+ l -= 2;
+ ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+ if (ent == 0)
+ break;
+ memset(ent, 0, sizeof(struct proc_dir_entry));
+ ent->name = p;
+ ent->namelen = l;
+ ent->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ ent->nlink = 2;
+ proc_register(de, ent);
+ *lastp = ent;
+ lastp = &ent->next;
+ add_node(child, ent);
+
+ /*
+ * If we left the address part on the name, consider
+ * adding symlinks from the name and address parts.
+ */
+ if (p[l] != 0 || (at = strchr(p, '@')) == 0)
+ continue;
+
+ /*
+ * If this is the first node with a given name property,
+ * add a symlink with the name property as its name.
+ */
+ for (sib = np->child; sib != child; sib = sib->sibling)
+ if (strcmp(sib->name, child->name) == 0)
+ break;
+ if (sib == child && strncmp(p, child->name, l) != 0) {
+ al = kmalloc(sizeof(struct proc_dir_entry),
+ GFP_KERNEL);
+ if (al == 0)
+ break;
+ memset(al, 0, sizeof(struct proc_dir_entry));
+ al->name = child->name;
+ al->namelen = strlen(child->name);
+ al->mode = S_IFLNK | S_IRUGO | S_IXUGO;
+ al->nlink = 1;
+ al->data = (void *) ent->name;
+ al->ops = &devtree_symlink_inode_operations;
+ proc_register(de, al);
+ *lastp = al;
+ lastp = &al->next;
+ }
+
+ /*
+ * Add another directory with the @address part as its name.
+ */
+ al = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+ if (al == 0)
+ break;
+ memset(al, 0, sizeof(struct proc_dir_entry));
+ al->name = at;
+ al->namelen = strlen(at);
+ al->mode = S_IFLNK | S_IRUGO | S_IXUGO;
+ al->nlink = 1;
+ al->data = (void *) ent->name;
+ al->ops = &devtree_symlink_inode_operations;
+ proc_register(de, al);
+ *lastp = al;
+ lastp = &al->next;
+ }
+ *lastp = 0;
+ de->subdir = list;
+}
+
+/*
+ * Called on initialization to set up the /proc/device-tree subtree
+ */
+void proc_device_tree_init(void)
+{
+ struct device_node *root;
+
+ proc_device_tree = create_proc_entry("device-tree", S_IFDIR, 0);
+ if (proc_device_tree == 0)
+ return;
+ root = find_path_device("/");
+ if (root == 0) {
+ printk(KERN_ERR "/proc/device-tree: can't find root\n");
+ return;
+ }
+ add_node(root, proc_device_tree);
+}
0, &proc_omirr_inode_operations
};
#endif
+#ifdef __powerpc__
+static struct proc_dir_entry proc_root_ppc_htab = {
+ PROC_PPC_HTAB, 8, "ppc_htab",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_ppc_htab_inode_operations
+};
+#endif
void proc_root_init(void)
{
}
proc_tty_init();
+#ifdef __powerpc__
+ proc_register(&proc_root, &proc_root_ppc_htab);
+#endif
+#ifdef CONFIG_PROC_DEVICETREE
+ proc_device_tree_init();
+#endif
}
/*
if (!IS_RDONLY(inode))
inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
-
+ mark_inode_dirty(inode);
+
DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->name);
return already_read;
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
-
+ mark_inode_dirty(inode);
+
file->f_pos = pos;
if (pos > inode->i_size)
sb->s_dev = 0;
return NULL;
}
- if (!S_ISSOCK(filp->f_inode->i_mode))
+ if (!S_ISSOCK(filp->f_dentry->d_inode->i_mode))
{
printk("smb_read_super: not a socket!\n");
sb->s_dev = 0;
}
smb_init_root_dirent(server, &(server->root.finfo));
- if (!(sb->s_mounted = iget(sb, smb_info_ino(&(server->root)))))
+ if (!(sb->s_root = d_alloc_root(iget(sb,
+ smb_info_ino(&(server->root))),NULL)))
{
sb->s_dev = 0;
printk("smb_read_super: get root inode failed\n");
smb_file_mmap_nopage(struct vm_area_struct *area,
unsigned long address, int no_share)
{
- struct inode *inode = area->vm_inode;
+ struct inode *inode = area->vm_dentry->d_inode;
unsigned long page;
unsigned int clear;
unsigned long tmp;
if (!IS_RDONLY(inode))
{
inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
vma->vm_dentry = dget(file->f_dentry);
if ((server == NULL)
|| ((file = server->sock_file) == NULL)
- || ((inode = file->f_inode) == NULL)
+ || ((inode = file->f_dentry->d_inode) == NULL)
|| (!S_ISSOCK(inode->i_mode)))
{
printk("smb_catch_keepalive: did not get valid server!\n");
if ((server == NULL)
|| ((file = server->sock_file) == NULL)
- || ((inode = file->f_inode) == NULL)
+ || ((inode = file->f_dentry->d_inode) == NULL)
|| (!S_ISSOCK(inode->i_mode)))
{
printk("smb_dont_catch_keepalive: "
return NULL;
if ((file = server->sock_file) == NULL)
return NULL;
- if ((inode = file->f_inode) == NULL)
+ if ((inode = file->f_dentry->d_inode) == NULL)
return NULL;
return &(inode->u.socket_i);
}
}
}
+#define flush_icache_range(start, end) do { } while (0)
+
/*
* flush all user-space atc entries.
*/
#define ext2_find_next_zero_bit(addr, size, offset) \
find_next_zero_bit((addr), (size), (offset))
+#endif /* !(__MIPSEB__) */
+
/*
* Bitmap functions for the minix filesystem.
* FIXME: These assume that Minix uses the native byte/bitorder.
+ * This limits the Minix filesystem's value for data exchange very much.
*/
#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
#define minix_test_bit(nr,addr) test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
-#endif /* __KERNEL__ */
#endif /* __ASM_MIPS_BITOPS_H */
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1995 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: checksum.h,v 1.5 1997/08/08 20:22:28 miguel Exp $
*/
#ifndef __ASM_MIPS_CHECKSUM_H
#define __ASM_MIPS_CHECKSUM_H
{
#ifdef CONFIG_MIPS_JAZZ
if (mips_machgroup == MACH_GROUP_JAZZ)
- vdma_free(PHYSADDR(addr));
+ vdma_free(vdma_phys2log(PHYSADDR(addr)));
#endif
free_pages(addr, __get_order(size));
}
--- /dev/null
+/*
+ * This is the user-visible SGI GFX interface.
+ *
+ * This must be used verbatim into the GNU libc. It does not include
+ * any kernel-only bits on it.
+ *
+ * miguel@nuclecu.unam.mx
+ */
+
+/* The iocls, yes, they do not make sense, but such is life */
+#define GFX_BASE 100
+#define GFX_GETNUM_BOARDS (GFX_BASE + 1)
+#define GFX_GETBOARD_INFO (GFX_BASE + 2)
+#define GFX_ATTACH_BOARD (GFX_BASE + 3)
+#define GFX_DETACH_BOARD (GFX_BASE + 4)
+#define GFX_IS_MANAGED (GFX_BASE + 5)
+
+#define GFX_MAPALL (GFX_BASE + 10)
+
+#define GFX_INFO_NAME_SIZE 16
+#define GFX_INFO_LABEL_SIZE 16
+
+struct gfx_info {
+ char name [GFX_INFO_NAME_SIZE]; /* board name */
+ char label [GFX_INFO_LABEL_SIZE]; /* label name */
+ unsigned short int xpmax, ypmax; /* screen resolution */
+ unsigned int lenght; /* size of a complete gfx_info for this board */
+};
+
+struct gfx_getboardinfo_args {
+ unsigned int board; /* board number. starting from zero */
+ void *buf; /* pointer to gfx_info */
+ unsigned int len; /* buffer size of buf */
+};
+
+struct gfx_attach_board_args {
+ unsigned int board; /* board number, starting from zero */
+ void *vaddr; /* address where the board registers should be mapped */
+};
+
+#ifdef __KERNEL__
+/* umap.c */
+extern void remove_mapping (struct task_struct *, unsigned long, unsigned long);
+extern void *vmalloc_uncached (unsigned long size);
+extern int vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr);
+#endif
void vdma_set_addr(int channel, long addr);
void vdma_set_count(int channel, int count);
int vdma_get_residue(int channel);
+int vdma_get_enable(int channel);
/*
* some definitions used by the driver functions
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * This file is a mess. Put on your peril sensitive glasses.
- *
- * $Id: keyboard.h,v 1.4 1997/06/16 00:31:46 ralf Exp $
+ * $Id: keyboard.h,v 1.5 1997/08/08 20:22:31 miguel Exp $
*/
#ifndef __ASM_MIPS_KEYBOARD_H
#define __ASM_MIPS_KEYBOARD_H
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/ioport.h>
+#include <asm/bootinfo.h>
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
#define kbd_setkeycode pckbd_setkeycode
#define kbd_getkeycode pckbd_getkeycode
#define kbd_unexpected_up pckbd_unexpected_up
#define kbd_leds pckbd_leds
#define kbd_init_hw pckbd_init_hw
+#define kbd_sysrq_xlate pckbd_sysrq_xlate
-/*
- * The default IO slowdown is doing 'inb()'s from 0x61, which should be
- * safe. But as that is the keyboard controller chip address, we do our
- * slowdowns here by doing short jumps: the keyboard controller should
- * be able to keep up
- */
-#define REALLY_SLOW_IO
-#define SLOW_IO_BY_JUMPING
-#include <asm/io.h>
+#define SYSRQ_KEY 0x54
-/*
- * keyboard controller registers
- */
-#define KBD_STATUS_REG (unsigned int) 0x64
-#define KBD_CNTL_REG (unsigned int) 0x64
-#define KBD_DATA_REG (unsigned int) 0x60
+#define INIT_KBD /* full initialization for the keyboard controller. */
-#ifdef CONFIG_SGI
-#include <asm/segment.h>
-#include <asm/sgihpc.h>
-#endif
-#include <asm/bootinfo.h>
-#include <asm/jazz.h>
+/* Some stoneage hardware needs delays after some operations. */
+#define kbd_pause() do { } while(0)
-#ifdef CONFIG_SGI
-#define KEYBOARD_IRQ 20
-#else
-/* Not true for Jazz machines, we cheat a bit for 'em. */
-#define KEYBOARD_IRQ 1
-#endif
+/* Pointers to keyboard hardware access and init functions. */
+unsigned char (*kbd_read_input)(void);
+void (*kbd_write_output)(unsigned char val);
+void (*kbd_write_command)(unsigned char val);
+unsigned char (*kbd_read_status)(void);
-#ifdef CONFIG_SGI
-#define DISABLE_KBD_DURING_INTERRUPTS 1
-#else
-#define DISABLE_KBD_DURING_INTERRUPTS 0
-#endif
+void (*keyboard_setup)(void);
-#ifndef CONFIG_SGI
-#define KBD_REPORT_ERR
-#endif
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
+#ifdef CONFIG_MIPS_JAZZ
-int (*kbd_inb_p)(unsigned short port);
-int (*kbd_inb)(unsigned short port);
-void (*kbd_outb_p)(unsigned char data, unsigned short port);
-void (*kbd_outb)(unsigned char data, unsigned short port);
+/* Not true for Jazz machines, we cheat a bit for 'em. */
+#define KEYBOARD_IRQ 1
-#ifdef CONFIG_MIPS_JAZZ
-#define INIT_KBD /* full initialization for the keyboard controller. */
+/*
+ * No PS/2 style mouse support for Jazz machines
+ */
-static volatile keyboard_hardware *jazz_kh;
-
-static int
-jazz_kbd_inb_p(unsigned short port)
-{
- int result;
-
- if(port == KBD_DATA_REG)
- result = jazz_kh->data;
- else /* Must be KBD_STATUS_REG */
- result = jazz_kh->command;
- inb(0x80);
-
- return result;
-}
-
-static int
-jazz_kbd_inb(unsigned short port)
-{
- int result;
-
- if(port == KBD_DATA_REG)
- result = jazz_kh->data;
- else /* Must be KBD_STATUS_REG */
- result = jazz_kh->command;
-
- return result;
-}
-
-static void
-jazz_kbd_outb_p(unsigned char data, unsigned short port)
-{
- if(port == KBD_DATA_REG)
- jazz_kh->data = data;
- else if(port == KBD_CNTL_REG)
- jazz_kh->command = data;
- inb(0x80);
-}
-
-static void
-jazz_kbd_outb(unsigned char data, unsigned short port)
-{
- if(port == KBD_DATA_REG)
- jazz_kh->data = data;
- else if(port == KBD_CNTL_REG)
- jazz_kh->command = data;
-}
#endif /* CONFIG_MIPS_JAZZ */
#ifdef CONFIG_SGI
-#define INIT_KBD /* full initialization for the keyboard controller. */
-static volatile struct hpc_keyb *sgi_kh;
-
-static int
-sgi_kbd_inb(unsigned short port)
-{
- int result;
-
- if(port == KBD_DATA_REG)
- result = sgi_kh->data;
- else /* Must be KBD_STATUS_REG */
- result = sgi_kh->command;
-
- return result;
-}
-
-static void
-sgi_kbd_outb(unsigned char data, unsigned short port)
-{
- if(port == KBD_DATA_REG)
- sgi_kh->data = data;
- else if(port == KBD_CNTL_REG)
- sgi_kh->command = data;
-}
+#define DISABLE_KBD_DURING_INTERRUPTS 1
+
+#define KEYBOARD_IRQ 20
+
+/*
+ * Machine specific bits for the PS/2 driver.
+ * Aux device and keyboard share the interrupt on the Indy.
+ */
+
+#define ps2_request_irq() 0
+#define ps2_free_irq(void) do { } while(0);
+
#endif /* CONFIG_SGI */
+#if defined(CONFIG_ACER_PICA_61) || defined(CONFIG_SNI_RM200_PCI) \
+ || defined(CONFIG_DESKSTATION_RPC44) || defined(CONFIG_DESKSTATION_TYNE)
+#define CONF_KEYBOARD_USES_IO_PORTS
+#endif
+
+#ifdef CONF_KEYBOARD_USES_IO_PORTS
/*
* Most other MIPS machines access the keyboard controller via
- * ordinary I/O ports.
+ * memory mapped I/O ports.
*/
-static int
-port_kbd_inb_p(unsigned short port)
-{
- return inb_p(port);
-}
-
-static int
-port_kbd_inb(unsigned short port)
-{
- return inb(port);
-}
-
-static void
-port_kbd_outb_p(unsigned char data, unsigned short port)
-{
- return outb_p(data, port);
-}
-
-static void
-port_kbd_outb(unsigned char data, unsigned short port)
-{
- return outb(data, port);
-}
-
-extern __inline__ void keyboard_setup(void)
-{
-#ifdef CONFIG_MIPS_JAZZ
- if (mips_machgroup == MACH_GROUP_JAZZ) {
- jazz_kh = (void *) JAZZ_KEYBOARD_ADDRESS;
- kbd_inb_p = jazz_kbd_inb_p;
- kbd_inb = jazz_kbd_inb;
- kbd_outb_p = jazz_kbd_outb_p;
- kbd_outb = jazz_kbd_outb;
- /*
- * Enable keyboard interrupts.
- */
- *((volatile u16 *)JAZZ_IO_IRQ_ENABLE) |= JAZZ_IE_KEYBOARD;
- set_cp0_status(IE_IRQ1, IE_IRQ1);
- } else
-#endif
- if (mips_machgroup == MACH_GROUP_ARC || /* this is for Deskstation */
- (mips_machgroup == MACH_GROUP_SNI_RM
- && mips_machtype == MACH_SNI_RM200_PCI)) {
- /*
- * These machines address their keyboard via the normal
- * port address range.
- *
- * Also enable Scan Mode 2.
- */
- kbd_inb_p = port_kbd_inb_p;
- kbd_inb = port_kbd_inb;
- kbd_outb_p = port_kbd_outb_p;
- kbd_outb = port_kbd_outb;
- request_region(0x60,16,"keyboard");
- }
-#ifdef CONFIG_SGI
- if (mips_machgroup == MACH_GROUP_SGI) {
- sgi_kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
- kbd_inb_p = sgi_kbd_inb;
- kbd_inb = sgi_kbd_inb;
- kbd_outb_p = sgi_kbd_outb;
- kbd_outb = sgi_kbd_outb;
- }
-#endif
-}
+#include <asm/io.h>
+
+#define KEYBOARD_IRQ 1
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+
+#define AUX_IRQ 12
+
+#define ps2_request_irq() \
+ request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)
+
+#define ps2_free_irq(inode) free_irq(AUX_IRQ, NULL)
+
+#endif /* CONF_KEYBOARD_USES_IO_PORTS */
#endif /* __KERNEL */
#endif /* __ASM_MIPS_KEYBOARD_H */
--- /dev/null
+/*
+ * SGI/Newport video card ioctl definitions
+ *
+ */
+
+typedef struct {
+ int flags;
+ u16 w, h;
+ u16 fields_sec;
+} ng1_vof_info_t;
+
+struct ng1_info {
+ struct gfx_info gfx_info;
+ u8 boardrev;
+ u8 rex3rev;
+ u8 vc2rev;
+ u8 monitortype;
+ u8 videoinstalled;
+ u8 mcrev;
+ u8 bitplanes;
+ u8 xmap9rev;
+ u8 cmaprev;
+ ng1_vof_info_t ng1_vof_info;
+ u8 bt445rev;
+ u8 paneltype;
+};
* - flush_cache_page(mm, vmaddr) flushes a single page
* - flush_cache_range(mm, start, end) flushes a range of pages
* - flush_page_to_ram(page) write back kernel page to ram
+ *
*/
extern void (*flush_cache_all)(void);
extern void (*flush_cache_mm)(struct mm_struct *mm);
extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
extern void (*flush_cache_sigtramp)(unsigned long addr);
extern void (*flush_page_to_ram)(unsigned long page);
+#define flush_icache_range(start, end) do { } while (0)
/* TLB flushing:
*
unsigned long end);
extern void (*flush_tlb_page)(struct vm_area_struct *vma, unsigned long page);
+/*
+ * - add_wired_entry() add a fixed TLB entry, and move wired register
+ */
+extern void (*add_wired_entry)(unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask);
+
+
/* Basically we have the same two-level (which is the logical three level
* Linux page table layout folded) page tables as the i386. Some day
* when we have proper page coloring support we can have a 1% quicker
#define _CACHE_CACHABLE_ACCELERATED (7<<9) /* R10000 only */
#define _CACHE_MASK (7<<9)
-#define __READABLE (_PAGE_READ|_PAGE_SILENT_READ|_PAGE_ACCESSED)
-#define __WRITEABLE (_PAGE_WRITE|_PAGE_SILENT_WRITE|_PAGE_MODIFIED)
+#define __READABLE (_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED)
+#define __WRITEABLE (_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED)
#define _PAGE_CHG_MASK (PAGE_MASK | __READABLE | __WRITEABLE | _CACHE_MASK)
#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
_CACHE_CACHABLE_NONCOHERENT)
#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
- _PAGE_ACCESSED | _CACHE_CACHABLE_NONCOHERENT)
+ _CACHE_CACHABLE_NONCOHERENT)
#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_READ | \
_CACHE_CACHABLE_NONCOHERENT)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_READ | \
_CACHE_CACHABLE_NONCOHERENT)
#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
_CACHE_CACHABLE_NONCOHERENT)
+#define PAGE_USERIO __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+ _CACHE_UNCACHED)
+#define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
+ _CACHE_UNCACHED)
/*
* MIPS can't do page protection for execute, and considers that the same like
*/
extern inline void set_pte(pte_t *ptep, pte_t pteval)
{
- *ptep = pteval;
+ *ptep = pteval;
}
extern inline void pte_clear(pte_t *ptep)
*/
extern inline int pmd_none(pmd_t pmd)
{
- return pmd_val(pmd) == ((unsigned long) invalid_pte_table);
+ return pmd_val(pmd) == (unsigned long) invalid_pte_table;
}
extern inline int pmd_bad(pmd_t pmd)
extern inline pte_t pte_mkold(pte_t pte)
{
- pte_val(pte) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ|_PAGE_SILENT_WRITE);
+ pte_val(pte) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ);
return pte;
}
extern inline pte_t pte_mkyoung(pte_t pte)
{
pte_val(pte) |= _PAGE_ACCESSED;
- if (pte_val(pte) & _PAGE_READ) {
+ if (pte_val(pte) & _PAGE_READ)
pte_val(pte) |= _PAGE_SILENT_READ;
- if ((pte_val(pte) & (_PAGE_WRITE|_PAGE_MODIFIED)) ==
- (_PAGE_WRITE|_PAGE_MODIFIED))
- pte_val(pte) |= _PAGE_SILENT_WRITE;
- }
return pte;
}
".set noreorder\n\t"
".set mips3\n\t"
"mfc0 %0, $5\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: "=r" (val));
return val;
".set noreorder\n\t"
".set mips3\n\t"
"mtc0 %0, $5\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: : "r" (val));
}
".set noreorder\n\t"
".set mips3\n\t"
"mfc0 %0, $2\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: "=r" (val));
return val;
".set noreorder\n\t"
".set mips3\n\t"
"mtc0 %0, $2\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: : "r" (val));
}
".set noreorder\n\t"
".set mips3\n\t"
"mfc0 %0, $3\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder" : "=r" (val));
return val;
".set noreorder\n\t"
".set mips3\n\t"
"mtc0 %0, $3\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: : "r" (val));
}
".set noreorder\n\t"
".set mips3\n\t"
"mfc0 %0, $10\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: "=r" (val));
".set noreorder\n\t"
".set mips3\n\t"
"mtc0 %0, $10\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: : "r" (val));
}
".set noreorder\n\t"
".set mips3\n\t"
"mfc0 %0, $0\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: "=r" (val));
return val;
".set noreorder\n\t"
".set mips3\n\t"
"mtc0 %0, $0\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder\n\t"
: : "r" (val));
}
".set noreorder\n\t"
".set mips3\n\t"
"mfc0 %0, $6\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder\n\t"
: "=r" (val));
return val;
"\n\t.set noreorder\n\t"
".set mips3\n\t"
"mtc0 %0, $6\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: : "r" (val));
}
".set noreorder\n\t"
".set mips3\n\t"
"mfc0 %0, $28\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: "=r" (val));
return val;
".set noreorder\n\t"
".set mips3\n\t"
"mtc0 %0, $28\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: : "r" (val));
}
".set noreorder\n\t"
".set mips3\n\t"
"mfc0 %0, $29\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: "=r" (val));
return val;
".set noreorder\n\t"
".set mips3\n\t"
"mtc0 %0, $29\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: : "r" (val));
}
".set noreorder\n\t"
".set mips3\n\t"
"mfc0 %0, $4\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: "=r" (val));
".set noreorder\n\t"
".set mips3\n\t"
"mtc0 %0, $4\n\t"
- ".set mips2\n\t"
+ ".set mips0\n\t"
".set reorder"
: : "r" (val));
}
#endif /* !defined (__LANGUAGE_ASSEMBLY__) */
-#define module_map vmalloc
-#define module_unmap vfree
-
#endif /* __ASM_MIPS_PGTABLE_H */
--- /dev/null
+/*
+ * SGI Rendering Resource Manager API (?).
+ *
+ * written by Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Ok, even if SGI choosed to do mmap trough ioctls, their
+ * kernel support for virtualizing the graphics card is nice.
+ *
+ * We should be able to make graphic applications on Linux
+ * fly.
+ *
+ * This header file should be included from GNU libc as well.
+ */
+
+
+/* Why like this you say? Well, gdb can print enums */
+#define RRM_BASE 1000
+#define RRM_CMD_LIMIT (RRM_BASE + 100)
+
+enum {
+ RRM_OPENRN = RRM_BASE, /* open rendering node */
+ RRM_CLOSERN,
+ RRM_BINDPROCTORN, /* set current rendering region for node */
+ RRM_BINDRNTOCLIP,
+ RRM_UNBINDRNFROMCLIP,
+ RRM_SWAPBUF,
+ RRM_SETSWAPINTERVAL,
+ RRM_WAITFORRETRACE,
+ RRM_SETDISPLAYMODE,
+ RRM_MESSAGE,
+ RRM_INVALIDATERN,
+ RRM_VALIDATECLIP,
+ RRM_VALIDATESWAPBUF,
+ RRM_SWAPGROUP,
+ RRM_SWAPUNGROUP,
+ RRM_VALIDATEMESSAGE,
+ RRM_GETDISPLAYMODES,
+ RRM_LOADDISPLAYMODE,
+ RRM_CUSHIONBUFFER,
+ RRM_SWAPREADY,
+ RRM_MGR_SWAPBUF,
+ RRM_SETVSYNC,
+ RRM_GETVSYNC,
+ RRM_WAITVSYNC,
+ RRM_BINDRNTOREADANDCLIP,
+ RRM_MAPCLIPTOSWPBUFID
+};
+
+/* Parameters for the above ioctls
+ *
+ * All of the ioctls take as their first argument the rendering node id.
+ *
+ */
+
+/*
+ * RRM_OPENRN:
+ *
+ * This is called by the IRIX X server with:
+ * rnid = 0xffffffff rmask = 0
+ *
+ * Returns a number like this: 0x10001.
+ * If you run the X server over and over, you get a value
+ * that is of the form (n * 0x10000) + 1.
+ *
+ * The return value seems to be the RNID.
+ */
+struct RRM_OpenRN {
+ int rnid;
+ unsigned int rmask;
+};
+
+struct RRM_CloseRN {
+ int rnid;
+};
+
+/*
+ * RRM_BINDPROCTORN:
+ *
+ * Return value when the X server calls it: 0
+ */
+struct RRM_BindProcToRN {
+ int rnid;
+};
+
+#ifdef __KERNEL__
+int rrm_command (unsigned int cmd, void *arg);
+int rrm_close (struct inode *inode, struct file *file);
+#endif
--- /dev/null
+/*
+ * Please note that the comments on this file may be out of date
+ * and that they represent what I have figured about the shmiq device
+ * so far in IRIX.
+ *
+ * This also contains some streams and idev bits.
+ *
+ * They may contain errors, please, refer to the source code of the Linux
+ * kernel for a definitive answer on what we have implemented
+ *
+ * Miguel.
+ */
+
+/* STREAMs ioctls */
+#define STRIOC ('S' << 8)
+#define I_STR (STRIOC | 010)
+#define I_PUSH (STRIOC | 02)
+#define I_LINK (STRIOC | 014)
+#define I_UNLINK (STRIOC | 015)
+
+/* Data structure passed on I_STR ioctls */
+struct strioctl {
+ int ic_cmd; /* streams ioctl command */
+ int ic_timout; /* timeout */
+ int ic_len; /* lenght of data */
+ void *ic_dp; /* data */
+};
+
+/*
+ * For mapping the shared memory input queue, you have to:
+ *
+ * 1. Map /dev/zero for the number of bytes you want to use
+ * for your shared memory input queue plus the size of the
+ * sharedMemoryInputQueue structure + 4 (I still have not figured
+ * what this one is for
+ *
+ * 2. Open /dev/shmiq
+ *
+ * 3. Open /dev/qcntlN N is [0..Nshmiqs]
+ *
+ * 4. Fill a shmiqreq structure. user_vaddr should point to the return
+ * address from the /dev/zero mmap. Arg is the number of shmqevents
+ * that fit into the /dev/zero region (remember that at the beginning there
+ * is a sharedMemoryInputQueue header).
+ *
+ * 5. Issue the ioctl (qcntlfd, QIOCATTACH, &your_shmiqreq);
+ */
+
+struct shmiqreq {
+ char *user_vaddr;
+ int arg;
+};
+
+/* map the shmiq into the process address space */
+#define QIOCATTACH _IOW('Q',1,struct shmiqreq)
+
+/* remove mappings */
+#define QIOCDETACH _IO('Q',2)
+
+/*
+ * A shared memory input queue event.
+ */
+struct shmqdata {
+ unsigned char device; /* device major */
+ unsigned char which; /* device minor */
+ unsigned char type; /* event type */
+ unsigned char flags; /* little event data */
+ union {
+ int pos; /* big event data */
+ short ptraxis [2]; /* event data for PTR events */
+ } un;
+};
+
+/* indetifies the shmiq and the device */
+struct shmiqlinkid {
+ short int devminor;
+ short int index;
+};
+
+struct shmqevent {
+ union {
+ int time;
+ struct shmiqlinkid id;
+ } un ;
+ struct shmqdata data ;
+};
+
+/*
+ * sharedMemoryInputQueue: this describes the shared memory input queue.
+ *
+ * head is the user index into the events, user can modify this one.
+ * tail is managed by the kernel.
+ * flags is one of SHMIQ_OVERFLOW or SHMIQ_CORRUPTED
+ * if OVERFLOW is set it seems ioctl QUIOCSERVICED should be called
+ * to notify the kernel.
+ * events where the kernel sticks the events.
+ */
+struct sharedMemoryInputQueue {
+ volatile int head; /* user's index into events */
+ volatile int tail; /* kernel's index into events */
+ volatile unsigned int flags; /* place for out-of-band data */
+#define SHMIQ_OVERFLOW 1
+#define SHMIQ_CORRUPTED 2
+ struct shmqevent events[1]; /* input event buffer */
+};
+
+/* have to figure this one out */
+#define QIOCGETINDX _IOWR('Q', 8, int)
+
+
+/* acknowledge shmiq overflow */
+#define QIOCSERVICED _IO('Q', 3)
+
+/* Double indirect I_STR ioctl, yeah, fun fun fun */
+
+struct muxioctl {
+ int index; /* lower stream index */
+ int realcmd; /* the actual command for the subdevice */
+};
+/* Double indirect ioctl */
+#define QIOCIISTR _IOW('Q', 7, struct muxioctl)
+
+/* Cursor ioclts: */
+
+/* set cursor tracking mode */
+#define QIOCURSTRK _IOW('Q', 4, int)
+
+/* set cursor filter box */
+#define QIOCURSIGN _IOW('Q', 5, int [4])
+
+/* set cursor axes */
+struct shmiqsetcurs {
+ short index;
+ short axes;
+};
+
+#define QIOCSETCURS _IOWR('Q', 9, struct shmiqsetcurs)
+
+/* set cursor position */
+struct shmiqsetcpos {
+ short x;
+ short y;
+};
+#define QIOCSETCPOS _IOWR('Q', 10, struct shmiqsetcpos)
+
+/* get time since last event */
+#define QIOCGETITIME _IOR('Q', 11, time_t)
+
+/* set curent screen */
+#define QIOCSETSCRN _IOW('Q',6,int)
+
+
+/* -------------------- iDev stuff -------------------- */
+
+#define IDEV_MAX_NAME_LEN 15
+#define IDEV_MAX_TYPE_LEN 15
+
+typedef struct {
+ char devName[IDEV_MAX_NAME_LEN+1];
+ char devType[IDEV_MAX_TYPE_LEN+1];
+ unsigned short nButtons;
+ unsigned short nValuators;
+ unsigned short nLEDs;
+ unsigned short nStrDpys;
+ unsigned short nIntDpys;
+ unsigned char nBells;
+ unsigned char flags;
+#define IDEV_HAS_KEYMAP 0x01
+#define IDEV_HAS_PROXIMITY 0x02
+#define IDEV_HAS_PCKBD 0x04
+} idevDesc;
+
+typedef struct {
+ char *nothing_for_now;
+} idevInfo;
+
+typedef struct {
+ char name [16];
+} idevKeymapDesc;
+
+#define IDEVINITDEVICE _IOW('i', 51, unsigned int)
+#define IDEVGETDEVICEDESC _IOWR('i', 0, idevDesc)
+#define IDEVGETKEYMAPDESC _IOWR('i', 2, idevKeymapDesc)
+
+#ifdef __KERNEL__
+
+/* These are only interpreted by SHMIQ-attacheable devices and are internal
+ * to the kernel
+ */
+#define SHMIQ_OFF _IO('Q',1)
+#define SHMIQ_ON _IO('Q',2)
+
+void shmiq_push_event (struct shmqevent *e);
+int get_sioc (struct strioctl *sioc, unsigned long arg);
+#endif
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (c) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (c) 1994, 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: string.h,v 1.4 1997/08/08 20:22:34 miguel Exp $
*/
#ifndef __ASM_MIPS_STRING_H
#define __ASM_MIPS_STRING_H
}
#define __HAVE_ARCH_MEMSET
-extern void *memset(void *__s, char __c, size_t __count);
+extern void *memset(void *__s, int __c, size_t __count);
#define __HAVE_ARCH_MEMCPY
extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
return x;
}
-extern unsigned long IRQ_vectors[16];
+extern unsigned long IRQ_vectors[32];
extern unsigned long exception_handlers[32];
#define set_int_vector(n,addr) \
+/*
+ * $Id: bitops.h,v 1.7 1997/08/03 00:12:07 paulus Exp $
+ * bitops.h: Bit string operations on the ppc
+ */
+
#ifndef _ASM_PPC_BITOPS_H_
#define _ASM_PPC_BITOPS_H_
#include <asm/system.h>
#include <asm/byteorder.h>
-#include <linux/kernel.h> /* for printk */
-
-#define BIT(n) 1<<(n&0x1F)
-typedef unsigned long BITFIELD;
+extern void set_bit(int nr, volatile void *addr);
+extern void clear_bit(int nr, volatile void *addr);
+extern void change_bit(int nr, volatile void *addr);
+extern int test_and_set_bit(int nr, volatile void *addr);
+extern int test_and_clear_bit(int nr, volatile void *addr);
+extern int test_and_change_bit(int nr, volatile void *addr);
/*
- * These are ifdef'd out here because using : "cc" as a constraing
+ * These are if'd out here because using : "cc" as a constraint
* results in errors from gcc. -- Cort
+ * Besides, they need to be changed so we have both set_bit
+ * and test_and_set_bit, etc.
*/
#if 0
extern __inline__ int set_bit(int nr, void * addr)
unsigned long mask = 1 << (nr & 0x1f);
unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
- if ((unsigned long)addr & 3)
- printk("set_bit(%lx, %p)\n", nr, addr);
-
__asm__ __volatile__(
"1:lwarx %0,0,%3 \n\t"
"or %1,%0,%2 \n\t"
: "r" (mask), "r" (p)
/*: "cc" */);
-n return (old & mask) != 0;
+ return (old & mask) != 0;
}
extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
unsigned long mask = 1 << (nr & 0x1f);
unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
- if ((unsigned long)addr & 3)
- printk("clear_bit(%lx, %p)\n", nr, addr);
__asm__ __volatile__("\n\
1: lwarx %0,0,%3
andc %1,%0,%2
unsigned long mask = 1 << (nr & 0x1f);
unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
- if ((unsigned long)addr & 3)
- printk("change_bit(%lx, %p)\n", nr, addr);
__asm__ __volatile__("\n\
1: lwarx %0,0,%3
xor %1,%0,%2
}
#endif
+extern __inline__ unsigned long test_bit(int nr, __const__ volatile void *addr)
+{
+ __const__ unsigned int *p = (__const__ unsigned int *) addr;
+
+ return (p[nr >> 5] >> (nr & 0x1f)) & 1UL;
+}
+
extern __inline__ int ffz(unsigned int x)
{
int n;
+ if (x == ~0)
+ return 32;
x = ~x & (x+1); /* set LS zero to 1, other bits to 0 */
__asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
return 31 - n;
* 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)
-extern __inline__ unsigned long find_first_zero_bit(void * addr, unsigned long size)
-{
- unsigned int * p = ((unsigned int *) addr);
- unsigned int result = 0;
- unsigned int tmp;
-
- if (size == 0)
- return 0;
- while (size & ~31UL) {
- if (~(tmp = *(p++)))
- goto found_middle;
- result += 32;
- size -= 32;
- }
- if (!size)
- return result;
- tmp = *p;
- tmp |= ~0UL << size;
-found_middle:
- return result + ffz(tmp);
-}
-
-/*
- * Find next zero bit in a bitmap reasonably efficiently..
- */
-extern __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size,
- unsigned long offset)
+extern __inline__ unsigned long 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;
size -= result;
offset &= 31UL;
if (offset) {
- tmp = *(p++);
+ tmp = *p++;
tmp |= ~0UL >> (32-offset);
if (size < 32)
goto found_first;
- if (~tmp)
+ if (tmp != ~0U)
goto found_middle;
size -= 32;
result += 32;
}
- while (size & ~31UL) {
- if (~(tmp = *(p++)))
+ while (size >= 32) {
+ if ((tmp = *p++) != ~0U)
goto found_middle;
result += 32;
size -= 32;
#define _EXT2_HAVE_ASM_BITOPS_
-#define ext2_find_first_zero_bit(addr, size) \
- ext2_find_next_zero_bit((addr), (size), 0)
+#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)
+#else
extern __inline__ int ext2_set_bit(int nr, void * addr)
{
-#ifdef __KERNEL__
- int s = _disable_interrupts();
-#endif
- int mask;
- unsigned char *ADDR = (unsigned char *) addr;
- int oldbit;
-
- ADDR += nr >> 3;
- mask = 1 << (nr & 0x07);
- oldbit = (*ADDR & mask) ? 1 : 0;
- *ADDR |= mask;
-#ifdef __KERNEL__
- _enable_interrupts(s);
-#endif
- return oldbit;
+ int mask;
+ unsigned char *ADDR = (unsigned char *) addr;
+ int oldbit;
+
+ ADDR += nr >> 3;
+ mask = 1 << (nr & 0x07);
+ oldbit = (*ADDR & mask) ? 1 : 0;
+ *ADDR |= mask;
+ return oldbit;
}
extern __inline__ int ext2_clear_bit(int nr, void * addr)
{
-#ifdef __KERNEL__
- int s = _disable_interrupts();
-#endif
- int mask;
- unsigned char *ADDR = (unsigned char *) addr;
- int oldbit;
-
- ADDR += nr >> 3;
- mask = 1 << (nr & 0x07);
- oldbit = (*ADDR & mask) ? 1 : 0;
- *ADDR = *ADDR & ~mask;
-#ifdef __KERNEL__
- _enable_interrupts(s);
-#endif
- return oldbit;
-}
+ int mask;
+ unsigned char *ADDR = (unsigned char *) addr;
+ int oldbit;
-
-/* The following routine need not be atomic. */
-extern __inline__ unsigned long test_bit(int nr, void *addr)
-{
- return 1UL & (((__const__ unsigned int *) addr)[nr >> 5] >> (nr & 31));
+ ADDR += nr >> 3;
+ mask = 1 << (nr & 0x07);
+ oldbit = (*ADDR & mask) ? 1 : 0;
+ *ADDR = *ADDR & ~mask;
+ return oldbit;
}
+#endif /* __KERNEL__ */
extern __inline__ int ext2_test_bit(int nr, __const__ void * addr)
{
- int mask;
__const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
- ADDR += nr >> 3;
- mask = 1 << (nr & 0x07);
- return ((mask & *ADDR) != 0);
+ return (ADDR[nr >> 3] >> (nr & 7)) & 1;
}
-extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+/*
+ * 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 long *p = ((unsigned long *) addr) + (offset >> 5);
- unsigned long result = offset & ~31UL;
- unsigned long tmp;
+ 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 = *(p++);
- tmp |= le32_to_cpu(~0UL >> (32-offset));
- if(size < 32)
+ if (offset) {
+ tmp = cpu_to_le32p(p++);
+ tmp |= ~0UL >> (32-offset);
+ if (size < 32)
goto found_first;
- if(~tmp)
+ if (tmp != ~0U)
goto found_middle;
size -= 32;
result += 32;
}
- while(size & ~31UL) {
- if(~(tmp = *(p++)))
+ while (size >= 32) {
+ if ((tmp = cpu_to_le32p(p++)) != ~0U)
goto found_middle;
result += 32;
size -= 32;
}
- if(!size)
+ if (!size)
return result;
- tmp = *p;
-
+ tmp = cpu_to_le32p(p);
found_first:
- return result + ffz(le32_to_cpu(tmp) | (~0UL << size));
+ tmp |= ~0U << size;
found_middle:
- return result + ffz(le32_to_cpu(tmp));
+ return result + ffz(tmp);
}
-#endif /* _ASM_PPC_BITOPS_H */
-
+/* 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 /* _ASM_PPC_BITOPS_H */
#include <asm/types.h>
#ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
#endif
#ifndef __BIG_ENDIAN_BITFIELD
#define __BIG_ENDIAN_BITFIELD
#endif
-#define ntohl(x) (x)
-#define ntohs(x) (x)
-#define htonl(x) (x)
-#define htons(x) (x)
+#define ntohl(x) ((unsigned long)(x))
+#define ntohs(x) ((unsigned short)(x))
+#define htonl(x) ((unsigned long)(x))
+#define htons(x) ((unsigned short)(x))
#define __htonl(x) ntohl(x)
#define __htons(x) ntohs(x)
asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
}
-
+#if 0
extern __inline__ __u16 cpu_to_le16(__u16 value)
{
return ld_le16(&value);
{
return ld_le32(&value);
}
+#else
+extern __inline__ __u16 cpu_to_le16(__u16 value)
+{
+ __u16 result;
+
+ asm("rlwimi %0,%1,8,16,23"
+ : "=r" (result)
+ : "r" (value), "0" (value >> 8));
+ return result;
+}
+extern __inline__ __u32 cpu_to_le32(__u32 value)
+{
+ __u32 result;
+
+ asm("rlwimi %0,%1,24,16,23\n\t"
+ "rlwimi %0,%1,8,8,15\n\t"
+ "rlwimi %0,%1,24,0,7"
+ : "=r" (result)
+ : "r" (value), "0" (value >> 24));
+ return result;
+}
+#endif /* 0 */
+
#define cpu_to_be16(x) (x)
#define cpu_to_be32(x) (x)
#define _PPC_CHECKSUM_H
-/*
- * This is a version of ip_compute_csum() optimized for IP headers,
- * which always checksum on 4 octet boundaries.
- */
-extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-extern unsigned short int csum_tcpudp_magic(unsigned long saddr,
- unsigned long daddr,
- unsigned short len,
- unsigned short proto,
- unsigned int sum);
-
/*
* computes the checksum of a memory block at buff, length len,
* and adds in "sum" (32-bit)
*
* it's best to have buff aligned on a 32-bit boundary
*/
-extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+extern unsigned int csum_partial(const unsigned char * buff, int len,
+ unsigned int sum);
/*
- * the same as csum_partial, but copies from src while it
- * checksums
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively (if that pointer is not
+ * NULL), and, for an error on src, zeroes the rest of dst.
*
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
+ * Like csum_partial, this must be called with even lengths,
+ * except for the last fragment.
*/
-unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
+extern unsigned int csum_partial_copy_generic(const char *src, char *dst,
+ int len, unsigned int sum,
+ int *src_err, int *dst_err);
+
+#define csum_partial_copy_from_user(src, dst, len, sum, errp) \
+ csum_partial_copy_generic((src), (dst), (len), (sum), (errp), 0)
/*
- * the same as csum_partial, but copies from user space (but on the alpha
- * we have just one address space, so this is identical to the above)
+ * Old versions which ignore errors.
*/
-#define csum_partial_copy_fromuser csum_partial_copy
+#define csum_partial_copy(src, dst, len, sum) \
+ csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+#define csum_partial_copy_fromuser(src, dst, len, sum) \
+ csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+
/*
- * this is a new version of the above that records errors it finds in *errp,
- * but continues and zeros the rest of the buffer.
- *
- * right now - it just calls csum_partial_copy()
- * -- Cort
+ * turns a 32-bit partial checksum (e.g. from csum_partial) into a
+ * 1's complement 16-bit checksum.
*/
-extern __inline__
-unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
- int len, int sum, int *err_ptr)
+static inline unsigned int csum_fold(unsigned int sum)
{
- int *dst_err_ptr=NULL;
- return csum_partial_copy( src, dst, len, sum);
+ unsigned int tmp;
+
+ /* swap the two 16-bit halves of sum */
+ __asm__("rlwinm %0,%1,16,0,31" : "=r" (tmp) : "r" (sum));
+ /* if there is a carry from adding the two 16-bit halves,
+ it will carry from the lower half into the upper half,
+ giving us the correct sum in the upper half. */
+ sum = ~(sum + tmp) >> 16;
+ return sum;
}
/*
* this routine is used for miscellaneous IP-like checksums, mainly
* in icmp.c
-A */
+ */
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold(csum_partial(buff, len, 0));
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries. ihl is the number
+ * of 32-bit words and is always >= 5.
+ */
+extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+extern unsigned short csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum);
-extern unsigned short ip_compute_csum(unsigned char * buff, int len);
-extern unsigned int csum_fold(unsigned int sum);
#endif
--- /dev/null
+/*
+ * Definitions for talking to the CUDA. The CUDA is a microcontroller
+ * which controls the ADB, system power, RTC, and various other things.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+/* First byte sent to or received from CUDA */
+#define ADB_PACKET 0
+#define CUDA_PACKET 1
+#define ERROR_PACKET 2
+#define TIMER_PACKET 3
+#define POWER_PACKET 4
+#define MACIIC_PACKET 5
+
+/* ADB commands (2nd byte) */
+#define ADB_BUSRESET 0
+#define ADB_FLUSH(id) (1 + ((id) << 4))
+#define ADB_WRITEREG(id, reg) (8 + (reg) + ((id) << 4))
+#define ADB_READREG(id, reg) (0xc + (reg) + ((id) << 4))
+
+/* ADB default device IDs (upper 4 bits of 2nd byte) */
+#define ADB_DONGLE 1 /* "software execution control" devices */
+#define ADB_KEYBOARD 2
+#define ADB_MOUSE 3
+#define ADB_TABLET 4
+#define ADB_MODEM 5
+#define ADB_MISC 7 /* maybe a monitor */
+
+/* CUDA commands (2nd byte) */
+#define CUDA_WARM_START 0
+#define CUDA_AUTOPOLL 1
+#define CUDA_GET_6805_ADDR 2
+#define CUDA_GET_TIME 3
+#define CUDA_GET_PRAM 7
+#define CUDA_SET_6805_ADDR 8
+#define CUDA_SET_TIME 9
+#define CUDA_POWERDOWN 0xa
+#define CUDA_POWERUP_TIME 0xb
+#define CUDA_SET_PRAM 0xc
+#define CUDA_MS_RESET 0xd
+#define CUDA_SEND_DFAC 0xe
+#define CUDA_RESET_SYSTEM 0x11
+#define CUDA_SET_IPL 0x12
+#define CUDA_SET_AUTO_RATE 0x14
+#define CUDA_GET_AUTO_RATE 0x16
+#define CUDA_SET_DEVICE_LIST 0x19
+#define CUDA_GET_DEVICE_LIST 0x1a
+#define CUDA_GET_SET_IIC 0x22
+
+#ifdef __KERNEL__
+
+struct cuda_request {
+ unsigned char data[16];
+ int nbytes;
+ unsigned char reply[16];
+ int reply_len;
+ unsigned char reply_expected;
+ unsigned char sent;
+ unsigned char got_reply;
+ void (*done)(struct cuda_request *);
+ void *arg;
+ struct cuda_request *next;
+};
+
+void via_cuda_init(void);
+int cuda_request(struct cuda_request *req,
+ void (*done)(struct cuda_request *), int nbytes, ...);
+int cuda_send_request(struct cuda_request *req);
+void cuda_poll(void);
+int adb_register(int default_id,
+ void (*handler)(unsigned char *, int, struct pt_regs *));
+
+#endif /* __KERNEL */
#ifndef _PPC_CURRENT_H
#define _PPC_CURRENT_H
-#include <linux/config.h>
-
-extern struct task_struct *current_set[1];
-
-register struct task_struct *current asm("r2");
+/*
+ * We keep `current' in r2 for speed.
+ */
+register struct task_struct *current asm ("r2");
#endif /* !(_PPC_CURRENT_H) */
--- /dev/null
+/*
+ * Definitions for using the Apple Descriptor-Based DMA controller
+ * in Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#ifndef _ASM_DBDMA_H_
+#define _ASM_DBDMA_H_
+/*
+ * DBDMA control/status registers. All little-endian.
+ */
+struct dbdma_regs {
+ unsigned int control; /* lets you change bits in status */
+ unsigned int status; /* DMA and device status bits (see below) */
+ unsigned int cmdptr_hi; /* upper 32 bits of command address */
+ unsigned int cmdptr; /* (lower 32 bits of) command address (phys) */
+ unsigned int intr_sel; /* select interrupt condition bit */
+ unsigned int br_sel; /* select branch condition bit */
+ unsigned int wait_sel; /* select wait condition bit */
+ unsigned int xfer_mode;
+ unsigned int data2ptr_hi;
+ unsigned int data2ptr;
+ unsigned int res1;
+ unsigned int address_hi;
+ unsigned int br_addr_hi;
+ unsigned int res2[3];
+};
+
+/* Bits in control and status registers */
+#define RUN 0x8000
+#define PAUSE 0x4000
+#define FLUSH 0x2000
+#define WAKE 0x1000
+#define DEAD 0x0800
+#define ACTIVE 0x0400
+#define BT 0x0100
+#define DEVSTAT 0x00ff
+
+/*
+ * DBDMA command structure. These fields are all little-endian!
+ */
+struct dbdma_cmd {
+ unsigned short req_count; /* requested byte transfer count */
+ unsigned short command; /* command word (has bit-fields) */
+ unsigned int phy_addr; /* physical data address */
+ unsigned int cmd_dep; /* command-dependent field */
+ unsigned short res_count; /* residual count after completion */
+ unsigned short xfer_status; /* transfer status */
+};
+
+/* DBDMA command values in command field */
+#define OUTPUT_MORE 0 /* transfer memory data to stream */
+#define OUTPUT_LAST 0x1000 /* ditto followed by end marker */
+#define INPUT_MORE 0x2000 /* transfer stream data to memory */
+#define INPUT_LAST 0x3000 /* ditto, expect end marker */
+#define STORE_WORD 0x4000 /* write word (4 bytes) to device reg */
+#define LOAD_WORD 0x5000 /* read word (4 bytes) from device reg */
+#define DBDMA_NOP 0x6000 /* do nothing */
+#define DBDMA_STOP 0x7000 /* suspend processing */
+
+/* Key values in command field */
+#define KEY_STREAM0 0 /* usual data stream */
+#define KEY_STREAM1 0x100 /* control/status stream */
+#define KEY_STREAM2 0x200 /* device-dependent stream */
+#define KEY_STREAM3 0x300 /* device-dependent stream */
+#define KEY_REGS 0x500 /* device register space */
+#define KEY_SYSTEM 0x600 /* system memory-mapped space */
+#define KEY_DEVICE 0x700 /* device memory-mapped space */
+
+/* Interrupt control values in command field */
+#define INTR_NEVER 0 /* don't interrupt */
+#define INTR_IFSET 0x10 /* intr if condition bit is 1 */
+#define INTR_IFCLR 0x20 /* intr if condition bit is 0 */
+#define INTR_ALWAYS 0x30 /* always interrupt */
+
+/* Branch control values in command field */
+#define BR_NEVER 0 /* don't branch */
+#define BR_IFSET 0x4 /* branch if condition bit is 1 */
+#define BR_IFCLR 0x8 /* branch if condition bit is 0 */
+#define BR_ALWAYS 0xc /* always branch */
+
+/* Wait control values in command field */
+#define WAIT_NEVER 0 /* don't wait */
+#define WAIT_IFSET 1 /* wait if condition bit is 1 */
+#define WAIT_IFCLR 2 /* wait if condition bit is 0 */
+#define WAIT_ALWAYS 3 /* always wait */
+
+/* Align an address for a DBDMA command structure */
+#define DBDMA_ALIGN(x) (((unsigned)(x) + sizeof(struct dbdma_cmd) - 1) \
+ & -sizeof(struct dbdma_cmd))
+#endif /* _ASM_DBDMA_H_ */
#ifndef _ASM_DMA_H
#define _ASM_DMA_H
+#define MAX_DMA_CHANNELS 8
+
+/* The maximum address that we can perform a DMA transfer to on this platform */
+/* Doesn't really apply... */
+#define MAX_DMA_ADDRESS 0xFFFFFFFF
+
#ifdef CONFIG_PREP
#include <asm/io.h> /* need byte IO */
*
*/
-#define MAX_DMA_CHANNELS 8
-
-/* The maximum address that we can perform a DMA transfer to on this platform */
-/* Doesn't really apply... */
-#define MAX_DMA_ADDRESS 0xFFFFFFFF
+#define POWERSTACK_SND_DMA 6
+#define POWERSTACK_SND_DMA2 7
/* 8237 DMA controllers */
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
#define DMA_HI_PAGE_6 0x489
#define DMA_HI_PAGE_7 0x48A
+#define DMA1_EXT_REG 0x40B
+#define DMA2_EXT_REG 0x4D6
+
#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */
switch(dmanr) {
case 0:
dma_outb(pagenr, DMA_LO_PAGE_0);
+ dma_outb(pagenr>>8, DMA_HI_PAGE_0);
break;
case 1:
dma_outb(pagenr, DMA_LO_PAGE_1);
+ dma_outb(pagenr>>8, DMA_HI_PAGE_1);
break;
case 2:
dma_outb(pagenr, DMA_LO_PAGE_2);
case 3:
dma_outb(pagenr, DMA_LO_PAGE_3);
break;
- case 5:
+ case 5:
dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
+ dma_outb(pagenr>>8, DMA_HI_PAGE_5);
break;
case 6:
- dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+ if (POWERSTACK_SND_DMA == 6 || POWERSTACK_SND_DMA2 == 6)
+ dma_outb(pagenr, DMA_LO_PAGE_6);
+ else
+ dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+ dma_outb(pagenr>>8, DMA_HI_PAGE_6);
break;
case 7:
- dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
- break;
+ if (POWERSTACK_SND_DMA == 7 || POWERSTACK_SND_DMA2 == 7)
+ dma_outb(pagenr, DMA_LO_PAGE_7);
+ else
+ dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
+ dma_outb(pagenr>>8, DMA_HI_PAGE_7);
+ break;
}
}
dma_outb( phys & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
dma_outb( (phys>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
} else {
+ if (dmanr == POWERSTACK_SND_DMA || dmanr == POWERSTACK_SND_DMA2) {
+ dma_outb( phys & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+ dma_outb( (phys>>8) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+ dma_outb( (dmanr&3), DMA2_EXT_REG);
+ } else {
dma_outb( (phys>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
dma_outb( (phys>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+ }
}
set_dma_page(dmanr, phys>>16);
}
dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
} else {
+ if (dmanr == POWERSTACK_SND_DMA || dmanr == POWERSTACK_SND_DMA2) {
+ dma_outb( count & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+ dma_outb( (count>>8) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+ } else {
dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+ }
}
}
return (dmanr<=3)? count : (count<<1);
}
+#else /* CONFIG_PREP */
-/* These are in kernel/dma.c: */
-extern void free_dma(unsigned int dmanr); /* release it again */
+#define DMA_MODE_READ 1
+#define DMA_MODE_WRITE 2
#endif /* CONFIG_PREP */
+/* These are in kernel/dma.c: */
+extern void free_dma(unsigned int dmanr); /* release it again */
+
#endif /* _ASM_DMA_H */
*/
#include <asm/ptrace.h>
-#define ELF_NGREG 32
-#define ELF_NFPREG 32
+#define ELF_NGREG 48 /* includes nip, msr, lr, etc. */
+#define ELF_NFPREG 33 /* includes fpscr */
/*
* This is used to ensure we don't load something for the wrong architecture.
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));
+
#endif
return index;
}
-extern void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
typedef union {
unsigned all : 8; /* all of the bits together */
#include <asm/page.h>
#include <asm/byteorder.h>
-#ifdef CONFIG_PREP
/* from the Carolina Technical Spec -- Cort */
#define IBM_ACORN 0x82A
#define SIO_CONFIG_RA 0x398
#define IBM_L2_INVALIDATE 0x814
#define IBM_SYS_CTL 0x81c
+extern unsigned long io_base;
#define SLOW_DOWN_IO
-#ifndef PCI_DRAM_OFFSET
-#define PCI_DRAM_OFFSET 0x80000000
-#endif
+#define _IO_BASE io_base
+#undef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET _IO_BASE
#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
+#define readw(addr) ld_le16((volatile unsigned short *)(addr))
+#define readl(addr) ld_le32(addr)
#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
-
-void outsl(int port, long *ptr, int len);
-
-__inline__ unsigned char outb(unsigned char val, int port);
-__inline__ unsigned short outw(unsigned short val, int port);
-__inline__ unsigned long outl(unsigned long val, int port);
-__inline__ unsigned char inb(int port);
-__inline__ unsigned short inw(int port);
-__inline__ unsigned long inl(int port);
-
-#define inb_p inb
-#define inw_p inw
-#define inl_p inl
-#define outb_p outb
-#define outw_p outw
-#define outl_p outl
-
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_PMAC
-/*
- * Read and write the non-volatile RAM.
- */
-extern int nvram_readb(int addr);
-extern void nvram_writeb(int addr, int val);
-
-#ifndef PCI_DRAM_OFFSET
-#define PCI_DRAM_OFFSET 0
-#endif
-
-#define inb(port) in_8((unsigned char *)(port))
-#define outb(val, port) out_8((unsigned char *)(port), (val))
-#define inw(port) in_le16((unsigned short *)(port))
-#define outw(val, port) out_le16((unsigned short *)(port), (val))
-#define inl(port) in_le32((unsigned long *)(port))
-#define outl(val, port) out_le32((unsigned long *)(port), (val))
-
-#define inb_p(port) in_8((unsigned char *)(port))
-#define outb_p(val, port) out_8((unsigned char *)(port), (val))
-#define inw_p(port) in_le16((unsigned short *)(port))
-#define outw_p(val, port) out_le16((unsigned short *)(port), (val))
-#define inl_p(port) in_le32(((unsigned long *)port))
-#define outl_p(val, port) out_le32((unsigned long *)(port), (val))
-
-#define insw(port, buf, ns) _insw((unsigned short *)(port), (buf), (ns))
-#define outsw(port, buf, ns) _outsw((unsigned short *)(port), (buf), (ns))
-#define insl(port, buf, nl) _insl((unsigned long *)(port), (buf), (nl))
-#define outsl(port, buf, nl) _outsl((unsigned long *)(port), (buf), (nl))
-#endif /* CONFIG_PMAC */
-
+#define writew(b,addr) st_le16((volatile unsigned short *)(addr),(b))
+#define writel(b,addr) st_le32((addr),(b))
+
+#define insb(port, buf, ns) _insb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
+#define outsb(port, buf, ns) _outsb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
+#define insw(port, buf, ns) _insw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define outsw(port, buf, ns) _outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define insl(port, buf, nl) _insl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define outsl(port, buf, nl) _outsl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+
+#define inb(port) in_8((unsigned char *)((port)+_IO_BASE))
+#define outb(val, port) out_8((unsigned char *)((port)+_IO_BASE), (val))
+#define inw(port) in_le16((unsigned short *)((port)+_IO_BASE))
+#define outw(val, port) out_le16((unsigned short *)((port)+_IO_BASE), (val))
+#define inl(port) in_le32((unsigned *)((port)+_IO_BASE))
+#define outl(val, port) out_le32((unsigned *)((port)+_IO_BASE), (val))
+
+#define inb_p(port) in_8((unsigned char *)((port)+_IO_BASE))
+#define outb_p(val, port) out_8((unsigned char *)((port)+_IO_BASE), (val))
+#define inw_p(port) in_le16((unsigned short *)((port)+_IO_BASE))
+#define outw_p(val, port) out_le16((unsigned short *)((port)+_IO_BASE), (val))
+#define inl_p(port) in_le32(((unsigned *)port))
+#define outl_p(val, port) out_le32((unsigned *)((port)+_IO_BASE), (val))
+
+extern void _insb(volatile unsigned char *port, void *buf, int ns);
+extern void _outsb(volatile unsigned char *port, const void *buf, int ns);
+extern void _insw(volatile unsigned short *port, void *buf, int ns);
+extern void _outsw(volatile unsigned short *port, const void *buf, int ns);
+extern void _insl(volatile unsigned long *port, void *buf, int nl);
+extern void _outsl(volatile unsigned long *port, const void *buf, int nl);
+
+#ifdef __KERNEL__
/*
* The PCI bus is inherently Little-Endian. The PowerPC is being
* run Big-Endian. Thus all values which cross the [PCI] barrier
*/
extern inline unsigned long virt_to_bus(volatile void * address)
{
- if (address == (void *)0) return 0;
- return ((unsigned long)((long)address - KERNELBASE + PCI_DRAM_OFFSET));
+ if (address == (void *)0)
+ return 0;
+ return (unsigned long)address - KERNELBASE + PCI_DRAM_OFFSET;
}
extern inline void * bus_to_virt(unsigned long address)
{
- if (address == 0) return 0;
- return ((void *)(address - PCI_DRAM_OFFSET + KERNELBASE));
+ if (address == 0)
+ return 0;
+ return (void *)(address - PCI_DRAM_OFFSET + KERNELBASE);
}
/*
extern void *ioremap(unsigned long address, unsigned long size);
/*
- * Change virtual addresses to physical addresses and vv.
- * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
- * make the kernel segment mapped at 0, we need to do translation
- * on the i386 as well)
+ * Change virtual addresses to physical addresses and vv, for
+ * addresses in the area where the kernel has the RAM mapped.
*/
extern inline unsigned long virt_to_phys(volatile void * address)
{
- return (unsigned long) address;
+ return (unsigned long) address - KERNELBASE;
}
extern inline void * phys_to_virt(unsigned long address)
{
- return (void *) address;
+ return (void *) (address + KERNELBASE);
}
-#define _IO_BASE ((unsigned long)0x80000000)
-
-/*
- * These are much more useful le/be io functions from Paul
- * than leXX_to_cpu() style functions since the ppc has
- * load/store byte reverse instructions
- * -- Cort
- */
+#endif /* __KERNEL__ */
/*
* Enforce In-order Execution of I/O:
#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 TIOCSBRK 0x5427 /* BSD compatibility */
+#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCSERCONFIG 0x5453
#define TIOCSERGWILD 0x5454
-#ifndef __i386_IPC_H__
-#define __i386_IPC_H__
+#ifndef __PPC_IPC_H__
+#define __PPC_IPC_H__
/*
- * These are used to wrap system calls on x86.
+ * These are used to wrap system calls on PowerPC.
*
- * See arch/i386/kernel/sys_i386.c for ugly details..
+ * See arch/ppc/kernel/syscalls.c for ugly details..
*/
struct ipc_kludge {
struct msgbuf *msgp;
#define IPCCALL(version,op) ((version)<<16 | (op))
-#endif
+#endif /* __PPC_IPC_H__ */
#include <linux/config.h>
-#ifdef CONFIG_PMAC
-#define NR_IRQS 32
-#else
-#define NR_IRQS 16
-#endif
+#define NR_IRQS 32
extern void disable_irq(unsigned int);
extern void enable_irq(unsigned int);
--- /dev/null
+/*
+ * include/asm-ppc/linux_logo.h: A linux logo to be displayed on boot
+ * (pinched from the sparc port).
+ *
+ * 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
+ * values have to start from 0x20
+ * (i.e. linux_logo_{red,green,blue}[0] is color 0x20)
+ */
+
+#include <linux/init.h>
+
+#define LINUX_LOGO_HEIGHT 80
+#define LINUX_LOGO_WIDTH 80
+#define LINUX_LOGO_COLORS 221
+
+unsigned char linux_logo_red[] __initdata = {
+ 0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+ 0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xE5,
+ 0xF1, 0xED, 0xEE, 0xE6, 0xC6, 0xDA, 0xDD, 0xE5,
+ 0xD9, 0xC6, 0xE3, 0xD0, 0xC6, 0xBA, 0xB0, 0xB6,
+ 0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xB0, 0xAD,
+ 0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x9D,
+ 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+ 0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+ 0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x0D, 0x03,
+ 0x66, 0x44, 0x24, 0x08, 0xD6, 0xE6, 0xE9, 0xE6,
+ 0xE7, 0xCA, 0xDC, 0xDB, 0xD5, 0xD0, 0xC9, 0xE2,
+ 0xD5, 0xC6, 0xC4, 0xB3, 0xB2, 0xB9, 0xA9, 0x9A,
+ 0xB2, 0x9D, 0xE8, 0xEC, 0xF5, 0xF5, 0xF4, 0xF4,
+ 0xEC, 0xEE, 0xF0, 0xF5, 0xE0, 0xD6, 0xC5, 0xC2,
+ 0xD9, 0xD5, 0xD8, 0xD6, 0xF6, 0xF4, 0xED, 0xEC,
+ 0xEB, 0xF1, 0xF6, 0xF5, 0xF5, 0xEE, 0xEF, 0xEC,
+ 0xE7, 0xE3, 0xE6, 0xD6, 0xDD, 0xC3, 0xD6, 0xD7,
+ 0xCD, 0xCA, 0xC3, 0xAC, 0x95, 0x99, 0xB7, 0xA3,
+ 0x8B, 0x88, 0x95, 0x8A, 0x94, 0xD2, 0xCC, 0xC4,
+ 0xA8, 0x8E, 0x8F, 0xAE, 0xB8, 0xAC, 0xB6, 0xB4,
+ 0xAD, 0xA5, 0xA0, 0x9B, 0x8B, 0xA3, 0x94, 0x87,
+ 0x85, 0x89, 0x53, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+ 0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+ 0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+ 0x42, 0x0F, 0x75, 0x78, 0x7D, 0x72, 0x5F, 0x6E,
+ 0x7A, 0x75, 0x6A, 0x58, 0x48, 0x4F, 0x00, 0x2B,
+ 0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x3B, 0x11,
+ 0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_green[] __initdata = {
+ 0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+ 0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xD3,
+ 0xDA, 0xD4, 0xD7, 0xCC, 0xC1, 0xCC, 0xCB, 0xC9,
+ 0xC5, 0xBC, 0xBC, 0xBB, 0xB7, 0xA5, 0xB0, 0xB6,
+ 0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xAD, 0xAD,
+ 0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x95,
+ 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+ 0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+ 0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x08, 0x02,
+ 0x53, 0x2E, 0x19, 0x06, 0xC6, 0xC8, 0xCF, 0xBD,
+ 0xB3, 0xB6, 0xB4, 0xAB, 0xA5, 0xA3, 0x9B, 0xB6,
+ 0xA7, 0x99, 0x92, 0xA4, 0x9E, 0x9D, 0x98, 0x8C,
+ 0x8A, 0x86, 0xCD, 0xCC, 0xC9, 0xD7, 0xCA, 0xC4,
+ 0xCA, 0xC3, 0xC7, 0xC3, 0xC8, 0xB4, 0x91, 0x8E,
+ 0x8A, 0x82, 0x87, 0x85, 0xBD, 0xBF, 0xB6, 0xBC,
+ 0xAE, 0xB7, 0xBC, 0xB8, 0xBF, 0xB6, 0xBC, 0xB5,
+ 0xAB, 0xA6, 0xAD, 0xB2, 0xA5, 0x87, 0x9C, 0x96,
+ 0x95, 0x8E, 0x87, 0x8F, 0x86, 0x86, 0x8E, 0x80,
+ 0x7A, 0x70, 0x7B, 0x78, 0x78, 0x7F, 0x77, 0x6F,
+ 0x70, 0x76, 0x59, 0x77, 0x68, 0x64, 0x7B, 0x7C,
+ 0x75, 0x6D, 0x77, 0x69, 0x65, 0x5F, 0x5B, 0x54,
+ 0x4F, 0x5B, 0x39, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+ 0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+ 0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+ 0x42, 0x0B, 0x69, 0x66, 0x64, 0x57, 0x4A, 0x4E,
+ 0x55, 0x4B, 0x46, 0x3B, 0x30, 0x33, 0x00, 0x2B,
+ 0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x29, 0x0D,
+ 0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_blue[] __initdata = {
+ 0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xEE, 0xE5, 0xDE,
+ 0xD7, 0xD3, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xB5,
+ 0xB0, 0xA6, 0xAC, 0x9B, 0xB5, 0xB5, 0xAE, 0x84,
+ 0x90, 0xA9, 0x81, 0x8D, 0x96, 0x86, 0xB0, 0xB6,
+ 0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xA7, 0xAD,
+ 0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA5, 0x87,
+ 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x9A, 0x9A, 0x99,
+ 0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+ 0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0xC8, 0xD7,
+ 0x9B, 0x8E, 0x8C, 0xB2, 0x77, 0x77, 0x4E, 0x77,
+ 0x69, 0x71, 0x78, 0x6B, 0x65, 0x66, 0x64, 0x59,
+ 0x5C, 0x5A, 0x48, 0x72, 0x7B, 0x6B, 0x67, 0x6E,
+ 0x42, 0x5B, 0x29, 0x36, 0x25, 0x10, 0x17, 0x14,
+ 0x19, 0x16, 0x13, 0x0E, 0x08, 0x2E, 0x2E, 0x3D,
+ 0x24, 0x24, 0x24, 0x24, 0x13, 0x12, 0x14, 0x14,
+ 0x0E, 0x08, 0x0D, 0x0F, 0x08, 0x0D, 0x0E, 0x08,
+ 0x08, 0x0C, 0x06, 0x06, 0x07, 0x16, 0x07, 0x0E,
+ 0x08, 0x0A, 0x07, 0x0D, 0x2D, 0x3E, 0x09, 0x4E,
+ 0x68, 0x52, 0x56, 0x58, 0x4B, 0x22, 0x20, 0x20,
+ 0x27, 0x39, 0x28, 0x19, 0x1E, 0x1E, 0x08, 0x06,
+ 0x07, 0x09, 0x08, 0x08, 0x05, 0x1D, 0x1F, 0x17,
+ 0x18, 0x06, 0x79, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+ 0x76, 0x71, 0x73, 0x6E, 0x6B, 0x68, 0x65, 0x62,
+ 0x4B, 0x5B, 0x5F, 0x55, 0x56, 0x52, 0x4F, 0x46,
+ 0x42, 0x5A, 0x14, 0x23, 0x3D, 0x2B, 0x21, 0x14,
+ 0x06, 0x04, 0x03, 0x07, 0x09, 0x13, 0x2A, 0x3A,
+ 0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x07, 0x09,
+ 0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo[] __initdata = {
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+ 0x58, 0x58, 0x59, 0x5C, 0x5D, 0x5F, 0x60, 0x61,
+ 0x62, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x60, 0x5E, 0x5E,
+ 0x5E, 0x5D, 0x5D, 0x5C, 0x5D, 0x5B, 0x58, 0x58,
+ 0x58, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+ 0x54, 0x56, 0x57, 0x67, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x67, 0x4C,
+ 0x4A, 0x49, 0x4A, 0x49, 0x4A, 0x49, 0x49, 0x4A,
+ 0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x50, 0x51, 0x52,
+ 0x54, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57, 0x58,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x58, 0x56, 0x56, 0x53,
+ 0x52, 0x53, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB,
+ 0x4B, 0x4B, 0x4B, 0x4A, 0x49, 0x4A, 0x4A, 0x49,
+ 0x49, 0x49, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B,
+ 0x4C, 0x4D, 0x52, 0x54, 0x56, 0x55, 0x57, 0x58,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
+ 0x50, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF4, 0xFB,
+ 0xFC, 0x67, 0x53, 0x50, 0x4D, 0x4C, 0x4C, 0x4C,
+ 0x4B, 0x4A, 0x4A, 0x48, 0x49, 0x48, 0x48, 0x49,
+ 0x49, 0x49, 0x4B, 0x4C, 0x50, 0x52, 0x53, 0x56,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x55, 0x54, 0x53, 0x51, 0x51, 0x50, 0x4C, 0x4D,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xD2, 0xD7, 0xF5,
+ 0xFC, 0xFC, 0x5D, 0x5D, 0x5C, 0x5C, 0x59, 0x58,
+ 0x58, 0x56, 0x52, 0x4C, 0x4B, 0x4A, 0x4A, 0x48,
+ 0x48, 0x48, 0x48, 0x48, 0x49, 0x4B, 0x4D, 0x51,
+ 0x54, 0x56, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x55, 0x54,
+ 0x53, 0x52, 0x51, 0x4D, 0x4D, 0x4D, 0x50, 0x50,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0x64, 0xD9, 0xF5,
+ 0xF9, 0xFC, 0xFC, 0x64, 0x63, 0x62, 0x61, 0x61,
+ 0x61, 0x60, 0x5E, 0x5B, 0x5A, 0x54, 0x52, 0x4C,
+ 0x4B, 0x49, 0x49, 0x47, 0x47, 0x48, 0x49, 0x4B,
+ 0x4C, 0x51, 0x53, 0x56, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x55, 0x53, 0x53,
+ 0x51, 0x50, 0x50, 0x50, 0x50, 0x50, 0x53, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xF5, 0xF9, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0x64, 0x64, 0x64, 0x64, 0x64,
+ 0x64, 0x64, 0x64, 0x63, 0x61, 0x61, 0x5E, 0x59,
+ 0x55, 0x52, 0x4C, 0x4A, 0x49, 0x47, 0x48, 0x48,
+ 0x49, 0x4B, 0x4D, 0x51, 0x54, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x55, 0x54, 0x54, 0x52, 0x51,
+ 0x51, 0x51, 0x51, 0x51, 0x53, 0x54, 0x59, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF7, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0x60, 0x60, 0x60, 0x61,
+ 0x62, 0x63, 0x64, 0x64, 0x65, 0x65, 0x64, 0x63,
+ 0x61, 0x5E, 0x59, 0x56, 0x4D, 0x4B, 0x48, 0x48,
+ 0x48, 0x48, 0x49, 0x4B, 0x50, 0x53, 0x56, 0x56,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x56, 0x54, 0x53, 0x52, 0x51, 0x51,
+ 0x51, 0x52, 0x53, 0x55, 0x59, 0x5D, 0x5E, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0x4C, 0x4E, 0x51, 0x52,
+ 0x57, 0x5A, 0x5E, 0x60, 0x61, 0x63, 0x65, 0xCB,
+ 0x64, 0x64, 0x63, 0x60, 0x5C, 0x57, 0x50, 0x4B,
+ 0x48, 0x47, 0x47, 0x47, 0x4A, 0x4C, 0x52, 0x53,
+ 0x54, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x55, 0x54, 0x53, 0x53, 0x51, 0x52, 0x52, 0x53,
+ 0x53, 0x57, 0x5A, 0x5D, 0x5E, 0x5E, 0x60, 0xFC,
+ 0xFC, 0xFC, 0xFB, 0xF9, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFA, 0xF9, 0xF5, 0xFB, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x45, 0x3F, 0x3F,
+ 0x45, 0x48, 0x4B, 0x4D, 0x54, 0x5A, 0x5E, 0x61,
+ 0x63, 0xCB, 0xCB, 0x65, 0x64, 0x62, 0x5E, 0x57,
+ 0x50, 0x4B, 0x48, 0x47, 0x47, 0x48, 0x4B, 0x4D,
+ 0x51, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+ 0x54, 0x54, 0x53, 0x53, 0x52, 0x53, 0x54, 0x57,
+ 0x59, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0xFC,
+ 0xFC, 0xFA, 0xFC, 0xFA, 0xE0, 0xFC, 0xFC, 0xFC,
+ 0xFB, 0xFB, 0xFB, 0xDF, 0xD8, 0xF9, 0xE0, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x4C, 0x4A, 0x48,
+ 0x48, 0x3E, 0x44, 0x43, 0x3F, 0x47, 0x4B, 0x52,
+ 0x5A, 0x5E, 0x62, 0x64, 0xCB, 0xCB, 0x64, 0x61,
+ 0x5E, 0x57, 0x4D, 0x49, 0x47, 0x47, 0x48, 0x4A,
+ 0x4C, 0x52, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+ 0x54, 0x53, 0x53, 0x54, 0x54, 0x55, 0x58, 0x5B,
+ 0x5C, 0x5D, 0x5E, 0x5D, 0x5D, 0x5B, 0x58, 0xFC,
+ 0xFC, 0xD8, 0x4C, 0x60, 0xFC, 0xF5, 0xFC, 0xFC,
+ 0xFC, 0xF7, 0x5F, 0x48, 0x48, 0x2C, 0xF8, 0xF9,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x4A, 0x49,
+ 0x49, 0x49, 0x49, 0x47, 0x3E, 0x44, 0x42, 0x3F,
+ 0x3E, 0x4B, 0x54, 0x5C, 0x61, 0x64, 0xCB, 0xCB,
+ 0x64, 0x61, 0x5D, 0x53, 0x4B, 0x49, 0x47, 0x47,
+ 0x49, 0x4B, 0x50, 0x53, 0x56, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x55, 0x54,
+ 0x53, 0x53, 0x54, 0x56, 0x58, 0x5A, 0x5B, 0x5D,
+ 0x5D, 0x5D, 0x5C, 0x5A, 0x54, 0x52, 0x4C, 0xFC,
+ 0xF7, 0x4E, 0x2D, 0x29, 0x4E, 0xFC, 0xFC, 0xFC,
+ 0xFB, 0x5F, 0x26, 0x24, 0x20, 0x2E, 0x65, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x45, 0x3F, 0x45,
+ 0x3E, 0x47, 0x47, 0x47, 0x47, 0x47, 0x3E, 0x44,
+ 0x43, 0x40, 0x44, 0x49, 0x51, 0x5C, 0x62, 0x64,
+ 0xCB, 0xCB, 0x63, 0x60, 0x58, 0x50, 0x49, 0x48,
+ 0x48, 0x48, 0x4A, 0x4D, 0x53, 0x54, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+ 0x54, 0x54, 0x55, 0x57, 0x59, 0x5B, 0x5C, 0x5D,
+ 0x5C, 0x5A, 0x54, 0x51, 0x4C, 0x4C, 0x54, 0xFC,
+ 0xF9, 0x23, 0xDB, 0x2D, 0x23, 0xFA, 0xFB, 0xFA,
+ 0xF5, 0x27, 0x21, 0xD9, 0xF8, 0x20, 0x21, 0xFB,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x5D, 0x58, 0x55,
+ 0x50, 0x48, 0x45, 0x43, 0x44, 0x44, 0x45, 0x45,
+ 0x3E, 0x3F, 0x43, 0x41, 0x3F, 0x48, 0x52, 0x5D,
+ 0x63, 0x65, 0xCB, 0x65, 0x61, 0x5D, 0x52, 0x4B,
+ 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+ 0x54, 0x58, 0x5A, 0x59, 0x5B, 0x5B, 0x5B, 0x5A,
+ 0x55, 0x52, 0x4D, 0x4D, 0x55, 0x5B, 0x5D, 0xFC,
+ 0xF1, 0xF9, 0xFC, 0xD4, 0x21, 0xCC, 0xF7, 0xF8,
+ 0xF2, 0x21, 0xD9, 0xFC, 0xF2, 0xFB, 0x21, 0x45,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xD1, 0xD0, 0xCD,
+ 0xCC, 0x63, 0x5E, 0x58, 0x50, 0x47, 0x43, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x40, 0x41, 0x3F, 0x4A,
+ 0x56, 0x5E, 0x64, 0xCB, 0x65, 0x63, 0x5E, 0x56,
+ 0x4C, 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54,
+ 0x58, 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54,
+ 0x57, 0x5A, 0x5A, 0x5C, 0x5B, 0x5A, 0x58, 0x54,
+ 0x51, 0x4C, 0x55, 0x5D, 0x5D, 0x5B, 0x54, 0xFC,
+ 0xF0, 0xF9, 0xFC, 0x65, 0x45, 0xCD, 0xFB, 0xFB,
+ 0xF8, 0x26, 0xFB, 0xFC, 0xFC, 0xFC, 0x21, 0x27,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0xFB, 0xD7, 0x35, 0x34,
+ 0x2F, 0x35, 0x36, 0x2F, 0x2F, 0x36, 0x2F, 0x2F,
+ 0x36, 0x36, 0x35, 0x35, 0x43, 0x42, 0x41, 0x2E,
+ 0x45, 0x4C, 0x5B, 0x62, 0x65, 0xCC, 0x64, 0x60,
+ 0x58, 0x4D, 0x49, 0x47, 0x47, 0x49, 0x4C, 0x51,
+ 0x58, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x57,
+ 0x58, 0x5A, 0x5A, 0x5B, 0x5A, 0x55, 0x54, 0x51,
+ 0x53, 0x5C, 0x5D, 0x5D, 0x54, 0x4B, 0x4D, 0xFC,
+ 0xFC, 0x44, 0xFC, 0xFB, 0x7B, 0xAB, 0xA8, 0xAE,
+ 0xAB, 0x7F, 0xFC, 0xFC, 0xFB, 0xFB, 0x22, 0x2A,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x2F, 0x30, 0x30,
+ 0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x40, 0x41,
+ 0x2E, 0x40, 0x48, 0x56, 0x5F, 0x64, 0xCC, 0x65,
+ 0x61, 0x59, 0x50, 0x49, 0x47, 0x47, 0x49, 0x4C,
+ 0x5A, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58,
+ 0x5A, 0x5A, 0x5A, 0x58, 0x55, 0x52, 0x51, 0x5A,
+ 0x5D, 0x5D, 0x57, 0x4C, 0x51, 0x54, 0x5D, 0xFC,
+ 0xFC, 0x2A, 0xFC, 0xC9, 0xAA, 0x8B, 0x8A, 0x8C,
+ 0xAB, 0x8C, 0x8C, 0xFB, 0xFB, 0x23, 0x20, 0xF1,
+ 0xFC, 0xFC, 0xFC, 0x3B, 0x33, 0x33, 0x32, 0x32,
+ 0x31, 0x32, 0x30, 0x32, 0x32, 0x32, 0x32, 0x30,
+ 0x31, 0x31, 0x31, 0x32, 0x33, 0x33, 0x3C, 0x41,
+ 0x41, 0x2E, 0x2D, 0x45, 0x4D, 0x5D, 0x63, 0xCC,
+ 0x65, 0x62, 0x5D, 0x51, 0x49, 0x47, 0x47, 0x4A,
+ 0x59, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58,
+ 0x5A, 0x5A, 0x58, 0x55, 0x53, 0x53, 0x5C, 0x5E,
+ 0x59, 0x51, 0x4E, 0x54, 0x59, 0x5E, 0x62, 0xFC,
+ 0xFC, 0xDB, 0xAA, 0xA1, 0x95, 0x9C, 0x8C, 0x88,
+ 0x82, 0x83, 0x83, 0x8C, 0x88, 0xAE, 0xB9, 0xFB,
+ 0xFC, 0xFC, 0xFC, 0x3C, 0x3B, 0x72, 0x38, 0x33,
+ 0x33, 0x33, 0x31, 0x33, 0x31, 0x31, 0x31, 0x31,
+ 0x33, 0x33, 0x38, 0x33, 0x72, 0x3B, 0x44, 0x2E,
+ 0x41, 0x2E, 0x2E, 0x2D, 0x43, 0x4B, 0x5B, 0x63,
+ 0xCB, 0xCC, 0x63, 0x5D, 0x51, 0x49, 0x47, 0x49,
+ 0x5C, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58,
+ 0x58, 0x58, 0x57, 0x53, 0x58, 0x5D, 0x5E, 0x55,
+ 0x51, 0x53, 0x58, 0x5E, 0x60, 0x63, 0x64, 0xFC,
+ 0xFC, 0xC0, 0xA6, 0x9D, 0x8B, 0x9C, 0x8C, 0x8C,
+ 0x6E, 0x83, 0x88, 0x8C, 0x8C, 0x8C, 0x83, 0xE8,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0x33, 0x70, 0x70, 0x6F,
+ 0x6F, 0x6F, 0x6F, 0x3A, 0x6F, 0x6D, 0x6F, 0x6F,
+ 0x70, 0x6F, 0x6F, 0x70, 0x6F, 0x32, 0x5A, 0x48,
+ 0x41, 0x2D, 0x2D, 0x2D, 0x2C, 0x41, 0x49, 0x5A,
+ 0x62, 0xCB, 0xCB, 0x63, 0x5D, 0x50, 0x49, 0x4A,
+ 0x5C, 0x58, 0x58, 0x57, 0x55, 0x57, 0x57, 0x57,
+ 0x57, 0x55, 0x56, 0x59, 0x5E, 0x5C, 0x52, 0x53,
+ 0x55, 0x5B, 0x5E, 0x61, 0x63, 0x64, 0x63, 0xFC,
+ 0xE8, 0xBF, 0xA4, 0x99, 0x9C, 0x8C, 0x88, 0x88,
+ 0x6E, 0x88, 0x8C, 0x8C, 0x8C, 0xC2, 0xA6, 0xC4,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x3A, 0x6F, 0x70,
+ 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
+ 0x70, 0x70, 0x70, 0x70, 0x37, 0x32, 0xCD, 0x5E,
+ 0x4C, 0x43, 0x2C, 0x2D, 0x2D, 0x2C, 0x2E, 0x47,
+ 0x57, 0x61, 0x65, 0xCC, 0x63, 0x5C, 0x50, 0x4D,
+ 0x5C, 0x5A, 0x57, 0x55, 0x55, 0x55, 0x58, 0x58,
+ 0x55, 0x54, 0x5B, 0x5E, 0x5D, 0x53, 0x53, 0x55,
+ 0x5D, 0x5E, 0x61, 0x61, 0x61, 0x61, 0x5E, 0xFC,
+ 0xEA, 0xBE, 0xA4, 0x9B, 0x8B, 0x85, 0x8C, 0x6E,
+ 0x8C, 0x8C, 0x8C, 0xA3, 0xAA, 0xA4, 0xA4, 0xE9,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0x36, 0x6D, 0x70, 0x73,
+ 0x70, 0x70, 0x70, 0x73, 0x73, 0x73, 0x73, 0x70,
+ 0x70, 0x70, 0x73, 0x70, 0x37, 0x38, 0xD1, 0xCF,
+ 0x61, 0x4D, 0x44, 0x2C, 0x2D, 0x2E, 0x2C, 0x2E,
+ 0x3E, 0x56, 0x61, 0xCB, 0xCC, 0x62, 0x5B, 0x57,
+ 0x59, 0x58, 0x55, 0x54, 0x54, 0x55, 0x58, 0x58,
+ 0x58, 0x5B, 0x5E, 0x5B, 0x53, 0x55, 0x55, 0x5C,
+ 0x5E, 0x61, 0x61, 0x60, 0x5D, 0x5A, 0x4E, 0xFC,
+ 0xFC, 0xEA, 0xAA, 0x9C, 0x8A, 0x85, 0x82, 0x8C,
+ 0x8C, 0xA8, 0xEB, 0xA8, 0xA4, 0xA4, 0xAA, 0xFC,
+ 0xFC, 0xFC, 0x64, 0xFB, 0x39, 0x31, 0x72, 0x78,
+ 0x73, 0x78, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73,
+ 0x78, 0x70, 0x73, 0x73, 0x33, 0xCC, 0xD2, 0xD1,
+ 0xCE, 0x62, 0x53, 0x3F, 0x2D, 0x2D, 0x41, 0x2C,
+ 0x2E, 0x3E, 0x56, 0x62, 0xCB, 0xCB, 0x61, 0x5D,
+ 0x54, 0x54, 0x54, 0x54, 0x56, 0x58, 0x58, 0x58,
+ 0x5C, 0x5E, 0x5A, 0x55, 0x58, 0x58, 0x5B, 0x5E,
+ 0x61, 0x5E, 0x5D, 0x5A, 0x52, 0x55, 0xCD, 0xFC,
+ 0xFC, 0x34, 0xC9, 0xE8, 0xA8, 0xAE, 0xC2, 0xE8,
+ 0xC3, 0xA6, 0xA7, 0xA6, 0xAA, 0x78, 0x2E, 0x42,
+ 0xFC, 0xFC, 0xD2, 0x64, 0xF8, 0x31, 0x72, 0x73,
+ 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x73,
+ 0x73, 0x73, 0x73, 0x72, 0x33, 0x5C, 0x64, 0xD2,
+ 0xD1, 0xCF, 0x63, 0x54, 0x3F, 0x2C, 0x41, 0x41,
+ 0x2C, 0x2E, 0x47, 0x58, 0x63, 0xCB, 0xCB, 0x62,
+ 0x52, 0x53, 0x53, 0x56, 0x58, 0x58, 0x5A, 0x5B,
+ 0x5E, 0x5A, 0x57, 0x58, 0x58, 0x58, 0x60, 0x60,
+ 0x5D, 0x5A, 0x55, 0x4E, 0x64, 0xD2, 0xD1, 0xFC,
+ 0xFC, 0x41, 0x3E, 0xC1, 0xC0, 0xA3, 0xA6, 0xA7,
+ 0xA7, 0xA9, 0xAA, 0xB8, 0x2E, 0x3F, 0x2C, 0x41,
+ 0xFC, 0xFC, 0xF7, 0xCE, 0xCD, 0x36, 0x72, 0x73,
+ 0x74, 0x75, 0x78, 0x75, 0x75, 0x75, 0x74, 0x74,
+ 0x74, 0x74, 0x78, 0x72, 0x6D, 0x49, 0x59, 0xCB,
+ 0xD1, 0xD1, 0xD2, 0xCB, 0x56, 0x3F, 0x2C, 0x41,
+ 0x40, 0x2D, 0x2E, 0x49, 0x5B, 0x64, 0xCC, 0x64,
+ 0x51, 0x53, 0x53, 0x55, 0x58, 0x59, 0x5B, 0x5E,
+ 0x59, 0x58, 0x58, 0x58, 0x55, 0x60, 0x60, 0x5C,
+ 0x5A, 0x53, 0x5B, 0xD0, 0xD3, 0xD3, 0xD3, 0xFB,
+ 0xFC, 0x40, 0x41, 0x45, 0xC4, 0xC0, 0xBE, 0xBE,
+ 0xC1, 0xC0, 0x3C, 0x47, 0x2E, 0x21, 0x22, 0x20,
+ 0x65, 0xFC, 0xFC, 0xFC, 0xFC, 0x6D, 0x72, 0x75,
+ 0x78, 0x76, 0x75, 0x79, 0x76, 0x76, 0x76, 0x76,
+ 0x75, 0x75, 0x75, 0x72, 0x6D, 0x2E, 0x48, 0x5D,
+ 0xCE, 0xD1, 0xD4, 0xD3, 0xCB, 0x56, 0x43, 0x2C,
+ 0x42, 0x43, 0x2E, 0x2E, 0x4A, 0x5D, 0x64, 0x64,
+ 0x50, 0x52, 0x56, 0x58, 0x5C, 0x5D, 0x5E, 0x5D,
+ 0x5A, 0x58, 0x58, 0x55, 0x61, 0x60, 0x58, 0x58,
+ 0x4E, 0x61, 0xD1, 0xD4, 0xD4, 0xD1, 0xEE, 0xFC,
+ 0xFC, 0x2B, 0x29, 0x2E, 0x3F, 0xB0, 0xAD, 0x81,
+ 0x46, 0x2D, 0x46, 0x2C, 0x24, 0x22, 0x22, 0x23,
+ 0x25, 0xFC, 0xFC, 0xFC, 0xFC, 0x6E, 0x73, 0x76,
+ 0x76, 0x79, 0x79, 0x79, 0x76, 0x76, 0x79, 0x76,
+ 0x79, 0x79, 0x79, 0x74, 0x3F, 0x41, 0x2C, 0x48,
+ 0x5F, 0xCF, 0xD5, 0xD7, 0xD6, 0xCD, 0x57, 0x40,
+ 0x2E, 0x3F, 0x44, 0x2E, 0x41, 0x4C, 0x60, 0x61,
+ 0x51, 0x53, 0x58, 0x5C, 0x5D, 0x5E, 0x5D, 0x5C,
+ 0x58, 0x57, 0x54, 0x5F, 0x5E, 0x55, 0x55, 0x52,
+ 0x64, 0xD4, 0xD5, 0xD4, 0xD1, 0x5D, 0xFA, 0xFB,
+ 0xF4, 0x21, 0x24, 0x41, 0x40, 0x44, 0x2E, 0x2E,
+ 0x42, 0x41, 0x2A, 0x24, 0x22, 0x22, 0x22, 0x22,
+ 0x23, 0xD9, 0xFC, 0xFC, 0xFC, 0xFC, 0xE5, 0xB8,
+ 0x8F, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F,
+ 0x8F, 0x8F, 0xB8, 0xE5, 0x3F, 0x3E, 0x43, 0x2C,
+ 0x48, 0x61, 0xD1, 0xD7, 0xD9, 0xD7, 0xD0, 0x57,
+ 0x41, 0x2E, 0x3E, 0x44, 0x2D, 0x40, 0x52, 0x5D,
+ 0x53, 0x55, 0x59, 0x5D, 0x5E, 0x5E, 0x5D, 0x5A,
+ 0x57, 0x53, 0x5E, 0x5E, 0x54, 0x53, 0x54, 0x65,
+ 0xD5, 0xD6, 0xD4, 0xCE, 0x53, 0xFB, 0xF9, 0xFC,
+ 0x24, 0x22, 0x23, 0x23, 0x41, 0x42, 0x2E, 0x40,
+ 0x2B, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x23, 0x23, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xBD,
+ 0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0xB5, 0xC6, 0xEB, 0x2D, 0x47, 0x4A, 0x47,
+ 0x2C, 0x3E, 0x61, 0xD4, 0xDC, 0xDC, 0xDA, 0xCF,
+ 0x54, 0x41, 0x41, 0x3E, 0x45, 0x2C, 0x3F, 0x4A,
+ 0x58, 0x5A, 0x5C, 0x5F, 0x60, 0x5E, 0x5D, 0x57,
+ 0x51, 0x5D, 0x5D, 0x51, 0x53, 0x53, 0xCB, 0xD5,
+ 0xD6, 0xD5, 0x63, 0x55, 0xFC, 0xFC, 0xFC, 0x2C,
+ 0x23, 0x22, 0x23, 0x22, 0x20, 0x2D, 0x2C, 0x26,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x21, 0xF0, 0xFC, 0xFC, 0xFC, 0xE2, 0xC6,
+ 0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0xC7, 0xE3, 0x3E, 0x2E, 0x49, 0x52,
+ 0x4C, 0x41, 0x44, 0x62, 0xD6, 0xDE, 0xDE, 0xD9,
+ 0xD0, 0x51, 0x2E, 0x40, 0x47, 0x44, 0x2C, 0x42,
+ 0x5D, 0x5D, 0x5F, 0x60, 0x60, 0x5D, 0x57, 0x51,
+ 0x58, 0x5D, 0x4E, 0x52, 0x55, 0x64, 0xD5, 0xD6,
+ 0xD4, 0x61, 0x59, 0x6B, 0xFC, 0xFC, 0xFC, 0x21,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x21, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x21, 0x24, 0xFC, 0xFC, 0xFC, 0xE2, 0xC7,
+ 0xB5, 0x90, 0x93, 0x93, 0x93, 0x90, 0x93, 0x93,
+ 0x90, 0xB5, 0xC8, 0xE4, 0x5F, 0x45, 0x2E, 0x4D,
+ 0x57, 0x57, 0x44, 0x43, 0x63, 0xDA, 0xDF, 0xDF,
+ 0xD9, 0xCE, 0x4C, 0x2C, 0x3F, 0x3E, 0x40, 0x40,
+ 0x60, 0x5E, 0x61, 0x61, 0x5E, 0x5B, 0x53, 0x52,
+ 0x5C, 0x52, 0x52, 0x55, 0x61, 0xD4, 0xD5, 0xD1,
+ 0x5E, 0x5B, 0x5C, 0xFB, 0xFC, 0xFC, 0x2A, 0x21,
+ 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0xFB, 0xFC, 0xFC, 0xB3, 0xC8,
+ 0xB5, 0x90, 0x92, 0xB5, 0x93, 0x93, 0xB5, 0x93,
+ 0x92, 0xB5, 0xC8, 0xB9, 0xD0, 0x5E, 0x44, 0x40,
+ 0x52, 0x58, 0x57, 0x48, 0x40, 0x63, 0xD9, 0xE0,
+ 0xE0, 0xD9, 0xCB, 0x49, 0x2D, 0x3F, 0x45, 0x3F,
+ 0x63, 0x61, 0x62, 0x60, 0x5E, 0x55, 0x4D, 0x59,
+ 0x53, 0x4E, 0x54, 0x5D, 0xD2, 0xD4, 0xD2, 0x5E,
+ 0x5C, 0x5D, 0xFC, 0xFC, 0xFC, 0xF8, 0x29, 0x23,
+ 0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x23, 0x22, 0x22, 0x23, 0x23, 0x23, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0xF0, 0xFC, 0xFC, 0xB3, 0xC7,
+ 0xB5, 0x93, 0xB5, 0x93, 0x93, 0x91, 0x93, 0x93,
+ 0x91, 0xB5, 0xC7, 0xAD, 0xD6, 0xD2, 0x5E, 0x3F,
+ 0x3F, 0x57, 0x57, 0x58, 0x4A, 0x41, 0x64, 0xDC,
+ 0xF1, 0xDF, 0xDA, 0x61, 0x45, 0x2E, 0x43, 0x47,
+ 0xCB, 0x63, 0x62, 0x5F, 0x58, 0x51, 0x53, 0x54,
+ 0x4C, 0x52, 0x5C, 0xCD, 0xD3, 0xD2, 0x60, 0x5D,
+ 0x5D, 0xFB, 0xFC, 0xFC, 0xFC, 0xDB, 0x49, 0x24,
+ 0x21, 0x23, 0x23, 0x22, 0x26, 0x26, 0x2A, 0x24,
+ 0x22, 0x23, 0x22, 0x21, 0x24, 0x26, 0x26, 0x2A,
+ 0x29, 0x2B, 0x24, 0x25, 0xFC, 0xFC, 0xB3, 0xC5,
+ 0x91, 0x91, 0x92, 0x91, 0x92, 0x92, 0x93, 0x93,
+ 0x91, 0x93, 0xC6, 0xAD, 0xDC, 0xD9, 0xD4, 0x60,
+ 0x43, 0x45, 0x58, 0x58, 0x57, 0x4B, 0x43, 0xCC,
+ 0xDD, 0xF1, 0xD8, 0xD5, 0x5D, 0x43, 0x41, 0x47,
+ 0xCD, 0x63, 0x62, 0x5D, 0x54, 0x4C, 0x55, 0x4B,
+ 0x51, 0x58, 0x62, 0xD0, 0xD0, 0x62, 0x5D, 0x5D,
+ 0x67, 0xFC, 0xFC, 0xFC, 0xFC, 0x58, 0x4E, 0x28,
+ 0x2A, 0x20, 0x23, 0x22, 0x23, 0x2A, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x23, 0x25, 0x2A, 0x2E, 0x2D,
+ 0x2E, 0x2E, 0x2E, 0x23, 0xFA, 0xFC, 0xB2, 0xBD,
+ 0xB5, 0x90, 0x91, 0x93, 0x92, 0x90, 0x91, 0x93,
+ 0x92, 0x91, 0xBD, 0xAD, 0xDE, 0xE0, 0xD8, 0xD7,
+ 0x61, 0x40, 0x48, 0x58, 0x58, 0x58, 0x48, 0x44,
+ 0xCF, 0xDE, 0xE0, 0xDD, 0xD0, 0x52, 0x41, 0x45,
+ 0xCD, 0x63, 0x61, 0x58, 0x4D, 0x51, 0x4C, 0x4B,
+ 0x54, 0x5D, 0xCC, 0xCE, 0x63, 0x61, 0x5D, 0x5D,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x27, 0x21,
+ 0x22, 0x22, 0x23, 0x22, 0x22, 0x24, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x20,
+ 0x27, 0x2B, 0x41, 0x2B, 0x23, 0xFC, 0xB2, 0xB6,
+ 0x93, 0x90, 0x92, 0xB5, 0x92, 0x90, 0xB5, 0x90,
+ 0x92, 0x93, 0xBC, 0xAD, 0xDC, 0xF1, 0xF3, 0xF0,
+ 0xD9, 0x61, 0x41, 0x4A, 0x58, 0x57, 0x57, 0x44,
+ 0x49, 0xD2, 0xDD, 0xD8, 0xDA, 0x63, 0x4A, 0x45,
+ 0xCC, 0x63, 0x5E, 0x52, 0x4B, 0x4C, 0x49, 0x51,
+ 0x5C, 0x61, 0xCD, 0x65, 0x63, 0x5E, 0x4E, 0xCF,
+ 0xFB, 0xFB, 0xF0, 0xFC, 0xD2, 0x2A, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x26, 0x41, 0x27, 0xF9, 0x81, 0xB7,
+ 0xB5, 0x91, 0x92, 0xB5, 0x91, 0xB5, 0x93, 0xB5,
+ 0x93, 0xB6, 0xB7, 0xB9, 0xCB, 0xD8, 0xF3, 0xF2,
+ 0xF2, 0xDB, 0x61, 0x2D, 0x51, 0x58, 0x57, 0x58,
+ 0x41, 0x51, 0xD4, 0xDB, 0xDC, 0xD1, 0x5B, 0x4C,
+ 0xCB, 0x62, 0x59, 0x4C, 0x4A, 0x49, 0x4B, 0x55,
+ 0x60, 0x64, 0xCC, 0x64, 0x5E, 0x55, 0x60, 0xE1,
+ 0xFB, 0xF8, 0xFC, 0xFC, 0x21, 0x22, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x21, 0x24, 0x2D, 0x21, 0xB4, 0xBB,
+ 0xB6, 0xB5, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6,
+ 0xB6, 0xB6, 0xBB, 0xB9, 0x45, 0xCB, 0xDF, 0xF3,
+ 0xF3, 0xF3, 0xDB, 0x5E, 0x2C, 0x51, 0x58, 0x58,
+ 0x52, 0x2D, 0x5C, 0xD4, 0xD9, 0xD5, 0x63, 0x58,
+ 0x64, 0x60, 0x53, 0x49, 0x4A, 0x49, 0x52, 0x5C,
+ 0x63, 0xCD, 0xCD, 0x63, 0x5C, 0x4E, 0x65, 0xFC,
+ 0xFC, 0xF5, 0xFC, 0xD2, 0x23, 0x22, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x21, 0x22, 0x25, 0x29, 0xB3, 0xC7,
+ 0xB5, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB6, 0xB5, 0xC7, 0xAD, 0x57, 0x3F, 0xCB, 0xF0,
+ 0xF3, 0xF3, 0xF2, 0xD9, 0x58, 0x41, 0x4C, 0x58,
+ 0x57, 0x47, 0x42, 0x62, 0xD4, 0xD4, 0xCC, 0x60,
+ 0x63, 0x5D, 0x50, 0x47, 0x48, 0x4B, 0x58, 0x60,
+ 0xCC, 0xCE, 0xCD, 0x60, 0x53, 0x5C, 0x62, 0xFB,
+ 0xF9, 0xFC, 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x23, 0x23, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0x81, 0xC7,
+ 0xB7, 0xB7, 0xBC, 0xB7, 0xBC, 0xBC, 0xBC, 0xB7,
+ 0xB7, 0xB7, 0xC8, 0x80, 0x58, 0x57, 0x40, 0xCE,
+ 0xF3, 0xF2, 0xF2, 0xF0, 0xD5, 0x4C, 0x3F, 0x4B,
+ 0x52, 0x50, 0x2D, 0x4B, 0x64, 0xD2, 0xCC, 0x61,
+ 0x60, 0x58, 0x4A, 0x47, 0x47, 0x4C, 0x59, 0x64,
+ 0xD0, 0xD0, 0x64, 0x59, 0x49, 0x5D, 0xFB, 0xFC,
+ 0xD9, 0xFC, 0xD6, 0x23, 0x22, 0x22, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x23, 0x21, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0xB4, 0xC8,
+ 0xBD, 0xB7, 0xBD, 0xBC, 0xBD, 0xC5, 0xBC, 0xC5,
+ 0xBC, 0xBD, 0xC7, 0xAC, 0x58, 0x57, 0x58, 0x2C,
+ 0xD1, 0xF0, 0xF3, 0xF3, 0xE0, 0xCD, 0x45, 0x3E,
+ 0x48, 0x4B, 0x3F, 0x41, 0x56, 0x64, 0x65, 0x62,
+ 0x5D, 0x52, 0x47, 0x48, 0x48, 0x53, 0x60, 0xCC,
+ 0xD2, 0xD0, 0x63, 0x52, 0x4E, 0x53, 0xFB, 0xFB,
+ 0xFC, 0xFC, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x23, 0x20, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0xB4, 0xC7,
+ 0xC5, 0xBC, 0xC5, 0xBD, 0xC5, 0xC5, 0xBD, 0xC5,
+ 0xBC, 0xC6, 0xC7, 0xB9, 0x58, 0x57, 0x58, 0x57,
+ 0x2D, 0xD4, 0xF1, 0xF2, 0xF0, 0xD9, 0x5D, 0x47,
+ 0x48, 0x3F, 0x42, 0x2C, 0x48, 0x5C, 0x5F, 0x60,
+ 0x58, 0x50, 0x47, 0x4A, 0x49, 0x55, 0x63, 0xD0,
+ 0xD2, 0xCD, 0x5D, 0x49, 0x4E, 0xE1, 0xFC, 0xF0,
+ 0xFC, 0xF8, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x20, 0x21, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x23, 0x23, 0x22, 0xC4, 0xC8,
+ 0xBD, 0xBD, 0xC6, 0xBD, 0xC6, 0xC6, 0xC5, 0xC6,
+ 0xBD, 0xC6, 0xC7, 0xE4, 0x54, 0x57, 0x58, 0x57,
+ 0x57, 0x43, 0xD7, 0xE0, 0xF1, 0xD8, 0xCD, 0x4B,
+ 0x4A, 0x47, 0x42, 0x2C, 0x3F, 0x4D, 0x58, 0x5C,
+ 0x52, 0x4B, 0x48, 0x4B, 0x4A, 0x58, 0xCB, 0xD3,
+ 0xD2, 0xCD, 0x58, 0x47, 0x4A, 0xFC, 0xFC, 0xFB,
+ 0xFC, 0x2B, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x26, 0x21, 0x21, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0xE5, 0xC8,
+ 0xBA, 0xC5, 0xC6, 0xC6, 0xC6, 0xC7, 0xC6, 0xC7,
+ 0xC5, 0xC6, 0xC8, 0xE5, 0x2E, 0x54, 0x58, 0x57,
+ 0x57, 0x4C, 0x4D, 0xDA, 0xD8, 0xD8, 0xD4, 0x5C,
+ 0x4B, 0x4B, 0x3F, 0x42, 0x44, 0x4A, 0x51, 0x58,
+ 0x4B, 0x48, 0x4B, 0x51, 0x4D, 0x5F, 0xD0, 0xD1,
+ 0xD0, 0x64, 0x51, 0x44, 0x6B, 0xFC, 0xFB, 0xFC,
+ 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x26, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0xE5, 0xED,
+ 0xE7, 0xBA, 0xC8, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7,
+ 0xC7, 0xE5, 0xED, 0xE6, 0x61, 0x41, 0x52, 0x58,
+ 0x58, 0x57, 0x45, 0x5E, 0xD7, 0xDD, 0xD5, 0x60,
+ 0x4B, 0x4C, 0x48, 0x4D, 0x4D, 0x50, 0x4D, 0x56,
+ 0x4A, 0x3E, 0x53, 0x53, 0x52, 0x63, 0xD3, 0xD0,
+ 0xCE, 0x60, 0x4A, 0x45, 0xFC, 0xFC, 0xF7, 0xFC,
+ 0xFC, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x21, 0x2A, 0x20, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x21, 0x23, 0xEB, 0xF6,
+ 0xF6, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
+ 0xF6, 0xF6, 0xF6, 0xE6, 0xDB, 0x58, 0x45, 0x4B,
+ 0x58, 0x57, 0x4D, 0x4B, 0x64, 0xD4, 0xD0, 0x5C,
+ 0x48, 0x51, 0x4C, 0x5D, 0x5E, 0x5C, 0x56, 0x59,
+ 0x3E, 0x4A, 0x58, 0x54, 0x52, 0x65, 0xD3, 0xD0,
+ 0xCF, 0x5D, 0x48, 0xFC, 0xFC, 0xFC, 0xFA, 0xFC,
+ 0xFC, 0x21, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x21, 0x2A, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x21, 0x4F, 0xE6, 0xC6,
+ 0xC6, 0xBD, 0xC6, 0xBD, 0xBD, 0xBD, 0xBD, 0xC6,
+ 0xC5, 0xBA, 0xC7, 0xE6, 0xF2, 0xD4, 0x49, 0x4B,
+ 0x3E, 0x4D, 0x52, 0x3E, 0x52, 0x63, 0x64, 0x56,
+ 0x48, 0x54, 0x4D, 0x61, 0xCC, 0xCC, 0x60, 0x60,
+ 0x47, 0x4D, 0x5C, 0x53, 0x58, 0xCF, 0xD1, 0xCF,
+ 0xD0, 0x59, 0x45, 0xFC, 0xFC, 0xFC, 0xEF, 0xF9,
+ 0xFC, 0x21, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x4F, 0xE4, 0xB9,
+ 0xAF, 0x80, 0x80, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F,
+ 0x80, 0xB4, 0xB9, 0xE4, 0x7F, 0xDE, 0x61, 0x52,
+ 0x54, 0x48, 0x3F, 0x43, 0x4D, 0x56, 0x59, 0x4B,
+ 0x3E, 0x58, 0x53, 0x61, 0xD3, 0xD4, 0xCF, 0xCD,
+ 0x4C, 0x58, 0x5F, 0x53, 0x5E, 0xD3, 0xD0, 0xCE,
+ 0xCE, 0x52, 0x3F, 0xFC, 0xFC, 0xFC, 0xF7, 0x65,
+ 0xFA, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x21, 0x2A, 0x23, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x21, 0xB1, 0xE4, 0xE6,
+ 0x7C, 0xB1, 0x7C, 0xB1, 0xB2, 0xB2, 0xB3, 0x3D,
+ 0xB3, 0x3C, 0xE5, 0xB3, 0xB0, 0xF1, 0xD0, 0x58,
+ 0x5D, 0x4D, 0x40, 0x41, 0x48, 0x51, 0x4C, 0x3F,
+ 0x3F, 0x4D, 0x5A, 0x5A, 0xD5, 0xD9, 0xD7, 0xD4,
+ 0x57, 0x5E, 0x61, 0x4C, 0x63, 0xD4, 0xCF, 0xCE,
+ 0xCB, 0x4D, 0x4A, 0xFC, 0xFC, 0xFC, 0xFC, 0xF0,
+ 0xFB, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x22, 0x23, 0x22, 0x23, 0x23, 0xB1, 0x81, 0x7D,
+ 0x39, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x7C, 0xB2, 0xB0, 0xDF, 0xD2, 0x57,
+ 0x60, 0x59, 0x5B, 0x59, 0x52, 0x4C, 0x4A, 0x40,
+ 0x42, 0x4A, 0x53, 0x4D, 0xD2, 0xDE, 0xDE, 0xD9,
+ 0x5E, 0x5E, 0x60, 0x4A, 0xCD, 0xD1, 0xCF, 0xCE,
+ 0x63, 0x49, 0x5C, 0xFB, 0xE8, 0x89, 0x9F, 0xFC,
+ 0xD6, 0x21, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x21, 0x2A, 0x22, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x7F, 0xB9,
+ 0x71, 0x6C, 0x38, 0x38, 0x33, 0x33, 0x33, 0x38,
+ 0x38, 0x71, 0xAD, 0xE4, 0xD3, 0xDA, 0xCC, 0x52,
+ 0x63, 0x60, 0xCE, 0xD4, 0xCF, 0x60, 0x4C, 0x40,
+ 0x3F, 0x45, 0x4B, 0x5A, 0xCB, 0xD8, 0xDE, 0xDC,
+ 0x5E, 0x5E, 0x5F, 0x4C, 0xD2, 0xD2, 0xCF, 0xCF,
+ 0x61, 0x45, 0x5E, 0xA7, 0x9D, 0x95, 0x8B, 0x99,
+ 0xFC, 0x41, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x2A, 0x23, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x77, 0x77, 0xF6,
+ 0xFC, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D,
+ 0x7D, 0xFC, 0x47, 0x64, 0xD0, 0xD0, 0x5D, 0x4B,
+ 0x62, 0xCC, 0xD1, 0xDE, 0xDE, 0xD4, 0x5E, 0x43,
+ 0x3F, 0x3E, 0x48, 0x53, 0x58, 0xDB, 0xD8, 0xDC,
+ 0x5E, 0x5E, 0x5E, 0x53, 0xD4, 0xD2, 0xD0, 0xD0,
+ 0x5E, 0x49, 0xA7, 0xA6, 0x89, 0x95, 0x8B, 0x9C,
+ 0x9C, 0xFB, 0xD4, 0x22, 0x22, 0x22, 0x22, 0x23,
+ 0x22, 0x23, 0x23, 0x2A, 0x22, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x23, 0x22, 0x23, 0x23, 0x98, 0x8C, 0x8C, 0x88,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8,
+ 0xE9, 0x9C, 0x48, 0x5C, 0xD0, 0xCB, 0x48, 0x49,
+ 0x5B, 0xCB, 0xCD, 0xE0, 0xF1, 0xDD, 0xD0, 0x4A,
+ 0x41, 0x47, 0x45, 0x4C, 0x48, 0xD7, 0xDE, 0xDC,
+ 0x5E, 0x5E, 0x5A, 0x58, 0xD1, 0xD0, 0xD0, 0xD2,
+ 0x5C, 0x55, 0xA7, 0xA6, 0x87, 0x86, 0x89, 0x94,
+ 0x9C, 0xA9, 0xFC, 0xF4, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x22, 0x2A, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x22, 0x23, 0xA4, 0x89, 0x8C, 0xAA,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF7,
+ 0x85, 0x88, 0x8D, 0x59, 0x64, 0x63, 0x47, 0x3E,
+ 0x4C, 0x60, 0x61, 0xE0, 0xF0, 0xDF, 0xD9, 0x5D,
+ 0x2E, 0x3E, 0x3E, 0x47, 0x4D, 0xCD, 0xDE, 0xDC,
+ 0x5D, 0x5C, 0x51, 0x5D, 0xD1, 0xD2, 0xD2, 0xD4,
+ 0x5A, 0xBE, 0xA7, 0x98, 0x8A, 0x8A, 0xA0, 0x8B,
+ 0x86, 0x86, 0xF7, 0xFC, 0xF7, 0x26, 0x23, 0x23,
+ 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x21, 0x21, 0x21, 0xA1, 0x98, 0x9F, 0xBF,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xA7,
+ 0x8C, 0x86, 0x8D, 0x59, 0x5E, 0x5D, 0x3F, 0x3E,
+ 0x47, 0x53, 0x63, 0xD9, 0xF0, 0xF1, 0xDE, 0xD0,
+ 0x43, 0x3E, 0x47, 0x45, 0x4A, 0x5B, 0xDC, 0xDA,
+ 0x5D, 0x59, 0x49, 0x5F, 0xD1, 0xD2, 0xD3, 0xB9,
+ 0xA5, 0xA7, 0x98, 0x9B, 0x96, 0x9D, 0x89, 0x89,
+ 0x8B, 0x9C, 0x9D, 0xFC, 0xFC, 0xFC, 0x26, 0x22,
+ 0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x29, 0x2D, 0x99, 0x99, 0xA2, 0xAA,
+ 0xC4, 0xFB, 0xFC, 0xFC, 0xFC, 0xF6, 0xBF, 0xA2,
+ 0x9C, 0x9C, 0x8E, 0xDC, 0xCD, 0x51, 0x41, 0x3E,
+ 0x45, 0x49, 0x58, 0xCD, 0xE0, 0xE0, 0xD8, 0xDA,
+ 0x4C, 0x4A, 0x45, 0x45, 0x48, 0x47, 0xDA, 0xDA,
+ 0x5C, 0x58, 0x44, 0x69, 0xA9, 0x98, 0xA4, 0xA6,
+ 0xA1, 0xA4, 0x99, 0x9E, 0x9D, 0x8B, 0x8A, 0x97,
+ 0x87, 0x9A, 0x8A, 0xC2, 0xFC, 0xFC, 0xFC, 0x4D,
+ 0x21, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+ 0x21, 0x22, 0x2D, 0x34, 0xA4, 0xA2, 0xA2, 0xA9,
+ 0xBF, 0xC0, 0xC3, 0xC1, 0xC0, 0xBE, 0xA6, 0x9D,
+ 0x99, 0x87, 0xA2, 0xF1, 0xDC, 0x64, 0x42, 0x45,
+ 0x47, 0x3E, 0x49, 0x4C, 0xDD, 0xDF, 0xD8, 0xDB,
+ 0x5E, 0x4C, 0x48, 0x45, 0x45, 0x41, 0xD1, 0xD6,
+ 0x5A, 0x55, 0x3F, 0xA7, 0xA1, 0x98, 0x9F, 0x99,
+ 0x9F, 0x9D, 0x9A, 0x95, 0x8B, 0x97, 0x89, 0x8A,
+ 0x88, 0x94, 0x9C, 0x8C, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xF4, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x23, 0x23, 0x2C, 0x2C, 0xA8, 0xA2, 0xA4, 0xA4,
+ 0xA9, 0xAA, 0xAA, 0xAA, 0xA9, 0xA6, 0x98, 0x9C,
+ 0x8B, 0x88, 0x98, 0x8D, 0xD8, 0xD6, 0x4E, 0x47,
+ 0x47, 0x49, 0x47, 0x3F, 0xDA, 0xDD, 0xDE, 0xDD,
+ 0xCC, 0x4A, 0x4B, 0x3E, 0x45, 0x43, 0x61, 0xD4,
+ 0x56, 0x51, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0x9A,
+ 0xA0, 0xA2, 0x98, 0x98, 0x8B, 0x8B, 0x98, 0x98,
+ 0x84, 0x8B, 0x94, 0x8A, 0xA4, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xF2, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x23,
+ 0x23, 0x22, 0x2C, 0x2D, 0xC0, 0xA4, 0xA2, 0xA4,
+ 0xA4, 0xA6, 0xA6, 0xA6, 0xA4, 0xA2, 0x9F, 0x89,
+ 0x8B, 0x9C, 0x9C, 0x8B, 0x68, 0xDB, 0x5F, 0x4B,
+ 0x3E, 0x49, 0x4B, 0x3E, 0xCC, 0xDA, 0xDC, 0xDD,
+ 0xD3, 0x49, 0x52, 0x48, 0x45, 0x45, 0x53, 0xD0,
+ 0x51, 0x4A, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0xA0,
+ 0x9B, 0x86, 0x89, 0x98, 0x89, 0x8A, 0x96, 0x8A,
+ 0x9C, 0x89, 0x89, 0x9C, 0x8C, 0xF6, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+ 0x22, 0x21, 0x2B, 0x34, 0xC0, 0xA8, 0xA4, 0xA2,
+ 0xA2, 0x98, 0xA1, 0xA0, 0x98, 0x9F, 0x95, 0x8A,
+ 0x94, 0xA1, 0x8A, 0x84, 0x9B, 0x68, 0xCC, 0x49,
+ 0x4A, 0x47, 0x4C, 0x4B, 0x51, 0xD3, 0xDA, 0xDC,
+ 0xD5, 0x56, 0x56, 0x4A, 0x3E, 0x45, 0x48, 0x63,
+ 0x4A, 0x47, 0x3E, 0xA7, 0x98, 0x9D, 0x9E, 0x8B,
+ 0x95, 0x9B, 0x89, 0x86, 0x9B, 0x8B, 0x89, 0x84,
+ 0x9A, 0xA1, 0x95, 0x9A, 0x8C, 0xA4, 0xFC, 0xFC,
+ 0xFC, 0xFA, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+ 0x21, 0x23, 0x2C, 0xF6, 0xBF, 0xA9, 0xA2, 0x99,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9B, 0x87, 0x8B,
+ 0x9C, 0x86, 0x9C, 0x8A, 0x87, 0x87, 0x89, 0x51,
+ 0x54, 0x47, 0x4B, 0x50, 0x4B, 0xCF, 0xD6, 0xDC,
+ 0xD5, 0x60, 0x54, 0x52, 0x48, 0x45, 0x40, 0x5A,
+ 0x45, 0x43, 0x47, 0xA7, 0x98, 0x9B, 0x95, 0x95,
+ 0x9A, 0x87, 0x98, 0x98, 0x8A, 0x86, 0x87, 0x9E,
+ 0x9B, 0x95, 0x9D, 0x9D, 0x99, 0x85, 0xA6, 0xFA,
+ 0xF2, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x22,
+ 0x21, 0x24, 0xFB, 0xF7, 0xBF, 0xA6, 0xA2, 0x99,
+ 0x97, 0x89, 0x86, 0x89, 0x9C, 0x96, 0x9E, 0x94,
+ 0x89, 0x99, 0x98, 0x89, 0x9E, 0x9B, 0x89, 0x8B,
+ 0x58, 0x4B, 0x4A, 0x52, 0x48, 0xCC, 0xD3, 0xDA,
+ 0xD3, 0x65, 0x4C, 0x58, 0x49, 0x3E, 0x2E, 0x4D,
+ 0x40, 0x41, 0x45, 0xA9, 0xA1, 0x9B, 0x9E, 0x9C,
+ 0x95, 0x8A, 0x94, 0x89, 0x96, 0x87, 0x9C, 0x9A,
+ 0x84, 0x9D, 0x9C, 0x9E, 0x9A, 0x9C, 0x9D, 0xBB,
+ 0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x23, 0x23,
+ 0x24, 0xFC, 0xFC, 0xF6, 0xBF, 0xA6, 0x9F, 0x99,
+ 0x89, 0x95, 0x87, 0x94, 0x9D, 0x9E, 0x97, 0x9E,
+ 0x95, 0x9B, 0x89, 0x95, 0x95, 0x9B, 0x89, 0x87,
+ 0x5D, 0x56, 0x3E, 0x51, 0x3E, 0x60, 0xCF, 0xD3,
+ 0xD2, 0xCD, 0x5C, 0x49, 0x4B, 0x3E, 0x2C, 0x48,
+ 0x3E, 0x43, 0x3E, 0xA9, 0xA1, 0x9B, 0x97, 0x94,
+ 0x95, 0x9A, 0x9C, 0x87, 0x87, 0x9B, 0x9C, 0x95,
+ 0x9D, 0x89, 0x9A, 0x89, 0x9E, 0x9E, 0x8C, 0xA6,
+ 0x20, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x20, 0x40,
+ 0xFC, 0xFC, 0xFC, 0xEC, 0xBE, 0xA4, 0x9F, 0x99,
+ 0x95, 0x9F, 0xA0, 0x88, 0x9D, 0x8B, 0x97, 0x95,
+ 0x87, 0x95, 0x96, 0x95, 0x97, 0x94, 0x94, 0x98,
+ 0xD3, 0x4C, 0x47, 0x4D, 0x42, 0x4C, 0x60, 0xCC,
+ 0xCE, 0xD0, 0x65, 0x4B, 0x47, 0x44, 0x2B, 0x45,
+ 0x4B, 0x47, 0x49, 0xA7, 0xA1, 0x9A, 0x97, 0x89,
+ 0x95, 0x97, 0x97, 0x9E, 0x89, 0x95, 0x89, 0x9C,
+ 0x87, 0x95, 0x97, 0x99, 0x95, 0x99, 0x9F, 0xA4,
+ 0xC4, 0x21, 0x21, 0x23, 0x21, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x21, 0x20, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xEA, 0xAA, 0xA6, 0xA2, 0x99,
+ 0x8B, 0x9A, 0x95, 0x9E, 0x9E, 0x9A, 0x94, 0x87,
+ 0x94, 0x94, 0x89, 0x94, 0x9B, 0x9B, 0xA7, 0xDC,
+ 0xDB, 0x65, 0x2E, 0x3E, 0x43, 0x44, 0x49, 0x58,
+ 0x63, 0xD3, 0xD3, 0x5E, 0x42, 0x42, 0x2D, 0x40,
+ 0x54, 0x4C, 0x4A, 0xA7, 0xA0, 0x99, 0x9B, 0x94,
+ 0xA0, 0x8A, 0x9B, 0x9D, 0x87, 0x95, 0x94, 0x8B,
+ 0x8A, 0x98, 0x9C, 0x8A, 0x9B, 0x99, 0xA2, 0xA6,
+ 0xBF, 0xEC, 0x2A, 0x20, 0x21, 0x23, 0x21, 0x20,
+ 0x20, 0x20, 0x20, 0x4C, 0xF9, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xEB, 0xAA, 0xA4, 0x9F, 0x9C,
+ 0x8B, 0x9B, 0x88, 0x84, 0x9E, 0x9D, 0x96, 0x94,
+ 0x94, 0x9A, 0x9B, 0x9B, 0xA4, 0xD5, 0xCD, 0xDE,
+ 0xF1, 0xDA, 0x4C, 0x2D, 0x41, 0x2B, 0x42, 0x4C,
+ 0x5E, 0xD4, 0xD7, 0xCD, 0x49, 0x2E, 0x2E, 0x41,
+ 0x5E, 0x57, 0xA7, 0xA6, 0xA7, 0xA4, 0xA2, 0x98,
+ 0x9D, 0x9C, 0xA1, 0x99, 0x9D, 0x88, 0x8B, 0x9C,
+ 0x8A, 0x9C, 0x9C, 0x94, 0x9C, 0x89, 0xA0, 0xA6,
+ 0xAA, 0xEB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFB, 0xE9, 0xAA, 0xA6, 0xA2, 0x8B,
+ 0x8B, 0x8A, 0x86, 0x9B, 0x9C, 0x98, 0xA0, 0x9B,
+ 0x9B, 0x84, 0xA7, 0xB4, 0x61, 0xD1, 0xD2, 0xE0,
+ 0xF1, 0xDC, 0x61, 0x2D, 0x2E, 0x3F, 0x56, 0x62,
+ 0x5D, 0xD4, 0xD9, 0xD3, 0x54, 0x41, 0x41, 0x44,
+ 0xCB, 0x60, 0x52, 0xA9, 0xA9, 0xA9, 0xA7, 0xA6,
+ 0xA6, 0xA4, 0xA4, 0xA2, 0xA2, 0x9D, 0x95, 0x89,
+ 0x9C, 0x8A, 0x9E, 0x9C, 0x8A, 0x9E, 0xA0, 0xA8,
+ 0xC0, 0xE9, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xE9, 0xAA, 0xA6, 0xA0, 0x99,
+ 0x9C, 0x8B, 0x9A, 0x84, 0x9B, 0x9B, 0x98, 0x98,
+ 0xA9, 0xB9, 0x49, 0x57, 0xCB, 0xD4, 0xD3, 0xF1,
+ 0xD8, 0xDA, 0xCE, 0x3F, 0x41, 0x4B, 0x5D, 0xCB,
+ 0x5E, 0xD6, 0xDB, 0xD6, 0x5D, 0x43, 0x3F, 0x49,
+ 0xD1, 0xCC, 0x4F, 0xDD, 0xC3, 0xBB, 0xBF, 0xAA,
+ 0xAA, 0xA9, 0xAA, 0xA8, 0xA8, 0xA6, 0xA6, 0xA2,
+ 0x9C, 0x9F, 0x9B, 0x9A, 0x9D, 0xA2, 0xA8, 0xAA,
+ 0xC1, 0xEA, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xEA, 0xC0, 0xAA, 0xA6, 0xA2,
+ 0xA2, 0x99, 0xA0, 0xA0, 0xA4, 0xA7, 0xA9, 0xC0,
+ 0x67, 0x49, 0x54, 0x60, 0xD0, 0xD4, 0xCC, 0xDF,
+ 0xD9, 0xD5, 0xD2, 0x3E, 0x47, 0x56, 0x60, 0xCD,
+ 0x5D, 0xD9, 0xD9, 0xD6, 0x61, 0x3F, 0x47, 0x52,
+ 0xD6, 0xD3, 0x62, 0x4D, 0x40, 0x4A, 0x57, 0xCA,
+ 0xC3, 0xC1, 0xC1, 0xC0, 0xBF, 0xBF, 0xAA, 0xAA,
+ 0xA6, 0xA4, 0xA4, 0xA4, 0xA6, 0xA8, 0xBE, 0xC1,
+ 0xC9, 0xEB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xEB, 0xC3, 0xC0, 0xAA, 0xA8,
+ 0xA6, 0xA6, 0xA6, 0xA9, 0xAA, 0xC0, 0xE8, 0xD0,
+ 0xD2, 0x4C, 0x5E, 0x64, 0xD0, 0xD1, 0x5F, 0xD9,
+ 0xD5, 0xD1, 0xD0, 0x48, 0x52, 0x5C, 0x64, 0xCD,
+ 0x5C, 0xDC, 0xD7, 0xD5, 0x62, 0x3F, 0x4C, 0x53,
+ 0xDA, 0xD7, 0xCE, 0x56, 0x40, 0x4B, 0x52, 0x56,
+ 0xCE, 0xDF, 0x6A, 0xEB, 0xE9, 0xC9, 0xC3, 0xC0,
+ 0xC0, 0xBF, 0xBE, 0xAA, 0xBF, 0xC0, 0xC3, 0xC9,
+ 0xEA, 0xF6, 0xEE, 0x58, 0x57, 0x5E, 0xD6, 0xD0,
+ 0xD2, 0x61, 0xCB, 0xD6, 0xD6, 0xD4, 0xDF, 0xF3,
+ 0xF2, 0xDD, 0xD7, 0xEB, 0xC9, 0xC1, 0xC0, 0xBF,
+ 0xAA, 0xAA, 0xAA, 0xBE, 0xC3, 0xF0, 0xD2, 0xD2,
+ 0xD2, 0x51, 0x62, 0xCC, 0xD0, 0xCC, 0x61, 0xD3,
+ 0xCF, 0xCE, 0xD2, 0x48, 0x5A, 0x61, 0xCC, 0xCE,
+ 0x5F, 0xD9, 0xD5, 0xD1, 0x63, 0x44, 0x56, 0x56,
+ 0xDC, 0xD9, 0xD4, 0x5E, 0x42, 0x4A, 0x4C, 0x57,
+ 0x5D, 0xD8, 0xE0, 0xD8, 0xDC, 0xCB, 0x66, 0xEC,
+ 0xE8, 0xC3, 0xC3, 0xC3, 0xC3, 0xC9, 0xE8, 0xEA,
+ 0xF6, 0x50, 0x3E, 0x58, 0x57, 0x5A, 0xD6, 0xD4,
+ 0xCC, 0x4B, 0x53, 0x5C, 0x64, 0xD1, 0xDF, 0xF3,
+ 0xF1, 0xDE, 0xD9, 0xF6, 0xEB, 0xC9, 0xC1, 0xC1,
+ 0xC0, 0xC0, 0xC1, 0xC9, 0xF0, 0xD6, 0xCD, 0xD6,
+ 0xD3, 0x53, 0xCB, 0xCF, 0xCD, 0x5F, 0x5F, 0xCE,
+ 0xCF, 0xCD, 0xD0, 0x47, 0x5F, 0xCB, 0xCE, 0xCD,
+ 0x63, 0xD6, 0xD3, 0xD1, 0x63, 0x3F, 0x58, 0x58,
+ 0xDB, 0xDC, 0xDA, 0x65, 0x3E, 0x49, 0x49, 0x4D,
+ 0x49, 0xDC, 0xDF, 0xE0, 0xDE, 0xD5, 0x47, 0x47,
+ 0x46, 0x6B, 0xEB, 0xEA, 0xE9, 0xEA, 0xEB, 0xF6,
+ 0xD0, 0x57, 0x57, 0x47, 0x47, 0x5B, 0xD4, 0xD4,
+ 0xCD, 0x44, 0x3E, 0x4B, 0x50, 0x4B, 0x51, 0xD5,
+ 0xDB, 0xD8, 0xDE, 0x4B, 0xF6, 0xF6, 0xEA, 0xE9,
+ 0xE8, 0xEA, 0xEB, 0x67, 0x5E, 0xCC, 0xD6, 0xDC,
+ 0xD5, 0x58, 0xCE, 0xCE, 0x62, 0x50, 0xCC, 0xD3,
+ 0xD2, 0xCD, 0xCD, 0x4B, 0x64, 0xCE, 0xCE, 0x64,
+ 0xCC, 0xD3, 0xD2, 0xD2, 0x61, 0x47, 0x5D, 0x5C,
+ 0xDD, 0xDD, 0xD9, 0xD1, 0x4C, 0x47, 0x49, 0x4A,
+ 0x4B, 0xD1, 0xD8, 0xE0, 0xDF, 0xDD, 0x5D, 0x4A,
+ 0x48, 0x52, 0x51, 0x3F, 0xF6, 0xEC, 0xE0, 0xE0,
+ 0xD3, 0x5E, 0x5F, 0x50, 0x4B, 0x50, 0xCB, 0xCE,
+ 0x64, 0x45, 0x4C, 0x57, 0x57, 0x58, 0x52, 0xD6,
+ 0xD3, 0xDE, 0xDF, 0xD1, 0x3E, 0x4B, 0xF6, 0xF6,
+ 0xEC, 0x66, 0x53, 0x43, 0x56, 0xD1, 0xD9, 0xDE,
+ 0xD4, 0x5E, 0xCE, 0xCC, 0x5B, 0x2C, 0xD4, 0xD5,
+ 0xD2, 0xD0, 0x63, 0x5D, 0xCD, 0xD0, 0xCD, 0x5E,
+ 0xD0, 0xCF, 0xCE, 0xD2, 0x5E, 0x50, 0x60, 0x5D,
+ 0xDE, 0xDD, 0xDC, 0xD7, 0x5D, 0x45, 0x47, 0x3E,
+ 0x4B, 0x5E, 0xDE, 0xDF, 0xE0, 0xD8, 0xCF, 0x3E,
+ 0x45, 0x51, 0x58, 0x42, 0xCB, 0xDA, 0xDE, 0xD8,
+ 0xD2, 0x61, 0xCC, 0xCF, 0xD6, 0xDA, 0xDA, 0xD5,
+ 0xD0, 0x50, 0x44, 0x57, 0x57, 0x58, 0x45, 0xD1,
+ 0xD1, 0xD7, 0xDF, 0xDF, 0xD7, 0xCF, 0x64, 0x60,
+ 0xCE, 0xCE, 0xCE, 0x63, 0xCF, 0xDA, 0xDE, 0xD9,
+ 0xCF, 0x63, 0xCD, 0x63, 0x4D, 0x4B, 0xD6, 0xD5,
+ 0xCE, 0xD3, 0x60, 0xCB, 0xD0, 0xD0, 0x65, 0x47,
+ 0xD0, 0xCC, 0xCC, 0xD1, 0x59, 0x5D, 0x63, 0x5E,
+ 0xDD, 0xDD, 0xDE, 0xDC, 0xCB, 0x40, 0x48, 0x45,
+ 0x3E, 0x3E, 0xD9, 0xDF, 0xE0, 0xDF, 0xDA, 0x51,
+ 0x4C, 0x48, 0x56, 0x4C, 0x5B, 0xD2, 0xDA, 0xDB,
+ 0xCB, 0x5F, 0xD0, 0xCC, 0xDC, 0xF0, 0xF3, 0xE0,
+ 0xDD, 0xCC, 0x41, 0x50, 0x57, 0x57, 0x4B, 0x5D,
+ 0xD3, 0xD1, 0xDE, 0xDF, 0xDE, 0xD7, 0xD0, 0xD0,
+ 0xD5, 0xD6, 0xD6, 0xCE, 0xD7, 0xDC, 0xDA, 0xD5,
+ 0x60, 0x63, 0x64, 0x5E, 0x47, 0x61, 0xD5, 0xD2,
+ 0xCF, 0xD0, 0x59, 0xCD, 0xD1, 0xCF, 0x61, 0x4D,
+ 0xCC, 0xCE, 0xCD, 0xD0, 0x52, 0x61, 0x64, 0x60,
+ 0xDA, 0xDE, 0xDE, 0xDD, 0xD1, 0x4B, 0x4A, 0x45,
+ 0x3E, 0x41, 0xCD, 0xDE, 0xE0, 0xF1, 0xDE, 0x63,
+ 0x4A, 0x4A, 0x4A, 0x4B, 0x50, 0xCB, 0xD4, 0xD7,
+ 0x5E, 0x54, 0x62, 0xD3, 0xD4, 0xF0, 0xF3, 0xF3,
+ 0xF2, 0xDE, 0x61, 0x40, 0x49, 0x56, 0x4D, 0x3E,
+ 0x4B, 0xCE, 0xD9, 0xD8, 0xD9, 0xD5, 0xCF, 0xD2,
+ 0xD6, 0xD6, 0xD1, 0xD1, 0xD7, 0xD5, 0xCF, 0xD0,
+ 0x54, 0x64, 0x63, 0x56, 0x2C, 0xCB, 0xD1, 0xCC,
+ 0xD3, 0xCD, 0x54, 0xCF, 0xD1, 0xCE, 0x5E, 0x5C,
+ 0xCE, 0xCE, 0xCE, 0xCB, 0x4B, 0x63, 0xCC, 0x61,
+ 0xD4, 0xDC, 0xDE, 0xDE, 0xDA, 0x5D, 0x45, 0x45,
+ 0x48, 0x3F, 0x52, 0xD9, 0xD8, 0xDF, 0xDF, 0xD2,
+ 0x52, 0x4B, 0x3E, 0x2E, 0x47, 0x60, 0xCF, 0xD3,
+ 0x59, 0x48, 0x50, 0x5E, 0xCC, 0xDE, 0xF2, 0xF2,
+ 0xF3, 0xF3, 0xDD, 0x5D, 0x3E, 0x48, 0x47, 0x47,
+ 0x58, 0xD1, 0xDA, 0xDA, 0xD5, 0xD1, 0xCD, 0xD2,
+ 0xD3, 0xCF, 0xD3, 0xD1, 0xCD, 0xD3, 0xD2, 0x5E,
+ 0x52, 0x64, 0x60, 0x4B, 0x45, 0x61, 0xCD, 0xD3,
+ 0xD3, 0x64, 0x61, 0xD0, 0xD0, 0x64, 0x45, 0x63,
+ 0xD0, 0xCE, 0xD0, 0x60, 0x56, 0xCB, 0xCC, 0x62,
+ 0xCE, 0xDA, 0xDE, 0xD8, 0xDD, 0xCC, 0x45, 0x49,
+ 0x3E, 0x47, 0x42, 0xD1, 0xDC, 0xD8, 0xD8, 0xD3,
+ 0x5D, 0x4C, 0x49, 0x3F, 0x47, 0x59, 0xCD, 0xCF,
+ 0x59, 0x2E, 0x48, 0x47, 0x52, 0x63, 0xF0, 0xF2,
+ 0xF3, 0xF3, 0xF2, 0xDA, 0x52, 0x4B, 0x52, 0x58,
+ 0x5E, 0x63, 0xD0, 0xD0, 0xD0, 0xCF, 0xCE, 0xCE,
+ 0xCF, 0x65, 0x61, 0xD6, 0xD6, 0xD6, 0xCB, 0x4B,
+ 0x61, 0x62, 0x5D, 0x43, 0x4B, 0x61, 0xD0, 0xD4,
+ 0xD1, 0x61, 0xCE, 0xD2, 0xCD, 0x5E, 0x4A, 0xCE,
+ 0xD0, 0xCC, 0xD0, 0x59, 0x61, 0xCC, 0xCC, 0x62,
+ 0xD1, 0xD5, 0xDE, 0xD8, 0xDD, 0xCF, 0x4B, 0x4A,
+ 0x45, 0x3E, 0x2D, 0xCB, 0xDC, 0xDE, 0xD8, 0xD5,
+ 0x60, 0x54, 0x51, 0x4C, 0x4D, 0x5C, 0xCC, 0xCE,
+ 0x5A, 0x2C, 0x50, 0x53, 0x3E, 0x59, 0xD8, 0xF3,
+ 0xF2, 0xF3, 0xF3, 0xE0, 0x5E, 0x4A, 0x4C, 0x53,
+ 0x5E, 0x63, 0xCC, 0xCC, 0xCC, 0xCD, 0xCF, 0xD3,
+ 0x62, 0x53, 0xD6, 0xD6, 0xD6, 0xD6, 0x5B, 0x48,
+ 0x64, 0x63, 0x59, 0x44, 0x57, 0x63, 0xD2, 0xD3,
+ 0xD0, 0x5E, 0xD0, 0xD1, 0xCB, 0x58, 0x4C, 0xCF,
+ 0xCF, 0xCE, 0xCE, 0x57, 0x63, 0xCC, 0xCD, 0x57,
+};
pte **pmap; /* Two-level page-map structure */
} MMU_context;
-/* Used to set up SDR register */
+/* Used to set up SDR1 register */
#define HASH_TABLE_SIZE_64K 0x00010000
#define HASH_TABLE_SIZE_128K 0x00020000
#define HASH_TABLE_SIZE_256K 0x00040000
#define HASH_TABLE_MASK_2M 0x01F
#define HASH_TABLE_MASK_4M 0x03F
+/* invalidate a TLB entry */
+extern inline void _tlbie(unsigned long va)
+{
+ asm volatile ("tlbie %0" : : "r"(va));
+}
+
+extern void _tlbia(void); /* invalidate all TLB entries */
+
#endif
do { \
struct mm_struct *mm = (tsk)->mm; \
if (mm->context == NO_CONTEXT) { \
- int i; \
if (next_mmu_context == LAST_CONTEXT) \
mmu_context_overflow(); \
mm->context = MUNGE_CONTEXT(++next_mmu_context);\
-/* $Id: namei.h,v 1.1 1997/07/25 09:28:40 cort Exp $
- * linux/include/asm-i386/namei.h
+/* $Id: namei.h,v 1.2 1997/07/31 07:10:55 paulus Exp $
+ * linux/include/asm-ppc/namei.h
+ * Adapted from linux/include/asm-alpha/namei.h
*
* Included from linux/fs/namei.c
*/
-#ifndef __I386_NAMEI_H
-#define __I386_NAMEI_H
+#ifndef __PPC_NAMEI_H
+#define __PPC_NAMEI_H
/* These dummy routines maybe changed to something useful
* for /usr/gnemul/ emulation stuff.
#define translate_open_namei(pathname, flag, mode, res_inode, base) \
do { } while (0)
-#endif /* __I386_NAMEI_H */
+#endif /* __PPC_NAMEI_H */
/* RTC Offsets */
-#define RTC_SECONDS 0x1FF9
-#define RTC_MINUTES 0x1FFA
-#define RTC_HOURS 0x1FFB
-#define RTC_DAY_OF_WEEK 0x1FFC
-#define RTC_DAY_OF_MONTH 0x1FFD
-#define RTC_MONTH 0x1FFE
-#define RTC_YEAR 0x1FFF
-#define RTC_CONTROLA 0x1FF8
-#define RTC_CONTROLB 0x1FF9
+#define MOTO_RTC_SECONDS 0x1FF9
+#define MOTO_RTC_MINUTES 0x1FFA
+#define MOTO_RTC_HOURS 0x1FFB
+#define MOTO_RTC_DAY_OF_WEEK 0x1FFC
+#define MOTO_RTC_DAY_OF_MONTH 0x1FFD
+#define MOTO_RTC_MONTH 0x1FFE
+#define MOTO_RTC_YEAR 0x1FFF
+#define MOTO_RTC_CONTROLA 0x1FF8
+#define MOTO_RTC_CONTROLB 0x1FF9
#ifndef BCD_TO_BIN
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
-/* map phys->virtual and virtual->phys */
+/* map phys->virtual and virtual->phys for RAM pages */
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
-#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT)
+#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT)
#define MAP_PAGE_RESERVED (1<<15)
-extern __inline__ unsigned long get_prezerod_page(void);
+extern unsigned long get_prezerod_page(void);
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
--- /dev/null
+#ifndef _ASM_PCI_BRIDGE_H
+#define _ASM_PCI_BRIDGE_H
+
+unsigned long pmac_find_bridges(unsigned long, unsigned long);
+
+/*
+ * pci_io_base returns the memory address at which you can access
+ * the I/O space for PCI bus number `bus' (or NULL on error).
+ */
+void *pci_io_base(unsigned int bus);
+
+/*
+ * pci_device_loc returns the bus number and device/function number
+ * for a device on a PCI bus, given its device_node struct.
+ * It returns 0 if OK, -1 on error.
+ */
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+ unsigned char *devfn_ptr);
+
+#endif
#ifndef _PPC_PGTABLE_H
#define _PPC_PGTABLE_H
-#include <linux/config.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
+#include <linux/mm.h>
extern void flush_tlb_all(void);
extern void flush_tlb_mm(struct mm_struct *mm);
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end);
-extern void flush_tlb(void);
-/* Caches aren't brain-dead on the ppc. */
-#define flush_cache_all()
-#define flush_cache_mm(mm)
-#define flush_cache_range(mm, start, end)
-#define flush_cache_page(vma, vmaddr)
+/*
+ * No cache flushing is required when address mappings are
+ * changed, because the caches on PowerPCs are physically
+ * addressed.
+ */
+#define flush_cache_all() do { } while (0)
+#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_range(mm, a, b) do { } while (0)
+#define flush_cache_page(vma, p) do { } while (0)
+extern void flush_icache_range(unsigned long, unsigned long);
+
/*
* For the page specified, write modified lines in the data cache
* out to memory, and invalidate lines in the instruction cache.
extern unsigned long va_to_phys(unsigned long address);
+/*
+ * The PowerPC MMU uses a hash table containing PTEs, together with
+ * a set of 16 segment registers (on 32-bit implementations), to define
+ * the virtual to physical address mapping.
+ *
+ * We use the hash table as an extended TLB, i.e. a cache of currently
+ * active mappings. We maintain a two-level page table tree, much like
+ * that used by the i386, for the sake of the Linux memory management code.
+ * Low-level assembler code in head.S (procedure hash_page) is responsible
+ * for extracting ptes from the tree and putting them into the hash table
+ * when necessary, and updating the accessed and modified bits in the
+ * page table tree.
+ */
+
/* PMD_SHIFT determines the size of the area mapped by the second-level page tables */
#define PMD_SHIFT 22
#define PMD_SIZE (1UL << PMD_SHIFT)
/* to set the page-dir */
/* tsk is a task_struct and pgdir is a pte_t */
-#define SET_PAGE_DIR(tsk,pgdir) ({ \
- ((tsk)->tss.pg_tables = (unsigned long *)(pgdir)); \
-})
+#define SET_PAGE_DIR(tsk,pgdir)
extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
extern inline int pmd_present(pmd_t pmd) { return (pmd_val(pmd) & PAGE_MASK) != 0; }
extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; }
-
+
/*
* 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
* as entries are faulted into the hash table by the low-level
* data/instruction access exception handlers.
*/
-#define update_mmu_cache(vma,address,pte) while(0){}
+#define update_mmu_cache(vma, addr, pte) do { } while (0)
+/*
+ * When flushing the tlb entry for a page, we also need to flush the
+ * hash table entry. flush_hash_page is assembler (for speed) in head.S.
+ */
+extern void flush_hash_segments(unsigned low_vsid, unsigned high_vsid);
+extern void flush_hash_page(unsigned context, unsigned long va);
+
+extern inline void
+flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+ if (vmaddr < TASK_SIZE)
+ flush_hash_page(vma->vm_mm->context, vmaddr);
+}
#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
#define SWP_OFFSET(entry) ((entry) >> 8)
#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
+#define module_map vmalloc
+#define module_unmap vfree
-
-#endif /* _PPC_PAGE_H */
+#endif /* _PPC_PGTABLE_H */
-#ifndef __i386_POLL_H
-#define __i386_POLL_H
+#ifndef __PPC_POLL_H
+#define __PPC_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
#ifndef __ASM_PPC_PROCESSOR_H
#define __ASM_PPC_PROCESSOR_H
-#include <linux/config.h>
-
+#include <asm/ptrace.h>
/* Bit encodings for Machine State Register (MSR) */
#define MSR_POW (1<<18) /* Enable Power Management */
#define MSR_RI (1<<1) /* Recoverable Exception */
#define MSR_LE (1<<0) /* Little-Endian enable */
-#define MSR_ MSR_FE0|MSR_FE1|MSR_ME
+#define MSR_ MSR_ME|MSR_FE0|MSR_FE1|MSR_RI
#define MSR_KERNEL MSR_|MSR_IR|MSR_DR
-#define MSR_USER MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
+#define MSR_USER MSR_KERNEL|MSR_PR|MSR_EE
-/* Bit encodings for Hardware Implementation Register (HID0) */
+/* Bit encodings for Hardware Implementation Register (HID0)
+ on PowerPC 603, 604, etc. processors (not 601). */
#define HID0_EMCP (1<<31) /* Enable Machine Check pin */
#define HID0_EBA (1<<29) /* Enable Bus Address Parity */
#define HID0_EBD (1<<28) /* Enable Bus Data Parity */
#define HID0_DCI (1<<10) /* Data Cache Invalidate */
#define HID0_SIED (1<<7) /* Serial Instruction Execution [Disable] */
#define HID0_BHTE (1<<2) /* Branch History Table Enable */
+
/* fpscr settings */
#define FPSCR_FX (1<<31)
#define FPSCR_FEX (1<<30)
+
#ifndef __ASSEMBLY__
/*
* PowerPC machine specifics
*/
-extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long );
+struct task_struct;
+void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp);
+void release_thread(struct task_struct *);
/*
* Bus types
#define wp_works_ok 1
#define wp_works_ok__is_a_macro /* for versions in ksyms.c */
+/*
+ * User space process size: 2GB. This is hardcoded into a few places,
+ * so don't change it unless you know what you are doing.
+ */
#define TASK_SIZE (0x80000000UL)
+
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-struct thread_struct
-{
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 8 * 3)
+
+struct thread_struct {
unsigned long ksp; /* Kernel stack pointer */
- unsigned long *pg_tables; /* MMU information */
-#ifdef CONFIG_PMAC
- unsigned long last_pc; /* PC when last entered system */
- unsigned long user_stack; /* [User] Stack when entered kernel */
-#endif
- unsigned long fpscr_pad; /* (so we can save fpscr with stfd) */
- unsigned long fpscr; /* fp status reg */
- double fpr[32]; /* Complete floating point set */
- unsigned long fp_used;
unsigned long wchan; /* Event task is sleeping on */
- struct pt_regs *regs; /* Pointer to saved register state */
+ struct pt_regs *regs; /* Pointer to saved register state */
unsigned long fs; /* for get_fs() validation */
signed long last_syscall;
- unsigned long pad[2]; /* pad to 16-byte boundry */
+ double fpr[32]; /* Complete floating point set */
+ unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */
+ unsigned long fpscr; /* Floating point status */
};
-/* Points to the thread_struct of the thread (if any) which
- currently owns the FPU. */
-#define fpu_tss (&(last_task_used_math->tss))
-
-#ifdef CONFIG_PMAC
-#define LAZY_TSS_FPR_INIT 0,0,0,0,{0},
-#endif
-#ifdef CONFIG_PREP
-#define LAZY_TSS_FPR_INIT 0,0,{0},
-#endif
+#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack)
#define INIT_TSS { \
- sizeof(init_stack) + (long) &init_stack, /* ksp */ \
- (long *)swapper_pg_dir, /* pg_tables */ \
- LAZY_TSS_FPR_INIT \
- 0, /*fp_used*/ 0, /*wchan*/ \
- sizeof(init_stack) + (long)&init_stack - \
- sizeof(struct pt_regs), /* regs */ \
- KERNEL_DS /*fs*/, 0 /*last_syscall*/ \
+ INIT_SP, /* ksp */ \
+ 0, /* wchan */ \
+ (struct pt_regs *)INIT_SP - 1, /* regs */ \
+ KERNEL_DS, /*fs*/ \
+ 0, /* last_syscall */ \
+ {0}, 0, 0 \
}
#define INIT_MMAP { &init_mm, KERNELBASE/*0*/, 0xffffffff/*0x40000000*/, \
static inline unsigned long thread_saved_pc(struct thread_struct *t)
{
return (t->regs) ? t->regs->nip : 0;
- /*return (t->last_pc);*/
}
-extern int _machine;
-#define _MACH_Motorola 0
-#define _MACH_IBM 1
-#define _MACH_Be 2
-#define _MACH_Pmac 3
-
/*
* NOTE! The task struct and the stack go together
*/
int ll_printk(const char *, ...);
void ll_puts(const char *);
+extern int _machine;
#endif /* ndef ASSEMBLY*/
+#define _MACH_Motorola 1 /* motorola prep */
+#define _MACH_IBM 2 /* ibm prep */
+#define _MACH_Pmac 4 /* pmac or pmac clone */
+#define _MACH_chrp 8 /* chrp machine */
+
+#define is_prep ((_machine == _MACH_Motorola)||(_machine == _MACH_IBM))
+
#define init_task (init_task_union.task)
#define init_stack (init_task_union.stack)
--- /dev/null
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+typedef void *phandle;
+typedef void *ihandle;
+
+extern ihandle prom_stdout;
+extern ihandle prom_chosen;
+extern phandle cpu_node;
+extern char prom_display_path[];
+
+struct reg_property {
+ unsigned int address;
+ unsigned int size;
+};
+
+struct translation_property {
+ unsigned int virt;
+ unsigned int size;
+ unsigned int phys;
+ unsigned int flags;
+};
+
+struct property {
+ char *name;
+ int length;
+ unsigned char *value;
+ struct property *next;
+};
+
+struct device_node {
+ char *name;
+ char *type;
+ phandle node;
+ int n_addrs;
+ struct reg_property *addrs;
+ int n_intrs;
+ int *intrs;
+ char *full_name;
+ struct property *properties;
+ struct device_node *parent;
+ struct device_node *child;
+ struct device_node *sibling;
+ struct device_node *next; /* next device of same type */
+ struct device_node *allnext; /* next in list of all nodes */
+};
+
+/* Prototypes */
+void abort(void);
+void prom_exit(void);
+void *call_prom(const char *service, int nargs, int nret, ...);
+void prom_print(const char *msg);
+void prom_init(char *params, int unused, void (*)(void *));
+void set_prom_callback(void);
+unsigned long copy_device_tree(unsigned long, unsigned long);
+struct device_node *find_devices(const char *name);
+struct device_node *find_type_devices(const char *type);
+struct device_node *find_path_device(const char *path);
+unsigned char *get_property(struct device_node *node, const char *name,
+ int *lenp);
+void print_properties(struct device_node *node);
#define _PPC_PTRACE_H
/*
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ *
* this should only contain volatile regs
* since we can keep non-volatile in the tss
* should set this up when only volatiles are saved
* by intr code.
*
- * I can't find any reference to the above comment (from Gary Thomas)
- * about _underhead/_overhead in the sys V abi for the ppc
- * dated july 25, 1994.
+ * Since this is going on the stack, *CARE MUST BE TAKEN* to insure
+ * that the overall structure is a multiple of 16 bytes in length.
*
- * the stack must be kept to a size that is a multiple of 16
- * so this includes the stack frame overhead
- * -- Cort.
- */
-
-/*
- * GCC sometimes accesses words at negative offsets from the stack
- * pointer, although the SysV ABI says it shouldn't. To cope with
- * this, we leave this much untouched space on the stack on exception
- * entry.
+ * Note that the offsets of the fields in this struct correspond with
+ * the PT_* values below. This simplifies arch/ppc/kernel/ptrace.c.
*/
-#define STACK_FRAME_OVERHEAD 16
-#define STACK_UNDERHEAD 64
#ifndef __ASSEMBLY__
struct pt_regs {
unsigned long gpr[32];
- unsigned long nip;
- unsigned long msr;
- unsigned long ctr;
- unsigned long link;
- unsigned long ccr;
- unsigned long xer;
- unsigned long dar; /* Fault registers */
- unsigned long dsisr;
-#if 0
- unsigned long srr1;
- unsigned long srr0;
- unsigned long hash1, hash2;
- unsigned long imiss, dmiss;
- unsigned long icmp, dcmp;
-#endif
+ unsigned long nip;
+ unsigned long msr;
unsigned long orig_gpr3; /* Used for restarting system calls */
- unsigned long result; /* Result of a system call */
+ unsigned long ctr;
+ unsigned long link;
+ unsigned long xer;
+ unsigned long ccr;
+ unsigned long mq; /* 601 only (not used at present) */
unsigned long trap; /* Reason for being here */
- unsigned long marker; /* Should have DEADDEAD */
+ unsigned long dar; /* Fault registers */
+ unsigned long dsisr;
+ unsigned long result; /* Result of a system call */
};
+#endif
+
+#define STACK_FRAME_OVERHEAD 16 /* size of minimum stack frame */
+/* Size of stack frame allocated when calling signal handler. */
+#define __SIGNAL_FRAMESIZE 64
#define instruction_pointer(regs) ((regs)->nip)
#define user_mode(regs) ((regs)->msr & 0x4000)
-#ifdef KERNEL
-extern void show_regs(struct pt_regs *);
-#endif
-/* should include and generate these in ppc_defs.h -- Cort */
-/* Offsets used by 'ptrace' system call interface */
-/* Note: these should correspond to gpr[x] */
+/*
+ * Offsets used by 'ptrace' system call interface.
+ * These can't be changed without breaking binary compatibility
+ * with MkLinux, etc.
+ */
#define PT_R0 0
#define PT_R1 1
#define PT_R2 2
#define PT_NIP 32
#define PT_MSR 33
+#ifdef __KERNEL__
#define PT_ORIG_R3 34
+#endif
#define PT_CTR 35
#define PT_LNK 36
#define PT_XER 37
#define PT_CCR 38
+#define PT_MQ 39
-#define PT_FPR0 48
-#endif /* __ASSEMBLY__ */
+#define PT_FPR0 48 /* each FP reg occupies 2 slots in this space */
+#define PT_FPR31 (PT_FPR0 + 2*31)
+#define PT_FPSCR (PT_FPR0 + 2*32 + 1)
-#endif /* _PPC_PTRACE_H */
+#endif
unsigned char DevicePnPHeap[2*MAX_DEVICES*AVE_PNP_SIZE];
} RESIDUAL;
+
+extern RESIDUAL res;
#endif /* ndef _RESIDUAL_ */
#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_NOFILE 6 /* max number of open files */
-#define RLIMIT_AS 7 /* address space limit(?) */
-#define RLIMIT_NPROC 8 /* max number of processes */
-#define RLIMIT_MEMLOCK 9 /* max locked-in-memory address space */
+#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 RLIM_NLIMITS 10
{_STK_LIM, _STK_LIM}, /* RLIMIT_STACK */ \
{ 0, LONG_MAX}, /* RLIMIT_CORE */ \
{LONG_MAX, LONG_MAX}, /* RLIMIT_RSS */ \
- { NR_OPEN, NR_OPEN}, /* RLIMIT_NOFILE */ \
- {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \
{MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, /* RLIMIT_NPROC */ \
+ { NR_OPEN, NR_OPEN}, /* RLIMIT_NOFILE */ \
{LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \
+ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \
}
#endif /* __KERNEL__ */
#ifndef _PPC_SCATTERLIST_H
#define _PPC_SCATTERLIST_H
+#include <linux/config.h>
+
struct scatterlist {
char * address; /* Location data is to be transferred to */
char * alt_address; /* Location of actual if address is a
unsigned int length;
};
+#ifdef CONFIG_PMAC
+/*
+ * This is used in the scsi code to decide if bounce buffers are needed.
+ * Fortunately the dma controllers on the PowerMac are a bit better
+ * than on PCs...
+ */
+#define ISA_DMA_THRESHOLD (~0UL)
+#endif
+
+#ifdef CONFIG_PREP
+/* PReP systems are like PCs */
#define ISA_DMA_THRESHOLD (0x00ffffff)
+#endif
#endif /* !(_PPC_SCATTERLIST_H) */
__asm__ __volatile__(
"1: lwarx %1,0,%2\n"
" cmpwi 0,%1,0\n"
- " addi %1,%1,-1\n"
+ " addic %1,%1,-1\n"
" ble- 2f\n"
" stwcx. %1,0,%2\n"
" bne- 1b\n"
- " mr %0,%1\n"
+ " li %0,1\n"
"2:"
- : "=r" (ret), "=r" (tmp)
+ : "=r" (ret), "=&r" (tmp)
: "r" (&sem->waking), "0" (0)
: "cr0", "memory");
#define SO_PASSCRED 20
#define SO_PEERCRED 21
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION 22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
+#define SO_SECURITY_ENCRYPTION_NETWORK 24
+
#endif /* _ASM_SOCKET_H */
#define __HAVE_ARCH_MEMMOVE
#define __HAVE_ARCH_MEMCMP
#define __HAVE_ARCH_MEMCHR
-/*#define bzero(addr,size) memset((addr),(int)(0),(size))*/
-extern inline void * memchr(const void * cs,int c,size_t count)
-{
- unsigned long i = 0;
- while ( count != i )
- {
- if ( (char)c == *(char *)(cs + i) )
- return (void *)(cs + i);
- i--;
- }
- return NULL;
-}
+
+extern int strcasecmp(const char *, const char *);
+
#endif
#ifndef __PPC_SYSTEM_H
#define __PPC_SYSTEM_H
-#include <linux/delay.h>
+#include <linux/kdev_t.h>
+#include <asm/processor.h>
#define mb() __asm__ __volatile__ ("sync" : : : "memory")
#define __save_flags(flags) ({\
__asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
-/* using Paul's in misc.S now -- Cort */
-extern void __restore_flags(unsigned long flags);
+extern __inline__ void __restore_flags(unsigned long flags)
+{
+ extern unsigned lost_interrupts;
+ extern void do_lost_interrupts(unsigned long);
+
+ if ((flags & MSR_EE) && lost_interrupts != 0) {
+ do_lost_interrupts(flags);
+ } else {
+ __asm__ __volatile__ ("sync; mtmsr %0; isync"
+ : : "r" (flags) : "memory");
+ }
+}
+
+#if 0
/*
- #define __sti() _soft_sti(void)
- #define __cli() _soft_cli(void)
+ * Gcc bug prevents us from using this inline func so for now
+ * it lives in misc.S
*/
+void __inline__ __restore_flags(unsigned long flags)
+{
+ extern unsigned lost_interrupts;
+ __asm__ __volatile__ (
+ "andi. 0,%0,%2 \n\t"
+ "beq 2f \n\t"
+ "cmpi 0,%1,0 \n\t"
+ "bne do_lost_interrupts \n\t"
+ "2: sync \n\t"
+ "mtmsr %0 \n\t"
+ "isync \n\t"
+ :
+ : "r" (flags), "r"(lost_interrupts), "i" (1<<15)/*MSR_EE*/
+ : "0", "cc");
+}
+#endif
+
extern void __sti(void);
extern void __cli(void);
-
-extern void _hard_sti(void);
-extern void _hard_cli(void);
-extern void _soft_sti(void);
-extern void _soft_cli(void);
extern int _disable_interrupts(void);
extern void _enable_interrupts(int);
+extern void print_backtrace(unsigned long *);
+extern void show_regs(struct pt_regs * regs);
extern void flush_instruction_cache(void);
extern void hard_reset_now(void);
extern void poweroff_now(void);
-extern void find_scsi_boot(void);
+/*extern void note_bootable_part(kdev_t, int);*/
extern int sd_find_target(void *, int);
extern int _get_PVR(void);
extern void via_cuda_init(void);
+extern void pmac_nvram_init(void);
extern void read_rtc_time(void);
extern void pmac_find_display(void);
extern void giveup_fpu(void);
-extern void store_cache_range(unsigned long, unsigned long);
extern void cvt_fd(float *from, double *to);
extern void cvt_df(double *from, float *to);
#define B57600 00020
#define B115200 00021
#define B230400 00022
+#define B460800 00023
#define CSIZE 00001400
#define CS5 00000000
-/* $Id: pgtable.h,v 1.62 1997/06/27 14:55:00 jj Exp $ */
+/* $Id: pgtable.h,v 1.63 1997/08/13 04:44:15 paulus Exp $ */
#ifndef _SPARC_PGTABLE_H
#define _SPARC_PGTABLE_H
extern void (*flush_cache_range)(struct mm_struct *, unsigned long start,
unsigned long end);
extern void (*flush_cache_page)(struct vm_area_struct *, unsigned long address);
+#define flush_icache_range(start, end) do { } while (0)
extern void (*flush_tlb_all)(void);
extern void (*flush_tlb_mm)(struct mm_struct *);
-/* $Id: atomic.h,v 1.15 1997/07/03 09:18:09 davem Exp $
+/* $Id: atomic.h,v 1.18 1997/08/07 03:38:31 davem Exp $
* atomic.h: Thankfully the V9 is at least reasonable for this
* stuff.
*
extern __inline__ void atomic_add(int i, atomic_t *v)
{
__asm__ __volatile__("
-1: lduw [%1], %%g1
- add %%g1, %0, %%g2
- cas [%1], %%g1, %%g2
- sub %%g1, %%g2, %%g1
- brnz,pn %%g1, 1b
+1: lduw [%1], %%g5
+ add %%g5, %0, %%g7
+ cas [%1], %%g5, %%g7
+ sub %%g5, %%g7, %%g5
+ brnz,pn %%g5, 1b
nop"
: /* No outputs */
: "HIr" (i), "r" (__atomic_fool_gcc(v))
- : "g1", "g2");
+ : "g5", "g7", "memory");
}
extern __inline__ void atomic_sub(int i, atomic_t *v)
{
__asm__ __volatile__("
-1: lduw [%1], %%g1
- sub %%g1, %0, %%g2
- cas [%1], %%g1, %%g2
- sub %%g1, %%g2, %%g1
- brnz,pn %%g1, 1b
+1: lduw [%1], %%g5
+ sub %%g5, %0, %%g7
+ cas [%1], %%g5, %%g7
+ sub %%g5, %%g7, %%g5
+ brnz,pn %%g5, 1b
nop"
: /* No outputs */
: "HIr" (i), "r" (__atomic_fool_gcc(v))
- : "g1", "g2");
+ : "g5", "g7", "memory");
}
/* Same as above, but return the result value. */
{
unsigned long oldval;
__asm__ __volatile__("
-1: lduw [%2], %%g1
- add %%g1, %1, %%g2
- cas [%2], %%g1, %%g2
- sub %%g1, %%g2, %%g1
- brnz,pn %%g1, 1b
- add %%g2, %1, %0"
+1: lduw [%2], %%g5
+ add %%g5, %1, %%g7
+ cas [%2], %%g5, %%g7
+ sub %%g5, %%g7, %%g5
+ brnz,pn %%g5, 1b
+ add %%g7, %1, %0"
: "=&r" (oldval)
: "HIr" (i), "r" (__atomic_fool_gcc(v))
- : "g1", "g2");
+ : "g5", "g7", "memory");
return (int)oldval;
}
{
unsigned long oldval;
__asm__ __volatile__("
-1: lduw [%2], %%g1
- sub %%g1, %1, %%g2
- cas [%2], %%g1, %%g2
- sub %%g1, %%g2, %%g1
- brnz,pn %%g1, 1b
- sub %%g2, %1, %0"
+1: lduw [%2], %%g5
+ sub %%g5, %1, %%g7
+ cas [%2], %%g5, %%g7
+ sub %%g5, %%g7, %%g5
+ brnz,pn %%g5, 1b
+ sub %%g7, %1, %0"
: "=&r" (oldval)
: "HIr" (i), "r" (__atomic_fool_gcc(v))
- : "g1", "g2");
+ : "g5", "g7", "memory");
return (int)oldval;
}
-/* $Id: bitops.h,v 1.19 1997/07/08 10:17:37 davem Exp $
+/* $Id: bitops.h,v 1.22 1997/08/07 02:54:04 davem Exp $
* bitops.h: Bit string operations on the V9.
*
- * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
*/
#ifndef _SPARC64_BITOPS_H
extern __inline__ unsigned long test_and_set_bit(unsigned long nr, void *addr)
{
- unsigned long oldbit;
- unsigned long temp0, temp1;
unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+ unsigned long oldbit;
__asm__ __volatile__("
- ldx [%4], %0
-1:
- andcc %0, %3, %2
+1: ldx [%2], %%g7
+ andcc %%g7, %1, %0
bne,pn %%xcc, 2f
- xor %0, %3, %1
- casx [%4], %0, %1
- cmp %0, %1
- bne,a,pn %%xcc, 1b
- ldx [%4], %0
+ xor %%g7, %1, %%g5
+ casx [%2], %%g7, %%g5
+ cmp %%g7, %%g5
+ bne,pn %%xcc, 1b
+ nop
2:
-" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+" : "=&r" (oldbit)
: "HIr" (1UL << (nr & 63)), "r" (m)
- : "cc");
+ : "g5", "g7", "cc", "memory");
return oldbit != 0;
}
extern __inline__ void set_bit(unsigned long nr, void *addr)
{
- (void) test_and_set_bit(nr, addr);
+ unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+ __asm__ __volatile__("
+1: ldx [%1], %%g7
+ andcc %%g7, %0, %%g0
+ bne,pn %%xcc, 2f
+ xor %%g7, %0, %%g5
+ casx [%1], %%g7, %%g5
+ cmp %%g7, %%g5
+ bne,pn %%xcc, 1b
+ nop
+2:
+" : /* no outputs */
+ : "HIr" (1UL << (nr & 63)), "r" (m)
+ : "g5", "g7", "cc", "memory");
}
extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, void *addr)
{
- unsigned long oldbit;
- unsigned long temp0, temp1;
unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+ unsigned long oldbit;
__asm__ __volatile__("
- ldx [%4], %0
-1:
- andcc %0, %3, %2
+1: ldx [%2], %%g7
+ andcc %%g7, %1, %0
be,pn %%xcc, 2f
- xor %0, %3, %1
- casx [%4], %0, %1
- cmp %0, %1
- bne,a,pn %%xcc, 1b
- ldx [%4], %0
+ xor %%g7, %1, %%g5
+ casx [%2], %%g7, %%g5
+ cmp %%g7, %%g5
+ bne,pn %%xcc, 1b
+ nop
2:
-" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+" : "=&r" (oldbit)
: "HIr" (1UL << (nr & 63)), "r" (m)
- : "cc");
+ : "g5", "g7", "cc", "memory");
return oldbit != 0;
}
extern __inline__ void clear_bit(unsigned long nr, void *addr)
{
- (void) test_and_clear_bit(nr, addr);
+ unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+ __asm__ __volatile__("
+1: ldx [%1], %%g7
+ andcc %%g7, %0, %%g0
+ be,pn %%xcc, 2f
+ xor %%g7, %0, %%g5
+ casx [%1], %%g7, %%g5
+ cmp %%g7, %%g5
+ bne,pn %%xcc, 1b
+ nop
+2:
+" : /* no outputs */
+ : "HIr" (1UL << (nr & 63)), "r" (m)
+ : "g5", "g7", "cc", "memory");
}
extern __inline__ unsigned long test_and_change_bit(unsigned long nr, void *addr)
{
- unsigned long oldbit;
- unsigned long temp0, temp1;
unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+ unsigned long oldbit;
__asm__ __volatile__("
- ldx [%4], %0
-1:
- and %0, %3, %2
- xor %0, %3, %1
- casx [%4], %0, %1
- cmp %0, %1
- bne,a,pn %%xcc, 1b
- ldx [%4], %0
-" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+1: ldx [%2], %%g7
+ and %%g7, %1, %0
+ xor %%g7, %1, %%g5
+ casx [%2], %%g7, %%g5
+ cmp %%g7, %%g5
+ bne,pn %%xcc, 1b
+ nop
+" : "=&r" (oldbit)
: "HIr" (1UL << (nr & 63)), "r" (m)
- : "cc");
+ : "g5", "g7", "cc", "memory");
return oldbit != 0;
}
extern __inline__ void change_bit(unsigned long nr, void *addr)
{
- (void) test_and_change_bit(nr, addr);
+ unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+ __asm__ __volatile__("
+1: ldx [%1], %%g7
+ xor %%g7, %0, %%g5
+ casx [%1], %%g7, %%g5
+ cmp %%g7, %%g5
+ bne,pn %%xcc, 1b
+ nop
+" : /* no outputs */
+ : "HIr" (1UL << (nr & 63)), "r" (m)
+ : "g5", "g7", "cc", "memory");
}
extern __inline__ unsigned long test_bit(int nr, __const__ void *addr)
*/
extern __inline__ int set_le_bit(int nr,void * addr)
{
- unsigned long oldbit;
- unsigned long temp0, temp1;
unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+ unsigned long oldbit;
__asm__ __volatile__("
- lduwa [%4] %5, %0
-1:
- andcc %0, %3, %2
+1: lduwa [%2] %3, %%g7
+ andcc %%g7, %1, %0
bne,pn %%icc, 2f
- xor %0, %3, %1
- casa [%4] %5, %0, %1
- cmp %0, %1
- bne,a,pn %%icc, 1b
- lduwa [%4] %5, %0
+ xor %%g7, %1, %%g5
+ casa [%2] %3, %%g7, %%g5
+ cmp %%g7, %%g5
+ bne,pn %%icc, 1b
+ nop
2:
-" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+" : "=&r" (oldbit)
: "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
- : "cc");
+ : "g5", "g7", "cc", "memory");
return oldbit != 0;
}
extern __inline__ int clear_le_bit(int nr, void * addr)
{
- unsigned long oldbit;
- unsigned long temp0, temp1;
unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+ unsigned long oldbit;
__asm__ __volatile__("
- lduwa [%4] %5, %0
-1:
- andcc %0, %3, %2
+1: lduwa [%2] %3, %%g7
+ andcc %%g7, %1, %0
be,pn %%icc, 2f
- xor %0, %3, %1
- casa [%4] %5, %0, %1
- cmp %0, %1
- bne,a,pn %%icc, 1b
- lduwa [%4] %5, %0
+ xor %%g7, %1, %%g5
+ casa [%2] %3, %%g7, %%g5
+ cmp %%g7, %%g5
+ bne,pn %%icc, 1b
+ nop
2:
-" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+" : "=&r" (oldbit)
: "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
- : "cc");
+ : "g5", "g7", "cc", "memory");
return oldbit != 0;
}
-/* $Id: checksum.h,v 1.9 1997/06/26 04:05:17 davem Exp $ */
+/* $Id: checksum.h,v 1.10 1997/08/09 18:09:03 jj Exp $ */
#ifndef __SPARC64_CHECKSUM_H
#define __SPARC64_CHECKSUM_H
csum_partial_copy_nocheck(src,dst,len,sum)
#define csum_partial_copy_fromuser(s, d, l, w) \
csum_partial_copy_from_user((char *) (s), (d), (l), (w), NULL)
+
+extern unsigned int csum_partial_copy_sparc64(const char *src, char *dst, int len, unsigned int sum);
extern __inline__ unsigned int
csum_partial_copy_nocheck (const char *src, char *dst, int len,
unsigned int sum)
{
- register unsigned long ret asm("o0") = (unsigned long)src;
- register char *d asm("o1") = dst;
- register unsigned long l asm("g1") = len;
-
- __asm__ __volatile__ ("
- wr %%g0, %5, %%asi
- call __csum_partial_copy_sparc_generic
- mov %4, %%g7
- srl %%o0, 0, %%o0
- " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum), "i" (ASI_P) :
- "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
- return (unsigned int)ret;
+ __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "i" (ASI_P));
+ return csum_partial_copy_sparc64(src, dst, len, sum);
}
extern __inline__ unsigned int
csum_partial_copy_from_user(const char *src, char *dst, int len,
unsigned int sum, int *err)
{
- register unsigned long ret asm("o0") = (unsigned long)src;
- register char *d asm("o1") = dst;
- register unsigned long l asm("g1") = len;
- register unsigned long s asm("g7") = sum;
-
- __asm__ __volatile__ ("
- .section __ex_table,#alloc
- .align 8
- .xword 1f,2
- .previous
- wr %%g0, %6, %%asi
-1:
- call __csum_partial_copy_sparc_generic
- stx %5, [%%sp + 0x7ff + 128]
- srl %%o0, 0, %%o0
- " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err), "i" (ASI_S) :
- "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
- return (unsigned int)ret;
+ __asm__ __volatile__ ("wr %%g0, %0, %%asi
+ stx %1, [%%sp + 0x7ff + 128]
+ " : : "i" (ASI_S), "r" (err));
+ return csum_partial_copy_sparc64(src, dst, len, sum);
}
#if 0
-/* $Id: delay.h,v 1.5 1997/06/18 12:36:23 jj Exp $
+/* $Id: delay.h,v 1.6 1997/07/29 21:11:22 davem Exp $
* delay.h: Linux delay routines on the V9.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu).
#ifndef __SPARC64_DELAY_H
#define __SPARC64_DELAY_H
-extern unsigned long loops_per_sec;
+#ifdef __SMP__
+#include <asm/smp.h>
+#endif
extern __inline__ void __delay(unsigned long loops)
{
: "cc");
}
-extern __inline__ void udelay(unsigned long usecs)
+extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
{
usecs *= 0x00000000000010c6UL; /* 2**32 / 1000000 */
mulx %1, %2, %0
srlx %0, 32, %0
" : "=r" (usecs)
- : "r" (usecs), "r" (loops_per_sec));
+ : "r" (usecs), "r" (lps));
__delay(usecs);
}
+#ifdef __SMP__
+#define __udelay_val cpu_data[smp_processor_id()].udelay_val
+#else
+#define __udelay_val loops_per_sec
+#endif
+
+#define udelay(usecs) __udelay((usecs),__udelay_val)
+
extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
{
return (a*b)/c;
--- /dev/null
+/* $Id: ebus.h,v 1.1 1997/08/12 04:13:12 ecd Exp $
+ * ebus.h: PCI to Ebus pseudo driver software state.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#ifndef __SPARC64_EBUS_H
+#define __SPARC64_EBUS_H
+
+#include <asm/oplib.h>
+
+struct linux_ebus_device {
+ struct linux_ebus_device *next;
+ struct linux_ebus *parent;
+ int prom_node;
+ char prom_name[64];
+ struct linux_prom_registers regs[PROMREG_MAX];
+ int num_registers;
+ struct linux_prom_irqs irqs[PROMINTR_MAX];
+ int num_irqs;
+};
+
+struct linux_ebus {
+ struct linux_ebus *next;
+ struct linux_ebus_device *devices;
+ struct linux_pbm_info *parent;
+ int prom_node;
+ char prom_name[64];
+ struct linux_prom_ranges ebus_ranges[PROMREG_MAX];
+ int num_ebus_ranges;
+};
+
+extern struct linux_ebus *ebus_chain;
+
+extern unsigned long ebus_init(unsigned long, unsigned long);
+extern void prom_apply_ebus_ranges(struct linux_ebus *ebus,
+ struct linux_prom_registers *regs,
+ int nregs);
+
+#define for_each_ebus(bus) \
+ for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
+
+#define for_each_ebusdev(dev, bus) \
+ for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
+
+#define for_all_ebusdev(dev, bus) \
+ for ((bus) = ebus_chain, ((dev) = (bus) ? (bus)->devices : 0); \
+ (bus); ((dev) = (dev)->next ? (dev)->next : \
+ ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+
+#endif /* !(__SPARC64_EBUS_H) */
--- /dev/null
+/* $Id: fhc.h,v 1.1 1997/08/08 04:26:40 davem Exp $
+ * fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_FHC_H
+#define _SPARC64_FHC_H
+
+#include <asm/firehose.h>
+#include <asm/oplib.h>
+
+struct linux_fhc;
+
+struct linux_central {
+ struct linux_fhc *child;
+ int prom_node;
+ char prom_name[64];
+
+ struct linux_prom_ranges central_ranges[PROMREG_MAX];
+ int num_central_ranges;
+};
+
+struct linux_fhc {
+ struct linux_fhc *next;
+ struct linux_central *parent; /* NULL if not central FHC */
+ struct fhc_regs fhc_regs;
+ int prom_node;
+ char prom_name[64];
+
+ struct linux_prom_ranges fhc_ranges[PROMREG_MAX];
+ int num_fhc_ranges;
+};
+
+extern struct linux_central *central_bus;
+
+extern void prom_apply_central_ranges(struct linux_central *central,
+ struct linux_prom_registers *regs,
+ int nregs);
+
+extern void prom_apply_fhc_ranges(struct linux_fhc *fhc,
+ struct linux_prom_registers *regs,
+ int nregs);
+
+#endif /* !(_SPARC64_FHC_H) */
-/* $Id: firehose.h,v 1.1 1997/04/11 02:38:47 davem Exp $
+/* $Id: firehose.h,v 1.2 1997/08/08 04:26:31 davem Exp $
* firehose.h: Defines for the Fire Hose Controller (FHC) found
- * on Sunfire/Wildfire systems.
+ * on Sunfire/Starfire/Wildfire systems.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
* for the FHC, thus we have the following few structs...
*/
struct fhc_ign_reg {
-/*0x2000*/ u64 fhc_ign; /* FHC Interrupt Group Number */
+/*0x2000*/ u64 fhc_ign; /* FHC Interrupt Group Number */
};
struct fhc_fanfail_regs {
-/*0x4000*/ u64 fhc_ff_imap; /* FHC FanFail Interrupt Map */
- u64 _unused1;
-/*0x4010*/ u64 fhc_ff_istate; /* FHC FanFail Interrupt State */
+/*0x4000*/ u32 _pad0, fhc_ff_imap; /* FHC FanFail Interrupt Map */
+ u64 _pad1;
+/*0x4010*/ u32 _pad2, fhc_ff_iclr; /* FHC FanFail Interrupt Clear */
};
struct fhc_system_regs {
-/*0x6000*/ u64 fhc_sys_imap; /* FHC System Interrupt Map */
- u64 _unused1;
-/*0x6010*/ u64 fhc_sys_istate; /* FHC System Interrupt State */
+/*0x6000*/ u32 _pad0, fhc_sys_imap; /* FHC System Interrupt Map */
+ u64 _pad1;
+/*0x6010*/ u32 _pad2, fhc_sys_iclr; /* FHC System Interrupt Clear */
};
struct fhc_uart_regs {
-/*0x8000*/ u64 fhc_uart_imap; /* FHC UART Interrupt Map */
- u64 _unused1;
-/*0x8010*/ u64 fhc_uart_istate;/* FHC UART Interrupt State */
+/*0x8000*/ u32 _pad0, fhc_uart_imap; /* FHC UART Interrupt Map */
+ u64 _pad1;
+/*0x8010*/ u32 _pad2, fhc_uart_iclr; /* FHC UART Interrupt Clear */
};
struct fhc_tod_regs {
-/*0xa000*/ u64 fhc_tod_imap; /* FHC TOD Interrupt Map */
- u64 _unused1;
-/*0xa010*/ u64 fhc_tod_istate; /* FHC TOD Interrupt State */
+/*0xa000*/ u32 _pad0, fhc_tod_imap; /* FHC TOD Interrupt Map */
+ u64 _pad1;
+/*0xa010*/ u32 _pad2, fhc_tod_iclr; /* FHC TOD Interrupt Clear */
};
/* All of the above. */
struct fhc_regs {
struct fhc_internal_regs *pregs;
struct fhc_ign_reg *ireg;
- struct fhc_fanfil_regs *ffregs;
+ struct fhc_fanfail_regs *ffregs;
struct fhc_system_regs *sregs;
struct fhc_uart_regs *uregs;
struct fhc_tod_regs *tregs;
#include <linux/tasks.h>
-extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
+#ifndef __SMP__
+extern unsigned int local_irq_count;
+#else
+#define local_irq_count (cpu_data[smp_processor_id()].irq_count)
+#endif
+#define in_interrupt() (local_irq_count != 0)
#ifndef __SMP__
-#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu) (local_irq_count == 0)
#define hardirq_endlock(cpu) do { } while(0)
-#define hardirq_enter(cpu) (local_irq_count[cpu]++)
-#define hardirq_exit(cpu) (local_irq_count[cpu]--)
+#define hardirq_enter(cpu) (local_irq_count++)
+#define hardirq_exit(cpu) (local_irq_count--)
#define synchronize_irq() do { } while(0)
static inline void hardirq_enter(int cpu)
{
- ++local_irq_count[cpu];
+ ++cpu_data[cpu].irq_count;
atomic_inc(&global_irq_count);
+ membar("#StoreLoad | #StoreStore");
}
static inline void hardirq_exit(int cpu)
{
+ membar("#StoreStore | #LoadStore");
atomic_dec(&global_irq_count);
- --local_irq_count[cpu];
+ --cpu_data[cpu].irq_count;
}
static inline int hardirq_trylock(int cpu)
unsigned long flags;
__save_and_cli(flags);
- if(atomic_add_return(1, &global_irq_count) != 1 ||
- *(((unsigned char *)(&global_irq_lock)))) {
+ atomic_inc(&global_irq_count);
+ if(atomic_read(&global_irq_count) != 1 ||
+ (*(((unsigned char *)(&global_irq_lock)))) != 0) {
atomic_dec(&global_irq_count);
__restore_flags(flags);
return 0;
}
- ++local_irq_count[cpu];
+ ++cpu_data[cpu].irq_count;
return 1;
}
-/* $Id: head.h,v 1.27 1997/07/13 17:30:43 davem Exp $ */
+/* $Id: head.h,v 1.30 1997/08/08 08:34:33 jj Exp $ */
#ifndef _SPARC64_HEAD_H
#define _SPARC64_HEAD_H
#include <asm/pstate.h>
#define KERNBASE 0x400000
-#define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
-
-/* We need a "cleaned" instruction... */
-#define CLEAN_WINDOW \
- rdpr %cleanwin, %l0; add %l0, 1, %l0; \
- wrpr %l0, 0x0, %cleanwin; \
- clr %o0; clr %o1; clr %o2; clr %o3; \
- clr %o4; clr %o5; clr %o6; clr %o7; \
- clr %l0; clr %l1; clr %l2; clr %l3; \
- clr %l4; clr %l5; clr %l6; clr %l7; \
- retry; \
- nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
-
-#define TRAP(routine) \
- ba,pt %xcc, etrap; \
- rd %pc, %g7; \
- call routine; \
- add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
- ba,pt %xcc, rtrap; \
- clr %l6; \
- nop; \
- nop;
-
-#define TRAP_NOSAVE(routine) \
- ba,pt %xcc, routine; \
- nop; \
- nop; nop; nop; nop; nop; nop;
-
-#define TRAPTL1(routine) \
- ba,pt %xcc, etraptl1; \
- rd %pc, %g7; \
- call routine; \
- add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
- ba,pt %xcc, rtrap; \
- clr %l6; \
- nop; \
- nop;
-
-#define TRAP_ARG(routine, arg) \
- ba,pt %xcc, etrap; \
- rd %pc, %g7; \
- add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
- call routine; \
- mov arg, %o1; \
- ba,pt %xcc, rtrap; \
- clr %l6; \
- nop;
-
-#define TRAPTL1_ARG(routine, arg) \
- ba,pt %xcc, etraptl1; \
- rd %pc, %g7; \
- add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
- call routine; \
- mov arg, %o1; \
- ba,pt %xcc, rtrap; \
- clr %l6; \
- nop;
-
-#define SYSCALL_TRAP(routine, systbl) \
- ba,pt %xcc, etrap; \
- rd %pc, %g7; \
- sethi %hi(systbl), %l7; \
- call routine; \
- or %l7, %lo(systbl), %l7; \
- nop; nop; nop;
-
-#define ACCESS_EXCEPTION_TRAP(routine) \
- rdpr %pstate, %g1; \
- wrpr %g1, PSTATE_MG|PSTATE_AG, %pstate; \
- ba,pt %xcc, etrap; \
- rd %pc, %g7; \
- call routine; \
- add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
- ba,pt %xcc, rtrap; \
- clr %l6;
-
-#define ACCESS_EXCEPTION_TRAPTL1(routine) \
- rdpr %pstate, %g1; \
- wrpr %g1, PSTATE_MG|PSTATE_AG, %pstate; \
- ba,pt %xcc, etraptl1; \
- rd %pc, %g7; \
- call routine; \
- add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
- ba,pt %xcc, rtrap; \
- clr %l6;
-
-#define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
-#define LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
-#define LINUX_64BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table64)
-#define GETCC_TRAP TRAP(getcc)
-#define SETCC_TRAP TRAP(setcc)
-/* FIXME: Write these actually */
-#define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
-#define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
-#define BREAKPOINT_TRAP TRAP(breakpoint_trap)
-#define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
-
-#define TRAP_IRQ(routine, level) \
- rdpr %pil, %g2; \
- wrpr %g0, 15, %pil; \
- ba,pt %xcc, etrap_irq; \
- rd %pc, %g7; \
- mov level, %o0; \
- call routine; \
- add %sp, STACK_BIAS + REGWIN_SZ, %o1; \
- ba,a,pt %xcc, rtrap_clr_l6;
-
-/* On UP this is ok, and worth the effort, for SMP we need
- * a different mechanism and thus cannot do it all in trap table. -DaveM
- */
-#ifndef __SMP__
-#define TRAP_IVEC \
- ldxa [%g2] ASI_UDB_INTR_R, %g3; \
- and %g3, 0x7ff, %g3; \
- sllx %g3, 3, %g3; \
- ldx [%g1 + %g3], %g5; \
- wr %g5, 0x0, %set_softint; \
- stxa %g0, [%g0] ASI_INTR_RECEIVE; \
- membar #Sync; \
- retry;
-#else
-#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
-#endif
-
-#define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
-
-#define BTRAPTL1(lvl) TRAPTL1_ARG(bad_trap_tl1, lvl)
-
-#define FLUSH_WINDOW_TRAP \
- ba,pt %xcc, etrap; \
- rd %pc, %g7; \
- flushw; \
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1; \
- add %l1, 4, %l2; \
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]; \
- ba,pt %xcc, rtrap_clr_l6; \
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC];
-
-/* Before touching these macros, you owe it to yourself to go and
- * see how arch/sparc64/kernel/winfixup.S works... -DaveM
- */
-
-/* Normal kernel spill */
-#define SPILL_0_NORMAL \
- stx %l0, [%sp + STACK_BIAS + 0x00]; \
- stx %l1, [%sp + STACK_BIAS + 0x08]; \
- stx %l2, [%sp + STACK_BIAS + 0x10]; \
- stx %l3, [%sp + STACK_BIAS + 0x18]; \
- stx %l4, [%sp + STACK_BIAS + 0x20]; \
- stx %l5, [%sp + STACK_BIAS + 0x28]; \
- stx %l6, [%sp + STACK_BIAS + 0x30]; \
- stx %l7, [%sp + STACK_BIAS + 0x38]; \
- stx %i0, [%sp + STACK_BIAS + 0x40]; \
- stx %i1, [%sp + STACK_BIAS + 0x48]; \
- stx %i2, [%sp + STACK_BIAS + 0x50]; \
- stx %i3, [%sp + STACK_BIAS + 0x58]; \
- stx %i4, [%sp + STACK_BIAS + 0x60]; \
- stx %i5, [%sp + STACK_BIAS + 0x68]; \
- stx %i6, [%sp + STACK_BIAS + 0x70]; \
- stx %i7, [%sp + STACK_BIAS + 0x78]; \
- saved; retry; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; nop; nop;
-
-/* Normal 64bit spill */
-#define SPILL_1_GENERIC(xxx) \
- wr %g0, xxx, %asi; \
- stxa %l0, [%sp + STACK_BIAS + 0x00] %asi; \
- stxa %l1, [%sp + STACK_BIAS + 0x08] %asi; \
- stxa %l2, [%sp + STACK_BIAS + 0x10] %asi; \
- stxa %l3, [%sp + STACK_BIAS + 0x18] %asi; \
- stxa %l4, [%sp + STACK_BIAS + 0x20] %asi; \
- stxa %l5, [%sp + STACK_BIAS + 0x28] %asi; \
- stxa %l6, [%sp + STACK_BIAS + 0x30] %asi; \
- stxa %l7, [%sp + STACK_BIAS + 0x38] %asi; \
- stxa %i0, [%sp + STACK_BIAS + 0x40] %asi; \
- stxa %i1, [%sp + STACK_BIAS + 0x48] %asi; \
- stxa %i2, [%sp + STACK_BIAS + 0x50] %asi; \
- stxa %i3, [%sp + STACK_BIAS + 0x58] %asi; \
- stxa %i4, [%sp + STACK_BIAS + 0x60] %asi; \
- stxa %i5, [%sp + STACK_BIAS + 0x68] %asi; \
- stxa %i6, [%sp + STACK_BIAS + 0x70] %asi; \
- stxa %i7, [%sp + STACK_BIAS + 0x78] %asi; \
- saved; retry; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; \
- b,a,pt %xcc, spill_fixup_mna; \
- b,a,pt %xcc, spill_fixup;
-
-/* Normal 32bit spill */
-#define SPILL_2_GENERIC(xxx) \
- wr %g0, xxx, %asi; \
- srl %sp, 0, %sp; \
- stwa %l0, [%sp + 0x00] %asi; \
- stwa %l1, [%sp + 0x04] %asi; \
- stwa %l2, [%sp + 0x08] %asi; \
- stwa %l3, [%sp + 0x0c] %asi; \
- stwa %l4, [%sp + 0x10] %asi; \
- stwa %l5, [%sp + 0x14] %asi; \
- stwa %l6, [%sp + 0x18] %asi; \
- stwa %l7, [%sp + 0x1c] %asi; \
- stwa %i0, [%sp + 0x20] %asi; \
- stwa %i1, [%sp + 0x24] %asi; \
- stwa %i2, [%sp + 0x28] %asi; \
- stwa %i3, [%sp + 0x2c] %asi; \
- stwa %i4, [%sp + 0x30] %asi; \
- stwa %i5, [%sp + 0x34] %asi; \
- stwa %i6, [%sp + 0x38] %asi; \
- stwa %i7, [%sp + 0x3c] %asi; \
- saved; retry; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; \
- b,a,pt %xcc, spill_fixup_mna; \
- b,a,pt %xcc, spill_fixup;
-
-#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
-#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
-#define SPILL_3_NORMAL SPILL_0_NORMAL
-#define SPILL_4_NORMAL SPILL_0_NORMAL
-#define SPILL_5_NORMAL SPILL_0_NORMAL
-#define SPILL_6_NORMAL SPILL_0_NORMAL
-#define SPILL_7_NORMAL SPILL_0_NORMAL
-
-#define SPILL_0_OTHER SPILL_0_NORMAL
-#define SPILL_1_OTHER SPILL_1_GENERIC(ASI_AIUS)
-#define SPILL_2_OTHER SPILL_2_GENERIC(ASI_AIUS)
-#define SPILL_3_OTHER SPILL_3_NORMAL
-#define SPILL_4_OTHER SPILL_4_NORMAL
-#define SPILL_5_OTHER SPILL_5_NORMAL
-#define SPILL_6_OTHER SPILL_6_NORMAL
-#define SPILL_7_OTHER SPILL_7_NORMAL
-
-/* Normal kernel fill */
-#define FILL_0_NORMAL \
- ldx [%sp + STACK_BIAS + 0x00], %l0; \
- ldx [%sp + STACK_BIAS + 0x08], %l1; \
- ldx [%sp + STACK_BIAS + 0x10], %l2; \
- ldx [%sp + STACK_BIAS + 0x18], %l3; \
- ldx [%sp + STACK_BIAS + 0x20], %l4; \
- ldx [%sp + STACK_BIAS + 0x28], %l5; \
- ldx [%sp + STACK_BIAS + 0x30], %l6; \
- ldx [%sp + STACK_BIAS + 0x38], %l7; \
- ldx [%sp + STACK_BIAS + 0x40], %i0; \
- ldx [%sp + STACK_BIAS + 0x48], %i1; \
- ldx [%sp + STACK_BIAS + 0x50], %i2; \
- ldx [%sp + STACK_BIAS + 0x58], %i3; \
- ldx [%sp + STACK_BIAS + 0x60], %i4; \
- ldx [%sp + STACK_BIAS + 0x68], %i5; \
- ldx [%sp + STACK_BIAS + 0x70], %i6; \
- ldx [%sp + STACK_BIAS + 0x78], %i7; \
- restored; retry; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; nop; nop;
-
-/* Normal 64bit fill */
-#define FILL_1_GENERIC(xxx) \
- wr %g0, xxx, %asi; \
- ldxa [%sp + STACK_BIAS + 0x00] %asi, %l0; \
- ldxa [%sp + STACK_BIAS + 0x08] %asi, %l1; \
- ldxa [%sp + STACK_BIAS + 0x10] %asi, %l2; \
- ldxa [%sp + STACK_BIAS + 0x18] %asi, %l3; \
- ldxa [%sp + STACK_BIAS + 0x20] %asi, %l4; \
- ldxa [%sp + STACK_BIAS + 0x28] %asi, %l5; \
- ldxa [%sp + STACK_BIAS + 0x30] %asi, %l6; \
- ldxa [%sp + STACK_BIAS + 0x38] %asi, %l7; \
- ldxa [%sp + STACK_BIAS + 0x40] %asi, %i0; \
- ldxa [%sp + STACK_BIAS + 0x48] %asi, %i1; \
- ldxa [%sp + STACK_BIAS + 0x50] %asi, %i2; \
- ldxa [%sp + STACK_BIAS + 0x58] %asi, %i3; \
- ldxa [%sp + STACK_BIAS + 0x60] %asi, %i4; \
- ldxa [%sp + STACK_BIAS + 0x68] %asi, %i5; \
- ldxa [%sp + STACK_BIAS + 0x70] %asi, %i6; \
- ldxa [%sp + STACK_BIAS + 0x78] %asi, %i7; \
- restored; retry; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; \
- b,a,pt %xcc, fill_fixup_mna; \
- b,a,pt %xcc, fill_fixup;
-
-/* Normal 32bit fill */
-#define FILL_2_GENERIC(xxx) \
- wr %g0, xxx, %asi; \
- srl %sp, 0, %sp; \
- lduwa [%sp + 0x00] %asi, %l0; \
- lduwa [%sp + 0x04] %asi, %l1; \
- lduwa [%sp + 0x08] %asi, %l2; \
- lduwa [%sp + 0x0c] %asi, %l3; \
- lduwa [%sp + 0x10] %asi, %l4; \
- lduwa [%sp + 0x14] %asi, %l5; \
- lduwa [%sp + 0x18] %asi, %l6; \
- lduwa [%sp + 0x1c] %asi, %l7; \
- lduwa [%sp + 0x20] %asi, %i0; \
- lduwa [%sp + 0x24] %asi, %i1; \
- lduwa [%sp + 0x28] %asi, %i2; \
- lduwa [%sp + 0x2c] %asi, %i3; \
- lduwa [%sp + 0x30] %asi, %i4; \
- lduwa [%sp + 0x34] %asi, %i5; \
- lduwa [%sp + 0x38] %asi, %i6; \
- lduwa [%sp + 0x3c] %asi, %i7; \
- restored; retry; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; \
- b,a,pt %xcc, fill_fixup_mna; \
- b,a,pt %xcc, fill_fixup;
-
-#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
-#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
-#define FILL_3_NORMAL FILL_0_NORMAL
-#define FILL_4_NORMAL FILL_0_NORMAL
-#define FILL_5_NORMAL FILL_0_NORMAL
-#define FILL_6_NORMAL FILL_0_NORMAL
-#define FILL_7_NORMAL FILL_0_NORMAL
-
-#define FILL_0_OTHER FILL_0_NORMAL
-#define FILL_1_OTHER FILL_1_GENERIC(ASI_AIUS)
-#define FILL_2_OTHER FILL_2_GENERIC(ASI_AIUS)
-#define FILL_3_OTHER FILL_3_NORMAL
-#define FILL_4_OTHER FILL_4_NORMAL
-#define FILL_5_OTHER FILL_5_NORMAL
-#define FILL_6_OTHER FILL_6_NORMAL
-#define FILL_7_OTHER FILL_7_NORMAL
#endif /* !(_SPARC64_HEAD_H) */
-/* $Id: ioctls.h,v 1.4 1997/06/23 07:26:03 davem Exp $ */
+/* $Id: ioctls.h,v 1.5 1997/08/12 04:13:13 ecd Exp $ */
#ifndef _ASM_SPARC64_IOCTLS_H
#define _ASM_SPARC64_IOCTLS_H
#define TIOCSERGETLSR 0x5459 /* Get line status register */
#define TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+#define TIOCMIWAIT 0x545C /* Wait for change on serial input line(s) */
+#define TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */
/* Kernel definitions */
#ifdef __KERNEL__
#include <asm/page.h>
#include <asm/sysio.h>
+#include <asm/spinlock.h>
/* The iommu handles all virtual to physical address translations
* that occur between the SYSIO and physical memory. Access by
#define IOPTE_WRITE 0x0000000000000002 /* Writeable */
struct iommu_struct {
- struct sysio_regs *sysio_regs;
- iopte_t *page_table;
+ struct sysio_regs *sysio_regs;
+ unsigned int *sbuf_flushflag_va;
+ unsigned long sbuf_flushflag_pa;
+ spinlock_t iommu_lock;
+
+ iopte_t *page_table;
/* For convenience */
unsigned long start; /* First managed virtual address */
-/* $Id: irq.h,v 1.4 1997/04/04 00:50:20 davem Exp $
+/* $Id: irq.h,v 1.6 1997/08/07 08:06:40 davem Exp $
* irq.h: IRQ registers on the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
#include <linux/linkage.h>
-#include <asm/system.h> /* For NCPUS */
+/* Sparc64 extensions to the interrupt registry flags. Mostly this is
+ * for passing along what bus type the device is on and also the true
+ * format of the dev_id cookie, see below.
+ */
+#define SA_BUSMASK 0x0f000
+#define SA_SBUS 0x01000
+#define SA_PCI 0x02000
+#define SA_FHC 0x03000
+#define SA_EBUS 0x04000
+#define SA_BUS(mask) ((mask) & SA_BUSMASK)
+
+struct devid_cookie {
+ /* Caller specifies these. */
+ void *real_dev_id; /* What dev_id would usually contain. */
+ unsigned int *imap; /* Anonymous IMAP register */
+ unsigned int *iclr; /* Anonymous ICLR register */
+ int pil; /* Anonymous PIL */
+ void *bus_cookie; /* SYSIO regs, PSYCHO regs, etc. */
+
+ /* Return values. */
+ unsigned int ret_ino;
+ unsigned int ret_pil;
+};
+
+#define SA_DCOOKIE 0x10000
#define NR_IRQS 15
-/* $Id: mmu_context.h,v 1.17 1997/07/13 19:13:39 davem Exp $ */
+/* $Id: mmu_context.h,v 1.19 1997/08/07 02:54:08 davem Exp $ */
#ifndef __SPARC64_MMU_CONTEXT_H
#define __SPARC64_MMU_CONTEXT_H
#ifndef __ASSEMBLY__
-#define destroy_context(mm) do { } while(0)
-
extern unsigned long tlb_context_cache;
#define CTX_VERSION_SHIFT PAGE_SHIFT
#define CTX_VERSION_MASK ((~0UL) << CTX_VERSION_SHIFT)
#define CTX_FIRST_VERSION ((1UL << CTX_VERSION_SHIFT) + 1UL)
-extern void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx);
+extern void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx);
-/* Initialize the context related info for a new mm_struct
+/* Initialize/destroy the context related info for a new mm_struct
* instance.
*/
-#define init_new_context(mm) get_new_mmu_context((mm), tlb_context_cache)
+#define init_new_context(mm) ((mm)->context = NO_CONTEXT)
+#define destroy_context(mm) ((mm)->context = NO_CONTEXT)
+
+#ifdef __SMP__
+#define LOCAL_FLUSH_PENDING(cpu) \
+ ((cpu_data[(cpu)].last_tlbversion_seen ^ tlb_context_cache) & CTX_VERSION_MASK)
+#define DO_LOCAL_FLUSH(cpu) do { __flush_tlb_all(); \
+ cpu_data[cpu].last_tlbversion_seen = \
+ tlb_context_cache & CTX_VERSION_MASK; \
+ } while(0)
+#else
+#define LOCAL_FLUSH_PENDING(cpu) 0
+#define DO_LOCAL_FLUSH(cpu) do { __flush_tlb_all(); } while(0)
+#endif
+
+extern void __flush_tlb_all(void);
extern __inline__ void get_mmu_context(struct task_struct *tsk)
{
struct mm_struct *mm = tsk->mm;
flushw_user();
+ if(LOCAL_FLUSH_PENDING(current->processor))
+ DO_LOCAL_FLUSH(current->processor);
if(!(tsk->tss.flags & SPARC_FLAG_KTHREAD) &&
!(tsk->flags & PF_EXITING)) {
unsigned long ctx = tlb_context_cache;
if((mm->context ^ ctx) & CTX_VERSION_MASK)
- get_new_mmu_context(mm, ctx);
+ get_new_mmu_context(mm, &tlb_context_cache);
/* Don't worry, set_fs() will restore it... */
tsk->tss.ctx = (tsk->tss.current_ds ?
-/* $Id: openprom.h,v 1.4 1997/03/24 06:42:08 davem Exp $ */
+/* $Id: openprom.h,v 1.5 1997/08/15 06:44:51 davem Exp $ */
#ifndef __SPARC64_OPENPROM_H
#define __SPARC64_OPENPROM_H
unsigned int or_size;
};
+/* Ranges and reg properties are a bit different for PCI. */
+struct linux_prom_pci_registers {
+ unsigned int phys_hi;
+ unsigned int phys_mid;
+ unsigned int phys_lo;
+
+ unsigned int size_hi;
+ unsigned int size_lo;
+};
+
+struct linux_prom_pci_ranges {
+ unsigned int child_phys_hi; /* Only certain bits are encoded here. */
+ unsigned int child_phys_mid;
+ unsigned int child_phys_lo;
+
+ unsigned int parent_phys_hi;
+ unsigned int parent_phys_lo;
+
+ unsigned int size_hi;
+ unsigned int size_lo;
+};
+
#endif /* !(__ASSEMBLY__) */
#endif /* !(__SPARC64_OPENPROM_H) */
-/* $Id: page.h,v 1.14 1997/06/26 22:32:03 davem Exp $ */
+/* $Id: page.h,v 1.15 1997/08/09 04:56:54 davem Exp $ */
#ifndef _SPARC64_PAGE_H
#define _SPARC64_PAGE_H
#endif /* (STRICT_MM_TYPECHECKS) */
-#endif /* !(__ASSEMBLY__) */
+#define TASK_UNMAPPED_BASE ((current->tss.flags & SPARC_FLAG_32BIT) ? \
+ (0x0000000070000000UL) : \
+ (0x0000030000000000UL))
-#ifndef __ASSEMBLY__
-#define TASK_UNMAPPED_BASE 0x0000000070000000UL
-#else
-#define TASK_UNMAPPED_BASE 0x0000000070000000
-#endif
+#endif /* !(__ASSEMBLY__) */
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
--- /dev/null
+/* $Id: pbm.h,v 1.4 1997/08/15 06:44:52 davem Exp $
+ * pbm.h: U2P PCI bus module pseudo driver software state.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_PBM_H
+#define __SPARC64_PBM_H
+
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/psycho.h>
+#include <asm/oplib.h>
+
+struct linux_psycho;
+
+struct linux_pbm_info {
+ struct linux_psycho *parent;
+ unsigned long *pbm_IO;
+ unsigned long *pbm_mem;
+ int prom_node;
+ char prom_name[64];
+ struct linux_prom_pci_ranges pbm_ranges[PROMREG_MAX];
+ int num_pbm_ranges;
+
+ /* Now things for the actual PCI bus probes. */
+ unsigned int pci_first_busno;
+ unsigned int pci_last_busno;
+ struct pci_bus pci_bus;
+};
+
+struct linux_psycho {
+ struct linux_psycho *next;
+ struct psycho_regs *psycho_regs;
+ unsigned long *pci_config_space;
+ unsigned long *pci_IO_space;
+ unsigned long *pci_mem_space;
+ u32 upa_portid;
+ struct linux_pbm_info pbm_A;
+ struct linux_pbm_info pbm_B;
+};
+
+extern struct linux_psycho *psycho_root;
+
+#endif /* !(__SPARC64_PBM_H) */
-/* $Id: pgtable.h,v 1.50 1997/07/24 16:48:31 davem Exp $
+/* $Id: pgtable.h,v 1.57 1997/08/13 04:44:20 paulus Exp $
* pgtable.h: SpitFire page table operations.
*
* Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
/* Cache and TLB flush operations. */
/* These are the same regardless of whether this is an SMP kernel or not. */
-#define flush_cache_mm(mm) do { } while(0)
-#define flush_cache_range(mm, start, end) do { } while(0)
-#define flush_cache_page(vma, page) do { } while(0)
+#define flush_cache_mm(mm) flushw_user()
+#define flush_cache_range(mm, start, end) flushw_user()
+#define flush_cache_page(vma, page) flushw_user()
/* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
#define flush_page_to_ram(page) do { } while (0)
+#define flush_icache_range(start, end) do { } while (0)
extern void __flush_cache_all(void);
extern void smp_flush_tlb_mm(struct mm_struct *mm);
extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end);
-extern void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
#define flush_cache_all() smp_flush_cache_all()
#define flush_tlb_all() smp_flush_tlb_all()
struct mm_struct *mm = vma->vm_mm;
if(mm->context != NO_CONTEXT)
- smp_flush_tlb_page(vma, page);
+ smp_flush_tlb_page(mm, page & PAGE_MASK);
}
#endif
extern inline unsigned long pgd_page(pgd_t pgd)
{ return (unsigned long) __va(pgd_val(pgd)); }
+#define PMD_NONE_MAGIC 0x80
+#define PGD_NONE_MAGIC 0x40
+
extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
extern inline void pte_clear(pte_t *pte) { pte_val(*pte) = 0; }
-extern inline int pmd_none(pmd_t pmd) { return pmd_val(pmd)==null_pte_table; }
-extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK); }
-extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd)!=null_pte_table; }
+extern inline int pmd_none(pmd_t pmd) { return pmd_val(pmd)&PMD_NONE_MAGIC; }
+extern inline int pmd_bad(pmd_t pmd) { return 0; }
+extern inline int pmd_present(pmd_t pmd) { return !(pmd_val(pmd)&PMD_NONE_MAGIC);}
extern inline void pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = null_pte_table; }
-extern inline int pgd_none(pgd_t pgd) { return pgd_val(pgd)==null_pmd_table; }
-extern inline int pgd_bad(pgd_t pgd) { return (pgd_val(pgd) & ~PAGE_MASK); }
-extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd)!=null_pmd_table; }
+extern inline int pgd_none(pgd_t pgd) { return pgd_val(pgd) & PGD_NONE_MAGIC; }
+extern inline int pgd_bad(pgd_t pgd) { return 0; }
+extern inline int pgd_present(pgd_t pgd) { return !(pgd_val(pgd)&PGD_NONE_MAGIC);}
extern inline void pgd_clear(pgd_t *pgdp) { pgd_val(*pgdp) = null_pmd_table; }
/* The following only work if pte_present() is true.
extern inline pte_t *pte_offset(pmd_t *dir, unsigned long address)
{ return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1)); }
-extern __inline__ void __init_pmd(pmd_t *pmdp)
+/* Very stupidly, we used to get new pgd's and pmd's, init their contents
+ * to point to the NULL versions of the next level page table, later on
+ * completely re-init them the same way, then free them up. This wasted
+ * a lot of work and caused unnecessary memory traffic. How broken...
+ * We fix this by caching them.
+ */
+
+#ifdef __SMP__
+/* Sliiiicck */
+#define pgd_quicklist (cpu_data[smp_processor_id()].pgd_cache)
+#define pmd_quicklist (cpu_data[smp_processor_id()].pmd_cache)
+#define pte_quicklist (cpu_data[smp_processor_id()].pte_cache)
+#define pgtable_cache_size (cpu_data[smp_processor_id()].pgcache_size)
+#else
+extern unsigned long *pgd_quicklist;
+extern unsigned long *pmd_quicklist;
+extern unsigned long *pte_quicklist;
+extern unsigned long pgtable_cache_size;
+#endif
+
+extern pgd_t *get_pgd_slow(void);
+
+extern __inline__ pgd_t *get_pgd_fast(void)
{
- extern void __bfill64(void *, unsigned long *);
-
- __bfill64((void *)pmdp, &null_pte_table);
+ pgd_t *ret;
+
+ if((ret = (pgd_t *)pgd_quicklist) != NULL) {
+ pgd_quicklist = (unsigned long *)pgd_val(*ret);
+ pgd_val(ret[0]) = pgd_val(ret[1]);
+ (pgtable_cache_size)--;
+ } else
+ ret = get_pgd_slow();
+ return ret;
}
-/* Turning this off makes things much faster, but eliminates some
- * sanity checking as well.
- */
-/* #define PGTABLE_SANITY_CHECKS */
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+ pgd_val(*pgd) = (unsigned long) pgd_quicklist;
+ pgd_quicklist = (unsigned long *) pgd;
+ (pgtable_cache_size)++;
+}
-/* Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on supervisor
- * bits if any.
- */
-extern inline void pte_free_kernel(pte_t *pte)
-{ free_page((unsigned long)pte); }
+extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
-extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+extern __inline__ pmd_t *get_pmd_fast(void)
{
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
- if (pmd_none(*pmd)) {
- if (page) {
- pmd_set(pmd, page);
- return page + address;
- }
- pmd_set(pmd, BAD_PTE);
- return NULL;
- }
- free_page((unsigned long) page);
- }
-#ifdef PGTABLE_SANITY_CHECKS
- if (pmd_bad(*pmd)) {
- printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
- pmd_set(pmd, BAD_PTE);
- return NULL;
+ pmd_t *ret;
+
+ if((ret = (pmd_t *)pmd_quicklist) != NULL) {
+ pmd_quicklist = (unsigned long *)pmd_val(*ret);
+ pmd_val(ret[0]) = pmd_val(ret[1]);
+ (pgtable_cache_size)--;
}
-#endif
- return (pte_t *) pmd_page(*pmd) + address;
+ return ret;
}
-extern inline void pmd_free_kernel(pmd_t *pmd)
-{ free_page((unsigned long) pmd); }
+extern __inline__ void free_pmd_fast(pgd_t *pmd)
+{
+ pmd_val(*pmd) = (unsigned long) pmd_quicklist;
+ pmd_quicklist = (unsigned long *) pmd;
+ (pgtable_cache_size)++;
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+extern __inline__ pte_t *get_pte_fast(void)
{
- address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
- if (pgd_none(*pgd)) {
- pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
- if (pgd_none(*pgd)) {
- if (page) {
- __init_pmd(page);
- pgd_set(pgd, page);
- return page + address;
- }
- pgd_set(pgd, BAD_PMD);
- return NULL;
- }
- free_page((unsigned long) page);
- }
-#ifdef PGTABLE_SANITY_CHECKS
- if (pgd_bad(*pgd)) {
- printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
- pgd_set(pgd, BAD_PMD);
- return NULL;
+ pte_t *ret;
+
+ if((ret = (pte_t *)pte_quicklist) != NULL) {
+ pte_quicklist = (unsigned long *)pte_val(*ret);
+ pte_val(ret[0]) = pte_val(ret[1]);
+ (pgtable_cache_size)--;
}
-#endif
- return (pmd_t *) pgd_page(*pgd) + address;
+ return ret;
+}
+
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+ pte_val(*pte) = (unsigned long) pte_quicklist;
+ pte_quicklist = (unsigned long *) pte;
+ (pgtable_cache_size)++;
}
-extern inline void pte_free(pte_t * pte)
-{ free_page((unsigned long)pte); }
+#define pte_free_kernel(pte) free_pte_fast(pte)
+#define pte_free(pte) free_pte_fast(pte)
+#define pmd_free_kernel(pmd) free_pmd_fast(pmd)
+#define pmd_free(pmd) free_pmd_fast(pmd)
+#define pgd_free(pgd) free_pgd_fast(pgd)
+#define pgd_alloc() get_pgd_fast()
extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
{
address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
if (pmd_none(*pmd)) {
- pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
- if (pmd_none(*pmd)) {
- if (page) {
- pmd_set(pmd, page);
- return page + address;
- }
- pmd_set(pmd, BAD_PTE);
- return NULL;
- }
- free_page((unsigned long) page);
- }
-#ifdef PGTABLE_SANITY_CHECKS
- if (pmd_bad(*pmd)) {
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- pmd_set(pmd, BAD_PTE);
- return NULL;
+ pte_t *page = get_pte_fast();
+
+ if (!page)
+ return get_pte_slow(pmd, address);
+ pmd_set(pmd, page);
+ return page + address;
}
-#endif
return (pte_t *) pmd_page(*pmd) + address;
}
-extern inline void pmd_free(pmd_t * pmd)
-{ free_page((unsigned long) pmd); }
-
extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
{
address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
if (pgd_none(*pgd)) {
- pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
- if (pgd_none(*pgd)) {
- if (page) {
- __init_pmd(page);
- pgd_set(pgd, page);
- return page + address;
- }
- pgd_set(pgd, BAD_PMD);
- return NULL;
- }
- free_page((unsigned long) page);
- }
-#ifdef PGTABLE_SANITY_CHECKS
- if (pgd_bad(*pgd)) {
- printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
- pgd_set(pgd, BAD_PMD);
- return NULL;
+ pmd_t *page = get_pmd_fast();
+
+ if (!page)
+ return get_pmd_slow(pgd, address);
+ pgd_set(pgd, page);
+ return page + address;
}
-#endif
return (pmd_t *) pgd_page(*pgd) + address;
}
-extern inline void pgd_free(pgd_t * pgd)
-{ free_page((unsigned long)pgd); }
-
-extern inline pgd_t * pgd_alloc(void)
-{
- extern void __bfill64(void *, unsigned long *);
- pgd_t *pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
-
- if (pgd)
- __bfill64((void *)pgd, &null_pmd_table);
- return pgd;
-}
+#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr)
+#define pmd_alloc_kernel(pgd, addr) pmd_alloc(pgd, addr)
extern pgd_t swapper_pg_dir[1024];
extern __u32 mmu_get_scsi_one(char *, unsigned long, struct linux_sbus *sbus);
extern void mmu_get_scsi_sgl(struct mmu_sglist *, int, struct linux_sbus *sbus);
+extern void mmu_release_scsi_one(u32 vaddr, unsigned long len,
+ struct linux_sbus *sbus);
+extern void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus);
+
+#define NEED_DMA_SYNCHRONIZATION
+#define mmu_sync_dma(dma_addr, len, sbus_instance) \
+ mmu_release_scsi_one((dma_addr), (len), (sbus_instance))
+
/* These do nothing with the way I have things setup. */
-#define mmu_release_scsi_one(vaddr, len, sbus) do { } while(0)
-#define mmu_release_scsi_sgl(sg, sz, sbus) do { } while(0)
#define mmu_lockarea(vaddr, len) (vaddr)
#define mmu_unlockarea(vaddr, len) do { } while(0)
-
-extern void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address,
- pte_t pte);
-
-extern inline void update_mmu_cache(struct vm_area_struct * vma,
- unsigned long address, pte_t pte)
-{
- /* Find and fix bad virutal cache aliases. */
- if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
- fixup_dcache_alias(vma, address, pte);
-}
+#define update_mmu_cache(vma, address, pte) do { } while(0)
/* Make a non-present pseudo-TTE. */
extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
--- /dev/null
+/* $Id: psycho.h,v 1.2 1997/08/11 14:35:40 davem Exp $
+ * psycho.h: UltraSparc AX specific PCI definitions.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#ifndef __SPARC64_PSYCHO_H
+#define __SPARC64_PSYCHO_H
+
+#include <linux/types.h>
+
+/* Ultra AX PSYCHO Register Set, one per controller probed. */
+struct psycho_regs {
+/*0x0000*/ u64 upa_id; /* PSYCHO UPA Port ID Register */
+/*0x0008*/ u64 upa_cfg; /* PSYCHO UPA Config Register */
+/*0x0010*/ u64 control; /* PSYCHO Control Register */
+/*0x0018*/ u64 __pad0;
+/*0x0020*/ u64 ecc_control; /* ECC Control Register */
+/*0x0028*/ u64 __pad1;
+
+ /* Uncorrectable Error Fault Registers */
+/*0x0030*/ u64 ue_afsr; /* UE Async Fault Status */
+/*0x0038*/ u64 ue_afar; /* UE Async Fault Address */
+
+ /* Correctable Error Fault Registers */
+/*0x0040*/ u64 ce_afsr; /* CE Async Fault Status */
+/*0x0048*/ u64 ce_afar; /* CE Async Fault Address */
+
+ u64 __pad2[0x16];
+
+ /* Performance Monitoring Registers */
+/*0x0100*/ u64 pmon_control;
+/*0x0108*/ u64 pmon_counter;
+
+ u64 __pad3[0x1e];
+
+ /* PCI Bus IOMMU lives here */
+/*0x0200*/ u64 iommu_control; /* IOMMU Control */
+/*0x0208*/ u64 iommu_tsbbase; /* IOMMU TSB Base */
+/*0x0210*/ u64 iommu_flush; /* IOMMU Flush Register */
+
+ u64 __pad4[0x13d];
+
+ /* Interrupt mapping/control registers */
+/*0x0c00*/ u64 imap_a_slot0; /* PCI A Slot 0 Int Mapping */
+/*0x0c08*/ u64 imap_a_slot1; /* PCI A Slot 1 Int Mapping */
+
+ u64 __pad5[0x2];
+
+/*0x0c20*/ u64 imap_b_slot0; /* PCI B Slot 0 Int Mapping */
+/*0x0c28*/ u64 imap_b_slot1; /* PCI B Slot 1 Int Mapping */
+/*0x0c30*/ u64 imap_b_slot2; /* PCI B Slot 2 Int Mapping */
+/*0x0c38*/ u64 imap_b_slot3; /* PCI B Slot 3 Int Mapping */
+
+ u64 __pad6[0x78];
+
+/*0x1000*/ u64 imap_scsi; /* SCSI Int Mapping */
+/*0x1008*/ u64 imap_eth; /* Ethernet Int Mapping */
+/*0x1010*/ u64 imap_bpp; /* Parallel Port Int Mapping */
+/*0x1018*/ u64 imap_au_rec; /* Audio Record Int Mapping */
+/*0x1020*/ u64 imap_au_play; /* Audio Playback Int Mapping */
+/*0x1028*/ u64 imap_pfail; /* Power Fail Int Mapping */
+/*0x1030*/ u64 imap_kms; /* Kbd/Mouse/Ser Int Mapping */
+/*0x1038*/ u64 imap_flpy; /* Floppy Int Mapping */
+/*0x1040*/ u64 imap_shw; /* Spare HW Int Mapping */
+/*0x1048*/ u64 imap_kbd; /* Kbd Only Int Mapping */
+/*0x1050*/ u64 imap_ms; /* Mouse Only Int Mapping */
+/*0x1058*/ u64 imap_ser; /* Serial Only Int Mapping */
+/*0x1060*/ u64 imap_tim0; /* Timer 0 Int Mapping */
+/*0x1068*/ u64 imap_tim1; /* Timer 1 Int Mapping */
+/*0x1070*/ u64 imap_ue; /* UE Int Mapping */
+/*0x1078*/ u64 imap_ce; /* CE Int Mapping */
+/*0x1080*/ u64 imap_a_err; /* PCI A Err Int Mapping */
+/*0x1088*/ u64 imap_b_err; /* PCI B Err Int Mapping */
+/*0x1090*/ u64 imap_pmgmt; /* Power Mgmt Int Mapping */
+/*0x1098*/ u64 imap_gfx; /* OB Graphics Int Mapping */
+/*0x10a0*/ u64 imap_eupa; /* UPA Expansion Int Mapping */
+
+ u64 __pad7[0x6b];
+
+ /* Interrupt Clear Registers */
+/*0x1400*/ u64 iclr_a_slot0[4]; /* PCI A Slot 0 Clear Int Reg */
+/*0x1420*/ u64 iclr_a_slot1[4]; /* PCI A Slot 1 Clear Int Reg */
+
+ u64 __pad8[0x8];
+
+/*0x1480*/ u64 iclr_b_slot0[4]; /* PCI B Slot 0 Clear Int Reg */
+/*0x14a0*/ u64 iclr_b_slot1[4]; /* PCI B Slot 1 Clear Int Reg */
+/*0x14c0*/ u64 iclr_b_slot2[4]; /* PCI B Slot 2 Clear Int Reg */
+/*0x14e0*/ u64 iclr_b_slot3[4]; /* PCI B Slot 3 Clear Int Reg */
+
+ u64 __pad9[0x60];
+
+/*0x1800*/ u64 iclr_scsi;
+/*0x1808*/ u64 iclr_eth;
+/*0x1810*/ u64 iclr_bpp;
+/*0x1818*/ u64 iclr_au_rec;
+/*0x1820*/ u64 iclr_au_play;
+/*0x1828*/ u64 iclr_pfail;
+/*0x1830*/ u64 iclr_kms;
+/*0x1838*/ u64 iclr_flpy;
+/*0x1840*/ u64 iclr_shw;
+/*0x1848*/ u64 iclr_kbd;
+/*0x1850*/ u64 iclr_ms;
+/*0x1858*/ u64 iclr_ser;
+/*0x1860*/ u64 iclr_tim0;
+/*0x1868*/ u64 iclr_tim1;
+/*0x1870*/ u64 iclr_ue;
+/*0x1878*/ u64 iclr_ce;
+/*0x1880*/ u64 iclr_a_err;
+/*0x1888*/ u64 iclr_b_err;
+/*0x1890*/ u64 iclr_pmgmt;
+
+ u64 __pad10[0x2d];
+
+ /* Interrupt Retry Timer. */
+/*0x1a00*/ u64 irq_retry;
+
+ u64 __pad11[0x3f];
+
+ /* Counters/Timers */
+/*0x1c00*/ u64 tim0_cnt;
+/*0x1c08*/ u64 tim0_lim;
+/*0x1c10*/ u64 tim1_cnt;
+/*0x1c18*/ u64 tim1_lim;
+
+ u64 __pad12[0x7c];
+
+ /* PCI Bus A Registers */
+/*0x2000*/ u64 pci_a_control; /* PCI Bus A Control Register */
+/*0x2008*/ u64 __pad13;
+/*0x2010*/ u64 pci_a_afsr; /* PCI Bus A Async Fault Status */
+/*0x2018*/ u64 pci_a_afar; /* PCI Bus A Async Fault Address*/
+/*0x2020*/ u64 pci_a_diag; /* PCI Bus A Diag Register */
+
+ u64 __pad14[0xfb];
+
+ /* PCI Bus A/IOMMU Streaming Buffer Registers */
+/*0x2800*/ u64 sbuf_a_control; /* StrBuffer Control */
+/*0x2808*/ u64 sbuf_a_pflush; /* StrBuffer Page Flush */
+/*0x2810*/ u64 sbuf_a_fsync; /* StrBuffer Flush Sync Reg */
+
+ u64 __pad15[0x2fd];
+
+ /* PCI Bus B Registers */
+/*0x4000*/ u64 pci_b_control; /* PCI Bus B Control Register */
+/*0x4008*/ u64 __pad16;
+/*0x4010*/ u64 pci_b_afsr; /* PCI Bus B Async Fault Status */
+/*0x4018*/ u64 pci_b_afar; /* PCI Bus B Async Fault Address*/
+/*0x4020*/ u64 pci_b_diag; /* PCI Bus B Diag Register */
+
+ u64 __pad17[0x7b];
+
+ /* IOMMU diagnostic things */
+/*0x4400*/ u64 iommu_vdiag; /* VADDR Diagnostic Register */
+/*0x4408*/ u64 iommu_tcompare; /* IOMMU TLB Tag Compare */
+
+ u64 __pad18[0x7e];
+
+ /* PCI Bus B/IOMMU Streaming Buffer Registers */
+/*0x4800*/ u64 sbuf_b_control; /* StrBuffer Control */
+/*0x4808*/ u64 sbuf_b_pflush; /* StrBuffer Page Flush */
+/*0x4810*/ u64 sbuf_b_fsync; /* StrBuffer Flush Sync Reg */
+
+ u64 __pad19[0xafd];
+
+ /* DMA Scoreboard Diagnostic Registers */
+/*0xa000*/ u64 dscore_reg0; /* DMA Scoreboard Diag Reg 0 */
+/*0xa008*/ u64 dscore_reg1; /* DMA Scoreboard Diag Reg 1 */
+
+ u64 __pad20[0x9e];
+
+ /* More IOMMU diagnostic things */
+/*0xa500*/ u64 iommu_lru[16]; /* IOMMU LRU Queue Diag */
+/*0xa580*/ u64 iommu_tag[16]; /* IOMMU TLB Tag Diag */
+/*0xa600*/ u64 iommu_data[16]; /* IOMMU TLB Data RAM Diag */
+
+ u64 __pad21[0x30];
+
+ /* Interrupt State Diagnostics */
+/*0xa800*/ u64 pci_istate;
+/*0xa808*/ u64 obio_istate;
+
+ u64 __pad22[0xfe];
+
+ /* Streaming Buffer A Diagnostic Area */
+/*0xb000*/ u64 sbuf_a_data[128]; /* StrBuffer Data Ram Diag */
+/*0xb400*/ u64 sbuf_a_errs[128]; /* StrBuffer Error Status Diag*/
+/*0xb800*/ u64 sbuf_a_ptag[16]; /* StrBuffer Page Tag Diag */
+/*0xb880*/ u64 __pad23[16];
+/*0xb900*/ u64 sbuf_a_ltag[16]; /* StrBuffer Line Tag Diag */
+
+ u64 __pad24[0xd0];
+
+ /* Streaming Buffer B Diagnostic Area */
+/*0xc000*/ u64 sbuf_b_data[128]; /* StrBuffer Data Ram Diag */
+/*0xc400*/ u64 sbuf_b_errs[128]; /* StrBuffer Error Status Diag*/
+/*0xc800*/ u64 sbuf_b_ptag[16]; /* StrBuffer Page Tag Diag */
+/*0xc880*/ u64 __pad25[16];
+/*0xc900*/ u64 sbuf_b_ltag[16]; /* StrBuffer Line Tag Diag */
+};
+
+/* PSYCHO UPA Port ID */
+#define PSYCHO_UPPID_FESC 0xff00000000000000 /* FCode escape, 0xfc */
+#define PSYCHO_UPPID_RESV1 0x00fffff800000000 /* Reserved */
+#define PSYCHO_UPPID_ENV 0x0000000400000000 /* Cannot generate ECC */
+#define PSYCHO_UPPID_ORD 0x0000000200000000 /* One Outstanding Read */
+#define PSYCHO_UPPID_RESV2 0x0000000180000000 /* Reserved */
+#define PSYCHO_UPPID_PDQ 0x000000007e000000 /* Data Queue size */
+#define PSYCHO_UPPID_PRQ 0x0000000001e00000 /* Request Queue size */
+#define PSYCHO_UPPID_UCAP 0x00000000001f0000 /* UPA Capabilities */
+#define PSYCHO_UPPID_JEDEC 0x000000000000ffff /* JEDEC ID for PSYCHO */
+
+/* PSYCHO UPA Configuration Register */
+#define PSYCHO_UPCFG_RESV 0xffffffffffffff00 /* Reserved */
+#define PSYCHO_UPCFG_SCIQ1 0x00000000000000f0 /* Unused, always zero */
+#define PSYCHO_UPCFG_SCIQ2 0x000000000000000f /* Requests Queue size 0x2 */
+
+/* PSYCHO Control Register */
+#define PSYCHO_CONTROL_IMPL 0xf000000000000000 /* Implementation of this PSYCHO*/
+#define PSYCHO_CONTROL_VER 0x0f00000000000000 /* Version of this PSYCHO */
+#define PSYCHO_CONTROL_MID 0x00f8000000000000 /* UPA Module ID of PSYCHO */
+#define PSYCHO_CONTROL_IGN 0x0007c00000000000 /* Interrupt Group Number */
+#define PSYCHO_CONTROL_RESV 0x00003ffffffffff0 /* Reserved */
+#define PSYCHO_CONTROL_APCKEN 0x0000000000000008 /* Address Parity Check Enable */
+#define PSYCHO_CONTROL_APERR 0x0000000000000004 /* Incoming System Addr Parerr */
+#define PSYCHO_CONTROL_IAP 0x0000000000000002 /* Invert UPA Parity */
+#define PSYCHO_CONTROL_MODE 0x0000000000000001 /* PSYCHO clock mode */
+
+/* PSYCHO ECC Control Register */
+#define PSYCHO_ECNTRL_ECCEN 0x8000000000000000 /* Enable ECC Checking */
+#define PSYCHO_ECNTRL_UEEN 0x4000000000000000 /* Enable UE Interrupts */
+#define PSYCHO_ECNTRL_CEEN 0x2000000000000000 /* Enable CE Interrupts */
+
+/* Uncorrectable Error AFSR, AFAR holds low 40bits of faulting physical address. */
+#define PSYCHO_UEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */
+#define PSYCHO_UEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */
+#define PSYCHO_UEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */
+#define PSYCHO_UEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */
+#define PSYCHO_UEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */
+#define PSYCHO_UEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/
+#define PSYCHO_UEAFSR_RESV1 0x03ff000000000000 /* Reserved */
+#define PSYCHO_UEAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */
+#define PSYCHO_UEAFSR_DOFF 0x00000000e0000000 /* Doubleword Offset */
+#define PSYCHO_UEAFSR_MID 0x000000001f000000 /* UPA MID causing the fault */
+#define PSYCHO_UEAFSR_BLK 0x0000000000800000 /* Trans was block operation */
+#define PSYCHO_UEAFSR_RESV2 0x00000000007fffff /* Reserved */
+
+/* Correctable Error AFSR, AFAR holds low 40bits of faulting physical address. */
+#define PSYCHO_CEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */
+#define PSYCHO_CEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */
+#define PSYCHO_CEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */
+#define PSYCHO_CEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */
+#define PSYCHO_CEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */
+#define PSYCHO_CEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/
+#define PSYCHO_CEAFSR_RESV1 0x0300000000000000 /* Reserved */
+#define PSYCHO_CEAFSR_ESYND 0x00ff000000000000 /* Syndrome Bits */
+#define PSYCHO_UEAFSR_SIZE 0x0000ffff00000000 /* Bytemask of failed transfer */
+#define PSYCHO_CEAFSR_DOFF 0x00000000e0000000 /* Double Offset */
+#define PSYCHO_CEAFSR_MID 0x000000001f000000 /* UPA MID causing the fault */
+#define PSYCHO_CEAFSR_BLK 0x0000000000800000 /* Trans was block operation */
+#define PSYCHO_CEAFSR_RESV2 0x00000000007fffff /* Reserved */
+
+/* DMA Scoreboard Diagnostic Register(s) */
+#define PSYCHO_DSCORE_VALID 0x8000000000000000 /* Entry is valid */
+#define PSYCHO_DSCORE_C 0x4000000000000000 /* Transaction cacheable */
+#define PSYCHO_DSCORE_READ 0x2000000000000000 /* Transaction was a read */
+#define PSYCHO_DSCORE_TAG 0x1f00000000000000 /* Transaction ID */
+#define PSYCHO_DSCORE_ADDR 0x00fffffffff80000 /* Transaction PADDR */
+#define PSYCHO_DSCORE_BMSK 0x000000000007fff8 /* Bytemask of pending transfer */
+#define PSYCHO_DSCORE_SRC 0x0000000000000007 /* Transaction source */
+
+/* PSYCHO PCI Control Register */
+#define PSYCHO_PCICTRL_RESV1 0xfffffff000000000 /* Reserved */
+#define PSYCHO_PCICTRL_SBH_ERR 0x0000000800000000 /* Streaming byte hole error */
+#define PSYCHO_PCICTRL_SERR 0x0000000400000000 /* SERR signal asserted */
+#define PSYCHO_PCICTRL_SPEED 0x0000000200000000 /* PCI speed (1 is U2P clock) */
+#define PSYCHO_PCICTRL_RESV2 0x00000001ffc00000 /* Reserved */
+#define PSYCHO_PCICTRL_ARB_PARK 0x0000000000200000 /* PCI arbitration parking */
+#define PSYCHO_PCICTRL_RESV3 0x00000000001ff800 /* Reserved */
+#define PSYCHO_PCICTRL_SBH_INT 0x0000000000000400 /* Streaming byte hole int enab */
+#define PSYCHO_PCICTRL_WEN 0x0000000000000200 /* Power Mgmt Wake Enable */
+#define PSYCHO_PCICTRL_EEN 0x0000000000000100 /* PCI Error Interrupt Enable */
+#define PSYCHO_PCICTRL_RESV4 0x00000000000000c0 /* Reserved */
+#define PSYCHO_PCICTRL_AEN 0x000000000000003f /* PCI DVMA Arbitration Enable */
+
+/* PSYCHO PCI AFSR, AFAR holds low 40 bits of physical address causing the fault. */
+#define PSYCHO_PCIAFSR_PMA 0x8000000000000000 /* Primary Master Abort Error */
+#define PSYCHO_PCIAFSR_PTA 0x4000000000000000 /* Primary Target Abort Error */
+#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000 /* Primary Excessive Retries */
+#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000 /* Primary Parity Error */
+#define PSYCHO_PCIAFSR_SMA 0x0800000000000000 /* Secondary Master Abort Error */
+#define PSYCHO_PCIAFSR_STA 0x0400000000000000 /* Secondary Target Abort Error */
+#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000 /* Secondary Excessive Retries */
+#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000 /* Secondary Parity Error */
+#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000 /* Reserved */
+#define PSYCHO_PCIAFSR_SIZE 0x0000ffff00000000 /* Bytemask of failed transfer */
+#define PSYCHO_PCIAFSR_BLK 0x0000000080000000 /* Trans was block operation */
+#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000 /* Reserved */
+#define PSYCHO_PCIAFSR_MID 0x000000003e000000 /* MID causing the error */
+#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffff /* Reserved */
+
+/* IOMMU things defined fully in asm-sparc64/iommu.h */
+
+/* Streaming Buffer Control Register */
+#define PSYCHO_SBUFCTRL_RESV 0xffffffffffffff80 /* Reserved */
+#define PSYCHO_SBUFCTRL_LRU_LP 0x0000000000000070 /* LRU Lock Pointer */
+#define PSYCHO_SBUFCTRL_LRU_LE 0x0000000000000008 /* LRU Lock Enable */
+#define PSYCHO_SBUFCTRL_RR_DIS 0x0000000000000004 /* Rerun Disable */
+#define PSYCHO_SBUFCTRL_DE 0x0000000000000002 /* Diag Mode Enable */
+#define PSYCHO_SBUFCTRL_SB_EN 0x0000000000000001 /* Streaming Buffer Enable */
+
+/* Streaming Buffer Page Invalidate/Flush Register */
+#define PSYCHO_SBUFFLUSH_ADDR 0x00000000ffffe000 /* DVMA Page to be flushed */
+#define PSYCHO_SBUFFLUSH_RESV 0x0000000000001fff /* Ignored bits */
+
+/* Streaming Buffer Flush Synchronization Register */
+#define PSYCHO_SBUFSYNC_ADDR 0x000001ffffffffc0 /* Physical address to update */
+#define PSYCHO_SBUFSYNC_RESV 0x000000000000003f /* Ignored bits */
+
+/* PSYCHO Interrupt mapping register(s). */
+#define PSYCHO_IMAP_RESV1 0xffffffff00000000 /* Reserved */
+#define PSYCHO_IMAP_VALID 0x0000000080000000 /* This enables delivery. */
+#define PSYCHO_IMAP_TID 0x000000007c000000 /* Target ID (MID to send it to)*/
+#define PSYCHO_IMAP_RESV2 0x0000000003fff800 /* Reserved */
+#define PSYCHO_IMAP_IGN 0x00000000000007c0 /* Interrupt Group Number. */
+#define PSYCHO_IMAP_INO 0x000000000000003f /* Interrupt Number Offset. */
+#define PSYCHO_IMAP_INR 0x00000000000007ff /* Interrupt # (Gfx/UPA_slave) */
+
+/* PSYCHO Interrupt clear pseudo register(s). */
+#define PSYCHO_ICLR_RESV1 0xfffffffffffffff0 /* Reserved */
+#define PSYCHO_ICLR_IDLE 0x0000000000000000 /* Transition to idle state. */
+#define PSYCHO_ICLR_TRANSMIT 0x0000000000000001 /* Transition to transmit state */
+#define PSYCHO_ICLR_RESV2 0x0000000000000002 /* Reserved. */
+#define PSYCHO_ICLR_PENDING 0x0000000000000003 /* Transition to pending state. */
+
+/* PSYCHO Interrupt Retry Timer register. */
+#define PSYCHO_IRETRY_LIMIT 0x00000000000fffff /* The retry interval. */
+
+/* PSYCHO Interrupt State registers. XXX fields to be documented later */
+
+/* PSYCHO Counter register. XXX fields to be documented later */
+
+/* PSYCHO Limit register. XXX fields to be documented later */
+
+/* PSYCHO Performance Monitor Control register. XXX fields to be documented later */
+
+/* PSYCHO Performance Monitor Counter register. XXX fields to be documented later */
+
+#endif /* !(__SPARC64_PSYCHO_H) */
--- /dev/null
+/* $Id: sab82532.h,v 1.2 1997/08/12 04:13:15 ecd Exp $
+ * sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#ifndef _SPARC64_SAB82532_H
+#define _SPARC64_SAB82532_H
+
+#include <linux/types.h>
+#include <linux/serial.h>
+
+struct sab82532_async_rd_regs {
+ u8 rfifo[0x20]; /* Receive FIFO */
+ u8 star; /* Status Register */
+ u8 __pad1;
+ u8 mode; /* Mode Register */
+ u8 timr; /* Timer Register */
+ u8 xon; /* XON Character */
+ u8 xoff; /* XOFF Character */
+ u8 tcr; /* Termination Character Register */
+ u8 dafo; /* Data Format */
+ u8 rfc; /* RFIFO Control Register */
+ u8 __pad2;
+ u8 rbcl; /* Receive Byte Count Low */
+ u8 rbch; /* Receive Byte Count High */
+ u8 ccr0; /* Channel Configuration Register 0 */
+ u8 ccr1; /* Channel Configuration Register 1 */
+ u8 ccr2; /* Channel Configuration Register 2 */
+ u8 ccr3; /* Channel Configuration Register 3 */
+ u8 __pad3[4];
+ u8 vstr; /* Version Status Register */
+ u8 __pad4[3];
+ u8 gis; /* Global Interrupt Status */
+ u8 ipc; /* Interrupt Port Configuration */
+ u8 isr0; /* Interrupt Status 0 */
+ u8 isr1; /* Interrupt Status 1 */
+ u8 pvr; /* Port Value Register */
+ u8 pis; /* Port Interrupt Status */
+ u8 pcr; /* Port Configuration Register */
+ u8 ccr4; /* Channel Configuration Register 4 */
+};
+
+struct sab82532_async_wr_regs {
+ u8 xfifo[0x20]; /* Transmit FIFO */
+ u8 cmdr; /* Command Register */
+ u8 __pad1;
+ u8 mode;
+ u8 timr;
+ u8 xon;
+ u8 xoff;
+ u8 tcr;
+ u8 dafo;
+ u8 rfc;
+ u8 __pad2;
+ u8 xbcl; /* Transmit Byte Count Low */
+ u8 xbch; /* Transmit Byte Count High */
+ u8 ccr0;
+ u8 ccr1;
+ u8 ccr2;
+ u8 ccr3;
+ u8 tsax; /* Time-Slot Assignment Reg. Transmit */
+ u8 tsar; /* Time-Slot Assignment Reg. Receive */
+ u8 xccr; /* Transmit Channel Capacity Register */
+ u8 rccr; /* Receive Channel Capacity Register */
+ u8 bgr; /* Baud Rate Generator Register */
+ u8 tic; /* Transmit Immediate Character */
+ u8 mxn; /* Mask XON Character */
+ u8 mxf; /* Mask XOFF Character */
+ u8 iva; /* Interrupt Vector Address */
+ u8 ipc;
+ u8 imr0; /* Interrupt Mask Register 0 */
+ u8 imr1; /* Interrupt Mask Register 1 */
+ u8 pvr;
+ u8 pim; /* Port Interrupt Mask */
+ u8 pcr;
+ u8 ccr4;
+};
+
+struct sab82532_async_rw_regs { /* Read/Write registers */
+ u8 __pad1[0x20];
+ u8 __pad2;
+ u8 __pad3;
+ u8 mode;
+ u8 timr;
+ u8 xon;
+ u8 xoff;
+ u8 tcr;
+ u8 dafo;
+ u8 rfc;
+ u8 __pad4;
+ u8 __pad5;
+ u8 __pad6;
+ u8 ccr0;
+ u8 ccr1;
+ u8 ccr2;
+ u8 ccr3;
+ u8 __pad7;
+ u8 __pad8;
+ u8 __pad9;
+ u8 __pad10;
+ u8 __pad11;
+ u8 __pad12;
+ u8 __pad13;
+ u8 __pad14;
+ u8 __pad15;
+ u8 ipc;
+ u8 __pad16;
+ u8 __pad17;
+ u8 pvr;
+ u8 __pad18;
+ u8 pcr;
+ u8 ccr4;
+};
+
+union sab82532_async_regs {
+ __volatile__ struct sab82532_async_rd_regs r;
+ __volatile__ struct sab82532_async_wr_regs w;
+ __volatile__ struct sab82532_async_rw_regs rw;
+};
+
+#define NR_PORTS 2
+
+union sab82532_irq_status {
+ unsigned long stat;
+ struct {
+ unsigned char isr0;
+ unsigned char isr1;
+ unsigned char ddsr;
+ } sreg;
+};
+
+struct sab82532 {
+ int magic;
+ int baud_base;
+ union sab82532_async_regs *regs;
+ int irq;
+ int flags; /* defined in tty.h */
+ int type; /* SAB82532 version */
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int timeout;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int quot;
+ int x_char;
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ int all_sent;
+ int is_console;
+ unsigned char interrupt_mask0;
+ unsigned char interrupt_mask1;
+ unsigned char pvr_dtr_bit;
+ unsigned char pvr_dsr_bit;
+ unsigned long event;
+ unsigned long last_active;
+ int line;
+ int count;
+ int blocked_open;
+ long session;
+ long pgrp;
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ struct tq_struct tqueue;
+ struct tq_struct tqueue_hangup;
+ struct async_icount icount;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct wait_queue *delta_msr_wait;
+ struct sab82532 *next;
+ struct sab82532 *prev;
+};
+
+
+/* RFIFO Status Byte */
+#define SAB82532_RSTAT_PE 0x80
+#define SAB82532_RSTAT_FE 0x40
+#define SAB82532_RSTAT_PARITY 0x01
+
+/* Status Register (STAR) */
+#define SAB82532_STAR_XDOV 0x80
+#define SAB82532_STAR_XFW 0x40
+#define SAB82532_STAR_RFNE 0x20
+#define SAB82532_STAR_FCS 0x10
+#define SAB82532_STAR_TEC 0x08
+#define SAB82532_STAR_CEC 0x04
+#define SAB82532_STAR_CTS 0x02
+
+/* Command Register (CMDR) */
+#define SAB82532_CMDR_RMC 0x80
+#define SAB82532_CMDR_RRES 0x40
+#define SAB82532_CMDR_RFRD 0x20
+#define SAB82532_CMDR_STI 0x10
+#define SAB82532_CMDR_XF 0x08
+#define SAB82532_CMDR_XRES 0x01
+
+/* Mode Register (MODE) */
+#define SAB82532_MODE_FRTS 0x40
+#define SAB82532_MODE_FCTS 0x20
+#define SAB82532_MODE_FLON 0x10
+#define SAB82532_MODE_RAC 0x08
+#define SAB82532_MODE_RTS 0x04
+#define SAB82532_MODE_TRS 0x02
+#define SAB82532_MODE_TLP 0x01
+
+/* Timer Register (TIMR) */
+#define SAB82532_TIMR_CNT_MASK 0xe0
+#define SAB82532_TIMR_VALUE_MASK 0x1f
+
+/* Data Format (DAFO) */
+#define SAB82532_DAFO_XBRK 0x40
+#define SAB82532_DAFO_STOP 0x20
+#define SAB82532_DAFO_PAR_SPACE 0x00
+#define SAB82532_DAFO_PAR_ODD 0x08
+#define SAB82532_DAFO_PAR_EVEN 0x10
+#define SAB82532_DAFO_PAR_MARK 0x18
+#define SAB82532_DAFO_PARE 0x04
+#define SAB82532_DAFO_CHL8 0x00
+#define SAB82532_DAFO_CHL7 0x01
+#define SAB82532_DAFO_CHL6 0x02
+#define SAB82532_DAFO_CHL5 0x03
+
+/* RFIFO Control Register (RFC) */
+#define SAB82532_RFC_DPS 0x40
+#define SAB82532_RFC_DXS 0x20
+#define SAB82532_RFC_RFDF 0x10
+#define SAB82532_RFC_RFTH_1 0x00
+#define SAB82532_RFC_RFTH_4 0x04
+#define SAB82532_RFC_RFTH_16 0x08
+#define SAB82532_RFC_RFTH_32 0x0c
+#define SAB82532_RFC_TCDE 0x01
+
+/* Received Byte Count High (RBCH) */
+#define SAB82532_RBCH_DMA 0x80
+#define SAB82532_RBCH_CAS 0x20
+
+/* Transmit Byte Count High (XBCH) */
+#define SAB82532_XBCH_DMA 0x80
+#define SAB82532_XBCH_CAS 0x20
+#define SAB82532_XBCH_XC 0x10
+
+/* Channel Configuration Register 0 (CCR0) */
+#define SAB82532_CCR0_PU 0x80
+#define SAB82532_CCR0_MCE 0x40
+#define SAB82532_CCR0_SC_NRZ 0x00
+#define SAB82532_CCR0_SC_NRZI 0x08
+#define SAB82532_CCR0_SC_FM0 0x10
+#define SAB82532_CCR0_SC_FM1 0x14
+#define SAB82532_CCR0_SC_MANCH 0x18
+#define SAB82532_CCR0_SM_HDLC 0x00
+#define SAB82532_CCR0_SM_SDLC_LOOP 0x01
+#define SAB82532_CCR0_SM_BISYNC 0x02
+#define SAB82532_CCR0_SM_ASYNC 0x03
+
+/* Channel Configuration Register 1 (CCR1) */
+#define SAB82532_CCR1_ODS 0x10
+#define SAB82532_CCR1_BCR 0x08
+#define SAB82532_CCR1_CM_MASK 0x07
+
+/* Channel Configuration Register 2 (CCR2) */
+#define SAB82532_CCR2_SOC1 0x80
+#define SAB82532_CCR2_SOC0 0x40
+#define SAB82532_CCR2_BR9 0x80
+#define SAB82532_CCR2_BR8 0x40
+#define SAB82532_CCR2_BDF 0x20
+#define SAB82532_CCR2_SSEL 0x10
+#define SAB82532_CCR2_XCS0 0x20
+#define SAB82532_CCR2_RCS0 0x10
+#define SAB82532_CCR2_TOE 0x08
+#define SAB82532_CCR2_RWX 0x04
+#define SAB82532_CCR2_DIV 0x01
+
+/* Channel Configuration Register 3 (CCR3) */
+#define SAB82532_CCR3_PSD 0x01
+
+/* Time Slot Assignment Register Transmit (TSAX) */
+#define SAB82532_TSAX_TSNX_MASK 0xfc
+#define SAB82532_TSAX_XCS2 0x02 /* see also CCR2 */
+#define SAB82532_TSAX_XCS1 0x01
+
+/* Time Slot Assignment Register Receive (TSAR) */
+#define SAB82532_TSAR_TSNR_MASK 0xfc
+#define SAB82532_TSAR_RCS2 0x02 /* see also CCR2 */
+#define SAB82532_TSAR_RCS1 0x01
+
+/* Version Status Register (VSTR) */
+#define SAB82532_VSTR_CD 0x80
+#define SAB82532_VSTR_DPLA 0x40
+#define SAB82532_VSTR_VN_MASK 0x0f
+#define SAB82532_VSTR_VN_1 0x00
+#define SAB82532_VSTR_VN_2 0x01
+#define SAB82532_VSTR_VN_3_2 0x02
+
+/* Global Interrupt Status Register (GIS) */
+#define SAB82532_GIS_PI 0x80
+#define SAB82532_GIS_ISA1 0x08
+#define SAB82532_GIS_ISA0 0x04
+#define SAB82532_GIS_ISB1 0x02
+#define SAB82532_GIS_ISB0 0x01
+
+/* Interrupt Vector Address (IVA) */
+#define SAB82532_IVA_MASK 0xf1
+
+/* Interrupt Port Configuration (IPC) */
+#define SAB82532_IPC_VIS 0x80
+#define SAB82532_IPC_SLA1 0x10
+#define SAB82532_IPC_SLA0 0x08
+#define SAB82532_IPC_CASM 0x04
+#define SAB82532_IPC_IC_OPEN_DRAIN 0x00
+#define SAB82532_IPC_IC_ACT_LOW 0x01
+#define SAB82532_IPC_IC_ACT_HIGH 0x03
+
+/* Interrupt Status Register 0 (ISR0) */
+#define SAB82532_ISR0_TCD 0x80
+#define SAB82532_ISR0_TIME 0x40
+#define SAB82532_ISR0_PERR 0x20
+#define SAB82532_ISR0_FERR 0x10
+#define SAB82532_ISR0_PLLA 0x08
+#define SAB82532_ISR0_CDSC 0x04
+#define SAB82532_ISR0_RFO 0x02
+#define SAB82532_ISR0_RPF 0x01
+
+/* Interrupt Status Register 1 (ISR1) */
+#define SAB82532_ISR1_BRK 0x80
+#define SAB82532_ISR1_BRKT 0x40
+#define SAB82532_ISR1_ALLS 0x20
+#define SAB82532_ISR1_XOFF 0x10
+#define SAB82532_ISR1_TIN 0x08
+#define SAB82532_ISR1_CSC 0x04
+#define SAB82532_ISR1_XON 0x02
+#define SAB82532_ISR1_XPR 0x01
+
+/* Interrupt Mask Register 0 (IMR0) */
+#define SAB82532_IMR0_TCD 0x80
+#define SAB82532_IMR0_PERR 0x20
+#define SAB82532_IMR0_SCD 0x10
+#define SAB82532_IMR0_PLLA 0x08
+#define SAB82532_IMR0_CDSC 0x04
+#define SAB82532_IMR0_RFO 0x02
+#define SAB82532_IMR0_RPF 0x01
+#define SAB82532_IMR0_OR_ME_IN 0x40
+
+/* Interrupt Mask Register 1 (IMR1) */
+#define SAB82532_IMR1_ALLS 0x20
+#define SAB82532_IMR1_XDU 0x10
+#define SAB82532_IMR1_TIN 0x08
+#define SAB82532_IMR1_CSC 0x04
+#define SAB82532_IMR1_XMR 0x02
+#define SAB82532_IMR1_XPR 0x01
+#define SAB82532_IMR1_OR_ME_IN 0xc0
+
+/* Port Interrupt Status Register (PIS) */
+#define SAB82532_PIS_SYNC_B 0x08
+#define SAB82532_PIS_DTR_B 0x04
+#define SAB82532_PIS_DTR_A 0x02
+#define SAB82532_PIS_SYNC_A 0x01
+
+/* Channel Configuration Register 4 (CCR4) */
+#define SAB82532_CCR4_MCK4 0x80
+#define SAB82532_CCR4_EBRG 0x40
+#define SAB82532_CCR4_TST1 0x20
+#define SAB82532_CCR4_ICD 0x10
+
+
+#endif /* !(_SPARC64_SAB82532_H) */
-/* $Id: sbus.h,v 1.3 1997/03/21 17:57:24 jj Exp $
+/* $Id: sbus.h,v 1.5 1997/08/12 04:13:16 ecd Exp $
* sbus.h: Defines for the Sun SBus.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
for((device) = (bus)->devices; (device); (device)=(device)->next)
#define for_all_sbusdev(device, bus) \
- for((bus) = SBus_chain, (device) = (bus)->devices; (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
-
-/* XXX This is promlib stuff, what is it doing here? XXX */
+ for((bus) = SBus_chain, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
/* Apply promlib probed SBUS ranges to registers. */
extern void prom_apply_sbus_ranges(struct linux_sbus *sbus,
extern __inline__ void down(struct semaphore * sem)
{
- if (atomic_dec_return(&sem->count) < 0)
+ int result;
+
+ result = atomic_dec_return(&sem->count);
+ membar("#StoreLoad | #StoreStore");
+ if (result < 0)
__down(sem);
}
extern __inline__ int down_interruptible(struct semaphore *sem)
{
- int ret = 0;
- if (atomic_dec_return(&sem->count) < 0)
+ int result, ret = 0;
+
+ result = atomic_dec_return(&sem->count);
+ membar("#StoreLoad | #StoreStore");
+ if (result < 0)
ret = __down_interruptible(sem);
return ret;
}
extern __inline__ void up(struct semaphore * sem)
{
+ membar("#StoreStore | #LoadStore");
if (atomic_inc_return(&sem->count) <= 0)
__up(sem);
}
-/* $Id: shmparam.h,v 1.1 1996/12/26 14:22:36 davem Exp $ */
+/* $Id: shmparam.h,v 1.2 1997/08/04 16:16:55 davem Exp $ */
#ifndef _ASMSPARC64_SHMPARAM_H
#define _ASMSPARC64_SHMPARAM_H
#define SHMMNI (1<<_SHM_ID_BITS) /* max num of segs system wide */
#define SHMALL /* max shm system wide (pages) */ \
(1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
-#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
+#define SHMLBA (PAGE_SIZE<<1) /* attach addr a multiple of this */
#define SHMSEG SHMMNI /* max shared segs per process */
#endif /* _ASMSPARC64_SHMPARAM_H */
#ifndef _SPARC64_SMP_H
#define _SPARC64_SMP_H
+#include <linux/tasks.h>
#include <asm/asi.h>
#ifndef __ASSEMBLY__
/* Per processor Sparc parameters we need. */
+/* Keep this a multiple of 64-bytes for cache reasons. */
struct cpuinfo_sparc {
- unsigned long udelay_val; /* that's it */
+ /* Dcache line 1 */
+ unsigned long irq_count;
+ unsigned int multiplier;
+ unsigned int counter;
+ unsigned long last_tlbversion_seen;
+ unsigned long pgcache_size;
+
+ /* Dcache line 2 */
+ unsigned long *pgd_cache;
+ unsigned long *pmd_cache;
+ unsigned long *pte_cache;
+ unsigned long udelay_val;
};
extern struct cpuinfo_sparc cpu_data[NR_CPUS];
* Private routines/data
*/
-extern int smp_found_cpus;
extern unsigned char boot_cpu_id;
extern unsigned long cpu_present_map;
-extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS];
-extern __volatile__ unsigned long kernel_counter;
-extern __volatile__ unsigned char active_kernel_processor;
-extern void smp_message_irq(void);
-extern unsigned long ipi_count;
-extern __volatile__ unsigned long kernel_counter;
-extern __volatile__ unsigned long syscall_count;
-
-extern void print_lock_state(void);
-
-typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
- unsigned long, unsigned long);
/*
* General functions that each host system must provide.
#define smp_processor_id() (current->processor)
-extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
#endif /* !(__ASSEMBLY__) */
-/* Sparc specific messages. */
-#define MSG_CROSS_CALL 0x0005 /* run func on cpus */
-
-/* Empirical PROM processor mailbox constants. If the per-cpu mailbox
- * contains something other than one of these then the ipi is from
- * Linux's active_kernel_processor. This facility exists so that
- * the boot monitor can capture all the other cpus when one catches
- * a watchdog reset or the user enters the monitor using L1-A keys.
- */
-#define MBOX_STOPCPU 0xFB
-#define MBOX_IDLECPU 0xFC
-#define MBOX_IDLECPU2 0xFD
-#define MBOX_STOPCPU2 0xFE
-
-#define PROC_CHANGE_PENALTY 20
-
-#define SMP_FROM_INT 1
-#define SMP_FROM_SYSCALL 2
+#define PROC_CHANGE_PENALTY 20
#endif /* !(__SMP__) */
-#define NO_PROC_ID 0xFF
+#define NO_PROC_ID 0xFF
#endif /* !(_SPARC64_SMP_H) */
__cli(); \
(task)->lock_depth = 0; \
klock_info.akp = NO_PROC_ID; \
+ membar("#LoadStore | #StoreStore"); \
klock_info.kernel_flag = 0; \
} \
release_irqlock(cpu); \
" mov %1, %%g2" \
: /* No outputs. */ \
: "r" (klip), "r" (depth) \
- : "g2", "g3", "g5", "g7", "memory", "cc"); \
+ : "g2", "g3", "g5", "memory", "cc"); \
} \
} while(0)
__asm__ __volatile__("
mov %%o7, %%g5
call ___lock_kernel
- ld [%%g6 + %0], %%g2
+ lduw [%%g6 + %0], %%g2
" : : "i" (AOFF_task_lock_depth), "r" (klip)
- : "g2", "g3", "g5", "g7", "memory", "cc");
+ : "g2", "g3", "g5", "memory", "cc");
}
/* Release kernel global lock. */
__asm__ __volatile__("
mov %%o7, %%g5
call ___unlock_kernel
- ld [%%g6 + %0], %%g2
+ lduw [%%g6 + %0], %%g2
" : : "i" (AOFF_task_lock_depth), "r" (klip)
: "g2", "g3", "g5", "memory", "cc");
}
typedef unsigned char spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
-#define spin_lock_init(lock) (*(lock) = 0)
-#define spin_unlock_wait(lock) do { barrier(); } while(*(volatile spinlock_t *)lock)
+
+#define spin_lock_init(lock) (*((unsigned char *)(lock)) = 0)
+
+#define spin_unlock_wait(lock) \
+do { membar("#LoadLoad"); \
+} while(*((volatile unsigned char *)lock))
extern __inline__ void spin_lock(spinlock_t *lock)
{
__asm__ __volatile__("
-1: ldstub [%0], %%g2
- brz,pt %%g2, 2f
- membar #LoadLoad | #LoadStore
- b,a %%xcc, 3f
-2:
- .text 2
-3: ldub [%0], %%g2
-4: brnz,a,pt %%g2, 4b
- ldub [%0], %%g2
- b,a 1b
+1: ldstub [%0], %%g7
+ brnz,pn %%g7, 2f
+ membar #StoreLoad | #StoreStore
+ .subsection 2
+2: ldub [%0], %%g7
+ brnz,pt %%g7, 2b
+ membar #LoadLoad
+ b,a,pt %%xcc, 1b
.previous
" : /* no outputs */
: "r" (lock)
- : "g2", "memory");
+ : "g7", "memory");
}
extern __inline__ int spin_trylock(spinlock_t *lock)
{
unsigned int result;
__asm__ __volatile__("ldstub [%1], %0\n\t"
- "membar #LoadLoad | #LoadStore"
+ "membar #StoreLoad | #StoreStore"
: "=r" (result)
: "r" (lock)
: "memory");
extern __inline__ void spin_unlock(spinlock_t *lock)
{
__asm__ __volatile__("membar #StoreStore | #LoadStore\n\t"
- "stb %%g0, [%0]"
+ "stb %%g0, [%0]\n\t"
: /* No outputs */
: "r" (lock)
: "memory");
{
__asm__ __volatile__("
wrpr %%g0, 15, %%pil
-1: ldstub [%0], %%g2
- brz,pt %%g2, 2f
- membar #LoadLoad | #LoadStore
- b,a 3f
-2:
- .text 2
-3: ldub [%0], %%g2
-4: brnz,a,pt %%g2, 4b
- ldub [%0], %%g2
- b,a 1b
+1: ldstub [%0], %%g7
+ brnz,pn %%g7, 2f
+ membar #StoreLoad | #StoreStore
+ .subsection 2
+2: ldub [%0], %%g7
+ brnz,pt %%g7, 2b
+ membar #LoadLoad
+ b,a,pt %%xcc, 1b
.previous
" : /* no outputs */
: "r" (lock)
- : "g2", "memory");
+ : "g7", "memory");
}
extern __inline__ void spin_unlock_irq(spinlock_t *lock)
__asm__ __volatile__( \
"\n rdpr %%pil, %0\n" \
" wrpr %%g0, 15, %%pil\n" \
- "1: ldstub [%1], %%g2\n" \
- " brz,pt %%g2, 2f\n" \
- " membar #LoadLoad | #LoadStore\n" \
- " b,a 3f\n" \
- "2:\n" \
- " .text 2\n" \
- "3: ldub [%1], %%g2\n" \
- "4: brnz,a,pt %%g2, 4b\n" \
- " ldub [%1], %%g2\n" \
- " b,a 1b\n" \
+ "1: ldstub [%1], %%g7\n" \
+ " brnz,pn %%g7, 2f\n" \
+ " membar #StoreLoad | #StoreStore\n" \
+ " .subsection 2\n" \
+ "2: ldub [%1], %%g7\n" \
+ " brnz,pt %%g7, 2b\n" \
+ " membar #LoadLoad\n" \
+ " b,a,pt %%xcc, 1b\n" \
" .previous\n" \
: "=&r" (flags) \
: "r" (lp) \
- : "g2", "memory"); \
+ : "g7", "memory"); \
} while(0)
extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
extern __inline__ void read_lock(rwlock_t *rw)
{
__asm__ __volatile__("
- ldx [%0], %%g2
-1: brgez,pt %%g2, 4f
- add %%g2, 1, %%g3
- b,a 2f
-4: casx [%0], %%g2, %%g3
- cmp %%g2, %%g3
- bne,a,pn %%xcc, 1b
- ldx [%0], %%g2
- membar #LoadLoad | #LoadStore
- .text 2
-2: ldx [%0], %%g2
-3: brlz,a,pt %%g2, 3b
- ldx [%0], %%g2
- b 4b
- add %%g2, 1, %%g3
+1: ldx [%0], %%g5
+ brlz,pn %%g5, 2f
+4: add %%g5, 1, %%g7
+ casx [%0], %%g5, %%g7
+ cmp %%g5, %%g7
+ bne,pn %%xcc, 1b
+ membar #StoreLoad | #StoreStore
+ .subsection 2
+2: ldx [%0], %%g5
+ brlz,pt %%g5, 2b
+ membar #LoadLoad
+ b,a,pt %%xcc, 4b
.previous
" : /* no outputs */
: "r" (rw)
- : "g2", "g3", "cc", "memory");
+ : "g5", "g7", "cc", "memory");
}
extern __inline__ void read_unlock(rwlock_t *rw)
{
__asm__ __volatile__("
- membar #StoreStore | #LoadStore
- ldx [%0], %%g2
-1: sub %%g2, 1, %%g3
- casx [%0], %%g2, %%g3
- cmp %%g2, %%g3
- bne,a,pn %%xcc, 1b
- ldx [%0], %%g2
+1: ldx [%0], %%g5
+ sub %%g5, 1, %%g7
+ casx [%0], %%g5, %%g7
+ cmp %%g5, %%g7
+ bne,pn %%xcc, 1b
+ membar #StoreLoad | #StoreStore
" : /* no outputs */
: "r" (rw)
- : "g2", "g3", "cc", "memory");
+ : "g5", "g7", "cc", "memory");
}
extern __inline__ void write_lock(rwlock_t *rw)
{
__asm__ __volatile__("
- sethi %%uhi(0x8000000000000000), %%g5
- ldx [%0], %%g2
- sllx %%g5, 32, %%g5
-1: brgez,pt %%g2, 4f
- or %%g2, %%g5, %%g3
- b,a 5f
-4: casx [%0], %%g2, %%g3
- cmp %%g2, %%g3
- bne,a,pn %%xcc, 1b
- ldx [%0], %%g2
- andncc %%g3, %%g5, %%g0
- be,pt %%xcc, 2f
- membar #LoadLoad | #LoadStore
- b,a 7f
-2:
- .text 2
-7: ldx [%0], %%g2
-3: andn %%g2, %%g5, %%g3
- casx [%0], %%g2, %%g3
- cmp %%g2, %%g3
- bne,a,pn %%xcc, 3b
- ldx [%0], %%g2
- membar #LoadLoad | #LoadStore
-5: ldx [%0], %%g2
-6: brlz,a,pt %%g2, 6b
- ldx [%0], %%g2
- b 4b
- or %%g2, %%g5, %%g3
+ sethi %%uhi(0x8000000000000000), %%g3
+ sllx %%g3, 32, %%g3
+1: ldx [%0], %%g5
+ brlz,pn %%g5, 5f
+4: or %%g5, %%g3, %%g7
+ casx [%0], %%g5, %%g7
+ cmp %%g5, %%g7
+ bne,pn %%xcc, 1b
+ andncc %%g7, %%g3, %%g0
+ bne,pn %%xcc, 7f
+ membar #StoreLoad | #StoreStore
+ .subsection 2
+7: ldx [%0], %%g5
+ andn %%g5, %%g3, %%g7
+ casx [%0], %%g5, %%g7
+ cmp %%g5, %%g7
+ bne,pn %%xcc, 7b
+ membar #StoreLoad | #StoreStore
+5: ldx [%0], %%g5
+ brnz,pt %%g5, 5b
+ membar #LoadLoad
+ b,a,pt %%xcc, 4b
.previous
" : /* no outputs */
: "r" (rw)
- : "g2", "g3", "g5", "memory", "cc");
+ : "g3", "g5", "g7", "memory", "cc");
}
extern __inline__ void write_unlock(rwlock_t *rw)
{
__asm__ __volatile__("
- membar #StoreStore | #LoadStore
- sethi %%uhi(0x8000000000000000), %%g5
- ldx [%0], %%g2
- sllx %%g5, 32, %%g5
-1: andn %%g2, %%g5, %%g3
- casx [%0], %%g2, %%g3
- cmp %%g2, %%g3
- bne,a,pn %%xcc, 1b
- ldx [%0], %%g2
+ sethi %%uhi(0x8000000000000000), %%g3
+ sllx %%g3, 32, %%g3
+1: ldx [%0], %%g5
+ andn %%g5, %%g3, %%g7
+ casx [%0], %%g5, %%g7
+ cmp %%g5, %%g7
+ bne,pn %%xcc, 1b
+ membar #StoreLoad | #StoreStore
" : /* no outputs */
: "r" (rw)
- : "g2", "g3", "g5", "memory", "cc");
+ : "g3", "g5", "g7", "memory", "cc");
}
#define read_lock_irq(lock) do { __cli(); read_lock(lock); } while (0)
-/* $Id: sysio.h,v 1.2 1997/04/03 12:26:45 davem Exp $
+/* $Id: sysio.h,v 1.6 1997/08/15 06:44:53 davem Exp $
* sysio.h: UltraSparc sun5 specific SBUS definitions.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
* slot 5) MACIO
* slot 6) SLAVIO
*
- * On Sunfire/Wildfire enterprise boxen these upper slots
+ * On Sunfire/Starfire/Wildfire enterprise boxen these upper slots
* are unused.
*/
/*0x2020*/ u64 sbus_s0cfg; /* SBUS Slot 0 Config */
/* SBUS/IOMMU Streaming Buffer Registers */
/*0x2800*/ u64 sbuf_control; /* StrBuffer Control */
/*0x2808*/ u64 sbuf_pflush; /* StrBuffer Page Flush */
-/*0x2810*/ u64 sbus_fsync; /* StrBuffer Flush Synchronization Reg */
+/*0x2810*/ u64 sbuf_fsync; /* StrBuffer Flush Synchronization Reg */
u64 __pad4[0x7d];
/* Interrupt mapping/control registers */
-/*0x2c00*/ u32 imap_slot0, _uim0; /* SBUS Slot 0 Int Mapping */
-/*0x2c08*/ u32 imap_slot1, _uim1; /* SBUS Slot 1 Int Mapping */
-/*0x2c10*/ u32 imap_slot2, _uim2; /* SBUS Slot 2 Int Mapping */
-/*0x2c18*/ u32 imap_slot3, _uim3; /* SBUS Slot 3 Int Mapping */
+/*0x2c00*/ u32 _uim0, imap_slot0; /* SBUS Slot 0 Int Mapping */
+/*0x2c08*/ u32 _uim1, imap_slot1; /* SBUS Slot 1 Int Mapping */
+/*0x2c10*/ u32 _uim2, imap_slot2; /* SBUS Slot 2 Int Mapping */
+/*0x2c18*/ u32 _uim3, imap_slot3; /* SBUS Slot 3 Int Mapping */
/* Interrupt Retry Timer. */
-/*0x2c20*/ u32 irq_retry, _irpad;
+/*0x2c20*/ u32 _irpad, irq_retry;
u64 __pad5[0x7b];
/* The following are only used on Fusion/Electron/Pulsar
- * desktop systems, they mean nothing on Sunfire/Wildfire
+ * desktop systems, they mean nothing on Sunfire/Starfire/Wildfire
*/
-/*0x3000*/ u32 imap_scsi, _uis; /* SCSI Int Mapping */
-/*0x3008*/ u32 imap_eth, _uie; /* Ethernet Int Mapping */
-/*0x3010*/ u32 imap_bpp, _uip; /* Parallel Port Int Mapping */
-/*0x3018*/ u32 imap_audio, _uia; /* Audio Int Mapping */
-/*0x3020*/ u32 imap_pfail, _uipf; /* Power Fail Int Mapping */
-/*0x3028*/ u32 imap_kms, _uik; /* Kbd/Mouse/Serial Int Mapping */
-/*0x3030*/ u32 imap_flpy, _uif; /* Floppy Int Mapping */
-/*0x3038*/ u32 imap_shw, _uishw; /* Spare HW Int Mapping */
-/*0x3040*/ u32 imap_kbd, _uikbd; /* Kbd Only Int Mapping */
-/*0x3048*/ u32 imap_ms, _uims; /* Mouse Only Int Mapping */
-/*0x3050*/ u32 imap_ser, _uiser; /* Serial Only Int Mapping */
+/*0x3000*/ u32 _uis, imap_scsi; /* SCSI Int Mapping */
+/*0x3008*/ u32 _uie, imap_eth; /* Ethernet Int Mapping */
+/*0x3010*/ u32 _uip, imap_bpp; /* Parallel Port Int Mapping */
+/*0x3018*/ u32 _uia, imap_audio; /* Audio Int Mapping */
+/*0x3020*/ u32 _uipf, imap_pfail; /* Power Fail Int Mapping */
+/*0x3028*/ u32 _uik, imap_kms; /* Kbd/Mouse/Serial Int Mapping */
+/*0x3030*/ u32 _uif, imap_flpy; /* Floppy Int Mapping */
+/*0x3038*/ u32 _uishw, imap_shw; /* Spare HW Int Mapping */
+/*0x3040*/ u32 _uikbd, imap_kbd; /* Kbd Only Int Mapping */
+/*0x3048*/ u32 _uims, imap_ms; /* Mouse Only Int Mapping */
+/*0x3050*/ u32 _uiser, imap_ser; /* Serial Only Int Mapping */
/*0x3058*/ u64 _imap_unused;
-/*0x3060*/ u32 imap_tim0, _uit0; /* Timer 0 Int Mapping */
-/*0x3068*/ u32 imap_tim1, _uit1; /* Timer 1 Int Mapping */
-/*0x3070*/ u32 imap_ue, _uiue; /* UE Int Mapping */
-/*0x3078*/ u32 imap_ce, _uice; /* CE Int Mapping */
-/*0x3080*/ u32 imap_sberr, _uisbe; /* SBUS Err Int Mapping */
-/*0x3088*/ u32 imap_pmgmt, _uipm; /* Power Mgmt Int Mapping */
-/*0x3090*/ u32 imap_gfx, _uigfx; /* OB Graphics Int Mapping */
-/*0x3098*/ u32 imap_eupa, _uieupa; /* UPA Expansion Int Mapping */
+/*0x3060*/ u32 _uit0, imap_tim0; /* Timer 0 Int Mapping */
+/*0x3068*/ u32 _uit1, imap_tim1; /* Timer 1 Int Mapping */
+/*0x3070*/ u32 _uiue, imap_ue; /* UE Int Mapping */
+/*0x3078*/ u32 _uice, imap_ce; /* CE Int Mapping */
+/*0x3080*/ u32 _uisbe, imap_sberr; /* SBUS Err Int Mapping */
+/*0x3088*/ u32 _uipm, imap_pmgmt; /* Power Mgmt Int Mapping */
+/*0x3090*/ u32 _uigfx, imap_gfx; /* OB Graphics Int Mapping */
+/*0x3098*/ u32 _uieupa, imap_eupa; /* UPA Expansion Int Mapping */
u64 __pad6[0x6c];
/* Interrupt Clear Registers */
-/*0x3400*/ u64 iclr_unused0;
-/*0x3408*/ u32 iclr_slot0, _ucs0;
+/*0x3400*/ u32 __ucu0, iclr_unused0;
+/*0x3408*/ u32 _ucs0, iclr_slot0;
u64 __pad7[0x7];
-/*0x3448*/ u32 iclr_slot1, _ucs1;
+/*0x3448*/ u32 _ucs1, iclr_slot1;
u64 __pad8[0x7];
-/*0x3488*/ u32 iclr_slot2, _ucs2;
+/*0x3488*/ u32 _ucs2, iclr_slot2;
u64 __pad9[0x7];
-/*0x34c8*/ u32 iclr_slot3, _ucs3;
+/*0x34c8*/ u32 _ucs3, iclr_slot3;
u64 __pad10[0x66];
-/*0x3800*/ u32 iclr_scsi, _ucscsi;
-/*0x3808*/ u32 iclr_eth, _uceth;
-/*0x3810*/ u32 iclr_bpp, _ucbpp;
-/*0x3818*/ u32 iclr_audio, _ucaudio;
-/*0x3820*/ u32 iclr_pfail, _ucpfail;
-/*0x3828*/ u32 iclr_kms, _uckms;
-/*0x3830*/ u32 iclr_flpt, _ucflpy;
-/*0x3838*/ u32 iclr_shw, _ucshw;
-/*0x3840*/ u32 iclr_kbd, _uckbd;
-/*0x3848*/ u32 iclr_ms, _ucms;
-/*0x3850*/ u32 iclr_ser, _ucser;
+/*0x3800*/ u32 _ucscsi, iclr_scsi;
+/*0x3808*/ u32 _uceth, iclr_eth;
+/*0x3810*/ u32 _ucbpp, iclr_bpp;
+/*0x3818*/ u32 _ucaudio, iclr_audio;
+/*0x3820*/ u32 _ucpfail, iclr_pfail;
+/*0x3828*/ u32 _uckms, iclr_kms;
+/*0x3830*/ u32 _ucflpy, iclr_flpt;
+/*0x3838*/ u32 _ucshw, iclr_shw;
+/*0x3840*/ u32 _uckbd, iclr_kbd;
+/*0x3848*/ u32 _ucms, iclr_ms;
+/*0x3850*/ u32 _ucser, iclr_ser;
/*0x3858*/ u64 iclr_unused1;
-/*0x3860*/ u32 iclr_tim0, _uctim0;
-/*0x3868*/ u32 iclr_tim1, _uctim1;
-/*0x3870*/ u32 iclr_ue, _ucue;
-/*0x3878*/ u32 iclr_ce, _ucce;
-/*0x3880*/ u32 iclr_serr, _ucserr;
-/*0x3888*/ u32 iclr_pmgmt, _ucpmgmt;
+/*0x3860*/ u32 _uctim0, iclr_tim0;
+/*0x3868*/ u32 _uctim1, iclr_tim1;
+/*0x3870*/ u32 _ucue, iclr_ue;
+/*0x3878*/ u32 _ucce, iclr_ce;
+/*0x3880*/ u32 _ucserr, iclr_serr;
+/*0x3888*/ u32 _ucpmgmt, iclr_pmgmt;
u64 __pad11[0x6e];
/* Counters/Timers */
-/*0x3c00*/ u32 tim0_cnt, _tim0_u0;
-/*0x3c08*/ u32 tim0_lim, _tim0_u1;
-/*0x3c10*/ u32 tim1_cnt, _tim1_u0;
-/*0x3c18*/ u32 tim1_lim, _tim1_u1;
+/*0x3c00*/ u64 tim0_cnt;
+/*0x3c08*/ u64 tim0_lim;
+/*0x3c10*/ u64 tim1_cnt;
+/*0x3c18*/ u64 tim1_lim;
u64 __pad12[0x7c];
/*0x4580*/ u64 iommu_tag[16]; /* IOMMU TLB Tag Diagnostic Access */
/*0x4600*/ u64 iommu_data[32]; /* IOMMU TLB Data RAM Diagnostic Access */
+ u64 __pad15[0x20];
+
/* Interrupt State Diagnostics */
/*0x4800*/ u64 sbus_istate;
/*0x4808*/ u64 obio_istate;
- u64 __pad15[0xfe];
+ u64 __pad16[0xfe];
/* Streaming Buffer Diagnostic Area */
/*0x5000*/ u64 sbuf_data[128]; /* StrBuffer Data Ram Diagnostic */
-/* $Id: system.h,v 1.29 1997/07/24 16:48:32 davem Exp $ */
+/* $Id: system.h,v 1.35 1997/08/07 03:53:00 davem Exp $ */
#ifndef __SPARC64_SYSTEM_H
#define __SPARC64_SYSTEM_H
#include <asm/processor.h>
#include <asm/asm_offsets.h>
-#define NCPUS 4 /* No SMP yet */
-
#ifndef __ASSEMBLY__
/*
* Sparc (general) CPU types
#define membar(type) __asm__ __volatile__ ("membar " type : : : "memory");
-#define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr))
+#define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
#define flushw_all() __asm__ __volatile__("flushw")
* I do not clobber it, when in fact I do. Please,
* when modifying this code inspect output of sched.s very
* carefully to make sure things still work. -DaveM
+ *
+ * SMP NOTE: At first glance it looks like there is a tiny
+ * race window here at the end. The possible problem
+ * would be if a tlbcachesync MONDO vector got delivered
+ * to us right before we set the final %g6 thread reg
+ * value. But that is impossible since only the holder
+ * of scheduler_lock can send a tlbcachesync MONDO and
+ * by definition we hold it right now. Normal tlb
+ * flush xcalls can come in, but those are safe and do
+ * not reference %g6.
*/
#define switch_to(prev, next) \
do { __label__ switch_continue; \
"rdpr %%pstate, %%g2\n\t" \
"wrpr %%g2, 0x3, %%pstate\n\t" \
"flushw\n\t" \
-/*XXX*/ "wr %%g0, 0, %%fprs\n\t" \
"stx %%i6, [%%sp + 2047 + 0x70]\n\t" \
"stx %%i7, [%%sp + 2047 + 0x78]\n\t" \
"rdpr %%wstate, %%o5\n\t" \
"rdpr %%cwp, %%o5\n\t" \
"stx %%o7, [%%g6 + %4]\n\t" \
"st %%o5, [%%g6 + %5]\n\t" \
+ "membar #Sync\n\t" \
"mov %0, %%g6\n\t" \
"ld [%0 + %5], %%g1\n\t" \
"wrpr %%g1, %%cwp\n\t" \
"o0", "o1", "o2", "o3", "o4", "o5"); \
switch_continue: } while(0)
-/* Unlike the hybrid v7/v8 kernel, we can assume swap exists under V9. */
-extern __inline__ unsigned long xchg_u32(__volatile__ unsigned int *m, unsigned int val)
+extern __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
{
- __asm__ __volatile__("swap [%2], %0"
- : "=&r" (val)
- : "0" (val), "r" (m));
+ __asm__ __volatile__("
+ mov %0, %%g5
+1: lduw [%2], %%g7
+ cas [%2], %%g7, %0
+ cmp %%g7, %0
+ bne,a,pn %%icc, 1b
+ mov %%g5, %0
+ membar #StoreLoad | #StoreStore
+" : "=&r" (val)
+ : "0" (val), "r" (m)
+ : "g5", "g7", "cc", "memory");
return val;
}
-/* Bolix, must use casx for 64-bit values. */
-extern __inline__ unsigned long xchg_u64(__volatile__ unsigned long *m,
- unsigned long val)
+extern __inline__ unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val)
{
- unsigned long temp;
__asm__ __volatile__("
- mov %0, %%g1
-1: ldx [%3], %1
- casx [%3], %1, %0
- cmp %1, %0
+ mov %0, %%g5
+1: ldx [%2], %%g7
+ casx [%2], %%g7, %0
+ cmp %%g7, %0
bne,a,pn %%xcc, 1b
- mov %%g1, %0
-" : "=&r" (val), "=&r" (temp)
+ mov %%g5, %0
+ membar #StoreLoad | #StoreStore
+" : "=&r" (val)
: "0" (val), "r" (m)
- : "g1", "cc");
+ : "g5", "g7", "cc", "memory");
return val;
}
{
switch (size) {
case 4:
- return xchg_u32(ptr, x);
+ return xchg32(ptr, x);
case 8:
- return xchg_u64(ptr, x);
+ return xchg64(ptr, x);
};
__xchg_called_with_bad_pointer();
return x;
#define HUPCL 0x00000400
#define CLOCAL 0x00000800
#define CBAUDEX 0x00001000
-/* We'll never see these speeds with the Zilogs, but for completeness... */
#define B57600 0x00001001
#define B115200 0x00001002
#define B230400 0x00001003
#define B460800 0x00001004
/* This is what we can do with the Zilogs. */
#define B76800 0x00001005
+/* This is what we can do with the SAB82532. */
+#define B153600 0x00001006
+#define B307200 0x00001007
+#define B614400 0x00001008
+#define B921600 0x00001009
+#define B1843200 0x0000100a
#define CIBAUD 0x100f0000 /* input baud rate (not used) */
#define CMSPAR 0x40000000 /* mark or space (stick) parity */
#define CRTSCTS 0x80000000 /* flow control */
--- /dev/null
+/* $Id: ttable.h,v 1.2 1997/08/09 09:03:36 davem Exp $ */
+#ifndef _SPARC64_TTABLE_H
+#define _SPARC64_TTABLE_H
+
+#define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
+
+/* We need a "cleaned" instruction... */
+#define CLEAN_WINDOW \
+ rdpr %cleanwin, %l0; add %l0, 1, %l0; \
+ wrpr %l0, 0x0, %cleanwin; \
+ clr %o0; clr %o1; clr %o2; clr %o3; \
+ clr %o4; clr %o5; clr %o6; clr %o7; \
+ clr %l0; clr %l1; clr %l2; clr %l3; \
+ clr %l4; clr %l5; clr %l6; clr %l7; \
+ retry; \
+ nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
+
+#define TRAP(routine) \
+ sethi %hi(109f), %g7; \
+ ba,pt %xcc, etrap; \
+109: or %g7, %lo(109b), %g7; \
+ call routine; \
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
+ ba,pt %xcc, rtrap; \
+ clr %l6; \
+ nop;
+
+#define TRAP_NOSAVE(routine) \
+ ba,pt %xcc, routine; \
+ nop; \
+ nop; nop; nop; nop; nop; nop;
+
+#define TRAPTL1(routine) \
+ sethi %hi(109f), %g7; \
+ ba,pt %xcc, etraptl1; \
+109: or %g7, %lo(109b), %g7; \
+ call routine; \
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
+ ba,pt %xcc, rtrap; \
+ clr %l6; \
+ nop;
+
+#define TRAP_ARG(routine, arg) \
+ sethi %hi(109f), %g7; \
+ ba,pt %xcc, etrap; \
+109: or %g7, %lo(109b), %g7; \
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
+ call routine; \
+ mov arg, %o1; \
+ ba,pt %xcc, rtrap; \
+ clr %l6;
+
+#define TRAPTL1_ARG(routine, arg) \
+ sethi %hi(109f), %g7; \
+ ba,pt %xcc, etraptl1; \
+109: or %g7, %lo(109b), %g7; \
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
+ call routine; \
+ mov arg, %o1; \
+ ba,pt %xcc, rtrap; \
+ clr %l6;
+
+#define SYSCALL_TRAP(routine, systbl) \
+ sethi %hi(109f), %g7; \
+ ba,pt %xcc, etrap; \
+109: or %g7, %lo(109b), %g7; \
+ call routine; \
+ sethi %hi(systbl), %l7; \
+ nop; nop; nop;
+
+#define ACCESS_EXCEPTION_TRAP(routine) \
+ rdpr %pstate, %g1; \
+ wrpr %g1, PSTATE_MG|PSTATE_AG, %pstate; \
+ ba,pt %xcc, etrap; \
+ rd %pc, %g7; \
+ call routine; \
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
+ ba,pt %xcc, rtrap; \
+ clr %l6;
+
+#define ACCESS_EXCEPTION_TRAPTL1(routine) \
+ rdpr %pstate, %g1; \
+ wrpr %g1, PSTATE_MG|PSTATE_AG, %pstate; \
+ ba,pt %xcc, etraptl1; \
+ rd %pc, %g7; \
+ call routine; \
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
+ ba,pt %xcc, rtrap; \
+ clr %l6;
+
+#define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
+#define LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
+#define LINUX_64BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table64)
+#define GETCC_TRAP TRAP(getcc)
+#define SETCC_TRAP TRAP(setcc)
+/* FIXME: Write these actually */
+#define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
+#define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
+#define BREAKPOINT_TRAP TRAP(breakpoint_trap)
+#define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
+
+#define TRAP_IRQ(routine, level) \
+ rdpr %pil, %g2; \
+ wrpr %g0, 15, %pil; \
+ b,pt %xcc, etrap_irq; \
+ rd %pc, %g7; \
+ mov level, %o0; \
+ call routine; \
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1; \
+ ba,a,pt %xcc, rtrap_clr_l6;
+
+#ifdef __SMP__
+#define TRAP_TICK \
+ rdpr %pil, %g2; \
+ wrpr %g0, 15, %pil; \
+ b,pt %xcc, etrap_irq; \
+ rd %pc, %g7; \
+ call smp_percpu_timer_interrupt; \
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
+ b,pt %xcc, rtrap; \
+ clr %l6;
+#else
+#define TRAP_TICK TRAP_IRQ(handler_irq, 14)
+#endif
+
+#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
+
+#define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
+
+#define BTRAPTL1(lvl) TRAPTL1_ARG(bad_trap_tl1, lvl)
+
+#define FLUSH_WINDOW_TRAP \
+ ba,pt %xcc, etrap; \
+ rd %pc, %g7; \
+ flushw; \
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1; \
+ add %l1, 4, %l2; \
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]; \
+ ba,pt %xcc, rtrap_clr_l6; \
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC];
+
+/* Before touching these macros, you owe it to yourself to go and
+ * see how arch/sparc64/kernel/winfixup.S works... -DaveM
+ */
+
+/* Normal kernel spill */
+#define SPILL_0_NORMAL \
+ stx %l0, [%sp + STACK_BIAS + 0x00]; \
+ stx %l1, [%sp + STACK_BIAS + 0x08]; \
+ stx %l2, [%sp + STACK_BIAS + 0x10]; \
+ stx %l3, [%sp + STACK_BIAS + 0x18]; \
+ stx %l4, [%sp + STACK_BIAS + 0x20]; \
+ stx %l5, [%sp + STACK_BIAS + 0x28]; \
+ stx %l6, [%sp + STACK_BIAS + 0x30]; \
+ stx %l7, [%sp + STACK_BIAS + 0x38]; \
+ stx %i0, [%sp + STACK_BIAS + 0x40]; \
+ stx %i1, [%sp + STACK_BIAS + 0x48]; \
+ stx %i2, [%sp + STACK_BIAS + 0x50]; \
+ stx %i3, [%sp + STACK_BIAS + 0x58]; \
+ stx %i4, [%sp + STACK_BIAS + 0x60]; \
+ stx %i5, [%sp + STACK_BIAS + 0x68]; \
+ stx %i6, [%sp + STACK_BIAS + 0x70]; \
+ stx %i7, [%sp + STACK_BIAS + 0x78]; \
+ saved; retry; nop; nop; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; nop; nop; nop;
+
+/* Normal 64bit spill */
+#define SPILL_1_GENERIC(xxx) \
+ wr %g0, xxx, %asi; \
+ stxa %l0, [%sp + STACK_BIAS + 0x00] %asi; \
+ stxa %l1, [%sp + STACK_BIAS + 0x08] %asi; \
+ stxa %l2, [%sp + STACK_BIAS + 0x10] %asi; \
+ stxa %l3, [%sp + STACK_BIAS + 0x18] %asi; \
+ stxa %l4, [%sp + STACK_BIAS + 0x20] %asi; \
+ stxa %l5, [%sp + STACK_BIAS + 0x28] %asi; \
+ stxa %l6, [%sp + STACK_BIAS + 0x30] %asi; \
+ stxa %l7, [%sp + STACK_BIAS + 0x38] %asi; \
+ stxa %i0, [%sp + STACK_BIAS + 0x40] %asi; \
+ stxa %i1, [%sp + STACK_BIAS + 0x48] %asi; \
+ stxa %i2, [%sp + STACK_BIAS + 0x50] %asi; \
+ stxa %i3, [%sp + STACK_BIAS + 0x58] %asi; \
+ stxa %i4, [%sp + STACK_BIAS + 0x60] %asi; \
+ stxa %i5, [%sp + STACK_BIAS + 0x68] %asi; \
+ stxa %i6, [%sp + STACK_BIAS + 0x70] %asi; \
+ stxa %i7, [%sp + STACK_BIAS + 0x78] %asi; \
+ saved; retry; nop; nop; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, spill_fixup_mna; \
+ b,a,pt %xcc, spill_fixup;
+
+/* Normal 32bit spill */
+#define SPILL_2_GENERIC(xxx) \
+ wr %g0, xxx, %asi; \
+ srl %sp, 0, %sp; \
+ stwa %l0, [%sp + 0x00] %asi; \
+ stwa %l1, [%sp + 0x04] %asi; \
+ stwa %l2, [%sp + 0x08] %asi; \
+ stwa %l3, [%sp + 0x0c] %asi; \
+ stwa %l4, [%sp + 0x10] %asi; \
+ stwa %l5, [%sp + 0x14] %asi; \
+ stwa %l6, [%sp + 0x18] %asi; \
+ stwa %l7, [%sp + 0x1c] %asi; \
+ stwa %i0, [%sp + 0x20] %asi; \
+ stwa %i1, [%sp + 0x24] %asi; \
+ stwa %i2, [%sp + 0x28] %asi; \
+ stwa %i3, [%sp + 0x2c] %asi; \
+ stwa %i4, [%sp + 0x30] %asi; \
+ stwa %i5, [%sp + 0x34] %asi; \
+ stwa %i6, [%sp + 0x38] %asi; \
+ stwa %i7, [%sp + 0x3c] %asi; \
+ saved; retry; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, spill_fixup_mna; \
+ b,a,pt %xcc, spill_fixup;
+
+#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
+#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
+#define SPILL_3_NORMAL SPILL_0_NORMAL
+#define SPILL_4_NORMAL SPILL_0_NORMAL
+#define SPILL_5_NORMAL SPILL_0_NORMAL
+#define SPILL_6_NORMAL SPILL_0_NORMAL
+#define SPILL_7_NORMAL SPILL_0_NORMAL
+
+#define SPILL_0_OTHER SPILL_0_NORMAL
+#define SPILL_1_OTHER SPILL_1_GENERIC(ASI_AIUS)
+#define SPILL_2_OTHER SPILL_2_GENERIC(ASI_AIUS)
+#define SPILL_3_OTHER SPILL_3_NORMAL
+#define SPILL_4_OTHER SPILL_4_NORMAL
+#define SPILL_5_OTHER SPILL_5_NORMAL
+#define SPILL_6_OTHER SPILL_6_NORMAL
+#define SPILL_7_OTHER SPILL_7_NORMAL
+
+/* Normal kernel fill */
+#define FILL_0_NORMAL \
+ ldx [%sp + STACK_BIAS + 0x00], %l0; \
+ ldx [%sp + STACK_BIAS + 0x08], %l1; \
+ ldx [%sp + STACK_BIAS + 0x10], %l2; \
+ ldx [%sp + STACK_BIAS + 0x18], %l3; \
+ ldx [%sp + STACK_BIAS + 0x20], %l4; \
+ ldx [%sp + STACK_BIAS + 0x28], %l5; \
+ ldx [%sp + STACK_BIAS + 0x30], %l6; \
+ ldx [%sp + STACK_BIAS + 0x38], %l7; \
+ ldx [%sp + STACK_BIAS + 0x40], %i0; \
+ ldx [%sp + STACK_BIAS + 0x48], %i1; \
+ ldx [%sp + STACK_BIAS + 0x50], %i2; \
+ ldx [%sp + STACK_BIAS + 0x58], %i3; \
+ ldx [%sp + STACK_BIAS + 0x60], %i4; \
+ ldx [%sp + STACK_BIAS + 0x68], %i5; \
+ ldx [%sp + STACK_BIAS + 0x70], %i6; \
+ ldx [%sp + STACK_BIAS + 0x78], %i7; \
+ restored; retry; nop; nop; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; nop; nop; nop;
+
+/* Normal 64bit fill */
+#define FILL_1_GENERIC(xxx) \
+ wr %g0, xxx, %asi; \
+ ldxa [%sp + STACK_BIAS + 0x00] %asi, %l0; \
+ ldxa [%sp + STACK_BIAS + 0x08] %asi, %l1; \
+ ldxa [%sp + STACK_BIAS + 0x10] %asi, %l2; \
+ ldxa [%sp + STACK_BIAS + 0x18] %asi, %l3; \
+ ldxa [%sp + STACK_BIAS + 0x20] %asi, %l4; \
+ ldxa [%sp + STACK_BIAS + 0x28] %asi, %l5; \
+ ldxa [%sp + STACK_BIAS + 0x30] %asi, %l6; \
+ ldxa [%sp + STACK_BIAS + 0x38] %asi, %l7; \
+ ldxa [%sp + STACK_BIAS + 0x40] %asi, %i0; \
+ ldxa [%sp + STACK_BIAS + 0x48] %asi, %i1; \
+ ldxa [%sp + STACK_BIAS + 0x50] %asi, %i2; \
+ ldxa [%sp + STACK_BIAS + 0x58] %asi, %i3; \
+ ldxa [%sp + STACK_BIAS + 0x60] %asi, %i4; \
+ ldxa [%sp + STACK_BIAS + 0x68] %asi, %i5; \
+ ldxa [%sp + STACK_BIAS + 0x70] %asi, %i6; \
+ ldxa [%sp + STACK_BIAS + 0x78] %asi, %i7; \
+ restored; retry; nop; nop; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, fill_fixup_mna; \
+ b,a,pt %xcc, fill_fixup;
+
+/* Normal 32bit fill */
+#define FILL_2_GENERIC(xxx) \
+ wr %g0, xxx, %asi; \
+ srl %sp, 0, %sp; \
+ lduwa [%sp + 0x00] %asi, %l0; \
+ lduwa [%sp + 0x04] %asi, %l1; \
+ lduwa [%sp + 0x08] %asi, %l2; \
+ lduwa [%sp + 0x0c] %asi, %l3; \
+ lduwa [%sp + 0x10] %asi, %l4; \
+ lduwa [%sp + 0x14] %asi, %l5; \
+ lduwa [%sp + 0x18] %asi, %l6; \
+ lduwa [%sp + 0x1c] %asi, %l7; \
+ lduwa [%sp + 0x20] %asi, %i0; \
+ lduwa [%sp + 0x24] %asi, %i1; \
+ lduwa [%sp + 0x28] %asi, %i2; \
+ lduwa [%sp + 0x2c] %asi, %i3; \
+ lduwa [%sp + 0x30] %asi, %i4; \
+ lduwa [%sp + 0x34] %asi, %i5; \
+ lduwa [%sp + 0x38] %asi, %i6; \
+ lduwa [%sp + 0x3c] %asi, %i7; \
+ restored; retry; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, fill_fixup_mna; \
+ b,a,pt %xcc, fill_fixup;
+
+#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
+#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
+#define FILL_3_NORMAL FILL_0_NORMAL
+#define FILL_4_NORMAL FILL_0_NORMAL
+#define FILL_5_NORMAL FILL_0_NORMAL
+#define FILL_6_NORMAL FILL_0_NORMAL
+#define FILL_7_NORMAL FILL_0_NORMAL
+
+#define FILL_0_OTHER FILL_0_NORMAL
+#define FILL_1_OTHER FILL_1_GENERIC(ASI_AIUS)
+#define FILL_2_OTHER FILL_2_GENERIC(ASI_AIUS)
+#define FILL_3_OTHER FILL_3_NORMAL
+#define FILL_4_OTHER FILL_4_NORMAL
+#define FILL_5_OTHER FILL_5_NORMAL
+#define FILL_6_OTHER FILL_6_NORMAL
+#define FILL_7_OTHER FILL_7_NORMAL
+
+#endif /* !(_SPARC64_TTABLE_H) */
-/* $Id: uaccess.h,v 1.20 1997/07/13 18:23:45 davem Exp $ */
+/* $Id: uaccess.h,v 1.21 1997/07/31 07:37:25 davem Exp $ */
#ifndef _ASM_UACCESS_H
#define _ASM_UACCESS_H
#define get_fs() (current->tss.current_ds)
#define get_ds() (KERNEL_DS)
+
+extern spinlock_t scheduler_lock;
+
#define set_fs(val) \
-do { \
+do { spin_lock(&scheduler_lock); \
current->tss.current_ds = (val); \
if ((val) == KERNEL_DS) { \
flushw_user (); \
} \
spitfire_set_secondary_context(current->tss.ctx); \
__asm__ __volatile__("flush %g6"); \
+ spin_unlock(&scheduler_lock); \
} while(0)
#define __user_ok(addr,size) 1
#ifdef CONFIG_AMIGA_Z2RAM
extern int z2_init(void);
#endif
+#ifdef CONFIG_MAC_FLOPPY
+extern int swim3_init(void);
+#endif
extern void set_device_ro(kdev_t dev,int flag);
void add_blkdev_randomness(int major);
extern void d_delete(struct dentry *);
/* allocate/de-allocate */
-extern void d_free(struct dentry *);
extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
extern void shrink_dcache(void);
extern int d_invalidate(struct dentry *);
PROC_HARDWARE,
PROC_SLABINFO,
PROC_PARPORT,
- PROC_OMIRR /* whether enabled or not */
+ PROC_OMIRR, /* whether enabled or not */
+ PROC_PPC_HTAB
};
enum pid_directory_inos {
PROC_SCSI_GVP11,
PROC_SCSI_ATARI,
PROC_SCSI_IDESCSI,
+ PROC_SCSI_MESH,
+ PROC_SCSI_53C94,
PROC_SCSI_SCSI_DEBUG,
PROC_SCSI_NOT_PRESENT,
PROC_SCSI_FILE, /* I'm assuming here that we */
extern struct inode_operations proc_ringbuf_inode_operations;
#endif
extern struct inode_operations proc_omirr_inode_operations;
+extern struct inode_operations proc_ppc_htab_inode_operations;
#endif
extern void proc_tty_init(void);
extern void proc_tty_register_driver(struct tty_driver *driver);
extern void proc_tty_unregister_driver(struct tty_driver *driver);
+
+/*
+ * proc_devtree.c
+ */
+extern void proc_device_tree_init(void);
#define VIDEO_TYPE_SUN 0x50 /* Sun frame buffer. */
+#define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */
+
/*
* This character is the same as _POSIX_VDISABLE: it cannot be used as
* a c_cc[] character, but indicates that a particular special character
#include <asm/irq.h>
#ifdef __SMP__
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#endif
extern char *get_options(char *str, int *ints);
/* Various random spinlocks we want to export */
EXPORT_SYMBOL(tqueue_lock);
EXPORT_SYMBOL(waitqueue_lock);
-EXPORT_SYMBOL(lk_lockmsg);
#endif
/* autoirq from drivers/net/auto_irq.c */
fib_class_get_info
});
proc_net_register(&(struct proc_dir_entry) {
- PROC_NET_RTRULES, 8, "rt_local",
+ PROC_NET_RTLOCAL, 8, "rt_local",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
fib_local_get_info
asmlinkage int sys_socket(int family, int type, int protocol)
{
- int fd, err;
+ int retval;
struct socket *sock;
lock_kernel();
- if ((err = sock_create(family, type, protocol, &sock)) < 0)
+ retval = sock_create(family, type, protocol, &sock);
+ if (retval < 0)
goto out;
- if ((fd = get_fd(sock->inode)) < 0)
- {
+ retval = get_fd(sock->inode);
+ if (retval < 0) {
sock_release(sock);
- err = -EINVAL;
- }
- else
- {
- sock->file = current->files->fd[fd];
- err = fd;
+ goto out;
}
+ sock->file = current->files->fd[retval];
out:
unlock_kernel();
- return err;
+ return retval;
}
/*